Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-03-28 19:15:09 +08:00
36 changed files with 3768 additions and 729 deletions

View File

@@ -68,6 +68,8 @@ namespace AccountMgr
if (!result)
return AOR_NAME_NOT_EXIST;
sScriptMgr->OnBeforeAccountDelete(accountId);
// Obtain accounts characters
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
stmt->SetData(0, accountId);

View File

@@ -708,6 +708,15 @@ void WorldSession::HandleSetTradeItemOpcode(WorldPacket& recvPacket)
return;
}
// PlayerScript Hook for checking traded items if we want to filter them in a custom module
if (!sScriptMgr->CanSetTradeItem(_player, item, tradeSlot))
{
// Do not send TRADE_STATUS_TRADE_CANCELED because it will cause double display of "Transaction canceled" notification
// On the trade initiator screen
SendTradeStatus(TRADE_STATUS_CLOSE_WINDOW);
return;
}
my_trade->SetItem(TradeSlots(tradeSlot), item);
}

View File

@@ -27,6 +27,14 @@ void ScriptMgr::OnAccountLogin(uint32 accountId)
});
}
void ScriptMgr::OnBeforeAccountDelete(uint32 accountId)
{
ExecuteScript<AccountScript>([&](AccountScript* script)
{
script->OnBeforeAccountDelete(accountId);
});
}
//void ScriptMgr::OnAccountLogout(uint32 accountId)
//{
// ExecuteScript<AccountScript>([&](AccountScript* script)

View File

@@ -29,6 +29,9 @@ public:
// Called when an account logged in successfully
virtual void OnAccountLogin(uint32 /*accountId*/) { }
// Called when an account is about to be deleted
virtual void OnBeforeAccountDelete(uint32 /*accountId*/) { }
// Called when an ip logged in successfully
virtual void OnLastIpUpdate(uint32 /*accountId*/, std::string /*ip*/) { }

View File

@@ -1516,6 +1516,19 @@ bool ScriptMgr::CanInitTrade(Player* player, Player* target)
return true;
}
bool ScriptMgr::CanSetTradeItem(Player* player, Item* tradedItem, uint8 tradeSlot)
{
auto ret = IsValidBoolScript<PlayerScript>([&](PlayerScript* script)
{
return !script->CanSetTradeItem(player, tradedItem, tradeSlot);
});
if (ret && *ret)
return false;
return true;
}
void ScriptMgr::OnSetServerSideVisibility(Player* player, ServerSideVisibilityType& type, AccountTypes& sec)
{
ExecuteScript<PlayerScript>([&](PlayerScript* script)

View File

@@ -422,6 +422,16 @@ public:
[[nodiscard]] virtual bool CanInitTrade(Player* /*player*/, Player* /*target*/) { return true; }
/**
* @brief This hook called just before finishing the handling of the action of a player setting an item in a trade slot
*
* @param player Contains information about the trade initiator Player
* @param tradedItem Contains information about the item set in the trade slot
*
* @return True if you want to continue setting the item in the trade slot, false if you want to cancel the trade
*/
[[nodiscard]] virtual bool CanSetTradeItem(Player* /*player*/, Item* /*tradedItem*/, uint8 /*tradeSlot*/) { return true; }
virtual void OnSetServerSideVisibility(Player* /*player*/, ServerSideVisibilityType& /*type*/, AccountTypes& /*sec*/) { }
virtual void OnSetServerSideVisibilityDetect(Player* /*player*/, ServerSideVisibilityType& /*type*/, AccountTypes& /*sec*/) { }

View File

@@ -473,6 +473,7 @@ public: /* PlayerScript */
bool CanJoinLfg(Player* player, uint8 roles, lfg::LfgDungeonSet& dungeons, const std::string& comment);
bool CanEnterMap(Player* player, MapEntry const* entry, InstanceTemplate const* instance, MapDifficulty const* mapDiff, bool loginCheck);
bool CanInitTrade(Player* player, Player* target);
bool CanSetTradeItem(Player* player, Item* tradedItem, uint8 tradeSlot);
void OnSetServerSideVisibility(Player* player, ServerSideVisibilityType& type, AccountTypes& sec);
void OnSetServerSideVisibilityDetect(Player* player, ServerSideVisibilityType& type, AccountTypes& sec);
void OnPlayerResurrect(Player* player, float restore_percent, bool applySickness);
@@ -502,6 +503,7 @@ public: /* PlayerScript */
public: /* AccountScript */
void OnAccountLogin(uint32 accountId);
void OnBeforeAccountDelete(uint32 accountId);
void OnLastIpUpdate(uint32 accountId, std::string ip);
void OnFailedAccountLogin(uint32 accountId);
void OnEmailChange(uint32 accountId);

View File

@@ -105,7 +105,10 @@ public:
Talk(SAY_ONDEATH);
// If Archimonde has not yet been initialized, this won't trigger
if (Creature* archi = instance->GetCreature(DATA_ARCHIMONDE))
{
archi->AI()->DoAction(ACTION_BECOME_ACTIVE_AND_CHANNEL);
archi->AI()->Talk(SAY_ARCHIMONDE_INTRO, 25000ms);
}
BossAI::JustDied(killer);
}

View File

@@ -614,7 +614,7 @@ struct npc_hyjal_frost_wyrm : public ScriptedAI
{
scheduler.Schedule(0s, [this](TaskContext context)
{
DoCastVictim(SPELL_GARGOYLE_STRIKE);
DoCastVictim(SPELL_FROST_BREATH);
context.Repeat(3500ms, 4s);
});
}

View File

@@ -178,6 +178,11 @@ enum HyjalPaths
HORDE_BOSS_PATH = 178527
};
enum BossActions
{
ACTION_BECOME_ACTIVE_AND_CHANNEL = 0
};
template <class AI, class T>
inline AI* GetHyjalAI(T* obj)
{

View File

@@ -491,6 +491,7 @@ public:
{
// No overlapping!
_scheduler.CancelGroup(CONTEXT_GROUP_WAVES);
trash = 0; // Reset counter here to avoid resetting the counter from scheduled waves. Required because creatures killed for RP events counts towards the kill counter as well, confirmed in Retail.
_scheduler.Schedule(1ms, [this, startWaves, maxWaves, timerptr](TaskContext context)
{
@@ -498,7 +499,6 @@ public:
if (_currentWave >= maxWaves)
return;
trash = 0; // Overrun event trash can modify the counter, so we set it to 0 at the start of every wave. World Update is sent in the first spawn
instance->SummonCreatureGroup(startWaves + _currentWave); // _currentWave should be 0 when this function is first called
// Check if it's time to summon Infernals

View File

@@ -37,7 +37,8 @@ enum Yells
{
SAY_AGGRO = 0,
SAY_DEATH = 1,
SAY_FAIL = 2
SAY_FAIL = 2,
SAY_THANKS = 0
};
class boss_infinite_corruptor : public CreatureScript
@@ -98,7 +99,7 @@ public:
{
cr->DespawnOrUnsummon(5000);
cr->RemoveAllAuras();
cr->Say("You have my thanks for saving my existence in this timeline. Now i must report back to my superiors. They must know immediately of what i just experienced.", LANG_UNIVERSAL);
cr->AI()->Talk(SAY_THANKS);
}
}
}

View File

@@ -97,13 +97,15 @@ enum Says
//Cityman
SAY_PHASE202 = 0,
SAY_PHASE204_1 = 0,
//Crazyman
SAY_PHASE204 = 0,
SAY_PHASE204 = 1,
//Drakonian
SAY_PHASE302 = 0,
SAY_PHASE305 = 1,
SAY_PHASE305_1 = 39,
};
enum NPCs
@@ -559,7 +561,7 @@ public:
case 11:
if (Creature* cityman = GetEventNpc(NPC_CITY_MAN2))
{
cityman->Say("Oh no...", LANG_UNIVERSAL); // missing script_text
cityman->AI()->Talk(SAY_PHASE204_1);
me->CastSpell(cityman, SPELL_ARTHAS_CRUSADER_STRIKE, true);
}
me->SetReactState(REACT_DEFENSIVE);
@@ -1019,7 +1021,7 @@ public:
}
summons.DespawnAll();
me->Say("I can't afford to spare you.", LANG_UNIVERSAL);
Talk(SAY_PHASE305_1);
me->SetFacingTo(0.0f);
ScheduleNextEvent(currentEvent, 5000);
break;

View File

@@ -36,10 +36,9 @@ enum Yells
EMOTE_VORTEX = 3,
EMOTE_TWINK_PACT = 4,
SAY_TWINK_PACT = 5,
SAY_KILL_PLAYER_1 = 6,
SAY_KILL_PLAYER = 6,
SAY_BERSERK = 7,
SAY_DEATH = 8,
SAY_KILL_PLAYER_2 = 9,
};
enum Equipment
@@ -502,10 +501,9 @@ struct boss_twin_valkyrAI : public ScriptedAI
{
if( who->GetTypeId() == TYPEID_PLAYER )
{
int32 id = urand(0, 1) ? SAY_KILL_PLAYER_1 : SAY_KILL_PLAYER_2;
Talk(id);
Talk(SAY_KILL_PLAYER);
if( Creature* twin = GetSister() )
twin->AI()->Talk(id);
twin->AI()->Talk(SAY_KILL_PLAYER);
}
}

View File

@@ -884,8 +884,7 @@ public:
{
if( Creature* c = instance->GetCreature(NPC_JaraxxusGUID) )
{
c->Yell("Banished to the Nether!", LANG_UNIVERSAL);
c->PlayDirectSound(16146, 0);
c->AI()->Talk(SAY_STAGE_1_06_1);
if( Creature* f = instance->GetCreature(NPC_FizzlebangGUID) )
{
c->CastSpell(f, 67888, true);

View File

@@ -260,6 +260,7 @@ enum eTexts
// Lord Jaraxxus
SAY_STAGE_1_05 = 0,
SAY_STAGE_1_06_1 = 9,
// The Lich King
SAY_STAGE_4_02 = 0,

View File

@@ -66,7 +66,8 @@ enum Spells
enum Misc
{
GO_CAGE = 185474
GO_CAGE = 185474,
ACTION_RESET_ADDS = 1
};
const Position olumWalk = { 456.17194f, -544.31866f, -7.5470476f, 0.00f };
@@ -75,6 +76,17 @@ struct boss_fathomlord_karathress : public BossAI
{
boss_fathomlord_karathress(Creature* creature) : BossAI(creature, DATA_FATHOM_LORD_KARATHRESS){ }
void JustReachedHome() override
{
instance->DoForAllMinions(DATA_FATHOM_LORD_KARATHRESS, [&](Creature* fathomguard)
{
if (!fathomguard->IsAlive())
{
fathomguard->Respawn(true);
}
});
}
void Reset() override
{
BossAI::Reset();
@@ -156,6 +168,18 @@ struct boss_fathomlord_karathress : public BossAI
DoCastSelf(SPELL_ENRAGE, true);
});
}
void DoAction(int32 action) override
{
if (action == ACTION_RESET_ADDS)
{
EnterEvadeMode();
instance->DoForAllMinions(DATA_FATHOM_LORD_KARATHRESS, [&](Creature* fathomguard)
{
fathomguard->DespawnOrUnsummon();
});
}
}
private:
bool _recentlySpoken;
};
@@ -259,6 +283,15 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
DoMeleeAttackIfReady();
}
void EnterEvadeMode(EvadeReason why) override
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
karathress->AI()->DoAction(ACTION_RESET_ADDS);
}
ScriptedAI::EnterEvadeMode(why);
}
private:
InstanceScript* _instance;
SummonList _summons;
@@ -434,6 +467,15 @@ struct boss_fathomguard_tidalvess : public ScriptedAI
DoMeleeAttackIfReady();
}
void EnterEvadeMode(EvadeReason why) override
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
karathress->AI()->DoAction(ACTION_RESET_ADDS);
}
ScriptedAI::EnterEvadeMode(why);
}
private:
TaskScheduler _scheduler;
TaskScheduler _totemScheduler;
@@ -518,6 +560,15 @@ struct boss_fathomguard_caribdis : public ScriptedAI
DoMeleeAttackIfReady();
}
void EnterEvadeMode(EvadeReason why) override
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
karathress->AI()->DoAction(ACTION_RESET_ADDS);
}
ScriptedAI::EnterEvadeMode(why);
}
private:
TaskScheduler _scheduler;
InstanceScript* _instance;

View File

@@ -95,10 +95,10 @@ struct boss_void_reaver : public BossAI
context.Repeat(12100ms, 15800ms);
}).Schedule(3450ms, GROUP_ARCANE_ORB, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, -18.0f, true))
me->CastSpell(target, SPELL_ARCANE_ORB, false);
else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 20.0f, true))
me->CastSpell(target, SPELL_ARCANE_ORB, false);
if (!DoCastRandomTarget(SPELL_ARCANE_ORB, 0, -18.0f))
{
DoCastRandomTarget(SPELL_ARCANE_ORB, 0, 18.0f);
}
context.Repeat(2400ms, 6300ms);
}).Schedule(14350ms, [this](TaskContext context)
{