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:
Fabian
2017-10-26 17:23:44 +02:00
parent 227702e19c
commit a3dc7b3f48
844 changed files with 26064 additions and 1824 deletions
+129
View File
@@ -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);
}
}
}
+60
View File
@@ -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) { }
}
}
+361
View File
@@ -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();
}
}
}
+499
View File
@@ -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
}
}
+69
View File
@@ -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) { }
}
}
+76
View File
@@ -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);
}
}
}
+134
View File
@@ -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());
}
}
}
+644
View File
@@ -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;
}
}
+83
View File
@@ -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;
}
}
+575
View File
@@ -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
+803
View File
@@ -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
+515
View File
@@ -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
}
}
+183
View File
@@ -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();
}
}
}
+385
View File
@@ -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
+311
View File
@@ -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;
}
}
+77
View File
@@ -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;
}
}
+871
View File
@@ -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;
}
}
+129
View File
@@ -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>();
}
}
+111
View File
@@ -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;
}
}
+241
View File
@@ -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
}
}
+108
View File
@@ -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;
}
}
+264
View File
@@ -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;
}
}
+23
View File
@@ -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
{
}
}
+23
View File
@@ -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
{
}
}
+844
View File
@@ -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
+498
View File
@@ -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;
}
}
}
+231
View File
@@ -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;
}
}
+751
View File
@@ -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; }
}
}
+980
View File
@@ -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;
}
}
+166
View File
@@ -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);
}
}
+66
View File
@@ -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) { }
}
}
+877
View File
@@ -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();
}
}
}
+197
View File
@@ -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;
}
}
}
}
+224
View File
@@ -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;
}
}
}
}
+294
View File
@@ -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;
}
}
}
}
+664
View File
@@ -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;
}
}
}
+248
View File
@@ -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;
}
}
}
+256
View File
@@ -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);
}
}
}
}
+180
View File
@@ -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;
}
}
}
+234
View File
@@ -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;
}
}
}
}
+622
View File
@@ -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;
}
}
}
+351
View File
@@ -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;
}
}
}
+226
View File
@@ -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;
}
}
}
+143
View File
@@ -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)));
}
}
}
+348
View File
@@ -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;
}
}
}
+555
View File
@@ -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
+261
View File
@@ -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
+868
View File
@@ -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
+203
View File
@@ -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;
}
}
}
+250
View File
@@ -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;
}
}
}
+317
View File
@@ -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
+282
View File
@@ -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;
}
}
}
+118
View File
@@ -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;
}
}
}
+248
View File
@@ -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;
}
}
}
+376
View File
@@ -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