More work on scripts.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -552,7 +561,7 @@ namespace Game.Chat
|
|||||||
{
|
{
|
||||||
[Command("2fa", CypherStrings.CommandAccSet2faHelp, RBACPermissions.CommandAccountSet2Fa, true)]
|
[Command("2fa", CypherStrings.CommandAccSet2faHelp, RBACPermissions.CommandAccountSet2Fa, true)]
|
||||||
static bool HandleAccountSet2FACommand(CommandHandler handler, string accountName, string secret)
|
static bool HandleAccountSet2FACommand(CommandHandler handler, string accountName, string secret)
|
||||||
{
|
{
|
||||||
/*uint targetAccountId = Global.AccountMgr.GetId(accountName);
|
/*uint targetAccountId = Global.AccountMgr.GetId(accountName);
|
||||||
if (targetAccountId == 0)
|
if (targetAccountId == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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":
|
||||||
@@ -267,7 +268,7 @@ namespace Game.Scripting
|
|||||||
{
|
{
|
||||||
UnitAI.FillAISpellInfo();
|
UnitAI.FillAISpellInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SplineChainLink> GetSplineChain(Creature who, ushort chainId)
|
public List<SplineChainLink> GetSplineChain(Creature who, ushort chainId)
|
||||||
{
|
{
|
||||||
return GetSplineChain(who.GetEntry(), chainId);
|
return GetSplineChain(who.GetEntry(), chainId);
|
||||||
@@ -762,7 +763,7 @@ namespace Game.Scripting
|
|||||||
|
|
||||||
RunScript<AchievementScript>(p => p.OnCompleted(player, achievement), Global.AchievementMgr.GetAchievementScriptId(achievement.Id));
|
RunScript<AchievementScript>(p => p.OnCompleted(player, achievement), Global.AchievementMgr.GetAchievementScriptId(achievement.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// AchievementCriteriaScript
|
// AchievementCriteriaScript
|
||||||
public bool OnCriteriaCheck(uint ScriptId, Player source, Unit target)
|
public bool OnCriteriaCheck(uint ScriptId, Player source, Unit target)
|
||||||
{
|
{
|
||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -1172,7 +1199,7 @@ namespace Game.Scripting
|
|||||||
uint _ScriptCount;
|
uint _ScriptCount;
|
||||||
public Dictionary<uint, SpellSummary> spellSummaryStorage = new();
|
public Dictionary<uint, SpellSummary> spellSummaryStorage = new();
|
||||||
Hashtable ScriptStorage = new();
|
Hashtable ScriptStorage = new();
|
||||||
|
|
||||||
// creature entry + chain ID
|
// creature entry + chain ID
|
||||||
MultiMap<Tuple<uint, ushort>, SplineChainLink> m_mSplineChainsMap = new(); // spline chains
|
MultiMap<Tuple<uint, ushort>, SplineChainLink> m_mSplineChainsMap = new(); // spline chains
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+229
-177
@@ -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()
|
|
||||||
{
|
|
||||||
OnEffectHitTarget.Add(new EffectHandler(HandleScriptEffect, 0, SpellEffectName.ScriptEffect));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Script] // 69736 - Lich Pet Aura Remove
|
|
||||||
class spell_gen_lich_pet_aura_remove : SpellScript
|
|
||||||
{
|
|
||||||
public override bool Validate(SpellInfo spellInfo)
|
|
||||||
{
|
|
||||||
return ValidateSpellInfo(SpellIds.LichPetAura);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleScriptEffect(uint effIndex)
|
|
||||||
{
|
|
||||||
GetHitUnit().RemoveAurasDueToSpell(SpellIds.LichPetAura);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Register()
|
|
||||||
{
|
|
||||||
OnEffectHitTarget.Add(new EffectHandler(HandleScriptEffect, 0, SpellEffectName.ScriptEffect));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Script] // 69732 - Lich Pet Aura
|
|
||||||
class spell_gen_lich_pet_aura : AuraScript
|
|
||||||
{
|
|
||||||
public override bool Validate(SpellInfo spellInfo)
|
|
||||||
{
|
|
||||||
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
|
|
||||||
class spell_pet_gen_lich_pet_periodic_emote : AuraScript
|
|
||||||
{
|
|
||||||
public override bool Validate(SpellInfo spellInfo)
|
|
||||||
{
|
|
||||||
return ValidateSpellInfo(SpellIds.LichPetEmote);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(), SpellIds.LichPetEmote, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Register()
|
|
||||||
{
|
|
||||||
OnEffectPeriodic.Add(new EffectPeriodicHandler(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 EffectApplyHandler(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 EffectHandler(HandleScript, 0, SpellEffectName.ScriptEffect));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
[Script]
|
||||||
|
class npc_pet_gen_soul_trader : ScriptedAI
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void JustAppeared()
|
||||||
|
{
|
||||||
|
Talk(SaySoulTraderIntro);
|
||||||
|
Unit owner = me.GetOwner();
|
||||||
|
if (owner != null)
|
||||||
|
DoCast(owner, SpellEtherealOnsummon);
|
||||||
|
|
||||||
|
base.JustAppeared();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Script] // 69735 - Lich Pet OnSummon
|
||||||
|
class spell_pet_gen_lich_pet_onsummon : SpellScript
|
||||||
|
{
|
||||||
|
const uint SpellLichPetAura = 69732;
|
||||||
|
|
||||||
|
public override bool Validate(SpellInfo spellInfo)
|
||||||
|
{
|
||||||
|
return ValidateSpellInfo(SpellLichPetAura);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleScript(uint effIndex)
|
||||||
|
{
|
||||||
|
Unit target = GetHitUnit();
|
||||||
|
target.CastSpell(target, SpellLichPetAura, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Register()
|
||||||
|
{
|
||||||
|
OnEffectHitTarget.Add(new(HandleScript, 0, SpellEffectName.ScriptEffect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Script] // 69736 - Lich Pet Aura Remove
|
||||||
|
class spell_pet_gen_lich_pet_aura_Remove : SpellScript
|
||||||
|
{
|
||||||
|
const uint SpellLichPetAura = 69732;
|
||||||
|
|
||||||
|
public override bool Validate(SpellInfo spellInfo)
|
||||||
|
{
|
||||||
|
return ValidateSpellInfo(SpellLichPetAura);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleScript(uint effIndex)
|
||||||
|
{
|
||||||
|
GetHitUnit().RemoveAurasDueToSpell(SpellLichPetAura);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Register()
|
||||||
|
{
|
||||||
|
OnEffectHitTarget.Add(new(HandleScript, 0, SpellEffectName.ScriptEffect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Script] // 69732 - Lich Pet Aura
|
||||||
|
class spell_pet_gen_lich_pet_AuraScript : AuraScript
|
||||||
|
{
|
||||||
|
const uint SpellLichPetAuraOnkill = 69731;
|
||||||
|
|
||||||
|
const uint NpcLichPet = 36979;
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
@@ -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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
{
|
|
||||||
if (!me.IsAlive())
|
|
||||||
return;
|
|
||||||
|
|
||||||
me.CombatStop(true);
|
|
||||||
EngagementOver();
|
|
||||||
me.ResetPlayerDamageReq();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Script]
|
|
||||||
class npc_pet_pri_shadowfiend : PetAI
|
|
||||||
{
|
|
||||||
public npc_pet_pri_shadowfiend(Creature creature) : base(creature) { }
|
|
||||||
|
|
||||||
public override void IsSummonedBy(WorldObject summoner)
|
|
||||||
{
|
|
||||||
Unit unitSummoner = summoner.ToUnit();
|
|
||||||
if (unitSummoner == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (unitSummoner.HasAura(SpellIds.GlyphOfShadowFiend))
|
|
||||||
DoCastAOE(SpellIds.ShadowFiendDeath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
[Script] // 189820 - Lightwell
|
||||||
|
class npc_pet_pri_lightwell : PassiveAI
|
||||||
|
{
|
||||||
|
const uint SpellPriestLightwellCharges = 59907;
|
||||||
|
|
||||||
|
public npc_pet_pri_lightwell(Creature creature) : base(creature)
|
||||||
|
{
|
||||||
|
DoCast(me, SpellPriestLightwellCharges, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void EnterEvadeMode(EvadeReason why)
|
||||||
|
{
|
||||||
|
if (!me.IsAlive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
me.CombatStop(true);
|
||||||
|
EngagementOver();
|
||||||
|
me.ResetPlayerDamageReq();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 19668 - Shadowfiend
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
{
|
|
||||||
_scheduler.CancelAll();
|
|
||||||
_scheduler.Schedule(TimeSpan.FromSeconds(0), task =>
|
|
||||||
{
|
|
||||||
DoCastVictim(SpellIds.AngeredEarth);
|
|
||||||
task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateAI(uint diff)
|
DoMeleeAttackIfReady();
|
||||||
{
|
|
||||||
if (!UpdateVictim())
|
|
||||||
return;
|
|
||||||
|
|
||||||
_scheduler.Update(diff);
|
|
||||||
|
|
||||||
DoMeleeAttackIfReady();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Script]
|
|
||||||
public class npc_pet_shaman_fire_elemental : ScriptedAI
|
|
||||||
{
|
|
||||||
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 =>
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (!UpdateVictim())
|
|
||||||
return;
|
|
||||||
|
|
||||||
_scheduler.Update(diff);
|
|
||||||
|
|
||||||
if (me.HasUnitState(UnitState.Casting))
|
|
||||||
return;
|
|
||||||
|
|
||||||
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 =>
|
||||||
|
{
|
||||||
|
DoCastVictim(SpellShamanFirenova);
|
||||||
|
task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
|
||||||
|
});
|
||||||
|
_scheduler.Schedule(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20), task =>
|
||||||
|
{
|
||||||
|
DoCastVictim(SpellShamanFireblast);
|
||||||
|
task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(20));
|
||||||
|
});
|
||||||
|
_scheduler.Schedule(TimeSpan.FromSeconds(0), task =>
|
||||||
|
{
|
||||||
|
DoCastVictim(SpellShamanFireshield);
|
||||||
|
task.Repeat(TimeSpan.FromSeconds(2));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateAI(uint diff)
|
||||||
|
{
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (me.HasUnitState(UnitState.Casting))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_scheduler.Update(diff, DoMeleeAttackIfReady);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user