| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030 |
- using System.Drawing;
- using Server.MirDatabase;
- using Server.MirEnvir;
- using Server.MirObjects.Monsters;
- using S = ServerPackets;
- namespace Server.MirObjects
- {
- public abstract class MapObject
- {
- protected static MessageQueue MessageQueue
- {
- get { return MessageQueue.Instance; }
- }
- protected static Envir Envir
- {
- get { return Envir.Main; }
- }
- public readonly uint ObjectID = Envir.ObjectID;
- public abstract ObjectType Race { get; }
- public abstract string Name { get; set; }
- public long ExplosionInflictedTime;
- public int ExplosionInflictedStage;
- private int SpawnThread;
- private Map _currentMap;
- public Map CurrentMap
- {
- set
- {
- _currentMap = value;
- CurrentMapIndex = _currentMap != null ? _currentMap.Info.Index : 0;
- }
- get { return _currentMap; }
- }
- public abstract int CurrentMapIndex { get; set; }
- public abstract Point CurrentLocation { get; set; }
- public abstract MirDirection Direction { get; set; }
- public abstract ushort Level { get; set; }
- public abstract int Health { get; }
- public abstract int MaxHealth { get; }
- public byte PercentHealth
- {
- get { return (byte)(Health / (float)MaxHealth * 100); }
- }
- public byte Light;
- public int AttackSpeed;
- protected long brownTime;
- public virtual long BrownTime
- {
- get { return brownTime; }
- set { brownTime = value; }
- }
- public long CellTime, PKPointTime, LastHitTime, EXPOwnerTime;
- public Color NameColour = Color.White;
- public bool Dead, Undead, Harvested, AutoRev;
- public List<KeyValuePair<string, string>> NPCVar = new List<KeyValuePair<string, string>>();
- public virtual int PKPoints { get; set; }
- public ushort PotHealthAmount, PotManaAmount, HealAmount, VampAmount;
- public bool CoolEye;
- private bool _hidden;
- public bool Hidden
- {
- get
- {
- return _hidden;
- }
- set
- {
- if (_hidden == value) return;
- _hidden = value;
- CurrentMap.Broadcast(new S.ObjectHidden { ObjectID = ObjectID, Hidden = value }, CurrentLocation);
- }
- }
- private bool _observer;
- public bool Observer
- {
- get
- {
- return _observer;
- }
- set
- {
- if (_observer == value) return;
- _observer = value;
- if (!_observer)
- BroadcastInfo();
- else
- Broadcast(new S.ObjectRemove { ObjectID = ObjectID });
- }
- }
- #region Sneaking
- private bool _sneakingActive;
- public bool SneakingActive
- {
- get { return _sneakingActive; }
- set
- {
- if (_sneakingActive == value) return;
- _sneakingActive = value;
- Observer = _sneakingActive;
- }
- }
- private bool _sneaking;
- public bool Sneaking
- {
- get { return _sneaking; }
- set { _sneaking = value; SneakingActive = value; }
- }
- #endregion
- public MapObject _target;
- public virtual MapObject Target
- {
- get { return _target; }
- set
- {
- if (_target == value) return;
- _target = value;
- }
- }
- protected MapObject master;
- public virtual MapObject Master
- {
- get { return master; }
- set { master = value; }
- }
- public MapObject LastHitter, EXPOwner, Owner;
- public long ExpireTime, OwnerTime, OperateTime;
- public int OperateDelay = 100;
- public Stats Stats;
- public List<MonsterObject> Pets = new List<MonsterObject>();
- public virtual List<Buff> Buffs { get; set; } = new List<Buff>();
- public List<PlayerObject> GroupMembers;
- public virtual AttackMode AMode { get; set; }
- public virtual PetMode PMode { get; set; }
- private bool _inSafeZone;
- public bool InSafeZone {
- get { return _inSafeZone; }
- set
- {
- if (_inSafeZone == value) return;
- _inSafeZone = value;
- OnSafeZoneChanged();
- }
- }
- public float ArmourRate, DamageRate; //recieved not given
- public virtual List<Poison> PoisonList { get; set; } = new List<Poison>();
- public PoisonType CurrentPoison = PoisonType.None;
- public List<DelayedAction> ActionList = new List<DelayedAction>();
- public LinkedListNode<MapObject> Node;
- public LinkedListNode<MapObject> NodeThreaded;
- public long RevTime;
- public virtual bool Blocking
- {
- get { return true; }
- }
- public Point Front
- {
- get { return Functions.PointMove(CurrentLocation, Direction, 1); }
- }
- public Point Back
- {
- get { return Functions.PointMove(CurrentLocation, Direction, -1); }
- }
- public virtual void Process()
- {
- if (Master != null && Master.Node == null) Master = null;
- if (LastHitter != null && LastHitter.Node == null) LastHitter = null;
- if (EXPOwner != null && EXPOwner.Node == null) EXPOwner = null;
- if (Target != null && (Target.Node == null || Target.Dead)) Target = null;
- if (Owner != null && Owner.Node == null) Owner = null;
- if (PKPoints > 0 && Envir.Time > PKPointTime)
- {
- PKPointTime = Envir.Time + Settings.PKDelay * Settings.Second;
- PKPoints--;
- }
- if (LastHitter != null && Envir.Time > LastHitTime)
- {
- LastHitter = null;
- }
- if (EXPOwner != null && Envir.Time > EXPOwnerTime)
- {
- EXPOwner = null;
- }
- for (int i = 0; i < ActionList.Count; i++)
- {
- if (Envir.Time < ActionList[i].Time) continue;
- Process(ActionList[i]);
- ActionList.RemoveAt(i);
- }
- }
- public virtual void OnSafeZoneChanged()
- {
- }
- public abstract void SetOperateTime();
- public int GetAttackPower(int min, int max)
- {
- if (min < 0) min = 0;
- if (min > max) max = min;
- if (Stats[Stat.Luck] > 0)
- {
- if (Stats[Stat.Luck] > Envir.Random.Next(Settings.MaxLuck))
- return max;
- }
- else if (Stats[Stat.Luck] < 0)
- {
- if (Stats[Stat.Luck] < -Envir.Random.Next(Settings.MaxLuck))
- return min;
- }
- return Envir.Random.Next(min, max + 1);
- }
- public int GetRangeAttackPower(int min, int max, int range)
- {
- //maxRange = highest possible damage
- //minRange = lowest possible damage
- decimal x = ((decimal)min / (Globals.MaxAttackRange)) * (Globals.MaxAttackRange - range);
- min -= (int)Math.Floor(x);
- return GetAttackPower(min, max);
- }
- public int GetDefencePower(int min, int max)
- {
- if (min < 0) min = 0;
- if (min > max) max = min;
- return Envir.Random.Next(min, max + 1);
- }
- public virtual void Remove(HumanObject player)
- {
- player.Enqueue(new S.ObjectRemove { ObjectID = ObjectID });
- }
- public virtual void Add(HumanObject player)
- {
- if (player.Race != ObjectType.Player) return;
- if (Race == ObjectType.Merchant)
- {
- NPCObject npc = (NPCObject)this;
- npc.CheckVisible((PlayerObject)player, true);
- return;
- }
- player.Enqueue(GetInfo());
- //if (Race == ObjectType.Player)
- //{
- // PlayerObject me = (PlayerObject)this;
- // player.Enqueue(me.GetInfoEx(player));
- //}
- //else
- //{
- // player.Enqueue(GetInfo());
- //}
- }
- public virtual void Remove(MonsterObject monster)
- {
- }
- public virtual void Add(MonsterObject monster)
- {
- }
- public abstract void Process(DelayedAction action);
- public bool CanFly(Point target)
- {
- Point location = CurrentLocation;
- while (location != target)
- {
- MirDirection dir = Functions.DirectionFromPoint(location, target);
- location = Functions.PointMove(location, dir, 1);
- if (location.X < 0 || location.Y < 0 || location.X >= CurrentMap.Width || location.Y >= CurrentMap.Height) return false;
- if (!CurrentMap.GetCell(location).Valid) return false;
- }
- return true;
- }
- public virtual void Spawned()
- {
- if (Node != null)
- throw new InvalidOperationException("Node is not null, Object already spawned");
- Node = Envir.Objects.AddLast(this);
- if ((Race == ObjectType.Monster) && Settings.Multithreaded)
- {
- SpawnThread = CurrentMap.Thread;
- NodeThreaded = Envir.MobThreads[SpawnThread].ObjectsList.AddLast(this);
- }
- OperateTime = Envir.Time + Envir.Random.Next(OperateDelay);
- BroadcastInfo();
- BroadcastHealthChange();
- InSafeZone = CurrentMap != null && CurrentMap.GetSafeZone(CurrentLocation) != null;
- }
- public virtual void Despawn()
- {
- if (Node == null)
- throw new InvalidOperationException("Node is null, Object already Despawned");
-
- Broadcast(new S.ObjectRemove { ObjectID = ObjectID });
- Envir.Objects.Remove(Node);
- if (Settings.Multithreaded && (Race == ObjectType.Monster))
- {
- Envir.MobThreads[SpawnThread].ObjectsList.Remove(NodeThreaded);
- }
- ActionList.Clear();
- for (int i = Pets.Count - 1; i >= 0; i--)
- Pets[i].Die();
- Node = null;
- }
- public MapObject FindObject(uint targetID, int dist)
- {
- for (int d = 0; d <= dist; d++)
- {
- for (int y = CurrentLocation.Y - d; y <= CurrentLocation.Y + d; y++)
- {
- if (y < 0) continue;
- if (y >= CurrentMap.Height) break;
- for (int x = CurrentLocation.X - d; x <= CurrentLocation.X + d; x += Math.Abs(y - CurrentLocation.Y) == d ? 1 : d * 2)
- {
- if (x < 0) continue;
- if (x >= CurrentMap.Width) break;
- Cell cell = CurrentMap.GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject ob = cell.Objects[i];
- if (ob.ObjectID != targetID) continue;
- return ob;
- }
- }
- }
- }
- return null;
- }
- public virtual void Broadcast(Packet p)
- {
- if (p == null || CurrentMap == null) return;
- for (int i = CurrentMap.Players.Count - 1; i >= 0; i--)
- {
- PlayerObject player = CurrentMap.Players[i];
- if (player == this) continue;
- if (Functions.InRange(CurrentLocation, player.CurrentLocation, Globals.DataRange))
- player.Enqueue(p);
- }
- }
- public virtual void BroadcastInfo()
- {
- Broadcast(GetInfo());
- return;
- }
- public bool IsAttackTarget(MapObject attacker)
- {
- if (attacker == null || attacker.Node == null) return false;
- if (Dead || attacker == this) return false;
- var flag = true;
- if (Race == ObjectType.Monster)
- {
- // Check if we are a training AI - we can be attacked in safezones
- if (((MonsterObject)this).Info.AI == 56)
- flag = false;
- }
- if (flag && (InSafeZone || attacker.InSafeZone)) return false;
- switch (attacker.Race)
- {
- case ObjectType.Player:
- return IsAttackTarget((PlayerObject)attacker);
- case ObjectType.Hero:
- return IsAttackTarget((HeroObject)attacker);
- case ObjectType.Monster:
- return IsAttackTarget((MonsterObject)attacker);
- default:
- throw new NotSupportedException();
- }
- }
- public abstract bool IsAttackTarget(HumanObject attacker);
- public abstract bool IsAttackTarget(MonsterObject attacker);
- public abstract int Attacked(HumanObject attacker, int damage, DefenceType type = DefenceType.ACAgility, bool damageWeapon = true);
- public abstract int Attacked(MonsterObject attacker, int damage, DefenceType type = DefenceType.ACAgility);
- public virtual int GetArmour(DefenceType type, MapObject attacker, out bool hit)
- {
- var armour = 0;
- hit = true;
- switch (type)
- {
- case DefenceType.ACAgility:
- if (Envir.Random.Next(Stats[Stat.Agility] + 1) > attacker.Stats[Stat.Accuracy])
- {
- BroadcastDamageIndicator(DamageType.Miss);
- hit = false;
- }
- armour = GetDefencePower(Stats[Stat.MinAC], Stats[Stat.MaxAC]);
- break;
- case DefenceType.AC:
- armour = GetDefencePower(Stats[Stat.MinAC], Stats[Stat.MaxAC]);
- break;
- case DefenceType.MACAgility:
- if (Envir.Random.Next(Settings.MagicResistWeight) < Stats[Stat.MagicResist])
- {
- BroadcastDamageIndicator(DamageType.Miss);
- hit = false;
- }
- if (Envir.Random.Next(Stats[Stat.Agility] + 1) > attacker.Stats[Stat.Accuracy])
- {
- BroadcastDamageIndicator(DamageType.Miss);
- hit = false;
- }
- armour = GetDefencePower(Stats[Stat.MinMAC], Stats[Stat.MaxMAC]);
- break;
- case DefenceType.MAC:
- if (Envir.Random.Next(Settings.MagicResistWeight) < Stats[Stat.MagicResist])
- {
- BroadcastDamageIndicator(DamageType.Miss);
- hit = false;
- }
- armour = GetDefencePower(Stats[Stat.MinMAC], Stats[Stat.MaxMAC]);
- break;
- case DefenceType.Agility:
- if (Envir.Random.Next(Stats[Stat.Agility] + 1) > attacker.Stats[Stat.Accuracy])
- {
- BroadcastDamageIndicator(DamageType.Miss);
- hit = false;
- }
- break;
- }
- return armour;
- }
- public virtual void ApplyNegativeEffects(HumanObject attacker, DefenceType type, ushort levelOffset)
- {
- if (attacker.SpecialMode.HasFlag(SpecialItemMode.Paralize) && type != DefenceType.MAC && type != DefenceType.MACAgility && 1 == Envir.Random.Next(1, 15))
- {
- ApplyPoison(new Poison { PType = PoisonType.Paralysis, Duration = 5, TickSpeed = 1000 }, attacker);
- }
- if ((attacker.Stats[Stat.Freezing] > 0) && (Settings.PvpCanFreeze || Race != ObjectType.Player) && type != DefenceType.MAC && type != DefenceType.MACAgility)
- {
- if ((Envir.Random.Next(Settings.FreezingAttackWeight) < attacker.Stats[Stat.Freezing]) && (Envir.Random.Next(levelOffset) == 0))
- ApplyPoison(new Poison { PType = PoisonType.Slow, Duration = Math.Min(10, (3 + Envir.Random.Next(attacker.Stats[Stat.Freezing]))), TickSpeed = 1000 }, attacker);
- }
- if (attacker.Stats[Stat.PoisonAttack] > 0 && type != DefenceType.MAC && type != DefenceType.MACAgility)
- {
- if ((Envir.Random.Next(Settings.PoisonAttackWeight) < attacker.Stats[Stat.PoisonAttack]) && (Envir.Random.Next(levelOffset) == 0))
- ApplyPoison(new Poison { PType = PoisonType.Green, Duration = 5, TickSpeed = 1000, Value = Math.Min(10, 3 + Envir.Random.Next(attacker.Stats[Stat.PoisonAttack])) }, attacker);
- }
- }
- public abstract int Struck(int damage, DefenceType type = DefenceType.ACAgility);
- public bool IsFriendlyTarget(MapObject ally)
- {
- switch (ally.Race)
- {
- case ObjectType.Player:
- return IsFriendlyTarget((PlayerObject)ally);
- case ObjectType.Hero:
- return IsFriendlyTarget((HeroObject)ally);
- case ObjectType.Monster:
- return IsFriendlyTarget((MonsterObject)ally);
- default:
- throw new NotSupportedException();
- }
- }
- public abstract bool IsFriendlyTarget(HumanObject ally);
- public abstract bool IsFriendlyTarget(MonsterObject ally);
- public abstract void ReceiveChat(string text, ChatType type);
- public abstract Packet GetInfo();
- public virtual void WinExp(uint amount, uint targetLevel = 0)
- {
- }
- public virtual bool CanGainGold(uint gold)
- {
- return false;
- }
- public virtual void WinGold(uint gold)
- {
- }
- public virtual bool Harvest(PlayerObject player) { return false; }
- public abstract void ApplyPoison(Poison p, MapObject Caster = null, bool NoResist = false, bool ignoreDefence = true);
- public virtual Buff AddBuff(BuffType type, MapObject owner, int duration, Stats stats, bool refreshStats = true, bool updateOnly = false, params int[] values)
- {
- if (!HasBuff(type, out Buff buff))
- {
- buff = new Buff(type)
- {
- Caster = owner,
- ObjectID = ObjectID,
- ExpireTime = duration,
- LastTime = Envir.Time,
- Stats = stats
- };
- Buffs.Add(buff);
- }
- else
- {
- if (!updateOnly)
- {
- switch (buff.StackType)
- {
- case BuffStackType.ResetDuration:
- {
- buff.ExpireTime = duration;
- }
- break;
- case BuffStackType.StackDuration:
- {
- buff.ExpireTime += duration;
- }
- break;
- case BuffStackType.StackStat:
- {
- if (stats != null)
- {
- buff.Stats.Add(stats);
- }
- }
- break;
- case BuffStackType.StackStatAndDuration:
- {
- if (stats != null)
- {
- buff.Stats.Add(stats);
- }
- buff.ExpireTime += duration;
- }
- break;
- case BuffStackType.ResetStat:
- {
- if (stats != null)
- {
- buff.Stats = stats;
- }
- }
- break;
- case BuffStackType.ResetStatAndDuration:
- {
- buff.ExpireTime = duration;
- if (stats != null)
- {
- buff.Stats = stats;
- }
- }
- break;
- case BuffStackType.Infinite:
- case BuffStackType.None:
- break;
- }
- }
- }
- if (buff.Properties.HasFlag(BuffProperty.PauseInSafeZone) && InSafeZone)
- {
- buff.Paused = true;
- }
- buff.Stats ??= new Stats();
- buff.Values = values ?? new int[0];
- if (buff.Caster?.Node == null)
- buff.Caster = owner;
- switch (buff.Type)
- {
- case BuffType.MoonLight:
- case BuffType.DarkBody:
- Hidden = true;
- Sneaking = true;
- HideFromTargets();
- break;
- case BuffType.Hiding:
- case BuffType.ClearRing:
- Hidden = true;
- HideFromTargets();
- break;
- }
- return buff;
- }
- public virtual void RemoveBuff(BuffType b)
- {
- for (int i = 0; i < Buffs.Count; i++)
- {
- if (Buffs[i].Type != b) continue;
- Buffs[i].FlagForRemoval = true;
- Buffs[i].Paused = false;
- Buffs[i].ExpireTime = 0;
- switch(b)
- {
- case BuffType.Hiding:
- case BuffType.MoonLight:
- case BuffType.DarkBody:
- if (!HasAnyBuffs(b, BuffType.ClearRing, BuffType.Hiding, BuffType.MoonLight, BuffType.DarkBody))
- {
- Hidden = false;
- }
- break;
- }
- }
- }
- public bool HasBuff(BuffType type)
- {
- for (int i = 0; i < Buffs.Count; i++)
- {
- if (Buffs[i].Type != type) continue;
- return true;
- }
- return false;
- }
- public bool HasBuff(BuffType type, out Buff buff)
- {
- for (int i = 0; i < Buffs.Count; i++)
- {
- if (Buffs[i].Type != type) continue;
- buff = Buffs[i];
- return true;
- }
- buff = null;
- return false;
- }
- public bool HasAnyBuffs(BuffType exceptBuff, params BuffType[] types)
- {
- return Buffs.Select(x => x.Type).Except(new List<BuffType> { exceptBuff }).Intersect(types).Any();
- }
- public virtual void PauseBuff(Buff b)
- {
- if (b.Paused) return;
- b.Paused = true;
- }
- public virtual void UnpauseBuff(Buff b)
- {
- if (!b.Paused) return;
- b.Paused = false;
- }
- protected void HideFromTargets()
- {
- for (int y = CurrentLocation.Y - Globals.DataRange; y <= CurrentLocation.Y + Globals.DataRange; y++)
- {
- if (y < 0) continue;
- if (y >= CurrentMap.Height) break;
- for (int x = CurrentLocation.X - Globals.DataRange; x <= CurrentLocation.X + Globals.DataRange; x++)
- {
- if (x < 0) continue;
- if (x >= CurrentMap.Width) break;
- if (x < 0 || x >= CurrentMap.Width) continue;
- Cell cell = CurrentMap.GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject ob = cell.Objects[i];
- if (ob.Race != ObjectType.Monster) continue;
- if (ob.Target == this && (!ob.CoolEye || ob.Level < Level)) ob.Target = null;
- }
- }
- }
- }
- public bool CheckStacked()
- {
- Cell cell = CurrentMap.GetCell(CurrentLocation);
- if (cell.Objects != null)
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject ob = cell.Objects[i];
- if (ob == this || !ob.Blocking) continue;
- return true;
- }
- return false;
- }
- public virtual bool Teleport(Map temp, Point location, bool effects = true, byte effectnumber = 0)
- {
- if (temp == null || !temp.ValidPoint(location)) return false;
- CurrentMap.RemoveObject(this);
- if (effects) Broadcast(new S.ObjectTeleportOut {ObjectID = ObjectID, Type = effectnumber});
- Broadcast(new S.ObjectRemove {ObjectID = ObjectID});
-
- CurrentMap = temp;
- CurrentLocation = location;
- InTrapRock = false;
- CurrentMap.AddObject(this);
- BroadcastInfo();
- if (effects) Broadcast(new S.ObjectTeleportIn { ObjectID = ObjectID, Type = effectnumber });
-
- BroadcastHealthChange();
-
- return true;
- }
- public virtual bool TeleportRandom(int attempts, int distance, Map map = null)
- {
- if (map == null) map = CurrentMap;
- if (map.Cells == null) return false;
- if (map.WalkableCells.Count == 0) return false;
- int cellIndex = Envir.Random.Next(map.WalkableCells.Count);
- return Teleport(map, map.WalkableCells[cellIndex]);
- }
- public Point GetRandomPoint(int attempts, int distance, Map map)
- {
- byte edgeoffset = 0;
- if (map.Width < 150)
- {
- if (map.Height < 30) edgeoffset = 2;
- else edgeoffset = 20;
- }
- for (int i = 0; i < attempts; i++)
- {
- Point location;
- if (distance <= 0)
- location = new Point(edgeoffset + Envir.Random.Next(map.Width - edgeoffset), edgeoffset + Envir.Random.Next(map.Height - edgeoffset)); //Can adjust Random Range...
- else
- location = new Point(CurrentLocation.X + Envir.Random.Next(-distance, distance + 1),
- CurrentLocation.Y + Envir.Random.Next(-distance, distance + 1));
- if (map.ValidPoint(location)) return location;
- }
- return new Point(0, 0);
- }
- public virtual void BroadcastHealthChange()
- {
- if (Race != ObjectType.Player && Race != ObjectType.Monster) return;
- byte time = Math.Min(byte.MaxValue, (byte)Math.Max(5, (RevTime - Envir.Time) / 1000));
- Packet p = new S.ObjectHealth { ObjectID = ObjectID, Percent = PercentHealth, Expire = time };
- if (Envir.Time < RevTime)
- {
- CurrentMap.Broadcast(p, CurrentLocation);
- return;
- }
- if (Race == ObjectType.Monster && !AutoRev && Master == null) return;
- if (Race == ObjectType.Player)
- {
- if (GroupMembers != null) //Send HP to group
- {
- for (int i = 0; i < GroupMembers.Count; i++)
- {
- PlayerObject member = GroupMembers[i];
- if (this == member) continue;
- if (member.CurrentMap != CurrentMap || !Functions.InRange(member.CurrentLocation, CurrentLocation, Globals.DataRange)) continue;
- member.Enqueue(p);
- }
- }
- return;
- }
- if (Master != null && Master.Race == ObjectType.Player)
- {
- PlayerObject player = (PlayerObject)Master;
- player.Enqueue(p);
- if (player.GroupMembers != null) //Send pet HP to group
- {
- for (int i = 0; i < player.GroupMembers.Count; i++)
- {
- PlayerObject member = player.GroupMembers[i];
- if (player == member) continue;
- if (member.CurrentMap != CurrentMap || !Functions.InRange(member.CurrentLocation, CurrentLocation, Globals.DataRange)) continue;
- member.Enqueue(p);
- }
- }
- }
- if (EXPOwner != null && EXPOwner.Race == ObjectType.Player)
- {
- PlayerObject player = (PlayerObject)EXPOwner;
- if (player.IsMember(Master)) return;
-
- player.Enqueue(p);
- if (player.GroupMembers != null)
- {
- for (int i = 0; i < player.GroupMembers.Count; i++)
- {
- PlayerObject member = player.GroupMembers[i];
- if (player == member) continue;
- if (member.CurrentMap != CurrentMap || !Functions.InRange(member.CurrentLocation, CurrentLocation, Globals.DataRange)) continue;
- member.Enqueue(p);
- }
- }
- }
- }
- public void BroadcastDamageIndicator(DamageType type, int damage = 0)
- {
- Packet p = new S.DamageIndicator { ObjectID = ObjectID, Damage = damage, Type = type };
- if (Race == ObjectType.Player)
- {
- PlayerObject player = (PlayerObject)this;
- player.Enqueue(p);
- }
- Broadcast(p);
- }
- public abstract void Die();
- public abstract int Pushed(MapObject pusher, MirDirection dir, int distance);
- public bool IsMember(MapObject member)
- {
- if (member == this) return true;
- if (GroupMembers == null || member == null) return false;
- for (int i = 0; i < GroupMembers.Count; i++)
- if (GroupMembers[i] == member) return true;
- return false;
- }
- public abstract void SendHealth(HumanObject player);
- public bool InTrapRock
- {
- set
- {
- if (this is PlayerObject)
- {
- var player = (PlayerObject)this;
- player.Enqueue(new S.InTrapRock { Trapped = value });
- }
- }
- get
- {
- Point checklocation;
- for (int i = 0; i <= 6; i += 2)
- {
- checklocation = Functions.PointMove(CurrentLocation, (MirDirection)i, 1);
- if (checklocation.X < 0) continue;
- if (checklocation.X >= CurrentMap.Width) continue;
- if (checklocation.Y < 0) continue;
- if (checklocation.Y >= CurrentMap.Height) continue;
- Cell cell = CurrentMap.GetCell(checklocation.X, checklocation.Y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int j = 0; j < cell.Objects.Count; j++)
- {
- MapObject ob = cell.Objects[j];
- switch (ob.Race)
- {
- case ObjectType.Monster:
- if (ob is TrapRock)
- {
- TrapRock rock = (TrapRock)ob;
- if (rock.Dead) continue;
- if (rock.Target != this) continue;
- if (!rock.Visible) continue;
- }
- else continue;
- return true;
- default:
- continue;
- }
- }
- }
- return false;
- }
- }
- }
- public class Poison
- {
- private MapObject owner;
- public MapObject Owner
- {
- get
- {
- return owner switch
- {
- HeroObject hero => hero.Owner,
- _ => owner
- };
- }
- set { owner = value; }
- }
- public PoisonType PType;
- public int Value;
- public long Duration, Time, TickTime, TickSpeed;
- public Poison() { }
- public Poison(BinaryReader reader)
- {
- Owner = null;
- PType = (PoisonType)reader.ReadByte();
- Value = reader.ReadInt32();
- Duration = reader.ReadInt64();
- Time = reader.ReadInt64();
- TickTime = reader.ReadInt64();
- TickSpeed = reader.ReadInt64();
- }
- }
- }
|