fix: Fixes ignoring mobs, champions, party crash, slayer rarity, boat speedhack, etc (#1222)
* Movie ignore mobiles to Mobile class * Allow necromancer familiars to ignore mobiles * ChampionSpawn should not quietly fail when creating new spawn * Fix client party crash bug: 2 people partied, the leader logs out, other client is hung * Fix spellbooks creating with magery/meditation only and creating magery multiple times * Fix BaseRunicTool.GetRandomSlayer() creating more undead slayers than intended * Do not allow players to dismount each other whilst mounted * Fix AOS onwards damage increase tooltip and wrong formula in AOS * Fix monsters killing other monster revenants + animate dead should not attack player pets + other animates * Fix fire steed having loot pack added twice * Fix oaks spawn not able to create Unicorns + Kirins via Activator.CreateInstace() due to constructor having name as parametr * Fix ignoreMobiles flag not propagated to client for non-players. * Fix harrower tents not leeching from players * Fix boats speedhacking around the map * Fix bless, agility etc. not renewing duration * Fix reveal always worked * Fix empty constructor for steeds so they don't throw now.
This commit is contained in:
parent
910e06767b
commit
053dbcbad0
54 changed files with 871 additions and 454 deletions
|
|
@ -329,6 +329,7 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
private int m_WarmodeChanges;
|
||||
private bool _warmodeSpamValue;
|
||||
private IWeapon m_Weapon;
|
||||
private bool _ignoreMobiles;
|
||||
|
||||
private bool m_YellowHealthbar;
|
||||
private List<StatMod> _statMods;
|
||||
|
|
@ -405,6 +406,20 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
|
||||
public virtual bool NewGuildDisplay => false;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public virtual bool IgnoreMobiles
|
||||
{
|
||||
get => _ignoreMobiles;
|
||||
set
|
||||
{
|
||||
if (_ignoreMobiles != value)
|
||||
{
|
||||
_ignoreMobiles = value;
|
||||
Delta(MobileDelta.Flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<Mobile> Stabled { get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)]
|
||||
|
|
@ -6974,6 +6989,11 @@ public class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPropertyLis
|
|||
flags |= 0x08;
|
||||
}
|
||||
|
||||
if (IgnoreMobiles)
|
||||
{
|
||||
flags |= 0x10;
|
||||
}
|
||||
|
||||
if (m_Warmode)
|
||||
{
|
||||
flags |= 0x40;
|
||||
|
|
|
|||
|
|
@ -94,7 +94,9 @@ namespace Server.Accounting
|
|||
_totalGameTime = reader.ReadTimeSpan();
|
||||
|
||||
if (version > 1)
|
||||
{
|
||||
_email = reader.ReadString();
|
||||
}
|
||||
|
||||
Timer.StartTimer(AfterDeserialization);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ using Server.Gumps;
|
|||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Regions;
|
||||
using Server.Logging;
|
||||
using Server.Utilities;
|
||||
|
||||
namespace Server.Engines.CannedEvil
|
||||
{
|
||||
public class ChampionSpawn : Item
|
||||
{
|
||||
private static readonly ILogger logger = LogFactory.GetLogger(typeof(ChampionSpawn));
|
||||
private bool m_Active;
|
||||
private ChampionSpawnType m_Type;
|
||||
private List<Mobile> m_Creatures;
|
||||
|
|
@ -597,11 +600,11 @@ namespace Server.Engines.CannedEvil
|
|||
{
|
||||
if (gainedPath)
|
||||
{
|
||||
m.SendLocalizedMessage(1054032); // You have gained a path in Valor!
|
||||
pm.SendLocalizedMessage(1054032); // You have gained a path in Valor!
|
||||
}
|
||||
else
|
||||
{
|
||||
m.SendLocalizedMessage(1054030); // You have gained in Valor!
|
||||
pm.SendLocalizedMessage(1054030); // You have gained in Valor!
|
||||
}
|
||||
|
||||
// No delay on Valor gains
|
||||
|
|
@ -682,10 +685,18 @@ namespace Server.Engines.CannedEvil
|
|||
|
||||
try
|
||||
{
|
||||
Champion = Activator.CreateInstance(ChampionSpawnInfo.GetInfo(m_Type).Champion) as Mobile;
|
||||
Champion = ChampionSpawnInfo.GetInfo(m_Type).Champion.CreateInstance<Mobile>();
|
||||
}
|
||||
catch (Exception e)
|
||||
{ Console.WriteLine($"Exception creating champion {m_Type}: {e}"); }
|
||||
{
|
||||
logger.Error(
|
||||
e,
|
||||
"Failed to spawn champion \"{MobileType}\" at {Location} ({Map}).",
|
||||
m_Type,
|
||||
Location,
|
||||
Map
|
||||
);
|
||||
}
|
||||
|
||||
if (Champion != null)
|
||||
{
|
||||
|
|
@ -851,12 +862,21 @@ namespace Server.Engines.CannedEvil
|
|||
|
||||
public Mobile Spawn(params Type[] types)
|
||||
{
|
||||
var type = types[Utility.Random(types.Length)];
|
||||
try
|
||||
{
|
||||
return Activator.CreateInstance(types[Utility.Random(types.Length)]) as Mobile;
|
||||
return type.CreateInstance<Mobile>();
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error(
|
||||
e,
|
||||
"Failed to spawn minion \"{Type}\" for champion {ChampionSpawnType} at {Location} ({Map}).",
|
||||
type,
|
||||
m_Type,
|
||||
Location,
|
||||
Map
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,9 +106,15 @@ namespace Server.Engines.CannedEvil
|
|||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Warning($"Failed to generate champion spawn {entry.m_ChampType.FullName} at {entry.m_SignLocation} ({entry.m_Map})");
|
||||
logger.Error(
|
||||
e,
|
||||
"Failed to generate champion \"{Type}\" at {Location} ({Map}).",
|
||||
entry.m_ChampType.FullName,
|
||||
entry.m_SignLocation,
|
||||
entry.m_Map
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class UnholySteed : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a dark steed";
|
||||
|
||||
[Constructible]
|
||||
public UnholySteed()
|
||||
: base("a dark steed", 0x74, 0x3EA7, AIType.AI_Melee, FightMode.Aggressor)
|
||||
public UnholySteed() : base(0x74, 0x3EA7, AIType.AI_Melee, FightMode.Aggressor)
|
||||
{
|
||||
SetStr(496, 525);
|
||||
SetDex(86, 105);
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class HolySteed : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a silver steed";
|
||||
[Constructible]
|
||||
public HolySteed()
|
||||
: base("a silver steed", 0x75, 0x3EA8, AIType.AI_Melee, FightMode.Aggressor)
|
||||
public HolySteed() : base(0x75, 0x3EA8, AIType.AI_Melee, FightMode.Aggressor)
|
||||
{
|
||||
SetStr(496, 525);
|
||||
SetDex(86, 105);
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ namespace Server.Factions
|
|||
public const int GoldPrice = 3000;
|
||||
private Faction m_Faction;
|
||||
|
||||
public override string DefaultName => "a war horse";
|
||||
|
||||
[Constructible]
|
||||
public FactionWarHorse(Faction faction = null)
|
||||
: base("a war horse", 0xE2, 0x3EA0, AIType.AI_Melee, FightMode.Aggressor)
|
||||
public FactionWarHorse(Faction faction = null) : base(0xE2, 0x3EA0, AIType.AI_Melee, FightMode.Aggressor)
|
||||
{
|
||||
BaseSoundID = 0xA8;
|
||||
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ namespace Server.Engines.PartySystem
|
|||
m.Party = this;
|
||||
|
||||
Span<byte> memberList =
|
||||
stackalloc byte[PartyPackets.GetPartyMemberListPacketLength(this)].InitializePacket();
|
||||
stackalloc byte[PartyPackets.GetPartyMemberListPacketLength(Count)].InitializePacket();
|
||||
Span<byte> attrsPacket = stackalloc byte[OutgoingMobilePackets.MobileAttributesPacketLength].InitializePacket();
|
||||
|
||||
for (var i = 0; i < Members.Count; ++i)
|
||||
|
|
@ -216,12 +216,7 @@ namespace Server.Engines.PartySystem
|
|||
}
|
||||
}
|
||||
|
||||
public void OnAccept(Mobile from)
|
||||
{
|
||||
OnAccept(from, false);
|
||||
}
|
||||
|
||||
public void OnAccept(Mobile from, bool force)
|
||||
public void OnAccept(Mobile from, bool force = false)
|
||||
{
|
||||
var ourFaction = Faction.Find(Leader);
|
||||
var theirFaction = Faction.Find(from);
|
||||
|
|
@ -289,28 +284,33 @@ namespace Server.Engines.PartySystem
|
|||
return;
|
||||
}
|
||||
|
||||
Span<byte> removeMember =
|
||||
stackalloc byte[PartyPackets.GetPartyRemoveMemberPacketLength(this)].InitializePacket();
|
||||
|
||||
var removed = false;
|
||||
for (var i = 0; i < Members.Count; i++)
|
||||
{
|
||||
if (Members[i].Mobile == m)
|
||||
{
|
||||
Members.RemoveAt(i);
|
||||
|
||||
m.NetState.SendPartyRemoveMember(m.Serial);
|
||||
m.Party = null;
|
||||
|
||||
m.SendLocalizedMessage(1005451); // You have been removed from the party.
|
||||
|
||||
PartyPackets.CreatePartyRemoveMember(removeMember, m.Serial, this);
|
||||
SendToAll(removeMember);
|
||||
SendToAll(1005452); // A player has been removed from your party.
|
||||
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed)
|
||||
{
|
||||
Span<byte> removeMember =
|
||||
stackalloc byte[PartyPackets.GetPartyRemoveMemberPacketLength(Count)].InitializePacket();
|
||||
|
||||
// Send empty party to the player removed
|
||||
m.NetState.SendPartyRemoveMember(m.Serial);
|
||||
m.Party = null;
|
||||
|
||||
m.SendLocalizedMessage(1005451); // You have been removed from the party.
|
||||
|
||||
PartyPackets.CreatePartyRemoveMember(removeMember, m.Serial, this);
|
||||
SendToAll(removeMember);
|
||||
SendToAll(1005452); // A player has been removed from your party.
|
||||
}
|
||||
|
||||
if (Members.Count == 1)
|
||||
{
|
||||
SendToAll(1005450); // The last person has left the party...
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Server.Engines.PartySystem
|
|||
public static class PartyPackets
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GetPartyMemberListPacketLength(Party p) => 7 + p.Count * 4;
|
||||
public static int GetPartyMemberListPacketLength(int partyCount) => 7 + partyCount * 4;
|
||||
|
||||
public static void CreatePartyMemberList(Span<byte> buffer, Party p)
|
||||
{
|
||||
|
|
@ -32,15 +32,16 @@ namespace Server.Engines.PartySystem
|
|||
return;
|
||||
}
|
||||
|
||||
var length = GetPartyMemberListPacketLength(p);
|
||||
var count = p.Count;
|
||||
var length = GetPartyMemberListPacketLength(count);
|
||||
var writer = new SpanWriter(buffer);
|
||||
writer.Write((byte)0xBF); // Packet ID
|
||||
writer.Write((ushort)length);
|
||||
writer.Write((ushort)0x06); // Sub-packet
|
||||
writer.Write((byte)0x01); // Command
|
||||
writer.Write((byte)p.Count);
|
||||
writer.Write((byte)count);
|
||||
|
||||
for (var i = 0; i < p.Count; ++i)
|
||||
for (var i = 0; i < count; ++i)
|
||||
{
|
||||
writer.Write(p[i].Mobile.Serial);
|
||||
}
|
||||
|
|
@ -53,14 +54,14 @@ namespace Server.Engines.PartySystem
|
|||
return;
|
||||
}
|
||||
|
||||
Span<byte> buffer = stackalloc byte[GetPartyMemberListPacketLength(p)];
|
||||
Span<byte> buffer = stackalloc byte[GetPartyMemberListPacketLength(p.Count)];
|
||||
CreatePartyMemberList(buffer, p);
|
||||
|
||||
ns.Send(buffer);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int GetPartyRemoveMemberPacketLength(Party p) => 11 + (p?.Count * 4 ?? 0);
|
||||
public static int GetPartyRemoveMemberPacketLength(int partyCount) => 11 + partyCount * 4;
|
||||
|
||||
public static void SendPartyRemoveMember(this NetState ns, Serial m, Party p = null)
|
||||
{
|
||||
|
|
@ -69,7 +70,7 @@ namespace Server.Engines.PartySystem
|
|||
return;
|
||||
}
|
||||
|
||||
Span<byte> buffer = stackalloc byte[GetPartyRemoveMemberPacketLength(p)];
|
||||
Span<byte> buffer = stackalloc byte[GetPartyRemoveMemberPacketLength(p?.Count ?? 0)];
|
||||
CreatePartyRemoveMember(buffer, m, p);
|
||||
|
||||
ns.Send(buffer);
|
||||
|
|
@ -82,14 +83,14 @@ namespace Server.Engines.PartySystem
|
|||
return;
|
||||
}
|
||||
|
||||
var length = GetPartyRemoveMemberPacketLength(p);
|
||||
var count = p?.Count ?? 0;
|
||||
var length = GetPartyRemoveMemberPacketLength(count);
|
||||
var writer = new SpanWriter(buffer);
|
||||
writer.Write((byte)0xBF); // Packet ID
|
||||
writer.Write((ushort)length);
|
||||
writer.Write((ushort)0x06); // Sub-packet
|
||||
writer.Write((byte)0x02); // Command
|
||||
|
||||
var count = p?.Count ?? 0;
|
||||
writer.Write((byte)count);
|
||||
writer.Write(removed);
|
||||
|
||||
|
|
|
|||
|
|
@ -218,13 +218,13 @@ namespace Server
|
|||
|
||||
m_Timer = new InternalTimer(this);
|
||||
m_Timer.Start();
|
||||
source.m_hontime = Core.Now + TimeSpan.FromMinutes(40);
|
||||
source._honorTime = Core.Now + TimeSpan.FromMinutes(40);
|
||||
|
||||
Timer.StartTimer(
|
||||
TimeSpan.FromMinutes(40),
|
||||
() =>
|
||||
{
|
||||
if (source.m_hontime < Core.Now && source.SentHonorContext != null)
|
||||
if (source._honorTime < Core.Now && source.SentHonorContext != null)
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ public static class ValorVirtue
|
|||
// Your challenge is heard by the Champion of this region! Beware its wrath!
|
||||
from.SendLocalizedMessage(1054037);
|
||||
idol.Spawn.Start();
|
||||
idol.Spawn.ActivatedByValor = true;
|
||||
// Uncomment to not allow advancing level after starting with valor.
|
||||
// idol.Spawn.HasBeenAdvanced = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -207,9 +207,10 @@ namespace Server.Items
|
|||
|
||||
private static void ApplySkillBonus(AosSkillBonuses attrs, int min, int max, int index, int low, int high)
|
||||
{
|
||||
var isSpellBook = attrs.Owner is Spellbook;
|
||||
var possibleSkills =
|
||||
new List<SkillName>(attrs.Owner is Spellbook ? m_PossibleSpellbookSkills : m_PossibleBonusSkills);
|
||||
var count = Core.SE ? possibleSkills.Count : possibleSkills.Count - 2;
|
||||
new List<SkillName>(isSpellBook ? m_PossibleSpellbookSkills : m_PossibleBonusSkills);
|
||||
var count = Core.SE || isSpellBook ? possibleSkills.Count : possibleSkills.Count - 2;
|
||||
|
||||
SkillName sk;
|
||||
bool found;
|
||||
|
|
@ -234,20 +235,30 @@ namespace Server.Items
|
|||
switch (res)
|
||||
{
|
||||
case ResistanceType.Physical:
|
||||
ar.PhysicalBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
{
|
||||
ar.PhysicalBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Fire:
|
||||
ar.FireBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
{
|
||||
ar.FireBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Cold:
|
||||
ar.ColdBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
{
|
||||
ar.ColdBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Poison:
|
||||
ar.PoisonBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
{
|
||||
ar.PoisonBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
}
|
||||
case ResistanceType.Energy:
|
||||
ar.EnergyBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
{
|
||||
ar.EnergyBonus += Scale(min, max, low, high);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -332,20 +343,30 @@ namespace Server.Items
|
|||
switch (Utility.Random(5))
|
||||
{
|
||||
case 0:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitPhysicalArea, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitPhysicalArea, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitFireArea, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitFireArea, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitColdArea, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitColdArea, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitPoisonArea, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitPoisonArea, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitEnergyArea, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitEnergyArea, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -355,17 +376,25 @@ namespace Server.Items
|
|||
switch (Utility.Random(4))
|
||||
{
|
||||
case 0:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitMagicArrow, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitMagicArrow, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitHarm, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitHarm, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitFireball, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitFireball, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLightning, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLightning, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -375,81 +404,129 @@ namespace Server.Items
|
|||
switch (Utility.Random(2))
|
||||
{
|
||||
case 0:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.UseBestSkill, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.UseBestSkill, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.MageWeapon, 1, 10);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.MageWeapon, 1, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.WeaponDamage, 1, 50);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.WeaponDamage, 1, 50);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.WeaponSpeed, 5, 30, 5);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.WeaponSpeed, 5, 30, 5);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.SpellChanneling, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.SpellChanneling, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitDispel, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitDispel, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechHits, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechHits, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLowerAttack, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLowerAttack, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLowerDefend, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLowerDefend, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechMana, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechMana, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechStam, 2, 50, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.HitLeechStam, 2, 50, 2);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.LowerStatReq, 10, 100, 10);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.LowerStatReq, 10, 100, 10);
|
||||
break;
|
||||
}
|
||||
case 17:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPhysicalBonus, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPhysicalBonus, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 18:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistFireBonus, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistFireBonus, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 19:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistColdBonus, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistColdBonus, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 20:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPoisonBonus, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPoisonBonus, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 21:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistEnergyBonus, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistEnergyBonus, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 22:
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.DurabilityBonus, 10, 100, 10);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosWeaponAttribute.DurabilityBonus, 10, 100, 10);
|
||||
break;
|
||||
}
|
||||
case 23:
|
||||
weapon.Slayer = GetRandomSlayer();
|
||||
break;
|
||||
{
|
||||
weapon.Slayer = GetRandomSlayer();
|
||||
break;
|
||||
}
|
||||
case 24:
|
||||
GetElementalDamages(weapon);
|
||||
break;
|
||||
{
|
||||
GetElementalDamages(weapon);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -529,14 +606,14 @@ namespace Server.Items
|
|||
return SlayerName.None;
|
||||
}
|
||||
|
||||
// -1 To Exclude the Fey Slayer which appears ONLY on a certain artifact.
|
||||
var group = groups[Utility.Random(groups.Length - 1)];
|
||||
// 10% chance of a super - skip fey
|
||||
if (Utility.RandomDouble() < 0.10)
|
||||
{
|
||||
return groups[Utility.Random(groups.Length - 1)].Super.Name;
|
||||
}
|
||||
|
||||
// 10% chance for a super slayer
|
||||
var entry = group.Entries.Length == 0 || Utility.Random(10) == 0
|
||||
? group.Super : group.Entries.RandomElement();
|
||||
|
||||
return entry.Name;
|
||||
// Minor slayer - skip fey and undead
|
||||
return groups[Utility.Random(groups.Length - 2)].Entries.RandomElement().Name;
|
||||
}
|
||||
|
||||
public void ApplyAttributesTo(BaseArmor armor)
|
||||
|
|
@ -611,87 +688,135 @@ namespace Server.Items
|
|||
{
|
||||
/* Begin Shields */
|
||||
case 0:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.SpellChanneling, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.SpellChanneling, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
if (Core.ML)
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15);
|
||||
}
|
||||
if (Core.ML)
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15);
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1);
|
||||
break;
|
||||
}
|
||||
/* Begin Armor */
|
||||
case 4:
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10);
|
||||
break;
|
||||
}
|
||||
/* End Shields */
|
||||
case 7:
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.MageArmor, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.MageArmor, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenHits, 1, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenHits, 1, 2);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenStam, 1, 3);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenStam, 1, 3);
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2);
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusHits, 1, 5);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusHits, 1, 5);
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusStam, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusStam, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20);
|
||||
break;
|
||||
}
|
||||
case 17:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100);
|
||||
break;
|
||||
}
|
||||
case 18:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 19:
|
||||
ApplyResistance(armor, min, max, ResistanceType.Physical, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyResistance(armor, min, max, ResistanceType.Physical, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 20:
|
||||
ApplyResistance(armor, min, max, ResistanceType.Fire, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyResistance(armor, min, max, ResistanceType.Fire, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 21:
|
||||
ApplyResistance(armor, min, max, ResistanceType.Cold, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyResistance(armor, min, max, ResistanceType.Cold, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 22:
|
||||
ApplyResistance(armor, min, max, ResistanceType.Poison, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyResistance(armor, min, max, ResistanceType.Poison, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 23:
|
||||
ApplyResistance(armor, min, max, ResistanceType.Energy, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyResistance(armor, min, max, ResistanceType.Energy, 1, 15);
|
||||
break;
|
||||
}
|
||||
/* End Armor */
|
||||
}
|
||||
}
|
||||
|
|
@ -728,62 +853,100 @@ namespace Server.Items
|
|||
switch (random)
|
||||
{
|
||||
case 0:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.ReflectPhysical, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenHits, 1, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenHits, 1, 2);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenStam, 1, 3);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenStam, 1, 3);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusHits, 1, 5);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusHits, 1, 5);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusStam, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusStam, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20);
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100);
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5);
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10);
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 17:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 18:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -819,77 +982,125 @@ namespace Server.Items
|
|||
switch (random)
|
||||
{
|
||||
case 0:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.WeaponDamage, 1, 25);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.WeaponDamage, 1, 25);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.DefendChance, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.AttackChance, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusStr, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusStr, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusDex, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusDex, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusInt, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusInt, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.EnhancePotions, 5, 25, 5);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.EnhancePotions, 5, 25, 5);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastRecovery, 1, 3);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastRecovery, 1, 3);
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20);
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.Luck, 1, 100);
|
||||
break;
|
||||
}
|
||||
case 17:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.SpellDamage, 1, 12);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.SpellDamage, 1, 12);
|
||||
break;
|
||||
}
|
||||
case 18:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.NightSight, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 19:
|
||||
ApplySkillBonus(skills, min, max, 0, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 0, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 20:
|
||||
ApplySkillBonus(skills, min, max, 1, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 1, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 21:
|
||||
ApplySkillBonus(skills, min, max, 2, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 2, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 22:
|
||||
ApplySkillBonus(skills, min, max, 3, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 3, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 23:
|
||||
ApplySkillBonus(skills, min, max, 4, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 4, 1, 15);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -938,41 +1149,65 @@ namespace Server.Items
|
|||
break;
|
||||
}
|
||||
case 4:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.BonusMana, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastSpeed, 1, 1);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastRecovery, 1, 3);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.CastRecovery, 1, 3);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.SpellDamage, 1, 12);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.SpellDamage, 1, 12);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
ApplySkillBonus(skills, min, max, 0, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 0, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
ApplySkillBonus(skills, min, max, 1, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 1, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
ApplySkillBonus(skills, min, max, 2, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 2, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
ApplySkillBonus(skills, min, max, 3, 1, 15);
|
||||
break;
|
||||
{
|
||||
ApplySkillBonus(skills, min, max, 3, 1, 15);
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerRegCost, 1, 20);
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.LowerManaCost, 1, 8);
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2);
|
||||
break;
|
||||
{
|
||||
ApplyAttribute(primary, min, max, AosAttribute.RegenMana, 1, 2);
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
spellbook.Slayer = GetRandomSlayer();
|
||||
break;
|
||||
{
|
||||
spellbook.Slayer = GetRandomSlayer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,11 +35,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class GrizzledMare : HellSteed
|
||||
{
|
||||
private static readonly string m_Myname = "a grizzled mare";
|
||||
public override string DefaultName => "a grizzled mare";
|
||||
|
||||
[Constructible]
|
||||
public GrizzledMare()
|
||||
: base(m_Myname)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -49,18 +48,11 @@ namespace Server.Mobiles
|
|||
|
||||
public override bool DeleteOnRelease => true;
|
||||
|
||||
public virtual void OnAfterDeserialize_Callback()
|
||||
{
|
||||
SetStats(this);
|
||||
|
||||
Name = m_Myname;
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(1); // version
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(IGenericReader reader)
|
||||
|
|
@ -68,11 +60,6 @@ namespace Server.Mobiles
|
|||
base.Deserialize(reader);
|
||||
|
||||
var version = reader.ReadInt();
|
||||
|
||||
if (version < 1)
|
||||
{
|
||||
Timer.StartTimer(TimeSpan.FromSeconds(0), OnAfterDeserialize_Callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ public class Dismount : WeaponAbility
|
|||
return;
|
||||
}
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
if (defender is ChaosDragoon or ChaosDragoonElite)
|
||||
{
|
||||
return;
|
||||
|
|
@ -33,11 +35,10 @@ public class Dismount : WeaponAbility
|
|||
if (attacker.Weapon is not Lance || !defender.Mounted && !defender.Flying && defender.Weapon is not Lance)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1061283); // You cannot perform that attack while mounted!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
var mount = defender.Mount;
|
||||
|
||||
if (mount == null && !AnimalForm.UnderTransformation(defender))
|
||||
|
|
|
|||
|
|
@ -18,6 +18,13 @@ namespace Server.Items
|
|||
|
||||
if (index >= 1 && index < WeaponAbility.Abilities.Length)
|
||||
{
|
||||
if (m.Mounted && index == 6) //dismount
|
||||
{
|
||||
WeaponAbility.ClearCurrentAbility(m);
|
||||
m.SendLocalizedMessage(1061283); // You cannot perform that attack while mounted!
|
||||
return;
|
||||
}
|
||||
|
||||
WeaponAbility.SetCurrentAbility(m, WeaponAbility.Abilities[index]);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -487,14 +487,7 @@ namespace Server.Items
|
|||
|
||||
if (Quality == WeaponQuality.Exceptional)
|
||||
{
|
||||
if (Attributes.WeaponDamage > 35)
|
||||
{
|
||||
Attributes.WeaponDamage -= 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
Attributes.WeaponDamage = 15;
|
||||
}
|
||||
Attributes.WeaponDamage = 35;
|
||||
|
||||
if (Core.ML)
|
||||
{
|
||||
|
|
@ -2385,27 +2378,8 @@ namespace Server.Items
|
|||
};
|
||||
}
|
||||
|
||||
public virtual int GetDamageBonus()
|
||||
{
|
||||
var quality = m_Quality switch
|
||||
{
|
||||
WeaponQuality.Low => -20,
|
||||
WeaponQuality.Exceptional => 20,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
var damageLevel = m_DamageLevel switch
|
||||
{
|
||||
WeaponDamageLevel.Ruin => 15,
|
||||
WeaponDamageLevel.Might => 20,
|
||||
WeaponDamageLevel.Force => 25,
|
||||
WeaponDamageLevel.Power => 30,
|
||||
WeaponDamageLevel.Vanq => 35,
|
||||
_ => 0
|
||||
};
|
||||
|
||||
return VirtualDamageBonus + quality + damageLevel;
|
||||
}
|
||||
// Note: AOS quality/damage bonuses removed since they are incorporated into the crafting already
|
||||
public virtual int GetDamageBonus() => VirtualDamageBonus;
|
||||
|
||||
public virtual double ScaleDamageAOS(Mobile attacker, double damage, bool checkSkills)
|
||||
{
|
||||
|
|
@ -2477,10 +2451,9 @@ namespace Server.Items
|
|||
damageBonus = 100;
|
||||
}
|
||||
|
||||
var totalBonus = strengthBonus + anatomyBonus + tacticsBonus + lumberBonus +
|
||||
(GetDamageBonus() + damageBonus) / 100.0;
|
||||
var totalBonus = strengthBonus + anatomyBonus + tacticsBonus + lumberBonus + damageBonus + GetDamageBonus();
|
||||
|
||||
return damage + (int)(damage * totalBonus);
|
||||
return damage + damage * totalBonus / 100.0;
|
||||
}
|
||||
|
||||
public virtual int ComputeDamageAOS(Mobile attacker, Mobile defender) =>
|
||||
|
|
|
|||
|
|
@ -402,11 +402,13 @@ namespace Server.Items
|
|||
Groups = new[]
|
||||
{
|
||||
humanoid,
|
||||
undead,
|
||||
elemental,
|
||||
abyss,
|
||||
arachnid,
|
||||
reptilian,
|
||||
// Skip undead for minor slayers
|
||||
undead,
|
||||
// Skip fey for random slayer
|
||||
fey
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ namespace Server
|
|||
var key = cols[0].ToLowerInvariant();
|
||||
var value = cols[1].Trim('"');
|
||||
|
||||
if (key == "type" && value != "profession")
|
||||
if (key == "type" && !value.InsensitiveEquals("profession"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2633,8 +2633,8 @@ public abstract class BaseAI
|
|||
var bc = m as BaseCreature;
|
||||
var pm = m as PlayerMobile;
|
||||
|
||||
// Monster don't attack it's own summon
|
||||
if (Core.AOS && bc != null && bc.Summoned && bc.SummonMaster == m_Mobile)
|
||||
// Monster don't attack it's own summon or the summon of another monster
|
||||
if (Core.AOS && bc != null && bc.Summoned && (bc.SummonMaster == m_Mobile || (!bc.SummonMaster.Player && IsHostile(bc.SummonMaster))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -2658,6 +2658,18 @@ public abstract class BaseAI
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Animated creatures cannot attack other animated creatures
|
||||
if (m_Mobile.IsAnimatedDead && bc?.IsAnimatedDead == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Animated creatures cannot attack pets of other players
|
||||
if (m_Mobile.IsAnimatedDead && bc?.Controlled == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If we only want faction friends, make sure it's one.
|
||||
|
|
@ -2726,7 +2738,7 @@ public abstract class BaseAI
|
|||
newFocusMob = m;
|
||||
val = theirVal;
|
||||
}
|
||||
// The summon is targeted when nothing else around. Otherwise this monster enters idle mode.
|
||||
// The summon is targeted when nothing else around. Otherwise this monster enters idle mode.
|
||||
// Do a check for this edge case so players cannot abuse by casting EVs offscreen to kill an idle monster.
|
||||
else if (Core.AOS && theirVal > enemySummonVal && m_Mobile.InLOS(m) && bc?.Summoned == true && bc?.Controlled != true)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,11 +11,10 @@ namespace Server.Mobiles
|
|||
private Mobile m_Rider;
|
||||
|
||||
public BaseMount(
|
||||
string name, int bodyID, int itemID, AIType aiType, FightMode fightMode = FightMode.Closest,
|
||||
int bodyID, int itemID, AIType aiType, FightMode fightMode = FightMode.Closest,
|
||||
int rangePerception = 10, int rangeFight = 1
|
||||
) : base(aiType, fightMode, rangePerception, rangeFight)
|
||||
{
|
||||
Name = name;
|
||||
Body = bodyID;
|
||||
|
||||
InternalItem = new MountItem(this, itemID);
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class Beetle : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a giant beetle";
|
||||
|
||||
[Constructible]
|
||||
public Beetle(string name = "a giant beetle") : base(name, 0x317, 0x3EBC, AIType.AI_Melee)
|
||||
public Beetle() : base( 0x317, 0x3EBC, AIType.AI_Melee)
|
||||
{
|
||||
SetStr(300);
|
||||
SetDex(100);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class DesertOstard : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a desert ostard";
|
||||
|
||||
[Constructible]
|
||||
public DesertOstard(string name = "a desert ostard") : base(name, 0xD2, 0x3EA3, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public DesertOstard() : base(0xD2, 0x3EA3, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
BaseSoundID = 0x270;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class FireSteed : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a fire steed";
|
||||
|
||||
[Constructible]
|
||||
public FireSteed(string name = "a fire steed") : base(name, 0xBE, 0x3E9E, AIType.AI_Melee)
|
||||
public FireSteed() : base(0xBE, 0x3E9E, AIType.AI_Melee)
|
||||
{
|
||||
BaseSoundID = 0xA8;
|
||||
|
||||
|
|
@ -37,6 +39,9 @@ namespace Server.Mobiles
|
|||
Tamable = true;
|
||||
ControlSlots = 2;
|
||||
MinTameSkill = 106.0;
|
||||
|
||||
PackItem(new SulfurousAsh(Utility.RandomMinMax(151, 300)));
|
||||
PackItem(new Ruby(Utility.RandomMinMax(16, 30)));
|
||||
}
|
||||
|
||||
public FireSteed(Serial serial) : base(serial)
|
||||
|
|
@ -52,8 +57,6 @@ namespace Server.Mobiles
|
|||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
PackItem(new SulfurousAsh(Utility.RandomMinMax(151, 300)));
|
||||
PackItem(new Ruby(Utility.RandomMinMax(16, 30)));
|
||||
}
|
||||
|
||||
public override void Serialize(IGenericWriter writer)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class ForestOstard : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a forest ostard";
|
||||
|
||||
[Constructible]
|
||||
public ForestOstard(string name = "a forest ostard") : base(name, 0xDB, 0x3EA5, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public ForestOstard() : base(0xDB, 0x3EA5, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
Hue = Utility.RandomSlimeHue() | 0x8000;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class FrenziedOstard : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a frenzied ostard";
|
||||
|
||||
[Constructible]
|
||||
public FrenziedOstard(string name = "a frenzied ostard") : base(name, 0xDA, 0x3EA4, AIType.AI_Melee)
|
||||
public FrenziedOstard() : base(0xDA, 0x3EA4, AIType.AI_Melee)
|
||||
{
|
||||
Hue = Race.Human.RandomHairHue() | 0x8000;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class HellSteed : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a frenzied ostard";
|
||||
|
||||
[Constructible]
|
||||
public HellSteed(string name = "a hellsteed") : base(name, 793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public HellSteed() : base(793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
SetStats(this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ namespace Server.Mobiles;
|
|||
|
||||
public class Hiryu : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a hiryu";
|
||||
|
||||
[Constructible]
|
||||
public Hiryu() : base("a hiryu", 243, 0x3E94, AIType.AI_Melee)
|
||||
public Hiryu() : base(243, 0x3E94, AIType.AI_Melee)
|
||||
{
|
||||
Hue = GetHue();
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,10 @@ namespace Server.Mobiles
|
|||
0xCC, 0x3EA2
|
||||
};
|
||||
|
||||
public override string DefaultName => "a horse";
|
||||
|
||||
[Constructible]
|
||||
public Horse(string name = "a horse") : base(name, 0xE2, 0x3EA0, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public Horse() : base(0xE2, 0x3EA0, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
var random = Utility.Random(4);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class Kirin : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a ki-rin";
|
||||
|
||||
[Constructible]
|
||||
public Kirin(string name = "a ki-rin") : base(name, 132, 0x3EAD, AIType.AI_Mage, FightMode.Evil)
|
||||
public Kirin() : base(132, 0x3EAD, AIType.AI_Mage, FightMode.Evil)
|
||||
{
|
||||
BaseSoundID = 0x3C5;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ namespace Server.Mobiles;
|
|||
|
||||
public class LesserHiryu : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a lesser hiryu";
|
||||
|
||||
[Constructible]
|
||||
public LesserHiryu() : base("a lesser hiryu", 243, 0x3E94, AIType.AI_Melee)
|
||||
public LesserHiryu() : base(243, 0x3E94, AIType.AI_Melee)
|
||||
{
|
||||
Hue = GetHue();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class Nightmare : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a nightmare";
|
||||
|
||||
[Constructible]
|
||||
public Nightmare(string name = "a nightmare") : base(
|
||||
name,
|
||||
0x74,
|
||||
0x3EA7,
|
||||
AIType.AI_Mage
|
||||
)
|
||||
public Nightmare() : base(0x74, 0x3EA7, AIType.AI_Mage)
|
||||
{
|
||||
BaseSoundID = Core.AOS ? 0xA8 : 0x16A;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class RidableLlama : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a ridable llama";
|
||||
|
||||
[Constructible]
|
||||
public RidableLlama(string name = "a ridable llama") : base(name, 0xDC, 0x3EA6, AIType.AI_Animal, FightMode.Aggressor
|
||||
public RidableLlama() : base(0xDC, 0x3EA6, AIType.AI_Animal, FightMode.Aggressor
|
||||
)
|
||||
{
|
||||
BaseSoundID = 0x3F3;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class Ridgeback : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a ridgeback";
|
||||
|
||||
[Constructible]
|
||||
public Ridgeback(string name = "a ridgeback") : base(name, 187, 0x3EBA, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public Ridgeback() : base(187, 0x3EBA, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
BaseSoundID = 0x3F3;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class SavageRidgeback : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a savage ridgeback";
|
||||
|
||||
[Constructible]
|
||||
public SavageRidgeback(string name = "a savage ridgeback") : base(name, 188, 0x3EB8, AIType.AI_Melee, FightMode.Aggressor)
|
||||
public SavageRidgeback() : base(188, 0x3EB8, AIType.AI_Melee, FightMode.Aggressor)
|
||||
{
|
||||
BaseSoundID = 0x3F3;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class ScaledSwampDragon : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a swamp dragon";
|
||||
|
||||
[Constructible]
|
||||
public ScaledSwampDragon(string name = "a swamp dragon") : base(name, 0x31F, 0x3EBE, AIType.AI_Melee, FightMode.Aggressor)
|
||||
public ScaledSwampDragon() : base(0x31F, 0x3EBE, AIType.AI_Melee, FightMode.Aggressor)
|
||||
{
|
||||
SetStr(201, 300);
|
||||
SetDex(66, 85);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class SeaHorse : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a sea horse";
|
||||
|
||||
[Constructible]
|
||||
public SeaHorse(string name = "a sea horse") : base(name, 0x90, 0x3EB3, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public SeaHorse() : base(0x90, 0x3EB3, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
InitStats(Utility.Random(50, 30), Utility.Random(50, 30), 10);
|
||||
Skills.MagicResist.Base = 25.0 + Utility.RandomDouble() * 5.0;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class SilverSteed : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a silver steed";
|
||||
|
||||
[Constructible]
|
||||
public SilverSteed(string name = "a silver steed") : base(name, 0x75, 0x3EA8, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public SilverSteed() : base(0x75, 0x3EA8, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
InitStats(Utility.Random(50, 30), Utility.Random(50, 30), 10);
|
||||
Skills.MagicResist.Base = 25.0 + Utility.RandomDouble() * 5.0;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ namespace Server.Mobiles
|
|||
public class SkeletalMount : BaseMount
|
||||
{
|
||||
[Constructible]
|
||||
public SkeletalMount(string name = null) : base(name, 793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public SkeletalMount() : base(793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
SetStr(91, 100);
|
||||
SetDex(46, 55);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class SwampDragon : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a swamp dragon";
|
||||
|
||||
private string _bardingCraftedBy;
|
||||
private bool m_BardingExceptional;
|
||||
private int m_BardingHP;
|
||||
|
|
@ -11,7 +13,7 @@ namespace Server.Mobiles
|
|||
private bool m_HasBarding;
|
||||
|
||||
[Constructible]
|
||||
public SwampDragon(string name = "a swamp dragon") : base(name, 0x31A, 0x3EBD, AIType.AI_Melee, FightMode.Aggressor)
|
||||
public SwampDragon() : base(0x31A, 0x3EBD, AIType.AI_Melee, FightMode.Aggressor)
|
||||
{
|
||||
BaseSoundID = 0x16A;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class Unicorn : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a unicorn";
|
||||
|
||||
[Constructible]
|
||||
public Unicorn(string name = "a unicorn") : base(name, 0x7A, 0x3EB4, AIType.AI_Mage, FightMode.Evil)
|
||||
public Unicorn() : base(0x7A, 0x3EB4, AIType.AI_Mage, FightMode.Evil)
|
||||
{
|
||||
BaseSoundID = 0x4BC;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ namespace Server.Mobiles
|
|||
{
|
||||
public abstract class BaseWarHorse : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a war horse";
|
||||
|
||||
public BaseWarHorse(
|
||||
int bodyID, int itemID, AIType aiType = AIType.AI_Melee, FightMode fightMode = FightMode.Aggressor,
|
||||
int rangePerception = 10, int rangeFight = 1
|
||||
) : base(
|
||||
"a war horse",
|
||||
bodyID,
|
||||
itemID,
|
||||
aiType,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ namespace Server.Mobiles
|
|||
public override bool BardImmune => true;
|
||||
public override Poison PoisonImmune => Poison.Lethal;
|
||||
public override bool Commandable => false;
|
||||
public override bool IgnoreMobiles => true;
|
||||
|
||||
public override bool PlayerRangeSensitive => false;
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ namespace Server.Mobiles
|
|||
public override bool BardImmune => true;
|
||||
public override Poison PoisonImmune => Poison.Lethal;
|
||||
|
||||
public override bool IgnoreMobiles => true;
|
||||
|
||||
public override void DisplayPaperdollTo(Mobile to)
|
||||
{
|
||||
// Do nothing
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Mobiles
|
|||
public class CuSidhe : BaseMount
|
||||
{
|
||||
[Constructible]
|
||||
public CuSidhe(string name = null) : base(name, 277, 0x3E91, AIType.AI_Animal, FightMode.Aggressor)
|
||||
public CuSidhe() : base(277, 0x3E91, AIType.AI_Animal, FightMode.Aggressor)
|
||||
{
|
||||
var chance = Utility.RandomDouble() * 23301;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace Server.Mobiles
|
|||
public class RedDeath : SkeletalMount
|
||||
{
|
||||
[Constructible]
|
||||
public RedDeath() : base("Red Death")
|
||||
public RedDeath() : base()
|
||||
{
|
||||
IsParagon = true;
|
||||
|
||||
|
|
@ -55,6 +55,8 @@ namespace Server.Mobiles
|
|||
{
|
||||
}
|
||||
|
||||
public override string DefaultName => "Red Death";
|
||||
|
||||
public override string CorpseName => "a Red Death corpse";
|
||||
|
||||
public override bool GivesMLMinorArtifact => true;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class Reptalon : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a reptalon";
|
||||
|
||||
[Constructible]
|
||||
public Reptalon() : base("a reptalon", 0x114, 0x3E90, AIType.AI_Melee)
|
||||
public Reptalon() : base(0x114, 0x3E90, AIType.AI_Melee)
|
||||
{
|
||||
BaseSoundID = 0x16A;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ namespace Server.Mobiles
|
|||
[Forge]
|
||||
public class FireBeetle : BaseMount
|
||||
{
|
||||
public override string DefaultName => "a fire beetle";
|
||||
|
||||
[Constructible]
|
||||
public FireBeetle() : base("a fire beetle", 0xA9, 0x3E95, AIType.AI_Melee)
|
||||
public FireBeetle() : base(0xA9, 0x3E95, AIType.AI_Melee)
|
||||
{
|
||||
SetStam(100);
|
||||
SetStr(300);
|
||||
|
|
|
|||
|
|
@ -165,9 +165,7 @@ namespace Server.Mobiles
|
|||
|
||||
private int m_HairModID = -1, m_HairModHue;
|
||||
|
||||
public DateTime m_hontime;
|
||||
|
||||
private bool m_IgnoreMobiles; // IgnoreMobiles should be moved to Server.Mobiles
|
||||
public DateTime _honorTime;
|
||||
|
||||
private Mobile m_InsuranceAward;
|
||||
private int m_InsuranceBonus;
|
||||
|
|
@ -420,20 +418,6 @@ namespace Server.Mobiles
|
|||
set;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool IgnoreMobiles // IgnoreMobiles should be moved to Server.Mobiles
|
||||
{
|
||||
get => m_IgnoreMobiles;
|
||||
set
|
||||
{
|
||||
if (m_IgnoreMobiles != value)
|
||||
{
|
||||
m_IgnoreMobiles = value;
|
||||
Delta(MobileDelta.Flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public NpcGuild NpcGuild { get; set; }
|
||||
|
||||
|
|
@ -952,18 +936,6 @@ namespace Server.Mobiles
|
|||
return true;
|
||||
}
|
||||
|
||||
public override int GetPacketFlags(bool stygianAbyss)
|
||||
{
|
||||
var flags = base.GetPacketFlags(stygianAbyss);
|
||||
|
||||
if (m_IgnoreMobiles)
|
||||
{
|
||||
flags |= 0x10;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public bool GetFlag(PlayerFlag flag) => (Flags & flag) != 0;
|
||||
|
||||
public void SetFlag(PlayerFlag flag, bool value)
|
||||
|
|
@ -2336,7 +2308,7 @@ namespace Server.Mobiles
|
|||
pm.DuelPlayer.Eliminated) || base.OnMoveOver(m);
|
||||
|
||||
public override bool CheckShove(Mobile shoved) =>
|
||||
m_IgnoreMobiles || TransformationSpellHelper.UnderTransformation(shoved, typeof(WraithFormSpell)) ||
|
||||
IgnoreMobiles || shoved.IgnoreMobiles || TransformationSpellHelper.UnderTransformation(shoved, typeof(WraithFormSpell)) ||
|
||||
base.CheckShove(shoved);
|
||||
|
||||
protected override void OnMapChange(Map oldMap)
|
||||
|
|
@ -3228,7 +3200,7 @@ namespace Server.Mobiles
|
|||
|
||||
if (AccessLevel > AccessLevel.Player)
|
||||
{
|
||||
m_IgnoreMobiles = true;
|
||||
IgnoreMobiles = true;
|
||||
}
|
||||
|
||||
var list = Stabled;
|
||||
|
|
|
|||
|
|
@ -146,12 +146,17 @@ namespace Server.Mobiles
|
|||
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (m == m_Owner || !(m_Owner.CanBeHarmful(m) || m.Player && m.Alive))
|
||||
if (m == m_Owner || !m_Owner.CanBeHarmful(m))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m is not BaseCreature bc || !(bc.Controlled || bc.Summoned || bc.Team != m_Owner.Team))
|
||||
if (m.Player && !m.Alive)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m is BaseCreature bc && !(bc.Controlled || bc.IsAnimatedDead || bc.Summoned || bc.Team != m_Owner.Team))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,11 +67,12 @@ namespace Server.Multis
|
|||
private DateTime m_DecayTime;
|
||||
|
||||
private Direction m_Facing;
|
||||
private TimerExecutionToken _moveTimerToken;
|
||||
|
||||
private string m_ShipName;
|
||||
|
||||
private TimerExecutionToken _turnTimerToken;
|
||||
|
||||
private TurnTimer _turnTimer;
|
||||
private MoveTimer _moveTimer;
|
||||
|
||||
public BaseBoat() : base(0x0)
|
||||
{
|
||||
|
|
@ -125,7 +126,7 @@ namespace Server.Multis
|
|||
public Direction Moving { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool IsMoving => _moveTimerToken.Running;
|
||||
public bool IsMoving => _moveTimer?.Running == true;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Speed { get; set; }
|
||||
|
|
@ -459,8 +460,8 @@ namespace Server.Multis
|
|||
Hold?.Delete();
|
||||
PPlank?.Delete();
|
||||
SPlank?.Delete();
|
||||
_turnTimerToken.Cancel();
|
||||
_moveTimerToken.Cancel();
|
||||
_turnTimer?.Stop();
|
||||
_moveTimer?.Stop();
|
||||
|
||||
Boats.Remove(this);
|
||||
}
|
||||
|
|
@ -1091,8 +1092,10 @@ namespace Server.Multis
|
|||
Speed = FastSpeed;
|
||||
Order = single ? BoatOrder.Single : BoatOrder.Course;
|
||||
|
||||
_moveTimerToken.Cancel();
|
||||
Timer.StartTimer(FastInterval, FastInterval, StopBoat, out _moveTimerToken);
|
||||
if (!SafelyStartMoveTimer(FastInterval, single))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (message)
|
||||
{
|
||||
|
|
@ -1279,11 +1282,27 @@ namespace Server.Multis
|
|||
|
||||
if (Order != BoatOrder.Move)
|
||||
{
|
||||
_moveTimerToken.Cancel();
|
||||
_turnTimer?.Stop();
|
||||
}
|
||||
|
||||
_turnTimerToken.Cancel();
|
||||
Timer.StartTimer(TimeSpan.FromMilliseconds(500), () => Turn(offset), out _turnTimerToken);
|
||||
_turnTimer ??= new TurnTimer(offset, this, TimeSpan.FromMilliseconds(500), message);
|
||||
|
||||
if (_turnTimer.Running && _turnTimer._turn == offset)
|
||||
{
|
||||
// Dont let them spin around in circles like crazy
|
||||
return true;
|
||||
}
|
||||
|
||||
// Have they issued a new command too soon? Ignore it if so
|
||||
var turnTimerNext = (_turnTimer.Next - Core.Now).TotalMilliseconds;
|
||||
if (turnTimerNext is < 0 and > -250)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
_turnTimer._turn = offset;
|
||||
_turnTimer.Stop();
|
||||
_turnTimer.Start();
|
||||
|
||||
if (message)
|
||||
{
|
||||
|
|
@ -1295,7 +1314,7 @@ namespace Server.Multis
|
|||
|
||||
public bool Turn(int offset, bool message = true)
|
||||
{
|
||||
_turnTimerToken.Cancel();
|
||||
_turnTimer?.Stop();
|
||||
|
||||
if (CheckDecay())
|
||||
{
|
||||
|
|
@ -1347,12 +1366,51 @@ namespace Server.Multis
|
|||
m_ClientSpeed = clientSpeed;
|
||||
Order = BoatOrder.Move;
|
||||
|
||||
_moveTimerToken.Cancel();
|
||||
Timer.StartTimer(interval, single ? 1 : 0, StopBoat, out _moveTimerToken);
|
||||
SafelyStartMoveTimer(interval, single);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SafelyStartMoveTimer(TimeSpan interval, bool single)
|
||||
{
|
||||
var singleNum = single ? 1 : 0;
|
||||
|
||||
if (_moveTimer != null)
|
||||
{
|
||||
// Do not allow them to travel faster simply by respamming the command
|
||||
if (_moveTimer.Running && _moveTimer.Interval == interval && _moveTimer.Single == singleNum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Have they issued a new command too soon? Ignore it if so
|
||||
var moverTimerNext = (_moveTimer.Next - Core.Now).TotalMilliseconds;
|
||||
if (moverTimerNext is < 0 and > -500)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Changing the interval or flipping between commands: "Forward" and "Forward One"
|
||||
TimeSpan delay = TimeSpan.Zero;
|
||||
if (interval.TotalMilliseconds > Math.Abs(moverTimerNext))
|
||||
{
|
||||
var addedDelay = (int)(interval.TotalMilliseconds - Math.Abs(moverTimerNext));
|
||||
delay = TimeSpan.FromMilliseconds(addedDelay);
|
||||
}
|
||||
|
||||
_moveTimer.Stop();
|
||||
_moveTimer.Delay = delay;
|
||||
_moveTimer.Interval = interval;
|
||||
}
|
||||
else
|
||||
{
|
||||
_moveTimer = new MoveTimer(this, interval, interval, singleNum);
|
||||
}
|
||||
|
||||
_moveTimer.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool StopMove(bool message)
|
||||
{
|
||||
if (CheckDecay())
|
||||
|
|
@ -1360,7 +1418,7 @@ namespace Server.Multis
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!_moveTimerToken.Running)
|
||||
if (_moveTimer?.Running == false)
|
||||
{
|
||||
if (message)
|
||||
{
|
||||
|
|
@ -1373,7 +1431,7 @@ namespace Server.Multis
|
|||
Moving = Direction.North;
|
||||
Speed = 0;
|
||||
m_ClientSpeed = 0;
|
||||
_moveTimerToken.Cancel();
|
||||
_moveTimer?.Stop();
|
||||
|
||||
if (message)
|
||||
{
|
||||
|
|
@ -1891,7 +1949,7 @@ namespace Server.Multis
|
|||
continue;
|
||||
}
|
||||
|
||||
// TODO: Remove visible check and use something better, like check for spawners, or other things in the ocean we shouldn't pick up on accident
|
||||
// TODO: Remove visible check and use something better, like check for spawners, or other things in the ocean we shouldn't pick up on accident
|
||||
if (_boat.Contains(item) && item.Visible && item.Z >= _boat.Z)
|
||||
{
|
||||
_current = current;
|
||||
|
|
@ -2047,6 +2105,45 @@ namespace Server.Multis
|
|||
EventSink.WorldSave += UpdateAllComponents;
|
||||
}
|
||||
|
||||
private class TurnTimer : Timer
|
||||
{
|
||||
internal int _turn;
|
||||
private bool _message;
|
||||
private BaseBoat _boat;
|
||||
|
||||
public TurnTimer(int turn, BaseBoat boat, TimeSpan delay, bool message = true) : base(delay)
|
||||
{
|
||||
_turn = turn;
|
||||
_message = message;
|
||||
_boat = boat;
|
||||
}
|
||||
protected override void OnTick()
|
||||
{
|
||||
_boat?.Turn(_turn, _message);
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private class MoveTimer : Timer
|
||||
{
|
||||
public TimeSpan BoatMoveDelay;
|
||||
public TimeSpan BoatMoveInterval;
|
||||
public int Single;
|
||||
private BaseBoat _boat;
|
||||
|
||||
public MoveTimer(BaseBoat boat, TimeSpan delay, TimeSpan interval, int single = 0) : base(delay, interval, single)
|
||||
{
|
||||
BoatMoveInterval = interval;
|
||||
BoatMoveDelay = delay;
|
||||
Single = single;
|
||||
_boat = boat;
|
||||
}
|
||||
protected override void OnTick()
|
||||
{
|
||||
_boat?.StopBoat();
|
||||
}
|
||||
}
|
||||
|
||||
private class DecayTimer : Timer
|
||||
{
|
||||
private readonly BaseBoat m_Boat;
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ namespace Server.Spells
|
|||
return true;
|
||||
}
|
||||
|
||||
if (mod == null || mod.Offset < offset)
|
||||
if (mod == null || mod.Offset <= offset)
|
||||
{
|
||||
target.AddStatMod(new StatMod(type, name, offset, duration));
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -77,17 +77,38 @@ namespace Server.Spells.Necromancy
|
|||
pool.Enqueue(m);
|
||||
}
|
||||
|
||||
var eable = m.GetMobilesInRange(2);
|
||||
var cbc = Caster as BaseCreature;
|
||||
var isMonster = cbc?.Controlled == false && (cbc.IsAnimatedDead || !cbc.Summoned);
|
||||
|
||||
var eable = m.GetMobilesInRange(2);
|
||||
foreach (Mobile targ in eable)
|
||||
{
|
||||
if (!(Caster is BaseCreature && targ is BaseCreature) &&
|
||||
targ != Caster && m != targ &&
|
||||
SpellHelper.ValidIndirectTarget(Caster, targ) &&
|
||||
Caster.CanBeHarmful(targ, false))
|
||||
if (targ == Caster || m == targ || !SpellHelper.ValidIndirectTarget(Caster, targ)
|
||||
|| !Caster.CanBeHarmful(targ, false))
|
||||
{
|
||||
pool.Enqueue(targ);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isMonster && targ.Player)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Animate dead casting poison strike shouldn't hit: familiars or player or pets
|
||||
if (targ is BaseCreature bc)
|
||||
{
|
||||
if (bc.IsAnimatedDead)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isMonster && (bc.Controlled || bc.Summoned || bc.Team == cbc.Team || bc.IsNecroFamiliar))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pool.Enqueue(targ);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
|
|
|||
|
|
@ -49,33 +49,39 @@ namespace Server.Spells.Necromancy
|
|||
using var pool = PooledRefQueue<Mobile>.Create();
|
||||
|
||||
var cbc = Caster as BaseCreature;
|
||||
var isMonster = cbc?.Controlled == false && !cbc.Summoned;
|
||||
var isMonster = cbc?.Controlled == false && (cbc.IsAnimatedDead || !cbc.Summoned);
|
||||
|
||||
var eable = Caster.GetMobilesInRange(Core.ML ? 4 : 5);
|
||||
foreach (var m in eable)
|
||||
foreach (var targ in eable)
|
||||
{
|
||||
if (Caster == m || !Caster.InLOS(m) || (!isMonster && !SpellHelper.ValidIndirectTarget(Caster, m)) ||
|
||||
!Caster.CanBeHarmful(m, false))
|
||||
if (targ == Caster
|
||||
|| !Caster.InLOS(targ)
|
||||
|| !isMonster && !SpellHelper.ValidIndirectTarget(Caster, targ)
|
||||
|| !Caster.CanBeHarmful(targ, false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isMonster)
|
||||
if (isMonster && targ.Player)
|
||||
{
|
||||
if (m is BaseCreature bc)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Animate dead casting poison strike shouldn't hit: familiars or player or pets
|
||||
if (targ is BaseCreature bc)
|
||||
{
|
||||
if (bc.IsAnimatedDead)
|
||||
{
|
||||
if (!bc.Controlled && !bc.Summoned && bc.Team == cbc.Team)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (!m.Player)
|
||||
|
||||
if (isMonster && (bc.Controlled || bc.Summoned || bc.Team == cbc.Team || bc.IsNecroFamiliar))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pool.Enqueue(m);
|
||||
pool.Enqueue(targ);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
|
|
|||
|
|
@ -36,10 +36,14 @@ namespace Server.Spells.Sixth
|
|||
|
||||
foreach (var m in eable)
|
||||
{
|
||||
if (m is ShadowKnight &&
|
||||
(m.X != p.X || m.Y != p.Y || !m.Hidden || m.AccessLevel != AccessLevel.Player &&
|
||||
Caster.AccessLevel <= m.AccessLevel ||
|
||||
!CheckDifficulty(Caster, m)))
|
||||
if (m is ShadowKnight && (m.X != p.X || m.Y != p.Y))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!m.Hidden
|
||||
|| m.AccessLevel > AccessLevel.Player && Caster.AccessLevel <= m.AccessLevel
|
||||
|| !CheckDifficulty(Caster, m))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue