*Merge some fixes from tc1
--HG-- branch : trunk
This commit is contained in:
@@ -407,7 +407,14 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri
|
||||
do
|
||||
{
|
||||
Field *fields = achievementResult->Fetch();
|
||||
CompletedAchievementData& ca = m_completedAchievements[fields[0].GetUInt32()];
|
||||
|
||||
uint32 achievement_id = fields[0].GetUInt32();
|
||||
|
||||
// don't must happen: cleanup at server startup in achievementmgr.LoadCompletedAchievements()
|
||||
if(!sAchievementStore.LookupEntry(achievement_id))
|
||||
continue;
|
||||
|
||||
CompletedAchievementData& ca = m_completedAchievements[achievement_id];
|
||||
ca.date = time_t(fields[1].GetUInt64());
|
||||
ca.changed = false;
|
||||
} while(achievementResult->NextRow());
|
||||
@@ -425,7 +432,15 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri
|
||||
time_t date = time_t(fields[2].GetUInt64());
|
||||
|
||||
AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(id);
|
||||
if (!criteria || (criteria->timeLimit && time_t(date + criteria->timeLimit) < time(NULL)))
|
||||
if (!criteria)
|
||||
{
|
||||
// we will remove not existed criteria for all characters
|
||||
sLog.outError("Not existed achievement creataria %u data removed from table `character_achievement_progress`.",id);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE criteria = %u",id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (criteria->timeLimit && time_t(date + criteria->timeLimit) < time(NULL))
|
||||
continue;
|
||||
|
||||
CriteriaProgress& progress = m_criteriaProgress[id];
|
||||
@@ -1763,7 +1778,17 @@ void AchievementGlobalMgr::LoadCompletedAchievements()
|
||||
{
|
||||
bar.step();
|
||||
Field *fields = result->Fetch();
|
||||
m_allCompletedAchievements.insert(fields[0].GetUInt32());
|
||||
|
||||
uint32 achievement_id = fields[0].GetUInt32();
|
||||
if(!sAchievementStore.LookupEntry(achievement_id))
|
||||
{
|
||||
// we will remove not existed achievement for all characters
|
||||
sLog.outError("Not existed achievement %u data removed from table `character_achievement`.",achievement_id);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE achievement = %u",achievement_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
m_allCompletedAchievements.insert(achievement_id);
|
||||
} while(result->NextRow());
|
||||
|
||||
delete result;
|
||||
|
||||
+73
-76
@@ -19,16 +19,9 @@
|
||||
*/
|
||||
|
||||
#include "AggressorAI.h"
|
||||
#include "Errors.h"
|
||||
#include "Creature.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "VMapFactory.h"
|
||||
#include "World.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
int
|
||||
AggressorAI::Permissible(const Creature *creature)
|
||||
int AggressorAI::Permissible(const Creature *creature)
|
||||
{
|
||||
// have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight
|
||||
if( !creature->isCivilian() && !creature->IsNeutralToAll() )
|
||||
@@ -37,79 +30,83 @@ AggressorAI::Permissible(const Creature *creature)
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
AggressorAI::AggressorAI(Creature *c) : CreatureAI(c), i_victimGuid(0), i_state(STATE_NORMAL), i_tracker(TIME_INTERVAL_LOOK)
|
||||
void AggressorAI::UpdateAI(const uint32 /*diff*/)
|
||||
{
|
||||
}
|
||||
|
||||
void AggressorAI::EnterEvadeMode()
|
||||
{
|
||||
if( !m_creature->isAlive() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking cuz his dead [guid=%u]", m_creature->GetGUIDLow());
|
||||
i_victimGuid = 0;
|
||||
m_creature->CombatStop(true);
|
||||
m_creature->DeleteThreatList();
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* victim = ObjectAccessor::GetUnit(*m_creature, i_victimGuid );
|
||||
|
||||
if( !victim )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking because victim is non exist [guid=%u]", m_creature->GetGUIDLow());
|
||||
}
|
||||
else if( !victim->isAlive() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking cuz his victim is dead [guid=%u]", m_creature->GetGUIDLow());
|
||||
}
|
||||
else if( victim->HasStealthAura() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking cuz his victim is stealth [guid=%u]", m_creature->GetGUIDLow());
|
||||
}
|
||||
else if( victim->isInFlight() )
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking cuz his victim is fly away [guid=%u]", m_creature->GetGUIDLow());
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_LOG("Creature stopped attacking due to target out run him [guid=%u]", m_creature->GetGUIDLow());
|
||||
//i_state = STATE_LOOK_AT_VICTIM;
|
||||
//i_tracker.Reset(TIME_INTERVAL_LOOK);
|
||||
}
|
||||
|
||||
if(!m_creature->GetCharmerOrOwner())
|
||||
{
|
||||
m_creature->RemoveAllAuras();
|
||||
|
||||
// Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
|
||||
if( m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
|
||||
m_creature->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
else if (m_creature->GetOwner() && m_creature->GetOwner()->isAlive())
|
||||
m_creature->GetMotionMaster()->MoveFollow(m_creature->GetOwner(),PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
|
||||
|
||||
m_creature->DeleteThreatList();
|
||||
i_victimGuid = 0;
|
||||
m_creature->CombatStop(true);
|
||||
m_creature->SetLootRecipient(NULL);
|
||||
}
|
||||
|
||||
void
|
||||
AggressorAI::UpdateAI(const uint32 /*diff*/)
|
||||
{
|
||||
// update i_victimGuid if m_creature->getVictim() !=0 and changed
|
||||
if(!UpdateVictim())
|
||||
return;
|
||||
|
||||
i_victimGuid = m_creature->getVictim()->GetGUID();
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
if( m_creature->isAttackReady() )
|
||||
int SpellAI::Permissible(const Creature *creature)
|
||||
{
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
void SpellAI::InitializeAI()
|
||||
{
|
||||
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
if(me->m_spells[i] && GetSpellStore()->LookupEntry(me->m_spells[i]))
|
||||
spells.push_back(me->m_spells[i]);
|
||||
}
|
||||
|
||||
void SpellAI::Reset()
|
||||
{
|
||||
events.Reset();
|
||||
}
|
||||
|
||||
void SpellAI::JustDied(Unit *killer)
|
||||
{
|
||||
for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
|
||||
if(AISpellInfo[*i].condition == AICOND_DIE)
|
||||
me->CastSpell(killer, *i, true);
|
||||
}
|
||||
|
||||
void SpellAI::EnterCombat(Unit *who)
|
||||
{
|
||||
for(SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
|
||||
{
|
||||
if( m_creature->IsWithinMeleeRange(m_creature->getVictim()))
|
||||
{
|
||||
m_creature->AttackerStateUpdate(m_creature->getVictim());
|
||||
m_creature->resetAttackTimer();
|
||||
}
|
||||
if(AISpellInfo[*i].condition == AICOND_AGGRO)
|
||||
me->CastSpell(who, *i, true);
|
||||
else if(AISpellInfo[*i].condition == AICOND_COMBAT)
|
||||
events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand()%AISpellInfo[*i].cooldown);
|
||||
}
|
||||
}
|
||||
|
||||
void SpellAI::UpdateAI(const uint32 diff)
|
||||
{
|
||||
if(!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if(me->hasUnitState(UNIT_STAT_CASTING))
|
||||
return;
|
||||
|
||||
if(uint32 spellId = events.ExecuteEvent())
|
||||
{
|
||||
Unit *target = NULL;
|
||||
//sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target);
|
||||
switch(AISpellInfo[spellId].target)
|
||||
{
|
||||
default:
|
||||
case AITARGET_SELF: target = me; break;
|
||||
case AITARGET_VICTIM: target = me->getVictim(); break;
|
||||
case AITARGET_ENEMY: target = SelectTarget(SELECT_TARGET_RANDOM); break;
|
||||
case AITARGET_ALLY: target = me; break;
|
||||
case AITARGET_BUFF: target = me; break;
|
||||
case AITARGET_DEBUFF:
|
||||
{
|
||||
const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId);
|
||||
bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY;
|
||||
float range = GetSpellMaxRange(spellInfo, false);
|
||||
target = SelectTarget(SELECT_TARGET_RANDOM, 0, range, playerOnly, -(int32)spellId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(target) me->CastSpell(target, spellId, false);
|
||||
events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown);
|
||||
}
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
+21
-17
@@ -22,31 +22,35 @@
|
||||
#define TRINITY_AGGRESSORAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Timer.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
|
||||
class Creature;
|
||||
|
||||
class TRINITY_DLL_DECL AggressorAI : public CreatureAI
|
||||
{
|
||||
enum AggressorState
|
||||
{
|
||||
STATE_NORMAL = 1,
|
||||
STATE_LOOK_AT_VICTIM = 2
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
explicit AggressorAI(Creature *c);
|
||||
|
||||
void EnterEvadeMode();
|
||||
explicit AggressorAI(Creature *c) : CreatureAI(c) {}
|
||||
|
||||
void UpdateAI(const uint32);
|
||||
static int Permissible(const Creature *);
|
||||
|
||||
private:
|
||||
uint64 i_victimGuid;
|
||||
AggressorState i_state;
|
||||
TimeTracker i_tracker;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef std::vector<uint32> SpellVct;
|
||||
|
||||
class TRINITY_DLL_SPEC SpellAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit SpellAI(Creature *c) : CreatureAI(c) {}
|
||||
|
||||
void InitializeAI();
|
||||
void Reset();
|
||||
void EnterCombat(Unit* who);
|
||||
void JustDied(Unit *killer);
|
||||
void UpdateAI(const uint32 diff);
|
||||
static int Permissible(const Creature *);
|
||||
private:
|
||||
EventMap events;
|
||||
SpellVct spells;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+50
-31
@@ -726,12 +726,10 @@ void BattleGround::EndBattleGround(uint32 winner)
|
||||
if (team == winner)
|
||||
{
|
||||
RewardMark(plr,ITEM_WINNER_COUNT);
|
||||
RewardQuest(plr);
|
||||
RewardQuestComplete(plr);
|
||||
}
|
||||
else if(winner !=0)
|
||||
{
|
||||
else if(winner)
|
||||
RewardMark(plr,ITEM_LOSER_COUNT);
|
||||
}
|
||||
|
||||
plr->CombatStopWithPets(true);
|
||||
|
||||
@@ -785,13 +783,6 @@ uint32 BattleGround::GetBattlemasterEntry() const
|
||||
|
||||
void BattleGround::RewardMark(Player *plr,uint32 count)
|
||||
{
|
||||
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
|
||||
if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
|
||||
return;
|
||||
|
||||
if(!plr || !count)
|
||||
return;
|
||||
|
||||
BattleGroundMarks mark;
|
||||
switch(GetTypeID())
|
||||
{
|
||||
@@ -811,21 +802,53 @@ void BattleGround::RewardMark(Player *plr,uint32 count)
|
||||
return;
|
||||
}
|
||||
|
||||
if ( objmgr.GetItemPrototype( mark ) )
|
||||
//if (IsSpell)
|
||||
// RewardSpellCast(plr,mark);
|
||||
//else
|
||||
RewardItem(plr,mark,count);
|
||||
}
|
||||
|
||||
void BattleGround::RewardSpellCast(Player *plr, uint32 spell_id)
|
||||
{
|
||||
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
|
||||
if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
|
||||
return;
|
||||
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||
if(!spellInfo)
|
||||
{
|
||||
ItemPosCountVec dest;
|
||||
uint32 no_space_count = 0;
|
||||
uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
|
||||
if( msg != EQUIP_ERR_OK ) // convert to possible store amount
|
||||
count -= no_space_count;
|
||||
|
||||
if(!dest.empty()) // can add some
|
||||
if(Item* item = plr->StoreNewItem( dest, mark, true, 0))
|
||||
plr->SendNewItem(item,count,false,true);
|
||||
|
||||
if (no_space_count > 0)
|
||||
SendRewardMarkByMail(plr,mark,no_space_count);
|
||||
sLog.outError("Battleground reward casting spell %u not exist.",spell_id);
|
||||
return;
|
||||
}
|
||||
|
||||
plr->CastSpell(plr, spellInfo, true);
|
||||
}
|
||||
|
||||
void BattleGround::RewardItem(Player *plr, uint32 item_id, uint32 count)
|
||||
{
|
||||
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
|
||||
if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
|
||||
return;
|
||||
|
||||
ItemPosCountVec dest;
|
||||
uint32 no_space_count = 0;
|
||||
uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item_id, count, &no_space_count );
|
||||
|
||||
if( msg == EQUIP_ERR_ITEM_NOT_FOUND)
|
||||
{
|
||||
sLog.outErrorDb("Battleground reward item (Entry %u) not exist in `item_template`.",item_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if( msg != EQUIP_ERR_OK ) // convert to possible store amount
|
||||
count -= no_space_count;
|
||||
|
||||
if( count != 0 && !dest.empty()) // can add some
|
||||
if (Item* item = plr->StoreNewItem( dest, item_id, true, 0))
|
||||
plr->SendNewItem(item,count,false,true);
|
||||
|
||||
if (no_space_count > 0)
|
||||
SendRewardMarkByMail(plr,item_id,no_space_count);
|
||||
}
|
||||
|
||||
void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
|
||||
@@ -865,12 +888,8 @@ void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
|
||||
}
|
||||
}
|
||||
|
||||
void BattleGround::RewardQuest(Player *plr)
|
||||
void BattleGround::RewardQuestComplete(Player *plr)
|
||||
{
|
||||
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
|
||||
if (plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
|
||||
return;
|
||||
|
||||
uint32 quest;
|
||||
switch(GetTypeID())
|
||||
{
|
||||
@@ -890,7 +909,7 @@ void BattleGround::RewardQuest(Player *plr)
|
||||
return;
|
||||
}
|
||||
|
||||
plr->CastSpell(plr, quest, true);
|
||||
RewardSpellCast(plr, quest);
|
||||
}
|
||||
|
||||
void BattleGround::BlockMovement(Player *plr)
|
||||
@@ -1739,7 +1758,7 @@ uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
|
||||
if (itr->second.Team == Team)
|
||||
{
|
||||
Player * pl = objmgr.GetPlayer(itr->first);
|
||||
if (pl && pl->isAlive())
|
||||
if (pl && pl->isAlive() && !pl->HasByteFlag(UNIT_FIELD_BYTES_2, 3, FORM_SPIRITOFREDEMPTION))
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +421,9 @@ class BattleGround
|
||||
void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID);
|
||||
void RewardMark(Player *plr,uint32 count);
|
||||
void SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count);
|
||||
void RewardQuest(Player *plr);
|
||||
void RewardItem(Player *plr, uint32 item_id, uint32 count);
|
||||
void RewardQuestComplete(Player *plr);
|
||||
void RewardSpellCast(Player *plr, uint32 spell_id);
|
||||
void UpdateWorldState(uint32 Field, uint32 Value);
|
||||
void UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source);
|
||||
void EndBattleGround(uint32 winner);
|
||||
|
||||
@@ -68,6 +68,7 @@ SET(game_STAT_SRCS
|
||||
Corpse.h
|
||||
CreatureAI.cpp
|
||||
CreatureAI.h
|
||||
CreatureAIFactory.h
|
||||
CreatureAIImpl.h
|
||||
CreatureAIRegistry.cpp
|
||||
CreatureAIRegistry.h
|
||||
@@ -208,8 +209,6 @@ SET(game_STAT_SRCS
|
||||
PointMovementGenerator.h
|
||||
PoolHandler.cpp
|
||||
PoolHandler.h
|
||||
PossessedAI.cpp
|
||||
PossessedAI.h
|
||||
QueryHandler.cpp
|
||||
QuestDef.cpp
|
||||
QuestDef.h
|
||||
@@ -262,6 +261,8 @@ SET(game_STAT_SRCS
|
||||
Traveller.h
|
||||
Unit.cpp
|
||||
Unit.h
|
||||
UnitAI.cpp
|
||||
UnitAI.h
|
||||
UnitEvents.h
|
||||
UpdateData.cpp
|
||||
UpdateData.h
|
||||
|
||||
@@ -173,7 +173,7 @@ void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ )
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
"SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, "
|
||||
// 9 10 11 12 13 14
|
||||
"characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, genitive "
|
||||
"characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, character_declinedname.genitive "
|
||||
"FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' "
|
||||
"LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid "
|
||||
"LEFT JOIN guild_member ON characters.guid = guild_member.guid "
|
||||
@@ -571,7 +571,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
|
||||
uint64 playerGuid = holder->GetGuid();
|
||||
|
||||
Player* pCurrChar = new Player(this);
|
||||
pCurrChar->GetMotionMaster()->Initialize();
|
||||
// for send server info and strings (config)
|
||||
ChatHandler chH = ChatHandler(pCurrChar);
|
||||
|
||||
@@ -585,6 +584,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
|
||||
return;
|
||||
}
|
||||
|
||||
pCurrChar->GetMotionMaster()->Initialize();
|
||||
|
||||
SetPlayer(pCurrChar);
|
||||
|
||||
pCurrChar->SendDungeonDifficulty(false);
|
||||
@@ -769,7 +770,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
|
||||
{
|
||||
sLog.outDebug( "WORLD: Restart character %u taxi flight", pCurrChar->GetGUIDLow() );
|
||||
|
||||
uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam());
|
||||
uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam(),true);
|
||||
uint32 path = pCurrChar->m_taxi.GetCurrentTaxiPath();
|
||||
|
||||
// search appropriate start path node
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
// |color|Hskill:skill_id|h[name]|h|r
|
||||
// |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click
|
||||
// |color|Htalent:talent_id,rank|h[name]|h|r - client, talent icon shift-click
|
||||
// |color|Htaxinode:id|h[name]|h|r
|
||||
// |color|Htele:id|h[name]|h|r
|
||||
// |color|Htrade:spell_id,cur_value,max_value,unk3int,unk3str|h[name]|h|r - client, spellbook profession icon shift-click
|
||||
|
||||
@@ -194,6 +195,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
{ "graveyard", SEC_MODERATOR, false, &ChatHandler::HandleGoGraveyardCommand, "", NULL },
|
||||
{ "grid", SEC_MODERATOR, false, &ChatHandler::HandleGoGridCommand, "", NULL },
|
||||
{ "object", SEC_MODERATOR, false, &ChatHandler::HandleGoObjectCommand, "", NULL },
|
||||
{ "taxinode", SEC_MODERATOR, false, &ChatHandler::HandleGoTaxinodeCommand, "", NULL },
|
||||
{ "trigger", SEC_MODERATOR, false, &ChatHandler::HandleGoTriggerCommand, "", NULL },
|
||||
{ "zonexy", SEC_MODERATOR, false, &ChatHandler::HandleGoZoneXYCommand, "", NULL },
|
||||
{ "xy", SEC_MODERATOR, false, &ChatHandler::HandleGoXYCommand, "", NULL },
|
||||
@@ -301,6 +303,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
{ "player", SEC_GAMEMASTER, true, NULL, "", lookupPlayerCommandTable },
|
||||
{ "skill", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSkillCommand, "", NULL },
|
||||
{ "spell", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupSpellCommand, "", NULL },
|
||||
{ "taxinode", SEC_ADMINISTRATOR, true, &ChatHandler::HandleLookupTaxiNodeCommand, "", NULL },
|
||||
{ "tele", SEC_MODERATOR, true, &ChatHandler::HandleLookupTeleCommand, "", NULL },
|
||||
{ NULL, 0, false, NULL, "", NULL }
|
||||
};
|
||||
|
||||
@@ -195,6 +195,7 @@ class ChatHandler
|
||||
bool HandleGoGraveyardCommand(const char* args);
|
||||
bool HandleGoGridCommand(const char* args);
|
||||
bool HandleGoObjectCommand(const char* args);
|
||||
bool HandleGoTaxinodeCommand(const char* args);
|
||||
bool HandleGoTriggerCommand(const char* args);
|
||||
bool HandleGoXYCommand(const char* args);
|
||||
bool HandleGoXYZCommand(const char* args);
|
||||
@@ -247,6 +248,7 @@ class ChatHandler
|
||||
bool HandleLookupQuestCommand(const char* args);
|
||||
bool HandleLookupSkillCommand(const char* args);
|
||||
bool HandleLookupSpellCommand(const char* args);
|
||||
bool HandleLookupTaxiNodeCommand(const char * args);
|
||||
bool HandleLookupTeleCommand(const char * args);
|
||||
|
||||
bool HandleModifyKnownTitlesCommand(const char* args);
|
||||
|
||||
+29
-11
@@ -164,8 +164,8 @@ Creature::~Creature()
|
||||
i_AI = NULL;
|
||||
}
|
||||
|
||||
if(m_uint32Values)
|
||||
sLog.outDetail("Deconstruct Creature Entry = %u", GetEntry());
|
||||
//if(m_uint32Values)
|
||||
// sLog.outDetail("Deconstruct Creature Entry = %u", GetEntry());
|
||||
}
|
||||
|
||||
void Creature::AddToWorld()
|
||||
@@ -175,7 +175,7 @@ void Creature::AddToWorld()
|
||||
{
|
||||
ObjectAccessor::Instance().AddObject(this);
|
||||
Unit::AddToWorld();
|
||||
SearchFormation();
|
||||
SearchFormationAndPath();
|
||||
AIM_Initialize();
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ void Creature::RemoveFromWorld()
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::SearchFormation()
|
||||
void Creature::SearchFormationAndPath()
|
||||
{
|
||||
if(isSummon())
|
||||
return;
|
||||
@@ -203,9 +203,28 @@ void Creature::SearchFormation()
|
||||
if(!lowguid)
|
||||
return;
|
||||
|
||||
bool usePath = (GetDefaultMovementType() == WAYPOINT_MOTION_TYPE);
|
||||
CreatureGroupInfoType::iterator frmdata = CreatureGroupMap.find(lowguid);
|
||||
if(frmdata != CreatureGroupMap.end())
|
||||
{
|
||||
if(usePath && lowguid != frmdata->second->leaderGUID)
|
||||
{
|
||||
SetDefaultMovementType(IDLE_MOTION_TYPE);
|
||||
usePath = false;
|
||||
}
|
||||
formation_mgr.AddCreatureToGroup(frmdata->second->leaderGUID, this);
|
||||
}
|
||||
|
||||
if(usePath)
|
||||
{
|
||||
if(WaypointMgr.GetPath(lowguid * 10))
|
||||
SetWaypointPathId(lowguid * 10);
|
||||
else
|
||||
{
|
||||
sLog.outErrorDb("Creature DBGUID %u has waypoint motion type, but it does not have a waypoint path!", lowguid);
|
||||
SetDefaultMovementType(IDLE_MOTION_TYPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::RemoveCorpse()
|
||||
@@ -436,6 +455,9 @@ void Creature::Update(uint32 diff)
|
||||
}
|
||||
else
|
||||
{
|
||||
// for delayed spells
|
||||
m_Events.Update( diff );
|
||||
|
||||
m_deathTimer -= diff;
|
||||
if (m_groupLootTimer && lootingGroupLeaderGUID)
|
||||
{
|
||||
@@ -2036,12 +2058,12 @@ bool Creature::IsOutOfThreatArea(Unit* pVictim) const
|
||||
if(sMapStore.LookupEntry(GetMapId())->IsDungeon())
|
||||
return false;
|
||||
|
||||
float length = pVictim->GetDistance(mHome_X, mHome_Y, mHome_Z);
|
||||
float AttackDist = GetAttackDistance(pVictim);
|
||||
uint32 ThreatRadius = sWorld.getConfig(CONFIG_THREAT_RADIUS);
|
||||
|
||||
//Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick.
|
||||
return ( length > (ThreatRadius > AttackDist ? ThreatRadius : AttackDist));
|
||||
return !pVictim->IsWithinDist3d(mHome_X,mHome_Y,mHome_Z,
|
||||
ThreatRadius > AttackDist ? ThreatRadius : AttackDist);
|
||||
}
|
||||
|
||||
CreatureDataAddon const* Creature::GetCreatureAddon() const
|
||||
@@ -2081,10 +2103,6 @@ bool Creature::LoadCreaturesAddon(bool reload)
|
||||
if (cainfo->move_flags != 0)
|
||||
SetUnitMovementFlags(cainfo->move_flags);
|
||||
|
||||
//Load Path
|
||||
if (cainfo->path_id != 0)
|
||||
m_path_id = cainfo->path_id;
|
||||
|
||||
if(cainfo->auras)
|
||||
{
|
||||
for (CreatureDataAddonAura const* cAura = cainfo->auras; cAura->spell_id; ++cAura)
|
||||
@@ -2105,7 +2123,7 @@ bool Creature::LoadCreaturesAddon(bool reload)
|
||||
continue;
|
||||
}
|
||||
|
||||
AddAuraEffect(AdditionalSpellInfo->Id, cAura->effect_idx, this);
|
||||
AddAuraEffect(AdditionalSpellInfo, cAura->effect_idx, this);
|
||||
sLog.outDebug("Spell: %u with Aura %u added to creature (GUIDLow: %u Entry: %u )", cAura->spell_id, AdditionalSpellInfo->EffectApplyAuraName[cAura->effect_idx],GetGUIDLow(),GetEntry());
|
||||
}
|
||||
}
|
||||
|
||||
+20
-5
@@ -108,6 +108,21 @@ enum Gossip_Guard_Skill
|
||||
GOSSIP_GUARD_SKILL_ENGINERING = 91
|
||||
};
|
||||
|
||||
enum GossipOptionIcon
|
||||
{
|
||||
GOSSIP_ICON_CHAT = 0, //white chat bubble
|
||||
GOSSIP_ICON_VENDOR = 1, //brown bag
|
||||
GOSSIP_ICON_TAXI = 2, //flight
|
||||
GOSSIP_ICON_TRAINER = 3, //book
|
||||
GOSSIP_ICON_INTERACT_1 = 4, //interaction wheel
|
||||
GOSSIP_ICON_INTERACT_2 = 5, //interaction wheel
|
||||
GOSSIP_ICON_MONEY_BAG = 6, //brown bag with yellow dot
|
||||
GOSSIP_ICON_TALK = 7, //white chat bubble with black dots
|
||||
GOSSIP_ICON_TABARD = 8, //tabard
|
||||
GOSSIP_ICON_BATTLE = 9, //two swords
|
||||
GOSSIP_ICON_DOT = 10 //yellow dot
|
||||
};
|
||||
|
||||
struct GossipOption
|
||||
{
|
||||
uint32 Id;
|
||||
@@ -300,7 +315,6 @@ struct CreatureDataAddonAura
|
||||
struct CreatureDataAddon
|
||||
{
|
||||
uint32 guidOrEntry;
|
||||
uint32 path_id;
|
||||
uint32 mount;
|
||||
uint32 bytes0;
|
||||
uint32 bytes1;
|
||||
@@ -635,6 +649,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
bool IsVisibleInGridForPlayer(Player const* pl) const;
|
||||
|
||||
void RemoveCorpse();
|
||||
bool isDeadByDefault() const { return m_isDeadByDefault; };
|
||||
|
||||
time_t const& GetRespawnTime() const { return m_respawnTime; }
|
||||
time_t GetRespawnTimeEx() const;
|
||||
@@ -676,13 +691,13 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
|
||||
uint32 GetGlobalCooldown() const { return m_GlobalCooldown; }
|
||||
|
||||
uint32 GetWaypointPath(){return m_path_id;}
|
||||
void LoadPath(uint32 pathid) { m_path_id = pathid; }
|
||||
uint32 GetWaypointPathId() const { return m_pathId; }
|
||||
void SetWaypointPathId(uint32 pathid) { m_pathId = pathid; }
|
||||
|
||||
uint32 GetCurrentWaypointID(){return m_waypointID;}
|
||||
void UpdateWaypointID(uint32 wpID){m_waypointID = wpID;}
|
||||
|
||||
void SearchFormation();
|
||||
void SearchFormationAndPath();
|
||||
CreatureGroup *GetFormation() {return m_formation;}
|
||||
void SetFormation(CreatureGroup *formation) {m_formation = formation;}
|
||||
|
||||
@@ -743,7 +758,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
|
||||
private:
|
||||
//WaypointMovementGenerator vars
|
||||
uint32 m_waypointID;
|
||||
uint32 m_path_id;
|
||||
uint32 m_pathId;
|
||||
|
||||
//Formation var
|
||||
CreatureGroup *m_formation;
|
||||
|
||||
+224
-75
@@ -19,49 +19,10 @@
|
||||
*/
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "Creature.h"
|
||||
#include "Player.h"
|
||||
#include "Pet.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "World.h"
|
||||
|
||||
void UnitAI::AttackStart(Unit *victim)
|
||||
{
|
||||
if(!victim)
|
||||
return;
|
||||
|
||||
if(me->Attack(victim, true))
|
||||
{
|
||||
//DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", me->GetName(), victim->GetGUIDLow());
|
||||
me->GetMotionMaster()->MoveChase(victim);
|
||||
}
|
||||
}
|
||||
|
||||
void UnitAI::DoMeleeAttackIfReady()
|
||||
{
|
||||
//Make sure our attack is ready and we aren't currently casting before checking distance
|
||||
if (me->isAttackReady() && !me->hasUnitState(UNIT_STAT_CASTING))
|
||||
{
|
||||
//If we are within range melee the target
|
||||
if (me->IsWithinMeleeRange(me->getVictim()))
|
||||
{
|
||||
me->AttackerStateUpdate(me->getVictim());
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
}
|
||||
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK) && !me->hasUnitState(UNIT_STAT_CASTING))
|
||||
{
|
||||
//If we are within range melee the target
|
||||
if (me->IsWithinMeleeRange(me->getVictim()))
|
||||
{
|
||||
me->AttackerStateUpdate(me->getVictim(), OFF_ATTACK);
|
||||
me->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Enable PlayerAI when charmed
|
||||
void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; }
|
||||
#include "SpellMgr.h"
|
||||
|
||||
//Disable CreatureAI when charmed
|
||||
void CreatureAI::OnCharmed(bool apply)
|
||||
@@ -71,11 +32,16 @@ void CreatureAI::OnCharmed(bool apply)
|
||||
me->IsAIEnabled = false;
|
||||
}
|
||||
|
||||
AISpellInfoType * CreatureAI::AISpellInfo;
|
||||
|
||||
void CreatureAI::DoZoneInCombat(Creature* creature)
|
||||
{
|
||||
if (!creature)
|
||||
creature = me;
|
||||
|
||||
if(!creature->CanHaveThreatList())
|
||||
return;
|
||||
|
||||
Map *map = creature->GetMap();
|
||||
if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
|
||||
{
|
||||
@@ -83,37 +49,38 @@ void CreatureAI::DoZoneInCombat(Creature* creature)
|
||||
return;
|
||||
}
|
||||
|
||||
if(!creature->getVictim())
|
||||
if(!creature->HasReactState(REACT_PASSIVE) && !creature->getVictim())
|
||||
{
|
||||
if(Unit *target = creature->SelectNearestTarget())
|
||||
AttackStart(target);
|
||||
creature->AI()->AttackStart(target);
|
||||
else if(creature->isSummon())
|
||||
{
|
||||
if(Unit *summoner = ((TempSummon*)creature)->GetSummoner())
|
||||
{
|
||||
if(summoner->getVictim()
|
||||
&& (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(summoner->getVictim())))
|
||||
AttackStart(summoner->getVictim());
|
||||
Unit *target = summoner->getAttackerForHelper();
|
||||
if(!target && summoner->CanHaveThreatList() && !summoner->getThreatManager().isThreatListEmpty())
|
||||
target = summoner->getThreatManager().getHostilTarget();
|
||||
if(target && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(target)))
|
||||
creature->AI()->AttackStart(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!creature->CanHaveThreatList() || !creature->getVictim())
|
||||
if(!creature->HasReactState(REACT_PASSIVE) && !creature->getVictim())
|
||||
{
|
||||
sLog.outError("DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (creature entry = %d)", creature->GetTypeId() == TYPEID_UNIT ? ((Creature*)creature)->GetEntry() : 0);
|
||||
sLog.outError("DoZoneInCombat called for creature that has empty threat list (creature entry = %u)", creature->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
Map::PlayerList const &PlayerList = map->GetPlayers();
|
||||
for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
|
||||
{
|
||||
if (Player* i_pl = i->getSource())
|
||||
if (i_pl->isAlive())
|
||||
{
|
||||
creature->SetInCombatWith(i_pl);
|
||||
i_pl->SetInCombatWith(creature);
|
||||
creature->AddThreat(i_pl, 0.0f);
|
||||
}
|
||||
if (i->getSource()->isAlive())
|
||||
{
|
||||
creature->SetInCombatWith(i->getSource());
|
||||
i->getSource()->SetInCombatWith(creature);
|
||||
creature->AddThreat(i->getSource(), 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,40 +106,222 @@ bool CreatureAI::UpdateVictim()
|
||||
return me->getVictim();
|
||||
}
|
||||
|
||||
void CreatureAI::EnterEvadeMode()
|
||||
bool CreatureAI::_EnterEvadeMode()
|
||||
{
|
||||
if(me->IsInEvadeMode() || !me->isAlive())
|
||||
return false;
|
||||
|
||||
me->RemoveAllAuras();
|
||||
me->DeleteThreatList();
|
||||
me->CombatStop();
|
||||
me->CombatStop(true);
|
||||
me->LoadCreaturesAddon();
|
||||
me->SetLootRecipient(NULL);
|
||||
|
||||
if(me->isAlive())
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
return true;
|
||||
}
|
||||
|
||||
void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
|
||||
void CreatureAI::EnterEvadeMode()
|
||||
{
|
||||
Creature *charmer = (Creature*)me->GetCharmer();
|
||||
if(!_EnterEvadeMode())
|
||||
return;
|
||||
|
||||
//kill self if charm aura has infinite duration
|
||||
if(charmer->IsInEvadeMode())
|
||||
if(Unit *owner = me->GetCharmerOrOwner())
|
||||
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE);
|
||||
else
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
inline bool SelectTargetHelper(const Unit * me, const Unit * target, const bool &playerOnly, const float &dist, const int32 &aura)
|
||||
{
|
||||
if(playerOnly && target->GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
|
||||
if(dist && !me->IsWithinCombatRange(target, dist))
|
||||
return false;
|
||||
|
||||
if(aura)
|
||||
{
|
||||
Unit::AuraEffectList const& auras = me->GetAurasByType(SPELL_AURA_MOD_CHARM);
|
||||
for(Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
|
||||
if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetParentAura()->IsPermanent())
|
||||
{
|
||||
charmer->Kill(me);
|
||||
return;
|
||||
}
|
||||
if(aura > 0)
|
||||
{
|
||||
if(!target->HasAura(aura))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(target->HasAura(aura))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!charmer->isInCombat())
|
||||
me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit *target = me->getVictim();
|
||||
if(!target || !charmer->canAttack(target))
|
||||
AttackStart(charmer->SelectNearestTarget());
|
||||
struct TargetDistanceOrder : public std::binary_function<const Unit *, const Unit *, bool>
|
||||
{
|
||||
const Unit * me;
|
||||
TargetDistanceOrder(const Unit* Target) : me(Target) {};
|
||||
// functor for operator ">"
|
||||
bool operator()(const Unit * _Left, const Unit * _Right) const
|
||||
{
|
||||
return (me->GetDistanceSq(_Left) < me->GetDistanceSq(_Right));
|
||||
}
|
||||
};
|
||||
|
||||
Unit* CreatureAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura)
|
||||
{
|
||||
if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
|
||||
{
|
||||
std::list<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList();
|
||||
if(position >= m_threatlist.size())
|
||||
return NULL;
|
||||
|
||||
std::list<Unit*> targetList;
|
||||
for(std::list<HostilReference*>::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr)
|
||||
if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura))
|
||||
targetList.push_back((*itr)->getTarget());
|
||||
|
||||
if(position >= targetList.size())
|
||||
return NULL;
|
||||
|
||||
targetList.sort(TargetDistanceOrder(m_creature));
|
||||
|
||||
if(targetType == SELECT_TARGET_NEAREST)
|
||||
{
|
||||
std::list<Unit*>::iterator i = targetList.begin();
|
||||
advance(i, position);
|
||||
return *i;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::list<Unit*>::reverse_iterator i = targetList.rbegin();
|
||||
advance(i, position);
|
||||
return *i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList();
|
||||
std::list<HostilReference*>::iterator i;
|
||||
while(position < m_threatlist.size())
|
||||
{
|
||||
if(targetType == SELECT_TARGET_BOTTOMAGGRO)
|
||||
{
|
||||
i = m_threatlist.end();
|
||||
advance(i, - (int32)position - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = m_threatlist.begin();
|
||||
if(targetType == SELECT_TARGET_TOPAGGRO)
|
||||
advance(i, position);
|
||||
else // random
|
||||
advance(i, position + rand()%(m_threatlist.size() - position));
|
||||
}
|
||||
|
||||
if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura))
|
||||
return (*i)->getTarget();
|
||||
else
|
||||
m_threatlist.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CreatureAI::SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura)
|
||||
{
|
||||
if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
|
||||
{
|
||||
std::list<HostilReference*> &m_threatlist = m_creature->getThreatManager().getThreatList();
|
||||
if(m_threatlist.empty())
|
||||
return;
|
||||
|
||||
for(std::list<HostilReference*>::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr)
|
||||
if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura))
|
||||
targetList.push_back((*itr)->getTarget());
|
||||
|
||||
targetList.sort(TargetDistanceOrder(me));
|
||||
targetList.resize(num);
|
||||
if(targetType == SELECT_TARGET_FARTHEST)
|
||||
targetList.reverse();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList();
|
||||
std::list<HostilReference*>::iterator i;
|
||||
while(!m_threatlist.empty() && num)
|
||||
{
|
||||
if(targetType == SELECT_TARGET_BOTTOMAGGRO)
|
||||
{
|
||||
i = m_threatlist.end();
|
||||
--i;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = m_threatlist.begin();
|
||||
if(targetType == SELECT_TARGET_RANDOM)
|
||||
advance(i, rand()%m_threatlist.size());
|
||||
}
|
||||
|
||||
if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura))
|
||||
{
|
||||
targetList.push_back((*i)->getTarget());
|
||||
--num;
|
||||
}
|
||||
m_threatlist.erase(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureAI::FillAISpellInfo()
|
||||
{
|
||||
AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()];
|
||||
|
||||
AISpellInfoType *AIInfo = AISpellInfo;
|
||||
const SpellEntry * spellInfo;
|
||||
|
||||
for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo)
|
||||
{
|
||||
spellInfo = GetSpellStore()->LookupEntry(i);
|
||||
if(!spellInfo)
|
||||
continue;
|
||||
|
||||
if(spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
|
||||
AIInfo->condition = AICOND_DIE;
|
||||
else if(IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1)
|
||||
AIInfo->condition = AICOND_AGGRO;
|
||||
else
|
||||
AIInfo->condition = AICOND_COMBAT;
|
||||
|
||||
if(AIInfo->cooldown < spellInfo->RecoveryTime)
|
||||
AIInfo->cooldown = spellInfo->RecoveryTime;
|
||||
|
||||
for(uint32 j = 0; j < 3; ++j)
|
||||
{
|
||||
if(spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY
|
||||
|| spellInfo->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY)
|
||||
{
|
||||
if(AIInfo->target < AITARGET_VICTIM)
|
||||
AIInfo->target = AITARGET_VICTIM;
|
||||
}
|
||||
|
||||
if(spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA)
|
||||
{
|
||||
if(spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY)
|
||||
{
|
||||
if(AIInfo->target < AITARGET_DEBUFF)
|
||||
AIInfo->target = AITARGET_DEBUFF;
|
||||
}
|
||||
else if(IsPositiveSpell(i))
|
||||
{
|
||||
if(AIInfo->target < AITARGET_BUFF)
|
||||
AIInfo->target = AITARGET_BUFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*void CreatureAI::AttackedBy( Unit* attacker )
|
||||
|
||||
+12
-134
@@ -21,23 +21,21 @@
|
||||
#ifndef TRINITY_CREATUREAI_H
|
||||
#define TRINITY_CREATUREAI_H
|
||||
|
||||
#include "UnitAI.h"
|
||||
#include "Common.h"
|
||||
#include "Platform/Define.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include "Dynamic/ObjectRegistry.h"
|
||||
#include "Dynamic/FactoryHolder.h"
|
||||
|
||||
class WorldObject;
|
||||
class Unit;
|
||||
class Creature;
|
||||
class Player;
|
||||
struct SpellEntry;
|
||||
struct AISpellInfoType;
|
||||
|
||||
#define TIME_INTERVAL_LOOK 5000
|
||||
#define VISIBILITY_RANGE 10000
|
||||
|
||||
//Spell targets used by SelectSpell
|
||||
enum SelectTarget
|
||||
enum SelectTargetType
|
||||
{
|
||||
SELECT_TARGET_DONTCARE = 0, //All target types allowed
|
||||
|
||||
@@ -77,120 +75,11 @@ enum SCEquip
|
||||
EQUIP_UNEQUIP = 0
|
||||
};
|
||||
|
||||
class EventMap : private std::map<uint32, uint32>
|
||||
{
|
||||
private:
|
||||
uint32 m_time, m_phase;
|
||||
public:
|
||||
explicit EventMap() : m_phase(0), m_time(0) {}
|
||||
|
||||
void Reset() { clear(); m_time = 0; m_phase = 0; }
|
||||
|
||||
void Update(uint32 time) { m_time += time; }
|
||||
|
||||
void SetPhase(uint32 phase)
|
||||
{
|
||||
if(phase && phase < 9)
|
||||
m_phase = (1 << (phase + 24));
|
||||
}
|
||||
|
||||
void ScheduleEvent(uint32 eventId, uint32 time, uint32 gcd = 0, uint32 phase = 0)
|
||||
{
|
||||
time += m_time;
|
||||
if(gcd && gcd < 9)
|
||||
eventId |= (1 << (gcd + 16));
|
||||
if(phase && phase < 9)
|
||||
eventId |= (1 << (phase + 24));
|
||||
iterator itr = find(time);
|
||||
while(itr != end())
|
||||
{
|
||||
++time;
|
||||
itr = find(time);
|
||||
}
|
||||
insert(std::make_pair(time, eventId));
|
||||
}
|
||||
|
||||
uint32 ExecuteEvent()
|
||||
{
|
||||
while(!empty())
|
||||
{
|
||||
if(begin()->first > m_time)
|
||||
return 0;
|
||||
else if(m_phase && (begin()->second & 0xFF000000) && !(begin()->second & m_phase))
|
||||
erase(begin());
|
||||
else
|
||||
{
|
||||
uint32 eventId = (begin()->second & 0x0000FFFF);
|
||||
erase(begin());
|
||||
return eventId;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DelayEvents(uint32 time, uint32 gcd)
|
||||
{
|
||||
time += m_time;
|
||||
gcd = (1 << (gcd + 16));
|
||||
for(iterator itr = begin(); itr != end();)
|
||||
{
|
||||
if(itr->first >= time)
|
||||
break;
|
||||
if(itr->second & gcd)
|
||||
{
|
||||
ScheduleEvent(time, itr->second);
|
||||
erase(itr++);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC UnitAI
|
||||
{
|
||||
protected:
|
||||
Unit* const me;
|
||||
public:
|
||||
explicit UnitAI(Unit *u) : me(u) {}
|
||||
virtual void AttackStart(Unit *);
|
||||
virtual void UpdateAI(const uint32 diff) = 0;
|
||||
|
||||
virtual void InitializeAI() { Reset(); }
|
||||
|
||||
virtual void Reset() {};
|
||||
|
||||
// Called when unit is charmed
|
||||
virtual void OnCharmed(bool apply) = 0;
|
||||
|
||||
// Pass parameters between AI
|
||||
virtual void DoAction(const int32 param) {}
|
||||
|
||||
//Do melee swing of current victim if in rnage and ready and not casting
|
||||
void DoMeleeAttackIfReady();
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC PlayerAI : public UnitAI
|
||||
{
|
||||
protected:
|
||||
Player* const me;
|
||||
public:
|
||||
explicit PlayerAI(Player *p) : UnitAI((Unit*)p), me(p) {}
|
||||
|
||||
void OnCharmed(bool apply);
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC SimpleCharmedAI : public PlayerAI
|
||||
{
|
||||
public:
|
||||
void UpdateAI(const uint32 diff);
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC CreatureAI : public UnitAI
|
||||
{
|
||||
protected:
|
||||
Creature* const me;
|
||||
Creature* const m_creature;
|
||||
Creature * const me;
|
||||
Creature * const m_creature;
|
||||
|
||||
bool UpdateVictim();
|
||||
public:
|
||||
@@ -235,7 +124,7 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI
|
||||
//virtual void AttackedBy(Unit* attacker);
|
||||
|
||||
// Called when creature is spawned or respawned (for reseting variables)
|
||||
virtual void JustRespawned() {}
|
||||
virtual void JustRespawned() { Reset(); }
|
||||
|
||||
// Called at waypoint reached or point movement finished
|
||||
virtual void MovementInform(uint32 /*MovementType*/, uint32 /*Data*/) {}
|
||||
@@ -273,22 +162,15 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI
|
||||
|
||||
// Pointer to controlled by AI creature
|
||||
//Creature* const m_creature;
|
||||
};
|
||||
|
||||
struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
|
||||
{
|
||||
Unit* SelectTarget(SelectAggroTarget target, uint32 position = 0, float dist = 0, bool playerOnly = false, int32 aura = 0);
|
||||
void SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget target, float dist = 0, bool playerOnly = false, int32 aura = 0);
|
||||
|
||||
SelectableAI(const char *id) : FactoryHolder<CreatureAI>(id) {}
|
||||
};
|
||||
static AISpellInfoType *AISpellInfo;
|
||||
static void FillAISpellInfo();
|
||||
|
||||
template<class REAL_AI>
|
||||
struct CreatureAIFactory : public SelectableAI
|
||||
{
|
||||
CreatureAIFactory(const char *name) : SelectableAI(name) {}
|
||||
|
||||
CreatureAI* Create(void *) const;
|
||||
|
||||
int Permit(const Creature *c) const { return REAL_AI::Permissible(c); }
|
||||
protected:
|
||||
bool _EnterEvadeMode();
|
||||
};
|
||||
|
||||
enum Permitions
|
||||
@@ -301,8 +183,4 @@ enum Permitions
|
||||
PERMIT_BASE_SPECIAL = 800
|
||||
};
|
||||
|
||||
typedef FactoryHolder<CreatureAI> CreatureAICreator;
|
||||
typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry;
|
||||
typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifndef TRINITY_CREATUREAIFACTORY_H
|
||||
#define TRINITY_CREATUREAIFACTORY_H
|
||||
|
||||
//#include "Policies/Singleton.h"
|
||||
#include "Dynamic/ObjectRegistry.h"
|
||||
#include "Dynamic/FactoryHolder.h"
|
||||
|
||||
struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
|
||||
{
|
||||
SelectableAI(const char *id) : FactoryHolder<CreatureAI>(id) {}
|
||||
};
|
||||
|
||||
template<class REAL_AI>
|
||||
struct CreatureAIFactory : public SelectableAI
|
||||
{
|
||||
CreatureAIFactory(const char *name) : SelectableAI(name) {}
|
||||
|
||||
CreatureAI* Create(void *) const;
|
||||
|
||||
int Permit(const Creature *c) const { return REAL_AI::Permissible(c); }
|
||||
};
|
||||
|
||||
template<class REAL_AI>
|
||||
inline CreatureAI*
|
||||
CreatureAIFactory<REAL_AI>::Create(void *data) const
|
||||
{
|
||||
Creature* creature = reinterpret_cast<Creature *>(data);
|
||||
return (new REAL_AI(creature));
|
||||
}
|
||||
|
||||
typedef FactoryHolder<CreatureAI> CreatureAICreator;
|
||||
typedef FactoryHolder<CreatureAI>::FactoryHolderRegistry CreatureAIRegistry;
|
||||
typedef FactoryHolder<CreatureAI>::FactoryHolderRepository CreatureAIRepository;
|
||||
#endif
|
||||
+148
-6
@@ -20,14 +20,156 @@
|
||||
#ifndef CREATUREAIIMPL_H
|
||||
#define CREATUREAIIMPL_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Common.h"
|
||||
#include "Platform/Define.h"
|
||||
|
||||
template<class REAL_AI>
|
||||
inline CreatureAI*
|
||||
CreatureAIFactory<REAL_AI>::Create(void *data) const
|
||||
#define HEROIC(n,h) (HeroicMode ? h : n)
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2)
|
||||
{
|
||||
Creature* creature = reinterpret_cast<Creature *>(data);
|
||||
return (new REAL_AI(creature));
|
||||
return rand()%2 ? v1 : v2;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3)
|
||||
{
|
||||
switch(rand()%3)
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4)
|
||||
{
|
||||
switch(rand()%4)
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline
|
||||
const T& RAND(const T& v1, const T& v2, const T& v3, const T& v4, const T& v5)
|
||||
{
|
||||
switch(rand()%4)
|
||||
{
|
||||
default:
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v4;
|
||||
case 4: return v5;
|
||||
}
|
||||
}
|
||||
|
||||
class EventMap : private std::map<uint32, uint32>
|
||||
{
|
||||
private:
|
||||
uint32 m_time, m_phase;
|
||||
public:
|
||||
explicit EventMap() : m_phase(0), m_time(0) {}
|
||||
|
||||
void Reset() { clear(); m_time = 0; m_phase = 0; }
|
||||
|
||||
void Update(uint32 time) { m_time += time; }
|
||||
|
||||
void SetPhase(uint32 phase)
|
||||
{
|
||||
if(phase && phase < 9)
|
||||
m_phase = (1 << (phase + 24));
|
||||
}
|
||||
|
||||
void ScheduleEvent(uint32 eventId, uint32 time, uint32 gcd = 0, uint32 phase = 0)
|
||||
{
|
||||
time += m_time;
|
||||
if(gcd && gcd < 9)
|
||||
eventId |= (1 << (gcd + 16));
|
||||
if(phase && phase < 9)
|
||||
eventId |= (1 << (phase + 24));
|
||||
iterator itr = find(time);
|
||||
while(itr != end())
|
||||
{
|
||||
++time;
|
||||
itr = find(time);
|
||||
}
|
||||
insert(std::make_pair(time, eventId));
|
||||
}
|
||||
|
||||
uint32 ExecuteEvent()
|
||||
{
|
||||
while(!empty())
|
||||
{
|
||||
if(begin()->first > m_time)
|
||||
return 0;
|
||||
else if(m_phase && (begin()->second & 0xFF000000) && !(begin()->second & m_phase))
|
||||
erase(begin());
|
||||
else
|
||||
{
|
||||
uint32 eventId = (begin()->second & 0x0000FFFF);
|
||||
erase(begin());
|
||||
return eventId;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DelayEvents(uint32 time, uint32 gcd)
|
||||
{
|
||||
time += m_time;
|
||||
gcd = (1 << (gcd + 16));
|
||||
for(iterator itr = begin(); itr != end();)
|
||||
{
|
||||
if(itr->first >= time)
|
||||
break;
|
||||
if(itr->second & gcd)
|
||||
{
|
||||
ScheduleEvent(time, itr->second);
|
||||
erase(itr++);
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
enum AITarget
|
||||
{
|
||||
AITARGET_SELF,
|
||||
AITARGET_VICTIM,
|
||||
AITARGET_ENEMY,
|
||||
AITARGET_ALLY,
|
||||
AITARGET_BUFF,
|
||||
AITARGET_DEBUFF,
|
||||
};
|
||||
|
||||
enum AICondition
|
||||
{
|
||||
AICOND_AGGRO,
|
||||
AICOND_COMBAT,
|
||||
AICOND_DIE,
|
||||
};
|
||||
|
||||
#define AI_DEFAULT_COOLDOWN 5000
|
||||
|
||||
struct AISpellInfoType
|
||||
{
|
||||
AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT), cooldown(AI_DEFAULT_COOLDOWN) {}
|
||||
AITarget target;
|
||||
AICondition condition;
|
||||
uint32 cooldown;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -23,16 +23,16 @@
|
||||
#include "AggressorAI.h"
|
||||
#include "GuardAI.h"
|
||||
#include "PetAI.h"
|
||||
#include "PossessedAI.h"
|
||||
#include "TotemAI.h"
|
||||
#include "OutdoorPvPObjectiveAI.h"
|
||||
#include "CreatureEventAI.h"
|
||||
#include "RandomMovementGenerator.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "MovementGeneratorImpl.h"
|
||||
#include "CreatureAIRegistry.h"
|
||||
#include "WaypointMovementGenerator.h"
|
||||
#include "CreatureAIFactory.h"
|
||||
|
||||
#include "CreatureAIImpl.h"
|
||||
namespace AIRegistry
|
||||
{
|
||||
void Initialize()
|
||||
@@ -46,7 +46,7 @@ namespace AIRegistry
|
||||
(new CreatureAIFactory<PetAI>("PetAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<OutdoorPvPObjectiveAI>("OutdoorPvPObjectiveAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<PossessedAI>("PossessedAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<SpellAI>("SpellAI"))->RegisterSelf();
|
||||
(new CreatureAIFactory<CreatureEventAI>("EventAI"))->RegisterSelf();
|
||||
|
||||
(new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf();
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
|
||||
#include "Creature.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "CreatureAISelector.h"
|
||||
#include "NullCreatureAI.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
@@ -27,6 +26,7 @@
|
||||
#include "ScriptCalls.h"
|
||||
#include "Pet.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "CreatureAIFactory.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1(CreatureAIRegistry);
|
||||
INSTANTIATE_SINGLETON_1(MovementGeneratorRegistry);
|
||||
@@ -69,6 +69,18 @@ namespace FactorySelector
|
||||
ai_factory = ai_registry.GetRegistryItem("CritterAI");
|
||||
}
|
||||
|
||||
if(!ai_factory)
|
||||
{
|
||||
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
{
|
||||
if(creature->m_spells[i])
|
||||
{
|
||||
ai_factory = ai_registry.GetRegistryItem("SpellAI");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// select by permit check
|
||||
if(!ai_factory)
|
||||
{
|
||||
|
||||
@@ -1054,14 +1054,7 @@ void CreatureEventAI::JustReachedHome()
|
||||
|
||||
void CreatureEventAI::EnterEvadeMode()
|
||||
{
|
||||
m_creature->RemoveAllAuras();
|
||||
m_creature->DeleteThreatList();
|
||||
m_creature->CombatStop(true);
|
||||
|
||||
if (m_creature->isAlive())
|
||||
m_creature->GetMotionMaster()->MoveTargetedHome();
|
||||
|
||||
m_creature->SetLootRecipient(NULL);
|
||||
CreatureAI::EnterEvadeMode();
|
||||
|
||||
if (bEmptyList)
|
||||
return;
|
||||
@@ -1295,13 +1288,10 @@ void CreatureEventAI::UpdateAI(const uint32 diff)
|
||||
break;
|
||||
case EVENT_T_RANGE:
|
||||
if (Combat)
|
||||
{
|
||||
if (m_creature->IsWithinDistInMap(m_creature->getVictim(),(float)(*i).Event.event_param2))
|
||||
{
|
||||
if (m_creature->GetDistance(m_creature->getVictim()) >= (float)(*i).Event.event_param1)
|
||||
if (m_creature->IsInMap(m_creature->getVictim()))
|
||||
if (m_creature->IsInRange(m_creature->getVictim(),
|
||||
(float)(*i).Event.event_param1,(float)(*i).Event.event_param2))
|
||||
ProcessEvent(*i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1555,8 +1545,7 @@ bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Trigge
|
||||
return false;
|
||||
|
||||
//Unit is out of range of this spell
|
||||
if (me->GetDistance(Target) > me->GetSpellMaxRangeForTarget(Target, TempRange)
|
||||
|| me->GetDistance(Target) < me->GetSpellMinRangeForTarget(Target, TempRange))
|
||||
if (!m_creature->IsInRange(Target,TempRange->minRangeHostile,TempRange->maxRangeHostile))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ enum AchievementFlags
|
||||
ACHIEVEMENT_FLAG_SUMM = 0x00000008, // Use summ criteria value from all reqirements (and calculate max value)
|
||||
ACHIEVEMENT_FLAG_MAX_USED = 0x00000010, // Show max criteria (and calculate max value ??)
|
||||
ACHIEVEMENT_FLAG_REQ_COUNT = 0x00000020, // Use not zero req count (and calculate max value)
|
||||
ACHIEVEMENT_FLAG_AVERANGE = 0x00000040, // Show as averange value (value / time_in_days) depend from other flag (by def use last criteria value)
|
||||
ACHIEVEMENT_FLAG_AVERAGE = 0x00000040, // Show as average value (value / time_in_days) depend from other flag (by def use last criteria value)
|
||||
ACHIEVEMENT_FLAG_BAR = 0x00000080, // Show as progress bar (value / max vale) depend from other flag (by def use last criteria value)
|
||||
ACHIEVEMENT_FLAG_REALM_FIRST_REACH = 0x00000100, //
|
||||
ACHIEVEMENT_FLAG_REALM_FIRST_KILL = 0x00000200, //
|
||||
|
||||
+54
-3
@@ -1143,7 +1143,7 @@ struct RandomPropertiesPointsEntry
|
||||
struct ScalingStatDistributionEntry
|
||||
{
|
||||
uint32 Id;
|
||||
uint32 StatMod[10];
|
||||
int32 StatMod[10];
|
||||
uint32 Modifier[10];
|
||||
uint32 MaxLevel;
|
||||
};
|
||||
@@ -1152,7 +1152,58 @@ struct ScalingStatValuesEntry
|
||||
{
|
||||
uint32 Id;
|
||||
uint32 Level;
|
||||
uint32 Multiplier[17];
|
||||
uint32 ssdMultiplier[5]; // Multiplier for ScalingStatDistribution
|
||||
uint32 armorMod[4]; // Armor for level
|
||||
uint32 dpsMod[6]; // DPS mod for level
|
||||
uint32 spellBonus; // not sure.. TODO: need more info about
|
||||
uint32 feralBonus; // Feral AP bonus
|
||||
|
||||
uint32 getssdMultiplier(uint32 mask) const
|
||||
{
|
||||
if (mask&0x001F)
|
||||
{
|
||||
if(mask & 0x00000001) return ssdMultiplier[0];
|
||||
if(mask & 0x00000002) return ssdMultiplier[1];
|
||||
if(mask & 0x00000004) return ssdMultiplier[2];
|
||||
if(mask & 0x00000008) return ssdMultiplier[3];
|
||||
if(mask & 0x00000010) return ssdMultiplier[4];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint32 getArmorMod(uint32 mask) const
|
||||
{
|
||||
if (mask&0x01E0)
|
||||
{
|
||||
if(mask & 0x00000020) return armorMod[0];
|
||||
if(mask & 0x00000040) return armorMod[1];
|
||||
if(mask & 0x00000080) return armorMod[2];
|
||||
if(mask & 0x00000100) return armorMod[3];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint32 getDPSMod(uint32 mask) const
|
||||
{
|
||||
if (mask&0x7E00)
|
||||
{
|
||||
if(mask & 0x00000200) return dpsMod[0];
|
||||
if(mask & 0x00000400) return dpsMod[1];
|
||||
if(mask & 0x00000800) return dpsMod[2];
|
||||
if(mask & 0x00001000) return dpsMod[3];
|
||||
if(mask & 0x00002000) return dpsMod[4];
|
||||
if(mask & 0x00004000) return dpsMod[5];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint32 getSpellBonus(uint32 mask) const
|
||||
{
|
||||
if (mask & 0x00008000) return spellBonus;
|
||||
return 0;
|
||||
}
|
||||
uint32 getFeralBonus(uint32 mask) const
|
||||
{
|
||||
if (mask & 0x00010000) return feralBonus;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
//struct SkillLineCategoryEntry{
|
||||
@@ -1517,7 +1568,7 @@ struct TaxiNodesEntry
|
||||
float x; // 2 m_x
|
||||
float y; // 3 m_y
|
||||
float z; // 4 m_z
|
||||
//char* name[16]; // 5-21 m_Name_lang
|
||||
char* name[16]; // 5-21 m_Name_lang
|
||||
// 22 string flags
|
||||
uint32 MountCreatureID[2]; // 23-24 m_MountCreatureID[2]
|
||||
};
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ const char StableSlotPricesfmt[] = "ni";
|
||||
const char SummonPropertiesfmt[] = "niiiii";
|
||||
const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxxxx";
|
||||
const char TalentTabEntryfmt[]="nxxxxxxxxxxxxxxxxxxxiiix";
|
||||
const char TaxiNodesEntryfmt[]="nifffxxxxxxxxxxxxxxxxxii";
|
||||
const char TaxiNodesEntryfmt[]="nifffssssssssssssssssxii";
|
||||
const char TaxiPathEntryfmt[]="niii";
|
||||
const char TaxiPathNodeEntryfmt[]="diiifffiixx";
|
||||
const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii";
|
||||
|
||||
@@ -174,7 +174,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
|
||||
//Normally non-players do not teleport to other maps.
|
||||
if(map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
|
||||
{
|
||||
((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this);
|
||||
((InstanceMap*)map)->GetInstanceData()->OnObjectCreate(this, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -198,7 +198,7 @@ void GameObject::Update(uint32 /*p_time*/)
|
||||
{
|
||||
// Arming Time for GAMEOBJECT_TYPE_TRAP (6)
|
||||
Unit* owner = GetOwner();
|
||||
if (owner && ((Player*)owner)->isInCombat())
|
||||
if (owner && owner->isInCombat())
|
||||
m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay;
|
||||
m_lootState = GO_READY;
|
||||
break;
|
||||
|
||||
+51
-10
@@ -489,7 +489,7 @@ namespace Trinity
|
||||
void Visit(PlayerMapType &m)
|
||||
{
|
||||
for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr)
|
||||
if(itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->GetDistance(i_searcher) <= i_dist)
|
||||
if (itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->IsWithinDist(i_searcher,i_dist))
|
||||
i_do(itr->getSource());
|
||||
}
|
||||
|
||||
@@ -499,6 +499,53 @@ namespace Trinity
|
||||
// CHECKS && DO classes
|
||||
|
||||
// WorldObject check classes
|
||||
class RaiseDeadObjectCheck
|
||||
{
|
||||
public:
|
||||
RaiseDeadObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {}
|
||||
bool operator()(Creature* u)
|
||||
{
|
||||
if (i_funit->GetTypeId()!=TYPEID_PLAYER || !((Player*)i_funit)->isHonorOrXPTarget(u) ||
|
||||
u->getDeathState() != CORPSE || u->isDeadByDefault() || u->isInFlight() ||
|
||||
( u->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1)) )==0 ||
|
||||
(u->GetDisplayId() != u->GetNativeDisplayId()))
|
||||
return false;
|
||||
|
||||
return i_funit->IsWithinDistInMap(u, i_range);
|
||||
}
|
||||
template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
|
||||
private:
|
||||
Unit* const i_funit;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
class ExplodeCorpseObjectCheck
|
||||
{
|
||||
public:
|
||||
ExplodeCorpseObjectCheck(Unit* funit, float range) : i_funit(funit), i_range(range) {}
|
||||
bool operator()(Player* u)
|
||||
{
|
||||
if (u->getDeathState()!=CORPSE || u->isInFlight() ||
|
||||
u->HasAuraType(SPELL_AURA_GHOST) || (u->GetDisplayId() != u->GetNativeDisplayId()))
|
||||
return false;
|
||||
|
||||
return i_funit->IsWithinDistInMap(u, i_range);
|
||||
}
|
||||
bool operator()(Creature* u)
|
||||
{
|
||||
if (u->getDeathState()!=CORPSE || u->isInFlight() || u->isDeadByDefault() ||
|
||||
(u->GetDisplayId() != u->GetNativeDisplayId()) ||
|
||||
(u->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL)!=0)
|
||||
return false;
|
||||
|
||||
return i_funit->IsWithinDistInMap(u, i_range);
|
||||
}
|
||||
template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
|
||||
private:
|
||||
Unit* const i_funit;
|
||||
float i_range;
|
||||
};
|
||||
|
||||
class CannibalizeObjectCheck
|
||||
{
|
||||
public:
|
||||
@@ -508,22 +555,16 @@ namespace Trinity
|
||||
if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() )
|
||||
return false;
|
||||
|
||||
if(i_funit->IsWithinDistInMap(u, i_range) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return i_funit->IsWithinDistInMap(u, i_range);
|
||||
}
|
||||
bool operator()(Corpse* u);
|
||||
bool operator()(Creature* u)
|
||||
{
|
||||
if( i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() ||
|
||||
if (i_funit->IsFriendlyTo(u) || u->isAlive() || u->isInFlight() ||
|
||||
(u->GetCreatureTypeMask() & CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD)==0)
|
||||
return false;
|
||||
|
||||
if(i_funit->IsWithinDistInMap(u, i_range) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return i_funit->IsWithinDistInMap(u, i_range);
|
||||
}
|
||||
template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
|
||||
private:
|
||||
|
||||
@@ -178,8 +178,11 @@ inline void Trinity::DynamicObjectUpdater::VisitHelper(Unit* target)
|
||||
if (i_dynobject.IsAffecting(target))
|
||||
return;
|
||||
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_dynobject.GetSpellId());
|
||||
uint32 eff_index = i_dynobject.GetEffIndex();
|
||||
if(target->HasAuraEffect(i_dynobject.GetSpellId(), eff_index, i_check->GetGUID()))
|
||||
return;
|
||||
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(i_dynobject.GetSpellId());
|
||||
if(spellInfo->EffectImplicitTargetB[eff_index] == TARGET_DEST_DYNOBJ_ALLY
|
||||
|| spellInfo->EffectImplicitTargetB[eff_index] == TARGET_UNIT_AREA_ALLY_DST)
|
||||
{
|
||||
@@ -205,7 +208,9 @@ inline void Trinity::DynamicObjectUpdater::VisitHelper(Unit* target)
|
||||
if (target->IsImmunedToSpell(spellInfo) || target->IsImmunedToSpellEffect(spellInfo, eff_index))
|
||||
return;
|
||||
// Apply PersistentAreaAura on target
|
||||
target->AddAuraEffect(spellInfo->Id, eff_index, i_dynobject.GetCaster());
|
||||
if(Aura *aur = target->AddAuraEffect(spellInfo, eff_index, i_dynobject.GetCaster()))
|
||||
aur->SetAuraDuration(i_dynobject.GetDuration());
|
||||
|
||||
i_dynobject.AddAffected(target);
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -571,7 +571,7 @@ void Group::GroupLoot(const uint64& playerGUID, Loot *loot, Creature *creature)
|
||||
continue;
|
||||
if ( i->AllowedForPlayer(member) )
|
||||
{
|
||||
if (member->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
|
||||
if (member->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
|
||||
{
|
||||
r->playerVote[member->GetGUID()] = NOT_EMITED_YET;
|
||||
++r->totalPlayersRolling;
|
||||
@@ -621,7 +621,7 @@ void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *crea
|
||||
|
||||
if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll) )
|
||||
{
|
||||
if (playerToRoll->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
|
||||
if (playerToRoll->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
|
||||
{
|
||||
r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
|
||||
++r->totalPlayersRolling;
|
||||
@@ -669,7 +669,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat
|
||||
if (!looter->IsInWorld())
|
||||
continue;
|
||||
|
||||
if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
|
||||
if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
|
||||
{
|
||||
data << looter->GetGUID();
|
||||
++real_count;
|
||||
@@ -681,7 +681,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat
|
||||
for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
|
||||
{
|
||||
Player *looter = itr->getSource();
|
||||
if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
|
||||
if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
|
||||
looter->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
@@ -1338,7 +1338,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
|
||||
{
|
||||
// not update if only update if need and ok
|
||||
Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid);
|
||||
if(looter && looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
|
||||
if(looter && looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
|
||||
return;
|
||||
}
|
||||
++guid_itr;
|
||||
@@ -1351,7 +1351,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
|
||||
{
|
||||
if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
|
||||
{
|
||||
if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
|
||||
if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
|
||||
{
|
||||
bool refresh = pl->GetLootGUID()==creature->GetGUID();
|
||||
|
||||
@@ -1372,7 +1372,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
|
||||
{
|
||||
if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
|
||||
{
|
||||
if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
|
||||
if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
|
||||
{
|
||||
bool refresh = pl->GetLootGUID()==creature->GetGUID();
|
||||
|
||||
|
||||
@@ -78,6 +78,12 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data )
|
||||
return;
|
||||
}
|
||||
|
||||
// restrict invite to GMs
|
||||
if (!sWorld.getConfig(CONFIG_ALLOW_GM_GROUP) && !GetPlayer()->isGameMaster() && player->isGameMaster())
|
||||
{
|
||||
SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_CANT_FIND_TARGET);
|
||||
return;
|
||||
}
|
||||
// can't group with
|
||||
if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeam() != player->GetTeam())
|
||||
{
|
||||
|
||||
@@ -126,7 +126,7 @@ void GuardAI::UpdateAI(const uint32 /*diff*/)
|
||||
|
||||
bool GuardAI::IsVisible(Unit *pl) const
|
||||
{
|
||||
return m_creature->GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_GUARDER)
|
||||
return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_GUARDER))
|
||||
&& pl->isVisibleForOrDetect(m_creature,true);
|
||||
}
|
||||
|
||||
|
||||
+86
-53
@@ -26,8 +26,9 @@
|
||||
|
||||
void InstanceData::SaveToDB()
|
||||
{
|
||||
if(!Save()) return;
|
||||
std::string data = Save();
|
||||
std::string data = GetSaveData();
|
||||
if(data.empty())
|
||||
return;
|
||||
CharacterDatabase.escape_string(data);
|
||||
CharacterDatabase.PExecute("UPDATE instance SET data = '%s' WHERE id = '%d'", data.c_str(), instance->GetInstanceId());
|
||||
}
|
||||
@@ -57,42 +58,66 @@ void InstanceData::OnCreatureCreate(Creature *creature, bool add)
|
||||
OnCreatureCreate(creature, creature->GetEntry());
|
||||
}
|
||||
|
||||
void InstanceData::SetBossRoomDoor(uint32 id, GameObject *door, bool add)
|
||||
void InstanceData::LoadDoorData(const DoorData *data)
|
||||
{
|
||||
if(id < bosses.size())
|
||||
while(data->entry)
|
||||
{
|
||||
if(add)
|
||||
{
|
||||
BossInfo *bossInfo = &bosses[id];
|
||||
bossInfo->roomDoor.insert(door);
|
||||
// Room door is only closed when encounter is in progress
|
||||
if(bossInfo->state == IN_PROGRESS)
|
||||
door->SetGoState(GO_STATE_READY);
|
||||
else
|
||||
door->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
else
|
||||
bosses[id].roomDoor.erase(door);
|
||||
if(data->bossId < bosses.size())
|
||||
doors.insert(std::make_pair(data->entry, DoorInfo(&bosses[data->bossId], data->type)));
|
||||
|
||||
++data;
|
||||
}
|
||||
sLog.outDebug("InstanceData::LoadDoorData: %u doors loaded.", doors.size());
|
||||
}
|
||||
|
||||
void InstanceData::SetBossPassageDoor(uint32 id, GameObject *door, bool add)
|
||||
void InstanceData::UpdateDoorState(GameObject *door)
|
||||
{
|
||||
if(id < bosses.size())
|
||||
DoorInfoMap::iterator lower = doors.lower_bound(door->GetEntry());
|
||||
DoorInfoMap::iterator upper = doors.upper_bound(door->GetEntry());
|
||||
if(lower == upper)
|
||||
return;
|
||||
|
||||
bool open = true;
|
||||
for(DoorInfoMap::iterator itr = lower; itr != upper; ++itr)
|
||||
{
|
||||
if(itr->second.type == DOOR_TYPE_ROOM)
|
||||
{
|
||||
if(itr->second.bossInfo->state == IN_PROGRESS)
|
||||
{
|
||||
open = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(itr->second.type == DOOR_TYPE_PASSAGE)
|
||||
{
|
||||
if(itr->second.bossInfo->state != DONE)
|
||||
{
|
||||
open = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
door->SetGoState(open ? GO_STATE_ACTIVE : GO_STATE_READY);
|
||||
}
|
||||
|
||||
void InstanceData::AddDoor(GameObject *door, bool add)
|
||||
{
|
||||
DoorInfoMap::iterator lower = doors.lower_bound(door->GetEntry());
|
||||
DoorInfoMap::iterator upper = doors.upper_bound(door->GetEntry());
|
||||
if(lower == upper)
|
||||
return;
|
||||
|
||||
for(DoorInfoMap::iterator itr = lower; itr != upper; ++itr)
|
||||
{
|
||||
if(add)
|
||||
{
|
||||
BossInfo *bossInfo = &bosses[id];
|
||||
bossInfo->passageDoor.insert(door);
|
||||
// Passage door is only opened when boss is defeated
|
||||
if(bossInfo->state == DONE)
|
||||
door->SetGoState(GO_STATE_ACTIVE);
|
||||
else
|
||||
door->SetGoState(GO_STATE_READY);
|
||||
}
|
||||
itr->second.bossInfo->door[itr->second.type].insert(door);
|
||||
else
|
||||
bosses[id].passageDoor.erase(door);
|
||||
itr->second.bossInfo->door[itr->second.type].erase(door);
|
||||
}
|
||||
|
||||
if(add)
|
||||
UpdateDoorState(door);
|
||||
}
|
||||
|
||||
void InstanceData::SetBossState(uint32 id, EncounterState state)
|
||||
@@ -100,33 +125,41 @@ void InstanceData::SetBossState(uint32 id, EncounterState state)
|
||||
if(id < bosses.size())
|
||||
{
|
||||
BossInfo *bossInfo = &bosses[id];
|
||||
bossInfo->state = state;
|
||||
switch(state)
|
||||
if(bossInfo->state == TO_BE_DECIDED) // loading
|
||||
bossInfo->state = state;
|
||||
else
|
||||
{
|
||||
case NOT_STARTED:
|
||||
// Open all room doors, close all passage doors
|
||||
for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i)
|
||||
(*i)->SetGoState(GO_STATE_ACTIVE);
|
||||
for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i)
|
||||
(*i)->SetGoState(GO_STATE_READY);
|
||||
break;
|
||||
case IN_PROGRESS:
|
||||
// Close all doors
|
||||
for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i)
|
||||
(*i)->SetGoState(GO_STATE_READY);
|
||||
for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i)
|
||||
(*i)->SetGoState(GO_STATE_READY);
|
||||
break;
|
||||
case DONE:
|
||||
// Open all doors
|
||||
for(DoorSet::iterator i = bossInfo->roomDoor.begin(); i != bossInfo->roomDoor.end(); ++i)
|
||||
(*i)->SetGoState(GO_STATE_ACTIVE);
|
||||
for(DoorSet::iterator i = bossInfo->passageDoor.begin(); i != bossInfo->passageDoor.end(); ++i)
|
||||
(*i)->SetGoState(GO_STATE_ACTIVE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if(bossInfo->state == state)
|
||||
return;
|
||||
bossInfo->state = state;
|
||||
SaveToDB();
|
||||
}
|
||||
|
||||
for(uint32 type = 0; type < MAX_DOOR_TYPES; ++type)
|
||||
for(DoorSet::iterator i = bossInfo->door[type].begin(); i != bossInfo->door[type].end(); ++i)
|
||||
UpdateDoorState(*i);
|
||||
}
|
||||
}
|
||||
|
||||
std::string InstanceData::LoadBossState(const char * data)
|
||||
{
|
||||
if(!data) return NULL;
|
||||
std::istringstream loadStream(data);
|
||||
uint32 buff;
|
||||
uint32 bossId = 0;
|
||||
for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i, ++bossId)
|
||||
{
|
||||
loadStream >> buff;
|
||||
if(buff < TO_BE_DECIDED)
|
||||
SetBossState(bossId, (EncounterState)buff);
|
||||
}
|
||||
return loadStream.str();
|
||||
}
|
||||
|
||||
std::string InstanceData::GetBossSaveData()
|
||||
{
|
||||
std::ostringstream saveStream;
|
||||
for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i)
|
||||
saveStream << (uint32)i->state << " ";
|
||||
return saveStream.str();
|
||||
}
|
||||
|
||||
+40
-22
@@ -37,16 +37,40 @@ enum EncounterState
|
||||
IN_PROGRESS = 1,
|
||||
FAIL = 2,
|
||||
DONE = 3,
|
||||
SPECIAL = 4
|
||||
SPECIAL = 4,
|
||||
TO_BE_DECIDED = 5,
|
||||
};
|
||||
|
||||
typedef std::set<GameObject*> DoorSet;
|
||||
|
||||
enum DoorType
|
||||
{
|
||||
DOOR_TYPE_ROOM = 0,
|
||||
DOOR_TYPE_PASSAGE,
|
||||
MAX_DOOR_TYPES,
|
||||
};
|
||||
|
||||
struct BossInfo
|
||||
{
|
||||
BossInfo() : state(NOT_STARTED) {}
|
||||
BossInfo() : state(TO_BE_DECIDED) {}
|
||||
EncounterState state;
|
||||
DoorSet roomDoor, passageDoor;
|
||||
DoorSet door[MAX_DOOR_TYPES];
|
||||
};
|
||||
|
||||
struct DoorInfo
|
||||
{
|
||||
explicit DoorInfo(BossInfo *_bossInfo, DoorType _type)
|
||||
: bossInfo(_bossInfo), type(_type) {}
|
||||
BossInfo *bossInfo;
|
||||
DoorType type;
|
||||
};
|
||||
|
||||
typedef std::multimap<uint32 /*entry*/, DoorInfo> DoorInfoMap;
|
||||
|
||||
struct DoorData
|
||||
{
|
||||
uint32 entry, bossId;
|
||||
DoorType type;
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC InstanceData
|
||||
@@ -62,10 +86,10 @@ class TRINITY_DLL_SPEC InstanceData
|
||||
virtual void Initialize() {}
|
||||
|
||||
//On load
|
||||
virtual void Load(const char* /*data*/) {}
|
||||
virtual void Load(const char * data) { LoadBossState(data); }
|
||||
|
||||
//When save is needed, this function generates the data
|
||||
virtual const char* Save() { return ""; }
|
||||
virtual std::string GetSaveData() { return GetBossSaveData(); }
|
||||
|
||||
void SaveToDB();
|
||||
|
||||
@@ -80,15 +104,10 @@ class TRINITY_DLL_SPEC InstanceData
|
||||
virtual void OnPlayerEnter(Player *) {}
|
||||
|
||||
//Called when a gameobject is created
|
||||
virtual void OnObjectCreate(GameObject *go, bool add)
|
||||
{
|
||||
OnObjectCreate(go);
|
||||
}
|
||||
virtual void OnObjectCreate(GameObject *) {}
|
||||
virtual void OnObjectCreate(GameObject *go, bool add) { OnObjectCreate(go); }
|
||||
|
||||
//called on creature creation
|
||||
virtual void OnCreatureCreate(Creature *, bool add);
|
||||
virtual void OnCreatureCreate(Creature *, uint32 entry) {}
|
||||
|
||||
//All-purpose data storage 64 bit
|
||||
virtual uint64 GetData64(uint32 /*Data*/) { return 0; }
|
||||
@@ -103,23 +122,22 @@ class TRINITY_DLL_SPEC InstanceData
|
||||
//use HandleGameObject(GUID,boolen,NULL); in any other script
|
||||
void HandleGameObject(uint64 GUID, bool open, GameObject *go = NULL);
|
||||
|
||||
void SetBossState(uint32 id, EncounterState state);
|
||||
virtual void SetBossState(uint32 id, EncounterState state);
|
||||
protected:
|
||||
void LoadDoorData(const DoorData *data);
|
||||
|
||||
void SetBossNumber(uint32 number) { bosses.resize(number); }
|
||||
void SetBossRoomDoor(uint32 id, GameObject *door, bool add);
|
||||
void SetBossPassageDoor(uint32 id, GameObject *door, bool add);
|
||||
|
||||
std::string GetBossSave()
|
||||
{
|
||||
std::ostringstream saveStream;
|
||||
for(std::vector<BossInfo>::iterator i = bosses.begin(); i != bosses.end(); ++i)
|
||||
saveStream << (uint32)i->state << " ";
|
||||
return saveStream.str();
|
||||
}
|
||||
void AddDoor(GameObject *door, bool add);
|
||||
void UpdateDoorState(GameObject *door);
|
||||
|
||||
std::string LoadBossState(const char * data);
|
||||
std::string GetBossSaveData();
|
||||
private:
|
||||
std::vector<BossInfo> bosses;
|
||||
DoorInfoMap doors;
|
||||
|
||||
virtual void OnObjectCreate(GameObject *) {}
|
||||
virtual void OnCreatureCreate(Creature *, uint32 entry) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "Group.h"
|
||||
#include "InstanceData.h"
|
||||
#include "ProgressBar.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include "Policies/SingletonImp.h"
|
||||
|
||||
INSTANTIATE_SINGLETON_1( InstanceSaveManager );
|
||||
|
||||
@@ -163,11 +165,11 @@ void InstanceSave::SaveToDB()
|
||||
if(map)
|
||||
{
|
||||
assert(map->IsDungeon());
|
||||
InstanceData *iData = ((InstanceMap *)map)->GetInstanceData();
|
||||
if(iData && iData->Save())
|
||||
if(InstanceData *iData = ((InstanceMap*)map)->GetInstanceData())
|
||||
{
|
||||
data = iData->Save();
|
||||
CharacterDatabase.escape_string(data);
|
||||
data = iData->GetSaveData();
|
||||
if(!data.empty())
|
||||
CharacterDatabase.escape_string(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include "zthread/Mutex.h"
|
||||
#include "ace/Thread_Mutex.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include "Utilities/UnorderedMap.h"
|
||||
@@ -113,7 +113,7 @@ class InstanceSave
|
||||
bool m_canReset;
|
||||
};
|
||||
|
||||
class TRINITY_DLL_DECL InstanceSaveManager : public Trinity::Singleton<InstanceSaveManager, Trinity::ClassLevelLockable<InstanceSaveManager, ZThread::Mutex> >
|
||||
class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSaveManager, MaNGOS::ClassLevelLockable<InstanceSaveManager, ACE_Thread_Mutex> >
|
||||
{
|
||||
friend class InstanceSave;
|
||||
public:
|
||||
|
||||
@@ -600,46 +600,6 @@ struct ItemPrototype
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 GetScalingStatValuesColumn() const
|
||||
{
|
||||
if(ScalingStatValue & 0x00000001) // stat mod
|
||||
return 0;
|
||||
if(ScalingStatValue & 0x00000002) // stat mod
|
||||
return 1;
|
||||
if(ScalingStatValue & 0x00000004) // stat mod
|
||||
return 2;
|
||||
if(ScalingStatValue & 0x00000008) // stat mod
|
||||
return 3;
|
||||
if(ScalingStatValue & 0x00000010) // stat mod
|
||||
return 4;
|
||||
if(ScalingStatValue & 0x00000020) // armor mod
|
||||
return 5;
|
||||
if(ScalingStatValue & 0x00000040) // armor mod
|
||||
return 6;
|
||||
if(ScalingStatValue & 0x00000080) // armor mod
|
||||
return 7;
|
||||
if(ScalingStatValue & 0x00000100) // armor mod
|
||||
return 8;
|
||||
if(ScalingStatValue & 0x00000200) // damage mod
|
||||
return 9;
|
||||
if(ScalingStatValue & 0x00000400) // damage mod
|
||||
return 10;
|
||||
if(ScalingStatValue & 0x00000800) // damage mod
|
||||
return 11;
|
||||
if(ScalingStatValue & 0x00001000) // damage mod
|
||||
return 12;
|
||||
if(ScalingStatValue & 0x00002000) // damage mod
|
||||
return 13;
|
||||
if(ScalingStatValue & 0x00004000) // damage mod
|
||||
return 14;
|
||||
if(ScalingStatValue & 0x00008000) // spell power
|
||||
return 15;
|
||||
if(ScalingStatValue & 0x00020000) // feral AP
|
||||
return 16;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 GetMaxStackSize() const { return Stackable > 0 ? uint32(Stackable) : uint32(0x7FFFFFFF-1); }
|
||||
|
||||
float getDPS() const
|
||||
@@ -652,12 +612,12 @@ struct ItemPrototype
|
||||
return temp*500/Delay;
|
||||
}
|
||||
|
||||
int32 getFeralBonus() const
|
||||
int32 getFeralBonus(int32 extraDPS = 0) const
|
||||
{
|
||||
// 0x02A5F3 - is mask for Melee weapon from ItemSubClassMask.dbc
|
||||
if (Class == ITEM_CLASS_WEAPON && (1<<SubClass)&0x02A5F3)
|
||||
{
|
||||
int32 bonus = int32(getDPS()*14.0f) - 767;
|
||||
int32 bonus = int32((extraDPS + getDPS())*14.0f) - 767;
|
||||
if (bonus < 0)
|
||||
return 0;
|
||||
return bonus;
|
||||
|
||||
+6
-4
@@ -328,7 +328,8 @@ enum TrinityStrings
|
||||
LANG_YOU_ALREADY_HAVE_PET = 344,
|
||||
LANG_CUSTOMIZE_PLAYER = 345,
|
||||
LANG_CUSTOMIZE_PLAYER_GUID = 346,
|
||||
// Room for more level 2 345-399 not used
|
||||
LANG_COMMAND_GOTAXINODENOTFOUND = 347,
|
||||
// Room for more level 2 348-399 not used
|
||||
|
||||
// level 3 chat
|
||||
LANG_SCRIPTS_RELOADED = 400,
|
||||
@@ -403,8 +404,7 @@ enum TrinityStrings
|
||||
LANG_COMMAND_TP_ADDED = 463,
|
||||
LANG_COMMAND_TP_ADDEDERR = 464,
|
||||
LANG_COMMAND_TP_DELETED = 465,
|
||||
// 466, // not used
|
||||
|
||||
LANG_COMMAND_NOTAXINODEFOUND = 466,
|
||||
LANG_COMMAND_TARGET_LISTAURAS = 467,
|
||||
LANG_COMMAND_TARGET_AURADETAIL = 468,
|
||||
LANG_COMMAND_TARGET_LISTAURATYPE = 469,
|
||||
@@ -765,7 +765,9 @@ enum TrinityStrings
|
||||
LANG_COMMAND_LEARN_PET_TALENTS = 1125,
|
||||
LANG_RESET_PET_TALENTS = 1126,
|
||||
LANG_RESET_PET_TALENTS_ONLINE = 1127,
|
||||
// Room for more level 3 1128-1199 not used
|
||||
LANG_TAXINODE_ENTRY_LIST_CHAT = 1128,
|
||||
LANG_TAXINODE_ENTRY_LIST_CONSOLE = 1129,
|
||||
// Room for more level 3 1130-1199 not used
|
||||
|
||||
// Debug commands
|
||||
LANG_CINEMATIC_NOT_EXIST = 1200,
|
||||
|
||||
+56
-4
@@ -2091,12 +2091,12 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args)
|
||||
|
||||
uint32 moneyuser = chr->GetMoney();
|
||||
|
||||
if(addmoney < 0)
|
||||
if (addmoney < 0)
|
||||
{
|
||||
int32 newmoney = moneyuser + addmoney;
|
||||
int32 newmoney = int32(moneyuser) + addmoney;
|
||||
|
||||
sLog.outDetail(GetTrinityString(LANG_CURRENT_MONEY), moneyuser, addmoney, newmoney);
|
||||
if(newmoney <= 0 )
|
||||
if (newmoney <= 0 )
|
||||
{
|
||||
PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, GetNameLink(chr).c_str());
|
||||
if (needReportToTarget(chr))
|
||||
@@ -2106,6 +2106,9 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newmoney > MAX_MONEY_AMOUNT)
|
||||
newmoney = MAX_MONEY_AMOUNT;
|
||||
|
||||
PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), GetNameLink(chr).c_str());
|
||||
if (needReportToTarget(chr))
|
||||
ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, GetNameLink().c_str(), abs(addmoney));
|
||||
@@ -2117,7 +2120,11 @@ bool ChatHandler::HandleModifyMoneyCommand(const char* args)
|
||||
PSendSysMessage(LANG_YOU_GIVE_MONEY, addmoney, GetNameLink(chr).c_str());
|
||||
if (needReportToTarget(chr))
|
||||
ChatHandler(chr).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, GetNameLink().c_str(), addmoney);
|
||||
chr->ModifyMoney( addmoney );
|
||||
|
||||
if (addmoney >=MAX_MONEY_AMOUNT)
|
||||
chr->SetMoney(MAX_MONEY_AMOUNT);
|
||||
else
|
||||
chr->ModifyMoney( addmoney );
|
||||
}
|
||||
|
||||
sLog.outDetail(GetTrinityString(LANG_NEW_MONEY), moneyuser, addmoney, chr->GetMoney() );
|
||||
@@ -2753,6 +2760,51 @@ bool ChatHandler::HandleGroupgoCommand(const char* args)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleGoTaxinodeCommand(const char* args)
|
||||
{
|
||||
Player* _player = m_session->GetPlayer();
|
||||
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
char* cNodeId = extractKeyFromLink((char*)args,"Htaxinode");
|
||||
if (!cNodeId)
|
||||
return false;
|
||||
|
||||
int32 i_nodeId = atoi(cNodeId);
|
||||
if (!i_nodeId)
|
||||
return false;
|
||||
|
||||
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i_nodeId);
|
||||
if (!node)
|
||||
{
|
||||
PSendSysMessage(LANG_COMMAND_GOTAXINODENOTFOUND,i_nodeId);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node->x == 0.0f && node->y == 0.0f && node->z == 0.0f ||
|
||||
!MapManager::IsValidMapCoord(node->map_id,node->x,node->y,node->z))
|
||||
{
|
||||
PSendSysMessage(LANG_INVALID_TARGET_COORD,node->x,node->y,node->map_id);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (_player->isInFlight())
|
||||
{
|
||||
_player->GetMotionMaster()->MovementExpired();
|
||||
_player->m_taxi.ClearTaxiDestinations();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
_player->SaveRecallPosition();
|
||||
|
||||
_player->TeleportTo(node->map_id, node->x, node->y, node->z, _player->GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
//teleport at coordinates
|
||||
bool ChatHandler::HandleGoXYCommand(const char* args)
|
||||
{
|
||||
|
||||
+43
-28
@@ -1288,7 +1288,7 @@ bool ChatHandler::HandleNpcAddMoveCommand(const char* args)
|
||||
|
||||
// update movement type
|
||||
WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
|
||||
if(pCreature && pCreature->GetWaypointPath())
|
||||
if(pCreature && pCreature->GetWaypointPathId())
|
||||
{
|
||||
pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
|
||||
pCreature->GetMotionMaster()->Initialize();
|
||||
@@ -1609,7 +1609,7 @@ bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args)
|
||||
{
|
||||
// update movement type
|
||||
if(doNotDelete == false)
|
||||
pCreature->LoadPath(0);
|
||||
pCreature->SetWaypointPathId(0);
|
||||
|
||||
pCreature->SetDefaultMovementType(move_type);
|
||||
pCreature->GetMotionMaster()->Initialize();
|
||||
@@ -2639,7 +2639,7 @@ bool ChatHandler::HandleWpAddCommand(const char* args)
|
||||
if (!path_number)
|
||||
{
|
||||
if(target)
|
||||
pathid = target->GetWaypointPath();
|
||||
pathid = target->GetWaypointPathId();
|
||||
else
|
||||
{
|
||||
QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(id) FROM waypoint_data");
|
||||
@@ -2694,7 +2694,6 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args)
|
||||
if(*args)
|
||||
path_number = strtok((char*)args, " ");
|
||||
|
||||
|
||||
uint32 pathid = 0;
|
||||
uint32 guidlow = 0;
|
||||
Creature* target = getSelectedCreature();
|
||||
@@ -2725,6 +2724,7 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
guidlow = target->GetDBTableGUIDLow();
|
||||
QueryResult *result = WorldDatabase.PQuery( "SELECT guid FROM creature_addon WHERE guid = '%u'",guidlow);
|
||||
|
||||
@@ -2735,10 +2735,11 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args)
|
||||
}
|
||||
else
|
||||
WorldDatabase.PExecute("INSERT INTO creature_addon(guid,path_id) VALUES ('%u','%u')", guidlow, pathid);
|
||||
*/
|
||||
|
||||
WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE, guidlow);
|
||||
|
||||
target->LoadPath(pathid);
|
||||
target->SetWaypointPathId(pathid);
|
||||
target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
|
||||
target->GetMotionMaster()->Initialize();
|
||||
target->MonsterSay("Path loaded.",0,0);
|
||||
@@ -2746,20 +2747,19 @@ bool ChatHandler::HandleWpLoadPathCommand(const char *args)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ChatHandler::HandleReloadAllPaths(const char* args)
|
||||
{
|
||||
if(!*args)
|
||||
return false;
|
||||
if(!*args)
|
||||
return false;
|
||||
|
||||
uint32 id = atoi(args);
|
||||
uint32 id = atoi(args);
|
||||
|
||||
if(!id)
|
||||
return false;
|
||||
if(!id)
|
||||
return false;
|
||||
|
||||
PSendSysMessage("%s%s|r|cff00ffff%u|r", "|cff00ff00", "Loading Path: ", id);
|
||||
WaypointMgr.UpdatePath(id);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleWpUnLoadPathCommand(const char *args)
|
||||
@@ -2773,24 +2773,39 @@ bool ChatHandler::HandleWpUnLoadPathCommand(const char *args)
|
||||
return true;
|
||||
}
|
||||
|
||||
if(target->GetCreatureAddon())
|
||||
if(target->GetWaypointPathId())
|
||||
{
|
||||
if(target->GetCreatureAddon()->path_id != 0)
|
||||
uint32 pathId = target->GetDBTableGUIDLow() * 10;
|
||||
if(target->GetWaypointPathId() == pathId)
|
||||
{
|
||||
WorldDatabase.PExecute("DELETE FROM creature_addon WHERE guid = %u", target->GetGUIDLow());
|
||||
target->UpdateWaypointID(0);
|
||||
WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow);
|
||||
target->LoadPath(0);
|
||||
target->SetDefaultMovementType(IDLE_MOTION_TYPE);
|
||||
target->GetMotionMaster()->MoveTargetedHome();
|
||||
target->GetMotionMaster()->Initialize();
|
||||
target->MonsterSay("Path unloaded.",0,0);
|
||||
return true;
|
||||
for(uint32 i = 1; i < 11; ++i)
|
||||
{
|
||||
if(i == 10)
|
||||
{
|
||||
PSendSysMessage("%s%s|r", "|cffff33ff", "Target cannot have more than 9 script paths. Unloading failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(WaypointMgr.GetPath(++pathId))
|
||||
continue;
|
||||
|
||||
WorldDatabase.PExecute("UPDATE waypoint_data SET id = %u WHERE id = %u", pathId, target->GetDBTableGUIDLow() * 10);
|
||||
WorldDatabase.PExecute("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", IDLE_MOTION_TYPE, guidlow);
|
||||
target->SetWaypointPathId(0);
|
||||
target->UpdateWaypointID(0);
|
||||
target->SetDefaultMovementType(IDLE_MOTION_TYPE);
|
||||
target->GetMotionMaster()->Initialize();
|
||||
target->GetMotionMaster()->MoveTargetedHome();
|
||||
PSendSysMessage("Path unloaded.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path.");
|
||||
return true;
|
||||
else
|
||||
PSendSysMessage("%s%s|r", "|cffff33ff", "Target has path but that path is not its default path. Unloading failed.");
|
||||
}
|
||||
PSendSysMessage("%s%s|r", "|cffff33ff", "Target have no loaded path.");
|
||||
else
|
||||
PSendSysMessage("%s%s|r", "|cffff33ff", "Target has no loaded path.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3264,7 +3279,7 @@ bool ChatHandler::HandleWpShowCommand(const char* args)
|
||||
return false;
|
||||
}
|
||||
|
||||
pathid = target->GetWaypointPath();
|
||||
pathid = target->GetWaypointPathId();
|
||||
}
|
||||
|
||||
else
|
||||
@@ -4629,7 +4644,7 @@ bool ChatHandler::HandleNpcAddFormationCommand(const char* args)
|
||||
group_member->groupAI = 0;
|
||||
|
||||
CreatureGroupMap[lowguid] = group_member;
|
||||
pCreature->SearchFormation();
|
||||
pCreature->SearchFormationAndPath();
|
||||
|
||||
WorldDatabase.PExecuteLog("INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES ('%u','%u','%f', '%f', '%u')",
|
||||
leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI);
|
||||
|
||||
+76
-14
@@ -1612,11 +1612,7 @@ bool ChatHandler::HandleCooldownCommand(const char* args)
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldPacket data( SMSG_CLEAR_COOLDOWN, (4+8) );
|
||||
data << uint32(spell_id);
|
||||
data << uint64(target->GetGUID());
|
||||
target->GetSession()->SendPacket(&data);
|
||||
target->RemoveSpellCooldown(spell_id);
|
||||
target->RemoveSpellCooldown(spell_id,true);
|
||||
PSendSysMessage(LANG_REMOVE_COOLDOWN, spell_id, target==m_session->GetPlayer() ? GetMangosString(LANG_YOU) : tNameLink.c_str());
|
||||
}
|
||||
return true;
|
||||
@@ -3694,6 +3690,68 @@ bool ChatHandler::HandleLookupObjectCommand(const char* args)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleLookupTaxiNodeCommand(const char * args)
|
||||
{
|
||||
if(!*args)
|
||||
return false;
|
||||
|
||||
std::string namepart = args;
|
||||
std::wstring wnamepart;
|
||||
|
||||
if(!Utf8toWStr(namepart,wnamepart))
|
||||
return false;
|
||||
|
||||
// converting string that we try to find to lower case
|
||||
wstrToLower( wnamepart );
|
||||
|
||||
uint32 counter = 0; // Counter for figure out that we found smth.
|
||||
|
||||
// Search in TaxiNodes.dbc
|
||||
for (uint32 id = 0; id < sTaxiNodesStore.GetNumRows(); id++)
|
||||
{
|
||||
TaxiNodesEntry const *nodeEntry = sTaxiNodesStore.LookupEntry(id);
|
||||
if(nodeEntry)
|
||||
{
|
||||
int loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale();
|
||||
std::string name = nodeEntry->name[loc];
|
||||
if(name.empty())
|
||||
continue;
|
||||
|
||||
if (!Utf8FitTo(name, wnamepart))
|
||||
{
|
||||
loc = 0;
|
||||
for(; loc < MAX_LOCALE; ++loc)
|
||||
{
|
||||
if(m_session && loc==m_session->GetSessionDbcLocale())
|
||||
continue;
|
||||
|
||||
name = nodeEntry->name[loc];
|
||||
if(name.empty())
|
||||
continue;
|
||||
|
||||
if (Utf8FitTo(name, wnamepart))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(loc < MAX_LOCALE)
|
||||
{
|
||||
// send taxinode in "id - [name] (Map:m X:x Y:y Z:z)" format
|
||||
if (m_session)
|
||||
PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CHAT, id, id, name.c_str(),localeNames[loc],
|
||||
nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z);
|
||||
else
|
||||
PSendSysMessage (LANG_TAXINODE_ENTRY_LIST_CONSOLE, id, name.c_str(), localeNames[loc],
|
||||
nodeEntry->map_id,nodeEntry->x,nodeEntry->y,nodeEntry->z);
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (counter == 0) // if counter == 0 then we found nth
|
||||
SendSysMessage(LANG_COMMAND_NOSPELLFOUND);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** \brief GM command level 3 - Create a guild.
|
||||
*
|
||||
* This command allows a GM (level 3) to create a guild.
|
||||
@@ -3966,31 +4024,34 @@ bool ChatHandler::HandleDamageCommand(const char * args)
|
||||
|
||||
Unit* target = getSelectedUnit();
|
||||
|
||||
if(!target || !m_session->GetPlayer()->GetSelection())
|
||||
if (!target || !m_session->GetPlayer()->GetSelection())
|
||||
{
|
||||
SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
|
||||
SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !target->isAlive() )
|
||||
if (!target->isAlive())
|
||||
return true;
|
||||
|
||||
char* damageStr = strtok((char*)args, " ");
|
||||
if(!damageStr)
|
||||
if (!damageStr)
|
||||
return false;
|
||||
|
||||
int32 damage = atoi((char*)damageStr);
|
||||
if(damage <=0)
|
||||
int32 damage_int = atoi((char*)damageStr);
|
||||
if(damage_int <=0)
|
||||
return true;
|
||||
|
||||
uint32 damage = damage_int;
|
||||
|
||||
char* schoolStr = strtok((char*)NULL, " ");
|
||||
|
||||
// flat melee damage without resistence/etc reduction
|
||||
if(!schoolStr)
|
||||
if (!schoolStr)
|
||||
{
|
||||
m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
||||
m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0);
|
||||
if (target != m_session->GetPlayer())
|
||||
m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_NORMAL, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4006,7 +4067,7 @@ bool ChatHandler::HandleDamageCommand(const char * args)
|
||||
char* spellStr = strtok((char*)NULL, " ");
|
||||
|
||||
// melee damage by specific school
|
||||
if(!spellStr)
|
||||
if (!spellStr)
|
||||
{
|
||||
uint32 absorb = 0;
|
||||
uint32 resist = 0;
|
||||
@@ -4018,6 +4079,7 @@ bool ChatHandler::HandleDamageCommand(const char * args)
|
||||
|
||||
damage -= absorb + resist;
|
||||
|
||||
m_session->GetPlayer()->DealDamageMods(target,damage,&absorb);
|
||||
m_session->GetPlayer()->DealDamage(target, damage, NULL, DIRECT_DAMAGE, schoolmask, NULL, false);
|
||||
m_session->GetPlayer()->SendAttackStateUpdate (HITINFO_NORMALSWING2, target, 1, schoolmask, damage, absorb, resist, VICTIMSTATE_NORMAL, 0);
|
||||
return true;
|
||||
@@ -4027,7 +4089,7 @@ bool ChatHandler::HandleDamageCommand(const char * args)
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
|
||||
uint32 spellid = extractSpellIdFromLink((char*)args);
|
||||
if(!spellid || !sSpellStore.LookupEntry(spellid))
|
||||
if (!spellid || !sSpellStore.LookupEntry(spellid))
|
||||
return false;
|
||||
|
||||
m_session->GetPlayer()->SpellNonMeleeDamageLog(target, spellid, damage);
|
||||
|
||||
@@ -224,7 +224,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ )
|
||||
Player* playerGroup = itr->getSource();
|
||||
if(!playerGroup)
|
||||
continue;
|
||||
if (player->GetDistance2d(playerGroup) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
|
||||
if (player->IsWithinDist(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false))
|
||||
playersNear.push_back(playerGroup);
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -120,7 +120,7 @@ void Map::LoadVMap(int gx,int gy)
|
||||
}
|
||||
}
|
||||
|
||||
void Map::LoadMap(int gx,int gy)
|
||||
void Map::LoadMap(int gx,int gy, bool reload)
|
||||
{
|
||||
if( i_InstanceId != 0 )
|
||||
{
|
||||
@@ -138,6 +138,9 @@ void Map::LoadMap(int gx,int gy)
|
||||
return;
|
||||
}
|
||||
|
||||
if(GridMaps[gx][gy] && !reload)
|
||||
return;
|
||||
|
||||
//map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?)
|
||||
if(GridMaps[gx][gy])
|
||||
{
|
||||
@@ -2503,7 +2506,7 @@ void InstanceMap::CreateInstanceData(bool load)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
const char* data = fields[0].GetString();
|
||||
if(data)
|
||||
if(data && data != "")
|
||||
{
|
||||
sLog.outDebug("Loading instance data for `%s` with id %u", objmgr.GetScriptName(i_script_id), i_InstanceId);
|
||||
i_data->Load(data);
|
||||
|
||||
+10
-15
@@ -23,9 +23,9 @@
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Policies/ThreadingModel.h"
|
||||
#include "zthread/Lockable.h"
|
||||
#include "zthread/Mutex.h"
|
||||
#include "zthread/FairReadWriteLock.h"
|
||||
#include "ace/RW_Thread_Mutex.h"
|
||||
#include "ace/Thread_Mutex.h"
|
||||
|
||||
#include "DBCStructure.h"
|
||||
#include "GridDefines.h"
|
||||
#include "Cell.h"
|
||||
@@ -46,13 +46,8 @@ class WorldObject;
|
||||
class TempSummon;
|
||||
class CreatureGroup;
|
||||
|
||||
namespace ZThread
|
||||
{
|
||||
class Lockable;
|
||||
class ReadWriteLock;
|
||||
}
|
||||
|
||||
typedef ZThread::FairReadWriteLock GridRWLock;
|
||||
typedef ACE_RW_Thread_Mutex GridRWLock;
|
||||
|
||||
template<class MUTEX, class LOCK_TYPE>
|
||||
struct RGuard
|
||||
@@ -68,9 +63,9 @@ struct WGuard
|
||||
Trinity::GeneralLock<LOCK_TYPE> i_lock;
|
||||
};
|
||||
|
||||
typedef RGuard<GridRWLock, ZThread::Lockable> GridReadGuard;
|
||||
typedef WGuard<GridRWLock, ZThread::Lockable> GridWriteGuard;
|
||||
typedef Trinity::SingleThreaded<GridRWLock>::Lock NullGuard;
|
||||
typedef RGuard<GridRWLock, ACE_Thread_Mutex> GridReadGuard;
|
||||
typedef WGuard<GridRWLock, ACE_Thread_Mutex> GridWriteGuard;
|
||||
typedef MaNGOS::SingleThreaded<GridRWLock>::Lock NullGuard;
|
||||
|
||||
//******************************************
|
||||
// Map file format defines
|
||||
@@ -251,7 +246,7 @@ typedef UNORDERED_MAP<Creature*, CreatureMover> CreatureMoveList;
|
||||
|
||||
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
|
||||
|
||||
class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::ObjectLevelLockable<Map, ZThread::Mutex>
|
||||
class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::ObjectLevelLockable<Map, ACE_Thread_Mutex>
|
||||
{
|
||||
friend class MapReference;
|
||||
public:
|
||||
@@ -426,7 +421,7 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
|
||||
private:
|
||||
void LoadMapAndVMap(int gx, int gy);
|
||||
void LoadVMap(int gx, int gy);
|
||||
void LoadMap(int gx,int gy);
|
||||
void LoadMap(int gx,int gy, bool reload = false);
|
||||
GridMap *GetGrid(float x, float y);
|
||||
|
||||
void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; }
|
||||
@@ -466,7 +461,7 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
|
||||
protected:
|
||||
void SetUnloadReferenceLock(const GridPair &p, bool on) { getNGrid(p.x_coord, p.y_coord)->setUnloadReferenceLock(on); }
|
||||
|
||||
typedef Trinity::ObjectLevelLockable<Map, ZThread::Mutex>::Lock Guard;
|
||||
typedef MaNGOS::ObjectLevelLockable<Map, ACE_Thread_Mutex>::Lock Guard;
|
||||
|
||||
MapEntry const* i_mapEntry;
|
||||
uint8 i_spawnMode;
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
#include "ObjectMgr.h"
|
||||
#include "Language.h"
|
||||
|
||||
#define CLASS_LOCK Trinity::ClassLevelLockable<MapManager, ZThread::Mutex>
|
||||
#define CLASS_LOCK MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex>
|
||||
INSTANTIATE_SINGLETON_2(MapManager, CLASS_LOCK);
|
||||
INSTANTIATE_CLASS_MUTEX(MapManager, ZThread::Mutex);
|
||||
INSTANTIATE_CLASS_MUTEX(MapManager, ACE_Thread_Mutex);
|
||||
|
||||
extern GridState* si_GridStates[]; // debugging code, should be deleted some day
|
||||
|
||||
|
||||
@@ -23,14 +23,14 @@
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include "zthread/Mutex.h"
|
||||
#include "ace/Thread_Mutex.h"
|
||||
#include "Common.h"
|
||||
#include "Map.h"
|
||||
#include "GridStates.h"
|
||||
|
||||
class Transport;
|
||||
|
||||
class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinity::ClassLevelLockable<MapManager, ZThread::Mutex> >
|
||||
class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex> >
|
||||
{
|
||||
|
||||
friend class Trinity::OperatorNew<MapManager>;
|
||||
@@ -149,7 +149,7 @@ class TRINITY_DLL_DECL MapManager : public Trinity::Singleton<MapManager, Trinit
|
||||
return (iter == i_maps.end() ? NULL : iter->second);
|
||||
}
|
||||
|
||||
typedef Trinity::ClassLevelLockable<MapManager, ZThread::Mutex>::Lock Guard;
|
||||
typedef MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex>::Lock Guard;
|
||||
uint32 i_gridCleanUpDelay;
|
||||
MapMapType i_maps;
|
||||
IntervalTimer i_timer;
|
||||
|
||||
+23
-20
@@ -44,6 +44,7 @@
|
||||
#include "Pet.h"
|
||||
#include "SocialMgr.h"
|
||||
#include "CellImpl.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "Vehicle.h"
|
||||
#include "CreatureAI.h"
|
||||
|
||||
@@ -561,12 +562,13 @@ void WorldSession::HandleAddFriendOpcode( WorldPacket & recv_data )
|
||||
sLog.outDebug( "WORLD: %s asked to add friend : '%s'",
|
||||
GetPlayer()->GetName(), friendName.c_str() );
|
||||
|
||||
CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race FROM characters WHERE name = '%s'", friendName.c_str());
|
||||
CharacterDatabase.AsyncPQuery(&WorldSession::HandleAddFriendOpcodeCallBack, GetAccountId(), friendNote, "SELECT guid, race, account FROM characters WHERE name = '%s'", friendName.c_str());
|
||||
}
|
||||
|
||||
void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult *result, uint32 accountId, std::string friendNote)
|
||||
{
|
||||
uint64 friendGuid;
|
||||
uint64 friendAcctid;
|
||||
uint32 team;
|
||||
FriendsResult friendResult;
|
||||
|
||||
@@ -582,30 +584,33 @@ void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult *result, uint32 acc
|
||||
{
|
||||
friendGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
|
||||
team = Player::TeamForRace((*result)[1].GetUInt8());
|
||||
friendAcctid = (*result)[2].GetUInt32();
|
||||
|
||||
delete result;
|
||||
|
||||
if(friendGuid)
|
||||
if ( session->GetSecurity() >= SEC_MODERATOR || sWorld.getConfig(CONFIG_ALLOW_GM_FRIEND) || accmgr.GetSecurity(friendAcctid) < SEC_MODERATOR)
|
||||
{
|
||||
if(friendGuid==session->GetPlayer()->GetGUID())
|
||||
friendResult = FRIEND_SELF;
|
||||
else if(session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR)
|
||||
friendResult = FRIEND_ENEMY;
|
||||
else if(session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
|
||||
friendResult = FRIEND_ALREADY;
|
||||
else
|
||||
if(friendGuid)
|
||||
{
|
||||
Player* pFriend = ObjectAccessor::FindPlayer(friendGuid);
|
||||
if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer()))
|
||||
friendResult = FRIEND_ADDED_ONLINE;
|
||||
if(friendGuid==session->GetPlayer()->GetGUID())
|
||||
friendResult = FRIEND_SELF;
|
||||
else if(session->GetPlayer()->GetTeam() != team && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && session->GetSecurity() < SEC_MODERATOR)
|
||||
friendResult = FRIEND_ENEMY;
|
||||
else if(session->GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
|
||||
friendResult = FRIEND_ALREADY;
|
||||
else
|
||||
friendResult = FRIEND_ADDED_OFFLINE;
|
||||
if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
|
||||
{
|
||||
friendResult = FRIEND_LIST_FULL;
|
||||
sLog.outDebug( "WORLD: %s's friend list is full.", session->GetPlayer()->GetName());
|
||||
Player* pFriend = ObjectAccessor::FindPlayer(friendGuid);
|
||||
if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(session->GetPlayer()))
|
||||
friendResult = FRIEND_ADDED_ONLINE;
|
||||
else
|
||||
friendResult = FRIEND_ADDED_OFFLINE;
|
||||
if(!session->GetPlayer()->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
|
||||
{
|
||||
friendResult = FRIEND_LIST_FULL;
|
||||
sLog.outDebug( "WORLD: %s's friend list is full.", session->GetPlayer()->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
session->GetPlayer()->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote);
|
||||
}
|
||||
}
|
||||
@@ -775,9 +780,7 @@ void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data)
|
||||
if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL))
|
||||
return;
|
||||
|
||||
float dist = corpse->GetDistance2d(GetPlayer());
|
||||
sLog.outDebug("Corpse 2D Distance: \t%f",dist);
|
||||
if (dist > CORPSE_RECLAIM_RADIUS)
|
||||
if (!corpse->IsWithinDist(GetPlayer(),CORPSE_RECLAIM_RADIUS,false))
|
||||
return;
|
||||
|
||||
uint64 guid;
|
||||
|
||||
@@ -203,14 +203,7 @@ MotionMaster::MoveTargetedHome()
|
||||
|
||||
Clear(false);
|
||||
|
||||
if(Unit *target = i_owner->GetCharmerOrOwner())
|
||||
{
|
||||
DEBUG_LOG("Pet or controlled unit (Entry: %u GUID: %u) targeting home",
|
||||
i_owner->GetEntry(), i_owner->GetGUIDLow() );
|
||||
|
||||
MoveFollow(target, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE, MOTION_SLOT_IDLE);
|
||||
}
|
||||
else if(i_owner->GetTypeId() == TYPEID_UNIT)
|
||||
if(i_owner->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow());
|
||||
Mutate(new HomeMovementGenerator<Creature>(), MOTION_SLOT_ACTIVE);
|
||||
@@ -218,7 +211,6 @@ MotionMaster::MoveTargetedHome()
|
||||
else
|
||||
{
|
||||
sLog.outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow() );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,40 +22,47 @@
|
||||
#define TRINITY_NULLCREATUREAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
|
||||
class TRINITY_DLL_DECL PassiveAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit PassiveAI(Creature *c) : CreatureAI(c) {}
|
||||
~PassiveAI() {}
|
||||
|
||||
void MoveInLineOfSight(Unit *) {}
|
||||
void AttackStart(Unit *) {}
|
||||
|
||||
void UpdateAI(const uint32);
|
||||
|
||||
static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; }
|
||||
};
|
||||
|
||||
class TRINITY_DLL_DECL PossessedAI : public PassiveAI
|
||||
class TRINITY_DLL_DECL PossessedAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit PossessedAI(Creature *c) : PassiveAI(c) {}
|
||||
explicit PossessedAI(Creature *c) : CreatureAI(c) {}
|
||||
|
||||
void MoveInLineOfSight(Unit *) {}
|
||||
void AttackStart(Unit *target);
|
||||
void UpdateAI(const uint32);
|
||||
void EnterEvadeMode() {}
|
||||
|
||||
void JustDied(Unit*);
|
||||
void KilledUnit(Unit* victim);
|
||||
|
||||
static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; }
|
||||
};
|
||||
|
||||
class TRINITY_DLL_DECL NullCreatureAI : public PassiveAI
|
||||
class TRINITY_DLL_DECL NullCreatureAI : public CreatureAI
|
||||
{
|
||||
public:
|
||||
explicit NullCreatureAI(Creature *c) : PassiveAI(c) {}
|
||||
explicit NullCreatureAI(Creature *c) : CreatureAI(c) {}
|
||||
|
||||
void MoveInLineOfSight(Unit *) {}
|
||||
void AttackStart(Unit *) {}
|
||||
void UpdateAI(const uint32) {}
|
||||
void EnterEvadeMode() {}
|
||||
|
||||
static int Permissible(const Creature *) { return PERMIT_BASE_IDLE; }
|
||||
};
|
||||
|
||||
class TRINITY_DLL_DECL CritterAI : public PassiveAI
|
||||
|
||||
+323
-8
@@ -1148,7 +1148,6 @@ InstanceData* WorldObject::GetInstanceData()
|
||||
Map *map = GetMap();
|
||||
return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
|
||||
}
|
||||
|
||||
//slow
|
||||
float WorldObject::GetDistance(const WorldObject* obj) const
|
||||
{
|
||||
@@ -1176,7 +1175,7 @@ float WorldObject::GetExactDistance2d(const float x, const float y) const
|
||||
return sqrt((dx*dx) + (dy*dy));
|
||||
}
|
||||
|
||||
float WorldObject::GetDistance(const float x, const float y, const float z) const
|
||||
float WorldObject::GetDistance(float x, float y, float z) const
|
||||
{
|
||||
float dx = GetPositionX() - x;
|
||||
float dy = GetPositionY() - y;
|
||||
@@ -1194,6 +1193,14 @@ float WorldObject::GetDistanceSq(const float &x, const float &y, const float &z)
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
float WorldObject::GetDistanceSq(const WorldObject *obj) const
|
||||
{
|
||||
float dx = GetPositionX() - obj->GetPositionX();
|
||||
float dy = GetPositionY() - obj->GetPositionY();
|
||||
float dz = GetPositionZ() - obj->GetPositionZ();
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
}
|
||||
|
||||
float WorldObject::GetDistance2d(const WorldObject* obj) const
|
||||
{
|
||||
float dx = GetPositionX() - obj->GetPositionX();
|
||||
@@ -1211,10 +1218,33 @@ float WorldObject::GetDistanceZ(const WorldObject* obj) const
|
||||
return ( dist > 0 ? dist : 0);
|
||||
}
|
||||
|
||||
bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D) const
|
||||
bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist2compare) const
|
||||
{
|
||||
if (!obj || !IsInMap(obj)) return false;
|
||||
float dx = GetPositionX() - x;
|
||||
float dy = GetPositionY() - y;
|
||||
float dz = GetPositionZ() - z;
|
||||
float distsq = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
float sizefactor = GetObjectSize();
|
||||
float maxdist = dist2compare + sizefactor;
|
||||
|
||||
return distsq < maxdist * maxdist;
|
||||
}
|
||||
|
||||
bool WorldObject::IsWithinDist2d(float x, float y, float dist2compare) const
|
||||
{
|
||||
float dx = GetPositionX() - x;
|
||||
float dy = GetPositionY() - y;
|
||||
float distsq = dx*dx + dy*dy;
|
||||
|
||||
float sizefactor = GetObjectSize();
|
||||
float maxdist = dist2compare + sizefactor;
|
||||
|
||||
return distsq < maxdist * maxdist;
|
||||
}
|
||||
|
||||
bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const
|
||||
{
|
||||
float dx = GetPositionX() - obj->GetPositionX();
|
||||
float dy = GetPositionY() - obj->GetPositionY();
|
||||
float distsq = dx*dx + dy*dy;
|
||||
@@ -1237,7 +1267,7 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
|
||||
return(IsWithinLOS(ox, oy, oz ));
|
||||
}
|
||||
|
||||
bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const
|
||||
bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
|
||||
{
|
||||
float x,y,z;
|
||||
GetPosition(x,y,z);
|
||||
@@ -1245,6 +1275,83 @@ bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) c
|
||||
return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);
|
||||
}
|
||||
|
||||
bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const
|
||||
{
|
||||
float dx1 = GetPositionX() - obj1->GetPositionX();
|
||||
float dy1 = GetPositionY() - obj1->GetPositionY();
|
||||
float distsq1 = dx1*dx1 + dy1*dy1;
|
||||
if(is3D)
|
||||
{
|
||||
float dz1 = GetPositionZ() - obj1->GetPositionZ();
|
||||
distsq1 += dz1*dz1;
|
||||
}
|
||||
|
||||
float dx2 = GetPositionX() - obj2->GetPositionX();
|
||||
float dy2 = GetPositionY() - obj2->GetPositionY();
|
||||
float distsq2 = dx2*dx2 + dy2*dy2;
|
||||
if(is3D)
|
||||
{
|
||||
float dz2 = GetPositionZ() - obj2->GetPositionZ();
|
||||
distsq2 += dz2*dz2;
|
||||
}
|
||||
|
||||
return distsq1 < distsq2;
|
||||
}
|
||||
|
||||
bool WorldObject::IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D /* = true */) const
|
||||
{
|
||||
float dx = GetPositionX() - obj->GetPositionX();
|
||||
float dy = GetPositionY() - obj->GetPositionY();
|
||||
float distsq = dx*dx + dy*dy;
|
||||
if(is3D)
|
||||
{
|
||||
float dz = GetPositionZ() - obj->GetPositionZ();
|
||||
distsq += dz*dz;
|
||||
}
|
||||
|
||||
float sizefactor = GetObjectSize() + obj->GetObjectSize();
|
||||
|
||||
float mindist = minRange + sizefactor;
|
||||
if(distsq < mindist * mindist)
|
||||
return false;
|
||||
|
||||
float maxdist = maxRange + sizefactor;
|
||||
return distsq < maxdist * maxdist;
|
||||
}
|
||||
|
||||
bool WorldObject::IsInRange2d(float x, float y, float minRange, float maxRange) const
|
||||
{
|
||||
float dx = GetPositionX() - x;
|
||||
float dy = GetPositionY() - y;
|
||||
float distsq = dx*dx + dy*dy;
|
||||
|
||||
float sizefactor = GetObjectSize();
|
||||
|
||||
float mindist = minRange + sizefactor;
|
||||
if(distsq < mindist * mindist)
|
||||
return false;
|
||||
|
||||
float maxdist = maxRange + sizefactor;
|
||||
return distsq < maxdist * maxdist;
|
||||
}
|
||||
|
||||
bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float maxRange) const
|
||||
{
|
||||
float dx = GetPositionX() - x;
|
||||
float dy = GetPositionY() - y;
|
||||
float dz = GetPositionZ() - z;
|
||||
float distsq = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
float sizefactor = GetObjectSize();
|
||||
|
||||
float mindist = minRange + sizefactor;
|
||||
if(distsq < mindist * mindist)
|
||||
return false;
|
||||
|
||||
float maxdist = maxRange + sizefactor;
|
||||
return distsq < maxdist * maxdist;
|
||||
}
|
||||
|
||||
float WorldObject::GetAngle(const WorldObject* obj) const
|
||||
{
|
||||
if(!obj) return 0;
|
||||
@@ -1309,6 +1416,21 @@ bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
|
||||
return (( angle >= lborder ) && ( angle <= rborder ));
|
||||
}
|
||||
|
||||
bool WorldObject::IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size) const
|
||||
{
|
||||
if(GetPositionX() > std::max(obj1->GetPositionX(), obj2->GetPositionX())
|
||||
|| GetPositionX() < std::min(obj1->GetPositionX(), obj2->GetPositionX())
|
||||
|| GetPositionY() > std::max(obj1->GetPositionY(), obj2->GetPositionY())
|
||||
|| GetPositionY() < std::min(obj1->GetPositionY(), obj2->GetPositionY()))
|
||||
return false;
|
||||
|
||||
if(!size)
|
||||
size = GetObjectSize() / 2;
|
||||
|
||||
float angle = obj1->GetAngle(this) - obj1->GetAngle(obj2);
|
||||
return abs(sin(angle)) * GetExactDistance2d(obj1->GetPositionX(), obj1->GetPositionY()) < size;
|
||||
}
|
||||
|
||||
void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
|
||||
{
|
||||
if(distance==0)
|
||||
@@ -1658,6 +1780,8 @@ TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float a
|
||||
return NULL;
|
||||
}
|
||||
|
||||
summon->SetHomePosition(x, y, z, angle);
|
||||
|
||||
summon->InitStats(duration);
|
||||
Add((Creature*)summon);
|
||||
summon->InitSummon();
|
||||
@@ -1680,7 +1804,6 @@ TempSummon* WorldObject::SummonCreature(uint32 entry, float x, float y, float z,
|
||||
if(!pCreature)
|
||||
return NULL;
|
||||
|
||||
pCreature->SetHomePosition(x, y, z, ang);
|
||||
pCreature->SetTempSummonType(spwtype);
|
||||
|
||||
return pCreature;
|
||||
@@ -1890,6 +2013,81 @@ Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint3
|
||||
return summon;
|
||||
}
|
||||
|
||||
/*
|
||||
namespace MaNGOS
|
||||
{
|
||||
class NearUsedPosDo
|
||||
{
|
||||
public:
|
||||
NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float angle, ObjectPosSelector& selector)
|
||||
: i_object(obj), i_searcher(searcher), i_angle(angle), i_selector(selector) {}
|
||||
|
||||
void operator()(Corpse*) const {}
|
||||
void operator()(DynamicObject*) const {}
|
||||
|
||||
void operator()(Creature* c) const
|
||||
{
|
||||
// skip self or target
|
||||
if(c==i_searcher || c==&i_object)
|
||||
return;
|
||||
|
||||
float x,y,z;
|
||||
|
||||
if( !c->isAlive() || c->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) ||
|
||||
!c->GetMotionMaster()->GetDestination(x,y,z) )
|
||||
{
|
||||
x = c->GetPositionX();
|
||||
y = c->GetPositionY();
|
||||
}
|
||||
|
||||
add(c,x,y);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void operator()(T* u) const
|
||||
{
|
||||
// skip self or target
|
||||
if(u==i_searcher || u==&i_object)
|
||||
return;
|
||||
|
||||
float x,y;
|
||||
|
||||
x = u->GetPositionX();
|
||||
y = u->GetPositionY();
|
||||
|
||||
add(u,x,y);
|
||||
}
|
||||
|
||||
// we must add used pos that can fill places around center
|
||||
void add(WorldObject* u, float x, float y) const
|
||||
{
|
||||
// u is too nearest/far away to i_object
|
||||
if(!i_object.IsInRange2d(x,y,i_selector.m_dist - i_selector.m_size,i_selector.m_dist + i_selector.m_size))
|
||||
return;
|
||||
|
||||
float angle = i_object.GetAngle(u)-i_angle;
|
||||
|
||||
// move angle to range -pi ... +pi
|
||||
while( angle > M_PI)
|
||||
angle -= 2.0f * M_PI;
|
||||
while(angle < -M_PI)
|
||||
angle += 2.0f * M_PI;
|
||||
|
||||
// dist include size of u
|
||||
float dist2d = i_object.GetDistance2d(x,y);
|
||||
i_selector.AddUsedPos(u->GetObjectSize(),angle,dist2d + i_object.GetObjectSize());
|
||||
}
|
||||
private:
|
||||
WorldObject const& i_object;
|
||||
WorldObject const* i_searcher;
|
||||
float i_angle;
|
||||
ObjectPosSelector& i_selector;
|
||||
};
|
||||
} // namespace MaNGOS
|
||||
*/
|
||||
|
||||
//===================================================================================================
|
||||
|
||||
void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const
|
||||
{
|
||||
x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle);
|
||||
@@ -1902,10 +2100,127 @@ void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float abs
|
||||
void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const
|
||||
{
|
||||
GetNearPoint2D(x,y,distance2d+searcher_size,absAngle);
|
||||
|
||||
z = GetPositionZ();
|
||||
|
||||
UpdateGroundPositionZ(x,y,z);
|
||||
|
||||
/*
|
||||
// if detection disabled, return first point
|
||||
if(!sWorld.getConfig(CONFIG_DETECT_POS_COLLISION))
|
||||
{
|
||||
UpdateGroundPositionZ(x,y,z); // update to LOS height if available
|
||||
return;
|
||||
}
|
||||
|
||||
// or remember first point
|
||||
float first_x = x;
|
||||
float first_y = y;
|
||||
bool first_los_conflict = false; // first point LOS problems
|
||||
|
||||
// prepare selector for work
|
||||
ObjectPosSelector selector(GetPositionX(),GetPositionY(),GetObjectSize(),distance2d+searcher_size);
|
||||
|
||||
// adding used positions around object
|
||||
{
|
||||
CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()));
|
||||
Cell cell(p);
|
||||
cell.data.Part.reserved = ALL_DISTRICT;
|
||||
cell.SetNoCreate();
|
||||
|
||||
MaNGOS::NearUsedPosDo u_do(*this,searcher,absAngle,selector);
|
||||
MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(this,u_do);
|
||||
|
||||
TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, GridTypeMapContainer > grid_obj_worker(worker);
|
||||
TypeContainerVisitor<MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo>, WorldTypeMapContainer > world_obj_worker(worker);
|
||||
|
||||
CellLock<GridReadGuard> cell_lock(cell, p);
|
||||
cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap());
|
||||
cell_lock->Visit(cell_lock, world_obj_worker, *GetMap());
|
||||
}
|
||||
|
||||
// maybe can just place in primary position
|
||||
if( selector.CheckOriginal() )
|
||||
{
|
||||
UpdateGroundPositionZ(x,y,z); // update to LOS height if available
|
||||
|
||||
if(IsWithinLOS(x,y,z))
|
||||
return;
|
||||
|
||||
first_los_conflict = true; // first point have LOS problems
|
||||
}
|
||||
|
||||
float angle; // candidate of angle for free pos
|
||||
|
||||
// special case when one from list empty and then empty side preferred
|
||||
if(selector.FirstAngle(angle))
|
||||
{
|
||||
GetNearPoint2D(x,y,distance2d,absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x,y,z); // update to LOS height if available
|
||||
|
||||
if(IsWithinLOS(x,y,z))
|
||||
return;
|
||||
}
|
||||
|
||||
// set first used pos in lists
|
||||
selector.InitializeAngle();
|
||||
|
||||
// select in positions after current nodes (selection one by one)
|
||||
while(selector.NextAngle(angle)) // angle for free pos
|
||||
{
|
||||
GetNearPoint2D(x,y,distance2d,absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x,y,z); // update to LOS height if available
|
||||
|
||||
if(IsWithinLOS(x,y,z))
|
||||
return;
|
||||
}
|
||||
|
||||
// BAD NEWS: not free pos (or used or have LOS problems)
|
||||
// Attempt find _used_ pos without LOS problem
|
||||
|
||||
if(!first_los_conflict)
|
||||
{
|
||||
x = first_x;
|
||||
y = first_y;
|
||||
|
||||
UpdateGroundPositionZ(x,y,z); // update to LOS height if available
|
||||
return;
|
||||
}
|
||||
|
||||
// special case when one from list empty and then empty side preferred
|
||||
if( selector.IsNonBalanced() )
|
||||
{
|
||||
if(!selector.FirstAngle(angle)) // _used_ pos
|
||||
{
|
||||
GetNearPoint2D(x,y,distance2d,absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x,y,z); // update to LOS height if available
|
||||
|
||||
if(IsWithinLOS(x,y,z))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// set first used pos in lists
|
||||
selector.InitializeAngle();
|
||||
|
||||
// select in positions after current nodes (selection one by one)
|
||||
while(selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
|
||||
{
|
||||
GetNearPoint2D(x,y,distance2d,absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x,y,z); // update to LOS height if available
|
||||
|
||||
if(IsWithinLOS(x,y,z))
|
||||
return;
|
||||
}
|
||||
|
||||
// BAD BAD NEWS: all found pos (free and used) have LOS problem :(
|
||||
x = first_x;
|
||||
y = first_y;
|
||||
|
||||
UpdateGroundPositionZ(x,y,z); // update to LOS height if available
|
||||
*/
|
||||
}
|
||||
|
||||
void WorldObject::GetGroundPoint(float &x, float &y, float &z, float dist, float angle)
|
||||
|
||||
+21
-4
@@ -461,10 +461,11 @@ class TRINITY_DLL_SPEC WorldObject : public Object
|
||||
virtual const char* GetNameForLocaleIdx(int32 /*locale_idx*/) const { return GetName(); }
|
||||
|
||||
float GetDistance( const WorldObject* obj ) const;
|
||||
float GetDistance(const float x, const float y, const float z) const;
|
||||
float GetDistance(float x, float y, float z) const;
|
||||
float GetDistanceSq(const float &x, const float &y, const float &z) const;
|
||||
float GetDistanceSq(const WorldObject *obj) const;
|
||||
float GetDistance2d(const WorldObject* obj) const;
|
||||
float GetDistance2d(const float x, const float y) const;
|
||||
float GetDistance2d(float x, float y) const;
|
||||
float GetExactDistance2d(const float x, const float y) const;
|
||||
float GetDistanceZ(const WorldObject* obj) const;
|
||||
bool IsInMap(const WorldObject* obj) const
|
||||
@@ -472,14 +473,30 @@ class TRINITY_DLL_SPEC WorldObject : public Object
|
||||
return IsInWorld() && obj->IsInWorld() && GetMapId()==obj->GetMapId() &&
|
||||
GetInstanceId()==obj->GetInstanceId() && InSamePhase(obj);
|
||||
}
|
||||
bool IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D = true) const;
|
||||
bool IsWithinLOS(const float x, const float y, const float z ) const;
|
||||
bool IsWithinDist3d(float x, float y, float z, float dist2compare) const;
|
||||
bool IsWithinDist2d(float x, float y, float dist2compare) const;
|
||||
bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const;
|
||||
bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const
|
||||
// use only if you will sure about placing both object at same map
|
||||
{
|
||||
return obj && _IsWithinDist(obj,dist2compare,is3D);
|
||||
}
|
||||
bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const
|
||||
{
|
||||
return obj && IsInMap(obj) && _IsWithinDist(obj,dist2compare,is3D);
|
||||
}
|
||||
bool IsWithinLOS(float x, float y, float z) const;
|
||||
bool IsWithinLOSInMap(const WorldObject* obj) const;
|
||||
bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const;
|
||||
bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const;
|
||||
bool IsInRange2d(float x, float y, float minRange, float maxRange) const;
|
||||
bool IsInRange3d(float x, float y, float z, float minRange, float maxRange) const;
|
||||
|
||||
float GetAngle( const WorldObject* obj ) const;
|
||||
float GetAngle( const float x, const float y ) const;
|
||||
void GetSinCos(const float x, const float y, float &vsin, float &vcos);
|
||||
bool HasInArc( const float arcangle, const WorldObject* obj ) const;
|
||||
bool IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size = 0) const;
|
||||
|
||||
virtual void SendMessageToSet(WorldPacket *data, bool self, bool to_possessor = true);
|
||||
virtual void SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool to_possessor = true);
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define CLASS_LOCK Trinity::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex>
|
||||
#define CLASS_LOCK MaNGOS::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex>
|
||||
INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK);
|
||||
INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ZThread::FastMutex);
|
||||
INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex);
|
||||
|
||||
ObjectAccessor::ObjectAccessor() {}
|
||||
ObjectAccessor::~ObjectAccessor() {}
|
||||
@@ -470,7 +470,7 @@ ObjectAccessor::UpdateObjectVisibility(WorldObject *obj)
|
||||
/// Define the static member of HashMapHolder
|
||||
|
||||
template <class T> UNORDERED_MAP< uint64, T* > HashMapHolder<T>::m_objectMap;
|
||||
template <class T> ZThread::FastMutex HashMapHolder<T>::i_lock;
|
||||
template <class T> ACE_Thread_Mutex HashMapHolder<T>::i_lock;
|
||||
|
||||
/// Global definitions for the hashmap storage
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "Platform/Define.h"
|
||||
#include "Policies/Singleton.h"
|
||||
#include "zthread/FastMutex.h"
|
||||
#include <ace/Thread_Mutex.h>
|
||||
#include "Utilities/UnorderedMap.h"
|
||||
#include "Policies/ThreadingModel.h"
|
||||
|
||||
@@ -51,8 +51,8 @@ class HashMapHolder
|
||||
public:
|
||||
|
||||
typedef UNORDERED_MAP< uint64, T* > MapType;
|
||||
typedef ZThread::FastMutex LockType;
|
||||
typedef Trinity::GeneralLock<LockType > Guard;
|
||||
typedef ACE_Thread_Mutex LockType;
|
||||
typedef MaNGOS::GeneralLock<LockType > Guard;
|
||||
|
||||
static void Insert(T* o) { m_objectMap[o->GetGUID()] = o; }
|
||||
|
||||
@@ -80,7 +80,7 @@ class HashMapHolder
|
||||
static MapType m_objectMap;
|
||||
};
|
||||
|
||||
class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor, Trinity::ClassLevelLockable<ObjectAccessor, ZThread::FastMutex> >
|
||||
class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor, MaNGOS::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex> >
|
||||
{
|
||||
|
||||
friend class Trinity::OperatorNew<ObjectAccessor>;
|
||||
@@ -228,8 +228,8 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
|
||||
friend struct WorldObjectChangeAccumulator;
|
||||
Player2CorpsesMapType i_player2corpse;
|
||||
|
||||
typedef ZThread::FastMutex LockType;
|
||||
typedef Trinity::GeneralLock<LockType > Guard;
|
||||
typedef ACE_Thread_Mutex LockType;
|
||||
typedef MaNGOS::GeneralLock<LockType > Guard;
|
||||
|
||||
static void _buildChangeObjectForPlayer(WorldObject *, UpdateDataMapType &);
|
||||
static void _buildPacket(Player *, Object *, UpdateDataMapType &);
|
||||
|
||||
@@ -4837,7 +4837,7 @@ void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, ui
|
||||
path = dest_i->second.ID;
|
||||
}
|
||||
|
||||
uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
|
||||
uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team, bool allowed_alt_team /* = false */)
|
||||
{
|
||||
uint16 mount_entry = 0;
|
||||
uint16 mount_id = 0;
|
||||
@@ -4848,6 +4848,9 @@ uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
|
||||
if (team == ALLIANCE)
|
||||
{
|
||||
mount_entry = node->MountCreatureID[1];
|
||||
if(!mount_entry && allowed_alt_team)
|
||||
mount_entry = node->MountCreatureID[0];
|
||||
|
||||
CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
|
||||
if(ci)
|
||||
mount_id = ci->Modelid_A1;
|
||||
@@ -4855,6 +4858,10 @@ uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
|
||||
if (team == HORDE)
|
||||
{
|
||||
mount_entry = node->MountCreatureID[0];
|
||||
|
||||
if(!mount_entry && allowed_alt_team)
|
||||
mount_entry = node->MountCreatureID[1];
|
||||
|
||||
CreatureInfo const *ci = GetCreatureTemplate(mount_entry);
|
||||
if(ci)
|
||||
mount_id = ci->Modelid_H1;
|
||||
|
||||
@@ -418,7 +418,7 @@ class ObjectMgr
|
||||
|
||||
uint32 GetNearestTaxiNode( float x, float y, float z, uint32 mapid, uint32 team );
|
||||
void GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost);
|
||||
uint16 GetTaxiMount( uint32 id, uint32 team );
|
||||
uint16 GetTaxiMount( uint32 id, uint32 team, bool allowed_alt_team = false);
|
||||
void GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds );
|
||||
void GetTransportPathNodes( uint32 path, TransportPath &pathnodes );
|
||||
|
||||
|
||||
@@ -768,7 +768,7 @@ bool OutdoorPvPObjectiveEP_PWT::HandleGossipOption(Player *plr, uint64 guid, uin
|
||||
nodes[1] = dst;
|
||||
|
||||
plr->PlayerTalkClass->CloseGossip();
|
||||
plr->ActivateTaxiPathTo(nodes, 0, cr);
|
||||
plr->ActivateTaxiPathTo(nodes, cr);
|
||||
// leave the opvp, seems like moveinlineofsight isn't called when entering a taxi
|
||||
HandlePlayerLeave(plr);
|
||||
}
|
||||
|
||||
+24
-6
@@ -190,10 +190,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getPetType() == HUNTER_PET || (getPetType() == SUMMON_PET && cinfo->type == CREATURE_TYPE_DEMON && owner->getClass() == CLASS_WARLOCK))
|
||||
m_charmInfo->SetPetNumber(pet_number, true);
|
||||
else
|
||||
m_charmInfo->SetPetNumber(pet_number, false);
|
||||
m_charmInfo->SetPetNumber(pet_number, IsPermanentPetFor(owner));
|
||||
|
||||
// set current pet as current
|
||||
// 0=current
|
||||
@@ -1685,6 +1682,27 @@ void Pet::ToggleAutocast(uint32 spellid, bool apply)
|
||||
}
|
||||
}
|
||||
|
||||
bool Pet::IsPermanentPetFor(Player* owner)
|
||||
{
|
||||
switch(getPetType())
|
||||
{
|
||||
case SUMMON_PET:
|
||||
switch(owner->getClass())
|
||||
{
|
||||
case CLASS_WARLOCK:
|
||||
return GetCreatureInfo()->type == CREATURE_TYPE_DEMON;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
return GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
case HUNTER_PET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Pet::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number)
|
||||
{
|
||||
SetMapId(map->GetId());
|
||||
@@ -1735,10 +1753,10 @@ void Pet::LearnPetPassives()
|
||||
void Pet::CastPetAuras(bool current)
|
||||
{
|
||||
Unit* owner = GetOwner();
|
||||
if(!owner)
|
||||
if(!owner || owner->GetTypeId()!=TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
if(getPetType() != HUNTER_PET && (getPetType() != SUMMON_PET || owner->getClass() != CLASS_WARLOCK))
|
||||
if(!IsPermanentPetFor((Player*)owner))
|
||||
return;
|
||||
|
||||
for(PetAuraSet::const_iterator itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
|
||||
|
||||
+5
-1
@@ -121,11 +121,13 @@ typedef std::vector<uint32> AutoSpellList;
|
||||
|
||||
#define ACTIVE_SPELLS_MAX 4
|
||||
|
||||
#define OWNER_MAX_DISTANCE 100
|
||||
#define OWNER_MAX_DISTANCE 100.0f
|
||||
|
||||
#define PET_FOLLOW_DIST 1
|
||||
#define PET_FOLLOW_ANGLE (M_PI/2)
|
||||
|
||||
class Player;
|
||||
|
||||
class Pet : public Guardian
|
||||
{
|
||||
public:
|
||||
@@ -140,6 +142,8 @@ class Pet : public Guardian
|
||||
bool isControlled() const { return getPetType()==SUMMON_PET || getPetType()==HUNTER_PET; }
|
||||
bool isTemporarySummoned() const { return m_duration > 0; }
|
||||
|
||||
bool IsPermanentPetFor(Player* owner); // pet have tab in character windows and set UNIT_FIELD_PETNUMBER
|
||||
|
||||
bool Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number);
|
||||
bool CreateBaseAtCreature(Creature* creature);
|
||||
bool LoadPetFromDB( Player* owner,uint32 petentry = 0,uint32 petnumber = 0, bool current = false );
|
||||
|
||||
@@ -89,10 +89,6 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
|
||||
switch(flag)
|
||||
{
|
||||
case ACT_COMMAND: //0x0700
|
||||
// Possessed or shared vision pets are only able to attack
|
||||
if ((pet->isPossessed() || pet->HasAuraType(SPELL_AURA_BIND_SIGHT)) && spellid != COMMAND_ATTACK)
|
||||
return;
|
||||
|
||||
switch(spellid)
|
||||
{
|
||||
case COMMAND_STAY: //flat=1792 //STAY
|
||||
@@ -162,10 +158,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid
|
||||
}
|
||||
case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
|
||||
if(pet->GetCharmerGUID() == GetPlayer()->GetGUID())
|
||||
{
|
||||
if(GetPlayer()->m_seer != pet)
|
||||
_player->StopCastingCharm();
|
||||
}
|
||||
_player->StopCastingCharm();
|
||||
else if(pet->GetOwnerGUID() == GetPlayer()->GetGUID())
|
||||
{
|
||||
assert(pet->GetTypeId() == TYPEID_UNIT);
|
||||
|
||||
+215
-111
@@ -230,7 +230,7 @@ bool PlayerTaxi::LoadTaxiDestinationsFromString( const std::string& values, uint
|
||||
}
|
||||
|
||||
// can't load taxi path without mount set (quest taxi path?)
|
||||
if(!objmgr.GetTaxiMount(GetTaxiSource(),team))
|
||||
if(!objmgr.GetTaxiMount(GetTaxiSource(),team,true))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -897,6 +897,8 @@ void Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
|
||||
|
||||
damage-=absorb+resist;
|
||||
|
||||
DealDamageMods(this,damage,&absorb);
|
||||
|
||||
WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21));
|
||||
data << uint64(GetGUID());
|
||||
data << uint8(type!=DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL);
|
||||
@@ -1490,7 +1492,12 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
|
||||
char_flags |= CHARACTER_FLAG_GHOST;
|
||||
if(HasAtLoginFlag(AT_LOGIN_RENAME))
|
||||
char_flags |= CHARACTER_FLAG_RENAME;
|
||||
if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) && (fields[14].GetCppString() != ""))
|
||||
if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED))
|
||||
{
|
||||
if(!fields[14].GetCppString().empty())
|
||||
char_flags |= CHARACTER_FLAG_DECLINED;
|
||||
}
|
||||
else
|
||||
char_flags |= CHARACTER_FLAG_DECLINED;
|
||||
|
||||
*p_data << uint32(char_flags); // character flags
|
||||
@@ -1505,7 +1512,7 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
|
||||
uint32 petFamily = 0;
|
||||
|
||||
// show pet at selection character in character list only for non-ghost character
|
||||
if(result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER))
|
||||
if (result && isAlive() && (pClass == CLASS_WARLOCK || pClass == CLASS_HUNTER || pClass == CLASS_DEATH_KNIGHT))
|
||||
{
|
||||
uint32 entry = fields[10].GetUInt32();
|
||||
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry);
|
||||
@@ -1666,7 +1673,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
if (!(options & TELE_TO_NOT_UNSUMMON_PET))
|
||||
{
|
||||
//same map, only remove pet if out of range for new position
|
||||
if(pet && pet->GetDistance(x,y,z) >= OWNER_MAX_DISTANCE)
|
||||
if(pet && !pet->IsWithinDist3d(x,y,z, OWNER_MAX_DISTANCE))
|
||||
UnsummonPetTemporaryIfAny();
|
||||
}
|
||||
|
||||
@@ -1798,7 +1805,7 @@ void Player::AddToWorld()
|
||||
///- The player should only be added when logging in
|
||||
Unit::AddToWorld();
|
||||
|
||||
for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++)
|
||||
for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
|
||||
{
|
||||
if(m_items[i])
|
||||
m_items[i]->AddToWorld();
|
||||
@@ -1815,7 +1822,7 @@ void Player::RemoveFromWorld()
|
||||
StopCastingBindSight();
|
||||
}
|
||||
|
||||
for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; i++)
|
||||
for(int i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
|
||||
{
|
||||
if(m_items[i])
|
||||
m_items[i]->RemoveFromWorld();
|
||||
@@ -3287,6 +3294,20 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool update_action_bar_
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Player::RemoveSpellCooldown( uint32 spell_id, bool update /* = false */ )
|
||||
{
|
||||
m_spellCooldowns.erase(spell_id);
|
||||
|
||||
if(update)
|
||||
{
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
|
||||
data << uint32(spell_id);
|
||||
data << uint64(GetGUID());
|
||||
SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RemoveArenaSpellCooldowns()
|
||||
{
|
||||
// remove cooldowns on spells that has < 15 min CD
|
||||
@@ -5729,23 +5750,26 @@ ReputationRank Player::GetReputationRank(uint32 faction) const
|
||||
}
|
||||
|
||||
//Calculate total reputation percent player gain with quest/creature level
|
||||
int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest)
|
||||
int32 Player::CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest)
|
||||
{
|
||||
float percent = 100.0f;
|
||||
|
||||
float rate = for_quest ? sWorld.getRate(RATE_REPUTATION_LOWLEVEL_QUEST) : sWorld.getRate(RATE_REPUTATION_LOWLEVEL_KILL);
|
||||
|
||||
if(rate != 1.0f && creatureOrQuestLevel <= MaNGOS::XP::GetGrayLevel(getLevel()))
|
||||
if (rate != 1.0f && creatureOrQuestLevel <= MaNGOS::XP::GetGrayLevel(getLevel()))
|
||||
percent *= rate;
|
||||
|
||||
int32 repMod = GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN);
|
||||
float repMod = GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN);
|
||||
|
||||
if (!for_quest)
|
||||
repMod += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_FACTION_REPUTATION_GAIN, faction);
|
||||
|
||||
percent += rep > 0 ? repMod : -repMod;
|
||||
|
||||
if(percent <= 0.0f)
|
||||
if (percent <= 0.0f)
|
||||
return 0;
|
||||
|
||||
return int32(sWorld.getRate(RATE_REPUTATION_GAIN)*rep*percent/100);
|
||||
return int32(sWorld.getRate(RATE_REPUTATION_GAIN)*rep*percent/100.0f);
|
||||
}
|
||||
|
||||
//Calculates how many reputation points player gains in victim's enemy factions
|
||||
@@ -5764,7 +5788,7 @@ void Player::RewardReputation(Unit *pVictim, float rate)
|
||||
|
||||
if(Rep->repfaction1 && (!Rep->team_dependent || GetTeam()==ALLIANCE))
|
||||
{
|
||||
int32 donerep1 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue1,false);
|
||||
int32 donerep1 = CalculateReputationGain(pVictim->getLevel(), Rep->repvalue1, Rep->repfaction1, false);
|
||||
donerep1 = int32(donerep1*rate);
|
||||
FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(Rep->repfaction1);
|
||||
uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1);
|
||||
@@ -5782,7 +5806,7 @@ void Player::RewardReputation(Unit *pVictim, float rate)
|
||||
|
||||
if(Rep->repfaction2 && (!Rep->team_dependent || GetTeam()==HORDE))
|
||||
{
|
||||
int32 donerep2 = CalculateReputationGain(pVictim->getLevel(),Rep->repvalue2,false);
|
||||
int32 donerep2 = CalculateReputationGain(pVictim->getLevel(), Rep->repvalue2, Rep->repfaction2, false);
|
||||
donerep2 = int32(donerep2*rate);
|
||||
FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(Rep->repfaction2);
|
||||
uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2);
|
||||
@@ -5807,7 +5831,7 @@ void Player::RewardReputation(Quest const *pQuest)
|
||||
{
|
||||
if(pQuest->RewRepFaction[i] && pQuest->RewRepValue[i] )
|
||||
{
|
||||
int32 rep = CalculateReputationGain(GetQuestLevel(pQuest),pQuest->RewRepValue[i],true);
|
||||
int32 rep = CalculateReputationGain(GetQuestLevel(pQuest), pQuest->RewRepValue[i], pQuest->RewRepFaction[i], true);
|
||||
FactionEntry const* factionEntry = sFactionStore.LookupEntry(pQuest->RewRepFaction[i]);
|
||||
if(factionEntry)
|
||||
GetReputationMgr().ModifyReputation(factionEntry, rep);
|
||||
@@ -6425,8 +6449,8 @@ void Player::_ApplyItemMods(Item *item, uint8 slot,bool apply)
|
||||
if(slot >= INVENTORY_SLOT_BAG_END || !item)
|
||||
return;
|
||||
|
||||
// not apply/remove mods for broken item
|
||||
if(item->IsBroken())
|
||||
// not apply mods for broken item
|
||||
if(item->IsBroken() && apply)
|
||||
return;
|
||||
|
||||
ItemPrototype const *proto = item->GetProto();
|
||||
@@ -6464,30 +6488,25 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl
|
||||
if(slot >= INVENTORY_SLOT_BAG_END || !proto)
|
||||
return;
|
||||
|
||||
ScalingStatDistributionEntry const *ssd = proto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution) : 0;
|
||||
ScalingStatValuesEntry const *ssv = proto->ScalingStatValue ? sScalingStatValuesStore.LookupEntry(getLevel()) : 0;
|
||||
|
||||
for (int i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
|
||||
{
|
||||
uint32 statType = 0;
|
||||
int32 val = 0;
|
||||
|
||||
if(proto->ScalingStatDistribution)
|
||||
int32 val = 0;
|
||||
// If set ScalingStatDistribution need get stats and values from it
|
||||
if (ssd && ssv)
|
||||
{
|
||||
if(ScalingStatDistributionEntry const *ssd = sScalingStatDistributionStore.LookupEntry(proto->ScalingStatDistribution))
|
||||
{
|
||||
statType = ssd->StatMod[i];
|
||||
|
||||
if(uint32 modifier = ssd->Modifier[i])
|
||||
{
|
||||
uint32 level = ((getLevel() > ssd->MaxLevel) ? ssd->MaxLevel : getLevel());
|
||||
if(ScalingStatValuesEntry const *ssv = sScalingStatValuesStore.LookupEntry(level))
|
||||
{
|
||||
uint32 multiplier = ssv->Multiplier[proto->GetScalingStatValuesColumn()];
|
||||
val = (multiplier * modifier) / 10000;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ssd->StatMod[i] < 0)
|
||||
continue;
|
||||
statType = ssd->StatMod[i];
|
||||
val = (ssv->getssdMultiplier(proto->ScalingStatValue) * ssd->Modifier[i]) / 10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i >= proto->StatsCount)
|
||||
continue;
|
||||
statType = proto->ItemStat[i].ItemStatType;
|
||||
val = proto->ItemStat[i].ItemStatValue;
|
||||
}
|
||||
@@ -6642,8 +6661,18 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl
|
||||
}
|
||||
}
|
||||
|
||||
if (proto->Armor)
|
||||
HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(proto->Armor), apply);
|
||||
// If set ScalingStatValue armor get it or use item armor
|
||||
uint32 armor = proto->Armor;
|
||||
if (ssv)
|
||||
{
|
||||
if (uint32 ssvarmor = ssv->getArmorMod(proto->ScalingStatValue))
|
||||
armor = ssvarmor;
|
||||
}
|
||||
// Add armor bonus from ArmorDamageModifier if > 0
|
||||
if (proto->ArmorDamageModifier > 0)
|
||||
armor+=proto->ArmorDamageModifier;
|
||||
if (armor)
|
||||
HandleStatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(armor), apply);
|
||||
|
||||
if (proto->Block)
|
||||
HandleBaseModValue(SHIELD_BLOCK_VALUE, FLAT_MOD, float(proto->Block), apply);
|
||||
@@ -6680,23 +6709,42 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl
|
||||
attType = OFF_ATTACK;
|
||||
}
|
||||
|
||||
if (proto->Damage[0].DamageMin > 0 )
|
||||
float minDamage = proto->Damage[0].DamageMin;
|
||||
float maxDamage = proto->Damage[0].DamageMax;
|
||||
int32 extraDPS = 0;
|
||||
// If set dpsMod in ScalingStatValue use it for min (70% from average), max (130% from average) damage
|
||||
if (ssv)
|
||||
{
|
||||
damage = apply ? proto->Damage[0].DamageMin : BASE_MINDAMAGE;
|
||||
if (extraDPS = ssv->getDPSMod(proto->ScalingStatValue))
|
||||
{
|
||||
float average = extraDPS * proto->Delay / 1000.0f;
|
||||
minDamage = 0.7f * average;
|
||||
maxDamage = 1.3f * average;
|
||||
}
|
||||
}
|
||||
if (minDamage > 0 )
|
||||
{
|
||||
damage = apply ? minDamage : BASE_MINDAMAGE;
|
||||
SetBaseWeaponDamage(attType, MINDAMAGE, damage);
|
||||
//sLog.outError("applying mindam: assigning %f to weapon mindamage, now is: %f", damage, GetWeaponDamageRange(attType, MINDAMAGE));
|
||||
}
|
||||
|
||||
if (proto->Damage[0].DamageMax > 0 )
|
||||
if (maxDamage > 0 )
|
||||
{
|
||||
damage = apply ? proto->Damage[0].DamageMax : BASE_MAXDAMAGE;
|
||||
damage = apply ? maxDamage : BASE_MAXDAMAGE;
|
||||
SetBaseWeaponDamage(attType, MAXDAMAGE, damage);
|
||||
}
|
||||
|
||||
// Druids get feral AP bonus from weapon dps
|
||||
// Apply feral bonus from ScalingStatValue if set
|
||||
if (ssv)
|
||||
{
|
||||
if (int32 feral_bonus = ssv->getFeralBonus(proto->ScalingStatValue))
|
||||
ApplyFeralAPBonus(feral_bonus, apply);
|
||||
}
|
||||
// Druids get feral AP bonus from weapon dps (lso use DPS from ScalingStatValue)
|
||||
if(getClass() == CLASS_DRUID)
|
||||
{
|
||||
int32 feral_bonus = proto->getFeralBonus();
|
||||
int32 feral_bonus = proto->getFeralBonus(extraDPS);
|
||||
if (feral_bonus > 0)
|
||||
ApplyFeralAPBonus(feral_bonus, apply);
|
||||
}
|
||||
@@ -9825,18 +9873,22 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
|
||||
return EQUIP_ERR_CANT_DO_RIGHT_NOW;
|
||||
}
|
||||
|
||||
uint8 eslot = FindEquipSlot( pProto, slot, swap );
|
||||
if( eslot == NULL_SLOT )
|
||||
ScalingStatDistributionEntry const *ssd = pProto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(pProto->ScalingStatDistribution) : 0;
|
||||
if (ssd && ssd->MaxLevel < getLevel())
|
||||
return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
|
||||
|
||||
uint8 msg = CanUseItem( pItem , not_loading );
|
||||
if( msg != EQUIP_ERR_OK )
|
||||
uint8 eslot = FindEquipSlot( pProto, slot, swap );
|
||||
if (eslot == NULL_SLOT)
|
||||
return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
|
||||
|
||||
uint8 msg = CanUseItem(pItem , not_loading);
|
||||
if (msg != EQUIP_ERR_OK)
|
||||
return msg;
|
||||
if( !swap && GetItemByPos( INVENTORY_SLOT_BAG_0, eslot ) )
|
||||
if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot))
|
||||
return EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE;
|
||||
|
||||
// if swap ignore item (equipped also)
|
||||
if(uint8 res2 = CanEquipUniqueItem(pItem, swap ? eslot : NULL_SLOT))
|
||||
if (uint8 res2 = CanEquipUniqueItem(pItem, swap ? eslot : NULL_SLOT))
|
||||
return res2;
|
||||
|
||||
// check unique-equipped special item classes
|
||||
@@ -9844,16 +9896,16 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
|
||||
{
|
||||
for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
|
||||
{
|
||||
if( Item* pBag = GetItemByPos( INVENTORY_SLOT_BAG_0, i ) )
|
||||
if (Item* pBag = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
|
||||
{
|
||||
if( ItemPrototype const* pBagProto = pBag->GetProto() )
|
||||
if (pBag != pItem)
|
||||
{
|
||||
if( pBagProto->Class==pProto->Class && (!swap || pBag->GetSlot() != eslot ) )
|
||||
if (ItemPrototype const* pBagProto = pBag->GetProto())
|
||||
{
|
||||
if(pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH)
|
||||
return EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH;
|
||||
else
|
||||
return EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER;
|
||||
if (pBagProto->Class==pProto->Class && (!swap || pBag->GetSlot() != eslot))
|
||||
return (pBagProto->SubClass == ITEM_SUBCLASS_AMMO_POUCH)
|
||||
? EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH
|
||||
: EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9862,25 +9914,25 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
|
||||
|
||||
uint32 type = pProto->InventoryType;
|
||||
|
||||
if(eslot == EQUIPMENT_SLOT_OFFHAND)
|
||||
if (eslot == EQUIPMENT_SLOT_OFFHAND)
|
||||
{
|
||||
if (type == INVTYPE_WEAPON || type == INVTYPE_WEAPONOFFHAND)
|
||||
{
|
||||
if(!CanDualWield())
|
||||
if (!CanDualWield())
|
||||
return EQUIP_ERR_CANT_DUAL_WIELD;
|
||||
}
|
||||
else if (type == INVTYPE_2HWEAPON)
|
||||
{
|
||||
if(!CanDualWield() || !CanTitanGrip())
|
||||
if (!CanDualWield() || !CanTitanGrip())
|
||||
return EQUIP_ERR_CANT_DUAL_WIELD;
|
||||
}
|
||||
|
||||
if(IsTwoHandUsed())
|
||||
if (IsTwoHandUsed())
|
||||
return EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED;
|
||||
}
|
||||
|
||||
// equip two-hand weapon case (with possible unequip 2 items)
|
||||
if( type == INVTYPE_2HWEAPON )
|
||||
if (type == INVTYPE_2HWEAPON)
|
||||
{
|
||||
if (eslot == EQUIPMENT_SLOT_OFFHAND)
|
||||
{
|
||||
@@ -9895,9 +9947,9 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
|
||||
// offhand item must can be stored in inventory for offhand item and it also must be unequipped
|
||||
Item *offItem = GetItemByPos( INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND );
|
||||
ItemPosCountVec off_dest;
|
||||
if( offItem && (!not_loading ||
|
||||
if (offItem && (!not_loading ||
|
||||
CanUnequipItem(uint16(INVENTORY_SLOT_BAG_0) << 8 | EQUIPMENT_SLOT_OFFHAND,false) != EQUIP_ERR_OK ||
|
||||
CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ) != EQUIP_ERR_OK ) )
|
||||
CanStoreItem( NULL_BAG, NULL_SLOT, off_dest, offItem, false ) != EQUIP_ERR_OK ))
|
||||
return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_INVENTORY_FULL;
|
||||
}
|
||||
}
|
||||
@@ -9905,10 +9957,8 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
|
||||
return EQUIP_ERR_OK;
|
||||
}
|
||||
}
|
||||
if( !swap )
|
||||
return EQUIP_ERR_ITEM_NOT_FOUND;
|
||||
else
|
||||
return EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
|
||||
|
||||
return !swap ? EQUIP_ERR_ITEM_NOT_FOUND : EQUIP_ERR_ITEMS_CANT_BE_SWAPPED;
|
||||
}
|
||||
|
||||
uint8 Player::CanUnequipItem( uint16 pos, bool swap ) const
|
||||
@@ -10127,38 +10177,49 @@ uint8 Player::CanBankItem( uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *p
|
||||
|
||||
uint8 Player::CanUseItem( Item *pItem, bool not_loading ) const
|
||||
{
|
||||
if( pItem )
|
||||
if (pItem)
|
||||
{
|
||||
sLog.outDebug( "STORAGE: CanUseItem item = %u", pItem->GetEntry());
|
||||
if( !isAlive() && not_loading )
|
||||
|
||||
if (!isAlive() && not_loading)
|
||||
return EQUIP_ERR_YOU_ARE_DEAD;
|
||||
//if( isStunned() )
|
||||
|
||||
//if (isStunned())
|
||||
// return EQUIP_ERR_YOU_ARE_STUNNED;
|
||||
|
||||
ItemPrototype const *pProto = pItem->GetProto();
|
||||
if( pProto )
|
||||
if (pProto)
|
||||
{
|
||||
if( pItem->IsBindedNotWith(GetGUID()) )
|
||||
if (pItem->IsBindedNotWith(GetGUID()))
|
||||
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
|
||||
if( (pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0 )
|
||||
|
||||
if ((pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0)
|
||||
return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM;
|
||||
if( pItem->GetSkill() != 0 )
|
||||
|
||||
if (pItem->GetSkill() != 0)
|
||||
{
|
||||
if( GetSkillValue( pItem->GetSkill() ) == 0 )
|
||||
if (GetSkillValue( pItem->GetSkill() ) == 0)
|
||||
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
|
||||
}
|
||||
if( pProto->RequiredSkill != 0 )
|
||||
|
||||
if (pProto->RequiredSkill != 0)
|
||||
{
|
||||
if( GetSkillValue( pProto->RequiredSkill ) == 0 )
|
||||
if (GetSkillValue( pProto->RequiredSkill ) == 0)
|
||||
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
|
||||
else if( GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank )
|
||||
|
||||
if (GetSkillValue( pProto->RequiredSkill ) < pProto->RequiredSkillRank)
|
||||
return EQUIP_ERR_ERR_CANT_EQUIP_SKILL;
|
||||
}
|
||||
if( pProto->RequiredSpell != 0 && !HasSpell( pProto->RequiredSpell ) )
|
||||
|
||||
if (pProto->RequiredSpell != 0 && !HasSpell(pProto->RequiredSpell))
|
||||
return EQUIP_ERR_NO_REQUIRED_PROFICIENCY;
|
||||
if( pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank )
|
||||
|
||||
if (pProto->RequiredReputationFaction && uint32(GetReputationRank(pProto->RequiredReputationFaction)) < pProto->RequiredReputationRank)
|
||||
return EQUIP_ERR_CANT_EQUIP_REPUTATION;
|
||||
if( getLevel() < pProto->RequiredLevel )
|
||||
|
||||
if (getLevel() < pProto->RequiredLevel)
|
||||
return EQUIP_ERR_CANT_EQUIP_LEVEL_I;
|
||||
|
||||
return EQUIP_ERR_OK;
|
||||
}
|
||||
}
|
||||
@@ -16712,7 +16773,7 @@ void Player::PetSpellInitialize()
|
||||
uint8 addlist = 0;
|
||||
data << uint8(addlist); // placeholder
|
||||
|
||||
if(pet->isControlled() && ((pet->getPetType() == HUNTER_PET) || ((pet->GetCreatureInfo()->type == CREATURE_TYPE_DEMON) && (getClass() == CLASS_WARLOCK))))
|
||||
if (pet->IsPermanentPetFor(this))
|
||||
{
|
||||
// spells loop
|
||||
for (PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
|
||||
@@ -17114,34 +17175,13 @@ void Player::HandleStealthedUnitsDetection()
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_id, Creature* npc)
|
||||
bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= NULL*/, uint32 spellid /*= 0*/)
|
||||
{
|
||||
if(nodes.size() < 2)
|
||||
return false;
|
||||
|
||||
// not let cheating with start flight mounted
|
||||
if(IsMounted())
|
||||
{
|
||||
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
||||
data << uint32(ERR_TAXIPLAYERALREADYMOUNTED);
|
||||
GetSession()->SendPacket(&data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW )
|
||||
{
|
||||
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
||||
data << uint32(ERR_TAXIPLAYERSHAPESHIFTED);
|
||||
GetSession()->SendPacket(&data);
|
||||
return false;
|
||||
}
|
||||
|
||||
// not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi
|
||||
if(GetSession()->isLogingOut() ||
|
||||
(!m_currentSpells[CURRENT_GENERIC_SPELL] ||
|
||||
m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Effect[0] != SPELL_EFFECT_SEND_TAXI)&&
|
||||
IsNonMeleeSpellCasted(false) ||
|
||||
isInCombat())
|
||||
if(GetSession()->isLogingOut() || isInCombat())
|
||||
{
|
||||
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
||||
data << uint32(ERR_TAXIPLAYERBUSY);
|
||||
@@ -17152,6 +17192,52 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
|
||||
if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE))
|
||||
return false;
|
||||
|
||||
// taximaster case
|
||||
if(npc)
|
||||
{
|
||||
// not let cheating with start flight mounted
|
||||
if(IsMounted())
|
||||
{
|
||||
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
||||
data << uint32(ERR_TAXIPLAYERALREADYMOUNTED);
|
||||
GetSession()->SendPacket(&data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW )
|
||||
{
|
||||
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
||||
data << uint32(ERR_TAXIPLAYERSHAPESHIFTED);
|
||||
GetSession()->SendPacket(&data);
|
||||
return false;
|
||||
}
|
||||
|
||||
// not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi
|
||||
if(IsNonMeleeSpellCasted(false))
|
||||
{
|
||||
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
||||
data << uint32(ERR_TAXIPLAYERBUSY);
|
||||
GetSession()->SendPacket(&data);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// cast case or scripted call case
|
||||
else
|
||||
{
|
||||
RemoveAurasByType(SPELL_AURA_MOUNTED);
|
||||
|
||||
if( m_ShapeShiftFormSpellId && m_form != FORM_BATTLESTANCE && m_form != FORM_BERSERKERSTANCE && m_form != FORM_DEFENSIVESTANCE && m_form != FORM_SHADOW )
|
||||
RemoveAurasDueToSpell(m_ShapeShiftFormSpellId);
|
||||
|
||||
if(m_currentSpells[CURRENT_GENERIC_SPELL] && m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id != spellid)
|
||||
InterruptSpell(CURRENT_GENERIC_SPELL,false);
|
||||
|
||||
InterruptSpell(CURRENT_AUTOREPEAT_SPELL,false);
|
||||
|
||||
if(m_currentSpells[CURRENT_CHANNELED_SPELL] && m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id != spellid)
|
||||
InterruptSpell(CURRENT_CHANNELED_SPELL,true);
|
||||
}
|
||||
|
||||
uint32 sourcenode = nodes[0];
|
||||
|
||||
// starting node too far away (cheat?)
|
||||
@@ -17179,8 +17265,8 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// node must have pos if not spell case (npc!=0)
|
||||
else if(npc)
|
||||
// node must have pos if taxi master case (npc != NULL)
|
||||
else if (npc)
|
||||
{
|
||||
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
||||
data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR);
|
||||
@@ -17232,10 +17318,11 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
|
||||
prevnode = lastnode;
|
||||
}
|
||||
|
||||
if(!mount_id) // if not provide then attempt use default.
|
||||
mount_id = objmgr.GetTaxiMount(sourcenode, GetTeam());
|
||||
// get mount model (in case non taximaster (npc==NULL) allow more wide lookup)
|
||||
uint16 mount_id = objmgr.GetTaxiMount(sourcenode, GetTeam(), npc == NULL);
|
||||
|
||||
if (mount_id == 0 || sourcepath == 0)
|
||||
// in spell case allow 0 model
|
||||
if (mount_id == 0 && spellid == 0 || sourcepath == 0)
|
||||
{
|
||||
WorldPacket data(SMSG_ACTIVATETAXIREPLY, 4);
|
||||
data << uint32(ERR_TAXIUNSPECIFIEDSERVERERROR);
|
||||
@@ -17277,6 +17364,21 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_i
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Player::ActivateTaxiPathTo( uint32 taxi_path_id, uint32 spellid /*= 0*/ )
|
||||
{
|
||||
TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(taxi_path_id);
|
||||
if(!entry)
|
||||
return false;
|
||||
|
||||
std::vector<uint32> nodes;
|
||||
|
||||
nodes.resize(2);
|
||||
nodes[0] = entry->from;
|
||||
nodes[1] = entry->to;
|
||||
|
||||
return ActivateTaxiPathTo(nodes,NULL,spellid);
|
||||
}
|
||||
|
||||
void Player::ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs )
|
||||
{
|
||||
// last check 2.0.10
|
||||
@@ -20509,12 +20611,14 @@ void Player::ResummonPetTemporaryUnSummonedIfAny()
|
||||
|
||||
bool Player::canSeeSpellClickOn(Creature const *c) const
|
||||
{
|
||||
SpellClickInfoMap const& map = objmgr.mSpellClickInfoMap;
|
||||
if(map.empty())
|
||||
SpellClickInfoMap::const_iterator lower = objmgr.mSpellClickInfoMap.lower_bound(c->GetEntry());
|
||||
SpellClickInfoMap::const_iterator upper = objmgr.mSpellClickInfoMap.upper_bound(c->GetEntry());
|
||||
if(lower == upper)
|
||||
return true;
|
||||
|
||||
for(SpellClickInfoMap::const_iterator itr = map.lower_bound(c->GetEntry()); itr != map.upper_bound(c->GetEntry()); ++itr)
|
||||
for(SpellClickInfoMap::const_iterator itr = lower; itr != upper; ++itr)
|
||||
{
|
||||
sLog.outError("%u %u %u %u", (uint32)itr->second.castFlags, itr->second.questId, itr->second.spellId);
|
||||
if(itr->second.questId == 0 || GetQuestStatus(itr->second.questId) == QUEST_STATUS_INCOMPLETE)
|
||||
return true;
|
||||
}
|
||||
|
||||
+8
-4
@@ -867,7 +867,8 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
|
||||
PlayerTaxi m_taxi;
|
||||
void InitTaxiNodesForLevel() { m_taxi.InitTaxiNodesForLevel(getRace(), getClass(), getLevel()); }
|
||||
bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, uint32 mount_id = 0 , Creature* npc = NULL);
|
||||
bool ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc = NULL, uint32 spellid = 0);
|
||||
bool ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid = 0);
|
||||
// mount_id can be used in scripting calls
|
||||
bool isAcceptWhispers() const { return m_ExtraFlags & PLAYER_EXTRA_ACCEPT_WHISPERS; }
|
||||
void SetAcceptWhispers(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; }
|
||||
@@ -1383,7 +1384,7 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time);
|
||||
void SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId = 0, Spell* spell = NULL);
|
||||
void ProhibitSpellScholl(SpellSchoolMask idSchoolMask, uint32 unTimeMs );
|
||||
void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); }
|
||||
void RemoveSpellCooldown(uint32 spell_id, bool update = false);
|
||||
void RemoveArenaSpellCooldowns();
|
||||
void RemoveAllSpellCooldown();
|
||||
void _LoadSpellCooldowns(QueryResult *result);
|
||||
@@ -1668,6 +1669,8 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
|
||||
//End of PvP System
|
||||
|
||||
inline SpellCooldowns GetSpellCooldowns() const { return m_spellCooldowns; }
|
||||
|
||||
void SetDrunkValue(uint16 newDrunkValue, uint32 itemid=0);
|
||||
uint16 GetDrunkValue() const { return m_drunk; }
|
||||
static DrunkenState GetDrunkenstateByValue(uint16 value);
|
||||
@@ -2151,7 +2154,6 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
|
||||
PlayerMails m_mail;
|
||||
PlayerSpellMap m_spells;
|
||||
SpellCooldowns m_spellCooldowns;
|
||||
uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use
|
||||
|
||||
ActionButtonList m_actionButtons;
|
||||
@@ -2256,7 +2258,7 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update );
|
||||
|
||||
void UpdateKnownCurrencies(uint32 itemId, bool apply);
|
||||
int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, bool for_quest);
|
||||
int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest);
|
||||
void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData );
|
||||
|
||||
GridReference<Player> m_gridRef;
|
||||
@@ -2284,6 +2286,8 @@ class TRINITY_DLL_SPEC Player : public Unit
|
||||
|
||||
AchievementMgr m_achievementMgr;
|
||||
ReputationMgr m_reputationMgr;
|
||||
|
||||
SpellCooldowns m_spellCooldowns;
|
||||
};
|
||||
|
||||
void AddItemsSetItem(Player*player,Item *item);
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* Thanks to the original authors: MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* Thanks to the original authors: MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef MANGOS_POSSESSEDAI_H
|
||||
#define MANGOS_POSSESSEDAI_H
|
||||
|
||||
|
||||
#endif
|
||||
@@ -58,6 +58,9 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
|
||||
bool is_water_ok = creature.canSwim();
|
||||
bool is_air_ok = creature.canFly();
|
||||
|
||||
for(uint32 i = 0;; ++i)
|
||||
{
|
||||
|
||||
const float angle = rand_norm()*(M_PI*2);
|
||||
const float range = rand_norm()*wander_distance;
|
||||
const float distanceX = range * cos(angle);
|
||||
@@ -72,6 +75,12 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
|
||||
|
||||
dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y);
|
||||
|
||||
if(i == 5)
|
||||
{
|
||||
nz = Z;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_air_ok) // 3D system above ground and above water (flying mode)
|
||||
{
|
||||
const float distanceZ = rand_norm() * sqrtf(dist)/2; // Limit height change
|
||||
@@ -79,12 +88,13 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
|
||||
float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height.
|
||||
float wz = map->GetWaterLevel(nx, ny);
|
||||
if (tz >= nz || wz >= nz)
|
||||
return; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
|
||||
continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick
|
||||
}
|
||||
//else if (is_water_ok) // 3D system under water and above ground (swimming mode)
|
||||
else // 2D only
|
||||
{
|
||||
dist = dist>=100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE)
|
||||
|
||||
// The fastest way to get an accurate result 90% of the time.
|
||||
// Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long.
|
||||
nz = map->GetHeight(nx,ny,Z+dist-2.0f,false); // Map check
|
||||
@@ -95,11 +105,14 @@ RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature)
|
||||
{
|
||||
nz = map->GetHeight(nx,ny,Z+dist-2.0f,true); // Vmap Higher
|
||||
if (fabs(nz-Z)>dist)
|
||||
return; // let's forget this bad coords where a z cannot be find and retry at next tick
|
||||
continue; // let's forget this bad coords where a z cannot be find and retry at next tick
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Traveller<Creature> traveller(creature);
|
||||
creature.SetOrientation(creature.GetAngle(nx,ny));
|
||||
i_destinationHolder.SetDestination(traveller, nx, ny, nz);
|
||||
@@ -130,7 +143,8 @@ RandomMovementGenerator<Creature>::Initialize(Creature &creature)
|
||||
if(!creature.isAlive())
|
||||
return;
|
||||
|
||||
wander_distance = creature.GetRespawnRadius();
|
||||
if(!wander_distance)
|
||||
wander_distance = creature.GetRespawnRadius();
|
||||
|
||||
if (creature.canFly())
|
||||
creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
|
||||
@@ -181,7 +195,7 @@ RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff
|
||||
creature.SetUnitMovementFlags(irand(0,RUNNING_CHANCE_RANDOMMV) > 0 ? MOVEMENTFLAG_WALK_MODE : MOVEMENTFLAG_NONE);
|
||||
_setRandomLocation(creature);
|
||||
}
|
||||
else if(creature.isPet() && creature.GetOwner() && creature.GetDistance(creature.GetOwner()) > PET_FOLLOW_DIST+2.5f)
|
||||
else if(creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(),PET_FOLLOW_DIST+2.5f))
|
||||
{
|
||||
creature.SetUnitMovementFlags(MOVEMENTFLAG_NONE);
|
||||
_setRandomLocation(creature);
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
#include "Platform/Define.h"
|
||||
#include <cassert>
|
||||
|
||||
#define MaNGOS Trinity
|
||||
#define GetMangosString GetTrinityString
|
||||
|
||||
enum Gender
|
||||
{
|
||||
GENDER_MALE = 0,
|
||||
@@ -1109,9 +1106,10 @@ enum SpellHitType
|
||||
{
|
||||
SPELL_HIT_TYPE_UNK1 = 0x00001,
|
||||
SPELL_HIT_TYPE_CRIT = 0x00002,
|
||||
SPELL_HIT_TYPE_UNK2 = 0x00004,
|
||||
SPELL_HIT_TYPE_UNK3 = 0x00008,
|
||||
SPELL_HIT_TYPE_UNK4 = 0x00020
|
||||
SPELL_HIT_TYPE_UNK3 = 0x00004,
|
||||
SPELL_HIT_TYPE_UNK4 = 0x00008,
|
||||
SPELL_HIT_TYPE_UNK5 = 0x00010, // replace caster?
|
||||
SPELL_HIT_TYPE_UNK6 = 0x00020
|
||||
};
|
||||
|
||||
enum SpellDmgClass
|
||||
@@ -1819,6 +1817,7 @@ enum CreatureType
|
||||
};
|
||||
|
||||
uint32 const CREATURE_TYPEMASK_HUMANOID_OR_UNDEAD = (1 << (CREATURE_TYPE_HUMANOID-1)) | (1 << (CREATURE_TYPE_UNDEAD-1));
|
||||
uint32 const CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL = (1 << (CREATURE_TYPE_MECHANICAL-1)) | (1 << (CREATURE_TYPE_ELEMENTAL-1));
|
||||
|
||||
// CreatureFamily.dbc
|
||||
enum CreatureFamily
|
||||
|
||||
+83
-49
@@ -476,6 +476,35 @@ Spell::~Spell()
|
||||
delete m_spellValue;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
WorldObject* Spell::FindCorpseUsing()
|
||||
{
|
||||
// non-standard target selection
|
||||
float max_range = GetSpellMaxRange(m_spellInfo, false);
|
||||
|
||||
CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
|
||||
Cell cell(p);
|
||||
cell.data.Part.reserved = ALL_DISTRICT;
|
||||
cell.SetNoCreate();
|
||||
|
||||
WorldObject* result = NULL;
|
||||
|
||||
T u_check(m_caster, max_range);
|
||||
MaNGOS::WorldObjectSearcher<T> searcher(m_caster, result, u_check);
|
||||
|
||||
TypeContainerVisitor<MaNGOS::WorldObjectSearcher<T>, GridTypeMapContainer > grid_searcher(searcher);
|
||||
CellLock<GridReadGuard> cell_lock(cell, p);
|
||||
cell_lock->Visit(cell_lock, grid_searcher, *m_caster->GetMap());
|
||||
|
||||
if (!result)
|
||||
{
|
||||
TypeContainerVisitor<MaNGOS::WorldObjectSearcher<T>, WorldTypeMapContainer > world_searcher(searcher);
|
||||
cell_lock->Visit(cell_lock, world_searcher, *m_caster->GetMap());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Spell::FillTargetMap()
|
||||
{
|
||||
for(uint32 i = 0; i < 3; ++i)
|
||||
@@ -535,17 +564,7 @@ void Spell::FillTargetMap()
|
||||
{
|
||||
case 20577: // Cannibalize
|
||||
{
|
||||
// non-standard target selection
|
||||
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
|
||||
float max_range = GetSpellMaxRangeForHostile(srange);
|
||||
WorldObject* result = NULL;
|
||||
|
||||
Trinity::CannibalizeObjectCheck u_check(m_caster, max_range);
|
||||
Trinity::WorldObjectSearcher<Trinity::CannibalizeObjectCheck > searcher(m_caster, result, u_check);
|
||||
m_caster->VisitNearbyGridObject(max_range, searcher);
|
||||
if(!result)
|
||||
m_caster->VisitNearbyWorldObject(max_range, searcher);
|
||||
|
||||
WorldObject* result = FindCorpseUsing<MaNGOS::CannibalizeObjectCheck> ();
|
||||
|
||||
if(result)
|
||||
{
|
||||
@@ -566,15 +585,7 @@ void Spell::FillTargetMap()
|
||||
{
|
||||
// clear cooldown at fail
|
||||
if(m_caster->GetTypeId()==TYPEID_PLAYER)
|
||||
{
|
||||
((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
|
||||
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
|
||||
data << uint32(m_spellInfo->Id);
|
||||
data << uint64(m_caster->GetGUID());
|
||||
((Player*)m_caster)->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true);
|
||||
SendCastResult(SPELL_FAILED_NO_EDIBLE_CORPSES);
|
||||
finish(false);
|
||||
}
|
||||
@@ -598,6 +609,7 @@ void Spell::FillTargetMap()
|
||||
case SPELL_EFFECT_SELF_RESURRECT:
|
||||
case SPELL_EFFECT_REPUTATION:
|
||||
case SPELL_EFFECT_LEARN_SPELL:
|
||||
case SPELL_EFFECT_SEND_TAXI:
|
||||
if(m_targets.getUnitTarget())
|
||||
AddUnitTarget(m_targets.getUnitTarget(), i);
|
||||
// Triggered spells have additional spell targets - cast them even if no explicit unit target is given (required for spell 50516 for example)
|
||||
@@ -1027,6 +1039,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
|
||||
|
||||
// Add bonuses and fill damageInfo struct
|
||||
caster->CalculateSpellDamageTaken(&damageInfo, m_damage, m_spellInfo);
|
||||
caster->DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
|
||||
|
||||
// Send log damage message to client
|
||||
caster->SendSpellNonMeleeDamageLog(&damageInfo);
|
||||
@@ -1186,8 +1199,8 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
|
||||
|
||||
if (aura_effmask)
|
||||
{
|
||||
Unit * caster = m_originalCaster ? m_originalCaster : m_caster;
|
||||
Aura * Aur= new Aura(m_spellInfo, aura_effmask, &m_currentBasePoints[0], unit, caster , m_CastItem, m_caster);
|
||||
Unit * caster = m_originalCaster ? m_originalCaster : m_caster;
|
||||
Aura * Aur = new Aura(m_spellInfo, aura_effmask, m_currentBasePoints, unit, caster, m_CastItem, m_caster);
|
||||
|
||||
if (!Aur->IsAreaAura())
|
||||
{
|
||||
@@ -1412,7 +1425,7 @@ struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit,
|
||||
// functor for operator ">"
|
||||
bool operator()(const Unit* _Left, const Unit* _Right) const
|
||||
{
|
||||
return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right));
|
||||
return MainTarget->GetDistanceOrder(_Left,_Right);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1477,7 +1490,7 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin
|
||||
if(cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS)
|
||||
break;
|
||||
while(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE
|
||||
&& !m_caster->isInFront(*next, max_range)
|
||||
&& !m_caster->isInFrontInMap(*next, max_range)
|
||||
|| !m_caster->canSeeOrDetect(*next, false)
|
||||
|| !cur->IsWithinLOSInMap(*next))
|
||||
{
|
||||
@@ -1595,6 +1608,8 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
|
||||
break;
|
||||
}
|
||||
case SPELL_TARGET_TYPE_CREATURE:
|
||||
if(m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetEntry() == i_spellST->second.targetEntry)
|
||||
return m_targets.getUnitTarget();
|
||||
case SPELL_TARGET_TYPE_DEAD:
|
||||
default:
|
||||
{
|
||||
@@ -1752,15 +1767,15 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
|
||||
|
||||
if(!target)
|
||||
return;
|
||||
else if(target->GetTypeId() == TYPEID_UNIT)
|
||||
else if(target->GetTypeId() == TYPEID_GAMEOBJECT)
|
||||
AddGOTarget((GameObject*)target, i);
|
||||
else
|
||||
{
|
||||
pushType = PUSH_CHAIN;
|
||||
|
||||
if(!m_targets.getUnitTarget())
|
||||
if(m_targets.getUnitTarget() != target)
|
||||
m_targets.setUnitTarget((Unit*)target);
|
||||
}
|
||||
else if(target->GetTypeId() == TYPEID_GAMEOBJECT)
|
||||
AddGOTarget((GameObject*)target, i);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1923,7 +1938,13 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
|
||||
m_targets.setDestination(st->target_X, st->target_Y, st->target_Z);
|
||||
}
|
||||
else
|
||||
sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id );
|
||||
{
|
||||
sLog.outError( "SPELL: unknown target coordinates for spell ID %u", m_spellInfo->Id );
|
||||
Unit *target = NULL;
|
||||
if(uint64 guid = m_caster->GetUInt64Value(UNIT_FIELD_TARGET))
|
||||
target = ObjectAccessor::GetUnit(*m_caster, guid);
|
||||
m_targets.setDestination(target ? target : m_caster);
|
||||
}
|
||||
break;
|
||||
case TARGET_DST_HOME:
|
||||
if(m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
@@ -2043,7 +2064,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur)
|
||||
else if(pushType)
|
||||
{
|
||||
// Dummy, just for client
|
||||
if(spellmgr.EffectTargetType[m_spellInfo->Effect[i]] == SPELL_REQUIRE_DEST)
|
||||
if(spellmgr.EffectTargetType[m_spellInfo->Effect[i]] != SPELL_REQUIRE_UNIT)
|
||||
return;
|
||||
|
||||
float radius;
|
||||
@@ -2225,9 +2246,20 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura
|
||||
|
||||
if(!m_targets.getUnitTargetGUID() && m_spellInfo->Targets & TARGET_FLAG_UNIT)
|
||||
{
|
||||
if(Unit *target = ObjectAccessor::GetUnit(*m_caster, m_caster->GetUInt64Value(UNIT_FIELD_TARGET)))
|
||||
if(IsValidSingleTargetSpell(target))
|
||||
m_targets.setUnitTarget(target);
|
||||
Unit *target = NULL;
|
||||
if(m_caster->GetTypeId() == TYPEID_UNIT)
|
||||
target = m_caster->getVictim();
|
||||
else
|
||||
target = ObjectAccessor::GetUnit(*m_caster, ((Player*)m_caster)->GetSelection());
|
||||
|
||||
if(target && IsValidSingleTargetSpell(target))
|
||||
m_targets.setUnitTarget(target);
|
||||
else
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_BAD_TARGETS);
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_spellState = SPELL_STATE_PREPARING;
|
||||
@@ -2835,8 +2867,7 @@ void Spell::finish(bool ok)
|
||||
m_caster->clearUnitState(UNIT_STAT_CASTING);
|
||||
|
||||
// Unsummon summon as possessed creatures on spell cancel
|
||||
if(IsChanneledSpell(m_spellInfo)
|
||||
&& m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
if(IsChanneledSpell(m_spellInfo) && m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
if (Unit * charm = m_caster->GetCharm())
|
||||
for(int i = 0; i < 3; ++i)
|
||||
@@ -2854,7 +2885,12 @@ void Spell::finish(bool ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isSummon())
|
||||
|
||||
// other code related only to successfully finished spells
|
||||
if(!ok)
|
||||
return;
|
||||
|
||||
if (m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isSummon())
|
||||
{
|
||||
// Unsummon statue
|
||||
uint32 spell = m_caster->GetUInt32Value(UNIT_CREATED_BY_SPELL);
|
||||
@@ -2867,10 +2903,6 @@ void Spell::finish(bool ok)
|
||||
}
|
||||
}
|
||||
|
||||
// other code related only to successfully finished spells
|
||||
if(!ok)
|
||||
return;
|
||||
|
||||
//remove spell mods
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
((Player*)m_caster)->RemoveSpellMods(this);
|
||||
@@ -3969,13 +4001,16 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
return SPELL_FAILED_NOT_IN_ARENA;
|
||||
|
||||
// zone check
|
||||
uint32 zone, area;
|
||||
m_caster->GetZoneAndAreaId(zone,area);
|
||||
if(m_caster->GetTypeId() == TYPEID_UNIT || !((Player*)m_caster)->isGameMaster())
|
||||
{
|
||||
uint32 zone, area;
|
||||
m_caster->GetZoneAndAreaId(zone,area);
|
||||
|
||||
SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area,
|
||||
m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL);
|
||||
if(locRes != SPELL_CAST_OK)
|
||||
return locRes;
|
||||
SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area,
|
||||
m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL);
|
||||
if(locRes != SPELL_CAST_OK)
|
||||
return locRes;
|
||||
}
|
||||
|
||||
// not let players cast spells at mount (and let do it to creatures)
|
||||
if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell &&
|
||||
@@ -4822,10 +4857,9 @@ SpellCastResult Spell::CheckRange(bool strict)
|
||||
|
||||
if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0)
|
||||
{
|
||||
float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ);
|
||||
if(dist > max_range)
|
||||
if(!m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,max_range))
|
||||
return SPELL_FAILED_OUT_OF_RANGE;
|
||||
if(dist < min_range)
|
||||
if(m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,min_range))
|
||||
return SPELL_FAILED_TOO_CLOSE;
|
||||
}
|
||||
|
||||
|
||||
+9
-3
@@ -412,6 +412,8 @@ class Spell
|
||||
|
||||
void SetTargetMap(uint32 i, uint32 cur);
|
||||
|
||||
template<typename T> WorldObject* FindCorpseUsing();
|
||||
|
||||
bool CheckTarget( Unit* target, uint32 eff );
|
||||
bool CanAutoCast(Unit* target);
|
||||
void CheckSrc() { if(!m_targets.HasSrc()) m_targets.setSrc(m_caster); }
|
||||
@@ -607,7 +609,7 @@ class Spell
|
||||
void SpellDamageWeaponDmg(uint32 i);
|
||||
void SpellDamageHeal(uint32 i);
|
||||
|
||||
void GetSummonPosition(float &x, float &y, float &z, float radius = 0.0f, uint32 count = 0);
|
||||
void GetSummonPosition(uint32 i, float &x, float &y, float &z, float radius = 0.0f, uint32 count = 0);
|
||||
void SummonGuardian (uint32 entry, SummonPropertiesEntry const *properties);
|
||||
|
||||
SpellCastResult CanOpenLock(uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
|
||||
@@ -666,6 +668,10 @@ namespace Trinity
|
||||
{
|
||||
Unit *target = (Unit*)itr->getSource();
|
||||
|
||||
// mostly phase check
|
||||
if(!itr->getSource()->IsInMap(i_source))
|
||||
continue;
|
||||
|
||||
switch (i_TargetType)
|
||||
{
|
||||
case SPELL_TARGETS_ENEMY:
|
||||
@@ -706,11 +712,11 @@ namespace Trinity
|
||||
i_data->push_back(target);
|
||||
break;
|
||||
case PUSH_IN_FRONT:
|
||||
if(i_source->isInFront(target, i_radius, M_PI/3))
|
||||
if(i_source->isInFrontInMap(target, i_radius, M_PI/3))
|
||||
i_data->push_back(target);
|
||||
break;
|
||||
case PUSH_IN_BACK:
|
||||
if(i_source->isInBack(target, i_radius, M_PI/3))
|
||||
if(i_source->isInBackInMap(target, i_radius, M_PI/3))
|
||||
i_data->push_back(target);
|
||||
break;
|
||||
case PUSH_IN_LINE:
|
||||
|
||||
+47
-61
@@ -196,7 +196,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
|
||||
&AuraEffect::HandleRangedAmmoHaste, //141 SPELL_AURA_MOD_RANGED_AMMO_HASTE
|
||||
&AuraEffect::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT
|
||||
&AuraEffect::HandleAuraModResistanceExclusive, //143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE
|
||||
&AuraEffect::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes
|
||||
&AuraEffect::HandleAuraSafeFall, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes
|
||||
&AuraEffect::HandleAuraModPetTalentsPoints, //145 SPELL_AURA_MOD_PET_TALENT_POINTS
|
||||
&AuraEffect::HandleNoImmediateEffect, //146 SPELL_AURA_ALLOW_TAME_PET_TYPE
|
||||
&AuraEffect::HandleModStateImmunityMask, //147 SPELL_AURA_MECHANIC_IMMUNITY_MASK
|
||||
@@ -242,7 +242,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
|
||||
&AuraEffect::HandleNoImmediateEffect, //187 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
|
||||
&AuraEffect::HandleNoImmediateEffect, //188 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
|
||||
&AuraEffect::HandleModRating, //189 SPELL_AURA_MOD_RATING
|
||||
&AuraEffect::HandleNULL, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN
|
||||
&AuraEffect::HandleNoImmediateEffect, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN implemented in Player::CalculateReputationGain
|
||||
&AuraEffect::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
|
||||
&AuraEffect::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_HASTE_MELEE
|
||||
&AuraEffect::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct)
|
||||
@@ -721,28 +721,28 @@ void AreaAuraEffect::Update(uint32 diff)
|
||||
}
|
||||
}
|
||||
|
||||
for(std::list<Unit *>::iterator tIter = targets.begin(); tIter != targets.end(); tIter++)
|
||||
for(std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end(); tIter++)
|
||||
{
|
||||
bool skip=false;
|
||||
for(Unit::AuraMap::iterator iter = (*tIter)->GetAuras().begin(); iter != (*tIter)->GetAuras().end();++iter)
|
||||
if(Aura *aur = (*tIter)->GetAura(GetId(), m_formalCasterGUID))
|
||||
{
|
||||
bool samecaster = iter->second->GetCasterGUID() == GetCasterGUID();
|
||||
if (samecaster && iter->first == GetId())
|
||||
{
|
||||
if (AuraEffect * aurEff = iter->second->GetPartAura(m_effIndex))
|
||||
{
|
||||
skip=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (spellmgr.IsNoStackSpellDueToSpell(GetId(), iter->first,samecaster))
|
||||
{
|
||||
skip=true;
|
||||
break;
|
||||
}
|
||||
if(aur->HasEffect(GetEffIndex()))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool skip = false;
|
||||
for(Unit::AuraMap::iterator iter = (*tIter)->GetAuras().begin(); iter != (*tIter)->GetAuras().end();++iter)
|
||||
{
|
||||
bool samecaster = iter->second->GetCasterGUID() == m_formalCasterGUID;
|
||||
if(spellmgr.IsNoStackSpellDueToSpell(GetId(), iter->first, samecaster))
|
||||
{
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(skip)
|
||||
continue;
|
||||
}
|
||||
if(skip)
|
||||
continue;
|
||||
|
||||
if(SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(GetSpellProto(), (*tIter)->getLevel()))
|
||||
{
|
||||
@@ -750,7 +750,7 @@ void AreaAuraEffect::Update(uint32 diff)
|
||||
// recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?)
|
||||
//if(actualSpellInfo != GetSpellProto())
|
||||
// actualBasePoints = actualSpellInfo->EffectBasePoints[m_effIndex];
|
||||
Aura * aur = (*tIter)->AddAuraEffect(actualSpellInfo->Id, GetEffIndex(), caster, &m_currentBasePoints);
|
||||
(*tIter)->AddAuraEffect(actualSpellInfo, GetEffIndex(), caster, &m_currentBasePoints);
|
||||
|
||||
if(m_areaAuraType == AREA_AURA_ENEMY)
|
||||
caster->CombatStart(*tIter);
|
||||
@@ -1000,7 +1000,7 @@ void Aura::_AddAura()
|
||||
for(std::vector<int32>::const_iterator itr = spell_triggered->begin(); itr != spell_triggered->end(); ++itr)
|
||||
{
|
||||
if(*itr < 0)
|
||||
m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), m_target);
|
||||
m_target->ApplySpellImmune(id, IMMUNITY_ID, -(*itr), true);
|
||||
else if(Unit* caster = GetCaster())
|
||||
caster->AddAura(*itr, m_target);
|
||||
}
|
||||
@@ -2667,25 +2667,6 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real)
|
||||
}
|
||||
case SPELLFAMILY_HUNTER:
|
||||
{
|
||||
// Improved Aspect of the Viper
|
||||
if( GetId()==38390 && m_target->GetTypeId()==TYPEID_PLAYER )
|
||||
{
|
||||
if(apply)
|
||||
{
|
||||
// + effect value for Aspect of the Viper
|
||||
SpellModifier *mod = new SpellModifier;
|
||||
mod->op = SPELLMOD_EFFECT1;
|
||||
mod->value = m_amount;
|
||||
mod->type = SPELLMOD_FLAT;
|
||||
mod->spellId = GetId();
|
||||
mod->mask[1] = 0x40000;
|
||||
|
||||
m_spellmod = mod;
|
||||
}
|
||||
|
||||
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
|
||||
return;
|
||||
}
|
||||
// Glyph of Aspect of the Monkey
|
||||
if(m_spellProto->Id==56833)
|
||||
{
|
||||
@@ -3880,25 +3861,11 @@ void AuraEffect::HandleAuraModSilence(bool apply, bool Real)
|
||||
if (m_target->m_currentSpells[i] && m_target->m_currentSpells[i]->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE)
|
||||
m_target->InterruptSpell(i,false); // Stop spells on prepare or casting state
|
||||
|
||||
/*
|
||||
switch (GetId())
|
||||
{
|
||||
// Arcane Torrent (Energy)
|
||||
case 25046:
|
||||
{
|
||||
Unit * caster = GetCaster();
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
// Search Mana Tap auras on caster
|
||||
AuraEffect * dummy = caster->GetDummyAura(28734);
|
||||
if (dummy)
|
||||
{
|
||||
int32 bp = dummy->GetParentAura()->GetStackAmount() * 10;
|
||||
caster->CastCustomSpell(caster, 25048, &bp, NULL, NULL, true);
|
||||
m_target->RemoveAurasDueToSpell(28734);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5698,6 +5665,7 @@ void AuraEffect::PeriodicTick()
|
||||
if(!pCaster)
|
||||
return;
|
||||
|
||||
// Consecrate ticks can miss and will not show up in the combat log
|
||||
if( GetSpellProto()->Effect[GetEffIndex()]==SPELL_EFFECT_PERSISTENT_AREA_AURA &&
|
||||
pCaster->SpellHitResult(m_target,GetSpellProto(),false)!=SPELL_MISS_NONE)
|
||||
return;
|
||||
@@ -5746,7 +5714,8 @@ void AuraEffect::PeriodicTick()
|
||||
}
|
||||
}
|
||||
m_amount = 100 * m_tickNumber;
|
||||
}break;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -5800,6 +5769,8 @@ void AuraEffect::PeriodicTick()
|
||||
sLog.outDetail("PeriodicTick: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
|
||||
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId(),absorb);
|
||||
|
||||
pCaster->DealDamageMods(m_target,pdamage,&absorb);
|
||||
|
||||
WorldPacket data(SMSG_PERIODICAURALOG, (21+16));// we guess size
|
||||
data.append(m_target->GetPackGUID());
|
||||
data.appendPackGUID(GetCasterGUID());
|
||||
@@ -5983,10 +5954,13 @@ void AuraEffect::PeriodicTick()
|
||||
}
|
||||
else
|
||||
{
|
||||
pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), gain, GetSpellSchoolMask(GetSpellProto()), 0, 0, false, 0, false);
|
||||
uint32 damage = gain;
|
||||
uint32 absorb = 0;
|
||||
pCaster->DealDamageMods(pCaster,damage,&absorb);
|
||||
pCaster->SendSpellNonMeleeDamageLog(pCaster, GetId(), damage, GetSpellSchoolMask(GetSpellProto()), absorb, 0, false, 0, false);
|
||||
|
||||
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
|
||||
pCaster->DealDamage(pCaster, gain, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true);
|
||||
pCaster->DealDamage(pCaster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6202,6 +6176,9 @@ void AuraEffect::PeriodicTick()
|
||||
SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask);
|
||||
//no SpellDamageBonus for burn mana
|
||||
pCaster->CalculateSpellDamageTaken(&damageInfo, gain, spellProto);
|
||||
|
||||
pCaster->DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
|
||||
|
||||
pCaster->SendSpellNonMeleeDamageLog(&damageInfo);
|
||||
|
||||
// Set trigger flag
|
||||
@@ -6973,3 +6950,12 @@ void Aura::UnregisterSingleCastAura()
|
||||
m_isSingleTargetAura = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraSafeFall( bool Apply, bool Real )
|
||||
{
|
||||
// implemented in WorldSession::HandleMovementOpcodes
|
||||
|
||||
// only special case
|
||||
if(Apply && Real && GetId()==32474 && m_target->GetTypeId()==TYPEID_PLAYER)
|
||||
((Player*)m_target)->ActivateTaxiPathTo(506,GetId());
|
||||
}
|
||||
|
||||
@@ -217,6 +217,7 @@ class TRINITY_DLL_SPEC AuraEffect
|
||||
void HandlePeriodicTriggerSpellWithValue(bool apply, bool Real);
|
||||
void HandlePeriodicEnergize(bool Apply, bool Real);
|
||||
void HandleAuraModResistanceExclusive(bool Apply, bool Real);
|
||||
void HandleAuraSafeFall(bool Apply, bool Real);
|
||||
void HandleAuraModPetTalentsPoints(bool Apply, bool Real);
|
||||
void HandleModStealth(bool Apply, bool Real);
|
||||
void HandleInvisibility(bool Apply, bool Real);
|
||||
|
||||
+53
-110
@@ -286,8 +286,7 @@ void Spell::EffectInstaKill(uint32 /*i*/)
|
||||
if(m_caster==unitTarget) // prevent interrupt message
|
||||
finish();
|
||||
|
||||
uint32 health = unitTarget->GetHealth();
|
||||
m_caster->DealDamage(unitTarget, health, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
||||
m_caster->DealDamage(unitTarget, unitTarget->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
|
||||
}
|
||||
|
||||
void Spell::EffectEnvirinmentalDMG(uint32 i)
|
||||
@@ -652,9 +651,9 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
|
||||
else if(m_spellInfo->SpellFamilyFlags[1]&0x00040000)
|
||||
{
|
||||
// Add main hand dps * effect[2] amount
|
||||
float averange = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
|
||||
float average = (m_caster->GetFloatValue(UNIT_FIELD_MINDAMAGE) + m_caster->GetFloatValue(UNIT_FIELD_MAXDAMAGE)) / 2;
|
||||
int32 count = m_caster->CalculateSpellDamage(m_spellInfo, 2, m_spellInfo->EffectBasePoints[2], unitTarget);
|
||||
damage += count * int32(averange * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
|
||||
damage += count * int32(average * IN_MILISECONDS) / m_caster->GetAttackTime(BASE_ATTACK);
|
||||
}
|
||||
// Shield of Righteousness
|
||||
else if(m_spellInfo->SpellFamilyFlags[1]&0x00100000)
|
||||
@@ -1012,17 +1011,6 @@ void Spell::EffectDummy(uint32 i)
|
||||
m_caster->CastSpell(unitTarget,29294,true);
|
||||
return;
|
||||
}
|
||||
case 28730: // Arcane Torrent (Mana)
|
||||
{
|
||||
Aura * dummy = m_caster->GetAura(28734, m_caster->GetGUID());
|
||||
if (dummy)
|
||||
{
|
||||
int32 bp = damage * dummy->GetStackAmount();
|
||||
m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
|
||||
m_caster->RemoveAurasDueToSpell(28734);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case 29200: // Purify Helboar Meat
|
||||
{
|
||||
if( m_caster->GetTypeId() != TYPEID_PLAYER )
|
||||
@@ -1324,12 +1312,7 @@ void Spell::EffectDummy(uint32 i)
|
||||
(GetSpellSchoolMask(spellInfo) & SPELL_SCHOOL_MASK_FROST) &&
|
||||
spellInfo->Id != 11958 && GetSpellRecoveryTime(spellInfo) > 0 )
|
||||
{
|
||||
((Player*)m_caster)->RemoveSpellCooldown(classspell);
|
||||
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
|
||||
data << uint32(classspell);
|
||||
data << uint64(m_caster->GetGUID());
|
||||
((Player*)m_caster)->GetSession()->SendPacket(&data);
|
||||
((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -1367,24 +1350,29 @@ void Spell::EffectDummy(uint32 i)
|
||||
if(!unitTarget)
|
||||
return;
|
||||
|
||||
uint32 rage = m_caster->GetPower(POWER_RAGE);
|
||||
uint32 rage=0;
|
||||
// Glyph of Execution bonus
|
||||
if (AuraEffect *aura = m_caster->GetDummyAura(58367))
|
||||
rage+=aura->GetAmount();
|
||||
|
||||
spell_id = 20647;
|
||||
bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
|
||||
m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
|
||||
// Sudden death cost modifier
|
||||
if (Aura * aur = m_caster->GetAura(52437))
|
||||
{
|
||||
rage += m_powerCost;
|
||||
m_caster->ModifyPower(POWER_RAGE,- m_powerCost);
|
||||
if (m_caster->GetPower(POWER_RAGE)<100)
|
||||
m_caster->SetPower(POWER_RAGE,100);
|
||||
m_caster->RemoveAura(aur);
|
||||
}
|
||||
else
|
||||
{
|
||||
rage += m_caster->GetPower(POWER_RAGE);
|
||||
m_caster->SetPower(POWER_RAGE,0);
|
||||
}
|
||||
|
||||
bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] +
|
||||
m_caster->GetTotalAttackPowerValue(BASE_ATTACK)*0.2f);
|
||||
break;
|
||||
}
|
||||
// Slam
|
||||
@@ -1580,14 +1568,7 @@ void Spell::EffectDummy(uint32 i)
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
|
||||
|
||||
if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && (spellInfo->SpellFamilyFlags[1] & 0x00000240 || spellInfo->SpellFamilyFlags[0] & 0x00000860))
|
||||
{
|
||||
((Player*)m_caster)->RemoveSpellCooldown(classspell);
|
||||
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
|
||||
data << uint32(classspell);
|
||||
data << uint64(m_caster->GetGUID());
|
||||
((Player*)m_caster)->GetSession()->SendPacket(&data);
|
||||
}
|
||||
((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1614,14 +1595,7 @@ void Spell::EffectDummy(uint32 i)
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(classspell);
|
||||
|
||||
if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0 )
|
||||
{
|
||||
((Player*)m_caster)->RemoveSpellCooldown(classspell);
|
||||
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
|
||||
data << uint32(classspell);
|
||||
data << uint64(m_caster->GetGUID());
|
||||
((Player*)m_caster)->GetSession()->SendPacket(&data);
|
||||
}
|
||||
((Player*)m_caster)->RemoveSpellCooldown(classspell,true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1716,17 +1690,8 @@ void Spell::EffectDummy(uint32 i)
|
||||
// non-standard cast requirement check
|
||||
if (!unitTarget || unitTarget->getAttackers().empty())
|
||||
{
|
||||
// clear cooldown at fail
|
||||
if(m_caster->GetTypeId()==TYPEID_PLAYER)
|
||||
{
|
||||
((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id);
|
||||
|
||||
WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8));
|
||||
data << uint32(m_spellInfo->Id);
|
||||
data << uint64(m_caster->GetGUID());
|
||||
((Player*)m_caster)->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true);
|
||||
SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT);
|
||||
return;
|
||||
}
|
||||
@@ -3230,7 +3195,7 @@ void Spell::EffectSummonType(uint32 i)
|
||||
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
|
||||
|
||||
float x, y, z;
|
||||
GetSummonPosition(x, y, z);
|
||||
GetSummonPosition(i, x, y, z);
|
||||
|
||||
/*//totem must be at same Z in case swimming caster and etc.
|
||||
if( fabs( z - m_caster->GetPositionZ() ) > 5 )
|
||||
@@ -3315,7 +3280,7 @@ void Spell::EffectSummonType(uint32 i)
|
||||
|
||||
summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
|
||||
summon->GetMotionMaster()->MoveTargetedHome();
|
||||
summon->AI()->EnterEvadeMode();
|
||||
|
||||
std::string name = m_originalCaster->GetName();
|
||||
name.append(petTypeSuffix[3]);
|
||||
@@ -3331,7 +3296,7 @@ void Spell::EffectSummonType(uint32 i)
|
||||
for(int32 count = 0; count < amount; ++count)
|
||||
{
|
||||
float px, py, pz;
|
||||
GetSummonPosition(px, py, pz, radius, count);
|
||||
GetSummonPosition(i, px, py, pz, radius, count);
|
||||
|
||||
TempSummonType summonType = (duration == 0) ? TEMPSUMMON_DEAD_DESPAWN : TEMPSUMMON_TIMED_DESPAWN;
|
||||
|
||||
@@ -4776,17 +4741,17 @@ void Spell::EffectScriptEffect(uint32 effIndex)
|
||||
unitTarget->CastSpell(unitTarget, 44870, true);
|
||||
break;
|
||||
}
|
||||
// spell of Brutallus - Stomp
|
||||
case 45185:
|
||||
{
|
||||
if(!unitTarget)
|
||||
return;
|
||||
|
||||
if(unitTarget->HasAura(46394)) // spell of Brutallus - Burn
|
||||
unitTarget->RemoveAurasDueToSpell(46394);
|
||||
// spell of Brutallus - Stomp
|
||||
case 45185:
|
||||
{
|
||||
if(!unitTarget)
|
||||
return;
|
||||
|
||||
break;
|
||||
}
|
||||
if(unitTarget->HasAura(46394)) // spell of Brutallus - Burn
|
||||
unitTarget->RemoveAurasDueToSpell(46394);
|
||||
|
||||
break;
|
||||
}
|
||||
// Negative Energy
|
||||
case 46289:
|
||||
{
|
||||
@@ -5891,47 +5856,7 @@ void Spell::EffectSendTaxi(uint32 i)
|
||||
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(m_spellInfo->EffectMiscValue[i]);
|
||||
if(!entry)
|
||||
return;
|
||||
|
||||
std::vector<uint32> nodes;
|
||||
|
||||
nodes.resize(2);
|
||||
nodes[0] = entry->from;
|
||||
nodes[1] = entry->to;
|
||||
|
||||
uint32 mountid = 0;
|
||||
switch(m_spellInfo->Id)
|
||||
{
|
||||
case 31606: //Stormcrow Amulet
|
||||
mountid = 17447;
|
||||
break;
|
||||
case 45071: //Quest - Sunwell Daily - Dead Scar Bombing Run
|
||||
case 45113: //Quest - Sunwell Daily - Ship Bombing Run
|
||||
case 45353: //Quest - Sunwell Daily - Ship Bombing Run Return
|
||||
mountid = 22840;
|
||||
break;
|
||||
case 34905: //Stealth Flight
|
||||
mountid = 6851;
|
||||
break;
|
||||
case 45883: //Amber Ledge to Beryl Point
|
||||
mountid = 23524;
|
||||
break;
|
||||
case 46064: //Amber Ledge to Coldarra
|
||||
mountid = 6371;
|
||||
break;
|
||||
case 53335: //Stormwind Harbor Flight - Peaceful
|
||||
mountid = 6852;
|
||||
break;
|
||||
case 41533: //Fly of the Netherwing
|
||||
case 41540: //Fly of the Netherwing
|
||||
mountid = 23468;
|
||||
break;
|
||||
}
|
||||
|
||||
((Player*)unitTarget)->ActivateTaxiPathTo(nodes,mountid);
|
||||
|
||||
((Player*)unitTarget)->ActivateTaxiPathTo(m_spellInfo->EffectMiscValue[i],m_spellInfo->Id);
|
||||
}
|
||||
|
||||
void Spell::EffectPlayerPull(uint32 i)
|
||||
@@ -6292,7 +6217,7 @@ void Spell::EffectSummonDemon(uint32 i)
|
||||
for(int32 count = 0; count < amount; ++count)
|
||||
{
|
||||
float px, py, pz;
|
||||
GetSummonPosition(px, py, pz, radius, count);
|
||||
GetSummonPosition(i, px, py, pz, radius, count);
|
||||
|
||||
int32 duration = GetSpellDuration(m_spellInfo);
|
||||
|
||||
@@ -6492,7 +6417,7 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties
|
||||
for(int32 count = 0; count < amount; ++count)
|
||||
{
|
||||
float px, py, pz;
|
||||
GetSummonPosition(px, py, pz, radius, count);
|
||||
GetSummonPosition(0, px, py, pz, radius, count);
|
||||
|
||||
TempSummon *summon = map->SummonCreature(entry, px, py, pz, m_caster->GetOrientation(), properties, duration, caster);
|
||||
if(!summon)
|
||||
@@ -6503,11 +6428,11 @@ void Spell::SummonGuardian(uint32 entry, SummonPropertiesEntry const *properties
|
||||
|
||||
summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, m_spellInfo->Id);
|
||||
|
||||
summon->GetMotionMaster()->MoveTargetedHome();
|
||||
summon->AI()->EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::GetSummonPosition(float &x, float &y, float &z, float radius, uint32 count)
|
||||
void Spell::GetSummonPosition(uint32 i, float &x, float &y, float &z, float radius, uint32 count)
|
||||
{
|
||||
if (m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)
|
||||
{
|
||||
@@ -6520,7 +6445,25 @@ void Spell::GetSummonPosition(float &x, float &y, float &z, float radius, uint32
|
||||
}
|
||||
// Summon in random point all other units if location present
|
||||
else
|
||||
m_caster->GetRandomPoint(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ,radius,x,y,z);
|
||||
{
|
||||
//This is a workaround. Do not have time to write much about it
|
||||
switch(m_spellInfo->EffectImplicitTargetA[i])
|
||||
{
|
||||
case TARGET_MINION:
|
||||
case TARGET_DEST_CASTER_RANDOM:
|
||||
m_caster->GetGroundPointAroundUnit(x, y, z, radius * rand_norm(), rand_norm()*2*M_PI);
|
||||
break;
|
||||
case TARGET_DEST_DEST_RANDOM:
|
||||
case TARGET_DEST_TARGET_RANDOM:
|
||||
m_caster->GetRandomPoint(m_targets.m_destX,m_targets.m_destY,m_targets.m_destZ,radius,x,y,z);
|
||||
break;
|
||||
default:
|
||||
x = m_targets.m_destX;
|
||||
y = m_targets.m_destY;
|
||||
z = m_targets.m_destZ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Summon if dest location not present near caster
|
||||
else
|
||||
@@ -6534,4 +6477,4 @@ void Spell::EffectRenamePet(uint32 /*eff_idx*/)
|
||||
return;
|
||||
|
||||
unitTarget->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED);
|
||||
}
|
||||
}
|
||||
+23
-14
@@ -27,6 +27,7 @@
|
||||
#include "Chat.h"
|
||||
#include "Spell.h"
|
||||
#include "BattleGroundMgr.h"
|
||||
#include "CreatureAI.h"
|
||||
|
||||
bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS];
|
||||
|
||||
@@ -1472,6 +1473,10 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool
|
||||
//if spells have exactly the same effect they cannot stack
|
||||
for(uint32 i = 0; i < 3; ++i)
|
||||
if(spellInfo_1->Effect[i] != spellInfo_2->Effect[i]
|
||||
// Overkill and master of subtlety need this
|
||||
|| spellInfo_1->EffectApplyAuraName[i] == SPELL_AURA_DUMMY
|
||||
|| spellInfo_1->EffectApplyAuraName[i] == SPELL_AURA_PERIODIC_DUMMY
|
||||
|
||||
|| spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i]
|
||||
|| spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i]) // paladin resist aura
|
||||
return false; // need itemtype check? need an example to add that check
|
||||
@@ -2426,31 +2431,32 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
case 45976: // Muru Portal Channel
|
||||
case 39365: // Thundering Storm
|
||||
case 41071: // Raise Dead (HACK)
|
||||
case 28542: // Life Drain - Sapphiron
|
||||
spellInfo->MaxAffectedTargets = 1;
|
||||
break;
|
||||
case 41376: // Spite
|
||||
case 39992: // Needle Spine
|
||||
case 29576: //Multi-Shot
|
||||
case 40816: //Saber Lash
|
||||
case 37790: //Spread Shot
|
||||
case 46771: //Flame Sear
|
||||
case 45248: //Shadow Blades
|
||||
case 29576: // Multi-Shot
|
||||
case 40816: // Saber Lash
|
||||
case 37790: // Spread Shot
|
||||
case 46771: // Flame Sear
|
||||
case 45248: // Shadow Blades
|
||||
case 41303: // Soul Drain
|
||||
case 54172: // Divine Storm (heal)
|
||||
case 29213: // Curse of the Plaguebringer
|
||||
case 29213: // Curse of the Plaguebringer - Noth
|
||||
case 28542: // Life Drain - Sapphiron
|
||||
spellInfo->MaxAffectedTargets = 3;
|
||||
break;
|
||||
case 38310: //Multi-Shot
|
||||
spellInfo->MaxAffectedTargets = 4;
|
||||
break;
|
||||
case 42005: // Bloodboil
|
||||
case 38296: //Spitfire Totem
|
||||
case 37676: //Insidious Whisper
|
||||
case 46009: //Negative Energy
|
||||
case 45641: //Fire Bloom
|
||||
case 54937: //Glyph of Holy Light
|
||||
case 55665: // Life Drain - Sapphiron
|
||||
case 38296: // Spitfire Totem
|
||||
case 37676: // Insidious Whisper
|
||||
case 46009: // Negative Energy
|
||||
case 45641: // Fire Bloom
|
||||
case 54937: // Glyph of Holy Light
|
||||
case 55665: // Life Drain - Sapphiron (H)
|
||||
case 28796: // Poison Bolt Volly - Faerlina
|
||||
spellInfo->MaxAffectedTargets = 5;
|
||||
break;
|
||||
case 40827: // Sinful Beam
|
||||
@@ -2458,7 +2464,8 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
case 40860: // Vile Beam
|
||||
case 40861: // Wicked Beam
|
||||
case 57669: // Replenishment
|
||||
case 54835: // Curse of the Plaguebringer
|
||||
case 54835: // Curse of the Plaguebringer - Noth (H)
|
||||
case 54098: // Poison Bolt Volly - Faerlina (H)
|
||||
spellInfo->MaxAffectedTargets = 10;
|
||||
break;
|
||||
case 8122: case 8124: case 10888: case 10890: // Psychic Scream
|
||||
@@ -2516,6 +2523,8 @@ void SpellMgr::LoadSpellCustomAttr()
|
||||
|
||||
SummonPropertiesEntry *properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(121));
|
||||
properties->Type = SUMMON_TYPE_TOTEM;
|
||||
|
||||
CreatureAI::FillAISpellInfo();
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellLinked()
|
||||
|
||||
@@ -128,7 +128,8 @@ void WorldSession::SendDoFlight( uint16 MountId, uint32 path, uint32 pathNode )
|
||||
while(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()==FLIGHT_MOTION_TYPE)
|
||||
GetPlayer()->GetMotionMaster()->MovementExpired(false);
|
||||
|
||||
GetPlayer()->Mount( MountId );
|
||||
if (MountId)
|
||||
GetPlayer()->Mount( MountId );
|
||||
GetPlayer()->GetMotionMaster()->MoveTaxiFlight(path,pathNode);
|
||||
}
|
||||
|
||||
@@ -190,7 +191,7 @@ void WorldSession::HandleActivateTaxiFarOpcode ( WorldPacket & recv_data )
|
||||
|
||||
sLog.outDebug( "WORLD: Received CMSG_ACTIVATETAXIEXPRESS from %d to %d" ,nodes.front(),nodes.back());
|
||||
|
||||
GetPlayer()->ActivateTaxiPathTo(nodes, 0, npc);
|
||||
GetPlayer()->ActivateTaxiPathTo(nodes, npc);
|
||||
}
|
||||
|
||||
void WorldSession::HandleTaxiNextDestinationOpcode(WorldPacket& /*recv_data*/)
|
||||
@@ -275,6 +276,6 @@ void WorldSession::HandleActivateTaxiOpcode( WorldPacket & recv_data )
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer()->ActivateTaxiPathTo(nodes, 0, npc);
|
||||
GetPlayer()->ActivateTaxiPathTo(nodes, npc);
|
||||
}
|
||||
|
||||
|
||||
@@ -208,10 +208,8 @@ void TempSummon::InitSummon()
|
||||
if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER && m_spells[0])
|
||||
{
|
||||
setFaction(owner->getFaction());
|
||||
if(m_spells[1] && GetMap()->IsHeroic())
|
||||
CastSpell(this, m_spells[1], false, 0, 0, m_summonerGUID);
|
||||
else
|
||||
CastSpell(this, m_spells[0], false, 0, 0, m_summonerGUID);
|
||||
SetLevel(owner->getLevel());
|
||||
CastSpell(this, m_spells[0], false, 0, 0, m_summonerGUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,6 +307,8 @@ void Guardian::InitStats(uint32 duration)
|
||||
{
|
||||
Minion::InitStats(duration);
|
||||
|
||||
InitStatsForLevel(m_owner->getLevel());
|
||||
|
||||
if(m_owner->GetTypeId() == TYPEID_PLAYER)
|
||||
m_charmInfo->InitCharmCreateSpells();
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "Creature.h"
|
||||
|
||||
class TempSummon : public Creature
|
||||
class TRINITY_DLL_SPEC TempSummon : public Creature
|
||||
{
|
||||
public:
|
||||
explicit TempSummon(SummonPropertiesEntry const *properties, Unit *owner);
|
||||
|
||||
+13
-13
@@ -461,30 +461,30 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
CHECK_PACKET_SIZE(recvPacket,8);
|
||||
|
||||
if( GetPlayer()->pTrader )
|
||||
if (GetPlayer()->pTrader)
|
||||
return;
|
||||
|
||||
uint64 ID;
|
||||
|
||||
if( !GetPlayer()->isAlive() )
|
||||
if (!GetPlayer()->isAlive())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_DEAD);
|
||||
return;
|
||||
}
|
||||
|
||||
if( GetPlayer()->hasUnitState(UNIT_STAT_STUNNED) )
|
||||
if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_STUNNED);
|
||||
return;
|
||||
}
|
||||
|
||||
if( isLogingOut() )
|
||||
if (isLogingOut())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_YOU_LOGOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
if( GetPlayer()->isInFlight() )
|
||||
if (GetPlayer()->isInFlight())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
@@ -494,43 +494,43 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
|
||||
|
||||
Player* pOther = ObjectAccessor::FindPlayer( ID );
|
||||
|
||||
if( !pOther )
|
||||
if (!pOther)
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_NO_TARGET);
|
||||
return;
|
||||
}
|
||||
|
||||
if( pOther == GetPlayer() || pOther->pTrader )
|
||||
if (pOther == GetPlayer() || pOther->pTrader)
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_BUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
if( !pOther->isAlive() )
|
||||
if (!pOther->isAlive())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_DEAD);
|
||||
return;
|
||||
}
|
||||
|
||||
if( pOther->isInFlight() )
|
||||
if (pOther->isInFlight())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
}
|
||||
|
||||
if( pOther->hasUnitState(UNIT_STAT_STUNNED) )
|
||||
if (pOther->hasUnitState(UNIT_STAT_STUNNED))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_STUNNED);
|
||||
return;
|
||||
}
|
||||
|
||||
if( pOther->GetSession()->isLogingOut() )
|
||||
if (pOther->GetSession()->isLogingOut())
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
if( pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()) )
|
||||
if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_IGNORE_YOU);
|
||||
return;
|
||||
@@ -542,7 +542,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
|
||||
return;
|
||||
}
|
||||
|
||||
if( pOther->GetDistance2d( _player ) > 10.0f )
|
||||
if (!pOther->IsWithinDistInMap(_player,10.0f,false))
|
||||
{
|
||||
SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR);
|
||||
return;
|
||||
|
||||
+150
-58
@@ -413,7 +413,7 @@ void Unit::resetAttackTimer(WeaponAttackType type)
|
||||
m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]);
|
||||
}
|
||||
|
||||
bool Unit::IsWithinCombatRange(Unit *obj, float dist2compare) const
|
||||
bool Unit::IsWithinCombatRange(const Unit *obj, float dist2compare) const
|
||||
{
|
||||
if (!obj || !IsInMap(obj)) return false;
|
||||
|
||||
@@ -428,7 +428,7 @@ bool Unit::IsWithinCombatRange(Unit *obj, float dist2compare) const
|
||||
return distsq < maxdist * maxdist;
|
||||
}
|
||||
|
||||
bool Unit::IsWithinMeleeRange(Unit *obj, float dist) const
|
||||
bool Unit::IsWithinMeleeRange(const Unit *obj, float dist) const
|
||||
{
|
||||
if (!obj || !IsInMap(obj)) return false;
|
||||
|
||||
@@ -535,10 +535,15 @@ void Unit::RemoveSpellbyDamageTaken(uint32 damage, uint32 spell)
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss)
|
||||
void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb)
|
||||
{
|
||||
if (!pVictim->isAlive() || pVictim->hasUnitState(UNIT_STAT_UNATTACKABLE) || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
|
||||
return 0;
|
||||
{
|
||||
if(absorb)
|
||||
absorb += damage;
|
||||
damage = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//You don't lose health from damage taken from another player while in a sanctuary
|
||||
//You still see it in the combat log though
|
||||
@@ -546,14 +551,30 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
|
||||
{
|
||||
const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
|
||||
if(area && area->flags & AREA_FLAG_SANCTUARY) //sanctuary
|
||||
return 0;
|
||||
{
|
||||
if(absorb)
|
||||
absorb += damage;
|
||||
damage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 originalDamage = damage;
|
||||
|
||||
//Script Event damage Deal
|
||||
//if( GetTypeId()== TYPEID_UNIT && ((Creature *)this)->AI())
|
||||
// ((Creature *)this)->AI()->DamageDeal(pVictim, damage);
|
||||
//Script Event damage taken
|
||||
if( pVictim->GetTypeId()== TYPEID_UNIT && ((Creature *)pVictim)->IsAIEnabled )
|
||||
{
|
||||
((Creature *)pVictim)->AI()->DamageTaken(this, damage);
|
||||
|
||||
if(absorb && originalDamage > damage)
|
||||
absorb += (originalDamage - damage);
|
||||
}
|
||||
|
||||
uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss)
|
||||
{
|
||||
if( pVictim->GetTypeId()== TYPEID_UNIT)
|
||||
{
|
||||
// Set tagging
|
||||
if(!pVictim->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_OTHER_TAGGER) && !((Creature*)pVictim)->isPet())
|
||||
{
|
||||
@@ -1203,6 +1224,7 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage
|
||||
SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask);
|
||||
damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
|
||||
CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
|
||||
DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
|
||||
SendSpellNonMeleeDamageLog(&damageInfo);
|
||||
DealSpellDamage(&damageInfo, true);
|
||||
return damageInfo.damage;
|
||||
@@ -1706,6 +1728,8 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
|
||||
//CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
|
||||
//damage-=absorb + resist;
|
||||
|
||||
pVictim->DealDamageMods(this,damage,NULL);
|
||||
|
||||
WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4+4+4));
|
||||
data << uint64(pVictim->GetGUID());
|
||||
data << uint64(GetGUID());
|
||||
@@ -2085,8 +2109,12 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
|
||||
int32 canabsorb = caster->GetHealth();
|
||||
if (canabsorb < absorbed)
|
||||
absorbed = canabsorb;
|
||||
DealDamage(caster, absorbed, NULL, damagetype, schoolMask, 0, false);
|
||||
|
||||
RemainingDamage -= absorbed;
|
||||
|
||||
uint32 ab_damage = absorbed;
|
||||
DealDamageMods(caster,ab_damage,NULL);
|
||||
DealDamage(caster, ab_damage, NULL, damagetype, schoolMask, 0, false);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -2195,10 +2223,15 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
|
||||
|
||||
RemainingDamage -= currentAbsorb;
|
||||
|
||||
SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, currentAbsorb, schoolMask, 0, 0, false, 0, false);
|
||||
|
||||
CleanDamage cleanDamage = CleanDamage(currentAbsorb, BASE_ATTACK, MELEE_HIT_NORMAL);
|
||||
DealDamage(caster, currentAbsorb, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
|
||||
uint32 splitted = currentAbsorb;
|
||||
uint32 splitted_absorb = 0;
|
||||
DealDamageMods(caster,splitted,&splitted_absorb);
|
||||
|
||||
SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, splitted_absorb, 0, false, 0, false);
|
||||
|
||||
CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
|
||||
DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
|
||||
}
|
||||
|
||||
AuraEffectList const& vSplitDamagePct = pVictim->GetAurasByType(SPELL_AURA_SPLIT_DAMAGE_PCT);
|
||||
@@ -2215,11 +2248,14 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
|
||||
if(!caster || caster == pVictim || !caster->IsInWorld() || !caster->isAlive())
|
||||
continue;
|
||||
|
||||
int32 splitted = int32(RemainingDamage * (*i)->GetAmount() / 100.0f);
|
||||
uint32 splitted = uint32(RemainingDamage * (*i)->GetAmount() / 100.0f);
|
||||
|
||||
RemainingDamage -= splitted;
|
||||
RemainingDamage -= int32(splitted);
|
||||
|
||||
SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, 0, 0, false, 0, false);
|
||||
uint32 split_absorb = 0;
|
||||
DealDamageMods(caster,splitted,&split_absorb);
|
||||
|
||||
SendSpellNonMeleeDamageLog(caster, (*i)->GetSpellProto()->Id, splitted, schoolMask, split_absorb, 0, false, 0, false);
|
||||
|
||||
CleanDamage cleanDamage = CleanDamage(splitted, BASE_ATTACK, MELEE_HIT_NORMAL);
|
||||
DealDamage(caster, splitted, &cleanDamage, DIRECT_DAMAGE, schoolMask, (*i)->GetSpellProto(), false);
|
||||
@@ -2354,6 +2390,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
|
||||
CalcDamageInfo damageInfo;
|
||||
CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
|
||||
// Send log damage message to client
|
||||
DealDamageMods(pVictim,damageInfo.damage,&damageInfo.absorb);
|
||||
SendAttackStateUpdate(&damageInfo);
|
||||
ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
|
||||
DealMeleeDamage(&damageInfo,true);
|
||||
@@ -2775,7 +2812,9 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
|
||||
return SPELL_MISS_NONE;
|
||||
|
||||
// Ranged attack cannot be parry/dodge only deflect
|
||||
if (attType == RANGED_ATTACK)
|
||||
// Check damage class instead of attack type to correctly handle judgements
|
||||
// - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
|
||||
if (spell->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
|
||||
{
|
||||
// only if in front
|
||||
if (pVictim->HasInArc(M_PI,this))
|
||||
@@ -3526,7 +3565,7 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool Unit::isInFront(Unit const* target, float distance, float arc) const
|
||||
bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
|
||||
{
|
||||
return IsWithinDistInMap(target, distance) && HasInArc( arc, target );
|
||||
}
|
||||
@@ -3536,7 +3575,7 @@ void Unit::SetInFront(Unit const* target)
|
||||
SetOrientation(GetAngle(target));
|
||||
}
|
||||
|
||||
bool Unit::isInBack(Unit const* target, float distance, float arc) const
|
||||
bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
|
||||
{
|
||||
return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target );
|
||||
}
|
||||
@@ -4272,7 +4311,7 @@ bool Unit::HasAura(Aura * aur) const
|
||||
bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, uint64 caster) const
|
||||
{
|
||||
if (Aura * aur = GetAura(spellId, caster))
|
||||
return bool(aur->HasEffect(effIndex));
|
||||
return aur->HasEffect(effIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4486,38 +4525,32 @@ void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log)
|
||||
data.append(log->target->GetPackGUID());
|
||||
data.append(log->attacker->GetPackGUID());
|
||||
data << uint32(log->SpellID);
|
||||
data << uint32(log->damage); //damage amount
|
||||
data << uint32(log->damage); // damage amount
|
||||
data << uint32(int32 (log->target->GetHealth()-log->damage ) >0 ? 0 : log->damage - log->target->GetHealth());
|
||||
data << uint8 (log->schoolMask); //damage school
|
||||
data << uint32(log->absorb); //AbsorbedDamage
|
||||
data << uint32(log->resist); //resist
|
||||
data << uint8 (log->phusicalLog); // damsge type? flag
|
||||
data << uint8 (log->unused); //unused
|
||||
data << uint32(log->blocked); //blocked
|
||||
//data << uint32(log->overkill); // overkill
|
||||
data << uint8 (log->schoolMask); // damage school
|
||||
data << uint32(log->absorb); // AbsorbedDamage
|
||||
data << uint32(log->resist); // resist
|
||||
data << uint8 (log->physicalLog); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
|
||||
data << uint8 (log->unused); // unused
|
||||
data << uint32(log->blocked); // blocked
|
||||
data << uint32(log->HitInfo);
|
||||
data << uint8 (0); // flag to use extend data
|
||||
data << uint8 (0); // flag to use extend data
|
||||
SendMessageToSet( &data, true );
|
||||
}
|
||||
|
||||
void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
|
||||
{
|
||||
sLog.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
|
||||
WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
|
||||
data.append(target->GetPackGUID());
|
||||
data.append(GetPackGUID());
|
||||
data << uint32(SpellID);
|
||||
int32 damageDone = Damage-AbsorbedDamage-Resist-Blocked;
|
||||
data << uint32(damageDone);
|
||||
data << uint32(int32 (target->GetHealth()-damageDone ) >0 ? 0 : damageDone - target->GetHealth());// wotlk
|
||||
data << uint8(damageSchoolMask); // spell school
|
||||
data << uint32(AbsorbedDamage); // AbsorbedDamage
|
||||
data << uint32(Resist); // resist
|
||||
data << uint8(PhysicalDamage); // if 1, then client show spell name (example: %s's ranged shot hit %s for %u school or %s suffers %u school damage from %s's spell_name
|
||||
data << uint8(0); // unk isFromAura
|
||||
data << uint32(Blocked); // blocked
|
||||
data << uint32(CriticalHit ? 0x27 : 0x25); // hitType, flags: 0x2 - SPELL_HIT_TYPE_CRIT, 0x10 - replace caster?
|
||||
data << uint8(0); // isDebug?
|
||||
SendMessageToSet( &data, true );
|
||||
SpellNonMeleeDamage log(this,target,SpellID,damageSchoolMask);
|
||||
log.damage = Damage-AbsorbedDamage-Resist-Blocked;
|
||||
log.absorb = AbsorbedDamage;
|
||||
log.resist = Resist;
|
||||
log.physicalLog = PhysicalDamage;
|
||||
log.blocked = Blocked;
|
||||
log.HitInfo = SPELL_HIT_TYPE_UNK1 | SPELL_HIT_TYPE_UNK3 | SPELL_HIT_TYPE_UNK6;
|
||||
if(CriticalHit)
|
||||
log.HitInfo |= SPELL_HIT_TYPE_CRIT;
|
||||
SendSpellNonMeleeDamageLog(&log);
|
||||
}
|
||||
|
||||
void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const *procSpell)
|
||||
@@ -5301,6 +5334,25 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
|
||||
CastSpell(this, 28682, true, castItem, triggeredByAura);
|
||||
return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns
|
||||
}
|
||||
// Glyph of Ice Block
|
||||
case 56372:
|
||||
{
|
||||
if(GetTypeId() != TYPEID_PLAYER)
|
||||
return false;
|
||||
|
||||
SpellCooldowns SpellCDs = ((Player*)this)->GetSpellCooldowns();
|
||||
// remove cooldowns on all ranks of Frost Nova
|
||||
for(SpellCooldowns::const_iterator itr = SpellCDs.begin(); itr != SpellCDs.end(); itr++)
|
||||
{
|
||||
SpellEntry const* SpellCDs_entry = sSpellStore.LookupEntry(itr->first);
|
||||
// Frost Nova
|
||||
if(SpellCDs_entry && SpellCDs_entry->SpellFamilyName == SPELLFAMILY_MAGE && SpellCDs_entry->SpellFamilyFlags[0] & 0x00000040)
|
||||
{
|
||||
((Player*)this)->RemoveSpellCooldown(SpellCDs_entry->Id, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -5579,6 +5631,31 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger
|
||||
triggered_spell_id = 56160;
|
||||
break;
|
||||
}
|
||||
// Glyph of Prayer of Healing
|
||||
case 55680:
|
||||
{
|
||||
triggered_spell_id = 56161;
|
||||
|
||||
SpellEntry const* GoPoH = sSpellStore.LookupEntry(triggered_spell_id);
|
||||
if(!GoPoH)
|
||||
return false;
|
||||
|
||||
int EffIndex = 0;
|
||||
for(int i = 0; i < MAX_SPELL_EFFECTS; i++)
|
||||
{
|
||||
if(GoPoH->Effect[i] == SPELL_EFFECT_APPLY_AURA)
|
||||
{
|
||||
EffIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int32 tickcount = GetSpellMaxDuration(GoPoH) / GoPoH->EffectAmplitude[EffIndex];
|
||||
if(!tickcount)
|
||||
return false;
|
||||
|
||||
basepoints0 = damage * triggerAmount / tickcount / 100;
|
||||
break;
|
||||
}
|
||||
// Improved Shadowform
|
||||
case 47570:
|
||||
case 47569:
|
||||
@@ -6750,6 +6827,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig
|
||||
|
||||
// Set trigger spell id, target, custom basepoints
|
||||
uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
|
||||
if(procSpell && procSpell->Id == trigger_spell_id)
|
||||
return false;
|
||||
|
||||
Unit* target = NULL;
|
||||
int32 basepoints0 = 0;
|
||||
|
||||
@@ -9918,7 +9998,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
|
||||
((Creature*)this)->SetHomePosition(GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
|
||||
if(enemy)
|
||||
{
|
||||
if(!((Creature*)this)->HasReactState(REACT_PASSIVE) && ((Creature*)this)->IsAIEnabled)
|
||||
if(((Creature*)this)->IsAIEnabled)
|
||||
((Creature*)this)->AI()->EnterCombat(enemy);
|
||||
if(((Creature*)this)->GetFormation())
|
||||
((Creature*)this)->GetFormation()->MemberAttackStart((Creature*)this, enemy);
|
||||
@@ -11579,11 +11659,14 @@ void CharmInfo::InitPossessCreateSpells()
|
||||
{
|
||||
for(uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
|
||||
{
|
||||
uint32 spellid = ((Creature*)m_unit)->m_spells[i];
|
||||
if(IsPassiveSpell(spellid))
|
||||
m_unit->CastSpell(m_unit, spellid, true);
|
||||
uint32 spellId = ((Creature*)m_unit)->m_spells[i];
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
|
||||
if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
|
||||
spellId = 0;
|
||||
if(IsPassiveSpell(spellId))
|
||||
m_unit->CastSpell(m_unit, spellId, true);
|
||||
else
|
||||
AddSpellToAB(0, spellid, ACT_DISABLED);
|
||||
AddSpellToAB(0, spellId, ACT_DISABLED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11601,6 +11684,10 @@ void CharmInfo::InitCharmCreateSpells()
|
||||
for(uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
|
||||
{
|
||||
uint32 spellId = ((Creature*)m_unit)->m_spells[x];
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
|
||||
if(spellInfo && spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
|
||||
spellId = 0;
|
||||
|
||||
m_charmspells[x].spellId = spellId;
|
||||
|
||||
if(!spellId)
|
||||
@@ -11615,7 +11702,6 @@ void CharmInfo::InitCharmCreateSpells()
|
||||
{
|
||||
ActiveStates newstate;
|
||||
bool onlyselfcast = true;
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
|
||||
|
||||
if(!spellInfo) onlyselfcast = false;
|
||||
for(uint32 i = 0;i<3 && onlyselfcast;++i) //non existent spell will not make any problems as onlyselfcast would be false -> break right away
|
||||
@@ -11925,6 +12011,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
|
||||
SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask);
|
||||
uint32 damage = SpellDamageBonus(pTarget, spellInfo, triggeredByAura->GetAmount(), SPELL_DIRECT_DAMAGE);
|
||||
CalculateSpellDamageTaken(&damageInfo, damage, spellInfo);
|
||||
DealDamageMods(damageInfo.target,damageInfo.damage,&damageInfo.absorb);
|
||||
SendSpellNonMeleeDamageLog(&damageInfo);
|
||||
DealSpellDamage(&damageInfo, true);
|
||||
break;
|
||||
@@ -12166,6 +12253,13 @@ void Unit::StopMoving()
|
||||
SendMessageToSet(&data,false);
|
||||
}
|
||||
|
||||
void Unit::SendMovementFlagUpdate()
|
||||
{
|
||||
WorldPacket data;
|
||||
BuildHeartBeatMsg(&data);
|
||||
SendMessageToSet(&data, false);
|
||||
}
|
||||
|
||||
/*
|
||||
void Unit::SetFeared(bool apply, uint64 casterGUID, uint32 spellID)
|
||||
{
|
||||
@@ -13574,16 +13668,14 @@ void Unit::AddAura(uint32 spellId, Unit* target)
|
||||
target->AddAura(Aur);
|
||||
}
|
||||
|
||||
Aura * Unit::AddAuraEffect(uint32 spellId, uint8 effIndex, Unit* caster, int32 * basePoints)
|
||||
Aura * Unit::AddAuraEffect(const SpellEntry * spellInfo, uint8 effIndex, Unit* caster, int32 * basePoints)
|
||||
{
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId);
|
||||
if(!spellInfo || !caster)
|
||||
return NULL;
|
||||
|
||||
// can't do that for passive auras - they stack from same caster so there is no way to get exact aura which should get effect
|
||||
//assert (!IsPassiveSpell(spellInfo));
|
||||
|
||||
Aura * aur = GetAura(spellId, caster->GetGUID());
|
||||
sLog.outDebug("AddAuraEffect: spell id: %u, effect index: %u", spellInfo->Id, (uint32)effIndex);
|
||||
|
||||
Aura *aur = GetAura(spellInfo->Id, caster->GetGUID());
|
||||
|
||||
if (aur)
|
||||
{
|
||||
@@ -13600,10 +13692,10 @@ Aura * Unit::AddAuraEffect(uint32 spellId, uint8 effIndex, Unit* caster, int32 *
|
||||
aur = new Aura(spellInfo, 1<<effIndex, amount, this ,caster);
|
||||
}
|
||||
else
|
||||
{
|
||||
aur = new Aura(spellInfo, 1<<effIndex, NULL, this ,caster);
|
||||
}
|
||||
AddAura(aur);
|
||||
|
||||
if(!AddAura(aur))
|
||||
return NULL;
|
||||
}
|
||||
return aur;
|
||||
}
|
||||
@@ -13901,7 +13993,7 @@ void Unit::NearTeleportTo( float x, float y, float z, float orientation, bool ca
|
||||
DestroyForNearbyPlayers();
|
||||
|
||||
GetMap()->CreatureRelocation((Creature*)this, x, y, z, orientation);
|
||||
ObjectAccessor::UpdateObjectVisibility(this);
|
||||
//ObjectAccessor::UpdateObjectVisibility(this);
|
||||
|
||||
//WorldPacket data;
|
||||
// Work strange for many spells: triggered active mover set for targeted player to creature
|
||||
|
||||
+25
-22
@@ -745,24 +745,25 @@ struct CalcDamageInfo
|
||||
|
||||
// Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode
|
||||
struct SpellNonMeleeDamage{
|
||||
SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask)
|
||||
: target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), schoolMask(_schoolMask),
|
||||
absorb(0), resist(0), phusicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0)
|
||||
{}
|
||||
SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask)
|
||||
: target(_target), attacker(_attacker), SpellID(_SpellID), damage(0), overkill(0), schoolMask(_schoolMask),
|
||||
absorb(0), resist(0), physicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0)
|
||||
{}
|
||||
|
||||
Unit *target;
|
||||
Unit *attacker;
|
||||
uint32 SpellID;
|
||||
uint32 damage;
|
||||
uint32 schoolMask;
|
||||
uint32 absorb;
|
||||
uint32 resist;
|
||||
bool phusicalLog;
|
||||
bool unused;
|
||||
uint32 blocked;
|
||||
uint32 HitInfo;
|
||||
// Used for help
|
||||
uint32 cleanDamage;
|
||||
Unit *target;
|
||||
Unit *attacker;
|
||||
uint32 SpellID;
|
||||
uint32 damage;
|
||||
uint32 overkill;
|
||||
uint32 schoolMask;
|
||||
uint32 absorb;
|
||||
uint32 resist;
|
||||
bool physicalLog;
|
||||
bool unused;
|
||||
uint32 blocked;
|
||||
uint32 HitInfo;
|
||||
// Used for help
|
||||
uint32 cleanDamage;
|
||||
};
|
||||
|
||||
uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition);
|
||||
@@ -939,8 +940,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
void SetCanDualWield(bool value) { m_canDualWield = value; }
|
||||
float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; }
|
||||
float GetMeleeReach() const { float reach = m_floatValues[UNIT_FIELD_COMBATREACH]; return reach > MIN_MELEE_REACH ? reach : MIN_MELEE_REACH; }
|
||||
bool IsWithinCombatRange(Unit *obj, float dist2compare) const;
|
||||
bool IsWithinMeleeRange(Unit *obj, float dist = MELEE_RANGE) const;
|
||||
bool IsWithinCombatRange(const Unit *obj, float dist2compare) const;
|
||||
bool IsWithinMeleeRange(const Unit *obj, float dist = MELEE_RANGE) const;
|
||||
void GetRandomContactPoint( const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax ) const;
|
||||
uint32 m_extraAttacks;
|
||||
bool m_canDualWield;
|
||||
@@ -1072,6 +1073,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
|
||||
uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
|
||||
void RemoveSpellbyDamageTaken(uint32 damage, uint32 spell);
|
||||
void DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb);
|
||||
uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage = NULL, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *spellProto = NULL, bool durabilityLoss = true);
|
||||
void Kill(Unit *pVictim, bool durabilityLoss = true);
|
||||
int32 DealHeal(Unit *pVictim, uint32 addhealth, SpellEntry const *spellProto, bool critical = false);
|
||||
@@ -1186,7 +1188,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
void CastSpell(GameObject *go, uint32 spellId, bool triggered, Item *castItem = NULL, AuraEffect* triggeredByAura = NULL, uint64 originalCaster = 0);
|
||||
void AddAura(uint32 spellId, Unit *target);
|
||||
void HandleAuraEffect(AuraEffect * aureff, bool apply);
|
||||
Aura *AddAuraEffect(uint32 spellId, uint8 effIndex, Unit* caster, int32 * basePoints=NULL);
|
||||
Aura *AddAuraEffect(const SpellEntry * spellInfo, uint8 effIndex, Unit* caster, int32 * basePoints=NULL);
|
||||
|
||||
bool IsDamageToThreatSpell(SpellEntry const * spellInfo) const;
|
||||
|
||||
@@ -1212,6 +1214,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
void SendMonsterMoveByPath(Path const& path, uint32 start, uint32 end);
|
||||
void SendMonsterMoveWithSpeed(float x, float y, float z, uint32 transitTime = 0, Player* player = NULL);
|
||||
void SendMonsterMoveWithSpeedToCurrentDestination(Player* player = NULL);
|
||||
void SendMovementFlagUpdate();
|
||||
|
||||
bool isAlive() const { return (m_deathState == ALIVE); };
|
||||
bool isDead() const { return ( m_deathState == DEAD || m_deathState == CORPSE ); };
|
||||
@@ -1400,9 +1403,9 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
|
||||
float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const;
|
||||
void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; }
|
||||
|
||||
bool isInFront(Unit const* target,float distance, float arc = M_PI) const;
|
||||
bool isInFrontInMap(Unit const* target,float distance, float arc = M_PI) const;
|
||||
void SetInFront(Unit const* target);
|
||||
bool isInBack(Unit const* target, float distance, float arc = M_PI) const;
|
||||
bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const;
|
||||
bool isInLine(Unit const* target, float distance) const;
|
||||
|
||||
// Visibility system
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "UnitAI.h"
|
||||
#include "Player.h"
|
||||
#include "Creature.h"
|
||||
#include "SpellAuras.h"
|
||||
|
||||
void UnitAI::AttackStart(Unit *victim)
|
||||
{
|
||||
if(!victim)
|
||||
return;
|
||||
|
||||
if(me->Attack(victim, true))
|
||||
{
|
||||
//DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", me->GetName(), victim->GetGUIDLow());
|
||||
me->GetMotionMaster()->MoveChase(victim);
|
||||
}
|
||||
}
|
||||
|
||||
void UnitAI::DoMeleeAttackIfReady()
|
||||
{
|
||||
if(me->hasUnitState(UNIT_STAT_CASTING))
|
||||
return;
|
||||
|
||||
//Make sure our attack is ready and we aren't currently casting before checking distance
|
||||
if (me->isAttackReady())
|
||||
{
|
||||
//If we are within range melee the target
|
||||
if (me->IsWithinMeleeRange(me->getVictim()))
|
||||
{
|
||||
me->AttackerStateUpdate(me->getVictim());
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
}
|
||||
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
|
||||
{
|
||||
//If we are within range melee the target
|
||||
if (me->IsWithinMeleeRange(me->getVictim()))
|
||||
{
|
||||
me->AttackerStateUpdate(me->getVictim(), OFF_ATTACK);
|
||||
me->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Enable PlayerAI when charmed
|
||||
void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; }
|
||||
|
||||
void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
|
||||
{
|
||||
Creature *charmer = (Creature*)me->GetCharmer();
|
||||
|
||||
//kill self if charm aura has infinite duration
|
||||
if(charmer->IsInEvadeMode())
|
||||
{
|
||||
Unit::AuraEffectList const& auras = me->GetAurasByType(SPELL_AURA_MOD_CHARM);
|
||||
for(Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
|
||||
if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetParentAura()->IsPermanent())
|
||||
{
|
||||
charmer->Kill(me);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!charmer->isInCombat())
|
||||
me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
|
||||
|
||||
Unit *target = me->getVictim();
|
||||
if(!target || !charmer->canAttack(target))
|
||||
AttackStart(charmer->SelectNearestTarget());
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*
|
||||
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_UNITAI_H
|
||||
#define TRINITY_UNITAI_H
|
||||
|
||||
#include "Platform/Define.h"
|
||||
|
||||
class Unit;
|
||||
class Player;
|
||||
|
||||
class TRINITY_DLL_SPEC UnitAI
|
||||
{
|
||||
protected:
|
||||
Unit * const me;
|
||||
public:
|
||||
explicit UnitAI(Unit *u) : me(u) {}
|
||||
virtual void AttackStart(Unit *);
|
||||
virtual void UpdateAI(const uint32 diff) = 0;
|
||||
|
||||
virtual void InitializeAI() { Reset(); }
|
||||
|
||||
virtual void Reset() {};
|
||||
|
||||
// Called when unit is charmed
|
||||
virtual void OnCharmed(bool apply) = 0;
|
||||
|
||||
// Pass parameters between AI
|
||||
virtual void DoAction(const int32 param) {}
|
||||
|
||||
//Do melee swing of current victim if in rnage and ready and not casting
|
||||
void DoMeleeAttackIfReady();
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC PlayerAI : public UnitAI
|
||||
{
|
||||
protected:
|
||||
Player* const me;
|
||||
public:
|
||||
explicit PlayerAI(Player *p) : UnitAI((Unit*)p), me(p) {}
|
||||
|
||||
void OnCharmed(bool apply);
|
||||
};
|
||||
|
||||
class TRINITY_DLL_SPEC SimpleCharmedAI : public PlayerAI
|
||||
{
|
||||
public:
|
||||
void UpdateAI(const uint32 diff);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -24,12 +24,12 @@
|
||||
#include "ProgressBar.h"
|
||||
#include "MapManager.h"
|
||||
|
||||
UNORDERED_MAP<uint32, WaypointPath*> waypoint_map;
|
||||
WaypointPathMap WaypointPathHolder;
|
||||
WaypointStore WaypointMgr;
|
||||
|
||||
void WaypointStore::Free()
|
||||
{
|
||||
waypoint_map.clear();
|
||||
WaypointPathHolder.clear();
|
||||
}
|
||||
|
||||
void WaypointStore::Load()
|
||||
@@ -37,7 +37,7 @@ void WaypointStore::Load()
|
||||
QueryResult *result = WorldDatabase.PQuery("SELECT MAX(`id`) FROM `waypoint_data`");
|
||||
if(!result)
|
||||
{
|
||||
sLog.outError(" an error occured while loading the table `waypoint_data` ( maybe it doesn't exist ?)\n");
|
||||
sLog.outError("an error occured while loading the table `waypoint_data` (maybe it doesn't exist ?)");
|
||||
exit(1); // Stop server at loading non exited table or not accessable table
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ void WaypointStore::Load()
|
||||
result = WorldDatabase.PQuery("SELECT `id`,`point`,`position_x`,`position_y`,`position_z`,`move_flag`,`delay`,`action`,`action_chance` FROM `waypoint_data` ORDER BY `id`, `point`");
|
||||
if(!result)
|
||||
{
|
||||
sLog.outErrorDb("The table `creature_addon` is empty or corrupted");
|
||||
sLog.outErrorDb("The table `waypoint_data` is empty or corrupted");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,22 +87,21 @@ void WaypointStore::Load()
|
||||
|
||||
path_data->push_back(wp);
|
||||
|
||||
if(id != last_id)
|
||||
waypoint_map[id] = path_data;
|
||||
if(id != last_id)
|
||||
WaypointPathHolder[id] = path_data;
|
||||
|
||||
last_id = id;
|
||||
|
||||
} while(result->NextRow()) ;
|
||||
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
void WaypointStore::UpdatePath(uint32 id)
|
||||
{
|
||||
|
||||
if(waypoint_map.find(id)!= waypoint_map.end())
|
||||
waypoint_map[id]->clear();
|
||||
// TODO: this will cause memory leak
|
||||
if(WaypointPathHolder.find(id) != WaypointPathHolder.end())
|
||||
WaypointPathHolder[id]->clear();
|
||||
|
||||
QueryResult *result;
|
||||
|
||||
@@ -145,7 +144,7 @@ void WaypointStore::UpdatePath(uint32 id)
|
||||
|
||||
}while (result->NextRow());
|
||||
|
||||
waypoint_map[id] = path_data;
|
||||
WaypointPathHolder[id] = path_data;
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,9 @@ struct WaypointData
|
||||
};
|
||||
|
||||
typedef std::vector<WaypointData*> WaypointPath;
|
||||
extern UNORDERED_MAP<uint32, WaypointPath*> waypoint_map;
|
||||
typedef UNORDERED_MAP<uint32, WaypointPath*> WaypointPathMap;
|
||||
|
||||
extern WaypointPathMap WaypointPathHolder;
|
||||
|
||||
class WaypointStore
|
||||
{
|
||||
@@ -48,9 +50,10 @@ class WaypointStore
|
||||
|
||||
WaypointPath* GetPath(uint32 id)
|
||||
{
|
||||
if(waypoint_map.find(id) != waypoint_map.end())
|
||||
return waypoint_map[id];
|
||||
else return 0;
|
||||
WaypointPathMap::iterator itr = WaypointPathHolder.find(id);
|
||||
if(itr != WaypointPathHolder.end())
|
||||
return itr->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline uint32 GetRecordsCount() { return records; }
|
||||
|
||||
@@ -100,7 +100,7 @@ WaypointMovementGenerator<Creature>::Initialize(Creature &u)
|
||||
//i_nextMoveTime.Reset(0);
|
||||
StopedByPlayer = false;
|
||||
if(!path_id)
|
||||
path_id = u.GetWaypointPath();
|
||||
path_id = u.GetWaypointPathId();
|
||||
waypoints = WaypointMgr.GetPath(path_id);
|
||||
i_currentNode = 0;
|
||||
if(waypoints && waypoints->size())
|
||||
@@ -226,7 +226,7 @@ template bool WaypointMovementGenerator<Player>::Update(Player &, const uint32 &
|
||||
template void WaypointMovementGenerator<Player>::MovementInform(Player &);
|
||||
|
||||
//----------------------------------------------------//
|
||||
void FlightPathMovementGenerator::LoadPath(Player &)
|
||||
void FlightPathMovementGenerator::SetWaypointPathId(Player &)
|
||||
{
|
||||
objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds);
|
||||
}
|
||||
@@ -251,7 +251,8 @@ void FlightPathMovementGenerator::Initialize(Player &player)
|
||||
player.getHostilRefManager().setOnlineOfflineState(false);
|
||||
player.addUnitState(UNIT_STAT_IN_FLIGHT);
|
||||
player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
|
||||
LoadPath(player);
|
||||
player.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
|
||||
SetWaypointPathId(player);
|
||||
Traveller<Player> traveller(player);
|
||||
// do not send movement, it was sent already
|
||||
i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
|
||||
@@ -270,6 +271,7 @@ void FlightPathMovementGenerator::Finalize(Player & player)
|
||||
|
||||
player.Unmount();
|
||||
player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
|
||||
player.RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING2);
|
||||
|
||||
if(player.m_taxi.empty())
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ class TRINITY_DLL_SPEC PathMovementBase
|
||||
|
||||
bool MovementInProgress(void) const { return i_currentNode < i_path.Size(); }
|
||||
|
||||
void LoadPath(T &);
|
||||
void SetWaypointPathId(T &);
|
||||
void ReloadPath(T &);
|
||||
uint32 GetCurrentNode() const { return i_currentNode; }
|
||||
|
||||
@@ -104,7 +104,7 @@ public PathMovementBase<Player>
|
||||
bool Update(Player &, const uint32 &);
|
||||
MovementGeneratorType GetMovementGeneratorType() { return FLIGHT_MOTION_TYPE; }
|
||||
|
||||
void LoadPath(Player &);
|
||||
void SetWaypointPathId(Player &);
|
||||
void ReloadPath(Player &) { /* don't reload flight path */ }
|
||||
|
||||
Path& GetPath() { return i_path; }
|
||||
|
||||
+3
-1
@@ -792,7 +792,9 @@ void World::LoadConfigSettings(bool reload)
|
||||
m_configs[CONFIG_GM_IN_GM_LIST] = sConfig.GetBoolDefault("GM.InGMList", false);
|
||||
m_configs[CONFIG_GM_IN_WHO_LIST] = sConfig.GetBoolDefault("GM.InWhoList", false);
|
||||
m_configs[CONFIG_GM_LOG_TRADE] = sConfig.GetBoolDefault("GM.LogTrade", false);
|
||||
m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1);
|
||||
m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1);
|
||||
m_configs[CONFIG_ALLOW_GM_GROUP] = sConfig.GetBoolDefault("GM.AllowInvite", false);
|
||||
m_configs[CONFIG_ALLOW_GM_FRIEND] = sConfig.GetBoolDefault("GM.AllowFriend", false);
|
||||
if(m_configs[CONFIG_START_GM_LEVEL] < m_configs[CONFIG_START_PLAYER_LEVEL])
|
||||
{
|
||||
sLog.outError("GM.StartLevel (%i) must be in range StartPlayerLevel(%u)..%u. Set to %u.",
|
||||
|
||||
+4
-2
@@ -141,6 +141,8 @@ enum WorldConfigs
|
||||
CONFIG_GM_IN_GM_LIST,
|
||||
CONFIG_GM_IN_WHO_LIST,
|
||||
CONFIG_GM_LOG_TRADE,
|
||||
CONFIG_ALLOW_GM_GROUP,
|
||||
CONFIG_ALLOW_GM_FRIEND,
|
||||
CONFIG_START_GM_LEVEL,
|
||||
CONFIG_GM_LOWER_SECURITY,
|
||||
CONFIG_GM_ALLOW_ACHIEVEMENT_GAINS,
|
||||
@@ -626,7 +628,7 @@ class World
|
||||
static float m_VisibleObjectGreyDistance;
|
||||
|
||||
// CLI command holder to be thread safe
|
||||
ZThread::LockedQueue<CliCommandHolder*, ZThread::FastMutex> cliCmdQueue;
|
||||
ACE_Based::LockedQueue<CliCommandHolder*,ACE_Thread_Mutex> cliCmdQueue;
|
||||
SqlResultQueue *m_resultQueue;
|
||||
|
||||
// next daily quests reset time
|
||||
@@ -637,7 +639,7 @@ class World
|
||||
|
||||
//sessions that are added async
|
||||
void AddSession_(WorldSession* s);
|
||||
ZThread::LockedQueue<WorldSession*, ZThread::FastMutex> addSessQueue;
|
||||
ACE_Based::LockedQueue<WorldSession*, ACE_Thread_Mutex> addSessQueue;
|
||||
|
||||
//used versions
|
||||
std::string m_DBVersion;
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#include "Config/ConfigEnv.h"
|
||||
#include "Log.h"
|
||||
|
||||
#define CLASS_LOCK Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex>
|
||||
#define CLASS_LOCK MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex>
|
||||
INSTANTIATE_SINGLETON_2(WorldLog, CLASS_LOCK);
|
||||
INSTANTIATE_CLASS_MUTEX(WorldLog, ZThread::FastMutex);
|
||||
INSTANTIATE_CLASS_MUTEX(WorldLog, ACE_Thread_Mutex);
|
||||
|
||||
#define WORLD_LOG_FILE_STRING "world.log"
|
||||
|
||||
|
||||
+2
-2
@@ -32,13 +32,13 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
/// %Log packets to a file
|
||||
class TRINITY_DLL_DECL WorldLog : public Trinity::Singleton<WorldLog, Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex> >
|
||||
class MANGOS_DLL_DECL WorldLog : public MaNGOS::Singleton<WorldLog, MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex> >
|
||||
{
|
||||
friend class Trinity::OperatorNew<WorldLog>;
|
||||
WorldLog();
|
||||
WorldLog(const WorldLog &);
|
||||
WorldLog& operator=(const WorldLog &);
|
||||
typedef Trinity::ClassLevelLockable<WorldLog, ZThread::FastMutex>::Lock Guard;
|
||||
typedef MaNGOS::ClassLevelLockable<WorldLog, ACE_Thread_Mutex>::Lock Guard;
|
||||
|
||||
/// Close the file in destructor
|
||||
~WorldLog();
|
||||
|
||||
@@ -719,8 +719,7 @@ class TRINITY_DLL_SPEC WorldSession
|
||||
uint32 m_latency;
|
||||
AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES];
|
||||
AddonsList m_addonsList;
|
||||
|
||||
ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> _recvQueue;
|
||||
ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue;
|
||||
};
|
||||
#endif
|
||||
/// @}
|
||||
|
||||
Reference in New Issue
Block a user