| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319 |
- using System.Drawing;
- using Server.MirDatabase;
- using Server.MirEnvir;
- using Server.MirNetwork;
- using S = ServerPackets;
- using Server.MirObjects.Monsters;
- namespace Server.MirObjects
- {
- public class HeroObject : HumanObject
- {
- public override ObjectType Race
- {
- get { return ObjectType.Hero; }
- }
- public override MirConnection Connection
- {
- get { return connection; }
- set { throw new NotSupportedException(); }
- }
- public HeroInfo HInfo;
- public new PlayerObject Owner;
- public override int PotionBeltMinimum => 0;
- public override int PotionBeltMaximum => 2;
- public override int AmuletBeltMinimum => 1;
- public override int AmuletBeltMaximum => 2;
- public override int BeltSize => 2;
- public override bool CanMove
- {
- get
- {
- return base.CanMove && !ActiveBlizzard && !ActiveReincarnation && (Owner.PMode == PetMode.MoveOnly || Owner.PMode == PetMode.Both || Owner.PMode == PetMode.FocusMasterTarget);
- }
- }
- public override bool CanWalk
- {
- get
- {
- return base.CanWalk && !ActiveBlizzard && !ActiveReincarnation && (Owner.PMode == PetMode.MoveOnly || Owner.PMode == PetMode.Both || Owner.PMode == PetMode.FocusMasterTarget);
- }
- }
- public override bool CanRun
- {
- get
- {
- return base.CanRun && !ActiveBlizzard && !ActiveReincarnation && (Owner.PMode == PetMode.MoveOnly || Owner.PMode == PetMode.Both || Owner.PMode == PetMode.FocusMasterTarget);
- }
- }
- public override bool CanAttack
- {
- get
- {
- return base.CanAttack && !ActiveBlizzard && !ActiveReincarnation && (Owner.PMode == PetMode.AttackOnly || Owner.PMode == PetMode.Both || Owner.PMode == PetMode.FocusMasterTarget);
- }
- }
- protected override bool CanCast
- {
- get
- {
- return base.CanCast && !ActiveBlizzard && !ActiveReincarnation && (Owner.PMode == PetMode.AttackOnly || Owner.PMode == PetMode.Both || Owner.PMode == PetMode.FocusMasterTarget);
- }
- }
- public const int SearchDelay = 3000, ViewRange = 8, RoamDelay = 1000, RevivalDelay = 2000, AutoPotDelay = 1000;
- public long RoamTime, AutoPotTime;
- public override long BrownTime
- {
- get { return Owner.BrownTime; }
- set { brownTime = value; }
- }
- public byte Grade
- {
- get { return HInfo.Grade; }
- set { HInfo.Grade = value; }
- }
- public bool AutoPot
- {
- get { return HInfo.AutoPot; }
- set { HInfo.AutoPot = value; }
- }
- public byte AutoHPPercent
- {
- get { return HInfo.AutoHPPercent; }
- set { HInfo.AutoHPPercent = value; }
- }
- public byte AutoMPPercent
- {
- get { return HInfo.AutoMPPercent; }
- set { HInfo.AutoMPPercent = value; }
- }
- public int HPItemIndex
- {
- get { return HInfo.HPItemIndex; }
- set { HInfo.HPItemIndex = value; }
- }
- public int MPItemIndex
- {
- get { return HInfo.MPItemIndex; }
- set { HInfo.MPItemIndex = value; }
- }
- protected Spell NextMagicSpell;
- protected MirDirection NextMagicDirection;
- protected uint NextMagicTargetID;
- protected Point NextMagicLocation;
- protected int TargetDistance;
- public override GuildObject MyGuild
- {
- get { return Owner.MyGuild; }
- set { throw new NotSupportedException(); }
- }
- public override MapObject Master
- {
- get { return Owner; }
- set { Owner = (PlayerObject)value; }
- }
- public HeroObject(CharacterInfo info, PlayerObject owner)
- {
- CheckCellTime = false;
- Owner = owner;
- base.Report = owner.Report;
- Load(info, null);
- }
- protected override void Load(CharacterInfo info, MirConnection connection)
- {
- info.Mount = new MountInfo(this);
- Info = info;
- HInfo = (HeroInfo)info;
- Stats = new Stats();
- if (Level == 0) NewCharacter();
- RefreshStats();
- SendInfo();
- switch (HP)
- {
- case 0:
- Dead = true;
- break;
- case -1:
- SetHP(Stats[Stat.HP]);
- SetMP(Stats[Stat.MP]);
- break;
- }
- }
- protected override void NewCharacter()
- {
- base.NewCharacter();
- Grade = (byte)Envir.Random.Next(4);
- }
- public override void Enqueue(Packet p)
- {
- if (p == null) return;
- switch ((ServerPacketIds)p.Index)
- {
- case ServerPacketIds.AddBuff:
- case ServerPacketIds.RemoveBuff:
- case ServerPacketIds.PauseBuff:
- case ServerPacketIds.MagicDelay:
- case ServerPacketIds.MagicLeveled:
- case ServerPacketIds.DeleteItem:
- case ServerPacketIds.UseItem:
- Owner.Enqueue(p);
- break;
- }
- }
- public override void RefreshNameColour()
- {
- Color colour = Color.MediumOrchid;
- if (colour == NameColour) return;
- NameColour = colour;
- if ((Owner.MyGuild == null) || (!Owner.MyGuild.IsAtWar()))
- Enqueue(new S.ColourChanged { NameColour = NameColour });
- BroadcastColourChange();
- }
- public void Spawn(Map map, Point p)
- {
- CurrentLocation = p;
- map.AddObject(this);
- CurrentMap = map;
- Envir.Heroes.Add(this);
- Spawned();
- }
- public void Despawn(bool cleanup)
- {
- Despawn();
- if (cleanup)
- CleanUp();
- }
- public override void Despawn()
- {
- Envir.Heroes.Remove(this);
-
- if (Node != null)
- {
- CurrentMap.RemoveObject(this);
- for (int i = Buffs.Count - 1; i >= 0; i--)
- {
- var buff = Buffs[i];
- buff.Caster = null;
- buff.ObjectID = 0;
- if (buff.Properties.HasFlag(BuffProperty.RemoveOnExit))
- {
- Buffs.RemoveAt(i);
- }
- }
- base.Despawn();
- }
- }
- protected override void CleanUp()
- {
- Owner = null;
- Info = null;
- }
- public override void Spawned()
- {
- base.Spawned();
- BroadcastHealthChange();
- BroadcastManaChange();
- BroadcastColourChange();
- }
- public override void Add(HumanObject player)
- {
- base.Add(player);
- if (player is PlayerObject viewer)
- {
- viewer.Enqueue(new S.ObjectColourChanged
- {
- ObjectID = ObjectID,
- NameColour = viewer.GetNameColour(this)
- });
- }
- }
- protected virtual void GetItemInfo()
- {
- UserItem item;
- for (int i = 0; i < Info.Inventory.Length; i++)
- {
- item = Info.Inventory[i];
- if (item == null) continue;
- Owner.CheckItem(item);
- }
- for (int i = 0; i < Info.Equipment.Length; i++)
- {
- item = Info.Equipment[i];
- if (item == null) continue;
- Owner.CheckItem(item);
- }
- if (HPItemIndex > 0)
- Owner.CheckItemInfo(Envir.GetItemInfo(HPItemIndex));
- if (MPItemIndex > 0)
- Owner.CheckItemInfo(Envir.GetItemInfo(MPItemIndex));
- }
- public override void SendMagicInfo(UserMagic magic)
- {
- Owner.Enqueue(magic.GetInfo(true));
- }
- protected bool CanUseMagic(UserMagic magic)
- {
- if (magic == null) return false;
- if (MagicCost(magic) > MP) return false;
- if (magic.Key <= 0) return false;
- return true;
- }
- protected bool HasMagic(Spell spell) => Info.Magics.Any(x => x.Spell == spell);
- public override bool TryMagic()
- {
- return true;
- }
- public override void BeginMagic(Spell spell, MirDirection dir, uint targetID, Point location, bool spellTargetLock = false)
- {
- NextMagicSpell = spell;
- NextMagicDirection = dir;
- NextMagicTargetID = targetID;
- NextMagicLocation = location;
- }
- public override MapObject DefaultMagicTarget => Owner;
- public override void UseItem(ulong id)
- {
- S.UseItem p = new S.UseItem { UniqueID = id, Grid = MirGridType.HeroInventory, Success = false };
- UserItem item = null;
- int index = -1;
- if (Owner.Hero != null && Owner.Hero.Dead) return;
- for (int i = 0; i < Info.Inventory.Length; i++)
- {
- item = Info.Inventory[i];
- if (item == null || item.UniqueID != id) continue;
- index = i;
- break;
- }
- if (item == null || index == -1 || !CanUseItem(item))
- {
- Owner.Enqueue(p);
- return;
- }
- if (Dead && !(item.Info.Type == ItemType.Scroll && item.Info.Shape == 6))
- {
- Owner.Enqueue(p);
- return;
- }
- switch (item.Info.Type)
- {
- case ItemType.Potion:
- switch (item.Info.Shape)
- {
- case 0: //NormalPotion
- PotHealthAmount = (ushort)Math.Min(ushort.MaxValue, PotHealthAmount + item.Info.Stats[Stat.HP]);
- PotManaAmount = (ushort)Math.Min(ushort.MaxValue, PotManaAmount + item.Info.Stats[Stat.MP]);
- break;
- case 1: //SunPotion
- ChangeHP(item.Info.Stats[Stat.HP]);
- ChangeMP(item.Info.Stats[Stat.MP]);
- break;
- case 2: //MysteryWater
- if (UnlockCurse)
- {
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.ReincarnationFailed), ChatType.Hint);
- Owner.Enqueue(p);
- return;
- }
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouCanUnequipCursedItem), ChatType.Hint);
- UnlockCurse = true;
- break;
- case 3: //Buff
- {
- int time = item.Info.Durability;
- if (item.GetTotal(Stat.MaxDC) > 0)
- AddBuff(BuffType.Impact, this, time * Settings.Minute, new Stats { [Stat.MaxDC] = item.GetTotal(Stat.MaxDC) });
- if (item.GetTotal(Stat.MaxMC) > 0)
- AddBuff(BuffType.Magic, this, time * Settings.Minute, new Stats { [Stat.MaxMC] = item.GetTotal(Stat.MaxMC) });
- if (item.GetTotal(Stat.MaxSC) > 0)
- AddBuff(BuffType.Taoist, this, time * Settings.Minute, new Stats { [Stat.MaxSC] = item.GetTotal(Stat.MaxSC) });
- if (item.GetTotal(Stat.AttackSpeed) > 0)
- AddBuff(BuffType.Storm, this, time * Settings.Minute, new Stats { [Stat.AttackSpeed] = item.GetTotal(Stat.AttackSpeed) });
- if (item.GetTotal(Stat.HP) > 0)
- AddBuff(BuffType.HealthAid, this, time * Settings.Minute, new Stats { [Stat.HP] = item.GetTotal(Stat.HP) });
- if (item.GetTotal(Stat.MP) > 0)
- AddBuff(BuffType.ManaAid, this, time * Settings.Minute, new Stats { [Stat.MP] = item.GetTotal(Stat.MP) });
- if (item.GetTotal(Stat.MaxAC) > 0)
- AddBuff(BuffType.Defence, this, time * Settings.Minute, new Stats { [Stat.MaxAC] = item.GetTotal(Stat.MaxAC) });
- if (item.GetTotal(Stat.MaxMAC) > 0)
- AddBuff(BuffType.MagicDefence, this, time * Settings.Minute, new Stats { [Stat.MaxMAC] = item.GetTotal(Stat.MaxMAC) });
- if (item.GetTotal(Stat.BagWeight) > 0)
- AddBuff(BuffType.BagWeight, this, time * Settings.Minute, new Stats { [Stat.BagWeight] = item.GetTotal(Stat.BagWeight) });
- }
- break;
- case 4: //Exp
- {
- int time = item.Info.Durability;
- AddBuff(BuffType.Exp, this, Settings.Minute * time, new Stats { [Stat.ExpRatePercent] = item.GetTotal(Stat.Luck) });
- }
- break;
- case 5: //Drop
- {
- int time = item.Info.Durability;
- AddBuff(BuffType.Drop, this, Settings.Minute * time, new Stats { [Stat.ItemDropRatePercent] = item.GetTotal(Stat.Luck) });
- }
- break;
- }
- break;
- case ItemType.Scroll:
- UserItem temp;
- switch (item.Info.Shape)
- {
- case 3: //BenedictionOil
- if (!TryLuckWeapon())
- {
- Owner.Enqueue(p);
- return;
- }
- break;
- case 4: //RepairOil
- temp = Info.Equipment[(int)EquipmentSlot.Weapon];
- if (temp == null || temp.MaxDura == temp.CurrentDura)
- {
- Owner.Enqueue(p);
- return;
- }
- if (temp.Info.Bind.HasFlag(BindMode.DontRepair))
- {
- Owner.Enqueue(p);
- return;
- }
- temp.MaxDura = (ushort)Math.Max(0, temp.MaxDura - Math.Min(5000, temp.MaxDura - temp.CurrentDura) / 30);
- temp.CurrentDura = (ushort)Math.Min(temp.MaxDura, temp.CurrentDura + 5000);
- temp.DuraChanged = false;
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.HeroWeaponPartiallyRepaired), ChatType.Hint);
- Owner.Enqueue(new S.ItemRepaired { UniqueID = temp.UniqueID, MaxDura = temp.MaxDura, CurrentDura = temp.CurrentDura });
- break;
- case 5: //WarGodOil
- temp = Info.Equipment[(int)EquipmentSlot.Weapon];
- if (temp == null || temp.MaxDura == temp.CurrentDura)
- {
- Owner.Enqueue(p);
- return;
- }
- if (temp.Info.Bind.HasFlag(BindMode.DontRepair) || (temp.Info.Bind.HasFlag(BindMode.NoSRepair)))
- {
- Owner.Enqueue(p);
- return;
- }
- temp.CurrentDura = temp.MaxDura;
- temp.DuraChanged = false;
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.HeroWeaponRepaired), ChatType.Hint);
- Owner.Enqueue(new S.ItemRepaired { UniqueID = temp.UniqueID, MaxDura = temp.MaxDura, CurrentDura = temp.CurrentDura });
- break;
- case 6: //ResurrectionScroll
- if (CurrentMap.Info.NoReincarnation)
- {
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CannotUseOnThisMap), ChatType.System);
- Owner.Enqueue(p);
- return;
- }
- if (Dead)
- {
- MP = Stats[Stat.MP];
- Revive(MaxHealth, true);
- }
- break;
- case 15: //Increase Hero inventory
- if (Info.Inventory.Length >= 42)
- {
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.HeroInventoryMax)
- , ChatType.System);
- Owner.Enqueue(p);
- return;
- }
- Enqueue(new S.ResizeInventory { Size = Info.ResizeInventory() });
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.HeroInventoryIncreased), ChatType.System);
- Owner.Enqueue(p);
- break;
- }
- break;
- case ItemType.Book:
- UserMagic magic = new UserMagic((Spell)item.Info.Shape);
- if (magic.Info == null)
- {
- Owner.Enqueue(p);
- return;
- }
- Info.Magics.Add(magic);
- SendMagicInfo(magic);
- RefreshStats();
- break;
- case ItemType.Food:
- temp = Info.Equipment[(int)EquipmentSlot.Mount];
- if (temp == null || temp.MaxDura == temp.CurrentDura)
- {
- Owner.Enqueue(p);
- return;
- }
- switch (item.Info.Shape)
- {
- case 0:
- temp.MaxDura = (ushort)Math.Max(0, temp.MaxDura - Math.Min(1000, temp.MaxDura - (temp.CurrentDura / 30)));
- break;
- case 1:
- break;
- }
- temp.CurrentDura = (ushort)Math.Min(temp.MaxDura, temp.CurrentDura + item.CurrentDura);
- temp.DuraChanged = false;
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.HeroMountFed), ChatType.Hint);
- Owner.Enqueue(new S.ItemRepaired { UniqueID = temp.UniqueID, MaxDura = temp.MaxDura, CurrentDura = temp.CurrentDura });
- RefreshStats();
- break;
- case ItemType.Transform: //Transforms
- {
- AddBuff(BuffType.Transform, this, (Settings.Second * item.Info.Durability), new Stats(), values: item.Info.Shape);
- }
- break;
- case ItemType.Deco:
- DecoObject decoOb = new DecoObject
- {
- Image = item.Info.Shape,
- CurrentMap = CurrentMap,
- CurrentLocation = CurrentLocation,
- };
- CurrentMap.AddObject(decoOb);
- decoOb.Spawned();
- Owner.Enqueue(decoOb.GetInfo());
- break;
- case ItemType.MonsterSpawn:
- var monsterID = item.Info.Stats[Stat.HP];
- var spawnAsPet = item.Info.Shape == 1;
- var conquestOnly = item.Info.Shape == 2;
- var monsterInfo = Envir.GetMonsterInfo(monsterID);
- if (monsterInfo == null) break;
- MonsterObject monster = MonsterObject.GetMonster(monsterInfo);
- if (monster == null) break;
- if (spawnAsPet)
- {
- if (Pets.Count(t => !t.Dead && t.Race != ObjectType.Creature) >= Globals.MaxPets)
- {
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.MaximumPetsReached), ChatType.Hint);
- Owner.Enqueue(p);
- return;
- }
- monster.Master = this;
- monster.PetLevel = 0;
- monster.MaxPetLevel = 7;
- Pets.Add(monster);
- }
- if (conquestOnly)
- {
- var con = CurrentMap.GetConquest(CurrentLocation);
- if (con == null)
- {
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.MonsterOnlySpawnDuringConquest), monsterInfo.GameName), ChatType.Hint);
- Owner.Enqueue(p);
- return;
- }
- }
- monster.Direction = Direction;
- monster.ActionTime = Envir.Time + 5000;
- if (!monster.Spawn(CurrentMap, Front))
- monster.Spawn(CurrentMap, CurrentLocation);
- break;
- case ItemType.SiegeAmmo:
- //TODO;
- break;
- default:
- return;
- }
- if (item.Count > 1) item.Count--;
- else Info.Inventory[index] = null;
- RefreshBagWeight();
- Report?.ItemChanged(item, 1, 1);
- p.Success = true;
- Owner.Enqueue(p);
- }
- public override void Die()
- {
- if (SpecialMode.HasFlag(SpecialItemMode.Revival) && Envir.Time > LastRevivalTime)
- {
- LastRevivalTime = Envir.Time + 300000;
- for (var i = (int)EquipmentSlot.RingL; i <= (int)EquipmentSlot.RingR; i++)
- {
- var item = Info.Equipment[i];
- if (item == null) continue;
- if (!(item.Info.Unique.HasFlag(SpecialItemMode.Revival)) || item.CurrentDura < 1000) continue;
- SetHP(Stats[Stat.HP]);
- item.CurrentDura = (ushort)(item.CurrentDura - 1000);
- Enqueue(new S.DuraChanged { UniqueID = item.UniqueID, CurrentDura = item.CurrentDura });
- RefreshStats();
- ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.HeroSecondChanceLife), ChatType.System);
- return;
- }
- }
- for (int i = Pets.Count - 1; i >= 0; i--)
- {
- if (Pets[i].Dead) continue;
- Pets[i].Die();
- }
- RemoveBuff(BuffType.MagicShield);
- RemoveBuff(BuffType.ElementalBarrier);
- if (!InSafeZone)
- DeathDrop(LastHitter);
- HP = 0;
- Dead = true;
- LogTime = Envir.Time;
- BrownTime = Envir.Time;
- Broadcast(new S.ObjectDied { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
- Owner.Enqueue(new S.UpdateHeroSpawnState { State = HeroSpawnState.Dead });
- for (int i = 0; i < Buffs.Count; i++)
- {
- Buff buff = Buffs[i];
- if (!buff.Properties.HasFlag(BuffProperty.RemoveOnDeath)) continue;
- RemoveBuff(buff.Type);
- }
- PoisonList.Clear();
- InTrapRock = false;
- }
- public override void Revive(int hp, bool effect)
- {
- if (!Dead) return;
- SetHP(hp);
- SetMP(Stats[Stat.MP]);
- CurrentMap.RemoveObject(this);
- Broadcast(new S.ObjectRemove { ObjectID = ObjectID });
- Dead = false;
- ActionTime = Envir.Time + RevivalDelay;
- CurrentMap.AddObject(this);
- BroadcastInfo();
- Broadcast(new S.ObjectRevived { ObjectID = ObjectID, Effect = effect });
- }
- public override void LevelUp()
- {
- base.LevelUp();
- Owner.Enqueue(new S.HeroLevelChanged { Level = Level, Experience = Experience, MaxExperience = MaxExperience });
- }
- protected override void SendHealthChanged()
- {
- Owner.Enqueue(new S.HeroHealthChanged { HP = HP, MP = MP });
- base.SendHealthChanged();
- BroadcastManaChange();
- }
- public override void BroadcastHealthChange()
- {
- 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;
- }
- Owner.Enqueue(p);
- if (Owner.GroupMembers != null)
- {
- for (int i = 0; i < Owner.GroupMembers.Count; i++)
- {
- PlayerObject member = Owner.GroupMembers[i];
- if (Master == member) continue;
- if (member.CurrentMap != CurrentMap || !Functions.InRange(member.CurrentLocation, CurrentLocation, Globals.DataRange)) continue;
- member.Enqueue(p);
- }
- }
- }
- public byte PercentMana
- {
- get { return (byte)(MP / (float)Stats[Stat.MP] * 100); }
- }
- public void BroadcastManaChange()
- {
- Packet p = new S.ObjectMana { ObjectID = ObjectID, Percent = PercentMana };
- Owner.Enqueue(p);
- }
- public override void Process(DelayedAction action)
- {
- if (action.FlaggedToRemove)
- return;
- switch (action.Type)
- {
- case DelayedType.Magic:
- CompleteMagic(action.Params);
- break;
- case DelayedType.Damage:
- CompleteAttack(action.Params);
- break;
- case DelayedType.Mine:
- CompleteMine(action.Params);
- break;
- case DelayedType.Poison:
- CompletePoison(action.Params);
- break;
- case DelayedType.DamageIndicator:
- CompleteDamageIndicator(action.Params);
- break;
- case DelayedType.SpellEffect:
- CompleteSpellEffect(action.Params);
- break;
- }
- }
- public override void Process()
- {
- if (Node == null || Info == null) return;
-
- if (Owner != null && Owner.CurrentMap != null && Owner.CurrentMap.Info.NoHero)
- {
- Owner.DespawnHero();
- return;
- }
- base.Process();
- if (Target != null && (Target.CurrentMap != CurrentMap || !Target.IsAttackTarget(this) || !Functions.InRange(CurrentLocation, Target.CurrentLocation, Globals.DataRange)))
- Target = null;
- if (Owner != null && !Owner.CurrentMap.Info.NoHero)
- {
- if ((!Functions.InRange(CurrentLocation, Owner.CurrentLocation, Globals.DataRange) || CurrentMap != Owner.CurrentMap) && CanMove)
- OwnerRecall();
- }
- if (Dead) return;
- if (Owner.PMode == PetMode.MoveOnly || Owner.PMode == PetMode.None)
- Target = null;
- ProcessAutoPot();
- ProcessStacking();
- ProcessSearch();
- ProcessAI();
- ProcessTarget();
- ProcessRoam();
- }
- protected void ProcessAutoPot()
- {
- if (Envir.Time < AutoPotTime) return;
- AutoPotTime = Envir.Time + AutoPotDelay;
- if (PercentHealth < AutoHPPercent && HPItemIndex > 0 && PotHealthAmount <= 0)
- TryAutoPot(HPItemIndex);
- if (PercentMana < AutoMPPercent && MPItemIndex > 0 && PotManaAmount <= 0)
- TryAutoPot(MPItemIndex);
- }
- protected void TryAutoPot(int ItemIndex)
- {
- for (int i = 0; i < Info.Inventory.Length; i++)
- {
- UserItem item = Info.Inventory[i];
- if (item == null) continue;
- if (item.Info.Index != ItemIndex) continue;
- UseItem(item.UniqueID);
- return;
- }
- }
- protected void ProcessAI()
- {
- if (NextMagicSpell != Spell.None) return;
- ProcessFriend();
- if (NextMagicSpell != Spell.None) return;
- ProcessAttack();
- }
- protected virtual void ProcessStacking()
- {
- Stacking = CheckStacked();
- if (CanMove && ((Owner != null && Owner.Front == CurrentLocation) || Stacking))
- {
- if (!Walk(Direction))
- {
- MirDirection dir = Direction;
- switch (Envir.Random.Next(3))
- {
- case 0:
- for (int i = 0; i < 7; i++)
- {
- dir = Functions.NextDir(dir);
- if (Walk(dir))
- break;
- }
- break;
- default:
- for (int i = 0; i < 7; i++)
- {
- dir = Functions.PreviousDir(dir);
- if (Walk(dir))
- break;
- }
- break;
- }
- }
- return;
- }
- }
- protected virtual void ProcessSearch()
- {
- if (Envir.Time < SearchTime) return;
- if (Owner.Info.HeroBehaviour == HeroBehaviour.Follow || !Mount.CanAttack) return;
- SearchTime = Envir.Time + SearchDelay;
- if (Target == null || Envir.Random.Next(3) == 0)
- FindTarget();
- }
- protected virtual void ProcessRoam()
- {
- if (Target != null || Envir.Time < RoamTime) return;
- if (Owner != null)
- {
- MoveTo(Owner.Back);
- return;
- }
- RoamTime = Envir.Time + RoamDelay;
- }
- protected virtual void ProcessFriend() { }
- protected virtual void ProcessAttack() { }
- protected virtual void ProcessTarget()
- {
- if (CanCast && NextMagicSpell != Spell.None)
- {
- Magic(NextMagicSpell, NextMagicDirection, NextMagicTargetID, NextMagicLocation);
- NextMagicSpell = Spell.None;
- }
- if (Target == null || !CanAttack) return;
- TargetDistance = Functions.MaxDistance(CurrentLocation, Target.CurrentLocation);
- if (InAttackRange())
- {
- Attack();
- if (Target != null && Target.Dead)
- {
- FindTarget();
- }
- return;
- }
- MoveTo(Target.CurrentLocation);
- }
- protected virtual void Attack()
- {
- if (!Target.IsAttackTarget(Owner))
- {
- Target = null;
- return;
- }
- Direction = Functions.DirectionFromPoint(CurrentLocation, Target.CurrentLocation);
- Attack(Direction, Spell.None);
- }
- protected virtual bool InAttackRange()
- {
- if (Target.CurrentMap != CurrentMap) return false;
- return Target.CurrentLocation != CurrentLocation && Functions.InRange(CurrentLocation, Target.CurrentLocation, 1);
- }
- protected List<MapObject> FindAllTargets(int dist, Point location, bool needSight = true)
- {
- List<MapObject> targets = new List<MapObject>();
- for (int d = 0; d <= dist; d++)
- {
- for (int y = location.Y - d; y <= location.Y + d; y++)
- {
- if (y < 0) continue;
- if (y >= CurrentMap.Height) break;
- for (int x = location.X - d; x <= location.X + d; x += Math.Abs(y - location.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];
- switch (ob.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- case ObjectType.Hero:
- if (!ob.IsAttackTarget(this)) continue;
- if (ob.Hidden && (!CoolEye || Level < ob.Level) && needSight) continue;
- if (ob.Race == ObjectType.Player)
- {
- PlayerObject player = ((PlayerObject)ob);
- if (player.GMGameMaster) continue;
- }
- targets.Add(ob);
- continue;
- default:
- continue;
- }
- }
- }
- }
- }
- return targets;
- }
- protected virtual void MoveTo(Point location)
- {
- if (CurrentLocation == location) return;
- bool inRange = Functions.InRange(location, CurrentLocation, 1);
- bool inRunRange = RidingMount ? Functions.InRange(location, CurrentLocation, 2) : inRange;
- if (inRange)
- {
- if (!CurrentMap.ValidPoint(location)) return;
- Cell cell = CurrentMap.GetCell(location);
- if (cell.Objects != null)
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject ob = cell.Objects[i];
- if (!ob.Blocking) continue;
- return;
- }
- }
- MirDirection dir = Functions.DirectionFromPoint(CurrentLocation, location);
- if (!inRunRange && _stepCounter > 0 && Run(dir))
- return;
- if (Walk(dir)) return;
- switch (Envir.Random.Next(2))
- {
- case 0:
- for (int i = 0; i < 7; i++)
- {
- dir = Functions.NextDir(dir);
- if (Walk(dir))
- return;
- }
- break;
- default:
- for (int i = 0; i < 7; i++)
- {
- dir = Functions.PreviousDir(dir);
- if (Walk(dir))
- return;
- }
- break;
- }
- }
- public void OwnerRecall()
- {
- if (Owner == null) return;
- if (Owner.CurrentMap != null && Owner.CurrentMap.Info.NoHero)
- return;
-
- if (Dead)
- {
- Despawn(false);
- return;
- }
- if (!Teleport(Owner.CurrentMap, Owner.Back))
- Teleport(Owner.CurrentMap, Owner.CurrentLocation);
- if (!Dead)
- {
- BroadcastManaChange();
- }
- }
- protected virtual void FindTarget()
- {
- Map Current = CurrentMap;
- for (int d = 0; d <= ViewRange; d++)
- {
- for (int y = CurrentLocation.Y - d; y <= CurrentLocation.Y + d; y++)
- {
- if (y < 0) continue;
- if (y >= Current.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 >= Current.Width) break;
- Cell cell = Current.Cells[x, y];
- if (cell.Objects == null || !cell.Valid) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject ob = cell.Objects[i];
- switch (ob.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Hero:
- if (ob is TownArcher) continue;
- if (!ob.IsAttackTarget(Owner)) continue;
- if (ob.Hidden && (!CoolEye || Level < ob.Level)) continue;
- if (ob.Master != null && Target != ob) continue;
- if (Owner.Info.HeroBehaviour == HeroBehaviour.CounterAttack && ob.Target != this && ob.Target != Owner) continue;
- Target = ob;
- return;
- case ObjectType.Player:
- PlayerObject playerob = (PlayerObject)ob;
- if (!ob.IsAttackTarget(Owner)) continue;
- if (playerob.GMGameMaster || ob.Hidden && (!CoolEye || Level < ob.Level)) continue;
- if (Target != ob && Owner.LastHitter != ob && ob.LastHitter != Owner) continue;
- Target = ob;
- if (Owner != null)
- {
- for (int j = 0; j < playerob.Pets.Count; j++)
- {
- MonsterObject pet = playerob.Pets[j];
- if (!pet.IsAttackTarget(this)) continue;
- Target = pet;
- break;
- }
- }
- return;
- default:
- continue;
- }
- }
- }
- }
- }
- }
- public override bool IsAttackTarget(HumanObject attacker)
- {
- if (Owner == null) return false;
- if (Dead) return false;
- return Owner.IsAttackTarget(attacker);
- }
- public override bool IsAttackTarget(MonsterObject attacker)
- {
- if (Owner == null) return false;
- if (Dead) return false;
- return Owner.IsAttackTarget(attacker);
- }
- public override bool IsFriendlyTarget(HumanObject ally)
- {
- if (Owner == null) return false;
- return Owner.IsFriendlyTarget(ally);
- }
- public override bool IsFriendlyTarget(MonsterObject ally)
- {
- if (Owner == null) return false;
- return Owner.IsFriendlyTarget(ally);
- }
- public override void WinExp(uint amount, uint targetLevel = 0)
- {
- Owner.WinExp(amount, targetLevel);
- }
- public override void GainExp(uint amount)
- {
- if (amount == 0) return;
- if (CurrentMap?.Info?.NoExperience == true) return;
-
- for (int i = 0; i < Pets.Count; i++)
- {
- MonsterObject monster = Pets[i];
- if (monster.CurrentMap == CurrentMap && Functions.InRange(monster.CurrentLocation, CurrentLocation, Globals.DataRange) && !monster.Dead)
- monster.PetExp(amount);
- }
- if (!CanGainExp) return;
- if (Stats[Stat.ExpRatePercent] > 0)
- {
- amount += (uint)Math.Max(0, (amount * Stats[Stat.ExpRatePercent]) / 100);
- }
- Experience += amount;
- Owner.Enqueue(new S.GainHeroExperience { Amount = amount });
- if (Experience < MaxExperience) return;
- if (Level >= ushort.MaxValue) return;
- //Calculate increased levels
- var experience = Experience;
- while (experience >= MaxExperience)
- {
- Level++;
- experience -= MaxExperience;
- RefreshLevelStats();
- if (Level >= ushort.MaxValue) break;
- }
- Experience = experience;
- LevelUp();
- }
- private void SendInfo()
- {
- GetItemInfo();
- S.HeroInformation packet = new S.HeroInformation
- {
- ObjectID = ObjectID,
- Name = Name,
- Class = Class,
- Gender = Gender,
- Level = Level,
- Hair = Hair,
- HP = HP,
- MP = MP,
- Experience = Experience,
- MaxExperience = MaxExperience,
- Inventory = new UserItem[Info.Inventory.Length],
- Equipment = new UserItem[Info.Equipment.Length],
- AutoPot = AutoPot,
- AutoHPPercent = AutoHPPercent,
- AutoMPPercent = AutoMPPercent,
- HPItemIndex = HPItemIndex,
- MPItemIndex = MPItemIndex
- };
- for (int i = 0; i < Info.Magics.Count; i++)
- packet.Magics.Add(Info.Magics[i].CreateClientMagic());
- Info.Inventory.CopyTo(packet.Inventory, 0);
- Info.Equipment.CopyTo(packet.Equipment, 0);
- Owner.Enqueue(packet);
- SendBaseStats();
- }
- public override void SendHealth(HumanObject player)
- {
- 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;
- }
- Owner.Enqueue(p);
- if (Owner.GroupMembers != null)
- {
- for (int i = 0; i < Owner.GroupMembers.Count; i++)
- {
- PlayerObject member = Owner.GroupMembers[i];
- if (Master == member) continue;
- if (member.CurrentMap != CurrentMap || !Functions.InRange(member.CurrentLocation, CurrentLocation, Globals.DataRange)) continue;
- member.Enqueue(p);
- }
- }
- }
- protected override void SendBaseStats()
- {
- Owner.Enqueue(new S.HeroBaseStatsInfo { Stats = Settings.HeroBaseStats[(byte)Class] });
- }
- protected override void RefreshLevelStats()
- {
- RefreshMaxExperience();
- foreach (var stat in Settings.HeroBaseStats[(byte)Class].Stats)
- {
- Stats[stat.Type] = stat.Calculate(Class, Level);
- }
- }
- public override void RefreshMaxExperience()
- {
- MaxExperience = Level < Settings.HeroExperienceList.Count ? Settings.HeroExperienceList[Level - 1] : 0;
- }
- public override Packet GetInfo()
- {
- return new S.ObjectHero
- {
- ObjectID = ObjectID,
- Name = CurrentMap.Info.NoNames ? "?????" : Name,
- NameColour = NameColour,
- Class = Class,
- Gender = Gender,
- Level = Level,
- Location = CurrentLocation,
- Direction = Direction,
- Hair = Hair,
- Weapon = Looks_Weapon,
- WeaponEffect = Looks_WeaponEffect,
- Armour = Looks_Armour,
- Light = Light,
- Poison = CurrentPoison,
- Dead = Dead,
- Hidden = Hidden,
- Effect = HasBuff(BuffType.MagicShield, out _) ? SpellEffect.MagicShieldUp : HasBuff(BuffType.ElementalBarrier, out _) ? SpellEffect.ElementalBarrierUp : SpellEffect.None,
- WingEffect = Looks_Wings,
- MountType = Mount.MountType,
- RidingMount = RidingMount,
- TransformType = TransformType,
- ElementOrbEffect = (uint)GetElementalOrbCount(),
- ElementOrbLvl = (uint)ElementsLevel,
- ElementOrbMax = (uint)Settings.OrbsExpList[Settings.OrbsExpList.Count - 1],
- Buffs = Buffs.Where(d => d.Info.Visible).Select(e => e.Type).ToList(),
- LevelEffects = LevelEffects,
- OwnerName = Owner.Name
- };
- }
- }
- }
|