aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp4
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp54
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp3
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h12
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp20
-rw-r--r--src/server/game/Accounts/AccountMgr.h4
-rw-r--r--src/server/game/Accounts/RBAC.cpp5
-rw-r--r--src/server/game/Accounts/RBAC.h2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp26
-rw-r--r--src/server/game/Entities/Creature/Creature.h17
-rw-r--r--src/server/game/Entities/Player/Player.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.h7
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp95
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rw-r--r--[-rwxr-xr-x]src/server/game/Entities/Vehicle/Vehicle.cpp547
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.h37
-rw-r--r--src/server/game/Events/GameEventMgr.cpp34
-rw-r--r--src/server/game/Events/GameEventMgr.h4
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp82
-rw-r--r--src/server/game/Globals/ObjectMgr.h2
-rw-r--r--src/server/game/Groups/Group.cpp2
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp3
-rw-r--r--src/server/game/Miscellaneous/Language.h3
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp5
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp162
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.cpp6
-rw-r--r--src/server/game/Spells/SpellInfo.h1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp13
-rw-r--r--src/server/game/Weather/Weather.cpp3
-rw-r--r--src/server/game/Weather/Weather.h2
-rw-r--r--src/server/game/World/World.cpp8
-rw-r--r--src/server/game/World/World.h2
33 files changed, 761 insertions, 410 deletions
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 23620bf1174..7cee0e20dd5 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -370,9 +370,7 @@ void ScriptedAI::SetEquipmentSlots(bool loadDefault, int32 mainHand /*= EQUIP_NO
{
if (loadDefault)
{
- if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(me->GetEntry()))
- me->LoadEquipment(creatureInfo->equipmentId, true);
-
+ me->LoadEquipment(me->GetOriginalEquipmentId(), true);
return;
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index e37b9e777d8..bc94169687c 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1459,15 +1459,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (Creature* npc = (*itr)->ToCreature())
{
uint32 slot[3];
- if (e.action.equip.entry)
+ int8 equipId = (int8)e.action.equip.entry;
+ if (equipId)
{
- EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(e.action.equip.entry);
+ EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(npc->GetEntry(), equipId);
if (!einfo)
{
- sLog->outError(LOG_FILTER_SQL, "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info entry %u", e.action.equip.entry);
+ sLog->outError(LOG_FILTER_SQL, "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature %u", equipId, npc->GetEntry());
return;
}
- npc->SetCurrentEquipmentId(e.action.equip.entry);
+ npc->SetCurrentEquipmentId(equipId);
slot[0] = einfo->ItemEntry[0];
slot[1] = einfo->ItemEntry[1];
slot[2] = einfo->ItemEntry[2];
@@ -1478,11 +1479,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
slot[1] = e.action.equip.slot2;
slot[2] = e.action.equip.slot3;
}
- if (!e.action.equip.mask || e.action.equip.mask & 1)
+ if (!e.action.equip.mask || (e.action.equip.mask & 1))
npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, slot[0]);
- if (!e.action.equip.mask || e.action.equip.mask & 2)
+ if (!e.action.equip.mask || (e.action.equip.mask & 2))
npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, slot[1]);
- if (!e.action.equip.mask || e.action.equip.mask & 4)
+ if (!e.action.equip.mask || (e.action.equip.mask & 4))
npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, slot[2]);
}
}
@@ -2028,6 +2029,45 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
delete targets;
break;
}
+ case SMART_ACTION_SET_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->SetUInt32Value(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
+ case SMART_ACTION_ADD_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->SetFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
+ case SMART_ACTION_REMOVE_GO_FLAG:
+ {
+ ObjectList* targets = GetTargets(e, unit);
+ if (!targets)
+ break;
+
+ for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
+ if (IsGameObject(*itr))
+ (*itr)->ToGameObject()->RemoveFlag(GAMEOBJECT_FLAGS, e.action.goFlag.flag);
+
+ delete targets;
+ break;
+ }
default:
sLog->outError(LOG_FILTER_SQL, "SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index 69902954fde..679d2d87ffc 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -907,6 +907,9 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_SET_HOME_POS:
case SMART_ACTION_SET_HEALTH_REGEN:
case SMART_ACTION_SET_ROOT:
+ case SMART_ACTION_SET_GO_FLAG:
+ case SMART_ACTION_ADD_GO_FLAG:
+ case SMART_ACTION_REMOVE_GO_FLAG:
break;
default:
sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index a3420071f5e..f117ab52e01 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -427,7 +427,6 @@ enum SMART_ACTION
SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue(+pct, -flat)
SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to dismount)
SMART_ACTION_SET_INGAME_PHASE_MASK = 44, // mask
-
SMART_ACTION_SET_DATA = 45, // Field, Data (only creature TODO)
SMART_ACTION_MOVE_FORWARD = 46, // distance
SMART_ACTION_SET_VISIBILITY = 47, // on/off
@@ -450,7 +449,6 @@ enum SMART_ACTION
SMART_ACTION_STORE_TARGET_LIST = 64, // varID,
SMART_ACTION_WP_RESUME = 65, // none
SMART_ACTION_SET_ORIENTATION = 66, //
-
SMART_ACTION_CREATE_TIMED_EVENT = 67, // id, InitialMin, InitialMax, RepeatMin(only if it repeats), RepeatMax(only if it repeats), chance
SMART_ACTION_PLAYMOVIE = 68, // entry
SMART_ACTION_MOVE_TO_POS = 69, // PointId, xyz
@@ -488,8 +486,11 @@ enum SMART_ACTION
SMART_ACTION_SET_HOME_POS = 101, // none
SMART_ACTION_SET_HEALTH_REGEN = 102, // 0/1
SMART_ACTION_SET_ROOT = 103, // off/on
+ SMART_ACTION_SET_GO_FLAG = 104, // Flags
+ SMART_ACTION_ADD_GO_FLAG = 105, // Flags
+ SMART_ACTION_REMOVE_GO_FLAG = 106, // Flags
- SMART_ACTION_END = 104
+ SMART_ACTION_END = 107
};
struct SmartAction
@@ -926,6 +927,11 @@ struct SmartAction
uint32 root;
} setRoot;
+ struct
+ {
+ uint32 flag;
+ } goFlag;
+
//! Note for any new future actions
//! All parameters must have type uint32
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index b1d0087c32c..bd560c8266e 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
@@ -56,7 +56,7 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
RBACData* rbac = new RBACData(GetId(username), username, -1);
// No need to Load From DB, as it's new data
- RBACGroupContainer const& groupsToAdd = _defaultGroups[0]; // 0: Default sec level
+ RBACGroupContainer const& groupsToAdd = _defaultSecGroups[0]; // 0: Default sec level
for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it)
rbac->AddGroup(*it, -1);
@@ -426,13 +426,23 @@ void AccountMgr::LoadRBAC()
uint8 secId = field[0].GetUInt8();
if (lastSecId != secId)
- groups = &_defaultGroups[secId];
+ groups = &_defaultSecGroups[secId];
groups->insert(field[1].GetUInt32());
}
while (result->NextRow());
sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u permission definitions, %u role definitions and %u group definitions in %u ms", count1, count2, count3, GetMSTimeDiffToNow(oldMSTime));
+
+ // Load default groups to be added to any RBAC Object.
+ std::string defaultGroups = ConfigMgr::GetStringDefault("RBAC.DefaultGroups", "");
+ Tokenizer tokens(defaultGroups, ',');
+ for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
+ if (uint32 groupId = atoi(*itr))
+ {
+ sLog->outError(LOG_FILTER_LFG, "Adding default group %u", groupId);
+ _defaultGroups.insert(groupId);
+ }
}
void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 securityLevel, int32 realmId)
@@ -459,7 +469,7 @@ void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 sec
uint8 secLevel = field[0].GetUInt8();
int32 realmId = field[1].GetUInt32();
- RBACGroupContainer const& groupsToRemove = _defaultGroups[secLevel];
+ RBACGroupContainer const& groupsToRemove = _defaultSecGroups[secLevel];
for (RBACGroupContainer::const_iterator it = groupsToRemove.begin(); it != groupsToRemove.end(); ++it)
rbac->RemoveGroup(*it, realmId);
}
@@ -467,7 +477,7 @@ void AccountMgr::UpdateAccountAccess(RBACData* rbac, uint32 accountId, uint8 sec
}
// Add new groups depending on the new security Level
- RBACGroupContainer const& groupsToAdd = _defaultGroups[securityLevel];
+ RBACGroupContainer const& groupsToAdd = _defaultSecGroups[securityLevel];
for (RBACGroupContainer::const_iterator it = groupsToAdd.begin(); it != groupsToAdd.end(); ++it)
rbac->AddGroup(*it, realmId);
diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h
index 90c533ca5fa..440e012f1fc 100644
--- a/src/server/game/Accounts/AccountMgr.h
+++ b/src/server/game/Accounts/AccountMgr.h
@@ -77,12 +77,14 @@ class AccountMgr
RBACGroupsContainer const& GetRBACGroupList() const { return _groups; }
RBACRolesContainer const& GetRBACRoleList() const { return _roles; }
RBACPermissionsContainer const& GetRBACPermissionList() const { return _permissions; }
+ RBACGroupContainer const& GetRBACDefaultGroups() const { return _defaultGroups; }
private:
RBACPermissionsContainer _permissions;
RBACRolesContainer _roles;
RBACGroupsContainer _groups;
- RBACDefaultSecurityGroupContainer _defaultGroups;
+ RBACDefaultSecurityGroupContainer _defaultSecGroups;
+ RBACGroupContainer _defaultGroups;
};
#define sAccountMgr ACE_Singleton<AccountMgr, ACE_Null_Mutex>::instance()
diff --git a/src/server/game/Accounts/RBAC.cpp b/src/server/game/Accounts/RBAC.cpp
index 4a069df05cd..121c9faae76 100644
--- a/src/server/game/Accounts/RBAC.cpp
+++ b/src/server/game/Accounts/RBAC.cpp
@@ -296,6 +296,11 @@ void RBACData::LoadFromDB()
while (result->NextRow());
}
+ // Add default groups
+ RBACGroupContainer const& groups = sAccountMgr->GetRBACDefaultGroups();
+ for (RBACGroupContainer::const_iterator itr = groups.begin(); itr != groups.end(); ++itr)
+ AddGroup(*itr);
+
// Force calculation of permissions, it wasn't performed at load time
// while adding groups, roles and permissions
CalculateNewPermissions();
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h
index d2c76b71801..f6e494e7b70 100644
--- a/src/server/game/Accounts/RBAC.h
+++ b/src/server/game/Accounts/RBAC.h
@@ -135,7 +135,7 @@ class RBACGroup: public RBACObject
RBACRoleContainer _roles; ///> Set of Roles
};
-/*
+/**
* @name RBACData
* @brief Contains all needed information about the acccount
*
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 97d414b9915..9cec59db168 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -145,7 +145,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapCreature(),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0),
m_PlayerDamageReq(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0),
m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE),
-m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(0), m_AlreadyCallAssistance(false),
+m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m_equipmentId(1), m_originalEquipmentId(1), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
m_creatureInfo(NULL), m_creatureData(NULL), m_path_id(0), m_formation(NULL)
{
@@ -323,8 +323,8 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data
// Load creature equipment
if (!data || data->equipmentId == 0) // use default from the template
- LoadEquipment(cinfo->equipmentId);
- else if (data && data->equipmentId != -1) // override, -1 means no equipment
+ LoadEquipment(GetOriginalEquipmentId());
+ else if (data && data->equipmentId != 0) // override, 0 means no equipment
LoadEquipment(data->equipmentId);
SetName(normalInfo->Name); // at normal entry always
@@ -1080,7 +1080,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
data.mapid = mapid;
data.phaseMask = phaseMask;
data.displayid = displayId;
- data.equipmentId = GetEquipmentId();
+ data.equipmentId = GetCurrentEquipmentId();
data.posX = GetPositionX();
data.posY = GetPositionY();
data.posZ = GetPositionZMinusOffset();
@@ -1115,7 +1115,7 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
stmt->setUInt8(index++, spawnMask);
stmt->setUInt16(index++, uint16(GetPhaseMask()));
stmt->setUInt32(index++, displayId);
- stmt->setInt32(index++, int32(GetEquipmentId()));
+ stmt->setInt32(index++, int32(GetCurrentEquipmentId()));
stmt->setFloat(index++, GetPositionX());
stmt->setFloat(index++, GetPositionY());
stmt->setFloat(index++, GetPositionZ());
@@ -1270,14 +1270,14 @@ bool Creature::CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint3
if (!vehId)
vehId = cinfo->VehicleId;
- if (vehId && !CreateVehicleKit(vehId, Entry))
- vehId = 0;
-
Object::_Create(guidlow, Entry, vehId ? HIGHGUID_VEHICLE : HIGHGUID_UNIT);
if (!UpdateEntry(Entry, team, data))
return false;
+ if (vehId && !CreateVehicleKit(vehId, Entry))
+ vehId = 0;
+
return true;
}
@@ -1355,24 +1355,24 @@ bool Creature::LoadCreatureFromDB(uint32 guid, Map* map, bool addToMap)
return true;
}
-void Creature::LoadEquipment(uint32 equip_entry, bool force)
+void Creature::LoadEquipment(int8 id, bool force /*= true*/)
{
- if (equip_entry == 0)
+ if (id == 0)
{
if (force)
{
- for (uint8 i = 0; i < 3; ++i)
+ for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0);
m_equipmentId = 0;
}
return;
}
- EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(equip_entry);
+ EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(GetEntry(), id);
if (!einfo)
return;
- m_equipmentId = equip_entry;
+ m_equipmentId = id;
for (uint8 i = 0; i < 3; ++i)
SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->ItemEntry[i]);
}
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 255014a7bbf..6e737709f99 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -138,7 +138,6 @@ struct CreatureTemplate
uint32 questItems[MAX_CREATURE_QUEST_ITEMS];
uint32 movementId;
bool RegenHealth;
- uint32 equipmentId;
uint32 MechanicImmuneMask;
uint32 flags_extra;
uint32 ScriptID;
@@ -234,7 +233,8 @@ struct EquipmentInfo
};
// Benchmarked: Faster than std::map (insert/find)
-typedef UNORDERED_MAP<uint16, EquipmentInfo> EquipmentInfoContainer;
+typedef UNORDERED_MAP<uint8, EquipmentInfo> EquipmentInfoContainerInternal;
+typedef UNORDERED_MAP<uint32, EquipmentInfoContainerInternal> EquipmentInfoContainer;
// from `creature` table
struct CreatureData
@@ -244,7 +244,7 @@ struct CreatureData
uint16 mapid;
uint16 phaseMask;
uint32 displayid;
- int32 equipmentId;
+ int8 equipmentId;
float posX;
float posY;
float posZ;
@@ -453,13 +453,12 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
bool Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint32 vehId, uint32 team, float x, float y, float z, float ang, const CreatureData* data = NULL);
bool LoadCreaturesAddon(bool reload = false);
void SelectLevel(const CreatureTemplate* cinfo);
- void LoadEquipment(uint32 equip_entry, bool force=false);
+ void LoadEquipment(int8 id = 1, bool force = false);
uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; }
void Update(uint32 time); // overwrited Unit::Update
void GetRespawnPosition(float &x, float &y, float &z, float* ori = NULL, float* dist =NULL) const;
- uint32 GetEquipmentId() const { return GetCreatureTemplate()->equipmentId; }
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
uint32 GetCorpseDelay() const { return m_corpseDelay; }
@@ -552,8 +551,11 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
void UpdateMaxPower(Powers power);
void UpdateAttackPowerAndDamage(bool ranged = false);
void UpdateDamagePhysical(WeaponAttackType attType);
+
+ uint8 GetOriginalEquipmentId() const { return m_originalEquipmentId; }
uint32 GetCurrentEquipmentId() { return m_equipmentId; }
- void SetCurrentEquipmentId(uint32 entry) { m_equipmentId = entry; }
+ void SetCurrentEquipmentId(uint8 id) { m_equipmentId = id; }
+
float GetSpellDamageMod(int32 Rank);
VendorItemData const* GetVendorItems() const;
@@ -748,7 +750,8 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature
void Regenerate(Powers power);
MovementGeneratorType m_defaultMovementType;
uint32 m_DBTableGuid; ///< For new or temporary creatures is 0 for saved it is lowguid
- uint32 m_equipmentId;
+ uint8 m_equipmentId;
+ uint8 m_originalEquipmentId;
bool m_AlreadyCallAssistance;
bool m_AlreadySearchedAssistance;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 19de01ffd41..d72b906e6a5 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -26027,7 +26027,7 @@ bool Player::AddItem(uint32 itemId, uint32 count)
ItemPosCountVec dest;
InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount);
if (msg != EQUIP_ERR_OK)
- count = noSpaceForCount;
+ count -= noSpaceForCount;
if (count == 0 || dest.empty())
{
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 9034c26d4f1..920e0357bc5 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -29,6 +29,8 @@
#include "QuestDef.h"
#include "SpellMgr.h"
#include "Unit.h"
+#include "Opcodes.h"
+#include "WorldSession.h"
#include <string>
#include <vector>
@@ -1813,6 +1815,11 @@ class Player : public Unit, public GridObject<Player>
return mMitems.erase(id) ? true : false;
}
+ void SendOnCancelExpectedVehicleRideAura()
+ {
+ WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
+ GetSession()->SendPacket(&data);
+ }
void PetSpellInitialize();
void CharmSpellInitialize();
void PossessSpellInitialize();
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index f7bc6a99fb1..d1f42de5749 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -2936,7 +2936,9 @@ void Unit::DeMorph()
Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, uint64 casterGUID /*= 0*/)
{
ASSERT(casterGUID || caster);
- if (!casterGUID)
+
+ // Check if these can stack anyway
+ if (!casterGUID && !newAura->IsStackableOnOneSlotWithDifferentCasters())
casterGUID = caster->GetGUID();
// passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
@@ -7585,48 +7587,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
return false;
break;
}
- // Shadow's Fate (Shadowmourne questline)
- case 71169:
- {
- // Victim needs more checks so bugs, rats or summons can not be affected by the proc.
- if (GetTypeId() != TYPEID_PLAYER || !victim || victim->GetTypeId() != TYPEID_UNIT || victim->GetCreatureType() == CREATURE_TYPE_CRITTER)
- return false;
-
- Player* player = ToPlayer();
- if (player->GetQuestStatus(24547) == QUEST_STATUS_INCOMPLETE)
- {
- break;
- }
- else if (player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_NORMAL || player->GetDifficulty(true) == RAID_DIFFICULTY_25MAN_HEROIC)
- {
- uint32 spellId = 0;
- uint32 questId = 0;
- switch (victim->GetEntry())
- {
- case 36678: // NPC: Professor Putricide
- questId = 24749; // Quest: Unholy Infusion
- spellId = 71516; // Spell: Shadow Infusion
- break;
- case 37955: // NPC: Blood-Queen Lana'thel
- questId = 24756; // Quest: Blood Infusion
- spellId = 72154; // Spell: Thirst Quenched
- break;
- case 36853: // NPC: Sindragosa
- questId = 24757; // Quest: Frost Infusion
- spellId = 72290; // Spell: Frost-Imbued Blade
- break;
- default:
- return false;
- }
-
- if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE || !player->HasAura(spellId))
- return false;
-
- break;
- }
- else
- return false;
- }
}
if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id))
@@ -10248,8 +10208,6 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
{
if (CreateVehicleKit(VehicleId, creatureEntry))
{
- GetVehicleKit()->Reset();
-
// Send others that we now have a vehicle
WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, GetPackGUID().size()+4);
data.appendPackGUID(GetGUID());
@@ -14823,7 +14781,10 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
// dismount players when charmed
if (GetTypeId() == TYPEID_PLAYER)
- Dismount();
+ RemoveAurasByType(SPELL_AURA_MOUNTED);
+
+ if (charmer->GetTypeId() == TYPEID_PLAYER)
+ charmer->RemoveAurasByType(SPELL_AURA_MOUNTED);
ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
ASSERT((type == CHARM_TYPE_VEHICLE) == IsVehicle());
@@ -16082,31 +16043,10 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a
{
if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->isInCombat())
return;
-
- InterruptNonMeleeSpells(false);
- player->StopCastingCharm();
- player->StopCastingBindSight();
- Dismount();
- RemoveAurasByType(SPELL_AURA_MOUNTED);
-
- // drop flag at invisible in bg
- if (Battleground* bg = player->GetBattleground())
- bg->EventPlayerDroppedFlag(player);
-
- WorldPacket data(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
- player->GetSession()->SendPacket(&data);
-
- player->UnsummonPetTemporaryIfAny();
}
ASSERT(!m_vehicle);
- m_vehicle = vehicle;
-
- if (!m_vehicle->AddPassenger(this, seatId))
- {
- m_vehicle = NULL;
- return;
- }
+ (void)vehicle->AddPassenger(this, seatId);
}
void Unit::ChangeSeat(int8 seatId, bool next)
@@ -16114,15 +16054,17 @@ void Unit::ChangeSeat(int8 seatId, bool next)
if (!m_vehicle)
return;
- if (seatId < 0)
- {
- seatId = m_vehicle->GetNextEmptySeat(GetTransSeat(), next);
- if (seatId < 0)
- return;
- }
- else if (seatId == GetTransSeat() || !m_vehicle->HasEmptySeat(seatId))
+ // Don't change if current and new seat are identical
+ if (seatId == GetTransSeat())
+ return;
+
+ SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId));
+ // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that.
+ if (seat == m_vehicle->Seats.end() || seat->second.Passenger)
return;
+ // Todo: the functions below could be consolidated and refactored to take
+ // SeatMap::const_iterator as parameter, to save redundant map lookups.
m_vehicle->RemovePassenger(this);
if (!m_vehicle->AddPassenger(this, seatId))
ASSERT(false);
@@ -16149,6 +16091,9 @@ void Unit::ExitVehicle(Position const* /*exitPosition*/)
void Unit::_ExitVehicle(Position const* exitPosition)
{
+ /// It's possible m_vehicle is NULL, when this function is called indirectly from @VehicleJoinEvent::Abort.
+ /// In that case it was not possible to add the passenger to the vehicle. The vehicle aura has already been removed
+ /// from the target in the aforementioned function and we don't need to do anything else at this point.
if (!m_vehicle)
return;
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index a8e088b2dd3..f9a0ca80f90 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -332,6 +332,7 @@ class UnitAI;
class Totem;
class Transport;
class Vehicle;
+class VehicleJoinEvent;
class TransportBase;
class SpellCastTargets;
@@ -2170,6 +2171,7 @@ class Unit : public WorldObject
uint32 GetRedirectThreatPercent() { return _redirectThreadInfo.GetThreatPct(); }
Unit* GetRedirectThreatTarget() { return _redirectThreadInfo.GetTargetGUID() ? GetUnit(*this, _redirectThreadInfo.GetTargetGUID()) : NULL; }
+ friend class VehicleJoinEvent;
bool IsAIEnabled, NeedChangeAI;
bool CreateVehicleKit(uint32 id, uint32 creatureEntry);
void RemoveVehicleKit();
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 16a90018293..02c5e4a2e1a 100755..100644
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -30,9 +30,12 @@
#include "SpellInfo.h"
#include "MoveSplineInit.h"
#include "TemporarySummon.h"
+#include "EventProcessor.h"
+#include "Player.h"
+#include "Battleground.h"
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) :
-_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE)
+UsableSeatNum(0), _me(unit), _vehicleInfo(vehInfo), _creatureEntry(creatureEntry), _status(STATUS_NONE)
{
for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i)
{
@@ -41,10 +44,16 @@ _me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntr
{
Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
if (veSeat->CanEnterOrExit())
- ++_usableSeatNum;
+ ++UsableSeatNum;
}
}
+ // Set or remove correct flags based on available seats. Will overwrite db data (if wrong).
+ if (UsableSeatNum)
+ _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
+ else
+ _me->RemoveFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
+
InitMovementInfoForBase();
}
@@ -56,6 +65,15 @@ Vehicle::~Vehicle()
ASSERT(!itr->second.Passenger);
}
+/**
+ * @fn void Vehicle::Install()
+ *
+ * @brief Initializes power type for vehicle. Nothing more.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::Install()
{
if (Creature* creature = _me->ToCreature())
@@ -114,15 +132,26 @@ void Vehicle::InstallAllAccessories(bool evading)
InstallAccessory(itr->AccessoryEntry, itr->SeatId, itr->IsMinion, itr->SummonedType, itr->SummonTime);
}
+/**
+ * @fn void Vehicle::Uninstall()
+ *
+ * @brief Removes all passengers and sets status to STATUS_UNINSTALLING.
+ * No new passengers can be added to the vehicle after this call.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::Uninstall()
{
/// @Prevent recursive uninstall call. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
- if (_status == STATUS_UNINSTALLING)
+ if (_status == STATUS_UNINSTALLING && !GetBase()->HasUnitTypeMask(UNIT_MASK_MINION))
{
sLog->outError(LOG_FILTER_VEHICLES, "Vehicle GuidLow: %u, Entry: %u attempts to uninstall, but already has STATUS_UNINSTALLING! "
"Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry());
return;
}
+
_status = STATUS_UNINSTALLING;
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Uninstall Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
RemoveAllPassengers();
@@ -131,26 +160,39 @@ void Vehicle::Uninstall()
sScriptMgr->OnUninstall(this);
}
+/**
+ * @fn void Vehicle::Reset(bool evading )
+ *
+ * @brief Reapplies immunities and reinstalls accessories. Only has effect for creatures.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param evading true if called from CreatureAI::EnterEvadeMode
+ */
+
void Vehicle::Reset(bool evading /*= false*/)
{
- sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
- if (_me->GetTypeId() == TYPEID_PLAYER)
- {
- if (_usableSeatNum)
- _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
- }
- else
- {
- ApplyAllImmunities();
- InstallAllAccessories(evading);
- if (_usableSeatNum)
- _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- }
+ if (GetBase()->GetTypeId() != TYPEID_UNIT)
+ return;
- if (GetBase()->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnReset(this);
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset (Entry: %u, GuidLow: %u, DBGuid: %u)", GetCreatureEntry(), _me->GetGUIDLow(), _me->ToCreature()->GetDBTableGUIDLow());
+
+ ApplyAllImmunities();
+ InstallAllAccessories(evading);
+
+ sScriptMgr->OnReset(this);
}
+/**
+ * @fn void Vehicle::ApplyAllImmunities()
+ *
+ * @brief Applies specific immunities that cannot be set in DB.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::ApplyAllImmunities()
{
// This couldn't be done in DB, because some spells have MECHANIC_NONE
@@ -199,10 +241,28 @@ void Vehicle::ApplyAllImmunities()
}
}
+/**
+ * @fn void Vehicle::RemoveAllPassengers()
+ *
+ * @brief Removes all current and pending passengers from the vehicle.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::RemoveAllPassengers()
{
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::RemoveAllPassengers. Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
+ /// Setting to_Abort to true will cause @VehicleJoinEvent::Abort to be executed on next @Unit::UpdateEvents call
+ /// This will properly "reset" the pending join process for the passenger.
+ while (_pendingJoinEvents.size())
+ {
+ VehicleJoinEvent* e = _pendingJoinEvents.front();
+ e->to_Abort = true;
+ _pendingJoinEvents.pop_front();
+ }
+
// Passengers always cast an aura with SPELL_AURA_CONTROL_VEHICLE on the vehicle
// We just remove the aura and the unapply handler will make the target leave the vehicle.
// We don't need to iterate over Seats
@@ -215,6 +275,19 @@ void Vehicle::RemoveAllPassengers()
// ASSERT(!itr->second.passenger);
}
+/**
+ * @fn bool Vehicle::HasEmptySeat(int8 seatId) const
+ *
+ * @brief Checks if vehicle's seat specified by 'seatId' is empty.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param seatId Identifier for the seat.
+ *
+ * @return true if empty seat, false if not.
+ */
+
bool Vehicle::HasEmptySeat(int8 seatId) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
@@ -223,6 +296,19 @@ bool Vehicle::HasEmptySeat(int8 seatId) const
return !seat->second.Passenger;
}
+/**
+ * @fn Unit* Vehicle::GetPassenger(int8 seatId) const
+ *
+ * @brief Gets a passenger on specified seat.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param seatId Seat to look on.
+ *
+ * @return null if it not found, else pointer to passenger if in world
+ */
+
Unit* Vehicle::GetPassenger(int8 seatId) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
@@ -232,78 +318,105 @@ Unit* Vehicle::GetPassenger(int8 seatId) const
return ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger);
}
-int8 Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
+/**
+ * @fn SeatMap::const_iterator Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
+ *
+ * @brief Gets the next empty seat based on current seat.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param seatId Identifier for the current seat.
+ * @param next true if iterating forward, false means iterating backwards.
+ *
+ * @return The next empty seat.
+ */
+
+SeatMap::const_iterator Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
if (seat == Seats.end())
- return -1;
+ return seat;
while (seat->second.Passenger || (!seat->second.SeatInfo->CanEnterOrExit() && !seat->second.SeatInfo->IsUsableByOverride()))
{
if (next)
{
- ++seat;
- if (seat == Seats.end())
+ if (++seat == Seats.end())
seat = Seats.begin();
}
else
{
- if (seat == Seats.begin())
+ if (seat-- == Seats.begin())
seat = Seats.end();
- --seat;
}
+ // Make sure we don't loop indefinetly
if (seat->first == seatId)
- return -1; // no available seat
+ return Seats.end();
}
- return seat->first;
+ return seat;
}
+/**
+ * @fn void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type,
+ * uint32 summonTime)
+ *
+ * @brief Installs an accessory.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param entry The NPC entry of accessory.
+ * @param seatId Identifier for the seat to add the accessory to.
+ * @param minion true if accessory considered a 'minion'. Implies that the accessory will despawn when the vehicle despawns.
+ * Essentially that it has no life without the vehicle. Their fates are bound.
+ * @param type See enum @SummonType.
+ * @param summonTime Time after which the minion is despawned in case of a timed despawn @type specified.
+ */
+
void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime)
{
/// @Prevent adding accessories when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == STATUS_UNINSTALLING)
{
- sLog->outError(LOG_FILTER_VEHICLES, "Vehicle GuidLow: %u, Entry: %u attempts to install accessory Entry: %u on seat %d with STATUS_UNINSTALLING! "
- "Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry(), entry, (int32)seatId);
+ sLog->outError(LOG_FILTER_VEHICLES, "Vehicle (GuidLow: %u, DB GUID: %u, Entry: %u) attempts to install accessory (Entry: %u) on seat %i with STATUS_UNINSTALLING! "
+ "Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(),
+ (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : _me->GetGUIDLow()), GetCreatureEntry(), entry, (int32)seatId);
return;
}
- sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle: Installing accessory entry %u on vehicle entry %u (seat:%i)", entry, GetCreatureEntry(), seatId);
- if (Unit* passenger = GetPassenger(seatId))
- {
- // already installed
- if (passenger->GetEntry() == entry)
- {
- ASSERT(passenger->GetTypeId() == TYPEID_UNIT);
- if (_me->GetTypeId() == TYPEID_UNIT)
- {
- if (_me->ToCreature()->IsInEvadeMode() && passenger->ToCreature()->IsAIEnabled)
- passenger->ToCreature()->AI()->EnterEvadeMode();
- return;
- }
- }
- else
- passenger->ExitVehicle(); // this should not happen
- }
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle (GuidLow: %u, DB Guid: %u, Entry %u): installing accessory (Entry: %u) on seat: %i",
+ _me->GetGUIDLow(), (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : _me->GetGUIDLow()), GetCreatureEntry(),
+ entry, (int32)seatId);
- if (TempSummon* accessory = _me->SummonCreature(entry, *_me, TempSummonType(type), summonTime))
- {
- if (minion)
- accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
+ TempSummon* accessory = _me->SummonCreature(entry, *_me, TempSummonType(type), summonTime);
+ ASSERT(accessory);
- if (!_me->HandleSpellClick(accessory, seatId))
- {
- accessory->UnSummon();
- return;
- }
+ if (minion)
+ accessory->AddUnitTypeMask(UNIT_MASK_ACCESSORY);
- if (GetBase()->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnInstallAccessory(this, accessory);
- }
+ (void)_me->HandleSpellClick(accessory, seatId);
+
+ /// If for some reason adding accessory to vehicle fails it will unsummon in
+ /// @VehicleJoinEvent::Abort
}
+/**
+ * @fn bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
+ *
+ * @brief Attempts to add a passenger to the vehicle on 'seatId'.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] The prospective passenger.
+ * @param seatId Identifier for the seat. Value of -1 indicates the next available seat.
+ *
+ * @return true if it succeeds, false if it fails.
+ */
+
bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
{
/// @Prevent adding passengers when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
@@ -314,10 +427,19 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
return false;
}
- if (unit->GetVehicle() != this)
- return false;
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s scheduling enter vehicle (entry: %u, vehicleId: %u, guid: %u (dbguid: %s) on seat %d",
+ unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(),
+ (_me->GetTypeId() == TYPEID_UNIT ? _me->ToCreature()->GetDBTableGUIDLow() : 0), (int32)seatId);
+ // The seat selection code may kick other passengers off the vehicle.
+ // While the validity of the following may be arguable, it is possible that when such a passenger
+ // exits the vehicle will dismiss. That's why the actual adding the passenger to the vehicle is scheduled
+ // asynchronously, so it can be cancelled easily in case the vehicle is uninstalled meanwhile.
SeatMap::iterator seat;
+ VehicleJoinEvent* e = new VehicleJoinEvent(this, unit);
+ unit->m_Events.AddEvent(e, unit->m_Events.CalculateTime(0));
+ _pendingJoinEvents.push_back(e);
+
if (seatId < 0) // no specific seat requirement
{
for (seat = Seats.begin(); seat != Seats.end(); ++seat)
@@ -325,86 +447,47 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
break;
if (seat == Seats.end()) // no available seat
+ {
+ CancelJoinEvent(e);
return false;
+ }
+
+ e->Seat = seat;
}
else
{
seat = Seats.find(seatId);
if (seat == Seats.end())
+ {
+ CancelJoinEvent(e);
return false;
+ }
+ e->Seat = seat;
if (seat->second.Passenger)
{
- if (Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger))
- passenger->ExitVehicle();
- else
- seat->second.Passenger = 0;
+ Unit* passenger = ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger);
+ ASSERT(passenger);
+ passenger->ExitVehicle();
}
ASSERT(!seat->second.Passenger);
}
- sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s enter vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
-
- seat->second.Passenger = unit->GetGUID();
- if (seat->second.SeatInfo->CanEnterOrExit())
- {
- ASSERT(_usableSeatNum);
- --_usableSeatNum;
- if (!_usableSeatNum)
- {
- if (_me->GetTypeId() == TYPEID_PLAYER)
- _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
- else
- _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- }
- }
-
- if (seat->second.SeatInfo->m_flags && !(seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING))
- unit->AddUnitState(UNIT_STATE_ONVEHICLE);
-
- VehicleSeatEntry const* veSeat = seat->second.SeatInfo;
- unit->m_movementInfo.t_pos.m_positionX = veSeat->m_attachmentOffsetX;
- unit->m_movementInfo.t_pos.m_positionY = veSeat->m_attachmentOffsetY;
- unit->m_movementInfo.t_pos.m_positionZ = veSeat->m_attachmentOffsetZ;
- unit->m_movementInfo.t_pos.SetOrientation(0);
- unit->m_movementInfo.t_time = 0; // 1 for player
- unit->m_movementInfo.t_seat = seat->first;
- unit->m_movementInfo.t_guid = _me->GetGUID();
-
- if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER &&
- seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
- ASSERT(_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
-
- if (_me->IsInWorld())
- {
- unit->SendClearTarget(); // SMSG_BREAK_TARGET
- unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
- // also adds MOVEMENTFLAG_ROOT
- Movement::MoveSplineInit init(unit);
- init.DisableTransportPathTransformations();
- init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
- init.SetFacing(0.0f);
- init.SetTransportEnter();
- init.Launch();
-
- if (_me->GetTypeId() == TYPEID_UNIT)
- {
- if (_me->ToCreature()->IsAIEnabled)
- _me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, true);
-
- // update all passenger's positions
- //Passenger's spline OR vehicle movement will update positions
- //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation());
- }
- }
-
- if (GetBase()->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnAddPassenger(this, unit, seatId);
-
return true;
}
+/**
+ * @fn void Vehicle::RemovePassenger(Unit* unit)
+ *
+ * @brief Removes the passenger from the vehicle.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] unit The passenger to remove..
+ */
+
void Vehicle::RemovePassenger(Unit* unit)
{
if (unit->GetVehicle() != this)
@@ -413,20 +496,12 @@ void Vehicle::RemovePassenger(Unit* unit)
SeatMap::iterator seat = GetSeatIteratorForPassenger(unit);
ASSERT(seat != Seats.end());
- sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s exit vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s exit vehicle entry %u id %u dbguid %u seat %d",
+ unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
seat->second.Passenger = 0;
- if (seat->second.SeatInfo->CanEnterOrExit())
- {
- if (!_usableSeatNum)
- {
- if (_me->GetTypeId() == TYPEID_PLAYER)
- _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
- else
- _me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- }
- ++_usableSeatNum;
- }
+ if (seat->second.SeatInfo->CanEnterOrExit() && ++UsableSeatNum)
+ _me->SetFlag(UNIT_NPC_FLAGS, (_me->GetTypeId() == TYPEID_PLAYER ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
unit->ClearUnitState(UNIT_STATE_ONVEHICLE);
@@ -435,7 +510,7 @@ void Vehicle::RemovePassenger(Unit* unit)
if (_me->IsInWorld())
{
- unit->m_movementInfo.t_pos.Relocate(0, 0, 0, 0);
+ unit->m_movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
unit->m_movementInfo.t_time = 0;
unit->m_movementInfo.t_seat = 0;
}
@@ -451,7 +526,15 @@ void Vehicle::RemovePassenger(Unit* unit)
sScriptMgr->OnRemovePassenger(this, unit);
}
-//! Must be called after m_base::Relocate
+/**
+ * @fn void Vehicle::RelocatePassengers()
+ *
+ * @brief Relocate passengers. Must be called after m_base::Relocate
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::RelocatePassengers()
{
ASSERT(_me->GetMap());
@@ -466,21 +549,40 @@ void Vehicle::RelocatePassengers()
float px, py, pz, po;
passenger->m_movementInfo.t_pos.GetPosition(px, py, pz, po);
CalculatePassengerPosition(px, py, pz, po);
+
passenger->UpdatePosition(px, py, pz, po);
}
}
}
+/**
+ * @fn void Vehicle::Dismiss()
+ *
+ * @brief Dismiss the vehicle. Removes passengers and despawns self. Only valid for creatures.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::Dismiss()
{
if (GetBase()->GetTypeId() != TYPEID_UNIT)
return;
- sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Dismiss Entry: %u, GuidLow %u", _creatureEntry, _me->GetGUIDLow());
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Dismiss Entry: %u, GuidLow %u, DBGuid: %u", GetCreatureEntry(), _me->GetGUIDLow(), _me->ToCreature()->GetDBTableGUIDLow());
Uninstall();
GetBase()->ToCreature()->DespawnOrUnsummon();
}
+/**
+ * @fn void Vehicle::InitMovementInfoForBase()
+ *
+ * @brief Sets correct MovementFlags2 based on VehicleFlags from DBC.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ */
+
void Vehicle::InitMovementInfoForBase()
{
uint32 vehicleFlags = GetVehicleInfo()->m_flags;
@@ -497,6 +599,19 @@ void Vehicle::InitMovementInfoForBase()
_me->AddExtraUnitMovementFlag(MOVEMENTFLAG2_FULL_SPEED_PITCHING);
}
+/**
+ * @fn VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger)
+ *
+ * @brief Returns information on the seat of specified passenger, represented by the format in VehicleSeat.dbc
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] The passenger for which we check the seat info.
+ *
+ * @return null if passenger not found on vehicle, else the DBC record for the seat.
+ */
+
VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger)
{
SeatMap::iterator itr;
@@ -507,6 +622,19 @@ VehicleSeatEntry const* Vehicle::GetSeatForPassenger(Unit* passenger)
return NULL;
}
+/**
+ * @fn SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger)
+ *
+ * @brief Gets seat iterator for specified passenger.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] passenger Passenger to look up.
+ *
+ * @return The seat iterator for specified passenger if it's found on the vehicle. Otherwise Seats.end() (invalid iterator).
+ */
+
SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger)
{
SeatMap::iterator itr;
@@ -517,6 +645,17 @@ SeatMap::iterator Vehicle::GetSeatIteratorForPassenger(Unit* passenger)
return Seats.end();
}
+/**
+ * @fn uint8 Vehicle::GetAvailableSeatCount() const
+ *
+ * @brief Gets the available seat count.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @return The available seat count.
+ */
+
uint8 Vehicle::GetAvailableSeatCount() const
{
uint8 ret = 0;
@@ -547,3 +686,139 @@ void Vehicle::CalculatePassengerOffset(float& x, float& y, float& z, float& o)
y = (iny - inx * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation()));
x = (inx + iny * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation()));
}
+
+/**
+ * @fn void Vehicle::CancelJoinEvent(VehicleJoinEvent* e)
+ *
+ * @brief Aborts delayed @VehicleJoinEvent objects.
+ * Implies that the related unit will not be boarding the vehicle after all.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param [in,out] e The VehicleJoinEvent* to process.
+ */
+
+void Vehicle::CancelJoinEvent(VehicleJoinEvent* e)
+{
+ e->to_Abort = true;
+ _pendingJoinEvents.pop_back();
+}
+
+/**
+ * @fn bool VehicleJoinEvent::Execute(uint64, uint32)
+ *
+ * @brief Actually adds the passenger @Passenger to vehicle @Target.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param parameter1 Unused
+ * @param parameter2 Unused.
+ *
+ * @return true, cannot fail.
+ *
+ */
+
+bool VehicleJoinEvent::Execute(uint64, uint32)
+{
+ ASSERT(Passenger->IsInWorld());
+ ASSERT(Target->GetBase()->IsInWorld());
+
+ Passenger->m_vehicle = Target;
+ Seat->second.Passenger = Passenger->GetGUID();
+ if (Seat->second.SeatInfo->CanEnterOrExit())
+ {
+ ASSERT(Target->UsableSeatNum);
+ --(Target->UsableSeatNum);
+ if (!Target->UsableSeatNum)
+ {
+ if (Target->GetBase()->GetTypeId() == TYPEID_PLAYER)
+ Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
+ else
+ Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ }
+ }
+
+ Passenger->InterruptNonMeleeSpells(false);
+
+ Player* player = Passenger->ToPlayer();
+ if (player)
+ {
+ // drop flag
+ if (Battleground* bg = player->GetBattleground())
+ bg->EventPlayerDroppedFlag(player);
+
+ player->StopCastingCharm();
+ player->StopCastingBindSight();
+ player->SendOnCancelExpectedVehicleRideAura();
+ player->UnsummonPetTemporaryIfAny();
+ }
+
+ if (Seat->second.SeatInfo->m_flags && !(Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING))
+ Passenger->AddUnitState(UNIT_STATE_ONVEHICLE);
+
+ VehicleSeatEntry const* veSeat = Seat->second.SeatInfo;
+ Passenger->m_movementInfo.t_pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
+ Passenger->m_movementInfo.t_time = 0; // 1 for player
+ Passenger->m_movementInfo.t_seat = Seat->first;
+ Passenger->m_movementInfo.t_guid = Target->GetBase()->GetGUID();
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT && Passenger->GetTypeId() == TYPEID_PLAYER &&
+ Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
+ ASSERT(Target->GetBase()->SetCharmedBy(Passenger, CHARM_TYPE_VEHICLE)) // SMSG_CLIENT_CONTROL
+
+ Passenger->SendClearTarget(); // SMSG_BREAK_TARGET
+ Passenger->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
+ // also adds MOVEMENTFLAG_ROOT
+
+ Movement::MoveSplineInit init(Passenger);
+ init.DisableTransportPathTransformations();
+ init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ, false, true);
+ init.SetFacing(0.0f);
+ init.SetTransportEnter();
+ init.Launch();
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT)
+ {
+ if (Target->GetBase()->ToCreature()->IsAIEnabled)
+ Target->GetBase()->ToCreature()->AI()->PassengerBoarded(Passenger, Seat->first, true);
+
+ sScriptMgr->OnAddPassenger(Target, Passenger, Seat->first);
+
+ // Actually quite a redundant hook. Could just use OnAddPassenger and check for unit typemask inside script.
+ if (Passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY))
+ sScriptMgr->OnInstallAccessory(Target, Passenger->ToCreature());
+
+ // update all passenger's positions
+ //Passenger's spline OR vehicle movement will update positions
+ //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation());
+ }
+
+ return true;
+}
+
+/**
+ * @fn void VehicleJoinEvent::Abort(uint64)
+ *
+ * @brief Aborts the event. Implies that unit @Passenger will not be boarding vehicle @Target after all.
+ *
+ * @author Machiavelli
+ * @date 17-2-2013
+ *
+ * @param parameter1 Unused
+ */
+
+void VehicleJoinEvent::Abort(uint64)
+{
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, board on vehicle GuidLow: %u, Entry: %u SeatId: %i cancelled",
+ Passenger->GetGUIDLow(), Passenger->GetEntry(), Target->GetBase()->GetGUIDLow(), Target->GetBase()->GetEntry(), (int32)Seat->first);
+
+ /// @SPELL_AURA_CONTROL_VEHICLE auras can be applied even when the passenger is not (yet) on the vehicle.
+ /// When this code is triggered it means that something went wrong in @Vehicle::AddPassenger, and we should remove
+ /// the aura manually.
+ Target->GetBase()->RemoveAurasByType(SPELL_AURA_CONTROL_VEHICLE, Passenger->GetGUID());
+
+ if (Passenger->IsInWorld() && Passenger->HasUnitTypeMask(UNIT_MASK_ACCESSORY))
+ Passenger->ToCreature()->DespawnOrUnsummon();
+}
diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h
index 823fb72b8a8..7ec0df8e533 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.h
+++ b/src/server/game/Entities/Vehicle/Vehicle.h
@@ -23,12 +23,12 @@
#include "Object.h"
#include "VehicleDefines.h"
#include "Unit.h"
+#include <deque>
struct VehicleEntry;
-
class Unit;
-
typedef std::set<uint64> GuidSet;
+class VehicleJoinEvent;
class Vehicle : public TransportBase
{
@@ -46,7 +46,7 @@ class Vehicle : public TransportBase
bool HasEmptySeat(int8 seatId) const;
Unit* GetPassenger(int8 seatId) const;
- int8 GetNextEmptySeat(int8 seatId, bool next) const;
+ SeatMap::const_iterator GetNextEmptySeat(int8 seatId, bool next) const;
uint8 GetAvailableSeatCount() const;
bool AddPassenger(Unit* passenger, int8 seatId = -1);
@@ -61,11 +61,15 @@ class Vehicle : public TransportBase
void SetLastShootPos(Position const& pos) { m_lastShootPos.Relocate(pos); }
Position GetLastShootPos() { return m_lastShootPos; }
- SeatMap Seats;
+ SeatMap Seats; ///< The collection of all seats on the vehicle. Including vacant ones.
VehicleSeatEntry const* GetSeatForPassenger(Unit* passenger);
protected:
+ friend class VehicleJoinEvent;
+ uint32 UsableSeatNum; ///< Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
+
+ protected:
friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry);
Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry);
friend void Unit::RemoveVehicleKit();
@@ -88,12 +92,27 @@ class Vehicle : public TransportBase
/// This method transforms supplied global coordinates into local offsets
void CalculatePassengerOffset(float& x, float& y, float& z, float& o);
- Unit* _me;
- VehicleEntry const* _vehicleInfo;
+ Unit* _me; ///< The underlying unit with the vehicle kit. Can be player or creature.
+ VehicleEntry const* _vehicleInfo; ///< DBC data for vehicle
GuidSet vehiclePlayers;
- uint32 _usableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
- uint32 _creatureEntry; // Can be different than me->GetBase()->GetEntry() in case of players
- Status _status;
+
+ uint32 _creatureEntry; ///< Can be different than the entry of _me in case of players
+ Status _status; ///< Internal variable for sanity checks
Position m_lastShootPos;
+ std::deque<VehicleJoinEvent*> _pendingJoinEvents; ///< Collection of delayed join events for prospective passengers
+ void CancelJoinEvent(VehicleJoinEvent* e);
+};
+
+class VehicleJoinEvent : public BasicEvent
+{
+ friend class Vehicle;
+ protected:
+ VehicleJoinEvent(Vehicle* v, Unit* u) : Target(v), Passenger(u), Seat(Target->Seats.end()) {}
+ bool Execute(uint64, uint32);
+ void Abort(uint64);
+
+ Vehicle* Target;
+ Unit* Passenger;
+ SeatMap::iterator Seat;
};
#endif
diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp
index 051d76f46ed..d06ff1fa533 100644
--- a/src/server/game/Events/GameEventMgr.cpp
+++ b/src/server/game/Events/GameEventMgr.cpp
@@ -450,8 +450,8 @@ void GameEventMgr::LoadFromDB()
{
uint32 oldMSTime = getMSTime();
- // 0 1 2 3
- QueryResult result = WorldDatabase.Query("SELECT creature.guid, game_event_model_equip.eventEntry, game_event_model_equip.modelid, game_event_model_equip.equipment_id "
+ // 0 1 2 3 4
+ QueryResult result = WorldDatabase.Query("SELECT creature.guid, creature.id, game_event_model_equip.eventEntry, game_event_model_equip.modelid, game_event_model_equip.equipment_id "
"FROM creature JOIN game_event_model_equip ON creature.guid=game_event_model_equip.guid");
if (!result)
@@ -466,7 +466,8 @@ void GameEventMgr::LoadFromDB()
Field* fields = result->Fetch();
uint32 guid = fields[0].GetUInt32();
- uint16 event_id = fields[1].GetUInt8();
+ uint32 entry = fields[1].GetUInt32();
+ uint16 event_id = fields[2].GetUInt8();
if (event_id >= mGameEventModelEquip.size())
{
@@ -476,17 +477,18 @@ void GameEventMgr::LoadFromDB()
ModelEquipList& equiplist = mGameEventModelEquip[event_id];
ModelEquip newModelEquipSet;
- newModelEquipSet.modelid = fields[2].GetUInt32();
- newModelEquipSet.equipment_id = fields[3].GetUInt32();
+ newModelEquipSet.modelid = fields[3].GetUInt32();
+ newModelEquipSet.equipment_id = fields[4].GetUInt8();
newModelEquipSet.equipement_id_prev = 0;
newModelEquipSet.modelid_prev = 0;
if (newModelEquipSet.equipment_id > 0)
{
- if (!sObjectMgr->GetEquipmentInfo(newModelEquipSet.equipment_id))
+ int8 equipId = static_cast<int8>(newModelEquipSet.equipment_id);
+ if (!sObjectMgr->GetEquipmentInfo(entry, equipId))
{
- sLog->outError(LOG_FILTER_SQL, "Table `game_event_model_equip` have creature (Guid: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.",
- guid, newModelEquipSet.equipment_id);
+ sLog->outError(LOG_FILTER_SQL, "Table `game_event_model_equip` have creature (Guid: %u, entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.",
+ guid, entry, newModelEquipSet.equipment_id);
continue;
}
}
@@ -1103,14 +1105,8 @@ void GameEventMgr::UnApplyEvent(uint16 event_id)
void GameEventMgr::ApplyNewEvent(uint16 event_id)
{
- switch (sWorld->getIntConfig(CONFIG_EVENT_ANNOUNCE))
- {
- case 0: // disable
- break;
- case 1: // announce events
- sWorld->SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str());
- break;
- }
+ if (sWorld->getBoolConfig(CONFIG_EVENT_ANNOUNCE))
+ sWorld->SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str());
sLog->outInfo(LOG_FILTER_GAMEEVENTS, "GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str());
@@ -1332,7 +1328,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
itr->second.equipement_id_prev = creature->GetCurrentEquipmentId();
itr->second.modelid_prev = creature->GetDisplayId();
creature->LoadEquipment(itr->second.equipment_id, true);
- if (itr->second.modelid >0 && itr->second.modelid_prev != itr->second.modelid)
+ if (itr->second.modelid > 0 && itr->second.modelid_prev != itr->second.modelid)
{
CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(itr->second.modelid);
if (minfo)
@@ -1347,7 +1343,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
else
{
creature->LoadEquipment(itr->second.equipement_id_prev, true);
- if (itr->second.modelid_prev >0 && itr->second.modelid_prev != itr->second.modelid)
+ if (itr->second.modelid_prev > 0 && itr->second.modelid_prev != itr->second.modelid)
{
CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(itr->second.modelid_prev);
if (minfo)
@@ -1370,7 +1366,7 @@ void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
sObjectMgr->GetCreatureModelRandomGender(&displayID);
if (data2->equipmentId == 0)
- itr->second.equipement_id_prev = cinfo->equipmentId;
+ itr->second.equipement_id_prev = 1;
else if (data2->equipmentId != -1)
itr->second.equipement_id_prev = data->equipmentId;
itr->second.modelid_prev = displayID;
diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h
index 25aa99f858a..192c441f50f 100644
--- a/src/server/game/Events/GameEventMgr.h
+++ b/src/server/game/Events/GameEventMgr.h
@@ -73,9 +73,9 @@ struct GameEventData
struct ModelEquip
{
uint32 modelid;
- uint32 equipment_id;
uint32 modelid_prev;
- uint32 equipement_id_prev;
+ uint8 equipment_id;
+ uint8 equipement_id_prev;
};
struct NPCVendorEntry
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 8597b6098a9..85022c9164c 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -427,8 +427,8 @@ void ObjectMgr::LoadCreatureTemplates()
"spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
// 71 72 73 74 75 76 77 78 79 80 81 82
"InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, "
- // 83 84 85 86 87 88 89
- " questItem6, movementId, RegenHealth, equipment_id, mechanic_immune_mask, flags_extra, ScriptName "
+ // 83 84 85 86 87 88
+ " questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName "
"FROM creature_template;");
if (!result)
@@ -525,10 +525,9 @@ void ObjectMgr::LoadCreatureTemplates()
creatureTemplate.movementId = fields[82].GetUInt32();
creatureTemplate.RegenHealth = fields[83].GetBool();
- creatureTemplate.equipmentId = fields[84].GetUInt32();
- creatureTemplate.MechanicImmuneMask = fields[85].GetUInt32();
- creatureTemplate.flags_extra = fields[86].GetUInt32();
- creatureTemplate.ScriptID = GetScriptId(fields[87].GetCString());
+ creatureTemplate.MechanicImmuneMask = fields[84].GetUInt32();
+ creatureTemplate.flags_extra = fields[85].GetUInt32();
+ creatureTemplate.ScriptID = GetScriptId(fields[86].GetCString());
++count;
}
@@ -877,15 +876,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
const_cast<CreatureTemplate*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
}
- if (cInfo->equipmentId > 0) // 0 no equipment
- {
- if (!GetEquipmentInfo(cInfo->equipmentId))
- {
- sLog->outError(LOG_FILTER_SQL, "Table `creature_template` lists creature (Entry: %u) with `equipment_id` %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId);
- const_cast<CreatureTemplate*>(cInfo)->equipmentId = 0;
- }
- }
-
/// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc
if (cInfo->scale <= 0.0f)
{
@@ -1011,11 +1001,28 @@ CreatureAddon const* ObjectMgr::GetCreatureTemplateAddon(uint32 entry)
return NULL;
}
-EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry)
+EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry, int8& id)
{
EquipmentInfoContainer::const_iterator itr = _equipmentInfoStore.find(entry);
- if (itr != _equipmentInfoStore.end())
- return &(itr->second);
+ if (itr == _equipmentInfoStore.end())
+ return NULL;
+
+ if (itr->second.empty())
+ return NULL;
+
+ if (id == -1) // select a random element
+ {
+ EquipmentInfoContainerInternal::const_iterator ritr = itr->second.begin();
+ std::advance(ritr, urand(0u, itr->second.size()));
+ id = std::distance(itr->second.begin(), ritr) + 1;
+ return &ritr->second;
+ }
+ else
+ {
+ EquipmentInfoContainerInternal::const_iterator itr2 = itr->second.find(id);
+ if (itr2 != itr->second.end())
+ return &itr2->second;
+ }
return NULL;
}
@@ -1024,7 +1031,8 @@ void ObjectMgr::LoadEquipmentTemplates()
{
uint32 oldMSTime = getMSTime();
- QueryResult result = WorldDatabase.Query("SELECT entry, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template");
+ // 0 1 2 3 4
+ QueryResult result = WorldDatabase.Query("SELECT entry, id, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template");
if (!result)
{
@@ -1037,13 +1045,21 @@ void ObjectMgr::LoadEquipmentTemplates()
{
Field* fields = result->Fetch();
- uint16 entry = fields[0].GetUInt16();
+ uint32 entry = fields[0].GetUInt32();
+
+ if (!sObjectMgr->GetCreatureTemplate(entry))
+ {
+ sLog->outError(LOG_FILTER_SQL, "Creature template (Entry: %u) does not exist but has a record in `creature_equip_template`", entry);
+ continue;
+ }
+
+ uint8 id = fields[1].GetUInt8();
- EquipmentInfo& equipmentInfo = _equipmentInfoStore[entry];
+ EquipmentInfo& equipmentInfo = _equipmentInfoStore[entry][id];
- equipmentInfo.ItemEntry[0] = fields[1].GetUInt32();
- equipmentInfo.ItemEntry[1] = fields[2].GetUInt32();
- equipmentInfo.ItemEntry[2] = fields[3].GetUInt32();
+ equipmentInfo.ItemEntry[0] = fields[2].GetUInt32();
+ equipmentInfo.ItemEntry[1] = fields[3].GetUInt32();
+ equipmentInfo.ItemEntry[2] = fields[4].GetUInt32();
for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
{
@@ -1054,8 +1070,8 @@ void ObjectMgr::LoadEquipmentTemplates()
if (!dbcItem)
{
- sLog->outError(LOG_FILTER_SQL, "Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u, forced to 0.",
- equipmentInfo.ItemEntry[i], i+1, entry);
+ sLog->outError(LOG_FILTER_SQL, "Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id=%u, forced to 0.",
+ equipmentInfo.ItemEntry[i], i+1, entry, id);
equipmentInfo.ItemEntry[i] = 0;
continue;
}
@@ -1070,8 +1086,8 @@ void ObjectMgr::LoadEquipmentTemplates()
dbcItem->InventoryType != INVTYPE_THROWN &&
dbcItem->InventoryType != INVTYPE_RANGEDRIGHT)
{
- sLog->outError(LOG_FILTER_SQL, "Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u is not equipable in a hand, forced to 0.",
- equipmentInfo.ItemEntry[i], i+1, entry);
+ sLog->outError(LOG_FILTER_SQL, "Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id = %u is not equipable in a hand, forced to 0.",
+ equipmentInfo.ItemEntry[i], i+1, entry, id);
equipmentInfo.ItemEntry[i] = 0;
}
}
@@ -1518,13 +1534,13 @@ void ObjectMgr::LoadCreatures()
if (!ok)
continue;
- // -1 no equipment, 0 use default
- if (data.equipmentId > 0)
+ // -1 random, 0 no equipment, 1 is default (may or may not have equipment)
+ if (data.equipmentId != 0)
{
- if (!GetEquipmentInfo(data.equipmentId))
+ if (!GetEquipmentInfo(data.id, data.equipmentId) && data.equipmentId != 1)
{
sLog->outError(LOG_FILTER_SQL, "Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId);
- data.equipmentId = -1;
+ data.equipmentId = 1;
}
}
@@ -1698,7 +1714,7 @@ uint32 ObjectMgr::AddCreData(uint32 entry, uint32 /*team*/, uint32 mapId, float
data.id = entry;
data.mapid = mapId;
data.displayid = 0;
- data.equipmentId = cInfo->equipmentId;
+ data.equipmentId = 1;
data.posX = x;
data.posY = y;
data.posZ = z;
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 8c14f902c1f..d0963a224b7 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -672,7 +672,7 @@ class ObjectMgr
CreatureModelInfo const* GetCreatureModelRandomGender(uint32* displayID);
static uint32 ChooseDisplayId(uint32 team, const CreatureTemplate* cinfo, const CreatureData* data = NULL);
static void ChooseCreatureFlags(const CreatureTemplate* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, const CreatureData* data = NULL);
- EquipmentInfo const* GetEquipmentInfo(uint32 entry);
+ EquipmentInfo const* GetEquipmentInfo(uint32 entry, int8& id);
CreatureAddon const* GetCreatureAddon(uint32 lowguid);
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry);
ItemTemplate const* GetItemTemplate(uint32 entry);
diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp
index 031a8ee96e7..90c97562185 100644
--- a/src/server/game/Groups/Group.cpp
+++ b/src/server/game/Groups/Group.cpp
@@ -665,7 +665,7 @@ void Group::ChangeLeader(uint64 guid)
if (!player)
return;
- sScriptMgr->OnGroupChangeLeader(this, m_leaderGuid, guid);
+ sScriptMgr->OnGroupChangeLeader(this, guid, m_leaderGuid);
if (!isBGGroup() && !isBFGroup())
{
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index e08a7a30699..4d72e79f4df 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -1650,8 +1650,7 @@ void WorldSession::HandleCancelMountAuraOpcode(WorldPacket& /*recvData*/)
return;
}
- _player->Dismount();
- _player->RemoveAurasByType(SPELL_AURA_MOUNTED);
+ _player->RemoveAurasByType(SPELL_AURA_MOUNTED); // Calls Dismount()
}
void WorldSession::HandleMoveSetCanFlyAckOpcode(WorldPacket& recvData)
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index 03884ae003e..99d36135977 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1041,7 +1041,8 @@ enum TrinityStrings
LANG_COMMAND_NO_ACHIEVEMENT_CRITERIA_FOUND = 5033,
LANG_COMMAND_NO_OUTDOOR_PVP_FORUND = 5034,
LANG_CALL_FOR_HELP = 5035,
- // Room for more Trinity strings 5036-9999
+ LANG_NPCINFO_EQUIPMENT = 5036,
+ // Room for more Trinity strings 5037-9999
// Level requirement notifications
LANG_SAY_REQ = 6604,
diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
index 5f93551a099..0ef69a38ea4 100644
--- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp
+++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp
@@ -5320,10 +5320,7 @@ void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode,
target->SendMessageToSet(&data, true);
if (apply)
- {
- data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0);
- target->ToPlayer()->GetSession()->SendPacket(&data);
- }
+ target->ToPlayer()->SendOnCancelExpectedVehicleRideAura();
}
void AuraEffect::HandlePreventResurrection(AuraApplication const* aurApp, uint8 mode, bool apply) const
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 4abca023dd3..36e58287599 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -933,6 +933,10 @@ bool Aura::CanBeSaved() const
if (HasEffectType(SPELL_AURA_OPEN_STABLE))
return false;
+ // Can't save vehicle auras, it requires both caster & target to be in world
+ if (HasEffectType(SPELL_AURA_CONTROL_VEHICLE))
+ return false;
+
// Incanter's Absorbtion - considering the minimal duration and problems with aura stacking
// we skip saving this aura
// Also for some reason other auras put as MultiSlot crash core on keeping them after restart,
@@ -1814,16 +1818,17 @@ void Aura::LoadScripts()
bool Aura::CallScriptCheckAreaTargetHandlers(Unit* target)
{
+ bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_AREA_TARGET);
std::list<AuraScript::CheckAreaTargetHandler>::iterator hookItrEnd = (*scritr)->DoCheckAreaTarget.end(), hookItr = (*scritr)->DoCheckAreaTarget.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- if (!(*hookItr).Call(*scritr, target))
- return false;
+ result &= hookItr->Call(*scritr, target);
+
(*scritr)->_FinishScriptCall();
}
- return true;
+ return result;
}
void Aura::CallScriptDispel(DispelInfo* dispelInfo)
@@ -1833,7 +1838,8 @@ void Aura::CallScriptDispel(DispelInfo* dispelInfo)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_DISPEL);
std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->OnDispel.end(), hookItr = (*scritr)->OnDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, dispelInfo);
+ hookItr->Call(*scritr, dispelInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1845,7 +1851,8 @@ void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_DISPEL);
std::list<AuraScript::AuraDispelHandler>::iterator hookItrEnd = (*scritr)->AfterDispel.end(), hookItr = (*scritr)->AfterDispel.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, dispelInfo);
+ hookItr->Call(*scritr, dispelInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1858,14 +1865,15 @@ bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplicati
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectApply.end(), effItr = (*scritr)->OnEffectApply.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
+
return preventDefault;
}
@@ -1877,12 +1885,12 @@ bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplicat
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->OnEffectRemove.end(), effItr = (*scritr)->OnEffectRemove.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
return preventDefault;
@@ -1895,10 +1903,9 @@ void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraAppl
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_APPLY, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectApply.end(), effItr = (*scritr)->AfterEffectApply.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1910,10 +1917,9 @@ void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApp
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_REMOVE, aurApp);
std::list<AuraScript::EffectApplyHandler>::iterator effEndItr = (*scritr)->AfterEffectRemove.end(), effItr = (*scritr)->AfterEffectRemove.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, mode);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, mode);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1926,14 +1932,15 @@ bool Aura::CallScriptEffectPeriodicHandlers(AuraEffect const* aurEff, AuraApplic
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PERIODIC, aurApp);
std::list<AuraScript::EffectPeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectPeriodic.end(), effItr = (*scritr)->OnEffectPeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
+
return preventDefault;
}
@@ -1944,10 +1951,9 @@ void Aura::CallScriptEffectUpdatePeriodicHandlers(AuraEffect* aurEff)
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_UPDATE_PERIODIC);
std::list<AuraScript::EffectUpdatePeriodicHandler>::iterator effEndItr = (*scritr)->OnEffectUpdatePeriodic.end(), effItr = (*scritr)->OnEffectUpdatePeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1959,10 +1965,9 @@ void Aura::CallScriptEffectCalcAmountHandlers(AuraEffect const* aurEff, int32 &
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_AMOUNT);
std::list<AuraScript::EffectCalcAmountHandler>::iterator effEndItr = (*scritr)->DoEffectCalcAmount.end(), effItr = (*scritr)->DoEffectCalcAmount.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, amount, canBeRecalculated);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, amount, canBeRecalculated);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1974,10 +1979,9 @@ void Aura::CallScriptEffectCalcPeriodicHandlers(AuraEffect const* aurEff, bool &
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_PERIODIC);
std::list<AuraScript::EffectCalcPeriodicHandler>::iterator effEndItr = (*scritr)->DoEffectCalcPeriodic.end(), effItr = (*scritr)->DoEffectCalcPeriodic.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, isPeriodic, amplitude);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, isPeriodic, amplitude);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -1989,10 +1993,9 @@ void Aura::CallScriptEffectCalcSpellModHandlers(AuraEffect const* aurEff, SpellM
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_CALC_SPELLMOD);
std::list<AuraScript::EffectCalcSpellModHandler>::iterator effEndItr = (*scritr)->DoEffectCalcSpellMod.end(), effItr = (*scritr)->DoEffectCalcSpellMod.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, spellMod);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, spellMod);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2004,11 +2007,13 @@ void Aura::CallScriptEffectAbsorbHandlers(AuraEffect* aurEff, AuraApplication co
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_ABSORB, aurApp);
std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->OnEffectAbsorb.end(), effItr = (*scritr)->OnEffectAbsorb.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
- defaultPrevented = (*scritr)->_IsDefaultActionPrevented();
+
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
+ if (!defaultPrevented)
+ defaultPrevented = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2020,10 +2025,9 @@ void Aura::CallScriptEffectAfterAbsorbHandlers(AuraEffect* aurEff, AuraApplicati
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_ABSORB, aurApp);
std::list<AuraScript::EffectAbsorbHandler>::iterator effEndItr = (*scritr)->AfterEffectAbsorb.end(), effItr = (*scritr)->AfterEffectAbsorb.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2035,10 +2039,9 @@ void Aura::CallScriptEffectManaShieldHandlers(AuraEffect* aurEff, AuraApplicatio
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_MANASHIELD, aurApp);
std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->OnEffectManaShield.end(), effItr = (*scritr)->OnEffectManaShield.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2050,10 +2053,9 @@ void Aura::CallScriptEffectAfterManaShieldHandlers(AuraEffect* aurEff, AuraAppli
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_MANASHIELD, aurApp);
std::list<AuraScript::EffectManaShieldHandler>::iterator effEndItr = (*scritr)->AfterEffectManaShield.end(), effItr = (*scritr)->AfterEffectManaShield.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, absorbAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, absorbAmount);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2065,26 +2067,27 @@ void Aura::CallScriptEffectSplitHandlers(AuraEffect* aurEff, AuraApplication con
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_SPLIT, aurApp);
std::list<AuraScript::EffectSplitHandler>::iterator effEndItr = (*scritr)->OnEffectSplit.end(), effItr = (*scritr)->OnEffectSplit.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, dmgInfo, splitAmount);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, dmgInfo, splitAmount);
+
(*scritr)->_FinishScriptCall();
}
}
bool Aura::CallScriptCheckProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
{
+ bool result = true;
for (std::list<AuraScript*>::iterator scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
{
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_CHECK_PROC, aurApp);
std::list<AuraScript::CheckProcHandler>::iterator hookItrEnd = (*scritr)->DoCheckProc.end(), hookItr = (*scritr)->DoCheckProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- if (!(*hookItr).Call(*scritr, eventInfo))
- return false;
+ result &= hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
- return true;
+
+ return result;
}
bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEventInfo& eventInfo)
@@ -2095,12 +2098,14 @@ bool Aura::CallScriptPrepareProcHandlers(AuraApplication const* aurApp, ProcEven
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PREPARE_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator effEndItr = (*scritr)->DoPrepareProc.end(), effItr = (*scritr)->DoPrepareProc.begin();
for (; effItr != effEndItr; ++effItr)
- (*effItr).Call(*scritr, eventInfo);
+ effItr->Call(*scritr, eventInfo);
+
+ if (prepare)
+ prepare = !(*scritr)->_IsDefaultActionPrevented();
- if (prepare && (*scritr)->_IsDefaultActionPrevented())
- prepare = false;
(*scritr)->_FinishScriptCall();
}
+
return prepare;
}
@@ -2111,7 +2116,8 @@ void Aura::CallScriptProcHandlers(AuraApplication const* aurApp, ProcEventInfo&
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->OnProc.end(), hookItr = (*scritr)->OnProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, eventInfo);
+ hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2123,7 +2129,8 @@ void Aura::CallScriptAfterProcHandlers(AuraApplication const* aurApp, ProcEventI
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_AFTER_PROC, aurApp);
std::list<AuraScript::AuraProcHandler>::iterator hookItrEnd = (*scritr)->AfterProc.end(), hookItr = (*scritr)->AfterProc.begin();
for (; hookItr != hookItrEnd; ++hookItr)
- (*hookItr).Call(*scritr, eventInfo);
+ hookItr->Call(*scritr, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
@@ -2136,12 +2143,12 @@ bool Aura::CallScriptEffectProcHandlers(AuraEffect const* aurEff, AuraApplicatio
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_PROC, aurApp);
std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->OnEffectProc.end(), effItr = (*scritr)->OnEffectProc.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, eventInfo);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, eventInfo);
+
if (!preventDefault)
preventDefault = (*scritr)->_IsDefaultActionPrevented();
+
(*scritr)->_FinishScriptCall();
}
return preventDefault;
@@ -2154,10 +2161,9 @@ void Aura::CallScriptAfterEffectProcHandlers(AuraEffect const* aurEff, AuraAppli
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_PROC, aurApp);
std::list<AuraScript::EffectProcHandler>::iterator effEndItr = (*scritr)->AfterEffectProc.end(), effItr = (*scritr)->AfterEffectProc.begin();
for (; effItr != effEndItr; ++effItr)
- {
- if ((*effItr).IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
- (*effItr).Call(*scritr, aurEff, eventInfo);
- }
+ if (effItr->IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()))
+ effItr->Call(*scritr, aurEff, eventInfo);
+
(*scritr)->_FinishScriptCall();
}
}
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 61e28a886ab..86d8f55c0ae 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -3610,7 +3610,7 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
Creature* npc = unitTarget->ToCreature();
- npc->LoadEquipment(npc->GetEquipmentId());
+ npc->LoadEquipment();
return;
}
// Emblazon Runeblade
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index aadc30e3921..990b35d0862 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1188,6 +1188,12 @@ bool SpellInfo::IsMultiSlotAura() const
return IsPassive() || Id == 55849 || Id == 40075 || Id == 44413; // Power Spark, Fel Flak Fire, Incanter's Absorption
}
+bool SpellInfo::IsStackableOnOneSlotWithDifferentCasters() const
+{
+ /// TODO: Re-verify meaning of SPELL_ATTR3_STACK_FOR_DIFF_CASTERS and update conditions here
+ return StackAmount > 1 && !IsChanneled() && !(AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS);
+}
+
bool SpellInfo::IsDeathPersistent() const
{
return AttributesEx3 & SPELL_ATTR3_DEATH_PERSISTENT;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index 7852c5c7270..ad344f0463d 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -443,6 +443,7 @@ public:
bool IsStackableWithRanks() const;
bool IsPassiveStackableWithRanks() const;
bool IsMultiSlotAura() const;
+ bool IsStackableOnOneSlotWithDifferentCasters() const;
bool IsDeathPersistent() const;
bool IsRequiringDeadTarget() const;
bool IsAllowingDeadTarget() const;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index b648a14fce5..8ec3d7d3731 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3354,6 +3354,17 @@ void SpellMgr::LoadSpellInfoCorrections()
case 64596: // Cosmic Smash (Algalon the Observer)
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
break;
+ case 64014: // Expedition Base Camp Teleport
+ case 64024: // Conservatory Teleport
+ case 64025: // Halls of Invention Teleport
+ case 64028: // Colossal Forge Teleport
+ case 64029: // Shattered Walkway Teleport
+ case 64030: // Antechamber Teleport
+ case 64031: // Scrapyard Teleport
+ case 64032: // Formation Grounds Teleport
+ case 65042: // Prison of Yogg-Saron Teleport
+ spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
+ break;
// ENDOF ULDUAR SPELLS
//
// TRIAL OF THE CRUSADER SPELLS
@@ -3447,7 +3458,7 @@ void SpellMgr::LoadSpellInfoCorrections()
case 71518: // Unholy Infusion Quest Credit (Professor Putricide)
case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
case 72289: // Frost Infusion Quest Credit (Sindragosa)
- spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // another missing radius
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // another missing radius
break;
case 71708: // Empowered Flare (Blood Prince Council)
case 72785: // Empowered Flare (Blood Prince Council)
diff --git a/src/server/game/Weather/Weather.cpp b/src/server/game/Weather/Weather.cpp
index ef1ee3ff08f..34a6ab35040 100644
--- a/src/server/game/Weather/Weather.cpp
+++ b/src/server/game/Weather/Weather.cpp
@@ -222,6 +222,9 @@ bool Weather::UpdateWeather()
char const* wthstr;
switch (state)
{
+ case WEATHER_STATE_FOG:
+ wthstr = "fog";
+ break;
case WEATHER_STATE_LIGHT_RAIN:
wthstr = "light rain";
break;
diff --git a/src/server/game/Weather/Weather.h b/src/server/game/Weather/Weather.h
index 3286d550157..bde4280cb25 100644
--- a/src/server/game/Weather/Weather.h
+++ b/src/server/game/Weather/Weather.h
@@ -46,7 +46,7 @@ struct WeatherData
enum WeatherState
{
WEATHER_STATE_FINE = 0,
- WEATHER_STATE_UNK = 1, // Used in some instance encounters.
+ WEATHER_STATE_FOG = 1, // Used in some instance encounters.
WEATHER_STATE_LIGHT_RAIN = 3,
WEATHER_STATE_MEDIUM_RAIN = 4,
WEATHER_STATE_HEAVY_RAIN = 5,
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 4a1d1566af1..1a7f4b8c2a9 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -979,7 +979,7 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = ConfigMgr::GetIntDefault("ChatFlood.MessageDelay", 1);
m_int_configs[CONFIG_CHATFLOOD_MUTE_TIME] = ConfigMgr::GetIntDefault("ChatFlood.MuteTime", 10);
- m_int_configs[CONFIG_EVENT_ANNOUNCE] = ConfigMgr::GetIntDefault("Event.Announce", 0);
+ m_bool_configs[CONFIG_EVENT_ANNOUNCE] = ConfigMgr::GetIntDefault("Event.Announce", false);
m_float_configs[CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS] = ConfigMgr::GetFloatDefault("CreatureFamilyFleeAssistanceRadius", 30.0f);
m_float_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS] = ConfigMgr::GetFloatDefault("CreatureFamilyAssistanceRadius", 10.0f);
@@ -1445,12 +1445,12 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature Model Based Info Data...");
sObjectMgr->LoadCreatureModelInfo();
- sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Equipment templates...");
- sObjectMgr->LoadEquipmentTemplates();
-
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature templates...");
sObjectMgr->LoadCreatureTemplates();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Equipment templates..."); // must be after LoadCreatureTemplates
+ sObjectMgr->LoadEquipmentTemplates();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Creature template addons...");
sObjectMgr->LoadCreatureTemplateAddons();
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 872a6c7afb3..e65eaf73983 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -174,6 +174,7 @@ enum WorldBoolConfigs
CONFIG_WINTERGRASP_ENABLE,
CONFIG_GUILD_LEVELING_ENABLED,
CONFIG_UI_QUESTLEVELS_IN_DIALOGS, // Should we add quest levels to the title in the NPC dialogs?
+ CONFIG_EVENT_ANNOUNCE,
BOOL_CONFIG_VALUE_COUNT
};
@@ -265,7 +266,6 @@ enum WorldIntConfigs
CONFIG_CHATFLOOD_MESSAGE_COUNT,
CONFIG_CHATFLOOD_MESSAGE_DELAY,
CONFIG_CHATFLOOD_MUTE_TIME,
- CONFIG_EVENT_ANNOUNCE,
CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY,
CONFIG_CREATURE_FAMILY_FLEE_DELAY,
CONFIG_WORLD_BOSS_LEVEL_DIFF,