Merge branch 'master' into Playerbot
This commit is contained in:
@@ -27,14 +27,15 @@
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
#define AC_SAI_IS_BOOLEAN_VALID(e, value) \
|
||||
{ \
|
||||
if (value > 1) \
|
||||
{ \
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses param {} of type Boolean with value {}, valid values are 0 or 1, skipped.", \
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), STRINGIZE(value), value); \
|
||||
return false; \
|
||||
} \
|
||||
bool SmartAIMgr::IsSAIBoolValid(SmartScriptHolder const& e, SAIBool value)
|
||||
{
|
||||
if (value != 0 && value != 1)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses param {} of type Boolean with value {}, valid values are 0 or 1, skipped.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), STRINGIZE(value), value);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SmartWaypointMgr* SmartWaypointMgr::instance()
|
||||
@@ -513,23 +514,22 @@ bool SmartAIMgr::IsTargetValid(SmartScriptHolder const& e)
|
||||
case SMART_TARGET_HOSTILE_LAST_AGGRO:
|
||||
case SMART_TARGET_HOSTILE_RANDOM:
|
||||
case SMART_TARGET_HOSTILE_RANDOM_NOT_TOP:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.hostileRandom.playerOnly);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.target.hostileRandom.playerOnly);
|
||||
case SMART_TARGET_FARTHEST:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.farthest.playerOnly);
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.farthest.isInLos);
|
||||
return IsSAIBoolValid(e, e.target.farthest.playerOnly) &&
|
||||
IsSAIBoolValid(e, e.target.farthest.isInLos);
|
||||
break;
|
||||
case SMART_TARGET_CLOSEST_CREATURE:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.unitClosest.dead);
|
||||
return IsSAIBoolValid(e, e.target.unitClosest.dead);
|
||||
break;
|
||||
case SMART_TARGET_CLOSEST_ENEMY:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.closestAttackable.playerOnly);
|
||||
return IsSAIBoolValid(e, e.target.closestAttackable.playerOnly);
|
||||
break;
|
||||
case SMART_TARGET_CLOSEST_FRIENDLY:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.closestFriendly.playerOnly);
|
||||
return IsSAIBoolValid(e, e.target.closestFriendly.playerOnly);
|
||||
break;
|
||||
case SMART_TARGET_OWNER_OR_SUMMONER:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.target.owner.useCharmerOrOwner);
|
||||
return IsSAIBoolValid(e, e.target.owner.useCharmerOrOwner);
|
||||
break;
|
||||
case SMART_TARGET_STORED:
|
||||
case SMART_TARGET_PLAYER_WITH_AURA:
|
||||
@@ -1079,9 +1079,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_EVENT_OOC_LOS:
|
||||
case SMART_EVENT_IC_LOS:
|
||||
if (!IsMinMaxValid(e, e.event.los.cooldownMin, e.event.los.cooldownMax))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e.event.los.hostilityMode >= AsUnderlyingType(SmartEvent::LOSHostilityMode::End))
|
||||
{
|
||||
@@ -1090,8 +1088,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
return false;
|
||||
}
|
||||
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.event.los.playerOnly);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.event.los.playerOnly);
|
||||
case SMART_EVENT_RESPAWN:
|
||||
if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && !sMapStore.LookupEntry(e.event.respawn.map))
|
||||
{
|
||||
@@ -1134,8 +1131,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
if (e.event.kill.creature && !IsCreatureValid(e, e.event.kill.creature))
|
||||
return false;
|
||||
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.event.kill.playerOnly);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.event.kill.playerOnly);
|
||||
case SMART_EVENT_VICTIM_CASTING:
|
||||
if (e.event.targetCasting.spellId > 0 && !sSpellMgr->GetSpellInfo(e.event.targetCasting.spellId))
|
||||
{
|
||||
@@ -1164,14 +1160,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_EVENT_ACCEPTED_QUEST:
|
||||
case SMART_EVENT_REWARD_QUEST:
|
||||
if (e.event.quest.quest && !IsQuestValid(e, e.event.quest.quest))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_EVENT_RECEIVE_EMOTE:
|
||||
{
|
||||
@@ -1464,8 +1456,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_SOUND:
|
||||
if (!IsSoundValid(e, e.action.sound.sound))
|
||||
return false;
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.sound.onlySelf);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.action.sound.onlySelf);
|
||||
case SMART_ACTION_RANDOM_SOUND:
|
||||
if (e.action.randomSound.sound1 && !IsSoundValid(e, e.action.randomSound.sound1))
|
||||
return false;
|
||||
@@ -1505,8 +1496,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
if (!IsQuestValid(e, e.action.questOffer.questID))
|
||||
return false;
|
||||
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.questOffer.directAdd);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.action.questOffer.directAdd);
|
||||
case SMART_ACTION_FAIL_QUEST:
|
||||
if (!IsQuestValid(e, e.action.quest.quest))
|
||||
return false;
|
||||
@@ -1651,8 +1641,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
return false;
|
||||
}
|
||||
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.summonCreature.attackInvoker);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.action.summonCreature.attackInvoker);
|
||||
case SMART_ACTION_CALL_KILLEDMONSTER:
|
||||
if (!IsCreatureValid(e, e.action.killedMonster.creature))
|
||||
return false;
|
||||
@@ -1660,8 +1649,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_UPDATE_TEMPLATE:
|
||||
if (!IsCreatureValid(e, e.action.updateTemplate.creature))
|
||||
return false;
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.updateTemplate.updateLevel);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.action.updateTemplate.updateLevel);
|
||||
case SMART_ACTION_SET_SHEATH:
|
||||
if (e.action.setSheath.sheath && e.action.setSheath.sheath >= MAX_SHEATH_STATE)
|
||||
{
|
||||
@@ -1707,8 +1695,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_WP_STOP:
|
||||
if (e.action.wpStop.quest && !IsQuestValid(e, e.action.wpStop.quest))
|
||||
return false;
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.wpStop.fail);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.action.wpStop.fail);
|
||||
case SMART_ACTION_WP_START:
|
||||
{
|
||||
if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID))
|
||||
@@ -1729,9 +1716,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
return false;
|
||||
}
|
||||
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.wpStart.run);
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.wpStart.repeat);
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.action.wpStart.run) &&
|
||||
IsSAIBoolValid(e, e.action.wpStart.repeat);
|
||||
}
|
||||
case SMART_ACTION_CREATE_TIMED_EVENT:
|
||||
{
|
||||
@@ -1872,85 +1858,42 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_AUTO_ATTACK:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.autoAttack.attack);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.autoAttack.attack);
|
||||
case SMART_ACTION_ALLOW_COMBAT_MOVEMENT:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.combatMove.move);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.combatMove.move);
|
||||
case SMART_ACTION_CALL_FOR_HELP:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.callHelp.withEmote);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.callHelp.withEmote);
|
||||
case SMART_ACTION_SET_VISIBILITY:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.visibility.state);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.visibility.state);
|
||||
case SMART_ACTION_SET_RUN:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setRun.run);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.setRun.run);
|
||||
case SMART_ACTION_SET_CAN_FLY:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setFly.fly);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.setFly.fly);
|
||||
case SMART_ACTION_SET_SWIM:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setSwim.swim);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.setSwim.swim);
|
||||
case SMART_ACTION_SET_COUNTER:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setCounter.reset);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.setCounter.reset);
|
||||
case SMART_ACTION_INTERRUPT_SPELL:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.interruptSpellCasting.withDelayed);
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.interruptSpellCasting.withInstant);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.interruptSpellCasting.withDelayed) &&
|
||||
IsSAIBoolValid(e, e.action.interruptSpellCasting.withInstant);
|
||||
case SMART_ACTION_SET_ROOT:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setRoot.root);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.setRoot.root);
|
||||
case SMART_ACTION_DISABLE_EVADE:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.disableEvade.disable);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.disableEvade.disable);
|
||||
case SMART_ACTION_LOAD_EQUIPMENT:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.loadEquipment.force);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.loadEquipment.force);
|
||||
case SMART_ACTION_TALK:
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.talk.useTalkTarget);
|
||||
if (!IsTextValid(e, e.action.talk.textGroupID))
|
||||
return false;
|
||||
break;
|
||||
return IsSAIBoolValid(e, e.action.talk.useTalkTarget);
|
||||
case SMART_ACTION_SIMPLE_TALK:
|
||||
if (!IsTextValid(e, e.action.simpleTalk.textGroupID))
|
||||
return false;
|
||||
break;
|
||||
case SMART_ACTION_SET_HEALTH_REGEN:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.setHealthRegen.regenHealth);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.setHealthRegen.regenHealth);
|
||||
case SMART_ACTION_CALL_TIMED_ACTIONLIST:
|
||||
{
|
||||
AC_SAI_IS_BOOLEAN_VALID(e, e.action.timedActionList.allowOverride);
|
||||
break;
|
||||
}
|
||||
return IsSAIBoolValid(e, e.action.timedActionList.allowOverride);
|
||||
case SMART_ACTION_FLEE_FOR_ASSIST:
|
||||
case SMART_ACTION_MOVE_TO_POS:
|
||||
case SMART_ACTION_EVADE:
|
||||
|
||||
@@ -2219,6 +2219,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsSAIBoolValid(SmartScriptHolder const& e, SAIBool value);
|
||||
static bool IsTextValid(SmartScriptHolder const& e, uint32 id);
|
||||
static bool CheckUnusedEventParams(SmartScriptHolder const& e);
|
||||
static bool CheckUnusedActionParams(SmartScriptHolder const& e);
|
||||
|
||||
@@ -32,7 +32,7 @@ enum AccountOpResult
|
||||
AOR_DB_INTERNAL_ERROR
|
||||
};
|
||||
|
||||
#define MAX_ACCOUNT_STR 20
|
||||
#define MAX_ACCOUNT_STR 17
|
||||
#define MAX_PASS_STR 16
|
||||
#define MAX_EMAIL_STR 255
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ bool ArenaSpectator::HandleSpectatorSpectateCommand(ChatHandler* handler, std::s
|
||||
if (player->IsInCombat())
|
||||
errors.push_back("Can't be in combat.");
|
||||
|
||||
if (player->isUsingLfg())
|
||||
if (player->IsUsingLfg())
|
||||
errors.push_back("Can't spectate while using LFG system.");
|
||||
|
||||
if (player->InBattlegroundQueue())
|
||||
|
||||
@@ -185,10 +185,7 @@ void Channel::JoinChannel(Player* player, std::string const& pass)
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasFlag(CHANNEL_FLAG_LFG) &&
|
||||
sWorld->getBoolConfig(CONFIG_RESTRICTED_LFG_CHANNEL) &&
|
||||
AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) &&
|
||||
player->GetGroup())
|
||||
if (IsLFG() && sWorld->getBoolConfig(CONFIG_RESTRICTED_LFG_CHANNEL) && !player->IsUsingLfg())
|
||||
{
|
||||
WorldPacket data;
|
||||
MakeNotInLfg(&data);
|
||||
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
[[nodiscard]] uint32 GetChannelDBId() const { return _channelDBId; }
|
||||
[[nodiscard]] bool IsConstant() const { return _channelId != 0; }
|
||||
[[nodiscard]] bool IsAnnounce() const { return _announce; }
|
||||
[[nodiscard]] bool IsLFG() const { return GetFlags() & CHANNEL_FLAG_LFG; }
|
||||
[[nodiscard]] bool IsLFG() const { return HasFlag(CHANNEL_FLAG_LFG); }
|
||||
[[nodiscard]] std::string const& GetPassword() const { return _password; }
|
||||
void SetPassword(std::string const& npassword) { _password = npassword; }
|
||||
[[nodiscard]] uint32 GetNumPlayers() const { return playersStore.size(); }
|
||||
|
||||
@@ -1001,43 +1001,25 @@ void GameObject::Delete()
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
|
||||
void GameObject::GetFishLoot(Loot* fishloot, Player* loot_owner)
|
||||
void GameObject::GetFishLoot(Loot* fishLoot, Player* lootOwner, bool junk /*= false*/)
|
||||
{
|
||||
fishloot->clear();
|
||||
fishLoot->clear();
|
||||
|
||||
uint32 zone, subzone;
|
||||
uint32 defaultzone = 1;
|
||||
GetZoneAndAreaId(zone, subzone);
|
||||
uint32 zone, area;
|
||||
uint32 defaultZone = 1;
|
||||
GetZoneAndAreaId(zone, area);
|
||||
|
||||
// if subzone loot exist use it
|
||||
fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true);
|
||||
if (fishloot->empty()) //use this becase if zone or subzone has set LOOT_MODE_JUNK_FISH,Even if no normal drop, fishloot->FillLoot return true. it wrong.
|
||||
uint16 lootMode = junk ? LOOT_MODE_JUNK_FISH : LOOT_MODE_DEFAULT;
|
||||
// Check to fill loot in the order area - zone - defaultZone.
|
||||
// This is because area and zone is not set in some places, like Off the coast of Storm Peaks.
|
||||
uint32 lootZones[] = { area, zone, defaultZone };
|
||||
for (uint32 fillZone : lootZones)
|
||||
{
|
||||
//subzone no result,use zone loot
|
||||
fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true);
|
||||
//use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks.
|
||||
if (fishloot->empty())
|
||||
fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true);
|
||||
}
|
||||
}
|
||||
fishLoot->FillLoot(fillZone, LootTemplates_Fishing, lootOwner, true, true, lootMode);
|
||||
|
||||
void GameObject::GetFishLootJunk(Loot* fishloot, Player* loot_owner)
|
||||
{
|
||||
fishloot->clear();
|
||||
|
||||
uint32 zone, subzone;
|
||||
uint32 defaultzone = 1;
|
||||
GetZoneAndAreaId(zone, subzone);
|
||||
|
||||
// if subzone loot exist use it
|
||||
fishloot->FillLoot(subzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
|
||||
if (fishloot->empty()) //use this becase if zone or subzone has normal mask drop, then fishloot->FillLoot return true.
|
||||
{
|
||||
//use zone loot
|
||||
fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
|
||||
if (fishloot->empty())
|
||||
//use zone 1 as default
|
||||
fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true, LOOT_MODE_JUNK_FISH);
|
||||
// If the loot is filled and the loot is eligible, then we break out of the loop.
|
||||
if (!fishLoot->empty() && !fishLoot->isLooted())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -198,8 +198,7 @@ public:
|
||||
void Refresh();
|
||||
void DespawnOrUnsummon(Milliseconds delay = 0ms, Seconds forcedRespawnTime = 0s);
|
||||
void Delete();
|
||||
void GetFishLoot(Loot* loot, Player* loot_owner);
|
||||
void GetFishLootJunk(Loot* loot, Player* loot_owner);
|
||||
void GetFishLoot(Loot* fishLoot, Player* lootOwner, bool junk = false);
|
||||
[[nodiscard]] GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
|
||||
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
|
||||
[[nodiscard]] GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
|
||||
|
||||
@@ -7896,7 +7896,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||
if (loot_type == LOOT_FISHING)
|
||||
go->GetFishLoot(loot, this);
|
||||
else if (loot_type == LOOT_FISHING_JUNK)
|
||||
go->GetFishLootJunk(loot, this);
|
||||
go->GetFishLoot(loot, this, true);
|
||||
|
||||
if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
|
||||
{
|
||||
@@ -13111,7 +13111,7 @@ PartyResult Player::CanUninviteFromGroup(ObjectGuid targetPlayerGUID) const
|
||||
return ERR_PARTY_RESULT_OK;
|
||||
}
|
||||
|
||||
bool Player::isUsingLfg()
|
||||
bool Player::IsUsingLfg()
|
||||
{
|
||||
return sLFGMgr->GetState(GetGUID()) != lfg::LFG_STATE_NONE;
|
||||
}
|
||||
|
||||
@@ -2062,6 +2062,7 @@ public:
|
||||
bool IsInChannel(const Channel* c);
|
||||
void CleanupChannels();
|
||||
void ClearChannelWatch();
|
||||
void UpdateLFGChannel();
|
||||
void UpdateLocalChannels(uint32 newZone);
|
||||
|
||||
void UpdateDefense();
|
||||
@@ -2397,7 +2398,7 @@ public:
|
||||
void SetAtLoginFlag(AtLoginFlags f) { m_atLoginFlags |= f; }
|
||||
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist = false);
|
||||
|
||||
bool isUsingLfg();
|
||||
bool IsUsingLfg();
|
||||
bool inRandomLfgDungeon();
|
||||
|
||||
typedef std::set<uint32> DFQuestsDoneList;
|
||||
|
||||
@@ -5687,7 +5687,8 @@ void Player::_LoadActions(PreparedQueryResult result)
|
||||
ab->uState = ACTIONBUTTON_UNCHANGED;
|
||||
else
|
||||
{
|
||||
LOG_ERROR("entities.player", "ActionButton loading problem, will be deleted from db...");
|
||||
|
||||
LOG_ERROR("entities.player", "ActionButton loading problem, will be deleted from db. player: {}, guid: {}, button: {}, action: {}, type: {}", GetName(), GetGUID().GetCounter(), button, action, type);
|
||||
|
||||
// Will deleted in DB at next save (it can create data until save but marked as deleted)
|
||||
m_actionButtons[button].uState = ACTIONBUTTON_DELETED;
|
||||
|
||||
@@ -462,6 +462,44 @@ void Player::UpdateNextMailTimeAndUnreads()
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateLFGChannel()
|
||||
{
|
||||
if (!sWorld->getBoolConfig(CONFIG_RESTRICTED_LFG_CHANNEL))
|
||||
return;
|
||||
|
||||
ChannelMgr* cMgr = ChannelMgr::forTeam(GetTeamId());
|
||||
if (!cMgr)
|
||||
return;
|
||||
|
||||
ChatChannelsEntry const* cce = sChatChannelsStore.LookupEntry(26); /*LookingForGroup*/
|
||||
Channel* cLFG = cMgr->GetJoinChannel(cce->pattern[m_session->GetSessionDbcLocale()], cce->ChannelID);
|
||||
if (!cLFG)
|
||||
return;
|
||||
|
||||
Channel* cUsed = nullptr;
|
||||
for (Channel* channel : m_channels)
|
||||
if (channel && channel->GetChannelId() == cce->ChannelID)
|
||||
{
|
||||
cUsed = cLFG;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsUsingLfg())
|
||||
{
|
||||
if (cUsed == cLFG)
|
||||
return;
|
||||
|
||||
cLFG->JoinChannel(this, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cLFG != cUsed)
|
||||
return;
|
||||
|
||||
cLFG->LeaveChannel(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateLocalChannels(uint32 newZone)
|
||||
{
|
||||
// pussywizard: mutex needed (tc changed opcode to THREAD UNSAFE)
|
||||
|
||||
@@ -10401,6 +10401,10 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
|
||||
if (meleeAttack)
|
||||
AddUnitState(UNIT_STATE_MELEE_ATTACKING);
|
||||
|
||||
// Update leash timer when attacking creatures
|
||||
if (victim->IsCreature())
|
||||
victim->ToCreature()->UpdateLeashExtensionTime();
|
||||
|
||||
// set position before any AI calls/assistance
|
||||
//if (IsCreature())
|
||||
// ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
|
||||
@@ -10410,6 +10414,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
|
||||
SetInCombatWith(victim);
|
||||
if (victim->IsPlayer())
|
||||
victim->SetInCombatWith(this);
|
||||
|
||||
AddThreat(victim, 0.0f);
|
||||
|
||||
creature->SendAIReaction(AI_REACTION_HOSTILE);
|
||||
@@ -13640,9 +13645,6 @@ void Unit::SetInCombatWith(Unit* enemy, uint32 duration)
|
||||
}
|
||||
}
|
||||
|
||||
if (Creature* pCreature = ToCreature())
|
||||
pCreature->UpdateLeashExtensionTime();
|
||||
|
||||
SetInCombatState(false, enemy, duration);
|
||||
}
|
||||
|
||||
@@ -13717,6 +13719,10 @@ void Unit::CombatStart(Unit* victim, bool initialAggro)
|
||||
SetInCombatWith(victim);
|
||||
victim->SetInCombatWith(this);
|
||||
|
||||
// Update leash timer when attacking creatures
|
||||
if (victim->IsCreature())
|
||||
victim->ToCreature()->UpdateLeashExtensionTime();
|
||||
|
||||
// Xinef: If pet started combat - put owner in combat
|
||||
if (!alreadyInCombat && IsInCombat())
|
||||
{
|
||||
@@ -13753,6 +13759,12 @@ void Unit::CombatStartOnCast(Unit* target, bool initialAggro, uint32 duration)
|
||||
// Xinef: If pet started combat - put owner in combat
|
||||
if (Unit* owner = GetOwner())
|
||||
owner->SetInCombatWith(target, duration);
|
||||
|
||||
// Update leash timer when attacking creatures
|
||||
if (target->IsCreature())
|
||||
target->ToCreature()->UpdateLeashExtensionTime();
|
||||
else if (ToCreature()) // Reset leash if it is a spell caster, else it may evade inbetween casts
|
||||
ToCreature()->UpdateLeashExtensionTime();
|
||||
}
|
||||
|
||||
Unit* who = target->GetCharmerOrOwnerOrSelf();
|
||||
|
||||
@@ -8688,7 +8688,7 @@ bool ObjectMgr::LoadModuleStringsLocale()
|
||||
std::string const* ObjectMgr::GetModuleString(std::string module, uint32 id, LocaleConstant locale) const
|
||||
{
|
||||
ModuleString const* ms = GetModuleString(module, id);
|
||||
if (ms->Content.size())
|
||||
if (ms && !ms->Content.empty())
|
||||
{
|
||||
if (ms->Content.size() > size_t(locale) && !ms->Content[locale].empty())
|
||||
return &ms->Content[locale];
|
||||
|
||||
@@ -47,15 +47,11 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
|
||||
return;
|
||||
|
||||
if (channelName.size() >= 100 || !DisallowHyperlinksAndMaybeKick(channelName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeamId()))
|
||||
{
|
||||
if (Channel* channel = cMgr->GetJoinChannel(channelName, channelId))
|
||||
channel->JoinChannel(GetPlayer(), password);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket)
|
||||
@@ -70,10 +66,8 @@ void WorldSession::HandleLeaveChannel(WorldPacket& recvPacket)
|
||||
return;
|
||||
|
||||
if (ChannelMgr* cMgr = ChannelMgr::forTeam(GetPlayer()->GetTeamId()))
|
||||
{
|
||||
if (Channel* channel = cMgr->GetChannel(channelName, GetPlayer()))
|
||||
channel->LeaveChannel(GetPlayer(), true);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleChannelList(WorldPacket& recvPacket)
|
||||
|
||||
@@ -71,6 +71,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPackets::LFG::LFGJoin& packet)
|
||||
GetPlayerInfo(), packet.Roles, newDungeons.size(), packet.Comment);
|
||||
|
||||
sLFGMgr->JoinLfg(GetPlayer(), uint8(packet.Roles), newDungeons, packet.Comment);
|
||||
GetPlayer()->UpdateLFGChannel();
|
||||
}
|
||||
|
||||
void WorldSession::HandleLfgLeaveOpcode(WorldPackets::LFG::LFGLeave& /*packet*/)
|
||||
@@ -87,6 +88,7 @@ void WorldSession::HandleLfgLeaveOpcode(WorldPackets::LFG::LFGLeave& /*packet*/)
|
||||
sLFGMgr->LeaveLfg(sLFGMgr->GetState(guid) == lfg::LFG_STATE_RAIDBROWSER ? guid : gguid);
|
||||
sLFGMgr->LeaveAllLfgQueues(guid, true, group ? group->GetGUID() : ObjectGuid::Empty);
|
||||
}
|
||||
GetPlayer()->UpdateLFGChannel();
|
||||
}
|
||||
|
||||
void WorldSession::HandleLfgProposalResultOpcode(WorldPacket& recvData)
|
||||
|
||||
@@ -55,6 +55,18 @@ void InstanceScript::SaveToDB()
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void InstanceScript::OnPlayerEnter(Player* player)
|
||||
{
|
||||
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsTwoFactionInstance())
|
||||
player->SetFaction((_teamIdInInstance == TEAM_HORDE) ? 1610 /*FACTION_HORDE*/ : 1 /*FACTION_ALLIANCE*/);
|
||||
}
|
||||
|
||||
void InstanceScript::OnPlayerLeave(Player* player)
|
||||
{
|
||||
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsTwoFactionInstance())
|
||||
player->SetFactionForRace(player->getRace());
|
||||
}
|
||||
|
||||
void InstanceScript::OnCreatureCreate(Creature* creature)
|
||||
{
|
||||
AddObject(creature);
|
||||
@@ -584,6 +596,12 @@ void InstanceScript::DoRespawnGameObject(ObjectGuid uiGuid, uint32 uiTimeToDespa
|
||||
LOG_DEBUG("scripts", "InstanceScript: DoRespawnGameObject failed");
|
||||
}
|
||||
|
||||
void InstanceScript::DoRespawnGameObject(uint32 type)
|
||||
{
|
||||
if (GameObject* go = instance->GetGameObject(GetObjectGuid(type)))
|
||||
go->Respawn();
|
||||
}
|
||||
|
||||
void InstanceScript::DoRespawnCreature(ObjectGuid guid, bool force)
|
||||
{
|
||||
if (Creature* creature = instance->GetCreature(guid))
|
||||
@@ -848,3 +866,21 @@ bool InstanceHasScript(WorldObject const* obj, char const* scriptName)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InstanceScript::IsTwoFactionInstance() const
|
||||
{
|
||||
switch (instance->GetId())
|
||||
{
|
||||
case 540: // Shattered Halls
|
||||
case 576: // Nexus
|
||||
case 631: // Icecrown Citadel
|
||||
case 632: // Forge of Souls
|
||||
case 649: // Trial of the Champion
|
||||
case 650: // Trial of the Crusader
|
||||
case 658: // Pit of Saron
|
||||
case 668: // Halls of Reflection
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ typedef std::map<ObjectGuid::LowType /*spawnId*/, uint8 /*state*/> ObjectStateMa
|
||||
class InstanceScript : public ZoneScript
|
||||
{
|
||||
public:
|
||||
explicit InstanceScript(Map* map) : instance(map), completedEncounters(0) {}
|
||||
explicit InstanceScript(Map* map) : instance(map), completedEncounters(0), _teamIdInInstance(TEAM_NEUTRAL) {}
|
||||
|
||||
~InstanceScript() override {}
|
||||
|
||||
@@ -182,10 +182,10 @@ public:
|
||||
GameObject* GetGameObject(uint32 type);
|
||||
|
||||
//Called when a player successfully enters the instance.
|
||||
virtual void OnPlayerEnter(Player* /*player*/) {}
|
||||
virtual void OnPlayerEnter(Player* /*player*/);
|
||||
|
||||
//Called when a player successfully leaves the instance.
|
||||
virtual void OnPlayerLeave(Player* /*player*/) {}
|
||||
virtual void OnPlayerLeave(Player* /*player*/);
|
||||
|
||||
virtual void OnPlayerAreaUpdate(Player* /*player*/, uint32 /*oldArea*/, uint32 /*newArea*/) {}
|
||||
|
||||
@@ -203,6 +203,9 @@ public:
|
||||
//Respawns a GO having negative spawntimesecs in gameobject-table
|
||||
void DoRespawnGameObject(ObjectGuid guid, uint32 timeToDespawn = MINUTE);
|
||||
|
||||
// Respawns a GO by instance storage index
|
||||
void DoRespawnGameObject(uint32 type);
|
||||
|
||||
// Respawns a creature.
|
||||
void DoRespawnCreature(ObjectGuid guid, bool force = false);
|
||||
|
||||
@@ -282,6 +285,10 @@ public:
|
||||
[[nodiscard]] bool AllBossesDone() const;
|
||||
[[nodiscard]] bool AllBossesDone(std::initializer_list<uint32> bossIds) const;
|
||||
|
||||
TeamId GetTeamIdInInstance() const { return _teamIdInInstance; }
|
||||
void SetTeamIdInInstance(TeamId teamId) { _teamIdInInstance = teamId; }
|
||||
bool IsTwoFactionInstance() const;
|
||||
|
||||
TaskScheduler scheduler;
|
||||
protected:
|
||||
void SetHeaders(std::string const& dataHeaders);
|
||||
@@ -336,6 +343,7 @@ private:
|
||||
ObjectGuidMap _objectGuids;
|
||||
ObjectStateMap _objectStateMap;
|
||||
uint32 completedEncounters; // completed encounter mask, bit indexes are DungeonEncounter.dbc boss numbers, used for packets
|
||||
TeamId _teamIdInInstance;
|
||||
std::unordered_set<uint32> _activatedAreaTriggers;
|
||||
};
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ bool Map::ExistMap(uint32 mapid, int gx, int gy)
|
||||
{
|
||||
if (header.mapMagic != MapMagic.asUInt || header.versionMagic != MapVersionMagic)
|
||||
{
|
||||
LOG_ERROR("maps", "Map file '{}' is from an incompatible map version (%.*u v{}), %.*s v{} is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files.",
|
||||
LOG_ERROR("maps", "Map file '{}' is from an incompatible map version ({:.4u} v{}), {:.4s} v{} is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files.",
|
||||
tmp, 4, header.mapMagic, header.versionMagic, 4, MapMagic.asChar, MapVersionMagic);
|
||||
}
|
||||
|
||||
@@ -3026,6 +3026,15 @@ bool InstanceMap::AddPlayerToMap(Player* player)
|
||||
m_resetAfterUnload = false;
|
||||
m_unloadWhenEmpty = false;
|
||||
|
||||
if (instance_data && instance_data->IsTwoFactionInstance()
|
||||
&& instance_data->GetTeamIdInInstance() == TEAM_NEUTRAL)
|
||||
{
|
||||
instance_data->SetTeamIdInInstance(player->GetTeamId());
|
||||
if (Group* group = player->GetGroup())
|
||||
if (Player* leader = ObjectAccessor::FindConnectedPlayer(group->GetLeaderGUID()))
|
||||
instance_data->SetTeamIdInInstance(leader->GetTeamId());
|
||||
}
|
||||
|
||||
// this will acquire the same mutex so it cannot be in the previous block
|
||||
Map::AddPlayerToMap(player);
|
||||
|
||||
|
||||
@@ -84,6 +84,21 @@ void ScriptMgr::OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex
|
||||
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_DUMMY_EFFECT_ITEM, script->OnDummyEffect(caster, spellID, effIndex, itemTarget));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnSpellCastCancel(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool bySelf)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_CAST_CANCEL, script->OnSpellCastCancel(spell, caster, spellInfo, bySelf));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnSpellCast(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool skipCheck)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_CAST, script->OnSpellCast(spell, caster, spellInfo, skipCheck));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnSpellPrepare(Spell* spell, Unit* caster, SpellInfo const* spellInfo)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(AllSpellScript, ALLSPELLHOOK_ON_PREPARE, script->OnSpellPrepare(spell, caster, spellInfo));
|
||||
}
|
||||
|
||||
AllSpellScript::AllSpellScript(char const* name, std::vector<uint16> enabledHooks)
|
||||
: ScriptObject(name, ALLSPELLHOOK_END)
|
||||
{
|
||||
|
||||
@@ -36,6 +36,9 @@ enum AllSpellHook
|
||||
ALLSPELLHOOK_ON_DUMMY_EFFECT_GAMEOBJECT,
|
||||
ALLSPELLHOOK_ON_DUMMY_EFFECT_CREATURE,
|
||||
ALLSPELLHOOK_ON_DUMMY_EFFECT_ITEM,
|
||||
ALLSPELLHOOK_ON_CAST_CANCEL,
|
||||
ALLSPELLHOOK_ON_CAST,
|
||||
ALLSPELLHOOK_ON_PREPARE,
|
||||
ALLSPELLHOOK_END
|
||||
};
|
||||
|
||||
@@ -100,6 +103,12 @@ public:
|
||||
* @param itemTarget Contains information about the Item
|
||||
*/
|
||||
virtual void OnDummyEffect(WorldObject* /*caster*/, uint32 /*spellID*/, SpellEffIndex /*effIndex*/, Item* /*itemTarget*/) { }
|
||||
|
||||
virtual void OnSpellCastCancel(Spell* /*spell*/, Unit* /*caster*/, SpellInfo const* /*spellInfo*/, bool /*bySelf*/) { }
|
||||
|
||||
virtual void OnSpellCast(Spell* /*spell*/, Unit* /*caster*/, SpellInfo const* /*spellInfo*/, bool /*skipCheck*/) { }
|
||||
|
||||
virtual void OnSpellPrepare(Spell* /*spell*/, Unit* /*caster*/, SpellInfo const* /*spellInfo*/) { }
|
||||
};
|
||||
|
||||
// Compatibility for old scripts
|
||||
|
||||
@@ -648,6 +648,9 @@ public: /* SpellSC */
|
||||
void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, GameObject* gameObjTarget);
|
||||
void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, Creature* creatureTarget);
|
||||
void OnDummyEffect(WorldObject* caster, uint32 spellID, SpellEffIndex effIndex, Item* itemTarget);
|
||||
void OnSpellCastCancel(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool bySelf);
|
||||
void OnSpellCast(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool skipCheck);
|
||||
void OnSpellPrepare(Spell* spell, Unit* caster, SpellInfo const* spellInfo);
|
||||
|
||||
public: /* GameEventScript */
|
||||
void OnGameEventStart(uint16 EventID);
|
||||
|
||||
@@ -3717,6 +3717,8 @@ SpellCastResult Spell::prepare(SpellCastTargets const* targets, AuraEffect const
|
||||
TriggerGlobalCooldown();
|
||||
}
|
||||
|
||||
sScriptMgr->OnSpellPrepare(this, m_caster, m_spellInfo);
|
||||
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
@@ -3788,6 +3790,8 @@ void Spell::cancel(bool bySelf)
|
||||
//set state back so finish will be processed
|
||||
m_spellState = oldState;
|
||||
|
||||
sScriptMgr->OnSpellCastCancel(this, m_caster, m_spellInfo, bySelf);
|
||||
|
||||
finish(false);
|
||||
}
|
||||
|
||||
@@ -4114,6 +4118,8 @@ void Spell::_cast(bool skipCheck)
|
||||
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
|
||||
m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true);
|
||||
|
||||
sScriptMgr->OnSpellCast(this, m_caster, m_spellInfo, skipCheck);
|
||||
|
||||
SetExecutedCurrently(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -2644,8 +2644,6 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const
|
||||
// some explicitly required dummy effect sets
|
||||
switch (Id)
|
||||
{
|
||||
case 28441:
|
||||
return false; // AB Effect 000
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user