Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-01-23 23:23:53 +08:00
77 changed files with 1682 additions and 1680 deletions
@@ -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);
+1 -1
View File
@@ -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())
+1 -4
View File
@@ -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);
+1 -1
View File
@@ -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)); }
+2 -2
View File
@@ -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;
}
+2 -1
View File
@@ -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)
+15 -3
View File
@@ -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();
+1 -1
View File
@@ -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)
+2
View File
@@ -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;
}
+11 -3
View File
@@ -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;
};
+10 -1
View File
@@ -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
+3
View File
@@ -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);
+6
View File
@@ -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);
}
-2
View File
@@ -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;
}