aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Miscellaneous/Language.h4
-rw-r--r--src/server/game/World/World.cpp1
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp150
-rw-r--r--src/server/scripts/Spells/spell_generic.cpp74
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp2
-rw-r--r--src/server/worldserver/worldserver.conf.dist8
7 files changed, 180 insertions, 60 deletions
diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h
index eceb0a8e7de..c1de3aae7cb 100644
--- a/src/server/game/Miscellaneous/Language.h
+++ b/src/server/game/Miscellaneous/Language.h
@@ -1054,7 +1054,7 @@ enum TrinityStrings
LANG_COMMAND_UNFREEZE = 5003,
LANG_COMMAND_NO_FROZEN_PLAYERS = 5004,
LANG_COMMAND_LIST_FREEZE = 5005,
- LANG_COMMAND_FROZEN_PLAYERS = 5006,
+ LANG_COMMAND_PERMA_FROZEN_PLAYER = 5006,
LANG_INSTANCE_RAID_GROUP_ONLY = 5007,
LANG_INSTANCE_CLOSED = 5008,
LANG_COMMAND_PLAYED_TO_ALL = 5009,
@@ -1068,7 +1068,7 @@ enum TrinityStrings
LANG_ARENA = 5016,
LANG_RAID = 5017,
//= 5018,
- //= 5019,
+ LANG_COMMAND_TEMP_FROZEN_PLAYER = 5019,
LANG_NPCINFO_PHASEMASK = 5020,
LANG_NPCINFO_ARMOR = 5021,
LANG_CHANNEL_ENABLE_OWNERSHIP = 5022,
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 5c65055f3c0..58e3cffa8de 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -856,6 +856,7 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_GM_VISIBLE_STATE] = sConfigMgr->GetIntDefault("GM.Visible", 2);
m_int_configs[CONFIG_GM_CHAT] = sConfigMgr->GetIntDefault("GM.Chat", 2);
m_int_configs[CONFIG_GM_WHISPERING_TO] = sConfigMgr->GetIntDefault("GM.WhisperingTo", 2);
+ m_int_configs[CONFIG_GM_FREEZE_DURATION] = sConfigMgr->GetIntDefault("GM.FreezeAuraDuration", 0);
m_int_configs[CONFIG_GM_LEVEL_IN_GM_LIST] = sConfigMgr->GetIntDefault("GM.InGMList.Level", SEC_ADMINISTRATOR);
m_int_configs[CONFIG_GM_LEVEL_IN_WHO_LIST] = sConfigMgr->GetIntDefault("GM.InWhoList.Level", SEC_ADMINISTRATOR);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 05bfcc21462..cc2078bc736 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -227,6 +227,7 @@ enum WorldIntConfigs
CONFIG_GM_ACCEPT_TICKETS,
CONFIG_GM_CHAT,
CONFIG_GM_WHISPERING_TO,
+ CONFIG_GM_FREEZE_DURATION,
CONFIG_GM_LEVEL_IN_GM_LIST,
CONFIG_GM_LEVEL_IN_WHO_LIST,
CONFIG_START_GM_LEVEL,
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 80b7710cd21..3e7b242f3cc 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -2241,69 +2241,100 @@ public:
static bool HandleFreezeCommand(ChatHandler* handler, char const* args)
{
- std::string name;
- Player* player;
- char const* TargetName = strtok((char*)args, " "); // get entered name
- if (!TargetName) // if no name entered use target
- {
- player = handler->getSelectedPlayer();
- if (player) //prevent crash with creature as target
- {
- name = player->GetName();
- normalizePlayerName(name);
- }
- }
- else // if name entered
+ Player* player = handler->getSelectedPlayer(); // Selected player, if any. Might be null.
+ uint32 freezeDuration = 0; // Freeze Duration (in seconds)
+ bool canApplyFreeze = false; // Determines if every possible argument is set so Freeze can be applied
+ bool getDurationFromConfig = false; // If there's no given duration, we'll retrieve the world cfg value later
+
+ /*
+ Possible Freeze Command Scenarios:
+ case 1 - .freeze (without args and a selected player)
+ case 2 - .freeze duration (with a selected player)
+ case 3 - .freeze player duration
+ case 4 - .freeze player (without specifying duration)
+ */
+
+ // case 1: .freeze
+ if (!*args)
{
- name = TargetName;
- normalizePlayerName(name);
- player = sObjectAccessor->FindPlayerByName(name);
+ // Might have a selected player. We'll check it later
+ // Get the duration from world cfg
+ getDurationFromConfig = true;
}
-
- if (!player)
+ else
{
- handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG);
- return true;
+ // Get the args that we might have (up to 2)
+ char const* arg1 = strtok((char*)args, " ");
+ char const* arg2 = strtok(NULL, " ");
+
+ // Analyze them to see if we got either a playerName or duration or both
+ if (arg1)
+ {
+ if (isNumeric(arg1))
+ {
+ // case 2: .freeze duration
+ // We have a selected player. We'll check him later
+ freezeDuration = uint32(atoi(arg1));
+ canApplyFreeze = true;
+ }
+ else
+ {
+ // case 3 or 4: .freeze player duration | .freeze player
+ // find the player
+ std::string name = arg1;
+ normalizePlayerName(name);
+ player = sObjectAccessor->FindPlayerByName(name);
+ // Check if we have duration set
+ if (arg2 && isNumeric(arg2))
+ {
+ freezeDuration = uint32(atoi(arg2));
+ canApplyFreeze = true;
+ }
+ else
+ getDurationFromConfig = true;
+ }
+ }
}
- if (player == handler->GetSession()->GetPlayer())
+ // Check if duration needs to be retrieved from config
+ if (getDurationFromConfig)
{
- handler->SendSysMessage(LANG_COMMAND_FREEZE_ERROR);
- return true;
+ freezeDuration = sWorld->getIntConfig(CONFIG_GM_FREEZE_DURATION);
+ canApplyFreeze = true;
}
- // effect
- if (player && (player != handler->GetSession()->GetPlayer()))
+ // Player and duration retrieval is over
+ if (canApplyFreeze)
{
- handler->PSendSysMessage(LANG_COMMAND_FREEZE, name.c_str());
-
- // stop combat + make player unattackable + duel stop + stop some spells
- player->setFaction(35);
- player->CombatStop();
- if (player->IsNonMeleeSpellCast(true))
- player->InterruptNonMeleeSpells(true);
- player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
-
- // if player class = hunter || warlock remove pet if alive
- if ((player->getClass() == CLASS_HUNTER) || (player->getClass() == CLASS_WARLOCK))
+ if (!player) // can be null if some previous selection failed
+ {
+ handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG);
+ return true;
+ }
+ else if (player == handler->GetSession()->GetPlayer())
+ {
+ // Can't freeze himself
+ handler->SendSysMessage(LANG_COMMAND_FREEZE_ERROR);
+ return true;
+ }
+ else // Apply the effect
{
- if (Pet* pet = player->GetPet())
+ // Add the freeze aura and set the proper duration
+ // Player combat status and flags are now handled
+ // in Freeze Spell AuraScript (OnApply)
+ Aura* freeze = player->AddAura(9454, player);
+ if (freeze)
{
- pet->SavePetToDB(PET_SAVE_AS_CURRENT);
- // not let dismiss dead pet
- if (pet->IsAlive())
- player->RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
+ if (freezeDuration)
+ freeze->SetDuration(freezeDuration * IN_MILLISECONDS);
+ handler->PSendSysMessage(LANG_COMMAND_FREEZE, player->GetName().c_str());
+ // save player
+ player->SaveToDB();
+ return true;
}
}
-
- if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(9454))
- Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, player, player);
-
- // save player
- player->SaveToDB();
}
-
- return true;
+ return false;
}
static bool HandleUnFreezeCommand(ChatHandler* handler, char const*args)
@@ -2329,15 +2360,10 @@ public:
{
handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str());
- // Reset player faction + allow combat + allow duels
- player->setFactionForRace(player->getRace());
- player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
-
// Remove Freeze spell (allowing movement and spells)
+ // Player Flags + Neutral faction removal is now
+ // handled on the Freeze Spell AuraScript (OnRemove)
player->RemoveAurasDueToSpell(9454);
-
- // Save player
- player->SaveToDB();
}
else
{
@@ -2394,7 +2420,17 @@ public:
{
Field* fields = result->Fetch();
std::string player = fields[0].GetString();
- handler->PSendSysMessage(LANG_COMMAND_FROZEN_PLAYERS, player.c_str());
+ int32 remaintime = fields[1].GetInt32();
+ // Save the frozen player to update remaining time in case of future .listfreeze uses
+ // before the frozen state expires
+ if (Player* frozen = sObjectAccessor->FindPlayerByName(player))
+ frozen->SaveToDB();
+ // Notify the freeze duration
+ if (remaintime == -1) // Permanent duration
+ handler->PSendSysMessage(LANG_COMMAND_PERMA_FROZEN_PLAYER, player.c_str());
+ else
+ // show time left (seconds)
+ handler->PSendSysMessage(LANG_COMMAND_TEMP_FROZEN_PLAYER, player.c_str(), remaintime / IN_MILLISECONDS);
}
while (result->NextRow());
diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
index 84e36b55c2c..e198a6a0c61 100644
--- a/src/server/scripts/Spells/spell_generic.cpp
+++ b/src/server/scripts/Spells/spell_generic.cpp
@@ -3609,6 +3609,79 @@ class spell_gen_eject_all_passengers : public SpellScriptLoader
}
};
+enum GMFreeze
+{
+ SPELL_GM_FREEZE = 9454
+};
+
+class spell_gen_gm_freeze : public SpellScriptLoader
+{
+ public:
+ spell_gen_gm_freeze() : SpellScriptLoader("spell_gen_gm_freeze") { }
+
+ class spell_gen_gm_freeze_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_gen_gm_freeze_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_GM_FREEZE))
+ return false;
+ return true;
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ // Do what was done before to the target in HandleFreezeCommand
+ if (Player* player = GetTarget()->ToPlayer())
+ {
+ // stop combat + make player unattackable + duel stop + stop some spells
+ player->setFaction(35);
+ player->CombatStop();
+ if (player->IsNonMeleeSpellCast(true))
+ player->InterruptNonMeleeSpells(true);
+ player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+
+ // if player class = hunter || warlock remove pet if alive
+ if ((player->getClass() == CLASS_HUNTER) || (player->getClass() == CLASS_WARLOCK))
+ {
+ if (Pet* pet = player->GetPet())
+ {
+ pet->SavePetToDB(PET_SAVE_AS_CURRENT);
+ // not let dismiss dead pet
+ if (pet->IsAlive())
+ player->RemovePet(pet, PET_SAVE_NOT_IN_SLOT);
+ }
+ }
+ }
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ // Do what was done before to the target in HandleUnfreezeCommand
+ if (Player* player = GetTarget()->ToPlayer())
+ {
+ // Reset player faction + allow combat + allow duels
+ player->setFactionForRace(player->getRace());
+ player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ // save player
+ player->SaveToDB();
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_gen_gm_freeze_AuraScript::OnApply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_gen_gm_freeze_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_gen_gm_freeze_AuraScript();
+ }
+};
+
void AddSC_generic_spell_scripts()
{
new spell_gen_absorb0_hitlimit1();
@@ -3689,4 +3762,5 @@ void AddSC_generic_spell_scripts()
new spell_gen_wg_water();
new spell_gen_whisper_gulch_yogg_saron_whisper();
new spell_gen_eject_all_passengers();
+ new spell_gen_gm_freeze();
}
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 0669d0b84f9..aa584d026fb 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -417,7 +417,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CHARACTER_SOCIAL, "DELETE FROM character_social WHERE guid = ? AND friend = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHARACTER_SOCIAL_NOTE, "UPDATE character_social SET note = ? WHERE guid = ? AND friend = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHARACTER_POSITION, "UPDATE characters SET position_x = ?, position_y = ?, position_z = ?, orientation = ?, map = ?, zone = ?, trans_x = 0, trans_y = 0, trans_z = 0, transguid = 0, taxi_path = '' WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_CHARACTER_AURA_FROZEN, "SELECT characters.name, character_aura.remaintime FROM characters LEFT JOIN character_aura ON (characters.guid = character_aura.guid) WHERE character_aura.spell = 9454", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHARACTER_ONLINE, "SELECT name, account, map, zone FROM characters WHERE online > 0", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_GUID, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_DEL_INFO_BY_NAME, "SELECT guid, deleteInfos_Name, deleteInfos_Account, deleteDate FROM characters WHERE deleteDate IS NOT NULL AND deleteInfos_Name LIKE CONCAT('%%', ?, '%%')", CONNECTION_SYNCH);
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
index b49f9ebd9ec..3fec13684da 100644
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -1548,6 +1548,14 @@ GM.Chat = 2
GM.WhisperingTo = 2
#
+# GM.FreezeAuraDuration
+# Description: Allows to set a default duration to the Freeze Aura
+# applied on players when using the .freeze command
+# Default: 0 - (Original aura duration. Lasts until the .unfreeze command is used)
+# N - (Aura duration if unspecified in .freeze command, in seconds)
+GM.FreezeAuraDuration = 0
+
+#
# GM.InGMList.Level
# Description: Maximum GM level shown in GM list (if enabled) in non-GM state (.gm off).
# Default: 3 - (Anyone)