More work on scripts.

This commit is contained in:
hondacrx
2023-10-13 20:25:10 -04:00
parent b2ac8035f2
commit 50cda96b45
16 changed files with 1073 additions and 732 deletions
+21
View File
@@ -167,10 +167,16 @@ namespace Game
string username; string username;
if (!GetName(accountId, out username)) if (!GetName(accountId, out username))
{
Global.ScriptMgr.OnFailedPasswordChange(accountId);
return AccountOpResult.NameNotExist; // account doesn't exist return AccountOpResult.NameNotExist; // account doesn't exist
}
if (newPassword.Length > MaxAccountLength) if (newPassword.Length > MaxAccountLength)
{
Global.ScriptMgr.OnFailedPasswordChange(accountId);
return AccountOpResult.PassTooLong; return AccountOpResult.PassTooLong;
}
(byte[] salt, byte[] verifier) = SRP6.MakeRegistrationData(username, newPassword); (byte[] salt, byte[] verifier) = SRP6.MakeRegistrationData(username, newPassword);
@@ -180,38 +186,53 @@ namespace Game
stmt.AddValue(2, accountId); stmt.AddValue(2, accountId);
DB.Login.Execute(stmt); DB.Login.Execute(stmt);
Global.ScriptMgr.OnPasswordChange(accountId);
return AccountOpResult.Ok; return AccountOpResult.Ok;
} }
public AccountOpResult ChangeEmail(uint accountId, string newEmail) public AccountOpResult ChangeEmail(uint accountId, string newEmail)
{ {
if (!GetName(accountId, out _)) if (!GetName(accountId, out _))
{
Global.ScriptMgr.OnFailedEmailChange(accountId);
return AccountOpResult.NameNotExist; // account doesn't exist return AccountOpResult.NameNotExist; // account doesn't exist
}
if (newEmail.Length > MaxEmailLength) if (newEmail.Length > MaxEmailLength)
{
Global.ScriptMgr.OnFailedEmailChange(accountId);
return AccountOpResult.EmailTooLong; return AccountOpResult.EmailTooLong;
}
PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.UPD_EMAIL); PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.UPD_EMAIL);
stmt.AddValue(0, newEmail); stmt.AddValue(0, newEmail);
stmt.AddValue(1, accountId); stmt.AddValue(1, accountId);
DB.Login.Execute(stmt); DB.Login.Execute(stmt);
Global.ScriptMgr.OnEmailChange(accountId);
return AccountOpResult.Ok; return AccountOpResult.Ok;
} }
public AccountOpResult ChangeRegEmail(uint accountId, string newEmail) public AccountOpResult ChangeRegEmail(uint accountId, string newEmail)
{ {
if (!GetName(accountId, out _)) if (!GetName(accountId, out _))
{
Global.ScriptMgr.OnFailedEmailChange(accountId);
return AccountOpResult.NameNotExist; // account doesn't exist return AccountOpResult.NameNotExist; // account doesn't exist
}
if (newEmail.Length > MaxEmailLength) if (newEmail.Length > MaxEmailLength)
{
Global.ScriptMgr.OnFailedEmailChange(accountId);
return AccountOpResult.EmailTooLong; return AccountOpResult.EmailTooLong;
}
PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.UPD_REG_EMAIL); PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.UPD_REG_EMAIL);
stmt.AddValue(0, newEmail); stmt.AddValue(0, newEmail);
stmt.AddValue(1, accountId); stmt.AddValue(1, accountId);
DB.Login.Execute(stmt); DB.Login.Execute(stmt);
Global.ScriptMgr.OnEmailChange(accountId);
return AccountOpResult.Ok; return AccountOpResult.Ok;
} }
+12 -3
View File
@@ -197,7 +197,7 @@ namespace Game.Chat
} }
[Command("create", CypherStrings.CommandAccCreateHelp, RBACPermissions.CommandAccountCreate, true)] [Command("create", CypherStrings.CommandAccCreateHelp, RBACPermissions.CommandAccountCreate, true)]
static bool HandleAccountCreateCommand(CommandHandler handler, string accountName, string password, [OptionalArg]string email) static bool HandleAccountCreateCommand(CommandHandler handler, string accountName, string password, [OptionalArg] string email)
{ {
if (accountName.Contains("@")) if (accountName.Contains("@"))
{ {
@@ -277,6 +277,7 @@ namespace Game.Chat
if (!Global.AccountMgr.CheckEmail(handler.GetSession().GetAccountId(), oldEmail)) if (!Global.AccountMgr.CheckEmail(handler.GetSession().GetAccountId(), oldEmail))
{ {
handler.SendSysMessage(CypherStrings.CommandWrongemail); handler.SendSysMessage(CypherStrings.CommandWrongemail);
Global.ScriptMgr.OnFailedEmailChange(handler.GetSession().GetAccountId());
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change email, but the provided email [{4}] is not equal to registration email [{5}].", Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change email, but the provided email [{4}] is not equal to registration email [{5}].",
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(), handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
@@ -287,6 +288,7 @@ namespace Game.Chat
if (!Global.AccountMgr.CheckPassword(handler.GetSession().GetAccountId(), password)) if (!Global.AccountMgr.CheckPassword(handler.GetSession().GetAccountId(), password))
{ {
handler.SendSysMessage(CypherStrings.CommandWrongoldpassword); handler.SendSysMessage(CypherStrings.CommandWrongoldpassword);
Global.ScriptMgr.OnFailedEmailChange(handler.GetSession().GetAccountId());
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change email, but the provided password is wrong.", Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change email, but the provided password is wrong.",
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString()); handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
@@ -296,12 +298,14 @@ namespace Game.Chat
if (email == oldEmail) if (email == oldEmail)
{ {
handler.SendSysMessage(CypherStrings.OldEmailIsNewEmail); handler.SendSysMessage(CypherStrings.OldEmailIsNewEmail);
Global.ScriptMgr.OnFailedEmailChange(handler.GetSession().GetAccountId());
return false; return false;
} }
if (email != emailConfirm) if (email != emailConfirm)
{ {
handler.SendSysMessage(CypherStrings.NewEmailsNotMatch); handler.SendSysMessage(CypherStrings.NewEmailsNotMatch);
Global.ScriptMgr.OnFailedEmailChange(handler.GetSession().GetAccountId());
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change email, but the provided password is wrong.", Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change email, but the provided password is wrong.",
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString()); handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
@@ -314,6 +318,7 @@ namespace Game.Chat
{ {
case AccountOpResult.Ok: case AccountOpResult.Ok:
handler.SendSysMessage(CypherStrings.CommandEmail); handler.SendSysMessage(CypherStrings.CommandEmail);
Global.ScriptMgr.OnEmailChange(handler.GetSession().GetAccountId());
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Changed Email from [{4}] to [{5}].", Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Changed Email from [{4}] to [{5}].",
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(), handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
@@ -321,6 +326,7 @@ namespace Game.Chat
break; break;
case AccountOpResult.EmailTooLong: case AccountOpResult.EmailTooLong:
handler.SendSysMessage(CypherStrings.EmailTooLong); handler.SendSysMessage(CypherStrings.EmailTooLong);
Global.ScriptMgr.OnFailedEmailChange(handler.GetSession().GetAccountId());
return false; return false;
default: default:
handler.SendSysMessage(CypherStrings.CommandNotchangeemail); handler.SendSysMessage(CypherStrings.CommandNotchangeemail);
@@ -340,7 +346,7 @@ namespace Game.Chat
if (!Global.AccountMgr.CheckPassword(handler.GetSession().GetAccountId(), oldPassword)) if (!Global.AccountMgr.CheckPassword(handler.GetSession().GetAccountId(), oldPassword))
{ {
handler.SendSysMessage(CypherStrings.CommandWrongoldpassword); handler.SendSysMessage(CypherStrings.CommandWrongoldpassword);
Global.ScriptMgr.OnFailedPasswordChange(handler.GetSession().GetAccountId());
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change password, but the provided old password is wrong.", Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change password, but the provided old password is wrong.",
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString()); handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
@@ -351,7 +357,7 @@ namespace Game.Chat
&& !Global.AccountMgr.CheckEmail(handler.GetSession().GetAccountId(), confirmEmail)) // ... and returns false if the comparison fails. && !Global.AccountMgr.CheckEmail(handler.GetSession().GetAccountId(), confirmEmail)) // ... and returns false if the comparison fails.
{ {
handler.SendSysMessage(CypherStrings.CommandWrongemail); handler.SendSysMessage(CypherStrings.CommandWrongemail);
Global.ScriptMgr.OnFailedPasswordChange(handler.GetSession().GetAccountId());
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change password, but the entered email [{4}] is wrong.", Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Tried to change password, but the entered email [{4}] is wrong.",
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(), handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
@@ -363,6 +369,7 @@ namespace Game.Chat
if (newPassword != confirmPassword) if (newPassword != confirmPassword)
{ {
handler.SendSysMessage(CypherStrings.NewPasswordsNotMatch); handler.SendSysMessage(CypherStrings.NewPasswordsNotMatch);
Global.ScriptMgr.OnFailedPasswordChange(handler.GetSession().GetAccountId());
return false; return false;
} }
@@ -372,12 +379,14 @@ namespace Game.Chat
{ {
case AccountOpResult.Ok: case AccountOpResult.Ok:
handler.SendSysMessage(CypherStrings.CommandPassword); handler.SendSysMessage(CypherStrings.CommandPassword);
Global.ScriptMgr.OnPasswordChange(handler.GetSession().GetAccountId());
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Changed Password.", Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Changed Password.",
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString()); handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
break; break;
case AccountOpResult.PassTooLong: case AccountOpResult.PassTooLong:
handler.SendSysMessage(CypherStrings.PasswordTooLong); handler.SendSysMessage(CypherStrings.PasswordTooLong);
Global.ScriptMgr.OnFailedPasswordChange(handler.GetSession().GetAccountId());
return false; return false;
default: default:
handler.SendSysMessage(CypherStrings.CommandNotchangepassword); handler.SendSysMessage(CypherStrings.CommandNotchangepassword);
+1 -1
View File
@@ -26,7 +26,7 @@ namespace Game.DungeonFinding
Global.LFGMgr.LeaveLfg(player.GetGUID(), true); Global.LFGMgr.LeaveLfg(player.GetGUID(), true);
} }
public override void OnLogin(Player player) public override void OnLogin(Player player, bool firstLogin)
{ {
if (!Global.LFGMgr.IsOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser)) if (!Global.LFGMgr.IsOptionEnabled(LfgOptions.EnableDungeonFinder | LfgOptions.EnableRaidBrowser))
return; return;
+14 -13
View File
@@ -984,7 +984,8 @@ namespace Game
SendNotification(CypherStrings.ResetTalents); SendNotification(CypherStrings.ResetTalents);
} }
if (pCurrChar.HasAtLoginFlag(AtLoginFlags.FirstLogin)) bool firstLogin = pCurrChar.HasAtLoginFlag(AtLoginFlags.FirstLogin);
if (firstLogin)
{ {
pCurrChar.RemoveAtLoginFlag(AtLoginFlags.FirstLogin); pCurrChar.RemoveAtLoginFlag(AtLoginFlags.FirstLogin);
@@ -1075,7 +1076,7 @@ namespace Game
SendNotification(CypherStrings.GmOn); SendNotification(CypherStrings.GmOn);
string IP_str = GetRemoteAddress(); string IP_str = GetRemoteAddress();
Log.outDebug(LogFilter.Network, $"Account: {GetAccountId()} (IP: {GetRemoteAddress()}) Login Character: [{pCurrChar.GetName()}] ({pCurrChar.GetGUID()}) Level: {pCurrChar.GetLevel()}, XP: { _player.GetXP()}/{_player.GetXPForNextLevel()} ({_player.GetXPForNextLevel() - _player.GetXP()} left)"); Log.outDebug(LogFilter.Network, $"Account: {GetAccountId()} (IP: {GetRemoteAddress()}) Login Character: [{pCurrChar.GetName()}] ({pCurrChar.GetGUID()}) Level: {pCurrChar.GetLevel()}, XP: {_player.GetXP()}/{_player.GetXPForNextLevel()} ({_player.GetXPForNextLevel() - _player.GetXP()} left)");
if (!pCurrChar.IsStandState() && !pCurrChar.HasUnitState(UnitState.Stunned)) if (!pCurrChar.IsStandState() && !pCurrChar.HasUnitState(UnitState.Stunned))
pCurrChar.SetStandState(UnitStandStateType.Stand); pCurrChar.SetStandState(UnitStandStateType.Stand);
@@ -1088,7 +1089,7 @@ namespace Game
// Handle Login-Achievements (should be handled after loading) // Handle Login-Achievements (should be handled after loading)
_player.UpdateCriteria(CriteriaType.Login, 1); _player.UpdateCriteria(CriteriaType.Login, 1);
Global.ScriptMgr.OnPlayerLogin(pCurrChar); Global.ScriptMgr.OnPlayerLogin(pCurrChar, firstLogin);
} }
public void AbortLogin(LoginFailureReason reason) public void AbortLogin(LoginFailureReason reason)
@@ -1166,18 +1167,18 @@ namespace Game
switch (packet.Action) switch (packet.Action)
{ {
case TutorialAction.Update: case TutorialAction.Update:
{
byte index = (byte)(packet.TutorialBit >> 5);
if (index >= SharedConst.MaxAccountTutorialValues)
{ {
byte index = (byte)(packet.TutorialBit >> 5); Log.outError(LogFilter.Network, "CMSG_TUTORIAL_FLAG received bad TutorialBit {0}.", packet.TutorialBit);
if (index >= SharedConst.MaxAccountTutorialValues) return;
{
Log.outError(LogFilter.Network, "CMSG_TUTORIAL_FLAG received bad TutorialBit {0}.", packet.TutorialBit);
return;
}
uint flag = GetTutorialInt(index);
flag |= (uint)(1 << (int)(packet.TutorialBit & 0x1F));
SetTutorialInt(index, flag);
break;
} }
uint flag = GetTutorialInt(index);
flag |= (uint)(1 << (int)(packet.TutorialBit & 0x1F));
SetTutorialInt(index, flag);
break;
}
case TutorialAction.Clear: case TutorialAction.Clear:
for (byte i = 0; i < SharedConst.MaxAccountTutorialValues; ++i) for (byte i = 0; i < SharedConst.MaxAccountTutorialValues; ++i)
SetTutorialInt(i, 0xFFFFFFFF); SetTutorialInt(i, 0xFFFFFFFF);
+9
View File
@@ -586,6 +586,8 @@ namespace Game.Networking
{ {
SendAuthResponseError(BattlenetRpcErrorCode.RiskAccountLocked); SendAuthResponseError(BattlenetRpcErrorCode.RiskAccountLocked);
Log.outDebug(LogFilter.Network, "HandleAuthSession: Sent Auth Response (Account IP differs)."); Log.outDebug(LogFilter.Network, "HandleAuthSession: Sent Auth Response (Account IP differs).");
// We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
Global.ScriptMgr.OnFailedAccountLogin(account.game.Id);
CloseSocket(); CloseSocket();
return; return;
} }
@@ -596,6 +598,8 @@ namespace Game.Networking
{ {
SendAuthResponseError(BattlenetRpcErrorCode.RiskAccountLocked); SendAuthResponseError(BattlenetRpcErrorCode.RiskAccountLocked);
Log.outDebug(LogFilter.Network, "WorldSocket.HandleAuthSession: Sent Auth Response (Account country differs. Original country: {0}, new country: {1}).", account.battleNet.LockCountry, _ipCountry); Log.outDebug(LogFilter.Network, "WorldSocket.HandleAuthSession: Sent Auth Response (Account country differs. Original country: {0}, new country: {1}).", account.battleNet.LockCountry, _ipCountry);
// We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well
Global.ScriptMgr.OnFailedAccountLogin(account.game.Id);
CloseSocket(); CloseSocket();
return; return;
} }
@@ -617,6 +621,7 @@ namespace Game.Networking
{ {
SendAuthResponseError(BattlenetRpcErrorCode.GameAccountBanned); SendAuthResponseError(BattlenetRpcErrorCode.GameAccountBanned);
Log.outError(LogFilter.Network, "WorldSocket:HandleAuthSession: Sent Auth Response (Account banned)."); Log.outError(LogFilter.Network, "WorldSocket:HandleAuthSession: Sent Auth Response (Account banned).");
Global.ScriptMgr.OnFailedAccountLogin(account.game.Id);
CloseSocket(); CloseSocket();
return; return;
} }
@@ -627,6 +632,7 @@ namespace Game.Networking
{ {
SendAuthResponseError(BattlenetRpcErrorCode.ServerIsPrivate); SendAuthResponseError(BattlenetRpcErrorCode.ServerIsPrivate);
Log.outInfo(LogFilter.Network, "WorldSocket:HandleAuthSession: User tries to login but his security level is not enough"); Log.outInfo(LogFilter.Network, "WorldSocket:HandleAuthSession: User tries to login but his security level is not enough");
Global.ScriptMgr.OnFailedAccountLogin(account.game.Id);
CloseSocket(); CloseSocket();
return; return;
} }
@@ -642,6 +648,9 @@ namespace Game.Networking
DB.Login.Execute(stmt); DB.Login.Execute(stmt);
} }
// At this point, we can safely hook a successful login
Global.ScriptMgr.OnAccountLogin(account.game.Id);
_worldSession = new WorldSession(account.game.Id, authSession.RealmJoinTicket, account.battleNet.Id, this, account.game.Security, (Expansion)account.game.Expansion, _worldSession = new WorldSession(account.game.Id, authSession.RealmJoinTicket, account.battleNet.Id, this, account.game.Security, (Expansion)account.game.Expansion,
mutetime, account.game.OS, account.battleNet.Locale, account.game.Recruiter, account.game.IsRectuiter); mutetime, account.game.OS, account.battleNet.Locale, account.game.Recruiter, account.game.IsRectuiter);
+27 -1
View File
@@ -653,7 +653,7 @@ namespace Game.Scripting
public virtual void OnSpellCast(Player player, Spell spell, bool skipCheck) { } public virtual void OnSpellCast(Player player, Spell spell, bool skipCheck) { }
// Called when a player logs in. // Called when a player logs in.
public virtual void OnLogin(Player player) { } public virtual void OnLogin(Player player, bool firstLogin) { }
// Called when a player logs out. // Called when a player logs out.
public virtual void OnLogout(Player player) { } public virtual void OnLogout(Player player) { }
@@ -692,6 +692,32 @@ namespace Game.Scripting
public virtual void OnPlayerChoiceResponse(Player player, uint choiceId, uint responseId) { } public virtual void OnPlayerChoiceResponse(Player player, uint choiceId, uint responseId) { }
} }
public class AccountScript : ScriptObject
{
public AccountScript(string name) : base(name)
{
Global.ScriptMgr.AddScript(this);
}
// Called when an account logged in succesfully
public virtual void OnAccountLogin(uint accountId) { }
// Called when an account login failed
public virtual void OnFailedAccountLogin(uint accountId) { }
// Called when Email is successfully changed for Account
public virtual void OnEmailChange(uint accountId) { }
// Called when Email failed to change for Account
public virtual void OnFailedEmailChange(uint accountId) { }
// Called when Password is successfully changed for Account
public virtual void OnPasswordChange(uint accountId) { }
// Called when Password failed to change for Account
public virtual void OnFailedPasswordChange(uint accountId) { }
}
public class GuildScript : ScriptObject public class GuildScript : ScriptObject
{ {
public GuildScript(string name) : base(name) public GuildScript(string name) : base(name)
+29 -2
View File
@@ -147,6 +147,7 @@ namespace Game.Scripting
case "TransportScript": case "TransportScript":
case "AchievementCriteriaScript": case "AchievementCriteriaScript":
case "PlayerScript": case "PlayerScript":
case "AccountScript":
case "GuildScript": case "GuildScript":
case "GroupScript": case "GroupScript":
case "AreaTriggerEntityScript": case "AreaTriggerEntityScript":
@@ -855,9 +856,9 @@ namespace Game.Scripting
{ {
ForEach<PlayerScript>(p => p.OnSpellCast(player, spell, skipCheck)); ForEach<PlayerScript>(p => p.OnSpellCast(player, spell, skipCheck));
} }
public void OnPlayerLogin(Player player) public void OnPlayerLogin(Player player, bool firstLogin)
{ {
ForEach<PlayerScript>(p => p.OnLogin(player)); ForEach<PlayerScript>(p => p.OnLogin(player, firstLogin));
} }
public void OnPlayerLogout(Player player) public void OnPlayerLogout(Player player)
{ {
@@ -904,6 +905,32 @@ namespace Game.Scripting
ForEach<PlayerScript>(p => p.OnPlayerChoiceResponse(player, choiceId, responseId)); ForEach<PlayerScript>(p => p.OnPlayerChoiceResponse(player, choiceId, responseId));
} }
// Account
public void OnAccountLogin(uint accountId)
{
ForEach<AccountScript>(script => script.OnAccountLogin(accountId));
}
public void OnFailedAccountLogin(uint accountId)
{
ForEach<AccountScript>(script => script.OnFailedAccountLogin(accountId));
}
public void OnEmailChange(uint accountId)
{
ForEach<AccountScript>(script => script.OnEmailChange(accountId));
}
public void OnFailedEmailChange(uint accountId)
{
ForEach<AccountScript>(script => script.OnFailedEmailChange(accountId));
}
public void OnPasswordChange(uint accountId)
{
ForEach<AccountScript>(script => script.OnPasswordChange(accountId));
}
public void OnFailedPasswordChange(uint accountId)
{
ForEach<AccountScript>(script => script.OnFailedPasswordChange(accountId));
}
// GuildScript // GuildScript
public void OnGuildAddMember(Guild guild, Player player, byte plRank) public void OnGuildAddMember(Guild guild, Player player, byte plRank)
{ {
+79 -85
View File
@@ -1,4 +1,4 @@
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved. // Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants; using Framework.Constants;
@@ -10,102 +10,96 @@ using Game.Spells;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Scripts.Pets namespace Scripts.Pets.DeathKnight
{ {
namespace DeathKnight [Script]
class npc_pet_dk_ebon_gargoyle : CasterAI
{ {
struct SpellIds const uint SpellSummonGargoyle1 = 49206;
{ const uint SpellSummonGargoyle2 = 50514;
public const uint SummonGargoyle1 = 49206; const uint SpellDismissGargoyle = 50515;
public const uint SummonGargoyle2 = 50514; const uint SpellSanctuary = 54661;
public const uint DismissGargoyle = 50515;
public const uint Sanctuary = 54661;
}
[Script] public npc_pet_dk_ebon_gargoyle(Creature creature) : base(creature) { }
class npc_pet_dk_ebon_gargoyle : CasterAI
{
public npc_pet_dk_ebon_gargoyle(Creature creature) : base(creature) { }
public override void InitializeAI() public override void InitializeAI()
{
base.InitializeAI();
ObjectGuid ownerGuid = me.GetOwnerGUID();
if (ownerGuid.IsEmpty())
return;
// Find victim of Summon Gargoyle spell
List<Unit> targets = new();
AnyUnfriendlyUnitInObjectRangeCheck u_check = new(me, me, 30.0f);
UnitListSearcher searcher = new(me, targets, u_check);
Cell.VisitAllObjects(me, searcher, 30.0f);
foreach (Unit target in targets)
{ {
base.InitializeAI(); if (target.HasAura(SpellSummonGargoyle1, ownerGuid))
ObjectGuid ownerGuid = me.GetOwnerGUID();
if (ownerGuid.IsEmpty())
return;
// Find victim of Summon Gargoyle spell
List<Unit> targets = new();
var u_check = new AnyUnfriendlyUnitInObjectRangeCheck(me, me, 30.0f);
var searcher = new UnitListSearcher(me, targets, u_check);
Cell.VisitAllObjects(me, searcher, 30.0f);
foreach (var target in targets)
{ {
if (target.HasAura(SpellIds.SummonGargoyle1, ownerGuid)) me.Attack(target, false);
{ break;
me.Attack(target, false);
break;
}
} }
} }
public override void JustDied(Unit killer)
{
// Stop Feeding Gargoyle when it dies
Unit owner = me.GetOwner();
if (owner)
owner.RemoveAurasDueToSpell(SpellIds.SummonGargoyle2);
}
// Fly away when dismissed
public override void SpellHit(WorldObject caster, SpellInfo spellInfo)
{
if (spellInfo.Id != SpellIds.DismissGargoyle || !me.IsAlive())
return;
Unit owner = me.GetOwner();
if (!owner || owner != caster)
return;
// Stop Fighting
me.SetUnitFlag(UnitFlags.NonAttackable);
// Sanctuary
me.CastSpell(me, SpellIds.Sanctuary, true);
me.SetReactState(ReactStates.Passive);
//! HACK: Creature's can't have MOVEMENTFLAG_FLYING
// Fly Away
me.SetCanFly(true);
me.SetSpeedRate(UnitMoveType.Flight, 0.75f);
me.SetSpeedRate(UnitMoveType.Run, 0.75f);
float x = me.GetPositionX() + 20 * (float)Math.Cos(me.GetOrientation());
float y = me.GetPositionY() + 20 * (float)Math.Sin(me.GetOrientation());
float z = me.GetPositionZ() + 40;
me.GetMotionMaster().Clear();
me.GetMotionMaster().MovePoint(0, x, y, z);
// Despawn as soon as possible
me.DespawnOrUnsummon(TimeSpan.FromSeconds(4));
}
} }
[Script] public override void JustDied(Unit killer)
class npc_pet_dk_guardian : AggressorAI
{ {
public npc_pet_dk_guardian(Creature creature) : base(creature) { } // Stop Feeding Gargoyle when it dies
Unit owner = me.GetOwner();
if (owner != null)
owner.RemoveAurasDueToSpell(SpellSummonGargoyle2);
}
public override bool CanAIAttack(Unit target) // Fly away when dismissed
{ public override void SpellHit(WorldObject caster, SpellInfo spellInfo)
if (!target) {
return false; if (spellInfo.Id != SpellDismissGargoyle || !me.IsAlive())
Unit owner = me.GetOwner(); return;
if (owner && !target.IsInCombatWith(owner))
return false; Unit owner = me.GetOwner();
return base.CanAIAttack(target); if (owner == null || owner != caster)
} return;
// Stop Fighting
me.SetUnitFlag(UnitFlags.NonAttackable);
// Sanctuary
me.CastSpell(me, SpellSanctuary, true);
me.SetReactState(ReactStates.Passive);
//! Hack: Creature's can't have MovementflagFlying
// Fly Away
me.SetCanFly(true);
me.SetSpeedRate(UnitMoveType.Flight, 0.75f);
me.SetSpeedRate(UnitMoveType.Run, 0.75f);
float x = me.GetPositionX() + 20 * MathF.Cos(me.GetOrientation());
float y = me.GetPositionY() + 20 * MathF.Sin(me.GetOrientation());
float z = me.GetPositionZ() + 40;
me.GetMotionMaster().Clear();
me.GetMotionMaster().MovePoint(0, x, y, z);
// Despawn as soon as possible
me.DespawnOrUnsummon(TimeSpan.FromSeconds(4));
}
}
[Script]
class npc_pet_dk_guardian : AggressorAI
{
public npc_pet_dk_guardian(Creature creature) : base(creature) { }
public override bool CanAIAttack(Unit target)
{
if (target == null)
return false;
Unit owner = me.GetOwner();
if (owner != null && !target.IsInCombatWith(owner))
return false;
return base.CanAIAttack(target);
} }
} }
} }
+206 -154
View File
@@ -1,200 +1,252 @@
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved. // Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants; using Framework.Constants;
using Framework.Dynamic;
using Game.AI; using Game.AI;
using Game.Entities; using Game.Entities;
using Game.Scripting; using Game.Scripting;
using Game.Spells; using Game.Spells;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Scripts.Pets namespace Scripts.Pets.Generic
{ {
namespace Generic [Script]
class npc_pet_gen_pandaren_monk : NullCreatureAI
{ {
struct SpellIds const uint SpellPandarenMonk = 69800;
Action<TaskContext> focusAction;
public npc_pet_gen_pandaren_monk(Creature creature) : base(creature)
{ {
//Mojo focusAction = task =>
public const uint FeelingFroggy = 43906;
public const uint SeductionVisual = 43919;
//SoulTrader
public const uint EtherealOnSummon = 50052;
public const uint EtherealPetRemoveAura = 50055;
// LichPet
public const uint LichPetAura = 69732;
public const uint LichPetAuraOnkill = 69731;
public const uint LichPetEmote = 70049;
}
struct CreatureIds
{
// LichPet
public const uint LichPet = 36979;
}
struct TextIds
{
//Mojo
public const uint SayMojo = 0;
//SoulTrader
public const uint SaySoulTraderInto = 0;
}
[Script]
class npc_pet_gen_soul_trader : ScriptedAI
{
public npc_pet_gen_soul_trader(Creature creature) : base(creature) { }
public override void OnDespawn()
{ {
Unit owner = me.GetOwner(); Unit owner = me.GetCharmerOrOwner();
if (owner != null) if (owner != null)
DoCast(owner, SpellIds.EtherealPetRemoveAura); me.SetFacingToObject(owner);
}
public override void JustAppeared() _scheduler.Schedule(TimeSpan.FromSeconds(1), _ =>
{
me.HandleEmoteCommand(Emote.OneshotBow);
_scheduler.Schedule(TimeSpan.FromSeconds(1), _ =>
{
Unit owner = me.GetCharmerOrOwner();
if (owner != null)
me.GetMotionMaster().MoveFollow(owner, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
});
});
};
}
public override void Reset()
{
_scheduler.CancelAll();
_scheduler.Schedule(TimeSpan.FromSeconds(1), focusAction);
}
public override void EnterEvadeMode(EvadeReason why)
{
if (!_EnterEvadeMode(why))
return;
Reset();
}
public override void ReceiveEmote(Player player, TextEmotes emote)
{
me.InterruptSpell(CurrentSpellTypes.Channeled);
me.StopMoving();
switch (emote)
{ {
Talk(TextIds.SaySoulTraderInto); case TextEmotes.Bow:
_scheduler.Schedule(TimeSpan.FromSeconds(1), focusAction);
Unit owner = me.GetOwner(); break;
if (owner != null) case TextEmotes.Drink:
DoCast(owner, SpellIds.EtherealOnSummon); _scheduler.Schedule(TimeSpan.FromSeconds(1), _ => me.CastSpell(me, SpellPandarenMonk, false));
break;
base.JustAppeared();
} }
} }
[Script] // 69735 - Lich Pet OnSummon public override void UpdateAI(uint diff)
class spell_gen_lich_pet_onsummon : SpellScript
{ {
public override bool Validate(SpellInfo spellInfo) _scheduler.Update(diff);
{
return ValidateSpellInfo(SpellIds.LichPetAura);
}
void HandleScriptEffect(uint effIndex) Unit owner = me.GetCharmerOrOwner();
{ if (owner != null)
Unit target = GetHitUnit(); if (!me.IsWithinDist(owner, 30.0f))
target.CastSpell(target, SpellIds.LichPetAura, true); me.InterruptSpell(CurrentSpellTypes.Channeled);
} }
}
public override void Register() [Script]
{ class npc_pet_gen_soul_trader : ScriptedAI
OnEffectHitTarget.Add(new EffectHandler(HandleScriptEffect, 0, SpellEffectName.ScriptEffect)); {
} const uint SaySoulTraderIntro = 0;
const uint SpellEtherealOnsummon = 50052;
const uint SpellEtherealPetRemoveAura = 50055;
public npc_pet_gen_soul_trader(Creature creature) : base(creature) { }
public override void OnDespawn()
{
Unit owner = me.GetOwner();
if (owner != null)
DoCast(owner, SpellEtherealPetRemoveAura);
} }
[Script] // 69736 - Lich Pet Aura Remove public override void JustAppeared()
class spell_gen_lich_pet_aura_remove : SpellScript
{ {
public override bool Validate(SpellInfo spellInfo) Talk(SaySoulTraderIntro);
{ Unit owner = me.GetOwner();
return ValidateSpellInfo(SpellIds.LichPetAura); if (owner != null)
} DoCast(owner, SpellEtherealOnsummon);
void HandleScriptEffect(uint effIndex) base.JustAppeared();
{ }
GetHitUnit().RemoveAurasDueToSpell(SpellIds.LichPetAura); }
}
public override void Register() [Script] // 69735 - Lich Pet OnSummon
{ class spell_pet_gen_lich_pet_onsummon : SpellScript
OnEffectHitTarget.Add(new EffectHandler(HandleScriptEffect, 0, SpellEffectName.ScriptEffect)); {
} const uint SpellLichPetAura = 69732;
public override bool Validate(SpellInfo spellInfo)
{
return ValidateSpellInfo(SpellLichPetAura);
} }
[Script] // 69732 - Lich Pet Aura void HandleScript(uint effIndex)
class spell_gen_lich_pet_aura : AuraScript
{ {
public override bool Validate(SpellInfo spellInfo) Unit target = GetHitUnit();
{ target.CastSpell(target, SpellLichPetAura, true);
return ValidateSpellInfo(SpellIds.LichPetAuraOnkill);
}
bool CheckProc(ProcEventInfo eventInfo)
{
return eventInfo.GetProcTarget().IsPlayer();
}
void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo)
{
PreventDefaultAction();
List<TempSummon> minionList = new();
GetUnitOwner().GetAllMinionsByEntry(minionList, CreatureIds.LichPet);
foreach (Creature minion in minionList)
if (minion.IsAIEnabled())
minion.GetAI().DoCastSelf(SpellIds.LichPetAuraOnkill);
}
public override void Register()
{
DoCheckProc.Add(new CheckProcHandler(CheckProc));
OnEffectProc.Add(new EffectProcHandler(HandleProc, 0, AuraType.ProcTriggerSpell));
}
} }
[Script] // 70050 - [DND] Lich Pet public override void Register()
class spell_pet_gen_lich_pet_periodic_emote : AuraScript
{ {
public override bool Validate(SpellInfo spellInfo) OnEffectHitTarget.Add(new(HandleScript, 0, SpellEffectName.ScriptEffect));
{ }
return ValidateSpellInfo(SpellIds.LichPetEmote); }
}
void OnPeriodic(AuraEffect aurEff) [Script] // 69736 - Lich Pet Aura Remove
{ class spell_pet_gen_lich_pet_aura_Remove : SpellScript
// The chance to cast this spell is not 100%. {
// Triggered spell roots creature for 3 sec and plays anim and sound (doesn't require any script). const uint SpellLichPetAura = 69732;
// Emote and sound never shows up in sniffs because both comes from spell visual directly.
// Both 69683 and 70050 can trigger spells at once and are not linked together in any way.
// Effect of 70050 is overlapped by effect of 69683 but not instantly (69683 is a series of spell casts, takes longer to execute).
// However, for some reason emote is not played if creature is idle and only if creature is moving or is already rooted.
// For now it's scripted manually in script below to play emote always.
if (RandomHelper.randChance(50))
GetTarget().CastSpell(GetTarget(), SpellIds.LichPetEmote, true);
}
public override void Register() public override bool Validate(SpellInfo spellInfo)
{ {
OnEffectPeriodic.Add(new EffectPeriodicHandler(OnPeriodic, 0, AuraType.PeriodicTriggerSpell)); return ValidateSpellInfo(SpellLichPetAura);
}
} }
[Script] // 70049 - [DND] Lich Pet void HandleScript(uint effIndex)
class spell_pet_gen_lich_pet_emote : AuraScript
{ {
void AfterApply(AuraEffect aurEff, AuraEffectHandleModes mode) GetHitUnit().RemoveAurasDueToSpell(SpellLichPetAura);
{
GetTarget().HandleEmoteCommand(Emote.OneshotCustomSpell01);
}
public override void Register()
{
AfterEffectApply.Add(new EffectApplyHandler(AfterApply, 0, AuraType.ModRoot, AuraEffectHandleModes.Real));
}
} }
[Script] // 69682 - Lil' K.T. Focus public override void Register()
class spell_pet_gen_lich_pet_focus : SpellScript
{ {
public override bool Validate(SpellInfo spellInfo) OnEffectHitTarget.Add(new(HandleScript, 0, SpellEffectName.ScriptEffect));
{ }
return ValidateSpellInfo((uint)spellInfo.GetEffect(0).CalcValue()); }
}
void HandleScript(uint effIndex) [Script] // 69732 - Lich Pet Aura
{ class spell_pet_gen_lich_pet_AuraScript : AuraScript
GetCaster().CastSpell(GetHitUnit(), (uint)GetEffectValue()); {
} const uint SpellLichPetAuraOnkill = 69731;
public override void Register() const uint NpcLichPet = 36979;
{
OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect)); public override bool Validate(SpellInfo spellInfo)
} {
return ValidateSpellInfo(SpellLichPetAuraOnkill);
}
bool CheckProc(ProcEventInfo eventInfo)
{
return eventInfo.GetProcTarget().IsPlayer();
}
void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo)
{
PreventDefaultAction();
Unit owner = GetUnitOwner();
List<TempSummon> minionList = new();
owner.GetAllMinionsByEntry(minionList, NpcLichPet);
foreach (TempSummon minion in minionList)
owner.CastSpell(minion, SpellLichPetAuraOnkill, true);
}
public override void Register()
{
DoCheckProc.Add(new(CheckProc));
OnEffectProc.Add(new(HandleProc, 0, AuraType.ProcTriggerSpell));
}
}
[Script] // 70050 - [Dnd] Lich Pet
class spell_pet_gen_lich_pet_periodic_emote : AuraScript
{
const uint SpellLichPetEmote = 70049;
public override bool Validate(SpellInfo spellInfo)
{
return ValidateSpellInfo(SpellLichPetEmote);
}
void OnPeriodic(AuraEffect aurEff)
{
// The chance to cast this spell is not 100%.
// Triggered spell roots creature for 3 sec and plays anim and sound (doesn't require any script).
// Emote and sound never shows up in sniffs because both comes from spell visual directly.
// Both 69683 and 70050 can trigger spells at once and are not linked together in any way.
// Effect of 70050 is overlapped by effect of 69683 but not instantly (69683 is a series of spell casts, takes longer to execute).
// However, for some reason emote is not played if creature is idle and only if creature is moving or is already rooted.
// For now it's scripted manually in script below to play emote always.
if (RandomHelper.randChance(50))
GetTarget().CastSpell(GetTarget(), SpellLichPetEmote, true);
}
public override void Register()
{
OnEffectPeriodic.Add(new(OnPeriodic, 0, AuraType.PeriodicTriggerSpell));
}
}
[Script] // 70049 - [Dnd] Lich Pet
class spell_pet_gen_lich_pet_emote : AuraScript
{
void AfterApply(AuraEffect aurEff, AuraEffectHandleModes mode)
{
GetTarget().HandleEmoteCommand(Emote.OneshotCustomSpell01);
}
public override void Register()
{
AfterEffectApply.Add(new(AfterApply, 0, AuraType.ModRoot, AuraEffectHandleModes.Real));
}
}
[Script] // 69682 - Lil' K.T. Focus
class spell_pet_gen_lich_pet_focus : SpellScript
{
public override bool Validate(SpellInfo spellInfo)
{
return ValidateSpellInfo((uint)spellInfo.GetEffect(0).CalcValue());
}
void HandleScript(uint effIndex)
{
GetCaster().CastSpell(GetHitUnit(), (uint)GetEffectValue());
}
public override void Register()
{
OnEffectHitTarget.Add(new(HandleScript, 0, SpellEffectName.ScriptEffect));
} }
} }
} }
+73 -82
View File
@@ -1,4 +1,4 @@
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved. // Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants; using Framework.Constants;
@@ -6,108 +6,99 @@ using Game.AI;
using Game.Combat; using Game.Combat;
using Game.Entities; using Game.Entities;
using Game.Scripting; using Game.Scripting;
using Game.Spells;
using System.Collections.Generic; using System.Collections.Generic;
namespace Scripts.Pets namespace Scripts.Pets.Hunter
{ {
namespace Hunter [Script]
class npc_pet_hunter_snake_trap : ScriptedAI
{ {
struct SpellIds const uint SpellHunterCripplingPoison = 30981; // Viper
const uint SpellHunterDeadlyPoisonPassive = 34657; // Venomous Snake
const uint SpellHunterMindNumbingPoison = 25810; // Viper
const uint NpcHunterViper = 19921;
bool _isViper;
uint _spellTimer;
public npc_pet_hunter_snake_trap(Creature creature) : base(creature) { }
public override void JustEngagedWith(Unit who) { }
public override void JustAppeared()
{ {
public const uint CripplingPoison = 30981; // Viper _isViper = me.GetEntry() == NpcHunterViper ? true : false;
public const uint DeadlyPoisonPassive = 34657; // Venomous Snake
public const uint MindNumbingPoison = 25810; // Viper me.SetMaxHealth((uint)(107 * (me.GetLevel() - 40) * 0.025f));
// Add delta to make them not all hit the same time
me.SetBaseAttackTime(WeaponAttackType.BaseAttack, me.GetBaseAttackTime(WeaponAttackType.BaseAttack) + RandomHelper.URand(0, 6));
if (!_isViper && !me.HasAura(SpellHunterDeadlyPoisonPassive))
DoCast(me, SpellHunterDeadlyPoisonPassive, true);
} }
struct CreatureIds // Redefined for random target selection:
public override void MoveInLineOfSight(Unit who) { }
public override void UpdateAI(uint diff)
{ {
public const int Viper = 19921; if (me.GetVictim() != null && me.GetVictim().HasBreakableByDamageCrowdControlAura())
} { // don't break cc
me.GetThreatManager().ClearFixate();
[Script] me.InterruptNonMeleeSpells(false);
class npc_pet_hunter_snake_trap : ScriptedAI me.AttackStop();
{ return;
public npc_pet_hunter_snake_trap(Creature creature) : base(creature) { }
public override void JustEngagedWith(Unit who) { }
public override void JustAppeared()
{
_isViper = me.GetEntry() == CreatureIds.Viper ? true : false;
me.SetMaxHealth((uint)(107 * (me.GetLevel() - 40) * 0.025f));
// Add delta to make them not all hit the same time
me.SetBaseAttackTime(WeaponAttackType.BaseAttack, me.GetBaseAttackTime(WeaponAttackType.BaseAttack) + RandomHelper.URand(0, 6) * Time.InMilliseconds);
if (!_isViper && !me.HasAura(SpellIds.DeadlyPoisonPassive))
DoCast(me, SpellIds.DeadlyPoisonPassive, new CastSpellExtraArgs(true));
} }
// Redefined for random target selection: if (me.IsSummon() && me.GetThreatManager().GetFixateTarget() == null)
public override void MoveInLineOfSight(Unit who) { } { // find new target
Unit summoner = me.ToTempSummon().GetSummonerUnit();
public override void UpdateAI(uint diff) List<Unit> targets = new();
{
if (me.GetVictim() && me.GetVictim().HasBreakableByDamageCrowdControlAura()) void addTargetIfValid(CombatReference refe)
{ // don't break cc {
me.GetThreatManager().ClearFixate(); Unit enemy = refe.GetOther(summoner);
me.InterruptNonMeleeSpells(false); if (!enemy.HasBreakableByDamageCrowdControlAura() && me.CanCreatureAttack(enemy) && me.IsWithinDistInMap(enemy, me.GetAttackDistance(enemy)))
me.AttackStop(); targets.Add(enemy);
return;
} }
if (me.IsSummon() && !me.GetThreatManager().GetFixateTarget()) foreach (var pair in summoner.GetCombatManager().GetPvPCombatRefs())
{ // find new target addTargetIfValid(pair.Value);
Unit summoner = me.ToTempSummon().GetSummonerUnit();
List<Unit> targets = new();
void addTargetIfValid(CombatReference refe) if (targets.Empty())
{ foreach (var pair in summoner.GetCombatManager().GetPvECombatRefs())
Unit enemy = refe.GetOther(summoner);
if (!enemy.HasBreakableByDamageCrowdControlAura() && me.CanCreatureAttack(enemy) && me.IsWithinDistInMap(enemy, me.GetAttackDistance(enemy)))
targets.Add(enemy);
}
foreach (var pair in summoner.GetCombatManager().GetPvPCombatRefs())
addTargetIfValid(pair.Value); addTargetIfValid(pair.Value);
if (targets.Empty()) foreach (Unit target in targets)
foreach (var pair in summoner.GetCombatManager().GetPvECombatRefs()) me.EngageWithTarget(target);
addTargetIfValid(pair.Value);
foreach (Unit target in targets) if (!targets.Empty())
me.EngageWithTarget(target);
if (!targets.Empty())
{
Unit target = targets.SelectRandom();
me.GetThreatManager().FixateTarget(target);
}
}
if (!UpdateVictim())
return;
// Viper
if (_isViper)
{ {
if (_spellTimer <= diff) Unit target = targets.SelectRandom();
{ me.GetThreatManager().FixateTarget(target);
if (RandomHelper.URand(0, 2) == 0) // 33% chance to cast
DoCastVictim(RandomHelper.RAND(SpellIds.MindNumbingPoison, SpellIds.CripplingPoison));
_spellTimer = 3000;
}
else
_spellTimer -= diff;
} }
DoMeleeAttackIfReady();
} }
bool _isViper; if (!UpdateVictim())
uint _spellTimer; return;
// Viper
if (_isViper)
{
if (_spellTimer <= diff)
{
if (RandomHelper.URand(0, 2) == 0) // 33% chance to cast
DoCastVictim(RandomHelper.RAND(SpellHunterMindNumbingPoison, SpellHunterCripplingPoison));
_spellTimer = 3000;
}
else
_spellTimer -= diff;
}
DoMeleeAttackIfReady();
} }
} }
} }
+131 -145
View File
@@ -1,4 +1,4 @@
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved. // Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants; using Framework.Constants;
@@ -6,175 +6,161 @@ using Game.AI;
using Game.Entities; using Game.Entities;
using Game.Scripting; using Game.Scripting;
namespace Scripts.Pets namespace Scripts.Pets.Mage
{ {
namespace Mage [Script]
class npc_pet_mage_mirror_image : ScriptedAI
{ {
struct SpellIds const uint SpellMageCloneMe = 45204;
const uint SpellMageFrostBolt = 59638;
const uint SpellMageFireBlast = 59637;
const uint TimerMirrorImageFireBlast = 6500;
float ChaseDistance = 35.0f;
uint _fireBlastTimer = 0;
public npc_pet_mage_mirror_image(Creature creature) : base(creature) { }
public override void InitializeAI()
{ {
public const uint CloneMe = 45204; Unit owner = me.GetOwner();
public const uint MastersThreatList = 58838; if (owner == null)
public const uint MageFrostBolt = 59638; return;
public const uint MageFireBlast = 59637;
// here mirror image casts on summoner spell (not present in client dbc) 49866
// here should be auras (not present in client dbc): 35657, 35658, 35659, 35660 selfcast by mirror images (stats related?)
// Clone Me!
owner.CastSpell(me, SpellMageCloneMe, true);
} }
struct MiscConst // custom UpdateVictim implementation to handle special target selection
// we prioritize between things that are in combat with owner based on the owner's threat to them
bool UpdateVictimCustom()
{ {
public const uint TimerMirrorImageInit = 0; Unit owner = me.GetOwner();
public const uint TimerMirrorImageFrostBolt = 4000; if (owner == null)
public const uint TimerMirrorImageFireBlast = 6000; return false;
}
[Script] if (!me.HasUnitState(UnitState.Casting) && !me.IsInCombat() && !owner.IsInCombat())
class npc_pet_mage_mirror_image : ScriptedAI return false;
{
const float CHASE_DISTANCE = 35.0f;
uint _fireBlastTimer = 0; Unit currentTarget = me.GetVictim();
if (currentTarget != null && !CanAIAttack(currentTarget))
public npc_pet_mage_mirror_image(Creature creature) : base(creature) { }
public override void InitializeAI()
{ {
Unit owner = me.GetOwner(); me.InterruptNonMeleeSpells(true); // do not finish casting on invalid targets
if (owner == null) me.AttackStop();
return; currentTarget = null;
// here mirror image casts on summoner spell (not present in client dbc) 49866
// here should be auras (not present in client dbc): 35657, 35658, 35659, 35660 selfcast by mirror images (stats related?)
// Clone Me!
owner.CastSpell(me, SpellIds.CloneMe, true);
} }
// custom UpdateVictim implementation to handle special target selection // don't reselect if we're currently casting anyway
// we prioritize between things that are in combat with owner based on the owner's threat to them if (currentTarget != null && me.HasUnitState(UnitState.Casting))
new bool UpdateVictim()
{
Unit owner = me.GetOwner();
if (owner == null)
return false;
if (!me.HasUnitState(UnitState.Casting) && !me.IsInCombat() && !owner.IsInCombat())
return false;
Unit currentTarget = me.GetVictim();
if (currentTarget && !CanAIAttack(currentTarget))
{
me.InterruptNonMeleeSpells(true); // do not finish casting on invalid targets
me.AttackStop();
currentTarget = null;
}
// don't reselect if we're currently casting anyway
if (currentTarget && me.HasUnitState(UnitState.Casting))
return true;
Unit selectedTarget = null;
var mgr = owner.GetCombatManager();
if (mgr.HasPvPCombat())
{ // select pvp target
float minDistance = 0.0f;
foreach (var pair in mgr.GetPvPCombatRefs())
{
Unit target = pair.Value.GetOther(owner);
if (!target.IsPlayer())
continue;
if (!CanAIAttack(target))
continue;
float dist = owner.GetDistance(target);
if (!selectedTarget || dist < minDistance)
{
selectedTarget = target;
minDistance = dist;
}
}
}
if (!selectedTarget)
{ // select pve target
float maxThreat = 0.0f;
foreach (var pair in mgr.GetPvECombatRefs())
{
Unit target = pair.Value.GetOther(owner);
if (!CanAIAttack(target))
continue;
float threat = target.GetThreatManager().GetThreat(owner);
if (threat >= maxThreat)
{
selectedTarget = target;
maxThreat = threat;
}
}
}
if (!selectedTarget)
{
EnterEvadeMode(EvadeReason.NoHostiles);
return false;
}
if (selectedTarget != me.GetVictim())
AttackStartCaster(selectedTarget, CHASE_DISTANCE);
return true; return true;
Unit selectedTarget = null;
var mgr = owner.GetCombatManager();
if (mgr.HasPvPCombat())
{ // select pvp target
float minDistance = 0.0f;
foreach (var pair in mgr.GetPvPCombatRefs())
{
Unit target = pair.Value.GetOther(owner);
if (!target.IsPlayer())
continue;
if (!CanAIAttack(target))
continue;
float dist = owner.GetDistance(target);
if (selectedTarget == null || dist < minDistance)
{
selectedTarget = target;
minDistance = dist;
}
}
} }
public override void UpdateAI(uint diff) if (selectedTarget == null)
{ // select pve target
float maxThreat = 0.0f;
foreach (var pair in mgr.GetPvECombatRefs())
{
Unit target = pair.Value.GetOther(owner);
if (!CanAIAttack(target))
continue;
float threat = target.GetThreatManager().GetThreat(owner);
if (threat >= maxThreat)
{
selectedTarget = target;
maxThreat = threat;
}
}
}
if (selectedTarget == null)
{ {
Unit owner = me.GetOwner(); EnterEvadeMode(EvadeReason.NoHostiles);
if (owner == null) return false;
{ }
me.DespawnOrUnsummon();
return;
}
if (_fireBlastTimer != 0) if (selectedTarget != me.GetVictim())
{ AttackStartCaster(selectedTarget, ChaseDistance);
if (_fireBlastTimer <= diff) return true;
_fireBlastTimer = 0; }
else
_fireBlastTimer -= diff;
}
if (!UpdateVictim()) public override void UpdateAI(uint diff)
return; {
Unit owner = me.GetOwner();
if (owner == null)
{
me.DespawnOrUnsummon();
return;
}
if (me.HasUnitState(UnitState.Casting)) if (_fireBlastTimer != 0)
return; {
if (_fireBlastTimer <= diff)
if (_fireBlastTimer == 0) _fireBlastTimer = 0;
{
DoCastVictim(SpellIds.MageFireBlast);
_fireBlastTimer = MiscConst.TimerMirrorImageFireBlast;
}
else else
DoCastVictim(SpellIds.MageFrostBolt); _fireBlastTimer -= diff;
} }
public override bool CanAIAttack(Unit who) if (!UpdateVictimCustom())
return;
if (me.HasUnitState(UnitState.Casting))
return;
if (_fireBlastTimer == 0)
{ {
Unit owner = me.GetOwner(); DoCastVictim(SpellMageFireBlast);
return owner && who.IsAlive() && me.IsValidAttackTarget(who) && _fireBlastTimer = TimerMirrorImageFireBlast;
!who.HasBreakableByDamageCrowdControlAura() &&
who.IsInCombatWith(owner) && CanAIAttack(who);
} }
else
DoCastVictim(SpellMageFrostBolt);
}
// Do not reload Creature templates on evade mode enter - prevent visual lost public override bool CanAIAttack(Unit who)
public override void EnterEvadeMode(EvadeReason why) {
Unit owner = me.GetOwner();
return owner != null && who.IsAlive() && me.IsValidAttackTarget(who) &&
!who.HasBreakableByDamageCrowdControlAura() &&
who.IsInCombatWith(owner) && base.CanAIAttack(who);
}
// Do not reload Creature templates on evade mode enter - prevent visual lost
public override void EnterEvadeMode(EvadeReason why)
{
if (me.IsInEvadeMode() || !me.IsAlive())
return;
Unit owner = me.GetCharmerOrOwner();
me.CombatStop(true);
if (owner != null && !me.HasUnitState(UnitState.Follow))
{ {
if (me.IsInEvadeMode() || !me.IsAlive()) me.GetMotionMaster().Clear();
return; me.GetMotionMaster().MoveFollow(owner, SharedConst.PetFollowDist, me.GetFollowAngle());
Unit owner = me.GetCharmerOrOwner();
me.CombatStop(true);
if (owner && !me.HasUnitState(UnitState.Follow))
{
me.GetMotionMaster().Clear();
me.GetMotionMaster().MoveFollow(owner, SharedConst.PetFollowDist, me.GetFollowAngle());
}
} }
} }
} }
+52 -32
View File
@@ -1,4 +1,4 @@
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved. // Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants; using Framework.Constants;
@@ -6,50 +6,70 @@ using Game.AI;
using Game.Entities; using Game.Entities;
using Game.Scripting; using Game.Scripting;
namespace Scripts.Pets namespace Scripts.Pets.Priest
{ {
namespace Priest [Script] // 198236 - Divine Image
class npc_pet_pri_divine_image : PassiveAI
{ {
struct SpellIds const uint SpellPriestDivineImageSpellCheck = 405216;
const uint SpellPriestInvokeTheNaaru = 196687;
public npc_pet_pri_divine_image(Creature creature) : base(creature) { }
public override void IsSummonedBy(WorldObject summoner)
{ {
public const uint GlyphOfShadowFiend = 58228; me.CastSpell(me, SpellPriestInvokeTheNaaru);
public const uint ShadowFiendDeath = 57989;
public const uint LightWellCharges = 59907; if (me.ToTempSummon().IsGuardian() && summoner.IsUnit())
(me as Guardian).SetBonusDamage((int)summoner.ToUnit().SpellBaseHealingBonusDone(SpellSchoolMask.Holy));
} }
[Script] public override void OnDespawn()
class npc_pet_pri_lightwell : PassiveAI
{ {
public npc_pet_pri_lightwell(Creature creature) : base(creature) Unit owner = me.GetOwner();
{ if (owner != null)
DoCast(creature, SpellIds.LightWellCharges, new Game.Spells.CastSpellExtraArgs(false)); owner.RemoveAura(SpellPriestDivineImageSpellCheck);
} }
}
public override void EnterEvadeMode(EvadeReason why) [Script] // 189820 - Lightwell
{ class npc_pet_pri_lightwell : PassiveAI
if (!me.IsAlive()) {
return; const uint SpellPriestLightwellCharges = 59907;
me.CombatStop(true); public npc_pet_pri_lightwell(Creature creature) : base(creature)
EngagementOver(); {
me.ResetPlayerDamageReq(); DoCast(me, SpellPriestLightwellCharges, false);
}
} }
[Script] public override void EnterEvadeMode(EvadeReason why)
class npc_pet_pri_shadowfiend : PetAI
{ {
public npc_pet_pri_shadowfiend(Creature creature) : base(creature) { } if (!me.IsAlive())
return;
public override void IsSummonedBy(WorldObject summoner) me.CombatStop(true);
{ EngagementOver();
Unit unitSummoner = summoner.ToUnit(); me.ResetPlayerDamageReq();
if (unitSummoner == null) }
return; }
if (unitSummoner.HasAura(SpellIds.GlyphOfShadowFiend)) // 19668 - Shadowfiend
DoCastAOE(SpellIds.ShadowFiendDeath); [Script] // 62982 - Mindbender
} class npc_pet_pri_shadowfiend_mindbender : PetAI
{
const uint SpellPriestAtonement = 81749;
const uint SpellPriestAtonementPassive = 195178;
public npc_pet_pri_shadowfiend_mindbender(Creature creature) : base(creature) { }
public override void IsSummonedBy(WorldObject summonerWO)
{
Unit summoner = summonerWO.ToUnit();
if (summoner == null)
return;
if (summoner.HasAura(SpellPriestAtonement))
DoCastSelf(SpellPriestAtonementPassive, TriggerCastFlags.FullMask);
} }
} }
} }
+55 -66
View File
@@ -1,4 +1,4 @@
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved. // Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants; using Framework.Constants;
@@ -7,85 +7,74 @@ using Game.Entities;
using Game.Scripting; using Game.Scripting;
using System; using System;
namespace Scripts.Pets namespace Scripts.Pets.Shaman
{ {
namespace Shaman [Script]
class npc_pet_shaman_earth_elemental : ScriptedAI
{ {
struct SpellIds const uint SpellShamanAngeredearth = 36213;
{
//npc_pet_shaman_earth_elemental
public const uint AngeredEarth = 36213;
//npc_pet_shaman_fire_elemental public npc_pet_shaman_earth_elemental(Creature creature) : base(creature) { }
public const uint FireBlast = 57984;
public const uint FireNova = 12470; public override void Reset()
public const uint FireShield = 13376; {
_scheduler.CancelAll();
_scheduler.Schedule(TimeSpan.FromSeconds(0), task =>
{
DoCastVictim(SpellShamanAngeredearth);
task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
});
} }
[Script] public override void UpdateAI(uint diff)
class npc_pet_shaman_earth_elemental : ScriptedAI
{ {
public npc_pet_shaman_earth_elemental(Creature creature) : base(creature) { } if (!UpdateVictim())
return;
public override void Reset() _scheduler.Update(diff);
DoMeleeAttackIfReady();
}
}
[Script]
class npc_pet_shaman_fire_elemental : ScriptedAI
{
const uint SpellShamanFireblast = 57984;
const uint SpellShamanFirenova = 12470;
const uint SpellShamanFireshield = 13376;
public npc_pet_shaman_fire_elemental(Creature creature) : base(creature) { }
public override void Reset()
{
_scheduler.CancelAll();
_scheduler.Schedule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20), task =>
{ {
_scheduler.CancelAll(); DoCastVictim(SpellShamanFirenova);
_scheduler.Schedule(TimeSpan.FromSeconds(0), task => task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
{ });
DoCastVictim(SpellIds.AngeredEarth); _scheduler.Schedule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20), task =>
task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
});
}
public override void UpdateAI(uint diff)
{ {
if (!UpdateVictim()) DoCastVictim(SpellShamanFireblast);
return; task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
});
_scheduler.Update(diff); _scheduler.Schedule(TimeSpan.FromSeconds(0), task =>
{
DoMeleeAttackIfReady(); DoCastVictim(SpellShamanFireshield);
} task.Repeat(TimeSpan.FromSeconds(2));
});
} }
[Script] public override void UpdateAI(uint diff)
public class npc_pet_shaman_fire_elemental : ScriptedAI
{ {
public npc_pet_shaman_fire_elemental(Creature creature) : base(creature) { } if (!UpdateVictim())
return;
public override void Reset() if (me.HasUnitState(UnitState.Casting))
{ return;
_scheduler.CancelAll();
_scheduler.Schedule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20), task =>
{
DoCastVictim(SpellIds.FireNova);
task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
});
_scheduler.Schedule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20), task =>
{
DoCastVictim(SpellIds.FireShield);
task.Repeat(TimeSpan.FromSeconds(2));
});
_scheduler.Schedule(TimeSpan.FromSeconds(0), task =>
{
DoCastVictim(SpellIds.FireBlast);
task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
});
}
public override void UpdateAI(uint diff) _scheduler.Update(diff, DoMeleeAttackIfReady);
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
if (me.HasUnitState(UnitState.Casting))
return;
DoMeleeAttackIfReady();
}
} }
} }
} }
+10 -10
View File
@@ -1,4 +1,4 @@
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved. // Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants; using Framework.Constants;
@@ -11,11 +11,11 @@ namespace Scripts.Shadowlands
[Script] // 323916 - Sulfuric Emission [Script] // 323916 - Sulfuric Emission
class spell_soulbind_sulfuric_emission : AuraScript class spell_soulbind_sulfuric_emission : AuraScript
{ {
static uint SPELL_SULFURIC_EMISSION_COOLDOWN_AURA = 347684; uint SpellSulfuricEmissionCooldownAura = 347684;
public override bool Validate(SpellInfo spellInfo) public override bool Validate(SpellInfo spellInfo)
{ {
return ValidateSpellInfo(SPELL_SULFURIC_EMISSION_COOLDOWN_AURA); return ValidateSpellInfo(SpellSulfuricEmissionCooldownAura);
} }
bool CheckProc(AuraEffect aurEff, ProcEventInfo procInfo) bool CheckProc(AuraEffect aurEff, ProcEventInfo procInfo)
@@ -23,7 +23,7 @@ namespace Scripts.Shadowlands
if (!procInfo.GetProcTarget().HealthBelowPct(aurEff.GetAmount())) if (!procInfo.GetProcTarget().HealthBelowPct(aurEff.GetAmount()))
return false; return false;
if (procInfo.GetProcTarget().HasAura(SPELL_SULFURIC_EMISSION_COOLDOWN_AURA)) if (procInfo.GetProcTarget().HasAura(SpellSulfuricEmissionCooldownAura))
return false; return false;
return true; return true;
@@ -31,27 +31,27 @@ namespace Scripts.Shadowlands
public override void Register() public override void Register()
{ {
DoCheckEffectProc.Add(new CheckEffectProcHandler(CheckProc, 0, AuraType.ProcTriggerSpell)); DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.ProcTriggerSpell));
} }
} }
[Script] // 332753 - Superior Tactics [Script] // 332753 - Superior Tactics
class spell_soulbind_superior_tactics : AuraScript class spell_soulbind_superior_tactics : AuraScript
{ {
static uint SPELL_SUPERIOR_TACTICS_COOLDOWN_AURA = 332926; uint SpellSuperiorTacticsCooldownAura = 332926;
public override bool Validate(SpellInfo spellInfo) public override bool Validate(SpellInfo spellInfo)
{ {
return ValidateSpellInfo(SPELL_SUPERIOR_TACTICS_COOLDOWN_AURA); return ValidateSpellInfo(SpellSuperiorTacticsCooldownAura);
} }
bool CheckProc(AuraEffect aurEff, ProcEventInfo procInfo) bool CheckProc(AuraEffect aurEff, ProcEventInfo procInfo)
{ {
if (GetTarget().HasAura(SPELL_SUPERIOR_TACTICS_COOLDOWN_AURA)) if (GetTarget().HasAura(SpellSuperiorTacticsCooldownAura))
return false; return false;
// only dispels from friendly targets count // only dispels from friendly targets count
if (procInfo.GetHitMask().HasFlag(ProcFlagsHit.Dispel) && !procInfo.GetTypeMask().HasFlag(ProcFlags.DealHelpfulAbility | ProcFlags.DealHelpfulSpell | ProcFlags.DealHelpfulPeriodic)) if ((procInfo.GetHitMask() & ProcFlagsHit.Dispel) != 0 && !(procInfo.GetTypeMask() & new ProcFlagsInit(ProcFlags.DealHelpfulAbility | ProcFlags.DealHelpfulSpell | ProcFlags.DealHelpfulPeriodic)))
return false; return false;
return true; return true;
@@ -59,7 +59,7 @@ namespace Scripts.Shadowlands
public override void Register() public override void Register()
{ {
DoCheckEffectProc.Add(new CheckEffectProcHandler(CheckProc, 0, AuraType.ProcTriggerSpell)); DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.ProcTriggerSpell));
} }
} }
} }
@@ -1,4 +1,4 @@
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved. // Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants; using Framework.Constants;
@@ -6,11 +6,37 @@ using Game.Entities;
using Game.Scripting; using Game.Scripting;
using Game.Spells; using Game.Spells;
using System.Collections.Generic; using System.Collections.Generic;
using static Global; using static Global;
namespace Scripts.Shadowlands.Torghast namespace Scripts.Shadowlands.Torghast
{ {
[Script] // 297721 - Subjugator's Manacles
class spell_torghast_subjugators_manacles : AuraScript
{
List<ObjectGuid> _triggeredTargets = new();
bool CheckProc(AuraEffect aurEff, ProcEventInfo procInfo)
{
if (_triggeredTargets.Contains(procInfo.GetProcTarget().GetGUID()))
return false;
_triggeredTargets.Add(procInfo.GetProcTarget().GetGUID());
return true;
}
void ResetMarkedTargets(bool isNowInCombat)
{
if (!isNowInCombat)
_triggeredTargets.Clear();
}
public override void Register()
{
DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.ProcTriggerSpell));
OnEnterLeaveCombat.Add(new(ResetMarkedTargets));
}
}
[Script] // 300771 - Blade of the Lifetaker [Script] // 300771 - Blade of the Lifetaker
class spell_torghast_blade_of_the_lifetaker : AuraScript class spell_torghast_blade_of_the_lifetaker : AuraScript
{ {
@@ -25,23 +51,23 @@ namespace Scripts.Shadowlands.Torghast
public override void Register() public override void Register()
{ {
OnEffectProc.Add(new EffectProcHandler(HandleProc, 0, AuraType.ProcTriggerSpell)); OnEffectProc.Add(new(HandleProc, 0, AuraType.ProcTriggerSpell));
} }
} }
[Script] // 300796 - Touch of the Unseen [Script] // 300796 - Touch of the Unseen
class spell_torghast_touch_of_the_unseen : AuraScript class spell_torghast_touch_of_the_unseen : AuraScript
{ {
static uint SPELL_DOOR_OF_SHADOWS = 300728; uint SpellDoorOfShadows = 300728;
public override bool Validate(SpellInfo spellInfo) public override bool Validate(SpellInfo spellInfo)
{ {
return ValidateSpellInfo(SPELL_DOOR_OF_SHADOWS); return ValidateSpellInfo(SpellDoorOfShadows);
} }
bool CheckProc(ProcEventInfo procInfo) bool CheckProc(ProcEventInfo procInfo)
{ {
return procInfo.GetSpellInfo() != null && procInfo.GetSpellInfo().Id == SPELL_DOOR_OF_SHADOWS; return procInfo.GetSpellInfo() != null && procInfo.GetSpellInfo().Id == SpellDoorOfShadows;
} }
void HandleProc(AuraEffect aurEff, ProcEventInfo procInfo) void HandleProc(AuraEffect aurEff, ProcEventInfo procInfo)
@@ -55,48 +81,48 @@ namespace Scripts.Shadowlands.Torghast
public override void Register() public override void Register()
{ {
DoCheckProc.Add(new CheckProcHandler(CheckProc)); DoCheckProc.Add(new(CheckProc));
OnEffectProc.Add(new EffectProcHandler(HandleProc, 0, AuraType.ProcTriggerSpell)); OnEffectProc.Add(new(HandleProc, 0, AuraType.ProcTriggerSpell));
} }
} }
[Script] // 305060 - Yel'Shir's Powerglove [Script] // 305060 - Yel'Shir's Powerglove
class spell_torghast_yelshirs_powerglove : SpellScript class spell_torghast_yelshirs_powerglove : SpellScript
{ {
void HandleEffect(uint effIndex) void CalculateDamage(Unit victim, ref int damage, ref int flatMod, ref float pctMod)
{ {
SpellInfo triggeringSpell = GetTriggeringSpell(); SpellInfo triggeringSpell = GetTriggeringSpell();
if (triggeringSpell != null) if (triggeringSpell != null)
{ {
Aura triggerAura = GetCaster().GetAura(triggeringSpell.Id); Aura triggerAura = GetCaster().GetAura(triggeringSpell.Id);
if (triggerAura != null) if (triggerAura != null)
SetEffectValue(GetEffectValue() * triggerAura.GetStackAmount()); pctMod *= triggerAura.GetStackAmount();
} }
} }
public override void Register() public override void Register()
{ {
OnEffectLaunchTarget.Add(new EffectHandler(HandleEffect, 0, SpellEffectName.SchoolDamage)); CalcDamage.Add(new(CalculateDamage));
} }
} }
[Script] // 321706 - Dimensional Blade [Script] // 321706 - Dimensional Blade
class spell_torghast_dimensional_blade : SpellScript class spell_torghast_dimensional_blade : SpellScript
{ {
static uint SPELL_MAGE_BLINK = 1953; uint SpellMageBlink = 1953;
static uint SPELL_MAGE_SHIMMER = 212653; uint SpellMageShimmer = 212653;
public override bool Validate(SpellInfo spellInfo) public override bool Validate(SpellInfo spellInfo)
{ {
return ValidateSpellInfo(SPELL_MAGE_BLINK, SPELL_MAGE_SHIMMER); return ValidateSpellInfo(SpellMageBlink, SpellMageShimmer);
} }
void FilterTargets(List<WorldObject> targets) void FilterTargets(List<WorldObject> targets)
{ {
if (!targets.Empty()) if (!targets.Empty())
{ {
GetCaster().GetSpellHistory().RestoreCharge(SpellMgr.GetSpellInfo(SPELL_MAGE_BLINK, Difficulty.None).ChargeCategoryId); GetCaster().GetSpellHistory().RestoreCharge(SpellMgr.GetSpellInfo(SpellMageBlink, Difficulty.None).ChargeCategoryId);
GetCaster().GetSpellHistory().RestoreCharge(SpellMgr.GetSpellInfo(SPELL_MAGE_SHIMMER, Difficulty.None).ChargeCategoryId); GetCaster().GetSpellHistory().RestoreCharge(SpellMgr.GetSpellInfo(SpellMageShimmer, Difficulty.None).ChargeCategoryId);
} }
// filter targets by entry here and not with conditions table because we need to know if any enemy was hit for charge restoration, not just mawrats // filter targets by entry here and not with conditions table because we need to know if any enemy was hit for charge restoration, not just mawrats
@@ -118,7 +144,190 @@ namespace Scripts.Shadowlands.Torghast
public override void Register() public override void Register()
{ {
OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargets, 1, Targets.UnitDestAreaEnemy)); OnObjectAreaTargetSelect.Add(new(FilterTargets, 1, Targets.UnitDestAreaEnemy));
}
}
[Script] // 341324 - Uncontrolled Darkness
class spell_torghast_uncontrolled_darkness : AuraScript
{
public int KillCounter;
public override void Register()
{
// just a value holder, no hooks
}
}
[Script] // 343174 - Uncontrolled Darkness
class spell_torghast_uncontrolled_darkness_proc : AuraScript
{
uint SpellUncontrolledDarkness = 341324;
uint SpellUncontrolledDarknessBuff = 341375;
public override bool Validate(SpellInfo spellInfo)
{
return ValidateSpellEffect((SpellUncontrolledDarkness, 1))
&& ValidateSpellInfo(SpellUncontrolledDarknessBuff);
}
void HandleProc(AuraEffect aurEff, ProcEventInfo procInfo)
{
Unit caster = GetCaster();
if (caster == null)
return;
Aura uncontrolledDarkness = caster.GetAura(SpellUncontrolledDarkness, caster.GetGUID());
if (uncontrolledDarkness == null)
return;
var script = uncontrolledDarkness.GetScript<spell_torghast_uncontrolled_darkness>();
if (script == null)
return;
if (caster.HasAura(SpellUncontrolledDarknessBuff))
{
if (++script.KillCounter >= uncontrolledDarkness.GetSpellInfo().GetEffect(1).CalcValue())
{
caster.RemoveAura(SpellUncontrolledDarknessBuff);
script.KillCounter = 0;
}
}
else
{
if (++script.KillCounter >= uncontrolledDarkness.GetSpellInfo().GetEffect(0).CalcValue())
{
caster.CastSpell(caster, SpellUncontrolledDarknessBuff, true);
script.KillCounter = 0;
}
}
}
public override void Register()
{
OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy));
}
}
[Script] // 342632 - Malevolent Stitching
class spell_torghast_fleshcraft_shield_proc : AuraScript
{
uint SpellLabelFleshcraftBuff = 1103;
bool CheckProc(ProcEventInfo procInfo)
{
return procInfo.GetSpellInfo() != null && procInfo.GetSpellInfo().HasLabel(SpellLabelFleshcraftBuff);
}
public override void Register()
{
DoCheckProc.Add(new(CheckProc));
}
}
[Script] // 342779 - Crystallized Dreams
class spell_torghast_soulshape_proc : AuraScript
{
uint SpellLabelSoulshape = 1100;
bool CheckProc(ProcEventInfo procInfo)
{
return procInfo.GetSpellInfo() != null && procInfo.GetSpellInfo().HasLabel(SpellLabelSoulshape);
}
public override void Register()
{
DoCheckProc.Add(new(CheckProc));
}
}
// 342793 - Murmuring Shawl
[Script] // 342799 - Gnarled Key
class spell_torghast_door_of_shadows_proc : AuraScript
{
uint SpellLabelDoorOfShadows = 726;
bool CheckProc(ProcEventInfo procInfo)
{
return procInfo.GetSpellInfo() != null && procInfo.GetSpellInfo().HasLabel(SpellLabelDoorOfShadows);
}
public override void Register()
{
DoCheckProc.Add(new(CheckProc));
}
}
[Script] // 348908 - Ethereal Wildseed
class spell_torghast_flicker_proc : AuraScript
{
uint SpellLabelFlicker = 1105;
bool CheckProc(ProcEventInfo procInfo)
{
return procInfo.GetSpellInfo() != null && procInfo.GetSpellInfo().HasLabel(SpellLabelFlicker);
}
public override void Register()
{
DoCheckProc.Add(new(CheckProc));
}
}
[Script] // 354569 - Potent Potion
class spell_torghast_potent_potion_proc : AuraScript
{
uint SpellLabelRejuvenatingSiphonedEssence = 1290;
bool CheckProc(ProcEventInfo procInfo)
{
return procInfo.GetSpellInfo() != null && procInfo.GetSpellInfo().HasLabel(SpellLabelRejuvenatingSiphonedEssence);
}
public override void Register()
{
DoCheckProc.Add(new(CheckProc));
}
}
[Script] // 354706 - Spiritual Rejuvenation Potion
class spell_torghast_potent_potion_calc : SpellScript
{
uint SpellLabelSpiritualRejuvenationPotion = 354568;
public override bool Validate(SpellInfo spellInfo)
{
return ValidateSpellEffect((SpellLabelSpiritualRejuvenationPotion, 1));
}
void SetValue(uint effIndex)
{
SetEffectValue(SpellMgr.GetSpellInfo(SpellLabelSpiritualRejuvenationPotion, GetCastDifficulty()).GetEffect(effIndex)
.CalcValue(GetCaster(), null, GetHitUnit()));
}
public override void Register()
{
OnEffectLaunchTarget.Add(new(SetValue, 0, SpellEffectName.Heal));
OnEffectHitTarget.Add(new(SetValue, 1, SpellEffectName.Energize));
}
}
[Script] // 373761 - Poisonous Spores
class spell_torghast_poisonous_spores : AuraScript
{
void HandleProc(AuraEffect aurEff, ProcEventInfo procInfo)
{
PreventDefaultAction();
Spell procSpell = procInfo.GetProcSpell();
procInfo.GetActor().CastSpell(procSpell.m_targets.GetDst(), aurEff.GetSpellEffectInfo().TriggerSpell,
new CastSpellExtraArgs(aurEff).SetTriggeringSpell(procSpell));
}
public override void Register()
{
OnEffectProc.Add(new(HandleProc, 0, AuraType.ProcTriggerSpell));
} }
} }
} }
+83 -76
View File
@@ -34,47 +34,48 @@ namespace Scripts.World.Achievements
UnknownAction = 12 UnknownAction = 12
} }
[Script]
class AccountActionIpLogger : AccountScript class AccountActionIpLogger : AccountScript
{ {
public AccountActionIpLogger() : base("AccountActionIpLogger") { } public AccountActionIpLogger() : base("AccountActionIpLogger") { }
// We log last_ip instead of last_attempt_ip, as login was successful // We log last_ip instead of last_attempt_ip, as login was successful
// AccountLogin = 0 // AccountLogin = 0
void OnAccountLogin(uint accountId) public override void OnAccountLogin(uint accountId)
{ {
AccountIPLogAction(accountId, AccountLogin); AccountIPLogAction(accountId, IPLoggingTypes.AccountLogin);
} }
// We log last_attempt_ip instead of last_ip, as failed login doesn't necessarily mean approperiate user // We log last_attempt_ip instead of last_ip, as failed login doesn't necessarily mean approperiate user
// AccountFailLogin = 1 // AccountFailLogin = 1
void OnFailedAccountLogin(uint accountId) public override void OnFailedAccountLogin(uint accountId)
{ {
AccountIPLogAction(accountId, AccountFailLogin); AccountIPLogAction(accountId, IPLoggingTypes.AccountFailLogin);
} }
// AccountChangePw = 2 // AccountChangePw = 2
void OnPasswordChange(uint accountId) public override void OnPasswordChange(uint accountId)
{ {
AccountIPLogAction(accountId, AccountChangePw); AccountIPLogAction(accountId, IPLoggingTypes.AccountChangePw);
} }
// AccountChangePwFail = 3 // AccountChangePwFail = 3
void OnFailedPasswordChange(uint accountId) public override void OnFailedPasswordChange(uint accountId)
{ {
AccountIPLogAction(accountId, AccountChangePwFail); AccountIPLogAction(accountId, IPLoggingTypes.AccountChangePwFail);
} }
// Registration Email can Not be changed apart from Gm level users. Thus, we do not require to log them... // Registration Email can Not be changed apart from Gm level users. Thus, we do not require to log them...
// AccountChangeEmail = 4 // AccountChangeEmail = 4
void OnEmailChange(uint accountId) public override void OnEmailChange(uint accountId)
{ {
AccountIPLogAction(accountId, AccountChangeEmail); // ... they get logged by gm command logger anyway AccountIPLogAction(accountId, IPLoggingTypes.AccountChangeEmail); // ... they get logged by gm command logger anyway
} }
// AccountChangeEmailFail = 5 // AccountChangeEmailFail = 5
void OnFailedEmailChange(uint accountId) public override void OnFailedEmailChange(uint accountId)
{ {
AccountIPLogAction(accountId, AccountChangeEmailFail); AccountIPLogAction(accountId, IPLoggingTypes.AccountChangeEmailFail);
} }
// AccountLogout = 6 // AccountLogout = 6
@@ -85,36 +86,36 @@ namespace Scripts.World.Achievements
// We declare all the required variables // We declare all the required variables
uint playerGuid = accountId; uint playerGuid = accountId;
uint realmId = realm.Id.Realm; uint realmId = Global.WorldMgr.GetRealmId().Index;
std.string systemNote = "Error"; // "Error" is a placeholder here. We change it later. string systemNote = "Error"; // "Error" is a placeholder here. We change it later.
// With this switch, we change systemNote so that we have a more accurate phraMath.Sing of what type it is. // With this switch, we change systemNote so that we have a more accurate phraMath.Sing of what type it is.
// Avoids Magicnumbers in Sql table // Avoids Magicnumbers in Sql table
switch (aType) switch (aType)
{ {
case AccountLogin: case IPLoggingTypes.AccountLogin:
systemNote = "Logged into WoW"; systemNote = "Logged into WoW";
break; break;
case AccountFailLogin: case IPLoggingTypes.AccountFailLogin:
systemNote = "Login to WoW Failed"; systemNote = "Login to WoW Failed";
break; break;
case AccountChangePw: case IPLoggingTypes.AccountChangePw:
systemNote = "Password Reset Completed"; systemNote = "Password Reset Completed";
break; break;
case AccountChangePwFail: case IPLoggingTypes.AccountChangePwFail:
systemNote = "Password Reset Failed"; systemNote = "Password Reset Failed";
break; break;
case AccountChangeEmail: case IPLoggingTypes.AccountChangeEmail:
systemNote = "Email Change Completed"; systemNote = "Email Change Completed";
break; break;
case AccountChangeEmailFail: case IPLoggingTypes.AccountChangeEmailFail:
systemNote = "Email Change Failed"; systemNote = "Email Change Failed";
break; break;
case AccountLogout: /*case IPLoggingTypes.AccountLogout:
systemNote = "Logged on AccountLogout"; //Can not be logged systemNote = "Logged on AccountLogout"; //Can not be logged
break; break;*/
// Neither should happen. Ever. Period. If it does, call Ghostbusters and all your local software defences to investigate. // Neither should happen. Ever. Period. If it does, call Ghostbusters and all your local software defences to investigate.
case UnknownAction: case IPLoggingTypes.UnknownAction:
default: default:
systemNote = "Error! Unknown action!"; systemNote = "Error! Unknown action!";
break; break;
@@ -123,54 +124,57 @@ namespace Scripts.World.Achievements
// Once we have done everything, we can Add the new log. // Once we have done everything, we can Add the new log.
// Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now; // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now;
// Rather, we let it be added with the Sql query. // Rather, we let it be added with the Sql query.
if (aType != AccountFailLogin) if (aType != IPLoggingTypes.AccountFailLogin)
{ {
// As we can assume most account actions are Not failed login, so this is the more accurate check. // As we can assume most account actions are Not failed login, so this is the more accurate check.
// For those, we need last_ip... // For those, we need last_ip...
PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.INS_ALDL_IP_LOGGING);
stmt.setUint(0, playerGuid); stmt.AddValue(0, playerGuid);
stmt.setUInt64(1, 0); stmt.AddValue(1, 0ul);
stmt.setUint(2, realmId); stmt.AddValue(2, realmId);
stmt.setUInt8(3, aType); stmt.AddValue(3, (byte)aType);
stmt.setUint(4, playerGuid); stmt.AddValue(4, playerGuid);
stmt.setString(5, systemNote); stmt.AddValue(5, systemNote);
LoginDatabase.Execute(stmt); DB.Login.Execute(stmt);
} }
else // ... but for failed login, we query last_attempt_ip from account table. Which we do with an unique query else // ... but for failed login, we query last_attempt_ip from account table. Which we do with an unique query
{ {
PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.INS_FACL_IP_LOGGING);
stmt.setUint(0, playerGuid); stmt.AddValue(0, playerGuid);
stmt.setUInt64(1, 0); stmt.AddValue(1, 0ul);
stmt.setUint(2, realmId); stmt.AddValue(2, realmId);
stmt.setUInt8(3, aType); stmt.AddValue(3, (byte)aType);
stmt.setUint(4, playerGuid); stmt.AddValue(4, playerGuid);
stmt.setString(5, systemNote); stmt.AddValue(5, systemNote);
LoginDatabase.Execute(stmt); DB.Login.Execute(stmt);
} }
return; return;
} }
} }
[Script]
class CharacterActionIpLogger : PlayerScript class CharacterActionIpLogger : PlayerScript
{ {
public CharacterActionIpLogger() : base("CharacterActionIpLogger") { } public CharacterActionIpLogger() : base("CharacterActionIpLogger") { }
// CharacterCreate = 7 // CharacterCreate = 7
void OnCreate(Player player) public override void OnCreate(Player player)
{ {
CharacterIPLogAction(player, CharacterCreate); CharacterIPLogAction(player, IPLoggingTypes.CharacterCreate);
} }
// CharacterLogin = 8 // CharacterLogin = 8
void OnLogin(Player player, bool firstLogin) public override void OnLogin(Player player, bool firstLogin)
{ {
CharacterIPLogAction(player, CharacterLogin); CharacterIPLogAction(player, IPLoggingTypes.CharacterLogin);
} }
// CharacterLogout = 9 // CharacterLogout = 9
void OnLogout(Player player) public override void OnLogout(Player player)
{ {
CharacterIPLogAction(player, CharacterLogout); CharacterIPLogAction(player, IPLoggingTypes.CharacterLogout);
} }
// CharacterDelete = 10 // CharacterDelete = 10
@@ -189,65 +193,67 @@ namespace Scripts.World.Achievements
// We declare all the required variables // We declare all the required variables
uint playerGuid = player.GetSession().GetAccountId(); uint playerGuid = player.GetSession().GetAccountId();
uint realmId = realm.Id.Realm; uint realmId = Global.WorldMgr.GetRealmId().Index;
std.string currentIp = player.GetSession().GetRemoteAddress(); string currentIp = player.GetSession().GetRemoteAddress();
std.string systemNote = "Error"; // "Error" is a placeholder here. We change it... string systemNote;
// ... with this switch, so that we have a more accurate phraMath.Sing of what type it is // ... with this switch, so that we have a more accurate phraMath.Sing of what type it is
switch (aType) switch (aType)
{ {
case CharacterCreate: case IPLoggingTypes.CharacterCreate:
systemNote = "Character Created"; systemNote = "Character Created";
break; break;
case CharacterLogin: case IPLoggingTypes.CharacterLogin:
systemNote = "Logged onto Character"; systemNote = "Logged onto Character";
break; break;
case CharacterLogout: case IPLoggingTypes.CharacterLogout:
systemNote = "Logged out of Character"; systemNote = "Logged out of Character";
break; break;
case CharacterDelete: case IPLoggingTypes.CharacterDelete:
systemNote = "Character Deleted"; systemNote = "Character Deleted";
break; break;
case CharacterFailedDelete: case IPLoggingTypes.CharacterFailedDelete:
systemNote = "Character Deletion Failed"; systemNote = "Character Deletion Failed";
break; break;
// Neither should happen. Ever. Period. If it does, call Mythbusters. // Neither should happen. Ever. Period. If it does, call Mythbusters.
case UnknownAction: case IPLoggingTypes.UnknownAction:
default: default:
systemNote = "Error! Unknown action!"; systemNote = "Error! Unknown action!";
break; break;
} }
// Once we have done everything, we can Add the new log. // Once we have done everything, we can Add the new log.
PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.INS_CHAR_IP_LOGGING);
stmt.setUint(0, playerGuid); stmt.AddValue(0, playerGuid);
stmt.setUInt64(1, player.GetGUID().GetCounter()); stmt.AddValue(1, player.GetGUID().GetCounter());
stmt.setUint(2, realmId); stmt.AddValue(2, realmId);
stmt.setUInt8(3, aType); stmt.AddValue(3, (byte)aType);
stmt.setString(4, currentIp); // We query the ip here. stmt.AddValue(4, currentIp); // We query the ip here.
stmt.setString(5, systemNote); stmt.AddValue(5, systemNote);
// Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now; // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now;
// Rather, we let it be added with the Sql query. // Rather, we let it be added with the Sql query.
LoginDatabase.Execute(stmt); DB.Login.Execute(stmt);
return; return;
} }
} }
[Script]
class CharacterDeleteActionIpLogger : PlayerScript class CharacterDeleteActionIpLogger : PlayerScript
{ {
public CharacterDeleteActionIpLogger() : base("CharacterDeleteActionIpLogger") { } public CharacterDeleteActionIpLogger() : base("CharacterDeleteActionIpLogger") { }
// CharacterDelete = 10 // CharacterDelete = 10
void OnDelete(ObjectGuid guid, uint accountId) public override void OnDelete(ObjectGuid guid, uint accountId)
{ {
DeleteIPLogAction(guid, accountId, CharacterDelete); DeleteIPLogAction(guid, accountId, IPLoggingTypes.CharacterDelete);
} }
// CharacterFailedDelete = 11 // CharacterFailedDelete = 11
void OnFailedDelete(ObjectGuid guid, uint accountId) public override void OnFailedDelete(ObjectGuid guid, uint accountId)
{ {
DeleteIPLogAction(guid, accountId, CharacterFailedDelete); DeleteIPLogAction(guid, accountId, IPLoggingTypes.CharacterFailedDelete);
} }
void DeleteIPLogAction(ObjectGuid guid, uint playerGuid, IPLoggingTypes aType) void DeleteIPLogAction(ObjectGuid guid, uint playerGuid, IPLoggingTypes aType)
@@ -255,40 +261,41 @@ namespace Scripts.World.Achievements
// Action Ip Logger is only intialized if config is set up // Action Ip Logger is only intialized if config is set up
// Else, this script isn't loaded in the first place: We require no config check. // Else, this script isn't loaded in the first place: We require no config check.
uint realmId = realm.Id.Realm; uint realmId = Global.WorldMgr.GetRealmId().Index;
// Query playerGuid/accountId, as we only have characterGuid // Query playerGuid/accountId, as we only have characterGuid
std.string systemNote = "Error"; // "Error" is a placeholder here. We change it later. string systemNote;
// With this switch, we change systemNote so that we have a more accurate phraMath.Sing of what type it is. // With this switch, we change systemNote so that we have a more accurate phraMath.Sing of what type it is.
// Avoids Magicnumbers in Sql table // Avoids Magicnumbers in Sql table
switch (aType) switch (aType)
{ {
case CharacterDelete: case IPLoggingTypes.CharacterDelete:
systemNote = "Character Deleted"; systemNote = "Character Deleted";
break; break;
case CharacterFailedDelete: case IPLoggingTypes.CharacterFailedDelete:
systemNote = "Character Deletion Failed"; systemNote = "Character Deletion Failed";
break; break;
// Neither should happen. Ever. Period. If it does, call to whatever god you have for mercy and guidance. // Neither should happen. Ever. Period. If it does, call to whatever god you have for mercy and guidance.
case UnknownAction: case IPLoggingTypes.UnknownAction:
default: default:
systemNote = "Error! Unknown action!"; systemNote = "Error! Unknown action!";
break; break;
} }
// Once we have done everything, we can Add the new log. // Once we have done everything, we can Add the new log.
PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.INS_ALDL_IP_LOGGING);
stmt.setUint(0, playerGuid); stmt.AddValue(0, playerGuid);
stmt.setUInt64(1, guid.GetCounter()); stmt.AddValue(1, guid.GetCounter());
stmt.setUint(2, realmId); stmt.AddValue(2, realmId);
stmt.setUInt8(3, aType); stmt.AddValue(3, (byte)aType);
stmt.setUint(4, playerGuid); stmt.AddValue(4, playerGuid);
stmt.setString(5, systemNote); stmt.AddValue(5, systemNote);
// Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now; // Seeing as the time differences should be minimal, we do not get unixtime and the timestamp right now;
// Rather, we let it be added with the Sql query. // Rather, we let it be added with the Sql query.
LoginDatabase.Execute(stmt); DB.Login.Execute(stmt);
return; return;
} }
} }