*Merge some fixes from tc1

--HG--
branch : trunk
This commit is contained in:
QAston
2009-05-15 18:00:50 +02:00
416 changed files with 12806 additions and 5768 deletions
+28 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
+3 -1
View File
@@ -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);
+3 -2
View File
@@ -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
+4 -3
View File
@@ -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
+3
View File
@@ -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 }
};
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+53
View File
@@ -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
View File
@@ -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
+3 -3
View File
@@ -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();
+13 -1
View File
@@ -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)
{
+5 -16
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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";
+2 -2
View File
@@ -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
View File
@@ -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:
+7 -2
View File
@@ -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
View File
@@ -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();
+6
View File
@@ -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())
{
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+6 -4
View File
@@ -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);
}
}
+2 -2
View File
@@ -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:
+2 -42
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2 -2
View File
@@ -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
+3 -3
View File
@@ -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
View File
@@ -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;
+1 -9
View File
@@ -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;
}
}
+13 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+3 -3
View File
@@ -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
+6 -6
View File
@@ -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 &);
+8 -1
View File
@@ -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;
+1 -1
View File
@@ -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 );
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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 );
+1 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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);
-20
View File
@@ -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
*/
-25
View File
@@ -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
+18 -4
View File
@@ -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);
+5 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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());
}
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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()
+4 -3
View File
@@ -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);
}
+4 -4
View File
@@ -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();
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+89
View File
@@ -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());
}
+68
View File
@@ -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
+10 -11
View File
@@ -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;
}
+7 -4
View File
@@ -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; }
+5 -3
View File
@@ -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())
{
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2 -2
View File
@@ -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
View File
@@ -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();
+1 -2
View File
@@ -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
/// @}