Merge commit 'origin/master' into 320

This commit is contained in:
tomrus88 2009-08-15 10:16:27 +04:00
commit 48a470dfc1
23 changed files with 471 additions and 193 deletions

View file

@ -23,7 +23,8 @@ DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` ( CREATE TABLE `db_version` (
`version` varchar(120) default NULL, `version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL,
`required_8342_01_mangos_spell_proc_event` bit(1) default NULL `cache_id` int(10) default '0',
`required_8364_01_mangos_db_version` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
-- --
@ -13591,6 +13592,7 @@ CREATE TABLE `spell_bonus_data` (
LOCK TABLES `spell_bonus_data` WRITE; LOCK TABLES `spell_bonus_data` WRITE;
/*!40000 ALTER TABLE `spell_bonus_data` DISABLE KEYS */; /*!40000 ALTER TABLE `spell_bonus_data` DISABLE KEYS */;
INSERT INTO `spell_bonus_data` VALUES INSERT INTO `spell_bonus_data` VALUES
/* Death Knight */
('48721', '0', '0', '0.04', 'Death Knight - Blood Boil'), ('48721', '0', '0', '0.04', 'Death Knight - Blood Boil'),
('55078', '0', '0', '0.055', 'Death Knight - Blood Plague Dummy Proc'), ('55078', '0', '0', '0.055', 'Death Knight - Blood Plague Dummy Proc'),
('50444', '0', '0', '0.105', 'Death Knight - Corpse Explosion Triggered'), ('50444', '0', '0', '0.105', 'Death Knight - Corpse Explosion Triggered'),
@ -13605,6 +13607,7 @@ INSERT INTO `spell_bonus_data` VALUES
('50536', '0', '0', '0.013', 'Death Knight - Unholy Blight Triggered'), ('50536', '0', '0', '0.013', 'Death Knight - Unholy Blight Triggered'),
('50401', '0', '0', '0', 'Death Knight - Razor Frost'), ('50401', '0', '0', '0', 'Death Knight - Razor Frost'),
('56903', '0', '0', '0', 'Death Knight - Lichflame'), ('56903', '0', '0', '0', 'Death Knight - Lichflame'),
/* Druid */
('5185', '1.6104', '0', '0', 'Druid - Healing Touch'), ('5185', '1.6104', '0', '0', 'Druid - Healing Touch'),
('33763', '0', '0.09518', '0', 'Druid - Lifebloom'), ('33763', '0', '0.09518', '0', 'Druid - Lifebloom'),
('774', '0', '0.37604', '0', 'Druid - Rejuvenation'), ('774', '0', '0.37604', '0', 'Druid - Rejuvenation'),
@ -13621,6 +13624,7 @@ INSERT INTO `spell_bonus_data` VALUES
('8921', '0.1515', '0.13', '0', 'Druid - Moonfire'), ('8921', '0.1515', '0.13', '0', 'Druid - Moonfire'),
('2912', '1', '0', '0', 'Druid - Starfire'), ('2912', '1', '0', '0', 'Druid - Starfire'),
('5176', '0.5714', '0', '0', 'Druid - Wrath'), ('5176', '0.5714', '0', '0', 'Druid - Wrath'),
/* Mage */
('30451', '0.7143', '0', '0', 'Mage - Arcane Blast'), ('30451', '0.7143', '0', '0', 'Mage - Arcane Blast'),
('1449', '0.2128', '0', '0', 'Mage - Arcane Explosion'), ('1449', '0.2128', '0', '0', 'Mage - Arcane Explosion'),
('7268', '0.2857', '0', '0', 'Mage - Arcane Missiles Triggered Spell'), ('7268', '0.2857', '0', '0', 'Mage - Arcane Missiles Triggered Spell'),
@ -13642,6 +13646,7 @@ INSERT INTO `spell_bonus_data` VALUES
('11426', '0.8053', '0', '0', 'Mage - Ice Barrier'), ('11426', '0.8053', '0', '0', 'Mage - Ice Barrier'),
('30455', '0.1429', '0', '0', 'Mage - Ice Lance'), ('30455', '0.1429', '0', '0', 'Mage - Ice Lance'),
('34913','0', '0', '0', 'Mage - Molten Armor Triggered'), ('34913','0', '0', '0', 'Mage - Molten Armor Triggered'),
/* Paladin */
('19750','0.4286', '0', '0', 'Paladin - Flash of Light'), ('19750','0.4286', '0', '0', 'Paladin - Flash of Light'),
('635', '0.7143', '0', '0', 'Paladin - Holy Light'), ('635', '0.7143', '0', '0', 'Paladin - Holy Light'),
('25912', '0.4286', '0', '0', 'Paladin - Holy Shock Triggered Hurt'), ('25912', '0.4286', '0', '0', 'Paladin - Holy Shock Triggered Hurt'),
@ -13662,7 +13667,7 @@ INSERT INTO `spell_bonus_data` VALUES
('25742', '0.07', '0', '0.039', 'Paladin - Seal of Righteousness Dummy Proc'), ('25742', '0.07', '0', '0.039', 'Paladin - Seal of Righteousness Dummy Proc'),
('53595', '0', '0', '0','Paladin - Hammer of the Righteous'), ('53595', '0', '0', '0','Paladin - Hammer of the Righteous'),
('31803', '0', '0.013', '0.15', 'Paladin - Holy Vengeance'), ('31803', '0', '0.013', '0.15', 'Paladin - Holy Vengeance'),
('52042', '0.045', '0', '0', 'Shaman - Healing Stream Totem Triggered Heal'), /* Priest */
('32546', '0.8068', '0', '0', 'Priest - Binding Heal'), ('32546', '0.8068', '0', '0', 'Priest - Binding Heal'),
('34861', '0.402', '0', '0', 'Priest - Circle of Healing'), ('34861', '0.402', '0', '0', 'Priest - Circle of Healing'),
('19236', '0.8068', '0', '0', 'Priest - Desperate Prayer'), ('19236', '0.8068', '0', '0', 'Priest - Desperate Prayer'),
@ -13685,9 +13690,11 @@ INSERT INTO `spell_bonus_data` VALUES
('589', '0', '0.1829', '0', 'Priest - Shadow Word: Pain'), ('589', '0', '0.1829', '0', 'Priest - Shadow Word: Pain'),
('585', '0.714', '0', '0', 'Priest - Smite'), ('585', '0.714', '0', '0', 'Priest - Smite'),
('34914', '0', '0.4', '0', 'Priest - Vampiric Touch'), ('34914', '0', '0.4', '0', 'Priest - Vampiric Touch'),
/* Shaman */
('974', '0.4762', '0', '0', 'Shaman - Earth Shield'), ('974', '0.4762', '0', '0', 'Shaman - Earth Shield'),
('1064', '1.34', '0', '0', 'Shaman - Chain Heal'), ('1064', '1.34', '0', '0', 'Shaman - Chain Heal'),
('331', '1.6106', '0', '0', 'Shaman - Healing Wave'), ('331', '1.6106', '0', '0', 'Shaman - Healing Wave'),
('52042', '0.045', '0', '0', 'Shaman - Healing Stream Totem Triggered Heal'),
('8004', '0.8082', '0', '0', 'Shaman - Lesser Healing Wave'), ('8004', '0.8082', '0', '0', 'Shaman - Lesser Healing Wave'),
('61295', '0.4', '0.18', '0', 'Shaman - Riptide'), ('61295', '0.4', '0.18', '0', 'Shaman - Riptide'),
('421', '0.57', '0', '0', 'Shaman - Chain Lightning'), ('421', '0.57', '0', '0', 'Shaman - Chain Lightning'),
@ -13702,6 +13709,7 @@ INSERT INTO `spell_bonus_data` VALUES
('26364', '0.33', '0', '0', 'Shaman - Lightning Shield Proc'), ('26364', '0.33', '0', '0', 'Shaman - Lightning Shield Proc'),
('8188', '0.1', '0', '0', 'Shaman - Magma Totam Passive'), ('8188', '0.1', '0', '0', 'Shaman - Magma Totam Passive'),
('3606', '0.1667', '0', '0', 'Shaman - Searing Totem Attack'), ('3606', '0.1667', '0', '0', 'Shaman - Searing Totem Attack'),
/* Warlock */
('980', '0', '0.1', '0', 'Warlock - Curse of Agony'), ('980', '0', '0.1', '0', 'Warlock - Curse of Agony'),
('603', '0', '2', '0', 'Warlock - Curse of Doom'), ('603', '0', '2', '0', 'Warlock - Curse of Doom'),
('172', '0', '0.3', '0', 'Warlock - Corruption'), ('172', '0', '0.3', '0', 'Warlock - Corruption'),
@ -13728,7 +13736,9 @@ INSERT INTO `spell_bonus_data` VALUES
('42223', '0.952', '0', '0', 'Warlock - Rain of Fire Triggered'), ('42223', '0.952', '0', '0', 'Warlock - Rain of Fire Triggered'),
('18220', '0.96', '0', '0', 'Warlock - Dark Pact'), ('18220', '0.96', '0', '0', 'Warlock - Dark Pact'),
('6229', '0.3', '0', '0', 'Warlock - Shadow Ward'), ('6229', '0.3', '0', '0', 'Warlock - Shadow Ward'),
('63106', '0', '0', '0', 'Warlock - Siphon Life Triggered'); ('63106', '0', '0', '0', 'Warlock - Siphon Life Triggered'),
/* Item */
(40293, 0, 0, 0, 'Item - Siphon Essence');
/*!40000 ALTER TABLE `spell_bonus_data` ENABLE KEYS */; /*!40000 ALTER TABLE `spell_bonus_data` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;

View file

@ -0,0 +1,6 @@
ALTER TABLE db_version CHANGE COLUMN required_8342_01_mangos_spell_proc_event required_8361_01_mangos_spell_bonus_data bit;
DELETE FROM `spell_bonus_data` where entry in (40293);
INSERT INTO `spell_bonus_data` VALUES
(40293, 0, 0, 0, 'Item - Siphon Essence');

View file

@ -0,0 +1,4 @@
ALTER TABLE db_version CHANGE COLUMN required_8361_01_mangos_spell_bonus_data required_8364_01_mangos_db_version bit;
ALTER TABLE db_version
ADD COLUMN cache_id int(10) default '0' AFTER creature_ai_version;

View file

@ -80,6 +80,8 @@ pkgdata_DATA = \
8339_01_characters_characters.sql \ 8339_01_characters_characters.sql \
8339_02_characters_character_battleground_data.sql \ 8339_02_characters_character_battleground_data.sql \
8342_01_mangos_spell_proc_event.sql \ 8342_01_mangos_spell_proc_event.sql \
8361_01_mangos_spell_bonus_data.sql \
8364_01_mangos_db_version.sql \
README README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -140,4 +142,6 @@ EXTRA_DIST = \
8339_01_characters_characters.sql \ 8339_01_characters_characters.sql \
8339_02_characters_character_battleground_data.sql \ 8339_02_characters_character_battleground_data.sql \
8342_01_mangos_spell_proc_event.sql \ 8342_01_mangos_spell_proc_event.sql \
8361_01_mangos_spell_bonus_data.sql \
8364_01_mangos_db_version.sql \
README README

View file

@ -855,7 +855,7 @@ void BattleGround::RewardItem(Player *plr, uint32 item_id, uint32 count)
if( count != 0 && !dest.empty()) // can add some if( count != 0 && !dest.empty()) // can add some
if (Item* item = plr->StoreNewItem( dest, item_id, true, 0)) if (Item* item = plr->StoreNewItem( dest, item_id, true, 0))
plr->SendNewItem(item,count,false,true); plr->SendNewItem(item,count,true,false);
if (no_space_count > 0) if (no_space_count > 0)
SendRewardMarkByMail(plr,item_id,no_space_count); SendRewardMarkByMail(plr,item_id,no_space_count);

View file

@ -19,6 +19,11 @@
#ifndef DBCENUMS_H #ifndef DBCENUMS_H
#define DBCENUMS_H #define DBCENUMS_H
// Client expected level limitation, like as used in DBC item max levels for "until max player level"
// use as default max player level, must be fit max level for used client
// also see MAX_LEVEL and STRONG_MAX_LEVEL define
#define DEFAULT_MAX_LEVEL 80
// client supported max level for player/pets/etc. Avoid overflow or client stability affected. // client supported max level for player/pets/etc. Avoid overflow or client stability affected.
// also see GT_MAX_LEVEL define // also see GT_MAX_LEVEL define
#define MAX_LEVEL 100 #define MAX_LEVEL 100

View file

@ -1094,8 +1094,8 @@ void Player::Update( uint32 p_time )
if( q_status.m_timer <= p_time ) if( q_status.m_timer <= p_time )
{ {
uint32 quest_id = *iter; uint32 quest_id = *iter;
++iter; // current iter will be removed in FailTimedQuest ++iter; // current iter will be removed in FailQuest
FailTimedQuest( quest_id ); FailQuest(quest_id);
} }
else else
{ {
@ -6510,13 +6510,20 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply)
void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply, bool only_level_scale /*= false*/) void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool apply, bool only_level_scale /*= false*/)
{ {
if(slot >= INVENTORY_SLOT_BAG_END || !proto) if (slot >= INVENTORY_SLOT_BAG_END || !proto)
return; return;
ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : NULL; ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : NULL;
ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : NULL; if (only_level_scale && !ssd)
return;
if(only_level_scale && !(ssd && ssv)) // req. check at equip, but allow use for extended range if range limit max level, set proper level
uint32 ssd_level = getLevel();
if (ssd && ssd_level > ssd->MaxLevel)
ssd_level = ssd->MaxLevel;
ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(ssd_level) : NULL;
if (only_level_scale && !ssv)
return; return;
for (int i = 0; i < MAX_ITEM_PROTO_STATS; ++i) for (int i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
@ -9786,7 +9793,8 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
} }
ScalingStatDistributionEntry const *ssd = pProto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(pProto->ScalingStatDistribution) : 0; ScalingStatDistributionEntry const *ssd = pProto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(pProto->ScalingStatDistribution) : 0;
if (ssd && ssd->MaxLevel < getLevel()) // check allowed level (extend range to upper values if MaxLevel more or equal max player level, this let GM set high level with 1...max range items)
if (ssd && ssd->MaxLevel < DEFAULT_MAX_LEVEL && ssd->MaxLevel < getLevel())
return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED; return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
uint8 eslot = FindEquipSlot( pProto, slot, swap ); uint8 eslot = FindEquipSlot( pProto, slot, swap );
@ -12784,41 +12792,30 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver
SetCanDelayTeleport(false); SetCanDelayTeleport(false);
} }
void Player::FailQuest( uint32 quest_id ) void Player::FailQuest(uint32 questId)
{ {
if( quest_id ) if (Quest const* pQuest = objmgr.GetQuestTemplate(questId))
{ {
IncompleteQuest( quest_id ); SetQuestStatus(questId, QUEST_STATUS_FAILED);
uint16 log_slot = FindQuestSlot( quest_id ); uint16 log_slot = FindQuestSlot(questId);
if( log_slot < MAX_QUEST_LOG_SIZE)
{
SetQuestSlotTimer(log_slot, 1 );
SetQuestSlotState(log_slot,QUEST_STATE_FAIL);
}
SendQuestFailed( quest_id );
}
}
void Player::FailTimedQuest( uint32 quest_id ) if (log_slot < MAX_QUEST_LOG_SIZE)
{
if( quest_id )
{ {
QuestStatusData& q_status = mQuestStatus[quest_id]; SetQuestSlotTimer(log_slot, 1);
SetQuestSlotState(log_slot, QUEST_STATE_FAIL);
}
if (pQuest->HasFlag(QUEST_MANGOS_FLAGS_TIMED))
{
QuestStatusData& q_status = mQuestStatus[questId];
q_status.m_timer = 0; q_status.m_timer = 0;
if (q_status.uState != QUEST_NEW)
q_status.uState = QUEST_CHANGED;
IncompleteQuest( quest_id ); SendQuestTimerFailed(questId);
uint16 log_slot = FindQuestSlot( quest_id );
if( log_slot < MAX_QUEST_LOG_SIZE)
{
SetQuestSlotTimer(log_slot, 1 );
SetQuestSlotState(log_slot,QUEST_STATE_FAIL);
} }
SendQuestTimerFailed( quest_id ); else
SendQuestFailed(questId);
} }
} }
@ -13267,21 +13264,22 @@ bool Player::CanShareQuest(uint32 quest_id) const
return false; return false;
} }
void Player::SetQuestStatus( uint32 quest_id, QuestStatus status ) void Player::SetQuestStatus(uint32 quest_id, QuestStatus status)
{ {
Quest const* qInfo = objmgr.GetQuestTemplate(quest_id); if (Quest const* qInfo = objmgr.GetQuestTemplate(quest_id))
if( qInfo )
{ {
if( status == QUEST_STATUS_NONE || status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE ) if (status == QUEST_STATUS_NONE || status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_FAILED)
{ {
if( qInfo->HasFlag( QUEST_MANGOS_FLAGS_TIMED ) ) if (qInfo->HasFlag(QUEST_MANGOS_FLAGS_TIMED))
m_timedquests.erase(qInfo->GetQuestId()); m_timedquests.erase(qInfo->GetQuestId());
} }
QuestStatusData& q_status = mQuestStatus[quest_id]; QuestStatusData& q_status = mQuestStatus[quest_id];
q_status.m_status = status; q_status.m_status = status;
if (q_status.uState != QUEST_NEW) q_status.uState = QUEST_CHANGED;
if (q_status.uState != QUEST_NEW)
q_status.uState = QUEST_CHANGED;
} }
UpdateForQuestWorldObjects(); UpdateForQuestWorldObjects();
@ -15124,16 +15122,20 @@ void Player::_LoadQuestStatus(QueryResult *result)
questStatusData.uState = QUEST_UNCHANGED; questStatusData.uState = QUEST_UNCHANGED;
// add to quest log // add to quest log
if( slot < MAX_QUEST_LOG_SIZE && if (slot < MAX_QUEST_LOG_SIZE &&
( questStatusData.m_status == QUEST_STATUS_INCOMPLETE || ((questStatusData.m_status == QUEST_STATUS_INCOMPLETE ||
questStatusData.m_status == QUEST_STATUS_COMPLETE && questStatusData.m_status == QUEST_STATUS_COMPLETE ||
(!questStatusData.m_rewarded || pQuest->IsDaily()) ) ) questStatusData.m_status == QUEST_STATUS_FAILED) &&
(!questStatusData.m_rewarded || pQuest->IsDaily())))
{ {
SetQuestSlot(slot, quest_id, quest_time); SetQuestSlot(slot, quest_id, quest_time);
if(questStatusData.m_status == QUEST_STATUS_COMPLETE) if (questStatusData.m_status == QUEST_STATUS_COMPLETE)
SetQuestSlotState(slot, QUEST_STATE_COMPLETE); SetQuestSlotState(slot, QUEST_STATE_COMPLETE);
if (questStatusData.m_status == QUEST_STATUS_FAILED)
SetQuestSlotState(slot, QUEST_STATE_FAIL);
for(uint8 idx = 0; idx < QUEST_OBJECTIVES_COUNT; ++idx) for(uint8 idx = 0; idx < QUEST_OBJECTIVES_COUNT; ++idx)
if(questStatusData.m_creatureOrGOcount[idx]) if(questStatusData.m_creatureOrGOcount[idx])
SetQuestSlotCounter(slot, idx, questStatusData.m_creatureOrGOcount[idx]); SetQuestSlotCounter(slot, idx, questStatusData.m_creatureOrGOcount[idx]);

View file

@ -1296,7 +1296,6 @@ class MANGOS_DLL_SPEC Player : public Unit
void IncompleteQuest( uint32 quest_id ); void IncompleteQuest( uint32 quest_id );
void RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce = true ); void RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce = true );
void FailQuest( uint32 quest_id ); void FailQuest( uint32 quest_id );
void FailTimedQuest( uint32 quest_id );
bool SatisfyQuestSkillOrClass( Quest const* qInfo, bool msg ); bool SatisfyQuestSkillOrClass( Quest const* qInfo, bool msg );
bool SatisfyQuestLevel( Quest const* qInfo, bool msg ); bool SatisfyQuestLevel( Quest const* qInfo, bool msg );
bool SatisfyQuestLog( bool msg ); bool SatisfyQuestLog( bool msg );

View file

@ -97,6 +97,7 @@ enum QuestStatus
QUEST_STATUS_UNAVAILABLE = 2, QUEST_STATUS_UNAVAILABLE = 2,
QUEST_STATUS_INCOMPLETE = 3, QUEST_STATUS_INCOMPLETE = 3,
QUEST_STATUS_AVAILABLE = 4, QUEST_STATUS_AVAILABLE = 4,
QUEST_STATUS_FAILED = 5,
MAX_QUEST_STATUS MAX_QUEST_STATUS
}; };

View file

@ -1045,6 +1045,14 @@ enum Targets
TARGET_BEHIND_VICTIM = 65, // uses in teleport behind spells, caster/target dependent from spell effect TARGET_BEHIND_VICTIM = 65, // uses in teleport behind spells, caster/target dependent from spell effect
TARGET_DYNAMIC_OBJECT_COORDINATES = 76, TARGET_DYNAMIC_OBJECT_COORDINATES = 76,
TARGET_SINGLE_ENEMY = 77, TARGET_SINGLE_ENEMY = 77,
TARGET_POINT_AT_NORTH = 78, // 78-85 possible _COORDINATES at radius with pi/4 step around target in unknown order, N?
TARGET_POINT_AT_SOUTH = 79, // S?
TARGET_POINT_AT_EAST = 80, // 80/81 must be symmetric from line caster->target, E (base at 82/83, 84/85 order) ?
TARGET_POINT_AT_WEST = 81, // 80/81 must be symmetric from line caster->target, W (base at 82/83, 84/85 order) ?
TARGET_POINT_AT_NE = 82, // from spell desc: "(NE)"
TARGET_POINT_AT_NW = 83, // from spell desc: "(NW)"
TARGET_POINT_AT_SE = 84, // from spell desc: "(SE)"
TARGET_POINT_AT_SW = 85, // from spell desc: "(SW)"
TARGET_SELF2 = 87, TARGET_SELF2 = 87,
TARGET_DIRECTLY_FORWARD = 89, TARGET_DIRECTLY_FORWARD = 89,
TARGET_NONCOMBAT_PET = 90, TARGET_NONCOMBAT_PET = 90,
@ -1833,11 +1841,26 @@ enum CreatureFamily
enum CreatureTypeFlags enum CreatureTypeFlags
{ {
CREATURE_TYPEFLAGS_TAMEABLE = 0x00001, CREATURE_TYPEFLAGS_TAMEABLE = 0x00001, //tameable by any hunter
CREATURE_TYPEFLAGS_HERBLOOT = 0x00100, CREATURE_TYPEFLAGS_UNK2 = 0x00002, //? Related to spirits/ghosts in any form? Allow gossip interaction if player is also ghost? Visibility?
CREATURE_TYPEFLAGS_MININGLOOT = 0x00200, CREATURE_TYPEFLAGS_UNK3 = 0x00004,
CREATURE_TYPEFLAGS_ENGINEERLOOT = 0x08000, CREATURE_TYPEFLAGS_UNK4 = 0x00008,
CREATURE_TYPEFLAGS_EXOTIC = 0x10000 CREATURE_TYPEFLAGS_UNK5 = 0x00010,
CREATURE_TYPEFLAGS_UNK6 = 0x00020,
CREATURE_TYPEFLAGS_UNK7 = 0x00040,
CREATURE_TYPEFLAGS_UNK8 = 0x00080,
CREATURE_TYPEFLAGS_HERBLOOT = 0x00100, //can be looted by herbalist
CREATURE_TYPEFLAGS_MININGLOOT = 0x00200, //can be looted by miner
CREATURE_TYPEFLAGS_UNK11 = 0x00400,
CREATURE_TYPEFLAGS_UNK12 = 0x00800, //? Related to mounts in some way. If mounted, fight mounted, mount appear as independant when rider dies?
CREATURE_TYPEFLAGS_UNK13 = 0x01000, //? Can aid any player in combat if in range?
CREATURE_TYPEFLAGS_UNK14 = 0x02000,
CREATURE_TYPEFLAGS_UNK15 = 0x04000, //? Possibly not in use
CREATURE_TYPEFLAGS_ENGINEERLOOT = 0x08000, //can be looted by engineer
CREATURE_TYPEFLAGS_EXOTIC = 0x10000, //can be tamed by hunter as exotic pet
CREATURE_TYPEFLAGS_UNK18 = 0x20000, //? Related to veichles/pvp?
CREATURE_TYPEFLAGS_UNK19 = 0x40000, //? Related to veichle/siege weapons?
CREATURE_TYPEFLAGS_UNK20 = 0x80000
}; };
enum CreatureEliteType enum CreatureEliteType

View file

@ -1205,7 +1205,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); unit->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
// can cause back attack (if detected) // can cause back attack (if detected)
if (!(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) && if (!(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO) && !IsPositiveSpell(m_spellInfo->Id) &&
m_caster->isVisibleForOrDetect(unit,false)) // stealth removed at Spell::cast if spell break it m_caster->isVisibleForOrDetect(unit,false)) // stealth removed at Spell::cast if spell break it
{ {
// use speedup check to avoid re-remove after above lines // use speedup check to avoid re-remove after above lines
@ -2110,6 +2110,39 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,UnitList& TagUnitMap)
if(DynamicObject* dynObj = m_caster->GetDynObject(m_triggeredByAuraSpell ? m_triggeredByAuraSpell->Id : m_spellInfo->Id)) if(DynamicObject* dynObj = m_caster->GetDynObject(m_triggeredByAuraSpell ? m_triggeredByAuraSpell->Id : m_spellInfo->Id))
m_targets.setDestination(dynObj->GetPositionX(), dynObj->GetPositionY(), dynObj->GetPositionZ()); m_targets.setDestination(dynObj->GetPositionX(), dynObj->GetPositionY(), dynObj->GetPositionZ());
break; break;
case TARGET_POINT_AT_NORTH:
case TARGET_POINT_AT_SOUTH:
case TARGET_POINT_AT_EAST:
case TARGET_POINT_AT_WEST:
case TARGET_POINT_AT_NE:
case TARGET_POINT_AT_NW:
case TARGET_POINT_AT_SE:
case TARGET_POINT_AT_SW:
{
if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
{
Unit* currentTarget = m_targets.getUnitTarget() ? m_targets.getUnitTarget() : m_caster;
float angle = currentTarget != m_caster ? currentTarget->GetAngle(m_caster) : m_caster->GetOrientation();
switch(cur)
{
case TARGET_POINT_AT_NORTH: break;
case TARGET_POINT_AT_SOUTH: angle += M_PI; break;
case TARGET_POINT_AT_EAST: angle -= M_PI/2; break;
case TARGET_POINT_AT_WEST: angle += M_PI/2; break;
case TARGET_POINT_AT_NE: angle -= M_PI/4; break;
case TARGET_POINT_AT_NW: angle += M_PI/4; break;
case TARGET_POINT_AT_SE: angle -= 3*M_PI/4; break;
case TARGET_POINT_AT_SW: angle += 3*M_PI/4; break;
}
float x,y;
currentTarget->GetNearPoint2D(x,y,radius,angle);
m_targets.setDestination(x,y,currentTarget->GetPositionZ());
}
break;
}
case TARGET_DIRECTLY_FORWARD: case TARGET_DIRECTLY_FORWARD:
{ {
if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) if (!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION))
@ -2345,6 +2378,9 @@ void Spell::cast(bool skipCheck)
if (m_spellInfo->Mechanic == MECHANIC_SHIELD && if (m_spellInfo->Mechanic == MECHANIC_SHIELD &&
(m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000000001))) (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000000000000001)))
AddPrecastSpell(6788); // Weakened Soul AddPrecastSpell(6788); // Weakened Soul
// Prayer of Mending (jump animation), we need formal caster instead original for correct animation
else if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000002000000000))
AddTriggeredSpell(41637);
switch(m_spellInfo->Id) switch(m_spellInfo->Id)
{ {
@ -2362,6 +2398,14 @@ void Spell::cast(bool skipCheck)
} }
break; break;
} }
case SPELLFAMILY_ROGUE:
// Fan of Knives (main hand)
if (m_spellInfo->Id == 51723 && m_caster->GetTypeId() == TYPEID_PLAYER &&
((Player*)m_caster)->haveOffhandWeapon())
{
AddTriggeredSpell(52874); // Fan of Knives (offhand)
}
break;
case SPELLFAMILY_PALADIN: case SPELLFAMILY_PALADIN:
{ {
// Divine Shield, Divine Protection or Hand of Protection // Divine Shield, Divine Protection or Hand of Protection
@ -2783,12 +2827,16 @@ void Spell::finish(bool ok)
// Not drop combopoints if negative spell and if any miss on enemy exist // Not drop combopoints if negative spell and if any miss on enemy exist
bool needDrop = true; bool needDrop = true;
if (!IsPositiveSpell(m_spellInfo->Id)) if (!IsPositiveSpell(m_spellInfo->Id))
{
for(std::list<TargetInfo>::const_iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit) for(std::list<TargetInfo>::const_iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
{
if (ihit->missCondition != SPELL_MISS_NONE && ihit->targetGUID!=m_caster->GetGUID()) if (ihit->missCondition != SPELL_MISS_NONE && ihit->targetGUID!=m_caster->GetGUID())
{ {
needDrop = false; needDrop = false;
break; break;
} }
}
}
if (needDrop) if (needDrop)
((Player*)m_caster)->ClearComboPoints(); ((Player*)m_caster)->ClearComboPoints();
} }
@ -3796,12 +3844,22 @@ SpellCastResult Spell::CheckCast(bool strict)
// auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode
// this case can be triggered if rank not found (too low-level target for first rank) // this case can be triggered if rank not found (too low-level target for first rank)
if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) if (m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem)
{
for(int i=0;i<3;++i) for(int i=0;i<3;++i)
if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) {
if(target->getLevel() + 10 < m_spellInfo->spellLevel) // check only spell that apply positive auras
if (IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA &&
// at not self target
!IsCasterSourceTarget(m_spellInfo->EffectImplicitTargetA[i]) &&
// and target low level
target->getLevel() + 10 < m_spellInfo->spellLevel)
{
return SPELL_FAILED_LOWLEVEL; return SPELL_FAILED_LOWLEVEL;
} }
}
}
}
else if (m_caster->GetTypeId() == TYPEID_PLAYER) // Target - is player caster else if (m_caster->GetTypeId() == TYPEID_PLAYER) // Target - is player caster
{ {
// Additional check for some spells // Additional check for some spells

View file

@ -2198,6 +2198,21 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
bg->RemovePlayerFromResurrectQueue(m_target->GetGUID()); bg->RemovePlayerFromResurrectQueue(m_target->GetGUID());
return; return;
} }
case 36730: // Flame Strike
{
m_target->CastSpell(m_target, 36731, true, NULL, this);
return;
}
case 44191: // Flame Strike
{
if (m_target->GetMap()->IsDungeon())
{
uint32 spellId = m_target->GetMap()->IsHeroic() ? 46163 : 44190;
m_target->CastSpell(m_target, spellId, true, NULL, this);
}
return;
}
case 45934: // Dark Fiend case 45934: // Dark Fiend
{ {
// Kill target if dispelled // Kill target if dispelled
@ -2389,6 +2404,19 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
((Player*)m_target)->AddSpellMod(m_spellmod, apply); ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
return; return;
} }
case 52610: // Savage Roar
{
if(apply)
{
if(m_target->m_form != FORM_CAT)
return;
m_target->CastSpell(m_target, 62071, true);
}
else
m_target-> RemoveAurasDueToSpell(62071);
return;
}
case 61336: // Survival Instincts case 61336: // Survival Instincts
{ {
if(apply) if(apply)
@ -2450,6 +2478,32 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
((Player*)m_target)->UpdateAttackPowerAndDamage(); ((Player*)m_target)->UpdateAttackPowerAndDamage();
return; return;
} }
// Improved Moonkin Form
if(GetSpellProto()->SpellIconID == 2855)
{
uint32 spell_id;
switch(GetId())
{
case 48384: spell_id = 50170; //Rank 1
case 48395: spell_id = 50171; //Rank 2
case 48396: spell_id = 50172; //Rank 3
default:
sLog.outError("HandleAuraDummy: Not handled rank of IMF (Spell: %u)",GetId());
return;
}
if(apply)
{
if(m_target->m_form != FORM_MOONKIN)
return;
m_target->CastSpell(m_target, spell_id, true);
}
else
m_target-> RemoveAurasDueToSpell(spell_id);
return;
}
break; break;
} }
case SPELLFAMILY_HUNTER: case SPELLFAMILY_HUNTER:
@ -2721,10 +2775,12 @@ void Aura::HandleAuraModShapeshift(bool apply, bool Real)
{ {
SpellEntry const* aurSpellInfo = (*iter)->GetSpellProto(); SpellEntry const* aurSpellInfo = (*iter)->GetSpellProto();
uint32 aurMechMask = GetAllSpellMechanicMask(aurSpellInfo);
// If spell that caused this aura has Croud Control or Daze effect // If spell that caused this aura has Croud Control or Daze effect
if((GetAllSpellMechanicMask(aurSpellInfo) & MECHANIC_NOT_REMOVED_BY_SHAPESHIFT) || if((aurMechMask & MECHANIC_NOT_REMOVED_BY_SHAPESHIFT) ||
// some Daze spells have these parameters instead of MECHANIC_DAZE // some Daze spells have these parameters instead of MECHANIC_DAZE (skip snare spells)
(aurSpellInfo->SpellIconID == 15 && aurSpellInfo->Dispel == 0)) aurSpellInfo->SpellIconID == 15 && aurSpellInfo->Dispel == 0 && (aurMechMask & (1 << MECHANIC_SNARE))==0)
{ {
++iter; ++iter;
continue; continue;
@ -5366,7 +5422,9 @@ void Aura::HandleShapeshiftBoosts(bool apply)
uint32 HotWSpellId = 0; uint32 HotWSpellId = 0;
uint32 MasterShaperSpellId = 0; uint32 MasterShaperSpellId = 0;
switch(GetModifier()->m_miscvalue) uint32 form = GetModifier()->m_miscvalue;
switch(form)
{ {
case FORM_CAT: case FORM_CAT:
spellId = 3025; spellId = 3025;
@ -5438,8 +5496,6 @@ void Aura::HandleShapeshiftBoosts(bool apply)
break; break;
} }
uint32 form = GetModifier()->m_miscvalue-1;
if(apply) if(apply)
{ {
if (spellId) m_target->CastSpell(m_target, spellId, true, NULL, this ); if (spellId) m_target->CastSpell(m_target, spellId, true, NULL, this );
@ -5455,7 +5511,7 @@ void Aura::HandleShapeshiftBoosts(bool apply)
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR_PASSIVE | (1<<7)))) if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR_PASSIVE | (1<<7))))
continue; continue;
if (spellInfo->Stances & (1<<form)) if (spellInfo->Stances & (1<<(form-1)))
m_target->CastSpell(m_target, itr->first, true, NULL, this); m_target->CastSpell(m_target, itr->first, true, NULL, this);
} }
@ -5478,10 +5534,41 @@ void Aura::HandleShapeshiftBoosts(bool apply)
if (((Player*)m_target)->HasSpell(17007)) if (((Player*)m_target)->HasSpell(17007))
{ {
SpellEntry const *spellInfo = sSpellStore.LookupEntry(24932); SpellEntry const *spellInfo = sSpellStore.LookupEntry(24932);
if (spellInfo && spellInfo->Stances & (1<<form)) if (spellInfo && spellInfo->Stances & (1<<(form-1)))
m_target->CastSpell(m_target, 24932, true, NULL, this); m_target->CastSpell(m_target, 24932, true, NULL, this);
} }
// Savage Roar
if (form == FORM_CAT && ((Player*)m_target)->HasAura(52610))
m_target->CastSpell(m_target, 62071, true);
// Improved Moonkin Form
if (form == FORM_MOONKIN)
{
Unit::AuraList const& dummyAuras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator i = dummyAuras.begin(); i != dummyAuras.end(); i++)
{
if ((*i)->GetSpellProto()->SpellFamilyName==SPELLFAMILY_DRUID &&
(*i)->GetSpellProto()->SpellIconID == 2855)
{
uint32 spell_id = 0;
switch((*i)->GetId())
{
case 48384:spell_id=50170;break;//Rank 1
case 48395:spell_id=50171;break;//Rank 2
case 48396:spell_id=50172;break;//Rank 3
default:
sLog.outError("Aura::HandleShapeshiftBoosts: Not handled rank of IMF (Spell: %u)",(*i)->GetId());
break;
}
if(spell_id)
m_target->CastSpell(m_target, spell_id, true, NULL, this);
break;
}
}
}
// Heart of the Wild // Heart of the Wild
if (HotWSpellId) if (HotWSpellId)
{ {
@ -5519,9 +5606,6 @@ void Aura::HandleShapeshiftBoosts(bool apply)
++itr; ++itr;
} }
} }
/*double healthPercentage = (double)m_target->GetHealth() / (double)m_target->GetMaxHealth();
m_target->SetHealth(uint32(ceil((double)m_target->GetMaxHealth() * healthPercentage)));*/
} }
void Aura::HandleSpellSpecificBoosts(bool apply) void Aura::HandleSpellSpecificBoosts(bool apply)
@ -5610,15 +5694,18 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
return; return;
} }
// prevent aura deletion, specially in multi-boost case
SetInUse(true);
if (apply) if (apply)
{ {
if (spellId1) if (spellId1)
m_target->CastSpell(m_target, spellId1, true, NULL, this); m_target->CastSpell(m_target, spellId1, true, NULL, this);
if (spellId2) if (spellId2 && !IsDeleted())
m_target->CastSpell(m_target, spellId2, true, NULL, this); m_target->CastSpell(m_target, spellId2, true, NULL, this);
if (spellId3) if (spellId3 && !IsDeleted())
m_target->CastSpell(m_target, spellId3, true, NULL, this); m_target->CastSpell(m_target, spellId3, true, NULL, this);
if (spellId4) if (spellId4 && !IsDeleted())
m_target->CastSpell(m_target, spellId4, true, NULL, this); m_target->CastSpell(m_target, spellId4, true, NULL, this);
} }
else else
@ -5632,6 +5719,8 @@ void Aura::HandleSpellSpecificBoosts(bool apply)
if (spellId4) if (spellId4)
m_target->RemoveAurasByCasterSpell(spellId4, GetCasterGUID()); m_target->RemoveAurasByCasterSpell(spellId4, GetCasterGUID());
} }
SetInUse(false);
} }
void Aura::HandleAuraEmpathy(bool apply, bool /*Real*/) void Aura::HandleAuraEmpathy(bool apply, bool /*Real*/)

View file

@ -1957,9 +1957,17 @@ void Spell::EffectForceCast(uint32 i)
unitTarget->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID); unitTarget->CastSpell(unitTarget, spellInfo, true, NULL, NULL, m_originalCasterGUID);
} }
void Spell::EffectTriggerSpell(uint32 i) void Spell::EffectTriggerSpell(uint32 effIndex)
{ {
uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[i]; // only unit case known
if (!unitTarget)
{
if(gameObjTarget || itemTarget)
sLog.outError("Spell::EffectTriggerSpell (Spell: %u): Unsupported non-unit case!",m_spellInfo->Id);
return;
}
uint32 triggered_spell_id = m_spellInfo->EffectTriggerSpell[effIndex];
// special cases // special cases
switch(triggered_spell_id) switch(triggered_spell_id)
@ -1967,21 +1975,21 @@ void Spell::EffectTriggerSpell(uint32 i)
// Vanish (not exist) // Vanish (not exist)
case 18461: case 18461:
{ {
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED); unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED); unitTarget->RemoveSpellsCausingAura(SPELL_AURA_MOD_STALKED);
// if this spell is given to NPC it must handle rest by it's own AI // if this spell is given to NPC it must handle rest by it's own AI
if ( m_caster->GetTypeId() != TYPEID_PLAYER ) if (unitTarget->GetTypeId() != TYPEID_PLAYER)
return; return;
// get highest rank of the Stealth spell // get highest rank of the Stealth spell
uint32 spellId = 0; uint32 spellId = 0;
const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap(); const PlayerSpellMap& sp_list = ((Player*)unitTarget)->GetSpellMap();
for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
{ {
// only highest rank is shown in spell book, so simply check if shown in spell book // only highest rank is shown in spell book, so simply check if shown in spell book
if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED) if (!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
continue; continue;
SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
@ -2000,10 +2008,10 @@ void Spell::EffectTriggerSpell(uint32 i)
return; return;
// reset cooldown on it if needed // reset cooldown on it if needed
if(((Player*)m_caster)->HasSpellCooldown(spellId)) if (((Player*)unitTarget)->HasSpellCooldown(spellId))
((Player*)m_caster)->RemoveSpellCooldown(spellId); ((Player*)unitTarget)->RemoveSpellCooldown(spellId);
m_caster->CastSpell(m_caster, spellId, true); m_caster->CastSpell(unitTarget, spellId, true);
return; return;
} }
// just skip // just skip
@ -2043,7 +2051,7 @@ void Spell::EffectTriggerSpell(uint32 i)
// Cloak of Shadows // Cloak of Shadows
case 35729: case 35729:
{ {
Unit::AuraMap& Auras = m_caster->GetAuras(); Unit::AuraMap& Auras = unitTarget->GetAuras();
for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter) for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
{ {
// remove all harmful spells on you... // remove all harmful spells on you...
@ -2061,7 +2069,7 @@ void Spell::EffectTriggerSpell(uint32 i)
// Priest Shadowfiend (34433) need apply mana gain trigger aura on pet // Priest Shadowfiend (34433) need apply mana gain trigger aura on pet
case 41967: case 41967:
{ {
if (Unit *pet = m_caster->GetPet()) if (Unit *pet = unitTarget->GetPet())
pet->CastSpell(pet, 28305, true); pet->CastSpell(pet, 28305, true);
return; return;
} }
@ -2069,63 +2077,54 @@ void Spell::EffectTriggerSpell(uint32 i)
// normal case // normal case
SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id ); SpellEntry const *spellInfo = sSpellStore.LookupEntry( triggered_spell_id );
if (!spellInfo)
if(!spellInfo)
{ {
sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id); sLog.outError("EffectTriggerSpell of spell %u: triggering unknown spell id %i", m_spellInfo->Id,triggered_spell_id);
return; return;
} }
// select formal caster for triggered spell
Unit* caster = m_caster;
// some triggered spells require specific equipment // some triggered spells require specific equipment
if(spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER) if (spellInfo->EquippedItemClass >=0 && m_caster->GetTypeId()==TYPEID_PLAYER)
{ {
// main hand weapon required // main hand weapon required
if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND) if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_MAIN_HAND)
{ {
Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK); Item* item = ((Player*)m_caster)->GetWeaponForAttack(BASE_ATTACK);
// skip spell if no weapon in slot or broken // skip spell if no weapon in slot or broken
if(!item || item->IsBroken() ) if (!item || item->IsBroken() )
return; return;
// skip spell if weapon not fit to triggered spell // skip spell if weapon not fit to triggered spell
if(!item->IsFitToSpellRequirements(spellInfo)) if (!item->IsFitToSpellRequirements(spellInfo))
return; return;
} }
// offhand hand weapon required // offhand hand weapon required
if(spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND) if (spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_OFFHAND)
{ {
Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK); Item* item = ((Player*)m_caster)->GetWeaponForAttack(OFF_ATTACK);
// skip spell if no weapon in slot or broken // skip spell if no weapon in slot or broken
if(!item || item->IsBroken() ) if (!item || item->IsBroken() )
return; return;
// skip spell if weapon not fit to triggered spell // skip spell if weapon not fit to triggered spell
if(!item->IsFitToSpellRequirements(spellInfo)) if (!item->IsFitToSpellRequirements(spellInfo))
return; return;
} }
} }
// some triggered spells must be casted instantly (for example, if next effect case instant kill caster)
bool instant = false;
for(uint32 j = i+1; j < 3; ++j)
{
if(m_spellInfo->Effect[j]==SPELL_EFFECT_INSTAKILL && m_spellInfo->EffectImplicitTargetA[j]==TARGET_SELF)
{
instant = true;
break;
}
}
if(instant)
{
if (unitTarget)
m_caster->CastSpell(unitTarget,spellInfo,true,m_CastItem,NULL,m_originalCasterGUID);
}
else else
AddTriggeredSpell(spellInfo); {
// Note: not exist spells with weapon req. and IsSpellHaveCasterSourceTargets == true
// so this just for speedup places in else
caster = IsSpellWithCasterSourceTargetsOnly(spellInfo) ? unitTarget : m_caster;
}
caster->CastSpell(unitTarget,spellInfo,true,NULL,NULL,m_originalCasterGUID);
} }
void Spell::EffectTriggerMissileSpell(uint32 effect_idx) void Spell::EffectTriggerMissileSpell(uint32 effect_idx)
@ -2403,15 +2402,7 @@ void Spell::EffectApplyAura(uint32 i)
Aur->SetAuraDuration(duration); Aur->SetAuraDuration(duration);
} }
bool added = unitTarget->AddAura(Aur); unitTarget->AddAura(Aur);
// Aura not added and deleted in AddAura call;
if (!added)
return;
// Prayer of Mending (jump animation), we need formal caster instead original for correct animation
if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000002000000000)))
m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID);
} }
void Spell::EffectUnlearnSpecialization( uint32 i ) void Spell::EffectUnlearnSpecialization( uint32 i )
@ -2686,6 +2677,26 @@ void Spell::DoCreateItem(uint32 i, uint32 itemtype)
return; return;
} }
// bg reward have some special in code work
uint32 bgType = 0;
switch(m_spellInfo->Id)
{
case SPELL_AV_MARK_WINNER:
case SPELL_AV_MARK_LOSER:
bgType = BATTLEGROUND_AV;
break;
case SPELL_WS_MARK_WINNER:
case SPELL_WS_MARK_LOSER:
bgType = BATTLEGROUND_WS;
break;
case SPELL_AB_MARK_WINNER:
case SPELL_AB_MARK_LOSER:
bgType = BATTLEGROUND_AB;
break;
default:
break;
}
uint32 num_to_add; uint32 num_to_add;
// TODO: maybe all this can be replaced by using correct calculated `damage` value // TODO: maybe all this can be replaced by using correct calculated `damage` value
@ -2766,35 +2777,17 @@ void Spell::DoCreateItem(uint32 i, uint32 itemtype)
// send info to the client // send info to the client
if(pItem) if(pItem)
player->SendNewItem(pItem, num_to_add, true, true); player->SendNewItem(pItem, num_to_add, true, bgType == 0);
// we succeeded in creating at least one item, so a levelup is possible // we succeeded in creating at least one item, so a levelup is possible
if(bgType == 0)
player->UpdateCraftSkill(m_spellInfo->Id); player->UpdateCraftSkill(m_spellInfo->Id);
} }
// for battleground marks send by mail if not add all expected // for battleground marks send by mail if not add all expected
if(no_space > 0 ) if(no_space > 0 && bgType)
{ {
BattleGroundTypeId bgType; if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(BattleGroundTypeId(bgType)))
switch(m_spellInfo->Id)
{
case SPELL_AV_MARK_WINNER:
case SPELL_AV_MARK_LOSER:
bgType = BATTLEGROUND_AV;
break;
case SPELL_WS_MARK_WINNER:
case SPELL_WS_MARK_LOSER:
bgType = BATTLEGROUND_WS;
break;
case SPELL_AB_MARK_WINNER:
case SPELL_AB_MARK_LOSER:
bgType = BATTLEGROUND_AB;
break;
default:
return;
}
if(BattleGround* bg = sBattleGroundMgr.GetBattleGroundTemplate(bgType))
bg->SendRewardMarkByMail(player, newitemid, no_space); bg->SendRewardMarkByMail(player, newitemid, no_space);
} }
} }
@ -4485,6 +4478,13 @@ void Spell::EffectWeaponDmg(uint32 i)
if(found) if(found)
totalDamagePercentMod *= 1.2f; // 120% if poisoned totalDamagePercentMod *= 1.2f; // 120% if poisoned
} }
// Fan of Knives
else if (m_caster->GetTypeId()==TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0004000000000000)))
{
Item* weapon = ((Player*)m_caster)->GetWeaponForAttack(m_attackType,true);
if (weapon && weapon->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_DAGGER)
totalDamagePercentMod *= 1.5f; // 150% to daggers
}
break; break;
} }
case SPELLFAMILY_PALADIN: case SPELLFAMILY_PALADIN:
@ -5054,6 +5054,11 @@ void Spell::EffectScriptEffect(uint32 effIndex)
} }
return; return;
} }
case 55693: // Remove Collapsing Cave Aura
if(unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(m_spellInfo->CalculateSimpleValue(effIndex));
break;
case 58418: // Portal to Orgrimmar case 58418: // Portal to Orgrimmar
case 58420: // Portal to Stormwind case 58420: // Portal to Stormwind
{ {
@ -6061,8 +6066,11 @@ void Spell::EffectCharge(uint32 /*i*/)
if (!unitTarget) if (!unitTarget)
return; return;
//TODO: research more ContactPoint/attack distance.
//3.666666 instead of ATTACK_DISTANCE(5.0f) in below seem to give more accurate result.
float x, y, z; float x, y, z;
unitTarget->GetContactPoint(m_caster, x, y, z); unitTarget->GetContactPoint(m_caster, x, y, z, 3.666666f);
if (unitTarget->GetTypeId() != TYPEID_PLAYER) if (unitTarget->GetTypeId() != TYPEID_PLAYER)
((Creature *)unitTarget)->StopMoving(); ((Creature *)unitTarget)->StopMoving();
@ -6090,7 +6098,7 @@ void Spell::EffectCharge2(uint32 /*i*/)
((Creature *)unitTarget)->StopMoving(); ((Creature *)unitTarget)->StopMoving();
} }
else if (unitTarget && unitTarget != m_caster) else if (unitTarget && unitTarget != m_caster)
unitTarget->GetContactPoint(m_caster, x, y, z); unitTarget->GetContactPoint(m_caster, x, y, z, 3.666666f);
else else
return; return;

View file

@ -301,15 +301,17 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId); SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
if (!spellproto) return false; if (!spellproto) return false;
switch(spellId)
{
case 28441: // not positive dummy spell
case 37675: // Chaos Blast
return false;
}
switch(spellproto->Effect[effIndex]) switch(spellproto->Effect[effIndex])
{ {
case SPELL_EFFECT_DUMMY:
// some explicitly required dummy effect sets
switch(spellId)
{
case 28441: return false; // AB Effect 000
default:
break;
}
break;
// always positive effects (check before target checks that provided non-positive result in some case for positive effects) // always positive effects (check before target checks that provided non-positive result in some case for positive effects)
case SPELL_EFFECT_HEAL: case SPELL_EFFECT_HEAL:
case SPELL_EFFECT_LEARN_SPELL: case SPELL_EFFECT_LEARN_SPELL:
@ -349,15 +351,21 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
break; break;
} }
} break; } break;
case SPELL_AURA_MOD_STAT:
case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from bas point sign (negative -> negative) case SPELL_AURA_MOD_DAMAGE_DONE: // dependent from bas point sign (negative -> negative)
case SPELL_AURA_MOD_STAT:
case SPELL_AURA_MOD_SKILL:
case SPELL_AURA_MOD_HEALING_PCT:
case SPELL_AURA_MOD_HEALING_DONE: case SPELL_AURA_MOD_HEALING_DONE:
if(spellproto->CalculateSimpleValue(effIndex) < 0) if(spellproto->CalculateSimpleValue(effIndex) < 0)
return false; return false;
break; break;
case SPELL_AURA_MOD_DAMAGE_TAKEN: // dependent from bas point sign (positive -> negative)
if(spellproto->CalculateSimpleValue(effIndex) > 0)
return false;
break;
case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: case SPELL_AURA_MOD_SPELL_CRIT_CHANCE:
if(spellproto->CalculateSimpleValue(effIndex) > 0) if(spellproto->CalculateSimpleValue(effIndex) > 0)
return true; // some expected possitive spells have SPELL_ATTR_EX_NEGATIVE return true; // some expected positive spells have SPELL_ATTR_EX_NEGATIVE
break; break;
case SPELL_AURA_ADD_TARGET_TRIGGER: case SPELL_AURA_ADD_TARGET_TRIGGER:
return true; return true;
@ -391,11 +399,14 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
if(spellproto->Id == 17624) if(spellproto->Id == 17624)
return false; return false;
break; break;
case SPELL_AURA_MOD_PACIFY_SILENCE:
if(spellproto->Id == 24740) // Wisp Costume
return true;
return false;
case SPELL_AURA_MOD_ROOT: case SPELL_AURA_MOD_ROOT:
case SPELL_AURA_MOD_SILENCE: case SPELL_AURA_MOD_SILENCE:
case SPELL_AURA_GHOST: case SPELL_AURA_GHOST:
case SPELL_AURA_PERIODIC_LEECH: case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_MOD_PACIFY_SILENCE:
case SPELL_AURA_MOD_STALKED: case SPELL_AURA_MOD_STALKED:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
return false; return false;
@ -460,14 +471,6 @@ bool IsPositiveEffect(uint32 spellId, uint32 effIndex)
break; break;
} }
} break; } break;
case SPELL_AURA_MOD_HEALING_PCT:
if(spellproto->CalculateSimpleValue(effIndex) < 0)
return false;
break;
case SPELL_AURA_MOD_SKILL:
if(spellproto->CalculateSimpleValue(effIndex) < 0)
return false;
break;
case SPELL_AURA_FORCE_REACTION: case SPELL_AURA_FORCE_REACTION:
if(spellproto->Id==42792) // Recently Dropped Flag (prevent cancel) if(spellproto->Id==42792) // Recently Dropped Flag (prevent cancel)
return false; return false;
@ -1411,6 +1414,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
// Survival Instincts and Survival Instincts // Survival Instincts and Survival Instincts
if( spellInfo_1->Id == 61336 && spellInfo_2->Id == 50322 || spellInfo_2->Id == 61336 && spellInfo_1->Id == 50322 ) if( spellInfo_1->Id == 61336 && spellInfo_2->Id == 50322 || spellInfo_2->Id == 61336 && spellInfo_1->Id == 50322 )
return false; return false;
// Savage Roar and Savage Roar (triggered)
if (spellInfo_1->SpellIconID == 2865 && spellInfo_2->SpellIconID == 2865)
return false;
} }
// Leader of the Pack and Scroll of Stamina (multi-family check) // Leader of the Pack and Scroll of Stamina (multi-family check)
@ -2490,17 +2497,17 @@ void SpellMgr::LoadSpellAreas()
SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId); SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId);
for(SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr) for(SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr)
{ {
if(spellArea.spellId && itr->second.spellId && spellArea.spellId != itr->second.spellId) if (spellArea.spellId != itr->second.spellId)
continue; continue;
if(spellArea.areaId && itr->second.areaId && spellArea.areaId!= itr->second.areaId) if (spellArea.areaId != itr->second.areaId)
continue; continue;
if(spellArea.questStart && itr->second.questStart && spellArea.questStart!= itr->second.questStart) if (spellArea.questStart != itr->second.questStart)
continue; continue;
if(spellArea.auraSpell && itr->second.auraSpell && spellArea.auraSpell!= itr->second.auraSpell) if (spellArea.auraSpell != itr->second.auraSpell)
continue; continue;
if(spellArea.raceMask && itr->second.raceMask && (spellArea.raceMask & itr->second.raceMask)==0) if ((spellArea.raceMask & itr->second.raceMask) == 0)
continue; continue;
if(spellArea.gender != GENDER_NONE && itr->second.gender != GENDER_NONE && spellArea.gender!= itr->second.gender) if (spellArea.gender != itr->second.gender)
continue; continue;
// duplicate by requirements // duplicate by requirements

View file

@ -240,9 +240,18 @@ inline bool IsCasterSourceTarget(uint32 target)
inline bool IsSpellWithCasterSourceTargetsOnly(SpellEntry const* spellInfo) inline bool IsSpellWithCasterSourceTargetsOnly(SpellEntry const* spellInfo)
{ {
for(int i = 0; i < 3; ++i) for(int i = 0; i < 3; ++i)
if(uint32 target = spellInfo->EffectImplicitTargetA[i]) {
if(!IsCasterSourceTarget(target)) uint32 targetA = spellInfo->EffectImplicitTargetA[i];
if(targetA && !IsCasterSourceTarget(targetA))
return false; return false;
uint32 targetB = spellInfo->EffectImplicitTargetB[i];
if(targetB && !IsCasterSourceTarget(targetB))
return false;
if(!targetA && !targetB)
return false;
}
return true; return true;
} }
@ -257,6 +266,14 @@ inline bool IsPointEffectTarget( Targets target )
case TARGET_CURRENT_ENEMY_COORDINATES: case TARGET_CURRENT_ENEMY_COORDINATES:
case TARGET_DUELVSPLAYER_COORDINATES: case TARGET_DUELVSPLAYER_COORDINATES:
case TARGET_DYNAMIC_OBJECT_COORDINATES: case TARGET_DYNAMIC_OBJECT_COORDINATES:
case TARGET_POINT_AT_NORTH:
case TARGET_POINT_AT_SOUTH:
case TARGET_POINT_AT_EAST:
case TARGET_POINT_AT_WEST:
case TARGET_POINT_AT_NE:
case TARGET_POINT_AT_NW:
case TARGET_POINT_AT_SE:
case TARGET_POINT_AT_SW:
return true; return true;
default: default:
break; break;

View file

@ -452,9 +452,10 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if(cInfo && cInfo->lootid) if(cInfo && cInfo->lootid)
pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE); pVictim->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
// some critters required for quests // some critters required for quests (need normal entry instead possible heroic in any cases)
if(GetTypeId() == TYPEID_PLAYER) if(GetTypeId() == TYPEID_PLAYER)
((Player*)this)->KilledMonster(cInfo ,pVictim->GetGUID()); if(CreatureInfo const* normalInfo = objmgr.GetCreatureTemplate(pVictim->GetEntry()))
((Player*)this)->KilledMonster(normalInfo,pVictim->GetGUID());
return damage; return damage;
} }
@ -3602,9 +3603,14 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
if(i_spellId == spellId) continue; if(i_spellId == spellId) continue;
bool is_triggered_by_spell = false; bool is_triggered_by_spell = false;
// prevent triggered aura of removing aura that triggered it // prevent triggering aura of removing aura that triggered it
for(int j = 0; j < 3; ++j) for(int j = 0; j < 3; ++j)
if (i_spellProto->EffectTriggerSpell[j] == spellProto->Id) if (i_spellProto->EffectTriggerSpell[j] == spellId)
is_triggered_by_spell = true;
// prevent triggered aura of removing aura that triggering it (triggered effect early some aura of parent spell
for(int j = 0; j < 3; ++j)
if (spellProto->EffectTriggerSpell[j] == i_spellId)
is_triggered_by_spell = true; is_triggered_by_spell = true;
if (is_triggered_by_spell) if (is_triggered_by_spell)
@ -5567,6 +5573,10 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
case 31876: case 31876:
case 31877: case 31877:
case 31878: case 31878:
// triggered only at casted Judgement spells, not at additional Judgement effects
if(!procSpell || procSpell->Category != 1210)
return false;
target = this; target = this;
triggered_spell_id = 31930; triggered_spell_id = 31930;
@ -11036,7 +11046,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)", sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
(isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId()); (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
HandleMeandingAuraProc(triggeredByAura); HandleMendingAuraProc(triggeredByAura);
break; break;
} }
case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE:
@ -11816,7 +11826,7 @@ bool Unit::IsTriggeredAtSpellProcEvent(Unit *pVictim, Aura* aura, SpellEntry con
return roll_chance_f(chance); return roll_chance_f(chance);
} }
bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura ) bool Unit::HandleMendingAuraProc( Aura* triggeredByAura )
{ {
// aura can be deleted at casts // aura can be deleted at casts
SpellEntry const* spellProto = triggeredByAura->GetSpellProto(); SpellEntry const* spellProto = triggeredByAura->GetSpellProto();
@ -11854,9 +11864,14 @@ bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura )
mod->mask = spellProto->SpellFamilyFlags; mod->mask = spellProto->SpellFamilyFlags;
mod->mask2 = spellProto->SpellFamilyFlags2; mod->mask2 = spellProto->SpellFamilyFlags2;
// remove before apply next (locked against deleted)
triggeredByAura->SetInUse(true);
RemoveAurasByCasterSpell(spellProto->Id,caster->GetGUID());
caster->AddSpellMod(mod, true); caster->AddSpellMod(mod, true);
CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID()); CastCustomSpell(target,spellProto->Id,&heal,NULL,NULL,true,NULL,triggeredByAura,caster->GetGUID());
caster->AddSpellMod(mod, false); caster->AddSpellMod(mod, false);
triggeredByAura->SetInUse(false);
} }
} }
} }

View file

@ -1551,7 +1551,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown); bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
bool HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 cooldown); bool HandleOverrideClassScriptAuraProc(Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 cooldown);
bool HandleMeandingAuraProc(Aura* triggeredByAura); bool HandleMendingAuraProc(Aura* triggeredByAura);
uint32 m_state; // Even derived shouldn't modify uint32 m_state; // Even derived shouldn't modify
uint32 m_CombatTimer; uint32 m_CombatTimer;

View file

@ -160,10 +160,10 @@ bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint3
else else
creature.Say(behavior->textid[0], 0, 0); creature.Say(behavior->textid[0], 0, 0);
} }
} // wpBehaviour found
i_hasDone[idx] = true; i_hasDone[idx] = true;
MovementInform(creature); MovementInform(creature);
} // wpBehaviour found
} // HasDone == false } // HasDone == false
} // i_creature.IsStopped() } // i_creature.IsStopped()

View file

@ -237,6 +237,11 @@ World::AddSession_ (WorldSession* s)
s->SendPacket (&packet); s->SendPacket (&packet);
s->SendAddonsInfo(); s->SendAddonsInfo();
WorldPacket pkt(SMSG_CLIENTCACHE_VERSION, 4);
pkt << uint32(sWorld.getConfig(CONFIG_CLIENTCACHE_VERSION));
s->SendPacket(&pkt);
s->SendTutorialsData(); s->SendTutorialsData();
UpdateMaxSessionCounters (); UpdateMaxSessionCounters ();
@ -673,12 +678,12 @@ void World::LoadConfigSettings(bool reload)
if(reload) if(reload)
{ {
uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", 80); uint32 val = sConfig.GetIntDefault("MaxPlayerLevel", DEFAULT_MAX_LEVEL);
if(val!=m_configs[CONFIG_MAX_PLAYER_LEVEL]) if(val!=m_configs[CONFIG_MAX_PLAYER_LEVEL])
sLog.outError("MaxPlayerLevel option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_MAX_PLAYER_LEVEL]); sLog.outError("MaxPlayerLevel option can't be changed at mangosd.conf reload, using current value (%u).",m_configs[CONFIG_MAX_PLAYER_LEVEL]);
} }
else else
m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", 80); m_configs[CONFIG_MAX_PLAYER_LEVEL] = sConfig.GetIntDefault("MaxPlayerLevel", DEFAULT_MAX_LEVEL);
if(m_configs[CONFIG_MAX_PLAYER_LEVEL] > MAX_LEVEL) if(m_configs[CONFIG_MAX_PLAYER_LEVEL] > MAX_LEVEL)
{ {
@ -867,7 +872,7 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_MAX_OVERSPEED_PINGS] = sConfig.GetIntDefault("MaxOverspeedPings",2); m_configs[CONFIG_MAX_OVERSPEED_PINGS] = sConfig.GetIntDefault("MaxOverspeedPings",2);
if(m_configs[CONFIG_MAX_OVERSPEED_PINGS] != 0 && m_configs[CONFIG_MAX_OVERSPEED_PINGS] < 2) if(m_configs[CONFIG_MAX_OVERSPEED_PINGS] != 0 && m_configs[CONFIG_MAX_OVERSPEED_PINGS] < 2)
{ {
sLog.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check. Set to 2.",m_configs[CONFIG_MAX_OVERSPEED_PINGS]); sLog.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check). Set to 2.",m_configs[CONFIG_MAX_OVERSPEED_PINGS]);
m_configs[CONFIG_MAX_OVERSPEED_PINGS] = 2; m_configs[CONFIG_MAX_OVERSPEED_PINGS] = 2;
} }
@ -954,6 +959,18 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET] = sConfig.GetBoolDefault("OffhandCheckAtTalentsReset", false); m_configs[CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET] = sConfig.GetBoolDefault("OffhandCheckAtTalentsReset", false);
if(int clientCacheId = sConfig.GetIntDefault("ClientCacheVersion", 0))
{
// overwrite DB/old value
if(clientCacheId > 0)
{
m_configs[CONFIG_CLIENTCACHE_VERSION] = clientCacheId;
sLog.outString("Client cache version set to: %u", clientCacheId);
}
else
sLog.outError("ClientCacheVersion can't be negative %d, ignored.", clientCacheId);
}
m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR); m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR);
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
@ -2115,13 +2132,16 @@ void World::UpdateMaxSessionCounters()
void World::LoadDBVersion() void World::LoadDBVersion()
{ {
QueryResult* result = WorldDatabase.Query("SELECT version, creature_ai_version FROM db_version LIMIT 1"); QueryResult* result = WorldDatabase.Query("SELECT version, creature_ai_version, cache_id FROM db_version LIMIT 1");
if(result) if(result)
{ {
Field* fields = result->Fetch(); Field* fields = result->Fetch();
m_DBVersion = fields[0].GetCppString(); m_DBVersion = fields[0].GetCppString();
m_CreatureEventAIVersion = fields[1].GetCppString(); m_CreatureEventAIVersion = fields[1].GetCppString();
// will be overwrite by config values if different and non-0
m_configs[CONFIG_CLIENTCACHE_VERSION] = fields[2].GetUInt32();
delete result; delete result;
} }

View file

@ -212,6 +212,7 @@ enum WorldConfigs
CONFIG_ARENA_SEASON_ID, CONFIG_ARENA_SEASON_ID,
CONFIG_ARENA_SEASON_IN_PROGRESS, CONFIG_ARENA_SEASON_IN_PROGRESS,
CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET, CONFIG_OFFHAND_CHECK_AT_TALENTS_RESET,
CONFIG_CLIENTCACHE_VERSION,
CONFIG_VALUE_COUNT CONFIG_VALUE_COUNT
}; };

View file

@ -569,6 +569,10 @@ LogColors = ""
# Default: 0 - recheck offhand slot weapon only at zone update # Default: 0 - recheck offhand slot weapon only at zone update
# 1 - recheck offhand slot weapon at talent reset also # 1 - recheck offhand slot weapon at talent reset also
# #
# ClientCacheVersion
# Client cache version for client cache data reset. Use any different from DB value and not recently used for triggering reset.
# Default: 0 (use DB value from world DB db_version.cache_id field)
#
# Event.Announce # Event.Announce
# Default: 0 (false) # Default: 0 (false)
# 1 (true) # 1 (true)
@ -627,6 +631,7 @@ MailDeliveryDelay = 3600
SkillChance.Prospecting = 0 SkillChance.Prospecting = 0
SkillChance.Milling = 0 SkillChance.Milling = 0
OffhandCheckAtTalentsReset = 0 OffhandCheckAtTalentsReset = 0
ClientCacheVersion = 0
Event.Announce = 0 Event.Announce = 0
BeepAtStart = 1 BeepAtStart = 1
Motd = "Welcome to the Massive Network Game Object Server." Motd = "Welcome to the Massive Network Game Object Server."

View file

@ -70,4 +70,8 @@ enum LoginResult
#define EXPECTED_MANGOS_CLIENT_BUILD {10257, 0} #define EXPECTED_MANGOS_CLIENT_BUILD {10257, 0}
// At update excepted builds please update if need define DEFAULT_MAX_LEVEL
// in DBCEnum.h to default max player level expected by build
// and also in mangosd.conf.in
#endif #endif

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "8342" #define REVISION_NR "8372"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__