mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 22:37:03 +00:00
Merge commit 'origin/master' into 310
This commit is contained in:
commit
05b1bda879
20 changed files with 299 additions and 38 deletions
|
|
@ -23,7 +23,7 @@ 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_7945_01_mangos_quest_template` bit(1) default NULL
|
`required_7980_01_mangos_item_required_target` 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';
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
@ -1659,6 +1659,27 @@ LOCK TABLES `item_loot_template` WRITE;
|
||||||
/*!40000 ALTER TABLE `item_loot_template` ENABLE KEYS */;
|
/*!40000 ALTER TABLE `item_loot_template` ENABLE KEYS */;
|
||||||
UNLOCK TABLES;
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `item_required_target`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `item_required_target`;
|
||||||
|
CREATE TABLE `item_required_target` (
|
||||||
|
`entry` mediumint(8) unsigned NOT NULL,
|
||||||
|
`type` tinyint(3) unsigned NOT NULL default '0',
|
||||||
|
`targetEntry` mediumint(8) unsigned NOT NULL default '0',
|
||||||
|
UNIQUE KEY `entry_type_target` (`entry`,`type`,`targetEntry`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `item_required_target`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `item_required_target` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `item_required_target` DISABLE KEYS */;
|
||||||
|
/*!40000 ALTER TABLE `item_required_target` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Table structure for table `item_template`
|
-- Table structure for table `item_template`
|
||||||
--
|
--
|
||||||
|
|
|
||||||
9
sql/updates/7980_01_mangos_item_required_target.sql
Normal file
9
sql/updates/7980_01_mangos_item_required_target.sql
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
ALTER TABLE db_version CHANGE COLUMN required_7945_01_mangos_quest_template required_7980_01_mangos_item_required_target bit;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `item_required_target`;
|
||||||
|
CREATE TABLE `item_required_target` (
|
||||||
|
`entry` mediumint(8) unsigned NOT NULL,
|
||||||
|
`type` tinyint(3) unsigned NOT NULL default '0',
|
||||||
|
`targetEntry` mediumint(8) unsigned NOT NULL default '0',
|
||||||
|
UNIQUE KEY `entry_type_target` (`entry`,`type`,`targetEntry`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED
|
||||||
|
|
@ -211,6 +211,7 @@ pkgdata_DATA = \
|
||||||
7932_01_characters_character_pet.sql \
|
7932_01_characters_character_pet.sql \
|
||||||
7938_01_realmd_account.sql \
|
7938_01_realmd_account.sql \
|
||||||
7945_01_mangos_quest_template.sql \
|
7945_01_mangos_quest_template.sql \
|
||||||
|
7980_01_mangos_item_required_target.sql \
|
||||||
README
|
README
|
||||||
|
|
||||||
## Additional files to include when running 'make dist'
|
## Additional files to include when running 'make dist'
|
||||||
|
|
@ -402,4 +403,5 @@ EXTRA_DIST = \
|
||||||
7932_01_characters_character_pet.sql \
|
7932_01_characters_character_pet.sql \
|
||||||
7938_01_realmd_account.sql \
|
7938_01_realmd_account.sql \
|
||||||
7945_01_mangos_quest_template.sql \
|
7945_01_mangos_quest_template.sql \
|
||||||
|
7980_01_mangos_item_required_target.sql \
|
||||||
README
|
README
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,14 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM:
|
||||||
|
if(team.team != ALLIANCE && team.team != HORDE)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM (%u) have unknown team in value1 (%u), ignore.",
|
||||||
|
criteria->ID, criteria->requiredType,dataType,gender.gender);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) have data for not supported data type (%u), ignore.", criteria->ID, criteria->requiredType,dataType);
|
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) have data for not supported data type (%u), ignore.", criteria->ID, criteria->requiredType,dataType);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -263,6 +271,10 @@ bool AchievementCriteriaData::Meets(Player const* source, Unit const* target, ui
|
||||||
return source->GetMap()->GetSpawnMode()==difficalty.difficalty;
|
return source->GetMap()->GetSpawnMode()==difficalty.difficalty;
|
||||||
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT:
|
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT:
|
||||||
return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount;
|
return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount;
|
||||||
|
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM:
|
||||||
|
if (!target || target->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return false;
|
||||||
|
return ((Player*)target)->GetTeam() == team.team;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,13 @@ enum AchievementCriteriaDataType
|
||||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit
|
ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE = 8, // minvalue value provided with achievement update must be not less that limit
|
||||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target
|
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL = 9, // minlevel minlevel of target
|
||||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10,// gender 0=male; 1=female
|
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER = 10,// gender 0=male; 1=female
|
||||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_DISABLED = 11,// used to prevent achievement createria complete if not all requirement implemented and listed in table
|
ACHIEVEMENT_CRITERIA_DATA_TYPE_DISABLED = 11,// used to prevent achievement creteria complete if not all requirement implemented and listed in table
|
||||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12,// difficulty normal/heroic difficulty for current event map
|
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12,// difficulty normal/heroic difficulty for current event map
|
||||||
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13,// count "with less than %u people in the zone"
|
ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13,// count "with less than %u people in the zone"
|
||||||
|
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14,// team HORDE(67), ALLIANCE(469)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 14 // maximum value in AchievementCriteriaDataType enum
|
#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 15 // maximum value in AchievementCriteriaDataType enum
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class Unit;
|
class Unit;
|
||||||
|
|
@ -128,6 +129,11 @@ struct AchievementCriteriaData
|
||||||
{
|
{
|
||||||
uint32 maxcount;
|
uint32 maxcount;
|
||||||
} map_players;
|
} map_players;
|
||||||
|
// ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM = 14
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint32 team;
|
||||||
|
} team;
|
||||||
// ...
|
// ...
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -411,6 +411,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||||
{ "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL },
|
{ "gameobject_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadGameObjectScriptsCommand, "", NULL },
|
||||||
{ "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL },
|
{ "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL },
|
||||||
{ "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL },
|
{ "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL },
|
||||||
|
{ "item_required_target", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemRequiredTragetCommand, "", NULL },
|
||||||
{ "locales_achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesAchievementRewardCommand,"", NULL },
|
{ "locales_achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesAchievementRewardCommand,"", NULL },
|
||||||
{ "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL },
|
{ "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL },
|
||||||
{ "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL },
|
{ "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL },
|
||||||
|
|
|
||||||
|
|
@ -331,6 +331,7 @@ class ChatHandler
|
||||||
bool HandleReloadGOQuestRelationsCommand(const char* args);
|
bool HandleReloadGOQuestRelationsCommand(const char* args);
|
||||||
bool HandleReloadGOQuestInvRelationsCommand(const char* args);
|
bool HandleReloadGOQuestInvRelationsCommand(const char* args);
|
||||||
bool HandleReloadItemEnchantementsCommand(const char* args);
|
bool HandleReloadItemEnchantementsCommand(const char* args);
|
||||||
|
bool HandleReloadItemRequiredTragetCommand(const char* args);
|
||||||
bool HandleReloadLocalesAchievementRewardCommand(const char* args);
|
bool HandleReloadLocalesAchievementRewardCommand(const char* args);
|
||||||
bool HandleReloadLocalesCreatureCommand(const char* args);
|
bool HandleReloadLocalesCreatureCommand(const char* args);
|
||||||
bool HandleReloadLocalesGameobjectCommand(const char* args);
|
bool HandleReloadLocalesGameobjectCommand(const char* args);
|
||||||
|
|
|
||||||
|
|
@ -762,6 +762,23 @@ bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Item::IsTargetValidForItemUse(Unit* pUnitTarget)
|
||||||
|
{
|
||||||
|
ItemRequiredTargetMapBounds bounds = objmgr.GetItemRequiredTargetMapBounds(GetProto()->ItemId);
|
||||||
|
|
||||||
|
if (bounds.first == bounds.second)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!pUnitTarget)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for(ItemRequiredTargetMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
|
||||||
|
if(itr->second.IsFitToRequirements(pUnitTarget))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Item::SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges)
|
void Item::SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges)
|
||||||
{
|
{
|
||||||
// Better lost small time at check in comparison lost time at item save to DB.
|
// Better lost small time at check in comparison lost time at item save to DB.
|
||||||
|
|
@ -967,4 +984,17 @@ bool Item::IsBindedNotWith( Player const* player ) const
|
||||||
{
|
{
|
||||||
return objmgr.GetPlayerAccountIdByGUID(GetOwnerGUID()) != player->GetSession()->GetAccountId();
|
return objmgr.GetPlayerAccountIdByGUID(GetOwnerGUID()) != player->GetSession()->GetAccountId();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemRequiredTarget::IsFitToRequirements( Unit* pUnitTarget ) const
|
||||||
|
{
|
||||||
|
switch(m_uiType)
|
||||||
|
{
|
||||||
|
case ITEM_TARGET_TYPE_CREATURE:
|
||||||
|
return pUnitTarget->isAlive();
|
||||||
|
case ITEM_TARGET_TYPE_DEAD:
|
||||||
|
return !pUnitTarget->isAlive();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
struct SpellEntry;
|
struct SpellEntry;
|
||||||
class Bag;
|
class Bag;
|
||||||
class QueryResult;
|
class QueryResult;
|
||||||
|
class Unit;
|
||||||
|
|
||||||
struct ItemSetEffect
|
struct ItemSetEffect
|
||||||
{
|
{
|
||||||
|
|
@ -195,6 +196,24 @@ enum ItemUpdateState
|
||||||
ITEM_REMOVED = 3
|
ITEM_REMOVED = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ItemRequiredTargetType
|
||||||
|
{
|
||||||
|
ITEM_TARGET_TYPE_CREATURE = 1,
|
||||||
|
ITEM_TARGET_TYPE_DEAD = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_ITEM_REQ_TARGET_TYPE 2
|
||||||
|
|
||||||
|
struct ItemRequiredTarget
|
||||||
|
{
|
||||||
|
ItemRequiredTarget(ItemRequiredTargetType uiType, uint32 uiTargetEntry) : m_uiType(uiType), m_uiTargetEntry(uiTargetEntry) {}
|
||||||
|
ItemRequiredTargetType m_uiType;
|
||||||
|
uint32 m_uiTargetEntry;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
bool IsFitToRequirements(Unit* pUnitTarget) const;
|
||||||
|
};
|
||||||
|
|
||||||
bool ItemCanGoIntoBag(ItemPrototype const *proto, ItemPrototype const *pBagProto);
|
bool ItemCanGoIntoBag(ItemPrototype const *proto, ItemPrototype const *pBagProto);
|
||||||
|
|
||||||
class MANGOS_DLL_SPEC Item : public Object
|
class MANGOS_DLL_SPEC Item : public Object
|
||||||
|
|
@ -230,6 +249,7 @@ class MANGOS_DLL_SPEC Item : public Object
|
||||||
bool IsInTrade() const { return mb_in_trade; }
|
bool IsInTrade() const { return mb_in_trade; }
|
||||||
|
|
||||||
bool IsFitToSpellRequirements(SpellEntry const* spellInfo) const;
|
bool IsFitToSpellRequirements(SpellEntry const* spellInfo) const;
|
||||||
|
bool IsTargetValidForItemUse(Unit* pUnitTarget);
|
||||||
bool IsLimitedToAnotherMapOrZone( uint32 cur_mapId, uint32 cur_zoneId) const;
|
bool IsLimitedToAnotherMapOrZone( uint32 cur_mapId, uint32 cur_zoneId) const;
|
||||||
bool GemsFitSockets() const;
|
bool GemsFitSockets() const;
|
||||||
|
|
||||||
|
|
@ -292,6 +312,7 @@ class MANGOS_DLL_SPEC Item : public Object
|
||||||
bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; }
|
bool hasInvolvedQuest(uint32 /*quest_id*/) const { return false; }
|
||||||
bool IsPotion() const { return GetProto()->IsPotion(); }
|
bool IsPotion() const { return GetProto()->IsPotion(); }
|
||||||
bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); }
|
bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8 m_slot;
|
uint8 m_slot;
|
||||||
Bag *m_container;
|
Bag *m_container;
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,7 @@ bool ChatHandler::HandleReloadAllItemCommand(const char*)
|
||||||
{
|
{
|
||||||
HandleReloadPageTextsCommand("a");
|
HandleReloadPageTextsCommand("a");
|
||||||
HandleReloadItemEnchantementsCommand("a");
|
HandleReloadItemEnchantementsCommand("a");
|
||||||
|
HandleReloadItemRequiredTragetCommand("a");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -584,6 +585,14 @@ bool ChatHandler::HandleReloadItemEnchantementsCommand(const char*)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ChatHandler::HandleReloadItemRequiredTragetCommand(const char*)
|
||||||
|
{
|
||||||
|
sLog.outString( "Re-Loading Item Required Targets Table..." );
|
||||||
|
objmgr.LoadItemRequiredTarget();
|
||||||
|
SendGlobalSysMessage("DB table `item_required_target` reloaded.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ChatHandler::HandleReloadGameObjectScriptsCommand(const char* arg)
|
bool ChatHandler::HandleReloadGameObjectScriptsCommand(const char* arg)
|
||||||
{
|
{
|
||||||
if(sWorld.IsScriptScheduled())
|
if(sWorld.IsScriptScheduled())
|
||||||
|
|
|
||||||
|
|
@ -1810,6 +1810,106 @@ void ObjectMgr::LoadItemPrototypes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectMgr::LoadItemRequiredTarget()
|
||||||
|
{
|
||||||
|
m_ItemRequiredTarget.clear(); // needed for reload case
|
||||||
|
|
||||||
|
uint32 count = 0;
|
||||||
|
|
||||||
|
QueryResult *result = WorldDatabase.Query("SELECT entry,type,targetEntry FROM item_required_target");
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
barGoLink bar(1);
|
||||||
|
|
||||||
|
bar.step();
|
||||||
|
|
||||||
|
sLog.outString();
|
||||||
|
sLog.outErrorDb(">> Loaded 0 ItemRequiredTarget. DB table `item_required_target` is empty.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
barGoLink bar(result->GetRowCount());
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field *fields = result->Fetch();
|
||||||
|
bar.step();
|
||||||
|
|
||||||
|
uint32 uiItemId = fields[0].GetUInt32();
|
||||||
|
uint32 uiType = fields[1].GetUInt32();
|
||||||
|
uint32 uiTargetEntry = fields[2].GetUInt32();
|
||||||
|
|
||||||
|
ItemPrototype const* pItemProto = sItemStorage.LookupEntry<ItemPrototype>(uiItemId);
|
||||||
|
|
||||||
|
if (!pItemProto)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Table `item_required_target`: Entry %u listed for TargetEntry %u does not exist in `item_template`.",uiItemId,uiTargetEntry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bIsItemSpellValid = false;
|
||||||
|
|
||||||
|
for(int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||||
|
{
|
||||||
|
if (SpellEntry const* pSpellInfo = sSpellStore.LookupEntry(pItemProto->Spells[i].SpellId))
|
||||||
|
{
|
||||||
|
if (pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE ||
|
||||||
|
pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
|
||||||
|
{
|
||||||
|
SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(pSpellInfo->Id);
|
||||||
|
SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(pSpellInfo->Id);
|
||||||
|
|
||||||
|
if (lower != upper)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pSpellInfo->EffectImplicitTargetA[i] == TARGET_CHAIN_DAMAGE ||
|
||||||
|
pSpellInfo->EffectImplicitTargetB[i] == TARGET_CHAIN_DAMAGE ||
|
||||||
|
pSpellInfo->EffectImplicitTargetA[i] == TARGET_DUELVSPLAYER ||
|
||||||
|
pSpellInfo->EffectImplicitTargetB[i] == TARGET_DUELVSPLAYER)
|
||||||
|
{
|
||||||
|
bIsItemSpellValid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bIsItemSpellValid)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Table `item_required_target`: Spell used by item %u does not have implicit target TARGET_CHAIN_DAMAGE(6), TARGET_DUELVSPLAYER(25), already listed in `spell_script_target` or doesn't have item spelltrigger.",uiItemId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uiType || uiType > MAX_ITEM_REQ_TARGET_TYPE)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Table `item_required_target`: Type %u for TargetEntry %u is incorrect.",uiType,uiTargetEntry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uiTargetEntry)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Table `item_required_target`: TargetEntry == 0 for Type (%u).",uiType);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sCreatureStorage.LookupEntry<CreatureInfo>(uiTargetEntry))
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Table `item_required_target`: creature template entry %u does not exist.",uiTargetEntry);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ItemRequiredTarget.insert(ItemRequiredTargetMap::value_type(uiItemId,ItemRequiredTarget(ItemRequiredTargetType(uiType),uiTargetEntry)));
|
||||||
|
|
||||||
|
++count;
|
||||||
|
} while (result->NextRow());
|
||||||
|
|
||||||
|
delete result;
|
||||||
|
|
||||||
|
sLog.outString();
|
||||||
|
sLog.outString(">> Loaded %u Item required targets", count);
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectMgr::LoadPetLevelInfo()
|
void ObjectMgr::LoadPetLevelInfo()
|
||||||
{
|
{
|
||||||
// Loading levels data
|
// Loading levels data
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,8 @@ typedef UNORDERED_MAP<uint32,NpcOptionLocale> NpcOptionLocaleMap;
|
||||||
typedef UNORDERED_MAP<uint32,PointOfInterestLocale> PointOfInterestLocaleMap;
|
typedef UNORDERED_MAP<uint32,PointOfInterestLocale> PointOfInterestLocaleMap;
|
||||||
|
|
||||||
typedef std::multimap<uint32,uint32> QuestRelations;
|
typedef std::multimap<uint32,uint32> QuestRelations;
|
||||||
|
typedef std::multimap<uint32,ItemRequiredTarget> ItemRequiredTargetMap;
|
||||||
|
typedef std::pair<ItemRequiredTargetMap::const_iterator, ItemRequiredTargetMap::const_iterator> ItemRequiredTargetMapBounds;
|
||||||
|
|
||||||
struct PetLevelInfo
|
struct PetLevelInfo
|
||||||
{
|
{
|
||||||
|
|
@ -498,6 +500,7 @@ class ObjectMgr
|
||||||
void LoadGameobjects();
|
void LoadGameobjects();
|
||||||
void LoadGameobjectRespawnTimes();
|
void LoadGameobjectRespawnTimes();
|
||||||
void LoadItemPrototypes();
|
void LoadItemPrototypes();
|
||||||
|
void LoadItemRequiredTarget();
|
||||||
void LoadItemLocales();
|
void LoadItemLocales();
|
||||||
void LoadQuestLocales();
|
void LoadQuestLocales();
|
||||||
void LoadNpcTextLocales();
|
void LoadNpcTextLocales();
|
||||||
|
|
@ -752,6 +755,12 @@ class ObjectMgr
|
||||||
uint32 GetScriptId(const char *name);
|
uint32 GetScriptId(const char *name);
|
||||||
|
|
||||||
int GetOrNewIndexForLocale(LocaleConstant loc);
|
int GetOrNewIndexForLocale(LocaleConstant loc);
|
||||||
|
|
||||||
|
ItemRequiredTargetMapBounds GetItemRequiredTargetMapBounds(uint32 uiItemEntry) const
|
||||||
|
{
|
||||||
|
return ItemRequiredTargetMapBounds(m_ItemRequiredTarget.lower_bound(uiItemEntry),m_ItemRequiredTarget.upper_bound(uiItemEntry));
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// first free id for selected id type
|
// first free id for selected id type
|
||||||
|
|
@ -810,6 +819,8 @@ class ObjectMgr
|
||||||
|
|
||||||
ScriptNameMap m_scriptNames;
|
ScriptNameMap m_scriptNames;
|
||||||
|
|
||||||
|
ItemRequiredTargetMap m_ItemRequiredTarget;
|
||||||
|
|
||||||
typedef std::vector<LocaleConstant> LocalForIndex;
|
typedef std::vector<LocaleConstant> LocalForIndex;
|
||||||
LocalForIndex m_LocalForIndex;
|
LocalForIndex m_LocalForIndex;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -245,19 +245,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
|
if(pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
|
||||||
{
|
Spell::SendCastResult(GetPlayer(),spellInfo,0,result);
|
||||||
WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
|
|
||||||
data << uint8(0) << uint32(spellid) << uint8(result);
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
|
|
||||||
data << uint32(spellInfo->RequiresSpellFocus);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
SendPacket(&data);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
pet->SendPetCastFail(spellid, result);
|
pet->SendPetCastFail(spellid, result);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2862,18 +2862,26 @@ void Spell::SendCastResult(SpellCastResult result)
|
||||||
if(((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time
|
if(((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
SendCastResult((Player*)m_caster,m_spellInfo,m_cast_count,result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spell::SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result)
|
||||||
|
{
|
||||||
|
if(result == SPELL_CAST_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
|
WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
|
||||||
data << uint8(m_cast_count); // single cast or multi 2.3 (0/1)
|
data << uint8(cast_count); // single cast or multi 2.3 (0/1)
|
||||||
data << uint32(m_spellInfo->Id);
|
data << uint32(spellInfo->Id);
|
||||||
data << uint8(result); // problem
|
data << uint8(result); // problem
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
|
case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
|
||||||
data << uint32(m_spellInfo->RequiresSpellFocus);
|
data << uint32(spellInfo->RequiresSpellFocus);
|
||||||
break;
|
break;
|
||||||
case SPELL_FAILED_REQUIRES_AREA:
|
case SPELL_FAILED_REQUIRES_AREA:
|
||||||
// hardcode areas limitation case
|
// hardcode areas limitation case
|
||||||
switch(m_spellInfo->Id)
|
switch(spellInfo->Id)
|
||||||
{
|
{
|
||||||
case 41617: // Cenarion Mana Salve
|
case 41617: // Cenarion Mana Salve
|
||||||
case 41619: // Cenarion Healing Salve
|
case 41619: // Cenarion Healing Salve
|
||||||
|
|
@ -2892,26 +2900,26 @@ void Spell::SendCastResult(SpellCastResult result)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPELL_FAILED_TOTEMS:
|
case SPELL_FAILED_TOTEMS:
|
||||||
if(m_spellInfo->Totem[0])
|
if(spellInfo->Totem[0])
|
||||||
data << uint32(m_spellInfo->Totem[0]);
|
data << uint32(spellInfo->Totem[0]);
|
||||||
if(m_spellInfo->Totem[1])
|
if(spellInfo->Totem[1])
|
||||||
data << uint32(m_spellInfo->Totem[1]);
|
data << uint32(spellInfo->Totem[1]);
|
||||||
break;
|
break;
|
||||||
case SPELL_FAILED_TOTEM_CATEGORY:
|
case SPELL_FAILED_TOTEM_CATEGORY:
|
||||||
if(m_spellInfo->TotemCategory[0])
|
if(spellInfo->TotemCategory[0])
|
||||||
data << uint32(m_spellInfo->TotemCategory[0]);
|
data << uint32(spellInfo->TotemCategory[0]);
|
||||||
if(m_spellInfo->TotemCategory[1])
|
if(spellInfo->TotemCategory[1])
|
||||||
data << uint32(m_spellInfo->TotemCategory[1]);
|
data << uint32(spellInfo->TotemCategory[1]);
|
||||||
break;
|
break;
|
||||||
case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
|
case SPELL_FAILED_EQUIPPED_ITEM_CLASS:
|
||||||
data << uint32(m_spellInfo->EquippedItemClass);
|
data << uint32(spellInfo->EquippedItemClass);
|
||||||
data << uint32(m_spellInfo->EquippedItemSubClassMask);
|
data << uint32(spellInfo->EquippedItemSubClassMask);
|
||||||
//data << uint32(m_spellInfo->EquippedItemInventoryTypeMask);
|
//data << uint32(spellInfo->EquippedItemInventoryTypeMask);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
((Player*)m_caster)->GetSession()->SendPacket(&data);
|
caster->GetSession()->SendPacket(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spell::SendSpellStart()
|
void Spell::SendSpellStart()
|
||||||
|
|
|
||||||
|
|
@ -386,6 +386,7 @@ class Spell
|
||||||
bool CheckTarget( Unit* target, uint32 eff );
|
bool CheckTarget( Unit* target, uint32 eff );
|
||||||
bool CanAutoCast(Unit* target);
|
bool CanAutoCast(Unit* target);
|
||||||
|
|
||||||
|
static void SendCastResult(Player* caster, SpellEntry const* spellInfo, uint8 cast_count, SpellCastResult result);
|
||||||
void SendCastResult(SpellCastResult result);
|
void SendCastResult(SpellCastResult result);
|
||||||
void SendSpellStart();
|
void SendSpellStart();
|
||||||
void SendSpellGo();
|
void SendSpellGo();
|
||||||
|
|
|
||||||
|
|
@ -119,9 +119,30 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
|
||||||
}
|
}
|
||||||
|
|
||||||
SpellCastTargets targets;
|
SpellCastTargets targets;
|
||||||
if(!targets.read(&recvPacket, pUser))
|
if (!targets.read(&recvPacket, pUser))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
targets.Update(pUser);
|
||||||
|
|
||||||
|
if (!pItem->IsTargetValidForItemUse(targets.getUnitTarget()))
|
||||||
|
{
|
||||||
|
// free greay item aftre use faul
|
||||||
|
pUser->SendEquipError(EQUIP_ERR_NONE, pItem, NULL);
|
||||||
|
|
||||||
|
// send spell error
|
||||||
|
if (SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid))
|
||||||
|
{
|
||||||
|
// for implicit area/coord target spells
|
||||||
|
if (IsPointEffectTarget(Targets(spellInfo->EffectImplicitTargetA[0])) ||
|
||||||
|
IsAreaEffectTarget(Targets(spellInfo->EffectImplicitTargetA[0])))
|
||||||
|
Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_NO_VALID_TARGETS);
|
||||||
|
// for explicit target spells
|
||||||
|
else
|
||||||
|
Spell::SendCastResult(_player,spellInfo,cast_count,SPELL_FAILED_BAD_TARGETS);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
|
//Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
|
||||||
if(!Script->ItemUse(pUser,pItem,targets))
|
if(!Script->ItemUse(pUser,pItem,targets))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,24 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI
|
||||||
|
|
||||||
bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId);
|
bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId);
|
||||||
|
|
||||||
|
inline bool IsPointEffectTarget( Targets target )
|
||||||
|
{
|
||||||
|
switch (target )
|
||||||
|
{
|
||||||
|
case TARGET_INNKEEPER_COORDINATES:
|
||||||
|
case TARGET_TABLE_X_Y_Z_COORDINATES:
|
||||||
|
case TARGET_CASTER_COORDINATES:
|
||||||
|
case TARGET_SCRIPT_COORDINATES:
|
||||||
|
case TARGET_CURRENT_ENEMY_COORDINATES:
|
||||||
|
case TARGET_DUELVSPLAYER_COORDINATES:
|
||||||
|
case TARGET_DYNAMIC_OBJECT_COORDINATES:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool IsAreaEffectTarget( Targets target )
|
inline bool IsAreaEffectTarget( Targets target )
|
||||||
{
|
{
|
||||||
switch (target )
|
switch (target )
|
||||||
|
|
|
||||||
|
|
@ -1154,6 +1154,9 @@ void World::SetInitialWorldSettings()
|
||||||
sLog.outString( "Loading SpellsScriptTarget...");
|
sLog.outString( "Loading SpellsScriptTarget...");
|
||||||
spellmgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo
|
spellmgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo
|
||||||
|
|
||||||
|
sLog.outString( "Loading ItemRequiredTarget...");
|
||||||
|
objmgr.LoadItemRequiredTarget();
|
||||||
|
|
||||||
sLog.outString( "Loading Creature Reputation OnKill Data..." );
|
sLog.outString( "Loading Creature Reputation OnKill Data..." );
|
||||||
objmgr.LoadReputationOnKill();
|
objmgr.LoadReputationOnKill();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
char* px = strtok((char*)args, " ");
|
char* px = strtok((char*)args, " ");
|
||||||
if(!px)
|
if (!px)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint8 failnum = (uint8)atoi(px);
|
uint8 failnum = (uint8)atoi(px);
|
||||||
|
|
@ -50,14 +50,13 @@ bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args)
|
||||||
char* p2 = strtok(NULL, " ");
|
char* p2 = strtok(NULL, " ");
|
||||||
uint8 failarg2 = p2 ? (uint8)atoi(p2) : 0;
|
uint8 failarg2 = p2 ? (uint8)atoi(p2) : 0;
|
||||||
|
|
||||||
|
|
||||||
WorldPacket data(SMSG_CAST_FAILED, 5);
|
WorldPacket data(SMSG_CAST_FAILED, 5);
|
||||||
data << uint8(0);
|
data << uint8(0);
|
||||||
data << uint32(133);
|
data << uint32(133);
|
||||||
data << uint8(failnum);
|
data << uint8(failnum);
|
||||||
if(p1 || p2)
|
if (p1 || p2)
|
||||||
data << uint32(failarg1);
|
data << uint32(failarg1);
|
||||||
if(p2)
|
if (p2)
|
||||||
data << uint32(failarg2);
|
data << uint32(failarg2);
|
||||||
|
|
||||||
m_session->SendPacket(&data);
|
m_session->SendPacket(&data);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __REVISION_NR_H__
|
#ifndef __REVISION_NR_H__
|
||||||
#define __REVISION_NR_H__
|
#define __REVISION_NR_H__
|
||||||
#define REVISION_NR "7979"
|
#define REVISION_NR "7981"
|
||||||
#endif // __REVISION_NR_H__
|
#endif // __REVISION_NR_H__
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue