aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/mangos.sql6
-rw-r--r--sql/updates/1138_world.sql1
-rw-r--r--sql/updates/7369_01_mangos_quest_template.sql7
-rw-r--r--src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp2
-rw-r--r--src/framework/Makefile.am64
-rw-r--r--src/game/AuctionHouseMgr.cpp34
-rw-r--r--src/game/BattleGround.cpp9
-rw-r--r--src/game/BattleGround.h4
-rw-r--r--src/game/BattleGroundAB.cpp24
-rw-r--r--src/game/BattleGroundAB.h2
-rw-r--r--src/game/BattleGroundEY.cpp25
-rw-r--r--src/game/BattleGroundEY.h6
-rw-r--r--src/game/BattleGroundMgr.cpp86
-rw-r--r--src/game/BattleGroundMgr.h10
-rw-r--r--src/game/BattleGroundWS.h4
-rw-r--r--src/game/Chat.cpp2
-rw-r--r--src/game/Creature.cpp12
-rw-r--r--src/game/GameEvent.cpp2
-rw-r--r--src/game/GridDefines.h2
-rw-r--r--src/game/Item.cpp2
-rw-r--r--src/game/Item.h2
-rw-r--r--src/game/ItemHandler.cpp6
-rw-r--r--src/game/ItemPrototype.h15
-rw-r--r--src/game/Level0.cpp2
-rw-r--r--src/game/Level3.cpp2
-rw-r--r--src/game/MiscHandler.cpp2
-rw-r--r--src/game/MovementHandler.cpp2
-rw-r--r--src/game/ObjectMgr.cpp91
-rw-r--r--src/game/Pet.cpp2
-rw-r--r--src/game/PetAI.cpp2
-rw-r--r--src/game/Player.cpp384
-rw-r--r--src/game/Player.h13
-rw-r--r--src/game/QuestDef.cpp57
-rw-r--r--src/game/QuestDef.h1
-rw-r--r--src/game/Spell.cpp106
-rw-r--r--src/game/Spell.h2
-rw-r--r--src/game/SpellAuras.cpp11
-rw-r--r--src/game/SpellEffects.cpp55
-rw-r--r--src/game/SpellHandler.cpp2
-rw-r--r--src/game/SpellMgr.cpp1
-rw-r--r--src/game/SpellMgr.h7
-rw-r--r--src/game/Unit.cpp17
-rw-r--r--src/game/Weather.cpp2
-rw-r--r--src/game/World.cpp17
-rw-r--r--src/game/World.h1
-rw-r--r--src/game/WorldSession.cpp3
-rw-r--r--src/mangosd/mangosd.conf.dist.in6
-rw-r--r--src/shared/Auth/Makefile.am20
-rw-r--r--src/shared/Common.h1
-rw-r--r--src/shared/Database/Makefile.am70
-rw-r--r--src/shared/Makefile.am50
-rw-r--r--src/shared/revision_nr.h2
-rw-r--r--src/shared/vmap/Makefile.am54
53 files changed, 746 insertions, 566 deletions
diff --git a/sql/mangos.sql b/sql/mangos.sql
index 829a7586d72..4e895e9e735 100644
--- a/sql/mangos.sql
+++ b/sql/mangos.sql
@@ -22,7 +22,7 @@
DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
- `required_7349_01_mangos_spell_area` bit(1) default NULL
+ `required_7369_01_mangos_quest_template` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@@ -13047,10 +13047,6 @@ CREATE TABLE `quest_template` (
`ReqSourceCount2` smallint(5) unsigned NOT NULL default '0',
`ReqSourceCount3` smallint(5) unsigned NOT NULL default '0',
`ReqSourceCount4` smallint(5) unsigned NOT NULL default '0',
- `ReqSourceRef1` tinyint(3) unsigned NOT NULL default '0',
- `ReqSourceRef2` tinyint(3) unsigned NOT NULL default '0',
- `ReqSourceRef3` tinyint(3) unsigned NOT NULL default '0',
- `ReqSourceRef4` tinyint(3) unsigned NOT NULL default '0',
`ReqCreatureOrGOId1` mediumint(9) NOT NULL default '0',
`ReqCreatureOrGOId2` mediumint(9) NOT NULL default '0',
`ReqCreatureOrGOId3` mediumint(9) NOT NULL default '0',
diff --git a/sql/updates/1138_world.sql b/sql/updates/1138_world.sql
new file mode 100644
index 00000000000..610f97139a5
--- /dev/null
+++ b/sql/updates/1138_world.sql
@@ -0,0 +1 @@
+INSERT INTO `spell_proc_event` VALUES (17619, 0x00, 13, 0x0000000000000000, 0x00008000, 0x00000000, 0.000000, 0.000000, 0);
diff --git a/sql/updates/7369_01_mangos_quest_template.sql b/sql/updates/7369_01_mangos_quest_template.sql
new file mode 100644
index 00000000000..734ebe58470
--- /dev/null
+++ b/sql/updates/7369_01_mangos_quest_template.sql
@@ -0,0 +1,7 @@
+ALTER TABLE db_version CHANGE COLUMN required_7349_01_mangos_spell_area required_7369_01_mangos_quest_template bit;
+
+ALTER TABLE quest_template
+ DROP COLUMN ReqSourceRef1,
+ DROP COLUMN ReqSourceRef2,
+ DROP COLUMN ReqSourceRef3,
+ DROP COLUMN ReqSourceRef4; \ No newline at end of file
diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp
index 98d5c352d3f..6e301d339c8 100644
--- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp
+++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal.cpp
@@ -54,7 +54,7 @@ CreatureAI* GetAI_npc_jaina_proudmoore(Creature *_Creature)
ai->Spell[0].TargetType = TARGETTYPE_RANDOM;
ai->Spell[1].SpellId = SPELL_PYROBLAST;
- ai->Spell[1].Cooldown = 2000 + rand()%7000;
+ ai->Spell[1].Cooldown = 5500 + rand()%4000;
ai->Spell[1].TargetType = TARGETTYPE_RANDOM;
ai->Spell[2].SpellId = SPELL_SUMMON_ELEMENTALS;
diff --git a/src/framework/Makefile.am b/src/framework/Makefile.am
index e76e12ee76a..34ec997cc06 100644
--- a/src/framework/Makefile.am
+++ b/src/framework/Makefile.am
@@ -27,39 +27,39 @@ AM_CPPFLAGS = $(TRINI_INCLUDES) -I$(srcdir)
# libMaNGOSScript shared library will later be reused by world server daemon.
noinst_LIBRARIES = libmangosframework.a
libmangosframework_a_SOURCES = \
- Policies/ObjectLifeTime.cpp \
- Utilities/EventProcessor.cpp
+ Policies/ObjectLifeTime.cpp \
+ Utilities/EventProcessor.cpp
## Additional files to include when running 'make dist'
# Source and header files for the Framework.
EXTRA_DIST = \
- Dynamic/FactoryHolder.h \
- Dynamic/ObjectRegistry.h \
- GameSystem/Grid.h \
- GameSystem/GridLoader.h \
- GameSystem/GridRefManager.h \
- GameSystem/GridReference.h \
- GameSystem/NGrid.h \
- GameSystem/TypeContainer.h \
- GameSystem/TypeContainerFunctions.h \
- GameSystem/TypeContainerFunctionsPtr.h \
- GameSystem/TypeContainerVisitor.h \
- Network/SocketDefines.h \
- Platform/CompilerDefs.h \
- Platform/Define.h \
- Policies/CreationPolicy.h \
- Policies/ObjectLifeTime.h \
- Policies/Singleton.h \
- Policies/SingletonImp.h \
- Policies/ThreadingModel.h \
- Utilities/CountedReference/Reference.h \
- Utilities/CountedReference/ReferenceHolder.h \
- Utilities/CountedReference/ReferenceImpl.h \
- Utilities/LinkedReference/RefManager.h \
- Utilities/LinkedReference/Reference.h \
- Utilities/ByteConverter.h \
- Utilities/Callback.h \
- Utilities/EventProcessor.h \
- Utilities/UnorderedMap.h \
- Utilities/LinkedList.h \
- Utilities/TypeList.h
+ Dynamic/FactoryHolder.h \
+ Dynamic/ObjectRegistry.h \
+ GameSystem/Grid.h \
+ GameSystem/GridLoader.h \
+ GameSystem/GridRefManager.h \
+ GameSystem/GridReference.h \
+ GameSystem/NGrid.h \
+ GameSystem/TypeContainer.h \
+ GameSystem/TypeContainerFunctions.h \
+ GameSystem/TypeContainerFunctionsPtr.h \
+ GameSystem/TypeContainerVisitor.h \
+ Network/SocketDefines.h \
+ Platform/CompilerDefs.h \
+ Platform/Define.h \
+ Policies/CreationPolicy.h \
+ Policies/ObjectLifeTime.h \
+ Policies/Singleton.h \
+ Policies/SingletonImp.h \
+ Policies/ThreadingModel.h \
+ Utilities/CountedReference/Reference.h \
+ Utilities/CountedReference/ReferenceHolder.h \
+ Utilities/CountedReference/ReferenceImpl.h \
+ Utilities/LinkedReference/RefManager.h \
+ Utilities/LinkedReference/Reference.h \
+ Utilities/ByteConverter.h \
+ Utilities/Callback.h \
+ Utilities/EventProcessor.h \
+ Utilities/UnorderedMap.h \
+ Utilities/LinkedList.h \
+ Utilities/TypeList.h
diff --git a/src/game/AuctionHouseMgr.cpp b/src/game/AuctionHouseMgr.cpp
index fd326217f3d..3c63b5f39ad 100644
--- a/src/game/AuctionHouseMgr.cpp
+++ b/src/game/AuctionHouseMgr.cpp
@@ -630,29 +630,29 @@ bool AuctionEntry::BuildAuctionInfo(WorldPacket & data) const
sLog.outError("auction to item, that doesn't exist !!!!");
return false;
}
- data << (uint32) Id;
- data << (uint32) pItem->GetEntry();
+ data << uint32(Id);
+ data << uint32(pItem->GetEntry());
for (uint8 i = 0; i < MAX_INSPECTED_ENCHANTMENT_SLOT; i++)
{
- data << (uint32) pItem->GetEnchantmentId(EnchantmentSlot(i));
- data << (uint32) pItem->GetEnchantmentDuration(EnchantmentSlot(i));
- data << (uint32) pItem->GetEnchantmentCharges(EnchantmentSlot(i));
+ data << uint32(pItem->GetEnchantmentId(EnchantmentSlot(i)));
+ data << uint32(pItem->GetEnchantmentDuration(EnchantmentSlot(i)));
+ data << uint32(pItem->GetEnchantmentCharges(EnchantmentSlot(i)));
}
- data << (uint32) pItem->GetItemRandomPropertyId(); //random item property id
- data << (uint32) pItem->GetItemSuffixFactor(); //SuffixFactor
- data << (uint32) pItem->GetCount(); //item->count
- data << (uint32) pItem->GetSpellCharges(); //item->charge FFFFFFF
- data << (uint32) 0; //Unknown
- data << (uint64) owner; //Auction->owner
- data << (uint32) startbid; //Auction->startbid (not sure if useful)
- data << (uint32) (bid ? GetAuctionOutBid() : 0);
+ data << uint32(pItem->GetItemRandomPropertyId()); //random item property id
+ data << uint32(pItem->GetItemSuffixFactor()); //SuffixFactor
+ data << uint32(pItem->GetCount()); //item->count
+ data << uint32(pItem->GetSpellCharges()); //item->charge FFFFFFF
+ data << uint32(0); //Unknown
+ data << uint64(owner); //Auction->owner
+ data << uint32(startbid); //Auction->startbid (not sure if useful)
+ data << uint32(bid ? GetAuctionOutBid() : 0);
//minimal outbid
- data << (uint32) buyout; //auction->buyout
- data << (uint32) (expire_time - time(NULL))* 1000; //time left
- data << (uint64) bidder; //auction->bidder current
- data << (uint32) bid; //current bid
+ data << uint32(buyout); //auction->buyout
+ data << uint32((expire_time-time(NULL))*IN_MILISECONDS);//time left
+ data << uint64(bidder) ; //auction->bidder current
+ data << uint32(bid); //current bid
return true;
}
diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp
index 3c73fab012c..24f83eb751f 100644
--- a/src/game/BattleGround.cpp
+++ b/src/game/BattleGround.cpp
@@ -971,7 +971,9 @@ void BattleGround::AddPlayer(Player *plr)
if(GetStatus() == STATUS_WAIT_JOIN) // not started yet
{
- plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
+ if(GetStatus() == STATUS_IN_PROGRESS)
+ plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
+ else plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
plr->SetHealth(plr->GetMaxHealth());
plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
@@ -1575,3 +1577,8 @@ void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid )
if(bg_raid) bg_raid->SetBattlegroundGroup(this);
old_raid = bg_raid;
}
+
+WorldSafeLocsEntry const* BattleGround::GetClosestGraveYard( Player* player )
+{
+ return objmgr.GetClosestGraveYard( player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam() );
+} \ No newline at end of file
diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h
index bc3af58041e..a8f6364ff0d 100644
--- a/src/game/BattleGround.h
+++ b/src/game/BattleGround.h
@@ -74,7 +74,7 @@ enum BattleGroundSpells
SPELL_SPIRIT_HEAL_CHANNEL = 22011, // Spirit Heal Channel
SPELL_SPIRIT_HEAL = 22012, // Spirit Heal
SPELL_RESURRECTION_VISUAL = 24171, // Resurrection Impact Visual
- SPELL_ARENA_PREPARATION = 32727, // use this one, 32728 not correct
+ SPELL_ARENA_PREPARATION = 32728, // use this one, 32727 has an invisibility aura which is wrong
SPELL_ALLIANCE_GOLD_FLAG = 32724,
SPELL_ALLIANCE_GREEN_FLAG = 32725,
SPELL_HORDE_GOLD_FLAG = 35774,
@@ -440,7 +440,7 @@ class BattleGround
virtual void EventPlayerCapturedFlag(Player* /*player*/) {}
/* Death related */
- virtual WorldSafeLocsEntry const* GetClosestGraveYard(float /*x*/, float /*y*/, float /*z*/, uint32 /*team*/) { return NULL; }
+ virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
virtual void AddPlayer(Player *plr); // must be implemented in BG subclass
diff --git a/src/game/BattleGroundAB.cpp b/src/game/BattleGroundAB.cpp
index 7aecb33af8e..21a6583537d 100644
--- a/src/game/BattleGroundAB.cpp
+++ b/src/game/BattleGroundAB.cpp
@@ -425,20 +425,21 @@ void BattleGroundAB::_NodeDeOccupied(uint8 node)
if( !ghost_list.empty() )
{
WorldSafeLocsEntry const *ClosestGrave = NULL;
- Player *plr;
for (std::vector<uint64>::const_iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
{
- plr = objmgr.GetPlayer(*itr);
- if( !plr )
+ Player* plr = objmgr.GetPlayer(*itr);
+ if (!plr)
continue;
- if( !ClosestGrave )
- ClosestGrave = GetClosestGraveYard(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), plr->GetTeam());
- plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
+ if (!ClosestGrave) // cache
+ ClosestGrave = GetClosestGraveYard(plr);
+
+ if (ClosestGrave)
+ plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
}
}
- if( m_BgCreatures[node] )
+ if( m_BgCreatures[node] )
DelCreature(node);
// buff object isn't despawned
@@ -619,9 +620,9 @@ void BattleGroundAB::Reset()
DelCreature(i);
}
-WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(float x, float y, float /*z*/, uint32 team)
+WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(Player* player)
{
- uint8 teamIndex = GetTeamIndexByTeamId(team);
+ uint8 teamIndex = GetTeamIndexByTeamId(player->GetTeam());
// Is there any occupied node for this team?
std::vector<uint8> nodes;
@@ -633,13 +634,16 @@ WorldSafeLocsEntry const* BattleGroundAB::GetClosestGraveYard(float x, float y,
// If so, select the closest node to place ghost on
if( !nodes.empty() )
{
+ float plr_x = player->GetPositionX();
+ float plr_y = player->GetPositionY();
+
float mindist = 999999.0f;
for (uint8 i = 0; i < nodes.size(); ++i)
{
WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] );
if( !entry )
continue;
- float dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y);
+ float dist = (entry->x - plr_x)*(entry->x - plr_x)+(entry->y - plr_y)*(entry->y - plr_y);
if( mindist > dist )
{
mindist = dist;
diff --git a/src/game/BattleGroundAB.h b/src/game/BattleGroundAB.h
index 5f05d182bee..3c080621033 100644
--- a/src/game/BattleGroundAB.h
+++ b/src/game/BattleGroundAB.h
@@ -244,7 +244,7 @@ class BattleGroundAB : public BattleGround
void HandleAreaTrigger(Player *Source, uint32 Trigger);
virtual bool SetupBattleGround();
virtual void Reset();
- virtual WorldSafeLocsEntry const* GetClosestGraveYard(float x, float y, float z, uint32 team);
+ virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
/* Scorekeeping */
virtual void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp
index 40d55ea6f18..78027b532bc 100644
--- a/src/game/BattleGroundEY.cpp
+++ b/src/game/BattleGroundEY.cpp
@@ -896,16 +896,16 @@ void BattleGroundEY::FillInitialWorldStates(WorldPacket& data)
data << uint32(0xc0d) << uint32(0x17b);
}
-WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(float x, float y, float z, uint32 team)
+WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(Player* player)
{
uint32 g_id = 0;
- if(team == ALLIANCE)
- g_id = EY_GRAVEYARD_MAIN_ALLIANCE;
- else if(team == HORDE)
- g_id = EY_GRAVEYARD_MAIN_HORDE;
- else
- return NULL;
+ switch(player->GetTeam())
+ {
+ case ALLIANCE: g_id = EY_GRAVEYARD_MAIN_ALLIANCE; break;
+ case HORDE: g_id = EY_GRAVEYARD_MAIN_HORDE; break;
+ default: return NULL;
+ }
float distance, nearestDistance;
@@ -920,19 +920,24 @@ WorldSafeLocsEntry const *BattleGroundEY::GetClosestGraveYard(float x, float y,
return NULL;
}
- distance = (entry->x - x)*(entry->x - x) + (entry->y - y)*(entry->y - y) + (entry->z - z)*(entry->z - z);
+ float plr_x = player->GetPositionX();
+ float plr_y = player->GetPositionY();
+ float plr_z = player->GetPositionZ();
+
+
+ distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z);
nearestDistance = distance;
for(uint8 i = 0; i < EY_POINTS_MAX; ++i)
{
- if(m_PointOwnedByTeam[i]==team && m_PointState[i]==EY_POINT_UNDER_CONTROL)
+ if(m_PointOwnedByTeam[i]==player->GetTeam() && m_PointState[i]==EY_POINT_UNDER_CONTROL)
{
entry = sWorldSafeLocsStore.LookupEntry(m_CapturingPointTypes[i].GraveYardId);
if(!entry)
sLog.outError("BattleGroundEY: Not found graveyard: %u",m_CapturingPointTypes[i].GraveYardId);
else
{
- distance = (entry->x - x)*(entry->x - x) + (entry->y - y)*(entry->y - y) + (entry->z - z)*(entry->z - z);
+ distance = (entry->x - plr_x)*(entry->x - plr_x) + (entry->y - plr_y)*(entry->y - plr_y) + (entry->z - plr_z)*(entry->z - plr_z);
if(distance < nearestDistance)
{
nearestDistance = distance;
diff --git a/src/game/BattleGroundEY.h b/src/game/BattleGroundEY.h
index 52106461e5a..fd5cf7ce763 100644
--- a/src/game/BattleGroundEY.h
+++ b/src/game/BattleGroundEY.h
@@ -26,8 +26,8 @@
class BattleGround;
#define EY_MAX_TEAM_SCORE 2000
-#define BG_EY_FLAG_RESPAWN_TIME 10000 //10 seconds
-#define BG_EY_FPOINTS_TICK_TIME 2000 //2 seconds
+#define BG_EY_FLAG_RESPAWN_TIME (10*IN_MILISECONDS) //10 seconds
+#define BG_EY_FPOINTS_TICK_TIME (2*IN_MILISECONDS) //2 seconds
enum BG_EY_WorldStates
{
@@ -317,7 +317,7 @@ class BattleGroundEY : public BattleGround
void HandleBuffUse(uint64 const& buff_guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
void HandleKillPlayer(Player *player, Player *killer);
- virtual WorldSafeLocsEntry const* GetClosestGraveYard(float x, float y, float z, uint32 team);
+ virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player);
virtual bool SetupBattleGround();
virtual void Reset();
void UpdateTeamScore(uint32 Team);
diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp
index c1cdc6d6f96..9911f4190ca 100644
--- a/src/game/BattleGroundMgr.cpp
+++ b/src/game/BattleGroundMgr.cpp
@@ -398,12 +398,14 @@ void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)
GroupsQueueType::iterator itr, next;
for(uint32 i = 0; i < BG_QUEUE_GROUP_TYPES_COUNT; i++)
{
- for(itr = m_QueuedGroups[queue_id][i].begin(); itr != m_QueuedGroups[queue_id][i].end(); itr = next)
+ itr = m_QueuedGroups[queue_id][i].begin();
+ next = itr;
+ while (next != m_QueuedGroups[queue_id][i].end())
{
// must do this way, because the groupinfo will be deleted when all playerinfos are removed
- GroupQueueInfo * ginfo = (*itr);
- next = itr;
+ itr = next;
++next;
+ GroupQueueInfo * ginfo = (*itr);
// if group was invited to this bg instance, then remove all references
if( ginfo->IsInvitedToBGInstanceGUID == bgInstanceId )
{
@@ -527,7 +529,7 @@ void BattleGroundQueue::FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel
// this method checks if premade versus premade battleground is possible
// then after 30 mins (default) in queue it moves premade group to normal queue
// it tries to invite as much players as it can - to MaxPlayersPerTeam, because premade groups have more than MinPlayersPerTeam players
-bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MaxPlayersPerTeam, uint32 MinPlayersPerTeam)
+bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam)
{
//check match
if(!m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].empty() && !m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].empty())
@@ -583,12 +585,9 @@ bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32
return false;
}
-//this function tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
-bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id)
+// this method tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
+bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers)
{
- uint32 minPlayers = bg_template->GetMinPlayersPerTeam();
- uint32 maxPlayers = bg_template->GetMaxPlayersPerTeam();
-
GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
for(uint32 i = 0; i < BG_TEAMS_COUNT; i++)
{
@@ -629,6 +628,68 @@ bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBas
return m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() >= minPlayers && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() >= minPlayers;
}
+// this method will check if we can invite players to same faction skirmish match
+bool BattleGroundQueue::CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam)
+{
+ if( m_SelectionPools[BG_TEAM_ALLIANCE].GetPlayerCount() < minPlayersPerTeam && m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() < minPlayersPerTeam )
+ return false;
+ uint32 teamIndex = BG_TEAM_ALLIANCE;
+ uint32 otherTeam = BG_TEAM_HORDE;
+ uint32 otherTeamId = HORDE;
+ if ( m_SelectionPools[BG_TEAM_HORDE].GetPlayerCount() == minPlayersPerTeam )
+ {
+ teamIndex = BG_TEAM_HORDE;
+ otherTeam = BG_TEAM_ALLIANCE;
+ otherTeamId = ALLIANCE;
+ }
+ //clear other team's selection
+ m_SelectionPools[otherTeam].Init();
+ //store last ginfo pointer
+ GroupQueueInfo* ginfo = m_SelectionPools[teamIndex].SelectedGroups.back();
+ //set itr_team to group that was added to selection pool latest
+ GroupsQueueType::iterator itr_team = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].begin();
+ for(; itr_team != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team)
+ if( ginfo == *itr_team )
+ break;
+ if( itr_team == m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end() )
+ return false;
+ GroupsQueueType::iterator itr_team2 = itr_team;
+ ++itr_team2;
+ //invite players to other selection pool
+ for(; itr_team2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr_team2)
+ {
+ if( !(*itr_team2)->IsInvitedToBGInstanceGUID )
+ {
+ m_SelectionPools[otherTeam].AddGroup(*itr_team2, minPlayersPerTeam);
+ if( m_SelectionPools[otherTeam].GetPlayerCount() == minPlayersPerTeam )
+ break;
+ }
+ }
+ if( m_SelectionPools[otherTeam].GetPlayerCount() != minPlayersPerTeam )
+ return false;
+
+ //here we have correct 2 selections and we need to change one teams team and move selection pool teams to other team's queue
+ for(GroupsQueueType::iterator itr = m_SelectionPools[otherTeam].SelectedGroups.begin(); itr != m_SelectionPools[otherTeam].SelectedGroups.end(); ++itr)
+ {
+ //set correct team
+ (*itr)->Team = otherTeamId;
+ //add team to other queue
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + otherTeam].push_front(*itr);
+ //remove team from old queue
+ GroupsQueueType::iterator itr2 = itr_team;
+ ++itr2;
+ for(; itr2 != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].end(); ++itr2)
+ {
+ if( *itr2 == *itr )
+ {
+ m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + teamIndex].erase(itr2);
+ break;
+ }
+ }
+ }
+ return true;
+}
+
/*
this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue
it must be called after fully adding the members of a group to ensure group joining
@@ -729,7 +790,7 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve
if( bg_template->isBattleGround() )
{
//check if there is premade against premade match
- if( CheckPremadeMatch(queue_id, bg_template->GetMaxPlayersPerTeam(), bg_template->GetMinPlayersPerTeam()) )
+ if( CheckPremadeMatch(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam) )
{
//create new battleground
BattleGround * bg2 = NULL;
@@ -754,7 +815,8 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve
if( !isRated )
{
// if there are enough players in pools, start new battleground or non rated arena
- if( CheckNormalMatch(bg_template, queue_id) )
+ if( CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
+ || (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
{
// we successfully created a pool
BattleGround * bg2 = NULL;
@@ -889,11 +951,13 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve
m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].push_front(*(itr_team[BG_TEAM_ALLIANCE]));
// erase from horde queue
m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].erase(itr_team[BG_TEAM_ALLIANCE]);
+ itr_team[BG_TEAM_ALLIANCE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].begin();
}
if( (*(itr_team[BG_TEAM_HORDE]))->Team != HORDE )
{
m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].push_front(*(itr_team[BG_TEAM_HORDE]));
m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE].erase(itr_team[BG_TEAM_HORDE]);
+ itr_team[BG_TEAM_HORDE] = m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_HORDE].begin();
}
InviteGroupToBG(*(itr_team[BG_TEAM_ALLIANCE]), arena, ALLIANCE);
diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h
index 41ad0728caf..1bd3a7110eb 100644
--- a/src/game/BattleGroundMgr.h
+++ b/src/game/BattleGroundMgr.h
@@ -26,7 +26,8 @@
typedef std::map<uint32, BattleGround*> BattleGroundSet;
-typedef std::deque<BattleGround*> BGFreeSlotQueueType;
+//this container can't be deque, because deque doesn't like removing the last element - if you remove it, it invalidates next iterator and crash appears
+typedef std::list<BattleGround*> BGFreeSlotQueueType;
typedef UNORDERED_MAP<uint32, BattleGroundTypeId> BattleMastersMap;
@@ -74,8 +75,9 @@ class BattleGroundQueue
void Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLevel queue_id, uint8 arenaType = 0, bool isRated = false, uint32 minRating = 0);
void FillPlayersToBG(BattleGround* bg, BGQueueIdBasedOnLevel queue_id);
- bool CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MaxPlayersPerTeam, uint32 MinPlayersPerTeam);
- bool CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id);
+ bool CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam);
+ bool CheckNormalMatch(BattleGround* bg_template, BGQueueIdBasedOnLevel queue_id, uint32 minPlayers, uint32 maxPlayers);
+ bool CheckSkirmishForSameFaction(BGQueueIdBasedOnLevel queue_id, uint32 minPlayersPerTeam);
GroupQueueInfo * AddGroup(Player * leader, BattleGroundTypeId bgTypeId, uint8 ArenaType, bool isRated, bool isPremade, uint32 ArenaRating, uint32 ArenaTeamId = 0);
void AddPlayer(Player *plr, GroupQueueInfo *ginfo);
void RemovePlayer(const uint64& guid, bool decreaseInvitedCount);
@@ -87,7 +89,7 @@ class BattleGroundQueue
QueuedPlayersMap m_QueuedPlayers;
//we need constant add to begin and constant remove / add from the end, therefore deque suits our problem well
- typedef std::deque<GroupQueueInfo*> GroupsQueueType;
+ typedef std::list<GroupQueueInfo*> GroupsQueueType;
/*
This two dimensional array is used to store All queued groups
diff --git a/src/game/BattleGroundWS.h b/src/game/BattleGroundWS.h
index 732c078d2f3..d52a0117fb5 100644
--- a/src/game/BattleGroundWS.h
+++ b/src/game/BattleGroundWS.h
@@ -24,8 +24,8 @@
#include "BattleGround.h"
#define BG_WS_MAX_TEAM_SCORE 3
-#define BG_WS_FLAG_RESPAWN_TIME 23000
-#define BG_WS_FLAG_DROP_TIME 10000
+#define BG_WS_FLAG_RESPAWN_TIME (23*IN_MILISECONDS)
+#define BG_WS_FLAG_DROP_TIME (10*IN_MILISECONDS)
enum BG_WS_Sound
{
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index 8173be95561..f30d4f76751 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -318,7 +318,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "skinning_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSkinningCommand, "", NULL },
{ "spell_affect", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAffectCommand, "", NULL },
{ "spell_required", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellRequiredCommand, "", NULL },
- { "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL },
+ { "spell_area", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellAreaCommand, "", NULL },
{ "spell_elixir", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellElixirCommand, "", NULL },
{ "spell_learn_spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadSpellLearnSpellCommand, "", NULL },
{ "spell_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesSpellCommand, "", NULL },
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp
index 52404842673..09e29591e66 100644
--- a/src/game/Creature.cpp
+++ b/src/game/Creature.cpp
@@ -1639,7 +1639,7 @@ void Creature::setDeathState(DeathState s)
{
if((s == JUST_DIED && !m_isDeadByDefault)||(s == JUST_ALIVED && m_isDeadByDefault))
{
- m_deathTimer = m_corpseDelay*1000;
+ m_deathTimer = m_corpseDelay*IN_MILISECONDS;
// always save boss respawn time at death to prevent crash cheating
if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY) || isWorldBoss())
@@ -1991,7 +1991,7 @@ void Creature::SaveRespawnTime()
if(m_respawnTime > time(NULL)) // dead (no corpse)
objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime);
else if(m_deathTimer > 0) // dead (corpse)
- objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),time(NULL)+m_respawnDelay+m_deathTimer/1000);
+ objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),time(NULL)+m_respawnDelay+m_deathTimer/IN_MILISECONDS);
}
bool Creature::IsOutOfThreatArea(Unit* pVictim) const
@@ -2116,7 +2116,7 @@ void Creature::AddCreatureSpellCooldown(uint32 spellid)
uint32 cooldown = GetSpellRecoveryTime(spellInfo);
if(cooldown)
- _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/1000);
+ _AddCreatureSpellCooldown(spellid, time(NULL) + cooldown/IN_MILISECONDS);
if(spellInfo->Category)
_AddCreatureCategoryCooldown(spellInfo->Category, time(NULL));
@@ -2135,7 +2135,7 @@ bool Creature::HasCategoryCooldown(uint32 spell_id) const
return true;
CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category);
- return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / 1000)) > time(NULL));
+ return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILISECONDS)) > time(NULL));
}
bool Creature::HasSpellCooldown(uint32 spell_id) const
@@ -2164,7 +2164,7 @@ time_t Creature::GetRespawnTimeEx() const
if(m_respawnTime > now) // dead (no corpse)
return m_respawnTime;
else if(m_deathTimer > 0) // dead (corpse)
- return now+m_respawnDelay+m_deathTimer/1000;
+ return now+m_respawnDelay+m_deathTimer/IN_MILISECONDS;
else
return now;
}
@@ -2206,7 +2206,7 @@ void Creature::AllLootRemovedFromCorpse()
// corpse was not skinnable -> apply corpse looted timer
if (!cinfo || !cinfo->SkinLootId)
- nDeathTimer = (uint32)((m_corpseDelay * 1000) * sWorld.getRate(RATE_CORPSE_DECAY_LOOTED));
+ nDeathTimer = (uint32)((m_corpseDelay * IN_MILISECONDS) * sWorld.getRate(RATE_CORPSE_DECAY_LOOTED));
// corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
else
nDeathTimer = 0;
diff --git a/src/game/GameEvent.cpp b/src/game/GameEvent.cpp
index 49b55f727e6..278ddbf0cf9 100644
--- a/src/game/GameEvent.cpp
+++ b/src/game/GameEvent.cpp
@@ -1076,7 +1076,7 @@ uint32 GameEvent::Update() // return the next e
for(std::set<uint16>::iterator itr = deactivate.begin(); itr != deactivate.end(); ++itr)
StopEvent(*itr);
sLog.outDetail("Next game event check in %u seconds.", nextEventDelay + 1);
- return (nextEventDelay + 1) * 1000; // Add 1 second to be sure event has started/stopped at next call
+ return (nextEventDelay + 1) * IN_MILISECONDS; // Add 1 second to be sure event has started/stopped at next call
}
void GameEvent::UnApplyEvent(uint16 event_id)
diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h
index b6623942676..a3fe011f402 100644
--- a/src/game/GridDefines.h
+++ b/src/game/GridDefines.h
@@ -48,7 +48,7 @@ class Player;
#define CENTER_GRID_OFFSET (SIZE_OF_GRIDS/2)
-#define MIN_GRID_DELAY MINUTE*1000
+#define MIN_GRID_DELAY (MINUTE*IN_MILISECONDS)
#define MIN_MAP_UPDATE_DELAY 50
#define SIZE_OF_GRID_CELL (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS)
diff --git a/src/game/Item.cpp b/src/game/Item.cpp
index ea8d77076eb..8454604a786 100644
--- a/src/game/Item.cpp
+++ b/src/game/Item.cpp
@@ -265,7 +265,7 @@ bool Item::Create( uint32 guidlow, uint32 itemid, Player const* owner)
SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability);
SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability);
- for(int i = 0; i < 5; ++i)
+ for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
SetSpellCharges(i,itemProto->Spells[i].SpellCharges);
SetUInt32Value(ITEM_FIELD_FLAGS, itemProto->Flags);
diff --git a/src/game/Item.h b/src/game/Item.h
index 8e4fc410531..f30fb8dd461 100644
--- a/src/game/Item.h
+++ b/src/game/Item.h
@@ -167,7 +167,7 @@ enum EnchantmentSlot
#define MAX_VISIBLE_ITEM_OFFSET 18 // 18 fields per visible item (creator(2) + enchantments(13) + properties(1) + seed(1) + pad(1))
-#define MAX_GEM_SOCKETS 3 // (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT)
+#define MAX_GEM_SOCKETS MAX_ITEM_PROTO_SOCKETS// (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) and item proto size, equal value expected
enum EnchantmentOffset
{
diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp
index a845ce29b50..cde9eb74443 100644
--- a/src/game/ItemHandler.cpp
+++ b/src/game/ItemHandler.cpp
@@ -357,7 +357,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
}
data << pProto->ScalingStatDistribution; // scaling stats distribution
data << pProto->ScalingStatValue; // some kind of flags used to determine stat values column
- for(int i = 0; i < 5; ++i)
+ for(int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
{
data << pProto->Damage[i].DamageMin;
data << pProto->Damage[i].DamageMax;
@@ -377,7 +377,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->AmmoType;
data << pProto->RangedModRange;
- for(int s = 0; s < 5; s++)
+ for(int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
{
// send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
// use `item_template` or if not set then only use spell cooldowns
@@ -431,7 +431,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
data << pProto->Map; // Added in 1.12.x & 2.0.1 client branch
data << pProto->BagFamily;
data << pProto->TotemCategory;
- for(int s = 0; s < 3; s++)
+ for(int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
{
data << pProto->Socket[s].Color;
data << pProto->Socket[s].Content;
diff --git a/src/game/ItemPrototype.h b/src/game/ItemPrototype.h
index 1087154c5e7..d7e923a2b77 100644
--- a/src/game/ItemPrototype.h
+++ b/src/game/ItemPrototype.h
@@ -493,6 +493,11 @@ struct _Socket
uint32 Content;
};
+#define MAX_ITEM_PROTO_DAMAGES 5
+#define MAX_ITEM_PROTO_SOCKETS 3
+#define MAX_ITEM_PROTO_SPELLS 5
+#define MAX_ITEM_PROTO_STATS 10
+
struct ItemPrototype
{
uint32 ItemId;
@@ -522,10 +527,10 @@ struct ItemPrototype
int32 Stackable; // 0: not allowed, -1: put in player coin info tab and don't limit stacking (so 1 slot)
uint32 ContainerSlots;
uint32 StatsCount;
- _ItemStat ItemStat[10];
+ _ItemStat ItemStat[MAX_ITEM_PROTO_STATS];
uint32 ScalingStatDistribution; // id from ScalingStatDistribution.dbc
uint32 ScalingStatValue; // mask for selecting column in ScalingStatValues.dbc
- _Damage Damage[5];
+ _Damage Damage[MAX_ITEM_PROTO_DAMAGES];
uint32 Armor;
uint32 HolyRes;
uint32 FireRes;
@@ -536,7 +541,7 @@ struct ItemPrototype
uint32 Delay;
uint32 AmmoType;
float RangedModRange;
- _Spell Spells[5];
+ _Spell Spells[MAX_ITEM_PROTO_SPELLS];
uint32 Bonding;
char* Description;
uint32 PageText;
@@ -555,7 +560,7 @@ struct ItemPrototype
uint32 Map; // id from Map.dbc
uint32 BagFamily; // id from ItemBagFamily.dbc
uint32 TotemCategory; // id from TotemCategory.dbc
- _Socket Socket[3];
+ _Socket Socket[MAX_ITEM_PROTO_SOCKETS];
uint32 socketBonus; // id from SpellItemEnchantment.dbc
uint32 GemProperties; // id from GemProperties.dbc
uint32 RequiredDisenchantSkill;
@@ -636,7 +641,7 @@ struct ItemPrototype
if (Delay == 0)
return 0;
float temp = 0;
- for (int i=0;i<5;++i)
+ for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
temp+=Damage[i].DamageMin + Damage[i].DamageMax;
return temp*500/Delay;
}
diff --git a/src/game/Level0.cpp b/src/game/Level0.cpp
index fcd40455072..e3c0c9f86f7 100644
--- a/src/game/Level0.cpp
+++ b/src/game/Level0.cpp
@@ -148,7 +148,7 @@ bool ChatHandler::HandleSaveCommand(const char* /*args*/)
// save or plan save after 20 sec (logout delay) if current next save time more this value and _not_ output any messages to prevent cheat planning
uint32 save_interval = sWorld.getConfig(CONFIG_INTERVAL_SAVE);
- if(save_interval==0 || save_interval > 20*1000 && player->GetSaveTimer() <= save_interval - 20*1000)
+ if(save_interval==0 || save_interval > 20*IN_MILISECONDS && player->GetSaveTimer() <= save_interval - 20*IN_MILISECONDS)
player->SaveToDB();
return true;
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index 6e2d8f0320e..781c9d1a0c6 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -4416,7 +4416,7 @@ bool ChatHandler::HandleLevelUpCommand(const char* args)
return false;
}
- name = GetNameLink(chr);
+ name = chr->GetName();
}
assert(chr || chr_guid);
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index fe3ff829ccd..c55590d6b67 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -1147,7 +1147,7 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket&/* recv_data*/)
recv_data >> guid;
recv_data >> flags >> time;
DEBUG_LOG("Guid " I64FMTD,guid);
- DEBUG_LOG("Flags %u, time %u",flags, time/1000);
+ DEBUG_LOG("Flags %u, time %u",flags, time/IN_MILISECONDS);
*/
}
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp
index b41b04728da..e9a3f7e90b4 100644
--- a/src/game/MovementHandler.cpp
+++ b/src/game/MovementHandler.cpp
@@ -233,7 +233,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
// fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
if (opcode == MSG_MOVE_FALL_LAND && !GetPlayer()->isInFlight())
- GetPlayer()->HandleFallDamage(movementInfo);
+ GetPlayer()->HandleFall(movementInfo);
if(((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != GetPlayer()->IsInWater())
{
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 14de27c69a8..5f7c9ae5b8b 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -1572,7 +1572,7 @@ void ObjectMgr::LoadItemPrototypes()
bool req = proto->InventoryType!=INVTYPE_NON_EQUIP || proto->PageText;
if(!req)
{
- for (int j = 0; j < 5; ++j)
+ for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j)
{
if(proto->Spells[j].SpellId)
{
@@ -1637,7 +1637,13 @@ void ObjectMgr::LoadItemPrototypes()
const_cast<ItemPrototype*>(proto)->Stackable = 255;
}
- for (int j = 0; j < 10; j++)
+ if(proto->StatsCount > MAX_ITEM_PROTO_STATS)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS);
+ const_cast<ItemPrototype*>(proto)->StatsCount = MAX_ITEM_PROTO_STATS;
+ }
+
+ for (int j = 0; j < MAX_ITEM_PROTO_STATS; ++j)
{
// for ItemStatValue != 0
if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD)
@@ -1647,7 +1653,7 @@ void ObjectMgr::LoadItemPrototypes()
}
}
- for (int j = 0; j < 5; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_DAMAGES; ++j)
{
if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL)
{
@@ -1704,7 +1710,7 @@ void ObjectMgr::LoadItemPrototypes()
}
// spell_3*,spell_4*,spell_5* is empty
- for (int j = 2; j < 5; j++)
+ for (int j = 2; j < MAX_ITEM_PROTO_SPELLS; ++j)
{
if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
{
@@ -1722,7 +1728,7 @@ void ObjectMgr::LoadItemPrototypes()
// normal spell list
else
{
- for (int j = 0; j < 5; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_SPELLS; ++j)
{
if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
{
@@ -1791,7 +1797,7 @@ void ObjectMgr::LoadItemPrototypes()
if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory))
sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory);
- for (int j = 0; j < 3; j++)
+ for (int j = 0; j < MAX_ITEM_PROTO_SOCKETS; j++)
{
if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color)
{
@@ -2824,25 +2830,25 @@ void ObjectMgr::LoadQuests()
"Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4,"
// 39 40 41 42 43 44 45 46
"ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4,"
- // 47 48 49 50 51 52 53 54 55 56 57 58
- "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4, ReqSourceRef1, ReqSourceRef2, ReqSourceRef3, ReqSourceRef4,"
- // 59 60 61 62 63 64 65 66
+ // 47 48 49 50 51 52 53 54
+ "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4,"
+ // 55 56 57 58 59 60 61 62
"ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4,"
- // 67 68 69 70
+ // 63 64 65 66
"ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4,"
- // 71 72 73 74 75 76
+ // 67 68 69 70 71 72
"RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6,"
- // 77 78 79 80 81 82
+ // 73 74 75 76 77 78
"RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6,"
- // 83 84 85 86 87 88 89 90
+ // 79 80 81 82 83 84 85 86
"RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4,"
- // 91 92 93 94 95 96 97 98 99 100
+ // 87 88 89 90 91 92 93 94 95 96
"RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5,"
- // 101 102 103 104 105 106 107 108 109 110 111
+ // 97 98 99 100 101 102 103 104 105 106 107
"RewHonorableKills, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt,"
- // 112 113 114 115 116 117 118 119 120 121
- "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
- // 122 123
+ // 108 109 110 111 112 113 114 115 116 117
+ "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
+ // 118 119
"StartScript, CompleteScript"
" FROM quest_template");
if(result == NULL)
@@ -3136,20 +3142,6 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(),j+1,id,id);
// no changes, quest can't be done for this requirement
}
-
- if(!qinfo->ReqSourceCount[j])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
-
- if(!qinfo->ReqSourceRef[j])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
}
else
{
@@ -3159,41 +3151,6 @@ void ObjectMgr::LoadQuests()
qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]);
// no changes, quest ignore this data
}
-
- if(qinfo->ReqSourceRef[j]>0)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]);
- // no changes, quest ignore this data
- }
- }
- }
-
- for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
- {
- uint32 ref = qinfo->ReqSourceRef[j];
- if(ref)
- {
- if(ref > QUEST_OBJECTIVES_COUNT)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.",
- qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT);
- // no changes, quest can't be done for this requirement
- }
- else
- if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,ref,ref,ref);
- // no changes, quest can't be done for this requirement
- }
- else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1])
- {
- sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.",
- qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]);
- // no changes, quest can't be done for this requirement
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
}
}
diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp
index b4b8bae9c67..77851ed6cbc 100644
--- a/src/game/Pet.cpp
+++ b/src/game/Pet.cpp
@@ -1054,7 +1054,7 @@ void Pet::_LoadSpellCooldowns()
continue;
data << uint32(spell_id);
- data << uint32(uint32(db_time-curTime)*1000); // in m.secs
+ data << uint32(uint32(db_time-curTime)*IN_MILISECONDS);
_AddCreatureSpellCooldown(spell_id,db_time);
diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp
index 9685b71a934..29450b549e1 100644
--- a/src/game/PetAI.cpp
+++ b/src/game/PetAI.cpp
@@ -291,7 +291,7 @@ void PetAI::UpdateAllies()
Unit* owner = i_pet.GetCharmerOrOwner();
Group *pGroup = NULL;
- m_updateAlliesTimer = 10000; //update friendly targets every 10 seconds, lesser checks increase performance
+ m_updateAlliesTimer = 10*IN_MILISECONDS; //update friendly targets every 10 seconds, lesser checks increase performance
if(!owner)
return;
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 850cdfdc0a9..cde74b4a66b 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -68,7 +68,7 @@
#include <cmath>
-#define ZONE_UPDATE_INTERVAL 1000
+#define ZONE_UPDATE_INTERVAL (1*IN_MILISECONDS)
#define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3))
#define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1)
@@ -367,7 +367,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this)
m_swingErrorMsg = 0;
- m_DetectInvTimer = 1000;
+ m_DetectInvTimer = 1*IN_MILISECONDS;
m_bgBattleGroundID = 0;
m_bgTypeID = BATTLEGROUND_TYPE_NONE;
@@ -424,6 +424,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this)
m_InstanceValid = true;
m_dungeonDifficulty = DIFFICULTY_NORMAL;
+ m_lastPotionId = 0;
+
for (int i = 0; i < BASEMOD_END; i++)
{
m_auraBaseMod[i][FLAT_MOD] = 0.0f;
@@ -872,7 +874,7 @@ void Player::StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue)
void Player::ModifyMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, uint32 Regen)
{
if(Type==BREATH_TIMER)
- m_breathTimer = ((MaxValue + 1000) - CurrentValue) / Regen;
+ m_breathTimer = ((MaxValue + 1*IN_MILISECONDS) - CurrentValue) / Regen;
WorldPacket data(SMSG_START_MIRROR_TIMER, (21));
data << (uint32)Type;
@@ -930,7 +932,7 @@ void Player::HandleDrowning()
return;
}
- uint32 UnderWaterTime = 3*MINUTE*1000; // default duration
+ uint32 UnderWaterTime = 3*MINUTE*IN_MILISECONDS; // default duration
AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING);
for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
@@ -942,7 +944,7 @@ void Player::HandleDrowning()
if (!(m_isunderwater & UNDERWATER_WATER_TRIGGER))
{
m_isunderwater|= UNDERWATER_WATER_TRIGGER;
- m_breathTimer = UnderWaterTime + 1000;
+ m_breathTimer = UnderWaterTime + 1*IN_MILISECONDS;
}
//single trigger "show Breathbar"
if ( m_breathTimer <= UnderWaterTime && !(m_isunderwater & UNDERWATER_WATER_BREATHB))
@@ -987,7 +989,7 @@ void Player::HandleLava()
if (!(m_isunderwater & UNDERWATER_INLAVA))
{
m_isunderwater|= UNDERWATER_WATER_BREATHB;
- m_breathTimer = 1000;
+ m_breathTimer = 1*IN_MILISECONDS;
}
*/
// Reset BreathTimer and still in the lava
@@ -1000,7 +1002,7 @@ void Player::HandleLava()
if ( !isGameMaster() )
EnvironmentalDamage(guid, DAMAGE_LAVA, damage);
- m_breathTimer = 1000;
+ m_breathTimer = 1*IN_MILISECONDS;
}
}
else if (!isAlive()) // Disable breath timer and reset underwater flags
@@ -1313,7 +1315,7 @@ void Player::Update( uint32 p_time )
{
m_drunkTimer += p_time;
- if (m_drunkTimer > 10000)
+ if (m_drunkTimer > 10*IN_MILISECONDS)
HandleSobering();
}
@@ -1643,6 +1645,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
else
// this will be used instead of the current location in SaveToDB
m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+
SetFallInformation(0, z);
//BuildHeartBeatMsg(&data);
@@ -2496,6 +2499,9 @@ void Player::InitStatsForLevel(bool reapplyMods)
void Player::SendInitialSpells()
{
+ time_t curTime = time(NULL);
+ time_t infTime = curTime + MONTH/2;
+
uint16 spellCount = 0;
WorldPacket data(SMSG_INITIAL_SPELLS, (1+2+4*m_spells.size()+2+m_spellCooldowns.size()*(2+2+2+4+4)));
@@ -2528,12 +2534,15 @@ void Player::SendInitialSpells()
if(!sEntry)
continue;
+ // not send infinity cooldown
+ if(itr->second.end > infTime)
+ continue;
+
data << uint16(itr->first);
time_t cooldown = 0;
- time_t curTime = time(NULL);
if(itr->second.end > curTime)
- cooldown = (itr->second.end-curTime)*1000;
+ cooldown = (itr->second.end-curTime)*IN_MILISECONDS;
data << uint16(itr->second.itemid); // cast item id
data << uint16(sEntry->Category); // spell category
@@ -3227,8 +3236,8 @@ void Player::RemoveArenaSpellCooldowns()
SpellEntry const * entry = sSpellStore.LookupEntry(itr->first);
// check if spellentry is present and if the cooldown is less than 15 mins
if( entry &&
- entry->RecoveryTime <= 15 * MINUTE * 1000 &&
- entry->CategoryRecoveryTime <= 15 * MINUTE * 1000 )
+ entry->RecoveryTime <= 15 * MINUTE * IN_MILISECONDS &&
+ entry->CategoryRecoveryTime <= 15 * MINUTE * IN_MILISECONDS )
{
// notify player
WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
@@ -3258,7 +3267,7 @@ void Player::RemoveAllSpellCooldown()
void Player::_LoadSpellCooldowns(QueryResult *result)
{
- m_spellCooldowns.clear();
+ // some cooldowns can be already set at aura loading...
//QueryResult *result = CharacterDatabase.PQuery("SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'",GetGUIDLow());
@@ -3299,17 +3308,20 @@ void Player::_SaveSpellCooldowns()
CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'", GetGUIDLow());
time_t curTime = time(NULL);
+ time_t infTime = curTime + MONTH/2;
// remove outdated and save active
for(SpellCooldowns::iterator itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end();)
{
if(itr->second.end <= curTime)
m_spellCooldowns.erase(itr++);
- else
+ else if(itr->second.end <= infTime) // not save locked cooldowns, it will be reset or set at reload
{
CharacterDatabase.PExecute("INSERT INTO character_spell_cooldown (guid,spell,item,time) VALUES ('%u', '%u', '%u', '" I64FMTD "')", GetGUIDLow(), itr->first, itr->second.itemid, uint64(itr->second.end));
++itr;
}
+ else
+ ++itr;
}
}
@@ -3432,6 +3444,13 @@ bool Player::resetTalents(bool no_cost)
//FIXME: remove pet before or after unlearn spells? for now after unlearn to allow removing of talent related, pet affecting auras
RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
+ if(m_canTitanGrip)
+ {
+ m_canTitanGrip = false;
+ if(sWorld.getConfig(CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET))
+ AutoUnequipOffhandIfNeed();
+ }
+
return true;
}
@@ -4003,7 +4022,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
{
if(Aura* Aur = GetAura(SPELL_ID_PASSIVE_RESURRECTION_SICKNESS,i))
{
- Aur->SetAuraDurationAndUpdate(delta*1000);
+ Aur->SetAuraDurationAndUpdate(delta*IN_MILISECONDS);
}
}
}
@@ -4023,7 +4042,7 @@ void Player::KillPlayer()
ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(GetMapId())->Instanceable());
// 6 minutes until repop at graveyard
- m_deathTimer = 6*MINUTE*1000;
+ m_deathTimer = 6*MINUTE*IN_MILISECONDS;
UpdateCorpseReclaimDelay(); // dependent at use SetDeathPvP() call before kill
SendCorpseReclaimDelay();
@@ -4348,10 +4367,8 @@ void Player::RepopAtGraveyard()
WorldSafeLocsEntry const *ClosestGrave = NULL;
// Special handle for battleground maps
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId(), m_bgTypeID);
-
- if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY || bg->GetTypeID() == BATTLEGROUND_AV))
- ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam());
+ if( BattleGround *bg = GetBattleGround() )
+ ClosestGrave = bg->GetClosestGraveYard(this);
else
ClosestGrave = objmgr.GetClosestGraveYard( GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam() );
@@ -6564,6 +6581,9 @@ void Player::UpdateZone(uint32 newZone)
if(isAlive())
DestroyZoneLimitedItem( true, newZone );
+ // check some item equip limitations (in result lost CanTitanGrip at talent reset, for example)
+ AutoUnequipOffhandIfNeed();
+
// recent client version not send leave/join channel packets for built-in local channels
UpdateLocalChannels( newZone );
@@ -6752,7 +6772,7 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl
if(slot >= INVENTORY_SLOT_BAG_END || !proto)
return;
- for (int i = 0; i < 10; i++)
+ for (int i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
{
uint32 statType = 0;
int32 val = 0;
@@ -7085,7 +7105,7 @@ void Player::ApplyItemEquipSpell(Item *item, bool apply, bool form_change)
if(!proto)
return;
- for (int i = 0; i < 5; i++)
+ for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = proto->Spells[i];
@@ -7198,7 +7218,7 @@ void Player::CastItemCombatSpell(Item *item,Unit* Target, WeaponAttackType attTy
if (!Target || Target == this )
return;
- for (int i = 0; i < 5; i++)
+ for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = proto->Spells[i];
@@ -7296,7 +7316,7 @@ void Player::CastItemUseSpell(Item *item,SpellCastTargets const& targets,uint8 c
int count = 0;
// item spells casted at use
- for(int i = 0; i < 5; ++i)
+ for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = proto->Spells[i];
@@ -12959,10 +12979,10 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
// shared timed quest
if(questGiver && questGiver->GetTypeId()==TYPEID_PLAYER)
- limittime = ((Player*)questGiver)->getQuestStatusMap()[quest_id].m_timer / 1000;
+ limittime = ((Player*)questGiver)->getQuestStatusMap()[quest_id].m_timer / IN_MILISECONDS;
AddTimedQuest( quest_id );
- questStatusData.m_timer = limittime * 1000;
+ questStatusData.m_timer = limittime * IN_MILISECONDS;
qtime = static_cast<uint32>(time(NULL)) + limittime;
}
else
@@ -14122,28 +14142,21 @@ bool Player::HasQuestForItem( uint32 itemid ) const
for (int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; j++)
{
// examined item is a source item
- if (qinfo->ReqSourceId[j] == itemid && qinfo->ReqSourceRef[j] > 0 && qinfo->ReqSourceRef[j] <= QUEST_OBJECTIVES_COUNT)
+ if (qinfo->ReqSourceId[j] == itemid)
{
- uint32 idx = qinfo->ReqSourceRef[j]-1;
+ ItemPrototype const *pProto = objmgr.GetItemPrototype(itemid);
- // total count of created ReqItems and SourceItems is less than ReqItemCount
- if(qinfo->ReqItemId[idx] != 0 &&
- q_status.m_itemcount[idx] * qinfo->ReqSourceCount[j] + GetItemCount(itemid,true) < qinfo->ReqItemCount[idx] * qinfo->ReqSourceCount[j])
+ // 'unique' item
+ if (pProto->MaxCount && GetItemCount(itemid,true) < pProto->MaxCount)
return true;
- // total count of casted ReqCreatureOrGOs and SourceItems is less than ReqCreatureOrGOCount
- if (qinfo->ReqCreatureOrGOId[idx] != 0)
+ // allows custom amount drop when not 0
+ if (qinfo->ReqSourceCount[j])
{
- if(q_status.m_creatureOrGOcount[idx] * qinfo->ReqSourceCount[j] + GetItemCount(itemid,true) < qinfo->ReqCreatureOrGOCount[idx] * qinfo->ReqSourceCount[j])
+ if (GetItemCount(itemid,true) < qinfo->ReqSourceCount[j])
return true;
- }
- // spell with SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT (with script) case
- else if(qinfo->ReqSpell[idx] != 0)
- {
- // not casted and need more reagents/item for use.
- if(!q_status.m_explored && GetItemCount(itemid,true) < qinfo->ReqSourceCount[j])
- return true;
- }
+ } else if (GetItemCount(itemid,true) < pProto->Stackable)
+ return true;
}
}
}
@@ -14684,6 +14697,14 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
{
if( (*iter)->GetGUIDLow() == transGUID)
{
+ MapEntry const* transMapEntry = sMapStore.LookupEntry((*iter)->GetMapId());
+ // client without expansion support
+ if(GetSession()->Expansion() < transMapEntry->Expansion())
+ {
+ sLog.outDebug("Player %s using client without required expansion tried login at transport at non accessible map %u", GetName(), (*iter)->GetMapId());
+ break;
+ }
+
m_transport = *iter;
m_transport->AddPassenger(this);
SetMapId(m_transport->GetMapId());
@@ -14693,7 +14714,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
if(!m_transport)
{
- sLog.outError("ERROR: Player (guidlow %d) have invalid transport guid (%u). Teleport to default race/class locations.",
+ sLog.outError("ERROR: Player (guidlow %d) have problems with transport guid (%u). Teleport to default race/class locations.",
guid,transGUID);
RelocateToHomebind();
@@ -14706,6 +14727,16 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
transGUID = 0;
}
}
+ else // not transport case
+ {
+ MapEntry const* mapEntry = sMapStore.LookupEntry(GetMapId());
+ // client without expansion support
+ if(GetSession()->Expansion() < mapEntry->Expansion())
+ {
+ sLog.outDebug("Player %s using client without required expansion tried login at non accessible map %u", GetName(), GetMapId());
+ RelocateToHomebind();
+ }
+ }
// NOW player must have valid map
// load the player's map here if it's not already loaded
@@ -15527,7 +15558,7 @@ void Player::_LoadQuestStatus(QueryResult *result)
if (quest_time <= sWorld.GetGameTime())
questStatusData.m_timer = 1;
else
- questStatusData.m_timer = (quest_time - sWorld.GetGameTime()) * 1000;
+ questStatusData.m_timer = (quest_time - sWorld.GetGameTime()) * IN_MILISECONDS;
}
else
quest_time = 0;
@@ -15974,9 +16005,11 @@ bool Player::_LoadHomeBind(QueryResult *result)
m_homebindZ = fields[4].GetFloat();
delete result;
- // accept saved data only for valid position (and non instanceable)
+ MapEntry const* bindMapEntry = sMapStore.LookupEntry(m_homebindMapId);
+
+ // accept saved data only for valid position (and non instanceable), and accessable
if( MapManager::IsValidMapCoord(m_homebindMapId,m_homebindX,m_homebindY,m_homebindZ) &&
- !sMapStore.LookupEntry(m_homebindMapId)->Instanceable() )
+ !bindMapEntry->Instanceable() && GetSession()->Expansion() >= bindMapEntry->Expansion())
{
ok = true;
}
@@ -16237,6 +16270,7 @@ void Player::_SaveAuras()
AuraMap::const_iterator itr2 = itr;
// save previous spellEffectPair to db
itr2--;
+
SpellEntry const *spellInfo = itr2->second->GetSpellProto();
//skip all auras from spells that are passive or need a shapeshift
@@ -16412,11 +16446,11 @@ void Player::_SaveQuestStatus()
case QUEST_NEW :
CharacterDatabase.PExecute("INSERT INTO character_queststatus (guid,quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4) "
"VALUES ('%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')",
- GetGUIDLow(), i->first, i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3]);
+ GetGUIDLow(), i->first, i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / IN_MILISECONDS+ sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3]);
break;
case QUEST_CHANGED :
CharacterDatabase.PExecute("UPDATE character_queststatus SET status = '%u',rewarded = '%u',explored = '%u',timer = '" I64FMTD "',mobcount1 = '%u',mobcount2 = '%u',mobcount3 = '%u',mobcount4 = '%u',itemcount1 = '%u',itemcount2 = '%u',itemcount3 = '%u',itemcount4 = '%u' WHERE guid = '%u' AND quest = '%u' ",
- i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3], GetGUIDLow(), i->first );
+ i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / IN_MILISECONDS + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3], GetGUIDLow(), i->first );
break;
case QUEST_UNCHANGED:
break;
@@ -17145,7 +17179,7 @@ void Player::PetSpellInitialize()
time_t cooldown = 0;
if(itr->second > curTime)
- cooldown = (itr->second - curTime) * 1000;
+ cooldown = (itr->second - curTime) * IN_MILISECONDS;
data << uint16(itr->first); // spellid
data << uint16(0); // spell category?
@@ -17158,7 +17192,7 @@ void Player::PetSpellInitialize()
time_t cooldown = 0;
if(itr->second > curTime)
- cooldown = (itr->second - curTime) * 1000;
+ cooldown = (itr->second - curTime) * IN_MILISECONDS;
data << uint16(itr->first); // spellid
data << uint16(0); // spell category?
@@ -17662,7 +17696,7 @@ void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs )
{
data << unSpellId;
data << unTimeMs; // in m.secs
- AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/1000);
+ AddSpellCooldown(unSpellId, 0, curTime + unTimeMs/IN_MILISECONDS);
}
}
GetSession()->SendPacket(&data);
@@ -18029,6 +18063,102 @@ void Player::UpdatePvP(bool state, bool ovrride)
}
}
+void Player::AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell, bool infinityCooldown)
+{
+ // init cooldown values
+ uint32 cat = 0;
+ int32 rec = -1;
+ int32 catrec = -1;
+
+ // some special item spells without correct cooldown in SpellInfo
+ // cooldown information stored in item prototype
+ // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
+
+ if(itemId)
+ {
+ if(ItemPrototype const* proto = ObjectMgr::GetItemPrototype(itemId))
+ {
+ for(int idx = 0; idx < 5; ++idx)
+ {
+ if(proto->Spells[idx].SpellId == spellInfo->Id)
+ {
+ cat = proto->Spells[idx].SpellCategory;
+ rec = proto->Spells[idx].SpellCooldown;
+ catrec = proto->Spells[idx].SpellCategoryCooldown;
+ break;
+ }
+ }
+ }
+ }
+
+ // if no cooldown found above then base at DBC data
+ if(rec < 0 && catrec < 0)
+ {
+ cat = spellInfo->Category;
+ rec = spellInfo->RecoveryTime;
+ catrec = spellInfo->CategoryRecoveryTime;
+ }
+
+ time_t curTime = time(NULL);
+
+ time_t catrecTime;
+ time_t recTime;
+
+ // overwrite time for selected category
+ if(infinityCooldown)
+ {
+ // use +MONTH as infinity mark for spell cooldown (will checked as MONTH/2 at save ans skipped)
+ // but not allow ignore until reset or re-login
+ catrecTime = catrec > 0 ? curTime+MONTH : 0;
+ recTime = rec > 0 ? curTime+MONTH : catrecTime;
+ }
+ else
+ {
+ // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
+ // prevent 0 cooldowns set by another way
+ if (rec <= 0 && catrec <= 0 && (cat == 76 || IsAutoRepeatRangedSpell(spellInfo) && spellInfo->Id != SPELL_ID_AUTOSHOT))
+ rec = GetAttackTime(RANGED_ATTACK);
+
+ // Now we have cooldown data (if found any), time to apply mods
+ if(rec > 0)
+ ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell);
+
+ if(catrec > 0)
+ ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell);
+
+ // replace negative cooldowns by 0
+ if (rec < 0) rec = 0;
+ if (catrec < 0) catrec = 0;
+
+ // no cooldown after applying spell mods
+ if( rec == 0 && catrec == 0)
+ return;
+
+ catrecTime = catrec ? curTime+catrec/IN_MILISECONDS : 0;
+ recTime = rec ? curTime+rec/IN_MILISECONDS : catrecTime;
+ }
+
+ // self spell cooldown
+ if(recTime > 0)
+ AddSpellCooldown(spellInfo->Id, itemId, recTime);
+
+ // category spells
+ if (cat && catrec > 0)
+ {
+ SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
+ if(i_scstore != sSpellCategoryStore.end())
+ {
+ for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
+ {
+ if(*i_scset == spellInfo->Id) // skip main spell, already handled above
+ continue;
+
+ AddSpellCooldown(*i_scset, itemId, catrecTime);
+ }
+ }
+ }
+}
+
void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time)
{
SpellCooldown sc;
@@ -18037,25 +18167,41 @@ void Player::AddSpellCooldown(uint32 spellid, uint32 itemid, time_t end_time)
m_spellCooldowns[spellid] = sc;
}
-void Player::SendCooldownEvent(SpellEntry const *spellInfo)
+void Player::SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId, Spell* spell)
{
- if ( !(spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE) )
- return;
+ // start cooldowns at server side, if any
+ AddSpellAndCategoryCooldowns(spellInfo,itemId,spell);
- // Get spell cooldown
- int32 cooldown = GetSpellRecoveryTime(spellInfo);
- // Apply spellmods
- ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, cooldown);
- if (cooldown < 0)
- cooldown = 0;
- // Add cooldown
- AddSpellCooldown(spellInfo->Id, 0, time(NULL) + cooldown / 1000);
- // Send activate
+ // Send activate cooldown timer (possible 0) at client side
WorldPacket data(SMSG_COOLDOWN_EVENT, (4+8));
data << spellInfo->Id;
data << GetGUID();
SendDirectMessage(&data);
}
+
+void Player::UpdatePotionCooldown(Spell* spell)
+{
+ // no potion used i combat or still in combat
+ if(!m_lastPotionId || isInCombat())
+ return;
+
+ // Call not from spell cast, send cooldown event for item spells if no in combat
+ if(!spell)
+ {
+ // spell/item pair let set proper cooldown (except not existed charged spell cooldown spellmods for potions)
+ if(ItemPrototype const* proto = ObjectMgr::GetItemPrototype(m_lastPotionId))
+ for(int idx = 0; idx < 5; ++idx)
+ if(proto->Spells[idx].SpellId && proto->Spells[idx].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
+ if(SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[idx].SpellId))
+ SendCooldownEvent(spellInfo,m_lastPotionId);
+ }
+ // from spell cases (m_lastPotionId set in Spell::SendSpellCooldown)
+ else
+ SendCooldownEvent(spell->m_spellInfo,m_lastPotionId,spell);
+
+ m_lastPotionId = 0;
+}
+
//slot to be excluded while counting
bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot)
{
@@ -18797,7 +18943,7 @@ void Player::SendInstanceResetWarning(uint32 mapid, uint32 time)
void Player::ApplyEquipCooldown( Item * pItem )
{
- for(int i = 0; i <5; ++i)
+ for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
_Spell const& spellData = pItem->GetProto()->Spells[i];
@@ -19242,8 +19388,8 @@ void Player::AutoUnequipOffhandIfNeed()
if(!offItem)
return;
- // need unequip for 2h-weapon without TitanGrip
- if (!IsTwoHandUsed())
+ // need unequip offhand for 2h-weapon without TitanGrip (in any from hands)
+ if (CanTitanGrip() || (offItem->GetProto()->InventoryType != INVTYPE_2HWEAPON && !IsTwoHandUsed()))
return;
ItemPosCountVec off_dest;
@@ -19255,7 +19401,16 @@ void Player::AutoUnequipOffhandIfNeed()
}
else
{
- sLog.outError("Player::EquipItem: Can's store offhand item at 2hand item equip for player (GUID: %u).",GetGUIDLow());
+ MailItemsInfo mi;
+ mi.AddItem(offItem->GetGUIDLow(), offItem->GetEntry(), offItem);
+ MoveItemFromInventory(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND, true);
+ CharacterDatabase.BeginTransaction();
+ offItem->DeleteFromInventoryDB(); // deletes item from character's inventory
+ offItem->SaveToDB(); // recursive and not have transaction guard into self, item not in inventory and can be save standalone
+ CharacterDatabase.CommitTransaction();
+
+ std::string subject = GetSession()->GetMangosString(LANG_NOT_EQUIPPED_ITEM);
+ WorldSession::SendMailTo(this, MAIL_NORMAL, MAIL_STATIONERY_GM, GetGUIDLow(), GetGUIDLow(), subject, 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
}
}
@@ -19702,7 +19857,7 @@ void Player::SendCorpseReclaimDelay(bool load)
//! corpse reclaim delay 30 * 1000ms or longer at often deaths
WorldPacket data(SMSG_CORPSE_RECLAIM_DELAY, 4);
- data << uint32(delay*1000);
+ data << uint32(delay*IN_MILISECONDS);
GetSession()->SendPacket( &data );
}
@@ -19796,52 +19951,6 @@ bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const
//-------------TRINITY---------------
//***********************************
-void Player::HandleFallDamage(MovementInfo& movementInfo)
-{
- //if(movementInfo.fallTime < 1500)
- // return;
-
- // calculate total z distance of the fall
- float z_diff = m_lastFallZ - movementInfo.z;
- sLog.outDebug("zDiff = %f", z_diff);
-
- //Players with low fall distance, Feather Fall or physical immunity (charges used) are ignored
- // 14.57 can be calculated by resolving damageperc formular below to 0
- if (z_diff >= 14.57f && !isDead() && !isGameMaster() &&
- !HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) &&
- !HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL) )
- {
- //Safe fall, fall height reduction
- int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
-
- float damageperc = 0.018f*(z_diff-safe_fall)-0.2426f;
-
- if(damageperc >0 )
- {
- uint32 damage = (uint32)(damageperc * GetMaxHealth()*sWorld.getRate(RATE_DAMAGE_FALL));
-
- float height = movementInfo.z;
- UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
-
- if (damage > 0)
- {
- //Prevent fall damage from being more than the player maximum health
- if (damage > GetMaxHealth())
- damage = GetMaxHealth();
-
- // Gust of Wind
- if (GetDummyAura(43621))
- damage = GetMaxHealth()/2;
-
- EnvironmentalDamage(GetGUID(), DAMAGE_FALL, damage);
- }
-
- //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
- DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
- }
- }
-}
-
void Player::HandleFallUnderMap()
{
if(InBattleGround()
@@ -20400,3 +20509,50 @@ uint8 Player::CanEquipUniqueItem( ItemPrototype const* itemProto, uint8 except_s
return EQUIP_ERR_OK;
}
+
+void Player::HandleFall(MovementInfo const& movementInfo)
+{
+ // calculate total z distance of the fall
+ float z_diff = m_lastFallZ - movementInfo.z;
+ sLog.outDebug("zDiff = %f", z_diff);
+
+ //Players with low fall distance, Feather Fall or physical immunity (charges used) are ignored
+ // 14.57 can be calculated by resolving damageperc formular below to 0
+ if (z_diff >= 14.57f && !isDead() && !isGameMaster() &&
+ !HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) &&
+ !HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL) )
+ {
+ //Safe fall, fall height reduction
+ int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
+
+ float damageperc = 0.018f*(z_diff-safe_fall)-0.2426f;
+
+ if(damageperc >0 )
+ {
+ uint32 damage = (uint32)(damageperc * GetMaxHealth()*sWorld.getRate(RATE_DAMAGE_FALL));
+
+ float height = movementInfo.z;
+ UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
+
+ if (damage > 0)
+ {
+ //Prevent fall damage from being more than the player maximum health
+ if (damage > GetMaxHealth())
+ damage = GetMaxHealth();
+
+ // Gust of Wind
+ if (GetDummyAura(43621))
+ damage = GetMaxHealth()/2;
+
+ EnvironmentalDamage(GetGUID(), DAMAGE_FALL, damage);
+
+ // recheck alive, might have died of EnvironmentalDamage
+ if (isAlive())
+ GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING, uint32(z_diff*100));
+ }
+
+ //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
+ DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
+ }
+ }
+}
diff --git a/src/game/Player.h b/src/game/Player.h
index 12a2b5dff62..f128dd4d422 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -1491,14 +1491,17 @@ class TRINITY_DLL_SPEC Player : public Unit
time_t t = time(NULL);
return itr != m_spellCooldowns.end() && itr->second.end > t ? itr->second.end - t : 0;
}
+ void AddSpellAndCategoryCooldowns(SpellEntry const* spellInfo, uint32 itemId, Spell* spell = NULL, bool infinityCooldown = false );
void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);
- void SendCooldownEvent(SpellEntry const *spellInfo);
+ void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL);
void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs );
void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); }
void RemoveArenaSpellCooldowns();
void RemoveAllSpellCooldown();
void _LoadSpellCooldowns(QueryResult *result);
void _SaveSpellCooldowns();
+ void SetLastPotionId(uint32 item_id) { m_lastPotionId = item_id; }
+ void UpdatePotionCooldown(Spell* spell = NULL);
void setResurrectRequestData(uint64 guid, uint32 mapId, float X, float Y, float Z, uint32 health, uint32 mana)
{
@@ -1982,7 +1985,7 @@ class TRINITY_DLL_SPEC Player : public Unit
/*** REST SYSTEM ***/
/*********************************************************/
- bool isRested() const { return GetRestTime() >= 10000; }
+ bool isRested() const { return GetRestTime() >= 10*IN_MILISECONDS; }
uint32 GetXPRestBonus(uint32 xp);
uint32 GetRestTime() const { return m_restTime;};
void SetRestTime(uint32 v) { m_restTime = v;};
@@ -2013,6 +2016,8 @@ class TRINITY_DLL_SPEC Player : public Unit
m_lastFallTime = time;
m_lastFallZ = z;
}
+ void HandleFall(MovementInfo const& movementInfo);
+
bool isMoving() const { return HasUnitMovementFlag(movementFlagsMask); }
bool isMovingOrTurning() const { return HasUnitMovementFlag(movementOrTurningFlagsMask); }
@@ -2021,7 +2026,6 @@ class TRINITY_DLL_SPEC Player : public Unit
bool IsAllowUseFlyMountsHere() const;
void HandleDrowning();
- void HandleFallDamage(MovementInfo& movementInfo);
void HandleFallUnderMap();
void SetClientControl(Unit* target, uint8 allowMove);
@@ -2292,6 +2296,7 @@ class TRINITY_DLL_SPEC Player : public Unit
PlayerMails m_mail;
PlayerSpellMap m_spells;
SpellCooldowns m_spellCooldowns;
+ uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
ActionButtonList m_actionButtons;
@@ -2446,7 +2451,7 @@ template <class T> T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T &bas
continue;
// special case (skip >10sec spell casts for instant cast setting)
- if( mod->op==SPELLMOD_CASTING_TIME && basevalue >= T(10000) && mod->value <= -100)
+ if( mod->op==SPELLMOD_CASTING_TIME && basevalue >= T(10*IN_MILISECONDS) && mod->value <= -100)
continue;
totalpct += mod->value;
diff --git a/src/game/QuestDef.cpp b/src/game/QuestDef.cpp
index bbc344732b8..799896c8280 100644
--- a/src/game/QuestDef.cpp
+++ b/src/game/QuestDef.cpp
@@ -75,59 +75,56 @@ Quest::Quest(Field * questRecord)
for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
ReqSourceCount[i] = questRecord[51+i].GetUInt32();
- for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
- ReqSourceRef[i] = questRecord[55+i].GetUInt32();
-
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ReqCreatureOrGOId[i] = questRecord[59+i].GetInt32();
+ ReqCreatureOrGOId[i] = questRecord[55+i].GetInt32();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ReqCreatureOrGOCount[i] = questRecord[63+i].GetUInt32();
+ ReqCreatureOrGOCount[i] = questRecord[59+i].GetUInt32();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ReqSpell[i] = questRecord[67+i].GetUInt32();
+ ReqSpell[i] = questRecord[63+i].GetUInt32();
for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- RewChoiceItemId[i] = questRecord[71+i].GetUInt32();
+ RewChoiceItemId[i] = questRecord[67+i].GetUInt32();
for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- RewChoiceItemCount[i] = questRecord[77+i].GetUInt32();
+ RewChoiceItemCount[i] = questRecord[73+i].GetUInt32();
for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
- RewItemId[i] = questRecord[83+i].GetUInt32();
+ RewItemId[i] = questRecord[79+i].GetUInt32();
for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
- RewItemCount[i] = questRecord[87+i].GetUInt32();
+ RewItemCount[i] = questRecord[83+i].GetUInt32();
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
- RewRepFaction[i] = questRecord[91+i].GetUInt32();
+ RewRepFaction[i] = questRecord[87+i].GetUInt32();
for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
- RewRepValue[i] = questRecord[96+i].GetInt32();
-
- RewHonorableKills = questRecord[101].GetUInt32();
- RewOrReqMoney = questRecord[102].GetInt32();
- RewMoneyMaxLevel = questRecord[103].GetUInt32();
- RewSpell = questRecord[104].GetUInt32();
- RewSpellCast = questRecord[105].GetUInt32();
- RewMailTemplateId = questRecord[106].GetUInt32();
- RewMailDelaySecs = questRecord[107].GetUInt32();
- PointMapId = questRecord[108].GetUInt32();
- PointX = questRecord[109].GetFloat();
- PointY = questRecord[110].GetFloat();
- PointOpt = questRecord[111].GetUInt32();
+ RewRepValue[i] = questRecord[92+i].GetInt32();
+
+ RewHonorableKills = questRecord[97].GetUInt32();
+ RewOrReqMoney = questRecord[98].GetInt32();
+ RewMoneyMaxLevel = questRecord[99].GetUInt32();
+ RewSpell = questRecord[100].GetUInt32();
+ RewSpellCast = questRecord[101].GetUInt32();
+ RewMailTemplateId = questRecord[102].GetUInt32();
+ RewMailDelaySecs = questRecord[103].GetUInt32();
+ PointMapId = questRecord[104].GetUInt32();
+ PointX = questRecord[105].GetFloat();
+ PointY = questRecord[106].GetFloat();
+ PointOpt = questRecord[107].GetUInt32();
for (int i = 0; i < QUEST_EMOTE_COUNT; ++i)
- DetailsEmote[i] = questRecord[112+i].GetUInt32();
+ DetailsEmote[i] = questRecord[108+i].GetUInt32();
- IncompleteEmote = questRecord[116].GetUInt32();
- CompleteEmote = questRecord[117].GetUInt32();
+ IncompleteEmote = questRecord[112].GetUInt32();
+ CompleteEmote = questRecord[113].GetUInt32();
for (int i = 0; i < QUEST_EMOTE_COUNT; ++i)
- OfferRewardEmote[i] = questRecord[118+i].GetInt32();
+ OfferRewardEmote[i] = questRecord[114+i].GetInt32();
- QuestStartScript = questRecord[122].GetUInt32();
- QuestCompleteScript = questRecord[123].GetUInt32();
+ QuestStartScript = questRecord[118].GetUInt32();
+ QuestCompleteScript = questRecord[119].GetUInt32();
QuestFlags |= SpecialFlags << 16;
diff --git a/src/game/QuestDef.h b/src/game/QuestDef.h
index 4d4c9829ba8..3afeaa0aa54 100644
--- a/src/game/QuestDef.h
+++ b/src/game/QuestDef.h
@@ -231,7 +231,6 @@ class Quest
uint32 ReqItemCount[QUEST_OBJECTIVES_COUNT];
uint32 ReqSourceId[QUEST_SOURCE_ITEM_IDS_COUNT];
uint32 ReqSourceCount[QUEST_SOURCE_ITEM_IDS_COUNT];
- uint32 ReqSourceRef[QUEST_SOURCE_ITEM_IDS_COUNT];
int32 ReqCreatureOrGOId[QUEST_OBJECTIVES_COUNT]; // >0 Creature <0 Gameobject
uint32 ReqCreatureOrGOCount[QUEST_OBJECTIVES_COUNT];
uint32 ReqSpell[QUEST_OBJECTIVES_COUNT];
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index b753b957fda..66f2eded6ac 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -49,7 +49,7 @@
#include "Util.h"
#include "TemporarySummon.h"
-#define SPELL_CHANNEL_UPDATE_INTERVAL 1000
+#define SPELL_CHANNEL_UPDATE_INTERVAL (1*IN_MILISECONDS)
extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
@@ -337,7 +337,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
if((m_caster->getClassMask() & CLASSMASK_WAND_USERS) != 0 && m_caster->GetTypeId()==TYPEID_PLAYER)
{
if(Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK))
- m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType);
+ m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage[0].DamageType);
}
}
// Set health leech amount to zero
@@ -2432,93 +2432,21 @@ void Spell::SendSpellCooldown()
return;
Player* _player = (Player*)m_caster;
- // Add cooldown for max (disable spell)
- // Cooldown started on SendCooldownEvent call
- if (m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
- {
- _player->AddSpellCooldown(m_spellInfo->Id, 0, time(NULL) - 1);
- return;
- }
-
- // init cooldown values
- uint32 cat = 0;
- int32 rec = -1;
- int32 catrec = -1;
-
- // some special item spells without correct cooldown in SpellInfo
- // cooldown information stored in item prototype
- // This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
- if(m_CastItem)
+ // mana/health potions, disabled by client
+ if (m_spellInfo->Category==SPELLCATEGORY_HEALTH_MANA_POTIONS)
{
- ItemPrototype const* proto = m_CastItem->GetProto();
- if(proto)
- {
- for(int idx = 0; idx < 5; ++idx)
- {
- if(proto->Spells[idx].SpellId == m_spellInfo->Id)
- {
- cat = proto->Spells[idx].SpellCategory;
- rec = proto->Spells[idx].SpellCooldown;
- catrec = proto->Spells[idx].SpellCategoryCooldown;
- break;
- }
- }
- }
- }
-
- // if no cooldown found above then base at DBC data
- if(rec < 0 && catrec < 0)
- {
- cat = m_spellInfo->Category;
- rec = m_spellInfo->RecoveryTime;
- catrec = m_spellInfo->CategoryRecoveryTime;
+ // need in some way provided data for Spell::finish SendCooldownEvent
+ if(m_CastItem)
+ _player->SetLastPotionId(m_CastItem->GetEntry());
+ return;
}
- // shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
- // prevent 0 cooldowns set by another way
- if (rec <= 0 && catrec <= 0 && (cat == 76 || IsAutoRepeatRangedSpell(m_spellInfo) && m_spellInfo->Id != SPELL_ID_AUTOSHOT))
- rec = _player->GetAttackTime(RANGED_ATTACK);
-
- // Now we have cooldown data (if found any), time to apply mods
- if(rec > 0)
- _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, rec, this);
-
- if(catrec > 0)
- _player->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COOLDOWN, catrec, this);
-
- // replace negative cooldowns by 0
- if (rec < 0) rec = 0;
- if (catrec < 0) catrec = 0;
-
- // no cooldown after applying spell mods
- if( rec == 0 && catrec == 0)
+ // have infinity cooldown but set at aura apply
+ if(m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
return;
- time_t curTime = time(NULL);
-
- time_t catrecTime = catrec ? curTime+catrec/1000 : 0; // in secs
- time_t recTime = rec ? curTime+rec/1000 : catrecTime;// in secs
-
- // self spell cooldown
- if(recTime > 0)
- _player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, recTime);
-
- // category spells
- if (catrec > 0)
- {
- SpellCategoryStore::const_iterator i_scstore = sSpellCategoryStore.find(cat);
- if(i_scstore != sSpellCategoryStore.end())
- {
- for(SpellCategorySet::const_iterator i_scset = i_scstore->second.begin(); i_scset != i_scstore->second.end(); ++i_scset)
- {
- if(*i_scset == m_spellInfo->Id) // skip main spell, already handled above
- continue;
-
- _player->AddSpellCooldown(*i_scset, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime);
- }
- }
- }
+ _player->AddSpellAndCategoryCooldowns(m_spellInfo,m_CastItem ? m_CastItem->GetEntry() : 0, this);
}
void Spell::update(uint32 difftime)
@@ -2672,6 +2600,10 @@ void Spell::finish(bool ok)
m_caster->resetAttackTimer(RANGED_ATTACK);
}
+ // mana/health potions, disabled by client, send event "not in combat"
+ if (m_caster->GetTypeId() == TYPEID_PLAYER && m_spellInfo->Category == SPELLCATEGORY_HEALTH_MANA_POTIONS)
+ ((Player*)m_caster)->UpdatePotionCooldown(this);
+
// call triggered spell only at successful cast (after clear combo points -> for add some if need)
// I assume what he means is that some triggered spells may add combo points
if(!m_TriggerSpells.empty())
@@ -3201,7 +3133,7 @@ void Spell::TakeCastItem()
bool expendable = false;
bool withoutCharges = false;
- for (int i = 0; i<5; i++)
+ for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (proto->Spells[i].SpellId)
{
@@ -3464,7 +3396,7 @@ void Spell::TakeReagents()
ItemPrototype const *proto = m_CastItem->GetProto();
if( proto && proto->ItemId == itemid )
{
- for(int s=0;s<5;s++)
+ for(int s=0;s < MAX_ITEM_PROTO_SPELLS; ++s)
{
// CastItem will be used up and does not count as reagent
int32 charges = m_CastItem->GetSpellCharges(s);
@@ -3774,7 +3706,7 @@ uint8 Spell::CanCast(bool strict)
// - with greater than 15 min CD without SPELL_ATTR_EX4_USABLE_IN_ARENA flag
// - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag
if( (m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) ||
- GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * 1000 && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) )
+ GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * IN_MILISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) )
if(MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId()))
if(mapEntry->IsBattleArena())
return SPELL_FAILED_NOT_IN_ARENA;
@@ -4963,7 +4895,7 @@ uint8 Spell::CheckItems()
ItemPrototype const *proto = m_CastItem->GetProto();
if(!proto)
return SPELL_FAILED_ITEM_NOT_READY;
- for(int s=0;s<5;s++)
+ for(int s=0;s < MAX_ITEM_PROTO_SPELLS; ++s)
{
// CastItem will be used up and does not count as reagent
int32 charges = m_CastItem->GetSpellCharges(s);
diff --git a/src/game/Spell.h b/src/game/Spell.h
index daeab913345..22fbd7bb25f 100644
--- a/src/game/Spell.h
+++ b/src/game/Spell.h
@@ -234,7 +234,7 @@ enum SpellTargets
SPELL_TARGETS_CHAINHEAL,
};
-#define SPELL_SPELL_CHANNEL_UPDATE_INTERVAL 1000
+#define SPELL_SPELL_CHANNEL_UPDATE_INTERVAL (1*IN_MILISECONDS)
typedef std::multimap<uint64, uint64> SpellTargetTimeMap;
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 3dcf984086e..94ecf0b198d 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -786,6 +786,16 @@ void Aura::_AddAura()
Unit* caster = GetCaster();
+ // set infinity cooldown state for spells
+ if(caster && caster->GetTypeId() == TYPEID_PLAYER)
+ {
+ if (m_spellProto->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
+ {
+ Item* castItem = m_castItemGuid ? ((Player*)caster)->GetItemByGuid(m_castItemGuid) : NULL;
+ ((Player*)caster)->AddSpellAndCategoryCooldowns(m_spellProto,castItem ? castItem->GetEntry() : 0, NULL,true);
+ }
+ }
+
// passive auras (except totem auras) do not get placed in the slots
// area auras with SPELL_AURA_NONE are not shown on target
// all further code applies only to active spells
@@ -976,6 +986,7 @@ void Aura::_RemoveAura()
if(caster && caster->GetTypeId() == TYPEID_PLAYER)
{
if ( GetSpellProto()->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE )
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
((Player*)caster)->SendCooldownEvent(GetSpellProto());
}
}
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 4792848f48f..6d50338c9d6 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -347,14 +347,6 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
}
break;
}
- case 43648: //Electrical Storm
- {
- if(unitTarget && unitTarget->HasAura(44007, 0)) // Immune Aura
- {
- damage = 0;
- }
- break;
- }
// percent from health with min
case 25599: // Thundercrash
{
@@ -662,7 +654,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
// Add main hand dps * effect[2] amount
float averange = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
- damage += count * int32(averange * 1000) / m_caster->GetAttackTime(BASE_ATTACK);
+ damage += count * int32(averange * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
}
break;
}
@@ -1230,7 +1222,7 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(m_caster, 30452, true, NULL);
return;
- }
+ }
case 53341:
case 53343:
{
@@ -2525,13 +2517,6 @@ void Spell::SpellDamageHeal(uint32 /*i*/)
sLog.outError("Target(GUID:" I64FMTD ") has aurastate AURA_STATE_SWIFTMEND but no matching aura.", unitTarget->GetGUID());
return;
}
- int idx = 0;
- while(idx < 3)
- {
- if(targetAura->GetSpellProto()->EffectApplyAuraName[idx] == SPELL_AURA_PERIODIC_HEAL)
- break;
- idx++;
- }
int32 tickheal = targetAura->GetModifier()->m_amount;
if(Unit* auraCaster = targetAura->GetCaster())
@@ -2539,7 +2524,15 @@ void Spell::SpellDamageHeal(uint32 /*i*/)
//int32 tickheal = targetAura->GetSpellProto()->EffectBasePoints[idx] + 1;
//It is said that talent bonus should not be included
- int32 tickcount = GetSpellDuration(targetAura->GetSpellProto()) / targetAura->GetSpellProto()->EffectAmplitude[idx];
+ int32 tickcount = 0;
+ if(targetAura->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID)
+ {
+ switch(targetAura->GetSpellProto()->SpellFamilyFlags)//TODO: proper spellfamily for 3.0.x
+ {
+ case 0x10: tickcount = 4; break; // Rejuvenation
+ case 0x40: tickcount = 6; break; // Regrowth
+ }
+ }
addhealth += tickheal * tickcount;
unitTarget->RemoveAurasByCasterSpell(targetAura->GetId(), targetAura->GetCasterGUID());
@@ -2971,6 +2964,10 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
if(uint32 trapEntry = gameObjTarget->GetGOInfo()->goober.linkedTrapId)
gameObjTarget->TriggeringLinkedGameObject(trapEntry,m_caster);
+ // activate GO scripts
+ Script->GOHello(player, gameObjTarget);
+ sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
+
return;
case GAMEOBJECT_TYPE_CHEST:
@@ -3474,7 +3471,7 @@ void Spell::EffectDispel(uint32 i)
// On succes dispel
// Devour Magic
- if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == 12)
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && m_spellInfo->Category == SPELLCATEGORY_DEVOUR_MAGIC)
{
uint32 heal_spell = 0;
switch (m_spellInfo->Id)
@@ -3547,7 +3544,7 @@ void Spell::EffectDistract(uint32 /*i*/)
// Set creature Distracted, Stop it, And turn it
unitTarget->SetOrientation(angle);
unitTarget->StopMoving();
- unitTarget->GetMotionMaster()->MoveDistract(damage*1000);
+ unitTarget->GetMotionMaster()->MoveDistract(damage*IN_MILISECONDS);
}
}
@@ -4576,7 +4573,7 @@ void Spell::EffectSummonObjectWild(uint32 i)
}
int32 duration = GetSpellDuration(m_spellInfo);
- pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
if(pGameObj->GetGoType() != GAMEOBJECT_TYPE_FLAGDROP) // make dropped flag clickable for other players (not set owner guid (created by) for this)...
@@ -4619,7 +4616,7 @@ void Spell::EffectSummonObjectWild(uint32 i)
if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map,
m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0, 0, 0, 0, 100, 1))
{
- linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
linkedGO->SetSpellId(m_spellInfo->Id);
m_caster->AddGameObject(linkedGO);
@@ -5338,7 +5335,7 @@ void Spell::EffectDuel(uint32 i)
pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction() );
pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1 );
int32 duration = GetSpellDuration(m_spellInfo);
- pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
m_caster->AddGameObject(pGameObj);
@@ -5415,7 +5412,7 @@ void Spell::EffectSummonPlayer(uint32 /*i*/)
WorldPacket data(SMSG_SUMMON_REQUEST, 8+4+4);
data << uint64(m_caster->GetGUID()); // summoner guid
data << uint32(m_caster->GetZoneId()); // summoner zone
- data << uint32(MAX_PLAYER_SUMMON_DELAY*1000); // auto decline after msecs
+ data << uint32(MAX_PLAYER_SUMMON_DELAY*IN_MILISECONDS); // auto decline after msecs
((Player*)unitTarget)->GetSession()->SendPacket(&data);
}
@@ -5598,7 +5595,7 @@ void Spell::EffectEnchantHeldItem(uint32 i)
return;
// Apply the temporary enchantment
- item->SetEnchantment(slot, enchant_id, duration*1000, 0);
+ item->SetEnchantment(slot, enchant_id, duration*IN_MILISECONDS, 0);
item_owner->ApplyEnchantment(item,slot,true);
}
}
@@ -5729,7 +5726,7 @@ void Spell::EffectSummonObject(uint32 i)
//pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL,m_caster->getLevel());
int32 duration = GetSpellDuration(m_spellInfo);
- pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetSpellId(m_spellInfo->Id);
m_caster->AddGameObject(pGameObj);
@@ -6413,7 +6410,7 @@ void Spell::EffectTransmitted(uint32 effIndex)
case 3: lastSec = 17; break;
}
- duration = duration - lastSec*1000 + FISHING_BOBBER_READY_TIME*1000;
+ duration = duration - lastSec*IN_MILISECONDS + FISHING_BOBBER_READY_TIME*IN_MILISECONDS;
break;
}
case GAMEOBJECT_TYPE_SUMMONING_RITUAL:
@@ -6433,7 +6430,7 @@ void Spell::EffectTransmitted(uint32 effIndex)
}
}
- pGameObj->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ pGameObj->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
pGameObj->SetOwnerGUID(m_caster->GetGUID() );
@@ -6456,7 +6453,7 @@ void Spell::EffectTransmitted(uint32 effIndex)
if(linkedGO->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap,
m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0, 0, 0, 0, 100, 1))
{
- linkedGO->SetRespawnTime(duration > 0 ? duration/1000 : 0);
+ linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILISECONDS : 0);
//linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel() );
linkedGO->SetSpellId(m_spellInfo->Id);
linkedGO->SetOwnerGUID(m_caster->GetGUID() );
diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp
index 3c739a85bb0..449025f0346 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -97,7 +97,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
if (pUser->isInCombat())
{
- for(int i = 0; i < 5; ++i)
+ for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(proto->Spells[i].SpellId))
{
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index dd4edcb7087..e294742e5c1 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -2691,6 +2691,7 @@ void SpellMgr::LoadSpellAreas()
spellArea.auraSpell = fields[5].GetUInt32();
spellArea.raceMask = fields[6].GetUInt32();
spellArea.gender = Gender(fields[7].GetUInt8());
+ spellArea.autocast = fields[8].GetBool();
if(!sSpellStore.LookupEntry(spell))
{
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index e041f67c358..4eeeb628709 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -225,6 +225,13 @@ enum SpellFailedReason
SPELL_FAILED_UNKNOWN = 181
};
+// only used in code
+enum SpellCategories
+{
+ SPELLCATEGORY_HEALTH_MANA_POTIONS = 4,
+ SPELLCATEGORY_DEVOUR_MAGIC = 12
+};
+
enum SpellFamilyNames
{
SPELLFAMILY_GENERIC = 0,
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index 8875c3301a7..049991d229e 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -4009,7 +4009,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit
// set its duration and maximum duration
// max duration 2 minutes (in msecs)
int32 dur = aur->GetAuraDuration();
- const int32 max_dur = 2*MINUTE*1000;
+ const int32 max_dur = 2*MINUTE*IN_MILISECONDS;
new_aur->SetAuraMaxDuration( max_dur > dur ? dur : max_dur );
new_aur->SetAuraDuration( max_dur > dur ? dur : max_dur );
@@ -4445,6 +4445,15 @@ void Unit::AddGameObject(GameObject* gameObj)
assert(gameObj && gameObj->GetOwnerGUID()==0);
m_gameObj.push_back(gameObj);
gameObj->SetOwnerGUID(GetGUID());
+
+ if ( GetTypeId()==TYPEID_PLAYER && gameObj->GetSpellId() )
+ {
+ SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId());
+ // Need disable spell use for owner
+ if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
+ ((Player*)this)->AddSpellAndCategoryCooldowns(createBySpell,0,NULL,true);
+ }
}
void Unit::RemoveGameObject(GameObject* gameObj, bool del)
@@ -4457,6 +4466,7 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del)
SpellEntry const* createBySpell = sSpellStore.LookupEntry(gameObj->GetSpellId());
// Need activate spell use for owner
if (createBySpell && createBySpell->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE)
+ // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existed cases)
((Player*)this)->SendCooldownEvent(createBySpell);
}
gameObj->SetOwnerGUID(0);
@@ -6332,7 +6342,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
}
case SPELLFAMILY_POTION:
{
- sLog.outError("It Procs!");
if (dummySpell->Id == 17619)
{
if (procSpell->Category==4) //potion category
@@ -9471,6 +9480,8 @@ void Unit::ClearInCombat()
// Player's state will be cleared in Player::UpdateContestedPvP
if(GetTypeId()!=TYPEID_PLAYER)
clearUnitState(UNIT_STAT_ATTACK_PLAYER);
+ else
+ ((Player*)this)->UpdatePotionCooldown();
if(GetTypeId() != TYPEID_PLAYER && ((Creature*)this)->isPet())
{
@@ -12330,6 +12341,7 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
// FORM_SPIRITOFREDEMPTION and related auras
pVictim->CastSpell(pVictim,27827,true,NULL,*itr);
+ pVictim->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // should not be attackable
SpiritOfRedemption = true;
break;
}
@@ -12340,6 +12352,7 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
{
DEBUG_LOG("SET JUST_DIED");
pVictim->setDeathState(JUST_DIED);
+ pVictim->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // reactive attackable flag
}
// 10% durability loss on death
diff --git a/src/game/Weather.cpp b/src/game/Weather.cpp
index 2c41fa886be..add72da5cc8 100644
--- a/src/game/Weather.cpp
+++ b/src/game/Weather.cpp
@@ -38,7 +38,7 @@ Weather::Weather(uint32 zone, WeatherZoneChances const* weatherChances) : m_zone
m_type = WEATHER_TYPE_FINE;
m_grade = 0;
- sLog.outDetail("WORLD: Starting weather system for zone %u (change every %u minutes).", m_zone, (uint32)(m_timer.GetInterval() / (1000*MINUTE)) );
+ sLog.outDetail("WORLD: Starting weather system for zone %u (change every %u minutes).", m_zone, (uint32)(m_timer.GetInterval() / (MINUTE*IN_MILISECONDS)) );
}
/// Launch a weather update
diff --git a/src/game/World.cpp b/src/game/World.cpp
index f056e8b8330..ff1e5f616a7 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -822,7 +822,7 @@ void World::LoadConfigSettings(bool reload)
}
if(reload)
{
- m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000);
+ m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILISECONDS);
m_timers[WUPDATE_UPTIME].Reset();
}
@@ -951,6 +951,8 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_ARENA_SEASON_ID] = sConfig.GetIntDefault ("Arena.ArenaSeason.ID", 1);
m_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfig.GetBoolDefault("Arena.ArenaSeason.InProgress", true);
+ m_configs[CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET] = sConfig.GetBoolDefault("OffhandCheckAtTalentsReset", false);
+
m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR);
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
@@ -1440,18 +1442,19 @@ void World::SetInitialWorldSettings()
m_timers[WUPDATE_OBJECTS].SetInterval(0);
m_timers[WUPDATE_SESSIONS].SetInterval(0);
- m_timers[WUPDATE_WEATHERS].SetInterval(1000);
- m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*1000); //set auction update interval to 1 minute
- m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*1000);
+ m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILISECONDS);
+ m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILISECONDS);
+ m_timers[WUPDATE_UPTIME].SetInterval(m_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILISECONDS);
//Update "uptime" table based on configuration entry in minutes.
- m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*1000); //erase corpses every 20 minutes
+ m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*IN_MILISECONDS);
+ //erase corpses every 20 minutes
//to set mailtimer to return mails every day between 4 and 5 am
//mailtimer is increased when updating auctions
//one second is 1000 -(tested on win system)
- mail_timer = ((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * 1000) / m_timers[WUPDATE_AUCTIONS].GetInterval() );
+ mail_timer = ((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * IN_MILISECONDS) / m_timers[WUPDATE_AUCTIONS].GetInterval() );
//1440
- mail_timer_expires = ( (DAY * 1000) / (m_timers[WUPDATE_AUCTIONS].GetInterval()));
+ mail_timer_expires = ( (DAY * IN_MILISECONDS) / (m_timers[WUPDATE_AUCTIONS].GetInterval()));
sLog.outDebug("Mail timer set to: %u, mail return is called every %u minutes", mail_timer, mail_timer_expires);
///- Initilize static helper structures
diff --git a/src/game/World.h b/src/game/World.h
index 02577e5e767..f8a587e7edd 100644
--- a/src/game/World.h
+++ b/src/game/World.h
@@ -215,6 +215,7 @@ enum WorldConfigs
CONFIG_INTERVAL_LOG_UPDATE,
CONFIG_MIN_LOG_UPDATE,
CONFIG_ENABLE_SINFO_LOGIN,
+ CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET,
CONFIG_VALUE_COUNT
};
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp
index bfe9946e7d3..70a864229ea 100644
--- a/src/game/WorldSession.cpp
+++ b/src/game/WorldSession.cpp
@@ -305,6 +305,9 @@ void WorldSession::LogoutPlayer(bool Save)
_player->BuildPlayerRepop();
_player->RepopAtGraveyard();
}
+ //drop a flag if player is carrying it
+ if(BattleGround *bg = _player->GetBattleGround())
+ bg->EventPlayerDroppedFlag(_player);
///- Teleport to home if the player is in an invalid instance
if(!_player->m_InstanceValid && !_player->isGameMaster())
diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in
index ee07906372c..1dc5605bb24 100644
--- a/src/mangosd/mangosd.conf.dist.in
+++ b/src/mangosd/mangosd.conf.dist.in
@@ -566,6 +566,11 @@ LogColors = ""
# Default: 0 - no skilups
# 1 - skilups possible
#
+# OffhandCheckAtTalentsReset
+# Talent reset can change offhand weapon restrictions for equip slots.
+# Default: 0 - recheck offhand slot weapon only at zone update
+# 1 - recheck offhand slot weapon at talent reset also
+#
# Event.Announce
# Default: 0 (false)
# 1 (true)
@@ -626,6 +631,7 @@ MaxGroupXPDistance = 74
MailDeliveryDelay = 3600
SkillChance.Prospecting = 0
SkillChance.Milling = 0
+OffhandCheckAtTalentsReset = 0
Event.Announce = 0
BeepAtStart = 1
Motd = "Welcome to a Trinity Core server."
diff --git a/src/shared/Auth/Makefile.am b/src/shared/Auth/Makefile.am
index 2d4cc03902d..7398e2f2fa7 100644
--- a/src/shared/Auth/Makefile.am
+++ b/src/shared/Auth/Makefile.am
@@ -29,13 +29,13 @@ AM_CPPFLAGS = $(TRINI_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(src
noinst_LIBRARIES = libmangosauth.a
libmangosauth_a_SOURCES = \
- AuthCrypt.cpp \
- AuthCrypt.h \
- BigNumber.cpp \
- BigNumber.h \
- Hmac.cpp \
- Hmac.h \
- Sha1.cpp \
- Sha1.h \
- md5.c \
- md5.h
+ AuthCrypt.cpp \
+ AuthCrypt.h \
+ BigNumber.cpp \
+ BigNumber.h \
+ Hmac.cpp \
+ Hmac.h \
+ Sha1.cpp \
+ Sha1.h \
+ md5.c \
+ md5.h
diff --git a/src/shared/Common.h b/src/shared/Common.h
index d1bbb5e4e01..abe804bb3a4 100644
--- a/src/shared/Common.h
+++ b/src/shared/Common.h
@@ -164,6 +164,7 @@ enum TimeConstants
HOUR = MINUTE*60,
DAY = HOUR*24,
MONTH = DAY*30,
+ YEAR = MONTH*12,
IN_MILISECONDS = 1000
};
diff --git a/src/shared/Database/Makefile.am b/src/shared/Database/Makefile.am
index e5dce08653b..b030fca9b7e 100644
--- a/src/shared/Database/Makefile.am
+++ b/src/shared/Database/Makefile.am
@@ -29,38 +29,38 @@ AM_CPPFLAGS = $(TRINI_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(src
noinst_LIBRARIES = libmangosdatabase.a
libmangosdatabase_a_SOURCES = \
- DBCStores.cpp \
- DBCStores.h \
- DBCStructure.h \
- DBCfmt.cpp \
- Database.cpp \
- Database.h \
- DatabaseEnv.h \
- DatabaseImpl.h \
- DatabaseMysql.cpp \
- DatabasePostgre.cpp \
- DatabaseMysql.h \
- DatabasePostgre.h \
- DatabaseSqlite.cpp \
- DatabaseSqlite.h \
- DBCEnums.h \
- Field.cpp \
- Field.h \
- MySQLDelayThread.h \
- PGSQLDelayThread.h \
- QueryResult.h \
- QueryResultMysql.cpp \
- QueryResultMysql.h \
- QueryResultPostgre.cpp \
- QueryResultPostgre.h \
- QueryResultSqlite.cpp \
- QueryResultSqlite.h \
- SQLStorage.cpp \
- SQLStorage.h \
- SQLStorageImpl.h \
- SqlDelayThread.cpp \
- SqlDelayThread.h \
- SqlOperations.cpp \
- SqlOperations.h \
- dbcfile.cpp \
- dbcfile.h
+ DBCStores.cpp \
+ DBCStores.h \
+ DBCStructure.h \
+ DBCfmt.cpp \
+ Database.cpp \
+ Database.h \
+ DatabaseEnv.h \
+ DatabaseImpl.h \
+ DatabaseMysql.cpp \
+ DatabasePostgre.cpp \
+ DatabaseMysql.h \
+ DatabasePostgre.h \
+ DatabaseSqlite.cpp \
+ DatabaseSqlite.h \
+ DBCEnums.h \
+ Field.cpp \
+ Field.h \
+ MySQLDelayThread.h \
+ PGSQLDelayThread.h \
+ QueryResult.h \
+ QueryResultMysql.cpp \
+ QueryResultMysql.h \
+ QueryResultPostgre.cpp \
+ QueryResultPostgre.h \
+ QueryResultSqlite.cpp \
+ QueryResultSqlite.h \
+ SQLStorage.cpp \
+ SQLStorage.h \
+ SQLStorageImpl.h \
+ SqlDelayThread.cpp \
+ SqlDelayThread.h \
+ SqlOperations.cpp \
+ SqlOperations.h \
+ dbcfile.cpp \
+ dbcfile.h
diff --git a/src/shared/Makefile.am b/src/shared/Makefile.am
index a5465f86c11..6b99351cb26 100644
--- a/src/shared/Makefile.am
+++ b/src/shared/Makefile.am
@@ -32,24 +32,24 @@ noinst_LIBRARIES = libmangosshared.a
# libmangosshared library will later be reused by ...
libmangosshared_a_SOURCES = \
- Base.cpp \
- Base.h \
- ByteBuffer.h \
- Common.cpp \
- Common.h \
- Errors.h \
- Log.cpp \
- Log.h \
- MemoryLeaks.cpp \
- MemoryLeaks.h \
- ProgressBar.cpp \
- ProgressBar.h \
- Timer.h \
- Util.cpp \
- Util.h \
- WorldPacket.h \
- revision_nr.h \
- revision.h
+ Base.cpp \
+ Base.h \
+ ByteBuffer.h \
+ Common.cpp \
+ Common.h \
+ Errors.h \
+ Log.cpp \
+ Log.h \
+ MemoryLeaks.cpp \
+ MemoryLeaks.h \
+ ProgressBar.cpp \
+ ProgressBar.h \
+ Timer.h \
+ Util.cpp \
+ Util.h \
+ WorldPacket.h \
+ revision_nr.h \
+ revision.h
# Get revision (git or svn)
# Get HG revision
@@ -67,16 +67,16 @@ $(REVISION_FILE) : $(top_builddir)/src/tools/genrevision/genrevision FORCE
## Additional files to include when running 'make dist'
# Disabled packet logger
EXTRA_DIST = \
- PacketLog.cpp \
- PacketLog.h
+ PacketLog.cpp \
+ PacketLog.h
# System configuration
EXTRA_DIST += \
- SystemConfig.h
+ SystemConfig.h
# System Win32 files
EXTRA_DIST += \
- ServiceWin32.cpp \
- ServiceWin32.h \
- WheatyExceptionReport.cpp \
- WheatyExceptionReport.h
+ ServiceWin32.cpp \
+ ServiceWin32.h \
+ WheatyExceptionReport.cpp \
+ WheatyExceptionReport.h
diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h
index 57867a1c1c1..3645f73bb00 100644
--- a/src/shared/revision_nr.h
+++ b/src/shared/revision_nr.h
@@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
- #define REVISION_NR "7354"
+ #define REVISION_NR "7373"
#endif // __REVISION_NR_H__
diff --git a/src/shared/vmap/Makefile.am b/src/shared/vmap/Makefile.am
index 3829117f2a9..483a926c907 100644
--- a/src/shared/vmap/Makefile.am
+++ b/src/shared/vmap/Makefile.am
@@ -29,30 +29,30 @@ AM_CPPFLAGS = $(TRINI_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(src
noinst_LIBRARIES = libmangosvmaps.a
libmangosvmaps_a_SOURCES = \
- AABSPTree.h \
- BaseModel.cpp \
- BaseModel.h \
- CoordModelMapping.cpp \
- CoordModelMapping.h \
- DebugCmdLogger.cpp \
- DebugCmdLogger.h \
- IVMapManager.h \
- ManagedModelContainer.cpp \
- ManagedModelContainer.h \
- ModelContainer.cpp \
- ModelContainer.h \
- NodeValueAccess.h \
- ShortBox.h \
- ShortVector.h \
- SubModel.cpp \
- SubModel.h \
- TileAssembler.cpp \
- TileAssembler.h \
- TreeNode.cpp \
- TreeNode.h \
- VMapDefinitions.h \
- VMapFactory.cpp \
- VMapFactory.h \
- VMapManager.cpp \
- VMapManager.h \
- VMapTools.h
+ AABSPTree.h \
+ BaseModel.cpp \
+ BaseModel.h \
+ CoordModelMapping.cpp \
+ CoordModelMapping.h \
+ DebugCmdLogger.cpp \
+ DebugCmdLogger.h \
+ IVMapManager.h \
+ ManagedModelContainer.cpp \
+ ManagedModelContainer.h \
+ ModelContainer.cpp \
+ ModelContainer.h \
+ NodeValueAccess.h \
+ ShortBox.h \
+ ShortVector.h \
+ SubModel.cpp \
+ SubModel.h \
+ TileAssembler.cpp \
+ TileAssembler.h \
+ TreeNode.cpp \
+ TreeNode.h \
+ VMapDefinitions.h \
+ VMapFactory.cpp \
+ VMapFactory.h \
+ VMapManager.cpp \
+ VMapManager.h \
+ VMapTools.h