diff options
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 |