Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-10-21 11:43:19 +08:00
92 changed files with 7381 additions and 667 deletions
+3 -3
View File
@@ -277,7 +277,7 @@ void PetAI::UpdateAI(uint32 diff)
{
if (CanAttack(target) && spell->CanAutoCast(target))
{
targetSpellStore.push_back(std::make_pair(target, spell));
targetSpellStore.emplace_back(target, spell);
spellUsed = true;
}
}
@@ -295,7 +295,7 @@ void PetAI::UpdateAI(uint32 diff)
if (spell->CanAutoCast(ally))
{
targetSpellStore.push_back(std::make_pair(ally, spell));
targetSpellStore.emplace_back(ally, spell);
spellUsed = true;
break;
}
@@ -310,7 +310,7 @@ void PetAI::UpdateAI(uint32 diff)
{
Spell* spell = new Spell(me, spellInfo, TRIGGERED_NONE);
if (spell->CanAutoCast(me->GetVictim()))
targetSpellStore.push_back(std::make_pair(me->GetVictim(), spell));
targetSpellStore.emplace_back(me->GetVictim(), spell);
else
delete spell;
}
+8 -11
View File
@@ -56,7 +56,7 @@ namespace AddonMgr
std::string name = fields[0].Get<std::string>();
uint32 crc = fields[1].Get<uint32>();
m_knownAddons.push_back(SavedAddon(name, crc));
m_knownAddons.emplace_back(name, crc);
++count;
} while (result->NextRow());
@@ -76,13 +76,12 @@ namespace AddonMgr
{
Field* fields = result->Fetch();
BannedAddon addon{};
addon.Id = fields[0].Get<uint32>() + offset;
addon.Timestamp = uint32(fields[3].Get<uint64>());
addon.NameMD5 = Acore::Crypto::MD5::GetDigestOf(fields[1].Get<std::string>());
addon.VersionMD5 = Acore::Crypto::MD5::GetDigestOf(fields[2].Get<std::string>());
uint32 Id = fields[0].Get<uint32>() + offset;
std::array<uint8, 16> NameMD5 = Acore::Crypto::MD5::GetDigestOf(fields[1].Get<std::string>());
std::array<uint8, 16> VersionMD5 = Acore::Crypto::MD5::GetDigestOf(fields[2].Get<std::string>());
uint32 Timestamp = uint32(fields[3].Get<uint64>());
m_bannedAddons.emplace_back(addon);
m_bannedAddons.emplace_back(Id, NameMD5, VersionMD5, Timestamp);
++count2;
} while (result->NextRow());
@@ -94,16 +93,14 @@ namespace AddonMgr
void SaveAddon(AddonInfo const& addon)
{
std::string name = addon.Name;
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ADDON);
stmt->SetData(0, name);
stmt->SetData(0, addon.Name);
stmt->SetData(1, addon.CRC);
CharacterDatabase.Execute(stmt);
m_knownAddons.push_back(SavedAddon(addon.Name, addon.CRC));
m_knownAddons.emplace_back(addon.Name, addon.CRC);
}
SavedAddon const* GetAddonInfo(const std::string& name)
+4 -4
View File
@@ -38,10 +38,7 @@ struct AddonInfo
struct SavedAddon
{
SavedAddon(std::string name, uint32 crc) : Name(std::move(name))
{
CRC = crc;
}
SavedAddon(std::string name, uint32 crc) : Name(std::move(name)), CRC(crc) {}
std::string Name;
uint32 CRC;
@@ -49,6 +46,9 @@ struct SavedAddon
struct BannedAddon
{
BannedAddon(uint32 id, std::array<uint8, 16> const& nameMD5, std::array<uint8, 16> const& versionMD5, uint32 timestamp)
: Id(id), NameMD5(nameMD5), VersionMD5(versionMD5), Timestamp(timestamp) {}
uint32 Id;
std::array<uint8, 16> NameMD5;
std::array<uint8, 16> VersionMD5;
+2 -2
View File
@@ -74,7 +74,7 @@ void ChannelMgr::LoadChannels()
if (!Utf8toWStr(channelName, channelWName))
{
LOG_ERROR("server.loading", "Failed to load channel '{}' from database - invalid utf8 sequence? Deleted.", channelName);
toDelete.push_back({ channelName, team });
toDelete.emplace_back(channelName, team);
continue;
}
@@ -82,7 +82,7 @@ void ChannelMgr::LoadChannels()
if (!mgr)
{
LOG_ERROR("server.loading", "Failed to load custom chat channel '{}' from database - invalid team {}. Deleted.", channelName, team);
toDelete.push_back({ channelName, team });
toDelete.emplace_back(channelName, team);
continue;
}
+8 -16
View File
@@ -78,21 +78,7 @@ void CharmInfo::InitPossessCreateSpells()
{
if (_unit->IsCreature())
{
// Adding switch until better way is found. Malcrom
// Adding entrys to this switch will prevent COMMAND_ATTACK being added to pet bar.
switch (_unit->GetEntry())
{
case 23575: // Mindless Abomination
case 24783: // Trained Rock Falcon
case 27664: // Crashin' Thrashin' Racer
case 40281: // Crashin' Thrashin' Racer
case 23109: // Vengeful Spirit
case 25653: // Power of the Blue Flight
break;
default:
InitEmptyActionBar();
break;
}
InitEmptyActionBar(false);
for (uint32 i = 0; i < MAX_CREATURE_SPELLS; ++i)
{
@@ -160,11 +146,14 @@ bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates new
{
uint32 spell_id = 0;
uint32 first_id = 0;
bool autocastable = false;
if (spellInfo)
{
spell_id = spellInfo->Id;
first_id = spellInfo->GetFirstRankSpell()->Id;
if (spellInfo->IsAutocastable())
autocastable = true;
}
// new spell rank can be already listed
@@ -188,7 +177,10 @@ bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates new
if (i != index && index <= MAX_UNIT_ACTION_BAR_INDEX)
continue;
SetActionBar(i, spell_id, newstate == ACT_DECIDE ? spellInfo->IsAutocastable() ? ACT_DISABLED : ACT_PASSIVE : newstate);
if (!spell_id && index == ACTION_BAR_INDEX_START)
SetActionBar(ACTION_BAR_INDEX_START, COMMAND_ATTACK, ACT_COMMAND);
else
SetActionBar(i, spell_id, newstate == ACT_DECIDE ? autocastable ? ACT_DISABLED : ACT_PASSIVE : newstate);
if (_unit->GetCharmer() && _unit->GetCharmer()->IsPlayer())
{
+28 -35
View File
@@ -1062,7 +1062,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
{
if (spellProto && victim->CanHaveThreatList() && !victim->HasUnitState(UNIT_STATE_EVADE) && !victim->IsInCombatWith(attacker))
{
victim->CombatStart(attacker, !(spellProto->AttributesEx3 & SPELL_ATTR3_SUPRESS_TARGET_PROCS));
victim->CombatStart(attacker, !(spellProto->AttributesEx3 & SPELL_ATTR3_SUPPRESS_TARGET_PROCS));
}
victim->AddThreat(attacker, float(damage), damageSchoolMask, spellProto);
@@ -4076,9 +4076,11 @@ void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool wi
if (spell->getState() != SPELL_STATE_FINISHED)
spell->cancel(bySelf);
m_currentSpells[spellType] = nullptr;
spell->SetReferencedFromCurrent(false);
else
{
m_currentSpells[spellType] = nullptr;
spell->SetReferencedFromCurrent(false);
}
}
}
@@ -5093,10 +5095,13 @@ void Unit::RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid)
++iter;
}
for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
{
if (iter->second->GetCastItemGUID() == castItemGuid)
RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT);
{
RemoveOwnedAura(iter, AURA_REMOVE_BY_DEFAULT);
iter = m_ownedAuras.lower_bound(spellId);
}
else
++iter;
}
@@ -19787,6 +19792,8 @@ void Unit::_ExitVehicle(Position const* exitPosition)
if (!m_vehicle)
return;
// This should be done before dismiss, because there may be some aura removal
VehicleSeatAddon const* seatAddon = m_vehicle->GetSeatAddonForSeatOfPassenger(this);
m_vehicle->RemovePassenger(this);
Player* player = ToPlayer();
@@ -19795,7 +19802,6 @@ void Unit::_ExitVehicle(Position const* exitPosition)
if (player && player->duel && player->duel->IsMounted)
player->DuelComplete(DUEL_FLED);
// This should be done before dismiss, because there may be some aura removal
Vehicle* vehicle = m_vehicle;
Unit* vehicleBase = m_vehicle->GetBase();
m_vehicle = nullptr;
@@ -19806,33 +19812,22 @@ void Unit::_ExitVehicle(Position const* exitPosition)
SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
Position pos;
if (!exitPosition) // Exit position not specified
pos = vehicleBase->GetPosition(); // This should use passenger's current position, leaving it as it is now
// because we calculate positions incorrect (sometimes under map)
else
// If we ask for a specific exit position, use that one. Otherwise allow scripts to modify it
if (exitPosition)
pos = *exitPosition;
// HACK
VehicleEntry const* vehicleInfo = vehicle->GetVehicleInfo();
if (vehicleInfo)
else
{
if (vehicleInfo->m_ID == 380) // Kologarn right arm
// Set exit position to vehicle position and use the current orientation
pos = vehicleBase->GetPosition(); // This should use passenger's current position, leaving it as it is now
pos.SetOrientation(vehicleBase->GetOrientation());
// Change exit position based on seat entry addon data
if (seatAddon)
{
pos.Relocate(1776.0f, -24.0f, 448.75f, 0.0f);
}
else if (vehicleInfo->m_ID == 91) // Helsman's Ship
{
pos.Relocate(2802.18f, 7054.91f, -0.6f, 4.67f);
}
else if (vehicleInfo->m_ID == 349) // AT Mounts, dismount to the right
{
float x = pos.GetPositionX() + 2.0f * cos(pos.GetOrientation() - M_PI / 2.0f);
float y = pos.GetPositionY() + 2.0f * std::sin(pos.GetOrientation() - M_PI / 2.0f);
float z = GetMapHeight(x, y, pos.GetPositionZ());
if (z > INVALID_HEIGHT)
{
pos.Relocate(x, y, z);
}
if (seatAddon->ExitParameter == VehicleExitParameters::VehicleExitParamOffset)
pos.RelocateOffset({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
else if (seatAddon->ExitParameter == VehicleExitParameters::VehicleExitParamDest)
pos.Relocate({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
}
}
@@ -19852,11 +19847,12 @@ void Unit::_ExitVehicle(Position const* exitPosition)
}
// xinef: hack for flameleviathan seat vehicle
VehicleEntry const* vehicleInfo = vehicle->GetVehicleInfo();
if (!vehicleInfo || vehicleInfo->m_ID != 341)
{
Movement::MoveSplineInit init(this);
init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
init.SetFacing(GetOrientation());
init.SetFacing(vehicleBase->GetOrientation());
init.SetTransportExit();
init.Launch();
}
@@ -19909,10 +19905,7 @@ void Unit::_ExitVehicle(Position const* exitPosition)
setDeathState(DeathState::JustDied);
// If for other reason we as minion are exiting the vehicle (ejected, master dismounted) - unsummon
else
{
SetVisible(false);
ToTempSummon()->UnSummon(2000); // Approximation
}
}
if (player)
+31 -14
View File
@@ -34,15 +34,18 @@ Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry)
if (uint32 seatId = _vehicleInfo->m_seatID[i])
if (VehicleSeatEntry const* veSeat = sVehicleSeatStore.LookupEntry(seatId))
{
Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
VehicleSeatAddon const* addon = sObjectMgr->GetVehicleSeatAddon(seatId);
Seats.insert(std::make_pair(i, VehicleSeat(veSeat, addon)));
if (veSeat->CanEnterOrExit())
++_usableSeatNum;
}
}
// Ulduar demolisher
if (vehInfo->m_ID == 338)
++_usableSeatNum;
// Set or remove correct flags based on available seats. Will overwrite db data (if wrong).
if (_usableSeatNum)
_me->SetNpcFlag((_me->IsPlayer() ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
else
_me->RemoveNpcFlag((_me->IsPlayer() ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK));
InitMovementInfoForBase();
}
@@ -230,6 +233,15 @@ Unit* Vehicle::GetPassenger(int8 seatId) const
return ObjectAccessor::GetUnit(*GetBase(), seat->second.Passenger.Guid);
}
VehicleSeatAddon const* Vehicle::GetSeatAddonForSeatOfPassenger(Unit const* passenger) const
{
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); itr++)
if (!itr->second.IsEmpty() && itr->second.Passenger.Guid == passenger->GetGUID())
return itr->second.SeatAddon;
return nullptr;
}
int8 Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
@@ -356,12 +368,9 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
ASSERT(_usableSeatNum);
--_usableSeatNum;
if (!_usableSeatNum)
{
if (_me->IsPlayer())
_me->RemoveNpcFlag(UNIT_NPC_FLAG_PLAYER_VEHICLE);
else
_me->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK);
}
_me->RemoveNpcFlag(_me->IsPlayer() ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK);
else
_me->SetNpcFlag(_me->IsPlayer() ? UNIT_NPC_FLAG_PLAYER_VEHICLE : UNIT_NPC_FLAG_SPELLCLICK);
}
if (!_me || !_me->IsInWorld() || _me->IsDuringRemoveFromWorld())
@@ -376,7 +385,14 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
VehicleSeatEntry const* veSeat = seat->second.SeatInfo;
unit->m_movementInfo.transport.pos.Relocate(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
VehicleSeatAddon const* veSeatAddon = seat->second.SeatAddon;
float o = veSeatAddon ? veSeatAddon->SeatOrientationOffset : 0.f;
float x = veSeat->m_attachmentOffsetX;
float y = veSeat->m_attachmentOffsetY;
float z = veSeat->m_attachmentOffsetZ;
unit->m_movementInfo.transport.pos.Relocate(x, y, z, o);
unit->m_movementInfo.transport.time = 0;
unit->m_movementInfo.transport.seat = seat->first;
unit->m_movementInfo.transport.guid = _me->GetGUID();
@@ -410,16 +426,17 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
// also adds MOVEMENTFLAG_ROOT
Movement::MoveSplineInit init(unit);
init.DisableTransportPathTransformations();
init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
init.MoveTo(x, y, z, false, true);
// Xinef: did not found anything unique in dbc, maybe missed something
if (veSeat->m_ID == 3566 || veSeat->m_ID == 3567 || veSeat->m_ID == 3568 || veSeat->m_ID == 3570)
{
float x = veSeat->m_attachmentOffsetX, y = veSeat->m_attachmentOffsetY, z = veSeat->m_attachmentOffsetZ, o;
CalculatePassengerPosition(x, y, z, &o);
init.SetFacing(_me->GetAngle(x, y));
}
else
init.SetFacing(0.0f);
{
init.SetFacing(o);
}
init.SetTransportEnter();
init.Launch();
@@ -41,6 +41,7 @@ public:
bool HasEmptySeat(int8 seatId) const;
Unit* GetPassenger(int8 seatId) const;
int8 GetNextEmptySeat(int8 seatId, bool next) const;
VehicleSeatAddon const* GetSeatAddonForSeatOfPassenger(Unit const* passenger) const;
uint8 GetAvailableSeatCount() const;
bool AddPassenger(Unit* passenger, int8 seatId = -1);
@@ -57,6 +57,14 @@ enum VehicleSpells
VEHICLE_SPELL_SHADE_CONTROL_END = 58664
};
enum class VehicleExitParameters
{
VehicleExitParamNone = 0, // provided parameters will be ignored
VehicleExitParamOffset = 1, // provided parameters will be used as offset values
VehicleExitParamDest = 2, // provided parameters will be used as absolute destination
VehicleExitParamMax
};
enum VehicleNPCs
{
NPC_EIDOLON_WATCHER = 31110,
@@ -75,9 +83,24 @@ struct PassengerInfo
}
};
struct VehicleSeatAddon
{
VehicleSeatAddon() { }
VehicleSeatAddon(float orientatonOffset, float exitX, float exitY, float exitZ, float exitO, uint8 param) :
SeatOrientationOffset(orientatonOffset), ExitParameterX(exitX), ExitParameterY(exitY), ExitParameterZ(exitZ),
ExitParameterO(exitO), ExitParameter(VehicleExitParameters(param)) { }
float SeatOrientationOffset = 0.f;
float ExitParameterX = 0.f;
float ExitParameterY = 0.f;
float ExitParameterZ = 0.f;
float ExitParameterO = 0.f;
VehicleExitParameters ExitParameter = VehicleExitParameters::VehicleExitParamNone;
};
struct VehicleSeat
{
explicit VehicleSeat(VehicleSeatEntry const* seatInfo) : SeatInfo(seatInfo)
explicit VehicleSeat(VehicleSeatEntry const* seatInfo, VehicleSeatAddon const* seatAddon) : SeatInfo(seatInfo), SeatAddon(seatAddon)
{
Passenger.Reset();
}
@@ -85,6 +108,7 @@ struct VehicleSeat
[[nodiscard]] bool IsEmpty() const { return !Passenger.Guid; }
VehicleSeatEntry const* SeatInfo;
VehicleSeatAddon const* SeatAddon;
PassengerInfo Passenger;
};
+56
View File
@@ -3483,6 +3483,62 @@ void ObjectMgr::LoadVehicleAccessories()
LOG_INFO("server.loading", " ");
}
void ObjectMgr::LoadVehicleSeatAddon()
{
uint32 oldMSTime = getMSTime();
_vehicleSeatAddonStore.clear(); // needed for reload case
uint32 count = 0;
// 0 1 2 3 4 5 6
QueryResult result = WorldDatabase.Query("SELECT `SeatEntry`, `SeatOrientation`, `ExitParamX`, `ExitParamY`, `ExitParamZ`, `ExitParamO`, `ExitParamValue` FROM `vehicle_seat_addon`");
if (!result)
{
LOG_ERROR("server.loading", ">> Loaded 0 vehicle seat addons. DB table `vehicle_seat_addon` is empty.");
return;
}
do
{
Field* fields = result->Fetch();
uint32 seatID = fields[0].Get<uint32>();
float orientation = fields[1].Get<float>();
float exitX = fields[2].Get<float>();
float exitY = fields[3].Get<float>();
float exitZ = fields[4].Get<float>();
float exitO = fields[5].Get<float>();
uint8 exitParam = fields[6].Get<uint8>();
if (!sVehicleSeatStore.LookupEntry(seatID))
{
LOG_ERROR("sql.sql", "Table `vehicle_seat_addon`: SeatID: %u does not exist in VehicleSeat.dbc. Skipping entry.", seatID);
continue;
}
// Sanitizing values
if (orientation > float(M_PI * 2))
{
LOG_ERROR("sql.sql", "Table `vehicle_seat_addon`: SeatID: %u is using invalid angle offset value (%f). Set Value to 0.", seatID, orientation);
orientation = 0.0f;
}
if (exitParam >= AsUnderlyingType(VehicleExitParameters::VehicleExitParamMax))
{
LOG_ERROR("sql.sql", "Table `vehicle_seat_addon`: SeatID: %u is using invalid exit parameter value (%u). Setting to 0 (none).", seatID, exitParam);
continue;
}
_vehicleSeatAddonStore[seatID] = VehicleSeatAddon(orientation, exitX, exitY, exitZ, exitO, exitParam);
++count;
} while (result->NextRow());
LOG_INFO("server.loading", ">> Loaded %u Vehicle Seat Addon entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadPetLevelInfo()
{
uint32 oldMSTime = getMSTime();
+12
View File
@@ -518,6 +518,7 @@ typedef std::map<std::pair<std::string, uint32>, ModuleString> ModuleStringConta
typedef std::unordered_map<int32, AcoreString> AcoreStringContainer;
typedef std::unordered_map<uint32, GossipMenuItemsLocale> GossipMenuItemsLocaleContainer;
typedef std::unordered_map<uint32, PointOfInterestLocale> PointOfInterestLocaleContainer;
typedef std::unordered_map<uint32, VehicleSeatAddon> VehicleSeatAddonContainer;
typedef std::multimap<uint32, uint32> QuestRelations;
typedef std::pair<QuestRelations::const_iterator, QuestRelations::const_iterator> QuestRelationBounds;
@@ -1053,6 +1054,7 @@ public:
void LoadMailServerTemplates();
void LoadVehicleTemplateAccessories();
void LoadVehicleAccessories();
void LoadVehicleSeatAddon();
void LoadGossipText();
@@ -1430,6 +1432,15 @@ public:
[[nodiscard]] bool IsTransportMap(uint32 mapId) const { return _transportMaps.count(mapId) != 0; }
VehicleSeatAddon const* GetVehicleSeatAddon(uint32 seatId) const
{
VehicleSeatAddonContainer::const_iterator itr = _vehicleSeatAddonStore.find(seatId);
if (itr == _vehicleSeatAddonStore.end())
return nullptr;
return &itr->second;
}
[[nodiscard]] uint32 GetQuestMoneyReward(uint8 level, uint32 questMoneyDifficulty) const;
void SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint32 reqPlayTime, uint32 rewardMoneyA, uint32 rewardMoneyH, uint32 rewardItemA, uint32 rewardItemCountA, uint32 rewardItemH, uint32 rewardItemCountH, std::string subject, std::string body, uint8 active) const;
private:
@@ -1507,6 +1518,7 @@ private:
VehicleAccessoryContainer _vehicleTemplateAccessoryStore;
VehicleAccessoryContainer _vehicleAccessoryStore;
VehicleSeatAddonContainer _vehicleSeatAddonStore;
LocaleConstant DBCLocaleIndex;
@@ -986,9 +986,6 @@ void WorldSession::HandleMoveRootAck(WorldPacket& recvData)
mover->m_movementInfo = movementInfo;
mover->UpdatePosition(movementInfo.pos);
WorldPacket data(MSG_MOVE_ROOT, 64);
WriteMovementInfo(&data, &movementInfo);
mover->SendMessageToSet(&data, _player);
}
void WorldSession::HandleMoveUnRootAck(WorldPacket& recvData)
@@ -1031,7 +1028,4 @@ void WorldSession::HandleMoveUnRootAck(WorldPacket& recvData)
mover->m_movementInfo = movementInfo;
mover->UpdatePosition(movementInfo.pos);
WorldPacket data(MSG_MOVE_UNROOT, 64);
WriteMovementInfo(&data, &movementInfo);
mover->SendMessageToSet(&data, _player);
}
+15 -19
View File
@@ -38,14 +38,8 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket& recvData)
recvData >> guid;
uint32 questStatus = DIALOG_STATUS_NONE;
GossipMenu& gossipMenu = _player->PlayerTalkClass->GetGossipMenu();
// Did we already get a gossip menu with that NPC? if so no need to status query
if (gossipMenu.GetSenderGUID() == guid)
{
return;
}
Object* questGiver = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT);
if (!questGiver)
{
LOG_DEBUG("network.opcode", "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for not found questgiver ({})", guid.ToString());
@@ -55,21 +49,23 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPacket& recvData)
switch (questGiver->GetTypeId())
{
case TYPEID_UNIT:
{
LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc {}", guid.ToString());
if (!questGiver->ToCreature()->IsHostileTo(_player)) // do not show quest status to enemies
questStatus = _player->GetQuestDialogStatus(questGiver);
break;
}
{
LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for npc {}", guid.ToString());
if (!questGiver->ToCreature()->IsHostileTo(_player)) // do not show quest status to enemies
questStatus = _player->GetQuestDialogStatus(questGiver);
break;
}
case TYPEID_GAMEOBJECT:
{
LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject {}", guid.ToString());
if (sWorld->getBoolConfig(CONFIG_OBJECT_QUEST_MARKERS))
{
LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_STATUS_QUERY for GameObject {}", guid.ToString());
if (sWorld->getBoolConfig(CONFIG_OBJECT_QUEST_MARKERS))
{
questStatus = _player->GetQuestDialogStatus(questGiver);
}
break;
questStatus = _player->GetQuestDialogStatus(questGiver);
}
break;
}
default:
LOG_ERROR("network.opcode", "QuestGiver called for unexpected type {}", questGiver->GetTypeId());
break;
+5 -5
View File
@@ -54,8 +54,8 @@ void LootItemStorage::LoadStorageFromDB()
Field* fields = result->Fetch();
StoredLootItemList& itemList = lootItemStore[ObjectGuid::Create<HighGuid::Item>(fields[0].Get<uint32>())];
itemList.push_back(StoredLootItem(fields[1].Get<uint32>(), fields[2].Get<uint32>(), fields[3].Get<uint32>(), fields[4].Get<int32>(), fields[5].Get<uint32>(), fields[6].Get<bool>(),
fields[7].Get<bool>(), fields[8].Get<bool>(), fields[9].Get<bool>(), fields[10].Get<bool>(), fields[11].Get<bool>(), fields[12].Get<uint32>()));
itemList.emplace_back(fields[1].Get<uint32>(), fields[2].Get<uint32>(), fields[3].Get<uint32>(), fields[4].Get<int32>(), fields[5].Get<uint32>(), fields[6].Get<bool>(),
fields[7].Get<bool>(), fields[8].Get<bool>(), fields[9].Get<bool>(), fields[10].Get<bool>(), fields[11].Get<bool>(), fields[12].Get<uint32>());
++count;
} while (result->NextRow());
@@ -94,7 +94,7 @@ void LootItemStorage::AddNewStoredLoot(Loot* loot, Player* /*player*/)
// Gold at first
if (loot->gold)
{
itemList.push_back(StoredLootItem(0, 0, loot->gold, 0, 0, false, false, false, false, false, false, 0));
itemList.emplace_back(0, 0, loot->gold, 0, 0, false, false, false, false, false, false, 0);
uint8 index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM);
@@ -134,8 +134,8 @@ void LootItemStorage::AddNewStoredLoot(Loot* loot, Player* /*player*/)
conditionLootId = li->conditions.front()->SourceGroup;
}
itemList.push_back(StoredLootItem(li->itemid, li->itemIndex, li->count, li->randomPropertyId, li->randomSuffix, li->follow_loot_rules, li->freeforall, li->is_blocked, li->is_counted,
li->is_underthreshold, li->needs_quest, conditionLootId));
itemList.emplace_back(li->itemid, li->itemIndex, li->count, li->randomPropertyId, li->randomSuffix, li->follow_loot_rules, li->freeforall, li->is_blocked, li->is_counted,
li->is_underthreshold, li->needs_quest, conditionLootId);
uint8 index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_SINGLE_ITEM);
+2 -2
View File
@@ -109,7 +109,7 @@ void LoadSkillDiscoveryTable()
continue;
}
SkillDiscoveryStore[reqSkillOrSpell].push_back(SkillDiscoveryEntry(spellId, reqSkillValue, chance));
SkillDiscoveryStore[reqSkillOrSpell].emplace_back(spellId, reqSkillValue, chance);
}
else if (reqSkillOrSpell == 0) // skill case
{
@@ -122,7 +122,7 @@ void LoadSkillDiscoveryTable()
}
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
SkillDiscoveryStore[-int32(_spell_idx->second->SkillLine)].push_back(SkillDiscoveryEntry(spellId, reqSkillValue, chance));
SkillDiscoveryStore[-int32(_spell_idx->second->SkillLine)].emplace_back(spellId, reqSkillValue, chance);
}
else
{
+16 -14
View File
@@ -2677,7 +2677,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
CallScriptBeforeHitHandlers(missInfo);
//Spells with this flag cannot trigger if effect is casted on self
bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2);
bool canEffectTrigger = !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS) && unitTarget->CanProc() && (CanExecuteTriggersOnHit(mask) || missInfo == SPELL_MISS_IMMUNE2);
bool reflectedSpell = missInfo == SPELL_MISS_REFLECT;
Unit* spellHitTarget = nullptr;
@@ -2890,7 +2890,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
m_triggeredByAuraSpell.effectIndex, this, &dmgInfo);
if (caster->IsPlayer() && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 &&
m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
m_spellInfo->HasAttribute(SPELL_ATTR4_SUPPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx);
}
@@ -2912,7 +2912,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
// Xinef: eg. rogue poisons can proc off cheap shot, etc. so this block should be here also
// Xinef: ofc count only spells that HIT the target, little hack used to fool the system
if ((procEx & PROC_EX_NORMAL_HIT || procEx & PROC_EX_CRITICAL_HIT) && caster->IsPlayer() && m_spellInfo->HasAttribute(SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT) == 0 &&
m_spellInfo->HasAttribute(SPELL_ATTR4_SUPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
m_spellInfo->HasAttribute(SPELL_ATTR4_SUPPRESS_WEAPON_PROCS) == 0 && (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED))
caster->ToPlayer()->CastItemCombatSpell(unitTarget, m_attackType, procVictim | PROC_FLAG_TAKEN_DAMAGE, procEx);
}
@@ -2930,7 +2930,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(effectUnit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
{
if (!m_triggeredByAuraSpell.spellInfo || m_damage || (!(m_triggeredByAuraSpell.spellInfo->Effects[m_triggeredByAuraSpell.effectIndex].TriggerSpell == m_spellInfo->Id) && !(m_triggeredByAuraSpell.spellInfo->IsAuraEffectEqual(m_spellInfo))))
m_caster->CombatStart(effectUnit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_SUPRESS_TARGET_PROCS));
m_caster->CombatStart(effectUnit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_SUPPRESS_TARGET_PROCS));
// Patch 3.0.8: All player spells which cause a creature to become aggressive to you will now also immediately cause the creature to be tapped.
if (effectUnit->IsInCombatWith(m_caster))
@@ -3079,7 +3079,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
}
// xinef: triggered spells should not prolong combat
if (unit->IsInCombat() && !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_TARGET_PROCS) && !m_triggeredByAuraSpell)
if (unit->IsInCombat() && !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS) && !m_triggeredByAuraSpell)
{
m_caster->SetInCombatState(unit->GetCombatTimer() > 0, unit);
unit->getHostileRefMgr().threatAssist(m_caster, 0.0f);
@@ -3840,8 +3840,8 @@ void Spell::_cast(bool skipCheck)
// As of 3.0.2 pets begin attacking their owner's target immediately
// Let any pets know we've attacked something. Check DmgClass for harmful spells only
// This prevents spells such as Hunter's Mark from triggering pet attack
// xinef: take into account SPELL_ATTR3_SUPRESS_TARGET_PROCS
if ((m_targets.GetTargetMask() & TARGET_FLAG_UNIT) && GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE && !GetSpellInfo()->HasAttribute(SPELL_ATTR3_SUPRESS_TARGET_PROCS))
// xinef: take into account SPELL_ATTR3_SUPPRESS_TARGET_PROCS
if ((m_targets.GetTargetMask() & TARGET_FLAG_UNIT) && GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE && !GetSpellInfo()->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS))
if (!playerCaster->m_Controlled.empty())
for (Unit::ControlSet::iterator itr = playerCaster->m_Controlled.begin(); itr != playerCaster->m_Controlled.end(); ++itr)
if (Unit* pet = *itr)
@@ -4081,13 +4081,15 @@ void Spell::_cast(bool skipCheck)
if (modOwner)
modOwner->SetSpellModTakingSpell(this, false);
if (const std::vector<int32>* spell_triggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id))
if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id))
{
for (std::vector<int32>::const_iterator i = spell_triggered->begin(); i != spell_triggered->end(); ++i)
if (*i < 0)
m_caster->RemoveAurasDueToSpell(-(*i));
for (int32 id : *spell_triggered)
{
if (id < 0)
m_caster->RemoveAurasDueToSpell(-id);
else
m_caster->CastSpell(m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : m_caster, *i, true);
m_caster->CastSpell(m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : m_caster, id, true);
}
}
// Interrupt Spell casting
@@ -4101,7 +4103,7 @@ void Spell::_cast(bool skipCheck)
if (Unit* target = m_targets.GetUnitTarget())
if (m_caster->IsPlayer() || (m_caster->IsPet() && m_caster->IsControlledByPlayer()))
if (GetDelayMoment() > 0 && !m_caster->IsFriendlyTo(target) && !m_spellInfo->HasAura(SPELL_AURA_BIND_SIGHT) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
m_caster->CombatStartOnCast(target, !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_TARGET_PROCS), GetDelayMoment() + 500); // xinef: increase this time so we dont leave and enter combat in a moment
m_caster->CombatStartOnCast(target, !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS), GetDelayMoment() + 500); // xinef: increase this time so we dont leave and enter combat in a moment
if (m_caster->IsPlayer())
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
@@ -5580,7 +5582,7 @@ void Spell::HandleThreatSpells()
if (m_UniqueTargetInfo.empty())
return;
if (m_spellInfo->HasAttribute(SPELL_ATTR1_NO_THREAT) || m_spellInfo->HasAttribute(SPELL_ATTR3_SUPRESS_TARGET_PROCS))
if (m_spellInfo->HasAttribute(SPELL_ATTR1_NO_THREAT) || m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS))
return;
float threat = 0.0f;
+40 -38
View File
@@ -304,12 +304,6 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->ProcCharges = 6;
});
// The Eye of Acherus (no spawn in phase 2 in db)
ApplySpellFix({ 51852 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].MiscValue |= 1;
});
// Crafty's Ultra-Advanced Proto-Typical Shortening Blaster
ApplySpellFix({ 51912 }, [](SpellInfo* spellInfo)
{
@@ -589,7 +583,7 @@ void SpellMgr::LoadSpellInfoCorrections()
{
// hack for seal of light and few spells, judgement consists of few single casts and each of them can proc
// some spell, base one has disabled proc flag but those dont have this flag
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Blessing of sanctuary stats
@@ -611,7 +605,13 @@ void SpellMgr::LoadSpellInfoCorrections()
// Seal of Command trigger
ApplySpellFix({ 20424 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Arcane Missiles
ApplySpellFix({ 5143, 5144, 5145, 8416, 8417, 10211, 10212, 25345, 27075, 38699, 38704, 42843, 42846 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
ApplySpellFix({
@@ -637,7 +637,7 @@ void SpellMgr::LoadSpellInfoCorrections()
ApplySpellFix({ 3411 }, [](SpellInfo* spellInfo)
{
spellInfo->Attributes |= SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Roar of Sacrifice
@@ -742,7 +742,7 @@ void SpellMgr::LoadSpellInfoCorrections()
6774 // Slice and Dice
}, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Envenom
@@ -817,7 +817,7 @@ void SpellMgr::LoadSpellInfoCorrections()
ApplySpellFix({ 50526 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_CASTER_MODIFIERS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Dancing Rune Weapon
@@ -856,13 +856,13 @@ void SpellMgr::LoadSpellInfoCorrections()
// Scourge Strike trigger
ApplySpellFix({ 70890 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Blood-caked Blade - Blood-caked Strike trigger
ApplySpellFix({ 50463 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Blood Gorged
@@ -1080,7 +1080,7 @@ void SpellMgr::LoadSpellInfoCorrections()
// Living Bomb
ApplySpellFix({ 44461, 55361, 55362 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
spellInfo->AttributesEx4 |= SPELL_ATTR4_REACTIVE_DAMAGE_PROC;
});
@@ -1294,13 +1294,13 @@ void SpellMgr::LoadSpellInfoCorrections()
ApplySpellFix({ 49376 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_3_YARDS); // 3yd
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Feral Charge - Cat
ApplySpellFix({ 61138, 61132, 50259 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Glyph of Barkskin
@@ -2190,7 +2190,7 @@ void SpellMgr::LoadSpellInfoCorrections()
// Oculus, Drake spell Stop Time
ApplySpellFix({ 49838 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
spellInfo->ExcludeTargetAuraSpell = 51162; // exclude planar shift
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_150_YARDS);
});
@@ -2277,7 +2277,7 @@ void SpellMgr::LoadSpellInfoCorrections()
{
spellInfo->Attributes |= SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT;
spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Trial of the Crusader, Lich King Intro spell
@@ -2313,7 +2313,7 @@ void SpellMgr::LoadSpellInfoCorrections()
{
spellInfo->Attributes |= SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT;
spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
ApplySpellFix({ 66318 }, [](SpellInfo* spellInfo)
@@ -2323,7 +2323,7 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Speed = 14.0f;
spellInfo->Attributes |= SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT;
spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
ApplySpellFix({ 66320, 67472, 67473, 67475 }, [](SpellInfo* spellInfo)
@@ -2907,7 +2907,7 @@ void SpellMgr::LoadSpellInfoCorrections()
// Lock Players and Tap Chest
ApplySpellFix({ 72347 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Award Reputation - Boss Kill
@@ -2940,7 +2940,7 @@ void SpellMgr::LoadSpellInfoCorrections()
{
// Patch 3.3.2 (2010-01-02): Deathbringer Saurfang will no longer gain blood power from Mark of the Fallen Champion.
// prevented in script, effect needed for Prayer of Mending
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Coldflame Jets (Traps after Saurfang)
@@ -3463,7 +3463,7 @@ void SpellMgr::LoadSpellInfoCorrections()
// A Tangled Skein
ApplySpellFix({ 51165, 51173 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
ApplySpellFix({
@@ -3657,13 +3657,13 @@ void SpellMgr::LoadSpellInfoCorrections()
// Frankly, It Makes No Sense... (10672)
ApplySpellFix({ 37851 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Honor Challenge (12939)
ApplySpellFix({ 21855 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Convocation at Zol'Heb (12730)
@@ -4088,7 +4088,7 @@ void SpellMgr::LoadSpellInfoCorrections()
53725 // Judgement of the Martyr
}, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 &= ~SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Chaos Bolt Passive
@@ -4188,7 +4188,7 @@ void SpellMgr::LoadSpellInfoCorrections()
// Brood Power : Bronze
ApplySpellFix({ 22311 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Rapture
@@ -4196,7 +4196,7 @@ void SpellMgr::LoadSpellInfoCorrections()
{
spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Everlasting Affliction
@@ -4306,7 +4306,7 @@ void SpellMgr::LoadSpellInfoCorrections()
// Death's Respite
ApplySpellFix({ 67731, 68305 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Wyvern Sting DoT
@@ -4367,7 +4367,7 @@ void SpellMgr::LoadSpellInfoCorrections()
// Uppercut
ApplySpellFix({ 26007 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Digestive Acid (Temporary)
@@ -4388,7 +4388,7 @@ void SpellMgr::LoadSpellInfoCorrections()
ApplySpellFix({ 6754 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Summon Cauldron Stuff
@@ -4749,8 +4749,8 @@ void SpellMgr::LoadSpellInfoCorrections()
// Gor'drek's Ointment
ApplySpellFix({ 32578 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
});
// Shadow Grasp
@@ -4813,7 +4813,7 @@ void SpellMgr::LoadSpellInfoCorrections()
7376 // Defensive Stance Passive
}, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_CASTER_PROCS;
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
// Conjure Refreshment Table (Rank 1, Rank 2)
@@ -4850,6 +4850,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(7);
});
// Siphon Life (heal)
ApplySpellFix({ 63106 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];
@@ -4986,10 +4992,6 @@ void SpellMgr::LoadSpellInfoCorrections()
vse->m_flags &= ~VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE;
vse = const_cast<VehicleSeatEntry*>(sVehicleSeatStore.LookupEntry(4693)); // Siege Engine, Accessory
vse->m_flags &= ~VEHICLE_SEAT_FLAG_PASSENGER_NOT_SELECTABLE;
vse = const_cast<VehicleSeatEntry*>(sVehicleSeatStore.LookupEntry(3011)); // Salvaged Demolisher, Ulduar - not allow to change seats
vse->m_flags &= ~VEHICLE_SEAT_FLAG_CAN_SWITCH;
vse = const_cast<VehicleSeatEntry*>(sVehicleSeatStore.LookupEntry(3077)); // Salvaged Demolisher Seat, Ulduar - not allow to change seats
vse->m_flags &= ~VEHICLE_SEAT_FLAG_CAN_SWITCH;
// pussywizard: fix z offset for some vehicles:
vse = const_cast<VehicleSeatEntry*>(sVehicleSeatStore.LookupEntry(6206)); // Marrowgar - Bone Spike
+3
View File
@@ -1818,6 +1818,9 @@ void World::SetInitialWorldSettings()
LOG_INFO("server.loading", "Loading Vehicle Accessories...");
sObjectMgr->LoadVehicleAccessories(); // must be after LoadCreatureTemplates() and LoadNPCSpellClickSpells()
LOG_INFO("server.loading", "Loading Vehicle Seat Addon Data...");
sObjectMgr->LoadVehicleSeatAddon(); // must be after loading DBC
LOG_INFO("server.loading", "Loading SpellArea Data..."); // must be after quest load
sSpellMgr->LoadSpellAreas();
+3 -3
View File
@@ -362,7 +362,7 @@ public:
continue;
}
questItems.push_back(std::pair(id, count));
questItems.emplace_back(id, count);
}
if (!questItems.empty())
@@ -585,7 +585,7 @@ public:
for (uint32 const& itemId : quest->RewardChoiceItemId)
{
uint8 index = 0;
questRewardItems.push_back(std::pair(itemId, quest->RewardChoiceItemCount[index++]));
questRewardItems.emplace_back(itemId, quest->RewardChoiceItemCount[index++]);
}
}
@@ -594,7 +594,7 @@ public:
for (uint32 const& itemId : quest->RewardItemId)
{
uint8 index = 0;
questRewardItems.push_back(std::pair(itemId, quest->RewardItemIdCount[index++]));
questRewardItems.emplace_back(itemId, quest->RewardItemIdCount[index++]);
}
}
@@ -56,14 +56,22 @@ public:
{
npc_crusade_persuadedAI(Creature* creature) : CombatAI(creature) { }
const uint32 SAY_AGGRO_CHANCE = 33;
const uint32 PERSUADE_SUCCESS_CHANCE = 3; // 30% chance
const uint32 SPEECH_TIMER_DEFAULT = 1000;
const uint32 SPEECH_TIMER_FOR_ROLEPLAY = 8000;
const uint32 SPEECH_COUNTER_PREVENT_SUCCESS_ROLEPLAY = 0;
const uint32 SPEECH_COUNTER_START_SUCCESS_ROLEPLAY = 1;
uint32 speechTimer;
uint32 speechCounter;
ObjectGuid playerGUID;
bool persuaded;
void Reset() override
{
speechTimer = 0;
speechCounter = 0;
speechCounter = SPEECH_COUNTER_PREVENT_SUCCESS_ROLEPLAY;
playerGUID.Clear();
me->SetReactState(REACT_AGGRESSIVE);
me->RestoreFaction();
@@ -71,7 +79,7 @@ public:
void JustEngagedWith(Unit*) override
{
if (roll_chance_i(33))
if (roll_chance_i(SAY_AGGRO_CHANCE))
Talk(SAY_AGGRO);
}
@@ -81,20 +89,23 @@ public:
{
if (Player* player = caster->ToPlayer())
{
if (player->GetQuestStatus(QUEST_HOW_TO_WIN_FRIENDS) == QUEST_STATUS_INCOMPLETE)
playerGUID = player->GetGUID();
speechTimer = SPEECH_TIMER_DEFAULT;
speechCounter = SPEECH_COUNTER_START_SUCCESS_ROLEPLAY;
uint32 persuadeRoll = urand(1, 10);
sCreatureTextMgr->SendChat(me, SAY_PERSUADE_RAND, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, player);
if (persuadeRoll <= PERSUADE_SUCCESS_CHANCE && player->GetQuestStatus(QUEST_HOW_TO_WIN_FRIENDS) == QUEST_STATUS_INCOMPLETE)
{
playerGUID = player->GetGUID();
speechTimer = 1000;
speechCounter = 1;
persuaded = true;
me->SetFaction(player->GetFaction());
me->CombatStop(true);
me->GetMotionMaster()->MoveIdle();
me->SetReactState(REACT_PASSIVE);
DoCastAOE(SPELL_THREAT_PULSE, true);
sCreatureTextMgr->SendChat(me, SAY_PERSUADE_RAND, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, player);
Talk(SAY_CRUSADER);
}
else
persuaded = false;
}
}
}
@@ -112,46 +123,53 @@ public:
return;
}
switch (speechCounter)
if (persuaded)
{
switch (speechCounter)
{
case 1:
Talk(SAY_PERSUADED1);
speechTimer = 8000;
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 2:
Talk(SAY_PERSUADED2);
speechTimer = 8000;
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 3:
Talk(SAY_PERSUADED3);
speechTimer = 8000;
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 4:
Talk(SAY_PERSUADED4);
speechTimer = 8000;
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 5:
sCreatureTextMgr->SendChat(me, SAY_PERSUADED5, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, player);
speechTimer = 8000;
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 6:
Talk(SAY_PERSUADED6);
Unit::Kill(player, me);
speechCounter = 0;
speechCounter = SPEECH_COUNTER_PREVENT_SUCCESS_ROLEPLAY;
player->GroupEventHappens(QUEST_HOW_TO_WIN_FRIENDS, me);
return;
}
}
++speechCounter;
DoCastAOE(SPELL_THREAT_PULSE, true);
++speechCounter;
}
else
{
Talk(SAY_CRUSADER);
speechCounter = SPEECH_COUNTER_PREVENT_SUCCESS_ROLEPLAY;
}
}
else
speechTimer -= diff;
speechTimer = (speechTimer > diff) ? (speechTimer - diff) : 0;
return;
}
@@ -623,7 +641,8 @@ public:
ExecuteSpeech_Counter = 0;
PlayerGUID.Clear();
me->SetImmuneToPC(false);
me->SetReactState(REACT_PASSIVE);
me->SetImmuneToPC(true);
}
bool MeetQuestCondition(Player* player)
@@ -734,6 +753,7 @@ public:
case 9:
Talk(SAY_EXEC_TIME, player);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->SetReactState(REACT_PASSIVE);
me->SetImmuneToPC(false);
break;
case 10:
@@ -509,63 +509,6 @@ public:
}
};
class boss_thurg : public CreatureScript
{
public:
boss_thurg()
: CreatureScript("boss_thurg")
{
}
struct boss_thurgAI : public boss_hexlord_addAI
{
boss_thurgAI(Creature* creature) : boss_hexlord_addAI(creature) { }
uint32 bloodlust_timer;
uint32 cleave_timer;
void Reset() override
{
bloodlust_timer = 15000;
cleave_timer = 10000;
boss_hexlord_addAI::Reset();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (bloodlust_timer <= diff)
{
std::list<Creature*> templist = DoFindFriendlyMissingBuff(50, SPELL_BLOODLUST);
if (!templist.empty())
{
if (Unit* target = *(templist.begin()))
DoCast(target, SPELL_BLOODLUST, false);
}
bloodlust_timer = 12000;
}
else bloodlust_timer -= diff;
if (cleave_timer <= diff)
{
DoCastVictim(SPELL_CLEAVE, false);
cleave_timer = 12000; //3 sec cast
}
else cleave_timer -= diff;
boss_hexlord_addAI::UpdateAI(diff);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulAmanAI<boss_thurgAI>(creature);
}
};
class boss_alyson_antille : public CreatureScript
{
public:
@@ -668,331 +611,30 @@ public:
}
};
struct boss_gazakrothAI : public boss_hexlord_addAI
class spell_hexlord_unstable_affliction : public AuraScript
{
boss_gazakrothAI(Creature* creature) : boss_hexlord_addAI(creature) { }
PrepareAuraScript(spell_hexlord_unstable_affliction);
uint32 firebolt_timer;
void Reset() override
bool Validate(SpellInfo const* /*spell*/) override
{
firebolt_timer = 2000;
boss_hexlord_addAI::Reset();
return ValidateSpellInfo({ SPELL_WL_UNSTABLE_AFFL_DISPEL });
}
void AttackStart(Unit* who) override
void HandleDispel(DispelInfo* dispelInfo)
{
if (!who)
return;
if (who->isTargetableForAttack())
{
if (me->Attack(who, false))
{
me->GetMotionMaster()->MoveChase(who, 20);
me->AddThreat(who, 0.0f);
}
}
if (Unit* caster = GetCaster())
caster->CastSpell(dispelInfo->GetDispeller(), SPELL_WL_UNSTABLE_AFFL_DISPEL, true, nullptr, GetEffect(EFFECT_0));
}
void UpdateAI(uint32 diff) override
void Register() override
{
if (!UpdateVictim())
return;
if (firebolt_timer <= diff)
{
DoCastVictim(SPELL_FIREBOLT, false);
firebolt_timer = 700;
}
else firebolt_timer -= diff;
boss_hexlord_addAI::UpdateAI(diff);
}
};
class boss_lord_raadan : public CreatureScript
{
public:
boss_lord_raadan()
: CreatureScript("boss_lord_raadan")
{
}
struct boss_lord_raadanAI : public boss_hexlord_addAI
{
boss_lord_raadanAI(Creature* creature) : boss_hexlord_addAI(creature) { }
uint32 flamebreath_timer;
uint32 thunderclap_timer;
void Reset() override
{
flamebreath_timer = 8000;
thunderclap_timer = 13000;
boss_hexlord_addAI::Reset();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (thunderclap_timer <= diff)
{
DoCastVictim(SPELL_THUNDERCLAP, false);
thunderclap_timer = 12000;
}
else thunderclap_timer -= diff;
if (flamebreath_timer <= diff)
{
DoCastVictim(SPELL_FLAME_BREATH, false);
flamebreath_timer = 12000;
}
else flamebreath_timer -= diff;
boss_hexlord_addAI::UpdateAI(diff);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulAmanAI<boss_lord_raadanAI>(creature);
}
};
class boss_darkheart : public CreatureScript
{
public:
boss_darkheart()
: CreatureScript("boss_darkheart")
{
}
struct boss_darkheartAI : public boss_hexlord_addAI
{
boss_darkheartAI(Creature* creature) : boss_hexlord_addAI(creature) { }
uint32 psychicwail_timer;
void Reset() override
{
psychicwail_timer = 8000;
boss_hexlord_addAI::Reset();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (psychicwail_timer <= diff)
{
DoCastVictim(SPELL_PSYCHIC_WAIL, false);
psychicwail_timer = 12000;
}
else psychicwail_timer -= diff;
boss_hexlord_addAI::UpdateAI(diff);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulAmanAI<boss_darkheartAI>(creature);
}
};
class boss_slither : public CreatureScript
{
public:
boss_slither()
: CreatureScript("boss_slither")
{
}
struct boss_slitherAI : public boss_hexlord_addAI
{
boss_slitherAI(Creature* creature) : boss_hexlord_addAI(creature) { }
uint32 venomspit_timer;
void Reset() override
{
venomspit_timer = 5000;
boss_hexlord_addAI::Reset();
}
void AttackStart(Unit* who) override
{
if (!who)
return;
if (who->isTargetableForAttack())
{
if (me->Attack(who, false))
{
me->GetMotionMaster()->MoveChase(who, 20);
me->AddThreat(who, 0.0f);
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (venomspit_timer <= diff)
{
if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(victim, SPELL_VENOM_SPIT, false);
venomspit_timer = 2500;
}
else venomspit_timer -= diff;
boss_hexlord_addAI::UpdateAI(diff);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulAmanAI<boss_slitherAI>(creature);
}
};
class boss_fenstalker : public CreatureScript
{
public:
boss_fenstalker()
: CreatureScript("boss_fenstalker")
{
}
struct boss_fenstalkerAI : public boss_hexlord_addAI
{
boss_fenstalkerAI(Creature* creature) : boss_hexlord_addAI(creature) { }
uint32 volatileinf_timer;
void Reset() override
{
volatileinf_timer = 15000;
boss_hexlord_addAI::Reset();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (volatileinf_timer <= diff)
{
// core bug
me->GetVictim()->CastSpell(me->GetVictim(), SPELL_VOLATILE_INFECTION, false);
volatileinf_timer = 12000;
}
else volatileinf_timer -= diff;
boss_hexlord_addAI::UpdateAI(diff);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulAmanAI<boss_fenstalkerAI>(creature);
}
};
class boss_koragg : public CreatureScript
{
public:
boss_koragg()
: CreatureScript("boss_koragg")
{
}
struct boss_koraggAI : public boss_hexlord_addAI
{
boss_koraggAI(Creature* creature) : boss_hexlord_addAI(creature) { }
uint32 coldstare_timer;
uint32 mightyblow_timer;
void Reset() override
{
coldstare_timer = 15000;
mightyblow_timer = 10000;
boss_hexlord_addAI::Reset();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (mightyblow_timer <= diff)
{
DoCastVictim(SPELL_MIGHTY_BLOW, false);
mightyblow_timer = 12000;
}
if (coldstare_timer <= diff)
{
if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
DoCast(victim, SPELL_COLD_STARE, false);
coldstare_timer = 12000;
}
boss_hexlord_addAI::UpdateAI(diff);
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulAmanAI<boss_koraggAI>(creature);
}
};
class spell_hexlord_unstable_affliction : public SpellScriptLoader
{
public:
spell_hexlord_unstable_affliction() : SpellScriptLoader("spell_hexlord_unstable_affliction") { }
class spell_hexlord_unstable_affliction_AuraScript : public AuraScript
{
PrepareAuraScript(spell_hexlord_unstable_affliction_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_WL_UNSTABLE_AFFL_DISPEL });
}
void HandleDispel(DispelInfo* dispelInfo)
{
if (Unit* caster = GetCaster())
caster->CastSpell(dispelInfo->GetDispeller(), SPELL_WL_UNSTABLE_AFFL_DISPEL, true, nullptr, GetEffect(EFFECT_0));
}
void Register() override
{
AfterDispel += AuraDispelFn(spell_hexlord_unstable_affliction_AuraScript::HandleDispel);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_hexlord_unstable_affliction_AuraScript();
AfterDispel += AuraDispelFn(spell_hexlord_unstable_affliction::HandleDispel);
}
};
void AddSC_boss_hex_lord_malacrass()
{
new boss_hexlord_malacrass();
new boss_thurg();
// new boss_gazakroth();
new boss_lord_raadan();
new boss_darkheart();
new boss_slither();
new boss_fenstalker();
new boss_koragg();
new boss_alyson_antille();
new spell_hexlord_unstable_affliction();
RegisterSpellScript(spell_hexlord_unstable_affliction);
}
@@ -346,6 +346,14 @@ struct boss_nalorakk : public BossAI
}
return true;
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
instance->SetData(DATA_NALORAKKEVENT, DONE);
}
private:
uint8 _phase;
bool _ranIntro;
@@ -70,17 +70,17 @@ struct boss_murmur : public BossAI
_Reset();
me->SetHealth(me->CountPctFromMaxHealth(40));
me->ResetPlayerDamageReq();
CastSupressionOOC();
CastSuppressionOOC();
}
void CastSupressionOOC()
void CastSuppressionOOC()
{
me->m_Events.CancelEventGroup(GROUP_OOC_CAST);
me->m_Events.AddEventAtOffset([this] {
if (me->FindNearestCreature(NPC_CABAL_SPELLBINDER, 35.0f))
{
me->CastCustomSpell(SPELL_SUPPRESSION, SPELLVALUE_MAX_TARGETS, 5, (Unit*)nullptr, false);
CastSupressionOOC();
CastSuppressionOOC();
}
}, 3600ms, 10900ms, GROUP_OOC_CAST);
}
@@ -175,6 +175,25 @@ Position illidanTakeoffPoint = { 727.6356f, 305.62753, 359.1486f };
Position illidanLand = { 676.648f, 304.76074f, 354.18906f, 6.230825424194335937f };
Position roomCenter = { 676.021f, 305.455f, 353.582f, 3.82227f };
Position const BladesPositions[2] =
{
{ 676.226013f, 325.230988f },
{ 678.059998f, 285.220001f }
};
class ChargeTargetSelector
{
public:
ChargeTargetSelector() { }
bool operator()(Unit* unit) const
{
return unit->IsPlayer()
&& unit->GetDistance2d(BladesPositions[0].GetPositionX(), BladesPositions[0].GetPositionY()) > 25.0f
&& unit->GetDistance2d(BladesPositions[1].GetPositionX(), BladesPositions[1].GetPositionY()) > 25.0f;
}
};
struct boss_illidan_stormrage : public BossAI
{
boss_illidan_stormrage(Creature* creature) : BossAI(creature, DATA_ILLIDAN_STORMRAGE), _canTalk(true), _dying(false), _inCutscene(false), beamPosId(0) { }
@@ -196,6 +215,7 @@ struct boss_illidan_stormrage : public BossAI
me->LoadEquipment(EQUIPMENT_GLAIVES, true);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->SetSheath(SHEATH_STATE_UNARMED);
me->SetControlled(false, UNIT_STATE_ROOT);
ScheduleHealthCheckEvent(90, [&] {
// Call for minions
@@ -604,6 +624,10 @@ struct boss_illidan_stormrage : public BossAI
BossAI::EnterEvadeMode(why);
me->DespawnOnEvade();
me->m_Events.CancelEventGroup(GROUP_BERSERK);
me->m_Events.CancelEventGroup(GROUP_PHASE_FLYING);
me->m_Events.CancelEventGroup(GROUP_DEMON_FORM);
}
void JustSummoned(Creature* summon) override
@@ -733,7 +757,7 @@ struct npc_akama_illidan : public ScriptedAI
void Reset() override
{
scheduler.CancelAll();
me->m_Events.KillAllEvents(true);
me->m_Events.KillAllEvents(false);
me->SetReactState(REACT_AGGRESSIVE);
if (instance->GetBossState(DATA_ILLIDAN_STORMRAGE) == DONE)
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
@@ -1316,26 +1340,16 @@ struct npc_flame_of_azzinoth : public ScriptedAI
void JustEngagedWith(Unit* /*who*/) override
{
ScheduleTimedEvent(10s, [&] {
if (Creature* _blade = ObjectAccessor::GetCreature(*me, _bladeGUID))
{
Unit* offTank = nullptr;
if (Creature* secondBlaze = me->FindNearestCreature(NPC_BLAZE, 100.0f, true))
offTank = secondBlaze->GetVictim();
if (Unit* target = _blade->AI()->SelectTarget(SelectTargetMethod::Random, 0, -40.0f, true))
{
if (!offTank || offTank != target)
DoCast(target, SPELL_CHARGE);
}
}
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, ChargeTargetSelector()))
DoCast(target, SPELL_CHARGE);
}, 5s, 20s);
ScheduleTimedEvent(10s, 20s, [&] {
DoCastVictim(SPELL_FLAME_BLAST);
me->m_Events.AddEventAtOffset([&] {
DoCastVictim(SPELL_BLAZE);
if (Unit* victim = me->GetVictim())
victim->CastSpell(victim, SPELL_BLAZE, true);
}, 1s);
}, 15s, 20s);
}
@@ -177,6 +177,7 @@ struct boss_illidari_council : public BossAI
else if (param == ACTION_END_ENCOUNTER)
{
me->setActive(false);
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry(), me);
for (uint8 i = DATA_GATHIOS_THE_SHATTERER; i <= DATA_VERAS_DARKSHADOW; ++i)
if (Creature* member = instance->GetCreature(i))
if (member->IsAlive())
@@ -339,7 +340,7 @@ struct boss_gathios_the_shatterer : public boss_illidari_council_memberAI
if (roll_chance_i(50))
Talk(SAY_COUNCIL_SPECIAL);
DoCastSelf(SPELL_CONSECRATION);
events.ScheduleEvent(EVENT_SPELL_AURA, 30s);
events.ScheduleEvent(EVENT_SPELL_CONSECRATION, 30s);
break;
case EVENT_SPELL_HAMMER_OF_JUSTICE:
if (Unit* target = me->GetVictim())
@@ -127,6 +127,7 @@ struct boss_mother_shahraz : public BossAI
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
me->m_Events.CancelEventGroup(GROUP_ENRAGE);
Talk(SAY_DEATH);
}
@@ -139,7 +139,8 @@ struct boss_supremus : public BossAI
DoResetThreatList();
me->AddThreat(target, 5000000.0f);
Talk(EMOTE_NEW_TARGET);
DoCastVictim(SPELL_CHARGE);
if (target->IsWithinDist(me, 40))
DoCast(target, SPELL_CHARGE);
}
context.Repeat(10s);
@@ -19,6 +19,7 @@
#include "ScriptedCreature.h"
#include "SpellScriptLoader.h"
#include "black_temple.h"
#include "Player.h"
#include "SpellScript.h"
enum Yells
@@ -39,7 +40,8 @@ enum Spells
SPELL_TIDAL_SHIELD = 39872,
SPELL_IMPALING_SPINE = 39837,
SPELL_SUMMON_IMPALING_SPINE = 39929,
SPELL_BERSERK = 26662
SPELL_BERSERK = 26662,
SPELL_REMOVE_SPINES = 40354
};
enum Events
@@ -48,6 +50,11 @@ enum Events
EVENT_ENRAGE = 2
};
enum Misc
{
ITEM_NAJENTUS_SPINE = 32408
};
struct boss_najentus : public BossAI
{
boss_najentus(Creature* creature) : BossAI(creature, DATA_HIGH_WARLORD_NAJENTUS), _canTalk(true) { }
@@ -56,6 +63,7 @@ struct boss_najentus : public BossAI
{
_Reset();
me->m_Events.CancelEventGroup(EVENT_ENRAGE);
DoCastSelf(SPELL_REMOVE_SPINES);
}
void JustEngagedWith(Unit* who) override
@@ -64,6 +72,7 @@ struct boss_najentus : public BossAI
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
DoCastSelf(SPELL_REMOVE_SPINES);
me->m_Events.AddEventAtOffset([this] {
Talk(SAY_ENRAGE);
@@ -113,6 +122,7 @@ struct boss_najentus : public BossAI
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
me->m_Events.CancelEventGroup(EVENT_ENRAGE);
Talk(SAY_DEATH);
}
@@ -156,9 +166,31 @@ class spell_najentus_hurl_spine : public SpellScript
}
};
class spell_najentus_remove_spines : public SpellScript
{
PrepareSpellScript(spell_najentus_remove_spines);
void RemoveSpines()
{
if (Unit* caster = GetCaster())
{
caster->GetMap()->DoForAllPlayers([&](Player* player)
{
player->DestroyItemCount(ITEM_NAJENTUS_SPINE, 5, true);
});
}
}
void Register() override
{
OnCast += SpellCastFn(spell_najentus_remove_spines::RemoveSpines);
}
};
void AddSC_boss_najentus()
{
RegisterBlackTempleCreatureAI(boss_najentus);
RegisterSpellScript(spell_najentus_needle_spine);
RegisterSpellScript(spell_najentus_hurl_spine);
RegisterSpellScript(spell_najentus_remove_spines);
}
+1 -1
View File
@@ -936,7 +936,7 @@ class spell_dru_starfall_dummy : public SpellScript
return;
}
// Any effect which causes you to lose control of your character will supress the starfall effect.
// Any effect which causes you to lose control of your character will suppress the starfall effect.
if (caster->HasUnitState(UNIT_STATE_CONTROLLED))
return;
+3 -3
View File
@@ -506,8 +506,8 @@ enum SpellAttr3 : uint32
SPELL_ATTR3_HIDE_CHANNEL_BAR = 0x00002000, // TITLE Do not display channel bar (client only)
SPELL_ATTR3_HIDE_IN_RAID_FILTER = 0x00004000, // TITLE Honorless Target
SPELL_ATTR3_NORMAL_RANGED_ATTACK = 0x00008000, // TITLE Unknown attribute 15@Attr3 DESCRIPTION Auto Shoot, Shoot, Throw - ranged normal attack attribute?
SPELL_ATTR3_SUPRESS_CASTER_PROCS = 0x00010000, // TITLE Cannot trigger procs
SPELL_ATTR3_SUPRESS_TARGET_PROCS = 0x00020000, // TITLE No initial aggro
SPELL_ATTR3_SUPPRESS_CASTER_PROCS = 0x00010000, // TITLE Cannot trigger procs
SPELL_ATTR3_SUPPRESS_TARGET_PROCS = 0x00020000, // TITLE No initial aggro
SPELL_ATTR3_ALWAYS_HIT = 0x00040000, // TITLE Ignore hit result DESCRIPTION Spell cannot miss, or be dodged/parried/blocked
SPELL_ATTR3_INSTANT_TARGET_PROCS = 0x00080000, // TITLE Cannot trigger spells during aura proc
SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD = 0x00100000, // TITLE Persists through death
@@ -550,7 +550,7 @@ enum SpellAttr4 : uint32
SPELL_ATTR4_AURA_NEVER_BOUNCES = 0x00100000, // TITLE Allow self-cast to override stronger aura (client only)
SPELL_ATTR4_ALLOW_ENETRING_ARENA = 0x00200000, // TITLE Keep when entering arena
SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM = 0x00400000, // TITLE Unknown attribute 22@Attr4 DESCRIPTION Seal of Command (42058,57770) and Gymer's Smash 55426
SPELL_ATTR4_SUPRESS_WEAPON_PROCS = 0x00800000, // TITLE Cannot trigger item spells
SPELL_ATTR4_SUPPRESS_WEAPON_PROCS = 0x00800000, // TITLE Cannot trigger item spells
SPELL_ATTR4_AUTO_RANGED_COMBAT = 0x01000000, // TITLE Unknown attribute 24@Attr4 DESCRIPTION Shoot-type spell?
SPELL_ATTR4_OWNER_POWER_SCALING = 0x02000000, // TITLE Pet Scaling aura
SPELL_ATTR4_ONLY_FLYING_AREAS = 0x04000000, // TITLE Only in Outland/Northrend
+9 -9
View File
@@ -560,8 +560,8 @@ AC_API_EXPORT EnumText EnumUtils<SpellAttr3>::ToString(SpellAttr3 value)
case SPELL_ATTR3_HIDE_CHANNEL_BAR: return { "SPELL_ATTR3_HIDE_CHANNEL_BAR", "Do not display channel bar (client only)", "" };
case SPELL_ATTR3_HIDE_IN_RAID_FILTER: return { "SPELL_ATTR3_HIDE_IN_RAID_FILTER", "Honorless Target", "" };
case SPELL_ATTR3_NORMAL_RANGED_ATTACK: return { "SPELL_ATTR3_NORMAL_RANGED_ATTACK", "Unknown attribute 15@Attr3", "Auto Shoot, Shoot, Throw - ranged normal attack attribute?" };
case SPELL_ATTR3_SUPRESS_CASTER_PROCS: return { "SPELL_ATTR3_SUPRESS_CASTER_PROCS", "Cannot trigger procs", "" };
case SPELL_ATTR3_SUPRESS_TARGET_PROCS: return { "SPELL_ATTR3_SUPRESS_TARGET_PROCS", "No initial aggro", "" };
case SPELL_ATTR3_SUPPRESS_CASTER_PROCS: return { "SPELL_ATTR3_SUPPRESS_CASTER_PROCS", "Cannot trigger procs", "" };
case SPELL_ATTR3_SUPPRESS_TARGET_PROCS: return { "SPELL_ATTR3_SUPPRESS_TARGET_PROCS", "No initial aggro", "" };
case SPELL_ATTR3_ALWAYS_HIT: return { "SPELL_ATTR3_ALWAYS_HIT", "Ignore hit result", "Spell cannot miss, or be dodged/parried/blocked" };
case SPELL_ATTR3_INSTANT_TARGET_PROCS: return { "SPELL_ATTR3_INSTANT_TARGET_PROCS", "Cannot trigger spells during aura proc", "" };
case SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD: return { "SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD", "Persists through death", "" };
@@ -604,8 +604,8 @@ AC_API_EXPORT SpellAttr3 EnumUtils<SpellAttr3>::FromIndex(std::size_t index)
case 13: return SPELL_ATTR3_HIDE_CHANNEL_BAR;
case 14: return SPELL_ATTR3_HIDE_IN_RAID_FILTER;
case 15: return SPELL_ATTR3_NORMAL_RANGED_ATTACK;
case 16: return SPELL_ATTR3_SUPRESS_CASTER_PROCS;
case 17: return SPELL_ATTR3_SUPRESS_TARGET_PROCS;
case 16: return SPELL_ATTR3_SUPPRESS_CASTER_PROCS;
case 17: return SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
case 18: return SPELL_ATTR3_ALWAYS_HIT;
case 19: return SPELL_ATTR3_INSTANT_TARGET_PROCS;
case 20: return SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD;
@@ -645,8 +645,8 @@ AC_API_EXPORT std::size_t EnumUtils<SpellAttr3>::ToIndex(SpellAttr3 value)
case SPELL_ATTR3_HIDE_CHANNEL_BAR: return 13;
case SPELL_ATTR3_HIDE_IN_RAID_FILTER: return 14;
case SPELL_ATTR3_NORMAL_RANGED_ATTACK: return 15;
case SPELL_ATTR3_SUPRESS_CASTER_PROCS: return 16;
case SPELL_ATTR3_SUPRESS_TARGET_PROCS: return 17;
case SPELL_ATTR3_SUPPRESS_CASTER_PROCS: return 16;
case SPELL_ATTR3_SUPPRESS_TARGET_PROCS: return 17;
case SPELL_ATTR3_ALWAYS_HIT: return 18;
case SPELL_ATTR3_INSTANT_TARGET_PROCS: return 19;
case SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD: return 20;
@@ -696,7 +696,7 @@ AC_API_EXPORT EnumText EnumUtils<SpellAttr4>::ToString(SpellAttr4 value)
case SPELL_ATTR4_AURA_NEVER_BOUNCES: return { "SPELL_ATTR4_AURA_NEVER_BOUNCES", "Allow self-cast to override stronger aura (client only)", "" };
case SPELL_ATTR4_ALLOW_ENETRING_ARENA: return { "SPELL_ATTR4_ALLOW_ENETRING_ARENA", "Keep when entering arena", "" };
case SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM: return { "SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM", "Unknown attribute 22@Attr4", "Seal of Command (42058,57770) and Gymer's Smash 55426" };
case SPELL_ATTR4_SUPRESS_WEAPON_PROCS: return { "SPELL_ATTR4_SUPRESS_WEAPON_PROCS", "Cannot trigger item spells", "" };
case SPELL_ATTR4_SUPPRESS_WEAPON_PROCS: return { "SPELL_ATTR4_SUPPRESS_WEAPON_PROCS", "Cannot trigger item spells", "" };
case SPELL_ATTR4_AUTO_RANGED_COMBAT: return { "SPELL_ATTR4_AUTO_RANGED_COMBAT", "Unknown attribute 24@Attr4", "Shoot-type spell?" };
case SPELL_ATTR4_OWNER_POWER_SCALING: return { "SPELL_ATTR4_OWNER_POWER_SCALING", "Pet Scaling aura", "" };
case SPELL_ATTR4_ONLY_FLYING_AREAS: return { "SPELL_ATTR4_ONLY_FLYING_AREAS", "Only in Outland/Northrend", "" };
@@ -740,7 +740,7 @@ AC_API_EXPORT SpellAttr4 EnumUtils<SpellAttr4>::FromIndex(std::size_t index)
case 20: return SPELL_ATTR4_AURA_NEVER_BOUNCES;
case 21: return SPELL_ATTR4_ALLOW_ENETRING_ARENA;
case 22: return SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM;
case 23: return SPELL_ATTR4_SUPRESS_WEAPON_PROCS;
case 23: return SPELL_ATTR4_SUPPRESS_WEAPON_PROCS;
case 24: return SPELL_ATTR4_AUTO_RANGED_COMBAT;
case 25: return SPELL_ATTR4_OWNER_POWER_SCALING;
case 26: return SPELL_ATTR4_ONLY_FLYING_AREAS;
@@ -781,7 +781,7 @@ AC_API_EXPORT std::size_t EnumUtils<SpellAttr4>::ToIndex(SpellAttr4 value)
case SPELL_ATTR4_AURA_NEVER_BOUNCES: return 20;
case SPELL_ATTR4_ALLOW_ENETRING_ARENA: return 21;
case SPELL_ATTR4_PROC_SUPPRESS_SWING_ANIM: return 22;
case SPELL_ATTR4_SUPRESS_WEAPON_PROCS: return 23;
case SPELL_ATTR4_SUPPRESS_WEAPON_PROCS: return 23;
case SPELL_ATTR4_AUTO_RANGED_COMBAT: return 24;
case SPELL_ATTR4_OWNER_POWER_SCALING: return 25;
case SPELL_ATTR4_ONLY_FLYING_AREAS: return 26;