Merge branch 'master' into 310

Conflicts:
	src/game/Player.cpp
	src/game/QueryHandler.cpp
This commit is contained in:
tomrus88 2009-03-06 08:03:34 +03:00
commit 6aadc16d7d
54 changed files with 1279 additions and 888 deletions

View file

@ -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_7382_01_mangos_creature_template` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@ -811,6 +811,8 @@ CREATE TABLE `creature_template` (
`AIName` char(64) NOT NULL default '',
`MovementType` tinyint(3) unsigned NOT NULL default '0',
`InhabitType` tinyint(3) unsigned NOT NULL default '3',
`unk16` float NOT NULL default '1',
`unk17` float NOT NULL default '1',
`RacialLeader` tinyint(3) unsigned NOT NULL default '0',
`RegenHealth` tinyint(3) unsigned NOT NULL default '1',
`equipment_id` mediumint(8) unsigned NOT NULL default '0',
@ -827,7 +829,7 @@ CREATE TABLE `creature_template` (
LOCK TABLES `creature_template` WRITE;
/*!40000 ALTER TABLE `creature_template` DISABLE KEYS */;
INSERT INTO `creature_template` VALUES
(1,1,10045,0,10045,0,'Waypoint(Only GM can see it)','Visual',NULL,1,1,64,64,0,0,0,35,35,0,0.91,1,0,14,15,0,100,2000,2200,4096,0,0,0,0,0,0,1.76,2.42,100,8,5242886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,3,0,1,0,0,0x82,'');
(1,1,10045,0,10045,0,'Waypoint(Only GM can see it)','Visual',NULL,1,1,64,64,0,0,0,35,35,0,0.91,1,0,14,15,0,100,2000,2200,4096,0,0,0,0,0,0,1.76,2.42,100,8,5242886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,3,1.0,1.0,0,1,0,0,0x82,'');
/*!40000 ALTER TABLE `creature_template` ENABLE KEYS */;
UNLOCK TABLES;
@ -1470,36 +1472,6 @@ CREATE TABLE `instance_template` (
LOCK TABLES `instance_template` WRITE;
/*!40000 ALTER TABLE `instance_template` DISABLE KEYS */;
INSERT INTO `instance_template` VALUES
(33,0,22,30,10,10,7200,NULL,NULL,NULL,NULL,''),
(34,0,24,32,10,10,7200,NULL,NULL,NULL,NULL,''),
(36,0,15,20,10,10,7200,NULL,NULL,NULL,NULL,''),
(43,0,15,21,10,10,7200,NULL,NULL,NULL,NULL,''),
(47,0,29,38,10,10,7200,NULL,NULL,NULL,NULL,''),
(48,0,24,32,10,10,7200,NULL,NULL,NULL,NULL,''),
(70,0,35,47,10,10,7200,NULL,NULL,NULL,NULL,''),
(90,0,29,38,10,10,7200,NULL,NULL,NULL,NULL,''),
(109,0,45,55,10,10,7200,NULL,NULL,NULL,NULL,''),
(129,0,37,46,10,10,7200,NULL,NULL,NULL,NULL,''),
(189,0,34,45,10,10,7200,NULL,NULL,NULL,NULL,''),
(209,0,44,54,10,10,7200,NULL,NULL,NULL,NULL,''),
(229,0,58,0,10,10,120000,78.5083,-225.044,49.839,5.1,''),
(230,0,52,0,5,5,7200,NULL,NULL,NULL,NULL,''),
(249,0,60,0,40,40,432000,NULL,NULL,NULL,NULL,''),
(289,0,57,0,5,5,7200,NULL,NULL,NULL,NULL,''),
(309,0,60,0,20,20,259200,NULL,NULL,NULL,NULL,''),
(329,0,58,60,5,5,7200,NULL,NULL,NULL,NULL,''),
(349,0,46,55,10,10,7200,NULL,NULL,NULL,NULL,''),
(389,0,13,18,10,10,7200,NULL,NULL,NULL,NULL,''),
(409,0,60,0,40,40,604800,NULL,NULL,NULL,NULL,''),
(429,0,55,60,5,5,7200,NULL,NULL,NULL,NULL,''),
(469,0,60,0,40,40,604800,NULL,NULL,NULL,NULL,''),
(509,0,60,0,20,20,259200,NULL,NULL,NULL,NULL,''),
(531,0,60,0,40,40,604800,NULL,NULL,NULL,NULL,''),
(533,0,80,0,10,25,0,NULL,NULL,NULL,NULL,''),
(615,0,80,0,10,25,0,NULL,NULL,NULL,NULL,''),
(616,0,80,0,10,25,0,NULL,NULL,NULL,NULL,''),
(624,0,80,0,10,25,0,NULL,NULL,NULL,NULL,'');
/*!40000 ALTER TABLE `instance_template` ENABLE KEYS */;
UNLOCK TABLES;
@ -13047,10 +13019,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',
@ -13299,7 +13267,7 @@ CREATE TABLE `spell_area` (
`quest_start` mediumint(8) unsigned NOT NULL default '0',
`quest_start_active` tinyint(1) unsigned NOT NULL default '0',
`quest_end` mediumint(8) unsigned NOT NULL default '0',
`aura_spell` mediumint(8) unsigned NOT NULL default '0',
`aura_spell` mediumint(8) NOT NULL default '0',
`racemask` mediumint(8) unsigned NOT NULL default '0',
`gender` tinyint(1) unsigned NOT NULL default '2',
`autocast` tinyint(1) unsigned NOT NULL default '0',

View file

@ -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;

View file

@ -0,0 +1,4 @@
ALTER TABLE db_version CHANGE COLUMN required_7369_01_mangos_quest_template required_7376_01_mangos_spell_area bit;
ALTER TABLE spell_area
CHANGE COLUMN `aura_spell` `aura_spell` mediumint(8) NOT NULL default '0';

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_7376_01_mangos_spell_area required_7382_01_mangos_creature_template bit;
ALTER TABLE creature_template
ADD COLUMN unk16 float NOT NULL default '1' AFTER InhabitType,
ADD COLUMN unk17 float NOT NULL default '1' AFTER unk16;

View file

@ -188,6 +188,9 @@ pkgdata_DATA = \
7331_01_mangos_command.sql \
7332_01_mangos_command.sql \
7349_01_mangos_spell_area.sql \
7369_01_mangos_quest_template.sql \
7376_01_mangos_spell_area.sql \
7382_01_mangos_creature_template.sql \
README
## Additional files to include when running 'make dist'
@ -356,4 +359,7 @@ EXTRA_DIST = \
7331_01_mangos_command.sql \
7332_01_mangos_command.sql \
7349_01_mangos_spell_area.sql \
7369_01_mangos_quest_template.sql \
7376_01_mangos_spell_area.sql \
7382_01_mangos_creature_template.sql \
README

View file

@ -27,6 +27,7 @@
#include "GameEvent.h"
#include "World.h"
#include "SpellMgr.h"
#include "ArenaTeam.h"
#include "ProgressBar.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
@ -374,6 +375,18 @@ void AchievementMgr::CheckAllAchievementCriteria()
UpdateAchievementCriteria(AchievementCriteriaTypes(i));
}
static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = { 1057, 1107, 1108 };
static const uint32 achievIdForDangeon[][4] =
{
// ach_cr_id,is_dungeon,is_raid,is_heroic_dungeon
{ 321, true, true, true },
{ 916, false, true, false },
{ 917, false, true, false },
{ 918, true, false, false },
{ 2219, false, false, true },
{ 0, false, false, false }
};
/**
* this function will be called whenever the user might have done a criteria relevant action
*/
@ -406,24 +419,55 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
switch (type)
{
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
SetCriteriaProgress(achievementCriteria, GetPlayer()->getLevel());
// std. case: increment at 1
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetByteValue(PLAYER_BYTES_2, 2)+1);
// std case: increment at miscvalue1
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_ACCUMULATE);
break;
// std case: high value at miscvalue1
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_HIGHEST);
break;
// specialized cases
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
if(achievementCriteria->kill_creature.creatureID != miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, miscvalue2, true);
SetCriteriaProgress(achievementCriteria, miscvalue2, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
SetCriteriaProgress(achievementCriteria, GetPlayer()->getLevel());
break;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
if(uint32 skillvalue = GetPlayer()->GetBaseSkillValue(achievementCriteria->reach_skill_level.skillID))
SetCriteriaProgress(achievementCriteria, skillvalue);
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
if(m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) != m_completedAchievements.end())
SetCriteriaProgress(achievementCriteria, 1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
{
uint32 counter =0;
@ -445,27 +489,13 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, counter);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, miscvalue1, true);
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
if(GetPlayer()->GetMapId() != achievementCriteria->complete_battleground.mapID)
continue;
SetCriteriaProgress(achievementCriteria, miscvalue1, true);
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
if(GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID))
SetCriteriaProgress(achievementCriteria, 1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
if(m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) != m_completedAchievements.end())
SetCriteriaProgress(achievementCriteria, 1);
SetCriteriaProgress(achievementCriteria, miscvalue1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
@ -473,21 +503,99 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
continue;
if(GetPlayer()->GetMapId() != achievementCriteria->death_at_map.mapID)
continue;
SetCriteriaProgress(achievementCriteria, 1, true);
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
// skip wrong arena achievements, if not achievIdByArenaSlot then normal totla death counter
bool notfit = false;
for(int i = 0; i < MAX_ARENA_SLOT; ++i)
{
if(achievIdByArenaSlot[i] == achievement->ID)
{
BattleGround* bg = GetPlayer()->GetBattleGround();
if(!bg || ArenaTeam::GetSlotByType(bg->GetArenaType())!=i)
notfit = true;
break;
}
}
if(notfit)
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
Map const* map = GetPlayer()->GetMap();
if(!map->IsDungeon())
continue;
// search case
bool found = false;
for(int i = 0; achievIdForDangeon[i][0]; ++i)
{
if(achievIdForDangeon[i][0] == achievement->ID)
{
if(map->IsRaid())
{
// if raid accepted (ignore difficulty)
if(!achievIdForDangeon[i][2])
break; // for
}
else if(GetPlayer()->GetDifficulty()==DIFFICULTY_NORMAL)
{
// dungeon in normal mode accepted
if(!achievIdForDangeon[i][1])
break; // for
}
else
{
// dungeon in heroic mode accepted
if(!achievIdForDangeon[i][3])
break; // for
}
found = true;
break; // for
}
}
if(!found)
continue;
//FIXME: work only for instances where max==min for players
if(((InstanceMap*)map)->GetMaxPlayers() != achievementCriteria->death_in_dungeon.manLimit)
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
if(miscvalue1 != achievementCriteria->killed_by_creature.creatureEntry)
continue;
SetCriteriaProgress(achievementCriteria, 1, true);
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, 1, true);
// if team check required: must kill by opposition faction
if(achievement->ID==318 && miscvalue2==GetPlayer()->GetTeam())
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
{
@ -506,17 +614,32 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
SetCriteriaProgress(achievementCriteria, miscvalue1);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
if(miscvalue2 != achievementCriteria->death_from.type)
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
if(GetPlayer()->GetQuestRewardStatus(achievementCriteria->complete_quest.questID))
SetCriteriaProgress(achievementCriteria, 1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
if (!miscvalue1 || miscvalue1 != achievementCriteria->be_spell_target.spellID)
continue;
if(achievementCriteria->use_item.itemID != miscvalue1)
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID)
continue;
SetCriteriaProgress(achievementCriteria, 1, true);
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
if(GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID))
SetCriteriaProgress(achievementCriteria, 1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
// speedup for non-login case
@ -524,25 +647,107 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
continue;
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetItemCount(achievementCriteria->own_item.itemID, true));
break;
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
continue;
if(achievementCriteria->use_item.itemID != miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
// You _have_ to loot that item, just owning it when logging in does _not_ count!
if(!miscvalue1)
continue;
if(miscvalue1 != achievementCriteria->own_item.itemID)
continue;
SetCriteriaProgress(achievementCriteria, miscvalue2, true);
SetCriteriaProgress(achievementCriteria, miscvalue2, PROGRESS_ACCUMULATE);
break;
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
if (!miscvalue1 || miscvalue1 != achievementCriteria->be_spell_target.spellID)
case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
{
WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference);
if(!worldOverlayEntry)
break;
int32 exploreFlag = GetAreaFlagByAreaID(worldOverlayEntry->areatableID);
if(exploreFlag < 0)
break;
uint32 playerIndexOffset = uint32(exploreFlag) / 32;
uint32 mask = 1<< (uint32(exploreFlag) % 32);
if(GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
SetCriteriaProgress(achievementCriteria, 1);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
SetCriteriaProgress(achievementCriteria, GetPlayer()->GetByteValue(PLAYER_BYTES_2, 2)+1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
{
int32 reputation = GetPlayer()->GetReputation(achievementCriteria->gain_reputation.factionID);
if (reputation > 0)
SetCriteriaProgress(achievementCriteria, reputation);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
{
uint32 counter = 0;
const FactionStateList factionStateList = GetPlayer()->GetFactionStateList();
for (FactionStateList::const_iterator iter = factionStateList.begin(); iter!= factionStateList.end(); ++iter)
{
if(GetPlayer()->ReputationToRank(iter->second.Standing) >= REP_EXALTED)
++counter;
}
SetCriteriaProgress(achievementCriteria, counter);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
{
// skip for login case
if(!miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, 1, true);
SetCriteriaProgress(achievementCriteria, 1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID)
}
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
{
// miscvalue1 = itemid
// miscvalue2 = diced value
if(!miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, 1, true);
if(miscvalue2 != achievementCriteria->roll_greed_on_loot.rollValue)
continue;
ItemPrototype const *pProto = objmgr.GetItemPrototype( miscvalue1 );
uint32 requiredItemLevel = 0;
if (achievementCriteria->ID == 2412 || achievementCriteria->ID == 2358)
requiredItemLevel = 185;
if(!pProto || pProto->ItemLevel <requiredItemLevel)
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
{
uint32 spellCount = 0;
for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
spellIter != GetPlayer()->GetSpellMap().end();
++spellIter)
{
for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
++skillIter)
{
if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine)
spellCount++;
}
}
SetCriteriaProgress(achievementCriteria, spellCount);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
{
if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID)
@ -564,162 +769,72 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
continue;
}
SetCriteriaProgress(achievementCriteria, 1, true);
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
{
uint32 spellCount = 0;
for (PlayerSpellMap::const_iterator spellIter = GetPlayer()->GetSpellMap().begin();
spellIter != GetPlayer()->GetSpellMap().end();
++spellIter)
{
for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
++skillIter)
{
if(skillIter->second->skillId == achievementCriteria->learn_skilline_spell.skillLine)
spellCount++;
}
}
SetCriteriaProgress(achievementCriteria, spellCount);
// std case: not exist in DBC, not triggered in code as result
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING:
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
{
// skip for login case
if(!miscvalue1)
continue;
SetCriteriaProgress(achievementCriteria, 1);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
{
int32 reputation = GetPlayer()->GetReputation(achievementCriteria->gain_reputation.factionID);
if (reputation > 0)
SetCriteriaProgress(achievementCriteria, reputation);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
{
uint32 counter = 0;
const FactionStateList factionStateList = GetPlayer()->GetFactionStateList();
for (FactionStateList::const_iterator iter = factionStateList.begin(); iter!= factionStateList.end(); ++iter)
{
if(GetPlayer()->ReputationToRank(iter->second.Standing) >= REP_EXALTED)
++counter;
}
SetCriteriaProgress(achievementCriteria, counter);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
{
WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->explore_area.areaReference);
if(!worldOverlayEntry)
break;
int32 exploreFlag = GetAreaFlagByAreaID(worldOverlayEntry->areatableID);
if(exploreFlag < 0)
break;
uint32 playerIndexOffset = uint32(exploreFlag) / 32;
uint32 mask = 1<< (uint32(exploreFlag) % 32);
if(GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
SetCriteriaProgress(achievementCriteria, 1);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
{
// miscvalue1 = itemid
// miscvalue2 = diced value
if(!miscvalue1)
continue;
if(miscvalue2 != achievementCriteria->roll_greed_on_loot.rollValue)
continue;
ItemPrototype const *pProto = objmgr.GetItemPrototype( miscvalue1 );
uint32 requiredItemLevel = 0;
if (achievementCriteria->ID == 2412 || achievementCriteria->ID == 2358)
requiredItemLevel = 185;
if(!pProto || pProto->ItemLevel <requiredItemLevel)
continue;
SetCriteriaProgress(achievementCriteria, 1, true);
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING:
case ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING:
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
case ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE:
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:
case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED:
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION:
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION:
case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
break; // Not implemented yet :(
// FIXME: not triggered in code as result, need to implement
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY:
case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID:
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE:
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING:
case ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING:
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE:
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS:
case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS:
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT:
case ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE:
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL:
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS:
case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION:
case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED:
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION:
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION:
case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED:
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED:
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN:
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE:
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
break; // Not implemented yet :(
}
if(IsCompletedCriteria(achievementCriteria))
CompletedCriteria(achievementCriteria);
@ -754,64 +869,87 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
switch(achievementCriteria->requiredType)
{
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
{
if (achievIdByClass[GetPlayer()->getClass()] == achievement->ID ||
achievIdByRace[GetPlayer()->getRace()] == achievement->ID)
return progress->counter >= achievementCriteria->reach_level.level;
return false;
}
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
return progress->counter >= achievementCriteria->buy_bank_slot.numberOfSlots;
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
return progress->counter >= achievementCriteria->kill_creature.creatureCount;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
{
// skip wrong class achievements
for(int i = 1; i < MAX_CLASSES; ++i)
if(achievIdByClass[i] == achievement->ID && i != GetPlayer()->getClass())
return false;
// skip wrong race achievements
for(int i = 1; i < MAX_RACES; ++i)
if(achievIdByRace[i] == achievement->ID && i != GetPlayer()->getRace())
return false;
// appropriate class/race or not class/race specific
return progress->counter >= achievementCriteria->reach_level.level;
}
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
return progress->counter >= achievementCriteria->reach_skill_level.skillLevel;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
return progress->counter >= achievementCriteria->complete_quest_count.totalQuestCount;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
return progress->counter >= achievementCriteria->complete_quests_in_zone.questCount;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST:
return progress->counter >= achievementCriteria->complete_daily_quest.questCount;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
return progress->counter >= achievementCriteria->fall_without_dying.fallHeight;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
return progress->counter >= achievementCriteria->use_item.itemCount;
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
return progress->counter >= achievementCriteria->own_item.itemCount;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
return progress->counter >= achievementCriteria->loot_item.itemCount;
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET:
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2:
return progress->counter >= achievementCriteria->be_spell_target.spellCount;
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL:
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
return progress->counter >= achievementCriteria->cast_spell.castCount;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
return progress->counter >= achievementCriteria->learn_skilline_spell.spellCount;
case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
return progress->counter >= achievementCriteria->visit_barber.numberOfVisits;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
return progress->counter >= achievementCriteria->own_item.itemCount;
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
return progress->counter >= achievementCriteria->use_item.itemCount;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
return progress->counter >= achievementCriteria->loot_item.itemCount;
case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
return progress->counter >= achievementCriteria->buy_bank_slot.numberOfSlots;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
return progress->counter >= achievementCriteria->gain_reputation.reputationAmount;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
return progress->counter >= achievementCriteria->gain_exalted_reputation.numberOfExaltedFactions;
case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
return progress->counter >= 1;
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
return progress->counter >= achievementCriteria->roll_greed_on_loot.count;
case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
return progress->counter >= achievementCriteria->visit_barber.numberOfVisits;
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT:
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT:
return progress->counter >= achievementCriteria->roll_greed_on_loot.count;
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD:
return progress->counter >= achievementCriteria->quest_reward_money.goldInCopper;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
return progress->counter >= achievementCriteria->loot_money.goldInCopper;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
return progress->counter >= achievementCriteria->learn_skilline_spell.spellCount;
// handle all statistic-only criteria here
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON:
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER:
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR:
return false;
}
return false;
@ -858,9 +996,9 @@ AchievementCompletionState AchievementMgr::GetAchievementCompletionState(Achieve
return ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED;
}
void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 newValue, bool relative)
void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype)
{
sLog.outDetail("AchievementMgr::SetCriteriaProgress(%u, %u)", entry->ID, newValue);
sLog.outDetail("AchievementMgr::SetCriteriaProgress(%u, %u) for (GUID:%u)", entry->ID, changeValue);
CriteriaProgress *progress = NULL;
CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID);
@ -868,18 +1006,30 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry,
if(iter == m_criteriaProgress.end())
{
// not create record for 0 counter
if(newValue == 0)
if(changeValue == 0)
return;
progress = &m_criteriaProgress[entry->ID];
progress->counter = newValue;
progress->counter = changeValue;
progress->date = time(NULL);
}
else
{
progress = &iter->second;
if(relative)
newValue += progress->counter;
uint32 newValue;
switch(ptype)
{
case PROGRESS_SET:
newValue = changeValue;
break;
case PROGRESS_ACCUMULATE:
newValue = progress->counter + changeValue;
break;
case PROGRESS_HIGHEST:
newValue = progress->counter < changeValue ? changeValue : progress->counter;
break;
}
// not update (not mark as changed) if counter will have same value
if(progress->counter == newValue)

View file

@ -104,9 +104,10 @@ class AchievementMgr
Player* GetPlayer() { return m_player;}
private:
enum ProgressType { PROGRESS_SET, PROGRESS_ACCUMULATE, PROGRESS_HIGHEST };
void SendAchievementEarned(AchievementEntry const* achievement);
void SendCriteriaUpdate(uint32 id, CriteriaProgress const* progress);
void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 newValue, bool relative=false);
void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 changeValue, ProgressType ptype = PROGRESS_SET);
void CompletedCriteria(AchievementCriteriaEntry const* entry);
void CompletedAchievement(AchievementEntry const* entry);
bool IsCompletedCriteria(AchievementCriteriaEntry const* entry);

View file

@ -358,6 +358,7 @@ void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
}
auction->bidder = pl->GetGUIDLow();
auction->bid = price;
GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, price);
// after this update we should save player's money ...
CharacterDatabase.PExecute("UPDATE auctionhouse SET buyguid = '%u',lastbid = '%u' WHERE id = '%u'", auction->bidder, auction->bid, auction->Id);
@ -381,6 +382,7 @@ void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
}
auction->bidder = pl->GetGUIDLow();
auction->bid = auction->buyout;
GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID, auction->buyout);
auctionmgr.SendAuctionSalePendingMail( auction );
auctionmgr.SendAuctionSuccessfulMail( auction );

View file

@ -223,6 +223,8 @@ void AuctionHouseMgr::SendAuctionSuccessfulMail( AuctionEntry * auction )
if (owner)
{
//FIXME: what do if owner offline
owner->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD, auction->bid);
//send auction owner notification, bidder must be current!
owner->GetSession()->SendAuctionOwnerNotification( auction );
}
@ -630,29 +632,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;
}

View file

@ -36,7 +36,7 @@ BattleGround::BattleGround()
{
m_TypeID = BattleGroundTypeId(0);
m_InstanceID = 0;
m_Status = 0;
m_Status = STATUS_NONE;
m_EndTime = 0;
m_LastResurrectTime = 0;
m_QueueId = QUEUE_ID_MAX_LEVEL_19;
@ -1514,3 +1514,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() );
}

View file

@ -111,11 +111,11 @@ const uint32 Buff_Entries[3] = { BG_OBJECTID_SPEEDBUFF_ENTRY, BG_OBJECTID_REGENB
enum BattleGroundStatus
{
STATUS_NONE = 0,
STATUS_WAIT_QUEUE = 1,
STATUS_WAIT_JOIN = 2,
STATUS_IN_PROGRESS = 3,
STATUS_WAIT_LEAVE = 4 // custom
STATUS_NONE = 0, // first status, should mean bg is not instance
STATUS_WAIT_QUEUE = 1, // means bg is empty and waiting for queue
STATUS_WAIT_JOIN = 2, // this means, that BG has already started and it is waiting for more players
STATUS_IN_PROGRESS = 3, // means bg is running
STATUS_WAIT_LEAVE = 4 // means some faction has won BG and it is ending
};
struct BattleGroundPlayer
@ -273,7 +273,7 @@ class BattleGround
BattleGroundTypeId GetTypeID() const { return m_TypeID; }
BGQueueIdBasedOnLevel GetQueueId() const { return m_QueueId; }
uint32 GetInstanceID() const { return m_InstanceID; }
uint32 GetStatus() const { return m_Status; }
BattleGroundStatus GetStatus() const { return m_Status; }
uint32 GetStartTime() const { return m_StartTime; }
uint32 GetEndTime() const { return m_EndTime; }
uint32 GetLastResurrectTime() const { return m_LastResurrectTime; }
@ -286,7 +286,7 @@ class BattleGround
uint32 GetMaxPlayersPerTeam() const { return m_MaxPlayersPerTeam; }
uint32 GetMinPlayersPerTeam() const { return m_MinPlayersPerTeam; }
int GetStartDelayTime() const { return m_StartDelayTime; }
int32 GetStartDelayTime() const { return m_StartDelayTime; }
uint8 GetArenaType() const { return m_ArenaType; }
uint8 GetWinner() const { return m_Winner; }
uint32 GetBattlemasterEntry() const;
@ -302,7 +302,7 @@ class BattleGround
this->SetLevelRange((ID + 1) * 10 + diff, (ID + 2) * 10 - ((diff + 1) % 2));
}
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
void SetStatus(uint32 Status) { m_Status = Status; }
void SetStatus(BattleGroundStatus Status) { m_Status = Status; }
void SetStartTime(uint32 Time) { m_StartTime = Time; }
void SetEndTime(uint32 Time) { m_EndTime = Time; }
void SetLastResurrectTime(uint32 Time) { m_LastResurrectTime = Time; }
@ -426,7 +426,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
@ -489,7 +489,7 @@ class BattleGround
/* Battleground */
BattleGroundTypeId m_TypeID;
uint32 m_InstanceID; //BattleGround Instance's GUID!
uint32 m_Status;
BattleGroundStatus m_Status;
uint32 m_StartTime;
uint32 m_EndTime;
uint32 m_LastResurrectTime;
@ -497,9 +497,6 @@ class BattleGround
uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5
bool m_InBGFreeSlotQueue; // used to make sure that BG is only once inserted into the BattleGroundMgr.BGFreeSlotQueue[bgTypeId] deque
bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave
// this variable is not used .... it can be found in many other ways... but to store it in BG object instance is useless
//uint8 m_BattleGroundType; // 3=BG, 4=arena
//instead of uint8 (in previous line) is bool used
bool m_IsArena;
uint8 m_Winner; // 0=alliance, 1=horde, 2=none
int32 m_StartDelayTime;
@ -537,7 +534,7 @@ class BattleGround
uint32 m_MinPlayersPerTeam;
uint32 m_MinPlayers;
/* Location */
/* Start location */
uint32 m_MapId;
float m_TeamStartLocX[BG_TEAMS_COUNT];
float m_TeamStartLocY[BG_TEAMS_COUNT];

View file

@ -409,20 +409,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
@ -603,9 +604,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;
@ -617,13 +618,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;

View file

@ -242,7 +242,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);

View file

@ -885,16 +885,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;
@ -909,19 +909,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;

View file

@ -24,8 +24,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
{
@ -315,7 +315,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);

View file

@ -370,7 +370,7 @@ void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
BattleGroundQueueTypeId bgQueueTypeId = BATTLEGROUND_QUEUE_NONE;
// get the bg what we were invited to
bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId,type);
bgQueueTypeId = BattleGroundMgr::BGQueueTypeId(bgTypeId, type);
BattleGroundQueue::QueuedPlayersMap& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers;
BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = qpMap.find(_player->GetGUID());
if(itrPlayerStatus == qpMap.end())

View file

@ -113,17 +113,18 @@ bool BattleGroundQueue::SelectionPool::KickGroup(uint32 size)
// add group to selection pool
// used when building selection pools
// returns true if we can invite more players, otherwise return false - (selection pool is set that time)
// returns true if we can invite more players
// returns false when selection pool is set
bool BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo *ginfo, uint32 desiredCount)
{
//if group is larger than desired count - don't allow to add it to pool
if (!ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size())
if( !ginfo->IsInvitedToBGInstanceGUID && desiredCount >= PlayerCount + ginfo->Players.size() )
{
SelectedGroups.push_back(ginfo);
// increase selected players count
PlayerCount += ginfo->Players.size();
}
if (PlayerCount == desiredCount)
if( PlayerCount < desiredCount )
return true;
return false;
}
@ -553,7 +554,8 @@ bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32
{
for(itr = m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].begin(); itr != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].end(); ++itr)
{
if( !(*itr)->IsInvitedToBGInstanceGUID && m_SelectionPools[i].AddGroup((*itr), maxPlayers) )
//if itr can join BG and player count is less that maxPlayers, then add group to selectionpool
if( !(*itr)->IsInvitedToBGInstanceGUID && !m_SelectionPools[i].AddGroup((*itr), maxPlayers) )
break;
}
}
@ -575,7 +577,7 @@ bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32
{
//we must insert group to normal queue and erase pointer from premade queue
m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + i].push_front((*itr));
m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr); //pop_front();
m_QueuedGroups[queue_id][BG_QUEUE_PREMADE_ALLIANCE + i].erase(itr);
}
}
}
@ -583,7 +585,7 @@ bool BattleGroundQueue::CheckPremadeMatch(BGQueueIdBasedOnLevel queue_id, uint32
return false;
}
//this function tries to create battleground or arena with MinPlayersPerTeam against MinPlayersPerTeam
// 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)
{
GroupsQueueType::const_iterator itr_team[BG_TEAMS_COUNT];
@ -612,7 +614,7 @@ bool BattleGroundQueue::CheckNormalMatch(BattleGround* bg_template, BGQueueIdBas
for(; itr_team[j] != m_QueuedGroups[queue_id][BG_QUEUE_NORMAL_ALLIANCE + j].end(); ++(itr_team[j]))
{
if( !(*(itr_team[j]))->IsInvitedToBGInstanceGUID )
if( m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()) )
if( !m_SelectionPools[j].AddGroup(*(itr_team[j]), m_SelectionPools[(j + 1) % BG_TEAMS_COUNT].GetPlayerCount()) )
break;
}
// do not allow to start bg with more than 2 players more on 1 faction
@ -626,6 +628,65 @@ 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 selection pool is full then break;
if( !(*itr_team2)->IsInvitedToBGInstanceGUID && !m_SelectionPools[otherTeam].AddGroup(*itr_team2, 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
@ -644,9 +705,8 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve
//battleground with free slot for player should be always in the beggining of the queue
// maybe it would be better to create bgfreeslotqueue for each queue_id_based_on_level
bool continueAdding = true;
BGFreeSlotQueueType::iterator itr, next;
for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); continueAdding && itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next)
{
next = itr;
++next;
@ -672,8 +732,6 @@ void BattleGroundQueue::Update(BattleGroundTypeId bgTypeId, BGQueueIdBasedOnLeve
if( !bg->HasFreeSlots() )
{
if( next == sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end() )
continueAdding = false;
// remove BG from BGFreeSlotQueue
bg->RemoveFromBGFreeSlotQueue();
}
@ -754,7 +812,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, MinPlayersPerTeam, MaxPlayersPerTeam) )
if( CheckNormalMatch(bg_template, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam)
|| (bg_template->isArena() && CheckSkirmishForSameFaction(queue_id, MinPlayersPerTeam)) )
{
// we successfully created a pool
BattleGround * bg2 = NULL;
@ -1473,11 +1532,6 @@ BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeI
// reset the new bg (set status to status_wait_queue from status_none)
bg->Reset();
if( bg->isBattleGround() && sWorld.getConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE) )
{
sWorld.SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, bg->GetName(), bg->GetMinLevel(), bg->GetMaxLevel());
}
// start the joining of the bg
bg->SetStatus(STATUS_WAIT_JOIN);
bg->SetQueueId(queue_id);

View file

@ -24,7 +24,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,6 +75,7 @@ class BattleGroundQueue
void FillPlayersToBG(BattleGround* bg, 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);

View file

@ -22,8 +22,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
{

View file

@ -1191,7 +1191,8 @@ void WorldSession::HandleAlterAppearance( WorldPacket & recv_data )
SendPacket(&data);
}
_player->SetMoney(_player->GetMoney() - Cost); // it isn't free
_player->ModifyMoney(-int32(Cost)); // it isn't free
_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER, Cost);
_player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id));
_player->SetByteValue(PLAYER_BYTES, 3, uint8(Color));

View file

@ -1450,7 +1450,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_IMMEDIATLY) || isWorldBoss())
@ -1756,7 +1756,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
@ -1877,7 +1877,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));
@ -1896,7 +1896,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
@ -1925,7 +1925,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;
}
@ -1967,7 +1967,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;

View file

@ -195,6 +195,8 @@ struct CreatureInfo
char const* AIName;
uint32 MovementType;
uint32 InhabitType;
float unk16;
float unk17;
bool RacialLeader;
bool RegenHealth;
uint32 equipmentId;

View file

@ -447,7 +447,7 @@ uint32 GameEvent::Update() // return the next e
nextEventDelay = calcDelay;
}
sLog.outBasic("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)

View file

@ -38,7 +38,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 MAX_NUMBER_OF_CELLS 8

View file

@ -145,7 +145,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;

View file

@ -222,6 +222,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
for (std::vector<Player*>::iterator i = playersNear.begin(); i != playersNear.end(); ++i)
{
(*i)->ModifyMoney( money_per_player );
(*i)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, money_per_player);
//Offset surely incorrect, but works
WorldPacket data( SMSG_LOOT_MONEY_NOTIFY, 4 );
data << uint32(money_per_player);
@ -229,7 +230,10 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
}
}
else
{
player->ModifyMoney( pLoot->gold );
player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, pLoot->gold);
}
pLoot->gold = 0;
pLoot->NotifyMoneyRemoved();
}

View file

@ -275,6 +275,13 @@ bool LootStoreItem::IsValid(LootStore const& store, uint32 entry) const
store.GetName(), entry, itemid, chance);
return false;
}
if( maxcount < mincountOrRef) // wrong max count
{
sLog.outErrorDb("Table '%s' entry %d item %d: max count (%u) less that min count (%i) - skipped", store.GetName(), entry, itemid, uint32(maxcount), mincountOrRef);
return false;
}
}
else // mincountOrRef < 0
{

View file

@ -122,9 +122,9 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
return;
}
uint32 reqmoney = money + 30;
if (items_count)
reqmoney = money + (30 * items_count);
uint32 cost = items_count ? 30 * items_count : 30; // price hardcoded in client
uint32 reqmoney = cost + money;
if (pl->GetMoney() < reqmoney)
{
@ -207,6 +207,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
}
pl->ModifyMoney( -int32(reqmoney) );
pl->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL, cost);
bool needItemDelay = false;

View file

@ -1130,7 +1130,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);
*/
}

View file

@ -231,52 +231,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())
{
// calculate total z distance of the fall
float z_diff = GetPlayer()->m_lastFallZ - movementInfo.z;
sLog.outDebug("zDiff = %f", z_diff);
Player *target = GetPlayer();
//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 && !target->isDead() && !target->isGameMaster() &&
!target->HasAuraType(SPELL_AURA_HOVER) && !target->HasAuraType(SPELL_AURA_FEATHER_FALL) &&
!target->HasAuraType(SPELL_AURA_FLY) && !target->IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL) )
{
//Safe fall, fall height reduction
int32 safe_fall = target->GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
float damageperc = 0.018f*(z_diff-safe_fall)-0.2426f;
if(damageperc >0 )
{
uint32 damage = (uint32)(damageperc * target->GetMaxHealth()*sWorld.getRate(RATE_DAMAGE_FALL));
float height = movementInfo.z;
target->UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
if (damage > 0)
{
//Prevent fall damage from being more than the player maximum health
if (damage > target->GetMaxHealth())
damage = target->GetMaxHealth();
// Gust of Wind
if (target->GetDummyAura(43621))
damage = target->GetMaxHealth()/2;
target->EnvironmentalDamage(target->GetGUID(), DAMAGE_FALL, damage);
// recheck alive, might have died of EnvironmentalDamage
if (target->isAlive())
target->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, target->GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
}
}
}
GetPlayer()->HandleFall(movementInfo);
if(((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != GetPlayer()->IsInWater())
{

View file

@ -84,7 +84,7 @@ ObjectAccessor::GetNPCIfCanInteractWith(Player const &player, uint64 guid, uint3
if(factionTemplate)
{
FactionEntry const* faction = sFactionStore.LookupEntry(factionTemplate->faction);
if( faction->reputationListID >= 0 && player.GetReputationRank(faction) <= REP_UNFRIENDLY)
if( faction && faction->reputationListID >= 0 && player.GetReputationRank(faction) <= REP_UNFRIENDLY)
return NULL;
}

View file

@ -2732,25 +2732,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)
@ -3044,20 +3044,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
{
@ -3067,41 +3053,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
}
}
}

View file

@ -1023,7 +1023,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);

View file

@ -298,7 +298,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;

View file

@ -62,7 +62,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)
@ -359,7 +359,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;
@ -416,6 +416,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;
@ -809,7 +811,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;
@ -833,6 +835,9 @@ void Player::StopMirrorTimer(MirrorTimerType Type)
void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 damage)
{
if(!isAlive() || isGameMaster())
return;
WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21));
data << (uint64)guid;
data << (uint8)(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL);
@ -843,13 +848,18 @@ void Player::EnvironmentalDamage(uint64 guid, EnviromentalDamage type, uint32 da
DealDamage(this, damage, NULL, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
if(type==DAMAGE_FALL && !isAlive()) // DealDamage not apply item durability loss at self damage
if(!isAlive())
{
DEBUG_LOG("We are fall to death, loosing 10 percents durability");
DurabilityLossAll(0.10f,false);
// durability lost message
WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
GetSession()->SendPacket(&data);
if(type==DAMAGE_FALL) // DealDamage not apply item durability loss at self damage
{
DEBUG_LOG("We are fall to death, loosing 10 percents durability");
DurabilityLossAll(0.10f,false);
// durability lost message
WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
GetSession()->SendPacket(&data);
}
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM, 1, type);
}
}
@ -867,7 +877,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)
@ -879,7 +889,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))
@ -924,7 +934,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
@ -933,11 +943,9 @@ void Player::HandleLava()
uint64 guid = GetGUID();
uint32 damage = urand(600, 700); // TODO: Get more detailed information about lava damage
// if not gamemaster then deal damage
if ( !isGameMaster() )
EnvironmentalDamage(guid, DAMAGE_LAVA, damage);
EnvironmentalDamage(guid, DAMAGE_LAVA, damage);
m_breathTimer = 1000;
m_breathTimer = 1*IN_MILISECONDS;
}
}
else if (!isAlive()) // Disable breath timer and reset underwater flags
@ -1257,7 +1265,7 @@ void Player::Update( uint32 p_time )
{
m_drunkTimer += p_time;
if (m_drunkTimer > 10000)
if (m_drunkTimer > 10*IN_MILISECONDS)
HandleSobering();
}
@ -1320,6 +1328,8 @@ void Player::setDeathState(DeathState s)
if(!ressSpellId)
ressSpellId = GetResurrectionSpellId();
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, 1);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON, 1);
}
Unit::setDeathState(s);
@ -1561,6 +1571,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);
@ -2398,6 +2409,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)));
@ -2430,12 +2444,15 @@ void Player::SendInitialSpells()
if(!sEntry)
continue;
// not send infinity cooldown
if(itr->second.end > infTime)
continue;
data << uint32(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
@ -3122,8 +3139,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));
@ -3153,7 +3170,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());
@ -3194,17 +3211,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;
}
}
@ -3319,6 +3339,7 @@ bool Player::resetTalents(bool no_cost)
if(!no_cost)
{
ModifyMoney(-(int32)cost);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS, cost);
m_resetTalentsCost = cost;
m_resetTalentsTime = time(NULL);
@ -3327,6 +3348,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;
}
@ -3883,7 +3911,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
{
if(Aura* Aur = GetAura(SPELL_ID_PASSIVE_RESURRECTION_SICKNESS,i))
{
Aur->SetAuraDuration(delta*1000);
Aur->SetAuraDuration(delta*IN_MILISECONDS);
Aur->SendAuraUpdate(false);
}
}
@ -3904,7 +3932,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
@ -4228,10 +4256,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))
ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam());
if( BattleGround *bg = GetBattleGround() )
ClosestGrave = bg->GetClosestGraveYard(this);
else
ClosestGrave = objmgr.GetClosestGraveYard( GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam() );
@ -5621,7 +5647,8 @@ void Player::SetFactionVisibleForFactionTemplateId(uint32 FactionTemplateId)
if(!factionTemplateEntry)
return;
SetFactionVisibleForFactionId(factionTemplateEntry->faction);
if(factionTemplateEntry->faction)
SetFactionVisibleForFactionId(factionTemplateEntry->faction);
}
void Player::SetFactionVisibleForFactionId(uint32 FactionId)
@ -6389,6 +6416,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 );
@ -9811,6 +9841,12 @@ uint8 Player::CanStoreItems( Item **pItems,int count) const
pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, t );
if( pBag )
{
pBagProto = pBag->GetProto();
// special bag already checked
if( pBagProto && (pBagProto->Class != ITEM_CLASS_CONTAINER || pBagProto->SubClass != ITEM_SUBCLASS_CONTAINER))
continue;
for(uint32 j = 0; j < pBag->GetBagSize(); j++)
{
if( inv_bags[t-INVENTORY_SLOT_BAG_START][j] == 0 )
@ -12600,10 +12636,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
@ -12728,10 +12764,18 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
if ( getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) )
GiveXP( XP , NULL );
else
ModifyMoney( int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)) );
{
int32 money = int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY));
ModifyMoney( money );
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, money);
}
// Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative
ModifyMoney( pQuest->GetRewOrReqMoney() );
if(pQuest->GetRewOrReqMoney())
{
ModifyMoney( pQuest->GetRewOrReqMoney() );
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney());
}
// honor reward
if(pQuest->GetRewHonorableKills())
@ -13762,28 +13806,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;
}
}
}
@ -14323,6 +14360,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());
@ -14332,7 +14377,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();
@ -14345,6 +14390,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
@ -15131,7 +15186,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;
@ -15557,9 +15612,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;
}
@ -15818,6 +15875,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
@ -15992,11 +16050,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;
@ -16679,7 +16737,7 @@ void Player::PetSpellInitialize()
time_t cooldown = 0;
if(itr->second > curTime)
cooldown = (itr->second - curTime) * 1000;
cooldown = (itr->second - curTime) * IN_MILISECONDS;
data << uint32(itr->first); // spellid
data << uint16(0); // spell category?
@ -16692,7 +16750,7 @@ void Player::PetSpellInitialize()
time_t cooldown = 0;
if(itr->second > curTime)
cooldown = (itr->second - curTime) * 1000;
cooldown = (itr->second - curTime) * IN_MILISECONDS;
data << uint32(itr->first); // spellid
data << uint16(0); // spell category?
@ -17167,6 +17225,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
//Checks and preparations done, DO FLIGHT
ModifyMoney(-(int32)totalcost);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING, totalcost);
// prevent stealth flight
RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
@ -17209,7 +17268,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);
@ -17576,6 +17635,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;
@ -17584,25 +17739,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)
{
@ -18479,7 +18650,7 @@ BGQueueIdBasedOnLevel Player::GetBattleGroundQueueIdFromLevel(BattleGroundTypeId
float Player::GetReputationPriceDiscount( Creature const* pCreature ) const
{
FactionTemplateEntry const* vendor_faction = pCreature->getFactionTemplateEntry();
if(!vendor_faction)
if(!vendor_faction || !vendor_faction->faction)
return 1.0f;
ReputationRank rank = GetReputationRank(vendor_faction->faction);
@ -18626,8 +18797,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;
@ -18639,7 +18810,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);
}
}
@ -19070,7 +19250,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 );
}

View file

@ -1509,14 +1509,17 @@ class MANGOS_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)
{
@ -1998,7 +2001,7 @@ class MANGOS_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;};
@ -2029,6 +2032,8 @@ class MANGOS_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); }
@ -2297,6 +2302,7 @@ class MANGOS_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;
@ -2445,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;

View file

@ -192,8 +192,8 @@ void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data )
data << uint32(ci->DisplayID_A2); // modelid_male2 ?
data << uint32(ci->DisplayID_H2); // modelid_femmale2 ?
data << uint32(0); // new in 3.1
data << float(1.0f); // unk
data << float(1.0f); // unk
data << float(ci->unk16); // unk
data << float(ci->unk17); // unk
data << uint8(ci->RacialLeader);
for(uint32 i = 0; i < 4; ++i)
data << uint32(0); // added in 3.1

View file

@ -73,59 +73,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[55+i].GetInt32();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
ReqCreatureOrGOId[i] = questRecord[59+i].GetInt32();
ReqCreatureOrGOCount[i] = questRecord[59+i].GetUInt32();
for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
ReqCreatureOrGOCount[i] = questRecord[63+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();
RewRepValue[i] = questRecord[92+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();
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;

View file

@ -229,7 +229,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];

View file

@ -46,7 +46,7 @@
#include "BattleGround.h"
#include "Util.h"
#define SPELL_CHANNEL_UPDATE_INTERVAL 1000
#define SPELL_CHANNEL_UPDATE_INTERVAL (1*IN_MILISECONDS)
extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
@ -2520,93 +2520,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)
// mana/health potions, disabled by client
if (m_spellInfo->Category==SPELLCATEGORY_HEALTH_MANA_POTIONS)
{
_player->AddSpellCooldown(m_spellInfo->Id, 0, time(NULL) - 1);
// need in some way provided data for Spell::finish SendCooldownEvent
if(m_CastItem)
_player->SetLastPotionId(m_CastItem->GetEntry());
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)
{
ItemPrototype const* proto = m_CastItem->GetProto();
if(proto)
{
for(int idx = 0; idx < MAX_ITEM_PROTO_SPELLS; ++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;
}
// 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)
@ -2797,6 +2725,10 @@ void Spell::finish(bool ok)
((Player*)m_caster)->ClearComboPoints();
}
// 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)
if(!m_TriggerSpells.empty())
TriggerSpell();
@ -3818,7 +3750,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;

View file

@ -204,7 +204,7 @@ enum SpellState
SPELL_STATE_DELAYED = 5
};
#define SPELL_SPELL_CHANNEL_UPDATE_INTERVAL 1000
#define SPELL_SPELL_CHANNEL_UPDATE_INTERVAL (1*IN_MILISECONDS)
typedef std::multimap<uint64, uint64> SpellTargetTimeMap;

View file

@ -581,7 +581,7 @@ void Aura::Update(uint32 diff)
{
Powers powertype = Powers(m_spellProto->powerType);
int32 manaPerSecond = m_spellProto->manaPerSecond + m_spellProto->manaPerSecondPerLevel * caster->getLevel();
m_timeCla = 1000;
m_timeCla = 1*IN_MILISECONDS;
if (manaPerSecond)
{
if(powertype==POWER_HEALTH)
@ -940,6 +940,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
if((!m_isPassive || (caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem())) &&
@ -1122,6 +1132,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());
}
}
@ -2067,22 +2078,6 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
m_modifier.m_amount = caster->SpellHealingBonus(m_target, GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE);
return;
}
// some auras applied at aura apply
if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER)
{
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
if(saBounds.first != saBounds.second)
{
uint32 zone = m_target->GetZoneId();
uint32 area = m_target->GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if(itr->second->autocast && itr->second->IsFitToRequirements((Player*)m_target,zone,area))
if( !m_target->HasAura(itr->second->spellId,0) )
m_target->CastSpell(m_target,itr->second->spellId,true);
}
}
}
// AT REMOVE
else
@ -2128,30 +2123,29 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
return;
}
// Waiting to Resurrect
if(GetId()==2584)
switch(GetId())
{
// Waiting to resurrect spell cancel, we must remove player from resurrect queue
if(m_target->GetTypeId() == TYPEID_PLAYER)
if(BattleGround *bg = ((Player*)m_target)->GetBattleGround())
bg->RemovePlayerFromResurrectQueue(m_target->GetGUID());
return;
}
// Dark Fiend
if(GetId()==45934)
{
// Kill target if dispelled
if (m_removeMode==AURA_REMOVE_BY_DISPEL)
m_target->DealDamage(m_target, m_target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
return;
}
// Burning Winds
if(GetId()==46308) // casted only at creatures at spawn
{
m_target->CastSpell(m_target,47287,true,NULL,this);
return;
case 2584: // Waiting to Resurrect
{
// Waiting to resurrect spell cancel, we must remove player from resurrect queue
if(m_target->GetTypeId() == TYPEID_PLAYER)
if(BattleGround *bg = ((Player*)m_target)->GetBattleGround())
bg->RemovePlayerFromResurrectQueue(m_target->GetGUID());
return;
}
case 45934: // Dark Fiend
{
// Kill target if dispelled
if (m_removeMode==AURA_REMOVE_BY_DISPEL)
m_target->DealDamage(m_target, m_target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
return;
}
case 46308: // Burning Winds
{
// casted only at creatures at spawn
m_target->CastSpell(m_target,47287,true,NULL,this);
return;
}
}
if (caster && m_removeMode == AURA_REMOVE_BY_DEATH)
@ -2172,21 +2166,6 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
}
}
// some auras remove at aura remove
if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER)
{
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
if(saBounds.first != saBounds.second)
{
uint32 zone = m_target->GetZoneId();
uint32 area = m_target->GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
if(!itr->second->IsFitToRequirements((Player*)m_target,zone,area))
m_target->RemoveAurasDueToSpell(itr->second->spellId);
}
}
}
// AT APPLY & REMOVE
@ -2411,6 +2390,29 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
m_target->RemovePetAura(petSpell);
return;
}
if(GetEffIndex()==0 && m_target->GetTypeId()==TYPEID_PLAYER)
{
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
if(saBounds.first != saBounds.second)
{
uint32 zone = m_target->GetZoneId();
uint32 area = m_target->GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
{
// some auras remove at aura remove
if(!itr->second->IsFitToRequirements((Player*)m_target,zone,area))
m_target->RemoveAurasDueToSpell(itr->second->spellId);
// some auras applied at aura apply
else if(itr->second->autocast)
{
if( !m_target->HasAura(itr->second->spellId,0) )
m_target->CastSpell(m_target,itr->second->spellId,true);
}
}
}
}
}
void Aura::HandleAuraMounted(bool apply, bool Real)
@ -2833,7 +2835,7 @@ void Aura::HandleAuraTransform(bool apply, bool Real)
// for players, start regeneration after 1s (in polymorph fast regeneration case)
// only if caster is Player (after patch 2.4.2)
if(IS_PLAYER_GUID(GetCasterGUID()) )
((Player*)m_target)->setRegenTimer(1000);
((Player*)m_target)->setRegenTimer(1*IN_MILISECONDS);
//dismount polymorphed target (after patch 2.4.2)
if (m_target->IsMounted())
@ -6683,6 +6685,29 @@ void Aura::HandlePhase(bool apply, bool Real)
m_target->SetPhaseMask(apply ? GetMiscValue() : PHASEMASK_NORMAL,false);
((Player*)m_target)->GetSession()->SendSetPhaseShift(apply ? GetMiscValue() : PHASEMASK_NORMAL);
if(GetEffIndex()==0)
{
SpellAreaForAreaMapBounds saBounds = spellmgr.GetSpellAreaForAuraMapBounds(GetId());
if(saBounds.first != saBounds.second)
{
uint32 zone = m_target->GetZoneId();
uint32 area = m_target->GetAreaId();
for(SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
{
// some auras remove at aura remove
if(!itr->second->IsFitToRequirements((Player*)m_target,zone,area))
m_target->RemoveAurasDueToSpell(itr->second->spellId);
// some auras applied at aura apply
else if(itr->second->autocast)
{
if( !m_target->HasAura(itr->second->spellId,0) )
m_target->CastSpell(m_target,itr->second->spellId,true);
}
}
}
}
}
else
m_target->SetPhaseMask(apply ? GetMiscValue() : PHASEMASK_NORMAL,false);

View file

@ -593,7 +593,7 @@ void Spell::EffectSchoolDMG(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;
}
@ -1109,7 +1109,23 @@ void Spell::EffectDummy(uint32 i)
{
m_caster->CastSpell(m_caster,54586,true);
return;
}
}
case 58418: // Portal to Orgrimmar
{
if(!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 58419, true);
break;
}
case 58420: // Portal to Stormwind
{
if(!unitTarget)
return;
unitTarget->CastSpell(unitTarget, 58421, true);
break;
}
}
//All IconID Check in there
@ -3416,7 +3432,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)
@ -3487,7 +3503,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);
}
}
@ -4578,7 +4594,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)...
@ -4621,7 +4637,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);
@ -5246,7 +5262,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);
@ -5323,7 +5339,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);
}
@ -5507,7 +5523,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);
}
}
@ -5638,7 +5654,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);
@ -6254,7 +6270,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:
@ -6274,7 +6290,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() );
@ -6297,7 +6313,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() );

View file

@ -2387,7 +2387,7 @@ void SpellMgr::LoadSpellAreas()
spellArea.questStart = fields[2].GetUInt32();
spellArea.questStartCanActive = fields[3].GetBool();
spellArea.questEnd = fields[4].GetUInt32();
spellArea.auraSpell = fields[5].GetUInt32();
spellArea.auraSpell = fields[5].GetInt32();
spellArea.raceMask = fields[6].GetUInt32();
spellArea.gender = Gender(fields[7].GetUInt8());
spellArea.autocast = fields[8].GetBool();
@ -2398,10 +2398,35 @@ void SpellMgr::LoadSpellAreas()
continue;
}
if(mSpellAreaForAuraMap.find(spellArea.spellId)!=mSpellAreaForAuraMap.end())
{
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement that already listed in table itself", spell,spellArea.auraSpell);
continue;
bool ok = true;
SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId);
for(SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr)
{
if(spellArea.spellId && itr->second.spellId && spellArea.spellId != itr->second.spellId)
continue;
if(spellArea.areaId && itr->second.areaId && spellArea.areaId!= itr->second.areaId)
continue;
if(spellArea.questStart && itr->second.questStart && spellArea.questStart!= itr->second.questStart)
continue;
if(spellArea.auraSpell && itr->second.auraSpell && spellArea.auraSpell!= itr->second.auraSpell)
continue;
if(spellArea.raceMask && itr->second.raceMask && (spellArea.raceMask & itr->second.raceMask)==0)
continue;
if(spellArea.gender != GENDER_NONE && itr->second.gender != GENDER_NONE && spellArea.gender!= itr->second.gender)
continue;
// duplicate by requirements
ok =false;
break;
}
if(!ok)
{
sLog.outErrorDb("Spell %u listed in `spell_area` already listed with similar requirements.", spell);
continue;
}
}
if(spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId))
@ -2433,33 +2458,33 @@ void SpellMgr::LoadSpellAreas()
if(spellArea.auraSpell)
{
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellArea.auraSpell);
SpellEntry const* spellInfo = sSpellStore.LookupEntry(abs(spellArea.auraSpell));
if(!spellInfo)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell,spellArea.auraSpell);
sLog.outErrorDb("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell,abs(spellArea.auraSpell));
continue;
}
if(spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_DUMMY)
if(spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_DUMMY && spellInfo->EffectApplyAuraName[0]!=SPELL_AURA_PHASE)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy aura in effect 0", spell,spellArea.auraSpell);
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell requirement (%u) without dummy/phase aura in effect 0", spell,abs(spellArea.auraSpell));
continue;
}
if(spellArea.auraSpell==spellArea.spellId)
if(abs(spellArea.auraSpell)==spellArea.spellId)
{
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell,spellArea.auraSpell);
sLog.outErrorDb("Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell,abs(spellArea.auraSpell));
continue;
}
// not allow autocast chains by auraSpell field
if(spellArea.autocast)
// not allow autocast chains by auraSpell field (but allow use as alternative if not present)
if(spellArea.autocast && spellArea.auraSpell > 0)
{
bool chain = false;
SpellAreaForAuraMapBounds saBound = GetSpellAreaForAuraMapBounds(spellArea.spellId);
for(SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr)
{
if(itr->second->autocast)
if(itr->second->autocast && itr->second->auraSpell > 0)
{
chain = true;
break;
@ -2475,7 +2500,7 @@ void SpellMgr::LoadSpellAreas()
SpellAreaMapBounds saBound2 = GetSpellAreaMapBounds(spellArea.auraSpell);
for(SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2)
{
if(itr2->second.autocast && itr2->second.auraSpell)
if(itr2->second.autocast && itr2->second.auraSpell > 0)
{
chain = true;
break;
@ -2523,7 +2548,7 @@ void SpellMgr::LoadSpellAreas()
// for search at aura apply
if(spellArea.auraSpell)
mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(spellArea.auraSpell,sa));
mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell),sa));
++count;
} while( result->NextRow() );
@ -2810,8 +2835,14 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32
if(auraSpell)
{
// not have expected aura
if(!player || !player->HasAura(auraSpell,0))
if(!player)
return false;
if(auraSpell > 0)
// have expected aura
return player->HasAura(auraSpell,0);
else
// not have expected aura
return !player->HasAura(-auraSpell,0);
}
return true;

View file

@ -223,6 +223,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,
@ -683,7 +690,7 @@ struct SpellArea
uint32 areaId; // zone/subzone/or 0 is not limited to zone
uint32 questStart; // quest start (quest must be active or rewarded for spell apply)
uint32 questEnd; // quest end (quest don't must be rewarded for spell apply)
uint32 auraSpell; // spell aura must be applied for spell apply
int32 auraSpell; // spell aura must be applied for spell apply )if possitive) and it don't must be applied in other case
uint32 raceMask; // can be applied only to races
Gender gender; // can be applied only to gender
bool questStartCanActive; // if true then quest start can be active (not only rewarded)

View file

@ -516,6 +516,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->isPet() && !((Creature*)pVictim)->hasLootRecipient())
((Creature*)pVictim)->SetLootRecipient(this);
if (health <= damage)
{
DEBUG_LOG("DealDamage: victim just died");
@ -592,12 +593,12 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
((Creature*)this)->AI()->KilledUnit(pVictim);
// achievement stuff
if ( pVictim->GetTypeId() == TYPEID_PLAYER)
if (pVictim->GetTypeId() == TYPEID_PLAYER)
{
if(GetTypeId() == TYPEID_UNIT)
if (GetTypeId() == TYPEID_UNIT)
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
else if(GetTypeId() == TYPEID_PLAYER)
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1);
else if(GetTypeId() == TYPEID_PLAYER && pVictim != this)
((Player*)pVictim)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, ((Player*)this)->GetTeam());
}
// 10% durability loss on death
@ -3679,7 +3680,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 );
@ -3987,7 +3988,7 @@ void Unit::RemoveDynObject(uint32 spellid)
return;
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
{
DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin());
DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*i);
if(!dynObj)
{
i = m_dynObjGUIDs.erase(i);
@ -4017,7 +4018,7 @@ DynamicObject * Unit::GetDynObject(uint32 spellId, uint32 effIndex)
{
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
{
DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin());
DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*i);
if(!dynObj)
{
i = m_dynObjGUIDs.erase(i);
@ -4035,7 +4036,7 @@ DynamicObject * Unit::GetDynObject(uint32 spellId)
{
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
{
DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*m_dynObjGUIDs.begin());
DynamicObject* dynObj = ObjectAccessor::GetDynamicObject(*this,*i);
if(!dynObj)
{
i = m_dynObjGUIDs.erase(i);
@ -4054,6 +4055,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)
@ -4066,6 +4076,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);
@ -6905,28 +6916,34 @@ bool Unit::IsHostileTo(Unit const* unit) const
if(tester->GetTypeId()==TYPEID_PLAYER)
{
// forced reaction
ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
if(forceItr!=((Player*)tester)->m_forcedReactions.end())
return forceItr->second <= REP_HOSTILE;
if(target_faction->faction)
{
ForcedReactions::const_iterator forceItr = ((Player*)tester)->m_forcedReactions.find(target_faction->faction);
if(forceItr!=((Player*)tester)->m_forcedReactions.end())
return forceItr->second <= REP_HOSTILE;
// if faction have reputation then hostile state for tester at 100% dependent from at_war state
if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
if(raw_target_faction->reputationListID >=0)
if(FactionState const* factionState = ((Player*)tester)->GetFactionState(raw_target_faction))
return (factionState->Flags & FACTION_FLAG_AT_WAR);
// if faction have reputation then hostile state for tester at 100% dependent from at_war state
if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
if(raw_target_faction->reputationListID >=0)
if(FactionState const* factionState = ((Player*)tester)->GetFactionState(raw_target_faction))
return (factionState->Flags & FACTION_FLAG_AT_WAR);
}
}
// CvP forced reaction and reputation case
else if(target->GetTypeId()==TYPEID_PLAYER)
{
// forced reaction
ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction);
if(forceItr!=((Player const*)target)->m_forcedReactions.end())
return forceItr->second <= REP_HOSTILE;
if(tester_faction->faction)
{
ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction);
if(forceItr!=((Player const*)target)->m_forcedReactions.end())
return forceItr->second <= REP_HOSTILE;
// apply reputation state
FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
return ((Player const*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE;
// apply reputation state
FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction);
if(raw_tester_faction && raw_tester_faction->reputationListID >=0 )
return ((Player const*)target)->GetReputationRank(raw_tester_faction) <= REP_HOSTILE;
}
}
// common faction based case (CvC,PvC,CvP)
@ -7014,28 +7031,34 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
if(tester->GetTypeId()==TYPEID_PLAYER)
{
// forced reaction
ForcedReactions::const_iterator forceItr = ((Player const*)tester)->m_forcedReactions.find(target_faction->faction);
if(forceItr!=((Player const*)tester)->m_forcedReactions.end())
return forceItr->second >= REP_FRIENDLY;
if(target_faction->faction)
{
ForcedReactions::const_iterator forceItr = ((Player const*)tester)->m_forcedReactions.find(target_faction->faction);
if(forceItr!=((Player const*)tester)->m_forcedReactions.end())
return forceItr->second >= REP_FRIENDLY;
// if faction have reputation then friendly state for tester at 100% dependent from at_war state
if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
if(raw_target_faction->reputationListID >=0)
if(FactionState const* FactionState = ((Player*)tester)->GetFactionState(raw_target_faction))
return !(FactionState->Flags & FACTION_FLAG_AT_WAR);
// if faction have reputation then friendly state for tester at 100% dependent from at_war state
if(FactionEntry const* raw_target_faction = sFactionStore.LookupEntry(target_faction->faction))
if(raw_target_faction->reputationListID >=0)
if(FactionState const* FactionState = ((Player*)tester)->GetFactionState(raw_target_faction))
return !(FactionState->Flags & FACTION_FLAG_AT_WAR);
}
}
// CvP forced reaction and reputation case
else if(target->GetTypeId()==TYPEID_PLAYER)
{
// forced reaction
ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction);
if(forceItr!=((Player const*)target)->m_forcedReactions.end())
return forceItr->second >= REP_FRIENDLY;
if(tester_faction->faction)
{
ForcedReactions::const_iterator forceItr = ((Player const*)target)->m_forcedReactions.find(tester_faction->faction);
if(forceItr!=((Player const*)target)->m_forcedReactions.end())
return forceItr->second >= REP_FRIENDLY;
// apply reputation state
if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction))
if(raw_tester_faction->reputationListID >=0 )
return ((Player const*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY;
// apply reputation state
if(FactionEntry const* raw_tester_faction = sFactionStore.LookupEntry(tester_faction->faction))
if(raw_tester_faction->reputationListID >=0 )
return ((Player const*)target)->GetReputationRank(raw_tester_faction) >= REP_FRIENDLY;
}
}
// common faction based case (CvC,PvC,CvP)
@ -7045,7 +7068,7 @@ bool Unit::IsFriendlyTo(Unit const* unit) const
bool Unit::IsHostileToPlayers() const
{
FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
if(!my_faction)
if(!my_faction || !my_faction->faction)
return false;
FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
@ -7058,7 +7081,7 @@ bool Unit::IsHostileToPlayers() const
bool Unit::IsNeutralToAll() const
{
FactionTemplateEntry const* my_faction = getFactionTemplateEntry();
if(!my_faction)
if(!my_faction || !my_faction->faction)
return true;
FactionEntry const* raw_faction = sFactionStore.LookupEntry(my_faction->faction);
@ -8575,6 +8598,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();
}
bool Unit::isTargetableForAttack() const
@ -11331,4 +11356,4 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
if(IsInWorld())
if(Pet* pet = GetPet())
pet->SetPhaseMask(newPhaseMask,true);
}
}

View file

@ -36,7 +36,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

View file

@ -552,9 +552,9 @@ void World::LoadConfigSettings(bool reload)
}
m_configs[CONFIG_ADDON_CHANNEL] = sConfig.GetBoolDefault("AddonChannel", true);
m_configs[CONFIG_GRID_UNLOAD] = sConfig.GetBoolDefault("GridUnload", true);
m_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 900000);
m_configs[CONFIG_INTERVAL_SAVE] = sConfig.GetIntDefault("PlayerSaveInterval", 15 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfig.GetIntDefault("GridCleanUpDelay", 300000);
m_configs[CONFIG_INTERVAL_GRIDCLEAN] = sConfig.GetIntDefault("GridCleanUpDelay", 5 * MINUTE * IN_MILISECONDS);
if(m_configs[CONFIG_INTERVAL_GRIDCLEAN] < MIN_GRID_DELAY)
{
sLog.outError("GridCleanUpDelay (%i) must be greater %u. Use this minimal value.",m_configs[CONFIG_INTERVAL_GRIDCLEAN],MIN_GRID_DELAY);
@ -572,7 +572,7 @@ void World::LoadConfigSettings(bool reload)
if(reload)
MapManager::Instance().SetMapUpdateInterval(m_configs[CONFIG_INTERVAL_MAPUPDATE]);
m_configs[CONFIG_INTERVAL_CHANGEWEATHER] = sConfig.GetIntDefault("ChangeWeatherInterval", 600000);
m_configs[CONFIG_INTERVAL_CHANGEWEATHER] = sConfig.GetIntDefault("ChangeWeatherInterval", 10 * MINUTE * IN_MILISECONDS);
if(reload)
{
@ -764,7 +764,7 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true);
m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4);
m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 1800000);
m_configs[CONFIG_INSTANCE_UNLOAD_DELAY] = sConfig.GetIntDefault("Instance.UnloadDelay", 30 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_MAX_PRIMARY_TRADE_SKILL] = sConfig.GetIntDefault("MaxPrimaryTradeSkill", 2);
m_configs[CONFIG_MIN_PETITION_SIGNS] = sConfig.GetIntDefault("MinPetitionSigns", 9);
@ -811,7 +811,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();
}
@ -932,7 +932,7 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_BATTLEGROUND_INVITATION_TYPE] = sConfig.GetIntDefault ("Battleground.InvitationType", 0);
m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault ("BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH] = sConfig.GetIntDefault ("BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault ("Arena.MaxRatingDifference", 100);
m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault ("Arena.MaxRatingDifference", 150);
m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault ("Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILISECONDS);
m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);
m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault ("Arena.AutoDistributeInterval", 7);
@ -940,6 +940,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);
@ -1365,18 +1367,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

View file

@ -195,6 +195,7 @@ enum WorldConfigs
CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE,
CONFIG_ARENA_SEASON_ID,
CONFIG_ARENA_SEASON_IN_PROGRESS,
CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET,
CONFIG_VALUE_COUNT
};

View file

@ -94,7 +94,7 @@ BindIP = "0.0.0.0"
#
# SocketSelectTime
# Socket select time (in milliseconds)
# Default: 10000
# Default: 10000 (10 secs)
#
# GridCleanUpDelay
# Grid clean up delay (in milliseconds)
@ -115,8 +115,8 @@ BindIP = "0.0.0.0"
# vmap.enableLOS
# vmap.enableHeight
# Enable/Disable VMmap support for line of sight and height calculation
# Default: 1 (true)
# 0 (false)
# Default: 0 (disable)
# 1 (enable)
#
# vmap.ignoreMapIds
# Map id that will be ignored by VMaps
@ -504,7 +504,7 @@ LogColors = ""
#
# Instance.UnloadDelay
# Unload the instance map from memory after some time if no players are inside.
# Default: 1800000 (miliseconds, i.e 30 minutes)
# Default: 1800000 (miliseconds 30 minutes)
# 0 (instance maps are kept in memory until they are reset)
#
# Quests.LowLevelHideDiff
@ -546,6 +546,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)
@ -600,6 +605,7 @@ MaxGroupXPDistance = 74
MailDeliveryDelay = 3600
SkillChance.Prospecting = 0
SkillChance.Milling = 0
OffhandCheckAtTalentsReset = 0
Event.Announce = 0
BeepAtStart = 1
Motd = "Welcome to the Massive Network Game Object Server."
@ -835,7 +841,7 @@ Channel.SilentlyGMJoin = 0
# 1 (enable)
#
# GM.InGMList
# Is GM showed in GM list (if visible) in non-GM state (.gmoff)
# Is GM showed in GM list (if visible) in non-GM state (.gm off)
# Default: 0 (false)
# 1 (true)
#
@ -860,8 +866,8 @@ Channel.SilentlyGMJoin = 0
#
# GM.AllowAchievementGain
# If enabled it allows gaining achievements for GM characters
# Default: 0 (disable)
# 1 (enable) (default)
# Default: 1 (enable)
# 0 (disable)
#
###################################################################################################################
@ -1046,7 +1052,7 @@ Visibility.Distance.Grey.Object = 10
#
# Death.Bones.World
# Death.Bones.BattlegroundOrArena
# Enabled/disabled creating bones instead corpse at resurrection (in normal zones/instacnes, or battleground/arenas)
# Enable/disable creating bones instead corpse at resurrection (in normal zones/instacnes, or battleground/arenas)
# Default: 1 (enabled)
# 0 (disabled)
#
@ -1110,19 +1116,19 @@ Death.Bones.BattlegroundOrArena = 1
# BATTLEGROUND CONFIG
#
# Battleground.CastDeserter
# Cast or not Deserter spell at player who leave battleground in progress
# Default: 1 (true)
# 0 (false)
# Cast Deserter spell at player who leave battleground in progress
# Default: 1 (enable)
# 0 (disable)
#
# Battleground.QueueAnnouncer.Enable
# Enable queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
# Default: 0 (disable)
# 1 (enable)
#
# Battleground.QueueAnnouncer.PlayerOnly
# Enable queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
# Default: 0 (disable)
# 1 (enable)
#
# Battleground.InvitationType
# Set Battleground invitation type
@ -1154,7 +1160,7 @@ BattleGround.PremadeGroupWaitForMatch = 1800000
#
# Arena.MaxRatingDifference
# The maximum rating difference between two groups in rated matches
# Default: 100 (enable, recommended)
# Default: 150 (enable, recommended)
# 0 (disable, rating difference is discarded)
#
# Arena.RatingDiscardTimer
@ -1162,7 +1168,7 @@ BattleGround.PremadeGroupWaitForMatch = 1800000
# rating information will be discarded when selecting teams for matches
# also initiates an update by this timer
# Default: 600000 (10 minutes, recommended)
# 0 (disable, DO NOT USE - it will cause lags)
# 0 (disable)
#
# Arena.AutoDistributePoints
# Set if arena points should be distributed automatically, or by GM command
@ -1176,8 +1182,8 @@ BattleGround.PremadeGroupWaitForMatch = 1800000
#
# Arena.QueueAnnouncer.Enable
# Enable bg queue announcer posting to chat
# Default: 0 (false)
# 1 (true)
# Default: 0 (disable)
# 1 (enable)
#
# Arena.ArenaSeason.ID
# Current area season id show in client
@ -1190,7 +1196,7 @@ BattleGround.PremadeGroupWaitForMatch = 1800000
#
###################################################################################################################
Arena.MaxRatingDifference = 100
Arena.MaxRatingDifference = 150
Arena.RatingDiscardTimer = 600000
Arena.AutoDistributePoints = 0
Arena.AutoDistributeInterval = 7

View file

@ -158,6 +158,7 @@ enum TimeConstants
HOUR = MINUTE*60,
DAY = HOUR*24,
MONTH = DAY*30,
YEAR = MONTH*12,
IN_MILISECONDS = 1000
};

View file

@ -72,7 +72,7 @@ struct AchievementCriteriaEntry
uint32 requiredType; // 2
union
{
// ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0
// ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE = 0
// TODO: also used for player deaths..
struct
{
@ -80,7 +80,7 @@ struct AchievementCriteriaEntry
uint32 creatureCount; // 4
} kill_creature;
// ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1
// ACHIEVEMENT_CRITERIA_TYPE_WIN_BG = 1
// TODO: there are further criterias instead just winning
struct
{
@ -88,27 +88,27 @@ struct AchievementCriteriaEntry
uint32 winCount; // 4
} win_bg;
// ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5
// ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5
struct
{
uint32 unused; // 3
uint32 level; // 4
} reach_level;
// ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7
// ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL = 7
struct
{
uint32 skillID; // 3
uint32 skillLevel; // 4
} reach_skill_level;
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT = 8
struct
{
uint32 linkedAchievement; // 3
} complete_achievement;
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT = 9
struct
{
uint32 unused; // 3
@ -129,67 +129,73 @@ struct AchievementCriteriaEntry
uint32 questCount; // 4
} complete_quests_in_zone;
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST = 14
struct
{
uint32 unused; // 3
uint32 questCount; // 4
} complete_daily_quest;
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND= 15
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND = 15
struct
{
uint32 mapID; // 3
} complete_battleground;
// ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP= 16
// ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP = 16
struct
{
uint32 mapID; // 3
} death_at_map;
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19
// ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON = 18
struct
{
uint32 manLimit; // 3
} death_in_dungeon;
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID = 19
struct
{
uint32 groupSize; // 3 can be 5, 10 or 25
} complete_raid;
// ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20
// ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE = 20
struct
{
uint32 creatureEntry; // 3
} killed_by_creature;
// ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24
// ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING = 24
struct
{
uint32 unused; // 3
uint32 fallHeight; // 4
} fall_without_dying;
// ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26
// ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM = 26
struct
{
uint32 type; // 0 - fatigue, 1 - drowning, 2 - falling, 3 - ??, 5 - fire and lava
} deaths;
uint32 type; // 3, see enum EnviromentalDamage
} death_from;
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST = 27
struct
{
uint32 questID; // 3
uint32 questCount; // 4
} complete_quest;
// ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28
// ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2= 69
// ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET = 28
// ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 = 69
struct
{
uint32 spellID; // 3
uint32 spellCount; // 4
} be_spell_target;
// ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL= 29
// ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110
// ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL = 29
// ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 = 110
struct
{
uint32 spellID; // 3
@ -203,32 +209,32 @@ struct AchievementCriteriaEntry
uint32 killCount; // 4
} honorable_kill_at_area;
// ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32
// ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA = 32
struct
{
uint32 mapID; // 3 Reference to Map.dbc
} win_arena;
// ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33
// ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA = 33
struct
{
uint32 mapID; // 3 Reference to Map.dbc
} play_arena;
// ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34
// ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL = 34
struct
{
uint32 spellID; // 3 Reference to Map.dbc
} learn_spell;
// ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36
// ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM = 36
struct
{
uint32 itemID; // 3
uint32 itemCount; // 4
} own_item;
// ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37
// ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA = 37
struct
{
uint32 unused; // 3
@ -236,62 +242,62 @@ struct AchievementCriteriaEntry
uint32 flag; // 5 4=in a row
} win_rated_arena;
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING = 38
struct
{
uint32 teamtype; // 3 {2,3,5}
} highest_team_rating;
// ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39
// ACHIEVEMENT_CRITERIA_TYPE_REACH_TEAM_RATING = 39
struct
{
uint32 teamtype; // 3 {2,3,5}
uint32 teamrating; // 4
} reach_team_rating;
// ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40
// ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL = 40
struct
{
uint32 skillID; // 3
uint32 skillLevel; // 4 apprentice=1, journeyman=2, expert=3, artisan=4, master=5, grand master=6
} learn_skill_level;
// ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41
// ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM = 41
struct
{
uint32 itemID; // 3
uint32 itemCount; // 4
} use_item;
// ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42
// ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM = 42
struct
{
uint32 itemID; // 3
uint32 itemCount; // 4
} loot_item;
// ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43
// ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA = 43
struct
{
// TODO: This rank is _NOT_ the index from AreaTable.dbc
uint32 areaReference; // 3
} explore_area;
// ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK= 44
// ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK = 44
struct
{
// TODO: This rank is _NOT_ the index from CharTitles.dbc
uint32 rank; // 3
} own_rank;
// ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT= 45
// ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT = 45
struct
{
uint32 unused; // 3
uint32 numberOfSlots; // 4
} buy_bank_slot;
// ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION= 46
// ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION = 46
struct
{
uint32 factionID; // 3
@ -305,56 +311,56 @@ struct AchievementCriteriaEntry
uint32 numberOfExaltedFactions; // 4
} gain_exalted_reputation;
// ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48
// ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP = 48
struct
{
uint32 unused; // 3
uint32 numberOfVisits; // 4
} visit_barber;
// ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49
// ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM = 49
// TODO: where is the required itemlevel stored?
struct
{
uint32 itemSlot; // 3
} equip_epic_item;
// ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT= 50
// ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT = 50
struct
{
uint32 rollValue; // 3
uint32 count; // 4
} roll_need_on_loot;
// ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT= 51
// ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT = 51
struct
{
uint32 rollValue; // 3
uint32 count; // 4
} roll_greed_on_loot;
// ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52
// ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS = 52
struct
{
uint32 classID; // 3
uint32 count; // 4
} hk_class;
// ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53
// ACHIEVEMENT_CRITERIA_TYPE_HK_RACE = 53
struct
{
uint32 raceID; // 3
uint32 count; // 4
} hk_race;
// ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54
// ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE = 54
// TODO: where is the information about the target stored?
struct
{
uint32 emoteID; // 3
} do_emote;
// ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13
// ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55
// ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56
// ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13
// ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55
// ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56
struct
{
uint32 unused; // 3
@ -363,28 +369,35 @@ struct AchievementCriteriaEntry
uint32 mapid; // 6
} healing_done;
// ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57
// ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57
struct
{
uint32 itemID; // 3
} equip_item;
// ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD= 62
struct
{
uint32 unused; // 3
uint32 goldInCopper; // 4
} quest_reward_money;
// ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67
// ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY = 67
struct
{
uint32 unused; // 3
uint32 goldInCopper; // 4
} loot_money;
// ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68
// ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT = 68
struct
{
uint32 goEntry; // 3
uint32 useCount; // 4
} use_gameobject;
// ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL= 70
// ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70
// TODO: are those special criteria stored in the dbc or do we have to add another sql table?
struct
{
@ -392,66 +405,66 @@ struct AchievementCriteriaEntry
uint32 killCount; // 4
} special_pvp_kill;
// ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72
// ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72
struct
{
uint32 goEntry; // 3
uint32 lootCount; // 4
} fish_in_gameobject;
// ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS= 75
// ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75
struct
{
uint32 skillLine; // 3
uint32 spellCount; // 4
} learn_skilline_spell;
// ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76
// ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76
struct
{
uint32 unused; // 3
uint32 duelCount; // 4
} win_duel;
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER = 96
struct
{
uint32 powerType; // 3 mana=0, 1=rage, 3=energy, 6=runic power
} highest_power;
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT = 97
struct
{
uint32 statType; // 3 4=spirit, 3=int, 2=stamina, 1=agi, 0=strength
} highest_stat;
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER = 98
struct
{
uint32 spellSchool; // 3
} highest_spellpower;
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100
// ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING = 100
struct
{
uint32 ratingType; // 3
} highest_rating;
// ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109
// ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE = 109
struct
{
uint32 lootType; // 3 3=fishing, 2=pickpocket, 4=disentchant
uint32 lootTypeCount; // 4
} loot_type;
// ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE= 112
// ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE = 112
struct
{
uint32 skillLine; // 3
uint32 spellCount; // 4
} learn_skill_line;
// ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113
// ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL = 113
struct
{
uint32 unused; // 3
@ -731,22 +744,38 @@ struct FactionTemplateEntry
// helpers
bool IsFriendlyTo(FactionTemplateEntry const& entry) const
{
if(enemyFaction[0] == entry.faction || enemyFaction[1] == entry.faction || enemyFaction[2] == entry.faction || enemyFaction[3] == entry.faction )
return false;
if(friendFaction[0] == entry.faction || friendFaction[1] == entry.faction || friendFaction[2] == entry.faction || friendFaction[3] == entry.faction )
return true;
if(entry.faction)
{
for(int i = 0; i < 4; ++i)
if (enemyFaction[i] == entry.faction)
return false;
for(int i = 0; i < 4; ++i)
if (friendFaction[i] == entry.faction)
return true;
}
return (friendlyMask & entry.ourMask) || (ourMask & entry.friendlyMask);
}
bool IsHostileTo(FactionTemplateEntry const& entry) const
{
if(enemyFaction[0] == entry.faction || enemyFaction[1] == entry.faction || enemyFaction[2] == entry.faction || enemyFaction[3] == entry.faction )
return true;
if(friendFaction[0] == entry.faction || friendFaction[1] == entry.faction || friendFaction[2] == entry.faction || friendFaction[3] == entry.faction )
return false;
if(entry.faction)
{
for(int i = 0; i < 4; ++i)
if (enemyFaction[i] == entry.faction)
return true;
for(int i = 0; i < 4; ++i)
if (friendFaction[i] == entry.faction)
return false;
}
return (hostileMask & entry.ourMask) != 0;
}
bool IsHostileToPlayers() const { return (hostileMask & FACTION_MASK_PLAYER) !=0; }
bool IsNeutralToAll() const { return hostileMask == 0 && friendlyMask == 0 && enemyFaction[0]==0 && enemyFaction[1]==0 && enemyFaction[2]==0 && enemyFaction[3]==0; }
bool IsNeutralToAll() const
{
for(int i = 0; i < 4; ++i)
if (enemyFaction[i] != 0)
return false;
return hostileMask == 0 && friendlyMask == 0;
}
bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_CONTESTED_GUARD)!=0; }
};

View file

@ -25,8 +25,8 @@ extern DatabasePostgre WorldDatabase;
extern DatabaseMysql WorldDatabase;
#endif
const char CreatureInfosrcfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiilliiis";
const char CreatureInfodstfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiilliiii";
const char CreatureInfosrcfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiis";
const char CreatureInfodstfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiii";
const char CreatureDataAddonInfofmt[]="iiiiiiis";
const char CreatureModelfmt[]="iffbi";
const char CreatureInfoAddonInfofmt[]="iiiiiiis";

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "7361"
#define REVISION_NR "7387"
#endif // __REVISION_NR_H__