Ported .Net Core commits:
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Movement;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class AISelector
|
||||
{
|
||||
public static CreatureAI SelectAI(Creature creature)
|
||||
{
|
||||
if (creature.IsPet())
|
||||
return new PetAI(creature);
|
||||
|
||||
//scriptname in db
|
||||
CreatureAI scriptedAI = Global.ScriptMgr.GetCreatureAI(creature);
|
||||
if (scriptedAI != null)
|
||||
return scriptedAI;
|
||||
|
||||
switch (creature.GetCreatureTemplate().AIName)
|
||||
{
|
||||
case "AggressorAI":
|
||||
return new AggressorAI(creature);
|
||||
case "ArcherAI":
|
||||
return new ArcherAI(creature);
|
||||
case "CombatAI":
|
||||
return new CombatAI(creature);
|
||||
case "CritterAI":
|
||||
return new CritterAI(creature);
|
||||
case "GuardAI":
|
||||
return new GuardAI(creature);
|
||||
case "NullCreatureAI":
|
||||
return new NullCreatureAI(creature);
|
||||
case "PassiveAI":
|
||||
return new PassiveAI(creature);
|
||||
case "PetAI":
|
||||
return new PetAI(creature);
|
||||
case "ReactorAI":
|
||||
return new ReactorAI(creature);
|
||||
case "SmartAI":
|
||||
return new SmartAI(creature);
|
||||
case "TotemAI":
|
||||
return new TotemAI(creature);
|
||||
case "TriggerAI":
|
||||
return new TriggerAI(creature);
|
||||
case "TurretAI":
|
||||
return new TurretAI(creature);
|
||||
case "VehicleAI":
|
||||
return new VehicleAI(creature);
|
||||
}
|
||||
|
||||
// select by NPC flags
|
||||
if (creature.IsVehicle())
|
||||
return new VehicleAI(creature);
|
||||
else if (creature.HasUnitTypeMask(UnitTypeMask.ControlableGuardian) && ((Guardian)creature).GetOwner().IsTypeId(TypeId.Player))
|
||||
return new PetAI(creature);
|
||||
else if (creature.HasFlag64(UnitFields.NpcFlags, NPCFlags.SpellClick))
|
||||
return new NullCreatureAI(creature);
|
||||
else if (creature.IsGuard())
|
||||
return new GuardAI(creature);
|
||||
else if (creature.HasUnitTypeMask(UnitTypeMask.ControlableGuardian))
|
||||
return new PetAI(creature);
|
||||
else if (creature.IsTotem())
|
||||
return new TotemAI(creature);
|
||||
else if (creature.IsTrigger())
|
||||
{
|
||||
if (creature.m_spells[0] != 0)
|
||||
return new TriggerAI(creature);
|
||||
else
|
||||
return new NullCreatureAI(creature);
|
||||
}
|
||||
else if (creature.IsCritter() && !creature.HasUnitTypeMask(UnitTypeMask.Guardian))
|
||||
return new CritterAI(creature);
|
||||
|
||||
if (!creature.IsCivilian() && !creature.IsNeutralToAll())
|
||||
return new AggressorAI(creature);
|
||||
|
||||
if (creature.IsCivilian() || creature.IsNeutralToAll())
|
||||
return new ReactorAI(creature);
|
||||
|
||||
return new NullCreatureAI(creature);
|
||||
}
|
||||
|
||||
public static IMovementGenerator SelectMovementAI(Creature creature)
|
||||
{
|
||||
switch (creature.m_defaultMovementType)
|
||||
{
|
||||
case MovementGeneratorType.Random:
|
||||
return new RandomMovementGenerator<Creature>();
|
||||
case MovementGeneratorType.Waypoint:
|
||||
return new WaypointMovementGenerator<Creature>();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static GameObjectAI SelectGameObjectAI(GameObject go)
|
||||
{
|
||||
// scriptname in db
|
||||
GameObjectAI scriptedAI = Global.ScriptMgr.GetGameObjectAI(go);
|
||||
if (scriptedAI != null)
|
||||
return scriptedAI;
|
||||
|
||||
switch (go.GetAIName())
|
||||
{
|
||||
case "GameObjectAI":
|
||||
return new GameObjectAI(go);
|
||||
case "SmartGameObjectAI":
|
||||
return new SmartGameObjectAI(go);
|
||||
}
|
||||
return new NullGameObjectAI(go);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Game.Entities;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class AreaTriggerAI
|
||||
{
|
||||
public AreaTriggerAI(AreaTrigger a)
|
||||
{
|
||||
at = a;
|
||||
}
|
||||
|
||||
// Called when the AreaTrigger has just been initialized, just before added to map
|
||||
public virtual void OnInitialize() { }
|
||||
|
||||
// Called when the AreaTrigger has just been created
|
||||
public virtual void OnCreate() { }
|
||||
|
||||
// Called on each AreaTrigger update
|
||||
public virtual void OnUpdate(uint diff) { }
|
||||
|
||||
// Called when the AreaTrigger reach splineIndex
|
||||
public virtual void OnSplineIndexReached(int splineIndex) { }
|
||||
|
||||
// Called when the AreaTrigger reach its destination
|
||||
public virtual void OnDestinationReached() { }
|
||||
|
||||
// Called when an unit enter the AreaTrigger
|
||||
public virtual void OnUnitEnter(Unit unit) { }
|
||||
|
||||
// Called when an unit exit the AreaTrigger, or when the AreaTrigger is removed
|
||||
public virtual void OnUnitExit(Unit unit) { }
|
||||
|
||||
// Called when the AreaTrigger is removed
|
||||
public virtual void OnRemove() { }
|
||||
|
||||
protected AreaTrigger at;
|
||||
}
|
||||
|
||||
class NullAreaTriggerAI : AreaTriggerAI
|
||||
{
|
||||
public NullAreaTriggerAI(AreaTrigger areaTrigger) : base(areaTrigger) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class CombatAI : CreatureAI
|
||||
{
|
||||
public CombatAI(Creature c) : base(c) { }
|
||||
|
||||
public override void InitializeAI()
|
||||
{
|
||||
for (var i = 0; i < SharedConst.MaxCreatureSpells; ++i)
|
||||
if (me.m_spells[i] != 0 && Global.SpellMgr.GetSpellInfo(me.m_spells[i]) != null)
|
||||
spells.Add(me.m_spells[i]);
|
||||
|
||||
base.InitializeAI();
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
_events.Reset();
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
foreach (var id in spells)
|
||||
if (AISpellInfo[id].condition == AICondition.Die)
|
||||
me.CastSpell(killer, id, true);
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit victim)
|
||||
{
|
||||
foreach (var id in spells)
|
||||
{
|
||||
if (AISpellInfo[id].condition == AICondition.Aggro)
|
||||
me.CastSpell(victim, id, false);
|
||||
else if (AISpellInfo[id].condition == AICondition.Combat)
|
||||
_events.ScheduleEvent(id, AISpellInfo[id].cooldown + RandomHelper.Rand32() % AISpellInfo[id].cooldown);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
uint spellId = _events.ExecuteEvent();
|
||||
if (spellId != 0)
|
||||
{
|
||||
DoCast(spellId);
|
||||
_events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + RandomHelper.Rand32() % AISpellInfo[spellId].cooldown);
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
public override void SpellInterrupted(uint spellId, uint unTimeMs)
|
||||
{
|
||||
_events.RescheduleEvent(spellId, unTimeMs);
|
||||
}
|
||||
|
||||
public List<uint> spells = new List<uint>();
|
||||
}
|
||||
|
||||
public class AggressorAI : CreatureAI
|
||||
{
|
||||
public AggressorAI(Creature c) : base(c) { }
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
public class CasterAI : CombatAI
|
||||
{
|
||||
public CasterAI(Creature c)
|
||||
: base(c)
|
||||
{
|
||||
m_attackDist = SharedConst.MeleeRange;
|
||||
}
|
||||
|
||||
public override void InitializeAI()
|
||||
{
|
||||
base.InitializeAI();
|
||||
|
||||
m_attackDist = 30.0f;
|
||||
foreach (var id in spells)
|
||||
if (AISpellInfo[id].condition == AICondition.Combat && m_attackDist > AISpellInfo[id].maxRange)
|
||||
m_attackDist = AISpellInfo[id].maxRange;
|
||||
if (m_attackDist == 30.0f)
|
||||
m_attackDist = SharedConst.MeleeRange;
|
||||
}
|
||||
|
||||
public override void AttackStart(Unit victim)
|
||||
{
|
||||
AttackStartCaster(victim, m_attackDist);
|
||||
}
|
||||
|
||||
public override void EnterCombat(Unit victim)
|
||||
{
|
||||
if (spells.Empty())
|
||||
return;
|
||||
|
||||
int spell = (int)(RandomHelper.Rand32() % spells.Count);
|
||||
uint count = 0;
|
||||
foreach (var id in spells)
|
||||
{
|
||||
|
||||
if (AISpellInfo[id].condition == AICondition.Aggro)
|
||||
me.CastSpell(victim, id, false);
|
||||
else if (AISpellInfo[id].condition == AICondition.Combat)
|
||||
{
|
||||
uint cooldown = AISpellInfo[id].realCooldown;
|
||||
if (count == spell)
|
||||
{
|
||||
DoCast(spells[spell]);
|
||||
cooldown += (uint)me.GetCurrentSpellCastTime(id);
|
||||
}
|
||||
_events.ScheduleEvent(id, cooldown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
if (me.GetVictim().HasBreakableByDamageCrowdControlAura(me))
|
||||
{
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
uint spellId = _events.ExecuteEvent();
|
||||
if (spellId != 0)
|
||||
{
|
||||
DoCast(spellId);
|
||||
uint casttime = (uint)me.GetCurrentSpellCastTime(spellId);
|
||||
_events.ScheduleEvent(spellId, (casttime != 0 ? casttime : 500) + AISpellInfo[spellId].realCooldown);
|
||||
}
|
||||
}
|
||||
|
||||
float m_attackDist;
|
||||
}
|
||||
|
||||
public class ArcherAI : CreatureAI
|
||||
{
|
||||
public ArcherAI(Creature c)
|
||||
: base(c)
|
||||
{
|
||||
if (me.m_spells[0] == 0)
|
||||
Log.outError(LogFilter.ScriptsAi, "ArcherAI set for creature (entry = {0}) with spell1=0. AI will do nothing", me.GetEntry());
|
||||
|
||||
var spellInfo = Global.SpellMgr.GetSpellInfo(me.m_spells[0]);
|
||||
m_minRange = spellInfo != null ? spellInfo.GetMinRange(false) : 0;
|
||||
|
||||
if (m_minRange == 0)
|
||||
m_minRange = SharedConst.MeleeRange;
|
||||
me.m_CombatDistance = spellInfo != null ? spellInfo.GetMaxRange(false) : 0;
|
||||
me.m_SightDistance = me.m_CombatDistance;
|
||||
}
|
||||
|
||||
public override void AttackStart(Unit who)
|
||||
{
|
||||
if (who == null)
|
||||
return;
|
||||
|
||||
if (me.IsWithinCombatRange(who, m_minRange))
|
||||
{
|
||||
if (me.Attack(who, true) && !who.IsFlying())
|
||||
me.GetMotionMaster().MoveChase(who);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me.Attack(who, false) && !who.IsFlying())
|
||||
me.GetMotionMaster().MoveChase(who, me.m_CombatDistance);
|
||||
}
|
||||
|
||||
if (who.IsFlying())
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
}
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (!me.IsWithinCombatRange(me.GetVictim(), m_minRange))
|
||||
DoSpellAttackIfReady(me.m_spells[0]);
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
float m_minRange;
|
||||
}
|
||||
|
||||
public class TurretAI : CreatureAI
|
||||
{
|
||||
public TurretAI(Creature c)
|
||||
: base(c)
|
||||
{
|
||||
if (me.m_spells[0] == 0)
|
||||
Log.outError(LogFilter.Server, "TurretAI set for creature (entry = {0}) with spell1=0. AI will do nothing", me.GetEntry());
|
||||
|
||||
var spellInfo = Global.SpellMgr.GetSpellInfo(me.m_spells[0]);
|
||||
m_minRange = spellInfo != null ? spellInfo.GetMinRange(false) : 0;
|
||||
me.m_CombatDistance = spellInfo != null ? spellInfo.GetMaxRange(false) : 0;
|
||||
me.m_SightDistance = me.m_CombatDistance;
|
||||
}
|
||||
public override bool CanAIAttack(Unit victim)
|
||||
{
|
||||
/// todo use one function to replace it
|
||||
if (!me.IsWithinCombatRange(me.GetVictim(), me.m_CombatDistance)
|
||||
|| (m_minRange != 0 && me.IsWithinCombatRange(me.GetVictim(), m_minRange)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public override void AttackStart(Unit victim)
|
||||
{
|
||||
if (victim != null)
|
||||
me.Attack(victim, false);
|
||||
}
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoSpellAttackIfReady(me.m_spells[0]);
|
||||
}
|
||||
|
||||
float m_minRange;
|
||||
}
|
||||
|
||||
public class VehicleAI : CreatureAI
|
||||
{
|
||||
const int VEHICLE_CONDITION_CHECK_TIME = 1000;
|
||||
const int VEHICLE_DISMISS_TIME = 5000;
|
||||
|
||||
public VehicleAI(Creature creature) : base(creature)
|
||||
{
|
||||
m_ConditionsTimer = VEHICLE_CONDITION_CHECK_TIME;
|
||||
LoadConditions();
|
||||
m_DoDismiss = false;
|
||||
m_DismissTimer = VEHICLE_DISMISS_TIME;
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
CheckConditions(diff);
|
||||
|
||||
if (m_DoDismiss)
|
||||
{
|
||||
if (m_DismissTimer < diff)
|
||||
{
|
||||
m_DoDismiss = false;
|
||||
me.DespawnOrUnsummon();
|
||||
}
|
||||
else
|
||||
m_DismissTimer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnCharmed(bool apply)
|
||||
{
|
||||
if (!me.GetVehicleKit().IsVehicleInUse() && !apply && m_HasConditions)//was used and has conditions
|
||||
m_DoDismiss = true;//needs reset
|
||||
else if (apply)
|
||||
m_DoDismiss = false;//in use again
|
||||
|
||||
m_DismissTimer = VEHICLE_DISMISS_TIME;//reset timer
|
||||
}
|
||||
|
||||
void LoadConditions()
|
||||
{
|
||||
m_HasConditions = Global.ConditionMgr.HasConditionsForNotGroupedEntry(ConditionSourceType.CreatureTemplateVehicle, me.GetEntry());
|
||||
}
|
||||
|
||||
void CheckConditions(uint diff)
|
||||
{
|
||||
if (m_ConditionsTimer < diff)
|
||||
{
|
||||
if (m_HasConditions)
|
||||
{
|
||||
Vehicle vehicleKit = me.GetVehicleKit();
|
||||
if (vehicleKit)
|
||||
{
|
||||
foreach (var pair in vehicleKit.Seats)
|
||||
{
|
||||
Unit passenger = Global.ObjAccessor.GetUnit(me, pair.Value.Passenger.Guid);
|
||||
if (passenger)
|
||||
{
|
||||
Player player = passenger.ToPlayer();
|
||||
if (player)
|
||||
{
|
||||
if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.CreatureTemplateVehicle, me.GetEntry(), player, me))
|
||||
{
|
||||
player.ExitVehicle();
|
||||
return;//check other pessanger in next tick
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ConditionsTimer = VEHICLE_CONDITION_CHECK_TIME;
|
||||
}
|
||||
else
|
||||
m_ConditionsTimer -= diff;
|
||||
}
|
||||
|
||||
bool m_HasConditions;
|
||||
uint m_ConditionsTimer;
|
||||
bool m_DoDismiss;
|
||||
uint m_DismissTimer;
|
||||
}
|
||||
|
||||
public class ReactorAI : CreatureAI
|
||||
{
|
||||
public ReactorAI(Creature c) : base(c) { }
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Dynamic;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using Game.Spells;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class CreatureAI : UnitAI
|
||||
{
|
||||
public CreatureAI(Creature _creature) : base(_creature)
|
||||
{
|
||||
me = _creature;
|
||||
MoveInLineOfSight_locked = false;
|
||||
}
|
||||
|
||||
public override void OnCharmed(bool apply)
|
||||
{
|
||||
if (apply)
|
||||
{
|
||||
me.NeedChangeAI = true;
|
||||
me.IsAIEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Talk(uint id, WorldObject whisperTarget = null)
|
||||
{
|
||||
Global.CreatureTextMgr.SendChat(me, (byte)id, whisperTarget);
|
||||
}
|
||||
|
||||
public void DoZoneInCombat(Creature creature = null, float maxRangeToNearestTarget = 250.0f)
|
||||
{
|
||||
if (!creature)
|
||||
creature = me;
|
||||
|
||||
if (!creature.CanHaveThreatList())
|
||||
return;
|
||||
|
||||
Map map = creature.GetMap();
|
||||
if (!map.IsDungeon()) //use IsDungeon instead of Instanceable, in case Battlegrounds will be instantiated
|
||||
{
|
||||
Log.outError(LogFilter.Server, "DoZoneInCombat call for map that isn't an instance (creature entry = {0})", creature.IsTypeId(TypeId.Unit) ? creature.ToCreature().GetEntry() : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!creature.HasReactState(ReactStates.Passive) && creature.GetVictim() == null)
|
||||
{
|
||||
Unit nearTarget = creature.SelectNearestTarget(maxRangeToNearestTarget);
|
||||
if (nearTarget != null)
|
||||
creature.GetAI().AttackStart(nearTarget);
|
||||
else if (creature.IsSummon())
|
||||
{
|
||||
Unit summoner = creature.ToTempSummon().GetSummoner();
|
||||
if (summoner != null)
|
||||
{
|
||||
Unit target = summoner.getAttackerForHelper();
|
||||
if (target == null && summoner.CanHaveThreatList() && !summoner.GetThreatManager().isThreatListEmpty())
|
||||
target = summoner.GetThreatManager().getHostilTarget();
|
||||
if (target != null && (creature.IsFriendlyTo(summoner) || creature.IsHostileTo(target)))
|
||||
creature.GetAI().AttackStart(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Intended duplicated check, the code above this should select a victim
|
||||
// If it can't find a suitable attack target then we should error out.
|
||||
if (!creature.HasReactState(ReactStates.Passive) && creature.GetVictim() == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "DoZoneInCombat called for creature that has empty threat list (creature entry = {0})", creature.GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
var playerList = map.GetPlayers();
|
||||
if (playerList.Empty())
|
||||
return;
|
||||
|
||||
foreach (var player in playerList)
|
||||
{
|
||||
if (player.IsGameMaster())
|
||||
continue;
|
||||
|
||||
if (player.IsAlive())
|
||||
{
|
||||
creature.SetInCombatWith(player);
|
||||
player.SetInCombatWith(creature);
|
||||
creature.AddThreat(player, 0.0f);
|
||||
}
|
||||
|
||||
/* Causes certain things to never leave the threat list (Priest Lightwell, etc):
|
||||
foreach (var unit in player.m_Controlled)
|
||||
{
|
||||
me.SetInCombatWith(unit);
|
||||
unit.SetInCombatWith(me);
|
||||
me.AddThreat(unit, 0.0f);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void MoveInLineOfSight_Safe(Unit who)
|
||||
{
|
||||
if (MoveInLineOfSight_locked)
|
||||
return;
|
||||
MoveInLineOfSight_locked = true;
|
||||
MoveInLineOfSight(who);
|
||||
MoveInLineOfSight_locked = false;
|
||||
}
|
||||
|
||||
public virtual void MoveInLineOfSight(Unit who)
|
||||
{
|
||||
if (me.GetVictim() != null)
|
||||
return;
|
||||
|
||||
if (me.GetCreatureType() == CreatureType.NonCombatPet)
|
||||
return;
|
||||
|
||||
if (me.HasReactState(ReactStates.Aggressive) && me.CanStartAttack(who, false))
|
||||
AttackStart(who);
|
||||
}
|
||||
|
||||
// Distract creature, if player gets too close while stealthed/prowling
|
||||
public void TriggerAlert(Unit who)
|
||||
{
|
||||
// If there's no target, or target isn't a player do nothing
|
||||
if (!who || !who.IsTypeId(TypeId.Player))
|
||||
return;
|
||||
|
||||
// If this unit isn't an NPC, is already distracted, is in combat, is confused, stunned or fleeing, do nothing
|
||||
if (!me.IsTypeId(TypeId.Unit) || me.IsInCombat() || me.HasUnitState(UnitState.Confused | UnitState.Stunned | UnitState.Fleeing | UnitState.Distracted))
|
||||
return;
|
||||
|
||||
// Only alert for hostiles!
|
||||
if (me.IsCivilian() || me.HasReactState(ReactStates.Passive) || !me.IsHostileTo(who) || !me._IsTargetAcceptable(who))
|
||||
return;
|
||||
|
||||
// Send alert sound (if any) for this creature
|
||||
me.SendAIReaction(AiReaction.Alert);
|
||||
|
||||
// Face the unit (stealthed player) and set distracted state for 5 seconds
|
||||
me.SetFacingTo(me.GetAngle(who.GetPositionX(), who.GetPositionY()), true);
|
||||
me.StopMoving();
|
||||
me.GetMotionMaster().MoveDistract(5 * Time.InMilliseconds);
|
||||
}
|
||||
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
public virtual void EnterEvadeMode(EvadeReason why = EvadeReason.Other)
|
||||
{
|
||||
if (!_EnterEvadeMode(why))
|
||||
return;
|
||||
|
||||
Log.outDebug( LogFilter.Unit, "Creature {0} enters evade mode.", me.GetEntry());
|
||||
|
||||
if (me.GetVehicle() == null) // otherwise me will be in evade mode forever
|
||||
{
|
||||
Unit owner = me.GetCharmerOrOwner();
|
||||
if (owner != null)
|
||||
{
|
||||
me.GetMotionMaster().Clear(false);
|
||||
me.GetMotionMaster().MoveFollow(owner, SharedConst.PetFollowDist, me.GetFollowAngle(), MovementSlot.Active);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Required to prevent attacking creatures that are evading and cause them to reenter combat
|
||||
// Does not apply to MoveFollow
|
||||
me.AddUnitState(UnitState.Evade);
|
||||
me.GetMotionMaster().MoveTargetedHome();
|
||||
}
|
||||
}
|
||||
|
||||
Reset();
|
||||
|
||||
if (me.IsVehicle()) // use the same sequence of addtoworld, aireset may remove all summons!
|
||||
me.GetVehicleKit().Reset(true);
|
||||
}
|
||||
|
||||
void SetGazeOn(Unit target)
|
||||
{
|
||||
if (me.IsValidAttackTarget(target))
|
||||
{
|
||||
if (!me.IsFocusing(null, true))
|
||||
AttackStart(target);
|
||||
me.SetReactState(ReactStates.Passive);
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateVictimWithGaze()
|
||||
{
|
||||
if (!me.IsInCombat())
|
||||
return false;
|
||||
|
||||
if (me.HasReactState(ReactStates.Passive))
|
||||
{
|
||||
if (me.GetVictim() != null)
|
||||
return true;
|
||||
else
|
||||
me.SetReactState(ReactStates.Aggressive);
|
||||
}
|
||||
|
||||
Unit victim = me.SelectVictim();
|
||||
if (victim != null)
|
||||
{
|
||||
if (!me.IsFocusing(null, true))
|
||||
AttackStart(victim);
|
||||
}
|
||||
|
||||
return me.GetVictim() != null;
|
||||
}
|
||||
|
||||
public bool UpdateVictim()
|
||||
{
|
||||
if (!me.IsInCombat())
|
||||
return false;
|
||||
|
||||
if (!me.HasReactState(ReactStates.Passive))
|
||||
{
|
||||
Unit victim = me.SelectVictim();
|
||||
if (victim != null)
|
||||
if (!me.IsFocusing(null, true))
|
||||
AttackStart(victim);
|
||||
|
||||
return me.GetVictim() != null;
|
||||
}
|
||||
else if (me.GetThreatManager().isThreatListEmpty())
|
||||
{
|
||||
EnterEvadeMode(EvadeReason.NoHostiles);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool _EnterEvadeMode(EvadeReason why = EvadeReason.Other)
|
||||
{
|
||||
if (!me.IsAlive())
|
||||
return false;
|
||||
|
||||
me.RemoveAurasOnEvade();
|
||||
|
||||
// sometimes bosses stuck in combat?
|
||||
me.DeleteThreatList();
|
||||
me.CombatStop(true);
|
||||
me.SetLootRecipient(null);
|
||||
me.ResetPlayerDamageReq();
|
||||
me.SetLastDamagedTime(0);
|
||||
me.SetCannotReachTarget(false);
|
||||
|
||||
if (me.IsInEvadeMode())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public CypherStrings VisualizeBoundary(int duration, Unit owner = null, bool fill = false)
|
||||
{
|
||||
if (!owner)
|
||||
return 0;
|
||||
|
||||
if (_boundary.Empty())
|
||||
return CypherStrings.CreatureMovementNotBounded;
|
||||
|
||||
List<KeyValuePair<int, int>> Q = new List<KeyValuePair<int, int>>();
|
||||
List<KeyValuePair<int, int>> alreadyChecked = new List<KeyValuePair<int, int>>();
|
||||
List<KeyValuePair<int, int>> outOfBounds = new List<KeyValuePair<int, int>>();
|
||||
|
||||
Position startPosition = owner.GetPosition();
|
||||
if (!CheckBoundary(startPosition)) // fall back to creature position
|
||||
{
|
||||
startPosition = me.GetPosition();
|
||||
if (!CheckBoundary(startPosition))
|
||||
{
|
||||
startPosition = me.GetHomePosition();
|
||||
if (!CheckBoundary(startPosition)) // fall back to creature home position
|
||||
return CypherStrings.CreatureNoInteriorPointFound;
|
||||
}
|
||||
}
|
||||
float spawnZ = startPosition.GetPositionZ() + SharedConst.BoundaryVisualizeSpawnHeight;
|
||||
|
||||
bool boundsWarning = false;
|
||||
Q.Add(new KeyValuePair<int, int>(0, 0));
|
||||
while (!Q.Empty())
|
||||
{
|
||||
var front = Q.First();
|
||||
bool hasOutOfBoundsNeighbor = false;
|
||||
foreach (var off in new List<KeyValuePair<int, int>>() { new KeyValuePair<int, int>(1, 0), new KeyValuePair<int, int>(0, 1), new KeyValuePair<int, int>(-1, 0), new KeyValuePair<int, int>(0, -1) })
|
||||
{
|
||||
var next = new KeyValuePair<int, int>(front.Key + off.Key, front.Value + off.Value);
|
||||
if (next.Key > SharedConst.BoundaryVisualizeFailsafeLimit || next.Key < -SharedConst.BoundaryVisualizeFailsafeLimit || next.Value > SharedConst.BoundaryVisualizeFailsafeLimit || next.Value < -SharedConst.BoundaryVisualizeFailsafeLimit)
|
||||
{
|
||||
boundsWarning = true;
|
||||
continue;
|
||||
}
|
||||
if (!alreadyChecked.Contains(next)) // never check a coordinate twice
|
||||
{
|
||||
Position nextPos = new Position(startPosition.GetPositionX() + next.Key * SharedConst.BoundaryVisualizeStepSize, startPosition.GetPositionY() + next.Value * SharedConst.BoundaryVisualizeStepSize, startPosition.GetPositionZ());
|
||||
if (CheckBoundary(nextPos))
|
||||
Q.Add(next);
|
||||
else
|
||||
{
|
||||
outOfBounds.Add(next);
|
||||
hasOutOfBoundsNeighbor = true;
|
||||
}
|
||||
alreadyChecked.Add(next);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (outOfBounds.Contains(next))
|
||||
hasOutOfBoundsNeighbor = true;
|
||||
}
|
||||
}
|
||||
if (fill || hasOutOfBoundsNeighbor)
|
||||
{
|
||||
var pos = new Position(startPosition.GetPositionX() + front.Key * SharedConst.BoundaryVisualizeStepSize, startPosition.GetPositionY() + front.Value * SharedConst.BoundaryVisualizeStepSize, spawnZ);
|
||||
TempSummon point = owner.SummonCreature(SharedConst.BoundaryVisualizeCreature, pos, TempSummonType.TimedDespawn, (uint)(duration * Time.InMilliseconds));
|
||||
if (point)
|
||||
{
|
||||
point.SetObjectScale(SharedConst.BoundaryVisualizeCreatureScale);
|
||||
point.SetFlag(UnitFields.Flags, UnitFlags.ImmuneToPc | UnitFlags.Stunned | UnitFlags.ImmuneToNpc);
|
||||
if (!hasOutOfBoundsNeighbor)
|
||||
point.SetFlag(UnitFields.Flags, UnitFlags.NotSelectable);
|
||||
}
|
||||
Q.Remove(front);
|
||||
}
|
||||
}
|
||||
return boundsWarning ? CypherStrings.CreatureMovementMaybeUnbounded : 0;
|
||||
}
|
||||
|
||||
public bool CheckBoundary(Position who = null)
|
||||
{
|
||||
if (who == null)
|
||||
who = me;
|
||||
|
||||
foreach (var boundary in _boundary)
|
||||
if (!boundary.IsWithinBoundary(who))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CheckInRoom()
|
||||
{
|
||||
if (CheckBoundary())
|
||||
return true;
|
||||
else
|
||||
{
|
||||
EnterEvadeMode(EvadeReason.Boundary);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Creature DoSummon(uint entry, Position pos, uint despawnTime = 30000, TempSummonType summonType = TempSummonType.CorpseTimedDespawn)
|
||||
{
|
||||
return me.SummonCreature(entry, pos, summonType, despawnTime);
|
||||
}
|
||||
|
||||
public Creature DoSummon(uint entry, WorldObject obj, float radius = 5.0f, uint despawnTime = 30000, TempSummonType summonType = TempSummonType.CorpseTimedDespawn)
|
||||
{
|
||||
Position pos = obj.GetRandomNearPosition(radius);
|
||||
return me.SummonCreature(entry, pos, summonType, despawnTime);
|
||||
}
|
||||
|
||||
public Creature DoSummonFlyer(uint entry, WorldObject obj, float flightZ, float radius = 5.0f, uint despawnTime = 30000, TempSummonType summonType = TempSummonType.CorpseTimedDespawn)
|
||||
{
|
||||
Position pos = obj.GetRandomNearPosition(radius);
|
||||
pos.posZ += flightZ;
|
||||
return me.SummonCreature(entry, pos, summonType, despawnTime);
|
||||
}
|
||||
|
||||
public void SetBoundary(List<AreaBoundary> boundary)
|
||||
{
|
||||
_boundary = boundary;
|
||||
me.DoImmediateBoundaryCheck();
|
||||
}
|
||||
|
||||
// Called for reaction at enter to combat if not in combat yet (enemy can be NULL)
|
||||
public virtual void EnterCombat(Unit victim) { }
|
||||
|
||||
// Called when the creature is killed
|
||||
public virtual void JustDied(Unit killer) { }
|
||||
|
||||
// Called when the creature kills a unit
|
||||
public virtual void KilledUnit(Unit victim) {}
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
public virtual void JustSummoned(Creature summon) { }
|
||||
public virtual void IsSummonedBy(Unit summoner) { }
|
||||
|
||||
public virtual void SummonedCreatureDespawn(Creature summon) { }
|
||||
public virtual void SummonedCreatureDies(Creature summon, Unit killer) { }
|
||||
|
||||
// Called when the creature successfully summons a gameobject
|
||||
public virtual void JustSummonedGameobject(GameObject gameobject) { }
|
||||
public virtual void SummonedGameobjectDespawn(GameObject gameobject) { }
|
||||
|
||||
// Called when the creature successfully registers a dynamicobject
|
||||
public virtual void JustRegisteredDynObject(DynamicObject dynObject) { }
|
||||
public virtual void JustUnregisteredDynObject(DynamicObject dynObject) { }
|
||||
|
||||
// Called when the creature successfully registers an areatrigger
|
||||
public virtual void JustRegisteredAreaTrigger(AreaTrigger areaTrigger) { }
|
||||
public virtual void JustUnregisteredAreaTrigger(AreaTrigger areaTrigger) { }
|
||||
|
||||
// Called when hit by a spell
|
||||
public virtual void SpellHit(Unit caster, SpellInfo spell) {}
|
||||
|
||||
// Called when spell hits a target
|
||||
public virtual void SpellHitTarget(Unit target, SpellInfo spell) {}
|
||||
|
||||
// Called when the creature is target of hostile action: swing, hostile spell landed, fear/etc)
|
||||
public virtual void AttackedBy(Unit attacker) { }
|
||||
public virtual bool IsEscorted() { return false; }
|
||||
|
||||
// Called when creature is spawned or respawned
|
||||
public virtual void JustRespawned() { }
|
||||
|
||||
public virtual void MovementInform(MovementGeneratorType type, uint id) { }
|
||||
|
||||
// Called when a spell cast gets interrupted
|
||||
public virtual void OnSpellCastInterrupt(SpellInfo spell) { }
|
||||
|
||||
// Called at reaching home after evade
|
||||
public virtual void JustReachedHome() { }
|
||||
|
||||
// Called at text emote receive from player
|
||||
public virtual void ReceiveEmote(Player player, TextEmotes emoteId) { }
|
||||
|
||||
// Called when owner takes damage
|
||||
public virtual void OwnerAttackedBy(Unit attacker) {}
|
||||
|
||||
// Called when owner attacks something
|
||||
public virtual void OwnerAttacked(Unit target) {}
|
||||
|
||||
// called when the corpse of this creature gets removed
|
||||
public virtual void CorpseRemoved(long respawnDelay) {}
|
||||
|
||||
public virtual void PassengerBoarded(Unit passenger, sbyte seatId, bool apply) { }
|
||||
|
||||
public virtual void OnSpellClick(Unit clicker, ref bool result) { }
|
||||
|
||||
public virtual bool CanSeeAlways(WorldObject obj) { return false; }
|
||||
|
||||
// Called when a player is charmed by the creature
|
||||
// If a PlayerAI* is returned, that AI is placed on the player instead of the default charm AI
|
||||
// Object destruction is handled by Unit::RemoveCharmedBy
|
||||
public virtual PlayerAI GetAIForCharmedPlayer(Player who) { return null; }
|
||||
|
||||
List<AreaBoundary> GetBoundary() { return _boundary; }
|
||||
|
||||
bool MoveInLineOfSight_locked;
|
||||
protected new Creature me;
|
||||
List<AreaBoundary> _boundary = new List<AreaBoundary>();
|
||||
|
||||
protected EventMap _events = new EventMap();
|
||||
protected TaskScheduler _scheduler = new TaskScheduler();
|
||||
}
|
||||
|
||||
public struct AISpellInfoType
|
||||
{
|
||||
public AITarget target;
|
||||
public AICondition condition;
|
||||
public uint cooldown;
|
||||
public uint realCooldown;
|
||||
public float maxRange;
|
||||
}
|
||||
|
||||
public enum AITarget
|
||||
{
|
||||
Self,
|
||||
Victim,
|
||||
Enemy,
|
||||
Ally,
|
||||
Buff,
|
||||
Debuff
|
||||
}
|
||||
|
||||
public enum AICondition
|
||||
{
|
||||
Aggro,
|
||||
Combat,
|
||||
Die
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Dynamic;
|
||||
using Game.Entities;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class GameObjectAI
|
||||
{
|
||||
public GameObjectAI(GameObject g)
|
||||
{
|
||||
go = g;
|
||||
_scheduler = new TaskScheduler();
|
||||
_events = new EventMap();
|
||||
}
|
||||
|
||||
public virtual void UpdateAI(uint diff) { }
|
||||
|
||||
public virtual void InitializeAI() { Reset(); }
|
||||
|
||||
public virtual void Reset() { }
|
||||
|
||||
// Pass parameters between AI
|
||||
public virtual void DoAction(int param = 0) { }
|
||||
public virtual void SetGUID(ulong guid, int id = 0) { }
|
||||
public virtual ulong GetGUID(int id = 0) { return 0; }
|
||||
|
||||
public virtual bool GossipHello(Player player, bool isUse) { return false; }
|
||||
public virtual bool GossipSelect(Player player, uint sender, uint action) { return false; }
|
||||
public virtual bool GossipSelectCode(Player player, uint sender, uint action, string code) { return false; }
|
||||
public virtual bool QuestAccept(Player player, Quest quest) { return false; }
|
||||
public virtual bool QuestReward(Player player, Quest quest, uint opt) { return false; }
|
||||
public virtual uint GetDialogStatus(Player player) { return 100; }
|
||||
public virtual void Destroyed(Player player, uint eventId) { }
|
||||
public virtual void SetData64(uint id, ulong value) { }
|
||||
public virtual ulong GetData64(uint id) { return 0; }
|
||||
public virtual uint GetData(uint id) { return 0; }
|
||||
public virtual void SetData(uint id, uint value) { }
|
||||
|
||||
public virtual void OnGameEvent(bool start, ushort eventId) { }
|
||||
public virtual void OnStateChanged(uint state, Unit unit) { }
|
||||
public virtual void EventInform(uint eventId) { }
|
||||
|
||||
protected TaskScheduler _scheduler;
|
||||
protected EventMap _events;
|
||||
|
||||
public GameObject go;
|
||||
}
|
||||
|
||||
public class NullGameObjectAI : GameObjectAI
|
||||
{
|
||||
public NullGameObjectAI(GameObject g) : base(g) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class GuardAI : ScriptedAI
|
||||
{
|
||||
public GuardAI(Creature creature) : base(creature) { }
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
public override bool CanSeeAlways(WorldObject obj)
|
||||
{
|
||||
if (!obj.isTypeMask(TypeMask.Unit))
|
||||
return false;
|
||||
|
||||
var threatList = me.GetThreatManager().getThreatList();
|
||||
foreach (var refe in threatList)
|
||||
if (refe.getUnitGuid() == obj.GetGUID())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
if (!me.IsAlive())
|
||||
{
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
me.CombatStop(true);
|
||||
me.DeleteThreatList();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Unit, "Guard entry: {0} enters evade mode.", me.GetEntry());
|
||||
|
||||
me.RemoveAllAuras();
|
||||
me.DeleteThreatList();
|
||||
me.CombatStop(true);
|
||||
|
||||
// Remove ChaseMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
|
||||
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Chase)
|
||||
me.GetMotionMaster().MoveTargetedHome();
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
Player player = killer.GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if (player != null)
|
||||
me.SendZoneUnderAttackMessage(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class PassiveAI : CreatureAI
|
||||
{
|
||||
public PassiveAI(Creature c) : base(c)
|
||||
{
|
||||
me.SetReactState(ReactStates.Passive);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (me.IsInCombat() && me.getAttackers().Empty())
|
||||
EnterEvadeMode(EvadeReason.NoHostiles);
|
||||
}
|
||||
|
||||
public override void AttackStart(Unit victim) { }
|
||||
|
||||
public override void MoveInLineOfSight(Unit who) { }
|
||||
}
|
||||
|
||||
public class PossessedAI : CreatureAI
|
||||
{
|
||||
public PossessedAI(Creature c) : base(c)
|
||||
{
|
||||
me.SetReactState(ReactStates.Passive);
|
||||
}
|
||||
|
||||
public override void AttackStart(Unit target)
|
||||
{
|
||||
me.Attack(target, true);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (me.GetVictim() != null)
|
||||
{
|
||||
if (!me.IsValidAttackTarget(me.GetVictim()))
|
||||
me.AttackStop();
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustDied(Unit unit)
|
||||
{
|
||||
// We died while possessed, disable our loot
|
||||
me.RemoveFlag(ObjectFields.DynamicFlags, UnitDynFlags.Lootable);
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
// We killed a creature, disable victim's loot
|
||||
if (victim.IsTypeId(TypeId.Unit))
|
||||
victim.RemoveFlag(ObjectFields.DynamicFlags, UnitDynFlags.Lootable);
|
||||
}
|
||||
|
||||
public override void OnCharmed(bool apply)
|
||||
{
|
||||
me.NeedChangeAI = true;
|
||||
me.IsAIEnabled = false;
|
||||
}
|
||||
|
||||
public override void MoveInLineOfSight(Unit who) { }
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why) { }
|
||||
}
|
||||
|
||||
public class NullCreatureAI : CreatureAI
|
||||
{
|
||||
public NullCreatureAI(Creature c) : base(c)
|
||||
{
|
||||
me.SetReactState(ReactStates.Passive);
|
||||
}
|
||||
|
||||
public override void MoveInLineOfSight(Unit unit) { }
|
||||
public override void AttackStart(Unit unit) { }
|
||||
public override void UpdateAI(uint diff) { }
|
||||
public override void EnterEvadeMode(EvadeReason why) { }
|
||||
public override void OnCharmed(bool apply) { }
|
||||
}
|
||||
|
||||
public class CritterAI : PassiveAI
|
||||
{
|
||||
public CritterAI(Creature c) : base(c)
|
||||
{
|
||||
me.SetReactState(ReactStates.Passive);
|
||||
}
|
||||
|
||||
public override void DamageTaken(Unit done_by, ref uint damage)
|
||||
{
|
||||
if (!me.HasUnitState(UnitState.Fleeing))
|
||||
me.SetControlled(true, UnitState.Fleeing);
|
||||
}
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
if (me.HasUnitState(UnitState.Fleeing))
|
||||
me.SetControlled(false, UnitState.Fleeing);
|
||||
base.EnterEvadeMode(why);
|
||||
}
|
||||
}
|
||||
|
||||
public class TriggerAI : NullCreatureAI
|
||||
{
|
||||
public TriggerAI(Creature c) : base(c) { }
|
||||
|
||||
public override void IsSummonedBy(Unit summoner)
|
||||
{
|
||||
if (me.m_spells[0] != 0)
|
||||
me.CastSpell(me, me.m_spells[0], false, null, null, summoner.GetGUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,644 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class PetAI : CreatureAI
|
||||
{
|
||||
public PetAI(Creature c) : base(c)
|
||||
{
|
||||
i_tracker = new TimeTracker(5000);
|
||||
|
||||
UpdateAllies();
|
||||
}
|
||||
|
||||
bool _needToStop()
|
||||
{
|
||||
// This is needed for charmed creatures, as once their target was reset other effects can trigger threat
|
||||
if (me.IsCharmed() && me.GetVictim() == me.GetCharmer())
|
||||
return true;
|
||||
|
||||
return !me.IsValidAttackTarget(me.GetVictim());
|
||||
}
|
||||
|
||||
void _stopAttack()
|
||||
{
|
||||
if (!me.IsAlive())
|
||||
{
|
||||
Log.outDebug(LogFilter.Server, "Creature stoped attacking cuz his dead [{0}]", me.GetGUID().ToString());
|
||||
me.GetMotionMaster().Clear();
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
me.CombatStop();
|
||||
me.getHostileRefManager().deleteReferences();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
me.AttackStop();
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
me.SendMeleeAttackStop(); // Should stop pet's attack button from flashing
|
||||
me.GetCharmInfo().SetIsCommandAttack(false);
|
||||
ClearCharmInfoFlags();
|
||||
HandleReturnMovement();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!me.IsAlive() || me.GetCharmInfo() == null)
|
||||
return;
|
||||
|
||||
Unit owner = me.GetCharmerOrOwner();
|
||||
|
||||
if (m_updateAlliesTimer <= diff)
|
||||
// UpdateAllies self set update timer
|
||||
UpdateAllies();
|
||||
else
|
||||
m_updateAlliesTimer -= diff;
|
||||
|
||||
if (me.GetVictim() && me.GetVictim().IsAlive())
|
||||
{
|
||||
// is only necessary to stop casting, the pet must not exit combat
|
||||
if (!me.GetCurrentSpell(CurrentSpellTypes.Channeled) && // ignore channeled spells (Pin, Seduction)
|
||||
(me.GetVictim() && me.GetVictim().HasBreakableByDamageCrowdControlAura(me)))
|
||||
{
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_needToStop())
|
||||
{
|
||||
Log.outDebug(LogFilter.Server, "Pet AI stopped attacking [{0}]", me.GetGUID().ToString());
|
||||
_stopAttack();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check before attacking to prevent pets from leaving stay position
|
||||
if (me.GetCharmInfo().HasCommandState(CommandStates.Stay))
|
||||
{
|
||||
if (me.GetCharmInfo().IsCommandAttack() || (me.GetCharmInfo().IsAtStay() && me.IsWithinMeleeRange(me.GetVictim())))
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
else
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me.HasReactState(ReactStates.Aggressive) || me.GetCharmInfo().IsAtStay())
|
||||
{
|
||||
// Every update we need to check targets only in certain cases
|
||||
// Aggressive - Allow auto select if owner or pet don't have a target
|
||||
// Stay - Only pick from pet or owner targets / attackers so targets won't run by
|
||||
// while chasing our owner. Don't do auto select.
|
||||
// All other cases (ie: defensive) - Targets are assigned by AttackedBy(), OwnerAttackedBy(), OwnerAttacked(), etc.
|
||||
Unit nextTarget = SelectNextTarget(me.HasReactState(ReactStates.Aggressive));
|
||||
|
||||
if (nextTarget)
|
||||
AttackStart(nextTarget);
|
||||
else
|
||||
HandleReturnMovement();
|
||||
}
|
||||
else
|
||||
HandleReturnMovement();
|
||||
}
|
||||
|
||||
// Autocast (casted only in combat or persistent spells in any state)
|
||||
if (!me.HasUnitState(UnitState.Casting))
|
||||
{
|
||||
List<Tuple<Unit, Spell>> targetSpellStore = new List<Tuple<Unit, Spell>>();
|
||||
|
||||
for (byte i = 0; i < me.GetPetAutoSpellSize(); ++i)
|
||||
{
|
||||
uint spellID = me.GetPetAutoSpellOnPos(i);
|
||||
if (spellID == 0)
|
||||
continue;
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellID);
|
||||
if (spellInfo == null)
|
||||
continue;
|
||||
|
||||
if (me.GetCharmInfo() != null && me.GetSpellHistory().HasGlobalCooldown(spellInfo))
|
||||
continue;
|
||||
|
||||
// check spell cooldown
|
||||
if (!me.GetSpellHistory().IsReady(spellInfo))
|
||||
continue;
|
||||
|
||||
if (spellInfo.IsPositive())
|
||||
{
|
||||
if (spellInfo.CanBeUsedInCombat())
|
||||
{
|
||||
// Check if we're in combat or commanded to attack
|
||||
if (!me.IsInCombat() && !me.GetCharmInfo().IsCommandAttack())
|
||||
continue;
|
||||
}
|
||||
|
||||
Spell spell = new Spell(me, spellInfo, TriggerCastFlags.None);
|
||||
bool spellUsed = false;
|
||||
|
||||
// Some spells can target enemy or friendly (DK Ghoul's Leap)
|
||||
// Check for enemy first (pet then owner)
|
||||
Unit target = me.getAttackerForHelper();
|
||||
if (!target && owner)
|
||||
target = owner.getAttackerForHelper();
|
||||
|
||||
if (target)
|
||||
{
|
||||
if (CanAIAttack(target) && spell.CanAutoCast(target))
|
||||
{
|
||||
targetSpellStore.Add(Tuple.Create(target, spell));
|
||||
spellUsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (spellInfo.HasEffect(SpellEffectName.JumpDest))
|
||||
{
|
||||
if (!spellUsed)
|
||||
spell.Dispose();
|
||||
continue; // Pets must only jump to target
|
||||
}
|
||||
|
||||
// No enemy, check friendly
|
||||
if (!spellUsed)
|
||||
{
|
||||
foreach (var tar in m_AllySet)
|
||||
{
|
||||
Unit ally = Global.ObjAccessor.GetUnit(me, tar);
|
||||
|
||||
//only buff targets that are in combat, unless the spell can only be cast while out of combat
|
||||
if (!ally)
|
||||
continue;
|
||||
|
||||
if (spell.CanAutoCast(ally))
|
||||
{
|
||||
targetSpellStore.Add(Tuple.Create(ally, spell));
|
||||
spellUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No valid targets at all
|
||||
if (!spellUsed)
|
||||
spell.Dispose();
|
||||
}
|
||||
else if (me.GetVictim() && CanAIAttack(me.GetVictim()) && spellInfo.CanBeUsedInCombat())
|
||||
{
|
||||
Spell spell = new Spell(me, spellInfo, TriggerCastFlags.None);
|
||||
if (spell.CanAutoCast(me.GetVictim()))
|
||||
targetSpellStore.Add(Tuple.Create(me.GetVictim(), spell));
|
||||
else
|
||||
spell.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//found units to cast on to
|
||||
if (!targetSpellStore.Empty())
|
||||
{
|
||||
int index = RandomHelper.IRand(0, targetSpellStore.Count - 1);
|
||||
var tss = targetSpellStore[index];
|
||||
|
||||
(Unit target, Spell spell) = tss;
|
||||
|
||||
targetSpellStore.RemoveAt(index);
|
||||
|
||||
SpellCastTargets targets = new SpellCastTargets();
|
||||
targets.SetUnitTarget(target);
|
||||
|
||||
spell.prepare(targets);
|
||||
}
|
||||
|
||||
// deleted cached Spell objects
|
||||
foreach (var pair in targetSpellStore)
|
||||
pair.Item2.Dispose();
|
||||
}
|
||||
|
||||
// Update speed as needed to prevent dropping too far behind and despawning
|
||||
me.UpdateSpeed(UnitMoveType.Run);
|
||||
me.UpdateSpeed(UnitMoveType.Walk);
|
||||
me.UpdateSpeed(UnitMoveType.Flight);
|
||||
}
|
||||
|
||||
void UpdateAllies()
|
||||
{
|
||||
m_updateAlliesTimer = 10 * Time.InMilliseconds; // update friendly targets every 10 seconds, lesser checks increase performance
|
||||
|
||||
Unit owner = me.GetCharmerOrOwner();
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
Group group = null;
|
||||
Player player = owner.ToPlayer();
|
||||
if (player)
|
||||
group = player.GetGroup();
|
||||
|
||||
//only pet and owner/not in group.ok
|
||||
if (m_AllySet.Count == 2 && !group)
|
||||
return;
|
||||
|
||||
//owner is in group; group members filled in already (no raid . subgroupcount = whole count)
|
||||
if (group && !group.isRaidGroup() && m_AllySet.Count == (group.GetMembersCount() + 2))
|
||||
return;
|
||||
|
||||
m_AllySet.Clear();
|
||||
m_AllySet.Add(me.GetGUID());
|
||||
if (group) //add group
|
||||
{
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player Target = refe.GetSource();
|
||||
if (!Target || !group.SameSubGroup(owner.ToPlayer(), Target))
|
||||
continue;
|
||||
|
||||
if (Target.GetGUID() == owner.GetGUID())
|
||||
continue;
|
||||
|
||||
m_AllySet.Add(Target.GetGUID());
|
||||
}
|
||||
}
|
||||
else //remove group
|
||||
m_AllySet.Add(owner.GetGUID());
|
||||
}
|
||||
|
||||
public override void KilledUnit(Unit victim)
|
||||
{
|
||||
// Called from Unit.Kill() in case where pet or owner kills something
|
||||
// if owner killed this victim, pet may still be attacking something else
|
||||
if (me.GetVictim() && me.GetVictim() != victim)
|
||||
return;
|
||||
|
||||
// Clear target just in case. May help problem where health / focus / mana
|
||||
// regen gets stuck. Also resets attack command.
|
||||
// Can't use _stopAttack() because that activates movement handlers and ignores
|
||||
// next target selection
|
||||
me.AttackStop();
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
me.SendMeleeAttackStop(); // Stops the pet's 'Attack' button from flashing
|
||||
|
||||
// Before returning to owner, see if there are more things to attack
|
||||
Unit nextTarget = SelectNextTarget(false);
|
||||
if (nextTarget)
|
||||
AttackStart(nextTarget);
|
||||
else
|
||||
HandleReturnMovement(); // Return
|
||||
}
|
||||
|
||||
public override void AttackStart(Unit victim)
|
||||
{
|
||||
// Overrides Unit.AttackStart to correctly evaluate Pet states
|
||||
|
||||
// Check all pet states to decide if we can attack this target
|
||||
if (!CanAIAttack(victim))
|
||||
return;
|
||||
|
||||
// Only chase if not commanded to stay or if stay but commanded to attack
|
||||
DoAttack(victim, (!me.GetCharmInfo().HasCommandState(CommandStates.Stay) || me.GetCharmInfo().IsCommandAttack()));
|
||||
}
|
||||
|
||||
public override void OwnerAttackedBy(Unit attacker)
|
||||
{
|
||||
// Called when owner takes damage. This function helps keep pets from running off
|
||||
// simply due to owner gaining aggro.
|
||||
|
||||
if (!attacker)
|
||||
return;
|
||||
|
||||
// Passive pets don't do anything
|
||||
if (me.HasReactState(ReactStates.Passive))
|
||||
return;
|
||||
|
||||
// Prevent pet from disengaging from current target
|
||||
if (me.GetVictim() && me.GetVictim().IsAlive())
|
||||
return;
|
||||
|
||||
// Continue to evaluate and attack if necessary
|
||||
AttackStart(attacker);
|
||||
}
|
||||
|
||||
public override void OwnerAttacked(Unit target)
|
||||
{
|
||||
// Called when owner attacks something. Allows defensive pets to know
|
||||
// that they need to assist
|
||||
|
||||
// Target might be null if called from spell with invalid cast targets
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
// Passive pets don't do anything
|
||||
if (me.HasReactState(ReactStates.Passive))
|
||||
return;
|
||||
|
||||
// Prevent pet from disengaging from current target
|
||||
if (me.GetVictim() && me.GetVictim().IsAlive())
|
||||
return;
|
||||
|
||||
// Continue to evaluate and attack if necessary
|
||||
AttackStart(target);
|
||||
}
|
||||
|
||||
Unit SelectNextTarget(bool allowAutoSelect)
|
||||
{
|
||||
// Provides next target selection after current target death.
|
||||
// This function should only be called internally by the AI
|
||||
// Targets are not evaluated here for being valid targets, that is done in _CanAttack()
|
||||
// The parameter: allowAutoSelect lets us disable aggressive pet auto targeting for certain situations
|
||||
|
||||
// Passive pets don't do next target selection
|
||||
if (me.HasReactState(ReactStates.Passive))
|
||||
return null;
|
||||
|
||||
// Check pet attackers first so we don't drag a bunch of targets to the owner
|
||||
Unit myAttacker = me.getAttackerForHelper();
|
||||
if (myAttacker)
|
||||
if (!myAttacker.HasBreakableByDamageCrowdControlAura())
|
||||
return myAttacker;
|
||||
|
||||
// Not sure why we wouldn't have an owner but just in case...
|
||||
if (!me.GetCharmerOrOwner())
|
||||
return null;
|
||||
|
||||
// Check owner attackers
|
||||
Unit ownerAttacker = me.GetCharmerOrOwner().getAttackerForHelper();
|
||||
if (ownerAttacker)
|
||||
if (!ownerAttacker.HasBreakableByDamageCrowdControlAura())
|
||||
return ownerAttacker;
|
||||
|
||||
// Check owner victim
|
||||
// 3.0.2 - Pets now start attacking their owners victim in defensive mode as soon as the hunter does
|
||||
Unit ownerVictim = me.GetCharmerOrOwner().GetVictim();
|
||||
if (ownerVictim)
|
||||
return ownerVictim;
|
||||
|
||||
// Neither pet or owner had a target and aggressive pets can pick any target
|
||||
// To prevent aggressive pets from chain selecting targets and running off, we
|
||||
// only select a random target if certain conditions are met.
|
||||
if (me.HasReactState(ReactStates.Aggressive) && allowAutoSelect)
|
||||
{
|
||||
if (!me.GetCharmInfo().IsReturning() || me.GetCharmInfo().IsFollowing() || me.GetCharmInfo().IsAtStay())
|
||||
{
|
||||
Unit nearTarget = me.SelectNearestHostileUnitInAggroRange(true);
|
||||
if (nearTarget)
|
||||
return nearTarget;
|
||||
}
|
||||
}
|
||||
|
||||
// Default - no valid targets
|
||||
return null;
|
||||
}
|
||||
|
||||
void HandleReturnMovement()
|
||||
{
|
||||
// Handles moving the pet back to stay or owner
|
||||
|
||||
// Prevent activating movement when under control of spells
|
||||
// such as "Eyes of the Beast"
|
||||
if (me.IsCharmed())
|
||||
return;
|
||||
|
||||
if (me.GetCharmInfo().HasCommandState(CommandStates.Stay))
|
||||
{
|
||||
if (!me.GetCharmInfo().IsAtStay() && !me.GetCharmInfo().IsReturning())
|
||||
{
|
||||
// Return to previous position where stay was clicked
|
||||
float x, y, z;
|
||||
|
||||
me.GetCharmInfo().GetStayPosition(out x, out y, out z);
|
||||
ClearCharmInfoFlags();
|
||||
me.GetCharmInfo().SetIsReturning(true);
|
||||
me.GetMotionMaster().Clear();
|
||||
me.GetMotionMaster().MovePoint(me.GetGUID().GetCounter(), x, y, z);
|
||||
}
|
||||
}
|
||||
else // COMMAND_FOLLOW
|
||||
{
|
||||
if (!me.GetCharmInfo().IsFollowing() && !me.GetCharmInfo().IsReturning())
|
||||
{
|
||||
ClearCharmInfoFlags();
|
||||
me.GetCharmInfo().SetIsReturning(true);
|
||||
me.GetMotionMaster().Clear();
|
||||
me.GetMotionMaster().MoveFollow(me.GetCharmerOrOwner(), SharedConst.PetFollowDist, me.GetFollowAngle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoAttack(Unit target, bool chase)
|
||||
{
|
||||
// Handles attack with or without chase and also resets flags
|
||||
// for next update / creature kill
|
||||
|
||||
if (me.Attack(target, true))
|
||||
{
|
||||
Unit owner = me.GetOwner();
|
||||
if (owner)
|
||||
owner.SetInCombatWith(target);
|
||||
|
||||
// Play sound to let the player know the pet is attacking something it picked on its own
|
||||
if (me.HasReactState(ReactStates.Aggressive) && !me.GetCharmInfo().IsCommandAttack())
|
||||
me.SendPetAIReaction(me.GetGUID());
|
||||
|
||||
if (chase)
|
||||
{
|
||||
bool oldCmdAttack = me.GetCharmInfo().IsCommandAttack(); // This needs to be reset after other flags are cleared
|
||||
ClearCharmInfoFlags();
|
||||
me.GetCharmInfo().SetIsCommandAttack(oldCmdAttack); // For passive pets commanded to attack so they will use spells
|
||||
me.GetMotionMaster().Clear();
|
||||
me.GetMotionMaster().MoveChase(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearCharmInfoFlags();
|
||||
me.GetCharmInfo().SetIsAtStay(true);
|
||||
me.GetMotionMaster().Clear();
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void MovementInform(MovementGeneratorType type, uint id)
|
||||
{
|
||||
// Receives notification when pet reaches stay or follow owner
|
||||
switch (type)
|
||||
{
|
||||
case MovementGeneratorType.Point:
|
||||
{
|
||||
// Pet is returning to where stay was clicked. data should be
|
||||
// pet's GUIDLow since we set that as the waypoint ID
|
||||
if (id == me.GetGUID().GetCounter() && me.GetCharmInfo().IsReturning())
|
||||
{
|
||||
ClearCharmInfoFlags();
|
||||
me.GetCharmInfo().SetIsAtStay(true);
|
||||
me.GetMotionMaster().Clear();
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MovementGeneratorType.Follow:
|
||||
{
|
||||
// If data is owner's GUIDLow then we've reached follow point,
|
||||
// otherwise we're probably chasing a creature
|
||||
if (me.GetCharmerOrOwner() && me.GetCharmInfo() != null && id == me.GetCharmerOrOwner().GetGUID().GetCounter() && me.GetCharmInfo().IsReturning())
|
||||
{
|
||||
ClearCharmInfoFlags();
|
||||
me.GetCharmInfo().SetIsFollowing(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanAIAttack(Unit victim)
|
||||
{
|
||||
// Evaluates wether a pet can attack a specific target based on CommandState, ReactState and other flags
|
||||
// IMPORTANT: The order in which things are checked is important, be careful if you add or remove checks
|
||||
|
||||
// Hmmm...
|
||||
if (!victim)
|
||||
return false;
|
||||
|
||||
if (!victim.IsAlive())
|
||||
{
|
||||
// Clear target to prevent getting stuck on dead targets
|
||||
me.AttackStop();
|
||||
me.InterruptNonMeleeSpells(false);
|
||||
me.SendMeleeAttackStop();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Passive - passive pets can attack if told to
|
||||
if (me.HasReactState(ReactStates.Passive))
|
||||
return me.GetCharmInfo().IsCommandAttack();
|
||||
|
||||
// CC - mobs under crowd control can be attacked if owner commanded
|
||||
if (victim.HasBreakableByDamageCrowdControlAura())
|
||||
return me.GetCharmInfo().IsCommandAttack();
|
||||
|
||||
// Returning - pets ignore attacks only if owner clicked follow
|
||||
if (me.GetCharmInfo().IsReturning())
|
||||
return !me.GetCharmInfo().IsCommandFollow();
|
||||
|
||||
// Stay - can attack if target is within range or commanded to
|
||||
if (me.GetCharmInfo().HasCommandState(CommandStates.Stay))
|
||||
return (me.IsWithinMeleeRange(victim) || me.GetCharmInfo().IsCommandAttack());
|
||||
|
||||
// Pets attacking something (or chasing) should only switch targets if owner tells them to
|
||||
if (me.GetVictim() && me.GetVictim() != victim)
|
||||
{
|
||||
// Check if our owner selected this target and clicked "attack"
|
||||
Unit ownerTarget = null;
|
||||
Player owner = me.GetCharmerOrOwner().ToPlayer();
|
||||
if (owner)
|
||||
ownerTarget = owner.GetSelectedUnit();
|
||||
else
|
||||
ownerTarget = me.GetCharmerOrOwner().GetVictim();
|
||||
|
||||
if (ownerTarget && me.GetCharmInfo().IsCommandAttack())
|
||||
return (victim.GetGUID() == ownerTarget.GetGUID());
|
||||
}
|
||||
|
||||
// Follow
|
||||
if (me.GetCharmInfo().HasCommandState(CommandStates.Follow))
|
||||
return !me.GetCharmInfo().IsReturning();
|
||||
|
||||
// default, though we shouldn't ever get here
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void ReceiveEmote(Player player, TextEmotes emoteId)
|
||||
{
|
||||
if (!me.GetOwnerGUID().IsEmpty() && me.GetOwnerGUID() == player.GetGUID())
|
||||
switch (emoteId)
|
||||
{
|
||||
case TextEmotes.Cower:
|
||||
if (me.IsPet() && me.ToPet().IsPetGhoul())
|
||||
me.HandleEmoteCommand(Emote.OneshotOmnicastGhoul);
|
||||
break;
|
||||
case TextEmotes.Angry:
|
||||
if (me.IsPet() && me.ToPet().IsPetGhoul())
|
||||
me.HandleEmoteCommand(Emote.StateStun);
|
||||
break;
|
||||
case TextEmotes.Glare:
|
||||
if (me.IsPet() && me.ToPet().IsPetGhoul())
|
||||
me.HandleEmoteCommand(Emote.StateStun);
|
||||
break;
|
||||
case TextEmotes.Soothe:
|
||||
if (me.IsPet() && me.ToPet().IsPetGhoul())
|
||||
me.HandleEmoteCommand( Emote.OneshotOmnicastGhoul);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnCharmed(bool apply)
|
||||
{
|
||||
me.NeedChangeAI = true;
|
||||
me.IsAIEnabled = false;
|
||||
}
|
||||
|
||||
void ClearCharmInfoFlags()
|
||||
{
|
||||
// Quick access to set all flags to FALSE
|
||||
|
||||
CharmInfo ci = me.GetCharmInfo();
|
||||
|
||||
if (ci != null)
|
||||
{
|
||||
ci.SetIsAtStay(false);
|
||||
ci.SetIsCommandAttack(false);
|
||||
ci.SetIsCommandFollow(false);
|
||||
ci.SetIsFollowing(false);
|
||||
ci.SetIsReturning(false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AttackedBy(Unit attacker)
|
||||
{
|
||||
// Called when pet takes damage. This function helps keep pets from running off
|
||||
// simply due to gaining aggro.
|
||||
|
||||
if (!attacker)
|
||||
return;
|
||||
|
||||
// Passive pets don't do anything
|
||||
if (me.HasReactState( ReactStates.Passive))
|
||||
return;
|
||||
|
||||
// Prevent pet from disengaging from current target
|
||||
if (me.GetVictim() && me.GetVictim().IsAlive())
|
||||
return;
|
||||
|
||||
// Continue to evaluate and attack if necessary
|
||||
AttackStart(attacker);
|
||||
}
|
||||
|
||||
// The following aren't used by the PetAI but need to be defined to override
|
||||
// default CreatureAI functions which interfere with the PetAI
|
||||
public override void MoveInLineOfSight(Unit who) { }
|
||||
public override void MoveInLineOfSight_Safe(Unit who) { }
|
||||
public override void EnterEvadeMode(EvadeReason why) { }
|
||||
|
||||
TimeTracker i_tracker;
|
||||
List<ObjectGuid> m_AllySet = new List<ObjectGuid>();
|
||||
uint m_updateAlliesTimer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class TotemAI : CreatureAI
|
||||
{
|
||||
public TotemAI(Creature c) : base(c)
|
||||
{
|
||||
i_victimGuid = ObjectGuid.Empty;
|
||||
}
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
me.CombatStop(true);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (me.ToTotem().GetTotemType() != TotemType.Active)
|
||||
return;
|
||||
|
||||
if (!me.IsAlive() || me.IsNonMeleeSpellCast(false))
|
||||
return;
|
||||
|
||||
// Search spell
|
||||
var spellInfo = Global.SpellMgr.GetSpellInfo(me.ToTotem().GetSpell());
|
||||
if (spellInfo == null)
|
||||
return;
|
||||
|
||||
// Get spell range
|
||||
float max_range = spellInfo.GetMaxRange(false);
|
||||
|
||||
// SPELLMOD_RANGE not applied in this place just because not existence range mods for attacking totems
|
||||
|
||||
Unit victim = !i_victimGuid.IsEmpty() ? Global.ObjAccessor.GetUnit(me, i_victimGuid) : null;
|
||||
|
||||
// Search victim if no, not attackable, or out of range, or friendly (possible in case duel end)
|
||||
if (victim == null || !victim.isTargetableForAttack() || !me.IsWithinDistInMap(victim, max_range) ||
|
||||
me.IsFriendlyTo(victim) || !me.CanSeeOrDetect(victim))
|
||||
{
|
||||
victim = null;
|
||||
var u_check = new NearestAttackableUnitInObjectRangeCheck(me, me.GetCharmerOrOwnerOrSelf(), max_range);
|
||||
var checker = new UnitLastSearcher(me, u_check);
|
||||
Cell.VisitAllObjects(me, checker, max_range);
|
||||
victim = checker.GetTarget();
|
||||
}
|
||||
|
||||
// If have target
|
||||
if (victim != null)
|
||||
{
|
||||
// remember
|
||||
i_victimGuid = victim.GetGUID();
|
||||
|
||||
// attack
|
||||
me.SetInFront(victim); // client change orientation by self
|
||||
me.CastSpell(victim, me.ToTotem().GetSpell(), false);
|
||||
}
|
||||
else
|
||||
i_victimGuid.Clear();
|
||||
}
|
||||
|
||||
ObjectGuid i_victimGuid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Combat;
|
||||
using Game.Entities;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class UnitAI
|
||||
{
|
||||
public UnitAI(Unit _unit)
|
||||
{
|
||||
me = _unit;
|
||||
}
|
||||
|
||||
public virtual void AttackStart(Unit victim)
|
||||
{
|
||||
if (victim != null && me.Attack(victim, true))
|
||||
{
|
||||
// Clear distracted state on attacking
|
||||
if (me.HasUnitState(UnitState.Distracted))
|
||||
{
|
||||
me.ClearUnitState(UnitState.Distracted);
|
||||
me.GetMotionMaster().Clear();
|
||||
}
|
||||
me.GetMotionMaster().MoveChase(victim);
|
||||
}
|
||||
}
|
||||
|
||||
public void AttackStartCaster(Unit victim, float dist)
|
||||
{
|
||||
if (victim != null && me.Attack(victim, false))
|
||||
me.GetMotionMaster().MoveChase(victim, dist);
|
||||
}
|
||||
|
||||
ThreatManager GetThreatManager()
|
||||
{
|
||||
return me.GetThreatManager();
|
||||
}
|
||||
|
||||
void SortByDistanceTo(Unit reference, List<Unit> targets)
|
||||
{
|
||||
targets.Sort(new ObjectDistanceOrderPred(reference));
|
||||
}
|
||||
|
||||
public void DoMeleeAttackIfReady()
|
||||
{
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
Unit victim = me.GetVictim();
|
||||
|
||||
if (!me.IsWithinMeleeRange(victim))
|
||||
return;
|
||||
|
||||
bool sparAttack = me.GetFactionTemplateEntry().ShouldSparAttack() && victim.GetFactionTemplateEntry().ShouldSparAttack();
|
||||
//Make sure our attack is ready and we aren't currently casting before checking distance
|
||||
if (me.isAttackReady())
|
||||
{
|
||||
if (sparAttack)
|
||||
me.FakeAttackerStateUpdate(victim);
|
||||
else
|
||||
me.AttackerStateUpdate(victim);
|
||||
|
||||
me.resetAttackTimer();
|
||||
}
|
||||
|
||||
if (me.haveOffhandWeapon() && me.isAttackReady(WeaponAttackType.OffAttack))
|
||||
{
|
||||
if (sparAttack)
|
||||
me.FakeAttackerStateUpdate(victim, WeaponAttackType.OffAttack);
|
||||
else
|
||||
me.AttackerStateUpdate(victim, WeaponAttackType.OffAttack);
|
||||
|
||||
me.resetAttackTimer(WeaponAttackType.OffAttack);
|
||||
}
|
||||
}
|
||||
|
||||
public bool DoSpellAttackIfReady(uint spell)
|
||||
{
|
||||
if (me.HasUnitState(UnitState.Casting) || !me.isAttackReady())
|
||||
return true;
|
||||
|
||||
var spellInfo = Global.SpellMgr.GetSpellInfo(spell);
|
||||
if (spellInfo != null)
|
||||
{
|
||||
if (me.IsWithinCombatRange(me.GetVictim(), spellInfo.GetMaxRange(false)))
|
||||
{
|
||||
me.CastSpell(me.GetVictim(), spellInfo, TriggerCastFlags.None);
|
||||
me.resetAttackTimer();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Unit SelectTarget(SelectAggroTarget targetType, uint position = 0, float dist = 0.0f, bool playerOnly = false, int aura = 0)
|
||||
{
|
||||
return SelectTarget(targetType, position, new DefaultTargetSelector(me, dist, playerOnly, aura));
|
||||
}
|
||||
|
||||
// Select the targets satifying the predicate.
|
||||
public Unit SelectTarget(SelectAggroTarget targetType, uint position, ISelector selector)
|
||||
{
|
||||
var threatlist = GetThreatManager().getThreatList();
|
||||
if (position >= threatlist.Count)
|
||||
return null;
|
||||
|
||||
List<Unit> targetList = new List<Unit>();
|
||||
Unit currentVictim = null;
|
||||
|
||||
var currentVictimReference = GetThreatManager().getCurrentVictim();
|
||||
if (currentVictimReference != null)
|
||||
{
|
||||
currentVictim = currentVictimReference.getTarget();
|
||||
|
||||
// Current victim always goes first
|
||||
if (currentVictim && selector.Check(currentVictim))
|
||||
targetList.Add(currentVictim);
|
||||
}
|
||||
|
||||
foreach (var hostileRef in threatlist)
|
||||
{
|
||||
if (currentVictim != null && hostileRef.getTarget() != currentVictim && selector.Check(hostileRef.getTarget()))
|
||||
targetList.Add(hostileRef.getTarget());
|
||||
else if (currentVictim == null && selector.Check(hostileRef.getTarget()))
|
||||
targetList.Add(hostileRef.getTarget());
|
||||
}
|
||||
|
||||
if (position >= targetList.Count)
|
||||
return null;
|
||||
|
||||
if (targetType == SelectAggroTarget.Nearest || targetType == SelectAggroTarget.Farthest)
|
||||
SortByDistanceTo(me, targetList);
|
||||
|
||||
switch (targetType)
|
||||
{
|
||||
case SelectAggroTarget.Nearest:
|
||||
case SelectAggroTarget.TopAggro:
|
||||
{
|
||||
return targetList.First();
|
||||
}
|
||||
case SelectAggroTarget.Farthest:
|
||||
case SelectAggroTarget.BottomAggro:
|
||||
{
|
||||
return targetList.Last();
|
||||
}
|
||||
case SelectAggroTarget.Random:
|
||||
{
|
||||
return targetList.SelectRandom();
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Unit> SelectTargetList(uint num, SelectAggroTarget targetType, float dist, bool playerOnly, int aura = 0)
|
||||
{
|
||||
return SelectTargetList(new DefaultTargetSelector(me, dist, playerOnly, aura), num, targetType);
|
||||
}
|
||||
|
||||
// Select the targets satifying the predicate.
|
||||
// predicate shall extend std.unary_function<Unit*, bool>
|
||||
public List<Unit> SelectTargetList(ISelector selector, uint maxTargets, SelectAggroTarget targetType)
|
||||
{
|
||||
var targetList = new List<Unit>();
|
||||
|
||||
var threatlist = GetThreatManager().getThreatList();
|
||||
if (threatlist.Empty())
|
||||
return targetList;
|
||||
|
||||
foreach (var hostileRef in threatlist)
|
||||
if (selector.Check(hostileRef.getTarget()))
|
||||
targetList.Add(hostileRef.getTarget());
|
||||
|
||||
if (targetList.Count < maxTargets)
|
||||
return targetList;
|
||||
|
||||
if (targetType == SelectAggroTarget.Nearest || targetType == SelectAggroTarget.Farthest)
|
||||
SortByDistanceTo(me, targetList);
|
||||
|
||||
if (targetType == SelectAggroTarget.Farthest || targetType == SelectAggroTarget.BottomAggro)
|
||||
targetList.Reverse();
|
||||
|
||||
if (targetType == SelectAggroTarget.Random)
|
||||
targetList = targetList.SelectRandom(maxTargets).ToList();
|
||||
else
|
||||
targetList.Resize(maxTargets);
|
||||
|
||||
return targetList;
|
||||
}
|
||||
|
||||
public void DoCast(uint spellId)
|
||||
{
|
||||
Unit target = null;
|
||||
|
||||
switch (AISpellInfo[spellId].target)
|
||||
{
|
||||
default:
|
||||
case AITarget.Self:
|
||||
target = me;
|
||||
break;
|
||||
case AITarget.Victim:
|
||||
target = me.GetVictim();
|
||||
break;
|
||||
case AITarget.Enemy:
|
||||
{
|
||||
var spellInfo = Global.SpellMgr.GetSpellInfo(spellId);
|
||||
if (spellInfo != null)
|
||||
{
|
||||
bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers);
|
||||
target = SelectTarget(SelectAggroTarget.Random, 0, spellInfo.GetMaxRange(false), playerOnly);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AITarget.Ally:
|
||||
case AITarget.Buff:
|
||||
target = me;
|
||||
break;
|
||||
case AITarget.Debuff:
|
||||
{
|
||||
var spellInfo = Global.SpellMgr.GetSpellInfo(spellId);
|
||||
if (spellInfo != null)
|
||||
{
|
||||
bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers);
|
||||
float range = spellInfo.GetMaxRange(false);
|
||||
|
||||
DefaultTargetSelector targetSelector = new DefaultTargetSelector(me, range, playerOnly, -(int)spellId);
|
||||
if (!spellInfo.AuraInterruptFlags.HasAnyFlag(SpellAuraInterruptFlags.NotVictim)
|
||||
&& targetSelector.Check(me.GetVictim()))
|
||||
target = me.GetVictim();
|
||||
else
|
||||
target = SelectTarget(SelectAggroTarget.Random, 0, targetSelector);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target != null)
|
||||
me.CastSpell(target, spellId, false);
|
||||
}
|
||||
|
||||
public void DoCast(Unit victim, uint spellId, bool triggered = false)
|
||||
{
|
||||
if (victim == null || (me.HasUnitState(UnitState.Casting) && !triggered))
|
||||
return;
|
||||
|
||||
me.CastSpell(victim, spellId, triggered);
|
||||
}
|
||||
|
||||
public void DoCastSelf(uint spellId, bool triggered = false) { DoCast(me, spellId, triggered); }
|
||||
|
||||
public void DoCastVictim(uint spellId, bool triggered = false)
|
||||
{
|
||||
if (me.GetVictim() == null || (me.HasUnitState(UnitState.Casting) && !triggered))
|
||||
return;
|
||||
|
||||
me.CastSpell(me.GetVictim(), spellId, triggered);
|
||||
}
|
||||
|
||||
public void DoCastAOE(uint spellId, bool triggered = false)
|
||||
{
|
||||
if (!triggered && me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
me.CastSpell((Unit)null, spellId, triggered);
|
||||
}
|
||||
|
||||
public static void FillAISpellInfo()
|
||||
{
|
||||
var spellStorage = Global.SpellMgr.GetSpellInfoStorage();
|
||||
AISpellInfo = new AISpellInfoType[spellStorage.Keys.Max() + 1];
|
||||
|
||||
foreach (var spellInfo in spellStorage.Values)
|
||||
{
|
||||
AISpellInfoType AIInfo = AISpellInfo[spellInfo.Id];
|
||||
if (spellInfo.HasAttribute(SpellAttr0.CastableWhileDead))
|
||||
AIInfo.condition = AICondition.Die;
|
||||
else if (spellInfo.IsPassive() || spellInfo.GetDuration() == -1)
|
||||
AIInfo.condition = AICondition.Aggro;
|
||||
else
|
||||
AIInfo.condition = AICondition.Combat;
|
||||
|
||||
if (AIInfo.cooldown < spellInfo.RecoveryTime)
|
||||
AIInfo.cooldown = spellInfo.RecoveryTime;
|
||||
|
||||
if (spellInfo.GetMaxRange(false) == 0)
|
||||
{
|
||||
if (AIInfo.target < AITarget.Self)
|
||||
AIInfo.target = AITarget.Self;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (SpellEffectInfo effect in spellInfo.GetEffectsForDifficulty(Difficulty.None))
|
||||
{
|
||||
if (effect == null)
|
||||
continue;
|
||||
|
||||
var targetType = effect.TargetA.GetTarget();
|
||||
|
||||
if (targetType == Targets.UnitEnemy || targetType == Targets.DestEnemy)
|
||||
{
|
||||
if (AIInfo.target < AITarget.Victim)
|
||||
AIInfo.target = AITarget.Victim;
|
||||
}
|
||||
else if (targetType == Targets.UnitDestAreaEnemy)
|
||||
{
|
||||
if (AIInfo.target < AITarget.Enemy)
|
||||
AIInfo.target = AITarget.Enemy;
|
||||
}
|
||||
|
||||
if (effect.Effect == SpellEffectName.ApplyAura)
|
||||
{
|
||||
if (targetType == Targets.UnitEnemy)
|
||||
{
|
||||
if (AIInfo.target < AITarget.Debuff)
|
||||
AIInfo.target = AITarget.Debuff;
|
||||
}
|
||||
else if (spellInfo.IsPositive())
|
||||
{
|
||||
if (AIInfo.target < AITarget.Buff)
|
||||
AIInfo.target = AITarget.Buff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AIInfo.realCooldown = spellInfo.RecoveryTime + spellInfo.StartRecoveryTime;
|
||||
AIInfo.maxRange = spellInfo.GetMaxRange(false) * 3 / 4;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool CanAIAttack(Unit victim) { return true; }
|
||||
|
||||
public virtual void UpdateAI(uint diff) { }
|
||||
|
||||
public virtual void InitializeAI()
|
||||
{
|
||||
if (!me.IsDead())
|
||||
Reset();
|
||||
}
|
||||
|
||||
public virtual void Reset() { }
|
||||
|
||||
public virtual void OnCharmed(bool apply) { }
|
||||
|
||||
public virtual void DoAction(int param) { }
|
||||
public virtual uint GetData(uint id = 0) { return 0; }
|
||||
public virtual void SetData(uint id, uint value) { }
|
||||
public virtual void SetGUID(ObjectGuid guid, int id = 0) { }
|
||||
public virtual ObjectGuid GetGUID(int id = 0) { return ObjectGuid.Empty; }
|
||||
|
||||
public virtual void DamageDealt(Unit victim, ref uint damage, DamageEffectType damageType) { }
|
||||
public virtual void DamageTaken(Unit attacker, ref uint damage) { }
|
||||
public virtual void HealReceived(Unit by, uint addhealth) { }
|
||||
public virtual void HealDone(Unit to, uint addhealth) { }
|
||||
public virtual void SpellInterrupted(uint spellId, uint unTimeMs) {}
|
||||
|
||||
public virtual void sGossipHello(Player player) { }
|
||||
public virtual void sGossipSelect(Player player, uint menuId, uint gossipListId) { }
|
||||
public virtual void sGossipSelectCode(Player player, uint menuId, uint gossipListId, string code) { }
|
||||
public virtual void sQuestAccept(Player player, Quest quest) { }
|
||||
public virtual void sQuestSelect(Player player, Quest quest) { }
|
||||
public virtual void sQuestComplete(Player player, Quest quest) { }
|
||||
public virtual void sQuestReward(Player player, Quest quest, uint opt) { }
|
||||
public virtual bool sOnDummyEffect(Unit caster, uint spellId, int effIndex) { return false; }
|
||||
public virtual void sOnGameEvent(bool start, ushort eventId) { }
|
||||
|
||||
public static AISpellInfoType[] AISpellInfo;
|
||||
|
||||
protected Unit me { get; private set; }
|
||||
}
|
||||
|
||||
public enum SelectAggroTarget
|
||||
{
|
||||
Random = 0, //Just selects a random target
|
||||
TopAggro, //Selects targes from top aggro to bottom
|
||||
BottomAggro, //Selects targets from bottom aggro to top
|
||||
Nearest,
|
||||
Farthest
|
||||
}
|
||||
|
||||
public interface ISelector
|
||||
{
|
||||
bool Check(Unit target);
|
||||
}
|
||||
|
||||
// default predicate function to select target based on distance, player and/or aura criteria
|
||||
public class DefaultTargetSelector : ISelector
|
||||
{
|
||||
Unit me;
|
||||
float m_dist;
|
||||
bool m_playerOnly;
|
||||
int m_aura;
|
||||
|
||||
// unit: the reference unit
|
||||
// dist: if 0: ignored, if > 0: maximum distance to the reference unit, if < 0: minimum distance to the reference unit
|
||||
// playerOnly: self explaining
|
||||
// aura: if 0: ignored, if > 0: the target shall have the aura, if < 0, the target shall NOT have the aura
|
||||
public DefaultTargetSelector(Unit unit, float dist, bool playerOnly, int aura)
|
||||
{
|
||||
me = unit;
|
||||
m_dist = dist;
|
||||
m_playerOnly = playerOnly;
|
||||
m_aura = aura;
|
||||
}
|
||||
|
||||
public bool Check(Unit target)
|
||||
{
|
||||
|
||||
if (me == null)
|
||||
return false;
|
||||
|
||||
if (target == null)
|
||||
return false;
|
||||
|
||||
if (m_playerOnly && !target.IsTypeId(TypeId.Player))
|
||||
return false;
|
||||
|
||||
if (m_dist > 0.0f && !me.IsWithinCombatRange(target, m_dist))
|
||||
return false;
|
||||
|
||||
if (m_dist < 0.0f && me.IsWithinCombatRange(target, -m_dist))
|
||||
return false;
|
||||
|
||||
if (m_aura != 0)
|
||||
{
|
||||
if (m_aura > 0)
|
||||
{
|
||||
if (!target.HasAura((uint)m_aura))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target.HasAura((uint)-m_aura))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Target selector for spell casts checking range, auras and attributes
|
||||
// todo Add more checks from Spell.CheckCast
|
||||
public class SpellTargetSelector : ISelector
|
||||
{
|
||||
public SpellTargetSelector(Unit caster, uint spellId)
|
||||
{
|
||||
_caster = caster;
|
||||
_spellInfo = Global.SpellMgr.GetSpellInfo(spellId);
|
||||
|
||||
Contract.Assert(_spellInfo != null);
|
||||
}
|
||||
|
||||
public bool Check(Unit target)
|
||||
{
|
||||
if (target == null)
|
||||
return false;
|
||||
|
||||
if (_spellInfo.CheckTarget(_caster, target) != SpellCastResult.SpellCastOk)
|
||||
return false;
|
||||
|
||||
// copypasta from Spell.CheckRange
|
||||
float minRange = 0.0f;
|
||||
float maxRange = 0.0f;
|
||||
float rangeMod = 0.0f;
|
||||
if (_spellInfo.RangeEntry != null)
|
||||
{
|
||||
if (_spellInfo.RangeEntry.Flags.HasAnyFlag(SpellRangeFlag.Melee))
|
||||
{
|
||||
rangeMod = _caster.GetCombatReach() + 4.0f / 3.0f;
|
||||
rangeMod += target.GetCombatReach();
|
||||
|
||||
rangeMod = Math.Max(rangeMod, SharedConst.NominalMeleeRange);
|
||||
}
|
||||
else
|
||||
{
|
||||
float meleeRange = 0.0f;
|
||||
if (_spellInfo.RangeEntry.Flags.HasAnyFlag(SpellRangeFlag.Ranged))
|
||||
{
|
||||
meleeRange = _caster.GetCombatReach() + 4.0f / 3.0f;
|
||||
meleeRange += target.GetCombatReach();
|
||||
|
||||
meleeRange = Math.Max(meleeRange, SharedConst.NominalMeleeRange);
|
||||
}
|
||||
|
||||
minRange = _caster.GetSpellMinRangeForTarget(target, _spellInfo) + meleeRange;
|
||||
maxRange = _caster.GetSpellMaxRangeForTarget(target, _spellInfo);
|
||||
|
||||
rangeMod = _caster.GetCombatReach();
|
||||
rangeMod += target.GetCombatReach();
|
||||
|
||||
if (minRange > 0.0f && !_spellInfo.RangeEntry.Flags.HasAnyFlag(SpellRangeFlag.Ranged))
|
||||
minRange += rangeMod;
|
||||
}
|
||||
|
||||
if (_caster.isMoving() && target.isMoving() && !_caster.IsWalking() && !target.IsWalking() &&
|
||||
(_spellInfo.RangeEntry.Flags.HasAnyFlag(SpellRangeFlag.Melee) || target.IsTypeId(TypeId.Player)))
|
||||
rangeMod += 8.0f / 3.0f;
|
||||
}
|
||||
|
||||
maxRange += rangeMod;
|
||||
|
||||
minRange *= minRange;
|
||||
maxRange *= maxRange;
|
||||
|
||||
if (target != _caster)
|
||||
{
|
||||
if (_caster.GetExactDistSq(target) > maxRange)
|
||||
return false;
|
||||
|
||||
if (minRange > 0.0f && _caster.GetExactDistSq(target) < minRange)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit _caster;
|
||||
SpellInfo _spellInfo;
|
||||
}
|
||||
|
||||
// Very simple target selector, will just skip main target
|
||||
// NOTE: When passing to UnitAI.SelectTarget remember to use 0 as position for random selection
|
||||
// because tank will not be in the temporary list
|
||||
public class NonTankTargetSelector : ISelector
|
||||
{
|
||||
public NonTankTargetSelector(Unit source, bool playerOnly = true)
|
||||
{
|
||||
_source = source;
|
||||
_playerOnly = playerOnly;
|
||||
}
|
||||
|
||||
public bool Check(Unit target)
|
||||
{
|
||||
if (target == null)
|
||||
return false;
|
||||
|
||||
if (_playerOnly && !target.IsTypeId(TypeId.Player))
|
||||
return false;
|
||||
|
||||
HostileReference currentVictim = _source.GetThreatManager().getCurrentVictim();
|
||||
if (currentVictim != null)
|
||||
return target.GetGUID() != currentVictim.getUnitGuid();
|
||||
|
||||
return target != _source.GetVictim();
|
||||
}
|
||||
|
||||
Unit _source;
|
||||
bool _playerOnly;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,803 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class ScriptedAI : CreatureAI
|
||||
{
|
||||
public ScriptedAI(Creature creature) : base(creature)
|
||||
{
|
||||
_isCombatMovementAllowed = true;
|
||||
_isHeroic = me.GetMap().IsHeroic();
|
||||
_difficulty = me.GetMap().GetSpawnMode();
|
||||
}
|
||||
|
||||
void AttackStartNoMove(Unit target)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
if (me.Attack(target, true))
|
||||
DoStartNoMovement(target);
|
||||
}
|
||||
|
||||
// Called before EnterCombat even before the creature is in combat.
|
||||
public override void AttackStart(Unit target)
|
||||
{
|
||||
if (IsCombatMovementAllowed())
|
||||
base.AttackStart(target);
|
||||
else
|
||||
AttackStartNoMove(target);
|
||||
}
|
||||
|
||||
//Called at World update tick
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
//Check if we have a current target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
//Start movement toward victim
|
||||
public void DoStartMovement(Unit target, float distance = 0.0f, float angle = 0.0f)
|
||||
{
|
||||
if (target != null)
|
||||
me.GetMotionMaster().MoveChase(target, distance, angle);
|
||||
}
|
||||
|
||||
//Start no movement on victim
|
||||
public void DoStartNoMovement(Unit target)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
}
|
||||
|
||||
//Stop attack of current victim
|
||||
public void DoStopAttack()
|
||||
{
|
||||
if (me.GetVictim() != null)
|
||||
me.AttackStop();
|
||||
}
|
||||
|
||||
//Cast spell by spell info
|
||||
void DoCastSpell(Unit target, SpellInfo spellInfo, bool triggered = false)
|
||||
{
|
||||
if (target == null || me.IsNonMeleeSpellCast(false))
|
||||
return;
|
||||
|
||||
me.StopMoving();
|
||||
me.CastSpell(target, spellInfo, triggered ? TriggerCastFlags.FullMask : TriggerCastFlags.None);
|
||||
}
|
||||
|
||||
//Plays a sound to all nearby players
|
||||
public void DoPlaySoundToSet(WorldObject source, uint soundId)
|
||||
{
|
||||
if (source == null)
|
||||
return;
|
||||
|
||||
if (!CliDB.SoundKitStorage.ContainsKey(soundId))
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, "Invalid soundId {0} used in DoPlaySoundToSet (Source: TypeId {1}, GUID {2})", soundId, source.GetTypeId(), source.GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
source.PlayDirectSound(soundId);
|
||||
}
|
||||
|
||||
//Spawns a creature relative to me
|
||||
public Creature DoSpawnCreature(uint entry, float offsetX, float offsetY, float offsetZ, float angle, TempSummonType type, uint despawntime)
|
||||
{
|
||||
return me.SummonCreature(entry, me.GetPositionX() + offsetX, me.GetPositionY() + offsetY, me.GetPositionZ() + offsetZ, angle, type, despawntime);
|
||||
}
|
||||
|
||||
//Returns spells that meet the specified criteria from the creatures spell list
|
||||
public SpellInfo SelectSpell(Unit target, SpellSchoolMask school, Mechanics mechanic, SelectTargetType targets, float rangeMin, float rangeMax, SelectEffect effect)
|
||||
{
|
||||
//No target so we can't cast
|
||||
if (target == null)
|
||||
return null;
|
||||
|
||||
//Silenced so we can't cast
|
||||
if (me.HasFlag(UnitFields.Flags, UnitFlags.Silenced))
|
||||
return null;
|
||||
|
||||
//Using the extended script system we first create a list of viable spells
|
||||
SpellInfo[] apSpell = new SpellInfo[SharedConst.MaxCreatureSpells];
|
||||
|
||||
uint spellCount = 0;
|
||||
|
||||
SpellInfo tempSpell = null;
|
||||
|
||||
//Check if each spell is viable(set it to null if not)
|
||||
for (uint i = 0; i < SharedConst.MaxCreatureSpells; i++)
|
||||
{
|
||||
tempSpell = Global.SpellMgr.GetSpellInfo(me.m_spells[i]);
|
||||
|
||||
//This spell doesn't exist
|
||||
if (tempSpell == null)
|
||||
continue;
|
||||
|
||||
// Targets and Effects checked first as most used restrictions
|
||||
//Check the spell targets if specified
|
||||
if (targets != 0 && !Convert.ToBoolean(Global.ScriptMgr.spellSummaryStorage[me.m_spells[i]].Targets & (1 << ((int)targets - 1))))
|
||||
continue;
|
||||
|
||||
//Check the type of spell if we are looking for a specific spell type
|
||||
if (effect != 0 && !Convert.ToBoolean(Global.ScriptMgr.spellSummaryStorage[me.m_spells[i]].Effects & (1 << ((int)effect - 1))))
|
||||
continue;
|
||||
|
||||
//Check for school if specified
|
||||
if (school != 0 && (tempSpell.SchoolMask & school) == 0)
|
||||
continue;
|
||||
|
||||
//Check for spell mechanic if specified
|
||||
if (mechanic != 0 && tempSpell.Mechanic != mechanic)
|
||||
continue;
|
||||
|
||||
//Check if the spell meets our range requirements
|
||||
if (rangeMin != 0 && me.GetSpellMinRangeForTarget(target, tempSpell) < rangeMin)
|
||||
continue;
|
||||
if (rangeMax != 0 && me.GetSpellMaxRangeForTarget(target, tempSpell) > rangeMax)
|
||||
continue;
|
||||
|
||||
//Check if our target is in range
|
||||
if (me.IsWithinDistInMap(target, me.GetSpellMinRangeForTarget(target, tempSpell)) || !me.IsWithinDistInMap(target, me.GetSpellMaxRangeForTarget(target, tempSpell)))
|
||||
continue;
|
||||
|
||||
//All good so lets add it to the spell list
|
||||
apSpell[spellCount] = tempSpell;
|
||||
++spellCount;
|
||||
}
|
||||
|
||||
//We got our usable spells so now lets randomly pick one
|
||||
if (spellCount == 0)
|
||||
return null;
|
||||
|
||||
return apSpell[RandomHelper.IRand(0, (int)(spellCount - 1))];
|
||||
}
|
||||
|
||||
//Drops all threat to 0%. Does not remove players from the threat list
|
||||
public void DoResetThreat()
|
||||
{
|
||||
if (!me.CanHaveThreatList() || me.GetThreatManager().isThreatListEmpty())
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, "DoResetThreat called for creature that either cannot have threat list or has empty threat list (me entry = {0})", me.GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
var threatlist = me.GetThreatManager().getThreatList();
|
||||
|
||||
foreach (var refe in threatlist)
|
||||
{
|
||||
Unit unit = Global.ObjAccessor.GetUnit(me, refe.getUnitGuid());
|
||||
if (unit != null && DoGetThreat(unit) != 0)
|
||||
DoModifyThreatPercent(unit, -100);
|
||||
}
|
||||
}
|
||||
|
||||
public float DoGetThreat(Unit unit)
|
||||
{
|
||||
if (unit == null)
|
||||
return 0.0f;
|
||||
return me.GetThreatManager().getThreat(unit);
|
||||
}
|
||||
|
||||
public void DoModifyThreatPercent(Unit unit, int pct)
|
||||
{
|
||||
if (unit == null)
|
||||
return;
|
||||
me.GetThreatManager().modifyThreatPercent(unit, pct);
|
||||
}
|
||||
|
||||
void DoTeleportTo(float x, float y, float z, uint time = 0)
|
||||
{
|
||||
me.Relocate(x, y, z);
|
||||
float speed = me.GetDistance(x, y, z) / (time * 0.001f);
|
||||
me.MonsterMoveWithSpeed(x, y, z, speed);
|
||||
}
|
||||
|
||||
void DoTeleportTo(float[] position)
|
||||
{
|
||||
me.NearTeleportTo(position[0], position[1], position[2], position[3]);
|
||||
}
|
||||
|
||||
//Teleports a player without dropping threat (only teleports to same map)
|
||||
void DoTeleportPlayer(Unit unit, float x, float y, float z, float o)
|
||||
{
|
||||
if (unit == null)
|
||||
return;
|
||||
Player player = unit.ToPlayer();
|
||||
if (player != null)
|
||||
player.TeleportTo(unit.GetMapId(), x, y, z, o, TeleportToOptions.NotLeaveCombat);
|
||||
else
|
||||
Log.outError(LogFilter.Scripts, "Creature {0} (Entry: {1}) Tried to teleport non-player unit (Type: {2} GUID: {3}) to X: {4} Y: {5} Z: {6} O: {7}. Aborted.",
|
||||
me.GetGUID(), me.GetEntry(), unit.GetTypeId(), unit.GetGUID(), x, y, z, o);
|
||||
}
|
||||
|
||||
void DoTeleportAll(float x, float y, float z, float o)
|
||||
{
|
||||
Map map = me.GetMap();
|
||||
if (!map.IsDungeon())
|
||||
return;
|
||||
|
||||
var PlayerList = map.GetPlayers();
|
||||
foreach (var player in PlayerList)
|
||||
if (player.IsAlive())
|
||||
player.TeleportTo(me.GetMapId(), x, y, z, o, TeleportToOptions.NotLeaveCombat);
|
||||
|
||||
}
|
||||
|
||||
//Returns friendly unit with the most amount of hp missing from max hp
|
||||
public Unit DoSelectLowestHpFriendly(float range, uint minHPDiff = 1)
|
||||
{
|
||||
var u_check = new MostHPMissingInRange<Unit>(me, range, minHPDiff);
|
||||
var searcher = new UnitLastSearcher(me, u_check);
|
||||
Cell.VisitAllObjects(me, searcher, range);
|
||||
|
||||
return searcher.GetTarget();
|
||||
}
|
||||
|
||||
//Returns a list of friendly CC'd units within range
|
||||
List<Creature> DoFindFriendlyCC(float range)
|
||||
{
|
||||
List<Creature> list = new List<Creature>();
|
||||
var u_check = new FriendlyCCedInRange(me, range);
|
||||
var searcher = new CreatureListSearcher(me, list, u_check);
|
||||
Cell.VisitAllObjects(me, searcher, range);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
//Returns a list of all friendly units missing a specific buff within range
|
||||
public List<Creature> DoFindFriendlyMissingBuff(float range, uint spellId)
|
||||
{
|
||||
List<Creature> list = new List<Creature>();
|
||||
var u_check = new FriendlyMissingBuffInRange(me, range, spellId);
|
||||
var searcher = new CreatureListSearcher(me, list, u_check);
|
||||
Cell.VisitAllObjects(me, searcher, range);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
//Return a player with at least minimumRange from me
|
||||
Player GetPlayerAtMinimumRange(float minimumRange)
|
||||
{
|
||||
var check = new PlayerAtMinimumRangeAway(me, minimumRange);
|
||||
var searcher = new PlayerSearcher(me, check);
|
||||
Cell.VisitWorldObjects(me, searcher, minimumRange);
|
||||
|
||||
return searcher.GetTarget();
|
||||
}
|
||||
|
||||
public void SetEquipmentSlots(bool loadDefault, int mainHand = -1, int offHand = -1, int ranged = -1)
|
||||
{
|
||||
if (loadDefault)
|
||||
{
|
||||
me.LoadEquipment(me.GetOriginalEquipmentId(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mainHand >= 0)
|
||||
me.SetVirtualItem(0, (uint)mainHand);
|
||||
|
||||
if (offHand >= 0)
|
||||
me.SetVirtualItem(1, (uint)offHand);
|
||||
|
||||
if (ranged >= 0)
|
||||
me.SetVirtualItem(2, (uint)ranged);
|
||||
}
|
||||
|
||||
// Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
|
||||
// NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart
|
||||
// You should make the necessary to make it happen so.
|
||||
// Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset().
|
||||
// It will keep the last value you set.
|
||||
public void SetCombatMovement(bool allowMovement)
|
||||
{
|
||||
_isCombatMovementAllowed = allowMovement;
|
||||
}
|
||||
|
||||
/*bool EnterEvadeIfOutOfCombatArea(uint diff)
|
||||
{
|
||||
if (_evadeCheckCooldown <= diff)
|
||||
_evadeCheckCooldown = 2500;
|
||||
else
|
||||
{
|
||||
_evadeCheckCooldown -= diff;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (me.IsInEvadeMode() || me.GetVictim() == null)
|
||||
return false;
|
||||
|
||||
float x = me.GetPositionX();
|
||||
float y = me.GetPositionY();
|
||||
float z = me.GetPositionZ();
|
||||
|
||||
switch (me.GetEntry())
|
||||
{
|
||||
case 12017: // broodlord (not move down stairs)
|
||||
if (z > 448.60f)
|
||||
return false;
|
||||
break;
|
||||
case 19516: // void reaver (calculate from center of room)
|
||||
if (me.GetDistance2d(432.59f, 371.93f) < 105.0f)
|
||||
return false;
|
||||
break;
|
||||
case 23578: // jan'alai (calculate by Z)
|
||||
if (z > 12.0f)
|
||||
return false;
|
||||
break;
|
||||
case 28860: // sartharion (calculate box)
|
||||
if (x > 3218.86f && x < 3275.69f && y < 572.40f && y > 484.68f)
|
||||
return false;
|
||||
break;
|
||||
default: // For most of creatures that certain area is their home area.
|
||||
Log.outInfo(LogFilter.Server, "Scripts: EnterEvadeIfOutOfCombatArea used for creature entry {0}, but does not have any definition. Using the default one.", me.GetEntry());
|
||||
uint homeAreaId = me.GetMap().GetAreaId(me.GetHomePosition().posX, me.GetHomePosition().posY, me.GetHomePosition().posZ);
|
||||
if (me.GetAreaId() == homeAreaId)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
EnterEvadeMode();
|
||||
return true;
|
||||
}*/
|
||||
|
||||
// Called at any Damage from any attacker (before damage apply)
|
||||
public override void DamageTaken(Unit attacker, ref uint damage) { }
|
||||
|
||||
//Called at creature death
|
||||
public override void JustDied(Unit killer) { }
|
||||
|
||||
//Called at creature killing another unit
|
||||
public override void KilledUnit(Unit victim) { }
|
||||
|
||||
// Called when the creature summon successfully other creature
|
||||
public override void JustSummoned(Creature summon) { }
|
||||
|
||||
// Called when a summoned creature is despawned
|
||||
public override void SummonedCreatureDespawn(Creature summon) { }
|
||||
|
||||
// Called when hit by a spell
|
||||
public override void SpellHit(Unit caster, SpellInfo spell) { }
|
||||
|
||||
// Called when spell hits a target
|
||||
public override void SpellHitTarget(Unit target, SpellInfo spell) { }
|
||||
|
||||
//Called at waypoint reached or PointMovement end
|
||||
public override void MovementInform(MovementGeneratorType type, uint id) { }
|
||||
|
||||
// Called when AI is temporarily replaced or put back when possess is applied or removed
|
||||
public virtual void OnPossess(bool apply) { }
|
||||
|
||||
public static Creature GetClosestCreatureWithEntry(WorldObject source, uint entry, float maxSearchRange, bool alive = true)
|
||||
{
|
||||
return source.FindNearestCreature(entry, maxSearchRange, alive);
|
||||
}
|
||||
|
||||
public GameObject GetClosestGameObjectWithEntry(WorldObject source, uint entry, float maxSearchRange)
|
||||
{
|
||||
return source.FindNearestGameObject(entry, maxSearchRange);
|
||||
}
|
||||
|
||||
//Called at creature reset either by death or evade
|
||||
public override void Reset() { }
|
||||
|
||||
//Called at creature aggro either by MoveInLOS or Attack Start
|
||||
public override void EnterCombat(Unit victim) { }
|
||||
|
||||
public bool HealthBelowPct(int pct) { return me.HealthBelowPct(pct); }
|
||||
public bool HealthAbovePct(int pct) { return me.HealthAbovePct(pct); }
|
||||
|
||||
public bool IsCombatMovementAllowed() { return _isCombatMovementAllowed; }
|
||||
|
||||
// return true for heroic mode. i.e.
|
||||
// - for dungeon in mode 10-heroic,
|
||||
// - for raid in mode 10-Heroic
|
||||
// - for raid in mode 25-heroic
|
||||
// DO NOT USE to check raid in mode 25-normal.
|
||||
public bool IsHeroic() { return _isHeroic; }
|
||||
|
||||
// return the dungeon or raid difficulty
|
||||
public Difficulty GetDifficulty() { return _difficulty; }
|
||||
|
||||
// return true for 25 man or 25 man heroic mode
|
||||
public bool Is25ManRaid() { return _difficulty == Difficulty.Raid25N || _difficulty == Difficulty.Raid25HC; }
|
||||
|
||||
public T DungeonMode<T>(T normal5, T heroic10)
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
case Difficulty.Normal:
|
||||
return normal5;
|
||||
case Difficulty.Heroic:
|
||||
default:
|
||||
return heroic10;
|
||||
}
|
||||
}
|
||||
|
||||
public T RaidMode<T>(T normal10, T normal25)
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
case Difficulty.Raid10N:
|
||||
return normal10;
|
||||
case Difficulty.Raid25N:
|
||||
default:
|
||||
return normal25;
|
||||
}
|
||||
}
|
||||
public T RaidMode<T>(T normal10, T normal25, T heroic10, T heroic25)
|
||||
{
|
||||
switch (_difficulty)
|
||||
{
|
||||
case Difficulty.Raid10N:
|
||||
return normal10;
|
||||
case Difficulty.Raid25N:
|
||||
return normal25;
|
||||
case Difficulty.Raid10HC:
|
||||
return heroic10;
|
||||
case Difficulty.Raid25HC:
|
||||
default:
|
||||
return heroic25;
|
||||
}
|
||||
}
|
||||
|
||||
Difficulty _difficulty;
|
||||
bool _isCombatMovementAllowed;
|
||||
bool _isHeroic;
|
||||
}
|
||||
|
||||
public class BossAI : ScriptedAI
|
||||
{
|
||||
public BossAI(Creature creature, uint bossId) : base(creature)
|
||||
{
|
||||
instance = creature.GetInstanceScript();
|
||||
summons = new SummonList(creature);
|
||||
_bossId = bossId;
|
||||
|
||||
if (instance != null)
|
||||
SetBoundary(instance.GetBossBoundary(bossId));
|
||||
|
||||
_scheduler.SetValidator(() =>
|
||||
{
|
||||
return !me.HasUnitState(UnitState.Casting);
|
||||
});
|
||||
}
|
||||
|
||||
public void _Reset()
|
||||
{
|
||||
if (!me.IsAlive())
|
||||
return;
|
||||
|
||||
me.SetCombatPulseDelay(0);
|
||||
me.ResetLootMode();
|
||||
_events.Reset();
|
||||
summons.DespawnAll();
|
||||
_scheduler.CancelAll();
|
||||
if (instance != null)
|
||||
instance.SetBossState(_bossId, EncounterState.NotStarted);
|
||||
}
|
||||
|
||||
public void _JustDied()
|
||||
{
|
||||
_events.Reset();
|
||||
summons.DespawnAll();
|
||||
_scheduler.CancelAll();
|
||||
if (instance != null)
|
||||
instance.SetBossState(_bossId, EncounterState.Done);
|
||||
}
|
||||
|
||||
public void _EnterCombat()
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
// bosses do not respawn, check only on enter combat
|
||||
if (!instance.CheckRequiredBosses(_bossId))
|
||||
{
|
||||
EnterEvadeMode(EvadeReason.SequenceBreak);
|
||||
return;
|
||||
}
|
||||
instance.SetBossState(_bossId, EncounterState.InProgress);
|
||||
}
|
||||
|
||||
me.SetCombatPulseDelay(5);
|
||||
me.setActive(true);
|
||||
DoZoneInCombat();
|
||||
ScheduleTasks();
|
||||
}
|
||||
|
||||
void TeleportCheaters()
|
||||
{
|
||||
float x, y, z;
|
||||
me.GetPosition(out x, out y, out z);
|
||||
|
||||
var threatList = me.GetThreatManager().getThreatList();
|
||||
foreach (var refe in threatList)
|
||||
{
|
||||
Unit target = refe.getTarget();
|
||||
if (target)
|
||||
if (target.IsTypeId(TypeId.Player) && !CheckBoundary(target))
|
||||
target.NearTeleportTo(x, y, z, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustSummoned(Creature summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
if (me.IsInCombat())
|
||||
DoZoneInCombat(summon);
|
||||
}
|
||||
|
||||
public override void SummonedCreatureDespawn(Creature summon)
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
|
||||
_events.ExecuteEvents(eventId =>
|
||||
{
|
||||
ExecuteEvent(eventId);
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
});
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
public void _DespawnAtEvade(uint delayToRespawn = 30, Creature who = null)
|
||||
{
|
||||
if (delayToRespawn < 2)
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, "_DespawnAtEvade called with delay of {0} seconds, defaulting to 2.", delayToRespawn);
|
||||
delayToRespawn = 2;
|
||||
}
|
||||
|
||||
if (!who)
|
||||
who = me;
|
||||
|
||||
TempSummon whoSummon = who.ToTempSummon();
|
||||
if (whoSummon)
|
||||
{
|
||||
Log.outWarn(LogFilter.ScriptsAi, "_DespawnAtEvade called on a temporary summon.");
|
||||
whoSummon.UnSummon();
|
||||
return;
|
||||
}
|
||||
|
||||
who.DespawnOrUnsummon(0, TimeSpan.FromSeconds(delayToRespawn));
|
||||
|
||||
if (instance != null && who == me)
|
||||
instance.SetBossState(_bossId, EncounterState.Fail);
|
||||
}
|
||||
|
||||
public virtual void ExecuteEvent(uint eventId) { }
|
||||
|
||||
public virtual void ScheduleTasks() { }
|
||||
|
||||
public override void Reset() { _Reset(); }
|
||||
public override void EnterCombat(Unit who) { _EnterCombat(); }
|
||||
public override void JustDied(Unit killer) { _JustDied(); }
|
||||
public override void JustReachedHome() { _JustReachedHome(); }
|
||||
|
||||
public override bool CanAIAttack(Unit victim) { return CheckBoundary(victim); }
|
||||
|
||||
public void _JustReachedHome() { me.setActive(false); }
|
||||
|
||||
public InstanceScript instance;
|
||||
public SummonList summons;
|
||||
uint _bossId;
|
||||
}
|
||||
|
||||
public class WorldBossAI : ScriptedAI
|
||||
{
|
||||
public WorldBossAI(Creature creature) : base(creature)
|
||||
{
|
||||
summons = new SummonList(creature);
|
||||
}
|
||||
|
||||
void _Reset()
|
||||
{
|
||||
if (!me.IsAlive())
|
||||
return;
|
||||
|
||||
_events.Reset();
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void _JustDied()
|
||||
{
|
||||
_events.Reset();
|
||||
summons.DespawnAll();
|
||||
}
|
||||
|
||||
void _EnterCombat()
|
||||
{
|
||||
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 0.0f, true);
|
||||
if (target)
|
||||
AttackStart(target);
|
||||
}
|
||||
|
||||
public override void JustSummoned(Creature summon)
|
||||
{
|
||||
summons.Summon(summon);
|
||||
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 0.0f, true);
|
||||
if (target)
|
||||
summon.GetAI().AttackStart(target);
|
||||
}
|
||||
|
||||
public override void SummonedCreatureDespawn(Creature summon)
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
|
||||
_events.ExecuteEvents(eventId =>
|
||||
{
|
||||
ExecuteEvent(eventId);
|
||||
|
||||
if (me.HasUnitState(UnitState.Casting))
|
||||
return;
|
||||
});
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
// Hook used to execute events scheduled into EventMap without the need
|
||||
// to override UpdateAI
|
||||
// note: You must re-schedule the event within this method if the event
|
||||
// is supposed to run more than once
|
||||
public virtual void ExecuteEvent(uint eventId) { }
|
||||
|
||||
public override void Reset() { _Reset(); }
|
||||
|
||||
public override void EnterCombat(Unit who) { _EnterCombat(); }
|
||||
|
||||
public override void JustDied(Unit killer) { _JustDied(); }
|
||||
|
||||
SummonList summons;
|
||||
}
|
||||
|
||||
public class SummonList : List<ObjectGuid>
|
||||
{
|
||||
public SummonList(Creature creature)
|
||||
{
|
||||
me = creature;
|
||||
}
|
||||
|
||||
public void Summon(Creature summon) { Add(summon.GetGUID()); }
|
||||
|
||||
public void DoZoneInCombat(uint entry = 0, float maxRangeToNearestTarget = 250.0f)
|
||||
{
|
||||
foreach (var id in this)
|
||||
{
|
||||
Creature summon = ObjectAccessor.GetCreature(me, id);
|
||||
if (summon && summon.IsAIEnabled && (entry == 0 || summon.GetEntry() == entry))
|
||||
{
|
||||
summon.GetAI().DoZoneInCombat(null, maxRangeToNearestTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DespawnEntry(uint entry)
|
||||
{
|
||||
foreach (var id in this)
|
||||
{
|
||||
Creature summon = ObjectAccessor.GetCreature(me, id);
|
||||
if (!summon)
|
||||
Remove(id);
|
||||
else if (summon.GetEntry() == entry)
|
||||
{
|
||||
Remove(id);
|
||||
summon.DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DespawnAll()
|
||||
{
|
||||
while (!this.Empty())
|
||||
{
|
||||
Creature summon = ObjectAccessor.GetCreature(me, this.FirstOrDefault());
|
||||
this.RemoveAt(0);
|
||||
if (summon)
|
||||
summon.DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
public void Despawn(Creature summon) { Remove(summon.GetGUID()); }
|
||||
|
||||
public void DespawnIf(Predicate<ObjectGuid> predicate)
|
||||
{
|
||||
RemoveAll(predicate);
|
||||
}
|
||||
|
||||
public void RemoveNotExisting()
|
||||
{
|
||||
foreach (var id in this.ToList())
|
||||
{
|
||||
if (!ObjectAccessor.GetCreature(me, id))
|
||||
Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
public void DoAction(int info, Predicate<ObjectGuid> predicate, ushort max = 0)
|
||||
{
|
||||
// We need to use a copy of SummonList here, otherwise original SummonList would be modified
|
||||
List<ObjectGuid> listCopy = new List<ObjectGuid>(this);
|
||||
listCopy.RandomResize(predicate, max);
|
||||
DoActionImpl(info, listCopy);
|
||||
}
|
||||
|
||||
public bool HasEntry(uint entry)
|
||||
{
|
||||
foreach (var id in this)
|
||||
{
|
||||
Creature summon = ObjectAccessor.GetCreature(me, id);
|
||||
if (summon && summon.GetEntry() == entry)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DoActionImpl(int action, List<ObjectGuid> summons)
|
||||
{
|
||||
foreach (var guid in summons)
|
||||
{
|
||||
Creature summon = ObjectAccessor.GetCreature(me, guid);
|
||||
if (summon && summon.IsAIEnabled)
|
||||
summon.GetAI().DoAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
Creature me;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
public class npc_escortAI : ScriptedAI
|
||||
{
|
||||
public npc_escortAI(Creature creature) : base(creature)
|
||||
{
|
||||
m_uiPlayerGUID = ObjectGuid.Empty;
|
||||
m_uiWPWaitTimer = 2500;
|
||||
m_uiPlayerCheckTimer = 1000;
|
||||
m_uiEscortState = eEscortState.None;
|
||||
MaxPlayerDistance = 50;
|
||||
m_pQuestForEscort = null;
|
||||
m_bIsActiveAttacker = true;
|
||||
m_bIsRunning = false;
|
||||
m_bCanInstantRespawn = false;
|
||||
m_bCanReturnToStart = false;
|
||||
DespawnAtEnd = true;
|
||||
DespawnAtFar = true;
|
||||
ScriptWP = false;
|
||||
HasImmuneToNPCFlags = false;
|
||||
}
|
||||
|
||||
public override void AttackStart(Unit who)
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me.Attack(who, true))
|
||||
{
|
||||
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Point)
|
||||
me.GetMotionMaster().MovementExpired();
|
||||
|
||||
if (IsCombatMovementAllowed())
|
||||
me.GetMotionMaster().MoveChase(who);
|
||||
}
|
||||
}
|
||||
|
||||
//see followerAI
|
||||
bool AssistPlayerInCombatAgainst(Unit who)
|
||||
{
|
||||
if (!who || !who.GetVictim())
|
||||
return false;
|
||||
|
||||
//experimental (unknown) flag not present
|
||||
if (!me.GetCreatureTemplate().TypeFlags.HasAnyFlag(CreatureTypeFlags.CanAssist))
|
||||
return false;
|
||||
|
||||
//not a player
|
||||
if (!who.GetVictim().GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
return false;
|
||||
|
||||
//never attack friendly
|
||||
if (me.IsFriendlyTo(who))
|
||||
return false;
|
||||
|
||||
//too far away and no free sight?
|
||||
if (me.IsWithinDistInMap(who, GetMaxPlayerDistance()) && me.IsWithinLOSInMap(who))
|
||||
{
|
||||
//already fighting someone?
|
||||
if (!me.GetVictim())
|
||||
{
|
||||
AttackStart(who);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
who.SetInCombatWith(me);
|
||||
me.AddThreat(who, 0.0f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void MoveInLineOfSight(Unit who)
|
||||
{
|
||||
if (me.HasReactState(ReactStates.Aggressive) && !me.HasUnitState(UnitState.Stunned) && who.isTargetableForAttack() && who.isInAccessiblePlaceFor(me))
|
||||
{
|
||||
if (HasEscortState(eEscortState.Escorting) && AssistPlayerInCombatAgainst(who))
|
||||
return;
|
||||
|
||||
if (!me.CanFly() && me.GetDistanceZ(who) > SharedConst.CreatureAttackRangeZ)
|
||||
return;
|
||||
|
||||
if (me.IsHostileTo(who))
|
||||
{
|
||||
float fAttackRadius = me.GetAttackDistance(who);
|
||||
if (me.IsWithinDistInMap(who, fAttackRadius) && me.IsWithinLOSInMap(who))
|
||||
{
|
||||
if (!me.GetVictim())
|
||||
{
|
||||
// Clear distracted state on combat
|
||||
if (me.HasUnitState(UnitState.Distracted))
|
||||
{
|
||||
me.ClearUnitState(UnitState.Distracted);
|
||||
me.GetMotionMaster().Clear();
|
||||
}
|
||||
|
||||
AttackStart(who);
|
||||
}
|
||||
else if (me.GetMap().IsDungeon())
|
||||
{
|
||||
who.SetInCombatWith(me);
|
||||
me.AddThreat(who, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
if (!HasEscortState(eEscortState.Escorting) || m_uiPlayerGUID.IsEmpty() || m_pQuestForEscort == null)
|
||||
return;
|
||||
|
||||
Player player = GetPlayerForEscort();
|
||||
if (player)
|
||||
{
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
|
||||
{
|
||||
Player member = groupRef.GetSource();
|
||||
if (member)
|
||||
member.FailQuest(m_pQuestForEscort.Id);
|
||||
}
|
||||
}
|
||||
else
|
||||
player.FailQuest(m_pQuestForEscort.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustRespawned()
|
||||
{
|
||||
m_uiEscortState = eEscortState.None;
|
||||
|
||||
if (!IsCombatMovementAllowed())
|
||||
SetCombatMovement(true);
|
||||
|
||||
//add a small delay before going to first waypoint, normal in near all cases
|
||||
m_uiWPWaitTimer = 2500;
|
||||
|
||||
if (me.getFaction() != me.GetCreatureTemplate().Faction)
|
||||
me.RestoreFaction();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void ReturnToLastPoint()
|
||||
{
|
||||
float x, y, z, o;
|
||||
me.GetHomePosition(out x, out y, out z, out o);
|
||||
me.GetMotionMaster().MovePoint(0xFFFFFF, x, y, z);
|
||||
}
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why = EvadeReason.Other)
|
||||
{
|
||||
me.RemoveAllAuras();
|
||||
me.DeleteThreatList();
|
||||
me.CombatStop(true);
|
||||
me.SetLootRecipient(null);
|
||||
|
||||
if (HasEscortState(eEscortState.Escorting))
|
||||
{
|
||||
AddEscortState(eEscortState.Returning);
|
||||
ReturnToLastPoint();
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI has left combat and is now returning to last point");
|
||||
}
|
||||
else
|
||||
{
|
||||
me.GetMotionMaster().MoveTargetedHome();
|
||||
if (HasImmuneToNPCFlags)
|
||||
me.SetFlag(UnitFields.Flags, UnitFlags.ImmuneToNpc);
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool IsPlayerOrGroupInRange()
|
||||
{
|
||||
Player player = GetPlayerForEscort();
|
||||
if (player)
|
||||
{
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
|
||||
{
|
||||
Player member = groupRef.GetSource();
|
||||
if (member)
|
||||
if (me.IsWithinDistInMap(member, GetMaxPlayerDistance()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (me.IsWithinDistInMap(player, GetMaxPlayerDistance()))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint diff)
|
||||
{
|
||||
//Waypoint Updating
|
||||
if (HasEscortState(eEscortState.Escorting) && !me.GetVictim() && m_uiWPWaitTimer != 0 && !HasEscortState(eEscortState.Returning))
|
||||
{
|
||||
if (m_uiWPWaitTimer <= diff)
|
||||
{
|
||||
//End of the line
|
||||
if (WPIndex == WaypointList.Count)
|
||||
{
|
||||
if (DespawnAtEnd)
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI reached end of waypoints");
|
||||
|
||||
if (m_bCanReturnToStart)
|
||||
{
|
||||
float fRetX, fRetY, fRetZ;
|
||||
me.GetRespawnPosition(out fRetX, out fRetY, out fRetZ);
|
||||
|
||||
me.GetMotionMaster().MovePoint(0xFFFFFE, fRetX, fRetY, fRetZ);
|
||||
|
||||
m_uiWPWaitTimer = 0;
|
||||
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI are returning home to spawn location: {0}, {1}, {2}, {3}", 0xFFFFFE, fRetX, fRetY, fRetZ);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_bCanInstantRespawn)
|
||||
{
|
||||
me.setDeathState(DeathState.JustDied);
|
||||
me.Respawn();
|
||||
}
|
||||
else
|
||||
me.DespawnOrUnsummon();
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI reached end of waypoints with Despawn off");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasEscortState(eEscortState.Paused))
|
||||
{
|
||||
me.GetMotionMaster().MovePoint(GetCurrentWaypoint().id, GetCurrentWaypoint().x, GetCurrentWaypoint().y, GetCurrentWaypoint().z);
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI start waypoint {0} ({1}, {2}, {3}).", GetCurrentWaypoint().id, GetCurrentWaypoint().x, GetCurrentWaypoint().y, GetCurrentWaypoint().z);
|
||||
|
||||
WaypointStart(GetCurrentWaypoint().id);
|
||||
|
||||
m_uiWPWaitTimer = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_uiWPWaitTimer -= diff;
|
||||
}
|
||||
|
||||
//Check if player or any member of his group is within range
|
||||
if (HasEscortState(eEscortState.Escorting) && !m_uiPlayerGUID.IsEmpty() && !me.GetVictim() && !HasEscortState(eEscortState.Returning))
|
||||
{
|
||||
if (m_uiPlayerCheckTimer <= diff)
|
||||
{
|
||||
if (DespawnAtFar && !IsPlayerOrGroupInRange())
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI failed because player/group was to far away or not found");
|
||||
|
||||
if (m_bCanInstantRespawn)
|
||||
{
|
||||
me.setDeathState(DeathState.JustDied);
|
||||
me.Respawn();
|
||||
}
|
||||
else
|
||||
me.DespawnOrUnsummon();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_uiPlayerCheckTimer = 1000;
|
||||
}
|
||||
else
|
||||
m_uiPlayerCheckTimer -= diff;
|
||||
}
|
||||
|
||||
UpdateEscortAI(diff);
|
||||
}
|
||||
|
||||
void UpdateEscortAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
public override void MovementInform(MovementGeneratorType moveType, uint pointId)
|
||||
{
|
||||
if (moveType != MovementGeneratorType.Point || !HasEscortState(eEscortState.Escorting))
|
||||
return;
|
||||
|
||||
//Combat start position reached, continue waypoint movement
|
||||
if (pointId == 0xFFFFFF)
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI has returned to original position before combat");
|
||||
|
||||
me.SetWalk(!m_bIsRunning);
|
||||
RemoveEscortState(eEscortState.Returning);
|
||||
|
||||
if (m_uiWPWaitTimer == 0)
|
||||
m_uiWPWaitTimer = 1;
|
||||
}
|
||||
else if (pointId == 0xFFFFFE)
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI has returned to original home location and will continue from beginning of waypoint list.");
|
||||
|
||||
WPIndex = 0;
|
||||
m_uiWPWaitTimer = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Make sure that we are still on the right waypoint
|
||||
if (GetCurrentWaypoint().id != pointId)
|
||||
{
|
||||
Log.outDebug(LogFilter.Server, "TSCR ERROR: EscortAI reached waypoint out of order {0}, expected {1}, creature entry {2}", pointId, GetCurrentWaypoint().id, me.GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI Waypoint {0} reached", GetCurrentWaypoint().id);
|
||||
|
||||
//Call WP function
|
||||
WaypointReached(GetCurrentWaypoint().id);
|
||||
|
||||
m_uiWPWaitTimer = GetCurrentWaypoint().WaitTimeMs + 1;
|
||||
|
||||
++WPIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddWaypoint(uint id, float x, float y, float z, uint waitTime = 0)
|
||||
{
|
||||
Escort_Waypoint t = new Escort_Waypoint(id, x, y, z, waitTime);
|
||||
|
||||
WaypointList.Add(t);
|
||||
ScriptWP = true;
|
||||
}
|
||||
|
||||
void FillPointMovementListForCreature()
|
||||
{
|
||||
var movePoints = Global.ScriptMgr.GetPointMoveList(me.GetEntry());
|
||||
if (movePoints.Empty())
|
||||
return;
|
||||
|
||||
foreach (var pointMove in movePoints)
|
||||
{
|
||||
Escort_Waypoint point = new Escort_Waypoint(pointMove.uiPointId, pointMove.fX, pointMove.fY, pointMove.fZ, pointMove.uiWaitTime);
|
||||
WaypointList.Add(point);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetRun(bool on = true)
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
if (!m_bIsRunning)
|
||||
me.SetWalk(false);
|
||||
else
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI attempt to set run mode, but is already running.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_bIsRunning)
|
||||
me.SetWalk(true);
|
||||
else
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI attempt to set walk mode, but is already walking.");
|
||||
}
|
||||
|
||||
m_bIsRunning = on;
|
||||
}
|
||||
|
||||
/// todo get rid of this many variables passed in function.
|
||||
public void Start(bool isActiveAttacker = true, bool run = false, ObjectGuid playerGUID = default(ObjectGuid), Quest quest = null, bool instantRespawn = false, bool canLoopPath = false, bool resetWaypoints = true)
|
||||
{
|
||||
if (me.GetVictim())
|
||||
{
|
||||
Log.outError(LogFilter.Server, "TSCR ERROR: EscortAI (script: {0}, creature entry: {1}) attempts to Start while in combat", me.GetScriptName(), me.GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasEscortState(eEscortState.Escorting))
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, "EscortAI (script: {0}, creature entry: {1}) attempts to Start while already escorting", me.GetScriptName(), me.GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ScriptWP && resetWaypoints) // sd2 never adds wp in script, but tc does
|
||||
{
|
||||
if (!WaypointList.Empty())
|
||||
WaypointList.Clear();
|
||||
FillPointMovementListForCreature();
|
||||
}
|
||||
|
||||
if (WaypointList.Empty())
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, "EscortAI (script: {0}, creature entry: {1}) starts with 0 waypoints (possible missing entry in script_waypoint. Quest: {2}).",
|
||||
me.GetScriptName(), me.GetEntry(), quest != null ? quest.Id : 0);
|
||||
return;
|
||||
}
|
||||
|
||||
//set variables
|
||||
m_bIsActiveAttacker = isActiveAttacker;
|
||||
m_bIsRunning = run;
|
||||
|
||||
m_uiPlayerGUID = playerGUID;
|
||||
m_pQuestForEscort = quest;
|
||||
|
||||
m_bCanInstantRespawn = instantRespawn;
|
||||
m_bCanReturnToStart = canLoopPath;
|
||||
|
||||
if (m_bCanReturnToStart && m_bCanInstantRespawn)
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn.");
|
||||
|
||||
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Waypoint)
|
||||
{
|
||||
me.GetMotionMaster().MovementExpired();
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle.");
|
||||
}
|
||||
|
||||
//disable npcflags
|
||||
me.SetUInt64Value(UnitFields.NpcFlags, (ulong)NPCFlags.None);
|
||||
if (me.HasFlag(UnitFields.Flags, UnitFlags.ImmuneToNpc))
|
||||
{
|
||||
HasImmuneToNPCFlags = true;
|
||||
me.RemoveFlag(UnitFields.Flags, UnitFlags.ImmuneToNpc);
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Scripts, "EscortAI started with {0} waypoints. ActiveAttacker = {1}, Run = {2}, PlayerGUID = {3}", WaypointList.Count, m_bIsActiveAttacker, m_bIsRunning, m_uiPlayerGUID);
|
||||
|
||||
WPIndex = 0;
|
||||
|
||||
//Set initial speed
|
||||
if (m_bIsRunning)
|
||||
me.SetWalk(false);
|
||||
else
|
||||
me.SetWalk(true);
|
||||
|
||||
AddEscortState(eEscortState.Escorting);
|
||||
}
|
||||
|
||||
public void SetEscortPaused(bool on)
|
||||
{
|
||||
if (!HasEscortState(eEscortState.Escorting))
|
||||
return;
|
||||
|
||||
if (on)
|
||||
AddEscortState(eEscortState.Paused);
|
||||
else
|
||||
RemoveEscortState(eEscortState.Paused);
|
||||
}
|
||||
|
||||
bool SetNextWaypoint(uint pointId, float x, float y, float z, float orientation)
|
||||
{
|
||||
me.UpdatePosition(x, y, z, orientation);
|
||||
return SetNextWaypoint(pointId, false, true);
|
||||
}
|
||||
|
||||
bool SetNextWaypoint(uint pointId, bool setPosition, bool resetWaypointsOnFail)
|
||||
{
|
||||
if (!WaypointList.Empty())
|
||||
WaypointList.Clear();
|
||||
|
||||
FillPointMovementListForCreature();
|
||||
|
||||
if (WaypointList.Empty())
|
||||
return false;
|
||||
|
||||
int size = WaypointList.Count;
|
||||
Escort_Waypoint waypoint = new Escort_Waypoint(0, 0, 0, 0, 0);
|
||||
do
|
||||
{
|
||||
waypoint = WaypointList.FirstOrDefault();
|
||||
WaypointList.RemoveAt(0);
|
||||
if (waypoint.id == pointId)
|
||||
{
|
||||
if (setPosition)
|
||||
me.UpdatePosition(waypoint.x, waypoint.y, waypoint.z, me.GetOrientation());
|
||||
|
||||
WPIndex = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while (!WaypointList.Empty());
|
||||
|
||||
// we failed.
|
||||
// we reset the waypoints in the start; if we pulled any, reset it again
|
||||
if (resetWaypointsOnFail && size != WaypointList.Count)
|
||||
{
|
||||
if (!WaypointList.Empty())
|
||||
WaypointList.Clear();
|
||||
|
||||
FillPointMovementListForCreature();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool GetWaypointPosition(uint pointId, ref float x, ref float y, ref float z)
|
||||
{
|
||||
var waypoints = Global.ScriptMgr.GetPointMoveList(me.GetEntry());
|
||||
if (waypoints.Empty())
|
||||
return false;
|
||||
|
||||
foreach (var point in waypoints)
|
||||
{
|
||||
if (point.uiPointId == pointId)
|
||||
{
|
||||
x = point.fX;
|
||||
y = point.fY;
|
||||
z = point.fZ;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void WaypointReached(uint pointId) { }
|
||||
public virtual void WaypointStart(uint pointId) { }
|
||||
|
||||
public bool HasEscortState(eEscortState escortState) { return m_uiEscortState.HasAnyFlag(escortState); }
|
||||
public override bool IsEscorted() { return m_uiEscortState.HasAnyFlag(eEscortState.Escorting); }
|
||||
|
||||
public void SetMaxPlayerDistance(float newMax) { MaxPlayerDistance = newMax; }
|
||||
public float GetMaxPlayerDistance() { return MaxPlayerDistance; }
|
||||
|
||||
public void SetDespawnAtEnd(bool despawn) { DespawnAtEnd = despawn; }
|
||||
public void SetDespawnAtFar(bool despawn) { DespawnAtFar = despawn; }
|
||||
public bool GetAttack() { return m_bIsActiveAttacker; }//used in EnterEvadeMode override
|
||||
public void SetCanAttack(bool attack) { m_bIsActiveAttacker = attack; }
|
||||
public ObjectGuid GetEventStarterGUID() { return m_uiPlayerGUID; }
|
||||
|
||||
public Player GetPlayerForEscort() { return Global.ObjAccessor.GetPlayer(me, m_uiPlayerGUID); }
|
||||
|
||||
void AddEscortState(eEscortState escortState) { m_uiEscortState |= escortState; }
|
||||
void RemoveEscortState(eEscortState escortState) { m_uiEscortState &= ~escortState; }
|
||||
|
||||
ObjectGuid m_uiPlayerGUID;
|
||||
uint m_uiWPWaitTimer;
|
||||
uint m_uiPlayerCheckTimer;
|
||||
eEscortState m_uiEscortState;
|
||||
float MaxPlayerDistance;
|
||||
|
||||
Quest m_pQuestForEscort; //generally passed in Start() when regular escort script.
|
||||
|
||||
List<Escort_Waypoint> WaypointList = new List<Escort_Waypoint>();
|
||||
Escort_Waypoint GetCurrentWaypoint()
|
||||
{
|
||||
return WaypointList[WPIndex];
|
||||
}
|
||||
int WPIndex;
|
||||
|
||||
bool m_bIsActiveAttacker; //obsolete, determined by faction.
|
||||
bool m_bIsRunning; //all creatures are walking by default (has flag MOVEMENTFLAG_WALK)
|
||||
bool m_bCanInstantRespawn; //if creature should respawn instantly after escort over (if not, database respawntime are used)
|
||||
bool m_bCanReturnToStart; //if creature can walk same path (loop) without despawn. Not for regular escort quests.
|
||||
bool DespawnAtEnd;
|
||||
bool DespawnAtFar;
|
||||
bool ScriptWP;
|
||||
bool HasImmuneToNPCFlags;
|
||||
}
|
||||
|
||||
public class Escort_Waypoint
|
||||
{
|
||||
public Escort_Waypoint(uint _id, float _x, float _y, float _z, uint _w)
|
||||
{
|
||||
id = _id;
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
WaitTimeMs = _w;
|
||||
}
|
||||
|
||||
public uint id;
|
||||
public float x;
|
||||
public float y;
|
||||
public float z;
|
||||
public uint WaitTimeMs;
|
||||
}
|
||||
|
||||
public enum eEscortState
|
||||
{
|
||||
None = 0x000, //nothing in progress
|
||||
Escorting = 0x001, //escort are in progress
|
||||
Returning = 0x002, //escort is returning after being in combat
|
||||
Paused = 0x004 //will not proceed with waypoints before state is removed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using System;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
enum eFollowState
|
||||
{
|
||||
None = 0x000,
|
||||
Inprogress = 0x001, //must always have this state for any follow
|
||||
Returning = 0x002, //when returning to combat start after being in combat
|
||||
Paused = 0x004, //disables following
|
||||
Complete = 0x008, //follow is completed and may end
|
||||
PreEvent = 0x010, //not implemented (allow pre event to run, before follow is initiated)
|
||||
PostEvent = 0x020 //can be set at complete and allow post event to run
|
||||
}
|
||||
|
||||
class FollowerAI : ScriptedAI
|
||||
{
|
||||
public FollowerAI(Creature creature) : base(creature)
|
||||
{
|
||||
m_uiUpdateFollowTimer = 2500;
|
||||
m_uiFollowState = eFollowState.None;
|
||||
m_pQuestForFollow = null;
|
||||
}
|
||||
|
||||
public override void AttackStart(Unit who)
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
if (me.Attack(who, true))
|
||||
{
|
||||
me.AddThreat(who, 0.0f);
|
||||
me.SetInCombatWith(who);
|
||||
who.SetInCombatWith(me);
|
||||
|
||||
if (me.HasUnitState(UnitState.Follow))
|
||||
me.ClearUnitState(UnitState.Follow);
|
||||
|
||||
if (IsCombatMovementAllowed())
|
||||
me.GetMotionMaster().MoveChase(who);
|
||||
}
|
||||
}
|
||||
|
||||
//This part provides assistance to a player that are attacked by who, even if out of normal aggro range
|
||||
//It will cause me to attack who that are attacking _any_ player (which has been confirmed may happen also on offi)
|
||||
//The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate.
|
||||
bool AssistPlayerInCombatAgainst(Unit who)
|
||||
{
|
||||
if (!who || !who.GetVictim())
|
||||
return false;
|
||||
|
||||
//experimental (unknown) flag not present
|
||||
if (!me.GetCreatureTemplate().TypeFlags.HasAnyFlag(CreatureTypeFlags.CanAssist))
|
||||
return false;
|
||||
|
||||
//not a player
|
||||
if (!who.GetVictim().GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
return false;
|
||||
|
||||
//never attack friendly
|
||||
if (me.IsFriendlyTo(who))
|
||||
return false;
|
||||
|
||||
//too far away and no free sight?
|
||||
if (me.IsWithinDistInMap(who, 100.0f) && me.IsWithinLOSInMap(who))
|
||||
{
|
||||
//already fighting someone?
|
||||
if (!me.GetVictim())
|
||||
{
|
||||
AttackStart(who);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
who.SetInCombatWith(me);
|
||||
me.AddThreat(who, 0.0f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void MoveInLineOfSight(Unit who)
|
||||
{
|
||||
if (me.HasReactState(ReactStates.Aggressive) && !me.HasUnitState(UnitState.Stunned) && who.isTargetableForAttack() && who.isInAccessiblePlaceFor(me))
|
||||
{
|
||||
if (HasFollowState(eFollowState.Inprogress) && AssistPlayerInCombatAgainst(who))
|
||||
return;
|
||||
|
||||
if (!me.CanFly() && me.GetDistanceZ(who) > SharedConst.CreatureAttackRangeZ)
|
||||
return;
|
||||
|
||||
if (me.IsHostileTo(who))
|
||||
{
|
||||
float fAttackRadius = me.GetAttackDistance(who);
|
||||
if (me.IsWithinDistInMap(who, fAttackRadius) && me.IsWithinLOSInMap(who))
|
||||
{
|
||||
if (!me.GetVictim())
|
||||
{
|
||||
// Clear distracted state on combat
|
||||
if (me.HasUnitState(UnitState.Distracted))
|
||||
{
|
||||
me.ClearUnitState(UnitState.Distracted);
|
||||
me.GetMotionMaster().Clear();
|
||||
}
|
||||
|
||||
AttackStart(who);
|
||||
}
|
||||
else if (me.GetMap().IsDungeon())
|
||||
{
|
||||
who.SetInCombatWith(me);
|
||||
me.AddThreat(who, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustDied(Unit killer)
|
||||
{
|
||||
if (!HasFollowState(eFollowState.Inprogress) || m_uiLeaderGUID.IsEmpty() || m_pQuestForFollow == null)
|
||||
return;
|
||||
|
||||
/// @todo need a better check for quests with time limit.
|
||||
Player player = GetLeaderForFollower();
|
||||
if (player)
|
||||
{
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
|
||||
{
|
||||
Player member = groupRef.GetSource();
|
||||
if (member)
|
||||
member.FailQuest(m_pQuestForFollow.Id);
|
||||
}
|
||||
}
|
||||
else
|
||||
player.FailQuest(m_pQuestForFollow.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public override void JustRespawned()
|
||||
{
|
||||
m_uiFollowState = eFollowState.None;
|
||||
|
||||
if (!IsCombatMovementAllowed())
|
||||
SetCombatMovement(true);
|
||||
|
||||
if (me.getFaction() != me.GetCreatureTemplate().Faction)
|
||||
me.SetFaction(me.GetCreatureTemplate().Faction);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public override void EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
me.RemoveAllAuras();
|
||||
me.DeleteThreatList();
|
||||
me.CombatStop(true);
|
||||
me.SetLootRecipient(null);
|
||||
|
||||
if (HasFollowState(eFollowState.Inprogress))
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI left combat, returning to CombatStartPosition.");
|
||||
|
||||
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Chase)
|
||||
{
|
||||
float fPosX, fPosY, fPosZ;
|
||||
me.GetPosition(out fPosX, out fPosY, out fPosZ);
|
||||
me.GetMotionMaster().MovePoint(0xFFFFFF, fPosX, fPosY, fPosZ);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Chase)
|
||||
me.GetMotionMaster().MoveTargetedHome();
|
||||
}
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
public override void UpdateAI(uint uiDiff)
|
||||
{
|
||||
if (HasFollowState(eFollowState.Inprogress) && !me.GetVictim())
|
||||
{
|
||||
if (m_uiUpdateFollowTimer <= uiDiff)
|
||||
{
|
||||
if (HasFollowState(eFollowState.Complete) && !HasFollowState(eFollowState.PostEvent))
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI is set completed, despawns.");
|
||||
me.DespawnOrUnsummon();
|
||||
return;
|
||||
}
|
||||
|
||||
bool bIsMaxRangeExceeded = true;
|
||||
|
||||
Player player = GetLeaderForFollower();
|
||||
if (player)
|
||||
{
|
||||
if (HasFollowState(eFollowState.Returning))
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI is returning to leader.");
|
||||
|
||||
RemoveFollowState(eFollowState.Returning);
|
||||
me.GetMotionMaster().MoveFollow(player, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
|
||||
return;
|
||||
}
|
||||
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
|
||||
{
|
||||
Player member = groupRef.GetSource();
|
||||
if (member && me.IsWithinDistInMap(member, 100.0f))
|
||||
{
|
||||
bIsMaxRangeExceeded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (me.IsWithinDistInMap(player, 100.0f))
|
||||
bIsMaxRangeExceeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bIsMaxRangeExceeded)
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI failed because player/group was to far away or not found");
|
||||
me.DespawnOrUnsummon();
|
||||
return;
|
||||
}
|
||||
|
||||
m_uiUpdateFollowTimer = 1000;
|
||||
}
|
||||
else
|
||||
m_uiUpdateFollowTimer -= uiDiff;
|
||||
}
|
||||
|
||||
UpdateFollowerAI(uiDiff);
|
||||
}
|
||||
|
||||
void UpdateFollowerAI(uint diff)
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
public override void MovementInform(MovementGeneratorType motionType, uint pointId)
|
||||
{
|
||||
if (motionType != MovementGeneratorType.Point || !HasFollowState(eFollowState.Inprogress))
|
||||
return;
|
||||
|
||||
if (pointId == 0xFFFFFF)
|
||||
{
|
||||
if (GetLeaderForFollower())
|
||||
{
|
||||
if (!HasFollowState(eFollowState.Paused))
|
||||
AddFollowState(eFollowState.Returning);
|
||||
}
|
||||
else
|
||||
me.DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
|
||||
void StartFollow(Player player, uint factionForFollower = 0, Quest quest = null)
|
||||
{
|
||||
if (me.GetVictim())
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI attempt to StartFollow while in combat.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasFollowState(eFollowState.Inprogress))
|
||||
{
|
||||
Log.outError(LogFilter.Scenario, "FollowerAI attempt to StartFollow while already following.");
|
||||
return;
|
||||
}
|
||||
|
||||
//set variables
|
||||
m_uiLeaderGUID = player.GetGUID();
|
||||
|
||||
if (factionForFollower != 0)
|
||||
me.SetFaction(factionForFollower);
|
||||
|
||||
m_pQuestForFollow = quest;
|
||||
|
||||
if (me.GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Waypoint)
|
||||
{
|
||||
me.GetMotionMaster().Clear();
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI start with WAYPOINT_MOTION_TYPE, set to MoveIdle.");
|
||||
}
|
||||
|
||||
me.SetUInt64Value(UnitFields.NpcFlags, (uint)NPCFlags.None);
|
||||
|
||||
AddFollowState(eFollowState.Inprogress);
|
||||
|
||||
me.GetMotionMaster().MoveFollow(player, SharedConst.PetFollowDist, SharedConst.PetFollowAngle);
|
||||
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI start follow {0} ({1})", player.GetName(), m_uiLeaderGUID.ToString());
|
||||
}
|
||||
|
||||
Player GetLeaderForFollower()
|
||||
{
|
||||
Player player = Global.ObjAccessor.GetPlayer(me, m_uiLeaderGUID);
|
||||
if (player)
|
||||
{
|
||||
if (player.IsAlive())
|
||||
return player;
|
||||
else
|
||||
{
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference groupRef = group.GetFirstMember(); groupRef != null; groupRef = groupRef.next())
|
||||
{
|
||||
Player member = groupRef.GetSource();
|
||||
|
||||
if (member && member.IsAlive() && me.IsWithinDistInMap(member, 100.0f))
|
||||
{
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI GetLeader changed and returned new leader.");
|
||||
m_uiLeaderGUID = member.GetGUID();
|
||||
return member;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Scripts, "FollowerAI GetLeader can not find suitable leader.");
|
||||
return null;
|
||||
}
|
||||
|
||||
void SetFollowComplete(bool bWithEndEvent = false)
|
||||
{
|
||||
if (me.HasUnitState(UnitState.Follow))
|
||||
{
|
||||
me.ClearUnitState(UnitState.Follow);
|
||||
|
||||
me.StopMoving();
|
||||
me.GetMotionMaster().Clear();
|
||||
me.GetMotionMaster().MoveIdle();
|
||||
}
|
||||
|
||||
if (bWithEndEvent)
|
||||
AddFollowState(eFollowState.PostEvent);
|
||||
else
|
||||
{
|
||||
if (HasFollowState(eFollowState.PostEvent))
|
||||
RemoveFollowState(eFollowState.PostEvent);
|
||||
}
|
||||
|
||||
AddFollowState(eFollowState.Complete);
|
||||
}
|
||||
|
||||
bool HasFollowState(eFollowState uiFollowState) { return (m_uiFollowState & uiFollowState) != 0; }
|
||||
|
||||
void AddFollowState(eFollowState uiFollowState) { m_uiFollowState |= uiFollowState; }
|
||||
void RemoveFollowState(eFollowState uiFollowState) { m_uiFollowState &= ~uiFollowState; }
|
||||
|
||||
ObjectGuid m_uiLeaderGUID;
|
||||
uint m_uiUpdateFollowTimer;
|
||||
eFollowState m_uiFollowState;
|
||||
|
||||
Quest m_pQuestForFollow; //normally we have a quest
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Accounts;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public sealed class AccountManager : Singleton<AccountManager>
|
||||
{
|
||||
const int MaxAccountLength = 16;
|
||||
const int MaxEmailLength = 64;
|
||||
|
||||
AccountManager() { }
|
||||
|
||||
public AccountOpResult CreateAccount(string username, string password, string email = "", uint bnetAccountId = 0, byte bnetIndex = 0)
|
||||
{
|
||||
if (username.Length > MaxAccountLength)
|
||||
return AccountOpResult.NameTooLong; // username's too long
|
||||
|
||||
if (password.Length > MaxAccountLength)
|
||||
return AccountOpResult.PassTooLong; // password's too long
|
||||
|
||||
if (GetId(username) != 0)
|
||||
return AccountOpResult.NameAlreadyExist; // username does already exist
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_ACCOUNT);
|
||||
stmt.AddValue(0, username);
|
||||
stmt.AddValue(1, CalculateShaPassHash(username, password));
|
||||
stmt.AddValue(2, email);
|
||||
stmt.AddValue(3, email);
|
||||
if (bnetAccountId != 0 && bnetIndex != 0)
|
||||
{
|
||||
stmt.AddValue(4, bnetAccountId);
|
||||
stmt.AddValue(5, bnetIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt.AddValue(4, null);
|
||||
stmt.AddValue(5, null);
|
||||
}
|
||||
DB.Login.Execute(stmt); // Enforce saving, otherwise AddGroup can fail
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_REALM_CHARACTERS_INIT);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok; // everything's fine
|
||||
}
|
||||
|
||||
public AccountOpResult DeleteAccount(uint accountId)
|
||||
{
|
||||
// Check if accounts exists
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
// Obtain accounts characters
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARS_BY_ACCOUNT_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ObjectGuid guid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
|
||||
// Kick if player is online
|
||||
Player p = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (p)
|
||||
{
|
||||
WorldSession s = p.GetSession();
|
||||
s.KickPlayer(); // mark session to remove at next session list update
|
||||
s.LogoutPlayer(false); // logout player without waiting next session list update
|
||||
}
|
||||
|
||||
Player.DeleteFromDB(guid, accountId, false); // no need to update realm characters
|
||||
} while (result.NextRow());
|
||||
}
|
||||
|
||||
// table realm specific but common for all characters of account for realm
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_TUTORIALS);
|
||||
stmt.AddValue(0, accountId);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ACCOUNT_DATA);
|
||||
stmt.AddValue(0, accountId);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHARACTER_BAN);
|
||||
stmt.AddValue(0, accountId);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_ACCESS);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_REALM_CHARACTERS);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_BANNED);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_MUTED);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Login.CommitTransaction(trans);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangeUsername(uint accountId, string newUsername, string newPassword)
|
||||
{
|
||||
// Check if accounts exists
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
if (newUsername.Length > MaxAccountLength)
|
||||
return AccountOpResult.NameTooLong;
|
||||
|
||||
if (newPassword.Length > MaxAccountLength)
|
||||
return AccountOpResult.PassTooLong;
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_USERNAME);
|
||||
stmt.AddValue(0, newUsername);
|
||||
stmt.AddValue(1, CalculateShaPassHash(newUsername, newPassword));
|
||||
stmt.AddValue(2, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangePassword(uint accountId, string newPassword)
|
||||
{
|
||||
string username;
|
||||
|
||||
if (!GetName(accountId, out username))
|
||||
return AccountOpResult.NameNotExist; // account doesn't exist
|
||||
|
||||
if (newPassword.Length > MaxAccountLength)
|
||||
return AccountOpResult.PassTooLong;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_PASSWORD);
|
||||
stmt.AddValue(0, CalculateShaPassHash(username, newPassword));
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_VS);
|
||||
stmt.AddValue(0, "");
|
||||
stmt.AddValue(1, "");
|
||||
stmt.AddValue(2, username);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangeEmail(uint accountId, string newEmail)
|
||||
{
|
||||
string username;
|
||||
|
||||
if (!GetName(accountId, out username))
|
||||
return AccountOpResult.NameNotExist; // account doesn't exist
|
||||
|
||||
if (newEmail.Length > MaxEmailLength)
|
||||
return AccountOpResult.EmailTooLong;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_EMAIL);
|
||||
stmt.AddValue(0, newEmail);
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangeRegEmail(uint accountId, string newEmail)
|
||||
{
|
||||
string username;
|
||||
|
||||
if (!GetName(accountId, out username))
|
||||
return AccountOpResult.NameNotExist; // account doesn't exist
|
||||
|
||||
if (newEmail.Length > MaxEmailLength)
|
||||
return AccountOpResult.EmailTooLong;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_REG_EMAIL);
|
||||
stmt.AddValue(0, newEmail);
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public uint GetId(string username)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_ACCOUNT_ID_BY_USERNAME);
|
||||
stmt.AddValue(0, username);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
return !result.IsEmpty() ? result.Read<uint>(0) : 0;
|
||||
}
|
||||
|
||||
public AccountTypes GetSecurity(uint accountId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_ACCOUNT_ACCESS_GMLEVEL);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
return !result.IsEmpty() ? (AccountTypes)result.Read<byte>(0) : AccountTypes.Player;
|
||||
}
|
||||
|
||||
public AccountTypes GetSecurity(uint accountId, int realmId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_GMLEVEL_BY_REALMID);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, realmId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
return !result.IsEmpty() ? (AccountTypes)result.Read<uint>(0) : AccountTypes.Player;
|
||||
}
|
||||
|
||||
public bool GetName(uint accountId, out string name)
|
||||
{
|
||||
name = "";
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_USERNAME_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
name = result.Read<string>(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetEmail(uint accountId, out string email)
|
||||
{
|
||||
email = "";
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_EMAIL_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
email = result.Read<string>(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CheckPassword(uint accountId, string password)
|
||||
{
|
||||
string username;
|
||||
|
||||
if (!GetName(accountId, out username))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_CHECK_PASSWORD);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, CalculateShaPassHash(username, password));
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
return result.IsEmpty() ? false : true;
|
||||
}
|
||||
|
||||
public bool CheckEmail(uint accountId, string newEmail)
|
||||
{
|
||||
string oldEmail;
|
||||
|
||||
// We simply return false for a non-existing email
|
||||
if (!GetEmail(accountId, out oldEmail))
|
||||
return false;
|
||||
|
||||
if (oldEmail == newEmail)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint GetCharactersCount(uint accountId)
|
||||
{
|
||||
// check character count
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_SUM_CHARS);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
return result.IsEmpty() ? 0 : (uint)result.Read<ulong>(0);
|
||||
}
|
||||
|
||||
string CalculateShaPassHash(string name, string password)
|
||||
{
|
||||
SHA1 sha = SHA1.Create();
|
||||
return sha.ComputeHash(Encoding.UTF8.GetBytes(name + ":" + password)).ToHexString();
|
||||
}
|
||||
|
||||
public bool IsPlayerAccount(AccountTypes gmlevel)
|
||||
{
|
||||
return gmlevel == AccountTypes.Player;
|
||||
}
|
||||
|
||||
public bool IsAdminAccount(AccountTypes gmlevel)
|
||||
{
|
||||
return gmlevel >= AccountTypes.Administrator && gmlevel <= AccountTypes.Console;
|
||||
}
|
||||
|
||||
public bool IsConsoleAccount(AccountTypes gmlevel)
|
||||
{
|
||||
return gmlevel == AccountTypes.Console;
|
||||
}
|
||||
|
||||
public void LoadRBAC()
|
||||
{
|
||||
ClearRBAC();
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC");
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
uint count1 = 0;
|
||||
uint count2 = 0;
|
||||
uint count3 = 0;
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC: Loading permissions");
|
||||
SQLResult result = DB.Login.Query("SELECT id, name FROM rbac_permissions");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 account permission definitions. DB table `rbac_permissions` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
uint id = result.Read<uint>(0);
|
||||
_permissions[id] = new RBACPermission(id, result.Read<string>(1));
|
||||
++count1;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC: Loading linked permissions");
|
||||
result = DB.Login.Query("SELECT id, linkedId FROM rbac_linked_permissions ORDER BY id ASC");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 linked permissions. DB table `rbac_linked_permissions` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint permissionId = 0;
|
||||
RBACPermission permission = null;
|
||||
|
||||
do
|
||||
{
|
||||
uint newId = result.Read<uint>(0);
|
||||
if (permissionId != newId)
|
||||
{
|
||||
permissionId = newId;
|
||||
permission = _permissions[newId];
|
||||
}
|
||||
|
||||
uint linkedPermissionId = result.Read<uint>(1);
|
||||
if (linkedPermissionId == permissionId)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RBAC Permission {0} has itself as linked permission. Ignored", permissionId);
|
||||
continue;
|
||||
}
|
||||
permission.AddLinkedPermission(linkedPermissionId);
|
||||
++count2;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC: Loading default permissions");
|
||||
result = DB.Login.Query("SELECT secId, permissionId FROM rbac_default_permissions ORDER BY secId ASC");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint secId = 255;
|
||||
do
|
||||
{
|
||||
uint newId = result.Read<uint>(0);
|
||||
if (secId != newId)
|
||||
secId = newId;
|
||||
|
||||
_defaultPermissions.Add((byte)secId, result.Read<uint>(1));
|
||||
++count3;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} permission definitions, {1} linked permissions and {2} default permissions in {3} ms", count1, count2, count3, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public void UpdateAccountAccess(RBACData rbac, uint accountId, byte securityLevel, int realmId)
|
||||
{
|
||||
if (rbac != null && securityLevel != rbac.GetSecurityLevel())
|
||||
rbac.SetSecurityLevel(securityLevel);
|
||||
|
||||
PreparedStatement stmt;
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
// Delete old security level from DB
|
||||
if (realmId == -1)
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_ACCESS);
|
||||
stmt.AddValue(0, accountId);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_ACCOUNT_ACCESS_BY_REALM);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, realmId);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
// Add new security level
|
||||
if (securityLevel != 0)
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_ACCOUNT_ACCESS);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, securityLevel);
|
||||
stmt.AddValue(2, realmId);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
DB.Login.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
public RBACPermission GetRBACPermission(uint permissionId)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:GetRBACPermission: {0}", permissionId);
|
||||
return _permissions.LookupByKey(permissionId);
|
||||
}
|
||||
|
||||
public bool HasPermission(uint accountId, RBACPermissions permissionId, uint realmId)
|
||||
{
|
||||
if (accountId == 0)
|
||||
{
|
||||
Log.outError(LogFilter.Rbac, "AccountMgr:HasPermission: Wrong accountId 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
RBACData rbac = new RBACData(accountId, "", (int)realmId);
|
||||
rbac.LoadFromDB();
|
||||
bool hasPermission = rbac.HasPermission(permissionId);
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "AccountMgr:HasPermission [AccountId: {0}, PermissionId: {1}, realmId: {2}]: {3}",
|
||||
accountId, permissionId, realmId, hasPermission);
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
void ClearRBAC()
|
||||
{
|
||||
_permissions.Clear();
|
||||
_defaultPermissions.Clear();
|
||||
}
|
||||
|
||||
public List<uint> GetRBACDefaultPermissions(byte secLevel)
|
||||
{
|
||||
return _defaultPermissions[secLevel];
|
||||
}
|
||||
|
||||
public Dictionary<uint, RBACPermission> GetRBACPermissionList() { return _permissions; }
|
||||
|
||||
Dictionary<uint, RBACPermission> _permissions = new Dictionary<uint, RBACPermission>();
|
||||
MultiMap<byte, uint> _defaultPermissions = new MultiMap<byte, uint>();
|
||||
}
|
||||
|
||||
public enum AccountOpResult
|
||||
{
|
||||
Ok,
|
||||
NameTooLong,
|
||||
PassTooLong,
|
||||
EmailTooLong,
|
||||
NameAlreadyExist,
|
||||
NameNotExist,
|
||||
DBInternalError,
|
||||
BadLink
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Database;
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public sealed class BNetAccountManager : Singleton<BNetAccountManager>
|
||||
{
|
||||
BNetAccountManager() { }
|
||||
|
||||
public AccountOpResult CreateBattlenetAccount(string email, string password, bool withGameAccount, out string gameAccountName)
|
||||
{
|
||||
gameAccountName = "";
|
||||
|
||||
if (email.Length > 320)
|
||||
return AccountOpResult.NameTooLong;
|
||||
|
||||
if (password.Length > 16)
|
||||
return AccountOpResult.PassTooLong;
|
||||
|
||||
if (GetId(email) != 0)
|
||||
return AccountOpResult.NameAlreadyExist;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BNET_ACCOUNT);
|
||||
stmt.AddValue(0, email);
|
||||
stmt.AddValue(1, CalculateShaPassHash(email, password));
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
uint newAccountId = GetId(email);
|
||||
Contract.Assert(newAccountId != 0);
|
||||
|
||||
if (withGameAccount)
|
||||
{
|
||||
gameAccountName = newAccountId + "#1";
|
||||
Global.AccountMgr.CreateAccount(gameAccountName, password, email, newAccountId, 1);
|
||||
}
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult ChangePassword(uint accountId, string newPassword)
|
||||
{
|
||||
string username;
|
||||
if (!GetName(accountId, out username))
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
if (newPassword.Length > 16)
|
||||
return AccountOpResult.PassTooLong;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_PASSWORD);
|
||||
stmt.AddValue(0, CalculateShaPassHash(username, newPassword));
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public bool CheckPassword(uint accountId, string password)
|
||||
{
|
||||
string username;
|
||||
if (!GetName(accountId, out username))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_CHECK_PASSWORD);
|
||||
stmt.AddValue(0, accountId);
|
||||
stmt.AddValue(1, CalculateShaPassHash(username, password));
|
||||
|
||||
return !DB.Login.Query(stmt).IsEmpty();
|
||||
}
|
||||
|
||||
public AccountOpResult LinkWithGameAccount(string email, string gameAccountName)
|
||||
{
|
||||
uint bnetAccountId = GetId(email);
|
||||
if (bnetAccountId == 0)
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
uint gameAccountId = Global.AccountMgr.GetId(gameAccountName);
|
||||
if (gameAccountId == 0)
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
if (GetIdByGameAccount(gameAccountId) != 0)
|
||||
return AccountOpResult.BadLink;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_GAME_ACCOUNT_LINK);
|
||||
stmt.AddValue(0, bnetAccountId);
|
||||
stmt.AddValue(1, GetMaxIndex(bnetAccountId) + 1);
|
||||
stmt.AddValue(2, gameAccountId);
|
||||
DB.Login.Execute(stmt);
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public AccountOpResult UnlinkGameAccount(string gameAccountName)
|
||||
{
|
||||
uint gameAccountId = Global.AccountMgr.GetId(gameAccountName);
|
||||
if (gameAccountId == 0)
|
||||
return AccountOpResult.NameNotExist;
|
||||
|
||||
if (GetIdByGameAccount(gameAccountId) == 0)
|
||||
return AccountOpResult.BadLink;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_GAME_ACCOUNT_LINK);
|
||||
stmt.AddValue(0, null);
|
||||
stmt.AddValue(1, null);
|
||||
stmt.AddValue(2, gameAccountId);
|
||||
DB.Login.Execute(stmt);
|
||||
return AccountOpResult.Ok;
|
||||
}
|
||||
|
||||
public uint GetId(string username)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_ACCOUNT_ID_BY_EMAIL);
|
||||
stmt.AddValue(0, username);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
return result.Read<uint>(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool GetName(uint accountId, out string name)
|
||||
{
|
||||
name = "";
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_ACCOUNT_EMAIL_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
name = result.Read<string>(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint GetIdByGameAccount(uint gameAccountId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT);
|
||||
stmt.AddValue(0, gameAccountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
return result.Read<uint>(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public byte GetMaxIndex(uint accountId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_MAX_ACCOUNT_INDEX);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
return result.Read<byte>(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string CalculateShaPassHash(string name, string password)
|
||||
{
|
||||
SHA256 sha256 = SHA256.Create();
|
||||
var i = sha256.ComputeHash(Encoding.UTF8.GetBytes(name));
|
||||
return sha256.ComputeHash(Encoding.UTF8.GetBytes(i.ToHexString() + ":" + password)).ToHexString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Accounts
|
||||
{
|
||||
public class RBACData
|
||||
{
|
||||
public RBACData(uint id, string name, int realmId, byte secLevel = 255)
|
||||
{
|
||||
_id = id;
|
||||
_name = name;
|
||||
_realmId = realmId;
|
||||
_secLevel = secLevel;
|
||||
}
|
||||
|
||||
public RBACCommandResult GrantPermission(uint permissionId, int realmId = 0)
|
||||
{
|
||||
// Check if permission Id exists
|
||||
RBACPermission perm = Global.AccountMgr.GetRBACPermission(permissionId);
|
||||
if (perm == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission does not exists",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.IdDoesNotExists;
|
||||
}
|
||||
|
||||
// Check if already added in denied list
|
||||
if (HasDeniedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission in deny list",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.InDeniedList;
|
||||
}
|
||||
|
||||
// Already added?
|
||||
if (HasGrantedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission already granted",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.CantAddAlreadyAdded;
|
||||
}
|
||||
|
||||
AddGrantedPermission(permissionId);
|
||||
|
||||
// Do not save to db when loading data from DB (realmId = 0)
|
||||
if (realmId != 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok and DB updated",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
SavePermission(permissionId, true, realmId);
|
||||
CalculateNewPermissions();
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.GrantPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
|
||||
return RBACCommandResult.OK;
|
||||
}
|
||||
|
||||
public RBACCommandResult DenyPermission(uint permissionId, int realmId = 0)
|
||||
{
|
||||
// Check if permission Id exists
|
||||
RBACPermission perm = Global.AccountMgr.GetRBACPermission(permissionId);
|
||||
if (perm == null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission does not exists",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.IdDoesNotExists;
|
||||
}
|
||||
|
||||
// Check if already added in granted list
|
||||
if (HasGrantedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission in grant list",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.InGrantedList;
|
||||
}
|
||||
|
||||
// Already added?
|
||||
if (HasDeniedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Permission already denied",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.CantAddAlreadyAdded;
|
||||
}
|
||||
|
||||
AddDeniedPermission(permissionId);
|
||||
|
||||
// Do not save to db when loading data from DB (realmId = 0)
|
||||
if (realmId != 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok and DB updated",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
SavePermission(permissionId, false, realmId);
|
||||
CalculateNewPermissions();
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.DenyPermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
|
||||
return RBACCommandResult.OK;
|
||||
}
|
||||
|
||||
void SavePermission(uint permission, bool granted, int realmId)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_RBAC_ACCOUNT_PERMISSION);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, permission);
|
||||
stmt.AddValue(2, granted);
|
||||
stmt.AddValue(3, realmId);
|
||||
DB.Login.Execute(stmt);
|
||||
}
|
||||
|
||||
public RBACCommandResult RevokePermission(uint permissionId, int realmId = 0)
|
||||
{
|
||||
// Check if it's present in any list
|
||||
if (!HasGrantedPermission(permissionId) && !HasDeniedPermission(permissionId))
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.RevokePermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Not granted or revoked",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
return RBACCommandResult.CantRevokeNotInList;
|
||||
}
|
||||
|
||||
RemoveGrantedPermission(permissionId);
|
||||
RemoveDeniedPermission(permissionId);
|
||||
|
||||
// Do not save to db when loading data from DB (realmId = 0)
|
||||
if (realmId != 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.RevokePermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok and DB updated",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_RBAC_ACCOUNT_PERMISSION);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, permissionId);
|
||||
stmt.AddValue(2, realmId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
CalculateNewPermissions();
|
||||
}
|
||||
else
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.RevokePermission [Id: {0} Name: {1}] (Permission {2}, RealmId {3}). Ok",
|
||||
GetId(), GetName(), permissionId, realmId);
|
||||
|
||||
return RBACCommandResult.OK;
|
||||
}
|
||||
|
||||
public void LoadFromDB()
|
||||
{
|
||||
ClearData();
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.LoadFromDB [Id: {0} Name: {1}]: Loading permissions", GetId(), GetName());
|
||||
// Load account permissions (granted and denied) that affect current realm
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_RBAC_ACCOUNT_PERMISSIONS);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, GetRealmId());
|
||||
|
||||
LoadFromDBCallback(DB.Login.Query(stmt));
|
||||
}
|
||||
|
||||
public QueryCallback LoadFromDBAsync()
|
||||
{
|
||||
ClearData();
|
||||
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.LoadFromDB [Id: {0} Name: {1}]: Loading permissions", GetId(), GetName());
|
||||
// Load account permissions (granted and denied) that affect current realm
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_RBAC_ACCOUNT_PERMISSIONS);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, GetRealmId());
|
||||
|
||||
return DB.Login.AsyncQuery(stmt);
|
||||
}
|
||||
|
||||
public void LoadFromDBCallback(SQLResult result)
|
||||
{
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
if (result.Read<bool>(1))
|
||||
GrantPermission(result.Read<uint>(0));
|
||||
else
|
||||
DenyPermission(result.Read<uint>(0));
|
||||
|
||||
} while (result.NextRow());
|
||||
}
|
||||
|
||||
// Add default permissions
|
||||
List<uint> permissions = Global.AccountMgr.GetRBACDefaultPermissions(_secLevel);
|
||||
foreach (var id in permissions)
|
||||
GrantPermission(id);
|
||||
|
||||
// Force calculation of permissions
|
||||
CalculateNewPermissions();
|
||||
}
|
||||
|
||||
void CalculateNewPermissions()
|
||||
{
|
||||
Log.outDebug(LogFilter.Rbac, "RBACData.CalculateNewPermissions [Id: {0} Name: {1}]", GetId(), GetName());
|
||||
|
||||
// Get the list of granted permissions
|
||||
_globalPerms = GetGrantedPermissions();
|
||||
ExpandPermissions(_globalPerms);
|
||||
List<uint> revoked = GetDeniedPermissions();
|
||||
ExpandPermissions(revoked);
|
||||
RemovePermissions(_globalPerms, revoked);
|
||||
}
|
||||
|
||||
void AddPermissions(List<uint> permsFrom, List<uint> permsTo)
|
||||
{
|
||||
foreach (var id in permsFrom)
|
||||
permsTo.Add(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a list of permissions from another list
|
||||
/// </summary>
|
||||
/// <param name="permsFrom"></param>
|
||||
/// <param name="permsToRemove"></param>
|
||||
void RemovePermissions(List<uint> permsFrom, List<uint> permsToRemove)
|
||||
{
|
||||
foreach (var id in permsToRemove)
|
||||
permsFrom.Remove(id);
|
||||
}
|
||||
|
||||
void ExpandPermissions(List<uint> permissions)
|
||||
{
|
||||
List<uint> toCheck = new List<uint>(permissions);
|
||||
permissions.Clear();
|
||||
|
||||
while (!toCheck.Empty())
|
||||
{
|
||||
// remove the permission from original list
|
||||
uint permissionId = toCheck.FirstOrDefault();
|
||||
toCheck.RemoveAt(0);
|
||||
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(permissionId);
|
||||
if (permission == null)
|
||||
continue;
|
||||
|
||||
// insert into the final list (expanded list)
|
||||
permissions.Add(permissionId);
|
||||
|
||||
// add all linked permissions (that are not already expanded) to the list of permissions to be checked
|
||||
List<uint> linkedPerms = permission.GetLinkedPermissions();
|
||||
foreach (var id in linkedPerms)
|
||||
if (!permissions.Contains(id))
|
||||
toCheck.Add(id);
|
||||
}
|
||||
|
||||
//Log.outDebug(LogFilter.General, "RBACData:ExpandPermissions: Expanded: {0}", GetDebugPermissionString(permissions));
|
||||
}
|
||||
|
||||
void ClearData()
|
||||
{
|
||||
_grantedPerms.Clear();
|
||||
_deniedPerms.Clear();
|
||||
_globalPerms.Clear();
|
||||
}
|
||||
|
||||
// Gets the Name of the Object
|
||||
public string GetName() { return _name; }
|
||||
// Gets the Id of the Object
|
||||
public uint GetId() { return _id; }
|
||||
|
||||
public bool HasPermission(RBACPermissions permission)
|
||||
{
|
||||
return _globalPerms.Contains((uint)permission);
|
||||
}
|
||||
|
||||
// Returns all the granted permissions (after computation)
|
||||
public List<uint> GetPermissions() { return _globalPerms; }
|
||||
// Returns all the granted permissions
|
||||
public List<uint> GetGrantedPermissions() { return _grantedPerms; }
|
||||
// Returns all the denied permissions
|
||||
public List<uint> GetDeniedPermissions() { return _deniedPerms; }
|
||||
|
||||
public void SetSecurityLevel(byte id)
|
||||
{
|
||||
_secLevel = id;
|
||||
LoadFromDB();
|
||||
}
|
||||
|
||||
public byte GetSecurityLevel() { return _secLevel; }
|
||||
int GetRealmId() { return _realmId; }
|
||||
|
||||
// Checks if a permission is granted
|
||||
bool HasGrantedPermission(uint permissionId)
|
||||
{
|
||||
return _grantedPerms.Contains(permissionId);
|
||||
}
|
||||
|
||||
// Checks if a permission is denied
|
||||
bool HasDeniedPermission(uint permissionId)
|
||||
{
|
||||
return _deniedPerms.Contains(permissionId);
|
||||
}
|
||||
|
||||
// Adds a new granted permission
|
||||
void AddGrantedPermission(uint permissionId)
|
||||
{
|
||||
_grantedPerms.Add(permissionId);
|
||||
}
|
||||
|
||||
// Removes a granted permission
|
||||
void RemoveGrantedPermission(uint permissionId)
|
||||
{
|
||||
_grantedPerms.Remove(permissionId);
|
||||
}
|
||||
|
||||
// Adds a new denied permission
|
||||
void AddDeniedPermission(uint permissionId)
|
||||
{
|
||||
_deniedPerms.Add(permissionId);
|
||||
}
|
||||
|
||||
// Removes a denied permission
|
||||
void RemoveDeniedPermission(uint permissionId)
|
||||
{
|
||||
_deniedPerms.Remove(permissionId);
|
||||
}
|
||||
|
||||
uint _id; // Account id
|
||||
string _name; // Account name
|
||||
int _realmId; // RealmId Affected
|
||||
byte _secLevel; // Account SecurityLevel
|
||||
List<uint> _grantedPerms = new List<uint>(); // Granted permissions
|
||||
List<uint> _deniedPerms = new List<uint>(); // Denied permissions
|
||||
List<uint> _globalPerms = new List<uint>(); // Calculated permissions
|
||||
}
|
||||
|
||||
public class RBACPermission
|
||||
{
|
||||
public RBACPermission(uint id = 0, string name = "")
|
||||
{
|
||||
_id = id;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
// Gets the Name of the Object
|
||||
public string GetName() { return _name; }
|
||||
// Gets the Id of the Object
|
||||
public uint GetId() { return _id; }
|
||||
|
||||
// Gets the Permissions linked to this permission
|
||||
public List<uint> GetLinkedPermissions() { return _perms; }
|
||||
// Adds a new linked Permission
|
||||
public void AddLinkedPermission(uint id) { _perms.Add(id); }
|
||||
// Removes a linked Permission
|
||||
void RemoveLinkedPermission(uint id) { _perms.Remove(id); }
|
||||
|
||||
|
||||
uint _id; // id of the object
|
||||
string _name; // name of the object
|
||||
List<uint> _perms = new List<uint>(); // Set of permissions
|
||||
}
|
||||
|
||||
public enum RBACCommandResult
|
||||
{
|
||||
OK,
|
||||
CantAddAlreadyAdded,
|
||||
CantRevokeNotInList,
|
||||
InGrantedList,
|
||||
InDeniedList,
|
||||
IdDoesNotExists
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattleGrounds;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class Arena : Battleground
|
||||
{
|
||||
public Arena()
|
||||
{
|
||||
StartDelayTimes[BattlegroundConst.EventIdFirst] = BattlegroundStartTimeIntervals.Delay1m;
|
||||
StartDelayTimes[BattlegroundConst.EventIdSecond] = BattlegroundStartTimeIntervals.Delay30s;
|
||||
StartDelayTimes[BattlegroundConst.EventIdThird] = BattlegroundStartTimeIntervals.Delay15s;
|
||||
StartDelayTimes[BattlegroundConst.EventIdFourth] = BattlegroundStartTimeIntervals.None;
|
||||
|
||||
StartMessageIds[BattlegroundConst.EventIdFirst] = CypherStrings.ArenaOneMinute;
|
||||
StartMessageIds[BattlegroundConst.EventIdSecond] = CypherStrings.ArenaThirtySeconds;
|
||||
StartMessageIds[BattlegroundConst.EventIdThird] = CypherStrings.ArenaFifteenSeconds;
|
||||
StartMessageIds[BattlegroundConst.EventIdFourth] = CypherStrings.ArenaHasBegun;
|
||||
}
|
||||
|
||||
public override void AddPlayer(Player player)
|
||||
{
|
||||
base.AddPlayer(player);
|
||||
PlayerScores[player.GetGUID()] = new ArenaScore(player.GetGUID(), player.GetBGTeam());
|
||||
|
||||
if (player.GetBGTeam() == Team.Alliance) // gold
|
||||
{
|
||||
if (player.GetTeam() == Team.Horde)
|
||||
player.CastSpell(player, ArenaSpellIds.HordeGoldFlag, true);
|
||||
else
|
||||
player.CastSpell(player, ArenaSpellIds.AllianceGoldFlag, true);
|
||||
}
|
||||
else // green
|
||||
{
|
||||
if (player.GetTeam() == Team.Horde)
|
||||
player.CastSpell(player, ArenaSpellIds.HordeGreenFlag, true);
|
||||
else
|
||||
player.CastSpell(player, ArenaSpellIds.AllianceGreenFlag, true);
|
||||
}
|
||||
|
||||
UpdateArenaWorldState();
|
||||
}
|
||||
|
||||
public override void RemovePlayer(Player player, ObjectGuid guid, Team team)
|
||||
{
|
||||
if (GetStatus() == BattlegroundStatus.WaitLeave)
|
||||
return;
|
||||
|
||||
UpdateArenaWorldState();
|
||||
CheckWinConditions();
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(ArenaWorldStates.AlivePlayersGreen, (int)GetAlivePlayersCountByTeam(Team.Horde));
|
||||
packet.AddState(ArenaWorldStates.AlivePlayersGold, (int)GetAlivePlayersCountByTeam(Team.Alliance));
|
||||
}
|
||||
|
||||
void UpdateArenaWorldState()
|
||||
{
|
||||
UpdateWorldState(ArenaWorldStates.AlivePlayersGreen, GetAlivePlayersCountByTeam(Team.Horde));
|
||||
UpdateWorldState(ArenaWorldStates.AlivePlayersGold, GetAlivePlayersCountByTeam(Team.Alliance));
|
||||
}
|
||||
|
||||
public override void HandleKillPlayer(Player victim, Player killer)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
base.HandleKillPlayer(victim, killer);
|
||||
|
||||
UpdateArenaWorldState();
|
||||
CheckWinConditions();
|
||||
}
|
||||
|
||||
public override void BuildPvPLogDataPacket(out PVPLogData pvpLogData)
|
||||
{
|
||||
base.BuildPvPLogDataPacket(out pvpLogData);
|
||||
|
||||
if (isRated())
|
||||
{
|
||||
pvpLogData.Ratings.HasValue = true;
|
||||
|
||||
for (byte i = 0; i < SharedConst.BGTeamsCount; ++i)
|
||||
{
|
||||
pvpLogData.Ratings.Value.Postmatch[i] = _arenaTeamScores[i].PostMatchRating;
|
||||
pvpLogData.Ratings.Value.Prematch[i] = _arenaTeamScores[i].PreMatchRating;
|
||||
pvpLogData.Ratings.Value.PrematchMMR[i] = _arenaTeamScores[i].PreMatchMMR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool SendPacket)
|
||||
{
|
||||
if (isRated() && GetStatus() == BattlegroundStatus.InProgress)
|
||||
{
|
||||
var bgPlayer = GetPlayers().LookupByKey(guid);
|
||||
if (bgPlayer != null) // check if the player was a participant of the match, or only entered through gm command (appear)
|
||||
{
|
||||
// if the player was a match participant, calculate rating
|
||||
|
||||
ArenaTeam winnerArenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(bgPlayer.Team)));
|
||||
ArenaTeam loserArenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamIdForTeam(bgPlayer.Team));
|
||||
|
||||
// left a rated match while the encounter was in progress, consider as loser
|
||||
if (winnerArenaTeam != null && loserArenaTeam != null && winnerArenaTeam != loserArenaTeam)
|
||||
{
|
||||
Player player = _GetPlayer(guid, bgPlayer.OfflineRemoveTime != 0, "Arena.RemovePlayerAtLeave");
|
||||
if (player)
|
||||
loserArenaTeam.MemberLost(player, GetArenaMatchmakerRating(GetOtherTeam(bgPlayer.Team)));
|
||||
else
|
||||
loserArenaTeam.OfflineMemberLost(guid, GetArenaMatchmakerRating(GetOtherTeam(bgPlayer.Team)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove player
|
||||
base.RemovePlayerAtLeave(guid, Transport, SendPacket);
|
||||
}
|
||||
|
||||
public override void CheckWinConditions()
|
||||
{
|
||||
if (GetAlivePlayersCountByTeam(Team.Alliance) == 0 && GetPlayersCountByTeam(Team.Horde) != 0)
|
||||
EndBattleground(Team.Horde);
|
||||
else if (GetPlayersCountByTeam(Team.Alliance) != 0 && GetAlivePlayersCountByTeam(Team.Horde) == 0)
|
||||
EndBattleground(Team.Alliance);
|
||||
}
|
||||
|
||||
public override void EndBattleground(Team winner)
|
||||
{
|
||||
// arena rating calculation
|
||||
if (isRated())
|
||||
{
|
||||
uint loserTeamRating = 0;
|
||||
uint loserMatchmakerRating = 0;
|
||||
int loserChange = 0;
|
||||
int loserMatchmakerChange = 0;
|
||||
uint winnerTeamRating = 0;
|
||||
uint winnerMatchmakerRating = 0;
|
||||
int winnerChange = 0;
|
||||
int winnerMatchmakerChange = 0;
|
||||
bool guildAwarded = false;
|
||||
|
||||
// In case of arena draw, follow this logic:
|
||||
// winnerArenaTeam => ALLIANCE, loserArenaTeam => HORDE
|
||||
ArenaTeam winnerArenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamIdForTeam(winner == 0 ? Team.Alliance : winner));
|
||||
ArenaTeam loserArenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(GetArenaTeamIdForTeam(winner == 0 ? Team.Horde : GetOtherTeam(winner)));
|
||||
|
||||
if (winnerArenaTeam != null && loserArenaTeam != null && winnerArenaTeam != loserArenaTeam)
|
||||
{
|
||||
// In case of arena draw, follow this logic:
|
||||
// winnerMatchmakerRating => ALLIANCE, loserMatchmakerRating => HORDE
|
||||
loserTeamRating = loserArenaTeam.GetRating();
|
||||
loserMatchmakerRating = GetArenaMatchmakerRating(winner == 0 ? Team.Horde : GetOtherTeam(winner));
|
||||
winnerTeamRating = winnerArenaTeam.GetRating();
|
||||
winnerMatchmakerRating = GetArenaMatchmakerRating(winner == 0 ? Team.Alliance : winner);
|
||||
|
||||
if (winner != 0)
|
||||
{
|
||||
winnerMatchmakerChange = winnerArenaTeam.WonAgainst(winnerMatchmakerRating, loserMatchmakerRating, ref winnerChange);
|
||||
loserMatchmakerChange = loserArenaTeam.LostAgainst(loserMatchmakerRating, winnerMatchmakerRating, ref loserChange);
|
||||
|
||||
Log.outDebug(LogFilter.Arena, "match Type: {0} --- Winner: old rating: {1}, rating gain: {2}, old MMR: {3}, MMR gain: {4} --- Loser: old rating: {5}, " +
|
||||
"rating loss: {6}, old MMR: {7}, MMR loss: {8} ---", GetArenaType(), winnerTeamRating, winnerChange, winnerMatchmakerRating, winnerMatchmakerChange,
|
||||
loserTeamRating, loserChange, loserMatchmakerRating, loserMatchmakerChange);
|
||||
|
||||
SetArenaMatchmakerRating(winner, (uint)(winnerMatchmakerRating + winnerMatchmakerChange));
|
||||
SetArenaMatchmakerRating(GetOtherTeam(winner), (uint)(loserMatchmakerRating + loserMatchmakerChange));
|
||||
|
||||
// bg team that the client expects is different to TeamId
|
||||
// alliance 1, horde 0
|
||||
byte winnerTeam = (byte)(winner == Team.Alliance ? BattlegroundTeamId.Alliance : BattlegroundTeamId.Horde);
|
||||
byte loserTeam = (byte)(winner == Team.Alliance ? BattlegroundTeamId.Horde : BattlegroundTeamId.Alliance);
|
||||
|
||||
_arenaTeamScores[winnerTeam].Assign(winnerTeamRating, (uint)(winnerTeamRating + winnerChange), winnerMatchmakerRating, GetArenaMatchmakerRating(winner));
|
||||
_arenaTeamScores[loserTeam].Assign(loserTeamRating, (uint)(loserTeamRating + loserChange), loserMatchmakerRating, GetArenaMatchmakerRating(GetOtherTeam(winner)));
|
||||
|
||||
Log.outDebug(LogFilter.Arena, "Arena match Type: {0} for Team1Id: {1} - Team2Id: {2} ended. WinnerTeamId: {3}. Winner rating: +{4}, Loser rating: {5}",
|
||||
GetArenaType(), GetArenaTeamIdByIndex(TeamId.Alliance), GetArenaTeamIdByIndex(TeamId.Horde), winnerArenaTeam.GetId(), winnerChange, loserChange);
|
||||
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.ArenaLogExtendedInfo))
|
||||
{
|
||||
foreach (var score in PlayerScores)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(score.Key);
|
||||
if (player)
|
||||
{
|
||||
Log.outDebug(LogFilter.Arena, "Statistics match Type: {0} for {1} (GUID: {2}, Team: {3}, IP: {4}): {5}",
|
||||
GetArenaType(), player.GetName(), score.Key, player.GetArenaTeamId((byte)(GetArenaType() == ArenaTypes.Team5v5 ? 2 : (GetArenaType() == ArenaTypes.Team3v3 ? 1 : 0))),
|
||||
player.GetSession().GetRemoteAddress(), score.Value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Deduct 16 points from each teams arena-rating if there are no winners after 45+2 minutes
|
||||
else
|
||||
{
|
||||
_arenaTeamScores[(int)BattlegroundTeamId.Alliance].Assign(winnerTeamRating, (uint)(winnerTeamRating + SharedConst.ArenaTimeLimitPointsLoss), winnerMatchmakerRating, GetArenaMatchmakerRating(Team.Alliance));
|
||||
_arenaTeamScores[(int)BattlegroundTeamId.Horde].Assign(loserTeamRating, (uint)(loserTeamRating + SharedConst.ArenaTimeLimitPointsLoss), loserMatchmakerRating, GetArenaMatchmakerRating(Team.Horde));
|
||||
|
||||
winnerArenaTeam.FinishGame(SharedConst.ArenaTimeLimitPointsLoss);
|
||||
loserArenaTeam.FinishGame(SharedConst.ArenaTimeLimitPointsLoss);
|
||||
}
|
||||
|
||||
uint aliveWinners = GetAlivePlayersCountByTeam(winner);
|
||||
foreach (var pair in GetPlayers())
|
||||
{
|
||||
Team team = pair.Value.Team;
|
||||
|
||||
if (pair.Value.OfflineRemoveTime != 0)
|
||||
{
|
||||
// if rated arena match - make member lost!
|
||||
if (team == winner)
|
||||
winnerArenaTeam.OfflineMemberLost(pair.Key, loserMatchmakerRating, winnerMatchmakerChange);
|
||||
else
|
||||
{
|
||||
if (winner == 0)
|
||||
winnerArenaTeam.OfflineMemberLost(pair.Key, loserMatchmakerRating, winnerMatchmakerChange);
|
||||
|
||||
loserArenaTeam.OfflineMemberLost(pair.Key, winnerMatchmakerRating, loserMatchmakerChange);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Player player = _GetPlayer(pair.Key, pair.Value.OfflineRemoveTime != 0, "Arena.EndBattleground");
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
// per player calculation
|
||||
if (team == winner)
|
||||
{
|
||||
// update achievement BEFORE personal rating update
|
||||
uint rating = player.GetArenaPersonalRating(winnerArenaTeam.GetSlot());
|
||||
player.UpdateCriteria(CriteriaTypes.WinRatedArena, rating != 0 ? rating : 1);
|
||||
player.UpdateCriteria(CriteriaTypes.WinRatedArena, GetMapId());
|
||||
|
||||
// Last standing - Rated 5v5 arena & be solely alive player
|
||||
if (GetArenaType() == ArenaTypes.Team5v5 && aliveWinners == 1 && player.IsAlive())
|
||||
player.CastSpell(player, ArenaSpellIds.LastManStanding, true);
|
||||
|
||||
if (!guildAwarded)
|
||||
{
|
||||
guildAwarded = true;
|
||||
ulong guildId = GetBgMap().GetOwnerGuildId(player.GetBGTeam());
|
||||
if (guildId != 0)
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(guildId);
|
||||
if (guild)
|
||||
guild.UpdateCriteria(CriteriaTypes.WinRatedArena, Math.Max(winnerArenaTeam.GetRating(), 1), 0, 0, null, player);
|
||||
}
|
||||
}
|
||||
|
||||
winnerArenaTeam.MemberWon(player, loserMatchmakerRating, winnerMatchmakerChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (winner == 0)
|
||||
winnerArenaTeam.MemberLost(player, loserMatchmakerRating, winnerMatchmakerChange);
|
||||
|
||||
loserArenaTeam.MemberLost(player, winnerMatchmakerRating, loserMatchmakerChange);
|
||||
|
||||
// Arena lost => reset the win_rated_arena having the "no_lose" condition
|
||||
player.ResetCriteria(CriteriaTypes.WinRatedArena, (uint)CriteriaCondition.NoLose);
|
||||
}
|
||||
}
|
||||
|
||||
// save the stat changes
|
||||
winnerArenaTeam.SaveToDB();
|
||||
loserArenaTeam.SaveToDB();
|
||||
// send updated arena team stats to players
|
||||
// this way all arena team members will get notified, not only the ones who participated in this match
|
||||
winnerArenaTeam.NotifyStatsChanged();
|
||||
loserArenaTeam.NotifyStatsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// end Battleground
|
||||
base.EndBattleground(winner);
|
||||
}
|
||||
|
||||
public ArenaTeamScore[] _arenaTeamScores = new ArenaTeamScore[SharedConst.BGTeamsCount];
|
||||
}
|
||||
|
||||
struct ArenaWorldStates
|
||||
{
|
||||
public const uint AlivePlayersGreen = 3600;
|
||||
public const uint AlivePlayersGold = 3601;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.BattleGrounds;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class ArenaScore : BattlegroundScore
|
||||
{
|
||||
public ArenaScore(ObjectGuid playerGuid, Team team) : base(playerGuid, team)
|
||||
{
|
||||
TeamId = (int)(team == Team.Alliance ? BattlegroundTeamId.Alliance : BattlegroundTeamId.Horde);
|
||||
}
|
||||
|
||||
public override void BuildPvPLogPlayerDataPacket(out PVPLogData.PlayerData playerData)
|
||||
{
|
||||
base.BuildPvPLogPlayerDataPacket(out playerData);
|
||||
|
||||
if (PreMatchRating != 0)
|
||||
playerData.PreMatchRating.Set(PreMatchRating);
|
||||
|
||||
if (PostMatchRating != PreMatchRating)
|
||||
playerData.RatingChange.Set((int)(PostMatchRating - PreMatchRating));
|
||||
|
||||
if (PreMatchMMR != 0)
|
||||
playerData.PreMatchMMR.Set(PreMatchMMR);
|
||||
|
||||
if (PostMatchMMR != PreMatchMMR)
|
||||
playerData.MmrChange.Set((int)(PostMatchMMR - PreMatchMMR));
|
||||
}
|
||||
|
||||
// For Logging purpose
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Damage done: {DamageDone} Healing done: {HealingDone} Killing blows: {KillingBlows} PreMatchRating: {PreMatchRating} " +
|
||||
$"PreMatchMMR: {PreMatchMMR} PostMatchRating: {PostMatchRating} PostMatchMMR: {PostMatchMMR}";
|
||||
}
|
||||
|
||||
uint PreMatchRating;
|
||||
uint PreMatchMMR;
|
||||
uint PostMatchRating;
|
||||
uint PostMatchMMR;
|
||||
}
|
||||
|
||||
public class ArenaTeamScore
|
||||
{
|
||||
public void Assign(uint preMatchRating, uint postMatchRating, uint preMatchMMR, uint postMatchMMR)
|
||||
{
|
||||
PreMatchRating = preMatchRating;
|
||||
PostMatchRating = postMatchRating;
|
||||
PreMatchMMR = preMatchMMR;
|
||||
PostMatchMMR = postMatchMMR;
|
||||
}
|
||||
|
||||
public uint PreMatchRating;
|
||||
public uint PostMatchRating;
|
||||
public uint PreMatchMMR;
|
||||
public uint PostMatchMMR;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,871 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class ArenaTeam
|
||||
{
|
||||
public ArenaTeam()
|
||||
{
|
||||
stats.Rating = (ushort)WorldConfig.GetIntValue(WorldCfg.ArenaStartRating);
|
||||
}
|
||||
|
||||
public bool Create(ObjectGuid captainGuid, byte _type, string arenaTeamName, uint backgroundColor, byte emblemStyle, uint emblemColor, byte borderStyle, uint borderColor)
|
||||
{
|
||||
// Check if captain is present
|
||||
if (!Global.ObjAccessor.FindPlayer(captainGuid))
|
||||
return false;
|
||||
|
||||
// Check if arena team name is already taken
|
||||
if (Global.ArenaTeamMgr.GetArenaTeamByName(arenaTeamName) != null)
|
||||
return false;
|
||||
|
||||
// Generate new arena team id
|
||||
teamId = Global.ArenaTeamMgr.GenerateArenaTeamId();
|
||||
|
||||
// Assign member variables
|
||||
CaptainGuid = captainGuid;
|
||||
type = _type;
|
||||
TeamName = arenaTeamName;
|
||||
BackgroundColor = backgroundColor;
|
||||
EmblemStyle = emblemStyle;
|
||||
EmblemColor = emblemColor;
|
||||
BorderStyle = borderStyle;
|
||||
BorderColor = borderColor;
|
||||
ulong captainLowGuid = captainGuid.GetCounter();
|
||||
|
||||
// Save arena team to db
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_ARENA_TEAM);
|
||||
stmt.AddValue(0, teamId);
|
||||
stmt.AddValue(1, TeamName);
|
||||
stmt.AddValue(2, captainLowGuid);
|
||||
stmt.AddValue(3, type);
|
||||
stmt.AddValue(4, stats.Rating);
|
||||
stmt.AddValue(5, BackgroundColor);
|
||||
stmt.AddValue(6, EmblemStyle);
|
||||
stmt.AddValue(7, EmblemColor);
|
||||
stmt.AddValue(8, BorderStyle);
|
||||
stmt.AddValue(9, BorderColor);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
// Add captain as member
|
||||
AddMember(CaptainGuid);
|
||||
|
||||
Log.outDebug(LogFilter.Arena, "New ArenaTeam created Id: {0}, Name: {1} Type: {2} Captain low GUID: {3}", GetId(), GetName(), GetArenaType(), captainLowGuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AddMember(ObjectGuid playerGuid)
|
||||
{
|
||||
string playerName;
|
||||
Class playerClass;
|
||||
|
||||
// Check if arena team is full (Can't have more than type * 2 players)
|
||||
if (GetMembersSize() >= GetArenaType() * 2)
|
||||
return false;
|
||||
|
||||
// Get player name and class either from db or ObjectMgr
|
||||
CharacterInfo characterInfo;
|
||||
Player player = Global.ObjAccessor.FindPlayer(playerGuid);
|
||||
if (player)
|
||||
{
|
||||
playerClass = player.GetClass();
|
||||
playerName = player.GetName();
|
||||
}
|
||||
else if ((characterInfo = Global.WorldMgr.GetCharacterInfo(playerGuid)) != null)
|
||||
{
|
||||
playerName = characterInfo.Name;
|
||||
playerClass = characterInfo.ClassID;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
// Check if player is already in a similar arena team
|
||||
if ((player && player.GetArenaTeamId(GetSlot()) != 0) || Player.GetArenaTeamIdFromDB(playerGuid, GetArenaType()) != 0)
|
||||
{
|
||||
Log.outDebug(LogFilter.Arena, "Arena: {0} {1} already has an arena team of type {2}", playerGuid.ToString(), playerName, GetArenaType());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set player's personal rating
|
||||
uint personalRating = 0;
|
||||
|
||||
if (WorldConfig.GetIntValue(WorldCfg.ArenaStartPersonalRating) > 0)
|
||||
personalRating = WorldConfig.GetUIntValue(WorldCfg.ArenaStartPersonalRating);
|
||||
else if (GetRating() >= 1000)
|
||||
personalRating = 1000;
|
||||
|
||||
// Try to get player's match maker rating from db and fall back to config setting if not found
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MATCH_MAKER_RATING);
|
||||
stmt.AddValue(0, playerGuid.GetCounter());
|
||||
stmt.AddValue(1, GetSlot());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
uint matchMakerRating;
|
||||
if (!result.IsEmpty())
|
||||
matchMakerRating = result.Read<ushort>(0);
|
||||
else
|
||||
matchMakerRating = WorldConfig.GetUIntValue(WorldCfg.ArenaStartMatchmakerRating);
|
||||
|
||||
// Remove all player signatures from other petitions
|
||||
// This will prevent player from joining too many arena teams and corrupt arena team data integrity
|
||||
//Player.RemovePetitionsAndSigns(playerGuid, GetArenaType());
|
||||
|
||||
// Feed data to the struct
|
||||
ArenaTeamMember newMember = new ArenaTeamMember();
|
||||
newMember.Name = playerName;
|
||||
newMember.Guid = playerGuid;
|
||||
newMember.Class = (byte)playerClass;
|
||||
newMember.SeasonGames = 0;
|
||||
newMember.WeekGames = 0;
|
||||
newMember.SeasonWins = 0;
|
||||
newMember.WeekWins = 0;
|
||||
newMember.PersonalRating = (ushort)(uint)0;
|
||||
newMember.MatchMakerRating = (ushort)matchMakerRating;
|
||||
|
||||
Members.Add(newMember);
|
||||
|
||||
// Save player's arena team membership to db
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_ARENA_TEAM_MEMBER);
|
||||
stmt.AddValue(0, teamId);
|
||||
stmt.AddValue(1, playerGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
// Inform player if online
|
||||
if (player)
|
||||
{
|
||||
player.SetInArenaTeam(teamId, GetSlot(), GetArenaType());
|
||||
player.SetArenaTeamIdInvited(0);
|
||||
|
||||
// Hide promote/remove buttons
|
||||
if (CaptainGuid != playerGuid)
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.Member, 1);
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Arena, "Player: {0} [{1}] joined arena team type: {2} [Id: {3}, Name: {4}].", playerName, playerGuid.ToString(), GetArenaType(), GetId(), GetName());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool LoadArenaTeamFromDB(SQLResult result)
|
||||
{
|
||||
if (result.IsEmpty())
|
||||
return false;
|
||||
|
||||
teamId = result.Read<uint>(0);
|
||||
TeamName = result.Read<string>(1);
|
||||
CaptainGuid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(2));
|
||||
type = result.Read<byte>(3);
|
||||
BackgroundColor = result.Read<uint>(4);
|
||||
EmblemStyle = result.Read<byte>(5);
|
||||
EmblemColor = result.Read<uint>(6);
|
||||
BorderStyle = result.Read<byte>(7);
|
||||
BorderColor = result.Read<uint>(8);
|
||||
stats.Rating = result.Read<ushort>(9);
|
||||
stats.WeekGames = result.Read<ushort>(10);
|
||||
stats.WeekWins = result.Read<ushort>(11);
|
||||
stats.SeasonGames = result.Read<ushort>(12);
|
||||
stats.SeasonWins = result.Read<ushort>(13);
|
||||
stats.Rank = result.Read<uint>(14);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool LoadMembersFromDB(SQLResult result)
|
||||
{
|
||||
if (result.IsEmpty())
|
||||
return false;
|
||||
|
||||
bool captainPresentInTeam = false;
|
||||
|
||||
do
|
||||
{
|
||||
uint arenaTeamId = result.Read<uint>(0);
|
||||
|
||||
// We loaded all members for this arena_team already, break cycle
|
||||
if (arenaTeamId > teamId)
|
||||
break;
|
||||
|
||||
ArenaTeamMember newMember = new ArenaTeamMember();
|
||||
newMember.Guid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(1));
|
||||
newMember.WeekGames = result.Read<ushort>(2);
|
||||
newMember.WeekWins = result.Read<ushort>(3);
|
||||
newMember.SeasonGames = result.Read<ushort>(4);
|
||||
newMember.SeasonWins = result.Read<ushort>(5);
|
||||
newMember.Name = result.Read<string>(6);
|
||||
newMember.Class = result.Read<byte>(7);
|
||||
newMember.PersonalRating = result.Read<ushort>(8);
|
||||
newMember.MatchMakerRating = (ushort)(result.Read<ushort>(9) > 0 ? result.Read<ushort>(9) : 1500);
|
||||
|
||||
// Delete member if character information is missing
|
||||
if (string.IsNullOrEmpty(newMember.Name))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "ArenaTeam {0} has member with empty name - probably {1} doesn't exist, deleting him from memberlist!", arenaTeamId, newMember.Guid.ToString());
|
||||
DelMember(newMember.Guid, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if team team has a valid captain
|
||||
if (newMember.Guid == GetCaptain())
|
||||
captainPresentInTeam = true;
|
||||
|
||||
// Put the player in the team
|
||||
Members.Add(newMember);
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
if (Empty() || !captainPresentInTeam)
|
||||
{
|
||||
// Arena team is empty or captain is not in team, delete from db
|
||||
Log.outDebug(LogFilter.Arena, "ArenaTeam {0} does not have any members or its captain is not in team, disbanding it...", teamId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetName(string name)
|
||||
{
|
||||
if (TeamName == name || string.IsNullOrEmpty(name) || name.Length > 24 || Global.ObjectMgr.IsReservedName(name) || !ObjectManager.IsValidCharterName(name))
|
||||
return false;
|
||||
|
||||
TeamName = name;
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_NAME);
|
||||
stmt.AddValue(0, TeamName);
|
||||
stmt.AddValue(1, GetId());
|
||||
DB.Characters.Execute(stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetCaptain(ObjectGuid guid)
|
||||
{
|
||||
// Disable remove/promote buttons
|
||||
Player oldCaptain = Global.ObjAccessor.FindPlayer(GetCaptain());
|
||||
if (oldCaptain)
|
||||
oldCaptain.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.Member, 1);
|
||||
|
||||
// Set new captain
|
||||
CaptainGuid = guid;
|
||||
|
||||
// Update database
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_CAPTAIN);
|
||||
stmt.AddValue(0, guid.GetCounter());
|
||||
stmt.AddValue(1, GetId());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
// Enable remove/promote buttons
|
||||
Player newCaptain = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (newCaptain)
|
||||
{
|
||||
newCaptain.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.Member, 0);
|
||||
if (oldCaptain)
|
||||
{
|
||||
Log.outDebug(LogFilter.Arena, "Player: {0} [GUID: {1}] promoted player: {2} [GUID: {3}] to leader of arena team [Id: {4}, Name: {5}] [Type: {6}].",
|
||||
oldCaptain.GetName(), oldCaptain.GetGUID().ToString(), newCaptain.GetName(),
|
||||
newCaptain.GetGUID().ToString(), GetId(), GetName(), GetArenaType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DelMember(ObjectGuid guid, bool cleanDb)
|
||||
{
|
||||
// Remove member from team
|
||||
foreach (var member in Members)
|
||||
if (member.Guid == guid)
|
||||
{
|
||||
Members.Remove(member);
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove arena team info from player data
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
{
|
||||
// delete all info regarding this team
|
||||
for (uint i = 0; i < (int)ArenaTeamInfoType.End; ++i)
|
||||
player.SetArenaTeamInfoField(GetSlot(), (ArenaTeamInfoType)i, 0);
|
||||
Log.outDebug(LogFilter.Arena, "Player: {0} [GUID: {1}] left arena team type: {2} [Id: {3}, Name: {4}].", player.GetName(), player.GetGUID().ToString(), GetArenaType(), GetId(), GetName());
|
||||
}
|
||||
|
||||
// Only used for single member deletion, for arena team disband we use a single query for more efficiency
|
||||
if (cleanDb)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM_MEMBER);
|
||||
stmt.AddValue(0, GetId());
|
||||
stmt.AddValue(1, guid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
public void Disband(WorldSession session)
|
||||
{
|
||||
// Broadcast update
|
||||
if (session != null)
|
||||
{
|
||||
Player player = session.GetPlayer();
|
||||
if (player)
|
||||
Log.outDebug(LogFilter.Arena, "Player: {0} [GUID: {1}] disbanded arena team type: {2} [Id: {3}, Name: {4}].", player.GetName(), player.GetGUID().ToString(), GetArenaType(), GetId(), GetName());
|
||||
}
|
||||
|
||||
// Remove all members from arena team
|
||||
while (!Members.Empty())
|
||||
DelMember(Members.FirstOrDefault().Guid, false);
|
||||
|
||||
// Update database
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM);
|
||||
stmt.AddValue(0, teamId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM_MEMBERS);
|
||||
stmt.AddValue(0, teamId);
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
// Remove arena team from ObjectMgr
|
||||
Global.ArenaTeamMgr.RemoveArenaTeam(teamId);
|
||||
}
|
||||
|
||||
public void Disband()
|
||||
{
|
||||
// Remove all members from arena team
|
||||
while (!Members.Empty())
|
||||
DelMember(Members.First().Guid, false);
|
||||
|
||||
// Update database
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM);
|
||||
stmt.AddValue(0, teamId);
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ARENA_TEAM_MEMBERS);
|
||||
stmt.AddValue(0, teamId);
|
||||
trans.Append(stmt);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
// Remove arena team from ObjectMgr
|
||||
Global.ArenaTeamMgr.RemoveArenaTeam(teamId);
|
||||
}
|
||||
|
||||
public void SendStats(WorldSession session)
|
||||
{
|
||||
/*WorldPacket data = new WorldPacket(ServerOpcodes.ArenaTeamStats);
|
||||
data.WriteUInt32(GetId()); // team id
|
||||
data.WriteUInt32(stats.Rating); // rating
|
||||
data.WriteUInt32(stats.WeekGames); // games this week
|
||||
data.WriteUInt32(stats.WeekWins); // wins this week
|
||||
data.WriteUInt32(stats.SeasonGames); // played this season
|
||||
data.WriteUInt32(stats.SeasonWins); // wins this season
|
||||
data.WriteUInt32(stats.Rank); // rank
|
||||
session.SendPacket(data);*/
|
||||
}
|
||||
|
||||
public void NotifyStatsChanged()
|
||||
{
|
||||
// This is called after a rated match ended
|
||||
// Updates arena team stats for every member of the team (not only the ones who participated!)
|
||||
foreach (var member in Members)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(member.Guid);
|
||||
if (player)
|
||||
SendStats(player.GetSession());
|
||||
}
|
||||
}
|
||||
|
||||
public void Inspect(WorldSession session, ObjectGuid guid)
|
||||
{
|
||||
ArenaTeamMember member = GetMember(guid);
|
||||
if (member == null)
|
||||
return;
|
||||
|
||||
WorldPacket data = new WorldPacket(ServerOpcodes.InspectPvp);
|
||||
data.WritePackedGuid(guid); // player guid
|
||||
data.WriteUInt8(GetSlot()); // slot (0...2)
|
||||
data.WriteUInt32(GetId()); // arena team id
|
||||
data.WriteUInt32(stats.Rating); // rating
|
||||
data.WriteUInt32(stats.SeasonGames); // season played
|
||||
data.WriteUInt32(stats.SeasonWins); // season wins
|
||||
data.WriteUInt32(member.SeasonGames); // played (count of all games, that the inspected member participated...)
|
||||
data.WriteUInt32(member.PersonalRating); // personal rating
|
||||
//session.SendPacket(data);
|
||||
}
|
||||
|
||||
void BroadcastPacket(ServerPacket packet)
|
||||
{
|
||||
foreach (var member in Members)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(member.Guid);
|
||||
if (player)
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte GetSlotByType(uint type)
|
||||
{
|
||||
switch ((ArenaTypes)type)
|
||||
{
|
||||
case ArenaTypes.Team2v2: return 0;
|
||||
case ArenaTypes.Team3v3: return 1;
|
||||
case ArenaTypes.Team5v5: return 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Log.outError(LogFilter.Arena, "FATAL: Unknown arena team type {0} for some arena team", type);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public static byte GetTypeBySlot(byte slot)
|
||||
{
|
||||
switch (slot)
|
||||
{
|
||||
case 0: return (byte)ArenaTypes.Team2v2;
|
||||
case 1: return (byte)ArenaTypes.Team3v3;
|
||||
case 2: return (byte)ArenaTypes.Team5v5;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Log.outError(LogFilter.Arena, "FATAL: Unknown arena team slot {0} for some arena team", slot);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public bool IsMember(ObjectGuid guid)
|
||||
{
|
||||
foreach (var member in Members)
|
||||
if (member.Guid == guid)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint GetAverageMMR(Group group)
|
||||
{
|
||||
if (!group)
|
||||
return 0;
|
||||
|
||||
uint matchMakerRating = 0;
|
||||
uint playerDivider = 0;
|
||||
foreach (var member in Members)
|
||||
{
|
||||
// Skip if player is not online
|
||||
if (!Global.ObjAccessor.FindPlayer(member.Guid))
|
||||
continue;
|
||||
|
||||
// Skip if player is not a member of group
|
||||
if (!group.IsMember(member.Guid))
|
||||
continue;
|
||||
|
||||
matchMakerRating += member.MatchMakerRating;
|
||||
++playerDivider;
|
||||
}
|
||||
|
||||
// x/0 = crash
|
||||
if (playerDivider == 0)
|
||||
playerDivider = 1;
|
||||
|
||||
matchMakerRating /= playerDivider;
|
||||
|
||||
return matchMakerRating;
|
||||
}
|
||||
|
||||
float GetChanceAgainst(uint ownRating, uint opponentRating)
|
||||
{
|
||||
// Returns the chance to win against a team with the given rating, used in the rating adjustment calculation
|
||||
// ELO system
|
||||
return (float)(1.0f / (1.0f + Math.Exp(Math.Log(10.0f) * ((float)opponentRating - (float)ownRating) / 650.0f)));
|
||||
}
|
||||
|
||||
int GetMatchmakerRatingMod(uint ownRating, uint opponentRating, bool won)
|
||||
{
|
||||
// 'Chance' calculation - to beat the opponent
|
||||
// This is a simulation. Not much info on how it really works
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
float won_mod = (won) ? 1.0f : 0.0f;
|
||||
float mod = won_mod - chance;
|
||||
|
||||
// Work in progress:
|
||||
/*
|
||||
// This is a simulation, as there is not much info on how it really works
|
||||
float confidence_mod = min(1.0f - fabs(mod), 0.5f);
|
||||
|
||||
// Apply confidence factor to the mod:
|
||||
mod *= confidence_factor
|
||||
|
||||
// And only after that update the new confidence factor
|
||||
confidence_factor -= ((confidence_factor - 1.0f) * confidence_mod) / confidence_factor;
|
||||
*/
|
||||
|
||||
// Real rating modification
|
||||
mod *= WorldConfig.GetFloatValue(WorldCfg.ArenaMatchmakerRatingModifier);
|
||||
|
||||
return (int)Math.Ceiling(mod);
|
||||
}
|
||||
|
||||
int GetRatingMod(uint ownRating, uint opponentRating, bool won)
|
||||
{
|
||||
// 'Chance' calculation - to beat the opponent
|
||||
// This is a simulation. Not much info on how it really works
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
|
||||
// Calculate the rating modification
|
||||
float mod;
|
||||
|
||||
// todo Replace this hack with using the confidence factor (limiting the factor to 2.0f)
|
||||
if (won)
|
||||
{
|
||||
if (ownRating < 1300)
|
||||
{
|
||||
float win_rating_modifier1 = WorldConfig.GetFloatValue(WorldCfg.ArenaWinRatingModifier1);
|
||||
|
||||
if (ownRating < 1000)
|
||||
mod = win_rating_modifier1 * (1.0f - chance);
|
||||
else
|
||||
mod = ((win_rating_modifier1 / 2.0f) + ((win_rating_modifier1 / 2.0f) * (1300.0f - ownRating) / 300.0f)) * (1.0f - chance);
|
||||
}
|
||||
else
|
||||
mod = WorldConfig.GetFloatValue(WorldCfg.ArenaWinRatingModifier2) * (1.0f - chance);
|
||||
}
|
||||
else
|
||||
mod = WorldConfig.GetFloatValue(WorldCfg.ArenaLoseRatingModifier) * (-chance);
|
||||
|
||||
return (int)Math.Ceiling(mod);
|
||||
}
|
||||
|
||||
public void FinishGame(int mod)
|
||||
{
|
||||
// Rating can only drop to 0
|
||||
if (stats.Rating + mod < 0)
|
||||
stats.Rating = 0;
|
||||
else
|
||||
{
|
||||
stats.Rating += (ushort)mod;
|
||||
|
||||
// Check if rating related achivements are met
|
||||
foreach (var member in Members)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(member.Guid);
|
||||
if (player)
|
||||
player.UpdateCriteria(CriteriaTypes.HighestTeamRating, stats.Rating, type);
|
||||
}
|
||||
}
|
||||
|
||||
// Update number of games played per season or week
|
||||
stats.WeekGames += 1;
|
||||
stats.SeasonGames += 1;
|
||||
|
||||
// Update team's rank, start with rank 1 and increase until no team with more rating was found
|
||||
stats.Rank = 1;
|
||||
foreach (var i in Global.ArenaTeamMgr.GetArenaTeamMap())
|
||||
{
|
||||
if (i.Value.GetArenaType() == type && i.Value.GetStats().Rating > stats.Rating)
|
||||
++stats.Rank;
|
||||
}
|
||||
}
|
||||
|
||||
public int WonAgainst(uint ownMMRating, uint opponentMMRating, ref int ratingChange)
|
||||
{
|
||||
// Called when the team has won
|
||||
// Change in Matchmaker rating
|
||||
int mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, true);
|
||||
|
||||
// Change in Team Rating
|
||||
ratingChange = GetRatingMod(stats.Rating, opponentMMRating, true);
|
||||
|
||||
// Modify the team stats accordingly
|
||||
FinishGame(ratingChange);
|
||||
|
||||
// Update number of wins per season and week
|
||||
stats.WeekWins += 1;
|
||||
stats.SeasonWins += 1;
|
||||
|
||||
// Return the rating change, used to display it on the results screen
|
||||
return mod;
|
||||
}
|
||||
|
||||
public int LostAgainst(uint ownMMRating, uint opponentMMRating, ref int ratingChange)
|
||||
{
|
||||
// Called when the team has lost
|
||||
// Change in Matchmaker Rating
|
||||
int mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, false);
|
||||
|
||||
// Change in Team Rating
|
||||
ratingChange = GetRatingMod(stats.Rating, opponentMMRating, false);
|
||||
|
||||
// Modify the team stats accordingly
|
||||
FinishGame(ratingChange);
|
||||
|
||||
// return the rating change, used to display it on the results screen
|
||||
return mod;
|
||||
}
|
||||
|
||||
public void MemberLost(Player player, uint againstMatchmakerRating, int matchmakerRatingChange = -12)
|
||||
{
|
||||
// Called for each participant of a match after losing
|
||||
foreach (var member in Members)
|
||||
{
|
||||
if (member.Guid == player.GetGUID())
|
||||
{
|
||||
// Update personal rating
|
||||
int mod = GetRatingMod(member.PersonalRating, againstMatchmakerRating, false);
|
||||
member.ModifyPersonalRating(player, mod, GetArenaType());
|
||||
|
||||
// Update matchmaker rating
|
||||
member.ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
|
||||
|
||||
// Update personal played stats
|
||||
member.WeekGames += 1;
|
||||
member.SeasonGames += 1;
|
||||
|
||||
// update the unit fields
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.GamesWeek, member.WeekGames);
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.GamesSeason, member.SeasonGames);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OfflineMemberLost(ObjectGuid guid, uint againstMatchmakerRating, int matchmakerRatingChange = -12)
|
||||
{
|
||||
// Called for offline player after ending rated arena match!
|
||||
foreach (var member in Members)
|
||||
{
|
||||
if (member.Guid == guid)
|
||||
{
|
||||
// update personal rating
|
||||
int mod = GetRatingMod(member.PersonalRating, againstMatchmakerRating, false);
|
||||
member.ModifyPersonalRating(null, mod, GetArenaType());
|
||||
|
||||
// update matchmaker rating
|
||||
member.ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
|
||||
|
||||
// update personal played stats
|
||||
member.WeekGames += 1;
|
||||
member.SeasonGames += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MemberWon(Player player, uint againstMatchmakerRating, int matchmakerRatingChange)
|
||||
{
|
||||
// called for each participant after winning a match
|
||||
foreach (var member in Members)
|
||||
{
|
||||
if (member.Guid == player.GetGUID())
|
||||
{
|
||||
// update personal rating
|
||||
int mod = GetRatingMod(member.PersonalRating, againstMatchmakerRating, true);
|
||||
member.ModifyPersonalRating(player, mod, GetArenaType());
|
||||
|
||||
// update matchmaker rating
|
||||
member.ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
|
||||
|
||||
// update personal stats
|
||||
member.WeekGames += 1;
|
||||
member.SeasonGames += 1;
|
||||
member.SeasonWins += 1;
|
||||
member.WeekWins += 1;
|
||||
// update unit fields
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.GamesWeek, member.WeekGames);
|
||||
player.SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType.GamesSeason, member.SeasonGames);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveToDB()
|
||||
{
|
||||
// Save team and member stats to db
|
||||
// Called after a match has ended or when calculating arena_points
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_STATS);
|
||||
stmt.AddValue(0, stats.Rating);
|
||||
stmt.AddValue(1, stats.WeekGames);
|
||||
stmt.AddValue(2, stats.WeekWins);
|
||||
stmt.AddValue(3, stats.SeasonGames);
|
||||
stmt.AddValue(4, stats.SeasonWins);
|
||||
stmt.AddValue(5, stats.Rank);
|
||||
stmt.AddValue(6, GetId());
|
||||
trans.Append(stmt);
|
||||
|
||||
foreach (var member in Members)
|
||||
{
|
||||
// Save the effort and go
|
||||
if (member.WeekGames == 0)
|
||||
continue;
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ARENA_TEAM_MEMBER);
|
||||
stmt.AddValue(0, member.PersonalRating);
|
||||
stmt.AddValue(1, member.WeekGames);
|
||||
stmt.AddValue(2, member.WeekWins);
|
||||
stmt.AddValue(3, member.SeasonGames);
|
||||
stmt.AddValue(4, member.SeasonWins);
|
||||
stmt.AddValue(5, GetId());
|
||||
stmt.AddValue(6, member.Guid.GetCounter());
|
||||
trans.Append(stmt);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.REP_CHARACTER_ARENA_STATS);
|
||||
stmt.AddValue(0, member.Guid.GetCounter());
|
||||
stmt.AddValue(1, GetSlot());
|
||||
stmt.AddValue(2, member.MatchMakerRating);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
public bool FinishWeek()
|
||||
{
|
||||
// No need to go further than this
|
||||
if (stats.WeekGames == 0)
|
||||
return false;
|
||||
|
||||
// Reset team stats
|
||||
stats.WeekGames = 0;
|
||||
stats.WeekWins = 0;
|
||||
|
||||
// Reset member stats
|
||||
foreach (var member in Members)
|
||||
{
|
||||
member.WeekGames = 0;
|
||||
member.WeekWins = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsFighting()
|
||||
{
|
||||
foreach (var member in Members)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(member.Guid);
|
||||
if (player)
|
||||
if (player.GetMap().IsBattleArena())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ArenaTeamMember GetMember(string name)
|
||||
{
|
||||
foreach (var member in Members)
|
||||
if (member.Name == name)
|
||||
return member;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArenaTeamMember GetMember(ObjectGuid guid)
|
||||
{
|
||||
foreach (var member in Members)
|
||||
if (member.Guid == guid)
|
||||
return member;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public uint GetId() { return teamId; }
|
||||
public byte GetArenaType() { return type; }
|
||||
public byte GetSlot() { return GetSlotByType(GetArenaType()); }
|
||||
|
||||
public ObjectGuid GetCaptain() { return CaptainGuid; }
|
||||
public string GetName() { return TeamName; }
|
||||
public ArenaTeamStats GetStats() { return stats; }
|
||||
public uint GetRating() { return stats.Rating; }
|
||||
|
||||
public int GetMembersSize() { return Members.Count; }
|
||||
bool Empty() { return Members.Empty(); }
|
||||
public List<ArenaTeamMember> GetMembers()
|
||||
{
|
||||
return Members;
|
||||
}
|
||||
|
||||
uint teamId;
|
||||
byte type;
|
||||
string TeamName;
|
||||
ObjectGuid CaptainGuid;
|
||||
|
||||
uint BackgroundColor; // ARGB format
|
||||
byte EmblemStyle; // icon id
|
||||
uint EmblemColor; // ARGB format
|
||||
byte BorderStyle; // border image id
|
||||
uint BorderColor; // ARGB format
|
||||
|
||||
List<ArenaTeamMember> Members = new List<ArenaTeamMember>();
|
||||
ArenaTeamStats stats;
|
||||
}
|
||||
|
||||
public class ArenaTeamMember
|
||||
{
|
||||
public ObjectGuid Guid;
|
||||
public string Name;
|
||||
public byte Class;
|
||||
public ushort WeekGames;
|
||||
public ushort WeekWins;
|
||||
public ushort SeasonGames;
|
||||
public ushort SeasonWins;
|
||||
public ushort PersonalRating;
|
||||
public ushort MatchMakerRating;
|
||||
|
||||
public void ModifyPersonalRating(Player player, int mod, uint type)
|
||||
{
|
||||
if (PersonalRating + mod < 0)
|
||||
PersonalRating = 0;
|
||||
else
|
||||
PersonalRating += (ushort)mod;
|
||||
|
||||
if (player)
|
||||
{
|
||||
player.SetArenaTeamInfoField(ArenaTeam.GetSlotByType(type), ArenaTeamInfoType.PersonalRating, PersonalRating);
|
||||
player.UpdateCriteria(CriteriaTypes.HighestPersonalRating, PersonalRating, type);
|
||||
}
|
||||
}
|
||||
|
||||
public void ModifyMatchmakerRating(int mod, uint slot)
|
||||
{
|
||||
if (MatchMakerRating + mod < 0)
|
||||
MatchMakerRating = 0;
|
||||
else
|
||||
MatchMakerRating += (ushort)mod;
|
||||
}
|
||||
}
|
||||
|
||||
public struct ArenaTeamStats
|
||||
{
|
||||
public ushort Rating;
|
||||
public ushort WeekGames;
|
||||
public ushort WeekWins;
|
||||
public ushort SeasonGames;
|
||||
public ushort SeasonWins;
|
||||
public uint Rank;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class ArenaTeamManager : Singleton<ArenaTeamManager>
|
||||
{
|
||||
ArenaTeamManager()
|
||||
{
|
||||
NextArenaTeamId = 1;
|
||||
}
|
||||
|
||||
public ArenaTeam GetArenaTeamById(uint arenaTeamId)
|
||||
{
|
||||
return ArenaTeamStorage.LookupByKey(arenaTeamId);
|
||||
}
|
||||
|
||||
public ArenaTeam GetArenaTeamByName(string arenaTeamName)
|
||||
{
|
||||
string search = arenaTeamName.ToLower();
|
||||
foreach (var team in ArenaTeamStorage.Values)
|
||||
{
|
||||
string teamName = team.GetName().ToLower();
|
||||
if (search == teamName)
|
||||
return team;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArenaTeam GetArenaTeamByCaptain(ObjectGuid guid)
|
||||
{
|
||||
foreach (var pair in ArenaTeamStorage)
|
||||
if (pair.Value.GetCaptain() == guid)
|
||||
return pair.Value;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void AddArenaTeam(ArenaTeam arenaTeam)
|
||||
{
|
||||
ArenaTeamStorage[arenaTeam.GetId()] = arenaTeam;
|
||||
}
|
||||
|
||||
public void RemoveArenaTeam(uint arenaTeamId)
|
||||
{
|
||||
ArenaTeamStorage.Remove(arenaTeamId);
|
||||
}
|
||||
|
||||
public uint GenerateArenaTeamId()
|
||||
{
|
||||
if (NextArenaTeamId >= 0xFFFFFFFE)
|
||||
{
|
||||
Log.outError(LogFilter.Battleground, "Arena team ids overflow!! Can't continue, shutting down server. ");
|
||||
Global.WorldMgr.StopNow();
|
||||
}
|
||||
return NextArenaTeamId++;
|
||||
}
|
||||
|
||||
public void LoadArenaTeams()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
// Clean out the trash before loading anything
|
||||
DB.Characters.Execute("DELETE FROM arena_team_member WHERE arenaTeamId NOT IN (SELECT arenaTeamId FROM arena_team)"); // One-time query
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
SQLResult result = DB.Characters.Query("SELECT arenaTeamId, name, captainGuid, type, backgroundColor, emblemStyle, emblemColor, borderStyle, borderColor, " +
|
||||
// 9 10 11 12 13 14
|
||||
"rating, weekGames, weekWins, seasonGames, seasonWins, rank FROM arena_team ORDER BY arenaTeamId ASC");
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 arena teams. DB table `arena_team` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
SQLResult result2 = DB.Characters.Query(
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
"SELECT arenaTeamId, atm.guid, atm.weekGames, atm.weekWins, atm.seasonGames, atm.seasonWins, c.name, class, personalRating, matchMakerRating FROM arena_team_member atm" +
|
||||
" INNER JOIN arena_team ate USING (arenaTeamId) LEFT JOIN characters AS c ON atm.guid = c.guid" +
|
||||
" LEFT JOIN character_arena_stats AS cas ON c.guid = cas.guid AND (cas.slot = 0 AND ate.type = 2 OR cas.slot = 1 AND ate.type = 3 OR cas.slot = 2 AND ate.type = 5)" +
|
||||
" ORDER BY atm.arenateamid ASC");
|
||||
|
||||
uint count = 0;
|
||||
do
|
||||
{
|
||||
ArenaTeam newArenaTeam = new ArenaTeam();
|
||||
|
||||
if (!newArenaTeam.LoadArenaTeamFromDB(result) || !newArenaTeam.LoadMembersFromDB(result2))
|
||||
{
|
||||
newArenaTeam.Disband(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
AddArenaTeam(newArenaTeam);
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} arena teams in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public void SetNextArenaTeamId(uint Id) { NextArenaTeamId = Id; }
|
||||
|
||||
public Dictionary<uint, ArenaTeam> GetArenaTeamMap() { return ArenaTeamStorage; }
|
||||
|
||||
uint NextArenaTeamId;
|
||||
Dictionary<uint, ArenaTeam> ArenaTeamStorage = new Dictionary<uint, ArenaTeam>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class BladesEdgeArena : Arena
|
||||
{
|
||||
public override void StartingEventCloseDoors()
|
||||
{
|
||||
for (int i = BladeEdgeObjectTypes.Door1; i <= BladeEdgeObjectTypes.Door4; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnImmediately);
|
||||
|
||||
for (int i = BladeEdgeObjectTypes.Buff1; i <= BladeEdgeObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnOneDay);
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
for (int i = BladeEdgeObjectTypes.Door1; i <= BladeEdgeObjectTypes.Door4; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (int i = BladeEdgeObjectTypes.Buff1; i <= BladeEdgeObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4538: // buff trigger?
|
||||
case 4539: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(0x9f3, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(BladeEdgeObjectTypes.Door1, BladeEfgeGameObjects.Door1, 6287.277f, 282.1877f, 3.810925f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(BladeEdgeObjectTypes.Door2, BladeEfgeGameObjects.Door2, 6189.546f, 241.7099f, 3.101481f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(BladeEdgeObjectTypes.Door3, BladeEfgeGameObjects.Door3, 6299.116f, 296.5494f, 3.308032f, 0.8813917f, 0, 0, 0.4265689f, 0.9044551f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(BladeEdgeObjectTypes.Door4, BladeEfgeGameObjects.Door4, 6177.708f, 227.3481f, 3.604374f, -2.260201f, 0, 0, 0.9044551f, -0.4265689f, BattlegroundConst.RespawnImmediately);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "BatteGroundBE: Failed to spawn door object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(BladeEdgeObjectTypes.Buff1, BladeEfgeGameObjects.Buff1, 6249.042f, 275.3239f, 11.22033f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120);
|
||||
result &= AddObject(BladeEdgeObjectTypes.Buff2, BladeEfgeGameObjects.Buff2, 6228.26f, 249.566f, 11.21812f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "BladesEdgeArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
struct BladeEdgeObjectTypes
|
||||
{
|
||||
public const int Door1 = 0;
|
||||
public const int Door2 = 1;
|
||||
public const int Door3 = 2;
|
||||
public const int Door4 = 3;
|
||||
public const int Buff1 = 4;
|
||||
public const int Buff2 = 5;
|
||||
public const int Max = 6;
|
||||
}
|
||||
|
||||
struct BladeEfgeGameObjects
|
||||
{
|
||||
public const uint Door1 = 183971;
|
||||
public const uint Door2 = 183973;
|
||||
public const uint Door3 = 183970;
|
||||
public const uint Door4 = 183972;
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Dynamic;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class DalaranSewersArena : Arena
|
||||
{
|
||||
public DalaranSewersArena()
|
||||
{
|
||||
_events = new EventMap();
|
||||
}
|
||||
|
||||
public override void StartingEventCloseDoors()
|
||||
{
|
||||
for (int i = DalaranSewersObjectTypes.Door1; i <= DalaranSewersObjectTypes.Door2; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnImmediately);
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
for (int i = DalaranSewersObjectTypes.Door1; i <= DalaranSewersObjectTypes.Door2; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (int i = DalaranSewersObjectTypes.Buff1; i <= DalaranSewersObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallWarning, RandomHelper.URand(DalaranSewersData.WaterfallTimerMin, DalaranSewersData.WaterfallTimerMax));
|
||||
_events.ScheduleEvent(DalaranSewersEvents.PipeKnockback, DalaranSewersData.PipeKnockbackFirstDelay);
|
||||
|
||||
SpawnBGObject(DalaranSewersObjectTypes.Water2, BattlegroundConst.RespawnImmediately);
|
||||
|
||||
DoorOpen(DalaranSewersObjectTypes.Water1); // Turn off collision
|
||||
DoorOpen(DalaranSewersObjectTypes.Water2);
|
||||
|
||||
// Remove effects of Demonic Circle Summon
|
||||
foreach (var pair in GetPlayers())
|
||||
{
|
||||
Player player = _GetPlayer(pair, "BattlegroundDS::StartingEventOpenDoors");
|
||||
if (player)
|
||||
player.RemoveAurasDueToSpell(DalaranSewersSpells.DemonicCircle);
|
||||
}
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 5347:
|
||||
case 5348:
|
||||
// Remove effects of Demonic Circle Summon
|
||||
player.RemoveAurasDueToSpell(DalaranSewersSpells.DemonicCircle);
|
||||
|
||||
// Someone has get back into the pipes and the knockback has already been performed,
|
||||
// so we reset the knockback count for kicking the player again into the arena.
|
||||
_events.ScheduleEvent(DalaranSewersEvents.PipeKnockback, DalaranSewersData.PipeKnockbackDelay);
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(3610, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(DalaranSewersObjectTypes.Door1, DalaranSewersGameObjects.Door1, 1350.95f, 817.2f, 20.8096f, 3.15f, 0, 0, 0.99627f, 0.0862864f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(DalaranSewersObjectTypes.Door2, DalaranSewersGameObjects.Door2, 1232.65f, 764.913f, 20.0729f, 6.3f, 0, 0, 0.0310211f, -0.999519f, BattlegroundConst.RespawnImmediately);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "DalaranSewersArena: Failed to spawn door object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// buffs
|
||||
result &= AddObject(DalaranSewersObjectTypes.Buff1, DalaranSewersGameObjects.Buff1, 1291.7f, 813.424f, 7.11472f, 4.64562f, 0, 0, 0.730314f, -0.683111f, 120);
|
||||
result &= AddObject(DalaranSewersObjectTypes.Buff2, DalaranSewersGameObjects.Buff2, 1291.7f, 768.911f, 7.11472f, 1.55194f, 0, 0, 0.700409f, 0.713742f, 120);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "DalaranSewersArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(DalaranSewersObjectTypes.Water1, DalaranSewersGameObjects.Water1, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, 120);
|
||||
result &= AddObject(DalaranSewersObjectTypes.Water2, DalaranSewersGameObjects.Water2, 1291.56f, 790.837f, 7.1f, 3.14238f, 0, 0, 0.694215f, -0.719768f, 120);
|
||||
result &= AddCreature(DalaranSewersData.NpcWaterSpout, DalaranSewersCreatureTypes.WaterfallKnockback, 1292.587f, 790.2205f, 7.19796f, 3.054326f, TeamId.Neutral, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddCreature(DalaranSewersData.NpcWaterSpout, DalaranSewersCreatureTypes.PipeKnockback1, 1369.977f, 817.2882f, 16.08718f, 3.106686f, TeamId.Neutral, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddCreature(DalaranSewersData.NpcWaterSpout, DalaranSewersCreatureTypes.PipeKnockback2, 1212.833f, 765.3871f, 16.09484f, 0.0f, TeamId.Neutral, BattlegroundConst.RespawnImmediately);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "DalaranSewersArena: Failed to spawn collision object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void PostUpdateImpl(uint diff)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
_events.ExecuteEvents(eventId =>
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case DalaranSewersEvents.WaterfallWarning:
|
||||
// Add the water
|
||||
DoorClose(DalaranSewersObjectTypes.Water2);
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallOn, DalaranSewersData.WaterWarningDuration);
|
||||
break;
|
||||
case DalaranSewersEvents.WaterfallOn:
|
||||
// Active collision and start knockback timer
|
||||
DoorClose(DalaranSewersObjectTypes.Water1);
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallOff, DalaranSewersData.WaterfallDuration);
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallKnockback, DalaranSewersData.WaterfallKnockbackTimer);
|
||||
break;
|
||||
case DalaranSewersEvents.WaterfallOff:
|
||||
// Remove collision and water
|
||||
DoorOpen(DalaranSewersObjectTypes.Water1);
|
||||
DoorOpen(DalaranSewersObjectTypes.Water2);
|
||||
_events.CancelEvent(DalaranSewersEvents.WaterfallKnockback);
|
||||
_events.ScheduleEvent(DalaranSewersEvents.WaterfallWarning, RandomHelper.URand(DalaranSewersData.WaterfallTimerMin, DalaranSewersData.WaterfallTimerMax));
|
||||
break;
|
||||
case DalaranSewersEvents.WaterfallKnockback:
|
||||
{
|
||||
// Repeat knockback while the waterfall still active
|
||||
Creature waterSpout = GetBGCreature(DalaranSewersCreatureTypes.WaterfallKnockback);
|
||||
if (waterSpout)
|
||||
waterSpout.CastSpell(waterSpout, DalaranSewersSpells.WaterSpout, true);
|
||||
_events.ScheduleEvent(eventId, DalaranSewersData.WaterfallKnockbackTimer);
|
||||
}
|
||||
break;
|
||||
case DalaranSewersEvents.PipeKnockback:
|
||||
{
|
||||
for (int i = DalaranSewersCreatureTypes.PipeKnockback1; i <= DalaranSewersCreatureTypes.PipeKnockback2; ++i)
|
||||
{
|
||||
Creature waterSpout = GetBGCreature(i);
|
||||
if (waterSpout)
|
||||
waterSpout.CastSpell(waterSpout, DalaranSewersSpells.Flush, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EventMap _events;
|
||||
}
|
||||
|
||||
struct DalaranSewersEvents
|
||||
{
|
||||
public const int WaterfallWarning = 1; // Water starting to fall, but no LoS Blocking nor movement blocking
|
||||
public const uint WaterfallOn = 2; // LoS and Movement blocking active
|
||||
public const uint WaterfallOff = 3;
|
||||
public const uint WaterfallKnockback = 4;
|
||||
|
||||
public const uint PipeKnockback = 5;
|
||||
}
|
||||
|
||||
struct DalaranSewersObjectTypes
|
||||
{
|
||||
public const int Door1 = 0;
|
||||
public const int Door2 = 1;
|
||||
public const int Water1 = 2; // Collision
|
||||
public const int Water2 = 3;
|
||||
public const int Buff1 = 4;
|
||||
public const int Buff2 = 5;
|
||||
public const int Max = 6;
|
||||
}
|
||||
|
||||
struct DalaranSewersGameObjects
|
||||
{
|
||||
public const uint Door1 = 192642;
|
||||
public const uint Door2 = 192643;
|
||||
public const uint Water1 = 194395; // Collision
|
||||
public const uint Water2 = 191877;
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
}
|
||||
|
||||
struct DalaranSewersCreatureTypes
|
||||
{
|
||||
public const int WaterfallKnockback = 0;
|
||||
public const int PipeKnockback1 = 1;
|
||||
public const int PipeKnockback2 = 2;
|
||||
public const int Max = 3;
|
||||
}
|
||||
|
||||
struct DalaranSewersData
|
||||
{
|
||||
// These values are NOT blizzlike... need the correct data!
|
||||
public const uint WaterfallTimerMin = 30000;
|
||||
public const uint WaterfallTimerMax = 60000;
|
||||
public const uint WaterWarningDuration = 5000;
|
||||
public const uint WaterfallDuration = 30000;
|
||||
public const uint WaterfallKnockbackTimer = 1500;
|
||||
|
||||
public const uint PipeKnockbackFirstDelay = 5000;
|
||||
public const uint PipeKnockbackDelay = 3000;
|
||||
public const uint PipeKnockbackTotalCount = 2;
|
||||
|
||||
public const uint NpcWaterSpout = 28567;
|
||||
}
|
||||
|
||||
struct DalaranSewersSpells
|
||||
{
|
||||
public const uint Flush = 57405; // Visual And Target Selector For The Starting Knockback From The Pipe
|
||||
public const uint FlushKnockback = 61698; // Knockback Effect For Previous Spell (Triggered, Not Needed To Be Cast)
|
||||
public const uint WaterSpout = 58873; // Knockback Effect Of The Central Waterfall
|
||||
|
||||
public const uint DemonicCircle = 48018; // Demonic Circle Summon
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
public class NagrandArena : Arena
|
||||
{
|
||||
public override void StartingEventCloseDoors()
|
||||
{
|
||||
for (int i = NagrandArenaObjectTypes.Door1; i <= NagrandArenaObjectTypes.Door4; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnImmediately);
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
for (int i = NagrandArenaObjectTypes.Door1; i <= NagrandArenaObjectTypes.Door4; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (int i = NagrandArenaObjectTypes.Buff1; i <= NagrandArenaObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4536: // buff trigger?
|
||||
case 4537: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(0xa11, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(NagrandArenaObjectTypes.Door1, NagrandArenaObjects.Door1, 4031.854f, 2966.833f, 12.6462f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(NagrandArenaObjectTypes.Door2, NagrandArenaObjects.Door2, 4081.179f, 2874.97f, 12.39171f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(NagrandArenaObjectTypes.Door3, NagrandArenaObjects.Door3, 4023.709f, 2981.777f, 10.70117f, -2.648788f, 0, 0, 0.9697962f, -0.2439165f, BattlegroundConst.RespawnImmediately);
|
||||
result &= AddObject(NagrandArenaObjectTypes.Door4, NagrandArenaObjects.Door4, 4090.064f, 2858.438f, 10.23631f, 0.4928045f, 0, 0, 0.2439165f, 0.9697962f, BattlegroundConst.RespawnImmediately);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "NagrandArena: Failed to spawn door object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(NagrandArenaObjectTypes.Buff1, NagrandArenaObjects.Buff1, 4009.189941f, 2895.250000f, 13.052700f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120);
|
||||
result &= AddObject(NagrandArenaObjectTypes.Buff2, NagrandArenaObjects.Buff2, 4103.330078f, 2946.350098f, 13.051300f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "NagrandArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
struct NagrandArenaObjectTypes
|
||||
{
|
||||
public const int Door1 = 0;
|
||||
public const int Door2 = 1;
|
||||
public const int Door3 = 2;
|
||||
public const int Door4 = 3;
|
||||
public const int Buff1 = 4;
|
||||
public const int Buff2 = 5;
|
||||
public const int Max = 6;
|
||||
}
|
||||
|
||||
struct NagrandArenaObjects
|
||||
{
|
||||
public const uint Door1 = 183978;
|
||||
public const uint Door2 = 183980;
|
||||
public const uint Door3 = 183977;
|
||||
public const uint Door4 = 183979;
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Dynamic;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class RingofValorArena : Arena
|
||||
{
|
||||
public RingofValorArena()
|
||||
{
|
||||
_events = new EventMap();
|
||||
}
|
||||
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(RingofValorObjectTypes.Elevator1, RingofValorGameObjects.Elevator1, 763.536377f, -294.535767f, 0.505383f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Elevator2, RingofValorGameObjects.Elevator2, 763.506348f, -273.873352f, 0.505383f, 0.000000f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn elevator object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RingofValorObjectTypes.Buff1, RingofValorGameObjects.Buff1, 735.551819f, -284.794678f, 28.276682f, 0.034906f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Buff2, RingofValorGameObjects.Buff2, 791.224487f, -284.794464f, 28.276682f, 2.600535f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RingofValorObjectTypes.Fire1, RingofValorGameObjects.Fire1, 743.543457f, -283.799469f, 28.286655f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Fire2, RingofValorGameObjects.Fire2, 782.971802f, -283.799469f, 28.286655f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Firedoor1, RingofValorGameObjects.Firedoor1, 743.711060f, -284.099609f, 27.542587f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Firedoor2, RingofValorGameObjects.Firedoor2, 783.221252f, -284.133362f, 27.535686f, 0.000000f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn fire/firedoor object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RingofValorObjectTypes.Gear1, RingofValorGameObjects.Gear1, 763.664551f, -261.872986f, 26.686588f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Gear2, RingofValorGameObjects.Gear2, 763.578979f, -306.146149f, 26.665222f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pulley1, RingofValorGameObjects.Pulley1, 700.722290f, -283.990662f, 39.517582f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pulley2, RingofValorGameObjects.Pulley2, 826.303833f, -283.996429f, 39.517582f, 0.000000f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn gear/pully object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RingofValorObjectTypes.Pilar1, RingofValorGameObjects.Pilar1, 763.632385f, -306.162384f, 25.909504f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pilar2, RingofValorGameObjects.Pilar2, 723.644287f, -284.493256f, 24.648525f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pilar3, RingofValorGameObjects.Pilar3, 763.611145f, -261.856750f, 25.909504f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.Pilar4, RingofValorGameObjects.Pilar4, 802.211609f, -284.493256f, 24.648525f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.PilarCollision1, RingofValorGameObjects.PilarCollision1, 763.632385f, -306.162384f, 30.639660f, 3.141593f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.PilarCollision2, RingofValorGameObjects.PilarCollision2, 723.644287f, -284.493256f, 32.382710f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.PilarCollision3, RingofValorGameObjects.PilarCollision3, 763.611145f, -261.856750f, 30.639660f, 0.000000f, 0, 0, 0, 0);
|
||||
result &= AddObject(RingofValorObjectTypes.PilarCollision4, RingofValorGameObjects.PilarCollision4, 802.211609f, -284.493256f, 32.382710f, 3.141593f, 0, 0, 0, 0);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RingofValorArena: Failed to spawn pilar object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
// Buff respawn
|
||||
SpawnBGObject(RingofValorObjectTypes.Buff1, 90);
|
||||
SpawnBGObject(RingofValorObjectTypes.Buff2, 90);
|
||||
// Elevators
|
||||
DoorOpen(RingofValorObjectTypes.Elevator1);
|
||||
DoorOpen(RingofValorObjectTypes.Elevator2);
|
||||
|
||||
_events.ScheduleEvent(RingofValorEvents.OpenFences, 20133);
|
||||
|
||||
// Should be false at first, TogglePillarCollision will do it.
|
||||
TogglePillarCollision(true);
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 5224:
|
||||
case 5226:
|
||||
// fire was removed in 3.2.0
|
||||
case 5473:
|
||||
case 5474:
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(0xe1a, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
|
||||
public override void PostUpdateImpl(uint diff)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
_events.ExecuteEvents(eventId =>
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case RingofValorEvents.OpenFences:
|
||||
// Open fire (only at game start)
|
||||
for (byte i = RingofValorObjectTypes.Fire1; i <= RingofValorObjectTypes.Firedoor2; ++i)
|
||||
DoorOpen(i);
|
||||
_events.ScheduleEvent(RingofValorEvents.CloseFire, 5000);
|
||||
break;
|
||||
case RingofValorEvents.CloseFire:
|
||||
for (byte i = RingofValorObjectTypes.Fire1; i <= RingofValorObjectTypes.Firedoor2; ++i)
|
||||
DoorClose(i);
|
||||
// Fire got closed after five seconds, leaves twenty seconds before toggling pillars
|
||||
_events.ScheduleEvent(RingofValorEvents.SwitchPillars, 20000);
|
||||
break;
|
||||
case RingofValorEvents.SwitchPillars:
|
||||
TogglePillarCollision(true);
|
||||
_events.Repeat(25000);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TogglePillarCollision(bool enable)
|
||||
{
|
||||
// Toggle visual pillars, pulley, gear, and collision based on previous state
|
||||
for (int i = RingofValorObjectTypes.Pilar1; i <= RingofValorObjectTypes.Gear2; ++i)
|
||||
{
|
||||
if (enable)
|
||||
DoorOpen(i);
|
||||
else
|
||||
DoorClose(i);
|
||||
}
|
||||
|
||||
for (byte i = RingofValorObjectTypes.Pilar2; i <= RingofValorObjectTypes.Pulley2; ++i)
|
||||
{
|
||||
if (enable)
|
||||
DoorClose(i);
|
||||
else
|
||||
DoorOpen(i);
|
||||
}
|
||||
|
||||
for (byte i = RingofValorObjectTypes.Pilar1; i <= RingofValorObjectTypes.PilarCollision4; ++i)
|
||||
{
|
||||
GameObject go = GetBGObject(i);
|
||||
if (go)
|
||||
{
|
||||
if (i >= RingofValorObjectTypes.PilarCollision1)
|
||||
{
|
||||
GameObjectState state = ((go.GetGoInfo().Door.startOpen != 0) == enable) ? GameObjectState.Active : GameObjectState.Ready;
|
||||
go.SetGoState(state);
|
||||
}
|
||||
|
||||
foreach (var guid in GetPlayers().Keys)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
go.SendUpdateToPlayer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EventMap _events;
|
||||
}
|
||||
|
||||
struct RingofValorEvents
|
||||
{
|
||||
public const int OpenFences = 0;
|
||||
public const int SwitchPillars = 1;
|
||||
public const int CloseFire = 2;
|
||||
}
|
||||
|
||||
struct RingofValorObjectTypes
|
||||
{
|
||||
public const int Buff1 = 1;
|
||||
public const int Buff2 = 2;
|
||||
public const int Fire1 = 3;
|
||||
public const int Fire2 = 4;
|
||||
public const int Firedoor1 = 5;
|
||||
public const int Firedoor2 = 6;
|
||||
|
||||
public const int Pilar1 = 7;
|
||||
public const int Pilar3 = 8;
|
||||
public const int Gear1 = 9;
|
||||
public const int Gear2 = 10;
|
||||
|
||||
public const int Pilar2 = 11;
|
||||
public const int Pilar4 = 12;
|
||||
public const int Pulley1 = 13;
|
||||
public const int Pulley2 = 14;
|
||||
|
||||
public const int PilarCollision1 = 15;
|
||||
public const int PilarCollision2 = 16;
|
||||
public const int PilarCollision3 = 17;
|
||||
public const int PilarCollision4 = 18;
|
||||
|
||||
public const int Elevator1 = 19;
|
||||
public const int Elevator2= 20;
|
||||
public const int Max = 21;
|
||||
}
|
||||
|
||||
struct RingofValorGameObjects
|
||||
{
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
public const uint Fire1 = 192704;
|
||||
public const uint Fire2 = 192705;
|
||||
|
||||
public const uint Firedoor2 = 192387;
|
||||
public const uint Firedoor1 = 192388;
|
||||
public const uint Pulley1 = 192389;
|
||||
public const uint Pulley2 = 192390;
|
||||
public const uint Gear1 = 192393;
|
||||
public const uint Gear2 = 192394;
|
||||
public const uint Elevator1 = 194582;
|
||||
public const uint Elevator2 = 194586;
|
||||
|
||||
public const uint PilarCollision1 = 194580; // Axe
|
||||
public const uint PilarCollision2 = 194579; // Arena
|
||||
public const uint PilarCollision3 = 194581; // Lightning
|
||||
public const uint PilarCollision4 = 194578; // Ivory
|
||||
|
||||
public const uint Pilar1 = 194583; // Axe
|
||||
public const uint Pilar2 = 194584; // Arena
|
||||
public const uint Pilar3 = 194585; // Lightning
|
||||
public const uint Pilar4 = 194587; // Ivory
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class RuinsofLordaeronArena : Arena
|
||||
{
|
||||
public override bool SetupBattleground()
|
||||
{
|
||||
bool result = true;
|
||||
result &= AddObject(RuinsofLordaeronObjectTypes.Door1, RuinsofLordaeronObjectTypes.Door1, 1293.561f, 1601.938f, 31.60557f, -1.457349f, 0, 0, -0.6658813f, 0.7460576f);
|
||||
result &= AddObject(RuinsofLordaeronObjectTypes.Door2, RuinsofLordaeronObjectTypes.Door2, 1278.648f, 1730.557f, 31.60557f, 1.684245f, 0, 0, 0.7460582f, 0.6658807f);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RuinsofLordaeronArena: Failed to spawn door object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
result &= AddObject(RuinsofLordaeronObjectTypes.Buff1, RuinsofLordaeronObjectTypes.Buff1, 1328.719971f, 1632.719971f, 36.730400f, -1.448624f, 0, 0, 0.6626201f, -0.7489557f, 120);
|
||||
result &= AddObject(RuinsofLordaeronObjectTypes.Buff2, RuinsofLordaeronObjectTypes.Buff2, 1243.300049f, 1699.170044f, 34.872601f, -0.06981307f, 0, 0, 0.03489945f, -0.9993908f, 120);
|
||||
if (!result)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "RuinsofLordaeronArena: Failed to spawn buff object!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void StartingEventCloseDoors()
|
||||
{
|
||||
for (int i = RuinsofLordaeronObjectTypes.Door1; i <= RuinsofLordaeronObjectTypes.Door2; ++i)
|
||||
SpawnBGObject(i, BattlegroundConst.RespawnImmediately);
|
||||
}
|
||||
|
||||
public override void StartingEventOpenDoors()
|
||||
{
|
||||
for (int i = RuinsofLordaeronObjectTypes.Door1; i <= RuinsofLordaeronObjectTypes.Door2; ++i)
|
||||
DoorOpen(i);
|
||||
|
||||
for (int i = RuinsofLordaeronObjectTypes.Buff1; i <= RuinsofLordaeronObjectTypes.Buff2; ++i)
|
||||
SpawnBGObject(i, 60);
|
||||
}
|
||||
|
||||
public override void HandleAreaTrigger(Player player, uint trigger, bool entered)
|
||||
{
|
||||
if (GetStatus() != BattlegroundStatus.InProgress)
|
||||
return;
|
||||
|
||||
switch (trigger)
|
||||
{
|
||||
case 4696: // buff trigger?
|
||||
case 4697: // buff trigger?
|
||||
break;
|
||||
default:
|
||||
base.HandleAreaTrigger(player, trigger, entered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillInitialWorldStates(InitWorldStates packet)
|
||||
{
|
||||
packet.AddState(0xbba, 1);
|
||||
base.FillInitialWorldStates(packet);
|
||||
}
|
||||
}
|
||||
|
||||
struct RuinsofLordaeronObjectTypes
|
||||
{
|
||||
public const int Door1 = 0;
|
||||
public const int Door2 = 1;
|
||||
public const int Buff1 = 2;
|
||||
public const int Buff2 = 3;
|
||||
public const int Max = 4;
|
||||
}
|
||||
|
||||
struct RuinsofLordaeronGameObjects
|
||||
{
|
||||
public const uint Door1 = 185918;
|
||||
public const uint Door2 = 185917;
|
||||
public const uint Buff1 = 184663;
|
||||
public const uint Buff2 = 184664;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class TigersPeak
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.Arenas
|
||||
{
|
||||
class TolvironArena
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.Dynamic;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Mails;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public class AuctionManager : Singleton<AuctionManager>
|
||||
{
|
||||
const int AH_MINIMUM_DEPOSIT = 100;
|
||||
|
||||
AuctionManager() { }
|
||||
|
||||
public AuctionHouseObject GetAuctionsMap(uint factionTemplateId)
|
||||
{
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionAuction))
|
||||
return mNeutralAuctions;
|
||||
|
||||
// teams have linked auction houses
|
||||
FactionTemplateRecord uEntry = CliDB.FactionTemplateStorage.LookupByKey(factionTemplateId);
|
||||
if (uEntry == null)
|
||||
return mNeutralAuctions;
|
||||
else if ((uEntry.Mask & (int)FactionMasks.Alliance) != 0)
|
||||
return mAllianceAuctions;
|
||||
else if ((uEntry.Mask & (int)FactionMasks.Horde) != 0)
|
||||
return mHordeAuctions;
|
||||
else
|
||||
return mNeutralAuctions;
|
||||
}
|
||||
|
||||
public ulong GetAuctionDeposit(AuctionHouseRecord entry, uint time, Item pItem, uint count)
|
||||
{
|
||||
uint MSV = pItem.GetTemplate().GetSellPrice();
|
||||
|
||||
if (MSV <= 0)
|
||||
return AH_MINIMUM_DEPOSIT * (uint)WorldConfig.GetFloatValue(WorldCfg.RateAuctionDeposit);
|
||||
|
||||
float multiplier = MathFunctions.CalculatePct((float)entry.DepositRate, 3);
|
||||
uint timeHr = (((time / 60) / 60) / 12);
|
||||
ulong deposit = (ulong)(((multiplier * MSV * count / 3) * timeHr * 3) * WorldConfig.GetFloatValue(WorldCfg.RateAuctionDeposit));
|
||||
|
||||
Log.outDebug(LogFilter.Auctionhouse, $"MSV: {MSV}");
|
||||
Log.outDebug(LogFilter.Auctionhouse, $"Items: {count}");
|
||||
Log.outDebug(LogFilter.Auctionhouse, $"Multiplier: {multiplier}");
|
||||
Log.outDebug(LogFilter.Auctionhouse, $"Deposit: {deposit}");
|
||||
|
||||
if (deposit < AH_MINIMUM_DEPOSIT * WorldConfig.GetFloatValue(WorldCfg.RateAuctionDeposit))
|
||||
return AH_MINIMUM_DEPOSIT * (uint)WorldConfig.GetFloatValue(WorldCfg.RateAuctionDeposit);
|
||||
else
|
||||
return deposit;
|
||||
}
|
||||
|
||||
public void SendAuctionWonMail(AuctionEntry auction, SQLTransaction trans)
|
||||
{
|
||||
Item item = GetAItem(auction.itemGUIDLow);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
uint bidderAccId = 0;
|
||||
ObjectGuid bidderGuid = ObjectGuid.Create(HighGuid.Player, auction.bidder);
|
||||
Player bidder = Global.ObjAccessor.FindPlayer(bidderGuid);
|
||||
// data for gm.log
|
||||
string bidderName = "";
|
||||
bool logGmTrade = false;
|
||||
|
||||
if (bidder)
|
||||
{
|
||||
bidderAccId = bidder.GetSession().GetAccountId();
|
||||
bidderName = bidder.GetName();
|
||||
logGmTrade = bidder.GetSession().HasPermission(RBACPermissions.LogGmTrade);
|
||||
}
|
||||
else
|
||||
{
|
||||
bidderAccId = ObjectManager.GetPlayerAccountIdByGUID(bidderGuid);
|
||||
logGmTrade = Global.AccountMgr.HasPermission(bidderAccId, RBACPermissions.LogGmTrade, Global.WorldMgr.GetRealm().Id.Realm);
|
||||
|
||||
if (logGmTrade && !ObjectManager.GetPlayerNameByGUID(bidderGuid, out bidderName))
|
||||
bidderName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown);
|
||||
}
|
||||
|
||||
if (logGmTrade)
|
||||
{
|
||||
ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, auction.owner);
|
||||
string ownerName;
|
||||
if (!ObjectManager.GetPlayerNameByGUID(ownerGuid, out ownerName))
|
||||
ownerName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown);
|
||||
|
||||
uint ownerAccId = ObjectManager.GetPlayerAccountIdByGUID(ownerGuid);
|
||||
|
||||
Log.outCommand(bidderAccId, $"GM {bidderName} (Account: {bidderAccId}) won item in auction: {item.GetTemplate().GetName()} (Entry: {item.GetEntry()} Count: {item.GetCount()}) and pay money: {auction.bid}. Original owner {ownerName} (Account: {ownerAccId})");
|
||||
}
|
||||
|
||||
// receiver exist
|
||||
if (bidder || bidderAccId != 0)
|
||||
{
|
||||
// set owner to bidder (to prevent delete item with sender char deleting)
|
||||
// owner in `data` will set at mail receive and item extracting
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ITEM_OWNER);
|
||||
stmt.AddValue(0, auction.bidder);
|
||||
stmt.AddValue(1, item.GetGUID().GetCounter());
|
||||
trans.Append(stmt);
|
||||
|
||||
if (bidder)
|
||||
{
|
||||
bidder.GetSession().SendAuctionWonNotification(auction, item);
|
||||
// FIXME: for offline player need also
|
||||
bidder.UpdateCriteria(CriteriaTypes.WonAuctions, 1);
|
||||
}
|
||||
|
||||
new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.Won), AuctionEntry.BuildAuctionMailBody(auction.owner, auction.bid, auction.buyout, 0, 0))
|
||||
.AddItem(item)
|
||||
.SendMailTo(trans, new MailReceiver(bidder, auction.bidder), new MailSender(auction), MailCheckMask.Copied);
|
||||
}
|
||||
else
|
||||
{
|
||||
// bidder doesn't exist, delete the item
|
||||
Global.AuctionMgr.RemoveAItem(auction.itemGUIDLow, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendAuctionSalePendingMail(AuctionEntry auction, SQLTransaction trans)
|
||||
{
|
||||
ObjectGuid owner_guid = ObjectGuid.Create(HighGuid.Player, auction.owner);
|
||||
Player owner = Global.ObjAccessor.FindPlayer(owner_guid);
|
||||
uint owner_accId = ObjectManager.GetPlayerAccountIdByGUID(owner_guid);
|
||||
// owner exist (online or offline)
|
||||
if (owner || owner_accId != 0)
|
||||
new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.SalePending), AuctionEntry.BuildAuctionMailBody(auction.bidder, auction.bid, auction.buyout, auction.deposit, auction.GetAuctionCut()))
|
||||
.SendMailTo(trans, new MailReceiver(owner, auction.owner), new MailSender(auction), MailCheckMask.Copied);
|
||||
}
|
||||
|
||||
//call this method to send mail to auction owner, when auction is successful, it does not clear ram
|
||||
public void SendAuctionSuccessfulMail(AuctionEntry auction, SQLTransaction trans)
|
||||
{
|
||||
ObjectGuid owner_guid = ObjectGuid.Create(HighGuid.Player, auction.owner);
|
||||
Player owner = Global.ObjAccessor.FindPlayer(owner_guid);
|
||||
uint owner_accId = ObjectManager.GetPlayerAccountIdByGUID(owner_guid);
|
||||
Item item = GetAItem(auction.itemGUIDLow);
|
||||
|
||||
// owner exist
|
||||
if (owner || owner_accId != 0)
|
||||
{
|
||||
ulong profit = auction.bid + auction.deposit - auction.GetAuctionCut();
|
||||
|
||||
//FIXME: what do if owner offline
|
||||
if (owner && item)
|
||||
{
|
||||
owner.UpdateCriteria(CriteriaTypes.GoldEarnedByAuctions, profit);
|
||||
owner.UpdateCriteria(CriteriaTypes.HighestAuctionSold, auction.bid);
|
||||
// send auction owner notification, bidder must be current!
|
||||
owner.GetSession().SendAuctionClosedNotification(auction, WorldConfig.GetIntValue(WorldCfg.MailDeliveryDelay), true, item);
|
||||
}
|
||||
|
||||
new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.Successful), AuctionEntry.BuildAuctionMailBody(auction.bidder, auction.bid, auction.buyout, auction.deposit, auction.GetAuctionCut()))
|
||||
.AddMoney(profit)
|
||||
.SendMailTo(trans, new MailReceiver(owner, auction.owner), new MailSender(auction), MailCheckMask.Copied, WorldConfig.GetUIntValue(WorldCfg.MailDeliveryDelay));
|
||||
}
|
||||
}
|
||||
|
||||
//does not clear ram
|
||||
public void SendAuctionExpiredMail(AuctionEntry auction, SQLTransaction trans)
|
||||
{
|
||||
//return an item in auction to its owner by mail
|
||||
Item item = GetAItem(auction.itemGUIDLow);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
ObjectGuid owner_guid = ObjectGuid.Create(HighGuid.Player, auction.owner);
|
||||
Player owner = Global.ObjAccessor.FindPlayer(owner_guid);
|
||||
uint owner_accId = ObjectManager.GetPlayerAccountIdByGUID(owner_guid);
|
||||
// owner exist
|
||||
if (owner || owner_accId != 0)
|
||||
{
|
||||
if (owner)
|
||||
owner.GetSession().SendAuctionClosedNotification(auction, 0f, false, item);
|
||||
|
||||
new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.Expired), AuctionEntry.BuildAuctionMailBody(0, 0, auction.buyout, auction.deposit, 0))
|
||||
.AddItem(item)
|
||||
.SendMailTo(trans, new MailReceiver(owner, auction.owner), new MailSender(auction), MailCheckMask.Copied, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// owner doesn't exist, delete the item
|
||||
Global.AuctionMgr.RemoveAItem(auction.itemGUIDLow, true);
|
||||
}
|
||||
}
|
||||
|
||||
//this function sends mail to old bidder
|
||||
public void SendAuctionOutbiddedMail(AuctionEntry auction, ulong newPrice, Player newBidder, SQLTransaction trans)
|
||||
{
|
||||
ObjectGuid oldBidder_guid = ObjectGuid.Create(HighGuid.Player, auction.bidder);
|
||||
Player oldBidder = Global.ObjAccessor.FindPlayer(oldBidder_guid);
|
||||
|
||||
uint oldBidder_accId = 0;
|
||||
if (oldBidder == null)
|
||||
oldBidder_accId = ObjectManager.GetPlayerAccountIdByGUID(oldBidder_guid);
|
||||
|
||||
Item item = GetAItem(auction.itemGUIDLow);
|
||||
|
||||
// old bidder exist
|
||||
if (oldBidder || oldBidder_accId != 0)
|
||||
{
|
||||
if (oldBidder && item)
|
||||
oldBidder.GetSession().SendAuctionOutBidNotification(auction, item);
|
||||
|
||||
new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.Outbidded), AuctionEntry.BuildAuctionMailBody(auction.owner, auction.bid, auction.buyout, auction.deposit, auction.GetAuctionCut()))
|
||||
.AddMoney(auction.bid)
|
||||
.SendMailTo(trans, new MailReceiver(oldBidder, auction.bidder), new MailSender(auction), MailCheckMask.Copied);
|
||||
}
|
||||
}
|
||||
|
||||
//this function sends mail, when auction is cancelled to old bidder
|
||||
public void SendAuctionCancelledToBidderMail(AuctionEntry auction, SQLTransaction trans)
|
||||
{
|
||||
ObjectGuid bidder_guid = ObjectGuid.Create(HighGuid.Player, auction.bidder);
|
||||
Player bidder = Global.ObjAccessor.FindPlayer(bidder_guid);
|
||||
|
||||
uint bidder_accId = 0;
|
||||
if (!bidder)
|
||||
bidder_accId = ObjectManager.GetPlayerAccountIdByGUID(bidder_guid);
|
||||
|
||||
// bidder exist
|
||||
if (bidder || bidder_accId != 0)
|
||||
new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.CancelledToBidder), AuctionEntry.BuildAuctionMailBody(auction.owner, auction.bid, auction.buyout, auction.deposit, 0))
|
||||
.AddMoney(auction.bid)
|
||||
.SendMailTo(trans, new MailReceiver(bidder, auction.bidder), new MailSender(auction), MailCheckMask.Copied);
|
||||
}
|
||||
|
||||
public void LoadAuctionItems()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
// need to clear in case we are reloading
|
||||
mAitems.Clear();
|
||||
|
||||
// data needs to be at first place for Item.LoadFromDB
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_AUCTION_ITEMS);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 auction items. DB table `auctionhouse` or `item_instance` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
uint count = 0;
|
||||
do
|
||||
{
|
||||
ulong itemGuid = result.Read<ulong>(0);
|
||||
uint itemEntry = result.Read<uint>(1);
|
||||
|
||||
ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemEntry);
|
||||
if (proto == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "AuctionHouseMgr:LoadAuctionItems: Unknown item (GUID: {0} item entry: {1}) in auction, skipped.", itemGuid, itemEntry);
|
||||
continue;
|
||||
}
|
||||
|
||||
Item item = Bag.NewItemOrBag(proto);
|
||||
if (!item.LoadFromDB(itemGuid, ObjectGuid.Empty, result.GetFields(), itemEntry))
|
||||
continue;
|
||||
|
||||
AddAItem(item);
|
||||
++count;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} auction items in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public void LoadAuctions()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_AUCTIONS);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 auctions. DB table `auctionhouse` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint count = 0;
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
do
|
||||
{
|
||||
AuctionEntry aItem = new AuctionEntry();
|
||||
if (!aItem.LoadFromDB(result.GetFields()))
|
||||
{
|
||||
aItem.DeleteFromDB(trans);
|
||||
continue;
|
||||
}
|
||||
|
||||
GetAuctionsMap(aItem.factionTemplateId).AddAuction(aItem);
|
||||
++count;
|
||||
} while (result.NextRow());
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} auctions in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
}
|
||||
|
||||
public void AddAItem(Item it)
|
||||
{
|
||||
Contract.Assert(it);
|
||||
Contract.Assert(!mAitems.ContainsKey(it.GetGUID().GetCounter()));
|
||||
mAitems[it.GetGUID().GetCounter()] = it;
|
||||
}
|
||||
|
||||
public bool RemoveAItem(ulong id, bool deleteItem = false)
|
||||
{
|
||||
var item = mAitems.LookupByKey(id);
|
||||
if (item == null)
|
||||
return false;
|
||||
|
||||
if (deleteItem)
|
||||
{
|
||||
item.FSetState(ItemUpdateState.Removed);
|
||||
item.SaveToDB(null);
|
||||
}
|
||||
|
||||
mAitems.Remove(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
mHordeAuctions.Update();
|
||||
mAllianceAuctions.Update();
|
||||
mNeutralAuctions.Update();
|
||||
}
|
||||
|
||||
public AuctionHouseRecord GetAuctionHouseEntry(uint factionTemplateId)
|
||||
{
|
||||
uint houseId = 0;
|
||||
return GetAuctionHouseEntry(factionTemplateId, ref houseId);
|
||||
}
|
||||
|
||||
public AuctionHouseRecord GetAuctionHouseEntry(uint factionTemplateId, ref uint houseId)
|
||||
{
|
||||
uint houseid = 7; // goblin auction house
|
||||
|
||||
if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionAuction))
|
||||
{
|
||||
// FIXME: found way for proper auctionhouse selection by another way
|
||||
// AuctionHouse.dbc have faction field with _player_ factions associated with auction house races.
|
||||
// but no easy way convert creature faction to player race faction for specific city
|
||||
switch (factionTemplateId)
|
||||
{
|
||||
case 12: houseid = 1; break; // human
|
||||
case 29: houseid = 6; break; // orc, and generic for horde
|
||||
case 55: houseid = 2; break; // dwarf, and generic for alliance
|
||||
case 68: houseid = 4; break; // undead
|
||||
case 80: houseid = 3; break; // n-elf
|
||||
case 104: houseid = 5; break; // trolls
|
||||
case 120: houseid = 7; break; // booty bay, neutral
|
||||
case 474: houseid = 7; break; // gadgetzan, neutral
|
||||
case 855: houseid = 7; break; // everlook, neutral
|
||||
case 1604: houseid = 6; break; // b-elfs,
|
||||
default: // for unknown case
|
||||
{
|
||||
FactionTemplateRecord u_entry = CliDB.FactionTemplateStorage.LookupByKey(factionTemplateId);
|
||||
if (u_entry == null)
|
||||
houseid = 7; // goblin auction house
|
||||
else if ((u_entry.Mask & (int)FactionMasks.Alliance) != 0)
|
||||
houseid = 1; // human auction house
|
||||
else if ((u_entry.Mask & (int)FactionMasks.Horde) != 0)
|
||||
houseid = 6; // orc auction house
|
||||
else
|
||||
houseid = 7; // goblin auction house
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
houseId = houseid;
|
||||
|
||||
return CliDB.AuctionHouseStorage.LookupByKey(houseid);
|
||||
}
|
||||
|
||||
public Item GetAItem(ulong id)
|
||||
{
|
||||
return mAitems.LookupByKey(id);
|
||||
}
|
||||
|
||||
AuctionHouseObject mHordeAuctions = new AuctionHouseObject();
|
||||
AuctionHouseObject mAllianceAuctions = new AuctionHouseObject();
|
||||
AuctionHouseObject mNeutralAuctions = new AuctionHouseObject();
|
||||
|
||||
Dictionary<ulong, Item> mAitems = new Dictionary<ulong, Item>();
|
||||
}
|
||||
|
||||
public class AuctionHouseObject
|
||||
{
|
||||
public void AddAuction(AuctionEntry auction)
|
||||
{
|
||||
Contract.Assert(auction != null);
|
||||
|
||||
AuctionsMap[auction.Id] = auction;
|
||||
Global.ScriptMgr.OnAuctionAdd(this, auction);
|
||||
}
|
||||
|
||||
public bool RemoveAuction(AuctionEntry auction)
|
||||
{
|
||||
bool wasInMap = AuctionsMap.Remove(auction.Id) ? true : false;
|
||||
|
||||
Global.ScriptMgr.OnAuctionRemove(this, auction);
|
||||
|
||||
// we need to delete the entry, it is not referenced any more
|
||||
auction = null;
|
||||
|
||||
return wasInMap;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
long curTime = Global.WorldMgr.GetGameTime();
|
||||
// Handle expired auctions
|
||||
|
||||
// If storage is empty, no need to update. next == NULL in this case.
|
||||
if (AuctionsMap.Empty())
|
||||
return;
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
foreach (var auction in AuctionsMap.Values)
|
||||
{
|
||||
// filter auctions expired on next update
|
||||
if (auction.expire_time > curTime + 60)
|
||||
continue;
|
||||
|
||||
// Either cancel the auction if there was no bidder
|
||||
if (auction.bidder == 0 && auction.bid == 0)
|
||||
{
|
||||
Global.AuctionMgr.SendAuctionExpiredMail(auction, trans);
|
||||
Global.ScriptMgr.OnAuctionExpire(this, auction);
|
||||
}
|
||||
// Or perform the transaction
|
||||
else
|
||||
{
|
||||
//we should send an "item sold" message if the seller is online
|
||||
//we send the item to the winner
|
||||
//we send the money to the seller
|
||||
Global.AuctionMgr.SendAuctionSuccessfulMail(auction, trans);
|
||||
Global.AuctionMgr.SendAuctionWonMail(auction, trans);
|
||||
Global.ScriptMgr.OnAuctionSuccessful(this, auction);
|
||||
}
|
||||
|
||||
// In any case clear the auction
|
||||
auction.DeleteFromDB(trans);
|
||||
|
||||
Global.AuctionMgr.RemoveAItem(auction.itemGUIDLow);
|
||||
RemoveAuction(auction);
|
||||
}
|
||||
|
||||
// Run DB changes
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
public void BuildListBidderItems(AuctionListBidderItemsResult packet, Player player, ref uint totalcount)
|
||||
{
|
||||
foreach (var Aentry in AuctionsMap.Values)
|
||||
{
|
||||
if (Aentry != null && Aentry.bidder == player.GetGUID().GetCounter())
|
||||
{
|
||||
Aentry.BuildAuctionInfo(packet.Items, false);
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildListOwnerItems(AuctionListOwnerItemsResult packet, Player player, ref uint totalcount)
|
||||
{
|
||||
foreach (var Aentry in AuctionsMap.Values)
|
||||
{
|
||||
if (Aentry != null && Aentry.owner == player.GetGUID().GetCounter())
|
||||
{
|
||||
Aentry.BuildAuctionInfo(packet.Items, false);
|
||||
++totalcount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BuildListAuctionItems(AuctionListItemsResult packet, Player player, string searchedname, uint listfrom, byte levelmin, byte levelmax, bool usable, Optional<AuctionSearchFilters> filters, uint quality)
|
||||
{
|
||||
long curTime = Global.WorldMgr.GetGameTime();
|
||||
|
||||
foreach (var Aentry in AuctionsMap.Values)
|
||||
{
|
||||
// Skip expired auctions
|
||||
if (Aentry.expire_time < curTime)
|
||||
continue;
|
||||
|
||||
Item item = Global.AuctionMgr.GetAItem(Aentry.itemGUIDLow);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
ItemTemplate proto = item.GetTemplate();
|
||||
if (filters.HasValue)
|
||||
{
|
||||
// if we dont want any class filters, Optional is not initialized
|
||||
// if we dont want this class included, SubclassMask is set to FILTER_SKIP_CLASS
|
||||
// if we want this class and did not specify and subclasses, its set to FILTER_SKIP_SUBCLASS
|
||||
// otherwise full restrictions apply
|
||||
if (filters.Value.Classes[(int)proto.GetClass()].SubclassMask == AuctionSearchFilters.FilterType.SkipClass)
|
||||
continue;
|
||||
|
||||
if (filters.Value.Classes[(int)proto.GetClass()].SubclassMask != AuctionSearchFilters.FilterType.SkipSubclass)
|
||||
{
|
||||
if (!Convert.ToBoolean((int)filters.Value.Classes[(int)proto.GetClass()].SubclassMask & (1u << (int)proto.GetSubClass())))
|
||||
continue;
|
||||
|
||||
if (!Convert.ToBoolean(filters.Value.Classes[(int)proto.GetClass()].InvTypes[(int)proto.GetSubClass()] & (1u << (int)proto.GetInventoryType())))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (quality != 0xffffffff && (uint)proto.GetQuality() != quality)
|
||||
continue;
|
||||
|
||||
if (levelmin != 0 && (proto.GetBaseRequiredLevel() < levelmin || (levelmax != 0x00 && proto.GetBaseRequiredLevel() > levelmax)))
|
||||
continue;
|
||||
|
||||
if (usable && player.CanUseItem(item) != InventoryResult.Ok)
|
||||
continue;
|
||||
|
||||
// Allow search by suffix (ie: of the Monkey) or partial name (ie: Monkey)
|
||||
// No need to do any of this if no search term was entered
|
||||
if (!string.IsNullOrEmpty(searchedname))
|
||||
{
|
||||
string name = proto.GetName(player.GetSession().GetSessionDbcLocale());
|
||||
if (string.IsNullOrEmpty(name))
|
||||
continue;
|
||||
|
||||
// DO NOT use GetItemEnchantMod(proto.RandomProperty) as it may return a result
|
||||
// that matches the search but it may not equal item.GetItemRandomPropertyId()
|
||||
// used in BuildAuctionInfo() which then causes wrong items to be listed
|
||||
int propRefID = item.GetItemRandomPropertyId();
|
||||
if (propRefID != 0)
|
||||
{
|
||||
string suffix = null;
|
||||
// Append the suffix to the name (ie: of the Monkey) if one exists
|
||||
// These are found in ItemRandomProperties.dbc, not ItemRandomSuffix.dbc
|
||||
// even though the DBC names seem misleading
|
||||
if (propRefID < 0)
|
||||
{
|
||||
ItemRandomSuffixRecord itemRandSuffix = CliDB.ItemRandomSuffixStorage.LookupByKey(-propRefID);
|
||||
if (itemRandSuffix != null)
|
||||
suffix = itemRandSuffix.Name[player.GetSession().GetSessionDbcLocale()];
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemRandomPropertiesRecord itemRandProp = CliDB.ItemRandomPropertiesStorage.LookupByKey(propRefID);
|
||||
if (itemRandProp != null)
|
||||
suffix = itemRandProp.Name[player.GetSession().GetSessionDbcLocale()];
|
||||
}
|
||||
|
||||
// dbc local name
|
||||
if (!string.IsNullOrEmpty(suffix))
|
||||
{
|
||||
// Append the suffix (ie: of the Monkey) to the name using localization
|
||||
// or default enUS if localization is invalid
|
||||
name += ' ' + suffix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the item if no search term or if entered search term was found
|
||||
if (packet.Items.Count < 50 && packet.TotalCount >= listfrom)
|
||||
Aentry.BuildAuctionInfo(packet.Items, true);
|
||||
|
||||
++packet.TotalCount;
|
||||
}
|
||||
}
|
||||
|
||||
public AuctionEntry GetAuction(uint id)
|
||||
{
|
||||
return AuctionsMap.LookupByKey(id);
|
||||
}
|
||||
|
||||
Dictionary<uint, AuctionEntry> AuctionsMap = new Dictionary<uint, AuctionEntry>();
|
||||
}
|
||||
|
||||
public class AuctionEntry
|
||||
{
|
||||
public void BuildAuctionInfo(List<AuctionItem> items, bool listAuctionItems)
|
||||
{
|
||||
Item item = Global.AuctionMgr.GetAItem(itemGUIDLow);
|
||||
if (!item)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "AuctionEntry:BuildAuctionInfo: Auction {0} has a non-existent item: {1}", Id, itemGUIDLow);
|
||||
return;
|
||||
}
|
||||
AuctionItem auctionItem = new AuctionItem();
|
||||
|
||||
auctionItem.AuctionItemID = (int)Id;
|
||||
auctionItem.Item = new ItemInstance(item);
|
||||
auctionItem.BuyoutPrice = buyout;
|
||||
auctionItem.CensorBidInfo = false;
|
||||
auctionItem.CensorServerSideInfo = listAuctionItems;
|
||||
auctionItem.Charges = item.GetSpellCharges();
|
||||
auctionItem.Count = (int)item.GetCount();
|
||||
auctionItem.DeleteReason = 0; // Always 0 ?
|
||||
auctionItem.DurationLeft = (int)((expire_time - Time.UnixTime) * Time.InMilliseconds);
|
||||
auctionItem.EndTime = (uint)expire_time;
|
||||
auctionItem.Flags = 0; // todo
|
||||
auctionItem.ItemGuid = item.GetGUID();
|
||||
auctionItem.MinBid = startbid;
|
||||
auctionItem.Owner = ObjectGuid.Create(HighGuid.Player, owner);
|
||||
auctionItem.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, ObjectManager.GetPlayerAccountIdByGUID(auctionItem.Owner));
|
||||
auctionItem.MinIncrement = bidder != 0 ? GetAuctionOutBid() : 0;
|
||||
auctionItem.Bidder = bidder != 0 ? ObjectGuid.Create(HighGuid.Player, bidder) : ObjectGuid.Empty;
|
||||
auctionItem.BidAmount = bidder != 0 ? bid : 0;
|
||||
|
||||
for (EnchantmentSlot c = 0; c < EnchantmentSlot.MaxInspected; c++)
|
||||
{
|
||||
if (item.GetEnchantmentId(c) == 0)
|
||||
continue;
|
||||
|
||||
auctionItem.Enchantments.Add(new ItemEnchantData((int)item.GetEnchantmentId(c), item.GetEnchantmentDuration(c), (int)item.GetEnchantmentCharges(c), (byte)c));
|
||||
}
|
||||
|
||||
byte i = 0;
|
||||
foreach (ItemDynamicFieldGems gemData in item.GetGems())
|
||||
{
|
||||
if (gemData.ItemId != 0)
|
||||
{
|
||||
ItemGemData gem = new ItemGemData();
|
||||
gem.Slot = i;
|
||||
gem.Item = new ItemInstance(gemData);
|
||||
auctionItem.Gems.Add(gem);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
items.Add(auctionItem);
|
||||
}
|
||||
|
||||
public ulong GetAuctionCut()
|
||||
{
|
||||
long cut = (long)(MathFunctions.CalculatePct(bid, auctionHouseEntry.ConsignmentRate) * WorldConfig.GetFloatValue(WorldCfg.RateAuctionCut));
|
||||
return (ulong)Math.Max(cut, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ulong GetAuctionOutBid()
|
||||
{
|
||||
ulong outbid = MathFunctions.CalculatePct(bid, 5);
|
||||
return outbid != 0 ? outbid : 1;
|
||||
}
|
||||
|
||||
public void DeleteFromDB(SQLTransaction trans)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_AUCTION);
|
||||
stmt.AddValue(0, Id);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
public void SaveToDB(SQLTransaction trans)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_AUCTION);
|
||||
stmt.AddValue(0, Id);
|
||||
stmt.AddValue(1, auctioneer);
|
||||
stmt.AddValue(2, itemGUIDLow);
|
||||
stmt.AddValue(3, owner);
|
||||
stmt.AddValue(4, buyout);
|
||||
stmt.AddValue(5, expire_time);
|
||||
stmt.AddValue(6, bidder);
|
||||
stmt.AddValue(7, bid);
|
||||
stmt.AddValue(8, startbid);
|
||||
stmt.AddValue(9, deposit);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
public bool LoadFromDB(SQLFields fields)
|
||||
{
|
||||
Id = fields.Read<uint>(0);
|
||||
auctioneer = fields.Read<ulong>(1);
|
||||
itemGUIDLow = fields.Read<ulong>(2);
|
||||
itemEntry = fields.Read<uint>(3);
|
||||
itemCount = fields.Read<uint>(4);
|
||||
owner = fields.Read<ulong>(5);
|
||||
buyout = fields.Read<ulong>(6);
|
||||
expire_time = fields.Read<uint>(7);
|
||||
bidder = fields.Read<ulong>(8);
|
||||
bid = fields.Read<ulong>(9);
|
||||
startbid = fields.Read<ulong>(10);
|
||||
deposit = fields.Read<ulong>(11);
|
||||
|
||||
CreatureData auctioneerData = Global.ObjectMgr.GetCreatureData(auctioneer);
|
||||
if (auctioneerData == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "Auction {0} has not a existing auctioneer (GUID : {1})", Id, auctioneer);
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureTemplate auctioneerInfo = Global.ObjectMgr.GetCreatureTemplate(auctioneerData.id);
|
||||
if (auctioneerInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "Auction {0} has not a existing auctioneer (GUID : {1} Entry: {2})", Id, auctioneer, auctioneerData.id);
|
||||
return false;
|
||||
}
|
||||
|
||||
factionTemplateId = auctioneerInfo.Faction;
|
||||
auctionHouseEntry = Global.AuctionMgr.GetAuctionHouseEntry(factionTemplateId, ref houseId);
|
||||
if (auctionHouseEntry == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "Auction {0} has auctioneer (GUID : {1} Entry: {2}) with wrong faction {3}", Id, auctioneer, auctioneerData.id, factionTemplateId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if sold item exists for guid
|
||||
// and itemEntry in fact (GetAItem will fail if problematic in result check in AuctionHouseMgr.LoadAuctionItems)
|
||||
if (!Global.AuctionMgr.GetAItem(itemGUIDLow))
|
||||
{
|
||||
Log.outError(LogFilter.Server, "Auction {0} has not a existing item : {1}", Id, itemGUIDLow);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool LoadFromFieldList(SQLFields fields)
|
||||
{
|
||||
// Loads an AuctionEntry item from a field list. Unlike "LoadFromDB()", this one
|
||||
// does not require the AuctionEntryMap to have been loaded with items. It simply
|
||||
// acts as a wrapper to fill out an AuctionEntry struct from a field list
|
||||
|
||||
Id = fields.Read<uint>(0);
|
||||
auctioneer = fields.Read<uint>(1);
|
||||
itemGUIDLow = fields.Read<uint>(2);
|
||||
itemEntry = fields.Read<uint>(3);
|
||||
itemCount = fields.Read<uint>(4);
|
||||
owner = fields.Read<uint>(5);
|
||||
buyout = fields.Read<uint>(6);
|
||||
expire_time = fields.Read<uint>(7);
|
||||
bidder = fields.Read<uint>(8);
|
||||
bid = fields.Read<uint>(9);
|
||||
startbid = fields.Read<uint>(10);
|
||||
deposit = fields.Read<uint>(11);
|
||||
|
||||
CreatureData auctioneerData = Global.ObjectMgr.GetCreatureData(auctioneer);
|
||||
if (auctioneerData == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "AuctionEntry:LoadFromFieldList() - Auction {0} has not a existing auctioneer (GUID : {1})", Id, auctioneer);
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureTemplate auctioneerInfo = Global.ObjectMgr.GetCreatureTemplate(auctioneerData.id);
|
||||
if (auctioneerInfo == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "AuctionEntry:LoadFromFieldList() - Auction {0} has not a existing auctioneer (GUID : {1} Entry: {2})", Id, auctioneer, auctioneerData.id);
|
||||
return false;
|
||||
}
|
||||
|
||||
factionTemplateId = auctioneerInfo.Faction;
|
||||
auctionHouseEntry = Global.AuctionMgr.GetAuctionHouseEntry(factionTemplateId);
|
||||
|
||||
if (auctionHouseEntry == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "AuctionEntry:LoadFromFieldList() - Auction {0} has auctioneer (GUID : {1} Entry: {2}) with wrong faction {3}", Id, auctioneer, auctioneerData.id, factionTemplateId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string BuildAuctionMailSubject(MailAuctionAnswers response)
|
||||
{
|
||||
return string.Format("{0}:0:{1}:{2}:{3}", itemEntry, response, Id, itemCount);
|
||||
}
|
||||
|
||||
public static string BuildAuctionMailBody(ulong lowGuid, ulong bid, ulong buyout, ulong deposit, ulong cut)
|
||||
{
|
||||
return string.Format($"{lowGuid}:{bid}:{buyout}:{deposit}:{cut}");
|
||||
}
|
||||
|
||||
// helpers
|
||||
public uint GetHouseId() { return houseId; }
|
||||
public uint GetHouseFaction() { return auctionHouseEntry.FactionID; }
|
||||
|
||||
public uint Id;
|
||||
public ulong auctioneer; // creature low guid
|
||||
public ulong itemGUIDLow;
|
||||
public uint itemEntry;
|
||||
public uint itemCount;
|
||||
public ulong owner;
|
||||
public ulong startbid; //maybe useless
|
||||
public ulong bid;
|
||||
public ulong buyout;
|
||||
public long expire_time;
|
||||
public ulong bidder;
|
||||
public ulong deposit; //deposit can be calculated only when creating auction
|
||||
public uint etime;
|
||||
uint houseId;
|
||||
public AuctionHouseRecord auctionHouseEntry; // in AuctionHouse.dbc
|
||||
public uint factionTemplateId;
|
||||
}
|
||||
|
||||
public class AuctionSearchFilters
|
||||
{
|
||||
public enum FilterType : uint
|
||||
{
|
||||
SkipClass = 0,
|
||||
SkipSubclass = 0xFFFFFFFF,
|
||||
SkipInvtype = 0xFFFFFFFF
|
||||
}
|
||||
|
||||
public Array<SubclassFilter> Classes = new Array<SubclassFilter>((int)ItemClass.Max);
|
||||
|
||||
public class SubclassFilter
|
||||
{
|
||||
public FilterType SubclassMask = FilterType.SkipClass;
|
||||
public Array<uint> InvTypes = new Array<uint>(ItemConst.MaxItemSubclassTotal);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.BattleFields
|
||||
{
|
||||
public class BattleFieldManager : Singleton<BattleFieldManager>
|
||||
{
|
||||
BattleFieldManager() { }
|
||||
|
||||
public void InitBattlefield()
|
||||
{
|
||||
BattleField wg = new BattlefieldWG();
|
||||
// respawn, init variables
|
||||
if (!wg.SetupBattlefield())
|
||||
{
|
||||
Log.outError(LogFilter.Battlefield, "Battlefield: Wintergrasp init failed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_battlefieldSet.Add(wg);
|
||||
Log.outInfo(LogFilter.Battlefield, "Battlefield: Wintergrasp successfully initiated.");
|
||||
}
|
||||
|
||||
/*
|
||||
For Cataclysm: Tol Barad
|
||||
Battlefield* tb = new BattlefieldTB;
|
||||
// respawn, init variables
|
||||
if (!tb.SetupBattlefield())
|
||||
{
|
||||
TC_LOG_DEBUG("bg.battlefield", "Battlefield: Tol Barad init failed.");
|
||||
delete tb;
|
||||
}
|
||||
else
|
||||
{
|
||||
_battlefieldSet.push_back(tb);
|
||||
TC_LOG_DEBUG("bg.battlefield", "Battlefield: Tol Barad successfully initiated.");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
public void AddZone(uint zoneId, BattleField bf)
|
||||
{
|
||||
_battlefieldMap[zoneId] = bf;
|
||||
}
|
||||
|
||||
public void HandlePlayerEnterZone(Player player, uint zoneId)
|
||||
{
|
||||
var bf = _battlefieldMap.LookupByKey(zoneId);
|
||||
if (bf == null)
|
||||
return;
|
||||
|
||||
if (!bf.IsEnabled() || bf.HasPlayer(player))
|
||||
return;
|
||||
|
||||
bf.HandlePlayerEnterZone(player, zoneId);
|
||||
Log.outDebug(LogFilter.Battlefield, "Player {0} entered battlefield id {1}", player.GetGUID().ToString(), bf.GetTypeId());
|
||||
}
|
||||
|
||||
public void HandlePlayerLeaveZone(Player player, uint zoneId)
|
||||
{
|
||||
var bf = _battlefieldMap.LookupByKey(zoneId);
|
||||
if (bf == null)
|
||||
return;
|
||||
|
||||
// teleport: remove once in removefromworld, once in updatezone
|
||||
if (!bf.HasPlayer(player))
|
||||
return;
|
||||
|
||||
bf.HandlePlayerLeaveZone(player, zoneId);
|
||||
Log.outDebug(LogFilter.Battlefield, "Player {0} left battlefield id {1}", player.GetGUID().ToString(), bf.GetTypeId());
|
||||
}
|
||||
|
||||
public BattleField GetBattlefieldToZoneId(uint zoneId)
|
||||
{
|
||||
var bf = _battlefieldMap.LookupByKey(zoneId);
|
||||
if (bf == null)
|
||||
{
|
||||
// no handle for this zone, return
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!bf.IsEnabled())
|
||||
return null;
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
public BattleField GetBattlefieldByBattleId(uint battleId)
|
||||
{
|
||||
foreach (var bf in _battlefieldSet)
|
||||
{
|
||||
if (bf.GetBattleId() == battleId)
|
||||
return bf;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BattleField GetBattlefieldByQueueId(ulong queueId)
|
||||
{
|
||||
foreach (var bf in _battlefieldSet)
|
||||
if (bf.GetQueueId() == queueId)
|
||||
return bf;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
ZoneScript GetZoneScript(uint zoneId)
|
||||
{
|
||||
var bf = _battlefieldMap.LookupByKey(zoneId);
|
||||
if (bf != null)
|
||||
return bf;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Update(uint diff)
|
||||
{
|
||||
_updateTimer += diff;
|
||||
if (_updateTimer > 1000)
|
||||
{
|
||||
foreach (var bf in _battlefieldSet)
|
||||
if (bf.IsEnabled())
|
||||
bf.Update(_updateTimer);
|
||||
_updateTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// contains all initiated battlefield events
|
||||
// used when initing / cleaning up
|
||||
List<BattleField> _battlefieldSet = new List<BattleField>();
|
||||
// maps the zone ids to an battlefield event
|
||||
// used in player event handling
|
||||
Dictionary<uint, BattleField> _battlefieldMap = new Dictionary<uint, BattleField>();
|
||||
// update interval
|
||||
uint _updateTimer;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.GameMath;
|
||||
using Game.Entities;
|
||||
|
||||
namespace Game.BattleFields
|
||||
{
|
||||
static class WGConst
|
||||
{
|
||||
public const uint ZoneId = 4197; // Wintergrasp
|
||||
public const uint MapId = 571; // Northrend
|
||||
|
||||
public const byte MaxOutsideNpcs = 14;
|
||||
public const byte OutsideAllianceNpc = 7;
|
||||
public const byte MaxWorkshops = 6;
|
||||
|
||||
#region Data
|
||||
public static BfWGCoordGY[] WGGraveYard =
|
||||
{
|
||||
new BfWGCoordGY(5104.750f, 2300.940f, 368.579f, 0.733038f, 1329, WGGossipText.GYNE, TeamId.Neutral),
|
||||
new BfWGCoordGY(5099.120f, 3466.036f, 368.484f, 5.317802f, 1330, WGGossipText.GYNW, TeamId.Neutral),
|
||||
new BfWGCoordGY(4314.648f, 2408.522f, 392.642f, 6.268125f, 1333, WGGossipText.GYSE, TeamId.Neutral),
|
||||
new BfWGCoordGY(4331.716f, 3235.695f, 390.251f, 0.008500f, 1334, WGGossipText.GYSW, TeamId.Neutral),
|
||||
new BfWGCoordGY(5537.986f, 2897.493f, 517.057f, 4.819249f, 1285, WGGossipText.GYKeep, TeamId.Neutral),
|
||||
new BfWGCoordGY(5032.454f, 3711.382f, 372.468f, 3.971623f, 1331, WGGossipText.GYHorde, TeamId.Horde),
|
||||
new BfWGCoordGY(5140.790f, 2179.120f, 390.950f, 1.972220f, 1332, WGGossipText.GYAlliance, TeamId.Alliance),
|
||||
};
|
||||
|
||||
public static uint[] ClockWorldState = { 3781, 4354 };
|
||||
public static uint[] WintergraspFaction = { 1732, 1735, 35 };
|
||||
|
||||
public static Position WintergraspStalkerPos = new Position(4948.985f, 2937.789f, 550.5172f, 1.815142f);
|
||||
|
||||
public static Position RelicPos = new Position(5440.379f, 2840.493f, 430.2816f, -1.832595f);
|
||||
public static Quaternion RelicRot = new Quaternion(0.0f, 0.0f, -0.7933531f, 0.6087617f);
|
||||
|
||||
//Destructible (Wall, Tower..)
|
||||
public static WintergraspBuildingSpawnData[] WGGameObjectBuilding =
|
||||
{
|
||||
// Wall (Not spawned in db)
|
||||
// Entry WS X Y Z O rX rY rZ rW Type
|
||||
new WintergraspBuildingSpawnData(190219, 3749, 5371.457f, 3047.472f, 407.5710f, 3.14159300f, 0.0f, 0.0f, -1.000000000f, 0.00000000f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(190220, 3750, 5331.264f, 3047.105f, 407.9228f, 0.05235888f, 0.0f, 0.0f, 0.026176450f, 0.99965730f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191795, 3764, 5385.841f, 2909.490f, 409.7127f, 0.00872424f, 0.0f, 0.0f, 0.004362106f, 0.99999050f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191796, 3772, 5384.452f, 2771.835f, 410.2704f, 3.14159300f, 0.0f, 0.0f, -1.000000000f, 0.00000000f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191799, 3762, 5371.436f, 2630.610f, 408.8163f, 3.13285800f, 0.0f, 0.0f, 0.999990500f, 0.00436732f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191800, 3766, 5301.838f, 2909.089f, 409.8661f, 0.00872424f, 0.0f, 0.0f, 0.004362106f, 0.99999050f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191801, 3770, 5301.063f, 2771.411f, 409.9014f, 3.14159300f, 0.0f, 0.0f, -1.000000000f, 0.00000000f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191802, 3751, 5280.197f, 2995.583f, 408.8249f, 1.61442800f, 0.0f, 0.0f, 0.722363500f, 0.69151360f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191803, 3752, 5279.136f, 2956.023f, 408.6041f, 1.57079600f, 0.0f, 0.0f, 0.707106600f, 0.70710690f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191804, 3767, 5278.685f, 2882.513f, 409.5388f, 1.57079600f, 0.0f, 0.0f, 0.707106600f, 0.70710690f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191806, 3769, 5279.502f, 2798.945f, 409.9983f, 1.57079600f, 0.0f, 0.0f, 0.707106600f, 0.70710690f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191807, 3759, 5279.937f, 2724.766f, 409.9452f, 1.56207000f, 0.0f, 0.0f, 0.704014800f, 0.71018530f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191808, 3760, 5279.601f, 2683.786f, 409.8488f, 1.55334100f, 0.0f, 0.0f, 0.700908700f, 0.71325110f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191809, 3761, 5330.955f, 2630.777f, 409.2826f, 3.13285800f, 0.0f, 0.0f, 0.999990500f, 0.00436732f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(190369, 3753, 5256.085f, 2933.963f, 409.3571f, 3.13285800f, 0.0f, 0.0f, 0.999990500f, 0.00436732f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(190370, 3758, 5257.463f, 2747.327f, 409.7427f, -3.13285800f, 0.0f, 0.0f, -0.999990500f, 0.00436732f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(190371, 3754, 5214.960f, 2934.089f, 409.1905f, -0.00872424f, 0.0f, 0.0f, -0.004362106f, 0.99999050f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(190372, 3757, 5215.821f, 2747.566f, 409.1884f, -3.13285800f, 0.0f, 0.0f, -0.999990500f, 0.00436732f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(190374, 3755, 5162.273f, 2883.043f, 410.2556f, 1.57952200f, 0.0f, 0.0f, 0.710185100f, 0.70401500f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(190376, 3756, 5163.724f, 2799.838f, 409.2270f, 1.57952200f, 0.0f, 0.0f, 0.710185100f, 0.70401500f, WGGameObjectBuildingType.Wall),
|
||||
|
||||
// Tower of keep (Not spawned in db)
|
||||
new WintergraspBuildingSpawnData(190221, 3711, 5281.154f, 3044.588f, 407.8434f, 3.115388f, 0.0f, 0.0f, 0.9999142f, 0.013101960f, WGGameObjectBuildingType.KeepTower), // NW
|
||||
new WintergraspBuildingSpawnData(190373, 3713, 5163.757f, 2932.228f, 409.1904f, 3.124123f, 0.0f, 0.0f, 0.9999619f, 0.008734641f, WGGameObjectBuildingType.KeepTower), // SW
|
||||
new WintergraspBuildingSpawnData(190377, 3714, 5166.397f, 2748.368f, 409.1884f, -1.570796f, 0.0f, 0.0f, -0.7071066f, 0.707106900f, WGGameObjectBuildingType.KeepTower), // SE
|
||||
new WintergraspBuildingSpawnData(190378, 3712, 5281.192f, 2632.479f, 409.0985f, -1.588246f, 0.0f, 0.0f, -0.7132492f, 0.700910500f, WGGameObjectBuildingType.KeepTower), // NE
|
||||
|
||||
// Wall (with passage) (Not spawned in db)
|
||||
new WintergraspBuildingSpawnData(191797, 3765, 5343.290f, 2908.860f, 409.5757f, 0.00872424f, 0.0f, 0.0f, 0.004362106f, 0.9999905f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191798, 3771, 5342.719f, 2771.386f, 409.6249f, 3.14159300f, 0.0f, 0.0f, -1.000000000f, 0.0000000f, WGGameObjectBuildingType.Wall),
|
||||
new WintergraspBuildingSpawnData(191805, 3768, 5279.126f, 2840.797f, 409.7826f, 1.57952200f, 0.0f, 0.0f, 0.710185100f, 0.7040150f, WGGameObjectBuildingType.Wall),
|
||||
|
||||
// South tower (Not spawned in db)
|
||||
new WintergraspBuildingSpawnData(190356, 3704, 4557.173f, 3623.943f, 395.8828f, 1.675516f, 0.0f, 0.0f, 0.7431450f, 0.669130400f, WGGameObjectBuildingType.Tower), // W
|
||||
new WintergraspBuildingSpawnData(190357, 3705, 4398.172f, 2822.497f, 405.6270f, -3.124123f, 0.0f, 0.0f, -0.9999619f, 0.008734641f, WGGameObjectBuildingType.Tower), // S
|
||||
new WintergraspBuildingSpawnData(190358, 3706, 4459.105f, 1944.326f, 434.9912f, -2.002762f, 0.0f, 0.0f, -0.8422165f, 0.539139500f, WGGameObjectBuildingType.Tower), // E
|
||||
|
||||
// Door of forteress (Not spawned in db)
|
||||
new WintergraspBuildingSpawnData(WGGameObjects.FortressGate, 3763, 5162.991f, 2841.232f, 410.1892f, -3.132858f, 0.0f, 0.0f, -0.9999905f, 0.00436732f, WGGameObjectBuildingType.Door),
|
||||
|
||||
// Last door (Not spawned in db)
|
||||
new WintergraspBuildingSpawnData(WGGameObjects.VaultGate, 3773, 5397.108f, 2841.54f, 425.9014f, 3.141593f, 0.0f, 0.0f, -1.0f, 0.0f, WGGameObjectBuildingType.DoorLast),
|
||||
};
|
||||
|
||||
public static StaticWintergraspTowerInfo[] TowerData =
|
||||
{
|
||||
new StaticWintergraspTowerInfo(WintergraspTowerIds.FortressNW, WintergraspText.NwKeeptowerDamage, WintergraspText.NwKeeptowerDestroy),
|
||||
new StaticWintergraspTowerInfo(WintergraspTowerIds.FortressSW,WintergraspText.SwKeeptowerDamage,WintergraspText.SwKeeptowerDestroy),
|
||||
new StaticWintergraspTowerInfo(WintergraspTowerIds.FortressSE,WintergraspText.SeKeeptowerDamage,WintergraspText.SeKeeptowerDestroy),
|
||||
new StaticWintergraspTowerInfo(WintergraspTowerIds.FortressNE,WintergraspText.NeKeeptowerDamage,WintergraspText.NeKeeptowerDestroy),
|
||||
new StaticWintergraspTowerInfo(WintergraspTowerIds.Shadowsight,WintergraspText.WesternTowerDamage,WintergraspText.WesternTowerDestroy),
|
||||
new StaticWintergraspTowerInfo(WintergraspTowerIds.WintersEdge,WintergraspText.SouthernTowerDamage,WintergraspText.SouthernTowerDestroy),
|
||||
new StaticWintergraspTowerInfo(WintergraspTowerIds.Flamewatch,WintergraspText.EasternTowerDamage,WintergraspText.EasternTowerDestroy)
|
||||
};
|
||||
|
||||
public static Position[] WGTurret =
|
||||
{
|
||||
new Position(5391.19f, 3060.8f, 419.616f, 1.69557f),
|
||||
new Position(5266.75f, 2976.5f, 421.067f, 3.20354f),
|
||||
new Position(5234.86f, 2948.8f, 420.88f, 1.61311f),
|
||||
new Position(5323.05f, 2923.7f, 421.645f, 1.5817f),
|
||||
new Position(5363.82f, 2923.87f, 421.709f, 1.60527f),
|
||||
new Position(5264.04f, 2861.34f, 421.587f, 3.21142f),
|
||||
new Position(5264.68f, 2819.78f, 421.656f, 3.15645f),
|
||||
new Position(5322.16f, 2756.69f, 421.646f, 4.69978f),
|
||||
new Position(5363.78f, 2756.77f, 421.629f, 4.78226f),
|
||||
new Position(5236.2f, 2732.68f, 421.649f, 4.72336f),
|
||||
new Position(5265.02f, 2704.63f, 421.7f, 3.12507f),
|
||||
new Position(5350.87f, 2616.03f, 421.243f, 4.72729f),
|
||||
new Position(5390.95f, 2615.5f, 421.126f, 4.6409f),
|
||||
new Position(5148.8f, 2820.24f, 421.621f, 3.16043f),
|
||||
new Position(5147.98f, 2861.93f, 421.63f, 3.18792f),
|
||||
};
|
||||
|
||||
public static WintergraspGameObjectData[] WGPortalDefenderData =
|
||||
{
|
||||
// Player teleporter
|
||||
new WintergraspGameObjectData(5153.408f, 2901.349f, 409.1913f, -0.06981169f, 0.0f, 0.0f, -0.03489876f, 0.9993908f, 190763, 191575),
|
||||
new WintergraspGameObjectData(5268.698f, 2666.421f, 409.0985f, -0.71558490f, 0.0f, 0.0f, -0.35020730f, 0.9366722f, 190763, 191575),
|
||||
new WintergraspGameObjectData(5197.050f, 2944.814f, 409.1913f, 2.33874000f, 0.0f, 0.0f, 0.92050460f, 0.3907318f, 190763, 191575),
|
||||
new WintergraspGameObjectData(5196.671f, 2737.345f, 409.1892f, -2.93213900f, 0.0f, 0.0f, -0.99452110f, 0.1045355f, 190763, 191575),
|
||||
new WintergraspGameObjectData(5314.580f, 3055.852f, 408.8620f, 0.54105060f, 0.0f, 0.0f, 0.26723770f, 0.9636307f, 190763, 191575),
|
||||
new WintergraspGameObjectData(5391.277f, 2828.094f, 418.6752f, -2.16420600f, 0.0f, 0.0f, -0.88294700f, 0.4694727f, 190763, 191575),
|
||||
new WintergraspGameObjectData(5153.931f, 2781.671f, 409.2455f, 1.65806200f, 0.0f, 0.0f, 0.73727700f, 0.6755905f, 190763, 191575),
|
||||
new WintergraspGameObjectData(5311.445f, 2618.931f, 409.0916f, -2.37364400f, 0.0f, 0.0f, -0.92718320f, 0.3746083f, 190763, 191575),
|
||||
new WintergraspGameObjectData(5269.208f, 3013.838f, 408.8276f, -1.76278200f, 0.0f, 0.0f, -0.77162460f, 0.6360782f, 190763, 191575),
|
||||
|
||||
new WintergraspGameObjectData(5401.634f, 2853.667f, 418.6748f, 2.63544400f, 0.0f, 0.0f, 0.96814730f, 0.2503814f, 192819, 192819), // return portal inside fortress, neutral
|
||||
|
||||
// Vehicle teleporter
|
||||
new WintergraspGameObjectData(5314.515f, 2703.687f, 408.5502f, -0.89011660f, 0.0f, 0.0f, -0.43051050f, 0.9025856f, 192951, 192951),
|
||||
new WintergraspGameObjectData(5316.252f, 2977.042f, 408.5385f, -0.82030330f, 0.0f, 0.0f, -0.39874840f, 0.9170604f, 192951, 192951)
|
||||
};
|
||||
|
||||
public static WintergraspTowerData[] AttackTowers =
|
||||
{
|
||||
//West Tower
|
||||
new WintergraspTowerData()
|
||||
{
|
||||
towerEntry = 190356,
|
||||
GameObject = new WintergraspGameObjectData[]
|
||||
{
|
||||
new WintergraspGameObjectData(4559.113f, 3606.216f, 419.9992f, 4.799657f, 0.0f, 0.0f, -0.67558960f, 0.73727790f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4539.420f, 3622.490f, 420.0342f, 3.211419f, 0.0f, 0.0f, -0.99939060f, 0.03490613f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4555.258f, 3641.648f, 419.9740f, 1.675514f, 0.0f, 0.0f, 0.74314400f, 0.66913150f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4574.872f, 3625.911f, 420.0792f, 0.087266f, 0.0f, 0.0f, 0.04361916f, 0.99904820f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4433.899f, 3534.142f, 360.2750f, 4.433136f, 0.0f, 0.0f, -0.79863550f, 0.60181500f, 192269, 192278), // Flag near workshop
|
||||
new WintergraspGameObjectData(4572.933f, 3475.519f, 363.0090f, 1.422443f, 0.0f, 0.0f, 0.65275960f, 0.75756520f, 192269, 192277) // Flag near bridge
|
||||
},
|
||||
CreatureBottom = new WintergraspObjectPositionData[]
|
||||
{
|
||||
new WintergraspObjectPositionData(4418.688477f, 3506.251709f, 358.975494f, 4.293305f, WGNpcs.GuardH, WGNpcs.GuardA), // Roaming Guard
|
||||
}
|
||||
},
|
||||
|
||||
//South Tower
|
||||
new WintergraspTowerData()
|
||||
{
|
||||
towerEntry = 190357,
|
||||
GameObject = new WintergraspGameObjectData[]
|
||||
{
|
||||
new WintergraspGameObjectData(4416.004f, 2822.666f, 429.8512f, 6.2657330f, 0.0f, 0.0f, -0.00872612f, 0.99996190f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4398.819f, 2804.698f, 429.7920f, 4.6949370f, 0.0f, 0.0f, -0.71325020f, 0.70090960f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4387.622f, 2719.566f, 389.9351f, 4.7385700f, 0.0f, 0.0f, -0.69779010f, 0.71630230f, 192366, 192414), // Flag near tower
|
||||
new WintergraspGameObjectData(4464.124f, 2855.453f, 406.1106f, 0.8290324f, 0.0f, 0.0f, 0.40274720f, 0.91531130f, 192366, 192429), // Flag near tower
|
||||
new WintergraspGameObjectData(4526.457f, 2810.181f, 391.1997f, 3.2899610f, 0.0f, 0.0f, -0.99724960f, 0.07411628f, 192269, 192278) // Flag near bridge
|
||||
},
|
||||
CreatureBottom = new WintergraspObjectPositionData[]
|
||||
{
|
||||
new WintergraspObjectPositionData(4452.859863f, 2808.870117f, 402.604004f, 6.056290f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
new WintergraspObjectPositionData(4455.899902f, 2835.958008f, 401.122559f, 0.034907f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
new WintergraspObjectPositionData(4412.649414f, 2953.792236f, 374.799957f, 0.980838f, WGNpcs.GuardH, WGNpcs.GuardA), // Roaming Guard
|
||||
new WintergraspObjectPositionData(4362.089844f, 2811.510010f, 407.337006f, 3.193950f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
new WintergraspObjectPositionData(4412.290039f, 2753.790039f, 401.015015f, 5.829400f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
new WintergraspObjectPositionData(4421.939941f, 2773.189941f, 400.894989f, 5.707230f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
}
|
||||
},
|
||||
|
||||
//East Tower
|
||||
new WintergraspTowerData()
|
||||
{
|
||||
towerEntry = 190358,
|
||||
GameObject = new WintergraspGameObjectData[]
|
||||
{
|
||||
new WintergraspGameObjectData(4466.793f, 1960.418f, 459.1437f, 1.151916f, 0.0f, 0.0f, 0.5446386f, 0.8386708f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4475.351f, 1937.031f, 459.0702f, 5.846854f, 0.0f, 0.0f, -0.2164392f, 0.9762961f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4451.758f, 1928.104f, 459.0759f, 4.276057f, 0.0f, 0.0f, -0.8433914f, 0.5372996f, 192488, 192501), // Flag on tower
|
||||
new WintergraspGameObjectData(4442.987f, 1951.898f, 459.0930f, 2.740162f, 0.0f, 0.0f, 0.9799242f, 0.1993704f, 192488, 192501) // Flag on tower
|
||||
},
|
||||
CreatureBottom = new WintergraspObjectPositionData[]
|
||||
{
|
||||
new WintergraspObjectPositionData(4501.060059f, 1990.280029f, 431.157013f, 1.029740f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
new WintergraspObjectPositionData(4463.830078f, 2015.180054f, 430.299988f, 1.431170f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
new WintergraspObjectPositionData(4494.580078f, 1943.760010f, 435.627014f, 6.195920f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
new WintergraspObjectPositionData(4450.149902f, 1897.579956f, 435.045013f, 4.398230f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
new WintergraspObjectPositionData(4428.870117f, 1906.869995f, 432.648010f, 3.996800f, WGNpcs.GuardH, WGNpcs.GuardA), // Standing Guard
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static WintergraspTowerCannonData[] TowerCannon =
|
||||
{
|
||||
new WintergraspTowerCannonData()
|
||||
{
|
||||
towerEntry = 190221,
|
||||
TurretTop = new Position[]
|
||||
{
|
||||
new Position(5255.88f, 3047.63f, 438.499f, 3.13677f),
|
||||
new Position(5280.9f, 3071.32f, 438.499f, 1.62879f),
|
||||
},
|
||||
},
|
||||
|
||||
new WintergraspTowerCannonData()
|
||||
{
|
||||
towerEntry = 190373,
|
||||
TurretTop = new Position[]
|
||||
{
|
||||
new Position(5138.59f, 2935.16f, 439.845f, 3.11723f),
|
||||
new Position(5163.06f, 2959.52f, 439.846f, 1.47258f),
|
||||
},
|
||||
},
|
||||
|
||||
new WintergraspTowerCannonData()
|
||||
{
|
||||
towerEntry = 190377,
|
||||
TurretTop = new Position[]
|
||||
{
|
||||
new Position(5163.84f, 2723.74f, 439.844f, 1.3994f),
|
||||
new Position(5139.69f, 2747.4f, 439.844f, 3.17221f),
|
||||
},
|
||||
},
|
||||
|
||||
new WintergraspTowerCannonData()
|
||||
{
|
||||
towerEntry = 190378,
|
||||
TurretTop = new Position[]
|
||||
{
|
||||
new Position(5278.21f, 2607.23f, 439.755f, 4.71944f),
|
||||
new Position(5255.01f, 2631.98f, 439.755f, 3.15257f),
|
||||
},
|
||||
},
|
||||
|
||||
new WintergraspTowerCannonData()
|
||||
{
|
||||
towerEntry = 190356,
|
||||
TowerCannonBottom = new Position[]
|
||||
{
|
||||
new Position(4537.380371f, 3599.531738f, 402.886993f, 3.998462f),
|
||||
new Position(4581.497559f, 3604.087158f, 402.886963f, 5.651723f),
|
||||
},
|
||||
TurretTop = new Position[]
|
||||
{
|
||||
new Position(4469.448242f, 1966.623779f, 465.647217f, 1.153573f),
|
||||
new Position(4581.895996f, 3626.438477f, 426.539062f, 0.117806f),
|
||||
},
|
||||
},
|
||||
|
||||
new WintergraspTowerCannonData()
|
||||
{
|
||||
towerEntry = 190357,
|
||||
TowerCannonBottom = new Position[]
|
||||
{
|
||||
new Position(4421.640137f, 2799.935791f, 412.630920f, 5.459298f),
|
||||
new Position(4420.263184f, 2845.340332f, 412.630951f, 0.742197f),
|
||||
},
|
||||
TurretTop = new Position[]
|
||||
{
|
||||
new Position(4423.430664f, 2822.762939f, 436.283142f, 6.223487f),
|
||||
new Position(4397.825684f, 2847.629639f, 436.283325f, 1.579430f),
|
||||
new Position(4398.814941f, 2797.266357f, 436.283051f, 4.703747f),
|
||||
},
|
||||
},
|
||||
|
||||
new WintergraspTowerCannonData()
|
||||
{
|
||||
towerEntry = 190358,
|
||||
TowerCannonBottom = new Position[]
|
||||
{
|
||||
new Position(4448.138184f, 1974.998779f, 441.995911f, 1.967238f),
|
||||
new Position(4448.713379f, 1955.148682f, 441.995178f, 0.380733f),
|
||||
},
|
||||
TurretTop = new Position[]
|
||||
{
|
||||
new Position(4469.448242f, 1966.623779f, 465.647217f, 1.153573f),
|
||||
new Position(4481.996582f, 1933.658325f, 465.647186f, 5.873029f),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
public static StaticWintergraspWorkshopInfo[] WorkshopData =
|
||||
{
|
||||
new StaticWintergraspWorkshopInfo()
|
||||
{
|
||||
WorkshopId = WGWorkshopIds.Ne,
|
||||
WorldStateId = WGWorldStates.NE,
|
||||
AllianceCaptureTextId = WintergraspText.SunkenRingCaptureAlliance,
|
||||
AllianceAttackTextId = WintergraspText.SunkenRingAttackAlliance,
|
||||
HordeCaptureTextId = WintergraspText.SunkenRingCaptureHorde,
|
||||
HordeAttackTextId = WintergraspText.SunkenRingAttackHorde
|
||||
},
|
||||
new StaticWintergraspWorkshopInfo()
|
||||
{
|
||||
WorkshopId = WGWorkshopIds.Nw,
|
||||
WorldStateId = WGWorldStates.NW,
|
||||
AllianceCaptureTextId = WintergraspText.BrokenTempleCaptureAlliance,
|
||||
AllianceAttackTextId = WintergraspText.BrokenTempleAttackAlliance,
|
||||
HordeCaptureTextId = WintergraspText.BrokenTempleCaptureHorde,
|
||||
HordeAttackTextId = WintergraspText.BrokenTempleAttackHorde
|
||||
},
|
||||
new StaticWintergraspWorkshopInfo()
|
||||
{
|
||||
WorkshopId = WGWorkshopIds.Se,
|
||||
WorldStateId = WGWorldStates.SE,
|
||||
AllianceCaptureTextId = WintergraspText.EastsparkCaptureAlliance,
|
||||
AllianceAttackTextId = WintergraspText.EastsparkAttackAlliance,
|
||||
HordeCaptureTextId = WintergraspText.EastsparkCaptureHorde,
|
||||
HordeAttackTextId = WintergraspText.EastsparkAttackHorde
|
||||
},
|
||||
|
||||
new StaticWintergraspWorkshopInfo()
|
||||
{
|
||||
WorkshopId = WGWorkshopIds.Sw,
|
||||
WorldStateId = WGWorldStates.SW,
|
||||
AllianceCaptureTextId = WintergraspText.WestsparkCaptureAlliance,
|
||||
AllianceAttackTextId = WintergraspText.WestsparkAttackAlliance,
|
||||
HordeCaptureTextId = WintergraspText.WestsparkCaptureHorde,
|
||||
HordeAttackTextId = WintergraspText.WestsparkAttackHorde
|
||||
},
|
||||
|
||||
// KEEP WORKSHOPS - It can't be taken, so it doesn't have a textids
|
||||
new StaticWintergraspWorkshopInfo()
|
||||
{
|
||||
WorkshopId = WGWorkshopIds.KeepWest,
|
||||
WorldStateId = WGWorldStates.KeepW
|
||||
},
|
||||
|
||||
new StaticWintergraspWorkshopInfo()
|
||||
{
|
||||
WorkshopId = WGWorkshopIds.KeepEast,
|
||||
WorldStateId = WGWorldStates.KeepE
|
||||
}
|
||||
};
|
||||
#endregion
|
||||
}
|
||||
|
||||
struct WGData
|
||||
{
|
||||
public const int DamagedTowerDef = 0;
|
||||
public const int BrokenTowerDef = 1;
|
||||
public const int DamagedTowerAtt = 2;
|
||||
public const int BrokenTowerAtt = 3;
|
||||
public const int MaxVehicleA = 4;
|
||||
public const int MaxVehicleH = 5;
|
||||
public const int VehicleA = 6;
|
||||
public const int VehicleH = 7;
|
||||
public const int WonA = 8;
|
||||
public const int DefA = 9;
|
||||
public const int WonH = 10;
|
||||
public const int DefH = 11;
|
||||
public const int Max = 12;
|
||||
}
|
||||
|
||||
struct WGAchievements
|
||||
{
|
||||
public const uint WinWg = 1717;
|
||||
public const uint WinWg100 = 1718; /// @Todo: Has To Be Implemented
|
||||
public const uint WgGnomeslaughter = 1723; /// @Todo: Has To Be Implemented
|
||||
public const uint WgTowerDestroy = 1727;
|
||||
public const uint DestructionDerbyA = 1737; /// @Todo: Has To Be Implemented
|
||||
public const uint WgTowerCannonKill = 1751; /// @Todo: Has To Be Implemented
|
||||
public const uint WgMasterA = 1752; /// @Todo: Has To Be Implemented
|
||||
public const uint WinWgTimer10 = 1755;
|
||||
public const uint StoneKeeper50 = 2085; /// @Todo: Has To Be Implemented
|
||||
public const uint StoneKeeper100 = 2086; /// @Todo: Has To Be Implemented
|
||||
public const uint StoneKeeper250 = 2087; /// @Todo: Has To Be Implemented
|
||||
public const uint StoneKeeper500 = 2088; /// @Todo: Has To Be Implemented
|
||||
public const uint StoneKeeper1000 = 2089; /// @Todo: Has To Be Implemented
|
||||
public const uint WgRanger = 2199; /// @Todo: Has To Be Implemented
|
||||
public const uint DestructionDerbyH = 2476; /// @Todo: Has To Be Implemented
|
||||
public const uint WgMasterH = 2776; /// @Todo: Has To Be Implemented
|
||||
}
|
||||
|
||||
struct WGSpells
|
||||
{
|
||||
// Wartime Auras
|
||||
public const uint Recruit = 37795;
|
||||
public const uint Corporal = 33280;
|
||||
public const uint Lieutenant = 55629;
|
||||
public const uint Tenacity = 58549;
|
||||
public const uint TenacityVehicle = 59911;
|
||||
public const uint TowerControl = 62064;
|
||||
public const uint SpiritualImmunity = 58729;
|
||||
public const uint GreatHonor = 58555;
|
||||
public const uint GreaterHonor = 58556;
|
||||
public const uint GreatestHonor = 58557;
|
||||
public const uint AllianceFlag = 14268;
|
||||
public const uint HordeFlag = 14267;
|
||||
public const uint GrabPassenger = 61178;
|
||||
|
||||
// Reward Spells
|
||||
public const uint VictoryReward = 56902;
|
||||
public const uint DefeatReward = 58494;
|
||||
public const uint DamagedTower = 59135;
|
||||
public const uint DestroyedTower = 59136;
|
||||
public const uint DamagedBuilding = 59201;
|
||||
public const uint IntactBuilding = 59203;
|
||||
|
||||
public const uint TeleportBridge = 59096;
|
||||
public const uint TeleportFortress = 60035;
|
||||
|
||||
public const uint TeleportDalaran = 53360;
|
||||
public const uint VictoryAura = 60044;
|
||||
|
||||
// Other Spells
|
||||
public const uint WintergraspWater = 36444;
|
||||
public const uint EssenceOfWintergrasp = 58045;
|
||||
public const uint WintergraspRestrictedFlightArea = 91604;
|
||||
|
||||
// Phasing Spells
|
||||
public const uint HordeControlsFactoryPhaseShift = 56618; // Adds Phase 16
|
||||
public const uint AllianceControlsFactoryPhaseShift = 56617; // Adds Phase 32
|
||||
|
||||
public const uint HordeControlPhaseShift = 55773; // Adds Phase 64
|
||||
public const uint AllianceControlPhaseShift = 55774; // Adds Phase 128
|
||||
}
|
||||
|
||||
struct WGNpcs
|
||||
{
|
||||
public const uint GuardH = 30739;
|
||||
public const uint GuardA = 30740;
|
||||
public const uint Stalker = 15214;
|
||||
|
||||
public const uint TaunkaSpiritGuide = 31841; // Horde Spirit Guide For Wintergrasp
|
||||
public const uint DwarvenSpiritGuide = 31842; // Alliance Spirit Guide For Wintergrasp
|
||||
|
||||
public const uint SiegeEngineAlliance = 28312;
|
||||
public const uint SiegeEngineHorde = 32627;
|
||||
public const uint Catapult = 27881;
|
||||
public const uint Demolisher = 28094;
|
||||
public const uint TowerCannon = 28366;
|
||||
}
|
||||
|
||||
struct WGGameObjects
|
||||
{
|
||||
public const uint FactoryBannerNe = 190475;
|
||||
public const uint FactoryBannerNw = 190487;
|
||||
public const uint FactoryBannerSe = 194959;
|
||||
public const uint FactoryBannerSw = 194962;
|
||||
|
||||
public const uint TitanSRelic = 192829;
|
||||
|
||||
public const uint FortressTower1 = 190221;
|
||||
public const uint FortressTower2 = 190373;
|
||||
public const uint FortressTower3 = 190377;
|
||||
public const uint FortressTower4 = 190378;
|
||||
|
||||
public const uint ShadowsightTower = 190356;
|
||||
public const uint WinterSEdgeTower = 190357;
|
||||
public const uint FlamewatchTower = 190358;
|
||||
|
||||
public const uint FortressGate = 190375;
|
||||
public const uint VaultGate = 191810;
|
||||
|
||||
public const uint KeepCollisionWall = 194323;
|
||||
}
|
||||
|
||||
struct WintergraspTowerIds
|
||||
{
|
||||
public const byte FortressNW = 0;
|
||||
public const byte FortressSW = 1;
|
||||
public const byte FortressSE = 2;
|
||||
public const byte FortressNE = 3;
|
||||
public const byte Shadowsight = 4;
|
||||
public const byte WintersEdge = 5;
|
||||
public const byte Flamewatch = 6;
|
||||
}
|
||||
|
||||
struct WGWorkshopIds
|
||||
{
|
||||
public const byte Se = 0;
|
||||
public const byte Sw = 1;
|
||||
public const byte Ne = 2;
|
||||
public const byte Nw = 3;
|
||||
public const byte KeepWest = 4;
|
||||
public const byte KeepEast = 5;
|
||||
}
|
||||
|
||||
struct WGWorldStates
|
||||
{
|
||||
public const uint NE = 3701;
|
||||
public const uint NW = 3700;
|
||||
public const uint SE = 3703;
|
||||
public const uint SW = 3702;
|
||||
public const uint KeepW = 3698;
|
||||
public const uint KeepE = 3699;
|
||||
|
||||
public const uint VehicleH = 3490;
|
||||
public const uint MaxVehicleH = 3491;
|
||||
public const uint VehicleA = 3680;
|
||||
public const uint MaxVehicleA = 3681;
|
||||
public const uint Active = 3801;
|
||||
public const uint Defender = 3802;
|
||||
public const uint Attacker = 3803;
|
||||
public const uint ShowWorldstate = 3710;
|
||||
public const uint AttackedH = 4022;
|
||||
public const uint AttackedA = 4023;
|
||||
public const uint DefendedH = 4024;
|
||||
public const uint DefendedA = 4025;
|
||||
}
|
||||
|
||||
struct WGGossipText
|
||||
{
|
||||
public const int GYNE = 20071;
|
||||
public const int GYNW = 20072;
|
||||
public const int GYSE = 20074;
|
||||
public const int GYSW = 20073;
|
||||
public const int GYKeep = 20070;
|
||||
public const int GYHorde = 20075;
|
||||
public const int GYAlliance = 20076;
|
||||
}
|
||||
|
||||
struct WGGraveyardId
|
||||
{
|
||||
public const uint WorkshopNE = 0;
|
||||
public const uint WorkshopNW = 1;
|
||||
public const uint WorkshopSE = 2;
|
||||
public const uint WorkshopSW = 3;
|
||||
public const uint Keep = 4;
|
||||
public const uint Horde = 5;
|
||||
public const uint Alliance = 6;
|
||||
public const uint Max = 7;
|
||||
}
|
||||
|
||||
struct WintergraspAreaIds
|
||||
{
|
||||
public const uint WintergraspFortress = 4575;
|
||||
public const uint TheSunkenRing = 4538;
|
||||
public const uint TheBrokenTemplate = 4539;
|
||||
public const uint WestparkWorkshop = 4611;
|
||||
public const uint EastparkWorkshop = 4612;
|
||||
public const uint Wintergrasp = 4197;
|
||||
public const uint TheChilledQuagmire = 4589;
|
||||
}
|
||||
|
||||
struct WintergraspQuests
|
||||
{
|
||||
public const uint VictoryAlliance = 13181;
|
||||
public const uint VictoryHorde = 13183;
|
||||
public const uint CreditTowersDestroyed = 35074;
|
||||
public const uint CreditDefendSiege = 31284;
|
||||
}
|
||||
|
||||
struct WintergraspText
|
||||
{
|
||||
// Invisible Stalker
|
||||
public const byte SouthernTowerDamage = 1;
|
||||
public const byte SouthernTowerDestroy = 2;
|
||||
public const byte EasternTowerDamage = 3;
|
||||
public const byte EasternTowerDestroy = 4;
|
||||
public const byte WesternTowerDamage = 5;
|
||||
public const byte WesternTowerDestroy = 6;
|
||||
public const byte NwKeeptowerDamage = 7;
|
||||
public const byte NwKeeptowerDestroy = 8;
|
||||
public const byte SeKeeptowerDamage = 9;
|
||||
public const byte SeKeeptowerDestroy = 10;
|
||||
public const byte BrokenTempleAttackAlliance = 11;
|
||||
public const byte BrokenTempleCaptureAlliance = 12;
|
||||
public const byte BrokenTempleAttackHorde = 13;
|
||||
public const byte BrokenTempleCaptureHorde = 14;
|
||||
public const byte EastsparkAttackAlliance = 15;
|
||||
public const byte EastsparkCaptureAlliance = 16;
|
||||
public const byte EastsparkAttackHorde = 17;
|
||||
public const byte EastsparkCaptureHorde = 18;
|
||||
public const byte SunkenRingAttackAlliance = 19;
|
||||
public const byte SunkenRingCaptureAlliance = 20;
|
||||
public const byte SunkenRingAttackHorde = 21;
|
||||
public const byte SunkenRingCaptureHorde = 22;
|
||||
public const byte WestsparkAttackAlliance = 23;
|
||||
public const byte WestsparkCaptureAlliance = 24;
|
||||
public const byte WestsparkAttackHorde = 25;
|
||||
public const byte WestsparkCaptureHorde = 26;
|
||||
|
||||
public const byte StartGrouping = 27;
|
||||
public const byte StartBattle = 28;
|
||||
public const byte FortressDefendAlliance = 29;
|
||||
public const byte FortressCaptureAlliance = 30;
|
||||
public const byte FortressDefendHorde = 31;
|
||||
public const byte FortressCaptureHorde = 32;
|
||||
|
||||
public const byte NeKeeptowerDamage = 33;
|
||||
public const byte NeKeeptowerDestroy = 34;
|
||||
public const byte SwKeeptowerDamage = 35;
|
||||
public const byte SwKeeptowerDestroy = 36;
|
||||
|
||||
public const byte RankCorporal = 37;
|
||||
public const byte RankFirstLieutenant = 38;
|
||||
}
|
||||
|
||||
enum WGGameObjectState
|
||||
{
|
||||
None,
|
||||
NeutralIntact,
|
||||
NeutralDamage,
|
||||
NeutralDestroy,
|
||||
HordeIntact,
|
||||
HordeDamage,
|
||||
HordeDestroy,
|
||||
AllianceIntact,
|
||||
AllianceDamage,
|
||||
AllianceDestroy
|
||||
}
|
||||
|
||||
enum WGGameObjectBuildingType
|
||||
{
|
||||
Door,
|
||||
Titanrelic,
|
||||
Wall,
|
||||
DoorLast,
|
||||
KeepTower,
|
||||
Tower
|
||||
}
|
||||
|
||||
//Data Structs
|
||||
struct BfWGCoordGY
|
||||
{
|
||||
public BfWGCoordGY(float x, float y, float z, float o, uint graveyardId, int textId, uint startControl)
|
||||
{
|
||||
pos = new Position(x, y, z, o);
|
||||
GraveyardID = graveyardId;
|
||||
TextId = textId;
|
||||
StartControl = startControl;
|
||||
}
|
||||
|
||||
public Position pos;
|
||||
public uint GraveyardID;
|
||||
public int TextId;// for gossip menu
|
||||
public uint StartControl;
|
||||
}
|
||||
|
||||
struct WintergraspBuildingSpawnData
|
||||
{
|
||||
public WintergraspBuildingSpawnData(uint entry, uint worldstate, float x, float y, float z, float o, float rX, float rY, float rZ, float rW, WGGameObjectBuildingType type)
|
||||
{
|
||||
Entry = entry;
|
||||
WorldState = worldstate;
|
||||
Pos = new Position(x, y, z, o);
|
||||
Rot = new Quaternion(rX, rY, rZ, rW);
|
||||
BuildingType = type;
|
||||
}
|
||||
|
||||
public uint Entry;
|
||||
public uint WorldState;
|
||||
public Position Pos;
|
||||
public Quaternion Rot;
|
||||
public WGGameObjectBuildingType BuildingType;
|
||||
}
|
||||
|
||||
struct WintergraspGameObjectData
|
||||
{
|
||||
public WintergraspGameObjectData(float x, float y, float z, float o, float rX, float rY, float rZ, float rW, uint hordeEntry, uint allianceEntry)
|
||||
{
|
||||
Pos = new Position(x, y, z, o);
|
||||
Rot = new Quaternion(rX, rY, rZ, rW);
|
||||
HordeEntry = hordeEntry;
|
||||
AllianceEntry = allianceEntry;
|
||||
}
|
||||
|
||||
public Position Pos;
|
||||
public Quaternion Rot;
|
||||
public uint HordeEntry;
|
||||
public uint AllianceEntry;
|
||||
}
|
||||
|
||||
class WintergraspTowerData
|
||||
{
|
||||
public uint towerEntry; // Gameobject id of tower
|
||||
public WintergraspGameObjectData[] GameObject = new WintergraspGameObjectData[6]; // Gameobject position and entry (Horde/Alliance)
|
||||
|
||||
// Creature: Turrets and Guard /// @todo: Killed on Tower destruction ? Tower damage ? Requires confirming
|
||||
public WintergraspObjectPositionData[] CreatureBottom = new WintergraspObjectPositionData[9];
|
||||
}
|
||||
|
||||
struct WintergraspObjectPositionData
|
||||
{
|
||||
public WintergraspObjectPositionData(float x, float y, float z, float o, uint hordeEntry, uint allianceEntry)
|
||||
{
|
||||
Pos = new Position(x, y, z, o);
|
||||
HordeEntry = hordeEntry;
|
||||
AllianceEntry = allianceEntry;
|
||||
}
|
||||
|
||||
public Position Pos;
|
||||
public uint HordeEntry;
|
||||
public uint AllianceEntry;
|
||||
}
|
||||
|
||||
class WintergraspTowerCannonData
|
||||
{
|
||||
public WintergraspTowerCannonData()
|
||||
{
|
||||
TowerCannonBottom = new Position[0];
|
||||
TurretTop = new Position[0];
|
||||
}
|
||||
|
||||
public uint towerEntry;
|
||||
public Position[] TowerCannonBottom;
|
||||
public Position[] TurretTop;
|
||||
}
|
||||
|
||||
class StaticWintergraspWorkshopInfo
|
||||
{
|
||||
public byte WorkshopId;
|
||||
public uint WorldStateId;
|
||||
public byte AllianceCaptureTextId;
|
||||
public byte AllianceAttackTextId;
|
||||
public byte HordeCaptureTextId;
|
||||
public byte HordeAttackTextId;
|
||||
}
|
||||
|
||||
class StaticWintergraspTowerInfo
|
||||
{
|
||||
public StaticWintergraspTowerInfo(byte towerId, byte damagedTextId, byte destroyedTextId)
|
||||
{
|
||||
TowerId = towerId;
|
||||
DamagedTextId = damagedTextId;
|
||||
DestroyedTextId = destroyedTextId;
|
||||
}
|
||||
|
||||
public byte TowerId;
|
||||
public byte DamagedTextId;
|
||||
public byte DestroyedTextId;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,919 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Arenas;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Game.BattleGrounds.Zones;
|
||||
|
||||
namespace Game.BattleGrounds
|
||||
{
|
||||
public class BattlegroundManager : Singleton<BattlegroundManager>
|
||||
{
|
||||
BattlegroundManager()
|
||||
{
|
||||
m_NextRatedArenaUpdate = WorldConfig.GetUIntValue(WorldCfg.ArenaRatedUpdateTimer);
|
||||
|
||||
for (var i = 0; i < (int)BattlegroundQueueTypeId.Max; ++i)
|
||||
m_BattlegroundQueues[i] = new BattlegroundQueue();
|
||||
}
|
||||
|
||||
public void DeleteAllBattlegrounds()
|
||||
{
|
||||
foreach (var data in bgDataStore.Values)
|
||||
{
|
||||
data.m_Battlegrounds.Clear();
|
||||
data.BGFreeSlotQueue.Clear();
|
||||
}
|
||||
|
||||
bgDataStore.Clear();
|
||||
}
|
||||
|
||||
public void Update(uint diff)
|
||||
{
|
||||
m_UpdateTimer += diff;
|
||||
if (m_UpdateTimer > 1000)
|
||||
{
|
||||
foreach (var data in bgDataStore.Values)
|
||||
{
|
||||
var bgs = data.m_Battlegrounds;
|
||||
|
||||
// first one is template and should not be deleted
|
||||
foreach (var pair in bgs.ToList())
|
||||
{
|
||||
Battleground bg = pair.Value;
|
||||
bg.Update(m_UpdateTimer);
|
||||
|
||||
if (bg.ToBeDeleted())
|
||||
{
|
||||
bgs.Remove(pair.Key);
|
||||
var clients = data.m_ClientBattlegroundIds[(int)bg.GetBracketId()];
|
||||
if (!clients.Empty())
|
||||
clients.Remove(bg.GetClientInstanceID());
|
||||
|
||||
bg.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_UpdateTimer = 0;
|
||||
}
|
||||
// update events timer
|
||||
for (var qtype = BattlegroundQueueTypeId.None; qtype < BattlegroundQueueTypeId.Max; ++qtype)
|
||||
m_BattlegroundQueues[(int)qtype].UpdateEvents(diff);
|
||||
|
||||
// update scheduled queues
|
||||
if (!m_QueueUpdateScheduler.Empty())
|
||||
{
|
||||
List<ulong> scheduled = new List<ulong>();
|
||||
Extensions.Swap(ref scheduled, ref m_QueueUpdateScheduler);
|
||||
|
||||
for (byte i = 0; i < scheduled.Count; i++)
|
||||
{
|
||||
uint arenaMMRating = (uint)(scheduled[i] >> 32);
|
||||
byte arenaType = (byte)(scheduled[i] >> 24 & 255);
|
||||
BattlegroundQueueTypeId bgQueueTypeId = (BattlegroundQueueTypeId)(scheduled[i] >> 16 & 255);
|
||||
BattlegroundTypeId bgTypeId = (BattlegroundTypeId)((scheduled[i] >> 8) & 255);
|
||||
BattlegroundBracketId bracket_id = (BattlegroundBracketId)(scheduled[i] & 255);
|
||||
m_BattlegroundQueues[(int)bgQueueTypeId].BattlegroundQueueUpdate(diff, bgTypeId, bracket_id, arenaType, arenaMMRating > 0, arenaMMRating);
|
||||
}
|
||||
}
|
||||
|
||||
// if rating difference counts, maybe force-update queues
|
||||
if (WorldConfig.GetIntValue(WorldCfg.ArenaMaxRatingDifference) != 0 && WorldConfig.GetIntValue(WorldCfg.ArenaRatedUpdateTimer) != 0)
|
||||
{
|
||||
// it's time to force update
|
||||
if (m_NextRatedArenaUpdate < diff)
|
||||
{
|
||||
// forced update for rated arenas (scan all, but skipped non rated)
|
||||
Log.outDebug(LogFilter.Arena, "BattlegroundMgr: UPDATING ARENA QUEUES");
|
||||
for (var qtype = BattlegroundQueueTypeId.Arena2v2; qtype <= BattlegroundQueueTypeId.Arena5v5; ++qtype)
|
||||
{
|
||||
for (int bracket = (int)BattlegroundBracketId.First; bracket < (int)BattlegroundBracketId.Max; ++bracket)
|
||||
{
|
||||
m_BattlegroundQueues[(int)qtype].BattlegroundQueueUpdate(diff,
|
||||
BattlegroundTypeId.AA, (BattlegroundBracketId)bracket,
|
||||
(byte)BGArenaType(qtype), true, 0);
|
||||
}
|
||||
}
|
||||
|
||||
m_NextRatedArenaUpdate = WorldConfig.GetUIntValue(WorldCfg.ArenaRatedUpdateTimer);
|
||||
}
|
||||
else
|
||||
m_NextRatedArenaUpdate -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
void BuildBattlegroundStatusHeader(ref BattlefieldStatusHeader header, Battleground bg, Player player, uint ticketId, uint joinTime, ArenaTypes arenaType)
|
||||
{
|
||||
header.Ticket = new RideTicket();
|
||||
header.Ticket.RequesterGuid = player.GetGUID();
|
||||
header.Ticket.Id = ticketId;
|
||||
header.Ticket.Type = RideType.Battlegrounds;
|
||||
header.Ticket.Time = (int)joinTime;
|
||||
header.QueueID = bg.GetQueueId();
|
||||
header.RangeMin = (byte)bg.GetMinLevel();
|
||||
header.RangeMax = (byte)bg.GetMaxLevel();
|
||||
header.TeamSize = (byte)(bg.isArena() ? arenaType : 0);
|
||||
header.InstanceID = bg.GetClientInstanceID();
|
||||
header.RegisteredMatch = bg.isRated();
|
||||
header.TournamentRules = false;
|
||||
}
|
||||
|
||||
public void BuildBattlegroundStatusNone(out BattlefieldStatusNone battlefieldStatus, Player player, uint ticketId, uint joinTime)
|
||||
{
|
||||
battlefieldStatus = new BattlefieldStatusNone();
|
||||
battlefieldStatus.Ticket.RequesterGuid = player.GetGUID();
|
||||
battlefieldStatus.Ticket.Id = ticketId;
|
||||
battlefieldStatus.Ticket.Type = RideType.Battlegrounds;
|
||||
battlefieldStatus.Ticket.Time = (int)joinTime;
|
||||
}
|
||||
|
||||
public void BuildBattlegroundStatusNeedConfirmation(out BattlefieldStatusNeedConfirmation battlefieldStatus, Battleground bg, Player player, uint ticketId, uint joinTime, uint timeout, ArenaTypes arenaType)
|
||||
{
|
||||
battlefieldStatus = new BattlefieldStatusNeedConfirmation();
|
||||
BuildBattlegroundStatusHeader(ref battlefieldStatus.Hdr, bg, player, ticketId, joinTime, arenaType);
|
||||
battlefieldStatus.Mapid = bg.GetMapId();
|
||||
battlefieldStatus.Timeout = timeout;
|
||||
battlefieldStatus.Role = 0;
|
||||
}
|
||||
|
||||
public void BuildBattlegroundStatusActive(out BattlefieldStatusActive battlefieldStatus, Battleground bg, Player player, uint ticketId, uint joinTime, ArenaTypes arenaType)
|
||||
{
|
||||
battlefieldStatus = new BattlefieldStatusActive();
|
||||
BuildBattlegroundStatusHeader(ref battlefieldStatus.Hdr, bg, player, ticketId, joinTime, arenaType);
|
||||
battlefieldStatus.ShutdownTimer = bg.GetRemainingTime();
|
||||
battlefieldStatus.ArenaFaction = (byte)(player.GetBGTeam() == Team.Horde ? TeamId.Horde : TeamId.Alliance);
|
||||
battlefieldStatus.LeftEarly = false;
|
||||
battlefieldStatus.StartTimer = bg.GetElapsedTime();
|
||||
battlefieldStatus.Mapid = bg.GetMapId();
|
||||
}
|
||||
|
||||
public void BuildBattlegroundStatusQueued(out BattlefieldStatusQueued battlefieldStatus, Battleground bg, Player player, uint ticketId, uint joinTime, uint avgWaitTime, ArenaTypes arenaType, bool asGroup)
|
||||
{
|
||||
battlefieldStatus = new BattlefieldStatusQueued();
|
||||
BuildBattlegroundStatusHeader(ref battlefieldStatus.Hdr, bg, player, ticketId, joinTime, arenaType);
|
||||
battlefieldStatus.AverageWaitTime = avgWaitTime;
|
||||
battlefieldStatus.AsGroup = asGroup;
|
||||
battlefieldStatus.SuspendedQueue = false;
|
||||
battlefieldStatus.EligibleForMatchmaking = true;
|
||||
battlefieldStatus.WaitTime = Time.GetMSTimeDiffToNow(joinTime);
|
||||
}
|
||||
|
||||
public void BuildBattlegroundStatusFailed(out BattlefieldStatusFailed battlefieldStatus, Battleground bg, Player pPlayer, uint ticketId, ArenaTypes arenaType, GroupJoinBattlegroundResult result, ObjectGuid errorGuid = default(ObjectGuid))
|
||||
{
|
||||
battlefieldStatus = new BattlefieldStatusFailed();
|
||||
battlefieldStatus.Ticket.RequesterGuid = pPlayer.GetGUID();
|
||||
battlefieldStatus.Ticket.Id = ticketId;
|
||||
battlefieldStatus.Ticket.Type = RideType.Battlegrounds;
|
||||
battlefieldStatus.Ticket.Time = (int)pPlayer.GetBattlegroundQueueJoinTime(BGQueueTypeId(bg.GetTypeID(), arenaType));
|
||||
battlefieldStatus.QueueID = bg.GetQueueId();
|
||||
battlefieldStatus.Reason = (int)result;
|
||||
if (!errorGuid.IsEmpty() && (result == GroupJoinBattlegroundResult.NotInBattleground || result == GroupJoinBattlegroundResult.JoinTimedOut))
|
||||
battlefieldStatus.ClientID = errorGuid;
|
||||
}
|
||||
|
||||
public Battleground GetBattleground(uint instanceId, BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
if (instanceId == 0)
|
||||
return null;
|
||||
|
||||
if (bgTypeId != BattlegroundTypeId.None)
|
||||
{
|
||||
var data = bgDataStore.LookupByKey(bgTypeId);
|
||||
return data.m_Battlegrounds.LookupByKey(instanceId);
|
||||
}
|
||||
|
||||
foreach (var it in bgDataStore)
|
||||
{
|
||||
var bgs = it.Value.m_Battlegrounds;
|
||||
var bg = bgs.LookupByKey(instanceId);
|
||||
if (bg)
|
||||
return bg;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Battleground GetBattlegroundTemplate(BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
if (bgDataStore.ContainsKey(bgTypeId))
|
||||
return bgDataStore[bgTypeId].Template;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
uint CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
|
||||
{
|
||||
if (IsArenaType(bgTypeId))
|
||||
return 0; //arenas don't have client-instanceids
|
||||
|
||||
// we create here an instanceid, which is just for
|
||||
// displaying this to the client and without any other use..
|
||||
// the client-instanceIds are unique for each Battleground-type
|
||||
// the instance-id just needs to be as low as possible, beginning with 1
|
||||
// the following works, because std.set is default ordered with "<"
|
||||
// the optimalization would be to use as bitmask std.vector<uint32> - but that would only make code unreadable
|
||||
|
||||
var clientIds = bgDataStore[bgTypeId].m_ClientBattlegroundIds[(int)bracket_id];
|
||||
uint lastId = 0;
|
||||
foreach (var id in clientIds)
|
||||
{
|
||||
if (++lastId != id) //if there is a gap between the ids, we will break..
|
||||
break;
|
||||
lastId = id;
|
||||
}
|
||||
|
||||
clientIds.Add(++lastId);
|
||||
return lastId;
|
||||
}
|
||||
|
||||
// create a new Battleground that will really be used to play
|
||||
public Battleground CreateNewBattleground(BattlegroundTypeId originalBgTypeId, PvpDifficultyRecord bracketEntry, ArenaTypes arenaType, bool isRated)
|
||||
{
|
||||
BattlegroundTypeId bgTypeId = GetRandomBG(originalBgTypeId);
|
||||
|
||||
// get the template BG
|
||||
Battleground bg_template = GetBattlegroundTemplate(bgTypeId);
|
||||
if (bg_template == null)
|
||||
{
|
||||
Log.outError(LogFilter.Battleground, "Battleground: CreateNewBattleground - bg template not found for {0}", bgTypeId);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (bgTypeId == BattlegroundTypeId.RB || bgTypeId == BattlegroundTypeId.AA)
|
||||
return null;
|
||||
|
||||
// create a copy of the BG template
|
||||
Battleground bg = bg_template.GetCopy();
|
||||
|
||||
bool isRandom = bgTypeId != originalBgTypeId && !bg.isArena();
|
||||
|
||||
bg.SetBracket(bracketEntry);
|
||||
bg.SetInstanceID(Global.MapMgr.GenerateInstanceId());
|
||||
bg.SetClientInstanceID(CreateClientVisibleInstanceId(isRandom ? BattlegroundTypeId.RB : bgTypeId, bracketEntry.GetBracketId()));
|
||||
bg.Reset(); // reset the new bg (set status to status_wait_queue from status_none)
|
||||
bg.SetStatus(BattlegroundStatus.WaitJoin); // start the joining of the bg
|
||||
bg.SetArenaType(arenaType);
|
||||
bg.SetTypeID(originalBgTypeId);
|
||||
bg.SetRandomTypeID(bgTypeId);
|
||||
bg.SetRated(isRated);
|
||||
bg.SetRandom(isRandom);
|
||||
bg.SetQueueId((ulong)bgTypeId | 0x1F10000000000000);
|
||||
|
||||
// Set up correct min/max player counts for scoreboards
|
||||
if (bg.isArena())
|
||||
{
|
||||
uint maxPlayersPerTeam = 0;
|
||||
switch (arenaType)
|
||||
{
|
||||
case ArenaTypes.Team2v2:
|
||||
maxPlayersPerTeam = 2;
|
||||
break;
|
||||
case ArenaTypes.Team3v3:
|
||||
maxPlayersPerTeam = 3;
|
||||
break;
|
||||
case ArenaTypes.Team5v5:
|
||||
maxPlayersPerTeam = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
bg.SetMaxPlayersPerTeam(maxPlayersPerTeam);
|
||||
bg.SetMaxPlayers(maxPlayersPerTeam * 2);
|
||||
}
|
||||
|
||||
return bg;
|
||||
}
|
||||
|
||||
// used to create the BG templates
|
||||
bool CreateBattleground(BattlegroundTemplate bgTemplate)
|
||||
{
|
||||
Battleground bg = GetBattlegroundTemplate(bgTemplate.Id);
|
||||
if (!bg)
|
||||
{
|
||||
// Create the BG
|
||||
switch (bgTemplate.Id)
|
||||
{
|
||||
//case BattlegroundTypeId.AV:
|
||||
// bg = new BattlegroundAV();
|
||||
//break;
|
||||
case BattlegroundTypeId.WS:
|
||||
bg = new BgWarsongGluch();
|
||||
break;
|
||||
case BattlegroundTypeId.AB:
|
||||
bg = new BgArathiBasin();
|
||||
break;
|
||||
case BattlegroundTypeId.NA:
|
||||
bg = new NagrandArena();
|
||||
break;
|
||||
case BattlegroundTypeId.BE:
|
||||
bg = new BladesEdgeArena();
|
||||
break;
|
||||
case BattlegroundTypeId.EY:
|
||||
bg = new BgEyeofStorm();
|
||||
break;
|
||||
case BattlegroundTypeId.RL:
|
||||
bg = new RuinsofLordaeronArena();
|
||||
break;
|
||||
case BattlegroundTypeId.SA:
|
||||
bg = new BgStrandOfAncients();
|
||||
break;
|
||||
case BattlegroundTypeId.DS:
|
||||
bg = new DalaranSewersArena();
|
||||
break;
|
||||
case BattlegroundTypeId.RV:
|
||||
bg = new RingofValorArena();
|
||||
break;
|
||||
//case BattlegroundTypeId.IC:
|
||||
//bg = new BattlegroundIC();
|
||||
//break;
|
||||
case BattlegroundTypeId.AA:
|
||||
bg = new Battleground();
|
||||
break;
|
||||
case BattlegroundTypeId.RB:
|
||||
bg = new Battleground();
|
||||
bg.SetRandom(true);
|
||||
break;
|
||||
/*
|
||||
case BattlegroundTypeId.TP:
|
||||
bg = new BattlegroundTP();
|
||||
break;
|
||||
case BattlegroundTypeId.BFG:
|
||||
bg = new BattlegroundBFG();
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
bg.SetTypeID(bgTemplate.Id);
|
||||
}
|
||||
|
||||
bg.SetMapId((uint)bgTemplate.BattlemasterEntry.MapId[0]);
|
||||
bg.SetName(bgTemplate.BattlemasterEntry.Name[Global.WorldMgr.GetDefaultDbcLocale()]);
|
||||
bg.SetInstanceID(0);
|
||||
bg.SetArenaorBGType(bgTemplate.IsArena());
|
||||
bg.SetMinPlayersPerTeam(bgTemplate.MinPlayersPerTeam);
|
||||
bg.SetMaxPlayersPerTeam(bgTemplate.MaxPlayersPerTeam);
|
||||
bg.SetMinPlayers(bgTemplate.MinPlayersPerTeam * 2);
|
||||
bg.SetMaxPlayers(bgTemplate.MaxPlayersPerTeam * 2);
|
||||
bg.SetTeamStartPosition(TeamId.Alliance, bgTemplate.StartLocation[TeamId.Alliance]);
|
||||
bg.SetTeamStartPosition(TeamId.Horde, bgTemplate.StartLocation[TeamId.Horde]);
|
||||
bg.SetStartMaxDist(bgTemplate.StartMaxDist);
|
||||
bg.SetLevelRange(bgTemplate.MinLevel, bgTemplate.MaxLevel);
|
||||
bg.SetScriptId(bgTemplate.scriptId);
|
||||
bg.SetQueueId((ulong)bgTemplate.Id | 0x1F10000000000000);
|
||||
|
||||
if (!bgDataStore.ContainsKey(bg.GetTypeID()))
|
||||
bgDataStore[bg.GetTypeID()] = new BattlegroundData();
|
||||
|
||||
bgDataStore[bg.GetTypeID()].Template = bg;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void LoadBattlegroundTemplates()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
_BattlegroundMapTemplates.Clear();
|
||||
_BattlegroundTemplates.Clear();
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9
|
||||
SQLResult result = DB.World.Query("SELECT ID, MinPlayersPerTeam, MaxPlayersPerTeam, MinLvl, MaxLvl, AllianceStartLoc, HordeStartLoc, StartMaxDist, Weight, ScriptName FROM Battleground_template");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outError(LogFilter.ServerLoading, "Loaded 0 Battlegrounds. DB table `Battleground_template` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint count = 0;
|
||||
do
|
||||
{
|
||||
BattlegroundTypeId bgTypeId = (BattlegroundTypeId)result.Read<uint>(0);
|
||||
if (Global.DisableMgr.IsDisabledFor(DisableType.Battleground, (uint)bgTypeId, null))
|
||||
continue;
|
||||
|
||||
// can be overwrite by values from DB
|
||||
BattlemasterListRecord bl = CliDB.BattlemasterListStorage.LookupByKey(bgTypeId);
|
||||
if (bl == null)
|
||||
{
|
||||
Log.outError(LogFilter.Battleground, "Battleground ID {0} not found in BattlemasterList.dbc. Battleground not created.", bgTypeId);
|
||||
continue;
|
||||
}
|
||||
|
||||
BattlegroundTemplate bgTemplate = new BattlegroundTemplate();
|
||||
bgTemplate.Id = bgTypeId;
|
||||
bgTemplate.MinPlayersPerTeam = result.Read<ushort>(1);
|
||||
bgTemplate.MaxPlayersPerTeam = result.Read<ushort>(2);
|
||||
bgTemplate.MinLevel = result.Read<byte>(3);
|
||||
bgTemplate.MaxLevel = result.Read<byte>(4);
|
||||
float dist = result.Read<float>(7);
|
||||
bgTemplate.StartMaxDist = dist * dist;
|
||||
bgTemplate.Weight = result.Read<byte>(8);
|
||||
|
||||
bgTemplate.scriptId = Global.ObjectMgr.GetScriptId(result.Read<string>(9));
|
||||
bgTemplate.BattlemasterEntry = bl;
|
||||
|
||||
if (bgTemplate.MaxPlayersPerTeam == 0 || bgTemplate.MinPlayersPerTeam > bgTemplate.MaxPlayersPerTeam)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Table `Battleground_template` for Id {0} has bad values for MinPlayersPerTeam ({1}) and MaxPlayersPerTeam({2})",
|
||||
bgTemplate.Id, bgTemplate.MinPlayersPerTeam, bgTemplate.MaxPlayersPerTeam);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bgTemplate.MinLevel == 0 || bgTemplate.MaxLevel == 0 || bgTemplate.MinLevel > bgTemplate.MaxLevel)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Table `Battleground_template` for Id {0} has bad values for LevelMin ({1}) and LevelMax({2})",
|
||||
bgTemplate.Id, bgTemplate.MinLevel, bgTemplate.MaxLevel);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bgTemplate.Id != BattlegroundTypeId.AA && bgTemplate.Id != BattlegroundTypeId.RB)
|
||||
{
|
||||
uint startId = result.Read<uint>(5);
|
||||
if (CliDB.WorldSafeLocsStorage.ContainsKey(startId))
|
||||
{
|
||||
WorldSafeLocsRecord start = CliDB.WorldSafeLocsStorage.LookupByKey(startId);
|
||||
bgTemplate.StartLocation[TeamId.Alliance] = new Position(start.Loc.X, start.Loc.Y, start.Loc.Z, (start.Facing + MathFunctions.PI) / 180);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Table `Battleground_template` for Id {0} has a non-existed WorldSafeLocs.dbc id {1} in field `AllianceStartLoc`. BG not created.", bgTemplate.Id, startId);
|
||||
continue;
|
||||
}
|
||||
|
||||
startId = result.Read<uint>(6);
|
||||
if (CliDB.WorldSafeLocsStorage.ContainsKey(startId))
|
||||
{
|
||||
WorldSafeLocsRecord start = CliDB.WorldSafeLocsStorage.LookupByKey(startId);
|
||||
bgTemplate.StartLocation[TeamId.Horde] = new Position(start.Loc.X, start.Loc.Y, start.Loc.Z, result.Read<float>(8));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Table `Battleground_template` for Id {0} has a non-existed WorldSafeLocs.dbc id {1} in field `HordeStartLoc`. BG not created.", bgTemplate.Id, startId);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CreateBattleground(bgTemplate))
|
||||
continue;
|
||||
|
||||
_BattlegroundTemplates[bgTypeId] = bgTemplate;
|
||||
|
||||
if (bgTemplate.BattlemasterEntry.MapId[1] == -1) // in this case we have only one mapId
|
||||
_BattlegroundMapTemplates[(uint)bgTemplate.BattlemasterEntry.MapId[0]] = _BattlegroundTemplates[bgTypeId];
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} Battlegrounds in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public void SendBattlegroundList(Player player, ObjectGuid guid, BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
BattlegroundTemplate bgTemplate = GetBattlegroundTemplateByTypeId(bgTypeId);
|
||||
if (bgTemplate == null)
|
||||
return;
|
||||
|
||||
BattlefieldList battlefieldList = new BattlefieldList();
|
||||
battlefieldList.BattlemasterGuid = guid;
|
||||
battlefieldList.BattlemasterListID = (int)bgTypeId;
|
||||
battlefieldList.MinLevel = (byte)bgTemplate.MinLevel;
|
||||
battlefieldList.MaxLevel = (byte)bgTemplate.MaxLevel;
|
||||
battlefieldList.PvpAnywhere = guid.IsEmpty();
|
||||
battlefieldList.HasRandomWinToday = player.GetRandomWinner();
|
||||
player.SendPacket(battlefieldList);
|
||||
}
|
||||
|
||||
public void SendToBattleground(Player player, uint instanceId, BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
Battleground bg = GetBattleground(instanceId, bgTypeId);
|
||||
if (bg)
|
||||
{
|
||||
uint mapid = bg.GetMapId();
|
||||
Team team = player.GetBGTeam();
|
||||
|
||||
Position pos = bg.GetTeamStartPosition(Battleground.GetTeamIndexByTeamId(team));
|
||||
Log.outDebug(LogFilter.Battleground, "BattlegroundMgr.SendToBattleground: Sending {0} to map {1}, {2} (bgType {3})", player.GetName(), mapid, pos.ToString(), bgTypeId);
|
||||
player.TeleportTo(mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
|
||||
}
|
||||
else
|
||||
Log.outError(LogFilter.Battleground, "BattlegroundMgr.SendToBattleground: Instance {0} (bgType {1}) not found while trying to teleport player {2}", instanceId, bgTypeId, player.GetName());
|
||||
}
|
||||
|
||||
public void SendAreaSpiritHealerQuery(Player player, Battleground bg, ObjectGuid guid)
|
||||
{
|
||||
uint time = 30000 - bg.GetLastResurrectTime(); // resurrect every 30 seconds
|
||||
if (time == 0xFFFFFFFF)
|
||||
time = 0;
|
||||
|
||||
AreaSpiritHealerTime areaSpiritHealerTime = new AreaSpiritHealerTime();
|
||||
areaSpiritHealerTime.HealerGuid = guid;
|
||||
areaSpiritHealerTime.TimeLeft = time;
|
||||
|
||||
player.SendPacket(areaSpiritHealerTime);
|
||||
}
|
||||
|
||||
bool IsArenaType(BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
return bgTypeId == BattlegroundTypeId.AA || bgTypeId == BattlegroundTypeId.BE || bgTypeId == BattlegroundTypeId.NA
|
||||
|| bgTypeId == BattlegroundTypeId.DS || bgTypeId == BattlegroundTypeId.RV || bgTypeId == BattlegroundTypeId.RL;
|
||||
}
|
||||
|
||||
public BattlegroundQueueTypeId BGQueueTypeId(BattlegroundTypeId bgTypeId, ArenaTypes arenaType)
|
||||
{
|
||||
switch (bgTypeId)
|
||||
{
|
||||
case BattlegroundTypeId.AB:
|
||||
return BattlegroundQueueTypeId.AB;
|
||||
case BattlegroundTypeId.AV:
|
||||
return BattlegroundQueueTypeId.AV;
|
||||
case BattlegroundTypeId.EY:
|
||||
return BattlegroundQueueTypeId.EY;
|
||||
case BattlegroundTypeId.IC:
|
||||
return BattlegroundQueueTypeId.IC;
|
||||
case BattlegroundTypeId.TP:
|
||||
return BattlegroundQueueTypeId.TP;
|
||||
case BattlegroundTypeId.BFG:
|
||||
return BattlegroundQueueTypeId.BFG;
|
||||
case BattlegroundTypeId.RB:
|
||||
return BattlegroundQueueTypeId.RB;
|
||||
case BattlegroundTypeId.SA:
|
||||
return BattlegroundQueueTypeId.SA;
|
||||
case BattlegroundTypeId.WS:
|
||||
return BattlegroundQueueTypeId.WS;
|
||||
case BattlegroundTypeId.AA:
|
||||
case BattlegroundTypeId.BE:
|
||||
case BattlegroundTypeId.DS:
|
||||
case BattlegroundTypeId.NA:
|
||||
case BattlegroundTypeId.RL:
|
||||
case BattlegroundTypeId.RV:
|
||||
switch (arenaType)
|
||||
{
|
||||
case ArenaTypes.Team2v2:
|
||||
return BattlegroundQueueTypeId.Arena2v2;
|
||||
case ArenaTypes.Team3v3:
|
||||
return BattlegroundQueueTypeId.Arena3v3;
|
||||
case ArenaTypes.Team5v5:
|
||||
return BattlegroundQueueTypeId.Arena5v5;
|
||||
default:
|
||||
return BattlegroundQueueTypeId.None;
|
||||
}
|
||||
default:
|
||||
return BattlegroundQueueTypeId.None;
|
||||
}
|
||||
}
|
||||
|
||||
public BattlegroundTypeId BGTemplateId(BattlegroundQueueTypeId bgQueueTypeId)
|
||||
{
|
||||
switch (bgQueueTypeId)
|
||||
{
|
||||
case BattlegroundQueueTypeId.WS:
|
||||
return BattlegroundTypeId.WS;
|
||||
case BattlegroundQueueTypeId.AB:
|
||||
return BattlegroundTypeId.AB;
|
||||
case BattlegroundQueueTypeId.AV:
|
||||
return BattlegroundTypeId.AV;
|
||||
case BattlegroundQueueTypeId.EY:
|
||||
return BattlegroundTypeId.EY;
|
||||
case BattlegroundQueueTypeId.SA:
|
||||
return BattlegroundTypeId.SA;
|
||||
case BattlegroundQueueTypeId.IC:
|
||||
return BattlegroundTypeId.IC;
|
||||
case BattlegroundQueueTypeId.TP:
|
||||
return BattlegroundTypeId.TP;
|
||||
case BattlegroundQueueTypeId.BFG:
|
||||
return BattlegroundTypeId.BFG;
|
||||
case BattlegroundQueueTypeId.RB:
|
||||
return BattlegroundTypeId.RB;
|
||||
case BattlegroundQueueTypeId.Arena2v2:
|
||||
case BattlegroundQueueTypeId.Arena3v3:
|
||||
case BattlegroundQueueTypeId.Arena5v5:
|
||||
return BattlegroundTypeId.AA;
|
||||
default:
|
||||
return 0; // used for unknown template (it existed and do nothing)
|
||||
}
|
||||
}
|
||||
|
||||
public ArenaTypes BGArenaType(BattlegroundQueueTypeId bgQueueTypeId)
|
||||
{
|
||||
switch (bgQueueTypeId)
|
||||
{
|
||||
case BattlegroundQueueTypeId.Arena2v2:
|
||||
return ArenaTypes.Team2v2;
|
||||
case BattlegroundQueueTypeId.Arena3v3:
|
||||
return ArenaTypes.Team3v3;
|
||||
case BattlegroundQueueTypeId.Arena5v5:
|
||||
return ArenaTypes.Team5v5;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleTesting()
|
||||
{
|
||||
m_Testing = !m_Testing;
|
||||
Global.WorldMgr.SendWorldText(m_Testing ? CypherStrings.DebugBgOn : CypherStrings.DebugBgOff);
|
||||
}
|
||||
|
||||
public void ToggleArenaTesting()
|
||||
{
|
||||
m_ArenaTesting = !m_ArenaTesting;
|
||||
Global.WorldMgr.SendWorldText(m_ArenaTesting ? CypherStrings.DebugArenaOn : CypherStrings.DebugArenaOff);
|
||||
}
|
||||
|
||||
public void SetHolidayWeekends(uint mask)
|
||||
{
|
||||
// The current code supports battlegrounds up to BattlegroundTypeId(31)
|
||||
for (var bgtype = 1; bgtype < (int)BattlegroundTypeId.Max && bgtype < 32; ++bgtype)
|
||||
{
|
||||
Battleground bg = GetBattlegroundTemplate((BattlegroundTypeId)bgtype);
|
||||
if (bg)
|
||||
bg.SetHoliday(Convert.ToBoolean(mask & (1 << bgtype)));
|
||||
}
|
||||
}
|
||||
|
||||
public void ScheduleQueueUpdate(uint arenaMatchmakerRating, ArenaTypes arenaType, BattlegroundQueueTypeId bgQueueTypeId, BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id)
|
||||
{
|
||||
//we will use only 1 number created of bgTypeId and bracket_id
|
||||
ulong scheduleId = ((ulong)arenaMatchmakerRating << 32) | ((uint)arenaType << 24) | ((uint)bgQueueTypeId << 16) | ((uint)bgTypeId << 8) | (uint)bracket_id;
|
||||
if (!m_QueueUpdateScheduler.Contains(scheduleId))
|
||||
m_QueueUpdateScheduler.Add(scheduleId);
|
||||
}
|
||||
|
||||
public uint GetMaxRatingDifference()
|
||||
{
|
||||
// this is for stupid people who can't use brain and set max rating difference to 0
|
||||
uint diff = WorldConfig.GetUIntValue(WorldCfg.ArenaMaxRatingDifference);
|
||||
if (diff == 0)
|
||||
diff = 5000;
|
||||
return diff;
|
||||
}
|
||||
|
||||
public uint GetRatingDiscardTimer()
|
||||
{
|
||||
return WorldConfig.GetUIntValue(WorldCfg.ArenaRatingDiscardTimer);
|
||||
}
|
||||
|
||||
public uint GetPrematureFinishTime()
|
||||
{
|
||||
return WorldConfig.GetUIntValue(WorldCfg.BattlegroundPrematureFinishTimer);
|
||||
}
|
||||
|
||||
public void LoadBattleMastersEntry()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
mBattleMastersMap.Clear(); // need for reload case
|
||||
|
||||
SQLResult result = DB.World.Query("SELECT entry, bg_template FROM battlemaster_entry");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 battlemaster entries. DB table `battlemaster_entry` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
uint count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
uint entry = result.Read<uint>(0);
|
||||
CreatureTemplate cInfo = Global.ObjectMgr.GetCreatureTemplate(entry);
|
||||
if (cInfo != null)
|
||||
{
|
||||
if (!cInfo.Npcflag.HasAnyFlag(NPCFlags.BattleMaster))
|
||||
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) listed in `battlemaster_entry` is not a battlemaster.", entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) listed in `battlemaster_entry` does not exist.", entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint bgTypeId = result.Read<uint>(1);
|
||||
if (!CliDB.BattlemasterListStorage.ContainsKey(bgTypeId))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Table `battlemaster_entry` contain entry {0} for not existed Battleground type {1}, ignored.", entry, bgTypeId);
|
||||
continue;
|
||||
}
|
||||
|
||||
++count;
|
||||
mBattleMastersMap[entry] = (BattlegroundTypeId)bgTypeId;
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
CheckBattleMasters();
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} battlemaster entries in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
void CheckBattleMasters()
|
||||
{
|
||||
var templates = Global.ObjectMgr.GetCreatureTemplates();
|
||||
foreach (var creature in templates)
|
||||
{
|
||||
if (creature.Value.Npcflag.HasAnyFlag(NPCFlags.BattleMaster) && !mBattleMastersMap.ContainsKey(creature.Value.Entry))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "CreatureTemplate (Entry: {0}) has UNIT_NPC_FLAG_BATTLEMASTER but no data in `battlemaster_entry` table. Removing flag!", creature.Value.Entry);
|
||||
templates[creature.Key].Npcflag &= ~NPCFlags.BattleMaster;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HolidayIds BGTypeToWeekendHolidayId(BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
switch (bgTypeId)
|
||||
{
|
||||
case BattlegroundTypeId.AV:
|
||||
return HolidayIds.CallToArmsAv;
|
||||
case BattlegroundTypeId.EY:
|
||||
return HolidayIds.CallToArmsEy;
|
||||
case BattlegroundTypeId.WS:
|
||||
return HolidayIds.CallToArmsWs;
|
||||
case BattlegroundTypeId.SA:
|
||||
return HolidayIds.CallToArmsSa;
|
||||
case BattlegroundTypeId.AB:
|
||||
return HolidayIds.CallToArmsAb;
|
||||
case BattlegroundTypeId.IC:
|
||||
return HolidayIds.CallToArmsIc;
|
||||
case BattlegroundTypeId.TP:
|
||||
return HolidayIds.CallToArmsTp;
|
||||
case BattlegroundTypeId.BFG:
|
||||
return HolidayIds.CallToArmsBfg;
|
||||
default:
|
||||
return HolidayIds.None;
|
||||
}
|
||||
}
|
||||
|
||||
public BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday)
|
||||
{
|
||||
switch (holiday)
|
||||
{
|
||||
case HolidayIds.CallToArmsAv:
|
||||
return BattlegroundTypeId.AV;
|
||||
case HolidayIds.CallToArmsEy:
|
||||
return BattlegroundTypeId.EY;
|
||||
case HolidayIds.CallToArmsWs:
|
||||
return BattlegroundTypeId.WS;
|
||||
case HolidayIds.CallToArmsSa:
|
||||
return BattlegroundTypeId.SA;
|
||||
case HolidayIds.CallToArmsAb:
|
||||
return BattlegroundTypeId.AB;
|
||||
case HolidayIds.CallToArmsIc:
|
||||
return BattlegroundTypeId.IC;
|
||||
case HolidayIds.CallToArmsTp:
|
||||
return BattlegroundTypeId.TP;
|
||||
case HolidayIds.CallToArmsBfg:
|
||||
return BattlegroundTypeId.BFG;
|
||||
default:
|
||||
return BattlegroundTypeId.None;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsBGWeekend(BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
return Global.GameEventMgr.IsHolidayActive(BGTypeToWeekendHolidayId(bgTypeId));
|
||||
}
|
||||
|
||||
BattlegroundTypeId GetRandomBG(BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
BattlegroundTemplate bgTemplate = GetBattlegroundTemplateByTypeId(bgTypeId);
|
||||
if (bgTemplate != null)
|
||||
{
|
||||
Dictionary<BattlegroundTypeId, float> selectionWeights = new Dictionary<BattlegroundTypeId, float>();
|
||||
|
||||
foreach (var mapId in bgTemplate.BattlemasterEntry.MapId)
|
||||
{
|
||||
if (mapId == -1)
|
||||
break;
|
||||
|
||||
BattlegroundTemplate bg = GetBattlegroundTemplateByMapId((uint)mapId);
|
||||
if (bg != null)
|
||||
{
|
||||
selectionWeights.Add(bg.Id, bg.Weight);
|
||||
}
|
||||
}
|
||||
|
||||
return selectionWeights.SelectRandomElementByWeight(i => i.Value).Key;
|
||||
}
|
||||
|
||||
return BattlegroundTypeId.None;
|
||||
}
|
||||
|
||||
public List<Battleground> GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId)
|
||||
{
|
||||
return bgDataStore[bgTypeId].BGFreeSlotQueue;
|
||||
}
|
||||
|
||||
public void AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground bg)
|
||||
{
|
||||
bgDataStore[bgTypeId].BGFreeSlotQueue.Insert(0, bg);
|
||||
}
|
||||
|
||||
public void RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint instanceId)
|
||||
{
|
||||
var queues = bgDataStore[bgTypeId].BGFreeSlotQueue;
|
||||
foreach (var bg in queues.ToList())
|
||||
{
|
||||
if (bg.GetInstanceID() == instanceId)
|
||||
{
|
||||
queues.Remove(bg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBattleground(Battleground bg)
|
||||
{
|
||||
if (bg)
|
||||
bgDataStore[bg.GetTypeID()].m_Battlegrounds[bg.GetInstanceID()] = bg;
|
||||
}
|
||||
|
||||
public void RemoveBattleground(BattlegroundTypeId bgTypeId, uint instanceId)
|
||||
{
|
||||
bgDataStore[bgTypeId].m_Battlegrounds.Remove(instanceId);
|
||||
}
|
||||
|
||||
public BattlegroundQueue GetBattlegroundQueue(BattlegroundQueueTypeId bgQueueTypeId) { return m_BattlegroundQueues[(int)bgQueueTypeId]; }
|
||||
|
||||
public bool isArenaTesting() { return m_ArenaTesting; }
|
||||
public bool isTesting() { return m_Testing; }
|
||||
|
||||
public BattlegroundTypeId GetBattleMasterBG(uint entry)
|
||||
{
|
||||
return mBattleMastersMap.LookupByKey(entry);
|
||||
}
|
||||
|
||||
BattlegroundTemplate GetBattlegroundTemplateByTypeId(BattlegroundTypeId id)
|
||||
{
|
||||
return _BattlegroundTemplates.LookupByKey(id);
|
||||
}
|
||||
|
||||
BattlegroundTemplate GetBattlegroundTemplateByMapId(uint mapId)
|
||||
{
|
||||
return _BattlegroundMapTemplates.LookupByKey(mapId);
|
||||
}
|
||||
|
||||
Dictionary<BattlegroundTypeId, BattlegroundData> bgDataStore = new Dictionary<BattlegroundTypeId, BattlegroundData>();
|
||||
BattlegroundQueue[] m_BattlegroundQueues = new BattlegroundQueue[(int)BattlegroundQueueTypeId.Max];
|
||||
Dictionary<uint, BattlegroundTypeId> mBattleMastersMap = new Dictionary<uint, BattlegroundTypeId>();
|
||||
Dictionary<BattlegroundTypeId, BattlegroundTemplate> _BattlegroundTemplates = new Dictionary<BattlegroundTypeId, BattlegroundTemplate>();
|
||||
Dictionary<uint, BattlegroundTemplate> _BattlegroundMapTemplates = new Dictionary<uint, BattlegroundTemplate>();
|
||||
List<ulong> m_QueueUpdateScheduler = new List<ulong>();
|
||||
uint m_NextRatedArenaUpdate;
|
||||
uint m_UpdateTimer;
|
||||
bool m_ArenaTesting;
|
||||
bool m_Testing;
|
||||
}
|
||||
|
||||
public class BattlegroundData
|
||||
{
|
||||
public BattlegroundData()
|
||||
{
|
||||
for (var i = 0; i < (int)BattlegroundBracketId.Max; ++i)
|
||||
m_ClientBattlegroundIds[i] = new List<uint>();
|
||||
}
|
||||
|
||||
public Dictionary<uint, Battleground> m_Battlegrounds = new Dictionary<uint, Battleground>();
|
||||
public List<uint>[] m_ClientBattlegroundIds = new List<uint>[(int)BattlegroundBracketId.Max];
|
||||
public List<Battleground> BGFreeSlotQueue = new List<Battleground>();
|
||||
public Battleground Template;
|
||||
}
|
||||
|
||||
class BattlegroundTemplate
|
||||
{
|
||||
public BattlegroundTypeId Id;
|
||||
public uint MinPlayersPerTeam;
|
||||
public uint MaxPlayersPerTeam;
|
||||
public uint MinLevel;
|
||||
public uint MaxLevel;
|
||||
public Position[] StartLocation = new Position[SharedConst.BGTeamsCount];
|
||||
public float StartMaxDist;
|
||||
public byte Weight;
|
||||
public uint scriptId;
|
||||
public BattlemasterListRecord BattlemasterEntry;
|
||||
|
||||
public bool IsArena() { return BattlemasterEntry.InstanceType == (uint)MapTypes.Arena; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System.Diagnostics.Contracts;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.BattleGrounds
|
||||
{
|
||||
public class BattlegroundScore
|
||||
{
|
||||
public BattlegroundScore(ObjectGuid playerGuid, Team team)
|
||||
{
|
||||
PlayerGuid = playerGuid;
|
||||
TeamId = (int)(team == Team.Alliance ? BattlegroundTeamId.Alliance : BattlegroundTeamId.Horde);
|
||||
}
|
||||
|
||||
public virtual void UpdateScore(ScoreType type, uint value)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ScoreType.KillingBlows:
|
||||
KillingBlows += value;
|
||||
break;
|
||||
case ScoreType.Deaths:
|
||||
Deaths += value;
|
||||
break;
|
||||
case ScoreType.HonorableKills:
|
||||
HonorableKills += value;
|
||||
break;
|
||||
case ScoreType.BonusHonor:
|
||||
BonusHonor += value;
|
||||
break;
|
||||
case ScoreType.DamageDone:
|
||||
DamageDone += value;
|
||||
break;
|
||||
case ScoreType.HealingDone:
|
||||
HealingDone += value;
|
||||
break;
|
||||
default:
|
||||
Contract.Assert(false, "Not implemented Battleground score type!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void BuildPvPLogPlayerDataPacket(out PVPLogData.PlayerData playerData)
|
||||
{
|
||||
playerData = new PVPLogData.PlayerData();
|
||||
playerData.PlayerGUID = PlayerGuid;
|
||||
playerData.Kills = KillingBlows;
|
||||
playerData.Faction = (byte)TeamId;
|
||||
if (HonorableKills != 0 || Deaths != 0 || BonusHonor != 0)
|
||||
{
|
||||
playerData.Honor.HasValue = true;
|
||||
playerData.Honor.Value.HonorKills = HonorableKills;
|
||||
playerData.Honor.Value.Deaths = Deaths;
|
||||
playerData.Honor.Value.ContributionPoints = BonusHonor;
|
||||
}
|
||||
|
||||
playerData.DamageDone = DamageDone;
|
||||
playerData.HealingDone = HealingDone;
|
||||
}
|
||||
|
||||
public virtual uint GetAttr1() { return 0; }
|
||||
public virtual uint GetAttr2() { return 0; }
|
||||
public virtual uint GetAttr3() { return 0; }
|
||||
public virtual uint GetAttr4() { return 0; }
|
||||
public virtual uint GetAttr5() { return 0; }
|
||||
|
||||
public ObjectGuid PlayerGuid;
|
||||
public int TeamId;
|
||||
|
||||
// Default score, present in every type
|
||||
public uint KillingBlows;
|
||||
public uint Deaths;
|
||||
public uint HonorableKills;
|
||||
public uint BonusHonor;
|
||||
public uint DamageDone;
|
||||
public uint HealingDone;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.BattleGrounds.Zones
|
||||
{
|
||||
class AlteracValley
|
||||
{
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.BattleGrounds.Zones
|
||||
{
|
||||
class BattleforGilneas
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.BattleGrounds.Zones
|
||||
{
|
||||
class DeepwindGorge
|
||||
{
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.BattleGrounds.Zones
|
||||
{
|
||||
class IsleofConquest
|
||||
{
|
||||
}
|
||||
|
||||
public struct ICCreatures
|
||||
{
|
||||
public const uint HighCommanderHalfordWyrmbane = 34924; // Alliance Boss
|
||||
public const uint OverlordAgmar = 34922; // Horde Boss
|
||||
public const uint KorKronGuard = 34918; // Horde Guard
|
||||
public const uint SevenThLegionInfantry = 34919; // Alliance Guard
|
||||
public const uint KeepCannon = 34944;
|
||||
public const uint Demolisher = 34775;
|
||||
public const uint SiegeEngineH = 35069;
|
||||
public const uint SiegeEngineA = 34776;
|
||||
public const uint GlaiveThrowerA = 34802;
|
||||
public const uint GlaiveThrowerH = 35273;
|
||||
public const uint Catapult = 34793;
|
||||
public const uint HordeGunshipCannon = 34935;
|
||||
public const uint AllianceGunshipCannon = 34929;
|
||||
public const uint HordeGunshipCaptain = 35003;
|
||||
public const uint AllianceGunshipCaptain = 34960;
|
||||
public const uint WorldTriggerNotFloating = 34984;
|
||||
public const uint WorldTriggerAllianceFriendly = 20213;
|
||||
public const uint WorldTriggerHordeFriendly = 20212;
|
||||
}
|
||||
|
||||
public struct ICSpells
|
||||
{
|
||||
public const uint OilRefinery = 68719;
|
||||
public const uint Quarry = 68720;
|
||||
public const uint Parachute = 66656;
|
||||
public const uint SlowFall = 12438;
|
||||
public const uint DestroyedVehicleAchievement = 68357;
|
||||
public const uint BackDoorJobAchievement = 68502;
|
||||
public const uint DrivingCreditDemolisher = 68365;
|
||||
public const uint DrivingCreditGlaive = 68363;
|
||||
public const uint DrivingCreditSiege = 68364;
|
||||
public const uint DrivingCreditCatapult = 68362;
|
||||
public const uint SimpleTeleport = 12980;
|
||||
public const uint TeleportVisualOnly = 51347;
|
||||
public const uint ParachuteIc = 66657;
|
||||
public const uint LaunchNoFallingDamage = 66251;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.BattleGrounds.Zones
|
||||
{
|
||||
class SilvershardMines
|
||||
{
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.BattleGrounds.Zones
|
||||
{
|
||||
class TempleofKotmogu
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Game.BattleGrounds.Zones
|
||||
{
|
||||
class TwinPeaks
|
||||
{
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.BattlePets
|
||||
{
|
||||
public class BattlePetMgr
|
||||
{
|
||||
public BattlePetMgr(WorldSession owner)
|
||||
{
|
||||
_owner = owner;
|
||||
for (byte i = 0; i < SharedConst.MaxPetBattleSlots; ++i)
|
||||
{
|
||||
BattlePetSlot slot = new BattlePetSlot();
|
||||
slot.Index = i;
|
||||
_slots.Add(slot);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
SQLResult result = DB.Login.Query("SELECT MAX(guid) FROM battle_pets");
|
||||
if (!result.IsEmpty())
|
||||
Global.ObjectMgr.GetGenerator(HighGuid.BattlePet).Set(result.Read<ulong>(0) + 1);
|
||||
|
||||
foreach (var breedState in CliDB.BattlePetBreedStateStorage.Values)
|
||||
{
|
||||
if (!_battlePetBreedStates.ContainsKey(breedState.BreedID))
|
||||
_battlePetBreedStates[breedState.BreedID] = new Dictionary<BattlePetState, int>();
|
||||
|
||||
_battlePetBreedStates[breedState.BreedID][(BattlePetState)breedState.State] = breedState.Value;
|
||||
}
|
||||
|
||||
foreach (var speciesState in CliDB.BattlePetSpeciesStateStorage.Values)
|
||||
{
|
||||
if (!_battlePetSpeciesStates.ContainsKey(speciesState.SpeciesID))
|
||||
_battlePetSpeciesStates[speciesState.SpeciesID] = new Dictionary<BattlePetState, int>();
|
||||
|
||||
_battlePetSpeciesStates[speciesState.SpeciesID][(BattlePetState)speciesState.State] = speciesState.Value;
|
||||
}
|
||||
|
||||
LoadAvailablePetBreeds();
|
||||
LoadDefaultPetQualities();
|
||||
}
|
||||
|
||||
static void LoadAvailablePetBreeds()
|
||||
{
|
||||
SQLResult result = DB.World.Query("SELECT speciesId, breedId FROM battle_pet_breeds");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 battle pet breeds. DB table `battle_pet_breeds` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint count = 0;
|
||||
do
|
||||
{
|
||||
uint speciesId = result.Read<uint>(0);
|
||||
ushort breedId = result.Read<ushort>(1);
|
||||
|
||||
if (!CliDB.BattlePetSpeciesStorage.ContainsKey(speciesId))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Non-existing BattlePetSpecies.db2 entry {0} was referenced in `battle_pet_breeds` by row ({1}, {2}).", speciesId, speciesId, breedId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: verify breed id (3 - 12 (male) or 3 - 22 (male and female)) if needed
|
||||
|
||||
_availableBreedsPerSpecies.Add(speciesId, (byte)breedId);
|
||||
++count;
|
||||
} while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} battle pet breeds.", count);
|
||||
}
|
||||
|
||||
static void LoadDefaultPetQualities()
|
||||
{
|
||||
SQLResult result = DB.World.Query("SELECT speciesId, quality FROM battle_pet_quality");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 battle pet qualities. DB table `battle_pet_quality` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
uint speciesId = result.Read<uint>(0);
|
||||
byte quality = result.Read<byte>(1);
|
||||
|
||||
if (!CliDB.BattlePetSpeciesStorage.ContainsKey(speciesId))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Non-existing BattlePetSpecies.db2 entry {0} was referenced in `battle_pet_quality` by row ({1}, {2}).", speciesId, speciesId, quality);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: verify quality (0 - 3 for player pets or 0 - 5 for both player and tamer pets) if needed
|
||||
|
||||
_defaultQualityPerSpecies[speciesId] = quality;
|
||||
} while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} battle pet qualities.", _defaultQualityPerSpecies.Count);
|
||||
}
|
||||
|
||||
public static ushort RollPetBreed(uint species)
|
||||
{
|
||||
var list = _availableBreedsPerSpecies.LookupByKey(species);
|
||||
if (list.Empty())
|
||||
return 3; // default B/B
|
||||
|
||||
return list.SelectRandom();
|
||||
}
|
||||
|
||||
public static byte GetDefaultPetQuality(uint species)
|
||||
{
|
||||
if (!_defaultQualityPerSpecies.ContainsKey(species))
|
||||
return 0; // default poor
|
||||
|
||||
return _defaultQualityPerSpecies[species];
|
||||
}
|
||||
|
||||
public void LoadFromDB(SQLResult petsResult, SQLResult slotsResult)
|
||||
{
|
||||
if (!petsResult.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
uint species = petsResult.Read<uint>(1);
|
||||
|
||||
BattlePetSpeciesRecord speciesEntry = CliDB.BattlePetSpeciesStorage.LookupByKey(species);
|
||||
if (speciesEntry != null)
|
||||
{
|
||||
if (GetPetCount(species) >= SharedConst.MaxBattlePetsPerSpecies)
|
||||
{
|
||||
Log.outError(LogFilter.Misc, "Battlenet account with id {0} has more than 3 battle pets of species {1}", _owner.GetBattlenetAccountId(), species);
|
||||
continue;
|
||||
}
|
||||
|
||||
BattlePet pet = new BattlePet();
|
||||
pet.PacketInfo.Guid = ObjectGuid.Create(HighGuid.BattlePet, petsResult.Read<ulong>(0));
|
||||
pet.PacketInfo.Species = species;
|
||||
pet.PacketInfo.Breed = petsResult.Read<ushort>(2);
|
||||
pet.PacketInfo.Level = petsResult.Read<ushort>(3);
|
||||
pet.PacketInfo.Exp = petsResult.Read<ushort>(4);
|
||||
pet.PacketInfo.Health = petsResult.Read<uint>(5);
|
||||
pet.PacketInfo.Quality = petsResult.Read<byte>(6);
|
||||
pet.PacketInfo.Flags = petsResult.Read<ushort>(7);
|
||||
pet.PacketInfo.Name = petsResult.Read<string>(8);
|
||||
pet.PacketInfo.CreatureID = speciesEntry.CreatureID;
|
||||
pet.SaveInfo = BattlePetSaveInfo.Unchanged;
|
||||
pet.CalculateStats();
|
||||
_pets[pet.PacketInfo.Guid.GetCounter()] = pet;
|
||||
}
|
||||
} while (petsResult.NextRow());
|
||||
}
|
||||
|
||||
if (!slotsResult.IsEmpty())
|
||||
{
|
||||
byte i = 0; // slots.GetRowCount() should equal MAX_BATTLE_PET_SLOTS
|
||||
|
||||
do
|
||||
{
|
||||
_slots[i].Index = slotsResult.Read<byte>(0);
|
||||
var battlePet = _pets.LookupByKey(slotsResult.Read<ulong>(1));
|
||||
if (battlePet != null)
|
||||
_slots[i].Pet = battlePet.PacketInfo;
|
||||
_slots[i].Locked = slotsResult.Read<bool>(2);
|
||||
i++;
|
||||
} while (slotsResult.NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveToDB(SQLTransaction trans)
|
||||
{
|
||||
PreparedStatement stmt;
|
||||
|
||||
foreach (var pair in _pets.ToList())
|
||||
{
|
||||
switch (pair.Value.SaveInfo)
|
||||
{
|
||||
case BattlePetSaveInfo.New:
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BATTLE_PETS);
|
||||
stmt.AddValue(0, pair.Key);
|
||||
stmt.AddValue(1, _owner.GetBattlenetAccountId());
|
||||
stmt.AddValue(2, pair.Value.PacketInfo.Species);
|
||||
stmt.AddValue(3, pair.Value.PacketInfo.Breed);
|
||||
stmt.AddValue(4, pair.Value.PacketInfo.Level);
|
||||
stmt.AddValue(5, pair.Value.PacketInfo.Exp);
|
||||
stmt.AddValue(6, pair.Value.PacketInfo.Health);
|
||||
stmt.AddValue(7, pair.Value.PacketInfo.Quality);
|
||||
stmt.AddValue(8, pair.Value.PacketInfo.Flags);
|
||||
stmt.AddValue(9, pair.Value.PacketInfo.Name);
|
||||
trans.Append(stmt);
|
||||
pair.Value.SaveInfo = BattlePetSaveInfo.Unchanged;
|
||||
break;
|
||||
case BattlePetSaveInfo.Changed:
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BATTLE_PETS);
|
||||
stmt.AddValue(0, pair.Value.PacketInfo.Level);
|
||||
stmt.AddValue(1, pair.Value.PacketInfo.Exp);
|
||||
stmt.AddValue(2, pair.Value.PacketInfo.Health);
|
||||
stmt.AddValue(3, pair.Value.PacketInfo.Quality);
|
||||
stmt.AddValue(4, pair.Value.PacketInfo.Flags);
|
||||
stmt.AddValue(5, pair.Value.PacketInfo.Name);
|
||||
stmt.AddValue(6, _owner.GetBattlenetAccountId());
|
||||
stmt.AddValue(7, pair.Key);
|
||||
trans.Append(stmt);
|
||||
pair.Value.SaveInfo = BattlePetSaveInfo.Unchanged;
|
||||
break;
|
||||
case BattlePetSaveInfo.Removed:
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_BATTLE_PETS);
|
||||
stmt.AddValue(0, _owner.GetBattlenetAccountId());
|
||||
stmt.AddValue(1, pair.Key);
|
||||
trans.Append(stmt);
|
||||
_pets.Remove(pair.Key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_BATTLE_PET_SLOTS);
|
||||
stmt.AddValue(0, _owner.GetBattlenetAccountId());
|
||||
trans.Append(stmt);
|
||||
|
||||
foreach (var slot in _slots)
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BATTLE_PET_SLOTS);
|
||||
stmt.AddValue(0, slot.Index);
|
||||
stmt.AddValue(1, _owner.GetBattlenetAccountId());
|
||||
stmt.AddValue(2, slot.Pet.Guid.GetCounter());
|
||||
stmt.AddValue(3, slot.Locked);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
public BattlePet GetPet(ObjectGuid guid)
|
||||
{
|
||||
return _pets.LookupByKey(guid.GetCounter());
|
||||
}
|
||||
|
||||
public void AddPet(uint species, uint creatureId, ushort level = 1)
|
||||
{
|
||||
ushort breed = 3;// default B/B
|
||||
byte quality = 0;
|
||||
|
||||
if (_availableBreedsPerSpecies.ContainsKey(species))
|
||||
breed = _availableBreedsPerSpecies[species].SelectRandom();
|
||||
|
||||
if (_defaultQualityPerSpecies.ContainsKey(species))
|
||||
quality = _defaultQualityPerSpecies[species];
|
||||
|
||||
AddPet(species, creatureId, breed, quality, level);
|
||||
}
|
||||
|
||||
public void AddPet(uint species, uint creatureId, ushort breed, byte quality, ushort level = 1)
|
||||
{
|
||||
BattlePetSpeciesRecord battlePetSpecies = CliDB.BattlePetSpeciesStorage.LookupByKey(species);
|
||||
if (battlePetSpecies == null) // should never happen
|
||||
return;
|
||||
|
||||
BattlePet pet = new BattlePet();
|
||||
pet.PacketInfo.Guid = ObjectGuid.Create(HighGuid.BattlePet, Global.ObjectMgr.GetGenerator(HighGuid.BattlePet).Generate());
|
||||
pet.PacketInfo.Species = species;
|
||||
pet.PacketInfo.CreatureID = creatureId;
|
||||
pet.PacketInfo.Level = level;
|
||||
pet.PacketInfo.Exp = 0;
|
||||
pet.PacketInfo.Flags = 0;
|
||||
pet.PacketInfo.Breed = breed;
|
||||
pet.PacketInfo.Quality = quality;
|
||||
pet.PacketInfo.Name = "";
|
||||
pet.CalculateStats();
|
||||
pet.PacketInfo.Health = pet.PacketInfo.MaxHealth;
|
||||
pet.SaveInfo = BattlePetSaveInfo.New;
|
||||
|
||||
_pets[pet.PacketInfo.Guid.GetCounter()] = pet;
|
||||
|
||||
List<BattlePet> updates = new List<BattlePet>();
|
||||
updates.Add(pet);
|
||||
SendUpdates(updates, true);
|
||||
|
||||
_owner.GetPlayer().UpdateCriteria(CriteriaTypes.OwnBattlePet, species);
|
||||
}
|
||||
|
||||
public void RemovePet(ObjectGuid guid)
|
||||
{
|
||||
BattlePet pet = GetPet(guid);
|
||||
if (pet == null)
|
||||
return;
|
||||
|
||||
pet.SaveInfo = BattlePetSaveInfo.Removed;
|
||||
|
||||
// spell is not unlearned on retail
|
||||
/*if (GetPetCount(pet.PacketInfo.Species) == 0)
|
||||
if (BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(pet.PacketInfo.Species))
|
||||
_owner.GetPlayer().RemoveSpell(speciesEntry.SummonSpellID);*/
|
||||
}
|
||||
|
||||
public byte GetPetCount(uint species)
|
||||
{
|
||||
return (byte)_pets.Values.Count(battlePet => battlePet.PacketInfo.Species == species && battlePet.SaveInfo != BattlePetSaveInfo.Removed);
|
||||
}
|
||||
|
||||
public void UnlockSlot(byte slot)
|
||||
{
|
||||
if (!_slots[slot].Locked)
|
||||
return;
|
||||
|
||||
_slots[slot].Locked = false;
|
||||
|
||||
PetBattleSlotUpdates updates = new PetBattleSlotUpdates();
|
||||
updates.Slots.Add(_slots[slot]);
|
||||
updates.AutoSlotted = false; // what's this?
|
||||
updates.NewSlot = true; // causes the "new slot unlocked" bubble to appear
|
||||
_owner.SendPacket(updates);
|
||||
}
|
||||
|
||||
public List<BattlePet> GetLearnedPets()
|
||||
{
|
||||
return _pets.Values.Where(p => p.SaveInfo != BattlePetSaveInfo.Removed).ToList();
|
||||
}
|
||||
|
||||
public void CageBattlePet(ObjectGuid guid)
|
||||
{
|
||||
BattlePet pet = GetPet(guid);
|
||||
if (pet == null)
|
||||
return;
|
||||
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
|
||||
if (_owner.GetPlayer().CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, SharedConst.BattlePetCageItemId, 1) != InventoryResult.Ok)
|
||||
return;
|
||||
|
||||
Item item = _owner.GetPlayer().StoreNewItem(dest, SharedConst.BattlePetCageItemId, true);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
item.SetModifier(ItemModifier.BattlePetSpeciesId, pet.PacketInfo.Species);
|
||||
item.SetModifier(ItemModifier.BattlePetBreedData, (uint)(pet.PacketInfo.Breed | (pet.PacketInfo.Quality << 24)));
|
||||
item.SetModifier(ItemModifier.BattlePetLevel, pet.PacketInfo.Level);
|
||||
item.SetModifier(ItemModifier.BattlePetDisplayId, pet.PacketInfo.CreatureID);
|
||||
|
||||
// FIXME: "You create: ." - item name missing in chat
|
||||
_owner.GetPlayer().SendNewItem(item, 1, true, true);
|
||||
|
||||
RemovePet(guid);
|
||||
|
||||
BattlePetDeleted deletePet = new BattlePetDeleted();
|
||||
deletePet.PetGuid = guid;
|
||||
_owner.SendPacket(deletePet);
|
||||
}
|
||||
|
||||
public void HealBattlePetsPct(byte pct)
|
||||
{
|
||||
// TODO: After each Pet Battle, any injured companion will automatically
|
||||
// regain 50 % of the damage that was taken during combat
|
||||
List<BattlePet> updates = new List<BattlePet>();
|
||||
|
||||
foreach (var pet in _pets.Values)
|
||||
{
|
||||
if (pet.PacketInfo.Health != pet.PacketInfo.MaxHealth)
|
||||
{
|
||||
pet.PacketInfo.Health += MathFunctions.CalculatePct(pet.PacketInfo.MaxHealth, pct);
|
||||
// don't allow Health to be greater than MaxHealth
|
||||
pet.PacketInfo.Health = Math.Min(pet.PacketInfo.Health, pet.PacketInfo.MaxHealth);
|
||||
if (pet.SaveInfo != BattlePetSaveInfo.New)
|
||||
pet.SaveInfo = BattlePetSaveInfo.Changed;
|
||||
updates.Add(pet);
|
||||
}
|
||||
}
|
||||
|
||||
SendUpdates(updates, false);
|
||||
}
|
||||
|
||||
public void SummonPet(ObjectGuid guid)
|
||||
{
|
||||
BattlePet pet = GetPet(guid);
|
||||
if (pet == null)
|
||||
return;
|
||||
|
||||
BattlePetSpeciesRecord speciesEntry = CliDB.BattlePetSpeciesStorage.LookupByKey(pet.PacketInfo.Species);
|
||||
if (speciesEntry == null)
|
||||
return;
|
||||
|
||||
// TODO: set proper CreatureID for spell DEFAULT_SUMMON_BATTLE_PET_SPELL (default EffectMiscValueA is 40721 - Murkimus the Gladiator)
|
||||
_owner.GetPlayer().CastSpell(_owner.GetPlayer(), speciesEntry.SummonSpellID != 0 ? speciesEntry.SummonSpellID : SharedConst.DefaultSummonBattlePetSpell);
|
||||
|
||||
// TODO: set pet level, quality... update fields
|
||||
}
|
||||
|
||||
void SendUpdates(List<BattlePet> pets, bool petAdded)
|
||||
{
|
||||
BattlePetUpdates updates = new BattlePetUpdates();
|
||||
foreach (var pet in pets)
|
||||
updates.Pets.Add(pet.PacketInfo);
|
||||
|
||||
updates.PetAdded = petAdded;
|
||||
_owner.SendPacket(updates);
|
||||
}
|
||||
|
||||
public void SendError(BattlePetError error, uint creatureId)
|
||||
{
|
||||
BattlePetErrorPacket battlePetError = new BattlePetErrorPacket();
|
||||
battlePetError.Result = error;
|
||||
battlePetError.CreatureID = creatureId;
|
||||
_owner.SendPacket(battlePetError);
|
||||
}
|
||||
|
||||
public BattlePetSlot GetSlot(byte slot) { return _slots[slot]; }
|
||||
WorldSession GetOwner() { return _owner; }
|
||||
|
||||
public ushort GetTrapLevel() { return _trapLevel; }
|
||||
public List<BattlePetSlot> GetSlots() { return _slots; }
|
||||
|
||||
WorldSession _owner;
|
||||
ushort _trapLevel;
|
||||
Dictionary<ulong, BattlePet> _pets = new Dictionary<ulong, BattlePet>();
|
||||
List<BattlePetSlot> _slots = new List<BattlePetSlot>();
|
||||
|
||||
static Dictionary<uint, Dictionary<BattlePetState, int>> _battlePetBreedStates = new Dictionary<uint, Dictionary<BattlePetState, int>>();
|
||||
static Dictionary<uint, Dictionary<BattlePetState, int>> _battlePetSpeciesStates = new Dictionary<uint, Dictionary<BattlePetState, int>>();
|
||||
static MultiMap<uint, byte> _availableBreedsPerSpecies = new MultiMap<uint, byte>();
|
||||
static Dictionary<uint, byte> _defaultQualityPerSpecies = new Dictionary<uint, byte>();
|
||||
|
||||
public class BattlePet
|
||||
{
|
||||
public void CalculateStats()
|
||||
{
|
||||
float health = 0.0f;
|
||||
float power = 0.0f;
|
||||
float speed = 0.0f;
|
||||
|
||||
// get base breed stats
|
||||
var breedState = _battlePetBreedStates.LookupByKey(PacketInfo.Breed);
|
||||
if (breedState == null) // non existing breed id
|
||||
return;
|
||||
|
||||
health = breedState[BattlePetState.StatStamina];
|
||||
power = breedState[BattlePetState.StatPower];
|
||||
speed = breedState[BattlePetState.StatSpeed];
|
||||
|
||||
// modify stats depending on species - not all pets have this
|
||||
var speciesState = _battlePetSpeciesStates.LookupByKey(PacketInfo.Species);
|
||||
if (speciesState != null)
|
||||
{
|
||||
health += speciesState[BattlePetState.StatStamina];
|
||||
power += speciesState[BattlePetState.StatPower];
|
||||
speed += speciesState[BattlePetState.StatSpeed];
|
||||
}
|
||||
|
||||
// modify stats by quality
|
||||
foreach (var breedQualityRecord in CliDB.BattlePetBreedQualityStorage.Values)
|
||||
{
|
||||
if (breedQualityRecord.Quality == PacketInfo.Quality)
|
||||
{
|
||||
health *= breedQualityRecord.Modifier;
|
||||
power *= breedQualityRecord.Modifier;
|
||||
speed *= breedQualityRecord.Modifier;
|
||||
break;
|
||||
}
|
||||
// TOOD: add check if pet has existing quality
|
||||
}
|
||||
|
||||
// scale stats depending on level
|
||||
health *= PacketInfo.Level;
|
||||
power *= PacketInfo.Level;
|
||||
speed *= PacketInfo.Level;
|
||||
|
||||
// set stats
|
||||
// round, ceil or floor? verify this
|
||||
PacketInfo.MaxHealth = (uint)((Math.Round(health / 20) + 100));
|
||||
PacketInfo.Power = (uint)(Math.Round(power / 100));
|
||||
PacketInfo.Speed = (uint)(Math.Round(speed / 100));
|
||||
}
|
||||
|
||||
public BattlePetStruct PacketInfo;
|
||||
public BattlePetSaveInfo SaveInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Collections;
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.BlackMarket
|
||||
{
|
||||
public class BlackMarketTemplate
|
||||
{
|
||||
public bool LoadFromDB(SQLFields fields)
|
||||
{
|
||||
MarketID = fields.Read<uint>(0);
|
||||
SellerNPC = fields.Read<uint>(1);
|
||||
Item.ItemID = fields.Read<uint>(2);
|
||||
Quantity = fields.Read<uint>(3);
|
||||
MinBid = fields.Read<ulong>(4);
|
||||
Duration = fields.Read<uint>(5);
|
||||
Chance = fields.Read<float>(6);
|
||||
|
||||
var bonusListIDsTok = new StringArray(fields.Read<string>(7), ' ');
|
||||
List<uint> bonusListIDs = new List<uint>();
|
||||
foreach (string token in bonusListIDsTok)
|
||||
bonusListIDs.Add(uint.Parse(token));
|
||||
|
||||
if (!bonusListIDs.Empty())
|
||||
{
|
||||
Item.ItemBonus.HasValue = true;
|
||||
Item.ItemBonus.Value.BonusListIDs = bonusListIDs;
|
||||
}
|
||||
|
||||
if (Global.ObjectMgr.GetCreatureTemplate(SellerNPC) == null)
|
||||
{
|
||||
Log.outError(LogFilter.Misc, "Black market template {0} does not have a valid seller. (Entry: {1})", MarketID, SellerNPC);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Global.ObjectMgr.GetItemTemplate(Item.ItemID) == null)
|
||||
{
|
||||
Log.outError(LogFilter.Misc, "Black market template {0} does not have a valid item. (Entry: {1})", MarketID, Item.ItemID);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public uint MarketID;
|
||||
public uint SellerNPC;
|
||||
public uint Quantity;
|
||||
public ulong MinBid;
|
||||
public long Duration;
|
||||
public float Chance;
|
||||
public ItemInstance Item;
|
||||
}
|
||||
|
||||
public class BlackMarketEntry
|
||||
{
|
||||
public void Initialize(uint marketId, uint duration)
|
||||
{
|
||||
_marketId = marketId;
|
||||
_secondsRemaining = duration;
|
||||
}
|
||||
|
||||
public void Update(long newTimeOfUpdate)
|
||||
{
|
||||
_secondsRemaining = (uint)(_secondsRemaining - (newTimeOfUpdate - Global.BlackMarketMgr.GetLastUpdate()));
|
||||
}
|
||||
|
||||
public BlackMarketTemplate GetTemplate()
|
||||
{
|
||||
return Global.BlackMarketMgr.GetTemplateByID(_marketId);
|
||||
}
|
||||
|
||||
public uint GetSecondsRemaining()
|
||||
{
|
||||
return (uint)(_secondsRemaining - (Time.UnixTime - Global.BlackMarketMgr.GetLastUpdate()));
|
||||
}
|
||||
|
||||
long GetExpirationTime()
|
||||
{
|
||||
return Time.UnixTime + GetSecondsRemaining();
|
||||
}
|
||||
|
||||
public bool IsCompleted()
|
||||
{
|
||||
return GetSecondsRemaining() <= 0;
|
||||
}
|
||||
|
||||
public bool LoadFromDB(SQLFields fields)
|
||||
{
|
||||
_marketId = fields.Read<uint>(0);
|
||||
|
||||
// Invalid MarketID
|
||||
BlackMarketTemplate templ = Global.BlackMarketMgr.GetTemplateByID(_marketId);
|
||||
if (templ == null)
|
||||
{
|
||||
Log.outError(LogFilter.Misc, "Black market auction {0} does not have a valid id.", _marketId);
|
||||
return false;
|
||||
}
|
||||
|
||||
_currentBid = fields.Read<ulong>(1);
|
||||
_secondsRemaining = (uint)(fields.Read<uint>(2) - Global.BlackMarketMgr.GetLastUpdate());
|
||||
_numBids = fields.Read<uint>(3);
|
||||
_bidder = fields.Read<ulong>(4);
|
||||
|
||||
// Either no bidder or existing player
|
||||
if (_bidder != 0 && ObjectManager.GetPlayerAccountIdByGUID(ObjectGuid.Create(HighGuid.Player, _bidder)) == 0) // Probably a better way to check if player exists
|
||||
{
|
||||
Log.outError(LogFilter.Misc, "Black market auction {0} does not have a valid bidder (GUID: {1}).", _marketId, _bidder);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SaveToDB(SQLTransaction trans)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_BLACKMARKET_AUCTIONS);
|
||||
|
||||
stmt.AddValue(0, _marketId);
|
||||
stmt.AddValue(1, _currentBid);
|
||||
stmt.AddValue(2, GetExpirationTime());
|
||||
stmt.AddValue(3, _numBids);
|
||||
stmt.AddValue(4, _bidder);
|
||||
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
public void DeleteFromDB(SQLTransaction trans)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_BLACKMARKET_AUCTIONS);
|
||||
stmt.AddValue(0, _marketId);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
public bool ValidateBid(ulong bid)
|
||||
{
|
||||
if (bid <= _currentBid)
|
||||
return false;
|
||||
|
||||
if (bid < _currentBid + GetMinIncrement())
|
||||
return false;
|
||||
|
||||
if (bid >= BlackMarketConst.MaxBid)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void PlaceBid(ulong bid, Player player, SQLTransaction trans) //Updated
|
||||
{
|
||||
if (bid < _currentBid)
|
||||
return;
|
||||
|
||||
_currentBid = bid;
|
||||
++_numBids;
|
||||
|
||||
if (GetSecondsRemaining() < 30 * Time.Minute)
|
||||
_secondsRemaining += 30 * Time.Minute;
|
||||
|
||||
_bidder = player.GetGUID().GetCounter();
|
||||
|
||||
player.ModifyMoney(-(long)bid);
|
||||
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_BLACKMARKET_AUCTIONS);
|
||||
|
||||
stmt.AddValue(0, _currentBid);
|
||||
stmt.AddValue(1, GetExpirationTime());
|
||||
stmt.AddValue(2, _numBids);
|
||||
stmt.AddValue(3, _bidder);
|
||||
stmt.AddValue(4, _marketId);
|
||||
|
||||
trans.Append(stmt);
|
||||
|
||||
Global.BlackMarketMgr.Update(true);
|
||||
}
|
||||
|
||||
public string BuildAuctionMailSubject(BMAHMailAuctionAnswers response)
|
||||
{
|
||||
return GetTemplate().Item.ItemID + ":0:" + response + ':' + GetMarketId() + ':' + GetTemplate().Quantity;
|
||||
}
|
||||
|
||||
public string BuildAuctionMailBody()
|
||||
{
|
||||
return GetTemplate().SellerNPC + ":" + _currentBid;
|
||||
}
|
||||
|
||||
|
||||
public uint GetMarketId() { return _marketId; }
|
||||
|
||||
public ulong GetCurrentBid() { return _currentBid; }
|
||||
void SetCurrentBid(ulong bid) { _currentBid = bid; }
|
||||
|
||||
public uint GetNumBids() { return _numBids; }
|
||||
void SetNumBids(uint numBids) { _numBids = numBids; }
|
||||
|
||||
public ulong GetBidder() { return _bidder; }
|
||||
void SetBidder(ulong bidder) { _bidder = bidder; }
|
||||
|
||||
public ulong GetMinIncrement() { return (_currentBid / 20) - ((_currentBid / 20) % MoneyConstants.Gold); } //5% increase every bid (has to be round gold value)
|
||||
|
||||
public void MailSent() { _mailSent = true; } // Set when mail has been sent
|
||||
public bool GetMailSent() { return _mailSent; }
|
||||
|
||||
uint _marketId;
|
||||
ulong _currentBid;
|
||||
uint _numBids;
|
||||
ulong _bidder;
|
||||
uint _secondsRemaining;
|
||||
bool _mailSent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Mails;
|
||||
using Game.Network.Packets;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.BlackMarket
|
||||
{
|
||||
public class BlackMarketManager : Singleton<BlackMarketManager>
|
||||
{
|
||||
BlackMarketManager() { }
|
||||
|
||||
public void LoadTemplates()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
// Clear in case we are reloading
|
||||
_templates.Clear();
|
||||
|
||||
SQLResult result = DB.World.Query("SELECT marketId, sellerNpc, itemEntry, quantity, minBid, duration, chance, bonusListIDs FROM blackmarket_template");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 black market templates. DB table `blackmarket_template` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
BlackMarketTemplate templ = new BlackMarketTemplate();
|
||||
|
||||
if (!templ.LoadFromDB(result.GetFields())) // Add checks
|
||||
continue;
|
||||
|
||||
AddTemplate(templ);
|
||||
} while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} black market templates in {1} ms.", _templates.Count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public void LoadAuctions()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
// Clear in case we are reloading
|
||||
_auctions.Clear();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_BLACKMARKET_AUCTIONS);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 black market auctions. DB table `blackmarket_auctions` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
_lastUpdate = Time.UnixTime; //Set update time before loading
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
do
|
||||
{
|
||||
BlackMarketEntry auction = new BlackMarketEntry();
|
||||
|
||||
if (!auction.LoadFromDB(result.GetFields()))
|
||||
{
|
||||
auction.DeleteFromDB(trans);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auction.IsCompleted())
|
||||
{
|
||||
auction.DeleteFromDB(trans);
|
||||
continue;
|
||||
}
|
||||
|
||||
AddAuction(auction);
|
||||
} while (result.NextRow());
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} black market auctions in {1} ms.", _auctions.Count, Time.GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
public void Update(bool updateTime = false)
|
||||
{
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
long now = Time.UnixTime;
|
||||
foreach (var entry in _auctions.Values)
|
||||
{
|
||||
if (entry.IsCompleted() && entry.GetBidder() != 0)
|
||||
SendAuctionWonMail(entry, trans);
|
||||
|
||||
if (updateTime)
|
||||
entry.Update(now);
|
||||
}
|
||||
|
||||
if (updateTime)
|
||||
_lastUpdate = now;
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
public void RefreshAuctions()
|
||||
{
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
// Delete completed auctions
|
||||
foreach (var pair in _auctions.ToList())
|
||||
{
|
||||
if (!pair.Value.IsCompleted())
|
||||
continue;
|
||||
|
||||
pair.Value.DeleteFromDB(trans);
|
||||
_auctions.Remove(pair.Key);
|
||||
}
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
trans = new SQLTransaction();
|
||||
|
||||
List<BlackMarketTemplate> templates = new List<BlackMarketTemplate>();
|
||||
foreach (var pair in _templates)
|
||||
{
|
||||
if (GetAuctionByID(pair.Value.MarketID) != null)
|
||||
continue;
|
||||
if (!RandomHelper.randChance(pair.Value.Chance))
|
||||
continue;
|
||||
|
||||
templates.Add(pair.Value);
|
||||
}
|
||||
|
||||
templates.RandomResize(WorldConfig.GetUIntValue(WorldCfg.BlackmarketMaxAuctions));
|
||||
|
||||
foreach (BlackMarketTemplate templat in templates)
|
||||
{
|
||||
BlackMarketEntry entry = new BlackMarketEntry();
|
||||
entry.Initialize(templat.MarketID, (uint)templat.Duration);
|
||||
entry.SaveToDB(trans);
|
||||
AddAuction(entry);
|
||||
}
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
Update(true);
|
||||
}
|
||||
|
||||
public bool IsEnabled()
|
||||
{
|
||||
return WorldConfig.GetBoolValue(WorldCfg.BlackmarketEnabled);
|
||||
}
|
||||
|
||||
public void BuildItemsResponse(BlackMarketRequestItemsResult packet, Player player)
|
||||
{
|
||||
packet.LastUpdateID = (int)_lastUpdate;
|
||||
foreach (var pair in _auctions)
|
||||
{
|
||||
BlackMarketTemplate templ = pair.Value.GetTemplate();
|
||||
|
||||
BlackMarketItem item = new BlackMarketItem();
|
||||
item.MarketID = pair.Value.GetMarketId();
|
||||
item.SellerNPC = templ.SellerNPC;
|
||||
item.Item = templ.Item;
|
||||
item.Quantity = templ.Quantity;
|
||||
|
||||
// No bids yet
|
||||
if (pair.Value.GetNumBids() == 0)
|
||||
{
|
||||
item.MinBid = templ.MinBid;
|
||||
item.MinIncrement = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.MinIncrement = pair.Value.GetMinIncrement(); // 5% increment minimum
|
||||
item.MinBid = pair.Value.GetCurrentBid() + item.MinIncrement;
|
||||
}
|
||||
|
||||
item.CurrentBid = pair.Value.GetCurrentBid();
|
||||
item.SecondsRemaining = pair.Value.GetSecondsRemaining();
|
||||
item.HighBid = (pair.Value.GetBidder() == player.GetGUID().GetCounter());
|
||||
item.NumBids = pair.Value.GetNumBids();
|
||||
|
||||
packet.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddAuction(BlackMarketEntry auction)
|
||||
{
|
||||
_auctions[auction.GetMarketId()] = auction;
|
||||
}
|
||||
|
||||
public void AddTemplate(BlackMarketTemplate templ)
|
||||
{
|
||||
_templates[templ.MarketID] = templ;
|
||||
}
|
||||
|
||||
public void SendAuctionWonMail(BlackMarketEntry entry, SQLTransaction trans)
|
||||
{
|
||||
// Mail already sent
|
||||
if (entry.GetMailSent())
|
||||
return;
|
||||
|
||||
uint bidderAccId = 0;
|
||||
ObjectGuid bidderGuid = ObjectGuid.Create(HighGuid.Player, entry.GetBidder());
|
||||
Player bidder = Global.ObjAccessor.FindConnectedPlayer(bidderGuid);
|
||||
// data for gm.log
|
||||
string bidderName = "";
|
||||
bool logGmTrade = false;
|
||||
|
||||
if (bidder)
|
||||
{
|
||||
bidderAccId = bidder.GetSession().GetAccountId();
|
||||
bidderName = bidder.GetName();
|
||||
logGmTrade = bidder.GetSession().HasPermission(RBACPermissions.LogGmTrade);
|
||||
}
|
||||
else
|
||||
{
|
||||
bidderAccId = ObjectManager.GetPlayerAccountIdByGUID(bidderGuid);
|
||||
if (bidderAccId == 0) // Account exists
|
||||
return;
|
||||
|
||||
logGmTrade = Global.AccountMgr.HasPermission(bidderAccId, RBACPermissions.LogGmTrade, Global.WorldMgr.GetRealmId().Realm);
|
||||
|
||||
if (logGmTrade && !ObjectManager.GetPlayerNameByGUID(bidderGuid, out bidderName))
|
||||
bidderName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown);
|
||||
}
|
||||
|
||||
// Create item
|
||||
BlackMarketTemplate templ = entry.GetTemplate();
|
||||
Item item = Item.CreateItem(templ.Item.ItemID, templ.Quantity);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
if (templ.Item.ItemBonus.HasValue)
|
||||
{
|
||||
foreach (uint bonusList in templ.Item.ItemBonus.Value.BonusListIDs)
|
||||
item.AddBonuses(bonusList);
|
||||
}
|
||||
|
||||
item.SetOwnerGUID(bidderGuid);
|
||||
|
||||
item.SaveToDB(trans);
|
||||
|
||||
// Log trade
|
||||
if (logGmTrade)
|
||||
Log.outCommand(bidderAccId, "GM {0} (Account: {1}) won item in blackmarket auction: {2} (Entry: {3} Count: {4}) and payed gold : {5}.",
|
||||
bidderName, bidderAccId, item.GetTemplate().GetName(), item.GetEntry(), item.GetCount(), entry.GetCurrentBid() / MoneyConstants.Gold);
|
||||
|
||||
if (bidder)
|
||||
bidder.GetSession().SendBlackMarketWonNotification(entry, item);
|
||||
|
||||
new MailDraft(entry.BuildAuctionMailSubject(BMAHMailAuctionAnswers.Won), entry.BuildAuctionMailBody())
|
||||
.AddItem(item)
|
||||
.SendMailTo(trans, new MailReceiver(bidder, entry.GetBidder()),new MailSender(entry), MailCheckMask.Copied);
|
||||
|
||||
entry.MailSent();
|
||||
}
|
||||
|
||||
public void SendAuctionOutbidMail(BlackMarketEntry entry, SQLTransaction trans)
|
||||
{
|
||||
ObjectGuid oldBidder_guid = ObjectGuid.Create(HighGuid.Player, entry.GetBidder());
|
||||
Player oldBidder = Global.ObjAccessor.FindConnectedPlayer(oldBidder_guid);
|
||||
|
||||
uint oldBidder_accId = 0;
|
||||
if (!oldBidder)
|
||||
oldBidder_accId = ObjectManager.GetPlayerAccountIdByGUID(oldBidder_guid);
|
||||
|
||||
// old bidder exist
|
||||
if (!oldBidder && oldBidder_accId == 0)
|
||||
return;
|
||||
|
||||
if (oldBidder)
|
||||
oldBidder.GetSession().SendBlackMarketOutbidNotification(entry.GetTemplate());
|
||||
|
||||
new MailDraft(entry.BuildAuctionMailSubject(BMAHMailAuctionAnswers.Outbid), entry.BuildAuctionMailBody())
|
||||
.AddMoney(entry.GetCurrentBid())
|
||||
.SendMailTo(trans, new MailReceiver(oldBidder, entry.GetBidder()), new MailSender(entry), MailCheckMask.Copied);
|
||||
}
|
||||
|
||||
public BlackMarketEntry GetAuctionByID(uint marketId)
|
||||
{
|
||||
return _auctions.LookupByKey(marketId);
|
||||
}
|
||||
|
||||
public BlackMarketTemplate GetTemplateByID(uint marketId)
|
||||
{
|
||||
return _templates.LookupByKey(marketId);
|
||||
}
|
||||
|
||||
public long GetLastUpdate() { return _lastUpdate; }
|
||||
|
||||
Dictionary<uint, BlackMarketEntry> _auctions = new Dictionary<uint, BlackMarketEntry>();
|
||||
Dictionary<uint, BlackMarketTemplate> _templates = new Dictionary<uint, BlackMarketTemplate>();
|
||||
long _lastUpdate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
using Game.Mails;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
public class CalendarManager : Singleton<CalendarManager>
|
||||
{
|
||||
CalendarManager()
|
||||
{
|
||||
_events = new List<CalendarEvent>();
|
||||
_invites = new MultiMap<ulong,CalendarInvite>();
|
||||
}
|
||||
|
||||
public void LoadFromDB()
|
||||
{
|
||||
uint count = 0;
|
||||
_maxEventId = 0;
|
||||
_maxInviteId = 0;
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
SQLResult result = DB.Characters.Query("SELECT EventID, Owner, Title, Description, EventType, TextureID, Date, Flags, LockDate FROM calendar_events");
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ulong eventID = result.Read<ulong>(0);
|
||||
ObjectGuid ownerGUID = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(1));
|
||||
string title = result.Read<string>(2);
|
||||
string description = result.Read<string>(3);
|
||||
CalendarEventType type = (CalendarEventType)result.Read<byte>(4);
|
||||
int textureID = result.Read<int>(5);
|
||||
uint date = result.Read<uint>(6);
|
||||
CalendarFlags flags = (CalendarFlags)result.Read<uint>(7);
|
||||
uint lockDate = result.Read<uint>(8);
|
||||
ulong guildID = 0;
|
||||
|
||||
if (flags.HasAnyFlag(CalendarFlags.GuildEvent) || flags.HasAnyFlag(CalendarFlags.WithoutInvites))
|
||||
guildID = Player.GetGuildIdFromDB(ownerGUID);
|
||||
|
||||
CalendarEvent calendarEvent = new CalendarEvent(eventID, ownerGUID, guildID, type, textureID, date, flags, title, description, lockDate);
|
||||
_events.Add(calendarEvent);
|
||||
|
||||
_maxEventId = Math.Max(_maxEventId, eventID);
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} calendar events", count);
|
||||
count = 0;
|
||||
|
||||
// 0 1 2 3 4 5 6 7
|
||||
result = DB.Characters.Query("SELECT InviteID, EventID, Invitee, Sender, Status, ResponseTime, ModerationRank, Note FROM calendar_invites");
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ulong inviteId = result.Read<ulong>(0);
|
||||
ulong eventId = result.Read<ulong>(1);
|
||||
ObjectGuid invitee = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(2));
|
||||
ObjectGuid senderGUID = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(3));
|
||||
CalendarInviteStatus status = (CalendarInviteStatus)result.Read<byte>(4);
|
||||
uint responseTime = result.Read<uint>(5);
|
||||
CalendarModerationRank rank = (CalendarModerationRank)result.Read<byte>(6);
|
||||
string note = result.Read<string>(7);
|
||||
|
||||
CalendarInvite invite = new CalendarInvite(inviteId, eventId, invitee, senderGUID, responseTime, status, rank, note);
|
||||
_invites.Add(eventId, invite);
|
||||
|
||||
_maxInviteId = Math.Max(_maxInviteId, inviteId);
|
||||
|
||||
++count;
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} calendar invites", count);
|
||||
|
||||
for (ulong i = 1; i < _maxEventId; ++i)
|
||||
if (GetEvent(i) == null)
|
||||
_freeEventIds.Add(i);
|
||||
|
||||
for (ulong i = 1; i < _maxInviteId; ++i)
|
||||
if (GetInvite(i) == null)
|
||||
_freeInviteIds.Add(i);
|
||||
}
|
||||
|
||||
public void AddEvent(CalendarEvent calendarEvent, CalendarSendEventType sendType)
|
||||
{
|
||||
_events.Add(calendarEvent);
|
||||
UpdateEvent(calendarEvent);
|
||||
SendCalendarEvent(calendarEvent.OwnerGuid, calendarEvent, sendType);
|
||||
}
|
||||
|
||||
public void AddInvite(CalendarEvent calendarEvent, CalendarInvite invite, SQLTransaction trans = null)
|
||||
{
|
||||
if (!calendarEvent.IsGuildAnnouncement() && calendarEvent.OwnerGuid != invite.InviteeGuid)
|
||||
SendCalendarEventInvite(invite);
|
||||
|
||||
if (!calendarEvent.IsGuildEvent() || invite.InviteeGuid == calendarEvent.OwnerGuid)
|
||||
SendCalendarEventInviteAlert(calendarEvent, invite);
|
||||
|
||||
if (!calendarEvent.IsGuildAnnouncement())
|
||||
{
|
||||
_invites.Add(invite.EventId, invite);
|
||||
UpdateInvite(invite, trans);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveEvent(ulong eventId, ObjectGuid remover)
|
||||
{
|
||||
CalendarEvent calendarEvent = GetEvent(eventId);
|
||||
|
||||
if (calendarEvent == null)
|
||||
{
|
||||
SendCalendarCommandResult(remover, CalendarError.EventInvalid);
|
||||
return;
|
||||
}
|
||||
|
||||
SendCalendarEventRemovedAlert(calendarEvent);
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
PreparedStatement stmt;
|
||||
MailDraft mail = new MailDraft(calendarEvent.BuildCalendarMailSubject(remover), calendarEvent.BuildCalendarMailBody());
|
||||
|
||||
var eventInvites = _invites[eventId];
|
||||
for (int i = 0; i < eventInvites.Count; ++i)
|
||||
{
|
||||
CalendarInvite invite = eventInvites[i];
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CALENDAR_INVITE);
|
||||
stmt.AddValue(0, invite.InviteId);
|
||||
trans.Append(stmt);
|
||||
|
||||
// guild events only? check invite status here?
|
||||
// When an event is deleted, all invited (accepted/declined? - verify) guildies are notified via in-game mail. (wowwiki)
|
||||
if (!remover.IsEmpty() && invite.InviteeGuid != remover)
|
||||
mail.SendMailTo(trans, new MailReceiver(invite.InviteeGuid.GetCounter()), new MailSender(calendarEvent), MailCheckMask.Copied);
|
||||
}
|
||||
|
||||
_invites.Remove(eventId);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CALENDAR_EVENT);
|
||||
stmt.AddValue(0, eventId);
|
||||
trans.Append(stmt);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
_events.Remove(calendarEvent);
|
||||
}
|
||||
|
||||
public void RemoveInvite(ulong inviteId, ulong eventId, ObjectGuid remover)
|
||||
{
|
||||
CalendarEvent calendarEvent = GetEvent(eventId);
|
||||
|
||||
if (calendarEvent == null)
|
||||
return;
|
||||
|
||||
CalendarInvite calendarInvite = null;
|
||||
foreach (var invite in _invites[eventId])
|
||||
{
|
||||
if (invite.InviteId == inviteId)
|
||||
{
|
||||
calendarInvite = invite;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (calendarInvite == null)
|
||||
return;
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CALENDAR_INVITE);
|
||||
stmt.AddValue(0, calendarInvite.InviteId);
|
||||
trans.Append(stmt);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
if (!calendarEvent.IsGuildEvent())
|
||||
SendCalendarEventInviteRemoveAlert(calendarInvite.InviteeGuid, calendarEvent, CalendarInviteStatus.Removed);
|
||||
|
||||
SendCalendarEventInviteRemove(calendarEvent, calendarInvite, (uint)calendarEvent.Flags);
|
||||
|
||||
// we need to find out how to use CALENDAR_INVITE_REMOVED_MAIL_SUBJECT to force client to display different mail
|
||||
//if (itr._invitee != remover)
|
||||
// MailDraft(calendarEvent.BuildCalendarMailSubject(remover), calendarEvent.BuildCalendarMailBody())
|
||||
// .SendMailTo(trans, MailReceiver(itr.GetInvitee()), calendarEvent, MAIL_CHECK_MASK_COPIED);
|
||||
|
||||
_invites.Remove(eventId, calendarInvite);
|
||||
}
|
||||
|
||||
public void UpdateEvent(CalendarEvent calendarEvent)
|
||||
{
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.REP_CALENDAR_EVENT);
|
||||
stmt.AddValue(0, calendarEvent.EventId);
|
||||
stmt.AddValue(1, calendarEvent.OwnerGuid.GetCounter());
|
||||
stmt.AddValue(2, calendarEvent.Title);
|
||||
stmt.AddValue(3, calendarEvent.Description);
|
||||
stmt.AddValue(4, calendarEvent.EventType);
|
||||
stmt.AddValue(5, calendarEvent.TextureId);
|
||||
stmt.AddValue(6, calendarEvent.Date);
|
||||
stmt.AddValue(7, calendarEvent.Flags);
|
||||
stmt.AddValue(8, calendarEvent.LockDate);
|
||||
trans.Append(stmt);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
public void UpdateInvite(CalendarInvite invite, SQLTransaction trans = null)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.REP_CALENDAR_INVITE);
|
||||
stmt.AddValue(0, invite.InviteId);
|
||||
stmt.AddValue(1, invite.EventId);
|
||||
stmt.AddValue(2, invite.InviteeGuid.GetCounter());
|
||||
stmt.AddValue(3, invite.SenderGuid.GetCounter());
|
||||
stmt.AddValue(4, invite.Status);
|
||||
stmt.AddValue(5, invite.ResponseTime);
|
||||
stmt.AddValue(6, invite.Rank);
|
||||
stmt.AddValue(7, invite.Note);
|
||||
DB.Characters.ExecuteOrAppend(trans, stmt);
|
||||
}
|
||||
|
||||
public void RemoveAllPlayerEventsAndInvites(ObjectGuid guid)
|
||||
{
|
||||
foreach (var calendarEvent in _events)
|
||||
if (calendarEvent.OwnerGuid == guid)
|
||||
RemoveEvent(calendarEvent.EventId, ObjectGuid.Empty); // don't send mail if removing a character
|
||||
|
||||
List<CalendarInvite> playerInvites = GetPlayerInvites(guid);
|
||||
foreach (var calendarInvite in playerInvites)
|
||||
RemoveInvite(calendarInvite.InviteId, calendarInvite.EventId, guid);
|
||||
}
|
||||
|
||||
public void RemovePlayerGuildEventsAndSignups(ObjectGuid guid, ulong guildId)
|
||||
{
|
||||
foreach (var calendarEvent in _events)
|
||||
if (calendarEvent.OwnerGuid == guid && (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()))
|
||||
RemoveEvent(calendarEvent.EventId, guid);
|
||||
|
||||
List<CalendarInvite> playerInvites = GetPlayerInvites(guid);
|
||||
foreach (var playerCalendarEvent in playerInvites)
|
||||
{
|
||||
CalendarEvent calendarEvent = GetEvent(playerCalendarEvent.EventId);
|
||||
if (calendarEvent != null)
|
||||
if (calendarEvent.IsGuildEvent() && calendarEvent.GuildId == guildId)
|
||||
RemoveInvite(playerCalendarEvent.InviteId, playerCalendarEvent.EventId, guid);
|
||||
}
|
||||
}
|
||||
|
||||
public CalendarEvent GetEvent(ulong eventId)
|
||||
{
|
||||
foreach (var calendarEvent in _events)
|
||||
if (calendarEvent.EventId == eventId)
|
||||
return calendarEvent;
|
||||
|
||||
Log.outDebug(LogFilter.Calendar, "CalendarMgr:GetEvent: {0} not found!", eventId);
|
||||
return null;
|
||||
}
|
||||
|
||||
public CalendarInvite GetInvite(ulong inviteId)
|
||||
{
|
||||
foreach (var calendarEvent in _invites.Values)
|
||||
if (calendarEvent.InviteId == inviteId)
|
||||
return calendarEvent;
|
||||
|
||||
Log.outDebug(LogFilter.Calendar, "CalendarMgr:GetInvite: {0} not found!", inviteId);
|
||||
return null;
|
||||
}
|
||||
|
||||
void FreeEventId(ulong id)
|
||||
{
|
||||
if (id == _maxEventId)
|
||||
--_maxEventId;
|
||||
else
|
||||
_freeEventIds.Add(id);
|
||||
}
|
||||
|
||||
public ulong GetFreeEventId()
|
||||
{
|
||||
if (_freeEventIds.Empty())
|
||||
return ++_maxEventId;
|
||||
|
||||
ulong eventId = _freeEventIds.FirstOrDefault();
|
||||
_freeEventIds.RemoveAt(0);
|
||||
return eventId;
|
||||
}
|
||||
|
||||
void FreeInviteId(ulong id)
|
||||
{
|
||||
if (id == _maxInviteId)
|
||||
--_maxInviteId;
|
||||
else
|
||||
_freeInviteIds.Add(id);
|
||||
}
|
||||
|
||||
public ulong GetFreeInviteId()
|
||||
{
|
||||
if (_freeInviteIds.Empty())
|
||||
return ++_maxInviteId;
|
||||
|
||||
ulong inviteId = _freeInviteIds.FirstOrDefault();
|
||||
_freeInviteIds.RemoveAt(0);
|
||||
return inviteId;
|
||||
}
|
||||
|
||||
public List<CalendarEvent> GetPlayerEvents(ObjectGuid guid)
|
||||
{
|
||||
List<CalendarEvent> events = new List<CalendarEvent>();
|
||||
|
||||
foreach (var pair in _invites)
|
||||
{
|
||||
if (pair.Value.InviteeGuid == guid)
|
||||
{
|
||||
CalendarEvent Event = GetEvent(pair.Key);
|
||||
if (Event != null) // null check added as attempt to fix #11512
|
||||
events.Add(Event);
|
||||
}
|
||||
}
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
{
|
||||
foreach (var calendarEvent in _events)
|
||||
if (calendarEvent.GuildId == player.GetGuildId())
|
||||
events.Add(calendarEvent);
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
public List<CalendarInvite> GetEventInvites(ulong eventId)
|
||||
{
|
||||
return _invites[eventId];
|
||||
}
|
||||
|
||||
public List<CalendarInvite> GetPlayerInvites(ObjectGuid guid)
|
||||
{
|
||||
List<CalendarInvite> invites = new List<CalendarInvite>();
|
||||
|
||||
foreach (var calendarEvent in _invites.Values)
|
||||
{
|
||||
if (calendarEvent.InviteeGuid == guid)
|
||||
invites.Add(calendarEvent);
|
||||
}
|
||||
|
||||
return invites;
|
||||
}
|
||||
|
||||
public uint GetPlayerNumPending(ObjectGuid guid)
|
||||
{
|
||||
List<CalendarInvite> invites = GetPlayerInvites(guid);
|
||||
|
||||
uint pendingNum = 0;
|
||||
foreach (var calendarEvent in invites)
|
||||
{
|
||||
switch (calendarEvent.Status)
|
||||
{
|
||||
case CalendarInviteStatus.Invited:
|
||||
case CalendarInviteStatus.Tentative:
|
||||
case CalendarInviteStatus.NotSignedUp:
|
||||
++pendingNum;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pendingNum;
|
||||
}
|
||||
|
||||
public void SendCalendarEventInvite(CalendarInvite invite)
|
||||
{
|
||||
CalendarEvent calendarEvent = GetEvent(invite.EventId);
|
||||
|
||||
ObjectGuid invitee = invite.InviteeGuid;
|
||||
Player player = Global.ObjAccessor.FindPlayer(invitee);
|
||||
|
||||
uint level = player ? player.getLevel() : Player.GetLevelFromDB(invitee);
|
||||
|
||||
SCalendarEventInvite packet = new SCalendarEventInvite();
|
||||
packet.EventID = calendarEvent != null ? calendarEvent.EventId : 0;
|
||||
packet.InviteGuid = invitee;
|
||||
packet.InviteID = calendarEvent != null ? invite.InviteId : 0;
|
||||
packet.Level = (byte)level;
|
||||
packet.ResponseTime = invite.ResponseTime;
|
||||
packet.Status = invite.Status;
|
||||
packet.Type = (byte)(calendarEvent != null ? calendarEvent.IsGuildEvent() ? 1 : 0 : 0); // Correct ?
|
||||
packet.ClearPending = calendarEvent != null ? !calendarEvent.IsGuildEvent() : true; // Correct ?
|
||||
|
||||
if (calendarEvent == null) // Pre-invite
|
||||
{
|
||||
player = Global.ObjAccessor.FindPlayer(invite.SenderGuid);
|
||||
if (player)
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (calendarEvent.OwnerGuid != invite.InviteeGuid) // correct?
|
||||
SendPacketToAllEventRelatives(packet, calendarEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendCalendarEventUpdateAlert(CalendarEvent calendarEvent, long originalDate)
|
||||
{
|
||||
CalendarEventUpdatedAlert packet = new CalendarEventUpdatedAlert();
|
||||
packet.ClearPending = true; // FIXME
|
||||
packet.Date = calendarEvent.Date;
|
||||
packet.Description = calendarEvent.Description;
|
||||
packet.EventID = calendarEvent.EventId;
|
||||
packet.EventName = calendarEvent.Title;
|
||||
packet.EventType = calendarEvent.EventType;
|
||||
packet.Flags = calendarEvent.Flags;
|
||||
packet.LockDate = calendarEvent.LockDate; // Always 0 ?
|
||||
packet.OriginalDate = originalDate;
|
||||
packet.TextureID = calendarEvent.TextureId;
|
||||
|
||||
SendPacketToAllEventRelatives(packet, calendarEvent);
|
||||
}
|
||||
|
||||
public void SendCalendarEventStatus(CalendarEvent calendarEvent, CalendarInvite invite)
|
||||
{
|
||||
CalendarEventInviteStatus packet = new CalendarEventInviteStatus();
|
||||
packet.ClearPending = true; // FIXME
|
||||
packet.Date = calendarEvent.Date;
|
||||
packet.EventID = calendarEvent.EventId;
|
||||
packet.Flags = calendarEvent.Flags;
|
||||
packet.InviteGuid = invite.InviteeGuid;
|
||||
packet.ResponseTime = invite.ResponseTime;
|
||||
packet.Status = invite.Status;
|
||||
|
||||
SendPacketToAllEventRelatives(packet, calendarEvent);
|
||||
}
|
||||
|
||||
void SendCalendarEventRemovedAlert(CalendarEvent calendarEvent)
|
||||
{
|
||||
CalendarEventRemovedAlert packet = new CalendarEventRemovedAlert();
|
||||
packet.ClearPending = true; // FIXME
|
||||
packet.Date = calendarEvent.Date;
|
||||
packet.EventID = calendarEvent.EventId;
|
||||
|
||||
SendPacketToAllEventRelatives(packet, calendarEvent);
|
||||
}
|
||||
|
||||
void SendCalendarEventInviteRemove(CalendarEvent calendarEvent, CalendarInvite invite, uint flags)
|
||||
{
|
||||
CalendarEventInviteRemoved packet = new CalendarEventInviteRemoved();
|
||||
packet.ClearPending = true; // FIXME
|
||||
packet.EventID = calendarEvent.EventId;
|
||||
packet.Flags = flags;
|
||||
packet.InviteGuid = invite.InviteeGuid;
|
||||
|
||||
SendPacketToAllEventRelatives(packet, calendarEvent);
|
||||
}
|
||||
|
||||
public void SendCalendarEventModeratorStatusAlert(CalendarEvent calendarEvent, CalendarInvite invite)
|
||||
{
|
||||
CalendarEventInviteModeratorStatus packet = new CalendarEventInviteModeratorStatus();
|
||||
packet.ClearPending = true; // FIXME
|
||||
packet.EventID = calendarEvent.EventId;
|
||||
packet.InviteGuid = invite.InviteeGuid;
|
||||
packet.Status = invite.Status;
|
||||
|
||||
SendPacketToAllEventRelatives(packet, calendarEvent);
|
||||
}
|
||||
|
||||
void SendCalendarEventInviteAlert(CalendarEvent calendarEvent, CalendarInvite invite)
|
||||
{
|
||||
CalendarEventInviteAlert packet = new CalendarEventInviteAlert();
|
||||
packet.Date = calendarEvent.Date;
|
||||
packet.EventID = calendarEvent.EventId;
|
||||
packet.EventName = calendarEvent.Title;
|
||||
packet.EventType = calendarEvent.EventType;
|
||||
packet.Flags = calendarEvent.Flags;
|
||||
packet.InviteID = invite.InviteId;
|
||||
packet.InvitedByGuid = invite.SenderGuid;
|
||||
packet.ModeratorStatus = invite.Rank;
|
||||
packet.OwnerGuid = calendarEvent.OwnerGuid;
|
||||
packet.Status = invite.Status;
|
||||
packet.TextureID = calendarEvent.TextureId;
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId);
|
||||
packet.EventGuildID = guild ? guild.GetGUID() : ObjectGuid.Empty;
|
||||
|
||||
if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement())
|
||||
{
|
||||
guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId);
|
||||
if (guild)
|
||||
guild.BroadcastPacket(packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(invite.InviteeGuid);
|
||||
if (player)
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendCalendarEvent(ObjectGuid guid, CalendarEvent calendarEvent, CalendarSendEventType sendType)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
List<CalendarInvite> eventInviteeList = _invites[calendarEvent.EventId];
|
||||
|
||||
CalendarSendEvent packet = new CalendarSendEvent();
|
||||
packet.Date = calendarEvent.Date;
|
||||
packet.Description = calendarEvent.Description;
|
||||
packet.EventID = calendarEvent.EventId;
|
||||
packet.EventName = calendarEvent.Title;
|
||||
packet.EventType = sendType;
|
||||
packet.Flags = calendarEvent.Flags;
|
||||
packet.GetEventType = calendarEvent.EventType;
|
||||
packet.LockDate = calendarEvent.LockDate; // Always 0 ?
|
||||
packet.OwnerGuid = calendarEvent.OwnerGuid;
|
||||
packet.TextureID = calendarEvent.TextureId;
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId);
|
||||
packet.EventGuildID = (guild ? guild.GetGUID() : ObjectGuid.Empty);
|
||||
|
||||
foreach (var calendarInvite in eventInviteeList)
|
||||
{
|
||||
ObjectGuid inviteeGuid = calendarInvite.InviteeGuid;
|
||||
Player invitee = Global.ObjAccessor.FindPlayer(inviteeGuid);
|
||||
|
||||
uint inviteeLevel = invitee ? invitee.getLevel() : Player.GetLevelFromDB(inviteeGuid);
|
||||
uint inviteeGuildId = invitee ? invitee.GetGuildId() : Player.GetGuildIdFromDB(inviteeGuid);
|
||||
|
||||
CalendarEventInviteInfo inviteInfo = new CalendarEventInviteInfo();
|
||||
inviteInfo.Guid = inviteeGuid;
|
||||
inviteInfo.Level = (byte)inviteeLevel;
|
||||
inviteInfo.Status = calendarInvite.Status;
|
||||
inviteInfo.Moderator = calendarInvite.Rank;
|
||||
inviteInfo.InviteType = (byte)(calendarEvent.IsGuildEvent() && calendarEvent.GuildId == inviteeGuildId ? 1 : 0);
|
||||
inviteInfo.InviteID = calendarInvite.InviteId;
|
||||
inviteInfo.ResponseTime = calendarInvite.ResponseTime;
|
||||
inviteInfo.Notes = calendarInvite.Note;
|
||||
|
||||
packet.Invites.Add(inviteInfo);
|
||||
}
|
||||
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
|
||||
void SendCalendarEventInviteRemoveAlert(ObjectGuid guid, CalendarEvent calendarEvent, CalendarInviteStatus status)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
{
|
||||
CalendarEventInviteRemovedAlert packet = new CalendarEventInviteRemovedAlert();
|
||||
packet.Date = calendarEvent.Date;
|
||||
packet.EventID = calendarEvent.EventId;
|
||||
packet.Flags = calendarEvent.Flags;
|
||||
packet.Status = status;
|
||||
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendCalendarClearPendingAction(ObjectGuid guid)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
player.SendPacket(new CalendarClearPendingAction());
|
||||
}
|
||||
|
||||
public void SendCalendarCommandResult(ObjectGuid guid, CalendarError err, string param = null)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(guid);
|
||||
if (player)
|
||||
{
|
||||
CalendarCommandResult packet = new CalendarCommandResult();
|
||||
packet.Command = 1; // FIXME
|
||||
packet.Result = err;
|
||||
|
||||
switch (err)
|
||||
{
|
||||
case CalendarError.OtherInvitesExceeded:
|
||||
case CalendarError.AlreadyInvitedToEventS:
|
||||
case CalendarError.IgnoringYouS:
|
||||
packet.Name = param;
|
||||
break;
|
||||
}
|
||||
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void SendPacketToAllEventRelatives(ServerPacket packet, CalendarEvent calendarEvent)
|
||||
{
|
||||
// Send packet to all guild members
|
||||
if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement())
|
||||
{
|
||||
Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId);
|
||||
if (guild)
|
||||
guild.BroadcastPacket(packet);
|
||||
}
|
||||
|
||||
// Send packet to all invitees if event is non-guild, in other case only to non-guild invitees (packet was broadcasted for them)
|
||||
List<CalendarInvite> invites = _invites[calendarEvent.EventId];
|
||||
foreach (var playerCalendarEvent in invites)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayer(playerCalendarEvent.InviteeGuid);
|
||||
if (player)
|
||||
if (!calendarEvent.IsGuildEvent() || (calendarEvent.IsGuildEvent() && player.GetGuildId() != calendarEvent.GuildId))
|
||||
player.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
List<CalendarEvent> _events;
|
||||
MultiMap<ulong, CalendarInvite> _invites;
|
||||
|
||||
List<ulong> _freeEventIds = new List<ulong>();
|
||||
List<ulong> _freeInviteIds = new List<ulong>();
|
||||
ulong _maxEventId;
|
||||
ulong _maxInviteId;
|
||||
}
|
||||
|
||||
public class CalendarInvite
|
||||
{
|
||||
public CalendarInvite()
|
||||
{
|
||||
InviteId = 1;
|
||||
ResponseTime = Time.UnixTime;
|
||||
Status = CalendarInviteStatus.Invited;
|
||||
Rank = CalendarModerationRank.Player;
|
||||
Note = "";
|
||||
}
|
||||
public CalendarInvite(CalendarInvite calendarInvite, ulong inviteId, ulong eventId)
|
||||
{
|
||||
InviteId = inviteId;
|
||||
EventId = eventId;
|
||||
InviteeGuid = calendarInvite.InviteeGuid;
|
||||
SenderGuid = calendarInvite.SenderGuid;
|
||||
ResponseTime = calendarInvite.ResponseTime;
|
||||
Status = calendarInvite.Status;
|
||||
Rank = calendarInvite.Rank;
|
||||
Note = calendarInvite.Note;
|
||||
}
|
||||
public CalendarInvite(ulong inviteId, ulong eventId, ObjectGuid invitee, ObjectGuid senderGUID, long responseTime, CalendarInviteStatus status, CalendarModerationRank rank, string note)
|
||||
{
|
||||
InviteId = inviteId;
|
||||
EventId = eventId;
|
||||
InviteeGuid = invitee;
|
||||
SenderGuid = senderGUID;
|
||||
ResponseTime = responseTime;
|
||||
|
||||
Status = status;
|
||||
Rank = rank;
|
||||
Note = note;
|
||||
}
|
||||
|
||||
public ulong InviteId { get; set; }
|
||||
public ulong EventId { get; set; }
|
||||
public ObjectGuid InviteeGuid { get; set; }
|
||||
public ObjectGuid SenderGuid { get; set; }
|
||||
public long ResponseTime { get; set; }
|
||||
public CalendarInviteStatus Status { get; set; }
|
||||
public CalendarModerationRank Rank { get; set; }
|
||||
public string Note { get; set; }
|
||||
}
|
||||
|
||||
public class CalendarEvent
|
||||
{
|
||||
public CalendarEvent(CalendarEvent calendarEvent, ulong eventId)
|
||||
{
|
||||
EventId = eventId;
|
||||
OwnerGuid = calendarEvent.OwnerGuid;
|
||||
GuildId = calendarEvent.GuildId;
|
||||
EventType = calendarEvent.EventType;
|
||||
TextureId = calendarEvent.TextureId;
|
||||
Date = calendarEvent.Date;
|
||||
Flags = calendarEvent.Flags;
|
||||
LockDate = calendarEvent.LockDate;
|
||||
Title = calendarEvent.Title;
|
||||
Description = calendarEvent.Description;
|
||||
}
|
||||
|
||||
public CalendarEvent(ulong eventId, ObjectGuid ownerGuid, ulong guildId, CalendarEventType type, int textureId, long date, CalendarFlags flags, string title, string description, long lockDate)
|
||||
{
|
||||
EventId = eventId;
|
||||
OwnerGuid = ownerGuid;
|
||||
GuildId = guildId;
|
||||
EventType = type;
|
||||
TextureId = textureId;
|
||||
Date = date;
|
||||
Flags = flags;
|
||||
LockDate = lockDate;
|
||||
Title = title;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public CalendarEvent()
|
||||
{
|
||||
EventId = 1;
|
||||
EventType = CalendarEventType.Other;
|
||||
TextureId = -1;
|
||||
Title = "";
|
||||
Description = "";
|
||||
}
|
||||
|
||||
public string BuildCalendarMailSubject(ObjectGuid remover)
|
||||
{
|
||||
return remover + ":" + Title;
|
||||
}
|
||||
|
||||
public string BuildCalendarMailBody()
|
||||
{
|
||||
var now = Time.UnixTimeToDateTime(Date);
|
||||
uint time = Convert.ToUInt32(((now.Year - 1900) - 100) << 24 | (now.Month - 1) << 20 | (now.Day - 1) << 14 | (int)now.DayOfWeek << 11 | now.Hour << 6 | now.Minute);
|
||||
return time.ToString();
|
||||
}
|
||||
|
||||
public bool IsGuildEvent() { return Flags.HasAnyFlag(CalendarFlags.GuildEvent); }
|
||||
public bool IsGuildAnnouncement() { return Flags.HasAnyFlag(CalendarFlags.WithoutInvites); }
|
||||
public bool IsLocked() { return Flags.HasAnyFlag(CalendarFlags.InvitesLocked); }
|
||||
|
||||
public ulong EventId { get; set; }
|
||||
public ObjectGuid OwnerGuid { get; set; }
|
||||
public ulong GuildId { get; set; }
|
||||
public CalendarEventType EventType { get; set; }
|
||||
public int TextureId { get; set; }
|
||||
public long Date { get; set; }
|
||||
public CalendarFlags Flags { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public long LockDate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,980 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Collections;
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
public class Channel
|
||||
{
|
||||
public Channel(uint channelId, Team team = 0, AreaTableRecord zoneEntry = null)
|
||||
{
|
||||
_channelFlags = ChannelFlags.General;
|
||||
_channelId = channelId;
|
||||
_channelTeam = team;
|
||||
_zoneEntry = zoneEntry;
|
||||
|
||||
ChatChannelsRecord channelEntry = CliDB.ChatChannelsStorage.LookupByKey(channelId);
|
||||
if (channelEntry.Flags.HasAnyFlag(ChannelDBCFlags.Trade)) // for trade channel
|
||||
_channelFlags |= ChannelFlags.Trade;
|
||||
|
||||
if (channelEntry.Flags.HasAnyFlag(ChannelDBCFlags.CityOnly2)) // for city only channels
|
||||
_channelFlags |= ChannelFlags.City;
|
||||
|
||||
if (channelEntry.Flags.HasAnyFlag(ChannelDBCFlags.Lfg)) // for LFG channel
|
||||
_channelFlags |= ChannelFlags.Lfg;
|
||||
else // for all other channels
|
||||
_channelFlags |= ChannelFlags.NotLfg;
|
||||
}
|
||||
|
||||
public Channel(string name, Team team = 0)
|
||||
{
|
||||
_announceEnabled = true;
|
||||
_ownershipEnabled = true;
|
||||
_channelFlags = ChannelFlags.Custom;
|
||||
_channelTeam = team;
|
||||
_channelName = name;
|
||||
|
||||
// If storing custom channels in the db is enabled either load or save the channel
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.PreserveCustomChannels))
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHANNEL);
|
||||
stmt.AddValue(0, _channelName);
|
||||
stmt.AddValue(1, _channelTeam);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty()) //load
|
||||
{
|
||||
_channelName = result.Read<string>(0); // re-get channel name. MySQL table collation is case insensitive
|
||||
_announceEnabled = result.Read<bool>(1);
|
||||
_ownershipEnabled = result.Read<bool>(2);
|
||||
_channelPassword = result.Read<string>(3);
|
||||
string bannedList = result.Read<string>(4);
|
||||
|
||||
if (string.IsNullOrEmpty(bannedList))
|
||||
{
|
||||
var tokens = new StringArray(bannedList, ' ');
|
||||
for (var i = 0; i < tokens.Length; ++i)
|
||||
{
|
||||
ObjectGuid bannedGuid = new ObjectGuid();
|
||||
bannedGuid.SetRawValue(ulong.Parse(tokens[i].Substring(0, 16)), ulong.Parse(tokens[i].Substring(16)));
|
||||
if (!bannedGuid.IsEmpty())
|
||||
{
|
||||
Log.outDebug(LogFilter.ChatSystem, "Channel({0}) loaded bannedStore guid:{1}", _channelName, bannedGuid);
|
||||
_bannedStore.Add(bannedGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // save
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHANNEL);
|
||||
stmt.AddValue(0, _channelName);
|
||||
stmt.AddValue(1, _channelTeam);
|
||||
DB.Characters.Execute(stmt);
|
||||
Log.outDebug(LogFilter.ChatSystem, "Channel({0}) saved in database", _channelName);
|
||||
}
|
||||
|
||||
_persistentChannel = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void GetChannelName(ref string channelName, uint channelId, LocaleConstant locale, AreaTableRecord zoneEntry)
|
||||
{
|
||||
if (channelId != 0)
|
||||
{
|
||||
ChatChannelsRecord channelEntry = CliDB.ChatChannelsStorage.LookupByKey(channelId);
|
||||
if (!channelEntry.Flags.HasAnyFlag(ChannelDBCFlags.Global))
|
||||
{
|
||||
if (channelEntry.Flags.HasAnyFlag(ChannelDBCFlags.CityOnly))
|
||||
channelName = string.Format(channelEntry.Name[locale].ConvertFormatSyntax(), Global.ObjectMgr.GetCypherString(CypherStrings.ChannelCity, locale));
|
||||
else
|
||||
channelName = string.Format(channelEntry.Name[locale].ConvertFormatSyntax(), zoneEntry.AreaName[locale]);
|
||||
}
|
||||
else
|
||||
channelName = channelEntry.Name[locale];
|
||||
}
|
||||
}
|
||||
|
||||
public string GetName(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
string result = _channelName;
|
||||
GetChannelName(ref result, _channelId, locale, _zoneEntry);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void UpdateChannelInDB()
|
||||
{
|
||||
if (_persistentChannel)
|
||||
{
|
||||
string banlist = "";
|
||||
foreach (var iter in _bannedStore)
|
||||
banlist += iter.GetRawValue().ToHexString() + ' ';
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHANNEL);
|
||||
stmt.AddValue(0, _announceEnabled);
|
||||
stmt.AddValue(1, _ownershipEnabled);
|
||||
stmt.AddValue(2, _channelPassword);
|
||||
stmt.AddValue(3, banlist);
|
||||
stmt.AddValue(4, _channelName);
|
||||
stmt.AddValue(5, _channelTeam);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
Log.outDebug(LogFilter.ChatSystem, "Channel({0}) updated in database", _channelName);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateChannelUseageInDB()
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHANNEL_USAGE);
|
||||
stmt.AddValue(0, _channelName);
|
||||
stmt.AddValue(1, _channelTeam);
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
|
||||
public static void CleanOldChannelsInDB()
|
||||
{
|
||||
if (WorldConfig.GetIntValue(WorldCfg.PreserveCustomChannelDuration) > 0)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_OLD_CHANNELS);
|
||||
stmt.AddValue(0, WorldConfig.GetIntValue(WorldCfg.PreserveCustomChannelDuration) * Time.Day);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
Log.outDebug(LogFilter.ChatSystem, "Cleaned out unused custom chat channels.");
|
||||
}
|
||||
}
|
||||
|
||||
public void JoinChannel(Player player, string pass)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
if (IsOn(guid))
|
||||
{
|
||||
// Do not send error message for built-in channels
|
||||
if (!IsConstant())
|
||||
{
|
||||
var builder = new ChannelNameBuilder(this, new PlayerAlreadyMemberAppend(guid));
|
||||
SendToOne(builder, guid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsBanned(guid))
|
||||
{
|
||||
var builder = new ChannelNameBuilder(this, new BannedAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_channelPassword) && pass != _channelPassword)
|
||||
{
|
||||
var builder = new ChannelNameBuilder(this, new WrongPasswordAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasFlag(ChannelFlags.Lfg) && WorldConfig.GetBoolValue(WorldCfg.RestrictedLfgChannel) &&
|
||||
Global.AccountMgr.IsPlayerAccount(player.GetSession().GetSecurity()) && //FIXME: Move to RBAC
|
||||
player.GetGroup())
|
||||
{
|
||||
var builder = new ChannelNameBuilder(this, new NotInLFGAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
player.JoinedChannel(this);
|
||||
|
||||
if (_announceEnabled && !player.GetSession().HasPermission(RBACPermissions.SilentlyJoinChannel))
|
||||
{
|
||||
var builder = new ChannelNameBuilder(this, new JoinedAppend(guid));
|
||||
SendToAll(builder);
|
||||
}
|
||||
|
||||
bool newChannel = _playersStore.Empty();
|
||||
|
||||
PlayerInfo playerInfo = new PlayerInfo();
|
||||
playerInfo.SetInvisible(!player.isGMVisible());
|
||||
_playersStore[guid] = playerInfo;
|
||||
|
||||
/*
|
||||
ChannelNameBuilder<YouJoinedAppend> builder = new ChannelNameBuilder(this, new YouJoinedAppend());
|
||||
SendToOne(builder, guid);
|
||||
*/
|
||||
|
||||
SendToOne(new ChannelNotifyJoinedBuilder(this), guid);
|
||||
|
||||
JoinNotify(player);
|
||||
|
||||
// Custom channel handling
|
||||
if (!IsConstant())
|
||||
{
|
||||
// Update last_used timestamp in db
|
||||
if (!_playersStore.Empty())
|
||||
UpdateChannelUseageInDB();
|
||||
|
||||
// If the channel has no owner yet and ownership is allowed, set the new owner.
|
||||
// or if the owner was a GM with .gm visible off
|
||||
// don't do this if the new player is, too, an invis GM, unless the channel was empty
|
||||
if (_ownershipEnabled && (newChannel || !playerInfo.IsInvisible()) && (_ownerGuid.IsEmpty() || _isOwnerInvisible))
|
||||
{
|
||||
_isOwnerInvisible = playerInfo.IsInvisible();
|
||||
|
||||
SetOwner(guid, !newChannel && !_isOwnerInvisible);
|
||||
_playersStore[guid].SetModerator(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void LeaveChannel(Player player, bool send = true)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
if (send)
|
||||
{
|
||||
var builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
player.LeftChannel(this);
|
||||
|
||||
if (send)
|
||||
{
|
||||
/*
|
||||
ChannelNameBuilder<YouLeftAppend> builder = new ChannelNameBuilder(this, new YouLeftAppend());
|
||||
SendToOne(builder, guid);
|
||||
*/
|
||||
|
||||
SendToOne(new ChannelNotifyLeftBuilder(this), guid);
|
||||
}
|
||||
|
||||
PlayerInfo info = _playersStore.LookupByKey(guid);
|
||||
bool changeowner = info.IsOwner();
|
||||
_playersStore.Remove(guid);
|
||||
|
||||
if (_announceEnabled && !player.GetSession().HasPermission(RBACPermissions.SilentlyJoinChannel))
|
||||
{
|
||||
var builder = new ChannelNameBuilder(this, new LeftAppend(guid));
|
||||
SendToAll(builder);
|
||||
}
|
||||
|
||||
LeaveNotify(player);
|
||||
|
||||
if (!IsConstant())
|
||||
{
|
||||
// Update last_used timestamp in db
|
||||
UpdateChannelUseageInDB();
|
||||
|
||||
// If the channel owner left and there are still playersStore inside, pick a new owner
|
||||
// do not pick invisible gm owner unless there are only invisible gms in that channel (rare)
|
||||
if (changeowner && _ownershipEnabled && !_playersStore.Empty())
|
||||
{
|
||||
ObjectGuid newowner = ObjectGuid.Empty;
|
||||
foreach (var key in _playersStore.Keys)
|
||||
{
|
||||
if (!_playersStore[key].IsInvisible())
|
||||
{
|
||||
newowner = key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newowner.IsEmpty())
|
||||
newowner = _playersStore.First().Key;
|
||||
|
||||
_playersStore[newowner].SetModerator(true);
|
||||
|
||||
SetOwner(newowner);
|
||||
|
||||
// if the new owner is invisible gm, set flag to automatically choose a new owner
|
||||
if (_playersStore[newowner].IsInvisible())
|
||||
_isOwnerInvisible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KickOrBan(Player player, string badname, bool ban)
|
||||
{
|
||||
ObjectGuid good = player.GetGUID();
|
||||
|
||||
if (!IsOn(good))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, good);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInfo info = _playersStore.LookupByKey(good);
|
||||
if (!info.IsModerator() && !player.GetSession().HasPermission(RBACPermissions.ChangeChannelNotModerator))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotModeratorAppend());
|
||||
SendToOne(builder, good);
|
||||
return;
|
||||
}
|
||||
|
||||
Player bad = Global.ObjAccessor.FindPlayerByName(badname);
|
||||
ObjectGuid victim = bad ? bad.GetGUID() : ObjectGuid.Empty;
|
||||
if (victim.IsEmpty() || !IsOn(victim))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerNotFoundAppend(badname));
|
||||
SendToOne(builder, good);
|
||||
return;
|
||||
}
|
||||
|
||||
bool changeowner = _ownerGuid == victim;
|
||||
|
||||
if (!player.GetSession().HasPermission(RBACPermissions.ChangeChannelNotModerator) && changeowner && good != _ownerGuid)
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotOwnerAppend());
|
||||
SendToOne(builder, good);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ban && !IsBanned(victim))
|
||||
{
|
||||
_bannedStore.Add(victim);
|
||||
UpdateChannelInDB();
|
||||
|
||||
if (!player.GetSession().HasPermission(RBACPermissions.SilentlyJoinChannel))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerBannedAppend(good, victim));
|
||||
SendToAll(builder);
|
||||
}
|
||||
|
||||
}
|
||||
else if (!player.GetSession().HasPermission(RBACPermissions.SilentlyJoinChannel))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerKickedAppend(good, victim));
|
||||
SendToAll(builder);
|
||||
}
|
||||
|
||||
_playersStore.Remove(victim);
|
||||
bad.LeftChannel(this);
|
||||
|
||||
if (changeowner && _ownershipEnabled && !_playersStore.Empty())
|
||||
{
|
||||
info.SetModerator(true);
|
||||
SetOwner(good);
|
||||
}
|
||||
}
|
||||
|
||||
public void UnBan(Player player, string badname)
|
||||
{
|
||||
ObjectGuid good = player.GetGUID();
|
||||
|
||||
if (!IsOn(good))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, good);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInfo info = _playersStore.LookupByKey(good);
|
||||
if (!info.IsModerator() && !player.GetSession().HasPermission(RBACPermissions.ChangeChannelNotModerator))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotModeratorAppend());
|
||||
SendToOne(builder, good);
|
||||
return;
|
||||
}
|
||||
|
||||
Player bad = Global.ObjAccessor.FindPlayerByName(badname);
|
||||
ObjectGuid victim = bad ? bad.GetGUID() : ObjectGuid.Empty;
|
||||
|
||||
if (victim.IsEmpty() || !IsBanned(victim))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerNotFoundAppend(badname));
|
||||
SendToOne(builder, good);
|
||||
return;
|
||||
}
|
||||
|
||||
_bannedStore.Remove(victim);
|
||||
|
||||
ChannelNameBuilder builder1 = new ChannelNameBuilder(this, new PlayerUnbannedAppend(good, victim));
|
||||
SendToAll(builder1);
|
||||
|
||||
UpdateChannelInDB();
|
||||
}
|
||||
|
||||
public void Password(Player player, string pass)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInfo info = _playersStore.LookupByKey(guid);
|
||||
if (!info.IsModerator() && !player.GetSession().HasPermission(RBACPermissions.ChangeChannelNotModerator))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotModeratorAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
_channelPassword = pass;
|
||||
|
||||
ChannelNameBuilder builder1 = new ChannelNameBuilder(this, new PasswordChangedAppend(guid));
|
||||
SendToAll(builder1);
|
||||
|
||||
UpdateChannelInDB();
|
||||
}
|
||||
|
||||
void SetMode(Player player, string p2n, bool mod, bool set)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInfo info = _playersStore.LookupByKey(guid);
|
||||
if (!info.IsModerator() && !player.GetSession().HasPermission(RBACPermissions.ChangeChannelNotModerator))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotModeratorAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (guid == _ownerGuid && p2n == player.GetName() && mod)
|
||||
return;
|
||||
|
||||
Player newp = Global.ObjAccessor.FindPlayerByName(p2n);
|
||||
ObjectGuid victim = newp ? newp.GetGUID() : ObjectGuid.Empty;
|
||||
|
||||
if (victim.IsEmpty() || !IsOn(victim) ||
|
||||
(player.GetTeam() != newp.GetTeam() &&
|
||||
(!player.GetSession().HasPermission(RBACPermissions.TwoSideInteractionChannel) ||
|
||||
!newp.GetSession().HasPermission(RBACPermissions.TwoSideInteractionChannel))))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerNotFoundAppend(p2n));
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_ownerGuid == victim && _ownerGuid != guid)
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotOwnerAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mod)
|
||||
SetModerator(newp.GetGUID(), set);
|
||||
else
|
||||
SetMute(newp.GetGUID(), set);
|
||||
}
|
||||
|
||||
public void SetInvisible(Player player, bool on)
|
||||
{
|
||||
var playerInfo = _playersStore.LookupByKey(player.GetGUID());
|
||||
if (playerInfo == null)
|
||||
return;
|
||||
|
||||
playerInfo.SetInvisible(on);
|
||||
|
||||
// we happen to be owner too, update flag
|
||||
if (_ownerGuid == player.GetGUID())
|
||||
_isOwnerInvisible = on;
|
||||
}
|
||||
|
||||
public void SetOwner(Player player, string newname)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
if (!player.GetSession().HasPermission(RBACPermissions.ChangeChannelNotModerator) && guid != _ownerGuid)
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotOwnerAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
Player newp = Global.ObjAccessor.FindPlayerByName(newname);
|
||||
ObjectGuid victim = newp ? newp.GetGUID() : ObjectGuid.Empty;
|
||||
|
||||
if (victim.IsEmpty() || !IsOn(victim) ||
|
||||
(player.GetTeam() != newp.GetTeam() &&
|
||||
(!player.GetSession().HasPermission(RBACPermissions.TwoSideInteractionChannel) ||
|
||||
!newp.GetSession().HasPermission(RBACPermissions.TwoSideInteractionChannel))))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerNotFoundAppend(newname));
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
_playersStore[victim].SetModerator(true);
|
||||
SetOwner(victim);
|
||||
}
|
||||
|
||||
public void SendWhoOwner(Player player)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
if (IsOn(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new ChannelOwnerAppend(this, _ownerGuid));
|
||||
SendToOne(builder, guid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
}
|
||||
}
|
||||
|
||||
public void List(Player player)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
string channelName = GetName(player.GetSession().GetSessionDbcLocale());
|
||||
Log.outDebug(LogFilter.ChatSystem, "SMSG_CHANNEL_LIST {0} Channel: {1}", player.GetSession().GetPlayerInfo(), channelName);
|
||||
|
||||
ChannelListResponse list = new ChannelListResponse();
|
||||
list.Display = true; /// always true?
|
||||
list.Channel = channelName;
|
||||
list.ChannelFlags = GetFlags();
|
||||
|
||||
uint gmLevelInWhoList = WorldConfig.GetUIntValue(WorldCfg.GmLevelInWhoList);
|
||||
|
||||
foreach (var pair in _playersStore)
|
||||
{
|
||||
Player member = Global.ObjAccessor.FindConnectedPlayer(pair.Key);
|
||||
|
||||
// PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
|
||||
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
|
||||
if (member && (player.GetSession().HasPermission(RBACPermissions.WhoSeeAllSecLevels) ||
|
||||
member.GetSession().GetSecurity() <= (AccountTypes)gmLevelInWhoList) &&
|
||||
member.IsVisibleGloballyFor(player))
|
||||
{
|
||||
list.Members.Add(new ChannelListResponse.ChannelPlayer(pair.Key, Global.WorldMgr.GetVirtualRealmAddress(), pair.Value.GetFlags()));
|
||||
}
|
||||
}
|
||||
|
||||
player.SendPacket(list);
|
||||
}
|
||||
|
||||
public void Announce(Player player)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInfo playerInfo = _playersStore.LookupByKey(guid);
|
||||
if (!playerInfo.IsModerator() && !player.GetSession().HasPermission(RBACPermissions.ChangeChannelNotModerator))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotModeratorAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
_announceEnabled = !_announceEnabled;
|
||||
|
||||
if (_announceEnabled)
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new AnnouncementsOnAppend(guid));
|
||||
SendToAll(builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new AnnouncementsOffAppend(guid));
|
||||
SendToAll(builder);
|
||||
}
|
||||
|
||||
UpdateChannelInDB();
|
||||
}
|
||||
|
||||
public void Say(ObjectGuid guid, string what, Language lang)
|
||||
{
|
||||
if (string.IsNullOrEmpty(what))
|
||||
return;
|
||||
|
||||
// TODO: Add proper RBAC check
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionChannel))
|
||||
lang = Language.Universal;
|
||||
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInfo playerInfo = _playersStore.LookupByKey(guid);
|
||||
if (playerInfo.IsMuted())
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new MutedAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
SendToAll(new ChannelSayBuilder(this, lang, what, guid), !playerInfo.IsModerator() ? guid : ObjectGuid.Empty);
|
||||
}
|
||||
|
||||
public void AddonSay(ObjectGuid guid, string prefix, string what)
|
||||
{
|
||||
if (what.IsEmpty())
|
||||
return;
|
||||
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
NotMemberAppend appender;
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, appender);
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerInfo playerInfo = _playersStore.LookupByKey(guid);
|
||||
if (playerInfo.IsMuted())
|
||||
{
|
||||
MutedAppend appender;
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, appender);
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
SendToAllWithAddon(new ChannelWhisperBuilder(this, Language.Addon, what, prefix, guid), prefix, !playerInfo.IsModerator() ? guid : ObjectGuid.Empty);
|
||||
}
|
||||
|
||||
public void Invite(Player player, string newname)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
|
||||
if (!IsOn(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new NotMemberAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
Player newp = Global.ObjAccessor.FindPlayerByName(newname);
|
||||
if (!newp || !newp.isGMVisible())
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerNotFoundAppend(newname));
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsBanned(newp.GetGUID()))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerInviteBannedAppend(newname));
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newp.GetTeam() != player.GetTeam() &&
|
||||
(!player.GetSession().HasPermission(RBACPermissions.TwoSideInteractionChannel) ||
|
||||
!newp.GetSession().HasPermission(RBACPermissions.TwoSideInteractionChannel)))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new InviteWrongFactionAppend());
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsOn(newp.GetGUID()))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new PlayerAlreadyMemberAppend(newp.GetGUID()));
|
||||
SendToOne(builder, guid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newp.GetSocial().HasIgnore(guid))
|
||||
{
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new InviteAppend(guid));
|
||||
SendToOne(builder, newp.GetGUID());
|
||||
}
|
||||
|
||||
ChannelNameBuilder builder1 = new ChannelNameBuilder(this, new PlayerInvitedAppend(newp.GetName()));
|
||||
SendToOne(builder1, guid);
|
||||
}
|
||||
|
||||
public void SetOwner(ObjectGuid guid, bool exclaim = true)
|
||||
{
|
||||
if (!_ownerGuid.IsEmpty())
|
||||
{
|
||||
// [] will re-add player after it possible removed
|
||||
var playerInfo = _playersStore.LookupByKey(_ownerGuid);
|
||||
if (playerInfo != null)
|
||||
playerInfo.SetOwner(false);
|
||||
}
|
||||
|
||||
_ownerGuid = guid;
|
||||
if (!_ownerGuid.IsEmpty())
|
||||
{
|
||||
ChannelMemberFlags oldFlag = GetPlayerFlags(_ownerGuid);
|
||||
var playerInfo = _playersStore.LookupByKey(_ownerGuid);
|
||||
if (playerInfo == null)
|
||||
return;
|
||||
|
||||
playerInfo.SetModerator(true);
|
||||
playerInfo.SetOwner(true);
|
||||
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new ModeChangeAppend(_ownerGuid, oldFlag, GetPlayerFlags(_ownerGuid)));
|
||||
SendToAll(builder);
|
||||
|
||||
if (exclaim)
|
||||
{
|
||||
ChannelNameBuilder ownerChangedBuilder = new ChannelNameBuilder(this, new OwnerChangedAppend(_ownerGuid));
|
||||
SendToAll(ownerChangedBuilder);
|
||||
}
|
||||
|
||||
UpdateChannelInDB();
|
||||
}
|
||||
}
|
||||
|
||||
public void SilenceAll(Player player, string name) { }
|
||||
|
||||
public void UnsilenceAll(Player player, string name) { }
|
||||
|
||||
public void DeclineInvite(Player player) { }
|
||||
|
||||
void JoinNotify(Player player)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
|
||||
if (IsConstant())
|
||||
SendToAllButOne(new ChannelUserlistAddBuilder(this, guid), guid);
|
||||
else
|
||||
SendToAll(new ChannelUserlistUpdateBuilder(this, guid));
|
||||
}
|
||||
|
||||
void LeaveNotify(Player player)
|
||||
{
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
|
||||
var builder = new ChannelUserlistRemoveBuilder(this, guid);
|
||||
|
||||
if (IsConstant())
|
||||
SendToAllButOne(builder, guid);
|
||||
else
|
||||
SendToAll(builder);
|
||||
}
|
||||
|
||||
void SetModerator(ObjectGuid guid, bool set)
|
||||
{
|
||||
if (!IsOn(guid))
|
||||
return;
|
||||
|
||||
PlayerInfo playerInfo = _playersStore.LookupByKey(guid);
|
||||
if (playerInfo.IsModerator() != set)
|
||||
{
|
||||
ChannelMemberFlags oldFlag = _playersStore[guid].GetFlags();
|
||||
playerInfo.SetModerator(set);
|
||||
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new ModeChangeAppend(guid, oldFlag, playerInfo.GetFlags()));
|
||||
SendToAll(builder);
|
||||
}
|
||||
}
|
||||
|
||||
void SetMute(ObjectGuid guid, bool set)
|
||||
{
|
||||
if (!IsOn(guid))
|
||||
return;
|
||||
|
||||
PlayerInfo playerInfo = _playersStore.LookupByKey(guid);
|
||||
if (playerInfo.IsMuted() != set)
|
||||
{
|
||||
ChannelMemberFlags oldFlag = _playersStore[guid].GetFlags();
|
||||
playerInfo.SetMuted(set);
|
||||
|
||||
ChannelNameBuilder builder = new ChannelNameBuilder(this, new ModeChangeAppend(guid, oldFlag, playerInfo.GetFlags()));
|
||||
SendToAll(builder);
|
||||
}
|
||||
}
|
||||
|
||||
void SendToAll(MessageBuilder builder, ObjectGuid guid = default(ObjectGuid))
|
||||
{
|
||||
LocalizedPacketDo localizer = new LocalizedPacketDo(builder);
|
||||
|
||||
foreach (var pair in _playersStore)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(pair.Key);
|
||||
if (player)
|
||||
if (guid.IsEmpty() || !player.GetSocial().HasIgnore(guid))
|
||||
localizer.Invoke(player);
|
||||
}
|
||||
}
|
||||
|
||||
void SendToAllButOne(MessageBuilder builder, ObjectGuid who)
|
||||
{
|
||||
LocalizedPacketDo localizer = new LocalizedPacketDo(builder);
|
||||
|
||||
foreach (var pair in _playersStore)
|
||||
{
|
||||
if (pair.Key != who)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(pair.Key);
|
||||
if (player)
|
||||
localizer.Invoke(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SendToOne(MessageBuilder builder, ObjectGuid who)
|
||||
{
|
||||
LocalizedPacketDo localizer = new LocalizedPacketDo(builder);
|
||||
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(who);
|
||||
if (player)
|
||||
localizer.Invoke(player);
|
||||
}
|
||||
|
||||
void SendToAllWithAddon(MessageBuilder builder, string addonPrefix, ObjectGuid guid = default(ObjectGuid))
|
||||
{
|
||||
LocalizedPacketDo localizer = new LocalizedPacketDo(builder);
|
||||
|
||||
foreach (var pair in _playersStore)
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(pair.Key);
|
||||
if (player)
|
||||
if (player.GetSession().IsAddonRegistered(addonPrefix) && (guid.IsEmpty() || !player.GetSocial().HasIgnore(guid)))
|
||||
localizer.Invoke(player);
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetChannelId() { return _channelId; }
|
||||
public bool IsConstant() { return _channelId != 0; }
|
||||
|
||||
public bool IsLFG() { return GetFlags().HasAnyFlag(ChannelFlags.Lfg); }
|
||||
bool IsAnnounce() { return _announceEnabled; }
|
||||
void SetAnnounce(bool nannounce) { _announceEnabled = nannounce; }
|
||||
|
||||
string GetPassword() { return _channelPassword; }
|
||||
void SetPassword(string npassword) { _channelPassword = npassword; }
|
||||
|
||||
public uint GetNumPlayers() { return (uint)_playersStore.Count; }
|
||||
|
||||
public ChannelFlags GetFlags() { return _channelFlags; }
|
||||
bool HasFlag(ChannelFlags flag) { return _channelFlags.HasAnyFlag(flag); }
|
||||
|
||||
public AreaTableRecord GetZoneEntry() { return _zoneEntry; }
|
||||
|
||||
public void Kick(Player player, string badname) { KickOrBan(player, badname, false); }
|
||||
public void Ban(Player player, string badname) { KickOrBan(player, badname, true); }
|
||||
|
||||
public void SetModerator(Player player, string newname) { SetMode(player, newname, true, true); }
|
||||
public void UnsetModerator(Player player, string newname) { SetMode(player, newname, true, false); }
|
||||
public void SetMute(Player player, string newname) { SetMode(player, newname, false, true); }
|
||||
public void UnsetMute(Player player, string newname) { SetMode(player, newname, false, false); }
|
||||
|
||||
public void SetOwnership(bool ownership) { _ownershipEnabled = ownership; }
|
||||
|
||||
bool IsOn(ObjectGuid who) { return _playersStore.ContainsKey(who); }
|
||||
bool IsBanned(ObjectGuid guid) { return _bannedStore.Contains(guid); }
|
||||
|
||||
public ChannelMemberFlags GetPlayerFlags(ObjectGuid guid)
|
||||
{
|
||||
var info = _playersStore.LookupByKey(guid);
|
||||
return info != null ? info.GetFlags() : 0;
|
||||
}
|
||||
|
||||
bool _announceEnabled;
|
||||
bool _ownershipEnabled;
|
||||
bool _persistentChannel;
|
||||
bool _isOwnerInvisible;
|
||||
|
||||
ChannelFlags _channelFlags;
|
||||
uint _channelId;
|
||||
Team _channelTeam;
|
||||
ObjectGuid _ownerGuid;
|
||||
string _channelName;
|
||||
string _channelPassword;
|
||||
Dictionary<ObjectGuid, PlayerInfo> _playersStore = new Dictionary<ObjectGuid, PlayerInfo>();
|
||||
List<ObjectGuid> _bannedStore = new List<ObjectGuid>();
|
||||
|
||||
AreaTableRecord _zoneEntry;
|
||||
|
||||
public class PlayerInfo
|
||||
{
|
||||
public ChannelMemberFlags GetFlags() { return flags; }
|
||||
|
||||
public bool IsInvisible() { return _invisible; }
|
||||
public void SetInvisible(bool on) { _invisible = on; }
|
||||
|
||||
public bool HasFlag(ChannelMemberFlags flag) { return flags.HasAnyFlag(flag); }
|
||||
|
||||
public void SetFlag(ChannelMemberFlags flag) { flags |= flag; }
|
||||
|
||||
public void RemoveFlag(ChannelMemberFlags flag) { flags &= ~flag; }
|
||||
|
||||
public bool IsOwner() { return HasFlag(ChannelMemberFlags.Owner); }
|
||||
|
||||
public void SetOwner(bool state)
|
||||
{
|
||||
if (state)
|
||||
SetFlag(ChannelMemberFlags.Owner);
|
||||
else
|
||||
RemoveFlag(ChannelMemberFlags.Owner);
|
||||
}
|
||||
|
||||
public bool IsModerator() { return HasFlag(ChannelMemberFlags.Moderator); }
|
||||
|
||||
public void SetModerator(bool state)
|
||||
{
|
||||
if (state)
|
||||
SetFlag(ChannelMemberFlags.Moderator);
|
||||
else
|
||||
RemoveFlag(ChannelMemberFlags.Moderator);
|
||||
}
|
||||
|
||||
public bool IsMuted() { return HasFlag(ChannelMemberFlags.Muted); }
|
||||
|
||||
public void SetMuted(bool state)
|
||||
{
|
||||
if (state)
|
||||
SetFlag(ChannelMemberFlags.Muted);
|
||||
else
|
||||
RemoveFlag(ChannelMemberFlags.Muted);
|
||||
}
|
||||
|
||||
ChannelMemberFlags flags;
|
||||
bool _invisible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,716 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Network;
|
||||
using Game.Network.Packets;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
interface IChannelAppender
|
||||
{
|
||||
void Append(ChannelNotify data);
|
||||
ChatNotify GetNotificationType();
|
||||
}
|
||||
|
||||
// initial packet data (notify type and channel name)
|
||||
class ChannelNameBuilder : MessageBuilder
|
||||
{
|
||||
public ChannelNameBuilder(Channel source, IChannelAppender modifier)
|
||||
{
|
||||
_source = source;
|
||||
_modifier = modifier;
|
||||
}
|
||||
|
||||
public override ServerPacket Invoke(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
// LocalizedPacketDo sends client DBC locale, we need to get available to server locale
|
||||
LocaleConstant localeIdx = Global.WorldMgr.GetAvailableDbcLocale(locale);
|
||||
|
||||
ChannelNotify data = new ChannelNotify();
|
||||
data.Type = _modifier.GetNotificationType();
|
||||
data.Channel = _source.GetName(localeIdx);
|
||||
_modifier.Append(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Channel _source;
|
||||
IChannelAppender _modifier;
|
||||
}
|
||||
|
||||
class ChannelNotifyJoinedBuilder : MessageBuilder
|
||||
{
|
||||
public ChannelNotifyJoinedBuilder(Channel source)
|
||||
{
|
||||
_source = source;
|
||||
}
|
||||
|
||||
public override ServerPacket Invoke(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
LocaleConstant localeIdx = Global.WorldMgr.GetAvailableDbcLocale(locale);
|
||||
|
||||
ChannelNotifyJoined notify = new ChannelNotifyJoined();
|
||||
//notify->ChannelWelcomeMsg = "";
|
||||
notify.ChatChannelID = (int)_source.GetChannelId();
|
||||
//notify->InstanceID = 0;
|
||||
notify.ChannelFlags = _source.GetFlags();
|
||||
notify.Channel = _source.GetName(localeIdx);
|
||||
return notify;
|
||||
}
|
||||
|
||||
Channel _source;
|
||||
}
|
||||
|
||||
class ChannelNotifyLeftBuilder : MessageBuilder
|
||||
{
|
||||
public ChannelNotifyLeftBuilder(Channel source)
|
||||
{
|
||||
_source = source;
|
||||
}
|
||||
|
||||
public override ServerPacket Invoke(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
LocaleConstant localeIdx = Global.WorldMgr.GetAvailableDbcLocale(locale);
|
||||
|
||||
ChannelNotifyLeft notify = new ChannelNotifyLeft();
|
||||
notify.Channel = _source.GetName(localeIdx);
|
||||
notify.ChatChannelID = 0;
|
||||
//notify->Suspended = false;
|
||||
return notify;
|
||||
}
|
||||
|
||||
Channel _source;
|
||||
}
|
||||
|
||||
class ChannelSayBuilder : MessageBuilder
|
||||
{
|
||||
public ChannelSayBuilder(Channel source, Language lang, string what, ObjectGuid guid)
|
||||
{
|
||||
_source = source;
|
||||
_lang = lang;
|
||||
_what = what;
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public override ServerPacket Invoke(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
LocaleConstant localeIdx = Global.WorldMgr.GetAvailableDbcLocale(locale);
|
||||
|
||||
ChatPkt packet = new ChatPkt();
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(_guid);
|
||||
if (player)
|
||||
packet.Initialize(ChatMsg.Channel, _lang, player, player, _what, 0, _source.GetName(localeIdx));
|
||||
else
|
||||
{
|
||||
packet.Initialize(ChatMsg.Channel, _lang, null, null, _what, 0, _source.GetName(localeIdx));
|
||||
packet.SenderGUID = _guid;
|
||||
packet.TargetGUID = _guid;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
Channel _source;
|
||||
Language _lang;
|
||||
string _what;
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
class ChannelWhisperBuilder : MessageBuilder
|
||||
{
|
||||
public ChannelWhisperBuilder(Channel source, Language lang, string what, string prefix, ObjectGuid guid)
|
||||
{
|
||||
_source = source;
|
||||
_lang = lang;
|
||||
_what = what;
|
||||
_prefix = prefix;
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public override ServerPacket Invoke(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
LocaleConstant localeIdx = Global.WorldMgr.GetAvailableDbcLocale(locale);
|
||||
|
||||
ChatPkt packet = new ChatPkt();
|
||||
Player player = Global.ObjAccessor.FindConnectedPlayer(_guid);
|
||||
if (player)
|
||||
packet.Initialize(ChatMsg.Channel, Language.Addon, player, player, _what, 0, _source.GetName(localeIdx), LocaleConstant.enUS, _prefix);
|
||||
else
|
||||
{
|
||||
packet.Initialize(ChatMsg.Channel, Language.Addon, null, null, _what, 0, _source.GetName(localeIdx), LocaleConstant.enUS, _prefix);
|
||||
packet.SenderGUID = _guid;
|
||||
packet.TargetGUID = _guid;
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
Channel _source;
|
||||
Language _lang;
|
||||
string _what;
|
||||
string _prefix;
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
class ChannelUserlistAddBuilder : MessageBuilder
|
||||
{
|
||||
public ChannelUserlistAddBuilder(Channel source, ObjectGuid guid)
|
||||
{
|
||||
_source = source;
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public override ServerPacket Invoke(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
LocaleConstant localeIdx = Global.WorldMgr.GetAvailableDbcLocale(locale);
|
||||
|
||||
UserlistAdd userlistAdd = new UserlistAdd();
|
||||
userlistAdd.AddedUserGUID = _guid;
|
||||
userlistAdd.ChannelFlags = _source.GetFlags();
|
||||
userlistAdd.UserFlags = _source.GetPlayerFlags(_guid);
|
||||
userlistAdd.ChannelID = _source.GetChannelId();
|
||||
userlistAdd.ChannelName = _source.GetName(localeIdx);
|
||||
return userlistAdd;
|
||||
}
|
||||
|
||||
Channel _source;
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
class ChannelUserlistUpdateBuilder : MessageBuilder
|
||||
{
|
||||
public ChannelUserlistUpdateBuilder(Channel source, ObjectGuid guid)
|
||||
{
|
||||
_source = source;
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public override ServerPacket Invoke(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
LocaleConstant localeIdx = Global.WorldMgr.GetAvailableDbcLocale(locale);
|
||||
|
||||
UserlistUpdate userlistUpdate = new UserlistUpdate();
|
||||
userlistUpdate.UpdatedUserGUID = _guid;
|
||||
userlistUpdate.ChannelFlags = _source.GetFlags();
|
||||
userlistUpdate.UserFlags = _source.GetPlayerFlags(_guid);
|
||||
userlistUpdate.ChannelID = _source.GetChannelId();
|
||||
userlistUpdate.ChannelName = _source.GetName(localeIdx);
|
||||
return userlistUpdate;
|
||||
}
|
||||
|
||||
Channel _source;
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
class ChannelUserlistRemoveBuilder : MessageBuilder
|
||||
{
|
||||
public ChannelUserlistRemoveBuilder(Channel source, ObjectGuid guid)
|
||||
{
|
||||
_source = source;
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public override ServerPacket Invoke(LocaleConstant locale = LocaleConstant.enUS)
|
||||
{
|
||||
LocaleConstant localeIdx = Global.WorldMgr.GetAvailableDbcLocale(locale);
|
||||
|
||||
UserlistRemove userlistRemove = new UserlistRemove();
|
||||
userlistRemove.RemovedUserGUID = _guid;
|
||||
userlistRemove.ChannelFlags = _source.GetFlags();
|
||||
userlistRemove.ChannelID = _source.GetChannelId();
|
||||
userlistRemove.ChannelName = _source.GetName(localeIdx);
|
||||
return userlistRemove;
|
||||
}
|
||||
|
||||
Channel _source;
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
//Appenders
|
||||
struct JoinedAppend : IChannelAppender
|
||||
{
|
||||
public JoinedAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.JoinedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct LeftAppend : IChannelAppender
|
||||
{
|
||||
public LeftAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.LeftNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct YouJoinedAppend : IChannelAppender
|
||||
{
|
||||
public YouJoinedAppend(Channel channel)
|
||||
{
|
||||
_channel = channel;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.YouJoinedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.ChatChannelID = (int)_channel.GetChannelId();
|
||||
}
|
||||
|
||||
Channel _channel;
|
||||
}
|
||||
|
||||
struct YouLeftAppend : IChannelAppender
|
||||
{
|
||||
public YouLeftAppend(Channel channel)
|
||||
{
|
||||
_channel = channel;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.YouLeftNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.ChatChannelID = (int)_channel.GetChannelId();
|
||||
}
|
||||
|
||||
Channel _channel;
|
||||
}
|
||||
|
||||
struct WrongPasswordAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.WrongPasswordNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct NotMemberAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.NotMemberNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct NotModeratorAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.NotModeratorNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct PasswordChangedAppend : IChannelAppender
|
||||
{
|
||||
public PasswordChangedAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PasswordChangedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct OwnerChangedAppend : IChannelAppender
|
||||
{
|
||||
public OwnerChangedAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.OwnerChangedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct PlayerNotFoundAppend : IChannelAppender
|
||||
{
|
||||
public PlayerNotFoundAppend(string playerName)
|
||||
{
|
||||
_playerName = playerName;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PlayerNotFoundNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.Sender = _playerName;
|
||||
}
|
||||
|
||||
string _playerName;
|
||||
}
|
||||
|
||||
struct NotOwnerAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.NotOwnerNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct ChannelOwnerAppend : IChannelAppender
|
||||
{
|
||||
public ChannelOwnerAppend(Channel channel, ObjectGuid ownerGuid)
|
||||
{
|
||||
_channel = channel;
|
||||
_ownerGuid = ownerGuid;
|
||||
_ownerName = "";
|
||||
|
||||
CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(_ownerGuid);
|
||||
if (characterInfo != null)
|
||||
_ownerName = characterInfo.Name;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.ChannelOwnerNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.Sender = ((_channel.IsConstant() || _ownerGuid.IsEmpty()) ? "Nobody" : _ownerName);
|
||||
}
|
||||
|
||||
Channel _channel;
|
||||
ObjectGuid _ownerGuid;
|
||||
|
||||
string _ownerName;
|
||||
}
|
||||
|
||||
struct ModeChangeAppend : IChannelAppender
|
||||
{
|
||||
public ModeChangeAppend(ObjectGuid guid, ChannelMemberFlags oldFlags, ChannelMemberFlags newFlags)
|
||||
{
|
||||
_guid = guid;
|
||||
_oldFlags = oldFlags;
|
||||
_newFlags = newFlags;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.ModeChangeNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
data.OldFlags = _oldFlags;
|
||||
data.NewFlags = _newFlags;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
ChannelMemberFlags _oldFlags;
|
||||
ChannelMemberFlags _newFlags;
|
||||
}
|
||||
|
||||
struct AnnouncementsOnAppend : IChannelAppender
|
||||
{
|
||||
public AnnouncementsOnAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.AnnouncementsOnNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct AnnouncementsOffAppend : IChannelAppender
|
||||
{
|
||||
public AnnouncementsOffAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.AnnouncementsOffNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct MutedAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.MutedNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct PlayerKickedAppend : IChannelAppender
|
||||
{
|
||||
public PlayerKickedAppend(ObjectGuid kicker, ObjectGuid kickee)
|
||||
{
|
||||
_kicker = kicker;
|
||||
_kickee = kickee;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PlayerKickedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _kicker;
|
||||
data.TargetGuid = _kickee;
|
||||
}
|
||||
|
||||
ObjectGuid _kicker;
|
||||
ObjectGuid _kickee;
|
||||
}
|
||||
|
||||
struct BannedAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.BannedNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct PlayerBannedAppend : IChannelAppender
|
||||
{
|
||||
public PlayerBannedAppend(ObjectGuid moderator, ObjectGuid banned)
|
||||
{
|
||||
_moderator = moderator;
|
||||
_banned = banned;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PlayerBannedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _moderator;
|
||||
data.TargetGuid = _banned;
|
||||
}
|
||||
|
||||
ObjectGuid _moderator;
|
||||
ObjectGuid _banned;
|
||||
}
|
||||
|
||||
struct PlayerUnbannedAppend : IChannelAppender
|
||||
{
|
||||
public PlayerUnbannedAppend(ObjectGuid moderator, ObjectGuid unbanned)
|
||||
{
|
||||
_moderator = moderator;
|
||||
_unbanned = unbanned;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PlayerUnbannedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _moderator;
|
||||
data.TargetGuid = _unbanned;
|
||||
}
|
||||
|
||||
ObjectGuid _moderator;
|
||||
ObjectGuid _unbanned;
|
||||
}
|
||||
|
||||
struct PlayerNotBannedAppend : IChannelAppender
|
||||
{
|
||||
public PlayerNotBannedAppend(string playerName)
|
||||
{
|
||||
_playerName = playerName;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PlayerNotBannedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.Sender = _playerName;
|
||||
}
|
||||
|
||||
string _playerName;
|
||||
}
|
||||
|
||||
struct PlayerAlreadyMemberAppend : IChannelAppender
|
||||
{
|
||||
public PlayerAlreadyMemberAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PlayerAlreadyMemberNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct InviteAppend : IChannelAppender
|
||||
{
|
||||
public InviteAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.InviteNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct InviteWrongFactionAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.InviteWrongFactionNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct WrongFactionAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.WrongFactionNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct InvalidNameAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.InvalidNameNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct NotModeratedAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.NotModeratedNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct PlayerInvitedAppend : IChannelAppender
|
||||
{
|
||||
public PlayerInvitedAppend(string playerName)
|
||||
{
|
||||
_playerName = playerName;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PlayerInvitedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.Sender = _playerName;
|
||||
}
|
||||
|
||||
string _playerName;
|
||||
}
|
||||
|
||||
struct PlayerInviteBannedAppend : IChannelAppender
|
||||
{
|
||||
public PlayerInviteBannedAppend(string playerName)
|
||||
{
|
||||
_playerName = playerName;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.PlayerInviteBannedNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.Sender = _playerName;
|
||||
}
|
||||
|
||||
string _playerName;
|
||||
}
|
||||
|
||||
struct ThrottledAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.ThrottledNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct NotInAreaAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.NotInAreaNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct NotInLFGAppend : IChannelAppender
|
||||
{
|
||||
public ChatNotify GetNotificationType() => ChatNotify.NotInLfgNotice;
|
||||
|
||||
public void Append(ChannelNotify data) { }
|
||||
}
|
||||
|
||||
struct VoiceOnAppend : IChannelAppender
|
||||
{
|
||||
public VoiceOnAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.VoiceOnNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
|
||||
struct VoiceOffAppend : IChannelAppender
|
||||
{
|
||||
public VoiceOffAppend(ObjectGuid guid)
|
||||
{
|
||||
_guid = guid;
|
||||
}
|
||||
|
||||
public ChatNotify GetNotificationType() => ChatNotify.VoiceOffNotice;
|
||||
|
||||
public void Append(ChannelNotify data)
|
||||
{
|
||||
data.SenderGuid = _guid;
|
||||
}
|
||||
|
||||
ObjectGuid _guid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
public class ChannelManager
|
||||
{
|
||||
public ChannelManager(Team team)
|
||||
{
|
||||
_team = team;
|
||||
}
|
||||
|
||||
public static ChannelManager ForTeam(Team team)
|
||||
{
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionChannel))
|
||||
return allianceChannelMgr; // cross-faction
|
||||
|
||||
if (team == Team.Alliance)
|
||||
return allianceChannelMgr;
|
||||
|
||||
if (team == Team.Horde)
|
||||
return hordeChannelMgr;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Channel GetChannelForPlayerByNamePart(string namePart, Player playerSearcher)
|
||||
{
|
||||
foreach (Channel channel in playerSearcher.GetJoinedChannels())
|
||||
{
|
||||
string chanName = channel.GetName(playerSearcher.GetSession().GetSessionDbcLocale());
|
||||
if (chanName.ToLower().Equals(namePart.ToLower()))
|
||||
return channel;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Channel GetJoinChannel(uint channelId, string name, AreaTableRecord zoneEntry = null)
|
||||
{
|
||||
if (channelId != 0) // builtin
|
||||
{
|
||||
ChatChannelsRecord channelEntry = CliDB.ChatChannelsStorage.LookupByKey(channelId);
|
||||
uint zoneId = zoneEntry != null ? zoneEntry.Id : 0;
|
||||
if (channelEntry.Flags.HasAnyFlag(ChannelDBCFlags.Global | ChannelDBCFlags.CityOnly))
|
||||
zoneId = 0;
|
||||
|
||||
Tuple<uint, uint> key = Tuple.Create(channelId, zoneId);
|
||||
var channel = _channels.LookupByKey(key);
|
||||
if (channel != null)
|
||||
return channel;
|
||||
|
||||
Channel newChannel = new Channel(channelId, _team, zoneEntry);
|
||||
_channels[key] = newChannel;
|
||||
return newChannel;
|
||||
}
|
||||
else // custom
|
||||
{
|
||||
var channel = _customChannels.LookupByKey(name.ToLower());
|
||||
if (channel != null)
|
||||
return channel;
|
||||
|
||||
Channel newChannel = new Channel(name, _team);
|
||||
_customChannels[name.ToLower()] = newChannel;
|
||||
return newChannel;
|
||||
}
|
||||
}
|
||||
|
||||
public Channel GetChannel(uint channelId, string name, Player player, bool notify = true, AreaTableRecord zoneEntry = null)
|
||||
{
|
||||
Channel result = null;
|
||||
if (channelId != 0) // builtin
|
||||
{
|
||||
ChatChannelsRecord channelEntry = CliDB.ChatChannelsStorage.LookupByKey(channelId);
|
||||
uint zoneId = zoneEntry != null ? zoneEntry.Id : 0;
|
||||
if (channelEntry.Flags.HasAnyFlag(ChannelDBCFlags.Global | ChannelDBCFlags.CityOnly))
|
||||
zoneId = 0;
|
||||
|
||||
Tuple<uint, uint> key = Tuple.Create(channelId, zoneId);
|
||||
var channel = _channels.LookupByKey(key);
|
||||
if (channel != null)
|
||||
result = channel;
|
||||
}
|
||||
else // custom
|
||||
{
|
||||
var channel = _customChannels.LookupByKey(name.ToLower());
|
||||
if (channel != null)
|
||||
result = channel;
|
||||
}
|
||||
|
||||
if (result == null && notify)
|
||||
{
|
||||
string channelName = name;
|
||||
Channel.GetChannelName(ref channelName, channelId, player.GetSession().GetSessionDbcLocale(), zoneEntry);
|
||||
|
||||
SendNotOnChannelNotify(player, channelName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void LeftChannel(string name)
|
||||
{
|
||||
string channelName = name.ToLower();
|
||||
|
||||
var channel = _customChannels.LookupByKey(channelName);
|
||||
if (channel == null)
|
||||
return;
|
||||
|
||||
if (channel.GetNumPlayers() == 0)
|
||||
_customChannels.Remove(channelName);
|
||||
}
|
||||
|
||||
public void LeftChannel(uint channelId, AreaTableRecord zoneEntry)
|
||||
{
|
||||
ChatChannelsRecord channelEntry = CliDB.ChatChannelsStorage.LookupByKey(channelId);
|
||||
uint zoneId = zoneEntry != null ? zoneEntry.Id : 0;
|
||||
if (channelEntry.Flags.HasAnyFlag(ChannelDBCFlags.Global | ChannelDBCFlags.CityOnly))
|
||||
zoneId = 0;
|
||||
|
||||
Tuple<uint, uint> key = Tuple.Create(channelId, zoneId);
|
||||
var channel = _channels.LookupByKey(key);
|
||||
if (channel == null)
|
||||
return;
|
||||
|
||||
if (channel.GetNumPlayers() == 0)
|
||||
_channels.Remove(key);
|
||||
}
|
||||
|
||||
public static void SendNotOnChannelNotify(Player player, string name)
|
||||
{
|
||||
ChannelNotify notify = new ChannelNotify();
|
||||
notify.Type = ChatNotify.NotMemberNotice;
|
||||
notify.Channel = name;
|
||||
player.SendPacket(notify);
|
||||
}
|
||||
|
||||
Dictionary<string, Channel> _customChannels = new Dictionary<string, Channel>();
|
||||
Dictionary<Tuple<uint /*channelId*/, uint /*zoneId*/>, Channel> _channels = new Dictionary<Tuple<uint, uint>, Channel>();
|
||||
Team _team;
|
||||
|
||||
static ChannelManager allianceChannelMgr = new ChannelManager(Team.Alliance);
|
||||
static ChannelManager hordeChannelMgr = new ChannelManager(Team.Horde);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using System;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class CommandAttribute : Attribute
|
||||
{
|
||||
public CommandAttribute(string command, RBACPermissions rbac, bool allowConsole = false)
|
||||
{
|
||||
Name = command.ToLower();
|
||||
Help = "";
|
||||
RBAC = rbac;
|
||||
AllowConsole = allowConsole;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command's name.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Help text for command.
|
||||
/// </summary>
|
||||
public string Help { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allow Console?
|
||||
/// </summary>
|
||||
public bool AllowConsole { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum user level required to invoke the command.
|
||||
/// </summary>
|
||||
public RBACPermissions RBAC { get; set; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class CommandGroupAttribute : CommandAttribute
|
||||
{
|
||||
public CommandGroupAttribute(string command, RBACPermissions rbac, bool allowConsole = false) : base(command, rbac, allowConsole) { }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class CommandNonGroupAttribute : CommandAttribute
|
||||
{
|
||||
public CommandNonGroupAttribute(string command, RBACPermissions rbac, bool allowConsole = false) : base(command, rbac, allowConsole) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,877 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Collections;
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Maps;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
public class CommandHandler
|
||||
{
|
||||
public CommandHandler(WorldSession session = null)
|
||||
{
|
||||
_session = session;
|
||||
}
|
||||
|
||||
public bool ParseCommand(string fullCmd)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fullCmd))
|
||||
return false;
|
||||
|
||||
string text = fullCmd;
|
||||
// chat case (.command or !command format)
|
||||
if (_session != null)
|
||||
{
|
||||
if (text[0] != '!' && text[0] != '.')
|
||||
return false;
|
||||
}
|
||||
|
||||
if (text.Length < 2)
|
||||
return false;
|
||||
|
||||
/// ignore messages staring from many dots.
|
||||
if ((text[0] == '.' && text[1] == '.') || (text[0] == '!' && text[1] == '!'))
|
||||
return false;
|
||||
|
||||
/// skip first . or ! (in console allowed use command with . and ! and without its)
|
||||
if (text[0] == '!' || text[0] == '.')
|
||||
text = text.Substring(1);
|
||||
|
||||
if (!ExecuteCommandInTable(CommandManager.GetCommands(), text, fullCmd))
|
||||
{
|
||||
if (_session != null && !_session.HasPermission(RBACPermissions.CommandsNotifyCommandNotFoundError))
|
||||
return false;
|
||||
|
||||
SendSysMessage(CypherStrings.NoCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ExecuteCommandInTable(List<ChatCommand> table, string text, string fullcmd)
|
||||
{
|
||||
string oldtext = text;
|
||||
StringArguments args = new StringArguments(text);
|
||||
string cmd = args.NextString();
|
||||
|
||||
foreach (var command in table)
|
||||
{
|
||||
if (!hasStringAbbr(command.Name, cmd))
|
||||
continue;
|
||||
|
||||
bool match = false;
|
||||
if (command.Name.Length > cmd.Length)
|
||||
{
|
||||
foreach (var command2 in table)
|
||||
{
|
||||
if (!hasStringAbbr(command2.Name, cmd))
|
||||
continue;
|
||||
|
||||
if (command2.Name.Equals(cmd))
|
||||
{
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match)
|
||||
continue;
|
||||
|
||||
if (!command.ChildCommands.Empty())
|
||||
{
|
||||
if (!ExecuteCommandInTable(command.ChildCommands, args.NextString(""), fullcmd))
|
||||
{
|
||||
string arg = args.NextString("");
|
||||
if (!arg.IsEmpty())
|
||||
SendSysMessage(CypherStrings.NoSubcmd);
|
||||
else
|
||||
SendSysMessage(CypherStrings.CmdSyntax);
|
||||
|
||||
ShowHelpForCommand(command.ChildCommands, arg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// must be available and have handler
|
||||
if (command.Handler == null || !IsAvailable(command))
|
||||
continue;
|
||||
|
||||
_sentErrorMessage = false;
|
||||
if (command.Handler(new StringArguments(!command.Name.IsEmpty() ? args.NextString("") : oldtext), this))
|
||||
{
|
||||
if (GetSession() == null) // ignore console
|
||||
return true;
|
||||
|
||||
Player player = GetPlayer();
|
||||
if (!Global.AccountMgr.IsPlayerAccount(GetSession().GetSecurity()))
|
||||
{
|
||||
ObjectGuid guid = player.GetTarget();
|
||||
uint areaId = player.GetAreaId();
|
||||
string areaName = "Unknown";
|
||||
string zoneName = "Unknown";
|
||||
|
||||
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(areaId);
|
||||
if (area != null)
|
||||
{
|
||||
var locale = GetSessionDbcLocale();
|
||||
areaName = area.AreaName[locale];
|
||||
AreaTableRecord zone = CliDB.AreaTableStorage.LookupByKey(area.ParentAreaID);
|
||||
if (zone != null)
|
||||
zoneName = zone.AreaName[locale];
|
||||
}
|
||||
|
||||
Log.outCommand(GetSession().GetAccountId(), "Command: {0} [Player: {1} ({2}) (Account: {3}) Postion: {4} Map: {5} ({6}) Area: {7} ({8}) Zone: {9} Selected: {10} ({11})]",
|
||||
fullcmd, player.GetName(), player.GetGUID().ToString(), GetSession().GetAccountId(), player.GetPosition(), player.GetMapId(),
|
||||
player.GetMap() ? player.GetMap().GetMapName() : "Unknown", areaId, areaName, zoneName, (player.GetSelectedUnit()) ? player.GetSelectedUnit().GetName() : "", guid.ToString());
|
||||
}
|
||||
}
|
||||
else if (!HasSentErrorMessage())
|
||||
{
|
||||
if (!command.Help.IsEmpty())
|
||||
SendSysMessage(command.Help);
|
||||
else
|
||||
SendSysMessage(CypherStrings.CmdSyntax);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool ShowHelpForCommand(List<ChatCommand> table, string text)
|
||||
{
|
||||
StringArguments args = new StringArguments(text);
|
||||
if (!args.Empty())
|
||||
{
|
||||
string cmd = args.NextString();
|
||||
foreach (var command in table)
|
||||
{
|
||||
// must be available (ignore handler existence for show command with possible available subcommands)
|
||||
if (!IsAvailable(command))
|
||||
continue;
|
||||
|
||||
if (!hasStringAbbr(command.Name, cmd))
|
||||
continue;
|
||||
|
||||
// have subcommand
|
||||
string subcmd = !cmd.IsEmpty() ? args.NextString() : "";
|
||||
if (!command.ChildCommands.Empty() && !subcmd.IsEmpty())
|
||||
{
|
||||
if (ShowHelpForCommand(command.ChildCommands, subcmd))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!command.Help.IsEmpty())
|
||||
SendSysMessage(command.Help);
|
||||
|
||||
if (!command.ChildCommands.Empty())
|
||||
if (ShowHelpForSubCommands(command.ChildCommands, command.Name, subcmd))
|
||||
return true;
|
||||
|
||||
return !command.Help.IsEmpty();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var command in table)
|
||||
{
|
||||
// must be available (ignore handler existence for show command with possible available subcommands)
|
||||
if (!IsAvailable(command))
|
||||
continue;
|
||||
|
||||
if (!command.Name.IsEmpty())
|
||||
continue;
|
||||
|
||||
if (!command.Help.IsEmpty())
|
||||
SendSysMessage(command.Help);
|
||||
|
||||
if (!command.ChildCommands.Empty())
|
||||
if (ShowHelpForSubCommands(command.ChildCommands, "", ""))
|
||||
return true;
|
||||
|
||||
return !command.Help.IsEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
return ShowHelpForSubCommands(table, "", text);
|
||||
}
|
||||
|
||||
public bool ShowHelpForSubCommands(List<ChatCommand> table, string cmd, string subcmd)
|
||||
{
|
||||
string list = "";
|
||||
foreach (var command in table)
|
||||
{
|
||||
// must be available (ignore handler existence for show command with possible available subcommands)
|
||||
if (!IsAvailable(command))
|
||||
continue;
|
||||
|
||||
// for empty subcmd show all available
|
||||
if (!subcmd.IsEmpty() && !hasStringAbbr(command.Name, subcmd))
|
||||
continue;
|
||||
|
||||
if (GetSession() != null)
|
||||
list += "\n ";
|
||||
else
|
||||
list += "\n\r ";
|
||||
|
||||
list += command.Name;
|
||||
|
||||
if (!command.ChildCommands.Empty())
|
||||
list += " ...";
|
||||
}
|
||||
|
||||
if (list.IsEmpty())
|
||||
return false;
|
||||
|
||||
if (table == CommandManager.GetCommands())
|
||||
{
|
||||
SendSysMessage(CypherStrings.AvailableCmd);
|
||||
SendSysMessage(list);
|
||||
}
|
||||
else
|
||||
SendSysMessage(CypherStrings.SubcmdsList, cmd, list);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool IsAvailable(ChatCommand cmd)
|
||||
{
|
||||
return HasPermission(cmd.Permission);
|
||||
}
|
||||
|
||||
public virtual bool HasPermission(RBACPermissions permission) { return _session.HasPermission(permission); }
|
||||
|
||||
public string extractKeyFromLink(StringArguments args, params string[] linkType)
|
||||
{
|
||||
int throwaway;
|
||||
return extractKeyFromLink(args, linkType, out throwaway);
|
||||
}
|
||||
public string extractKeyFromLink(StringArguments args, string[] linkType, out int found_idx)
|
||||
{
|
||||
string throwaway;
|
||||
return extractKeyFromLink(args, linkType, out found_idx, out throwaway);
|
||||
}
|
||||
public string extractKeyFromLink(StringArguments args, string[] linkType, out int found_idx, out string something1)
|
||||
{
|
||||
found_idx = 0;
|
||||
something1 = null;
|
||||
|
||||
// skip empty
|
||||
if (args.Empty())
|
||||
return null;
|
||||
|
||||
// return non link case
|
||||
if (args[0] != '|')
|
||||
return args.NextString();
|
||||
|
||||
if (args[1] == 'c')
|
||||
{
|
||||
string check = args.NextString("|");
|
||||
if (string.IsNullOrEmpty(check))
|
||||
return null;
|
||||
}
|
||||
else
|
||||
args.NextChar();
|
||||
|
||||
string cLinkType = args.NextString(":");
|
||||
if (string.IsNullOrEmpty(cLinkType))
|
||||
return null;
|
||||
|
||||
for (var i = 0; i < linkType.Length; ++i)
|
||||
{
|
||||
if (cLinkType == linkType[i])
|
||||
{
|
||||
string cKey = args.NextString(":|"); // extract key
|
||||
|
||||
something1 = args.NextString(":|"); // extract something
|
||||
|
||||
args.NextString("]"); // restart scan tail and skip name with possible spaces
|
||||
args.NextString(); // skip link tail (to allow continue strtok(NULL, s) use after return from function
|
||||
found_idx = i;
|
||||
return cKey;
|
||||
}
|
||||
}
|
||||
|
||||
args.NextString();
|
||||
SendSysMessage(CypherStrings.WrongLinkType);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void extractOptFirstArg(StringArguments args, out string arg1, out string arg2)
|
||||
{
|
||||
string p1 = args.NextString();
|
||||
string p2 = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(p2))
|
||||
{
|
||||
p2 = p1;
|
||||
p1 = null;
|
||||
}
|
||||
|
||||
arg1 = p1;
|
||||
arg2 = p2;
|
||||
}
|
||||
|
||||
public GameTele extractGameTeleFromLink(StringArguments args)
|
||||
{
|
||||
string cId = extractKeyFromLink(args, "Htele");
|
||||
if (string.IsNullOrEmpty(cId))
|
||||
return null;
|
||||
|
||||
uint id;
|
||||
if (!uint.TryParse(cId, out id))
|
||||
return null;
|
||||
|
||||
return Global.ObjectMgr.GetGameTele(id);
|
||||
}
|
||||
|
||||
public string extractQuotedArg(string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return null;
|
||||
|
||||
if (!str.Contains("\""))
|
||||
return null;
|
||||
|
||||
return str.Replace("\"", String.Empty);
|
||||
}
|
||||
string extractPlayerNameFromLink(StringArguments args)
|
||||
{
|
||||
// |color|Hplayer:name|h[name]|h|r
|
||||
string name = extractKeyFromLink(args, "Hplayer");
|
||||
if (name.IsEmpty())
|
||||
return "";
|
||||
|
||||
if (!ObjectManager.NormalizePlayerName(ref name))
|
||||
return "";
|
||||
|
||||
return name;
|
||||
}
|
||||
public bool extractPlayerTarget(StringArguments args, out Player player)
|
||||
{
|
||||
ObjectGuid guid;
|
||||
string name;
|
||||
return extractPlayerTarget(args, out player, out guid, out name);
|
||||
}
|
||||
public bool extractPlayerTarget(StringArguments args, out Player player, out ObjectGuid playerGuid)
|
||||
{
|
||||
string name;
|
||||
return extractPlayerTarget(args, out player, out playerGuid, out name);
|
||||
}
|
||||
|
||||
public bool extractPlayerTarget(StringArguments args, out Player player, out ObjectGuid playerGuid, out string playerName)
|
||||
{
|
||||
player = null;
|
||||
playerGuid = ObjectGuid.Empty;
|
||||
playerName = "";
|
||||
|
||||
if (!args.Empty())
|
||||
{
|
||||
string name = extractPlayerNameFromLink(args);
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
_sentErrorMessage = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
player = Global.ObjAccessor.FindPlayerByName(name);
|
||||
ObjectGuid guid = player == null ? ObjectManager.GetPlayerGUIDByName(name) : ObjectGuid.Empty;
|
||||
|
||||
playerGuid = player != null ? player.GetGUID() : guid;
|
||||
playerName = player != null || !guid.IsEmpty() ? name : "";
|
||||
}
|
||||
else
|
||||
{
|
||||
player = getSelectedPlayer();
|
||||
playerGuid = player != null ? player.GetGUID() : ObjectGuid.Empty;
|
||||
playerName = player != null ? player.GetName() : "";
|
||||
}
|
||||
|
||||
if (player == null && playerGuid.IsEmpty() && string.IsNullOrEmpty(playerName))
|
||||
{
|
||||
SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
_sentErrorMessage = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public ulong extractLowGuidFromLink(StringArguments args, ref HighGuid guidHigh)
|
||||
{
|
||||
int type;
|
||||
|
||||
string[] guidKeys =
|
||||
{
|
||||
"Hplayer",
|
||||
"Hcreature",
|
||||
"Hgameobject"
|
||||
};
|
||||
// |color|Hcreature:creature_guid|h[name]|h|r
|
||||
// |color|Hgameobject:go_guid|h[name]|h|r
|
||||
// |color|Hplayer:name|h[name]|h|r
|
||||
string idS = extractKeyFromLink(args, guidKeys, out type);
|
||||
if (string.IsNullOrEmpty(idS))
|
||||
return 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
guidHigh = HighGuid.Player;
|
||||
if (!ObjectManager.NormalizePlayerName(ref idS))
|
||||
return 0;
|
||||
|
||||
Player player = Global.ObjAccessor.FindPlayerByName(idS);
|
||||
if (player)
|
||||
return player.GetGUID().GetCounter();
|
||||
|
||||
ObjectGuid guid = ObjectManager.GetPlayerGUIDByName(idS);
|
||||
if (guid.IsEmpty())
|
||||
return 0;
|
||||
|
||||
return guid.GetCounter();
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
guidHigh = HighGuid.Creature;
|
||||
ulong lowguid = ulong.Parse(idS);
|
||||
return lowguid;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
guidHigh = HighGuid.GameObject;
|
||||
ulong lowguid = ulong.Parse(idS);
|
||||
return lowguid;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown type?
|
||||
return 0;
|
||||
}
|
||||
|
||||
static string[] spellKeys =
|
||||
{
|
||||
"Hspell", // normal spell
|
||||
"Htalent", // talent spell
|
||||
"Henchant", // enchanting recipe spell
|
||||
"Htrade", // profession/skill spell
|
||||
"Hglyph", // glyph
|
||||
};
|
||||
public uint extractSpellIdFromLink(StringArguments args)
|
||||
{
|
||||
// number or [name] Shift-click form |color|Henchant:recipe_spell_id|h[prof_name: recipe_name]|h|r
|
||||
// number or [name] Shift-click form |color|Hglyph:glyph_slot_id:glyph_prop_id|h[value]|h|r
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r
|
||||
// number or [name] Shift-click form |color|Htalent:talent_id, rank|h[name]|h|r
|
||||
// number or [name] Shift-click form |color|Htrade:spell_id, skill_id, max_value, cur_value|h[name]|h|r
|
||||
int type = 0;
|
||||
string param1_str = null;
|
||||
string idS = extractKeyFromLink(args, spellKeys, out type, out param1_str);
|
||||
if (string.IsNullOrEmpty(idS))
|
||||
return 0;
|
||||
|
||||
uint id = uint.Parse(idS);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
return id;
|
||||
case 1:
|
||||
{
|
||||
// talent
|
||||
TalentRecord talentEntry = CliDB.TalentStorage.LookupByKey(id);
|
||||
if (talentEntry == null)
|
||||
return 0;
|
||||
|
||||
return talentEntry.SpellID;
|
||||
}
|
||||
case 2:
|
||||
case 3:
|
||||
return id;
|
||||
case 4:
|
||||
{
|
||||
uint glyph_prop_id = !string.IsNullOrEmpty(param1_str) ? uint.Parse(param1_str) : 0;
|
||||
|
||||
GlyphPropertiesRecord glyphPropEntry = CliDB.GlyphPropertiesStorage.LookupByKey(glyph_prop_id);
|
||||
if (glyphPropEntry == null)
|
||||
return 0;
|
||||
|
||||
return glyphPropEntry.SpellID;
|
||||
}
|
||||
}
|
||||
|
||||
// unknown type?
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Player getSelectedPlayer()
|
||||
{
|
||||
if (_session == null)
|
||||
return null;
|
||||
|
||||
ObjectGuid selected = _session.GetPlayer().GetTarget();
|
||||
|
||||
if (selected.IsEmpty())
|
||||
return _session.GetPlayer();
|
||||
|
||||
return Global.ObjAccessor.FindPlayer(selected);
|
||||
}
|
||||
public Unit getSelectedUnit()
|
||||
{
|
||||
if (_session == null)
|
||||
return null;
|
||||
|
||||
ObjectGuid selected = _session.GetPlayer().GetTarget();
|
||||
|
||||
if (selected.IsEmpty())
|
||||
return _session.GetPlayer();
|
||||
|
||||
return Global.ObjAccessor.GetUnit(_session.GetPlayer(), selected);
|
||||
}
|
||||
public WorldObject GetSelectedObject()
|
||||
{
|
||||
if (_session == null)
|
||||
return null;
|
||||
|
||||
ObjectGuid selected = _session.GetPlayer().GetTarget();
|
||||
|
||||
if (selected.IsEmpty())
|
||||
return GetNearbyGameObject();
|
||||
|
||||
return Global.ObjAccessor.GetUnit(_session.GetPlayer(), selected);
|
||||
}
|
||||
public Creature getSelectedCreature()
|
||||
{
|
||||
if (_session == null)
|
||||
return null;
|
||||
|
||||
return ObjectAccessor.GetCreatureOrPetOrVehicle(_session.GetPlayer(), _session.GetPlayer().GetTarget());
|
||||
}
|
||||
public Player getSelectedPlayerOrSelf()
|
||||
{
|
||||
if (_session == null)
|
||||
return null;
|
||||
|
||||
ObjectGuid selected = _session.GetPlayer().GetTarget();
|
||||
if (selected.IsEmpty())
|
||||
return _session.GetPlayer();
|
||||
|
||||
// first try with selected target
|
||||
Player targetPlayer = Global.ObjAccessor.FindConnectedPlayer(selected);
|
||||
// if the target is not a player, then return self
|
||||
if (!targetPlayer)
|
||||
targetPlayer = _session.GetPlayer();
|
||||
|
||||
return targetPlayer;
|
||||
}
|
||||
|
||||
public GameObject GetObjectFromPlayerMapByDbGuid(ulong lowguid)
|
||||
{
|
||||
if (_session == null)
|
||||
return null;
|
||||
|
||||
var bounds = _session.GetPlayer().GetMap().GetGameObjectBySpawnIdStore().LookupByKey(lowguid);
|
||||
if (!bounds.Empty())
|
||||
return bounds.First();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Creature GetCreatureFromPlayerMapByDbGuid(ulong lowguid)
|
||||
{
|
||||
if (!_session)
|
||||
return null;
|
||||
|
||||
// Select the first alive creature or a dead one if not found
|
||||
Creature creature = null;
|
||||
var bounds = _session.GetPlayer().GetMap().GetCreatureBySpawnIdStore().LookupByKey(lowguid);
|
||||
foreach (var it in bounds)
|
||||
{
|
||||
creature = it;
|
||||
if (it.IsAlive())
|
||||
break;
|
||||
}
|
||||
|
||||
return creature;
|
||||
}
|
||||
GameObject GetNearbyGameObject()
|
||||
{
|
||||
if (_session == null)
|
||||
return null;
|
||||
|
||||
Player pl = _session.GetPlayer();
|
||||
NearestGameObjectCheck check = new NearestGameObjectCheck(pl);
|
||||
GameObjectLastSearcher searcher = new GameObjectLastSearcher(pl, check);
|
||||
Cell.VisitGridObjects(pl, searcher, MapConst.SizeofGrids);
|
||||
return searcher.GetTarget();
|
||||
}
|
||||
|
||||
public string playerLink(string name, bool console = false)
|
||||
{
|
||||
return console ? name : "|cffffffff|Hplayer:" + name + "|h[" + name + "]|h|r";
|
||||
}
|
||||
public virtual string GetNameLink()
|
||||
{
|
||||
return GetNameLink(_session.GetPlayer());
|
||||
}
|
||||
public string GetNameLink(Player obj)
|
||||
{
|
||||
return playerLink(obj.GetName());
|
||||
}
|
||||
public virtual bool needReportToTarget(Player chr)
|
||||
{
|
||||
Player pl = _session.GetPlayer();
|
||||
return pl != chr && pl.IsVisibleGloballyFor(chr);
|
||||
}
|
||||
public bool HasLowerSecurity(Player target, ObjectGuid guid, bool strong = false)
|
||||
{
|
||||
WorldSession target_session = null;
|
||||
uint target_account = 0;
|
||||
|
||||
if (target != null)
|
||||
target_session = target.GetSession();
|
||||
else if (!guid.IsEmpty())
|
||||
target_account = ObjectManager.GetPlayerAccountIdByGUID(guid);
|
||||
|
||||
if (target_session == null && target_account == 0)
|
||||
{
|
||||
SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
_sentErrorMessage = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return HasLowerSecurityAccount(target_session, target_account, strong);
|
||||
}
|
||||
public bool HasLowerSecurityAccount(WorldSession target, uint target_account, bool strong = false)
|
||||
{
|
||||
AccountTypes target_ac_sec;
|
||||
|
||||
// allow everything from console and RA console
|
||||
if (_session == null)
|
||||
return false;
|
||||
|
||||
// ignore only for non-players for non strong checks (when allow apply command at least to same sec level)
|
||||
if (!Global.AccountMgr.IsPlayerAccount(_session.GetSecurity()) && !strong && !WorldConfig.GetBoolValue(WorldCfg.GmLowerSecurity))
|
||||
return false;
|
||||
|
||||
if (target != null)
|
||||
target_ac_sec = target.GetSecurity();
|
||||
else if (target_account != 0)
|
||||
target_ac_sec = Global.AccountMgr.GetSecurity(target_account);
|
||||
else
|
||||
return true; // caller must report error for (target == NULL && target_account == 0)
|
||||
|
||||
if (_session.GetSecurity() < target_ac_sec || (strong && _session.GetSecurity() <= target_ac_sec))
|
||||
{
|
||||
SendSysMessage(CypherStrings.YoursSecurityIsLow);
|
||||
_sentErrorMessage = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasStringAbbr(string name, string part)
|
||||
{
|
||||
// non "" command
|
||||
if (!name.IsEmpty())
|
||||
{
|
||||
// "" part from non-"" command
|
||||
if (part.IsEmpty())
|
||||
return false;
|
||||
|
||||
int partIndex = 0;
|
||||
while (true)
|
||||
{
|
||||
if (partIndex >= part.Length)
|
||||
return true;
|
||||
else if (partIndex >= name.Length)
|
||||
return false;
|
||||
else if (char.ToLower(name[partIndex]) != char.ToLower(part[partIndex]))
|
||||
return false;
|
||||
++partIndex;
|
||||
}
|
||||
}
|
||||
// allow with any for ""
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public WorldSession GetSession()
|
||||
{
|
||||
return _session;
|
||||
}
|
||||
public Player GetPlayer()
|
||||
{
|
||||
return _session.GetPlayer();
|
||||
}
|
||||
public string GetCypherString(CypherStrings str)
|
||||
{
|
||||
return Global.ObjectMgr.GetCypherString(str);
|
||||
}
|
||||
|
||||
public virtual LocaleConstant GetSessionDbcLocale()
|
||||
{
|
||||
return _session.GetSessionDbcLocale();
|
||||
}
|
||||
public virtual byte GetSessionDbLocaleIndex()
|
||||
{
|
||||
return (byte)_session.GetSessionDbLocaleIndex();
|
||||
}
|
||||
public string GetParsedString(CypherStrings cypherString, params object[] args)
|
||||
{
|
||||
return string.Format(Global.ObjectMgr.GetCypherString(cypherString), args);
|
||||
}
|
||||
|
||||
public void SendSysMessage(CypherStrings cypherString, params object[] args)
|
||||
{
|
||||
SendSysMessage(Global.ObjectMgr.GetCypherString(cypherString), args);
|
||||
}
|
||||
public virtual void SendSysMessage(string str, params object[] args)
|
||||
{
|
||||
_sentErrorMessage = true;
|
||||
string msg = string.Format(str, args);
|
||||
|
||||
ChatPkt messageChat = new ChatPkt();
|
||||
|
||||
var lines = new StringArray(msg, "\n", "\r");
|
||||
for (var i = 0; i < lines.Length; ++i)
|
||||
{
|
||||
messageChat.Initialize(ChatMsg.System, Language.Universal, null, null, lines[i]);
|
||||
_session.SendPacket(messageChat);
|
||||
}
|
||||
}
|
||||
|
||||
public void SendNotification(CypherStrings str, params object[] args)
|
||||
{
|
||||
_session.SendNotification(str, args);
|
||||
}
|
||||
|
||||
public void SendGlobalSysMessage(string str)
|
||||
{
|
||||
// Chat output
|
||||
ChatPkt data = new ChatPkt();
|
||||
data.Initialize(ChatMsg.System, Language.Universal, null, null, str);
|
||||
Global.WorldMgr.SendGlobalMessage(data);
|
||||
}
|
||||
|
||||
public void SendGlobalGMSysMessage(string str)
|
||||
{
|
||||
// Chat output
|
||||
ChatPkt data = new ChatPkt();
|
||||
data.Initialize(ChatMsg.System, Language.Universal, null, null, str);
|
||||
Global.WorldMgr.SendGlobalGMMessage(data);
|
||||
}
|
||||
|
||||
public bool GetPlayerGroupAndGUIDByName(string name, out Player player, out Group group, out ObjectGuid guid, bool offline = false)
|
||||
{
|
||||
player = null;
|
||||
guid = ObjectGuid.Empty;
|
||||
group = null;
|
||||
|
||||
if (!name.IsEmpty())
|
||||
{
|
||||
if (!ObjectManager.NormalizePlayerName(ref name))
|
||||
{
|
||||
SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
player = Global.ObjAccessor.FindPlayerByName(name);
|
||||
if (offline)
|
||||
guid = ObjectManager.GetPlayerGUIDByName(name);
|
||||
}
|
||||
|
||||
if (player)
|
||||
{
|
||||
group = player.GetGroup();
|
||||
if (guid.IsEmpty() || !offline)
|
||||
guid = player.GetGUID();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getSelectedPlayer())
|
||||
player = getSelectedPlayer();
|
||||
else
|
||||
player = _session.GetPlayer();
|
||||
|
||||
if (guid.IsEmpty() || !offline)
|
||||
guid = player.GetGUID();
|
||||
group = player.GetGroup();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasSentErrorMessage() { return _sentErrorMessage; }
|
||||
|
||||
internal bool _sentErrorMessage;
|
||||
WorldSession _session;
|
||||
}
|
||||
|
||||
public class ConsoleHandler : CommandHandler
|
||||
{
|
||||
public override bool IsAvailable(ChatCommand cmd)
|
||||
{
|
||||
return cmd.AllowConsole;
|
||||
}
|
||||
|
||||
public override bool HasPermission(RBACPermissions permission)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SendSysMessage(string str, params object[] args)
|
||||
{
|
||||
_sentErrorMessage = true;
|
||||
string msg = string.Format(str, args);
|
||||
|
||||
Log.outInfo(LogFilter.Server, msg);
|
||||
}
|
||||
|
||||
public override string GetNameLink()
|
||||
{
|
||||
return GetCypherString(CypherStrings.ConsoleCommand);
|
||||
}
|
||||
|
||||
public override bool needReportToTarget(Player chr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override LocaleConstant GetSessionDbcLocale()
|
||||
{
|
||||
return Global.WorldMgr.GetDefaultDbcLocale();
|
||||
}
|
||||
|
||||
public override byte GetSessionDbLocaleIndex()
|
||||
{
|
||||
return (byte)Global.WorldMgr.GetDefaultDbcLocale();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Configuration;
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
public class CommandManager
|
||||
{
|
||||
static CommandManager()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
|
||||
{
|
||||
if (type.Attributes.HasAnyFlag(TypeAttributes.NestedPrivate))
|
||||
continue;
|
||||
|
||||
var groupAttribute = type.GetCustomAttribute<CommandGroupAttribute>(true);
|
||||
if (groupAttribute != null)
|
||||
{
|
||||
_commands.Add(groupAttribute.Name, new ChatCommand(type, groupAttribute));
|
||||
}
|
||||
|
||||
foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic))
|
||||
{
|
||||
var commandAttribute = method.GetCustomAttribute<CommandNonGroupAttribute>(true);
|
||||
if (commandAttribute != null)
|
||||
_commands.Add(commandAttribute.Name, new ChatCommand(commandAttribute, (HandleCommandDelegate)method.CreateDelegate(typeof(HandleCommandDelegate))));
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_COMMANDS);
|
||||
SQLResult result = DB.World.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
string name = result.Read<string>(0);
|
||||
SetDataForCommandInTable(GetCommands(), name, result.Read<uint>(1), result.Read<string>(2), name);
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.outException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static bool SetDataForCommandInTable(List<ChatCommand> table, string text, uint permission, string help, string fullcommand)
|
||||
{
|
||||
StringArguments args = new StringArguments(text);
|
||||
string cmd = args.NextString().ToLower();
|
||||
|
||||
foreach (var command in table)
|
||||
{
|
||||
// for data fill use full explicit command names
|
||||
if (command.Name != cmd)
|
||||
continue;
|
||||
|
||||
// select subcommand from child commands list (including "")
|
||||
if (!command.ChildCommands.Empty())
|
||||
{
|
||||
var arg = args.NextString("");
|
||||
if (SetDataForCommandInTable(command.ChildCommands, arg, permission, help, fullcommand))
|
||||
return true;
|
||||
else if (!arg.IsEmpty())
|
||||
return false;
|
||||
|
||||
// fail with "" subcommands, then use normal level up command instead
|
||||
}
|
||||
// expected subcommand by full name DB content
|
||||
else if (!args.NextString().IsEmpty())
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Table `command` have unexpected subcommand '{0}' in command '{1}', skip.", text, fullcommand);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (command.Permission != (RBACPermissions)permission)
|
||||
Log.outInfo(LogFilter.Misc, "Table `command` overwrite for command '{0}' default permission ({1}) by {2}", fullcommand, command.Permission, permission);
|
||||
|
||||
command.Permission = (RBACPermissions)permission;
|
||||
command.Help = help;
|
||||
return true;
|
||||
}
|
||||
|
||||
// in case "" command let process by caller
|
||||
if (!cmd.IsEmpty())
|
||||
{
|
||||
if (table == GetCommands())
|
||||
Log.outError(LogFilter.Sql, "Table `command` have not existed command '{0}', skip.", cmd);
|
||||
else
|
||||
Log.outError(LogFilter.Sql, "Table `command` have not existed subcommand '{0}' in command '{1}', skip.", cmd, fullcommand);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void InitConsole()
|
||||
{
|
||||
if (ConfigMgr.GetDefaultValue("BeepAtStart", true))
|
||||
Console.Beep();
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.Write("Cypher>> ");
|
||||
|
||||
var handler = new ConsoleHandler();
|
||||
while (!Global.WorldMgr.IsStopped)
|
||||
{
|
||||
handler.ParseCommand(Console.ReadLine());
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.Write("Cypher>> ");
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ChatCommand> GetCommands()
|
||||
{
|
||||
return _commands.Values.ToList();
|
||||
}
|
||||
|
||||
static SortedDictionary<string, ChatCommand> _commands = new SortedDictionary<string, ChatCommand>();
|
||||
}
|
||||
|
||||
public delegate bool HandleCommandDelegate(StringArguments args, CommandHandler handler);
|
||||
|
||||
public class ChatCommand
|
||||
{
|
||||
public ChatCommand(CommandAttribute attribute, HandleCommandDelegate handler)
|
||||
{
|
||||
Name = attribute.Name;
|
||||
Permission = attribute.RBAC;
|
||||
AllowConsole = attribute.AllowConsole;
|
||||
Handler = handler;
|
||||
Help = attribute.Help;
|
||||
}
|
||||
|
||||
public ChatCommand(Type type, CommandAttribute attribute)
|
||||
{
|
||||
Name = attribute.Name;
|
||||
Permission = attribute.RBAC;
|
||||
AllowConsole = attribute.AllowConsole;
|
||||
Help = attribute.Help;
|
||||
|
||||
foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic))
|
||||
{
|
||||
CommandAttribute commandAttribute = method.GetCustomAttribute<CommandAttribute>(false);
|
||||
if (commandAttribute == null)
|
||||
continue;
|
||||
|
||||
if (commandAttribute.GetType() == typeof(CommandNonGroupAttribute))
|
||||
continue;
|
||||
|
||||
ChildCommands.Add(new ChatCommand(commandAttribute, (HandleCommandDelegate)method.CreateDelegate(typeof(HandleCommandDelegate))));
|
||||
}
|
||||
|
||||
foreach (var nestedType in type.GetNestedTypes(BindingFlags.NonPublic))
|
||||
{
|
||||
var groupAttribute = nestedType.GetCustomAttribute<CommandGroupAttribute>(true);
|
||||
if (groupAttribute == null)
|
||||
continue;
|
||||
|
||||
ChildCommands.Add(new ChatCommand(nestedType, groupAttribute));
|
||||
}
|
||||
|
||||
ChildCommands = ChildCommands.OrderBy(p => string.IsNullOrEmpty(p.Name)).ThenBy(p => p.Name).ToList();
|
||||
}
|
||||
|
||||
public string Name;
|
||||
public RBACPermissions Permission;
|
||||
public bool AllowConsole;
|
||||
public HandleCommandDelegate Handler;
|
||||
public string Help;
|
||||
public List<ChatCommand> ChildCommands = new List<ChatCommand>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,815 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.Accounts;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("account", RBACPermissions.CommandAccount, true)]
|
||||
class AccountCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandAccount)]
|
||||
static bool HandleAccountCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (handler.GetSession() == null)
|
||||
return false;
|
||||
|
||||
// GM Level
|
||||
AccountTypes gmLevel = handler.GetSession().GetSecurity();
|
||||
handler.SendSysMessage(CypherStrings.AccountLevel, gmLevel);
|
||||
|
||||
// Security level required
|
||||
WorldSession session = handler.GetSession();
|
||||
bool hasRBAC = (session.HasPermission(RBACPermissions.EmailConfirmForPassChange) ? true : false);
|
||||
uint pwConfig = 0; // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
|
||||
|
||||
handler.SendSysMessage(CypherStrings.AccountSecType, (pwConfig == 0 ? "Lowest level: No Email input required." :
|
||||
pwConfig == 1 ? "Highest level: Email input required." : pwConfig == 2 ? "Special level: Your account may require email input depending on settings. That is the case if another lien is printed." :
|
||||
"Unknown security level: Notify technician for details."));
|
||||
|
||||
// RBAC required display - is not displayed for console
|
||||
if (pwConfig == 2 && session != null && hasRBAC)
|
||||
handler.SendSysMessage(CypherStrings.RbacEmailRequired);
|
||||
|
||||
// Email display if sufficient rights
|
||||
if (session.HasPermission(RBACPermissions.MayCheckOwnEmail))
|
||||
{
|
||||
string emailoutput;
|
||||
uint accountId = session.GetAccountId();
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.GET_EMAIL_BY_ID);
|
||||
stmt.AddValue(0, accountId);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
emailoutput = result.Read<string>(0);
|
||||
handler.SendSysMessage(CypherStrings.CommandEmailOutput, emailoutput);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("addon", RBACPermissions.CommandAccountAddon)]
|
||||
static bool HandleAccountAddonCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint accountId = handler.GetSession().GetAccountId();
|
||||
|
||||
int expansion = args.NextInt32(); //get int anyway (0 if error)
|
||||
if (expansion < 0 || expansion > WorldConfig.GetIntValue(WorldCfg.Expansion))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ImproperValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_EXPANSION);
|
||||
stmt.AddValue(0, expansion);
|
||||
stmt.AddValue(1, accountId);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.AccountAddon, expansion);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("create", RBACPermissions.CommandAccountCreate, true)]
|
||||
static bool HandleAccountCreateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
var accountName = args.NextString().ToUpper();
|
||||
var password = args.NextString();
|
||||
string email = "";
|
||||
|
||||
if (string.IsNullOrEmpty(accountName) || string.IsNullOrEmpty(password))
|
||||
return false;
|
||||
|
||||
if (accountName.Contains("@"))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountUseBnetCommands);
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountOpResult result = Global.AccountMgr.CreateAccount(accountName, password, email);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.AccountCreated, accountName);
|
||||
if (handler.GetSession() != null)
|
||||
{
|
||||
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) created Account {4} (Email: '{5}')",
|
||||
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
|
||||
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
|
||||
accountName, email);
|
||||
}
|
||||
break;
|
||||
case AccountOpResult.NameTooLong:
|
||||
handler.SendSysMessage(CypherStrings.AccountNameTooLong);
|
||||
return false;
|
||||
case AccountOpResult.PassTooLong:
|
||||
handler.SendSysMessage(CypherStrings.AccountPassTooLong);
|
||||
return false;
|
||||
case AccountOpResult.NameAlreadyExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountAlreadyExist);
|
||||
return false;
|
||||
case AccountOpResult.DBInternalError:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotCreatedSqlError, accountName);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotCreated, accountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("delete", RBACPermissions.CommandAccountDelete, true)]
|
||||
static bool HandleAccountDeleteCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string accountName = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(accountName))
|
||||
return false;
|
||||
|
||||
uint accountId = Global.AccountMgr.GetId(accountName);
|
||||
if (accountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handler.HasLowerSecurityAccount(null, accountId, true))
|
||||
return false;
|
||||
|
||||
AccountOpResult result = Global.AccountMgr.DeleteAccount(accountId);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.AccountDeleted, accountName);
|
||||
break;
|
||||
case AccountOpResult.NameNotExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
case AccountOpResult.DBInternalError:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotDeletedSqlError, accountName);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotDeleted, accountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("email", RBACPermissions.CommandAccountSetSecEmail)]
|
||||
static bool HandleAccountEmailCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
string oldEmail = args.NextString();
|
||||
string password = args.NextString();
|
||||
string email = args.NextString();
|
||||
string emailConfirmation = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(oldEmail) || string.IsNullOrEmpty(password)
|
||||
|| string.IsNullOrEmpty(email) || string.IsNullOrEmpty(emailConfirmation))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Global.AccountMgr.CheckEmail(handler.GetSession().GetAccountId(), oldEmail))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandWrongemail);
|
||||
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().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
|
||||
email, oldEmail);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Global.AccountMgr.CheckPassword(handler.GetSession().GetAccountId(), password))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandWrongoldpassword);
|
||||
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().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (email == oldEmail)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.OldEmailIsNewEmail);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (email != emailConfirmation)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NewEmailsNotMatch);
|
||||
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().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
AccountOpResult result = Global.AccountMgr.ChangeEmail(handler.GetSession().GetAccountId(), email);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.CommandEmail);
|
||||
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().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
|
||||
oldEmail, email);
|
||||
break;
|
||||
case AccountOpResult.EmailTooLong:
|
||||
handler.SendSysMessage(CypherStrings.EmailTooLong);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.CommandNotchangeemail);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("password", RBACPermissions.CommandAccountPassword)]
|
||||
static bool HandleAccountPasswordCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// If no args are given at all, we can return false right away.
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// First, we check config. What security type (sec type) is it ? Depending on it, the command branches out
|
||||
uint pwConfig = WorldConfig.GetUIntValue(WorldCfg.AccPasschangesec); // 0 - PW_NONE, 1 - PW_EMAIL, 2 - PW_RBAC
|
||||
|
||||
// Command is supposed to be: .account password [$oldpassword] [$newpassword] [$newpasswordconfirmation] [$emailconfirmation]
|
||||
string oldPassword = args.NextString(); // This extracts [$oldpassword]
|
||||
string newPassword = args.NextString(); // This extracts [$newpassword]
|
||||
string passwordConfirmation = args.NextString(); // This extracts [$newpasswordconfirmation]
|
||||
string emailConfirmation = args.NextString(); // This defines the emailConfirmation variable, which is optional depending on sec type.
|
||||
|
||||
//Is any of those variables missing for any reason ? We return false.
|
||||
if (string.IsNullOrEmpty(oldPassword) || string.IsNullOrEmpty(newPassword)
|
||||
|| string.IsNullOrEmpty(passwordConfirmation))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We compare the old, saved password to the entered old password - no chance for the unauthorized.
|
||||
if (!Global.AccountMgr.CheckPassword(handler.GetSession().GetAccountId(), oldPassword))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandWrongoldpassword);
|
||||
|
||||
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().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
|
||||
return false;
|
||||
}
|
||||
// This compares the old, current email to the entered email - however, only...
|
||||
if ((pwConfig == 1 || (pwConfig == 2 && handler.GetSession().HasPermission(RBACPermissions.EmailConfirmForPassChange))) // ...if either PW_EMAIL or PW_RBAC with the Permission is active...
|
||||
&& !Global.AccountMgr.CheckEmail(handler.GetSession().GetAccountId(), emailConfirmation)) // ... and returns false if the comparison fails.
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandWrongemail);
|
||||
|
||||
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().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
|
||||
emailConfirmation);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Making sure that newly entered password is correctly entered.
|
||||
if (newPassword != passwordConfirmation)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NewPasswordsNotMatch);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Changes password and prints result.
|
||||
AccountOpResult result = Global.AccountMgr.ChangePassword(handler.GetSession().GetAccountId(), newPassword);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.CommandPassword);
|
||||
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] (GUID: {3}) Changed Password.",
|
||||
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(),
|
||||
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
|
||||
break;
|
||||
case AccountOpResult.PassTooLong:
|
||||
handler.SendSysMessage(CypherStrings.PasswordTooLong);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.CommandNotchangepassword);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("onlinelist", RBACPermissions.CommandAccountOnlineList, true)]
|
||||
static bool HandleAccountOnlineListCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// Get the list of accounts ID logged to the realm
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_ONLINE);
|
||||
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountListEmpty);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Display the list of account/characters online
|
||||
handler.SendSysMessage(CypherStrings.AccountListBarHeader);
|
||||
handler.SendSysMessage(CypherStrings.AccountListHeader);
|
||||
handler.SendSysMessage(CypherStrings.AccountListBar);
|
||||
|
||||
// Cycle through accounts
|
||||
do
|
||||
{
|
||||
string name = result.Read<string>(0);
|
||||
uint account = result.Read<uint>(1);
|
||||
|
||||
// Get the username, last IP and GM level of each account
|
||||
// No SQL injection. account is uint32.
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_INFO);
|
||||
stmt.AddValue(0, account);
|
||||
SQLResult resultLogin = DB.Login.Query(stmt);
|
||||
|
||||
if (!resultLogin.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountListLine, resultLogin.Read<string>(0),
|
||||
name, resultLogin.Read<string>(1), result.Read<ushort>(2), result.Read<ushort>(3),
|
||||
resultLogin.Read<byte>(3), resultLogin.Read<byte>(2));
|
||||
}
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.AccountListError, name);
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
handler.SendSysMessage(CypherStrings.AccountListBar);
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("set", RBACPermissions.CommandAccountSet, true)]
|
||||
class SetCommands
|
||||
{
|
||||
[Command("password", RBACPermissions.CommandAccountSetPassword, true)]
|
||||
static bool HandleSetPasswordCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the command line arguments
|
||||
string accountName = args.NextString();
|
||||
string password = args.NextString();
|
||||
string passwordConfirmation = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(accountName) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(passwordConfirmation))
|
||||
return false;
|
||||
|
||||
uint targetAccountId = Global.AccountMgr.GetId(accountName);
|
||||
if (targetAccountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
// can set password only for target with less security
|
||||
// This also restricts setting handler's own password
|
||||
if (handler.HasLowerSecurityAccount(null, targetAccountId, true))
|
||||
return false;
|
||||
|
||||
if (!password.Equals(passwordConfirmation))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NewPasswordsNotMatch);
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountOpResult result = Global.AccountMgr.ChangePassword(targetAccountId, password);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.CommandPassword);
|
||||
break;
|
||||
case AccountOpResult.NameNotExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
case AccountOpResult.PassTooLong:
|
||||
handler.SendSysMessage(CypherStrings.PasswordTooLong);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.CommandNotchangepassword);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("addon", RBACPermissions.CommandAccountSetAddon, true)]
|
||||
static bool HandleSetAddonCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// Get the command line arguments
|
||||
string account = args.NextString();
|
||||
string exp = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(account))
|
||||
return false;
|
||||
|
||||
string accountName;
|
||||
uint accountId;
|
||||
|
||||
if (string.IsNullOrEmpty(exp))
|
||||
{
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
accountId = player.GetSession().GetAccountId();
|
||||
Global.AccountMgr.GetName(accountId, out accountName);
|
||||
exp = account;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert Account name to Upper Format
|
||||
accountName = account.ToUpper();
|
||||
|
||||
accountId = Global.AccountMgr.GetId(accountName);
|
||||
if (accountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Let set addon state only for lesser (strong) security level
|
||||
// or to self account
|
||||
if (handler.GetSession() != null && handler.GetSession().GetAccountId() != accountId &&
|
||||
handler.HasLowerSecurityAccount(null, accountId, true))
|
||||
return false;
|
||||
|
||||
byte expansion = byte.Parse(exp); //get int anyway (0 if error)
|
||||
if (expansion > WorldConfig.GetIntValue(WorldCfg.Expansion))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_EXPANSION);
|
||||
|
||||
stmt.AddValue(0, expansion);
|
||||
stmt.AddValue(1, accountId);
|
||||
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.AccountSetaddon, accountName, accountId, expansion);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("gmlevel", RBACPermissions.CommandAccountSetGmlevel, true)]
|
||||
static bool HandleSetGmLevelCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
string targetAccountName = "";
|
||||
uint targetAccountId = 0;
|
||||
AccountTypes targetSecurity = 0;
|
||||
uint gm = 0;
|
||||
string arg1 = args.NextString();
|
||||
string arg2 = args.NextString();
|
||||
string arg3 = args.NextString();
|
||||
bool isAccountNameGiven = true;
|
||||
|
||||
if (string.IsNullOrEmpty(arg3))
|
||||
{
|
||||
if (!handler.getSelectedPlayer())
|
||||
return false;
|
||||
isAccountNameGiven = false;
|
||||
}
|
||||
|
||||
if (!isAccountNameGiven && string.IsNullOrEmpty(arg2))
|
||||
return false;
|
||||
|
||||
if (isAccountNameGiven)
|
||||
{
|
||||
targetAccountName = arg1;
|
||||
if (Global.AccountMgr.GetId(targetAccountName) == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, targetAccountName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for invalid specified GM level.
|
||||
gm = isAccountNameGiven ? uint.Parse(arg2) : uint.Parse(arg1);
|
||||
if (gm > (uint)AccountTypes.Console)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
// command.getSession() == NULL only for console
|
||||
targetAccountId = (isAccountNameGiven) ? Global.AccountMgr.GetId(targetAccountName) : handler.getSelectedPlayer().GetSession().GetAccountId();
|
||||
int gmRealmID = (isAccountNameGiven) ? int.Parse(arg3) : int.Parse(arg2);
|
||||
AccountTypes playerSecurity;
|
||||
if (handler.GetSession() != null)
|
||||
playerSecurity = Global.AccountMgr.GetSecurity(handler.GetSession().GetAccountId(), gmRealmID);
|
||||
else
|
||||
playerSecurity = AccountTypes.Console;
|
||||
|
||||
// can set security level only for target with less security and to less security that we have
|
||||
// This is also reject self apply in fact
|
||||
targetSecurity = Global.AccountMgr.GetSecurity(targetAccountId, gmRealmID);
|
||||
if (targetSecurity >= playerSecurity || (AccountTypes)gm >= playerSecurity)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.YoursSecurityIsLow);
|
||||
return false;
|
||||
}
|
||||
PreparedStatement stmt;
|
||||
// Check and abort if the target gm has a higher rank on one of the realms and the new realm is -1
|
||||
if (gmRealmID == -1 && !Global.AccountMgr.IsConsoleAccount(playerSecurity))
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_ACCESS_GMLEVEL_TEST);
|
||||
stmt.AddValue(0, targetAccountId);
|
||||
stmt.AddValue(1, gm);
|
||||
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.YoursSecurityIsLow);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if provided realmID has a negative value other than -1
|
||||
if (gmRealmID < -1)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidRealmid);
|
||||
return false;
|
||||
}
|
||||
|
||||
RBACData rbac = isAccountNameGiven ? null : handler.getSelectedPlayer().GetSession().GetRBACData();
|
||||
Global.AccountMgr.UpdateAccountAccess(rbac, targetAccountId, (byte)gm, gmRealmID);
|
||||
handler.SendSysMessage(CypherStrings.YouChangeSecurity, targetAccountName, gm);
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("sec", RBACPermissions.CommandAccountSetSec, true)]
|
||||
class SetSecCommands
|
||||
{
|
||||
[Command("email", RBACPermissions.CommandAccountSetSecEmail, true)]
|
||||
static bool HandleSetEmailCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// Get the command line arguments
|
||||
string accountName = args.NextString();
|
||||
string email = args.NextString();
|
||||
string emailConfirmation = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(accountName) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(emailConfirmation))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint targetAccountId = Global.AccountMgr.GetId(accountName);
|
||||
if (targetAccountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// can set email only for target with less security
|
||||
/// This also restricts setting handler's own email.
|
||||
if (handler.HasLowerSecurityAccount(null, targetAccountId, true))
|
||||
return false;
|
||||
|
||||
if (!email.Equals(emailConfirmation))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NewEmailsNotMatch);
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountOpResult result = Global.AccountMgr.ChangeEmail(targetAccountId, email);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.CommandEmail);
|
||||
Log.outInfo(LogFilter.Player, "ChangeEmail: Account {0} [Id: {1}] had it's email changed to {2}.", accountName, targetAccountId, email);
|
||||
break;
|
||||
case AccountOpResult.NameNotExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
case AccountOpResult.EmailTooLong:
|
||||
handler.SendSysMessage(CypherStrings.EmailTooLong);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.CommandNotchangeemail);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("regmail", RBACPermissions.CommandAccountSetSecRegmail, true)]
|
||||
static bool HandleSetRegEmailCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
//- We do not want anything short of console to use this by default.
|
||||
//- So we force that.
|
||||
if (handler.GetSession())
|
||||
return false;
|
||||
|
||||
// Get the command line arguments
|
||||
string accountName = args.NextString();
|
||||
string email = args.NextString();
|
||||
string emailConfirmation = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(accountName) || string.IsNullOrEmpty(email) || string.IsNullOrEmpty(emailConfirmation))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint targetAccountId = Global.AccountMgr.GetId(accountName);
|
||||
if (targetAccountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// can set email only for target with less security
|
||||
/// This also restricts setting handler's own email.
|
||||
if (handler.HasLowerSecurityAccount(null, targetAccountId, true))
|
||||
return false;
|
||||
|
||||
if (!email.Equals(emailConfirmation))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NewEmailsNotMatch);
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountOpResult result = Global.AccountMgr.ChangeRegEmail(targetAccountId, email);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.CommandEmail);
|
||||
Log.outInfo(LogFilter.Player, "ChangeRegEmail: Account {0} [Id: {1}] had it's Registration Email changed to {2}.", accountName, targetAccountId, email);
|
||||
break;
|
||||
case AccountOpResult.NameNotExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
case AccountOpResult.EmailTooLong:
|
||||
handler.SendSysMessage(CypherStrings.EmailTooLong);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.CommandNotchangeemail);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("lock", RBACPermissions.CommandAccountLock)]
|
||||
class LockCommands
|
||||
{
|
||||
[Command("country", RBACPermissions.CommandAccountLockCountry)]
|
||||
static bool HandleAccountLockCountryCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
string param = args.NextString();
|
||||
if (!param.IsEmpty())
|
||||
{
|
||||
if (param == "on")
|
||||
{
|
||||
var ipBytes = System.Net.IPAddress.Parse(handler.GetSession().GetRemoteAddress()).GetAddressBytes();
|
||||
Array.Reverse(ipBytes);
|
||||
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_LOGON_COUNTRY);
|
||||
stmt.AddValue(0, BitConverter.ToUInt32(ipBytes, 0));
|
||||
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
string country = result.Read<string>(0);
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_ACCOUNT_LOCK_CONTRY);
|
||||
stmt.AddValue(0, country);
|
||||
stmt.AddValue(1, handler.GetSession().GetAccountId());
|
||||
DB.Login.Execute(stmt);
|
||||
handler.SendSysMessage(CypherStrings.CommandAcclocklocked);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage("[IP2NATION] Table empty");
|
||||
Log.outDebug(LogFilter.Server, "[IP2NATION] Table empty");
|
||||
}
|
||||
}
|
||||
else if (param == "off")
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_ACCOUNT_LOCK_CONTRY);
|
||||
stmt.AddValue(0, "00");
|
||||
stmt.AddValue(1, handler.GetSession().GetAccountId());
|
||||
DB.Login.Execute(stmt);
|
||||
handler.SendSysMessage(CypherStrings.CommandAcclockunlocked);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("ip", RBACPermissions.CommandAccountLockIp)]
|
||||
static bool HandleAccountLockIpCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
string param = args.NextString();
|
||||
if (!string.IsNullOrEmpty(param))
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_ACCOUNT_LOCK);
|
||||
|
||||
if (param == "on")
|
||||
{
|
||||
stmt.AddValue(0, true); // locked
|
||||
handler.SendSysMessage(CypherStrings.CommandAcclocklocked);
|
||||
}
|
||||
else if (param == "off")
|
||||
{
|
||||
stmt.AddValue(0, false); // unlocked
|
||||
handler.SendSysMessage(CypherStrings.CommandAcclockunlocked);
|
||||
}
|
||||
stmt.AddValue(1, handler.GetSession().GetAccountId());
|
||||
|
||||
DB.Login.Execute(stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
//Holder for now.
|
||||
[CommandGroup("ahbot", RBACPermissions.CommandAhbot)]
|
||||
class AhBotCommands
|
||||
{
|
||||
[Command("rebuild", RBACPermissions.CommandAhbotRebuild, true)]
|
||||
static bool HandleAHBotRebuildCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/*char* arg = strtok((char*)args, " ");
|
||||
|
||||
bool all = false;
|
||||
if (arg && strcmp(arg, "all") == 0)
|
||||
all = true;
|
||||
|
||||
sAuctionBot->Rebuild(all);*/
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("reload", RBACPermissions.CommandAhbotReload, true)]
|
||||
static bool HandleAHBotReloadCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
//sAuctionBot->ReloadAllConfig();
|
||||
//handler->SendSysMessage(LANG_AHBOT_RELOAD_OK);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("status", RBACPermissions.CommandAhbotStatus, true)]
|
||||
static bool HandleAHBotStatusCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/* char* arg = strtok((char*)args, " ");
|
||||
if (!arg)
|
||||
return false;
|
||||
|
||||
bool all = false;
|
||||
if (strcmp(arg, "all") == 0)
|
||||
all = true;
|
||||
|
||||
AuctionHouseBotStatusInfo statusInfo;
|
||||
sAuctionBot->PrepareStatusInfos(statusInfo);
|
||||
|
||||
WorldSession* session = handler->GetSession();
|
||||
|
||||
if (!session)
|
||||
{
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_BAR_CONSOLE);
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_TITLE1_CONSOLE);
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_MIDBAR_CONSOLE);
|
||||
}
|
||||
else
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_TITLE1_CHAT);
|
||||
|
||||
public uint fmtId = session ? LANG_AHBOT_STATUS_FORMAT_CHAT : LANG_AHBOT_STATUS_FORMAT_CONSOLE;
|
||||
|
||||
handler->PSendSysMessage(fmtId, handler->GetCypherString(LANG_AHBOT_STATUS_ITEM_COUNT),
|
||||
statusInfo[AUCTION_HOUSE_ALLIANCE].ItemsCount,
|
||||
statusInfo[AUCTION_HOUSE_HORDE].ItemsCount,
|
||||
statusInfo[AUCTION_HOUSE_NEUTRAL].ItemsCount,
|
||||
statusInfo[AUCTION_HOUSE_ALLIANCE].ItemsCount +
|
||||
statusInfo[AUCTION_HOUSE_HORDE].ItemsCount +
|
||||
statusInfo[AUCTION_HOUSE_NEUTRAL].ItemsCount);
|
||||
|
||||
if (all)
|
||||
{
|
||||
handler->PSendSysMessage(fmtId, handler->GetCypherString(LANG_AHBOT_STATUS_ITEM_RATIO),
|
||||
sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO),
|
||||
sAuctionBotConfig->GetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO),
|
||||
sAuctionBotConfig->GetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO),
|
||||
sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO) +
|
||||
sAuctionBotConfig->GetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO) +
|
||||
sAuctionBotConfig->GetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO));
|
||||
|
||||
if (!session)
|
||||
{
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_BAR_CONSOLE);
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_TITLE2_CONSOLE);
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_MIDBAR_CONSOLE);
|
||||
}
|
||||
else
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_TITLE2_CHAT);
|
||||
|
||||
for (int i = 0; i < MAX_AUCTION_QUALITY; ++i)
|
||||
handler->PSendSysMessage(fmtId, handler->GetCypherString(ahbotQualityIds[i]),
|
||||
statusInfo[AUCTION_HOUSE_ALLIANCE].QualityInfo[i],
|
||||
statusInfo[AUCTION_HOUSE_HORDE].QualityInfo[i],
|
||||
statusInfo[AUCTION_HOUSE_NEUTRAL].QualityInfo[i],
|
||||
sAuctionBotConfig->GetConfigItemQualityAmount(AuctionQuality(i)));
|
||||
}
|
||||
|
||||
if (!session)
|
||||
handler->SendSysMessage(LANG_AHBOT_STATUS_BAR_CONSOLE);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("items", RBACPermissions.CommandAhbotItems)]
|
||||
class ItemsCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandAhbotItems, true)]
|
||||
static bool HandleAHBotItemsAmountCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/*public uint qVals[MAX_AUCTION_QUALITY];
|
||||
char* arg = strtok((char*)args, " ");
|
||||
for (int i = 0; i < MAX_AUCTION_QUALITY; ++i)
|
||||
{
|
||||
if (!arg)
|
||||
return false;
|
||||
qVals[i] = atoi(arg);
|
||||
arg = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
sAuctionBot->SetItemsAmount(qVals);
|
||||
|
||||
for (int i = 0; i < MAX_AUCTION_QUALITY; ++i)
|
||||
handler->PSendSysMessage(LANG_AHBOT_ITEMS_AMOUNT, handler->GetCypherString(ahbotQualityIds[i]), sAuctionBotConfig->GetConfigItemQualityAmount(AuctionQuality(i)));
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("blue", RBACPermissions.CommandAhbotItemsBlue, true)]
|
||||
static bool HandleAHBotItemsAmountQualityBlue(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
[Command("gray", RBACPermissions.CommandAhbotItemsGray, true)]
|
||||
static bool HandleAHBotItemsAmountQualityGray(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
[Command("green", RBACPermissions.CommandAhbotItemsGreen, true)]
|
||||
static bool HandleAHBotItemsAmountQualityGreen(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
[Command("orange", RBACPermissions.CommandAhbotItemsOrange, true)]
|
||||
static bool HandleAHBotItemsAmountQualityOrange(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
[Command("purple", RBACPermissions.CommandAhbotItemsPurple, true)]
|
||||
static bool HandleAHBotItemsAmountQualityPurple(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
[Command("white", RBACPermissions.CommandAhbotItemsWhite, true)]
|
||||
static bool HandleAHBotItemsAmountQualityWhite(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
[Command("yellow", RBACPermissions.CommandAhbotItemsYellow, true)]
|
||||
static bool HandleAHBotItemsAmountQualityYellow(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
static bool HandleAHBotItemsAmountQualityCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/*
|
||||
char* arg = strtok((char*)args, " ");
|
||||
if (!arg)
|
||||
return false;
|
||||
public uint qualityVal = atoi(arg);
|
||||
|
||||
sAuctionBot->SetItemsAmountForQuality(Q, qualityVal);
|
||||
handler->PSendSysMessage(LANG_AHBOT_ITEMS_AMOUNT, handler->GetCypherString(ahbotQualityIds[Q]),
|
||||
sAuctionBotConfig->GetConfigItemQualityAmount(Q));
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("ratio", RBACPermissions.CommandAhbotRatio)]
|
||||
class RatioCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandAhbotRatio, true)]
|
||||
static bool HandleAHBotItemsRatioCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/*public uint rVal[MAX_AUCTION_QUALITY];
|
||||
char* arg = strtok((char*)args, " ");
|
||||
for (int i = 0; i < MAX_AUCTION_QUALITY; ++i)
|
||||
{
|
||||
if (!arg)
|
||||
return false;
|
||||
rVal[i] = atoi(arg);
|
||||
arg = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
sAuctionBot->SetItemsRatio(rVal[0], rVal[1], rVal[2]);
|
||||
|
||||
for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i)
|
||||
handler->PSendSysMessage(LANG_AHBOT_ITEMS_RATIO, AuctionBotConfig::GetHouseTypeName(AuctionHouseType(i)), sAuctionBotConfig->GetConfigItemAmountRatio(AuctionHouseType(i)));
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("alliance", RBACPermissions.CommandAhbotRatioAlliance, true)]
|
||||
static bool HandleAHBotItemsRatioHouseAlliance(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
[Command("horde", RBACPermissions.CommandAhbotRatioHorde, true)]
|
||||
static bool HandleAHBotItemsRatioHouseHorde(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
[Command("neutral", RBACPermissions.CommandAhbotRatioNeutral, true)]
|
||||
static bool HandleAHBotItemsRatioHouseNeutral(StringArguments args, CommandHandler handler) { return true; }
|
||||
|
||||
static bool HandleAHBotItemsRatioHouseCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/*char* arg = strtok((char*)args, " ");
|
||||
if (!arg)
|
||||
return false;
|
||||
public uint ratioVal = atoi(arg);
|
||||
|
||||
sAuctionBot->SetItemsRatioForHouse(H, ratioVal);
|
||||
handler->PSendSysMessage(LANG_AHBOT_ITEMS_RATIO, AuctionBotConfig::GetHouseTypeName(H), sAuctionBotConfig->GetConfigItemAmountRatio(H));
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Arenas;
|
||||
using Game.Entities;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("arena", RBACPermissions.CommandArena)]
|
||||
class ArenaCommands
|
||||
{
|
||||
[Command("create", RBACPermissions.CommandArenaCreate, true)]
|
||||
static bool HandleArenaCreateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args[0] != '"' ? args : null, out target))
|
||||
return false;
|
||||
|
||||
string name = handler.extractQuotedArg(args.NextString());
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return false;
|
||||
|
||||
byte type = args.NextByte();
|
||||
if (type == 0)
|
||||
return false;
|
||||
|
||||
if (Global.ArenaTeamMgr.GetArenaTeamByName(name) != null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorNameExists, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == 2 || type == 3 || type == 5)
|
||||
{
|
||||
if (Player.GetArenaTeamIdFromDB(target.GetGUID(), type) != 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorSize, target.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
ArenaTeam arena = new ArenaTeam();
|
||||
|
||||
if (!arena.Create(target.GetGUID(), type, name, 4293102085, 101, 4293253939, 4, 4284049911))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.ArenaTeamMgr.AddArenaTeam(arena);
|
||||
handler.SendSysMessage(CypherStrings.ArenaCreate, arena.GetName(), arena.GetId(), arena.GetArenaType(), arena.GetCaptain());
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("disband", RBACPermissions.CommandArenaDisband, true)]
|
||||
static bool HandleArenaDisbandCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint teamId = args.NextUInt32();
|
||||
if (teamId == 0)
|
||||
return false;
|
||||
|
||||
ArenaTeam arena = Global.ArenaTeamMgr.GetArenaTeamById(teamId);
|
||||
|
||||
if (arena == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorNotFound, teamId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arena.IsFighting())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorCombat);
|
||||
return false;
|
||||
}
|
||||
|
||||
string name = arena.GetName();
|
||||
arena.Disband();
|
||||
if (handler.GetSession() != null)
|
||||
Log.outDebug(LogFilter.Arena, "GameMaster: {0} [GUID: {1}] disbanded arena team type: {2} [Id: {3}].",
|
||||
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(), arena.GetArenaType(), teamId);
|
||||
else
|
||||
Log.outDebug(LogFilter.Arena, "Console: disbanded arena team type: {0} [Id: {1}].", arena.GetArenaType(), teamId);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ArenaDisband, name, teamId);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("rename", RBACPermissions.CommandArenaRename, true)]
|
||||
static bool HandleArenaRenameCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string oldArenaStr = handler.extractQuotedArg(args.NextString());
|
||||
if (string.IsNullOrEmpty(oldArenaStr))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
string newArenaStr = handler.extractQuotedArg(args.NextString());
|
||||
if (string.IsNullOrEmpty(newArenaStr))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
ArenaTeam arena = Global.ArenaTeamMgr.GetArenaTeamByName(oldArenaStr);
|
||||
if (arena == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AreanErrorNameNotFound, oldArenaStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Global.ArenaTeamMgr.GetArenaTeamByName(newArenaStr) != null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorNameExists, oldArenaStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arena.IsFighting())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorCombat);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!arena.SetName(newArenaStr))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ArenaRename, arena.GetId(), oldArenaStr, newArenaStr);
|
||||
if (handler.GetSession() != null)
|
||||
Log.outDebug(LogFilter.Arena, "GameMaster: {0} [GUID: {1}] rename arena team \"{2}\"[Id: {3}] to \"{4}\"",
|
||||
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(), oldArenaStr, arena.GetId(), newArenaStr);
|
||||
else
|
||||
Log.outDebug(LogFilter.Arena, "Console: rename arena team \"{0}\"[Id: {1}] to \"{2}\"", oldArenaStr, arena.GetId(), newArenaStr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("captain", RBACPermissions.CommandArenaCaptain)]
|
||||
static bool HandleArenaCaptainCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string idStr;
|
||||
string nameStr;
|
||||
handler.extractOptFirstArg(args, out idStr, out nameStr);
|
||||
if (string.IsNullOrEmpty(idStr))
|
||||
return false;
|
||||
|
||||
uint teamId = uint.Parse(idStr);
|
||||
if (teamId == 0)
|
||||
return false;
|
||||
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
if (!handler.extractPlayerTarget(new StringArguments(nameStr), out target, out targetGuid))
|
||||
return false;
|
||||
|
||||
ArenaTeam arena = Global.ArenaTeamMgr.GetArenaTeamById(teamId);
|
||||
|
||||
if (arena == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorNotFound, teamId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotExistOrOffline, nameStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arena.IsFighting())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorCombat);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!arena.IsMember(targetGuid))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorNotMember, nameStr, arena.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arena.GetCaptain() == targetGuid)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorCaptain, nameStr, arena.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
arena.SetCaptain(targetGuid);
|
||||
|
||||
CharacterInfo oldCaptainNameData = Global.WorldMgr.GetCharacterInfo(arena.GetCaptain());
|
||||
if (oldCaptainNameData == null)
|
||||
return false;
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ArenaCaptain, arena.GetName(), arena.GetId(), oldCaptainNameData.Name, target.GetName());
|
||||
if (handler.GetSession() != null)
|
||||
Log.outDebug(LogFilter.Arena, "GameMaster: {0} [GUID: {1}] promoted player: {2} [GUID: {3}] to leader of arena team \"{4}\"[Id: {5}]",
|
||||
handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(), target.GetName(), target.GetGUID().ToString(), arena.GetName(), arena.GetId());
|
||||
else
|
||||
Log.outDebug(LogFilter.Arena, "Console: promoted player: {0} [GUID: {1}] to leader of arena team \"{2}\"[Id: {3}]",
|
||||
target.GetName(), target.GetGUID().ToString(), arena.GetName(), arena.GetId());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("info", RBACPermissions.CommandArenaInfo, true)]
|
||||
static bool HandleArenaInfoCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint teamId = args.NextUInt32();
|
||||
if (teamId == 0)
|
||||
return false;
|
||||
|
||||
ArenaTeam arena = Global.ArenaTeamMgr.GetArenaTeamById(teamId);
|
||||
|
||||
if (arena == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaErrorNotFound, teamId);
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ArenaInfoHeader, arena.GetName(), arena.GetId(), arena.GetRating(), arena.GetArenaType(), arena.GetArenaType());
|
||||
foreach (var member in arena.GetMembers())
|
||||
handler.SendSysMessage(CypherStrings.ArenaInfoMembers, member.Name, member.Guid, member.PersonalRating, (arena.GetCaptain() == member.Guid ? "- Captain" : ""));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("lookup", RBACPermissions.CommandArenaLookup)]
|
||||
static bool HandleArenaLookupCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string name = args.NextString().ToLower();
|
||||
|
||||
bool found = false;
|
||||
foreach (var arena in Global.ArenaTeamMgr.GetArenaTeamMap().Values)
|
||||
{
|
||||
if (arena.GetName() == name)
|
||||
{
|
||||
if (handler.GetSession() != null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ArenaLookup, arena.GetName(), arena.GetId(), arena.GetArenaType(), arena.GetArenaType());
|
||||
found = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
handler.SendSysMessage(CypherStrings.AreanErrorNameNotFound, name);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("bnetaccount", RBACPermissions.CommandBnetAccount, true)]
|
||||
class BNetAccountCommands
|
||||
{
|
||||
[Command("create", RBACPermissions.CommandBnetAccountCreate, true)]
|
||||
static bool HandleAccountCreateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// Parse the command line arguments
|
||||
string accountName = args.NextString();
|
||||
string password = args.NextString();
|
||||
if (string.IsNullOrEmpty(accountName) || string.IsNullOrEmpty(password))
|
||||
return false;
|
||||
|
||||
if (!accountName.Contains('@'))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountInvalidBnetName);
|
||||
return false;
|
||||
}
|
||||
|
||||
string createGameAccountParam = args.NextString();
|
||||
bool createGameAccount = true;
|
||||
if (!string.IsNullOrEmpty(createGameAccountParam))
|
||||
createGameAccount = bool.Parse(createGameAccountParam);
|
||||
|
||||
string gameAccountName;
|
||||
switch (Global.BNetAccountMgr.CreateBattlenetAccount(accountName, password, createGameAccount, out gameAccountName))
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
if (createGameAccount)
|
||||
handler.SendSysMessage(CypherStrings.AccountCreatedBnetWithGame, accountName, gameAccountName);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.AccountCreated, accountName);
|
||||
|
||||
if (handler.GetSession() != null)
|
||||
{
|
||||
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] ({3}) created Battle.net account {4}{5}{6}",
|
||||
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetPlayer().GetName(),
|
||||
handler.GetSession().GetPlayer().GetGUID().ToString(), accountName, createGameAccount ? " with game account " : "", createGameAccount ? gameAccountName : "");
|
||||
}
|
||||
break;
|
||||
case AccountOpResult.NameTooLong:
|
||||
handler.SendSysMessage(CypherStrings.AccountNameTooLong);
|
||||
return false;
|
||||
case AccountOpResult.PassTooLong:
|
||||
handler.SendSysMessage(CypherStrings.AccountPassTooLong);
|
||||
return false;
|
||||
case AccountOpResult.NameAlreadyExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountAlreadyExist);
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("gameaccountcreate", RBACPermissions.CommandBnetAccountCreateGame, true)]
|
||||
static bool HandleGameAccountCreateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
string bnetAccountName = args.NextString();
|
||||
uint accountId = Global.BNetAccountMgr.GetId(bnetAccountName);
|
||||
if (accountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, bnetAccountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
byte index = (byte)(Global.BNetAccountMgr.GetMaxIndex(accountId) + 1);
|
||||
string accountName = accountId.ToString() + '#' + index;
|
||||
|
||||
switch (Global.AccountMgr.CreateAccount(accountName, "DUMMY", bnetAccountName, accountId, index))
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.AccountCreated, accountName);
|
||||
if (handler.GetSession() != null)
|
||||
{
|
||||
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Character:[{2}] ({3}) created Account {4} (Email: '{5}')",
|
||||
handler.GetSession().GetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(),
|
||||
accountName, bnetAccountName);
|
||||
}
|
||||
break;
|
||||
case AccountOpResult.NameTooLong:
|
||||
handler.SendSysMessage(CypherStrings.AccountNameTooLong);
|
||||
return false;
|
||||
case AccountOpResult.PassTooLong:
|
||||
handler.SendSysMessage(CypherStrings.AccountPassTooLong);
|
||||
return false;
|
||||
case AccountOpResult.NameAlreadyExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountAlreadyExist);
|
||||
return false;
|
||||
case AccountOpResult.DBInternalError:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotCreatedSqlError, accountName);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotCreated, accountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("link", RBACPermissions.CommandBnetAccountLink, true)]
|
||||
static bool HandleAccountLinkCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
string bnetAccountName = args.NextString();
|
||||
string gameAccountName = args.NextString();
|
||||
|
||||
switch (Global.BNetAccountMgr.LinkWithGameAccount(bnetAccountName, gameAccountName))
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.AccountBnetLinked, bnetAccountName, gameAccountName);
|
||||
break;
|
||||
case AccountOpResult.NameNotExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountOrBnetDoesNotExist, bnetAccountName, gameAccountName);
|
||||
break;
|
||||
case AccountOpResult.BadLink:
|
||||
handler.SendSysMessage( CypherStrings.AccountAlreadyLinked, gameAccountName);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("listgameaccounts", RBACPermissions.CommandBnetAccountListGameAccounts, true)]
|
||||
static bool HandleListGameAccountsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string battlenetAccountName = args.NextString();
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_BNET_GAME_ACCOUNT_LIST);
|
||||
stmt.AddValue(0, battlenetAccountName);
|
||||
|
||||
SQLResult accountList = DB.Login.Query(stmt);
|
||||
if (!accountList.IsEmpty())
|
||||
{
|
||||
var formatDisplayName = new Func<string, string>(name =>
|
||||
{
|
||||
int index = name.IndexOf('#');
|
||||
if (index > 0)
|
||||
return "WoW" + name.Substring(++index);
|
||||
else
|
||||
return name;
|
||||
});
|
||||
|
||||
handler.SendSysMessage("----------------------------------------------------");
|
||||
handler.SendSysMessage(CypherStrings.AccountBnetListHeader);
|
||||
handler.SendSysMessage("----------------------------------------------------");
|
||||
do
|
||||
{
|
||||
handler.SendSysMessage("| {10:0} | {1} | {2} |", accountList.Read<uint>(0), accountList.Read<string>(1), formatDisplayName(accountList.Read<string>(1)));
|
||||
} while (accountList.NextRow());
|
||||
handler.SendSysMessage("----------------------------------------------------");
|
||||
}
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.AccountBnetListNoAccounts, battlenetAccountName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("password", RBACPermissions.CommandBnetAccountPassword, true)]
|
||||
static bool HandleAccountPasswordCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// If no args are given at all, we can return false right away.
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Command is supposed to be: .account password [$oldpassword] [$newpassword] [$newpasswordconfirmation] [$emailconfirmation]
|
||||
string oldPassword = args.NextString(); // This extracts [$oldpassword]
|
||||
string newPassword = args.NextString(); // This extracts [$newpassword]
|
||||
string passwordConfirmation = args.NextString(); // This extracts [$newpasswordconfirmation]
|
||||
|
||||
//Is any of those variables missing for any reason ? We return false.
|
||||
if (string.IsNullOrEmpty(oldPassword) || string.IsNullOrEmpty(newPassword) || string.IsNullOrEmpty(passwordConfirmation))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We compare the old, saved password to the entered old password - no chance for the unauthorized.
|
||||
if (!Global.BNetAccountMgr.CheckPassword(handler.GetSession().GetBattlenetAccountId(), oldPassword))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandWrongoldpassword);
|
||||
|
||||
Log.outInfo(LogFilter.Player, "Battle.net account: {0} (IP: {1}) Character:[{2}] ({3}) Tried to change password, but the provided old password is wrong.",
|
||||
handler.GetSession().GetBattlenetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Making sure that newly entered password is correctly entered.
|
||||
if (newPassword != passwordConfirmation)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NewPasswordsNotMatch);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Changes password and prints result.
|
||||
AccountOpResult result = Global.BNetAccountMgr.ChangePassword(handler.GetSession().GetBattlenetAccountId(), newPassword);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.CommandPassword);
|
||||
Log.outInfo(LogFilter.Player, "Battle.net account: {0} (IP: {1}) Character:[{2}] ({3}) Changed Password.",
|
||||
handler.GetSession().GetBattlenetAccountId(), handler.GetSession().GetRemoteAddress(), handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString());
|
||||
break;
|
||||
case AccountOpResult.PassTooLong:
|
||||
handler.SendSysMessage(CypherStrings.PasswordTooLong);
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.CommandNotchangepassword);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("unlink", RBACPermissions.CommandBnetAccountUnlink, true)]
|
||||
static bool HandleAccountUnlinkCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
string gameAccountName = args.NextString();
|
||||
switch (Global.BNetAccountMgr.UnlinkGameAccount(gameAccountName))
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.AccountBnetUnlinked, gameAccountName);
|
||||
break;
|
||||
case AccountOpResult.NameNotExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, gameAccountName);
|
||||
break;
|
||||
case AccountOpResult.BadLink:
|
||||
handler.SendSysMessage(CypherStrings.AccountBnetNotLinked, gameAccountName);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("lock", RBACPermissions.CommandBnetAccount, true)]
|
||||
class LockCommands {
|
||||
[Command("country", RBACPermissions.CommandBnetAccountLockCountry, true)]
|
||||
static bool HandleLockCountryCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
string param = args.NextString();
|
||||
if (!string.IsNullOrEmpty(param))
|
||||
{
|
||||
if (param == "on")
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_LOGON_COUNTRY);
|
||||
var ipBytes = System.Net.IPAddress.Parse(handler.GetSession().GetRemoteAddress()).GetAddressBytes();
|
||||
Array.Reverse(ipBytes);
|
||||
stmt.AddValue(0, BitConverter.ToUInt32(ipBytes, 0));
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
string country = result.Read<string>(0);
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_ACCOUNT_LOCK_CONTRY);
|
||||
stmt.AddValue(0, country);
|
||||
stmt.AddValue(1, handler.GetSession().GetBattlenetAccountId());
|
||||
DB.Login.Execute(stmt);
|
||||
handler.SendSysMessage(CypherStrings.CommandAcclocklocked);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage("[IP2NATION] Table empty");
|
||||
Log.outDebug(LogFilter.Server, "[IP2NATION] Table empty");
|
||||
}
|
||||
}
|
||||
else if (param == "off")
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_ACCOUNT_LOCK_CONTRY);
|
||||
stmt.AddValue(0, "00");
|
||||
stmt.AddValue(1, handler.GetSession().GetBattlenetAccountId());
|
||||
DB.Login.Execute(stmt);
|
||||
handler.SendSysMessage(CypherStrings.CommandAcclockunlocked);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("ip", RBACPermissions.CommandBnetAccountLockIp, true)]
|
||||
static bool HandleLockIpCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
string param = args.NextString();
|
||||
|
||||
if (!string.IsNullOrEmpty(param))
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_ACCOUNT_LOCK);
|
||||
if (param == "on")
|
||||
{
|
||||
stmt.AddValue(0, true); // locked
|
||||
handler.SendSysMessage(CypherStrings.CommandAcclocklocked);
|
||||
}
|
||||
else if (param == "off")
|
||||
{
|
||||
stmt.AddValue(0, false); // unlocked
|
||||
handler.SendSysMessage(CypherStrings.CommandAcclockunlocked);
|
||||
}
|
||||
|
||||
stmt.AddValue(1, handler.GetSession().GetBattlenetAccountId());
|
||||
DB.Login.Execute(stmt);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("set", RBACPermissions.CommandBnetAccountSet, true)]
|
||||
class SetCommands
|
||||
{
|
||||
[Command("password", RBACPermissions.CommandBnetAccountSetPassword, true)]
|
||||
static bool HandleSetPasswordCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the command line arguments
|
||||
string accountName = args.NextString();
|
||||
string password = args.NextString();
|
||||
string passwordConfirmation = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(accountName) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(passwordConfirmation))
|
||||
return false;
|
||||
|
||||
uint targetAccountId = Global.BNetAccountMgr.GetId(accountName);
|
||||
if (targetAccountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password != passwordConfirmation)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NewPasswordsNotMatch);
|
||||
return false;
|
||||
}
|
||||
|
||||
AccountOpResult result = Global.BNetAccountMgr.ChangePassword(targetAccountId, password);
|
||||
switch (result)
|
||||
{
|
||||
case AccountOpResult.Ok:
|
||||
handler.SendSysMessage(CypherStrings.CommandPassword);
|
||||
break;
|
||||
case AccountOpResult.NameNotExist:
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return false;
|
||||
case AccountOpResult.PassTooLong:
|
||||
handler.SendSysMessage(CypherStrings.PasswordTooLong);
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,664 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("ban", RBACPermissions.CommandBan, true)]
|
||||
class BanCommands
|
||||
{
|
||||
[Command("account", RBACPermissions.CommandBanAccount, true)]
|
||||
static bool HandleBanAccountCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleBanHelper(BanMode.Account, args, handler);
|
||||
}
|
||||
|
||||
[Command("character", RBACPermissions.CommandBanCharacter, true)]
|
||||
static bool HandleBanCharacterCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string name = args.NextString();
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return false;
|
||||
|
||||
string durationStr = args.NextString();
|
||||
if (string.IsNullOrEmpty(durationStr))
|
||||
return false;
|
||||
|
||||
uint duration = uint.Parse(durationStr);
|
||||
|
||||
string reasonStr = args.NextString("");
|
||||
if (string.IsNullOrEmpty(reasonStr))
|
||||
return false;
|
||||
|
||||
if (!ObjectManager.NormalizePlayerName(ref name))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
string author = handler.GetSession() != null ? handler.GetSession().GetPlayerName() : "Server";
|
||||
|
||||
switch (Global.WorldMgr.BanCharacter(name, durationStr, reasonStr, author))
|
||||
{
|
||||
case BanReturn.Success:
|
||||
{
|
||||
if (duration > 0)
|
||||
{
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.ShowBanInWorld))
|
||||
Global.WorldMgr.SendWorldText(CypherStrings.BanCharacterYoubannedmessageWorld, author, name, Time.secsToTimeString(Time.TimeStringToSecs(durationStr), true), reasonStr);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.BanYoubanned, name, Time.secsToTimeString(Time.TimeStringToSecs(durationStr), true), reasonStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.ShowBanInWorld))
|
||||
Global.WorldMgr.SendWorldText(CypherStrings.BanCharacterYoupermbannedmessageWorld, author, name, reasonStr);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.BanYoupermbanned, name, reasonStr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BanReturn.Notfound:
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BanNotfound, "character", name);
|
||||
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("playeraccount", RBACPermissions.CommandBanPlayeraccount, true)]
|
||||
static bool HandleBanAccountByCharCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleBanHelper(BanMode.Character, args, handler);
|
||||
}
|
||||
|
||||
[Command("ip", RBACPermissions.CommandBanIp, true)]
|
||||
static bool HandleBanIPCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleBanHelper(BanMode.IP, args, handler);
|
||||
}
|
||||
|
||||
static bool HandleBanHelper(BanMode mode, StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string nameOrIP = args.NextString();
|
||||
if (string.IsNullOrEmpty(nameOrIP))
|
||||
return false;
|
||||
|
||||
uint duration;
|
||||
string durationStr = args.NextString();
|
||||
if (string.IsNullOrEmpty(durationStr) || !uint.TryParse(durationStr, out duration))
|
||||
return false;
|
||||
|
||||
string reasonStr = args.NextString("");
|
||||
if (string.IsNullOrEmpty(reasonStr))
|
||||
return false;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case BanMode.Character:
|
||||
if (!ObjectManager.NormalizePlayerName(ref nameOrIP))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case BanMode.IP:
|
||||
IPAddress address;
|
||||
if (!IPAddress.TryParse(nameOrIP, out address))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
string author = handler.GetSession() ? handler.GetSession().GetPlayerName() : "Server";
|
||||
switch (Global.WorldMgr.BanAccount(mode, nameOrIP, durationStr, reasonStr, author))
|
||||
{
|
||||
case BanReturn.Success:
|
||||
if (uint.Parse(durationStr) > 0)
|
||||
{
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.ShowBanInWorld))
|
||||
Global.WorldMgr.SendWorldText(CypherStrings.BanAccountYoubannedmessageWorld, author, nameOrIP, Time.secsToTimeString(Time.TimeStringToSecs(durationStr)).ToString(), reasonStr);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.BanYoubanned, nameOrIP, Time.secsToTimeString(Time.TimeStringToSecs(durationStr), true), reasonStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (WorldConfig.GetBoolValue(WorldCfg.ShowBanInWorld))
|
||||
Global.WorldMgr.SendWorldText(CypherStrings.BanAccountYoupermbannedmessageWorld, author, nameOrIP, reasonStr);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.BanYoupermbanned, nameOrIP, reasonStr);
|
||||
}
|
||||
break;
|
||||
case BanReturn.SyntaxError:
|
||||
return false;
|
||||
case BanReturn.Notfound:
|
||||
switch (mode)
|
||||
{
|
||||
default:
|
||||
handler.SendSysMessage(CypherStrings.BanNotfound, "account", nameOrIP);
|
||||
break;
|
||||
case BanMode.Character:
|
||||
handler.SendSysMessage(CypherStrings.BanNotfound, "character", nameOrIP);
|
||||
break;
|
||||
case BanMode.IP:
|
||||
handler.SendSysMessage(CypherStrings.BanNotfound, "ip", nameOrIP);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("baninfo", RBACPermissions.CommandBaninfo, true)]
|
||||
class BanInfoCommands
|
||||
{
|
||||
[Command("account", RBACPermissions.CommandBaninfoAccount, true)]
|
||||
static bool HandleBanInfoAccountCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string accountName = args.NextString("");
|
||||
if (string.IsNullOrEmpty(accountName))
|
||||
return false;
|
||||
|
||||
uint accountId = Global.AccountMgr.GetId(accountName);
|
||||
if (accountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return true;
|
||||
}
|
||||
|
||||
return HandleBanInfoHelper(accountId, accountName, handler);
|
||||
}
|
||||
|
||||
[Command("character", RBACPermissions.CommandBaninfoCharacter, true)]
|
||||
static bool HandleBanInfoCharacterCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string name = args.NextString();
|
||||
Player target = Global.ObjAccessor.FindPlayerByName(name);
|
||||
ObjectGuid targetGuid;
|
||||
|
||||
if (!target)
|
||||
{
|
||||
targetGuid = ObjectManager.GetPlayerGUIDByName(name);
|
||||
if (targetGuid.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BaninfoNocharacter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
targetGuid = target.GetGUID();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_BANINFO);
|
||||
stmt.AddValue(0, targetGuid.GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharNotBanned, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.BaninfoBanhistory, name);
|
||||
do
|
||||
{
|
||||
long unbanDate = result.Read<uint>(3);
|
||||
bool active = false;
|
||||
if (result.Read<bool>(2) && (result.Read<uint>(1) == 0 || unbanDate >= Time.UnixTime))
|
||||
active = true;
|
||||
bool permanent = (result.Read<uint>(1) == 0);
|
||||
string banTime = permanent ? handler.GetCypherString(CypherStrings.BaninfoInfinite) : Time.secsToTimeString(result.Read<uint>(1), true);
|
||||
handler.SendSysMessage(CypherStrings.BaninfoHistoryentry, Time.UnixTimeToDateTime(result.Read<uint>(0)).ToShortTimeString(), banTime,
|
||||
active ? handler.GetCypherString(CypherStrings.Yes) : handler.GetCypherString(CypherStrings.No), result.Read<string>(4), result.Read<string>(5));
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("ip", RBACPermissions.CommandBaninfoIp, true)]
|
||||
static bool HandleBanInfoIPCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string ip = args.NextString("");
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
return false;
|
||||
|
||||
SQLResult result = DB.Login.Query("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason, bannedby, unbandate-bandate FROM ip_banned WHERE ip = '{0}'", ip);
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BaninfoNoip);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool permanent = result.Read<ulong>(6) == 0;
|
||||
handler.SendSysMessage(CypherStrings.BaninfoIpentry, result.Read<string>(0), result.Read<string>(1), permanent ? handler.GetCypherString( CypherStrings.BaninfoNever) : result.Read<string>(2),
|
||||
permanent ? handler.GetCypherString( CypherStrings.BaninfoInfinite) : Time.secsToTimeString(result.Read<ulong>(3), true), result.Read<string>(4), result.Read<string>(5));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleBanInfoHelper(uint accountId, string accountName, CommandHandler handler)
|
||||
{
|
||||
SQLResult result = DB.Login.Query("SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate, banreason, bannedby FROM account_banned WHERE id = '{0}' ORDER BY bandate ASC", accountId);
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BaninfoNoaccountban, accountName);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.BaninfoBanhistory, accountName);
|
||||
do
|
||||
{
|
||||
long unbanDate = result.Read<uint>(3);
|
||||
bool active = false;
|
||||
if (result.Read<bool>(2) && (result.Read<ulong>(1) == 0 || unbanDate >= Time.UnixTime))
|
||||
active = true;
|
||||
bool permanent = (result.Read<ulong>(1) == 0);
|
||||
string banTime = permanent ? handler.GetCypherString(CypherStrings.BaninfoInfinite) : Time.secsToTimeString(result.Read<ulong>(1), true);
|
||||
handler.SendSysMessage(CypherStrings.BaninfoHistoryentry,
|
||||
result.Read<string>(0), banTime, active ? handler.GetCypherString(CypherStrings.Yes) : handler.GetCypherString(CypherStrings.No), result.Read<string>(4), result.Read<string>(5));
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[CommandGroup("banlist", RBACPermissions.CommandBanlist, true)]
|
||||
class BanListCommands
|
||||
{
|
||||
[Command("account", RBACPermissions.CommandBanlistAccount, true)]
|
||||
static bool HandleBanListAccountCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_EXPIRED_IP_BANS);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
string filterStr = args.NextString();
|
||||
string filter = !string.IsNullOrEmpty(filterStr) ? filterStr : "";
|
||||
|
||||
SQLResult result;
|
||||
if (string.IsNullOrEmpty(filter))
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_BANNED_ALL);
|
||||
result = DB.Login.Query(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_BANNED_BY_USERNAME);
|
||||
stmt.AddValue(0, filter);
|
||||
result = DB.Login.Query(stmt);
|
||||
}
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BanlistNoaccount);
|
||||
return true;
|
||||
}
|
||||
|
||||
return HandleBanListHelper(result, handler);
|
||||
}
|
||||
|
||||
[Command("character", RBACPermissions.CommandBanlistCharacter, true)]
|
||||
static bool HandleBanListCharacterCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string filter = args.NextString();
|
||||
if (string.IsNullOrEmpty(filter))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_BY_NAME_FILTER);
|
||||
stmt.AddValue(0, filter);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BanlistNocharacter);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.BanlistMatchingcharacter);
|
||||
|
||||
// Chat short output
|
||||
if (handler.GetSession())
|
||||
{
|
||||
do
|
||||
{
|
||||
|
||||
PreparedStatement stmt2 = DB.Characters.GetPreparedStatement(CharStatements.SEL_BANNED_NAME);
|
||||
stmt2.AddValue(0, result.Read<ulong>(0));
|
||||
SQLResult banResult = DB.Characters.Query(stmt2);
|
||||
if (!banResult.IsEmpty())
|
||||
handler.SendSysMessage(banResult.Read<string>(0));
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
// Console wide output
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BanlistCharacters);
|
||||
handler.SendSysMessage(" =============================================================================== ");
|
||||
handler.SendSysMessage(CypherStrings.BanlistCharactersHeader);
|
||||
do
|
||||
{
|
||||
handler.SendSysMessage("-------------------------------------------------------------------------------");
|
||||
|
||||
string char_name = result.Read<string>(1);
|
||||
|
||||
PreparedStatement stmt2 = DB.Characters.GetPreparedStatement(CharStatements.SEL_BANINFO_LIST);
|
||||
stmt2.AddValue(0, result.Read<ulong>(0));
|
||||
SQLResult banInfo = DB.Characters.Query(stmt2);
|
||||
if (!banInfo.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
long timeBan = banInfo.Read<uint>(0);
|
||||
DateTime tmBan = Time.UnixTimeToDateTime(timeBan);
|
||||
string bannedby = banInfo.Read<string>(2).Substring(0, 15);
|
||||
string banreason = banInfo.Read<string>(3).Substring(0, 15);
|
||||
|
||||
if (banInfo.Read<uint>(0) == banInfo.Read<uint>(1))
|
||||
{
|
||||
handler.SendSysMessage("|{0}|{1:D2}-{2:D2}-{3:D2} {4:D2}:{5:D2}| permanent |{6}|{7}|",
|
||||
char_name, tmBan.Year % 100, tmBan.Month + 1, tmBan.Day, tmBan.Hour, tmBan.Minute,
|
||||
bannedby, banreason);
|
||||
}
|
||||
else
|
||||
{
|
||||
long timeUnban = banInfo.Read<uint>(1);
|
||||
DateTime tmUnban = Time.UnixTimeToDateTime(timeUnban);
|
||||
handler.SendSysMessage("|{0}|{1:D2}-{2:D2}-{3:D2} {4:D2}:{5:D2}|{6:D2}-{7:D2}-{8:D2} {9:D2}:{10:D2}|{11}|{12}|",
|
||||
char_name, tmBan.Year % 100, tmBan.Month + 1, tmBan.Day, tmBan.Hour, tmBan.Minute,
|
||||
tmUnban.Year % 100, tmUnban.Month + 1, tmUnban.Day, tmUnban.Hour, tmUnban.Minute,
|
||||
bannedby, banreason);
|
||||
}
|
||||
}
|
||||
while (banInfo.NextRow());
|
||||
}
|
||||
}
|
||||
while (result.NextRow());
|
||||
handler.SendSysMessage(" =============================================================================== ");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("ip", RBACPermissions.CommandBanlistIp, true)]
|
||||
static bool HandleBanListIPCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_EXPIRED_IP_BANS);
|
||||
DB.Login.Execute(stmt);
|
||||
|
||||
string filterStr = args.NextString();
|
||||
string filter = !string.IsNullOrEmpty(filterStr) ? filterStr : "";
|
||||
|
||||
SQLResult result;
|
||||
|
||||
if (string.IsNullOrEmpty(filter))
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_IP_BANNED_ALL);
|
||||
result = DB.Login.Query(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_IP_BANNED_BY_IP);
|
||||
stmt.AddValue(0, filter);
|
||||
result = DB.Login.Query(stmt);
|
||||
}
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BanlistNoip);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.BanlistMatchingip);
|
||||
// Chat short output
|
||||
if (handler.GetSession())
|
||||
{
|
||||
do
|
||||
{
|
||||
handler.SendSysMessage("{0}", result.Read<string>(0));
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
// Console wide output
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BanlistIps);
|
||||
handler.SendSysMessage(" ===============================================================================");
|
||||
handler.SendSysMessage(CypherStrings.BanlistIpsHeader);
|
||||
do
|
||||
{
|
||||
handler.SendSysMessage("-------------------------------------------------------------------------------");
|
||||
|
||||
long timeBan = result.Read<uint>(1);
|
||||
DateTime tmBan = Time.UnixTimeToDateTime(timeBan);
|
||||
string bannedby = result.Read<string>(3).Substring(0, 15);
|
||||
string banreason = result.Read<string>(4).Substring(0, 15);
|
||||
|
||||
if (result.Read<uint>(1) == result.Read<uint>(2))
|
||||
{
|
||||
handler.SendSysMessage("|{0}|{1:D2}-{2:D2}-{3:D2} {4:D2}:{5:D2}| permanent |{6}|{7}|",
|
||||
result.Read<string>(0), tmBan.Year % 100, tmBan.Month + 1, tmBan.Day, tmBan.Hour, tmBan.Minute,
|
||||
bannedby, banreason);
|
||||
}
|
||||
else
|
||||
{
|
||||
long timeUnban = result.Read<uint>(2);
|
||||
DateTime tmUnban;
|
||||
tmUnban = Time.UnixTimeToDateTime(timeUnban);
|
||||
handler.SendSysMessage("|{0}|{1:D2}-{2:D2}-{3:D2} {4:D2}:{5:D2}|{6:D2}-{7:D2}-{8:D2} {9:D2}:{10:D2}|{11}|{12}|",
|
||||
result.Read<string>(0), tmBan.Year % 100, tmBan.Month + 1, tmBan.Day, tmBan.Hour, tmBan.Minute,
|
||||
tmUnban.Year % 100, tmUnban.Month + 1, tmUnban.Day, tmUnban.Hour, tmUnban.Minute,
|
||||
bannedby, banreason);
|
||||
}
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
handler.SendSysMessage(" ===============================================================================");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleBanListHelper(SQLResult result, CommandHandler handler)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BanlistMatchingaccount);
|
||||
|
||||
// Chat short output
|
||||
if (handler.GetSession())
|
||||
{
|
||||
do
|
||||
{
|
||||
|
||||
uint accountid = result.Read<uint>(0);
|
||||
|
||||
SQLResult banResult = DB.Login.Query("SELECT account.username FROM account, account_banned WHERE account_banned.id='{0}' AND account_banned.id=account.id", accountid);
|
||||
if (!banResult.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(banResult.Read<string>(0));
|
||||
}
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
// Console wide output
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BanlistAccounts);
|
||||
handler.SendSysMessage(" ===============================================================================");
|
||||
handler.SendSysMessage(CypherStrings.BanlistAccountsHeader);
|
||||
do
|
||||
{
|
||||
handler.SendSysMessage("-------------------------------------------------------------------------------");
|
||||
|
||||
uint accountId = result.Read<uint>(0);
|
||||
|
||||
string accountName;
|
||||
|
||||
// "account" case, name can be get in same query
|
||||
if (result.GetRowCount() > 1)
|
||||
accountName = result.Read<string>(1);
|
||||
// "character" case, name need extract from another DB
|
||||
else
|
||||
Global.AccountMgr.GetName(accountId, out accountName);
|
||||
|
||||
// No SQL injection. id is uint32.
|
||||
SQLResult banInfo = DB.Login.Query("SELECT bandate, unbandate, bannedby, banreason FROM account_banned WHERE id = {0} ORDER BY unbandate", accountId);
|
||||
if (!banInfo.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
long timeBan = banInfo.Read<uint>(0);
|
||||
DateTime tmBan;
|
||||
tmBan = Time.UnixTimeToDateTime(timeBan);
|
||||
string bannedby = banInfo.Read<string>(2).Substring(0, 15);
|
||||
string banreason = banInfo.Read<string>(3).Substring(0, 15);
|
||||
|
||||
if (banInfo.Read<uint>(0) == banInfo.Read<uint>(1))
|
||||
{
|
||||
handler.SendSysMessage("|{0}|{1:D2}-{2:D2}-{3:D2} {4:D2}:{5:D2}| permanent |{6}|{7}|",
|
||||
accountName.Substring(0, 15), tmBan.Year % 100, tmBan.Month + 1, tmBan.Day, tmBan.Hour, tmBan.Minute,
|
||||
bannedby, banreason);
|
||||
}
|
||||
else
|
||||
{
|
||||
long timeUnban = banInfo.Read <uint>(1);
|
||||
DateTime tmUnban;
|
||||
tmUnban = Time.UnixTimeToDateTime(timeUnban);
|
||||
handler.SendSysMessage("|{0}|{1:D2}-{2:D2}-{3:D2} {4:D2}:{5:D2}|{6:D2}-{7:D2}-{8:D2} {9:D2}:{10:D2}|{11}|{12}|",
|
||||
accountName.Substring(0, 15), tmBan.Year % 100, tmBan.Month + 1, tmBan.Day, tmBan.Hour, tmBan.Minute,
|
||||
tmUnban.Year % 100, tmUnban.Month + 1, tmUnban.Day, tmUnban.Hour, tmUnban.Minute,
|
||||
bannedby, banreason);
|
||||
}
|
||||
}
|
||||
while (banInfo.NextRow());
|
||||
}
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
handler.SendSysMessage(" ===============================================================================");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("unban", RBACPermissions.CommandUnban, true)]
|
||||
class UnBanCommands
|
||||
{
|
||||
[Command("account", RBACPermissions.CommandUnbanAccount, true)]
|
||||
static bool HandleUnBanAccountCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleUnBanHelper(BanMode.Account, args, handler);
|
||||
}
|
||||
|
||||
[Command("character", RBACPermissions.CommandUnbanCharacter, true)]
|
||||
static bool HandleUnBanCharacterCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string name = args.NextString();
|
||||
if (!ObjectManager.NormalizePlayerName(ref name))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Global.WorldMgr.RemoveBanCharacter(name))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("playeraccount", RBACPermissions.CommandUnbanPlayeraccount, true)]
|
||||
static bool HandleUnBanAccountByCharCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleUnBanHelper(BanMode.Character, args, handler);
|
||||
}
|
||||
|
||||
[Command("ip", RBACPermissions.CommandUnbanIp, true)]
|
||||
static bool HandleUnBanIPCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleUnBanHelper(BanMode.IP, args, handler);
|
||||
}
|
||||
|
||||
static bool HandleUnBanHelper(BanMode mode, StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string nameOrIP = args.NextString();
|
||||
if (string.IsNullOrEmpty(nameOrIP))
|
||||
return false;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case BanMode.Character:
|
||||
if (!ObjectManager.NormalizePlayerName(ref nameOrIP))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case BanMode.IP:
|
||||
IPAddress address;
|
||||
if (!IPAddress.TryParse(nameOrIP, out address))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Global.WorldMgr.RemoveBanAccount(mode, nameOrIP))
|
||||
handler.SendSysMessage(CypherStrings.UnbanUnbanned, nameOrIP);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.UnbanError, nameOrIP);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.BattleFields;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("bf", RBACPermissions.CommandBf)]
|
||||
class BattleFieldCommands
|
||||
{
|
||||
[Command("enable", RBACPermissions.CommandBfEnable)]
|
||||
static bool HandleBattlefieldEnable(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint battleid = args.NextUInt32();
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByBattleId(battleid);
|
||||
|
||||
if (bf == null)
|
||||
return false;
|
||||
|
||||
if (bf.IsEnabled())
|
||||
{
|
||||
bf.ToggleBattlefield(false);
|
||||
if (battleid == 1)
|
||||
handler.SendGlobalGMSysMessage("Wintergrasp is disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
bf.ToggleBattlefield(true);
|
||||
if (battleid == 1)
|
||||
handler.SendGlobalGMSysMessage("Wintergrasp is enabled");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("start", RBACPermissions.CommandBfStart)]
|
||||
static bool HandleBattlefieldStart(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint battleid = args.NextUInt32();
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByBattleId(battleid);
|
||||
|
||||
if (bf == null)
|
||||
return false;
|
||||
|
||||
bf.StartBattle();
|
||||
|
||||
if (battleid == 1)
|
||||
handler.SendGlobalGMSysMessage("Wintergrasp (Command start used)");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("stop", RBACPermissions.CommandBfStop)]
|
||||
static bool HandleBattlefieldEnd(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint battleid = args.NextUInt32();
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByBattleId(battleid);
|
||||
|
||||
if (bf == null)
|
||||
return false;
|
||||
|
||||
bf.EndBattle(true);
|
||||
|
||||
if (battleid == 1)
|
||||
handler.SendGlobalGMSysMessage("Wintergrasp (Command stop used)");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("switch", RBACPermissions.CommandBfSwitch)]
|
||||
static bool HandleBattlefieldSwitch(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint battleid = args.NextUInt32();
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByBattleId(battleid);
|
||||
|
||||
if (bf == null)
|
||||
return false;
|
||||
|
||||
bf.EndBattle(false);
|
||||
if (battleid == 1)
|
||||
handler.SendGlobalGMSysMessage("Wintergrasp (Command switch used)");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("timer", RBACPermissions.CommandBfTimer)]
|
||||
static bool HandleBattlefieldTimer(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint battleid = args.NextUInt32();
|
||||
BattleField bf = Global.BattleFieldMgr.GetBattlefieldByBattleId(battleid);
|
||||
|
||||
if (bf == null)
|
||||
return false;
|
||||
|
||||
uint time = args.NextUInt32();
|
||||
|
||||
bf.SetTimer(time * Time.InMilliseconds);
|
||||
bf.SendInitWorldStatesToAll();
|
||||
if (battleid == 1)
|
||||
handler.SendGlobalGMSysMessage("Wintergrasp (Command timer used)");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using Game.Spells;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("cast", RBACPermissions.CommandCast)]
|
||||
class CastCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandCast)]
|
||||
static bool HandleCastCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectCharOrCreature);
|
||||
return false;
|
||||
}
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
if (spellId == 0)
|
||||
return false;
|
||||
|
||||
if (!CheckSpellExistsAndIsValid(handler, spellId))
|
||||
return false;
|
||||
|
||||
string triggeredStr = args.NextString();
|
||||
if (!string.IsNullOrEmpty(triggeredStr))
|
||||
{
|
||||
if (triggeredStr != "triggered")
|
||||
return false;
|
||||
}
|
||||
|
||||
bool triggered = (triggeredStr != null);
|
||||
|
||||
handler.GetSession().GetPlayer().CastSpell(target, spellId, triggered);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("back", RBACPermissions.CommandCastBack)]
|
||||
static bool HandleCastBackCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Creature caster = handler.getSelectedCreature();
|
||||
if (!caster)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectCharOrCreature);
|
||||
return false;
|
||||
}
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
if (spellId == 0)
|
||||
return false;
|
||||
|
||||
if (CheckSpellExistsAndIsValid(handler, spellId))
|
||||
return false;
|
||||
|
||||
string triggeredStr = args.NextString();
|
||||
if (!string.IsNullOrEmpty(triggeredStr))
|
||||
{
|
||||
if (triggeredStr != "triggered")
|
||||
return false;
|
||||
}
|
||||
|
||||
bool triggered = (triggeredStr != null);
|
||||
|
||||
caster.CastSpell(handler.GetSession().GetPlayer(), spellId, triggered);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("dist", RBACPermissions.CommandCastDist)]
|
||||
static bool HandleCastDistCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
if (spellId == 0)
|
||||
return false;
|
||||
|
||||
if (CheckSpellExistsAndIsValid(handler, spellId))
|
||||
return false;
|
||||
|
||||
float dist = args.NextSingle();
|
||||
|
||||
string triggeredStr = args.NextString();
|
||||
if (!string.IsNullOrEmpty(triggeredStr))
|
||||
{
|
||||
if (triggeredStr != "triggered")
|
||||
return false;
|
||||
}
|
||||
|
||||
bool triggered = (triggeredStr != null);
|
||||
|
||||
float x, y, z;
|
||||
handler.GetSession().GetPlayer().GetClosePoint(out x, out y, out z, dist);
|
||||
|
||||
handler.GetSession().GetPlayer().CastSpell(x, y, z, spellId, triggered);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("self", RBACPermissions.CommandCastSelf)]
|
||||
static bool HandleCastSelfCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectCharOrCreature);
|
||||
return false;
|
||||
}
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
if (spellId == 0)
|
||||
return false;
|
||||
|
||||
if (CheckSpellExistsAndIsValid(handler, spellId))
|
||||
return false;
|
||||
|
||||
target.CastSpell(target, spellId, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("target", RBACPermissions.CommandCastTarget)]
|
||||
static bool HandleCastTargetCommad(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Creature caster = handler.getSelectedCreature();
|
||||
if (!caster)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectCharOrCreature);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!caster.GetVictim())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectedTargetNotHaveVictim);
|
||||
return false;
|
||||
}
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
if (spellId == 0)
|
||||
return false;
|
||||
|
||||
if (CheckSpellExistsAndIsValid(handler, spellId))
|
||||
return false;
|
||||
|
||||
string triggeredStr = args.NextString();
|
||||
if (!string.IsNullOrEmpty(triggeredStr))
|
||||
{
|
||||
if (triggeredStr != "triggered")
|
||||
return false;
|
||||
}
|
||||
|
||||
bool triggered = (triggeredStr != null);
|
||||
|
||||
caster.CastSpell(caster.GetVictim(), spellId, triggered);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("dest", RBACPermissions.CommandCastDest)]
|
||||
static bool HandleCastDestCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Unit caster = handler.getSelectedUnit();
|
||||
if (!caster)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectCharOrCreature);
|
||||
return false;
|
||||
}
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
if (spellId == 0)
|
||||
return false;
|
||||
|
||||
if (CheckSpellExistsAndIsValid(handler, spellId))
|
||||
return false;
|
||||
|
||||
float x = args.NextSingle();
|
||||
float y = args.NextSingle();
|
||||
float z = args.NextSingle();
|
||||
|
||||
if (x == 0f || y == 0f || z == 0f)
|
||||
return false;
|
||||
|
||||
string triggeredStr = args.NextString();
|
||||
if (!string.IsNullOrEmpty(triggeredStr))
|
||||
{
|
||||
if (triggeredStr != "triggered")
|
||||
return false;
|
||||
}
|
||||
|
||||
bool triggered = (triggeredStr != null);
|
||||
|
||||
caster.CastSpell(x, y, z, spellId, triggered);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CheckSpellExistsAndIsValid(CommandHandler handler, uint spellId)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId);
|
||||
if (spellInfo == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNospellfound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Global.SpellMgr.IsSpellValid(spellInfo, handler.GetPlayer()))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandSpellBroken, spellId);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,897 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("character", RBACPermissions.CommandCharacter, true)]
|
||||
class CharacterCommands
|
||||
{
|
||||
[Command("titles", RBACPermissions.CommandCharacterTitles, true)]
|
||||
static bool HandleCharacterTitlesCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args, out target))
|
||||
return false;
|
||||
|
||||
LocaleConstant loc = handler.GetSessionDbcLocale();
|
||||
string targetName = target.GetName();
|
||||
string knownStr = handler.GetCypherString(CypherStrings.Known);
|
||||
|
||||
// Search in CharTitles.dbc
|
||||
foreach (var titleInfo in CliDB.CharTitlesStorage.Values)
|
||||
{
|
||||
if (target.HasTitle(titleInfo))
|
||||
{
|
||||
string name = (target.GetGender() == Gender.Male ? titleInfo.NameMale : titleInfo.NameFemale)[handler.GetSessionDbcLocale()];
|
||||
if (string.IsNullOrEmpty(name))
|
||||
continue;
|
||||
|
||||
string activeStr = target.GetUInt32Value(PlayerFields.ChosenTitle) == titleInfo.MaskID
|
||||
? handler.GetCypherString(CypherStrings.Active) : "";
|
||||
|
||||
string titleNameStr = string.Format(name.ConvertFormatSyntax(), targetName);
|
||||
|
||||
// send title in "id (idx:idx) - [namedlink locale]" format
|
||||
if (handler.GetSession() != null)
|
||||
handler.SendSysMessage(CypherStrings.TitleListChat, titleInfo.Id, titleInfo.MaskID, titleInfo.Id, titleNameStr, loc, knownStr, activeStr);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.TitleListConsole, titleInfo.Id, titleInfo.MaskID, name, loc, knownStr, activeStr);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//rename characters
|
||||
[Command("rename", RBACPermissions.CommandCharacterRename, true)]
|
||||
static bool HandleCharacterRenameCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
string newNameStr = args.NextString();
|
||||
|
||||
if (!string.IsNullOrEmpty(newNameStr))
|
||||
{
|
||||
string playerOldName;
|
||||
string newName = newNameStr;
|
||||
|
||||
if (target)
|
||||
{
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
playerOldName = target.GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check offline security
|
||||
if (handler.HasLowerSecurity(null, targetGuid))
|
||||
return false;
|
||||
|
||||
ObjectManager.GetPlayerNameByGUID(targetGuid, out playerOldName);
|
||||
}
|
||||
|
||||
if (!ObjectManager.NormalizePlayerName(ref newName))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ObjectManager.CheckPlayerName(newName, target ? target.GetSession().GetSessionDbcLocale() : Global.WorldMgr.GetDefaultDbcLocale(), true) != ResponseCodes.CharNameSuccess)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldSession session = handler.GetSession();
|
||||
if (session != null)
|
||||
{
|
||||
if (!session.HasPermission(RBACPermissions.SkipCheckCharacterCreationReservedname) && Global.ObjectMgr.IsReservedName(newName))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ReservedName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHECK_NAME);
|
||||
stmt.AddValue(0, newName);
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.RenamePlayerAlreadyExists, newName);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove declined name from db
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_DECLINED_NAME);
|
||||
stmt.AddValue(0, targetGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
if (target)
|
||||
{
|
||||
target.SetName(newName);
|
||||
session = target.GetSession();
|
||||
if (session != null)
|
||||
session.KickPlayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_NAME_BY_GUID);
|
||||
stmt.AddValue(0, newName);
|
||||
stmt.AddValue(1, targetGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
|
||||
Global.WorldMgr.UpdateCharacterInfo(targetGuid, newName);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.RenamePlayerWithNewName, playerOldName, newName);
|
||||
|
||||
Player player = handler.GetPlayer();
|
||||
if (player)
|
||||
Log.outCommand(session.GetAccountId(), "GM {0} (Account: {1}) forced rename {2} to player {3} (Account: {4})", player.GetName(), session.GetAccountId(), newName, playerOldName, ObjectManager.GetPlayerAccountIdByGUID(targetGuid));
|
||||
else
|
||||
Log.outCommand(0, "CONSOLE forced rename '{0}' to '{1}' ({2})", playerOldName, newName, targetGuid.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
handler.SendSysMessage(CypherStrings.RenamePlayer, handler.GetNameLink(target));
|
||||
target.SetAtLoginFlag(AtLoginFlags.Rename);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check offline security
|
||||
if (handler.HasLowerSecurity(null, targetGuid))
|
||||
return false;
|
||||
|
||||
string oldNameLink = handler.playerLink(targetName);
|
||||
handler.SendSysMessage(CypherStrings.RenamePlayerGuid, oldNameLink, targetGuid.ToString());
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt.AddValue(0, AtLoginFlags.Rename);
|
||||
stmt.AddValue(1, targetGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("level", RBACPermissions.CommandCharacterLevel, true)]
|
||||
static bool HandleCharacterLevelCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
string nameStr;
|
||||
string levelStr;
|
||||
handler.extractOptFirstArg(args, out nameStr, out levelStr);
|
||||
if (string.IsNullOrEmpty(levelStr))
|
||||
return false;
|
||||
|
||||
// exception opt second arg: .character level $name
|
||||
if (!levelStr.IsNumber())
|
||||
{
|
||||
nameStr = levelStr;
|
||||
levelStr = null; // current level will used
|
||||
}
|
||||
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
if (!handler.extractPlayerTarget(new StringArguments(nameStr), out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
int oldlevel = (int)(target ? target.getLevel() : Player.GetLevelFromDB(targetGuid));
|
||||
int newlevel = !string.IsNullOrEmpty(levelStr) ? int.Parse(levelStr) : oldlevel;
|
||||
|
||||
if (newlevel < 1)
|
||||
return false; // invalid level
|
||||
|
||||
if (newlevel > SharedConst.StrongMaxLevel) // hardcoded maximum level
|
||||
newlevel = SharedConst.StrongMaxLevel;
|
||||
|
||||
HandleCharacterLevel(target, targetGuid, oldlevel, newlevel, handler);
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer() != target) // including player == NULL
|
||||
{
|
||||
string nameLink = handler.playerLink(targetName);
|
||||
handler.SendSysMessage(CypherStrings.YouChangeLvl, nameLink, newlevel);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// customize characters
|
||||
[Command("customize", RBACPermissions.CommandCharacterCustomize, true)]
|
||||
static bool HandleCharacterCustomizeCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt.AddValue(0, AtLoginFlags.Customize);
|
||||
if (target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CustomizePlayer, handler.GetNameLink(target));
|
||||
target.SetAtLoginFlag(AtLoginFlags.Customize);
|
||||
stmt.AddValue(1, target.GetGUID().GetCounter());
|
||||
}
|
||||
else
|
||||
{
|
||||
string oldNameLink = handler.playerLink(targetName);
|
||||
stmt.AddValue(1, targetGuid.GetCounter());
|
||||
handler.SendSysMessage(CypherStrings.CustomizePlayerGuid, oldNameLink, targetGuid.ToString());
|
||||
}
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("changefaction", RBACPermissions.CommandCharacterChangefaction, true)]
|
||||
static bool HandleCharacterChangeFactionCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt.AddValue(0, AtLoginFlags.ChangeFaction);
|
||||
if (target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CustomizePlayer, handler.GetNameLink(target));
|
||||
target.SetAtLoginFlag(AtLoginFlags.ChangeFaction);
|
||||
stmt.AddValue(1, target.GetGUID().GetCounter());
|
||||
}
|
||||
else
|
||||
{
|
||||
string oldNameLink = handler.playerLink(targetName);
|
||||
handler.SendSysMessage(CypherStrings.CustomizePlayerGuid, oldNameLink, targetGuid.ToString());
|
||||
stmt.AddValue(1, targetGuid.GetCounter());
|
||||
}
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("changerace", RBACPermissions.CommandCharacterChangerace, true)]
|
||||
static bool HandleCharacterChangeRaceCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt.AddValue(0, AtLoginFlags.ChangeRace);
|
||||
if (target)
|
||||
{
|
||||
/// @todo add text into database
|
||||
handler.SendSysMessage(CypherStrings.CustomizePlayer, handler.GetNameLink(target));
|
||||
target.SetAtLoginFlag(AtLoginFlags.ChangeRace);
|
||||
stmt.AddValue(1, target.GetGUID().GetCounter());
|
||||
}
|
||||
else
|
||||
{
|
||||
string oldNameLink = handler.playerLink(targetName);
|
||||
/// @todo add text into database
|
||||
handler.SendSysMessage(CypherStrings.CustomizePlayerGuid, oldNameLink, targetGuid.ToString());
|
||||
stmt.AddValue(1, targetGuid.GetCounter());
|
||||
}
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("reputation", RBACPermissions.CommandCharacterReputation, true)]
|
||||
static bool HandleCharacterReputationCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args, out target))
|
||||
return false;
|
||||
|
||||
LocaleConstant loc = handler.GetSessionDbcLocale();
|
||||
|
||||
var targetFSL = target.GetReputationMgr().GetStateList();
|
||||
foreach (var pair in targetFSL)
|
||||
{
|
||||
FactionState faction = pair.Value;
|
||||
FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(faction.ID);
|
||||
string factionName = factionEntry != null ? factionEntry.Name[loc] : "#Not found#";
|
||||
ReputationRank rank = target.GetReputationMgr().GetRank(factionEntry);
|
||||
string rankName = handler.GetCypherString(ReputationMgr.ReputationRankStrIndex[(int)rank]);
|
||||
StringBuilder ss = new StringBuilder();
|
||||
if (handler.GetSession() != null)
|
||||
ss.AppendFormat("{0} - |cffffffff|Hfaction:{0}|h[{1} {2}]|h|r", faction.ID, factionName, loc);
|
||||
else
|
||||
ss.AppendFormat("{0} - {1} {2}", faction.ID, factionName, loc);
|
||||
|
||||
ss.AppendFormat(" {0} ({1})", rankName, target.GetReputationMgr().GetReputation(factionEntry));
|
||||
|
||||
if (faction.Flags.HasAnyFlag(FactionFlags.Visible))
|
||||
ss.Append(handler.GetCypherString(CypherStrings.FactionVisible));
|
||||
if (faction.Flags.HasAnyFlag(FactionFlags.AtWar))
|
||||
ss.Append(handler.GetCypherString(CypherStrings.FactionAtwar));
|
||||
if (faction.Flags.HasAnyFlag(FactionFlags.PeaceForced))
|
||||
ss.Append(handler.GetCypherString(CypherStrings.FactionPeaceForced));
|
||||
if (faction.Flags.HasAnyFlag(FactionFlags.Hidden))
|
||||
ss.Append(handler.GetCypherString(CypherStrings.FactionHidden));
|
||||
if (faction.Flags.HasAnyFlag(FactionFlags.InvisibleForced))
|
||||
ss.Append(handler.GetCypherString(CypherStrings.FactionInvisibleForced));
|
||||
if (faction.Flags.HasAnyFlag(FactionFlags.Inactive))
|
||||
ss.Append(handler.GetCypherString(CypherStrings.FactionInactive));
|
||||
|
||||
handler.SendSysMessage(ss.ToString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("erase", RBACPermissions.CommandCharacterErase, true)]
|
||||
static bool HandleCharacterEraseCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string characterName = args.NextString();
|
||||
if (string.IsNullOrEmpty(characterName))
|
||||
return false;
|
||||
|
||||
if (!ObjectManager.NormalizePlayerName(ref characterName))
|
||||
return false;
|
||||
|
||||
ObjectGuid characterGuid;
|
||||
uint accountId;
|
||||
|
||||
Player player = Global.ObjAccessor.FindPlayerByName(characterName);
|
||||
if (player)
|
||||
{
|
||||
characterGuid = player.GetGUID();
|
||||
accountId = player.GetSession().GetAccountId();
|
||||
player.GetSession().KickPlayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
characterGuid = ObjectManager.GetPlayerGUIDByName(characterName);
|
||||
if (characterGuid.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoPlayer, characterName);
|
||||
return false;
|
||||
}
|
||||
accountId = ObjectManager.GetPlayerAccountIdByGUID(characterGuid);
|
||||
}
|
||||
|
||||
string accountName;
|
||||
Global.AccountMgr.GetName(accountId, out accountName);
|
||||
|
||||
Player.DeleteFromDB(characterGuid, accountId, true, true);
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeleted, characterName, characterGuid.ToString(), accountName, accountId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("deleted", RBACPermissions.CommandCharacterDeleted, true)]
|
||||
class DeletedCommands
|
||||
{
|
||||
[Command("delete", RBACPermissions.CommandCharacterDeletedDelete, true)]
|
||||
static bool HandleCharacterDeletedDeleteCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// It is required to submit at least one argument
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
List<DeletedInfo> foundList = new List<DeletedInfo>();
|
||||
if (!GetDeletedCharacterInfoList(foundList, args.NextString()))
|
||||
return false;
|
||||
|
||||
if (foundList.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListEmpty);
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedDelete);
|
||||
HandleCharacterDeletedListHelper(foundList, handler);
|
||||
|
||||
// Call the appropriate function to delete them (current account for deleted characters is 0)
|
||||
foreach (var info in foundList)
|
||||
Player.DeleteFromDB(info.guid, 0, false, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("list", RBACPermissions.CommandCharacterDeletedList, true)]
|
||||
static bool HandleCharacterDeletedListCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
List<DeletedInfo> foundList = new List<DeletedInfo>();
|
||||
if (!GetDeletedCharacterInfoList(foundList, args.NextString()))
|
||||
return false;
|
||||
|
||||
// if no characters have been found, output a warning
|
||||
if (foundList.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListEmpty);
|
||||
return false;
|
||||
}
|
||||
|
||||
HandleCharacterDeletedListHelper(foundList, handler);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("restore", RBACPermissions.CommandCharacterDeletedRestore, true)]
|
||||
static bool HandleCharacterDeletedRestoreCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// It is required to submit at least one argument
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string searchString = args.NextString();
|
||||
string newCharName = args.NextString();
|
||||
uint newAccount = args.NextUInt32();
|
||||
|
||||
List<DeletedInfo> foundList = new List<DeletedInfo>();
|
||||
if (!GetDeletedCharacterInfoList(foundList, searchString))
|
||||
return false;
|
||||
|
||||
if (foundList.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListEmpty);
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedRestore);
|
||||
HandleCharacterDeletedListHelper(foundList, handler);
|
||||
|
||||
if (newCharName.IsEmpty())
|
||||
{
|
||||
// Drop not existed account cases
|
||||
foreach (var info in foundList)
|
||||
HandleCharacterDeletedRestoreHelper(info, handler);
|
||||
}
|
||||
else if (foundList.Count == 1 && ObjectManager.NormalizePlayerName(ref newCharName))
|
||||
{
|
||||
DeletedInfo delInfo = foundList[0];
|
||||
|
||||
// update name
|
||||
delInfo.name = newCharName;
|
||||
|
||||
// if new account provided update deleted info
|
||||
if (newAccount != 0 && newAccount != delInfo.accountId)
|
||||
{
|
||||
delInfo.accountId = newAccount;
|
||||
Global.AccountMgr.GetName(newAccount, out delInfo.accountName);
|
||||
}
|
||||
|
||||
HandleCharacterDeletedRestoreHelper(delInfo, handler);
|
||||
}
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedErrRename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("old", RBACPermissions.CommandCharacterDeletedOld, true)]
|
||||
static bool HandleCharacterDeletedOldCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
int keepDays = WorldConfig.GetIntValue(WorldCfg.ChardeleteKeepDays);
|
||||
|
||||
string daysStr = args.NextString();
|
||||
if (!daysStr.IsEmpty())
|
||||
{
|
||||
if (!daysStr.IsNumber())
|
||||
return false;
|
||||
|
||||
keepDays = int.Parse(daysStr);
|
||||
if (keepDays < 0)
|
||||
return false;
|
||||
}
|
||||
// config option value 0 -> disabled and can't be used
|
||||
else if (keepDays <= 0)
|
||||
return false;
|
||||
|
||||
Player.DeleteOldCharacters(keepDays);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetDeletedCharacterInfoList(List<DeletedInfo> foundList, string searchString)
|
||||
{
|
||||
SQLResult result;
|
||||
PreparedStatement stmt;
|
||||
if (!searchString.IsEmpty())
|
||||
{
|
||||
// search by GUID
|
||||
if (searchString.IsNumber())
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_DEL_INFO_BY_GUID);
|
||||
stmt.AddValue(0, ulong.Parse(searchString));
|
||||
result = DB.Characters.Query(stmt);
|
||||
}
|
||||
// search by name
|
||||
else
|
||||
{
|
||||
if (!ObjectManager.NormalizePlayerName(ref searchString))
|
||||
return false;
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_DEL_INFO_BY_NAME);
|
||||
stmt.AddValue(0, searchString);
|
||||
result = DB.Characters.Query(stmt);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_DEL_INFO);
|
||||
result = DB.Characters.Query(stmt);
|
||||
}
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
DeletedInfo info;
|
||||
|
||||
info.guid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(0));
|
||||
info.name = result.Read<string>(1);
|
||||
info.accountId = result.Read<uint>(2);
|
||||
|
||||
// account name will be empty for not existed account
|
||||
Global.AccountMgr.GetName(info.accountId, out info.accountName);
|
||||
info.deleteDate = result.Read<uint>(3);
|
||||
foundList.Add(info);
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
static void HandleCharacterDeletedListHelper(List<DeletedInfo> foundList, CommandHandler handler)
|
||||
{
|
||||
if (handler.GetSession() == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListBar);
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListHeader);
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListBar);
|
||||
}
|
||||
|
||||
foreach (var info in foundList)
|
||||
{
|
||||
string dateStr = Time.UnixTimeToDateTime(info.deleteDate).ToShortDateString();
|
||||
|
||||
if (!handler.GetSession())
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListLineConsole,
|
||||
info.guid.ToString(), info.name, info.accountName.IsEmpty() ? "<Not existed>" : info.accountName,
|
||||
info.accountId, dateStr);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListLineChat,
|
||||
info.guid.ToString(), info.name, info.accountName.IsEmpty() ? "<Not existed>" : info.accountName,
|
||||
info.accountId, dateStr);
|
||||
}
|
||||
|
||||
if (!handler.GetSession())
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedListBar);
|
||||
}
|
||||
static void HandleCharacterDeletedRestoreHelper(DeletedInfo delInfo, CommandHandler handler)
|
||||
{
|
||||
if (delInfo.accountName.IsEmpty()) // account not exist
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedSkipAccount, delInfo.name, delInfo.guid.ToString(), delInfo.accountId);
|
||||
return;
|
||||
}
|
||||
|
||||
// check character count
|
||||
uint charcount = Global.AccountMgr.GetCharactersCount(delInfo.accountId);
|
||||
if (charcount >= WorldConfig.GetIntValue(WorldCfg.CharactersPerRealm))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedSkipFull, delInfo.name, delInfo.guid.ToString(), delInfo.accountId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ObjectManager.GetPlayerGUIDByName(delInfo.name).IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharacterDeletedSkipName, delInfo.name, delInfo.guid.ToString(), delInfo.accountId);
|
||||
return;
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_RESTORE_DELETE_INFO);
|
||||
stmt.AddValue(0, delInfo.name);
|
||||
stmt.AddValue(1, delInfo.accountId);
|
||||
stmt.AddValue(2, delInfo.guid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
Global.WorldMgr.UpdateCharacterInfoDeleted(delInfo.guid, false, delInfo.name);
|
||||
}
|
||||
|
||||
struct DeletedInfo
|
||||
{
|
||||
public ObjectGuid guid; // the GUID from the character
|
||||
public string name; // the character name
|
||||
public uint accountId; // the account id
|
||||
public string accountName; // the account name
|
||||
public long deleteDate; // the date at which the character has been deleted
|
||||
}
|
||||
}
|
||||
|
||||
[CommandNonGroup("levelup", RBACPermissions.CommandLevelup)]
|
||||
static bool LevelUp(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
string nameStr;
|
||||
string levelStr;
|
||||
handler.extractOptFirstArg(args, out nameStr, out levelStr);
|
||||
|
||||
// exception opt second arg: .character level $name
|
||||
if (!string.IsNullOrEmpty(levelStr) && !levelStr.IsNumber())
|
||||
{
|
||||
nameStr = levelStr;
|
||||
levelStr = null; // current level will used
|
||||
}
|
||||
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
if (!handler.extractPlayerTarget(new StringArguments(nameStr), out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
int oldlevel = (int)(target ? target.getLevel() : Player.GetLevelFromDB(targetGuid));
|
||||
int addlevel = !string.IsNullOrEmpty(levelStr) ? int.Parse(levelStr) : 1;
|
||||
int newlevel = oldlevel + addlevel;
|
||||
|
||||
if (newlevel < 1)
|
||||
newlevel = 1;
|
||||
|
||||
if (newlevel > SharedConst.StrongMaxLevel) // hardcoded maximum level
|
||||
newlevel = SharedConst.StrongMaxLevel;
|
||||
|
||||
HandleCharacterLevel(target, targetGuid, oldlevel, newlevel, handler);
|
||||
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer() != target) // including chr == NULL
|
||||
{
|
||||
string nameLink = handler.playerLink(targetName);
|
||||
handler.SendSysMessage(CypherStrings.YouChangeLvl, nameLink, newlevel);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void HandleCharacterLevel(Player player, ObjectGuid playerGuid, int oldLevel, int newLevel, CommandHandler handler)
|
||||
{
|
||||
if (player)
|
||||
{
|
||||
player.GiveLevel((uint)newLevel);
|
||||
player.InitTalentForLevel();
|
||||
player.SetUInt32Value(PlayerFields.Xp, 0);
|
||||
|
||||
if (handler.needReportToTarget(player))
|
||||
{
|
||||
if (oldLevel == newLevel)
|
||||
player.SendSysMessage(CypherStrings.YoursLevelProgressReset, handler.GetNameLink());
|
||||
else if (oldLevel < newLevel)
|
||||
player.SendSysMessage(CypherStrings.YoursLevelUp, handler.GetNameLink(), newLevel);
|
||||
else // if (oldlevel > newlevel)
|
||||
player.SendSysMessage(CypherStrings.YoursLevelDown, handler.GetNameLink(), newLevel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update level and reset XP, everything else will be updated at login
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_LEVEL);
|
||||
stmt.AddValue(0, newLevel);
|
||||
stmt.AddValue(1, playerGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("pdump", RBACPermissions.CommandPdump, true)]
|
||||
class PdumpCommand
|
||||
{
|
||||
[Command("load", RBACPermissions.CommandPdumpLoad, true)]
|
||||
static bool HandlePDumpLoadCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/*
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string fileStr = strtok((char*)args, " ");
|
||||
if (!fileStr)
|
||||
return false;
|
||||
|
||||
char* accountStr = strtok(NULL, " ");
|
||||
if (!accountStr)
|
||||
return false;
|
||||
|
||||
string accountName = accountStr;
|
||||
if (!AccountMgr.normalizeString(accountName))
|
||||
{
|
||||
handler.SendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName);
|
||||
handler.SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint accountId = AccountMgr.GetId(accountName);
|
||||
if (!accountId)
|
||||
{
|
||||
accountId = atoi(accountStr); // use original string
|
||||
if (!accountId)
|
||||
{
|
||||
handler.SendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!AccountMgr.GetName(accountId, accountName))
|
||||
{
|
||||
handler.SendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName);
|
||||
handler.SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
char* guidStr = NULL;
|
||||
char* nameStr = strtok(NULL, " ");
|
||||
|
||||
string name;
|
||||
if (nameStr)
|
||||
{
|
||||
name = nameStr;
|
||||
// normalize the name if specified and check if it exists
|
||||
if (!ObjectManager.NormalizePlayerName(name))
|
||||
{
|
||||
handler.SendSysMessage(LANG_INVALID_CHARACTER_NAME);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ObjectMgr.CheckPlayerName(name, true) != CHAR_NAME_SUCCESS)
|
||||
{
|
||||
handler.SendSysMessage(LANG_INVALID_CHARACTER_NAME);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
guidStr = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
public uint guid = 0;
|
||||
|
||||
if (guidStr)
|
||||
{
|
||||
guid = uint32(atoi(guidStr));
|
||||
if (!guid)
|
||||
{
|
||||
handler.SendSysMessage(LANG_INVALID_CHARACTER_GUID);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Global.ObjectMgr.GetPlayerAccountIdByGUID(guid))
|
||||
{
|
||||
handler.SendSysMessage(LANG_CHARACTER_GUID_IN_USE, guid);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (PlayerDumpReader().LoadDump(fileStr, accountId, name, guid))
|
||||
{
|
||||
case DUMP_SUCCESS:
|
||||
handler.SendSysMessage(LANG_COMMAND_IMPORT_SUCCESS);
|
||||
break;
|
||||
case DUMP_FILE_OPEN_ERROR:
|
||||
handler.SendSysMessage(LANG_FILE_OPEN_FAIL, fileStr);
|
||||
|
||||
return false;
|
||||
case DUMP_FILE_BROKEN:
|
||||
handler.SendSysMessage(LANG_DUMP_BROKEN, fileStr);
|
||||
|
||||
return false;
|
||||
case DUMP_TOO_MANY_CHARS:
|
||||
handler.SendSysMessage(LANG_ACCOUNT_CHARACTER_LIST_FULL, accountName, accountId);
|
||||
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(LANG_COMMAND_IMPORT_FAILED);
|
||||
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("write", RBACPermissions.CommandPdumpWrite, true)]
|
||||
static bool HandlePDumpWriteCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
/*
|
||||
char* fileStr = strtok((char*)args, " ");
|
||||
char* playerStr = strtok(NULL, " ");
|
||||
|
||||
if (!fileStr || !playerStr)
|
||||
return false;
|
||||
|
||||
uint64 guid;
|
||||
// character name can't start from number
|
||||
if (isNumeric(playerStr))
|
||||
guid = MAKE_NEW_GUID(atoi(playerStr), 0, HIGHGUID_PLAYER);
|
||||
else
|
||||
{
|
||||
string name = handler.extractPlayerNameFromLink(playerStr);
|
||||
if (name.empty())
|
||||
{
|
||||
handler.SendSysMessage(LANG_PLAYER_NOT_FOUND);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
guid = Global.ObjectMgr.GetPlayerGUIDByName(name);
|
||||
}
|
||||
|
||||
if (!Global.ObjectMgr.GetPlayerAccountIdByGUID(guid))
|
||||
{
|
||||
handler.SendSysMessage(LANG_PLAYER_NOT_FOUND);
|
||||
handler.SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (PlayerDumpWriter().WriteDump(fileStr, uint32(guid)))
|
||||
{
|
||||
case DUMP_SUCCESS:
|
||||
handler.SendSysMessage(LANG_COMMAND_EXPORT_SUCCESS);
|
||||
break;
|
||||
case DUMP_FILE_OPEN_ERROR:
|
||||
handler.SendSysMessage(LANG_FILE_OPEN_FAIL, fileStr);
|
||||
|
||||
return false;
|
||||
case DUMP_CHARACTER_DELETED:
|
||||
handler.SendSysMessage(LANG_COMMAND_EXPORT_DELETED_CHAR);
|
||||
|
||||
return false;
|
||||
default:
|
||||
handler.SendSysMessage(LANG_COMMAND_EXPORT_FAILED);
|
||||
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("cheat", RBACPermissions.CommandCheat)]
|
||||
class CheatCommands
|
||||
{
|
||||
[Command("god", RBACPermissions.CommandCheatGod)]
|
||||
static bool HandleGodModeCheat(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer())
|
||||
return false;
|
||||
|
||||
string argstr = args.NextString();
|
||||
if (args.Empty())
|
||||
argstr = (handler.GetSession().GetPlayer().GetCommandStatus(PlayerCommandStates.God)) ? "off" : "on";
|
||||
|
||||
if (argstr == "off")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetCommandStatusOff(PlayerCommandStates.God);
|
||||
handler.SendSysMessage("Godmode is OFF. You can take damage.");
|
||||
return true;
|
||||
}
|
||||
else if (argstr == "on")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetCommandStatusOn(PlayerCommandStates.God);
|
||||
handler.SendSysMessage("Godmode is ON. You won't take damage.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("casttime", RBACPermissions.CommandCheatCasttime)]
|
||||
static bool HandleCasttimeCheat(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer())
|
||||
return false;
|
||||
|
||||
string argstr = args.NextString();
|
||||
|
||||
if (args.Empty())
|
||||
argstr = (handler.GetSession().GetPlayer().GetCommandStatus(PlayerCommandStates.Casttime)) ? "off" : "on";
|
||||
|
||||
if (argstr == "off")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetCommandStatusOff(PlayerCommandStates.Casttime);
|
||||
handler.SendSysMessage("CastTime Cheat is OFF. Your spells will have a casttime.");
|
||||
return true;
|
||||
}
|
||||
else if (argstr == "on")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetCommandStatusOn(PlayerCommandStates.Casttime);
|
||||
handler.SendSysMessage("CastTime Cheat is ON. Your spells won't have a casttime.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("cooldown", RBACPermissions.CommandCheatCooldown)]
|
||||
static bool HandleCoolDownCheat(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer())
|
||||
return false;
|
||||
|
||||
string argstr = args.NextString();
|
||||
|
||||
if (args.Empty())
|
||||
argstr = (handler.GetSession().GetPlayer().GetCommandStatus(PlayerCommandStates.Cooldown)) ? "off" : "on";
|
||||
|
||||
if (argstr == "off")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetCommandStatusOff(PlayerCommandStates.Cooldown);
|
||||
handler.SendSysMessage("Cooldown Cheat is OFF. You are on the global cooldown.");
|
||||
return true;
|
||||
}
|
||||
else if (argstr == "on")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetCommandStatusOn(PlayerCommandStates.Cooldown);
|
||||
handler.SendSysMessage("Cooldown Cheat is ON. You are not on the global cooldown.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("power", RBACPermissions.CommandCheatPower)]
|
||||
static bool HandlePowerCheat(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer())
|
||||
return false;
|
||||
|
||||
string argstr = args.NextString();
|
||||
|
||||
if (args.Empty())
|
||||
argstr = (handler.GetSession().GetPlayer().GetCommandStatus(PlayerCommandStates.Power)) ? "off" : "on";
|
||||
|
||||
if (argstr == "off")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetCommandStatusOff(PlayerCommandStates.Power);
|
||||
handler.SendSysMessage("Power Cheat is OFF. You need mana/rage/energy to use spells.");
|
||||
return true;
|
||||
}
|
||||
else if (argstr == "on")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetCommandStatusOn(PlayerCommandStates.Power);
|
||||
handler.SendSysMessage("Power Cheat is ON. You don't need mana/rage/energy to use spells.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("status", RBACPermissions.CommandCheatStatus)]
|
||||
static bool HandleCheatStatus(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
string enabled = "ON";
|
||||
string disabled = "OFF";
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandCheatStatus);
|
||||
handler.SendSysMessage(CypherStrings.CommandCheatGod, player.GetCommandStatus(PlayerCommandStates.God) ? enabled : disabled);
|
||||
handler.SendSysMessage(CypherStrings.CommandCheatCd, player.GetCommandStatus(PlayerCommandStates.Cooldown) ? enabled : disabled);
|
||||
handler.SendSysMessage(CypherStrings.CommandCheatCt, player.GetCommandStatus(PlayerCommandStates.Casttime) ? enabled : disabled);
|
||||
handler.SendSysMessage(CypherStrings.CommandCheatPower, player.GetCommandStatus(PlayerCommandStates.Power) ? enabled : disabled);
|
||||
handler.SendSysMessage(CypherStrings.CommandCheatWw, player.GetCommandStatus(PlayerCommandStates.Waterwalk) ? enabled : disabled);
|
||||
handler.SendSysMessage(CypherStrings.CommandCheatTaxinodes, player.isTaxiCheater() ? enabled : disabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("waterwalk", RBACPermissions.CommandCheatWaterwalk)]
|
||||
static bool HandleWaterWalkCheat(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer())
|
||||
return false;
|
||||
|
||||
string argstr = args.NextString();
|
||||
|
||||
Player target = handler.GetSession().GetPlayer();
|
||||
if (args.Empty())
|
||||
argstr = (target.GetCommandStatus(PlayerCommandStates.Waterwalk)) ? "off" : "on";
|
||||
|
||||
if (argstr == "off")
|
||||
{
|
||||
target.SetCommandStatusOff(PlayerCommandStates.Waterwalk);
|
||||
target.SetWaterWalking(false);
|
||||
handler.SendSysMessage("Waterwalking is OFF. You can't walk on water.");
|
||||
return true;
|
||||
}
|
||||
else if (argstr == "on")
|
||||
{
|
||||
target.SetCommandStatusOn(PlayerCommandStates.Waterwalk);
|
||||
target.SetWaterWalking(true);
|
||||
handler.SendSysMessage("Waterwalking is ON. You can walk on water.");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("taxi", RBACPermissions.CommandCheatTaxi)]
|
||||
static bool HandleTaxiCheatCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
string argstr = args.NextString();
|
||||
|
||||
Player chr = handler.getSelectedPlayer();
|
||||
if (!chr)
|
||||
chr = handler.GetSession().GetPlayer();
|
||||
else if (handler.HasLowerSecurity(chr, ObjectGuid.Empty)) // check online security
|
||||
return false;
|
||||
|
||||
if (args.Empty())
|
||||
argstr = (chr.isTaxiCheater()) ? "off" : "on";
|
||||
|
||||
if (argstr == "off")
|
||||
{
|
||||
chr.SetTaxiCheater(false);
|
||||
handler.SendSysMessage(CypherStrings.YouRemoveTaxis, handler.GetNameLink(chr));
|
||||
if (handler.needReportToTarget(chr))
|
||||
chr.SendSysMessage(CypherStrings.YoursTaxisRemoved, handler.GetNameLink());
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (argstr == "on")
|
||||
{
|
||||
chr.SetTaxiCheater(true);
|
||||
handler.SendSysMessage(CypherStrings.YouGiveTaxis, handler.GetNameLink(chr));
|
||||
if (handler.needReportToTarget(chr))
|
||||
chr.SendSysMessage(CypherStrings.YoursTaxisAdded, handler.GetNameLink());
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("explore", RBACPermissions.CommandCheatExplore)]
|
||||
static bool HandleExploreCheat(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
int flag = args.NextInt32();
|
||||
Player chr = handler.getSelectedPlayer();
|
||||
if (!chr)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (flag != 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.YouSetExploreAll, handler.GetNameLink(chr));
|
||||
if (handler.needReportToTarget(chr))
|
||||
chr.SendSysMessage(CypherStrings.YoursExploreSetAll, handler.GetNameLink());
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.YouSetExploreNothing, handler.GetNameLink(chr));
|
||||
if (handler.needReportToTarget(chr))
|
||||
chr.SendSysMessage(CypherStrings.YoursExploreSetNothing, handler.GetNameLink());
|
||||
}
|
||||
|
||||
for (ushort i = 0; i < PlayerConst.ExploredZonesSize; ++i)
|
||||
{
|
||||
if (flag != 0)
|
||||
handler.GetSession().GetPlayer().SetFlag(PlayerFields.ExploredZones1 + i, 0xFFFFFFFF);
|
||||
else
|
||||
handler.GetSession().GetPlayer().SetFlag(PlayerFields.ExploredZones1 + i, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using Game.Spells;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
struct Spells
|
||||
{
|
||||
public const uint LFGDundeonDeserter = 71041;
|
||||
public const uint BGDeserter = 26013;
|
||||
}
|
||||
|
||||
[CommandGroup("deserter", RBACPermissions.CommandDeserter)]
|
||||
class DeserterCommands
|
||||
{
|
||||
[CommandGroup("instance", RBACPermissions.CommandDeserterInstance)]
|
||||
class DeserterInstanceCommands
|
||||
{
|
||||
[Command("add", RBACPermissions.CommandDeserterInstanceAdd)]
|
||||
static bool HandleDeserterInstanceAdd(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleDeserterAdd(args, handler, true);
|
||||
}
|
||||
|
||||
[Command("remove", RBACPermissions.CommandDeserterInstanceRemove)]
|
||||
static bool HandleDeserterInstanceRemove(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleDeserterRemove(args, handler, true);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("bg", RBACPermissions.CommandDeserterBg)]
|
||||
class DeserterBGCommands
|
||||
{
|
||||
[Command("add", RBACPermissions.CommandDeserterBgAdd)]
|
||||
static bool HandleDeserterBGAdd(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleDeserterAdd(args, handler, false);
|
||||
}
|
||||
|
||||
[Command("remove", RBACPermissions.CommandDeserterBgRemove)]
|
||||
static bool HandleDeserterBGRemove(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleDeserterRemove(args, handler, false);
|
||||
}
|
||||
}
|
||||
|
||||
static bool HandleDeserterAdd(StringArguments args, CommandHandler handler, bool isInstance)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
string timeStr = args.NextString();
|
||||
if (string.IsNullOrEmpty(timeStr))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint time = uint.Parse(timeStr);
|
||||
if (time == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
Aura aura = player.AddAura(isInstance ? Spells.LFGDundeonDeserter : Spells.BGDeserter, player);
|
||||
if (aura == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
aura.SetDuration((int)(time * Time.InMilliseconds));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDeserterRemove(StringArguments args, CommandHandler handler, bool isInstance)
|
||||
{
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
player.RemoveAura(isInstance ? Spells.LFGDundeonDeserter : Spells.BGDeserter);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("disable", RBACPermissions.CommandDisable)]
|
||||
class DisableCommands
|
||||
{
|
||||
[CommandGroup("add", RBACPermissions.CommandDisableAdd, true)]
|
||||
class DisableAddCommands
|
||||
{
|
||||
static bool HandleAddDisables(StringArguments args, CommandHandler handler, DisableType disableType)
|
||||
{
|
||||
string entryStr = args.NextString();
|
||||
if (string.IsNullOrEmpty(entryStr) || int.Parse(entryStr) == 0)
|
||||
return false;
|
||||
|
||||
string flagsStr = args.NextString();
|
||||
uint flags = !string.IsNullOrEmpty(flagsStr) ? byte.Parse(flagsStr) : 0u;
|
||||
|
||||
string disableComment = args.NextString("");
|
||||
if (string.IsNullOrEmpty(disableComment))
|
||||
return false;
|
||||
|
||||
uint entry = uint.Parse(entryStr);
|
||||
|
||||
string disableTypeStr = "";
|
||||
switch (disableType)
|
||||
{
|
||||
case DisableType.Spell:
|
||||
{
|
||||
if (!Global.SpellMgr.HasSpellInfo(entry))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNospellfound);
|
||||
return false;
|
||||
}
|
||||
disableTypeStr = "spell";
|
||||
break;
|
||||
}
|
||||
case DisableType.Quest:
|
||||
{
|
||||
if (Global.ObjectMgr.GetQuestTemplate(entry) == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNoquestfound, entry);
|
||||
return false;
|
||||
}
|
||||
disableTypeStr = "quest";
|
||||
break;
|
||||
}
|
||||
case DisableType.Map:
|
||||
{
|
||||
if (!CliDB.MapStorage.ContainsKey(entry))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNomapfound);
|
||||
return false;
|
||||
}
|
||||
disableTypeStr = "map";
|
||||
break;
|
||||
}
|
||||
case DisableType.Battleground:
|
||||
{
|
||||
if (!CliDB.BattlemasterListStorage.ContainsKey(entry))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNoBattlegroundFound);
|
||||
return false;
|
||||
}
|
||||
disableTypeStr = "Battleground";
|
||||
break;
|
||||
}
|
||||
case DisableType.Criteria:
|
||||
{
|
||||
if (Global.CriteriaMgr.GetCriteria(entry) == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNoAchievementCriteriaFound);
|
||||
return false;
|
||||
}
|
||||
disableTypeStr = "criteria";
|
||||
break;
|
||||
}
|
||||
case DisableType.OutdoorPVP:
|
||||
{
|
||||
if (entry > (int)OutdoorPvPTypes.Max)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNoOutdoorPvpForund);
|
||||
return false;
|
||||
}
|
||||
disableTypeStr = "outdoorpvp";
|
||||
break;
|
||||
}
|
||||
case DisableType.VMAP:
|
||||
{
|
||||
if (!CliDB.MapStorage.ContainsKey(entry))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNomapfound);
|
||||
return false;
|
||||
}
|
||||
disableTypeStr = "vmap";
|
||||
break;
|
||||
}
|
||||
case DisableType.MMAP:
|
||||
{
|
||||
if (!CliDB.MapStorage.ContainsKey(entry))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNomapfound);
|
||||
return false;
|
||||
}
|
||||
disableTypeStr = "mmap";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_DISABLES);
|
||||
stmt.AddValue(0, entry);
|
||||
stmt.AddValue(1, disableType);
|
||||
SQLResult result = DB.World.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage("This {0} (Id: {1}) is already disabled.", disableTypeStr, entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
stmt = DB.World.GetPreparedStatement(WorldStatements.INS_DISABLES);
|
||||
stmt.AddValue(0, entry);
|
||||
stmt.AddValue(1, disableType);
|
||||
stmt.AddValue(2, flags);
|
||||
stmt.AddValue(3, disableComment);
|
||||
DB.World.Execute(stmt);
|
||||
|
||||
handler.SendSysMessage("Add Disabled {0} (Id: {1}) for reason {2}", disableTypeStr, entry, disableComment);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("spell", RBACPermissions.CommandDisableAddSpell, true)]
|
||||
static bool HandleAddDisableSpellCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleAddDisables(args, handler, DisableType.Spell);
|
||||
}
|
||||
|
||||
[Command("quest", RBACPermissions.CommandDisableAddQuest, true)]
|
||||
static bool HandleAddDisableQuestCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleAddDisables(args, handler, DisableType.Quest);
|
||||
}
|
||||
|
||||
[Command("map", RBACPermissions.CommandDisableAddMap, true)]
|
||||
static bool HandleAddDisableMapCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleAddDisables(args, handler, DisableType.Map);
|
||||
}
|
||||
|
||||
[Command("Battleground", RBACPermissions.CommandDisableAddBattleground, true)]
|
||||
static bool HandleAddDisableBattlegroundCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleAddDisables(args, handler, DisableType.Battleground);
|
||||
}
|
||||
|
||||
[Command("criteria", RBACPermissions.CommandDisableAddCriteria, true)]
|
||||
static bool HandleAddDisableCriteriaCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleAddDisables(args, handler, DisableType.Criteria);
|
||||
}
|
||||
|
||||
[Command("outdoorpvp", RBACPermissions.CommandDisableAddOutdoorpvp, true)]
|
||||
static bool HandleAddDisableOutdoorPvPCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
HandleAddDisables(args, handler, DisableType.OutdoorPVP);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("vmap", RBACPermissions.CommandDisableAddVmap, true)]
|
||||
static bool HandleAddDisableVmapCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleAddDisables(args, handler, DisableType.VMAP);
|
||||
}
|
||||
|
||||
[Command("mmap", RBACPermissions.CommandDisableAddMmap, true)]
|
||||
static bool HandleAddDisableMMapCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleAddDisables(args, handler, DisableType.MMAP);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("remove", RBACPermissions.CommandDisableRemove, true)]
|
||||
class DisableRemoveCommands
|
||||
{
|
||||
static bool HandleRemoveDisables(StringArguments args, CommandHandler handler, DisableType disableType)
|
||||
{
|
||||
string entryStr = args.NextString();
|
||||
if (string.IsNullOrEmpty(entryStr) || uint.Parse(entryStr) == 0)
|
||||
return false;
|
||||
|
||||
uint entry = uint.Parse(entryStr);
|
||||
|
||||
string disableTypeStr = "";
|
||||
switch (disableType)
|
||||
{
|
||||
case DisableType.Spell:
|
||||
disableTypeStr = "spell";
|
||||
break;
|
||||
case DisableType.Quest:
|
||||
disableTypeStr = "quest";
|
||||
break;
|
||||
case DisableType.Map:
|
||||
disableTypeStr = "map";
|
||||
break;
|
||||
case DisableType.Battleground:
|
||||
disableTypeStr = "Battleground";
|
||||
break;
|
||||
case DisableType.Criteria:
|
||||
disableTypeStr = "criteria";
|
||||
break;
|
||||
case DisableType.OutdoorPVP:
|
||||
disableTypeStr = "outdoorpvp";
|
||||
break;
|
||||
case DisableType.VMAP:
|
||||
disableTypeStr = "vmap";
|
||||
break;
|
||||
case DisableType.MMAP:
|
||||
disableTypeStr = "mmap";
|
||||
break;
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_DISABLES);
|
||||
stmt.AddValue(0, entry);
|
||||
stmt.AddValue(1, disableType);
|
||||
SQLResult result = DB.World.Query(stmt);
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage("This {0} (Id: {1}) is not disabled.", disableTypeStr, entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
stmt = DB.World.GetPreparedStatement(WorldStatements.DEL_DISABLES);
|
||||
stmt.AddValue(0, entry);
|
||||
stmt.AddValue(1, disableType);
|
||||
DB.World.Execute(stmt);
|
||||
|
||||
handler.SendSysMessage("Remove Disabled {0} (Id: {1})", disableTypeStr, entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("spell", RBACPermissions.CommandDisableRemoveSpell, true)]
|
||||
static bool HandleRemoveDisableSpellCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleRemoveDisables(args, handler, DisableType.Spell);
|
||||
}
|
||||
|
||||
[Command("quest", RBACPermissions.CommandDisableRemoveQuest, true)]
|
||||
static bool HandleRemoveDisableQuestCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleRemoveDisables(args, handler, DisableType.Quest);
|
||||
}
|
||||
|
||||
[Command("map", RBACPermissions.CommandDisableRemoveMap, true)]
|
||||
static bool HandleRemoveDisableMapCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleRemoveDisables(args, handler, DisableType.Map);
|
||||
}
|
||||
|
||||
[Command("Battleground", RBACPermissions.CommandDisableRemoveBattleground, true)]
|
||||
static bool HandleRemoveDisableBattlegroundCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleRemoveDisables(args, handler, DisableType.Battleground);
|
||||
}
|
||||
|
||||
[Command("criteria", RBACPermissions.CommandDisableRemoveCriteria, true)]
|
||||
static bool HandleRemoveDisableCriteriaCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleRemoveDisables(args, handler, DisableType.Criteria);
|
||||
}
|
||||
|
||||
[Command("outdoorpvp", RBACPermissions.CommandDisableRemoveOutdoorpvp, true)]
|
||||
static bool HandleRemoveDisableOutdoorPvPCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleRemoveDisables(args, handler, DisableType.OutdoorPVP);
|
||||
}
|
||||
|
||||
[Command("vmap", RBACPermissions.CommandDisableRemoveVmap, true)]
|
||||
static bool HandleRemoveDisableVmapCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleRemoveDisables(args, handler, DisableType.VMAP);
|
||||
}
|
||||
|
||||
[Command("mmap", RBACPermissions.CommandDisableRemoveMmap, true)]
|
||||
static bool HandleRemoveDisableMMapCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
return HandleRemoveDisables(args, handler, DisableType.MMAP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("event", RBACPermissions.CommandEvent)]
|
||||
class EventCommands
|
||||
{
|
||||
[Command("info", RBACPermissions.CommandEvent, true)]
|
||||
static bool HandleEventInfoCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameevent");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ushort eventId = ushort.Parse(id);
|
||||
|
||||
var events = Global.GameEventMgr.GetEventMap();
|
||||
|
||||
if (eventId >= events.Length)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.EventNotExist);
|
||||
return false;
|
||||
}
|
||||
|
||||
GameEventData eventData = events[eventId];
|
||||
if (!eventData.isValid())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.EventNotExist);
|
||||
return false;
|
||||
}
|
||||
|
||||
var activeEvents = Global.GameEventMgr.GetActiveEventList();
|
||||
bool active = activeEvents.Contains(eventId);
|
||||
string activeStr = active ? Global.ObjectMgr.GetCypherString(CypherStrings.Active) : "";
|
||||
|
||||
string startTimeStr = Time.UnixTimeToDateTime(eventData.start).ToLongDateString();
|
||||
string endTimeStr = Time.UnixTimeToDateTime(eventData.end).ToLongDateString();
|
||||
|
||||
uint delay = Global.GameEventMgr.NextCheck(eventId);
|
||||
long nextTime = Time.UnixTime + delay;
|
||||
string nextStr = nextTime >= eventData.start && nextTime < eventData.end ? Time.UnixTimeToDateTime(Time.UnixTime + delay).ToShortTimeString() : "-";
|
||||
|
||||
string occurenceStr = Time.secsToTimeString(eventData.occurence * Time.Minute);
|
||||
string lengthStr = Time.secsToTimeString(eventData.length * Time.Minute);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.EventInfo, eventId, eventData.description, activeStr,
|
||||
startTimeStr, endTimeStr, occurenceStr, lengthStr, nextStr);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("activelist", RBACPermissions.CommandEventActivelist, true)]
|
||||
static bool HandleEventActiveListCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint counter = 0;
|
||||
|
||||
var events = Global.GameEventMgr.GetEventMap();
|
||||
var activeEvents = Global.GameEventMgr.GetActiveEventList();
|
||||
|
||||
string active = Global.ObjectMgr.GetCypherString(CypherStrings.Active);
|
||||
|
||||
foreach (var eventId in activeEvents)
|
||||
{
|
||||
GameEventData eventData = events[eventId];
|
||||
|
||||
if (handler.GetSession() != null)
|
||||
handler.SendSysMessage(CypherStrings.EventEntryListChat, eventId, eventId, eventData.description, active);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.EventEntryListConsole, eventId, eventData.description, active);
|
||||
|
||||
++counter;
|
||||
}
|
||||
|
||||
if (counter == 0)
|
||||
handler.SendSysMessage(CypherStrings.Noeventfound);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("start", RBACPermissions.CommandEventStart, true)]
|
||||
static bool HandleEventStartCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameevent");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ushort eventId = ushort.Parse(id);
|
||||
|
||||
var events = Global.GameEventMgr.GetEventMap();
|
||||
|
||||
if (eventId < 1 || eventId >= events.Length)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.EventNotExist);
|
||||
return false;
|
||||
}
|
||||
|
||||
GameEventData eventData = events[eventId];
|
||||
if (!eventData.isValid())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.EventNotExist);
|
||||
return false;
|
||||
}
|
||||
|
||||
var activeEvents = Global.GameEventMgr.GetActiveEventList();
|
||||
if (activeEvents.Contains(eventId))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.EventAlreadyActive, eventId);
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.GameEventMgr.StartEvent(eventId, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("stop", RBACPermissions.CommandEventStop, true)]
|
||||
static bool HandleEventStopCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameevent");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ushort eventId = ushort.Parse(id);
|
||||
|
||||
var events = Global.GameEventMgr.GetEventMap();
|
||||
|
||||
if (eventId < 1 || eventId >= events.Length)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.EventNotExist);
|
||||
return false;
|
||||
}
|
||||
|
||||
GameEventData eventData = events[eventId];
|
||||
if (!eventData.isValid())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.EventNotExist);
|
||||
return false;
|
||||
}
|
||||
|
||||
var activeEvents = Global.GameEventMgr.GetActiveEventList();
|
||||
|
||||
if (!activeEvents.Contains(eventId))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.EventNotActive, eventId);
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.GameEventMgr.StopEvent(eventId, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("gm", RBACPermissions.CommandGm)]
|
||||
class GMCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandGm)]
|
||||
static bool HandleGMCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player _player = handler.GetSession().GetPlayer();
|
||||
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendNotification(_player.IsGameMaster() ? CypherStrings.GmOn : CypherStrings.GmOff);
|
||||
return true;
|
||||
}
|
||||
|
||||
string param = args.NextString();
|
||||
if (param == "on")
|
||||
{
|
||||
_player.SetGameMaster(true);
|
||||
handler.SendNotification(CypherStrings.GmOn);
|
||||
_player.UpdateTriggerVisibility();
|
||||
return true;
|
||||
}
|
||||
if (param == "off")
|
||||
{
|
||||
_player.SetGameMaster(false);
|
||||
handler.SendNotification(CypherStrings.GmOff);
|
||||
_player.UpdateTriggerVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("chat", RBACPermissions.CommandGmChat)]
|
||||
static bool HandleGMChatCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
WorldSession session = handler.GetSession();
|
||||
if (session != null)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
if (session.HasPermission(RBACPermissions.ChatUseStaffBadge) && session.GetPlayer().isGMChat())
|
||||
session.SendNotification(CypherStrings.GmChatOn);
|
||||
else
|
||||
session.SendNotification(CypherStrings.GmChatOff);
|
||||
return true;
|
||||
}
|
||||
|
||||
string param = args.NextString();
|
||||
|
||||
if (param == "on")
|
||||
{
|
||||
session.GetPlayer().SetGMChat(true);
|
||||
session.SendNotification(CypherStrings.GmChatOn);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (param == "off")
|
||||
{
|
||||
session.GetPlayer().SetGMChat(false);
|
||||
session.SendNotification(CypherStrings.GmChatOff);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("fly", RBACPermissions.CommandGmFly)]
|
||||
static bool HandleGMFlyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target = handler.getSelectedPlayer();
|
||||
if (target == null)
|
||||
target = handler.GetPlayer();
|
||||
|
||||
string arg = args.NextString().ToLower();
|
||||
|
||||
if (arg == "on")
|
||||
target.SetCanFly(true);
|
||||
else if (arg == "off")
|
||||
target.SetCanFly(false);
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
handler.SendSysMessage(CypherStrings.CommandFlymodeStatus, handler.GetNameLink(target), arg);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("ingame", RBACPermissions.CommandGmIngame, true)]
|
||||
static bool HandleGMListIngameCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
bool first = true;
|
||||
bool footer = false;
|
||||
|
||||
var m = Global.ObjAccessor.GetPlayers();
|
||||
foreach (var pl in m)
|
||||
{
|
||||
AccountTypes accountType = pl.GetSession().GetSecurity();
|
||||
if ((pl.IsGameMaster() ||
|
||||
(pl.GetSession().HasPermission(RBACPermissions.CommandsAppearInGmList) &&
|
||||
accountType <= (AccountTypes)WorldConfig.GetIntValue(WorldCfg.GmLevelInGmList))) &&
|
||||
(handler.GetSession() == null || pl.IsVisibleGloballyFor(handler.GetSession().GetPlayer())))
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
footer = true;
|
||||
handler.SendSysMessage(CypherStrings.GmsOnSrv);
|
||||
handler.SendSysMessage("========================");
|
||||
}
|
||||
int size = pl.GetName().Length;
|
||||
byte security = (byte)accountType;
|
||||
int max = ((16 - size) / 2);
|
||||
int max2 = max;
|
||||
if ((max + max2 + size) == 16)
|
||||
max2 = max - 1;
|
||||
if (handler.GetSession() != null)
|
||||
handler.SendSysMessage("| {0} GMLevel {1}", pl.GetName(), security);
|
||||
else
|
||||
handler.SendSysMessage("|{0}{1}{2}| {3} |", max, " ", pl.GetName(), max2, " ", security);
|
||||
}
|
||||
}
|
||||
if (footer)
|
||||
handler.SendSysMessage("========================");
|
||||
if (first)
|
||||
handler.SendSysMessage(CypherStrings.GmsNotLogged);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("list", RBACPermissions.CommandGmList, true)]
|
||||
static bool HandleGMListFullCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// Get the accounts with GM Level >0
|
||||
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_GM_ACCOUNTS);
|
||||
stmt.AddValue(0, AccountTypes.Moderator);
|
||||
stmt.AddValue(1, Global.WorldMgr.GetRealm().Id.Realm);
|
||||
SQLResult result = DB.Login.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage( CypherStrings.Gmlist);
|
||||
handler.SendSysMessage("========================");
|
||||
// Cycle through them. Display username and GM level
|
||||
do
|
||||
{
|
||||
string name = result.Read<string>(0);
|
||||
byte security = result.Read<byte>(1);
|
||||
int max = (16 - name.Length) / 2;
|
||||
int max2 = max;
|
||||
if ((max + max2 + name.Length) == 16)
|
||||
max2 = max - 1;
|
||||
string padding = "";
|
||||
if (handler.GetSession() != null)
|
||||
handler.SendSysMessage("| {0} GMLevel {1}", name, security);
|
||||
else
|
||||
handler.SendSysMessage("|{0}{1}{2}| {3} |", padding.PadRight(max), name, padding.PadRight(max2), security);
|
||||
} while (result.NextRow());
|
||||
handler.SendSysMessage("========================");
|
||||
}
|
||||
else
|
||||
handler.SendSysMessage( CypherStrings.GmlistEmpty);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("visible", RBACPermissions.CommandGmVisible)]
|
||||
static bool HandleGMVisibleCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player _player = handler.GetSession().GetPlayer();
|
||||
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.YouAre, _player.isGMVisible() ? Global.ObjectMgr.GetCypherString(CypherStrings.Visible) : Global.ObjectMgr.GetCypherString(CypherStrings.Invisible));
|
||||
return true;
|
||||
}
|
||||
|
||||
uint VISUAL_AURA = 37800;
|
||||
string param = args.NextString();
|
||||
|
||||
if (param == "on")
|
||||
{
|
||||
if (_player.HasAura(VISUAL_AURA, ObjectGuid.Empty))
|
||||
_player.RemoveAurasDueToSpell(VISUAL_AURA);
|
||||
|
||||
_player.SetGMVisible(true);
|
||||
_player.UpdateObjectVisibility();
|
||||
handler.GetSession().SendNotification(CypherStrings.InvisibleVisible);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (param == "off")
|
||||
{
|
||||
_player.AddAura(VISUAL_AURA, _player);
|
||||
_player.SetGMVisible(false);
|
||||
_player.UpdateObjectVisibility();
|
||||
handler.GetSession().SendNotification(CypherStrings.InvisibleInvisible);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,617 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.GameMath;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("gobject", RBACPermissions.CommandGobject)]
|
||||
class GameObjectCommands
|
||||
{
|
||||
[Command("activate", RBACPermissions.CommandGobjectActivate)]
|
||||
static bool HandleGameObjectActivateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ulong guidLow = ulong.Parse(id);
|
||||
if (guidLow == 0)
|
||||
return false;
|
||||
|
||||
GameObject obj = handler.GetObjectFromPlayerMapByDbGuid(guidLow);
|
||||
if (!obj)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandObjnotfound, guidLow);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Activate
|
||||
obj.SetLootState(LootState.Ready);
|
||||
obj.UseDoorOrButton(10000, false, handler.GetSession().GetPlayer());
|
||||
|
||||
handler.SendSysMessage("Object activated!");
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("delete", RBACPermissions.CommandGobjectDelete)]
|
||||
static bool HandleGameObjectDeleteCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ulong guidLow = ulong.Parse(id);
|
||||
if (guidLow == 0)
|
||||
return false;
|
||||
|
||||
GameObject obj = handler.GetObjectFromPlayerMapByDbGuid(guidLow);
|
||||
if (!obj)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandObjnotfound, guidLow);
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGuid ownerGuid = obj.GetOwnerGUID();
|
||||
if (ownerGuid.IsEmpty())
|
||||
{
|
||||
Unit owner = Global.ObjAccessor.GetUnit(handler.GetPlayer(), ownerGuid);
|
||||
if (!owner || !ownerGuid.IsPlayer())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandDelobjrefercreature, ownerGuid.ToString(), obj.GetGUID().ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
owner.RemoveGameObject(obj, false);
|
||||
}
|
||||
|
||||
obj.SetRespawnTime(0); // not save respawn time
|
||||
obj.Delete();
|
||||
obj.DeleteFromDB();
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandDelobjmessage, obj.GetGUID().ToString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("move", RBACPermissions.CommandGobjectMove)]
|
||||
static bool HandleGameObjectMoveCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ulong guidLow = ulong.Parse(id);
|
||||
if (guidLow == 0)
|
||||
return false;
|
||||
|
||||
GameObject obj = handler.GetObjectFromPlayerMapByDbGuid(guidLow);
|
||||
if (!obj)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandObjnotfound, guidLow);
|
||||
return false;
|
||||
}
|
||||
|
||||
string toX = args.NextString();
|
||||
string toY = args.NextString();
|
||||
string toZ = args.NextString();
|
||||
|
||||
float x, y, z;
|
||||
if (string.IsNullOrEmpty(toX))
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
player.GetPosition(out x, out y, out z);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(toY) || string.IsNullOrEmpty(toZ))
|
||||
return false;
|
||||
|
||||
x = float.Parse(toX);
|
||||
y = float.Parse(toY);
|
||||
z = float.Parse(toZ);
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(obj.GetMapId(), x, y, z))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, obj.GetMapId());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
obj.DestroyForNearbyPlayers();
|
||||
obj.RelocateStationaryPosition(x, y, z, obj.GetOrientation());
|
||||
obj.GetMap().GameObjectRelocation(obj, x, y, z, obj.GetOrientation());
|
||||
|
||||
obj.SaveToDB();
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandMoveobjmessage, obj.GetSpawnId(), obj.GetGoInfo().name, obj.GetGUID().ToString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("near", RBACPermissions.CommandGobjectNear)]
|
||||
static bool HandleGameObjectNearCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
float distance = args.Empty() ? 10.0f : args.NextSingle();
|
||||
uint count = 0;
|
||||
|
||||
Player player = handler.GetPlayer();
|
||||
|
||||
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_GAMEOBJECT_NEAREST);
|
||||
stmt.AddValue(0, player.GetPositionX());
|
||||
stmt.AddValue(1, player.GetPositionY());
|
||||
stmt.AddValue(2, player.GetPositionZ());
|
||||
stmt.AddValue(3, player.GetMapId());
|
||||
stmt.AddValue(4, player.GetPositionX());
|
||||
stmt.AddValue(5, player.GetPositionY());
|
||||
stmt.AddValue(6, player.GetPositionZ());
|
||||
stmt.AddValue(7, distance * distance);
|
||||
SQLResult result = DB.World.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ulong guid = result.Read<ulong>(0);
|
||||
uint entry = result.Read<uint>(1);
|
||||
float x = result.Read<float>(2);
|
||||
float y = result.Read<float>(3);
|
||||
float z = result.Read<float>(4);
|
||||
ushort mapId = result.Read<ushort>(5);
|
||||
|
||||
GameObjectTemplate gameObjectInfo = Global.ObjectMgr.GetGameObjectTemplate(entry);
|
||||
if (gameObjectInfo == null)
|
||||
continue;
|
||||
|
||||
handler.SendSysMessage(CypherStrings.GoListChat, guid, entry, guid, gameObjectInfo.name, x, y, z, mapId);
|
||||
|
||||
++count;
|
||||
} while (result.NextRow());
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandNearobjmessage, distance, count);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("target", RBACPermissions.CommandGobjectTarget)]
|
||||
static bool HandleGameObjectTargetCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
SQLResult result;
|
||||
var activeEventsList = Global.GameEventMgr.GetActiveEventList();
|
||||
|
||||
if (!args.Empty())
|
||||
{
|
||||
// number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r
|
||||
string idStr = handler.extractKeyFromLink(args, "Hgameobject_entry");
|
||||
if (string.IsNullOrEmpty(idStr))
|
||||
return false;
|
||||
|
||||
uint objectId = uint.Parse(idStr);
|
||||
if (objectId != 0)
|
||||
result = DB.World.Query("SELECT guid, id, position_x, position_y, position_z, orientation, map, PhaseId, PhaseGroup, (POW(position_x - '{0}', 2) + POW(position_y - '{1}', 2) + POW(position_z - '{2}', 2)) AS order_ FROM gameobject WHERE map = '{3}' AND id = '{4}' ORDER BY order_ ASC LIMIT 1",
|
||||
player.GetPositionX(), player.GetPositionY(), player.GetPositionZ(), player.GetMapId(), objectId);
|
||||
else
|
||||
{
|
||||
result = DB.World.Query(
|
||||
"SELECT guid, id, position_x, position_y, position_z, orientation, map, PhaseId, PhaseGroup, (POW(position_x - {0}, 2) + POW(position_y - {1}, 2) + POW(position_z - {2}, 2)) AS order_ " +
|
||||
"FROM gameobject LEFT JOIN gameobject_template ON gameobject_template.entry = gameobject.id WHERE map = {3} AND name LIKE CONCAT('%%', '{4}', '%%') ORDER BY order_ ASC LIMIT 1",
|
||||
player.GetPositionX(), player.GetPositionY(), player.GetPositionZ(), player.GetMapId(), objectId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuilder eventFilter = new StringBuilder();
|
||||
eventFilter.Append(" AND (eventEntry IS NULL ");
|
||||
bool initString = true;
|
||||
|
||||
foreach (var entry in activeEventsList)
|
||||
{
|
||||
if (initString)
|
||||
{
|
||||
eventFilter.Append("OR eventEntry IN (" + entry);
|
||||
initString = false;
|
||||
}
|
||||
else
|
||||
eventFilter.Append(',' + entry);
|
||||
}
|
||||
|
||||
if (!initString)
|
||||
eventFilter.Append("))");
|
||||
else
|
||||
eventFilter.Append(')');
|
||||
|
||||
result = DB.World.Query("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, PhaseId, PhaseGroup, " +
|
||||
"(POW(position_x - {0}, 2) + POW(position_y - {1}, 2) + POW(position_z - {2}, 2)) AS order_ FROM gameobject " +
|
||||
"LEFT OUTER JOIN game_event_gameobject on gameobject.guid = game_event_gameobject.guid WHERE map = '{3}' {4} ORDER BY order_ ASC LIMIT 10",
|
||||
handler.GetSession().GetPlayer().GetPositionX(), handler.GetSession().GetPlayer().GetPositionY(), handler.GetSession().GetPlayer().GetPositionZ(),
|
||||
handler.GetSession().GetPlayer().GetMapId(), eventFilter.ToString());
|
||||
}
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandTargetobjnotfound);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
float x, y, z, o;
|
||||
ulong guidLow;
|
||||
uint id, phaseId, phaseGroup;
|
||||
ushort mapId;
|
||||
uint poolId;
|
||||
|
||||
do
|
||||
{
|
||||
guidLow = result.Read<ulong>(0);
|
||||
id = result.Read<uint>(1);
|
||||
x = result.Read<float>(2);
|
||||
y = result.Read<float>(3);
|
||||
z = result.Read<float>(4);
|
||||
o = result.Read<float>(5);
|
||||
mapId = result.Read<ushort>(6);
|
||||
phaseId = result.Read<uint>(7);
|
||||
phaseGroup = result.Read<uint>(8);
|
||||
poolId = Global.PoolMgr.IsPartOfAPool<GameObject>(guidLow);
|
||||
if (poolId == 0 || Global.PoolMgr.IsSpawnedObject<GameObject>(guidLow))
|
||||
found = true;
|
||||
} while (result.NextRow() && !found);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GameobjectNotExist, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObjectTemplate objectInfo = Global.ObjectMgr.GetGameObjectTemplate(id);
|
||||
|
||||
if (objectInfo == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GameobjectNotExist, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObject target = handler.GetObjectFromPlayerMapByDbGuid(guidLow);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.GameobjectDetail, guidLow, objectInfo.name, guidLow, id, x, y, z, mapId, o, phaseId, phaseGroup);
|
||||
|
||||
if (target)
|
||||
{
|
||||
int curRespawnDelay = (int)(target.GetRespawnTimeEx() - Time.UnixTime);
|
||||
if (curRespawnDelay < 0)
|
||||
curRespawnDelay = 0;
|
||||
|
||||
string curRespawnDelayStr = Time.secsToTimeString((uint)curRespawnDelay, true);
|
||||
string defRespawnDelayStr = Time.secsToTimeString(target.GetRespawnDelay(), true);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandRawpawntimes, defRespawnDelayStr, curRespawnDelayStr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("turn", RBACPermissions.CommandGobjectTurn)]
|
||||
static bool HandleGameObjectTurnCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ulong guidLow = ulong.Parse(id);
|
||||
if (guidLow == 0)
|
||||
return false;
|
||||
|
||||
GameObject obj = handler.GetObjectFromPlayerMapByDbGuid(guidLow);
|
||||
if (!obj)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandObjnotfound, guidLow);
|
||||
return false;
|
||||
}
|
||||
|
||||
string orientation = args.NextString();
|
||||
float oz = 0.0f, oy = 0.0f, ox = 0.0f;
|
||||
if (!orientation.IsEmpty())
|
||||
{
|
||||
oz = float.Parse(orientation);
|
||||
|
||||
orientation = args.NextString();
|
||||
if (!orientation.IsEmpty())
|
||||
{
|
||||
oy = float.Parse(orientation);
|
||||
orientation = args.NextString();
|
||||
if (!orientation.IsEmpty())
|
||||
ox = float.Parse(orientation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Player player = handler.GetPlayer();
|
||||
oz = player.GetOrientation();
|
||||
}
|
||||
|
||||
obj.Relocate(obj.GetPositionX(), obj.GetPositionY(), obj.GetPositionZ());
|
||||
obj.RelocateStationaryPosition(obj.GetPositionX(), obj.GetPositionY(), obj.GetPositionZ(), obj.GetOrientation());
|
||||
obj.SetWorldRotationAngles(oz, oy, ox);
|
||||
obj.DestroyForNearbyPlayers();
|
||||
obj.UpdateObjectVisibility();
|
||||
|
||||
obj.SaveToDB();
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandTurnobjmessage, obj.GetSpawnId(), obj.GetGoInfo().name, obj.GetGUID().ToString(), obj.GetOrientation());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("info", RBACPermissions.CommandGobjectInfo)]
|
||||
static bool HandleGameObjectInfoCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint entry = 0;
|
||||
GameObjectTypes type = 0;
|
||||
uint displayId = 0;
|
||||
string name;
|
||||
uint lootId = 0;
|
||||
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string param1 = handler.extractKeyFromLink(args, "Hgameobject_entry");
|
||||
if (param1.IsEmpty())
|
||||
return false;
|
||||
|
||||
if (param1.Equals("guid"))
|
||||
{
|
||||
string cValue = handler.extractKeyFromLink(args, "Hgameobject");
|
||||
if (cValue.IsEmpty())
|
||||
return false;
|
||||
|
||||
ulong guidLow = ulong.Parse(cValue);
|
||||
GameObjectData data = Global.ObjectMgr.GetGOData(guidLow);
|
||||
if (data == null)
|
||||
return false;
|
||||
entry = data.id;
|
||||
}
|
||||
else
|
||||
entry = uint.Parse(param1);
|
||||
|
||||
GameObjectTemplate gameObjectInfo = Global.ObjectMgr.GetGameObjectTemplate(entry);
|
||||
if (gameObjectInfo == null)
|
||||
return false;
|
||||
|
||||
type = gameObjectInfo.type;
|
||||
displayId = gameObjectInfo.displayId;
|
||||
name = gameObjectInfo.name;
|
||||
lootId = gameObjectInfo.GetLootId();
|
||||
|
||||
handler.SendSysMessage(CypherStrings.GoinfoEntry, entry);
|
||||
handler.SendSysMessage(CypherStrings.GoinfoType, type);
|
||||
handler.SendSysMessage(CypherStrings.GoinfoLootid, lootId);
|
||||
handler.SendSysMessage(CypherStrings.GoinfoDisplayid, displayId);
|
||||
handler.SendSysMessage(CypherStrings.GoinfoName, name);
|
||||
handler.SendSysMessage(CypherStrings.GoinfoSize, gameObjectInfo.size);
|
||||
|
||||
GameObjectTemplateAddon addon = Global.ObjectMgr.GetGameObjectTemplateAddon(entry);
|
||||
if (addon != null)
|
||||
handler.SendSysMessage(CypherStrings.GoinfoAddon, addon.faction, addon.flags);
|
||||
|
||||
GameObjectDisplayInfoRecord modelInfo = CliDB.GameObjectDisplayInfoStorage.LookupByKey(displayId);
|
||||
if (modelInfo != null)
|
||||
handler.SendSysMessage(CypherStrings.GoinfoModel, modelInfo.GeoBoxMax.X, modelInfo.GeoBoxMax.Y, modelInfo.GeoBoxMax.Z, modelInfo.GeoBoxMin.X, modelInfo.GeoBoxMin.Y, modelInfo.GeoBoxMin.Z);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("add", RBACPermissions.CommandGobjectAdd)]
|
||||
class AddCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandGobjectAdd)]
|
||||
static bool HandleGameObjectAddCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject_entry");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
uint objectId = uint.Parse(id);
|
||||
if (objectId == 0)
|
||||
return false;
|
||||
|
||||
uint spawntimeSecs = args.NextUInt32();
|
||||
|
||||
GameObjectTemplate objectInfo = Global.ObjectMgr.GetGameObjectTemplate(objectId);
|
||||
if (objectInfo == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GameobjectNotExist, objectId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (objectInfo.displayId != 0 && !CliDB.GameObjectDisplayInfoStorage.ContainsKey(objectInfo.displayId))
|
||||
{
|
||||
// report to DB errors log as in loading case
|
||||
Log.outError(LogFilter.Sql, "Gameobject (Entry {0} GoType: {1}) have invalid displayId ({2}), not spawned.", objectId, objectInfo.type, objectInfo.displayId);
|
||||
handler.SendSysMessage(CypherStrings.GameobjectHaveInvalidData, objectId);
|
||||
return false;
|
||||
}
|
||||
|
||||
Player player = handler.GetPlayer();
|
||||
Map map = player.GetMap();
|
||||
|
||||
GameObject obj = new GameObject();
|
||||
|
||||
Quaternion rotation = new Quaternion(Matrix3.fromEulerAnglesZYX(player.GetOrientation(), 0.0f, 0.0f));
|
||||
if (!obj.Create(objectInfo.entry, map, 0, player, rotation, 255, GameObjectState.Ready))
|
||||
return false;
|
||||
|
||||
obj.CopyPhaseFrom(player);
|
||||
|
||||
if (spawntimeSecs != 0)
|
||||
{
|
||||
obj.SetRespawnTime((int)spawntimeSecs);
|
||||
}
|
||||
|
||||
// fill the gameobject data and save to the db
|
||||
obj.SaveToDB(map.GetId(), (byte)(1 << (int)map.GetSpawnMode()), player.GetPhaseMask());
|
||||
ulong spawnId = obj.GetSpawnId();
|
||||
|
||||
// this will generate a new guid if the object is in an instance
|
||||
if (!obj.LoadGameObjectFromDB(spawnId, map))
|
||||
return false;
|
||||
|
||||
// TODO: is it really necessary to add both the real and DB table guid here ?
|
||||
Global.ObjectMgr.AddGameObjectToGrid(spawnId, Global.ObjectMgr.GetGOData(spawnId));
|
||||
handler.SendSysMessage(CypherStrings.GameobjectAdd, objectId, objectInfo.name, spawnId, player.GetPositionX(), player.GetPositionY(), player.GetPositionZ());
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("temp", RBACPermissions.CommandGobjectAddTemp)]
|
||||
static bool HandleGameObjectAddTempCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint id = args.NextUInt32();
|
||||
if (id == 0)
|
||||
return false;
|
||||
|
||||
Player player = handler.GetPlayer();
|
||||
|
||||
uint spawntime = args.NextUInt32();
|
||||
uint spawntm = 300;
|
||||
|
||||
if (spawntime != 0)
|
||||
spawntm = spawntime;
|
||||
|
||||
Quaternion rotation = new Quaternion(Matrix3.fromEulerAnglesZYX(player.GetOrientation(), 0.0f, 0.0f));
|
||||
|
||||
if (Global.ObjectMgr.GetGameObjectTemplate(id) == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GameobjectNotExist, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
player.SummonGameObject(id, player, rotation, spawntm);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("set", RBACPermissions.CommandGobjectSet)]
|
||||
class SetCommands
|
||||
{
|
||||
[Command("phase", RBACPermissions.CommandGobjectSetPhase)]
|
||||
static bool HandleGameObjectSetPhaseCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/*// number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ulong guidLow = ulong.Parse(id);
|
||||
if (guidLow == 0)
|
||||
return false;
|
||||
|
||||
GameObject obj = null;
|
||||
|
||||
// by DB guid
|
||||
GameObjectData gameObjectData = Global.ObjectMgr.GetGOData(guidLow);
|
||||
if (gameObjectData != null)
|
||||
obj = handler.GetObjectGlobalyWithGuidOrNearWithDbGuid(guidLow, gameObjectData.id);
|
||||
|
||||
if (!obj)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandObjnotfound, guidLow);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint phaseMask = args.NextUInt32();
|
||||
if (phaseMask == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
obj.SetPhaseMask(phaseMask, true);
|
||||
obj.SaveToDB();*/
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("state", RBACPermissions.CommandGobjectSetState)]
|
||||
static bool HandleGameObjectSetStateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ulong guidLow = ulong.Parse(id);
|
||||
if (guidLow == 0)
|
||||
return false;
|
||||
|
||||
GameObject obj = handler.GetObjectFromPlayerMapByDbGuid(guidLow);
|
||||
if (!obj)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandObjnotfound, guidLow);
|
||||
return false;
|
||||
}
|
||||
|
||||
string type = args.NextString();
|
||||
if (string.IsNullOrEmpty(type))
|
||||
return false;
|
||||
|
||||
int objectType = int.Parse(type);
|
||||
if (objectType < 0)
|
||||
{
|
||||
if (objectType == -1)
|
||||
obj.SendGameObjectDespawn();
|
||||
else if (objectType == -2)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
string state = args.NextString();
|
||||
if (string.IsNullOrEmpty(state))
|
||||
return false;
|
||||
|
||||
uint objectState = uint.Parse(state);
|
||||
|
||||
if (objectType < 4)
|
||||
obj.SetByteValue(GameObjectFields.Bytes1, (byte)objectType, (byte)objectState);
|
||||
else if (objectType == 4)
|
||||
obj.SendCustomAnim(objectState);
|
||||
|
||||
handler.SendSysMessage("Set gobject type {0} state {1}", objectType, objectState);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,622 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using Game.SupportSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("go", RBACPermissions.CommandGo)]
|
||||
class GoCommands
|
||||
{
|
||||
[Command("creature", RBACPermissions.CommandGoCreature)]
|
||||
static bool HandleGoCreatureCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
// "id" or number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r
|
||||
string param1 = handler.extractKeyFromLink(args, "Hcreature");
|
||||
if (string.IsNullOrEmpty(param1))
|
||||
return false;
|
||||
|
||||
string whereClause = "";
|
||||
|
||||
// User wants to teleport to the NPC's template entry
|
||||
if (param1.Equals("id"))
|
||||
{
|
||||
// Get the "creature_template.entry"
|
||||
// number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r
|
||||
string idStr = handler.extractKeyFromLink(args, "Hcreature_entry");
|
||||
if (string.IsNullOrEmpty(idStr))
|
||||
return false;
|
||||
|
||||
int entry = int.Parse(idStr);
|
||||
if (entry == 0)
|
||||
return false;
|
||||
|
||||
whereClause += "WHERE id = '" + entry + '\'';
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong guidLow = ulong.Parse(param1);
|
||||
|
||||
// Number is invalid - maybe the user specified the mob's name
|
||||
if (guidLow == 0)
|
||||
{
|
||||
string name = param1;
|
||||
whereClause += ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name LIKE '" + name + '\'';
|
||||
}
|
||||
else
|
||||
whereClause += "WHERE guid = '" + guidLow + '\'';
|
||||
}
|
||||
|
||||
SQLResult result = DB.World.Query("SELECT position_x, position_y, position_z, orientation, map FROM creature {0}", whereClause);
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandGocreatnotfound);
|
||||
return false;
|
||||
}
|
||||
if (result.GetRowCount() > 1)
|
||||
handler.SendSysMessage(CypherStrings.CommandGocreatmultiple);
|
||||
|
||||
float x = result.Read<float>(0);
|
||||
float y = result.Read<float>(1);
|
||||
float z = result.Read<float>(2);
|
||||
float o = result.Read<float>(3);
|
||||
uint mapId = result.Read<ushort>(4);
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(mapId, x, y, z, o) || Global.ObjectMgr.IsTransportMap(mapId))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
player.TeleportTo(mapId, x, y, z, o);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("graveyard", RBACPermissions.CommandGoGraveyard)]
|
||||
static bool HandleGoGraveyardCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint graveyardId = args.NextUInt32();
|
||||
if (graveyardId == 0)
|
||||
return false;
|
||||
|
||||
WorldSafeLocsRecord gy = CliDB.WorldSafeLocsStorage.LookupByKey(graveyardId);
|
||||
if (gy == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandGraveyardnoexist, graveyardId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(gy.MapID, gy.Loc.X, gy.Loc.Y, gy.Loc.Z))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, gy.Loc.X, gy.Loc.Y, gy.MapID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
player.TeleportTo(gy.MapID, gy.Loc.X, gy.Loc.Y, gy.Loc.Z, (gy.Facing * MathFunctions.PI) / 180); // Orientation is initially in degrees
|
||||
return true;
|
||||
}
|
||||
|
||||
//teleport to grid
|
||||
[Command("grid", RBACPermissions.CommandGoGrid)]
|
||||
static bool HandleGoGridCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
string gridX = args.NextString();
|
||||
string gridY = args.NextString();
|
||||
string id = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(gridX) || string.IsNullOrEmpty(gridY))
|
||||
return false;
|
||||
|
||||
uint mapId = !string.IsNullOrEmpty(id) ? uint.Parse(id) : player.GetMapId();
|
||||
|
||||
// center of grid
|
||||
float x = (float.Parse(gridX) - MapConst.CenterGridId + 0.5f) * MapConst.SizeofGrids;
|
||||
float y = (float.Parse(gridY) - MapConst.CenterGridId + 0.5f) * MapConst.SizeofGrids;
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(mapId, x, y))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
||||
float z = Math.Max(map.GetHeight(x, y, MapConst.MaxHeight), map.GetWaterLevel(x, y));
|
||||
|
||||
player.TeleportTo(mapId, x, y, z, player.GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
//teleport to gameobject
|
||||
[Command("object", RBACPermissions.CommandGoObject)]
|
||||
static bool HandleGoObjectCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
// number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
ulong guidLow = ulong.Parse(id);
|
||||
if (guidLow == 0)
|
||||
return false;
|
||||
|
||||
float x, y, z, o;
|
||||
uint mapId;
|
||||
|
||||
// by DB guid
|
||||
GameObjectData goData = Global.ObjectMgr.GetGOData(guidLow);
|
||||
if (goData != null)
|
||||
{
|
||||
x = goData.posX;
|
||||
y = goData.posY;
|
||||
z = goData.posZ;
|
||||
o = goData.orientation;
|
||||
mapId = goData.mapid;
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandGoobjnotfound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(mapId, x, y, z, o) || Global.ObjectMgr.IsTransportMap(mapId))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
player.TeleportTo(mapId, x, y, z, o);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("quest", RBACPermissions.CommandGoQuest)]
|
||||
static bool HandleGoQuestCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
string id = handler.extractKeyFromLink(args, "Hquest");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
uint questID = uint.Parse(id);
|
||||
if (questID == 0)
|
||||
return false;
|
||||
|
||||
if (Global.ObjectMgr.GetQuestTemplate(questID) == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandQuestNotfound, questID);
|
||||
return false;
|
||||
}
|
||||
|
||||
float x, y, z = 0;
|
||||
uint mapId = 0;
|
||||
|
||||
var poiData = Global.ObjectMgr.GetQuestPOIList(questID);
|
||||
if (poiData != null)
|
||||
{
|
||||
var data = poiData[0];
|
||||
|
||||
mapId = (uint)data.MapID;
|
||||
|
||||
x = data.points[0].X;
|
||||
y = data.points[0].Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandQuestNotfound, questID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(mapId, x, y) || Global.ObjectMgr.IsTransportMap(mapId))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
||||
z = Math.Max(map.GetHeight(x, y, MapConst.MaxHeight), map.GetWaterLevel(x, y));
|
||||
|
||||
player.TeleportTo(mapId, x, y, z, 0.0f);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("taxinode", RBACPermissions.CommandGoTaxinode)]
|
||||
static bool HandleGoTaxinodeCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string id = handler.extractKeyFromLink(args, "Htaxinode");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
uint nodeId = uint.Parse(id);
|
||||
if (nodeId == 0)
|
||||
return false;
|
||||
|
||||
TaxiNodesRecord node = CliDB.TaxiNodesStorage.LookupByKey(nodeId);
|
||||
if (node == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandGotaxinodenotfound, nodeId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((node.Pos.X == 0.0f && node.Pos.Y == 0.0f && node.Pos.Z == 0.0f) ||
|
||||
!GridDefines.IsValidMapCoord(node.MapID, node.Pos.X, node.Pos.Y, node.Pos.Z))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, node.Pos.X, node.Pos.Y, node.MapID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
player.TeleportTo(node.MapID, node.Pos.X, node.Pos.Y, node.Pos.Z, player.GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("trigger", RBACPermissions.CommandGoTrigger)]
|
||||
static bool HandleGoTriggerCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint areaTriggerId = args.NextUInt32();
|
||||
if (areaTriggerId == 0)
|
||||
return false;
|
||||
|
||||
AreaTriggerRecord at = CliDB.AreaTriggerStorage.LookupByKey(areaTriggerId);
|
||||
if (at == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandGoareatrnotfound, areaTriggerId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(at.MapID, at.Pos.X, at.Pos.Y, at.Pos.Z))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, at.Pos.X, at.Pos.Y, at.MapID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
player.TeleportTo(at.MapID, at.Pos.X, at.Pos.Y, at.Pos.Z, player.GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
//teleport at coordinates
|
||||
[Command("zonexy", RBACPermissions.CommandGoZonexy)]
|
||||
static bool HandleGoZoneXYCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
string zoneX = args.NextString();
|
||||
string zoneY = args.NextString();
|
||||
|
||||
string id = handler.extractKeyFromLink(args, "Harea"); // string or [name] Shift-click form |color|Harea:area_id|h[name]|h|r
|
||||
|
||||
if (string.IsNullOrEmpty(zoneX) || string.IsNullOrEmpty(zoneY))
|
||||
return false;
|
||||
|
||||
float x = float.Parse(zoneX);
|
||||
float y = float.Parse(zoneY);
|
||||
|
||||
// prevent accept wrong numeric args
|
||||
if ((x == 0.0f && zoneX[0] != '0') || (y == 0.0f && zoneY[0] != '0'))
|
||||
return false;
|
||||
|
||||
uint areaId = !string.IsNullOrEmpty(id) ? uint.Parse(id) : player.GetZoneId();
|
||||
|
||||
AreaTableRecord areaEntry = CliDB.AreaTableStorage.LookupByKey(areaId);
|
||||
|
||||
if (x < 0 || x > 100 || y < 0 || y > 100 || areaEntry == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidZoneCoord, x, y, areaId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// update to parent zone if exist (client map show only zones without parents)
|
||||
AreaTableRecord zoneEntry = areaEntry.ParentAreaID != 0 ? CliDB.AreaTableStorage.LookupByKey(areaEntry.ParentAreaID) : areaEntry;
|
||||
Contract.Assert(zoneEntry != null);
|
||||
|
||||
Map map = Global.MapMgr.CreateBaseMap(zoneEntry.MapId);
|
||||
|
||||
if (map.Instanceable())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidZoneMap, areaId, areaEntry.AreaName[handler.GetSessionDbcLocale()], map.GetId(), map.GetMapName());
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.DB2Mgr.Zone2MapCoordinates(areaEntry.ParentAreaID != 0 ? areaEntry.ParentAreaID : areaId, ref x, ref y);
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(zoneEntry.MapId, x, y))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, zoneEntry.MapId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
float z = Math.Max(map.GetHeight(x, y, MapConst.MaxHeight), map.GetWaterLevel(x, y));
|
||||
|
||||
player.TeleportTo(zoneEntry.MapId, x, y, z, player.GetOrientation());
|
||||
return true;
|
||||
}
|
||||
|
||||
//teleport at coordinates, including Z and orientation
|
||||
[Command("xyz", RBACPermissions.CommandGoXyz)]
|
||||
static bool HandleGoXYZCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
string goX = args.NextString();
|
||||
string goY = args.NextString();
|
||||
string goZ = args.NextString();
|
||||
string id = args.NextString();
|
||||
string port = args.NextString();
|
||||
|
||||
if (goX.IsEmpty() || goY.IsEmpty())
|
||||
return false;
|
||||
|
||||
float x = float.Parse(goX);
|
||||
float y = float.Parse(goY);
|
||||
float z;
|
||||
float ort = !port.IsEmpty() ? float.Parse(port) : player.GetOrientation();
|
||||
uint mapId = !id.IsEmpty() ? uint.Parse(id) : player.GetMapId();
|
||||
|
||||
if (!goZ.IsEmpty())
|
||||
{
|
||||
z = float.Parse(goZ);
|
||||
if (!GridDefines.IsValidMapCoord(mapId, x, y, z))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!GridDefines.IsValidMapCoord(mapId, x, y))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, mapId);
|
||||
return false;
|
||||
}
|
||||
Map map = Global.MapMgr.CreateBaseMap(mapId);
|
||||
z = Math.Max(map.GetHeight(x, y, MapConst.MaxHeight), map.GetWaterLevel(x, y));
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
player.TeleportTo(mapId, x, y, z, ort);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("bugticket", RBACPermissions.CommandGoBugTicket)]
|
||||
static bool HandleGoBugTicketCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleGoTicketCommand<BugTicket>(args, handler);
|
||||
}
|
||||
|
||||
[Command("complaintticket", RBACPermissions.CommandGoComplaintTicket)]
|
||||
static bool HandleGoComplaintTicketCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleGoTicketCommand<ComplaintTicket>(args, handler);
|
||||
}
|
||||
|
||||
[Command("suggestionticket", RBACPermissions.CommandGoSuggestionTicket)]
|
||||
static bool HandleGoSuggestionTicketCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleGoTicketCommand<SuggestionTicket>(args, handler);
|
||||
}
|
||||
|
||||
static bool HandleGoTicketCommand<T>(StringArguments args, CommandHandler handler)where T : Ticket
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint ticketId = args.NextUInt32();
|
||||
if (ticketId == 0)
|
||||
return false;
|
||||
|
||||
T ticket = Global.SupportMgr.GetTicket<T>(ticketId);
|
||||
if (ticket == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandTicketnotexist);
|
||||
return true;
|
||||
}
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
ticket.TeleportTo(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("offset", RBACPermissions.CommandGoOffset)]
|
||||
static bool HandleGoOffsetCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
|
||||
string goX = args.NextString();
|
||||
string goY = args.NextString();
|
||||
string goZ = args.NextString();
|
||||
string id = args.NextString();
|
||||
string port = args.NextString();
|
||||
|
||||
float x, y, z, o;
|
||||
player.GetPosition(out x, out y, out z, out o);
|
||||
if (!goX.IsEmpty())
|
||||
x += float.Parse(goX);
|
||||
if (!goY.IsEmpty())
|
||||
y += float.Parse(goY);
|
||||
if (!goZ.IsEmpty())
|
||||
z += float.Parse(goZ);
|
||||
if (!port.IsEmpty())
|
||||
o += float.Parse(port);
|
||||
|
||||
if (!GridDefines.IsValidMapCoord(x, y, z, o))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InvalidTargetCoord, x, y, player.GetMapId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
player.TeleportTo(player.GetMapId(), x, y, z, o);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.DungeonFinding;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Maps;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("group", RBACPermissions.CommandGroup)]
|
||||
class GroupCommands
|
||||
{
|
||||
// Summon group of player
|
||||
[Command("summon", RBACPermissions.CommandGroupSummon)]
|
||||
static bool HandleGroupSummonCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args, out target))
|
||||
return false;
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
Group group = target.GetGroup();
|
||||
|
||||
string nameLink = handler.GetNameLink(target);
|
||||
|
||||
if (!group)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NotInGroup, nameLink);
|
||||
return false;
|
||||
}
|
||||
|
||||
Player gmPlayer = handler.GetSession().GetPlayer();
|
||||
Group gmGroup = gmPlayer.GetGroup();
|
||||
Map gmMap = gmPlayer.GetMap();
|
||||
bool toInstance = gmMap.Instanceable();
|
||||
|
||||
// we are in instance, and can summon only player in our group with us as lead
|
||||
if (toInstance && (
|
||||
!gmGroup || group.GetLeaderGUID() != gmPlayer.GetGUID() ||
|
||||
gmGroup.GetLeaderGUID() != gmPlayer.GetGUID()))
|
||||
// the last check is a bit excessive, but let it be, just in case
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CannotSummonToInst);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (GroupReference refe = group.GetFirstMember(); refe != null; refe = refe.next())
|
||||
{
|
||||
Player player = refe.GetSource();
|
||||
|
||||
if (!player || player == gmPlayer || player.GetSession() == null)
|
||||
continue;
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(player, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
string plNameLink = handler.GetNameLink(player);
|
||||
|
||||
if (player.IsBeingTeleported())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.IsTeleported, plNameLink);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (toInstance)
|
||||
{
|
||||
Map playerMap = player.GetMap();
|
||||
|
||||
if (playerMap.Instanceable() && playerMap.GetInstanceId() != gmMap.GetInstanceId())
|
||||
{
|
||||
// cannot summon from instance to instance
|
||||
handler.SendSysMessage(CypherStrings.CannotSummonToInst, plNameLink);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.Summoning, plNameLink, "");
|
||||
if (handler.needReportToTarget(player))
|
||||
player.SendSysMessage(CypherStrings.SummonedBy, handler.GetNameLink());
|
||||
|
||||
// stop flight if need
|
||||
if (player.IsInFlight())
|
||||
{
|
||||
player.GetMotionMaster().MovementExpired();
|
||||
player.CleanupAfterTaxiFlight();
|
||||
}
|
||||
// save only in non-flight case
|
||||
else
|
||||
player.SaveRecallPosition();
|
||||
|
||||
// before GM
|
||||
float x, y, z;
|
||||
gmPlayer.GetClosePoint(out x, out y, out z, player.GetObjectSize());
|
||||
player.TeleportTo(gmPlayer.GetMapId(), x, y, z, player.GetOrientation());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("leader", RBACPermissions.CommandGroupLeader)]
|
||||
static bool HandleGroupLeaderCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = null;
|
||||
Group group = null;
|
||||
ObjectGuid guid = ObjectGuid.Empty;
|
||||
string nameStr = args.NextString();
|
||||
|
||||
if (!handler.GetPlayerGroupAndGUIDByName(nameStr, out player, out group, out guid))
|
||||
return false;
|
||||
|
||||
if (!group)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GroupNotInGroup, player.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (group.GetLeaderGUID() != guid)
|
||||
{
|
||||
group.ChangeLeader(guid);
|
||||
group.SendUpdate();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("disband", RBACPermissions.CommandGroupDisband)]
|
||||
static bool HandleGroupDisbandCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = null;
|
||||
Group group = null;
|
||||
ObjectGuid guid = ObjectGuid.Empty;
|
||||
string nameStr = args.NextString();
|
||||
|
||||
if (!handler.GetPlayerGroupAndGUIDByName(nameStr, out player, out group, out guid))
|
||||
return false;
|
||||
|
||||
if (!group)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GroupNotInGroup, player.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
group.Disband();
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("remove", RBACPermissions.CommandGroupRemove)]
|
||||
static bool HandleGroupRemoveCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = null;
|
||||
Group group = null;
|
||||
ObjectGuid guid = ObjectGuid.Empty;
|
||||
string nameStr = args.NextString();
|
||||
|
||||
if (!handler.GetPlayerGroupAndGUIDByName(nameStr, out player, out group, out guid))
|
||||
return false;
|
||||
|
||||
if (!group)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GroupNotInGroup, player.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
group.RemoveMember(guid);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("join", RBACPermissions.CommandGroupJoin)]
|
||||
static bool HandleGroupJoinCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player playerSource = null;
|
||||
Player playerTarget = null;
|
||||
Group groupSource = null;
|
||||
Group groupTarget = null;
|
||||
ObjectGuid guidSource = ObjectGuid.Empty;
|
||||
ObjectGuid guidTarget = ObjectGuid.Empty;
|
||||
string nameplgrStr = args.NextString();
|
||||
string nameplStr = args.NextString();
|
||||
|
||||
if (!handler.GetPlayerGroupAndGUIDByName(nameplgrStr, out playerSource, out groupSource, out guidSource, true))
|
||||
return false;
|
||||
|
||||
if (!groupSource)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GroupNotInGroup, playerSource.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!handler.GetPlayerGroupAndGUIDByName(nameplStr, out playerTarget, out groupTarget, out guidTarget, true))
|
||||
return false;
|
||||
|
||||
if (groupTarget || playerTarget.GetGroup() == groupSource)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GroupAlreadyInGroup, playerTarget.GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (groupSource.IsFull())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GroupFull);
|
||||
return false;
|
||||
}
|
||||
|
||||
groupSource.AddMember(playerTarget);
|
||||
groupSource.BroadcastGroupUpdate();
|
||||
handler.SendSysMessage(CypherStrings.GroupPlayerJoined, playerTarget.GetName(), playerSource.GetName());
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("list", RBACPermissions.CommandGroupList)]
|
||||
static bool HandleGroupListCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// Get ALL the variables!
|
||||
Player playerTarget;
|
||||
uint phase = 0;
|
||||
ObjectGuid guidTarget;
|
||||
string nameTarget;
|
||||
string zoneName = "";
|
||||
string onlineState = "";
|
||||
|
||||
// Parse the guid to uint32...
|
||||
ObjectGuid parseGUID = ObjectGuid.Create(HighGuid.Player, args.NextUInt64());
|
||||
|
||||
// ... and try to extract a player out of it.
|
||||
if (ObjectManager.GetPlayerNameByGUID(parseGUID, out nameTarget))
|
||||
{
|
||||
playerTarget = Global.ObjAccessor.FindPlayer(parseGUID);
|
||||
guidTarget = parseGUID;
|
||||
}
|
||||
// If not, we return false and end right away.
|
||||
else if (!handler.extractPlayerTarget(args, out playerTarget, out guidTarget, out nameTarget))
|
||||
return false;
|
||||
|
||||
// Next, we need a group. So we define a group variable.
|
||||
Group groupTarget = null;
|
||||
|
||||
// We try to extract a group from an online player.
|
||||
if (playerTarget)
|
||||
groupTarget = playerTarget.GetGroup();
|
||||
|
||||
// If not, we extract it from the SQL.
|
||||
if (!groupTarget)
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GROUP_MEMBER);
|
||||
stmt.AddValue(0, guidTarget.GetCounter());
|
||||
SQLResult resultGroup = DB.Characters.Query(stmt);
|
||||
if (!resultGroup.IsEmpty())
|
||||
groupTarget = Global.GroupMgr.GetGroupByDbStoreId(resultGroup.Read<uint>(0));
|
||||
}
|
||||
|
||||
// If both fails, players simply has no party. Return false.
|
||||
if (!groupTarget)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GroupNotInGroup, nameTarget);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We get the group members after successfully detecting a group.
|
||||
var members = groupTarget.GetMemberSlots();
|
||||
|
||||
// To avoid a cluster fuck, namely trying multiple queries to simply get a group member count...
|
||||
handler.SendSysMessage(CypherStrings.GroupType, (groupTarget.isRaidGroup() ? "raid" : "party"), members.Count);
|
||||
// ... we simply move the group type and member count print after retrieving the slots and simply output it's size.
|
||||
|
||||
// While rather dirty codestyle-wise, it saves space (if only a little). For each member, we look several informations up.
|
||||
foreach (var slot in members)
|
||||
{
|
||||
// Check for given flag and assign it to that iterator
|
||||
string flags = "";
|
||||
if (slot.flags.HasAnyFlag(GroupMemberFlags.Assistant))
|
||||
flags = "Assistant";
|
||||
|
||||
if (slot.flags.HasAnyFlag(GroupMemberFlags.MainTank))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(flags))
|
||||
flags += ", ";
|
||||
flags += "MainTank";
|
||||
}
|
||||
|
||||
if (slot.flags.HasAnyFlag(GroupMemberFlags.MainAssist))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(flags))
|
||||
flags += ", ";
|
||||
flags += "MainAssist";
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(flags))
|
||||
flags = "None";
|
||||
|
||||
// Check if iterator is online. If is...
|
||||
Player p = Global.ObjAccessor.FindPlayer(slot.guid);
|
||||
if (p && p.IsInWorld)
|
||||
{
|
||||
// ... than, it prints information like "is online", where he is, etc...
|
||||
onlineState = "online";
|
||||
phase = (!p.IsGameMaster() ? p.GetPhaseMask() : uint.MaxValue);
|
||||
|
||||
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(p.GetAreaId());
|
||||
if (area != null)
|
||||
{
|
||||
AreaTableRecord zone = CliDB.AreaTableStorage.LookupByKey(area.ParentAreaID);
|
||||
if (zone != null)
|
||||
zoneName = zone.AreaName[handler.GetSessionDbcLocale()];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ... else, everything is set to offline or neutral values.
|
||||
zoneName = "<ERROR>";
|
||||
onlineState = "Offline";
|
||||
phase = 0;
|
||||
}
|
||||
|
||||
// Now we can print those informations for every single member of each group!
|
||||
handler.SendSysMessage(CypherStrings.GroupPlayerNameGuid, slot.name, onlineState,
|
||||
zoneName, phase, slot.guid.ToString(), flags, LFGQueue.GetRolesString(slot.roles));
|
||||
}
|
||||
|
||||
// And finish after every iterator is done.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using Game.Guilds;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("guild", RBACPermissions.CommandGuild, true)]
|
||||
class GuildCommands
|
||||
{
|
||||
[Command("create", RBACPermissions.CommandGuildCreate, true)]
|
||||
static bool HandleGuildCreateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args[0] != '"' ? args : null, out target))
|
||||
return false;
|
||||
|
||||
string guildname = handler.extractQuotedArg(args.NextString());
|
||||
if (string.IsNullOrEmpty(guildname))
|
||||
return false;
|
||||
|
||||
if (target.GetGuildId() != 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerInGuild);
|
||||
return true;
|
||||
}
|
||||
|
||||
Guild guild = new Guild();
|
||||
if (!guild.Create(target, guildname))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GuildNotCreated);
|
||||
return false;
|
||||
}
|
||||
|
||||
Global.GuildMgr.AddGuild(guild);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("delete", RBACPermissions.CommandGuildDelete, true)]
|
||||
static bool HandleGuildDeleteCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
string guildName = handler.extractQuotedArg(args.NextString());
|
||||
if (string.IsNullOrEmpty(guildName))
|
||||
return false;
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildByName(guildName);
|
||||
if (guild == null)
|
||||
return false;
|
||||
|
||||
guild.Disband();
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("invite", RBACPermissions.CommandGuildInvite, true)]
|
||||
static bool HandleGuildInviteCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args[0] != '"' ? args : null, out target))
|
||||
return false;
|
||||
|
||||
string guildName = handler.extractQuotedArg(args.NextString());
|
||||
if (string.IsNullOrEmpty(guildName))
|
||||
return false;
|
||||
|
||||
Guild targetGuild = Global.GuildMgr.GetGuildByName(guildName);
|
||||
if (targetGuild == null)
|
||||
return false;
|
||||
|
||||
targetGuild.AddMember(target.GetGUID());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("uninvite", RBACPermissions.CommandGuildUninvite, true)]
|
||||
static bool HandleGuildUninviteCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
ObjectGuid targetGuid = ObjectGuid.Empty;
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid))
|
||||
return false;
|
||||
|
||||
uint guildId = target != null ? target.GetGuildId() : Player.GetGuildIdFromDB(targetGuid);
|
||||
if (guildId == 0)
|
||||
return false;
|
||||
|
||||
Guild targetGuild = Global.GuildMgr.GetGuildById(guildId);
|
||||
if (targetGuild == null)
|
||||
return false;
|
||||
|
||||
targetGuild.DeleteMember(targetGuid, false, true, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("rank", RBACPermissions.CommandGuildRank, true)]
|
||||
static bool HandleGuildRankCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
string nameStr;
|
||||
string rankStr;
|
||||
handler.extractOptFirstArg(args, out nameStr, out rankStr);
|
||||
if (string.IsNullOrEmpty(rankStr))
|
||||
return false;
|
||||
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string target_name;
|
||||
if (!handler.extractPlayerTarget(new StringArguments(nameStr), out target, out targetGuid, out target_name))
|
||||
return false;
|
||||
|
||||
ulong guildId = target ? target.GetGuildId() : Player.GetGuildIdFromDB(targetGuid);
|
||||
if (guildId == 0)
|
||||
return false;
|
||||
|
||||
Guild targetGuild = Global.GuildMgr.GetGuildById(guildId);
|
||||
if (!targetGuild)
|
||||
return false;
|
||||
|
||||
byte newRank = byte.Parse(rankStr);
|
||||
return targetGuild.ChangeMemberRank(targetGuid, newRank);
|
||||
}
|
||||
|
||||
[Command("rename", RBACPermissions.CommandGuildRename, true)]
|
||||
static bool HandleGuildRenameCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string oldGuildStr = handler.extractQuotedArg(args.NextString());
|
||||
if (string.IsNullOrEmpty(oldGuildStr))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
string newGuildStr = handler.extractQuotedArg(args.NextString());
|
||||
if (string.IsNullOrEmpty(newGuildStr))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.InsertGuildName);
|
||||
return false;
|
||||
}
|
||||
|
||||
Guild guild = Global.GuildMgr.GetGuildByName(oldGuildStr);
|
||||
if (!guild)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandCouldnotfind, oldGuildStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Global.GuildMgr.GetGuildByName(newGuildStr))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.GuildRenameAlreadyExists, newGuildStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!guild.SetName(newGuildStr))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.GuildRenameDone, oldGuildStr, newGuildStr);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("info", RBACPermissions.CommandGuildInfo, true)]
|
||||
static bool HandleGuildInfoCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Guild guild = null;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
|
||||
if (!args.Empty() && args[0] != '\0')
|
||||
{
|
||||
if (char.IsDigit(args[0]))
|
||||
guild = Global.GuildMgr.GetGuildById(args.NextUInt64());
|
||||
else
|
||||
guild = Global.GuildMgr.GetGuildByName(args.NextString());
|
||||
}
|
||||
else if (target)
|
||||
guild = target.GetGuild();
|
||||
|
||||
if (!guild)
|
||||
return false;
|
||||
|
||||
// Display Guild Information
|
||||
handler.SendSysMessage(CypherStrings.GuildInfoName, guild.GetName(), guild.GetId()); // Guild Id + Name
|
||||
|
||||
string guildMasterName;
|
||||
if (ObjectManager.GetPlayerNameByGUID(guild.GetLeaderGUID(), out guildMasterName))
|
||||
handler.SendSysMessage(CypherStrings.GuildInfoGuildMaster, guildMasterName, guild.GetLeaderGUID().ToString()); // Guild Master
|
||||
|
||||
// Format creation date
|
||||
|
||||
var createdDateTime = Time.UnixTimeToDateTime(guild.GetCreatedDate());
|
||||
handler.SendSysMessage(CypherStrings.GuildInfoCreationDate, createdDateTime.ToLongDateString()); // Creation Date
|
||||
handler.SendSysMessage(CypherStrings.GuildInfoMemberCount, guild.GetMembersCount()); // Number of Members
|
||||
handler.SendSysMessage(CypherStrings.GuildInfoBankGold, guild.GetBankMoney() / 100 / 100); // Bank Gold (in gold coins)
|
||||
handler.SendSysMessage(CypherStrings.GuildInfoLevel, guild.GetLevel()); // Level
|
||||
handler.SendSysMessage(CypherStrings.GuildInfoMotd, guild.GetMOTD()); // Message of the Day
|
||||
handler.SendSysMessage(CypherStrings.GuildInfoExtraInfo, guild.GetInfo()); // Extra Information
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("honor", RBACPermissions.CommandHonor)]
|
||||
class HonorCommands
|
||||
{
|
||||
[Command("update", RBACPermissions.CommandHonorUpdate)]
|
||||
static bool HandleHonorUpdateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target = handler.getSelectedPlayer();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
target.UpdateHonorFields();
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("add", RBACPermissions.CommandHonorAdd)]
|
||||
class HonorAddCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandHonorAdd)]
|
||||
static bool HandleHonorAddCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target = handler.getSelectedPlayer();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
int amount = args.NextInt32();
|
||||
target.RewardHonor(null, 1, amount);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("kill", RBACPermissions.CommandHonorAddKill)]
|
||||
static bool HandleHonorAddKillCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
Player player = target.ToPlayer();
|
||||
if (player)
|
||||
if (handler.HasLowerSecurity(player, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
handler.GetPlayer().RewardHonor(target, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Maps;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("instance", RBACPermissions.CommandInstance, true)]
|
||||
class InstanceCommands
|
||||
{
|
||||
[Command("listbinds", RBACPermissions.CommandInstanceListbinds)]
|
||||
static bool HandleInstanceListBinds(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
player = handler.GetSession().GetPlayer();
|
||||
|
||||
string format = "map: {0} inst: {1} perm: {2} diff: {3} canReset: {4} TTR: {5}";
|
||||
|
||||
uint counter = 0;
|
||||
for (byte i = 0; i < (int)Difficulty.Max; ++i)
|
||||
{
|
||||
var binds = player.GetBoundInstances((Difficulty)i);
|
||||
foreach (var pair in binds)
|
||||
{
|
||||
InstanceSave save = pair.Value.save;
|
||||
string timeleft = Time.GetTimeString(save.GetResetTime() - Time.UnixTime);
|
||||
handler.SendSysMessage(format, pair.Key, save.GetInstanceId(), pair.Value.perm ? "yes" : "no", save.GetDifficultyID(), save.CanReset() ? "yes" : "no", timeleft);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
handler.SendSysMessage("player binds: {0}", counter);
|
||||
|
||||
counter = 0;
|
||||
Group group = player.GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (byte i = 0; i < (int)Difficulty.Max; ++i)
|
||||
{
|
||||
var binds = group.GetBoundInstances((Difficulty)i);
|
||||
foreach (var pair in binds)
|
||||
{
|
||||
InstanceSave save = pair.Value.save;
|
||||
string timeleft = Time.GetTimeString(save.GetResetTime() - Time.UnixTime);
|
||||
handler.SendSysMessage(format, pair.Key, save.GetInstanceId(), pair.Value.perm ? "yes" : "no", save.GetDifficultyID(), save.CanReset() ? "yes" : "no", timeleft);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
handler.SendSysMessage("group binds: {0}", counter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("unbind", RBACPermissions.CommandInstanceUnbind)]
|
||||
static bool HandleInstanceUnbind(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
player = handler.GetSession().GetPlayer();
|
||||
|
||||
string map = args.NextString();
|
||||
string pDiff = args.NextString();
|
||||
sbyte diff = -1;
|
||||
if (string.IsNullOrEmpty(pDiff))
|
||||
diff = sbyte.Parse(pDiff);
|
||||
ushort counter = 0;
|
||||
ushort MapId = 0;
|
||||
|
||||
if (map != "all")
|
||||
{
|
||||
MapId = ushort.Parse(map);
|
||||
if (MapId == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (byte i = 0; i < (int)Difficulty.Max; ++i)
|
||||
{
|
||||
var binds = player.GetBoundInstances((Difficulty)i);
|
||||
foreach (var pair in binds)
|
||||
{
|
||||
InstanceSave save = pair.Value.save;
|
||||
if (pair.Key != player.GetMapId() && (MapId == 0 || MapId == pair.Key) && (diff == -1 || diff == (sbyte)save.GetDifficultyID()))
|
||||
{
|
||||
string timeleft = Time.GetTimeString(save.GetResetTime() - Time.UnixTime);
|
||||
handler.SendSysMessage("unbinding map: {0} inst: {1} perm: {2} diff: {3} canReset: {4} TTR: {5}", pair.Key, save.GetInstanceId(),
|
||||
pair.Value.perm ? "yes" : "no", save.GetDifficultyID(), save.CanReset() ? "yes" : "no", timeleft);
|
||||
player.UnbindInstance(pair.Key, (Difficulty)i);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
handler.SendSysMessage("instances unbound: {0}", counter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("stats", RBACPermissions.CommandInstanceStats, true)]
|
||||
static bool HandleInstanceStats(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
handler.SendSysMessage("instances loaded: {0}", Global.MapMgr.GetNumInstances());
|
||||
handler.SendSysMessage("players in instances: {0}", Global.MapMgr.GetNumPlayersInInstances());
|
||||
handler.SendSysMessage("instance saves: {0}", Global.InstanceSaveMgr.GetNumInstanceSaves());
|
||||
handler.SendSysMessage("players bound: {0}", Global.InstanceSaveMgr.GetNumBoundPlayersTotal());
|
||||
handler.SendSysMessage("groups bound: {0}", Global.InstanceSaveMgr.GetNumBoundGroupsTotal());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("savedata", RBACPermissions.CommandInstanceSavedata)]
|
||||
static bool HandleInstanceSaveData(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
InstanceMap map = player.GetMap().ToInstanceMap();
|
||||
if (map == null)
|
||||
{
|
||||
handler.SendSysMessage("Map is not a dungeon.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map.GetInstanceScript() == null)
|
||||
{
|
||||
handler.SendSysMessage("Map has no instance data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
map.GetInstanceScript().SaveToDB();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("setbossstate", RBACPermissions.CommandInstanceSetBossState)]
|
||||
static bool HandleInstanceSetBossState(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string param1 = args.NextString();
|
||||
string param2 = args.NextString();
|
||||
string param3 = args.NextString();
|
||||
uint encounterId = 0;
|
||||
EncounterState state = 0;
|
||||
Player player = null;
|
||||
|
||||
// Character name must be provided when using this from console.
|
||||
if (string.IsNullOrEmpty(param2) || (string.IsNullOrEmpty(param3) && handler.GetSession() == null))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(param3))
|
||||
player = handler.GetSession().GetPlayer();
|
||||
else
|
||||
{
|
||||
if (ObjectManager.NormalizePlayerName(ref param3))
|
||||
player = Global.ObjAccessor.FindPlayerByName(param3);
|
||||
}
|
||||
|
||||
if (!player)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
InstanceMap map = player.GetMap().ToInstanceMap();
|
||||
if (map == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NotDungeon);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map.GetInstanceScript() == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoInstanceData);
|
||||
return false;
|
||||
}
|
||||
|
||||
encounterId = uint.Parse(param1);
|
||||
state = (EncounterState)int.Parse(param2);
|
||||
|
||||
// Reject improper values.
|
||||
if (state > EncounterState.ToBeDecided || encounterId > map.GetInstanceScript().GetEncounterCount())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
map.GetInstanceScript().SetBossState(encounterId, state);
|
||||
handler.SendSysMessage(CypherStrings.CommandInstSetBossState, encounterId, state);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("getbossstate", RBACPermissions.CommandInstanceGetBossState)]
|
||||
static bool HandleInstanceGetBossState(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string param1 = args.NextString();
|
||||
string param2 = args.NextString();
|
||||
uint encounterId = 0;
|
||||
Player player = null;
|
||||
|
||||
// Character name must be provided when using this from console.
|
||||
if (string.IsNullOrEmpty(param1) || (string.IsNullOrEmpty(param2) && handler.GetSession() == null))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CmdSyntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(param2))
|
||||
player = handler.GetSession().GetPlayer();
|
||||
else
|
||||
{
|
||||
if (ObjectManager.NormalizePlayerName(ref param2))
|
||||
player = Global.ObjAccessor.FindPlayerByName(param2);
|
||||
}
|
||||
|
||||
if (!player)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
InstanceMap map = player.GetMap().ToInstanceMap();
|
||||
if (map == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NotDungeon);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map.GetInstanceScript() == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoInstanceData);
|
||||
return false;
|
||||
}
|
||||
|
||||
encounterId = uint.Parse(param1);
|
||||
|
||||
if (encounterId > map.GetInstanceScript().GetEncounterCount())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
EncounterState state = map.GetInstanceScript().GetBossState(encounterId);
|
||||
handler.SendSysMessage(CypherStrings.CommandInstGetBossState, encounterId, state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.DungeonFinding;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("lfg", RBACPermissions.CommandLfg, true)]
|
||||
class LFGCommands
|
||||
{
|
||||
[Command("player", RBACPermissions.CommandLfgPlayer, true)]
|
||||
static bool HandleLfgPlayerInfoCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target = null;
|
||||
string playerName;
|
||||
ObjectGuid guid;
|
||||
if (!handler.extractPlayerTarget(args, out target, out guid, out playerName))
|
||||
return false;
|
||||
|
||||
GetPlayerInfo(handler, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("group", RBACPermissions.CommandLfgGroup, true)]
|
||||
static bool HandleLfgGroupInfoCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player playerTarget = null;
|
||||
ObjectGuid guidTarget;
|
||||
string nameTarget;
|
||||
|
||||
ObjectGuid parseGUID = ObjectGuid.Create(HighGuid.Player, args.NextUInt64());
|
||||
if (ObjectManager.GetPlayerNameByGUID(parseGUID, out nameTarget))
|
||||
{
|
||||
playerTarget = Global.ObjAccessor.FindPlayer(parseGUID);
|
||||
guidTarget = parseGUID;
|
||||
}
|
||||
else if (!handler.extractPlayerTarget(args, out playerTarget, out guidTarget, out nameTarget))
|
||||
return false;
|
||||
|
||||
Group groupTarget = null;
|
||||
if (playerTarget)
|
||||
groupTarget = playerTarget.GetGroup();
|
||||
else
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GROUP_MEMBER);
|
||||
stmt.AddValue(0, guidTarget.GetCounter());
|
||||
SQLResult resultGroup = DB.Characters.Query(stmt);
|
||||
if (!resultGroup.IsEmpty())
|
||||
groupTarget = Global.GroupMgr.GetGroupByDbStoreId(resultGroup.Read<uint>(0));
|
||||
}
|
||||
|
||||
if (!groupTarget)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.LfgNotInGroup, nameTarget);
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGuid guid = groupTarget.GetGUID();
|
||||
handler.SendSysMessage(CypherStrings.LfgGroupInfo, groupTarget.isLFGGroup(), Global.LFGMgr.GetState(guid), Global.LFGMgr.GetDungeon(guid));
|
||||
|
||||
foreach (var slot in groupTarget.GetMemberSlots())
|
||||
{
|
||||
Player p = Global.ObjAccessor.FindPlayer(slot.guid);
|
||||
if (p)
|
||||
GetPlayerInfo(handler, p);
|
||||
else
|
||||
handler.SendSysMessage("{0} is offline.", slot.name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("options", RBACPermissions.CommandLfgOptions, true)]
|
||||
static bool HandleLfgOptionsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
int options = -1;
|
||||
string str = args.NextString();
|
||||
if (!string.IsNullOrEmpty(str))
|
||||
{
|
||||
int tmp = int.Parse(str);
|
||||
if (tmp > -1)
|
||||
options = tmp;
|
||||
}
|
||||
|
||||
if (options != -1)
|
||||
{
|
||||
Global.LFGMgr.SetOptions((LfgOptions)options);
|
||||
handler.SendSysMessage(CypherStrings.LfgOptionsChanged);
|
||||
}
|
||||
handler.SendSysMessage(CypherStrings.LfgOptions, Global.LFGMgr.GetOptions());
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("queue", RBACPermissions.CommandLfgQueue, true)]
|
||||
static bool HandleLfgQueueInfoCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
handler.SendSysMessage(Global.LFGMgr.DumpQueueInfo(args.NextBoolean()));
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("clean", RBACPermissions.CommandLfgClean, true)]
|
||||
static bool HandleLfgCleanCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.LfgClean);
|
||||
Global.LFGMgr.Clean();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GetPlayerInfo(CommandHandler handler, Player player)
|
||||
{
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
ObjectGuid guid = player.GetGUID();
|
||||
var dungeons = Global.LFGMgr.GetSelectedDungeons(guid);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.LfgPlayerInfo, player.GetName(), Global.LFGMgr.GetState(guid), dungeons.Count, LFGQueue.ConcatenateDungeons(dungeons),
|
||||
LFGQueue.GetRolesString(Global.LFGMgr.GetRoles(guid)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("learn", RBACPermissions.CommandLearn)]
|
||||
class LearnCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandLearn)]
|
||||
static bool HandleLearnCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player targetPlayer = handler.getSelectedPlayerOrSelf();
|
||||
|
||||
if (!targetPlayer)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form
|
||||
uint spell = handler.extractSpellIdFromLink(args);
|
||||
if (spell == 0 || !Global.SpellMgr.HasSpellInfo(spell))
|
||||
return false;
|
||||
|
||||
string all = args.NextString();
|
||||
bool allRanks = !string.IsNullOrEmpty(all) ? all == "all" : false;
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell);
|
||||
if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo, handler.GetSession().GetPlayer()))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandSpellBroken, spell);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!allRanks && targetPlayer.HasSpell(spell))
|
||||
{
|
||||
if (targetPlayer == handler.GetSession().GetPlayer())
|
||||
handler.SendSysMessage(CypherStrings.YouKnownSpell);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.TargetKnownSpell, handler.GetNameLink(targetPlayer));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (allRanks)
|
||||
targetPlayer.LearnSpellHighestRank(spell);
|
||||
else
|
||||
targetPlayer.LearnSpell(spell, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("all", RBACPermissions.CommandLearnAll)]
|
||||
class LearnAllCommands
|
||||
{
|
||||
[Command("gm", RBACPermissions.CommandLearnAllGm)]
|
||||
static bool HandleLearnAllGMCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
foreach (var spellInfo in Global.SpellMgr.GetSpellInfoStorage().Values)
|
||||
{
|
||||
if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo, handler.GetSession().GetPlayer(), false))
|
||||
continue;
|
||||
|
||||
if (!spellInfo.IsAbilityOfSkillType(SkillType.Internal))
|
||||
continue;
|
||||
|
||||
handler.GetSession().GetPlayer().LearnSpell(spellInfo.Id, false);
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.LearningGmSkills);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("lang", RBACPermissions.CommandLearnAllLang)]
|
||||
static bool HandleLearnAllLangCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// skipping UNIVERSAL language (0)
|
||||
for (byte i = 1; i < Enum.GetValues(typeof(Language)).Length; ++i)
|
||||
handler.GetSession().GetPlayer().LearnSpell(ObjectManager.lang_description[i].spell_id, false);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandLearnAllLang);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("default", RBACPermissions.CommandLearnAllDefault)]
|
||||
static bool HandleLearnAllDefaultCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args, out target))
|
||||
return false;
|
||||
|
||||
target.LearnDefaultSkills();
|
||||
target.LearnCustomSpells();
|
||||
target.LearnQuestRewardedSpells();
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandLearnAllDefaultAndQuest, handler.GetNameLink(target));
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("crafts", RBACPermissions.CommandLearnAllCrafts)]
|
||||
static bool HandleLearnAllCraftsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args, out target))
|
||||
return false;
|
||||
|
||||
foreach (var skillInfo in CliDB.SkillLineStorage.Values)
|
||||
{
|
||||
if ((skillInfo.CategoryID == SkillCategory.Profession || skillInfo.CategoryID == SkillCategory.Secondary) && skillInfo.CanLink != 0) // only prof. with recipes have
|
||||
{
|
||||
HandleLearnSkillRecipesHelper(target, skillInfo.Id);
|
||||
}
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandLearnAllCraft);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("recipes", RBACPermissions.CommandLearnAllRecipes)]
|
||||
static bool HandleLearnAllRecipesCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// Learns all recipes of specified profession and sets skill to max
|
||||
// Example: .learn all_recipes enchanting
|
||||
|
||||
Player target = handler.getSelectedPlayer();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// converting string that we try to find to lower case
|
||||
string namePart = args.NextString().ToLower();
|
||||
|
||||
string name = "";
|
||||
uint skillId = 0;
|
||||
foreach (var skillInfo in CliDB.SkillLineStorage.Values)
|
||||
{
|
||||
if ((skillInfo.CategoryID != SkillCategory.Profession &&
|
||||
skillInfo.CategoryID != SkillCategory.Secondary) ||
|
||||
skillInfo.CanLink == 0) // only prof with recipes have set
|
||||
continue;
|
||||
|
||||
LocaleConstant locale = handler.GetSessionDbcLocale();
|
||||
name = skillInfo.DisplayName[locale];
|
||||
if (string.IsNullOrEmpty(name))
|
||||
continue;
|
||||
|
||||
if (!name.Like(namePart))
|
||||
{
|
||||
locale = 0;
|
||||
for (; locale < LocaleConstant.Total; ++locale)
|
||||
{
|
||||
if (locale == handler.GetSessionDbcLocale())
|
||||
continue;
|
||||
|
||||
name = skillInfo.DisplayName[locale];
|
||||
if (name.IsEmpty())
|
||||
continue;
|
||||
|
||||
if (name.Like(namePart))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (locale < LocaleConstant.Total)
|
||||
{
|
||||
skillId = skillInfo.Id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skillId == 0)
|
||||
return false;
|
||||
|
||||
HandleLearnSkillRecipesHelper(target, skillId);
|
||||
|
||||
ushort maxLevel = target.GetPureMaxSkillValue((SkillType)skillId);
|
||||
target.SetSkill(skillId, target.GetSkillStep((SkillType)skillId), maxLevel, maxLevel);
|
||||
handler.SendSysMessage(CypherStrings.CommandLearnAllRecipes, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HandleLearnSkillRecipesHelper(Player player, uint skillId)
|
||||
{
|
||||
uint classmask = player.getClassMask();
|
||||
|
||||
foreach (var skillLine in CliDB.SkillLineAbilityStorage.Values)
|
||||
{
|
||||
// wrong skill
|
||||
if (skillLine.SkillLine != skillId)
|
||||
continue;
|
||||
|
||||
// not high rank
|
||||
if (skillLine.SupercedesSpell != 0)
|
||||
continue;
|
||||
|
||||
// skip racial skills
|
||||
if (skillLine.RaceMask != 0)
|
||||
continue;
|
||||
|
||||
// skip wrong class skills
|
||||
if (skillLine.ClassMask != 0 && (skillLine.ClassMask & classmask) == 0)
|
||||
continue;
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(skillLine.SpellID);
|
||||
if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo, player, false))
|
||||
continue;
|
||||
|
||||
player.LearnSpell(skillLine.SpellID, false);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("my", RBACPermissions.CommandLearnAllMy)]
|
||||
class LearnAllMyCommands
|
||||
{
|
||||
[Command("class", RBACPermissions.CommandLearnAllMyClass)]
|
||||
static bool HandleLearnAllMyClassCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
HandleLearnAllMySpellsCommand(args, handler);
|
||||
HandleLearnAllMyTalentsCommand(args, handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("spells", RBACPermissions.CommandLearnAllMySpells)]
|
||||
static bool HandleLearnAllMySpellsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
ChrClassesRecord classEntry = CliDB.ChrClassesStorage.LookupByKey(handler.GetSession().GetPlayer().GetClass());
|
||||
if (classEntry == null)
|
||||
return true;
|
||||
uint family = classEntry.SpellClassSet;
|
||||
|
||||
foreach (var entry in CliDB.SkillLineAbilityStorage.Values)
|
||||
{
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(entry.SpellID);
|
||||
if (spellInfo == null)
|
||||
continue;
|
||||
|
||||
// skip server-side/triggered spells
|
||||
if (spellInfo.SpellLevel == 0)
|
||||
continue;
|
||||
|
||||
// skip wrong class/race skills
|
||||
if (!handler.GetSession().GetPlayer().IsSpellFitByClassAndRace(spellInfo.Id))
|
||||
continue;
|
||||
|
||||
// skip other spell families
|
||||
if ((uint)spellInfo.SpellFamilyName != family)
|
||||
continue;
|
||||
|
||||
// skip broken spells
|
||||
if (!Global.SpellMgr.IsSpellValid(spellInfo, handler.GetSession().GetPlayer(), false))
|
||||
continue;
|
||||
|
||||
handler.GetSession().GetPlayer().LearnSpell(spellInfo.Id, false);
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandLearnClassSpells);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("talents", RBACPermissions.CommandLearnAllMyTalents)]
|
||||
static bool HandleLearnAllMyTalentsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
uint playerClass = (uint)player.GetClass();
|
||||
|
||||
foreach (var talentInfo in CliDB.TalentStorage.Values)
|
||||
{
|
||||
if (playerClass != talentInfo.ClassID)
|
||||
continue;
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talentInfo.SpellID);
|
||||
if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo, handler.GetSession().GetPlayer(), false))
|
||||
continue;
|
||||
|
||||
// learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
|
||||
player.LearnSpellHighestRank(talentInfo.SpellID);
|
||||
player.AddTalent(talentInfo, player.GetActiveTalentGroup(), true);
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandLearnClassTalents);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("pettalents", RBACPermissions.CommandLearnAllMyPettalents)]
|
||||
static bool HandleLearnAllMyPetTalentsCommand(StringArguments args, CommandHandler handler) { return true; }
|
||||
}
|
||||
}
|
||||
|
||||
[CommandNonGroup("unlearn", RBACPermissions.CommandUnlearn)]
|
||||
static bool HandleUnLearnCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
if (spellId == 0)
|
||||
return false;
|
||||
|
||||
string allStr = args.NextString();
|
||||
bool allRanks = !string.IsNullOrEmpty(allStr) ? allStr == "all" : false;
|
||||
|
||||
Player target = handler.getSelectedPlayer();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (allRanks)
|
||||
spellId = Global.SpellMgr.GetFirstSpellInChain(spellId);
|
||||
|
||||
if (target.HasSpell(spellId))
|
||||
target.RemoveSpell(spellId, false, !allRanks);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.ForgetSpell);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,555 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using Game.Spells;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("list", RBACPermissions.CommandList, true)]
|
||||
class ListCommands
|
||||
{
|
||||
[Command("auras", RBACPermissions.CommandListAuras)]
|
||||
static bool HandleListAurasCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Unit unit = handler.getSelectedUnit();
|
||||
if (!unit)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectCharOrCreature);
|
||||
return false;
|
||||
}
|
||||
|
||||
string talentStr = handler.GetCypherString(CypherStrings.Talent);
|
||||
string passiveStr = handler.GetCypherString(CypherStrings.Passive);
|
||||
|
||||
var auras = unit.GetAppliedAuras();
|
||||
handler.SendSysMessage(CypherStrings.CommandTargetListauras, auras.Count);
|
||||
foreach (var pair in auras)
|
||||
{
|
||||
|
||||
AuraApplication aurApp = pair.Value;
|
||||
Aura aura = aurApp.GetBase();
|
||||
string name = aura.GetSpellInfo().SpellName[handler.GetSessionDbcLocale()];
|
||||
bool talent = aura.GetSpellInfo().HasAttribute(SpellCustomAttributes.IsTalent);
|
||||
|
||||
string ss_name = "|cffffffff|Hspell:" + aura.GetId() + "|h[" + name + "]|h|r";
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandTargetAuradetail, aura.GetId(), (handler.GetSession() != null ? ss_name : name),
|
||||
aurApp.GetEffectMask(), aura.GetCharges(), aura.GetStackAmount(), aurApp.GetSlot(),
|
||||
aura.GetDuration(), aura.GetMaxDuration(), (aura.IsPassive() ? passiveStr : ""),
|
||||
(talent ? talentStr : ""), aura.GetCasterGUID().IsPlayer() ? "player" : "creature",
|
||||
aura.GetCasterGUID().ToString());
|
||||
}
|
||||
|
||||
for (ushort i = 0; i < (int)AuraType.Total; ++i)
|
||||
{
|
||||
var auraList = unit.GetAuraEffectsByType((AuraType)i);
|
||||
if (auraList.Empty())
|
||||
continue;
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandTargetListauratype, auraList.Count, i);
|
||||
|
||||
foreach (var eff in auraList)
|
||||
handler.SendSysMessage(CypherStrings.CommandTargetAurasimple, eff.GetId(), eff.GetEffIndex(), eff.GetAmount());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("creature", RBACPermissions.CommandListCreature, true)]
|
||||
static bool HandleListCreatureCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hcreature_entry");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
uint creatureId = uint.Parse(id);
|
||||
if (creatureId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandInvalidcreatureid, creatureId);
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureTemplate cInfo = Global.ObjectMgr.GetCreatureTemplate(creatureId);
|
||||
if (cInfo == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandInvalidcreatureid, creatureId);
|
||||
return false;
|
||||
}
|
||||
|
||||
string countStr = args.NextString();
|
||||
uint count = !string.IsNullOrEmpty(countStr) ? uint.Parse(countStr) : 10;
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
uint creatureCount = 0;
|
||||
SQLResult result = DB.World.Query("SELECT COUNT(guid) FROM creature WHERE id='{0}'", creatureId);
|
||||
if (!result.IsEmpty())
|
||||
creatureCount = result.Read<uint>(0);
|
||||
|
||||
if (handler.GetSession() != null)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
result = DB.World.Query("SELECT guid, position_x, position_y, position_z, map, (POW(position_x - '{0}', 2) + POW(position_y - '{1}', 2) + POW(position_z - '{2}', 2)) AS order_ FROM creature WHERE id = '{3}' ORDER BY order_ ASC LIMIT {4}",
|
||||
player.GetPositionX(), player.GetPositionY(), player.GetPositionZ(), creatureId, count);
|
||||
}
|
||||
else
|
||||
result = DB.World.Query("SELECT guid, position_x, position_y, position_z, map FROM creature WHERE id = '{0}' LIMIT {1}",
|
||||
creatureId, count);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ulong guid = result.Read<ulong>(0);
|
||||
float x = result.Read<float>(1);
|
||||
float y = result.Read<float>(2);
|
||||
float z = result.Read<float>(3);
|
||||
ushort mapId = result.Read<ushort>(4);
|
||||
|
||||
if (handler.GetSession() != null)
|
||||
handler.SendSysMessage(CypherStrings.CreatureListChat, guid, guid, cInfo.Name, x, y, z, mapId);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.CreatureListConsole, guid, cInfo.Name, x, y, z, mapId);
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandListcreaturemessage, creatureId, creatureCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("item", RBACPermissions.CommandListItem, true)]
|
||||
static bool HandleListItemCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string id = handler.extractKeyFromLink(args, "Hitem");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
uint itemId = uint.Parse(id);
|
||||
if (itemId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandItemidinvalid, itemId);
|
||||
return false;
|
||||
}
|
||||
|
||||
ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(itemId);
|
||||
if (itemTemplate == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandItemidinvalid, itemId);
|
||||
return false;
|
||||
}
|
||||
|
||||
string countStr = args.NextString();
|
||||
uint count = !string.IsNullOrEmpty(countStr) ? uint.Parse(countStr) : 10;
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
SQLResult result;
|
||||
|
||||
// inventory case
|
||||
uint inventoryCount = 0;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_INVENTORY_COUNT_ITEM);
|
||||
stmt.AddValue(0, itemId);
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
inventoryCount = result.Read<uint>(0);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_INVENTORY_ITEM_BY_ENTRY);
|
||||
stmt.AddValue(0, itemId);
|
||||
stmt.AddValue(1, count);
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ObjectGuid itemGuid = ObjectGuid.Create(HighGuid.Item, result.Read<ulong>(0));
|
||||
uint itemBag = result.Read<uint>(1);
|
||||
byte itemSlot = result.Read<byte>(2);
|
||||
ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(3));
|
||||
uint ownerAccountId = result.Read<uint>(4);
|
||||
string ownerName = result.Read<string>(5);
|
||||
|
||||
string itemPos = "";
|
||||
if (Player.IsEquipmentPos((byte)itemBag, itemSlot))
|
||||
itemPos = "[equipped]";
|
||||
else if (Player.IsInventoryPos((byte)itemBag, itemSlot))
|
||||
itemPos = "[in inventory]";
|
||||
else if (Player.IsBankPos((byte)itemBag, itemSlot))
|
||||
itemPos = "[in bank]";
|
||||
else
|
||||
itemPos = "";
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ItemlistSlot, itemGuid.ToString(), ownerName, ownerGuid.ToString(), ownerAccountId, itemPos);
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
uint resultCount = (uint)result.GetRowCount();
|
||||
|
||||
if (count > resultCount)
|
||||
count -= resultCount;
|
||||
else if (count != 0)
|
||||
count = 0;
|
||||
}
|
||||
|
||||
// mail case
|
||||
uint mailCount = 0;
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_COUNT_ITEM);
|
||||
stmt.AddValue(0, itemId);
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
mailCount = result.Read<uint>(0);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_ITEMS_BY_ENTRY);
|
||||
stmt.AddValue(0, itemId);
|
||||
stmt.AddValue(1, count);
|
||||
result = DB.Characters.Query(stmt);
|
||||
}
|
||||
else
|
||||
result = null;
|
||||
|
||||
if (result != null && !result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ulong itemGuid = result.Read<ulong>(0);
|
||||
ulong itemSender = result.Read<ulong>(1);
|
||||
ulong itemReceiver = result.Read<ulong>(2);
|
||||
uint itemSenderAccountId = result.Read<uint>(3);
|
||||
string itemSenderName = result.Read<string>(4);
|
||||
uint itemReceiverAccount = result.Read<uint>(5);
|
||||
string itemReceiverName = result.Read<string>(6);
|
||||
|
||||
string itemPos = "[in mail]";
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ItemlistMail, itemGuid, itemSenderName, itemSender, itemSenderAccountId, itemReceiverName, itemReceiver, itemReceiverAccount, itemPos);
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
uint resultCount = (uint)result.GetRowCount();
|
||||
|
||||
if (count > resultCount)
|
||||
count -= resultCount;
|
||||
else if (count != 0)
|
||||
count = 0;
|
||||
}
|
||||
|
||||
// auction case
|
||||
uint auctionCount = 0;
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_AUCTIONHOUSE_COUNT_ITEM);
|
||||
stmt.AddValue(0, itemId);
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
auctionCount = result.Read<uint>(0);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_AUCTIONHOUSE_ITEM_BY_ENTRY);
|
||||
stmt.AddValue(0, itemId);
|
||||
stmt.AddValue(1, count);
|
||||
result = DB.Characters.Query(stmt);
|
||||
}
|
||||
else
|
||||
result = null;
|
||||
|
||||
if (result != null && !result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ObjectGuid itemGuid = ObjectGuid.Create(HighGuid.Item, result.Read<ulong>(0));
|
||||
ObjectGuid owner = ObjectGuid.Create(HighGuid.Player, result.Read<ulong>(1));
|
||||
uint ownerAccountId = result.Read<uint>(2);
|
||||
string ownerName = result.Read<string>(3);
|
||||
|
||||
string itemPos = "[in auction]";
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ItemlistAuction, itemGuid.ToString(), ownerName, owner.ToString(), ownerAccountId, itemPos);
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
|
||||
// guild bank case
|
||||
uint guildCount = 0;
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUILD_BANK_COUNT_ITEM);
|
||||
stmt.AddValue(0, itemId);
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
guildCount = result.Read<uint>(0);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUILD_BANK_ITEM_BY_ENTRY);
|
||||
stmt.AddValue(0, itemId);
|
||||
stmt.AddValue(1, count);
|
||||
result = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ObjectGuid itemGuid = ObjectGuid.Create(HighGuid.Item, result.Read<ulong>(0));
|
||||
ObjectGuid guildGuid = ObjectGuid.Create(HighGuid.Guild, result.Read<ulong>(1));
|
||||
string guildName = result.Read<string>(2);
|
||||
|
||||
string itemPos = "[in guild bank]";
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ItemlistGuild, itemGuid.ToString(), guildName, guildGuid.ToString(), itemPos);
|
||||
}
|
||||
while (result.NextRow());
|
||||
|
||||
uint resultCount = (uint)result.GetRowCount();
|
||||
|
||||
if (count > resultCount)
|
||||
count -= resultCount;
|
||||
else if (count != 0)
|
||||
count = 0;
|
||||
}
|
||||
|
||||
if (inventoryCount + mailCount + auctionCount + guildCount == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandNoitemfound);
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandListitemmessage, itemId, inventoryCount + mailCount + auctionCount + guildCount, inventoryCount, mailCount, auctionCount, guildCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("mail", RBACPermissions.CommandListMail, true)]
|
||||
static bool HandleListMailCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
PreparedStatement stmt = null;
|
||||
|
||||
ObjectGuid parseGUID = ObjectGuid.Create(HighGuid.Player, args.NextUInt64());
|
||||
if (ObjectManager.GetPlayerNameByGUID(parseGUID, out targetName))
|
||||
{
|
||||
target = Global.ObjAccessor.FindPlayer(parseGUID);
|
||||
targetGuid = parseGUID;
|
||||
}
|
||||
else if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_LIST_COUNT);
|
||||
stmt.AddValue(0, targetGuid.GetCounter());
|
||||
SQLResult result = DB.Characters.Query(stmt);
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
uint countMail = result.Read<uint>(0);
|
||||
|
||||
string nameLink = handler.playerLink(targetName);
|
||||
handler.SendSysMessage(CypherStrings.ListMailHeader, countMail, nameLink, targetGuid.ToString());
|
||||
handler.SendSysMessage(CypherStrings.AccountListBar);
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_LIST_INFO);
|
||||
stmt.AddValue(0, targetGuid.GetCounter());
|
||||
SQLResult result1 = DB.Characters.Query(stmt);
|
||||
|
||||
if (!result1.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
uint messageId = result1.Read<uint>(0);
|
||||
ulong senderId = result1.Read<ulong>(1);
|
||||
string sender = result1.Read<string>(2);
|
||||
ulong receiverId = result1.Read<ulong>(3);
|
||||
string receiver = result1.Read<string>(4);
|
||||
string subject = result1.Read<string>(5);
|
||||
long deliverTime = result1.Read<uint>(6);
|
||||
long expireTime = result1.Read<uint>(7);
|
||||
ulong money = result1.Read<ulong>(8);
|
||||
byte hasItem = result1.Read<byte>(9);
|
||||
uint gold = (uint)(money / MoneyConstants.Gold);
|
||||
uint silv = (uint)(money % MoneyConstants.Gold) / MoneyConstants.Silver;
|
||||
uint copp = (uint)(money % MoneyConstants.Gold) % MoneyConstants.Silver;
|
||||
string receiverStr = handler.playerLink(receiver);
|
||||
string senderStr = handler.playerLink(sender);
|
||||
handler.SendSysMessage(CypherStrings.ListMailInfo1, messageId, subject, gold, silv, copp);
|
||||
handler.SendSysMessage(CypherStrings.ListMailInfo2, senderStr, senderId, receiverStr, receiverId);
|
||||
handler.SendSysMessage(CypherStrings.ListMailInfo3, Time.UnixTimeToDateTime(deliverTime).ToLongDateString(), Time.UnixTimeToDateTime(expireTime).ToLongDateString());
|
||||
|
||||
if (hasItem == 1)
|
||||
{
|
||||
SQLResult result2 = DB.Characters.Query("SELECT item_guid FROM mail_items WHERE mail_id = '{0}'", messageId);
|
||||
if (!result2.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
uint item_guid = result2.Read<uint>(0);
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_LIST_ITEMS);
|
||||
stmt.AddValue(0, item_guid);
|
||||
SQLResult result3 = DB.Characters.Query(stmt);
|
||||
if (!result3.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
uint item_entry = result3.Read<uint>(0);
|
||||
uint item_count = result3.Read<uint>(1);
|
||||
SQLResult result4 = DB.World.Query("SELECT name, quality FROM item_template WHERE entry = '{0}'", item_entry);
|
||||
|
||||
string item_name = result4.Read<string>(0);
|
||||
int item_quality = result4.Read<byte>(1);
|
||||
if (handler.GetSession() != null)
|
||||
{
|
||||
uint color = ItemConst.ItemQualityColors[item_quality];
|
||||
string itemStr = "|c" + color + "|Hitem:" + item_entry + ":0:0:0:0:0:0:0:0:0|h[" + item_name + "]|h|r";
|
||||
handler.SendSysMessage(CypherStrings.ListMailInfoItem, itemStr, item_entry, item_guid, item_count);
|
||||
}
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.ListMailInfoItem, item_name, item_entry, item_guid, item_count);
|
||||
}
|
||||
while (result3.NextRow());
|
||||
}
|
||||
}
|
||||
while (result2.NextRow());
|
||||
}
|
||||
}
|
||||
handler.SendSysMessage(CypherStrings.AccountListBar);
|
||||
}
|
||||
while (result1.NextRow());
|
||||
}
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.ListMailNotFound);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.ListMailNotFound);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("object", RBACPermissions.CommandListObject, true)]
|
||||
static bool HandleListObjectCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
// number or [name] Shift-click form |color|Hgameobject_entry:go_id|h[name]|h|r
|
||||
string id = handler.extractKeyFromLink(args, "Hgameobject_entry");
|
||||
if (string.IsNullOrEmpty(id))
|
||||
return false;
|
||||
|
||||
uint gameObjectId = uint.Parse(id);
|
||||
if (gameObjectId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandListobjinvalidid, gameObjectId);
|
||||
return false;
|
||||
}
|
||||
|
||||
GameObjectTemplate gInfo = Global.ObjectMgr.GetGameObjectTemplate(gameObjectId);
|
||||
if (gInfo == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandListobjinvalidid, gameObjectId);
|
||||
return false;
|
||||
}
|
||||
|
||||
string countStr = args.NextString();
|
||||
uint count = !string.IsNullOrEmpty(countStr) ? uint.Parse(countStr) : 10;
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
uint objectCount = 0;
|
||||
SQLResult result = DB.World.Query("SELECT COUNT(guid) FROM gameobject WHERE id='{0}'", gameObjectId);
|
||||
if (!result.IsEmpty())
|
||||
objectCount = result.Read<uint>(0);
|
||||
|
||||
if (handler.GetSession() != null)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
result = DB.World.Query("SELECT guid, position_x, position_y, position_z, map, id, (POW(position_x - '{0}', 2) + POW(position_y - '{1}', 2) + POW(position_z - '{2}', 2)) AS order_ FROM gameobject WHERE id = '{3}' ORDER BY order_ ASC LIMIT {4}",
|
||||
player.GetPositionX(), player.GetPositionY(), player.GetPositionZ(), gameObjectId, count);
|
||||
}
|
||||
else
|
||||
result = DB.World.Query("SELECT guid, position_x, position_y, position_z, map, id FROM gameobject WHERE id = '{0}' LIMIT {1}",
|
||||
gameObjectId, count);
|
||||
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
do
|
||||
{
|
||||
ulong guid = result.Read<ulong>(0);
|
||||
float x = result.Read<float>(1);
|
||||
float y = result.Read<float>(2);
|
||||
float z = result.Read<float>(3);
|
||||
ushort mapId = result.Read<ushort>(4);
|
||||
uint entry = result.Read<uint>(5);
|
||||
|
||||
if (handler.GetSession() != null)
|
||||
handler.SendSysMessage(CypherStrings.GoListChat, guid, entry, guid, gInfo.name, x, y, z, mapId);
|
||||
else
|
||||
handler.SendSysMessage(CypherStrings.GoListConsole, guid, gInfo.name, x, y, z, mapId);
|
||||
}
|
||||
while (result.NextRow());
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandListobjmessage, gameObjectId, objectCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("scenes", RBACPermissions.CommandListScenes)]
|
||||
static bool HandleListScenesCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target = handler.getSelectedPlayer();
|
||||
if (!target)
|
||||
target = handler.GetSession().GetPlayer();
|
||||
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
var instanceByPackageMap = target.GetSceneMgr().GetSceneTemplateByInstanceMap();
|
||||
|
||||
handler.SendSysMessage(CypherStrings.DebugSceneObjectList, target.GetSceneMgr().GetActiveSceneCount());
|
||||
|
||||
foreach (var instanceByPackage in instanceByPackageMap)
|
||||
handler.SendSysMessage(CypherStrings.DebugSceneObjectDetail, instanceByPackage.Value.ScenePackageId, instanceByPackage.Key);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using Game.Movement;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("mmap", RBACPermissions.CommandMmap, true)]
|
||||
class MMapsCommands
|
||||
{
|
||||
[Command("path", RBACPermissions.CommandMmapPath)]
|
||||
static bool PathCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (Global.MMapMgr.GetNavMesh(handler.GetPlayer().GetMapId(), handler.GetSession().GetPlayer().GetTerrainSwaps()) == null)
|
||||
{
|
||||
handler.SendSysMessage("NavMesh not loaded for current map.");
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage("mmap path:");
|
||||
|
||||
// units
|
||||
Player player = handler.GetPlayer();
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (player == null || target == null)
|
||||
{
|
||||
handler.SendSysMessage("Invalid target/source selection.");
|
||||
return true;
|
||||
}
|
||||
|
||||
string para = args.NextString();
|
||||
|
||||
bool useStraightPath = false;
|
||||
if (para.Equals("true"))
|
||||
useStraightPath = true;
|
||||
|
||||
bool useStraightLine = false;
|
||||
if (para.Equals("line"))
|
||||
useStraightLine = true;
|
||||
|
||||
// unit locations
|
||||
float x, y, z;
|
||||
player.GetPosition(out x, out y, out z);
|
||||
|
||||
// path
|
||||
PathGenerator path = new PathGenerator(target);
|
||||
path.SetUseStraightPath(useStraightPath);
|
||||
bool result = path.CalculatePath(x, y, z, false, useStraightLine);
|
||||
|
||||
var pointPath = path.GetPath();
|
||||
handler.SendSysMessage("{0}'s path to {1}:", target.GetName(), player.GetName());
|
||||
handler.SendSysMessage("Building: {0}", useStraightPath ? "StraightPath" : useStraightLine ? "Raycast" : "SmoothPath");
|
||||
handler.SendSysMessage("Result: {0} - Length: {1} - Type: {2}", (result ? "true" : "false"), pointPath.Length, path.GetPathType());
|
||||
|
||||
var start = path.GetStartPosition();
|
||||
var end = path.GetEndPosition();
|
||||
var actualEnd = path.GetActualEndPosition();
|
||||
|
||||
handler.SendSysMessage("StartPosition ({0:F3}, {1:F3}, {2:F3})", start.X, start.Y, start.Z);
|
||||
handler.SendSysMessage("EndPosition ({0:F3}, {1:F3}, {2:F3})", end.X, end.Y, end.Z);
|
||||
handler.SendSysMessage("ActualEndPosition ({0:F3}, {1:F3}, {2:F3})", actualEnd.X, actualEnd.Y, actualEnd.Z);
|
||||
|
||||
if (!player.IsGameMaster())
|
||||
handler.SendSysMessage("Enable GM mode to see the path points.");
|
||||
|
||||
for (uint i = 0; i < pointPath.Length; ++i)
|
||||
player.SummonCreature(1, pointPath[i].X, pointPath[i].Y, pointPath[i].Z, 0, TempSummonType.TimedDespawn, 9000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("loc", RBACPermissions.CommandMmapLoc)]
|
||||
static bool LocCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
handler.SendSysMessage("mmap tileloc:");
|
||||
|
||||
// grid tile location
|
||||
Player player = handler.GetPlayer();
|
||||
|
||||
int gx = (int)(32 - player.GetPositionX() / MapConst.SizeofGrids);
|
||||
int gy = (int)(32 - player.GetPositionY() / MapConst.SizeofGrids);
|
||||
|
||||
handler.SendSysMessage("{0:D4}{1:D2}{2:D2}.mmtile", player.GetMapId(), gy, gx);
|
||||
handler.SendSysMessage("gridloc [{0}, {1}]", gx, gy);
|
||||
|
||||
// calculate navmesh tile location
|
||||
Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(handler.GetPlayer().GetMapId(), handler.GetSession().GetPlayer().GetTerrainSwaps());
|
||||
Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(handler.GetPlayer().GetMapId(), player.GetInstanceId(), handler.GetSession().GetPlayer().GetTerrainSwaps());
|
||||
if (navmesh == null || navmeshquery == null)
|
||||
{
|
||||
handler.SendSysMessage("NavMesh not loaded for current map.");
|
||||
return true;
|
||||
}
|
||||
|
||||
float[] min = navmesh.getParams().orig;
|
||||
float x, y, z;
|
||||
player.GetPosition(out x, out y, out z);
|
||||
float[] location = { y, z, x };
|
||||
float[] extents = { 3.0f, 5.0f, 3.0f };
|
||||
|
||||
int tilex = (int)((y - min[0]) / MapConst.SizeofGrids);
|
||||
int tiley = (int)((x - min[2]) / MapConst.SizeofGrids);
|
||||
|
||||
handler.SendSysMessage("Calc [{0:D2}, {1:D2}]", tilex, tiley);
|
||||
|
||||
// navmesh poly . navmesh tile location
|
||||
Detour.dtQueryFilter filter = new Detour.dtQueryFilter();
|
||||
float[] nothing = new float[3];
|
||||
ulong polyRef = 0;
|
||||
if (Detour.dtStatusFailed(navmeshquery.findNearestPoly(location, extents, filter, ref polyRef, ref nothing)))
|
||||
{
|
||||
handler.SendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (polyRef == 0)
|
||||
handler.SendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)");
|
||||
else
|
||||
{
|
||||
Detour.dtMeshTile tile = new Detour.dtMeshTile();
|
||||
Detour.dtPoly poly = new Detour.dtPoly();
|
||||
if (Detour.dtStatusSucceed(navmesh.getTileAndPolyByRef(polyRef, ref tile, ref poly)))
|
||||
{
|
||||
if (tile != null)
|
||||
{
|
||||
handler.SendSysMessage("Dt [{0:D2},{1:D2}]", tile.header.x, tile.header.y);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
handler.SendSysMessage("Dt [??,??] (no tile loaded)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("loadedtiles", RBACPermissions.CommandMmapLoadedtiles)]
|
||||
static bool LoadedTilesCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint mapid = handler.GetPlayer().GetMapId();
|
||||
Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(mapid, handler.GetSession().GetPlayer().GetTerrainSwaps());
|
||||
Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(mapid, handler.GetPlayer().GetInstanceId(), handler.GetSession().GetPlayer().GetTerrainSwaps());
|
||||
if (navmesh == null || navmeshquery == null)
|
||||
{
|
||||
handler.SendSysMessage("NavMesh not loaded for current map.");
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage("mmap loadedtiles:");
|
||||
|
||||
for (int i = 0; i < navmesh.getMaxTiles(); ++i)
|
||||
{
|
||||
Detour.dtMeshTile tile = navmesh.getTile(i);
|
||||
if (tile == null)
|
||||
continue;
|
||||
|
||||
handler.SendSysMessage("[{0:D2}, {1:D2}]", tile.header.x, tile.header.y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("stats", RBACPermissions.CommandMmapStats)]
|
||||
static bool HandleMmapStatsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint mapId = handler.GetPlayer().GetMapId();
|
||||
handler.SendSysMessage("mmap stats:");
|
||||
handler.SendSysMessage(" global mmap pathfinding is {0}abled", Global.DisableMgr.IsPathfindingEnabled(mapId) ? "En" : "Dis");
|
||||
handler.SendSysMessage(" {0} maps loaded with {1} tiles overall", Global.MMapMgr.getLoadedMapsCount(), Global.MMapMgr.getLoadedTilesCount());
|
||||
|
||||
Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(handler.GetPlayer().GetMapId(), handler.GetSession().GetPlayer().GetTerrainSwaps());
|
||||
if (navmesh == null)
|
||||
{
|
||||
handler.SendSysMessage("NavMesh not loaded for current map.");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint tileCount = 0;
|
||||
int nodeCount = 0;
|
||||
int polyCount = 0;
|
||||
int vertCount = 0;
|
||||
int triCount = 0;
|
||||
int triVertCount = 0;
|
||||
for (int i = 0; i < navmesh.getMaxTiles(); ++i)
|
||||
{
|
||||
Detour.dtMeshTile tile = navmesh.getTile(i);
|
||||
if (tile == null)
|
||||
continue;
|
||||
|
||||
tileCount++;
|
||||
nodeCount += tile.header.bvNodeCount;
|
||||
polyCount += tile.header.polyCount;
|
||||
vertCount += tile.header.vertCount;
|
||||
triCount += tile.header.detailTriCount;
|
||||
triVertCount += tile.header.detailVertCount;
|
||||
}
|
||||
|
||||
handler.SendSysMessage("Navmesh stats:");
|
||||
handler.SendSysMessage(" {0} tiles loaded", tileCount);
|
||||
handler.SendSysMessage(" {0} BVTree nodes", nodeCount);
|
||||
handler.SendSysMessage(" {0} polygons ({1} vertices)", polyCount, vertCount);
|
||||
handler.SendSysMessage(" {0} triangles ({1} vertices)", triCount, triVertCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("testarea", RBACPermissions.CommandMmapTestarea)]
|
||||
static bool TestArea(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
float radius = 40.0f;
|
||||
WorldObject obj = handler.GetPlayer();
|
||||
|
||||
// Get Creatures
|
||||
List<Unit> creatureList = new List<Unit>();
|
||||
|
||||
var go_check = new AnyUnitInObjectRangeCheck(obj, radius);
|
||||
var go_search = new UnitListSearcher(obj, creatureList, go_check);
|
||||
|
||||
Cell.VisitGridObjects(obj, go_search, radius);
|
||||
if (!creatureList.Empty())
|
||||
{
|
||||
handler.SendSysMessage("Found {0} Creatures.", creatureList.Count);
|
||||
|
||||
uint paths = 0;
|
||||
uint uStartTime = Time.GetMSTime();
|
||||
|
||||
float gx, gy, gz;
|
||||
obj.GetPosition(out gx, out gy, out gz);
|
||||
foreach (var creature in creatureList)
|
||||
{
|
||||
PathGenerator path = new PathGenerator(creature);
|
||||
path.CalculatePath(gx, gy, gz);
|
||||
++paths;
|
||||
}
|
||||
|
||||
uint uPathLoadTime = Time.GetMSTimeDiffToNow(uStartTime);
|
||||
handler.SendSysMessage("Generated {0} paths in {1} ms", paths, uPathLoadTime);
|
||||
}
|
||||
else
|
||||
handler.SendSysMessage("No creatures in {0} yard range.", radius);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
class MessageCommands
|
||||
{
|
||||
[CommandNonGroup("nameannounce", RBACPermissions.CommandNameannounce, true)]
|
||||
static bool HandleNameAnnounceCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string name = "Console";
|
||||
WorldSession session = handler.GetSession();
|
||||
if (session)
|
||||
name = session.GetPlayer().GetName();
|
||||
|
||||
Global.WorldMgr.SendWorldText(CypherStrings.AnnounceColor, name, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandNonGroup("gmnameannounce", RBACPermissions.CommandGmnameannounce, true)]
|
||||
static bool HandleGMNameAnnounceCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string name = "Console";
|
||||
WorldSession session = handler.GetSession();
|
||||
if (session)
|
||||
name = session.GetPlayer().GetName();
|
||||
|
||||
Global.WorldMgr.SendGMText(CypherStrings.AnnounceColor, name, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandNonGroup("announce", RBACPermissions.CommandAnnounce, true)]
|
||||
static bool HandleAnnounceCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string str = handler.GetParsedString(CypherStrings.Systemmessage, args.NextString(""));
|
||||
Global.WorldMgr.SendServerMessage(ServerMessageType.String, str);
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandNonGroup("gmannounce", RBACPermissions.CommandGmannounce, true)]
|
||||
static bool HandleGMAnnounceCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Global.WorldMgr.SendGMText(CypherStrings.GmBroadcast, args.NextString(""));
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandNonGroup("notify", RBACPermissions.CommandNotify, true)]
|
||||
static bool HandleNotifyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string str = handler.GetCypherString(CypherStrings.GlobalNotify);
|
||||
str += args.NextString("");
|
||||
|
||||
Global.WorldMgr.SendGlobalMessage(new PrintNotification(str));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandNonGroup("gmnotify", RBACPermissions.CommandGmnotify, true)]
|
||||
static bool HandleGMNotifyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string str = handler.GetCypherString(CypherStrings.GmNotify);
|
||||
str += args.NextString("");
|
||||
|
||||
Global.WorldMgr.SendGlobalGMMessage(new PrintNotification(str));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandNonGroup("whispers", RBACPermissions.CommandWhispers)]
|
||||
static bool HandleWhispersCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandWhisperaccepting, handler.GetSession().GetPlayer().isAcceptWhispers() ? handler.GetCypherString(CypherStrings.On) : handler.GetCypherString(CypherStrings.Off));
|
||||
return true;
|
||||
}
|
||||
|
||||
string argStr = args.NextString();
|
||||
// whisper on
|
||||
if (argStr == "on")
|
||||
{
|
||||
handler.GetSession().GetPlayer().SetAcceptWhispers(true);
|
||||
handler.SendSysMessage(CypherStrings.CommandWhisperon);
|
||||
return true;
|
||||
}
|
||||
|
||||
// whisper off
|
||||
if (argStr == "off")
|
||||
{
|
||||
// Remove all players from the Gamemaster's whisper whitelist
|
||||
handler.GetSession().GetPlayer().ClearWhisperWhiteList();
|
||||
handler.GetSession().GetPlayer().SetAcceptWhispers(false);
|
||||
handler.SendSysMessage(CypherStrings.CommandWhisperoff);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argStr == "remove")
|
||||
{
|
||||
string name = args.NextString();
|
||||
if (ObjectManager.NormalizePlayerName(ref name))
|
||||
{
|
||||
Player player = Global.ObjAccessor.FindPlayerByName(name);
|
||||
if (player)
|
||||
{
|
||||
handler.GetSession().GetPlayer().RemoveFromWhisperWhiteList(player.GetGUID());
|
||||
handler.SendSysMessage(CypherStrings.CommandWhisperoffplayer, name);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("channel", RBACPermissions.CommandChannel, true)]
|
||||
class ChannelCommands
|
||||
{
|
||||
[CommandGroup("set", RBACPermissions.CommandChannelSet, true)]
|
||||
class ChannelSetCommands
|
||||
{
|
||||
[Command("ownership", RBACPermissions.CommandChannelSetOwnership)]
|
||||
static bool HandleChannelSetOwnership(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string channelStr = args.NextString();
|
||||
string argStr = args.NextString("");
|
||||
|
||||
if (channelStr.IsEmpty() || argStr.IsEmpty())
|
||||
return false;
|
||||
|
||||
uint channelId = 0;
|
||||
foreach (var channelEntry in CliDB.ChatChannelsStorage.Values)
|
||||
{
|
||||
if (channelEntry.Name[handler.GetSessionDbcLocale()].Equals(channelStr))
|
||||
{
|
||||
channelId = channelEntry.Id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AreaTableRecord zoneEntry = null;
|
||||
foreach (var entry in CliDB.AreaTableStorage.Values)
|
||||
{
|
||||
if (entry.AreaName[handler.GetSessionDbcLocale()].Equals(channelStr))
|
||||
{
|
||||
zoneEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
Channel channel = null;
|
||||
|
||||
ChannelManager cMgr = ChannelManager.ForTeam(player.GetTeam());
|
||||
if (cMgr != null)
|
||||
channel = cMgr.GetChannel(channelId, channelStr, player, false, zoneEntry);
|
||||
|
||||
if (argStr.ToLower() == "on")
|
||||
{
|
||||
if (channel != null)
|
||||
channel.SetOwnership(true);
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHANNEL_OWNERSHIP);
|
||||
stmt.AddValue(0, 1);
|
||||
stmt.AddValue(1, channelStr);
|
||||
DB.Characters.Execute(stmt);
|
||||
handler.SendSysMessage(CypherStrings.ChannelEnableOwnership, channelStr);
|
||||
}
|
||||
else if (argStr.ToLower() == "off")
|
||||
{
|
||||
if (channel != null)
|
||||
channel.SetOwnership(false);
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHANNEL_OWNERSHIP);
|
||||
stmt.AddValue(0, 0);
|
||||
stmt.AddValue(1, channelStr);
|
||||
DB.Characters.Execute(stmt);
|
||||
handler.SendSysMessage(CypherStrings.ChannelDisableOwnership, channelStr);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,868 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Network.Packets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("modify", RBACPermissions.CommandModify)]
|
||||
class ModifyCommand
|
||||
{
|
||||
[Command("hp", RBACPermissions.CommandModifyHp)]
|
||||
static bool HandleModifyHPCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
int hp, hpmax = 0;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (CheckModifyResources(args, handler, target, out hp, out hpmax))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeHp, CypherStrings.YoursHpChanged, hp, hpmax);
|
||||
target.SetMaxHealth((uint)hpmax);
|
||||
target.SetHealth((uint)hp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("mana", RBACPermissions.CommandModifyMana)]
|
||||
static bool HandleModifyManaCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
int mana, manamax;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
|
||||
if (CheckModifyResources(args, handler, target, out mana, out manamax))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeMana, CypherStrings.YoursManaChanged, mana, manamax);
|
||||
target.SetMaxPower(PowerType.Mana, manamax);
|
||||
target.SetPower(PowerType.Mana, mana);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("energy", RBACPermissions.CommandModifyEnergy)]
|
||||
static bool HandleModifyEnergyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
int energy, energymax;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
byte energyMultiplier = 10;
|
||||
if (CheckModifyResources(args, handler, target, out energy, out energymax, energyMultiplier))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeEnergy, CypherStrings.YoursEnergyChanged, energy / energyMultiplier, energymax / energyMultiplier);
|
||||
target.SetMaxPower(PowerType.Energy, energymax);
|
||||
target.SetPower(PowerType.Energy, energy);
|
||||
Log.outDebug(LogFilter.Misc, handler.GetCypherString(CypherStrings.CurrentEnergy), target.GetMaxPower(PowerType.Energy));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("rage", RBACPermissions.CommandModifyRage)]
|
||||
static bool HandleModifyRageCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
int rage, ragemax;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
byte rageMultiplier = 10;
|
||||
if (CheckModifyResources(args, handler, target, out rage, out ragemax, rageMultiplier))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeRage, CypherStrings.YoursRageChanged, rage / rageMultiplier, ragemax / rageMultiplier);
|
||||
target.SetMaxPower(PowerType.Rage, ragemax);
|
||||
target.SetPower(PowerType.Rage, rage);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("runicpower", RBACPermissions.CommandModifyRunicpower)]
|
||||
static bool HandleModifyRunicPowerCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
int rune, runemax;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
byte runeMultiplier = 10;
|
||||
if (CheckModifyResources(args, handler, target, out rune, out runemax, runeMultiplier))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeRunicPower, CypherStrings.YoursRunicPowerChanged, rune / runeMultiplier, runemax / runeMultiplier);
|
||||
target.SetMaxPower(PowerType.RunicPower, runemax);
|
||||
target.SetPower(PowerType.RunicPower, rune);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("faction", RBACPermissions.CommandModifyFaction)]
|
||||
static bool HandleModifyFactionCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
string pfactionid = handler.extractKeyFromLink(args, "Hfaction");
|
||||
|
||||
Creature target = handler.getSelectedCreature();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectCreature);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(pfactionid))
|
||||
{
|
||||
uint _factionid = target.getFaction();
|
||||
uint _flag = target.GetUInt32Value(UnitFields.Flags);
|
||||
ulong _npcflag = target.GetUInt64Value(UnitFields.NpcFlags);
|
||||
uint _dyflag = target.GetUInt32Value(ObjectFields.DynamicFlags);
|
||||
handler.SendSysMessage(CypherStrings.CurrentFaction, target.GetGUID().ToString(), _factionid, _flag, _npcflag, _dyflag);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint factionid = uint.Parse(pfactionid);
|
||||
uint flag;
|
||||
|
||||
string pflag = args.NextString();
|
||||
if (string.IsNullOrEmpty(pflag))
|
||||
flag = target.GetUInt32Value(UnitFields.Flags);
|
||||
else
|
||||
flag = uint.Parse(pflag);
|
||||
|
||||
string pnpcflag = args.NextString();
|
||||
|
||||
ulong npcflag;
|
||||
if (string.IsNullOrEmpty(pnpcflag))
|
||||
npcflag = target.GetUInt64Value(UnitFields.NpcFlags);
|
||||
else
|
||||
npcflag = ulong.Parse(pnpcflag);
|
||||
|
||||
string pdyflag = args.NextString();
|
||||
|
||||
uint dyflag;
|
||||
if (string.IsNullOrEmpty(pdyflag))
|
||||
dyflag = target.GetUInt32Value(ObjectFields.DynamicFlags);
|
||||
else
|
||||
dyflag = uint.Parse(pdyflag);
|
||||
|
||||
if (!CliDB.FactionTemplateStorage.ContainsKey(factionid))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.WrongFaction, factionid);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.YouChangeFaction, target.GetGUID().ToString(), factionid, flag, npcflag, dyflag);
|
||||
|
||||
target.SetFaction(factionid);
|
||||
target.SetUInt32Value(UnitFields.Flags, flag);
|
||||
target.SetUInt64Value(UnitFields.NpcFlags, npcflag);
|
||||
target.SetUInt32Value(ObjectFields.DynamicFlags, dyflag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("spell", RBACPermissions.CommandModifySpell)]
|
||||
static bool HandleModifySpellCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
byte spellflatid = args.NextByte();
|
||||
if (spellflatid == 0)
|
||||
return false;
|
||||
|
||||
byte op = args.NextByte();
|
||||
if (op == 0)
|
||||
return false;
|
||||
|
||||
ushort val = args.NextUInt16();
|
||||
if (val == 0)
|
||||
return false;
|
||||
|
||||
ushort mark;
|
||||
|
||||
string pmark = args.NextString();
|
||||
if (string.IsNullOrEmpty(pmark))
|
||||
mark = 65535;
|
||||
else
|
||||
mark = ushort.Parse(pmark);
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
handler.SendSysMessage(CypherStrings.YouChangeSpellflatid, spellflatid, val, mark, handler.GetNameLink(target));
|
||||
if (handler.needReportToTarget(target))
|
||||
target.SendSysMessage(CypherStrings.YoursSpellflatidChanged, handler.GetNameLink(), spellflatid, val, mark);
|
||||
|
||||
SetSpellModifier packet = new SetSpellModifier(ServerOpcodes.SetFlatSpellModifier);
|
||||
SpellModifierInfo spellMod = new SpellModifierInfo();
|
||||
spellMod.ModIndex = op;
|
||||
SpellModifierData modData;
|
||||
modData.ClassIndex = spellflatid;
|
||||
modData.ModifierValue = val;
|
||||
spellMod.ModifierData.Add(modData);
|
||||
packet.Modifiers.Add(spellMod);
|
||||
target.SendPacket(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("talentpoints", RBACPermissions.CommandModifyTalentpoints)]
|
||||
static bool HandleModifyTalentCommand(StringArguments args, CommandHandler handler) { return false; }
|
||||
|
||||
[Command("scale", RBACPermissions.CommandModifyScale)]
|
||||
static bool HandleModifyScaleCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
float Scale;
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (CheckModifySpeed(args, handler, target, out Scale, 0.1f, 10.0f, false))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeSize, CypherStrings.YoursSizeChanged, Scale);
|
||||
target.SetObjectScale(Scale);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("mount", RBACPermissions.CommandModifyMount)]
|
||||
static bool HandleModifyMountCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string mountStr = args.NextString();
|
||||
if (mountStr.IsEmpty())
|
||||
return false;
|
||||
|
||||
if (uint.TryParse(mountStr, out uint mount))
|
||||
return false;
|
||||
|
||||
if (!CliDB.CreatureDisplayInfoStorage.HasRecord(mount))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoMount);
|
||||
return false;
|
||||
}
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
float speed;
|
||||
if (!CheckModifySpeed(args, handler, target, out speed, 0.1f, 50.0f))
|
||||
return false;
|
||||
|
||||
NotifyModification(handler, target, CypherStrings.YouGiveMount, CypherStrings.MountGived);
|
||||
target.Mount(mount);
|
||||
target.SetSpeedRate(UnitMoveType.Run, speed);
|
||||
target.SetSpeedRate(UnitMoveType.Flight, speed);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("money", RBACPermissions.CommandModifyMoney)]
|
||||
static bool HandleModifyMoneyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
long moneyToAdd = args.NextInt64();
|
||||
ulong targetMoney = target.GetMoney();
|
||||
|
||||
if (moneyToAdd < 0)
|
||||
{
|
||||
ulong newmoney = (targetMoney + (ulong)moneyToAdd);
|
||||
|
||||
Log.outDebug(LogFilter.ChatSystem, Global.ObjectMgr.GetCypherString(CypherStrings.CurrentMoney), targetMoney, moneyToAdd, newmoney);
|
||||
if (newmoney <= 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.YouTakeAllMoney, handler.GetNameLink(target));
|
||||
if (handler.needReportToTarget(target))
|
||||
target.SendSysMessage(CypherStrings.YoursAllMoneyGone, handler.GetNameLink());
|
||||
|
||||
target.SetMoney(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong moneyToAddMsg = (ulong)(moneyToAdd * -1);
|
||||
if (newmoney > PlayerConst.MaxMoneyAmount)
|
||||
newmoney = PlayerConst.MaxMoneyAmount;
|
||||
|
||||
handler.SendSysMessage(CypherStrings.YouTakeMoney, Math.Abs(moneyToAdd), handler.GetNameLink(target));
|
||||
if (handler.needReportToTarget(target))
|
||||
target.SendSysMessage(CypherStrings.YoursMoneyTaken, handler.GetNameLink(), Math.Abs(moneyToAdd));
|
||||
target.SetMoney(newmoney);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.YouGiveMoney, moneyToAdd, handler.GetNameLink(target));
|
||||
if (handler.needReportToTarget(target))
|
||||
target.SendSysMessage(CypherStrings.YoursMoneyGiven, handler.GetNameLink(), moneyToAdd);
|
||||
|
||||
if ((ulong)moneyToAdd >= PlayerConst.MaxMoneyAmount)
|
||||
moneyToAdd = Convert.ToInt64(PlayerConst.MaxMoneyAmount);
|
||||
|
||||
moneyToAdd = Math.Min(moneyToAdd, (long)(PlayerConst.MaxMoneyAmount - targetMoney));
|
||||
|
||||
target.ModifyMoney(moneyToAdd);
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.ChatSystem, Global.ObjectMgr.GetCypherString(CypherStrings.NewMoney), targetMoney, moneyToAdd, target.GetMoney());
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("bit", RBACPermissions.CommandModifyBit)]
|
||||
static bool HandleModifyBitCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
if (target.IsTypeId(TypeId.Player) && handler.HasLowerSecurity(target.ToPlayer(), ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
ushort field = args.NextUInt16();
|
||||
int bit = args.NextInt32();
|
||||
|
||||
if (field < (int)ObjectFields.End || field >= target.valuesCount)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
if (bit < 1 || bit > 32)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target.HasFlag(field, (1 << (bit - 1))))
|
||||
{
|
||||
target.RemoveFlag(field, (1 << (bit - 1)));
|
||||
handler.SendSysMessage(CypherStrings.RemoveBit, bit, field);
|
||||
}
|
||||
else
|
||||
{
|
||||
target.SetFlag(field, (1 << (bit - 1)));
|
||||
handler.SendSysMessage(CypherStrings.SetBit, bit, field);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("honor", RBACPermissions.CommandModifyHonor)]
|
||||
static bool HandleModifyHonorCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
int amount = args.NextInt32();
|
||||
|
||||
//target.ModifyCurrency(CurrencyTypes.HonorPoints, amount, true, true);
|
||||
handler.SendSysMessage("NOT IMPLEMENTED: {0} honor NOT added.", amount);
|
||||
|
||||
//handler.SendSysMessage(CypherStrings.CommandModifyHonor, handler.GetNameLink(target), target.GetCurrency((uint)CurrencyTypes.HonorPoints));
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("drunk", RBACPermissions.CommandModifyDrunk)]
|
||||
static bool HandleModifyDrunkCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
byte drunklevel = args.NextByte();
|
||||
if (drunklevel > 100)
|
||||
drunklevel = 100;
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (target)
|
||||
target.SetDrunkValue(drunklevel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("reputation", RBACPermissions.CommandModifyReputation)]
|
||||
static bool HandleModifyRepCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
string factionTxt = handler.extractKeyFromLink(args, "Hfaction");
|
||||
if (string.IsNullOrEmpty(factionTxt))
|
||||
return false;
|
||||
|
||||
uint factionId = uint.Parse(factionTxt);
|
||||
|
||||
int amount = 0;
|
||||
string rankTxt = args.NextString();
|
||||
if (factionId == 0 || rankTxt.IsEmpty())
|
||||
return false;
|
||||
|
||||
amount = int.Parse(rankTxt);
|
||||
if ((amount == 0) && !(amount < 0) && !rankTxt.IsNumber())
|
||||
{
|
||||
string rankStr = rankTxt.ToLower();
|
||||
|
||||
int r = 0;
|
||||
amount = -42000;
|
||||
for (; r < (int)ReputationRank.Max; ++r)
|
||||
{
|
||||
string rank = handler.GetCypherString(ReputationMgr.ReputationRankStrIndex[r]);
|
||||
if (string.IsNullOrEmpty(rank))
|
||||
continue;
|
||||
|
||||
if (rank.Equals(rankStr))
|
||||
{
|
||||
string deltaTxt = args.NextString();
|
||||
if (!string.IsNullOrEmpty(deltaTxt))
|
||||
{
|
||||
int delta = int.Parse(deltaTxt);
|
||||
if ((delta < 0) || (delta > ReputationMgr.PointsInRank[r] - 1))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandFactionDelta, (ReputationMgr.PointsInRank[r] - 1));
|
||||
return false;
|
||||
}
|
||||
amount += delta;
|
||||
}
|
||||
break;
|
||||
}
|
||||
amount += ReputationMgr.PointsInRank[r];
|
||||
}
|
||||
if (r >= (int)ReputationRank.Max)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandFactionInvparam, rankTxt);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(factionId);
|
||||
if (factionEntry == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandFactionUnknown, factionId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (factionEntry.ReputationIndex < 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandFactionNorepError, factionEntry.Name[handler.GetSessionDbcLocale()], factionId);
|
||||
return false;
|
||||
}
|
||||
|
||||
target.GetReputationMgr().SetOneFactionReputation(factionEntry, amount, false);
|
||||
target.GetReputationMgr().SendState(target.GetReputationMgr().GetState(factionEntry));
|
||||
handler.SendSysMessage(CypherStrings.CommandModifyRep, factionEntry.Name[handler.GetSessionDbcLocale()], factionId, handler.GetNameLink(target), target.GetReputationMgr().GetReputation(factionEntry));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("phase", RBACPermissions.CommandModifyPhase)]
|
||||
static bool HandleModifyPhaseCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint phaseId = args.NextUInt32();
|
||||
if (!CliDB.PhaseStorage.ContainsKey(phaseId))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PhaseNotfound);
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (!target)
|
||||
target = handler.GetSession().GetPlayer();
|
||||
|
||||
target.SetInPhase(phaseId, true, !target.IsInPhase(phaseId));
|
||||
|
||||
if (target.IsTypeId(TypeId.Player))
|
||||
target.ToPlayer().SendUpdatePhasing();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("standstate", RBACPermissions.CommandModifyStandstate)]
|
||||
static bool HandleModifyStandStateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint anim_id = args.NextUInt32();
|
||||
handler.GetSession().GetPlayer().SetUInt32Value(UnitFields.NpcEmotestate, anim_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("gender", RBACPermissions.CommandModifyGender)]
|
||||
static bool HandleModifyGenderCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerInfo info = Global.ObjectMgr.GetPlayerInfo(target.GetRace(), target.GetClass());
|
||||
if (info == null)
|
||||
return false;
|
||||
|
||||
string gender_str = args.NextString();
|
||||
Gender gender;
|
||||
|
||||
if (gender_str == "male") // MALE
|
||||
{
|
||||
if (target.GetGender() == Gender.Male)
|
||||
return true;
|
||||
|
||||
gender = Gender.Male;
|
||||
}
|
||||
else if (gender_str == "female") // FEMALE
|
||||
{
|
||||
if (target.GetGender() == Gender.Female)
|
||||
return true;
|
||||
|
||||
gender = Gender.Female;
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.MustMaleOrFemale);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set gender
|
||||
target.SetByteValue(UnitFields.Bytes0, 3, (byte)gender);
|
||||
target.SetByteValue(PlayerFields.Bytes3, PlayerFieldOffsets.Bytes3OffsetGender, (byte)gender);
|
||||
|
||||
// Change display ID
|
||||
target.InitDisplayIds();
|
||||
|
||||
handler.SendSysMessage(CypherStrings.YouChangeGender, handler.GetNameLink(target), gender);
|
||||
|
||||
if (handler.needReportToTarget(target))
|
||||
target.SendSysMessage(CypherStrings.YourGenderChanged, gender, handler.GetNameLink());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("currency", RBACPermissions.CommandModifyCurrency)]
|
||||
static bool HandleModifyCurrencyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint currencyId = args.NextUInt32();
|
||||
if (!CliDB.CurrencyTypesStorage.ContainsKey(currencyId))
|
||||
return false;
|
||||
|
||||
uint amount = args.NextUInt32();
|
||||
if (amount == 0)
|
||||
return false;
|
||||
|
||||
target.ModifyCurrency((CurrencyTypes)currencyId, (int)amount, true, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandNonGroup("morph", RBACPermissions.CommandMorph)]
|
||||
static bool HandleModifyMorphCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
uint display_id = args.NextUInt32();
|
||||
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (!target)
|
||||
target = handler.GetSession().GetPlayer();
|
||||
|
||||
// check online security
|
||||
else if (target.IsTypeId(TypeId.Player) && handler.HasLowerSecurity(target.ToPlayer(), ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
target.SetDisplayId(display_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandNonGroup("demorph", RBACPermissions.CommandDemorph)]
|
||||
static bool HandleDeMorphCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (!target)
|
||||
target = handler.GetSession().GetPlayer();
|
||||
|
||||
// check online security
|
||||
else if (target.IsTypeId(TypeId.Player) && handler.HasLowerSecurity(target.ToPlayer(), ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
target.DeMorph();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("xp", RBACPermissions.CommandModifyXp)]
|
||||
static bool HandleModifyXPCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
int xp = args.NextInt32();
|
||||
|
||||
if (xp < 1)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
// we can run the command
|
||||
target.GiveXP((uint)xp, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("speed", RBACPermissions.CommandModifySpeed)]
|
||||
class ModifySpeed
|
||||
{
|
||||
[Command("", RBACPermissions.CommandModifySpeed)]
|
||||
static bool HandleModifySpeedCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return HandleModifyASpeedCommand(args, handler);
|
||||
}
|
||||
|
||||
[Command("all", RBACPermissions.CommandModifySpeedAll)]
|
||||
static bool HandleModifyASpeedCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
float allSpeed;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (CheckModifySpeed(args, handler, target, out allSpeed, 0.1f, 50.0f))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeAspeed, CypherStrings.YoursAspeedChanged, allSpeed);
|
||||
target.SetSpeedRate(UnitMoveType.Walk, allSpeed);
|
||||
target.SetSpeedRate(UnitMoveType.Run, allSpeed);
|
||||
target.SetSpeedRate(UnitMoveType.Swim, allSpeed);
|
||||
target.SetSpeedRate(UnitMoveType.Flight, allSpeed);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("swim", RBACPermissions.CommandModifySpeedSwim)]
|
||||
static bool HandleModifySwimCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
float swimSpeed;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (CheckModifySpeed(args, handler, target, out swimSpeed, 0.1f, 50.0f))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeSwimSpeed, CypherStrings.YoursSwimSpeedChanged, swimSpeed);
|
||||
target.SetSpeedRate(UnitMoveType.Swim, swimSpeed);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("backwalk", RBACPermissions.CommandModifySpeedBackwalk)]
|
||||
static bool HandleModifyBWalkCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
float backSpeed;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (CheckModifySpeed(args, handler, target, out backSpeed, 0.1f, 50.0f))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeBackSpeed, CypherStrings.YoursBackSpeedChanged, backSpeed);
|
||||
target.SetSpeedRate(UnitMoveType.RunBack, backSpeed);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("fly", RBACPermissions.CommandModifySpeedFly)]
|
||||
static bool HandleModifyFlyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
float flySpeed;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (CheckModifySpeed(args, handler, target, out flySpeed, 0.1f, 50.0f, false))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeFlySpeed, CypherStrings.YoursFlySpeedChanged, flySpeed);
|
||||
target.SetSpeedRate(UnitMoveType.Flight, flySpeed);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("walk", RBACPermissions.CommandModifySpeedWalk)]
|
||||
static bool HandleModifyWalkSpeedCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
float Speed;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (CheckModifySpeed(args, handler, target, out Speed, 0.1f, 50.0f))
|
||||
{
|
||||
NotifyModification(handler, target, CypherStrings.YouChangeSpeed, CypherStrings.YoursSpeedChanged, Speed);
|
||||
target.SetSpeedRate(UnitMoveType.Run, Speed);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void NotifyModification(CommandHandler handler, Unit target, CypherStrings resourceMessage, CypherStrings resourceReportMessage, params object[] args)
|
||||
{
|
||||
Player player = target.ToPlayer();
|
||||
if (player)
|
||||
{
|
||||
handler.SendSysMessage(resourceMessage, new object[] { handler.GetNameLink(player) }.Combine(args));
|
||||
if (handler.needReportToTarget(player))
|
||||
player.SendSysMessage(resourceReportMessage, new object[] { handler.GetNameLink() }.Combine(args));
|
||||
}
|
||||
}
|
||||
|
||||
static bool CheckModifyResources(StringArguments args, CommandHandler handler, Player target, out int res, out int resmax, byte multiplier = 1)
|
||||
{
|
||||
res = 0;
|
||||
resmax = 0;
|
||||
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
res = args.NextInt32() * multiplier;
|
||||
resmax = args.NextInt32() * multiplier;
|
||||
|
||||
if (resmax == 0)
|
||||
resmax = res;
|
||||
|
||||
if (res < 1 || resmax < 1 || resmax < res)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (handler.HasLowerSecurity(target, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CheckModifySpeed(StringArguments args, CommandHandler handler, Unit target, out float speed, float minimumBound, float maximumBound, bool checkInFlight = true)
|
||||
{
|
||||
speed = 0f;
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
speed = args.NextSingle();
|
||||
|
||||
if (speed > maximumBound || speed < minimumBound)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
Player player = target.ToPlayer();
|
||||
if (player)
|
||||
{
|
||||
// check online security
|
||||
if (handler.HasLowerSecurity(player, ObjectGuid.Empty))
|
||||
return false;
|
||||
|
||||
if (player.IsInFlight() && checkInFlight)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CharInFlight, handler.GetNameLink(player));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using Game.Spells;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("pet", RBACPermissions.CommandPet)]
|
||||
class PetCommands
|
||||
{
|
||||
[Command("create", RBACPermissions.CommandPetCreate)]
|
||||
static bool HandlePetCreateCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
Creature creatureTarget = handler.getSelectedCreature();
|
||||
|
||||
if (!creatureTarget || creatureTarget.IsPet() || creatureTarget.IsTypeId(TypeId.Player))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectCreature);
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureTemplate creatureTemplate = creatureTarget.GetCreatureTemplate();
|
||||
// Creatures with family CreatureFamily.None crashes the server
|
||||
if (creatureTemplate.Family == CreatureFamily.None)
|
||||
{
|
||||
handler.SendSysMessage("This creature cannot be tamed. (Family id: 0).");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!player.GetPetGUID().IsEmpty())
|
||||
{
|
||||
handler.SendSysMessage("You already have a pet");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything looks OK, create new pet
|
||||
Pet pet = new Pet(player, PetType.Hunter);
|
||||
if (!pet.CreateBaseAtCreature(creatureTarget))
|
||||
{
|
||||
handler.SendSysMessage("Error 1");
|
||||
return false;
|
||||
}
|
||||
|
||||
creatureTarget.setDeathState(DeathState.JustDied);
|
||||
creatureTarget.RemoveCorpse();
|
||||
creatureTarget.SetHealth(0); // just for nice GM-mode view
|
||||
|
||||
pet.SetGuidValue(UnitFields.CreatedBy, player.GetGUID());
|
||||
pet.SetUInt32Value(UnitFields.FactionTemplate, player.getFaction());
|
||||
|
||||
if (!pet.InitStatsForLevel(creatureTarget.getLevel()))
|
||||
{
|
||||
Log.outError(LogFilter.ChatSystem, "InitStatsForLevel() in EffectTameCreature failed! Pet deleted.");
|
||||
handler.SendSysMessage("Error 2");
|
||||
return false;
|
||||
}
|
||||
|
||||
// prepare visual effect for levelup
|
||||
pet.SetUInt32Value(UnitFields.Level, creatureTarget.getLevel() - 1);
|
||||
|
||||
pet.GetCharmInfo().SetPetNumber(Global.ObjectMgr.GeneratePetNumber(), true);
|
||||
// this enables pet details window (Shift+P)
|
||||
pet.InitPetCreateSpells();
|
||||
pet.SetFullHealth();
|
||||
|
||||
pet.GetMap().AddToMap(pet.ToCreature());
|
||||
|
||||
// visual effect for levelup
|
||||
pet.SetUInt32Value(UnitFields.Level, creatureTarget.getLevel());
|
||||
|
||||
player.SetMinion(pet, true);
|
||||
pet.SavePetToDB(PetSaveMode.AsCurrent);
|
||||
player.PetSpellInitialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("learn", RBACPermissions.CommandPetLearn)]
|
||||
static bool HandlePetLearnCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Pet pet = GetSelectedPlayerPetOrOwn(handler);
|
||||
if (!pet)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectPlayerOrPet);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
if (spellId == 0 || !Global.SpellMgr.HasSpellInfo(spellId))
|
||||
return false;
|
||||
|
||||
// Check if pet already has it
|
||||
if (pet.HasSpell(spellId))
|
||||
{
|
||||
handler.SendSysMessage("Pet already has spell: {0}", spellId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if spell is valid
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId);
|
||||
if (spellInfo == null || !Global.SpellMgr.IsSpellValid(spellInfo))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandSpellBroken, spellId);
|
||||
return false;
|
||||
}
|
||||
|
||||
pet.learnSpell(spellId);
|
||||
|
||||
handler.SendSysMessage("Pet has learned spell {0}", spellId);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("unlearn", RBACPermissions.CommandPetUnlearn)]
|
||||
static bool HandlePetUnlearnCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Pet pet = GetSelectedPlayerPetOrOwn(handler);
|
||||
if (!pet)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectPlayerOrPet);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint spellId = handler.extractSpellIdFromLink(args);
|
||||
|
||||
if (pet.HasSpell(spellId))
|
||||
pet.removeSpell(spellId, false);
|
||||
else
|
||||
handler.SendSysMessage("Pet doesn't have that spell");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("level", RBACPermissions.CommandPetLevel)]
|
||||
static bool HandlePetLevelCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Pet pet = GetSelectedPlayerPetOrOwn(handler);
|
||||
Player owner = pet ? pet.GetOwner() : null;
|
||||
if (!pet || !owner)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.SelectPlayerOrPet);
|
||||
return false;
|
||||
}
|
||||
|
||||
int level = args.NextInt32();
|
||||
if (level == 0)
|
||||
level = (int)(owner.getLevel() - pet.getLevel());
|
||||
if (level == 0 || level < -SharedConst.StrongMaxLevel || level > SharedConst.StrongMaxLevel)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.BadValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
int newLevel = (int)pet.getLevel() + level;
|
||||
if (newLevel < 1)
|
||||
newLevel = 1;
|
||||
else if (newLevel > owner.getLevel())
|
||||
newLevel = (int)owner.getLevel();
|
||||
|
||||
pet.GivePetLevel(newLevel);
|
||||
return true;
|
||||
}
|
||||
|
||||
static Pet GetSelectedPlayerPetOrOwn(CommandHandler handler)
|
||||
{
|
||||
Unit target = handler.getSelectedUnit();
|
||||
if (target)
|
||||
{
|
||||
if (target.IsTypeId(TypeId.Player))
|
||||
return target.ToPlayer().GetPet();
|
||||
if (target.IsPet())
|
||||
return target.ToPet();
|
||||
return null;
|
||||
}
|
||||
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
return player ? player.GetPet() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("quest", RBACPermissions.CommandQuest)]
|
||||
class QuestCommands
|
||||
{
|
||||
[Command("add", RBACPermissions.CommandQuestAdd)]
|
||||
static bool Add(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
// .addquest #entry'
|
||||
// number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r
|
||||
string cId = handler.extractKeyFromLink(args, "Hquest");
|
||||
if (string.IsNullOrEmpty(cId))
|
||||
return false;
|
||||
|
||||
uint entry = uint.Parse(cId);
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(entry);
|
||||
if (quest == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandQuestNotfound, entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check item starting quest (it can work incorrectly if added without item in inventory)
|
||||
var itc = Global.ObjectMgr.GetItemTemplates();
|
||||
var result = itc.Values.FirstOrDefault(p => p.GetStartQuest() == entry);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandQuestStartfromitem, entry, result.GetId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// ok, normal (creature/GO starting) quest
|
||||
if (player.CanAddQuest(quest, true))
|
||||
player.AddQuestAndCheckCompletion(quest, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("complete", RBACPermissions.CommandQuestComplete)]
|
||||
static bool Complete(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
// .quest complete #entry
|
||||
// number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r
|
||||
string cId = handler.extractKeyFromLink(args, "Hquest");
|
||||
if (string.IsNullOrEmpty(cId))
|
||||
return false;
|
||||
|
||||
uint entry = uint.Parse(cId);
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(entry);
|
||||
|
||||
// If player doesn't have the quest
|
||||
if (quest == null || player.GetQuestStatus(entry) == QuestStatus.None)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandQuestNotfound, entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < quest.Objectives.Count; ++i)
|
||||
{
|
||||
QuestObjective obj = quest.Objectives[i];
|
||||
|
||||
switch (obj.Type)
|
||||
{
|
||||
case QuestObjectiveType.Item:
|
||||
{
|
||||
uint curItemCount = player.GetItemCount((uint)obj.ObjectID, true);
|
||||
List<ItemPosCount> dest = new List<ItemPosCount>();
|
||||
InventoryResult msg = player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, (uint)obj.ObjectID, (uint)(obj.Amount - curItemCount));
|
||||
if (msg == InventoryResult.Ok)
|
||||
{
|
||||
Item item = player.StoreNewItem(dest, (uint)obj.ObjectID, true);
|
||||
player.SendNewItem(item, (uint)(obj.Amount - curItemCount), true, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QuestObjectiveType.Monster:
|
||||
{
|
||||
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate((uint)obj.ObjectID);
|
||||
if (creatureInfo != null)
|
||||
for (int z = 0; z < obj.Amount; ++z)
|
||||
player.KilledMonster(creatureInfo, ObjectGuid.Empty);
|
||||
break;
|
||||
}
|
||||
case QuestObjectiveType.GameObject:
|
||||
{
|
||||
for (int z = 0; z < obj.Amount; ++z)
|
||||
player.KillCreditGO((uint)obj.ObjectID);
|
||||
break;
|
||||
}
|
||||
case QuestObjectiveType.MinReputation:
|
||||
{
|
||||
int curRep = player.GetReputationMgr().GetReputation((uint)obj.ObjectID);
|
||||
if (curRep < obj.Amount)
|
||||
{
|
||||
FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(obj.ObjectID);
|
||||
if (factionEntry != null)
|
||||
player.GetReputationMgr().SetReputation(factionEntry, obj.Amount);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QuestObjectiveType.MaxReputation:
|
||||
{
|
||||
int curRep = player.GetReputationMgr().GetReputation((uint)obj.ObjectID);
|
||||
if (curRep > obj.Amount)
|
||||
{
|
||||
FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(obj.ObjectID);
|
||||
if (factionEntry != null)
|
||||
player.GetReputationMgr().SetReputation(factionEntry, obj.Amount);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QuestObjectiveType.Money:
|
||||
{
|
||||
player.ModifyMoney(obj.Amount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
player.CompleteQuest(entry);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("remove", RBACPermissions.CommandQuestRemove)]
|
||||
static bool Remove(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
// .removequest #entry'
|
||||
// number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r
|
||||
string cId = handler.extractKeyFromLink(args, "Hquest");
|
||||
if (string.IsNullOrEmpty(cId))
|
||||
return false;
|
||||
|
||||
uint entry = uint.Parse(cId);
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(entry);
|
||||
if (quest == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandQuestNotfound, entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove all quest entries for 'entry' from quest log
|
||||
for (byte slot = 0; slot < SharedConst.MaxQuestLogSize; ++slot)
|
||||
{
|
||||
uint logQuest = player.GetQuestSlotQuestId(slot);
|
||||
if (logQuest == entry)
|
||||
{
|
||||
player.SetQuestSlot(slot, 0);
|
||||
|
||||
// we ignore unequippable quest items in this case, its' still be equipped
|
||||
player.TakeQuestSourceItem(logQuest, false);
|
||||
|
||||
if (quest.HasFlag(QuestFlags.Pvp))
|
||||
{
|
||||
player.pvpInfo.IsHostile = player.pvpInfo.IsInHostileArea || player.HasPvPForcingQuest();
|
||||
player.UpdatePvPState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.RemoveActiveQuest(entry, false);
|
||||
player.RemoveRewardedQuest(entry);
|
||||
|
||||
Global.ScriptMgr.OnQuestStatusChange(player, entry);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.CommandQuestRemoved);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("reward", RBACPermissions.CommandQuestReward)]
|
||||
static bool Reward(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
// .quest reward #entry
|
||||
// number or [name] Shift-click form |color|Hquest:quest_id:quest_level|h[name]|h|r
|
||||
string cId = handler.extractKeyFromLink(args, "Hquest");
|
||||
if (string.IsNullOrEmpty(cId))
|
||||
return false;
|
||||
|
||||
uint entry = uint.Parse(cId);
|
||||
|
||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(entry);
|
||||
|
||||
// If player doesn't have the quest
|
||||
if (quest == null || player.GetQuestStatus(entry) != QuestStatus.Complete)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandQuestNotfound, entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
player.RewardQuest(quest, 0, player);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.Accounts;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("rbac", RBACPermissions.CommandRbac, true)]
|
||||
class RbacComands
|
||||
{
|
||||
[Command("list", RBACPermissions.CommandRbacList, true)]
|
||||
static bool HandleRBACListPermissionsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint id = args.NextUInt32();
|
||||
|
||||
if (id == 0)
|
||||
{
|
||||
var permissions = Global.AccountMgr.GetRBACPermissionList();
|
||||
handler.SendSysMessage(CypherStrings.RbacListPermissionsHeader);
|
||||
foreach (var permission in permissions.Values)
|
||||
handler.SendSysMessage(CypherStrings.RbacListElement, permission.GetId(), permission.GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(id);
|
||||
if (permission == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.RbacWrongParameterId, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.RbacListPermissionsHeader);
|
||||
handler.SendSysMessage(CypherStrings.RbacListElement, permission.GetId(), permission.GetName());
|
||||
handler.SendSysMessage(CypherStrings.RbacListPermsLinkedHeader);
|
||||
var permissions = permission.GetLinkedPermissions();
|
||||
foreach (var permissionId in permissions)
|
||||
{
|
||||
RBACPermission rbacPermission = Global.AccountMgr.GetRBACPermission(permissionId);
|
||||
if (rbacPermission != null)
|
||||
handler.SendSysMessage(CypherStrings.RbacListElement, rbacPermission.GetId(), rbacPermission.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("account", RBACPermissions.CommandRbacAcc, true)]
|
||||
class RbacAccountCommands
|
||||
{
|
||||
[Command("grant", RBACPermissions.CommandRbacAccPermGrant, true)]
|
||||
static bool HandleRBACPermGrantCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
RBACCommandData command = ReadParams(args, handler);
|
||||
if (command == null)
|
||||
return false;
|
||||
|
||||
RBACCommandResult result = command.rbac.GrantPermission(command.id, command.realmId);
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(command.id);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case RBACCommandResult.CantAddAlreadyAdded:
|
||||
handler.SendSysMessage(CypherStrings.RbacPermGrantedInList, command.id, permission.GetName(),
|
||||
command.realmId, command.rbac.GetId(), command.rbac.GetName());
|
||||
break;
|
||||
case RBACCommandResult.InDeniedList:
|
||||
handler.SendSysMessage(CypherStrings.RbacPermGrantedInDeniedList, command.id, permission.GetName(),
|
||||
command.realmId, command.rbac.GetId(), command.rbac.GetName());
|
||||
break;
|
||||
case RBACCommandResult.OK:
|
||||
handler.SendSysMessage(CypherStrings.RbacPermGranted, command.id, permission.GetName(),
|
||||
command.realmId, command.rbac.GetId(), command.rbac.GetName());
|
||||
break;
|
||||
case RBACCommandResult.IdDoesNotExists:
|
||||
handler.SendSysMessage(CypherStrings.RbacWrongParameterId, command.id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("deny", RBACPermissions.CommandRbacAccPermDeny, true)]
|
||||
static bool HandleRBACPermDenyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
RBACCommandData command = ReadParams(args, handler);
|
||||
|
||||
if (command == null)
|
||||
return false;
|
||||
|
||||
RBACCommandResult result = command.rbac.DenyPermission(command.id, command.realmId);
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(command.id);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case RBACCommandResult.CantAddAlreadyAdded:
|
||||
handler.SendSysMessage(CypherStrings.RbacPermDeniedInList, command.id, permission.GetName(),
|
||||
command.realmId, command.rbac.GetId(), command.rbac.GetName());
|
||||
break;
|
||||
case RBACCommandResult.InGrantedList:
|
||||
handler.SendSysMessage(CypherStrings.RbacPermDeniedInGrantedList, command.id, permission.GetName(),
|
||||
command.realmId, command.rbac.GetId(), command.rbac.GetName());
|
||||
break;
|
||||
case RBACCommandResult.OK:
|
||||
handler.SendSysMessage(CypherStrings.RbacPermDenied, command.id, permission.GetName(),
|
||||
command.realmId, command.rbac.GetId(), command.rbac.GetName());
|
||||
break;
|
||||
case RBACCommandResult.IdDoesNotExists:
|
||||
handler.SendSysMessage(CypherStrings.RbacWrongParameterId, command.id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("revoke", RBACPermissions.CommandRbacAccPermRevoke, true)]
|
||||
static bool HandleRBACPermRevokeCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
RBACCommandData command = ReadParams(args, handler);
|
||||
|
||||
if (command == null)
|
||||
return false;
|
||||
|
||||
RBACCommandResult result = command.rbac.RevokePermission(command.id, command.realmId);
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(command.id);
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case RBACCommandResult.CantRevokeNotInList:
|
||||
handler.SendSysMessage(CypherStrings.RbacPermRevokedNotInList, command.id, permission.GetName(),
|
||||
command.realmId, command.rbac.GetId(), command.rbac.GetName());
|
||||
break;
|
||||
case RBACCommandResult.OK:
|
||||
handler.SendSysMessage(CypherStrings.RbacPermRevoked, command.id, permission.GetName(),
|
||||
command.realmId, command.rbac.GetId(), command.rbac.GetName());
|
||||
break;
|
||||
case RBACCommandResult.IdDoesNotExists:
|
||||
handler.SendSysMessage(CypherStrings.RbacWrongParameterId, command.id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("list", RBACPermissions.CommandRbacAccPermList, true)]
|
||||
static bool HandleRBACPermListCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
RBACCommandData command = ReadParams(args, handler, false);
|
||||
|
||||
if (command == null)
|
||||
return false;
|
||||
|
||||
handler.SendSysMessage(CypherStrings.RbacListHeaderGranted, command.rbac.GetId(), command.rbac.GetName());
|
||||
var granted = command.rbac.GetGrantedPermissions();
|
||||
if (granted.Empty())
|
||||
handler.SendSysMessage(CypherStrings.RbacListEmpty);
|
||||
else
|
||||
{
|
||||
foreach (var id in granted)
|
||||
{
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(id);
|
||||
handler.SendSysMessage(CypherStrings.RbacListElement, permission.GetId(), permission.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.RbacListHeaderDenied, command.rbac.GetId(), command.rbac.GetName());
|
||||
var denied = command.rbac.GetDeniedPermissions();
|
||||
if (denied.Empty())
|
||||
handler.SendSysMessage(CypherStrings.RbacListEmpty);
|
||||
else
|
||||
{
|
||||
foreach (var id in denied)
|
||||
{
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(id);
|
||||
handler.SendSysMessage(CypherStrings.RbacListElement, permission.GetId(), permission.GetName());
|
||||
}
|
||||
}
|
||||
handler.SendSysMessage(CypherStrings.RbacListHeaderBySecLevel, command.rbac.GetId(), command.rbac.GetName(), command.rbac.GetSecurityLevel());
|
||||
var defaultPermissions = Global.AccountMgr.GetRBACDefaultPermissions(command.rbac.GetSecurityLevel());
|
||||
if (defaultPermissions.Empty())
|
||||
handler.SendSysMessage(CypherStrings.RbacListEmpty);
|
||||
else
|
||||
{
|
||||
foreach (var id in defaultPermissions)
|
||||
{
|
||||
RBACPermission permission = Global.AccountMgr.GetRBACPermission(id);
|
||||
handler.SendSysMessage(CypherStrings.RbacListElement, permission.GetId(), permission.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static RBACCommandData ReadParams(StringArguments args, CommandHandler handler, bool checkParams = true)
|
||||
{
|
||||
if (args.Empty())
|
||||
return null;
|
||||
|
||||
string param1 = args.NextString();
|
||||
string param2 = args.NextString();
|
||||
string param3 = args.NextString();
|
||||
|
||||
int realmId = -1;
|
||||
uint accountId = 0;
|
||||
string accountName;
|
||||
uint id = 0;
|
||||
RBACCommandData data;
|
||||
RBACData rdata = null;
|
||||
bool useSelectedPlayer = false;
|
||||
|
||||
if (checkParams)
|
||||
{
|
||||
if (string.IsNullOrEmpty(param3))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(param2))
|
||||
realmId = int.Parse(param2);
|
||||
|
||||
if (!string.IsNullOrEmpty(param1))
|
||||
id = uint.Parse(param1);
|
||||
|
||||
useSelectedPlayer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
id = uint.Parse(param2);
|
||||
realmId = int.Parse(param3);
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.RbacWrongParameterId, id);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (realmId < -1 || realmId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.RbacWrongParameterRealm, realmId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (string.IsNullOrEmpty(param1))
|
||||
useSelectedPlayer = true;
|
||||
|
||||
if (useSelectedPlayer)
|
||||
{
|
||||
Player player = handler.getSelectedPlayer();
|
||||
if (!player)
|
||||
return null;
|
||||
|
||||
rdata = player.GetSession().GetRBACData();
|
||||
accountId = rdata.GetId();
|
||||
Global.AccountMgr.GetName(accountId, out accountName);
|
||||
}
|
||||
else
|
||||
{
|
||||
accountName = param1;
|
||||
accountId = Global.AccountMgr.GetId(accountName);
|
||||
|
||||
if (accountId == 0)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.AccountNotExist, accountName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkParams && handler.HasLowerSecurityAccount(null, accountId, true))
|
||||
return null;
|
||||
|
||||
data = new RBACCommandData();
|
||||
|
||||
if (rdata == null)
|
||||
{
|
||||
data.rbac = new RBACData(accountId, accountName, (int)Global.WorldMgr.GetRealm().Id.Realm, (byte)Global.AccountMgr.GetSecurity(accountId, (int)Global.WorldMgr.GetRealm().Id.Realm));
|
||||
data.rbac.LoadFromDB();
|
||||
data.needDelete = true;
|
||||
}
|
||||
else
|
||||
data.rbac = rdata;
|
||||
|
||||
data.id = id;
|
||||
data.realmId = realmId;
|
||||
return data;
|
||||
}
|
||||
|
||||
class RBACCommandData
|
||||
{
|
||||
public uint id;
|
||||
public int realmId;
|
||||
public RBACData rbac;
|
||||
public bool needDelete;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.Achievements;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("reset", RBACPermissions.CommandReset, true)]
|
||||
class ResetCommands
|
||||
{
|
||||
[Command("achievements", RBACPermissions.CommandResetAchievements, true)]
|
||||
static bool HandleResetAchievementsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid))
|
||||
return false;
|
||||
|
||||
if (target)
|
||||
target.ResetAchievements();
|
||||
else
|
||||
PlayerAchievementMgr.DeleteFromDB(targetGuid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("honor", RBACPermissions.CommandResetHonor, true)]
|
||||
static bool HandleResetHonorCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args, out target))
|
||||
return false;
|
||||
|
||||
target.SetUInt32Value(PlayerFields.Kills, 0);
|
||||
target.SetUInt32Value(PlayerFields.LifetimeHonorableKills, 0);
|
||||
target.UpdateCriteria(CriteriaTypes.EarnHonorableKill);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleResetStatsOrLevelHelper(Player player)
|
||||
{
|
||||
ChrClassesRecord classEntry = CliDB.ChrClassesStorage.LookupByKey(player.GetClass());
|
||||
if (classEntry == null)
|
||||
{
|
||||
Log.outError(LogFilter.Server, "Class {0} not found in DBC (Wrong DBC files?)", player.GetClass());
|
||||
return false;
|
||||
}
|
||||
|
||||
PowerType powerType = classEntry.PowerType;
|
||||
|
||||
// reset m_form if no aura
|
||||
if (!player.HasAuraType(AuraType.ModShapeshift))
|
||||
player.SetShapeshiftForm(ShapeShiftForm.None);
|
||||
|
||||
player.setFactionForRace(player.GetRace());
|
||||
player.SetUInt32Value(UnitFields.DisplayPower, (uint)powerType);
|
||||
|
||||
// reset only if player not in some form;
|
||||
if (player.GetShapeshiftForm() == ShapeShiftForm.None)
|
||||
player.InitDisplayIds();
|
||||
|
||||
player.SetByteValue(UnitFields.Bytes2, UnitBytes2Offsets.PvpFlag, (byte)UnitBytes2Flags.PvP);
|
||||
|
||||
player.SetUInt32Value(UnitFields.Flags, (uint)UnitFlags.PvpAttackable);
|
||||
|
||||
//-1 is default value
|
||||
player.SetUInt32Value(PlayerFields.WatchedFactionIndex, 0xFFFFFFFF);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("level", RBACPermissions.CommandResetLevel, true)]
|
||||
static bool HandleResetLevelCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args, out target))
|
||||
return false;
|
||||
|
||||
if (!HandleResetStatsOrLevelHelper(target))
|
||||
return false;
|
||||
|
||||
byte oldLevel = (byte)target.getLevel();
|
||||
|
||||
// set starting level
|
||||
uint startLevel = (uint)(target.GetClass() != Class.Deathknight ? WorldConfig.GetIntValue(WorldCfg.StartPlayerLevel) : WorldConfig.GetIntValue(WorldCfg.StartDeathKnightPlayerLevel));
|
||||
|
||||
target._ApplyAllLevelScaleItemMods(false);
|
||||
target.SetLevel(startLevel);
|
||||
target.InitRunes();
|
||||
target.InitStatsForLevel(true);
|
||||
target.InitTaxiNodesForLevel();
|
||||
target.InitTalentForLevel();
|
||||
target.SetUInt32Value(PlayerFields.Xp, 0);
|
||||
|
||||
target._ApplyAllLevelScaleItemMods(true);
|
||||
|
||||
// reset level for pet
|
||||
Pet pet = target.GetPet();
|
||||
if (pet)
|
||||
pet.SynchronizeLevelWithOwner();
|
||||
|
||||
Global.ScriptMgr.OnPlayerLevelChanged(target, oldLevel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("spells", RBACPermissions.CommandResetSpells, true)]
|
||||
static bool HandleResetSpellsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
if (target)
|
||||
{
|
||||
target.ResetSpells();
|
||||
|
||||
target.SendSysMessage(CypherStrings.ResetSpells);
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer() != target)
|
||||
handler.SendSysMessage(CypherStrings.ResetSpellsOnline, handler.GetNameLink(target));
|
||||
}
|
||||
else
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt.AddValue(0, (ushort)AtLoginFlags.ResetSpells);
|
||||
stmt.AddValue(1, targetGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ResetSpellsOffline, targetName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("stats", RBACPermissions.CommandResetStats, true)]
|
||||
static bool HandleResetStatsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
if (!handler.extractPlayerTarget(args, out target))
|
||||
return false;
|
||||
|
||||
if (!HandleResetStatsOrLevelHelper(target))
|
||||
return false;
|
||||
|
||||
target.InitRunes();
|
||||
target.InitStatsForLevel(true);
|
||||
target.InitTaxiNodesForLevel();
|
||||
target.InitTalentForLevel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("talents", RBACPermissions.CommandResetTalents, true)]
|
||||
static bool HandleResetTalentsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName))
|
||||
{
|
||||
/* TODO: 6.x remove/update pet talents
|
||||
// Try reset talents as Hunter Pet
|
||||
Creature* creature = handler.getSelectedCreature();
|
||||
if (!*args && creature && creature.IsPet())
|
||||
{
|
||||
Unit* owner = creature.GetOwner();
|
||||
if (owner && owner.GetTypeId() == TYPEID_PLAYER && creature.ToPet().IsPermanentPetFor(owner.ToPlayer()))
|
||||
{
|
||||
creature.ToPet().resetTalents();
|
||||
owner.ToPlayer().SendTalentsInfoData(true);
|
||||
|
||||
ChatHandler(owner.ToPlayer().GetSession()).SendSysMessage(LANG_RESET_PET_TALENTS);
|
||||
if (!handler.GetSession() || handler.GetSession().GetPlayer() != owner.ToPlayer())
|
||||
handler.PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE, handler.GetNameLink(owner.ToPlayer()).c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target)
|
||||
{
|
||||
target.ResetTalents(true);
|
||||
target.ResetTalentSpecialization();
|
||||
target.SendTalentsInfoData();
|
||||
target.SendSysMessage(CypherStrings.ResetTalents);
|
||||
if (handler.GetSession() == null || handler.GetSession().GetPlayer() != target)
|
||||
handler.SendSysMessage(CypherStrings.ResetTalentsOnline, handler.GetNameLink(target));
|
||||
|
||||
/* TODO: 6.x remove/update pet talents
|
||||
Pet* pet = target.GetPet();
|
||||
Pet.resetTalentsForAllPetsOf(target, pet);
|
||||
if (pet)
|
||||
target.SendTalentsInfoData(true);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
else if (!targetGuid.IsEmpty())
|
||||
{
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt.AddValue(0, (ushort)(AtLoginFlags.None | AtLoginFlags.ResetPetTalents));
|
||||
stmt.AddValue(1, targetGuid.GetCounter());
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
string nameLink = handler.playerLink(targetName);
|
||||
handler.SendSysMessage(CypherStrings.ResetTalentsOffline, nameLink);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.NoCharSelected);
|
||||
return false;
|
||||
}
|
||||
|
||||
[Command("all", RBACPermissions.CommandResetAll, true)]
|
||||
static bool HandleResetAllCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string caseName = args.NextString();
|
||||
|
||||
AtLoginFlags atLogin;
|
||||
|
||||
// Command specially created as single command to prevent using short case names
|
||||
if (caseName == "spells")
|
||||
{
|
||||
atLogin = AtLoginFlags.ResetSpells;
|
||||
Global.WorldMgr.SendWorldText(CypherStrings.ResetallSpells);
|
||||
if (handler.GetSession() == null)
|
||||
handler.SendSysMessage(CypherStrings.ResetallSpells);
|
||||
}
|
||||
else if (caseName == "talents")
|
||||
{
|
||||
atLogin = AtLoginFlags.ResetTalents | AtLoginFlags.ResetPetTalents;
|
||||
Global.WorldMgr.SendWorldText(CypherStrings.ResetallTalents);
|
||||
if (handler.GetSession() == null)
|
||||
handler.SendSysMessage(CypherStrings.ResetallTalents);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.ResetallUnknownCase, args);
|
||||
return false;
|
||||
}
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ALL_AT_LOGIN_FLAGS);
|
||||
stmt.AddValue(0, (ushort)atLogin);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
var plist = Global.ObjAccessor.GetPlayers();
|
||||
foreach (var player in plist)
|
||||
player.SetAtLoginFlag(atLogin);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("scene", RBACPermissions.CommandScene)]
|
||||
class SceneCommands
|
||||
{
|
||||
[Command("cancel", RBACPermissions.CommandSceneCancel)]
|
||||
static bool HandleCancelSceneCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint id = args.NextUInt32();
|
||||
|
||||
if (!CliDB.SceneScriptPackageStorage.HasRecord(id))
|
||||
return false;
|
||||
|
||||
target.GetSceneMgr().CancelSceneByPackageId(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("debug", RBACPermissions.CommandSceneDedug)]
|
||||
static bool HandleDebugSceneCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
if (player)
|
||||
{
|
||||
player.GetSceneMgr().ToggleDebugSceneMode();
|
||||
handler.SendSysMessage(player.GetSceneMgr().IsInDebugSceneMode() ? CypherStrings.CommandSceneDebugOn : CypherStrings.CommandSceneDebugOff);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("play", RBACPermissions.CommandScenePlay)]
|
||||
static bool HandlePlaySceneCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string sceneIdStr = args.NextString();
|
||||
if (sceneIdStr.IsEmpty())
|
||||
return false;
|
||||
|
||||
uint sceneId = uint.Parse(sceneIdStr);
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Global.ObjectMgr.GetSceneTemplate(sceneId) == null)
|
||||
return false;
|
||||
|
||||
target.GetSceneMgr().PlayScene(sceneId);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("playpackage", RBACPermissions.CommandScenePlayPackage)]
|
||||
static bool HandlePlayScenePackageCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string scenePackageIdStr = args.NextString();
|
||||
string flagsStr = args.NextString("");
|
||||
|
||||
if (scenePackageIdStr.IsEmpty())
|
||||
return false;
|
||||
|
||||
uint scenePackageId = uint.Parse(scenePackageIdStr);
|
||||
uint flags = !flagsStr.IsEmpty() ? uint.Parse(flagsStr) : (uint)SceneFlags.Unk16;
|
||||
Player target = handler.getSelectedPlayerOrSelf();
|
||||
|
||||
if (!target)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CliDB.SceneScriptPackageStorage.HasRecord(scenePackageId))
|
||||
return false;
|
||||
|
||||
target.GetSceneMgr().PlaySceneByPackageId(scenePackageId, (SceneFlags)flags);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Framework.IO;
|
||||
using Game.Entities;
|
||||
using Game.Mails;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Chat.Commands
|
||||
{
|
||||
[CommandGroup("send", RBACPermissions.CommandSend, false)]
|
||||
class SendCommands
|
||||
{
|
||||
[Command("mail", RBACPermissions.CommandSendMail, true)]
|
||||
static bool HandleSendMailCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// format: name "subject text" "mail text"
|
||||
Player target;
|
||||
ObjectGuid targetGuid;
|
||||
string targetName;
|
||||
if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName))
|
||||
return false;
|
||||
|
||||
string tail1 = args.NextString("");
|
||||
if (string.IsNullOrEmpty(tail1))
|
||||
return false;
|
||||
|
||||
string subject = handler.extractQuotedArg(tail1);
|
||||
if (string.IsNullOrEmpty(subject))
|
||||
return false;
|
||||
|
||||
string tail2 = args.NextString("");
|
||||
if (string.IsNullOrEmpty(tail2))
|
||||
return false;
|
||||
|
||||
string text = handler.extractQuotedArg(tail2);
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return false;
|
||||
|
||||
// from console show not existed sender
|
||||
MailSender sender = new MailSender(MailMessageType.Normal, handler.GetSession() ? handler.GetSession().GetPlayer().GetGUID().GetCounter() : 0, MailStationery.Gm);
|
||||
|
||||
/// @todo Fix poor design
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
new MailDraft(subject, text)
|
||||
.SendMailTo(trans, new MailReceiver(target, targetGuid.GetCounter()), sender);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
string nameLink = handler.playerLink(targetName);
|
||||
handler.SendSysMessage(CypherStrings.MailSent, nameLink);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("items", RBACPermissions.CommandSendItems, true)]
|
||||
static bool HandleSendItemsCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
// format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12]
|
||||
Player receiver;
|
||||
ObjectGuid receiverGuid;
|
||||
string receiverName;
|
||||
if (!handler.extractPlayerTarget(args, out receiver, out receiverGuid, out receiverName))
|
||||
return false;
|
||||
|
||||
string tail1 = args.NextString("");
|
||||
if (string.IsNullOrEmpty(tail1))
|
||||
return false;
|
||||
|
||||
string subject = handler.extractQuotedArg(tail1);
|
||||
if (string.IsNullOrEmpty(subject))
|
||||
return false;
|
||||
|
||||
string tail2 = args.NextString("");
|
||||
if (string.IsNullOrEmpty(tail2))
|
||||
return false;
|
||||
|
||||
string text = handler.extractQuotedArg(tail2);
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return false;
|
||||
|
||||
// extract items
|
||||
List<KeyValuePair<uint, uint>> items = new List<KeyValuePair<uint, uint>>();
|
||||
|
||||
// get all tail string
|
||||
StringArguments tail = new StringArguments(args.NextString(""));
|
||||
|
||||
// get from tail next item str
|
||||
StringArguments itemStr;
|
||||
while ((itemStr = new StringArguments(tail.NextString(" "))) != null)
|
||||
{
|
||||
// parse item str
|
||||
string itemIdStr = itemStr.NextString(":");
|
||||
string itemCountStr = itemStr.NextString(" ");
|
||||
|
||||
uint itemId = uint.Parse(itemIdStr);
|
||||
if (itemId == 0)
|
||||
return false;
|
||||
|
||||
ItemTemplate item_proto = Global.ObjectMgr.GetItemTemplate(itemId);
|
||||
if (item_proto == null)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandItemidinvalid, itemId);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint itemCount = !string.IsNullOrEmpty(itemCountStr) ? uint.Parse(itemCountStr) : 1;
|
||||
if (itemCount < 1 || (item_proto.GetMaxCount() > 0 && itemCount > item_proto.GetMaxCount()))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandInvalidItemCount, itemCount, itemId);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (itemCount > item_proto.GetMaxStackSize())
|
||||
{
|
||||
items.Add(new KeyValuePair<uint, uint>(itemId, item_proto.GetMaxStackSize()));
|
||||
itemCount -= item_proto.GetMaxStackSize();
|
||||
}
|
||||
|
||||
items.Add(new KeyValuePair<uint, uint>(itemId, itemCount));
|
||||
|
||||
if (items.Count > SharedConst.MaxMailItems)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandMailItemsLimit, SharedConst.MaxMailItems);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// from console show not existed sender
|
||||
MailSender sender = new MailSender(MailMessageType.Normal, handler.GetSession() ? handler.GetSession().GetPlayer().GetGUID().GetCounter() : 0, MailStationery.Gm);
|
||||
|
||||
// fill mail
|
||||
MailDraft draft = new MailDraft(subject, text);
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
foreach (var pair in items)
|
||||
{
|
||||
Item item = Item.CreateItem(pair.Key, pair.Value, handler.GetSession() ? handler.GetSession().GetPlayer() : null);
|
||||
if (item)
|
||||
{
|
||||
item.SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted
|
||||
draft.AddItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
draft.SendMailTo(trans, new MailReceiver(receiver, receiverGuid.GetCounter()), sender);
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
string nameLink = handler.playerLink(receiverName);
|
||||
handler.SendSysMessage(CypherStrings.MailSent, nameLink);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("money", RBACPermissions.CommandSendMoney, true)]
|
||||
static bool HandleSendMoneyCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/// format: name "subject text" "mail text" money
|
||||
|
||||
Player receiver;
|
||||
ObjectGuid receiverGuid;
|
||||
string receiverName;
|
||||
if (!handler.extractPlayerTarget(args, out receiver, out receiverGuid, out receiverName))
|
||||
return false;
|
||||
|
||||
string tail1 = args.NextString("");
|
||||
if (string.IsNullOrEmpty(tail1))
|
||||
return false;
|
||||
|
||||
string subject = handler.extractQuotedArg(tail1);
|
||||
if (string.IsNullOrEmpty(subject))
|
||||
return false;
|
||||
|
||||
string tail2 = args.NextString("");
|
||||
if (string.IsNullOrEmpty(tail2))
|
||||
return false;
|
||||
|
||||
string text = handler.extractQuotedArg(tail2);
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return false;
|
||||
|
||||
string moneyStr = args.NextString("");
|
||||
long money = !string.IsNullOrEmpty(moneyStr) ? long.Parse(moneyStr) : 0;
|
||||
if (money <= 0)
|
||||
return false;
|
||||
|
||||
// from console show not existed sender
|
||||
MailSender sender = new MailSender(MailMessageType.Normal, handler.GetSession() ? handler.GetSession().GetPlayer().GetGUID().GetCounter() : 0, MailStationery.Gm);
|
||||
|
||||
SQLTransaction trans = new SQLTransaction();
|
||||
|
||||
new MailDraft(subject, text)
|
||||
.AddMoney((uint)money)
|
||||
.SendMailTo(trans, new MailReceiver(receiver, receiverGuid.GetCounter()), sender);
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
string nameLink = handler.playerLink(receiverName);
|
||||
handler.SendSysMessage(CypherStrings.MailSent, nameLink);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("message", RBACPermissions.CommandSendMessage, true)]
|
||||
static bool HandleSendMessageCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
/// - Find the player
|
||||
Player player;
|
||||
if (!handler.extractPlayerTarget(args, out player))
|
||||
return false;
|
||||
|
||||
string msgStr = args.NextString("");
|
||||
if (string.IsNullOrEmpty(msgStr))
|
||||
return false;
|
||||
|
||||
// Check that he is not logging out.
|
||||
if (player.GetSession().isLogingOut())
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.PlayerNotFound);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// - Send the message
|
||||
player.GetSession().SendNotification("{0}", msgStr);
|
||||
player.GetSession().SendNotification("|cffff0000[Message from administrator]:|r");
|
||||
|
||||
// Confirmation message
|
||||
string nameLink = handler.GetNameLink(player);
|
||||
handler.SendSysMessage(CypherStrings.Sendmessage, nameLink, msgStr);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Configuration;
|
||||
using Framework.Constants;
|
||||
using Framework.IO;
|
||||
using System;
|
||||
|
||||
namespace Game.Chat
|
||||
{
|
||||
[CommandGroup("server", RBACPermissions.CommandServer, true)]
|
||||
class ServerCommands
|
||||
{
|
||||
[Command("corpses", RBACPermissions.CommandServerCorpses, true)]
|
||||
static bool Corpses(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Global.WorldMgr.RemoveOldCorpses();
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("exit", RBACPermissions.CommandServerExit, true)]
|
||||
static bool Exit(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.CommandExit);
|
||||
Global.WorldMgr.StopNow(ShutdownExitCode.Shutdown);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("info", RBACPermissions.CommandServerInfo, true)]
|
||||
static bool Info(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint playersNum = Global.WorldMgr.GetPlayerCount();
|
||||
uint maxPlayersNum = Global.WorldMgr.GetMaxPlayerCount();
|
||||
int activeClientsNum = Global.WorldMgr.GetActiveSessionCount();
|
||||
int queuedClientsNum = Global.WorldMgr.GetQueuedSessionCount();
|
||||
uint maxActiveClientsNum = Global.WorldMgr.GetMaxActiveSessionCount();
|
||||
uint maxQueuedClientsNum = Global.WorldMgr.GetMaxQueuedSessionCount();
|
||||
string uptime = Time.secsToTimeString(Global.WorldMgr.GetUptime());
|
||||
uint updateTime = Global.WorldMgr.GetUpdateTime();
|
||||
|
||||
handler.SendSysMessage(CypherStrings.ConnectedPlayers, playersNum, maxPlayersNum);
|
||||
handler.SendSysMessage(CypherStrings.ConnectedUsers, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum);
|
||||
handler.SendSysMessage(CypherStrings.Uptime, uptime);
|
||||
handler.SendSysMessage(CypherStrings.UpdateDiff, updateTime);
|
||||
// Can't use Global.WorldMgr.ShutdownMsg here in case of console command
|
||||
if (Global.WorldMgr.IsShuttingDown())
|
||||
handler.SendSysMessage(CypherStrings.ShutdownTimeleft, Time.secsToTimeString(Global.WorldMgr.GetShutDownTimeLeft()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("motd", RBACPermissions.CommandServerMotd, true)]
|
||||
static bool Motd(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.MotdCurrent, Global.WorldMgr.GetMotd());
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("plimit", RBACPermissions.CommandServerPlimit, true)]
|
||||
static bool PLimit(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (!args.Empty())
|
||||
{
|
||||
string paramStr = args.NextString();
|
||||
if (string.IsNullOrEmpty(paramStr))
|
||||
return false;
|
||||
|
||||
int limit = paramStr.Length;
|
||||
|
||||
switch (paramStr.ToLower())
|
||||
{
|
||||
case "player":
|
||||
Global.WorldMgr.SetPlayerSecurityLimit(AccountTypes.Player);
|
||||
break;
|
||||
case "moderator":
|
||||
Global.WorldMgr.SetPlayerSecurityLimit(AccountTypes.Moderator);
|
||||
break;
|
||||
case "gamemaster":
|
||||
Global.WorldMgr.SetPlayerSecurityLimit(AccountTypes.GameMaster);
|
||||
break;
|
||||
case "administrator":
|
||||
Global.WorldMgr.SetPlayerSecurityLimit(AccountTypes.Administrator);
|
||||
break;
|
||||
case "reset":
|
||||
Global.WorldMgr.SetPlayerAmountLimit(ConfigMgr.GetDefaultValue<uint>("PlayerLimit", 100));
|
||||
Global.WorldMgr.LoadDBAllowedSecurityLevel();
|
||||
break;
|
||||
default:
|
||||
int value = int.Parse(paramStr);
|
||||
if (value < 0)
|
||||
Global.WorldMgr.SetPlayerSecurityLimit((AccountTypes)(-value));
|
||||
else
|
||||
Global.WorldMgr.SetPlayerAmountLimit((uint)value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint playerAmountLimit = Global.WorldMgr.GetPlayerAmountLimit();
|
||||
AccountTypes allowedAccountType = Global.WorldMgr.GetPlayerSecurityLimit();
|
||||
string secName = "";
|
||||
switch (allowedAccountType)
|
||||
{
|
||||
case AccountTypes.Player:
|
||||
secName = "Player";
|
||||
break;
|
||||
case AccountTypes.Moderator:
|
||||
secName = "Moderator";
|
||||
break;
|
||||
case AccountTypes.GameMaster:
|
||||
secName = "Gamemaster";
|
||||
break;
|
||||
case AccountTypes.Administrator:
|
||||
secName = "Administrator";
|
||||
break;
|
||||
default:
|
||||
secName = "<unknown>";
|
||||
break;
|
||||
}
|
||||
handler.SendSysMessage("Player limits: amount {0}, min. security level {1}.", playerAmountLimit, secName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsOnlyUser(WorldSession mySession)
|
||||
{
|
||||
// check if there is any session connected from a different address
|
||||
string myAddr = mySession ? mySession.GetRemoteAddress() : "";
|
||||
var sessions = Global.WorldMgr.GetAllSessions();
|
||||
foreach (var session in sessions)
|
||||
if (session && myAddr != session.GetRemoteAddress())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseExitCode(string exitCodeStr, out int exitCode)
|
||||
{
|
||||
exitCode = int.Parse(exitCodeStr);
|
||||
|
||||
// Handle atoi() errors
|
||||
if (exitCode == 0 && (exitCodeStr[0] != '0' || (exitCodeStr.Length > 1 && exitCodeStr[1] != '\0')))
|
||||
return false;
|
||||
|
||||
// Exit code should be in range of 0-125, 126-255 is used
|
||||
// in many shells for their own return codes and code > 255
|
||||
// is not supported in many others
|
||||
if (exitCode < 0 || exitCode > 125)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ShutdownServer(StringArguments args,CommandHandler handler, ShutdownMask shutdownMask, ShutdownExitCode defaultExitCode)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string delayStr = args.NextString();
|
||||
if (delayStr.IsEmpty())
|
||||
return false;
|
||||
|
||||
int delay;
|
||||
if (int.TryParse(delayStr, out delay))
|
||||
{
|
||||
// Prevent interpret wrong arg value as 0 secs shutdown time
|
||||
if ((delay == 0 && (delayStr[0] != '0' || delayStr.Length > 1 && delayStr[1] != '\0')) || delay < 0)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
delay = (int)Time.TimeStringToSecs(delayStr);
|
||||
|
||||
if (delay == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
string reason = "";
|
||||
string exitCodeStr = "";
|
||||
string nextToken;
|
||||
while (!(nextToken = args.NextString()).IsEmpty())
|
||||
{
|
||||
if (nextToken.IsNumber())
|
||||
exitCodeStr = nextToken;
|
||||
else
|
||||
{
|
||||
reason = nextToken;
|
||||
reason += args.NextString("\0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int exitCode = (int)defaultExitCode;
|
||||
if (!exitCodeStr.IsEmpty())
|
||||
if (!ParseExitCode(exitCodeStr, out exitCode))
|
||||
return false;
|
||||
|
||||
// Override parameter "delay" with the configuration value if there are still players connected and "force" parameter was not specified
|
||||
if (delay < WorldConfig.GetIntValue(WorldCfg.ForceShutdownThreshold) && !shutdownMask.HasAnyFlag(ShutdownMask.Force) && !IsOnlyUser(handler.GetSession()))
|
||||
{
|
||||
delay = WorldConfig.GetIntValue(WorldCfg.ForceShutdownThreshold);
|
||||
handler.SendSysMessage(CypherStrings.ShutdownDelayed, delay);
|
||||
}
|
||||
|
||||
Global.WorldMgr.ShutdownServ((uint)delay, shutdownMask, (ShutdownExitCode)exitCode, reason);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[CommandGroup("idleRestart", RBACPermissions.CommandServerIdlerestart, true)]
|
||||
class IdleRestartCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandServerIdlerestart, true)]
|
||||
static bool HandleServerIdleRestartCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return ShutdownServer(args, handler, ShutdownMask.Restart | ShutdownMask.Idle, ShutdownExitCode.Restart);
|
||||
}
|
||||
|
||||
[Command("cancel", RBACPermissions.CommandServerIdlerestartCancel, true)]
|
||||
static bool Cancel(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Global.WorldMgr.ShutdownCancel();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("idleshutdown", RBACPermissions.CommandServerIdleshutdown, true)]
|
||||
class IdleshutdownCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandServerIdleshutdown, true)]
|
||||
static bool HandleServerIdleShutDownCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return ShutdownServer(args, handler, ShutdownMask.Idle, ShutdownExitCode.Shutdown);
|
||||
}
|
||||
|
||||
[Command("cancel", RBACPermissions.CommandServerIdleshutdownCancel, true)]
|
||||
static bool Cancel(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Global.WorldMgr.ShutdownCancel();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("restart", RBACPermissions.CommandServerInfo, true)]
|
||||
class RestartCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandServerRestart, true)]
|
||||
static bool HandleServerRestartCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return ShutdownServer(args, handler, ShutdownMask.Restart, ShutdownExitCode.Restart);
|
||||
}
|
||||
|
||||
[Command("cancel", RBACPermissions.CommandServerRestartCancel, true)]
|
||||
static bool HandleServerRestartCancelCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Global.WorldMgr.ShutdownCancel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("force", RBACPermissions.CommandServerRestartCancel, true)]
|
||||
static bool HandleServerForceRestartCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return ShutdownServer(args, handler, ShutdownMask.Force | ShutdownMask.Restart, ShutdownExitCode.Restart);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("shutdown", RBACPermissions.CommandServerMotd, true)]
|
||||
class ShutdownCommands
|
||||
{
|
||||
[Command("", RBACPermissions.CommandServerShutdown, true)]
|
||||
static bool HandleServerShutDownCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return ShutdownServer(args, handler, 0, ShutdownExitCode.Shutdown);
|
||||
}
|
||||
|
||||
[Command("cancel", RBACPermissions.CommandServerShutdownCancel, true)]
|
||||
static bool HandleServerShutDownCancelCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
uint timer = Global.WorldMgr.ShutdownCancel();
|
||||
if (timer != 0)
|
||||
handler.SendSysMessage(CypherStrings.ShutdownCancelled, timer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("force", RBACPermissions.CommandServerShutdownCancel, true)]
|
||||
static bool HandleServerForceShutDownCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
return ShutdownServer(args, handler, ShutdownMask.Force, ShutdownExitCode.Shutdown);
|
||||
}
|
||||
}
|
||||
|
||||
[CommandGroup("set", RBACPermissions.CommandServerSet, true)]
|
||||
class SetCommands
|
||||
{
|
||||
[Command("difftime", RBACPermissions.CommandServerSetDifftime, true)]
|
||||
static bool HandleServerSetDiffTimeCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string newTimeStr = args.NextString();
|
||||
if (newTimeStr.IsEmpty())
|
||||
return false;
|
||||
|
||||
int newTime = int.Parse(newTimeStr);
|
||||
if (newTime < 0)
|
||||
return false;
|
||||
|
||||
//Global.WorldMgr.SetRecordDiffInterval(newTime);
|
||||
//printf("Record diff every %i ms\n", newTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("loglevel", RBACPermissions.CommandServerSetLoglevel, true)]
|
||||
static bool HandleServerSetLogLevelCommand(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
if (args.Empty())
|
||||
return false;
|
||||
|
||||
string type = args.NextString();
|
||||
string name = args.NextString();
|
||||
string level = args.NextString();
|
||||
|
||||
if (string.IsNullOrEmpty(type) || string.IsNullOrEmpty(name) || string.IsNullOrEmpty(level) || name.IsEmpty() || level.IsEmpty() || (type[0] != 'a' && type[0] != 'l'))
|
||||
return false;
|
||||
|
||||
return Log.SetLogLevel(name, level, type[0] == 'l');
|
||||
}
|
||||
|
||||
[Command("motd", RBACPermissions.CommandServerSetMotd, true)]
|
||||
static bool SetMotd(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
Global.WorldMgr.SetMotd(args.NextString(""));
|
||||
handler.SendSysMessage(CypherStrings.MotdNew, args);
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("closed", RBACPermissions.CommandServerSetClosed, true)]
|
||||
static bool SetClosed(StringArguments args, CommandHandler handler)
|
||||
{
|
||||
string arg1 = args.NextString();
|
||||
if (arg1.Equals("on"))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.WorldClosed);
|
||||
Global.WorldMgr.SetClosed(true);
|
||||
return true;
|
||||
}
|
||||
else if (arg1.Equals("off"))
|
||||
{
|
||||
handler.SendSysMessage(CypherStrings.WorldOpened);
|
||||
Global.WorldMgr.SetClosed(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
handler.SendSysMessage(CypherStrings.UseBol);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user