feat: Adds stun, death explosion, poison gas, throw hatchet abilities (#1180)

* Adds Colossal Blow
* Adds Death Explosion
* Adds Poison Gas
* Adds AOE Poison Gas (Counter)
* Adds Stun
* Adds Throw Hatchet
This commit is contained in:
Kamron Batman 2022-10-02 10:16:37 -07:00 committed by GitHub
parent 43e7fe29c2
commit dc6f75c3b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 1062 additions and 935 deletions

View file

@ -0,0 +1,60 @@
using System;
using Server.Collections;
namespace Server.Mobiles;
public abstract class AreaEffectMonsterAbility : MonsterAbility
{
public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.OnCombatAction;
public override MonsterAbilityType AbilityType => MonsterAbilityType.MassPoison;
public override double ChanceToTrigger => 0.5;
public override TimeSpan MinTriggerCooldown => TimeSpan.FromSeconds(5.0);
public override TimeSpan MaxTriggerCooldown => TimeSpan.FromSeconds(30.0);
public virtual int CombatantRange => 3;
public virtual int AreaRange => 3;
public override bool CanTrigger(BaseCreature source)
{
if (!base.CanTrigger(source))
{
return false;
}
var combatant = source.Combatant;
// Only do the mass ability as a side-effect of combating a specific target
return combatant?.Deleted == false && combatant.Map == source.Map && source.InRange(combatant.Location, CombatantRange) &&
source.CanBeHarmful(combatant) && source.InLOS(combatant);
}
public override void Trigger(BaseCreature source, Mobile target)
{
// target is null for OnCombatAction triggers
var eable = source.GetMobilesInRange(2);
using var queue = PooledRefQueue<Mobile>.Create();
foreach (var m in eable)
{
if (CanEffectTarget(source, m))
{
queue.Enqueue(m);
}
}
eable.Free();
while (queue.Count > 0)
{
DoEffectTarget(source, queue.Dequeue());
}
base.Trigger(source, target);
}
protected virtual bool CanEffectTarget(BaseCreature source, Mobile defender) =>
source != defender && defender.Alive && source.IsEnemy(defender) && source.CanBeHarmful(defender);
protected abstract void DoEffectTarget(BaseCreature source, Mobile defender);
}

View file

@ -2,7 +2,7 @@
public class ChaosBreath : FireBreath
{
public override int BreathChaosDamage => 100;
public override int ChaosDamage => 100;
public override int BreathFireDamage => 0;
public override int FireDamage => 0;
}

View file

@ -2,7 +2,7 @@
public class ColdBreath : FireBreath
{
public override int BreathColdDamage => 100;
public override int BreathFireDamage => 0;
public override int ColdDamage => 100;
public override int FireDamage => 0;
public override int BreathEffectHue => 0x480;
}

View file

@ -0,0 +1,27 @@
using Server.Network;
namespace Server.Mobiles;
public class ColossalBlow : StunAttack
{
public override void Trigger(BaseCreature source, Mobile target)
{
target.Animate(21, 6, 1, true, false, 0);
source.PlaySound(0xEE);
target.LocalOverheadMessage(
MessageType.Regular,
0x3B2,
false,
"You have been stunned by a colossal blow!"
);
base.Trigger(source, target);
}
protected override void Recover(Mobile defender)
{
base.Recover(defender);
defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses.");
}
}

View file

@ -0,0 +1,29 @@
using System;
namespace Server.Mobiles;
public class DeathExplosion : AreaEffectMonsterAbility
{
public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.OnDeath;
public override double ChanceToTrigger => 1.0;
public override TimeSpan MinTriggerCooldown => TimeSpan.Zero;
public override TimeSpan MaxTriggerCooldown => TimeSpan.Zero;
public override bool CanTrigger(BaseCreature source) => true;
public override void Trigger(BaseCreature source, Mobile target)
{
source.FixedParticles(0x36BD, 20, 10, 5044, EffectLayer.Head);
source. PlaySound(0x307);
base.Trigger(source, target);
}
protected override void DoEffectTarget(BaseCreature source, Mobile defender)
{
source.DoHarmful(defender);
// TODO: Is the damage type correct?
AOS.Damage(defender, source, defender.HitsMax / 5, true, 100, 0, 0, 0, 0);
}
}

View file

@ -0,0 +1,55 @@
using Server.Collections;
using Server.Items;
using Server.Network;
namespace Server.Mobiles;
public class DestroyEquipment : MonsterAbilityAttack
{
public override MonsterAbilityType AbilityType => MonsterAbilityType.DestroyEquipment;
public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.GiveMeleeDamage;
public override double ChanceToTrigger => 0.05;
public virtual int AttackRange => 1;
protected override void OnAttack(BaseCreature source, Mobile defender)
{
base.OnAttack(source, defender);
using var queue = PooledRefQueue<Item>.Create();
for (var i = 0; i < defender.Items.Count; i++)
{
var item = defender.Items[i];
if (item.Deleted || item.LootType is LootType.Blessed or LootType.Newbied || item.BlessedFor != null)
{
continue;
}
if (!(Mobile.InsuranceEnabled && item.Insured) && item is IDurability { MaxHitPoints: > 0 })
{
queue.Enqueue(item);
}
}
if (queue.Count == 0)
{
return;
}
var toDestroy = queue.PeekRandom();
var name = toDestroy.Name?.Trim().DefaultIfNullOrEmpty(toDestroy.ItemData.Name);
// TODO: Is there supposed to be a special effect?
// TODO: Is there supposed to be a special sound?
toDestroy.Delete();
// Their ~1_NAME~ is destroyed by the attack.
defender.NonlocalOverheadMessage(MessageType.Regular, 0x3B2, 1080034, name);
// Your ~1_NAME~ is destroyed by the attack.
defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1080035, name);
}
protected override bool CanEffectTarget(BaseCreature source, Mobile defender) =>
defender.Player && defender.AccessLevel == AccessLevel.Player && source.InRange(defender, AttackRange);
}

View file

@ -5,7 +5,7 @@ namespace Server.Mobiles;
public class FireBreath : MonsterAbility
{
public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.Action;
public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.OnAction;
public override MonsterAbilityType AbilityType => MonsterAbilityType.FireBreath;
public override double ChanceToTrigger => 0.5;
@ -27,12 +27,12 @@ public class FireBreath : MonsterAbility
public virtual int BreathRange(BaseCreature source) => source.RangePerception;
// Damage Types
public virtual int BreathChaosDamage => 0;
public virtual int BreathPhysicalDamage => 0;
public virtual int BreathFireDamage => 100;
public virtual int BreathColdDamage => 0;
public virtual int BreathPoisonDamage => 0;
public virtual int BreathEnergyDamage => 0;
public virtual int ChaosDamage => 0;
public virtual int PhysicalDamage => 0;
public virtual int FireDamage => 100;
public virtual int ColdDamage => 0;
public virtual int PoisonDamage => 0;
public virtual int EnergyDamage => 0;
// Effect details and sound
public virtual int BreathEffectItemID => 0x36D4;
@ -146,39 +146,39 @@ public class FireBreath : MonsterAbility
{
if (!Evasion.CheckSpellEvasion(target))
{
var physDamage = BreathPhysicalDamage;
var fireDamage = BreathFireDamage;
var coldDamage = BreathColdDamage;
var poisDamage = BreathPoisonDamage;
var nrgyDamage = BreathEnergyDamage;
var physDamage = PhysicalDamage;
var fireDamage = FireDamage;
var coldDamage = ColdDamage;
var poisDamage = PoisonDamage;
var nrgyDamage = EnergyDamage;
if (BreathChaosDamage > 0)
if (ChaosDamage > 0)
{
switch (Utility.Random(5))
{
case 0:
{
physDamage += BreathChaosDamage;
physDamage += ChaosDamage;
break;
}
case 1:
{
fireDamage += BreathChaosDamage;
fireDamage += ChaosDamage;
break;
}
case 2:
{
coldDamage += BreathChaosDamage;
coldDamage += ChaosDamage;
break;
}
case 3:
{
poisDamage += BreathChaosDamage;
poisDamage += ChaosDamage;
break;
}
case 4:
{
nrgyDamage += BreathChaosDamage;
nrgyDamage += ChaosDamage;
break;
}
}

View file

@ -12,4 +12,18 @@ public abstract partial class MonsterAbility
// Summon Undead
public static SummonSkeletons SummonSkeletons => new();
public static SummonLesserUndead SummonLesserUndead => new();
// Stun
public static ColossalBlow ColossalBlow => new();
// Poison
public static PoisonGasCounter PoisonGasCounter => new();
public static PoisonGasAreaAttack PoisonGasAreaAttack => new();
// Explosions
public static DeathExplosion DeathExplosion => new();
public static ThrowHatchetCounter ThrowHatchetCounter => new();
public static DestroyEquipment DestroyEquipment => new();
}

View file

@ -0,0 +1,22 @@
namespace Server.Mobiles;
public abstract class MonsterAbilityAttack : MonsterAbility
{
public override void Trigger(BaseCreature source, Mobile target)
{
if (CanEffectTarget(source, target))
{
OnAttack(source, target);
}
base.Trigger(source, target);
}
protected virtual void OnAttack(BaseCreature source, Mobile defender)
{
source.DoHarmful(defender);
}
protected virtual bool CanEffectTarget(BaseCreature source, Mobile defender) =>
defender.Alive && source.CanBeHarmful(defender);
}

View file

@ -5,12 +5,14 @@ namespace Server.Mobiles;
[Flags]
public enum MonsterAbilityTrigger
{
None = 0x00000000, // Passive, or some custom event.
Action = 0x00000001, // On Think
None = 0x00000000, // Passive, or some custom event.
OnAction = 0x00000001, // On Think
TakeMeleeDamage = 0x00000002,
GiveMeleeDamage = 0x00000004, // Includes firing a bow
TakeSpellDamage = 0x00000008,
GiveSpellDamage = 0x00000010,
OnCombatAction = 0x00000020,
OnDeath = 0x00000040,
TakeDamage = TakeMeleeDamage | TakeSpellDamage
}

View file

@ -5,5 +5,10 @@ public enum MonsterAbilityType
Generic,
FireBreath,
GraspingClaw,
SummonUndead
SummonUndead,
Stun,
Poison,
MassPoison,
ThrowWeapon,
DestroyEquipment
}

View file

@ -0,0 +1,19 @@
namespace Server.Mobiles;
public class PoisonGasAreaAttack : AreaEffectMonsterAbility
{
public override MonsterAbilityType AbilityType => MonsterAbilityType.MassPoison;
public override void Trigger(BaseCreature source, Mobile target)
{
source.FixedParticles(0x376A, 9, 32, 0x2539, EffectLayer.LeftHand);
source.PlaySound(0x1DE);
base.Trigger(source, target);
}
protected override void DoEffectTarget(BaseCreature source, Mobile defender)
{
defender.ApplyPoison(source, Poison.Deadly);
}
}

View file

@ -0,0 +1,22 @@
namespace Server.Mobiles;
public class PoisonGasCounter : MonsterAbilityAttack
{
public override MonsterAbilityType AbilityType => MonsterAbilityType.Poison;
public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.TakeDamage;
public override double ChanceToTrigger => 0.05;
public virtual int AttackRange => 1;
protected override bool CanEffectTarget(BaseCreature source, Mobile defender) =>
source.InRange(defender, AttackRange) && defender is not BaseCreature { BardProvoked: true };
protected override void OnAttack(BaseCreature source, Mobile defender)
{
source.Animate(10, 4, 1, true, false, 0);
AOS.Damage(defender, source, 50, 100, 0, 0, 0, 0, 0);
defender.FixedParticles(0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255);
defender.ApplyPoison(source, Poison.Deadly);
}
}

View file

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using Server.Items;
namespace Server.Mobiles;
public abstract class StunAttack : MonsterAbility
{
// Prevents infinite loop
private HashSet<BaseCreature> _stunning;
public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.GiveMeleeDamage;
public override MonsterAbilityType AbilityType => MonsterAbilityType.Stun;
public override double ChanceToTrigger => 0.3;
public virtual TimeSpan StunDuration => TimeSpan.FromSeconds(5.0);
public override bool CanTrigger(BaseCreature source) => !_stunning.Contains(source) && base.CanTrigger(source);
public override void Trigger(BaseCreature source, Mobile target)
{
if (source.Weapon is BaseWeapon weapon)
{
_stunning ??= new HashSet<BaseCreature>();
_stunning.Add(source);
weapon.OnHit(source, target);
_stunning.Remove(source);
}
if (target.Alive)
{
target.Frozen = true;
Timer.DelayCall(StunDuration, Recover, target);
}
base.Trigger(source, target);
}
protected virtual void Recover(Mobile defender)
{
defender.Frozen = false;
defender.Combatant = null;
}
}

View file

@ -0,0 +1,19 @@
using Server.Items;
namespace Server.Mobiles;
public class ThrowHatchetCounter : MonsterAbilityAttack
{
public override MonsterAbilityType AbilityType => MonsterAbilityType.ThrowWeapon;
public override MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.TakeDamage;
public override double ChanceToTrigger => 0.4;
protected override void OnAttack(BaseCreature source, Mobile defender)
{
source.MovingEffect(defender, 0xF43, 10, 0, false, false);
AOS.Damage(defender, source, 50, 100, 0, 0, 0, 0, 0);
}
protected override bool CanEffectTarget(BaseCreature source, Mobile defender) =>
base.CanEffectTarget(source, defender) && defender.Weapon is BaseRanged;
}

View file

@ -2869,6 +2869,8 @@ namespace Server.Mobiles
public override bool OnBeforeDeath()
{
TriggerAbility(MonsterAbilityTrigger.OnDeath, null);
var treasureLevel = TreasureMapLevel;
if (treasureLevel == 1 && Map == Map.Trammel && TreasureMap.IsInHavenIsland(this))
@ -3515,7 +3517,7 @@ namespace Server.Mobiles
}
// Fire breath, etc.
TriggerAbility(MonsterAbilityTrigger.Action, Combatant);
TriggerAbility(MonsterAbilityTrigger.OnAction, Combatant);
if ((CanHeal || CanHealOwner) && Alive && !IsHealing && !BardPacified)
{
@ -4170,6 +4172,7 @@ namespace Server.Mobiles
public virtual void OnActionCombat()
{
TriggerAbility(MonsterAbilityTrigger.OnCombatAction, null);
}
public virtual void OnActionGuard()

View file

@ -1,188 +1,117 @@
using System;
using Server.Items;
using Server.Network;
namespace Server.Mobiles
namespace Server.Mobiles;
public class Betrayer : BaseCreature
{
public class Betrayer : BaseCreature
[Constructible]
public Betrayer() : base(AIType.AI_Mage)
{
private DateTime m_NextAbilityTime;
private bool m_Stunning;
Body = 767;
[Constructible]
public Betrayer() : base(AIType.AI_Mage)
SetStr(401, 500);
SetDex(81, 100);
SetInt(151, 200);
SetHits(241, 300);
SetDamage(16, 22);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 60, 70);
SetResistance(ResistanceType.Fire, 60, 70);
SetResistance(ResistanceType.Cold, 60, 70);
SetResistance(ResistanceType.Poison, 30, 40);
SetResistance(ResistanceType.Energy, 20, 30);
SetSkill(SkillName.Anatomy, 90.1, 100.0);
SetSkill(SkillName.EvalInt, 90.1, 100.0);
SetSkill(SkillName.Magery, 50.1, 100.0);
SetSkill(SkillName.Meditation, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 120.1, 130.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.Wrestling, 90.1, 100.0);
Fame = 15000;
Karma = -15000;
VirtualArmor = 65;
SpeechHue = Utility.RandomDyedHue();
PackItem(new PowerCrystal());
if (Utility.RandomDouble() < 0.02)
{
Body = 767;
SetStr(401, 500);
SetDex(81, 100);
SetInt(151, 200);
SetHits(241, 300);
SetDamage(16, 22);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 60, 70);
SetResistance(ResistanceType.Fire, 60, 70);
SetResistance(ResistanceType.Cold, 60, 70);
SetResistance(ResistanceType.Poison, 30, 40);
SetResistance(ResistanceType.Energy, 20, 30);
SetSkill(SkillName.Anatomy, 90.1, 100.0);
SetSkill(SkillName.EvalInt, 90.1, 100.0);
SetSkill(SkillName.Magery, 50.1, 100.0);
SetSkill(SkillName.Meditation, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 120.1, 130.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.Wrestling, 90.1, 100.0);
Fame = 15000;
Karma = -15000;
VirtualArmor = 65;
SpeechHue = Utility.RandomDyedHue();
PackItem(new PowerCrystal());
if (Utility.RandomDouble() < 0.02)
{
PackItem(new BlackthornWelcomeBook());
}
m_NextAbilityTime = Core.Now + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 30));
PackItem(new BlackthornWelcomeBook());
}
}
public Betrayer(Serial serial)
: base(serial)
public Betrayer(Serial serial) : base(serial)
{
}
public override string CorpseName => "a betrayer corpse";
public override string DefaultName => "a betrayer";
public override bool AlwaysMurderer => true;
public override bool BardImmune => !Core.AOS;
public override Poison PoisonImmune => Poison.Lethal;
public override int Meat => 1;
public override int TreasureMapLevel => 5;
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (Utility.RandomDouble() < 0.05)
{
}
public override string CorpseName => "a betrayer corpse";
public override string DefaultName => "a betrayer";
public override bool AlwaysMurderer => true;
public override bool BardImmune => !Core.AOS;
public override Poison PoisonImmune => Poison.Lethal;
public override int Meat => 1;
public override int TreasureMapLevel => 5;
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (Utility.RandomDouble() < 0.05)
if (!IsParagon)
{
if (!IsParagon)
if (Utility.RandomDouble() < 0.75)
{
if (Utility.RandomDouble() < 0.75)
{
c.DropItem(DawnsMusicGear.RandomCommon);
}
else
{
c.DropItem(DawnsMusicGear.RandomUncommon);
}
c.DropItem(DawnsMusicGear.RandomCommon);
}
else
{
c.DropItem(DawnsMusicGear.RandomRare);
c.DropItem(DawnsMusicGear.RandomUncommon);
}
}
}
public override int GetDeathSound() => 0x423;
public override int GetAttackSound() => 0x23B;
public override int GetHurtSound() => 0x140;
public override void GenerateLoot()
{
AddLoot(LootPack.FilthyRich);
AddLoot(LootPack.Rich);
AddLoot(LootPack.Gems, 1);
}
public override void OnGaveMeleeAttack(Mobile defender, int damage)
{
base.OnGaveMeleeAttack(defender, damage);
if (!m_Stunning && Utility.RandomDouble() < 0.3)
else
{
m_Stunning = true;
defender.Animate(21, 6, 1, true, false, 0);
PlaySound(0xEE);
defender.LocalOverheadMessage(
MessageType.Regular,
0x3B2,
false,
"You have been stunned by a colossal blow!"
);
if (Weapon is BaseWeapon weapon)
{
weapon.OnHit(this, defender);
}
if (defender.Alive)
{
defender.Frozen = true;
Timer.StartTimer(TimeSpan.FromSeconds(5.0), () => Recover_Callback(defender));
}
c.DropItem(DawnsMusicGear.RandomRare);
}
}
private void Recover_Callback(Mobile defender)
{
defender.Frozen = false;
defender.Combatant = null;
defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses.");
m_Stunning = false;
}
public override void OnActionCombat()
{
var combatant = Combatant;
if (Core.Now < m_NextAbilityTime || combatant?.Deleted != false || combatant.Map != Map ||
!InRange(combatant, 3) || !CanBeHarmful(combatant) || !InLOS(combatant))
{
return;
}
m_NextAbilityTime = Core.Now + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 30));
if (Utility.RandomBool())
{
FixedParticles(0x376A, 9, 32, 0x2539, EffectLayer.LeftHand);
PlaySound(0x1DE);
foreach (var m in GetMobilesInRange(2))
{
if (m != this && IsEnemy(m))
{
m.ApplyPoison(this, Poison.Deadly);
}
}
}
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}
public override int GetDeathSound() => 0x423;
public override int GetAttackSound() => 0x23B;
public override int GetHurtSound() => 0x140;
public override void GenerateLoot()
{
AddLoot(LootPack.FilthyRich);
AddLoot(LootPack.Rich);
AddLoot(LootPack.Gems, 1);
}
private static MonsterAbility[] _abilities = { MonsterAbility.ColossalBlow, MonsterAbility.PoisonGasAreaAttack };
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -1,106 +1,82 @@
using Server.Items;
namespace Server.Mobiles
namespace Server.Mobiles;
public class GargoyleDestroyer : BaseCreature
{
public class GargoyleDestroyer : BaseCreature
[Constructible]
public GargoyleDestroyer() : base(AIType.AI_Mage)
{
[Constructible]
public GargoyleDestroyer() : base(AIType.AI_Mage)
Body = 0x2F3;
BaseSoundID = 0x174;
SetStr(760, 850);
SetDex(102, 150);
SetInt(152, 200);
SetHits(482, 485);
SetDamage(7, 14);
SetResistance(ResistanceType.Physical, 40, 60);
SetResistance(ResistanceType.Fire, 60, 70);
SetResistance(ResistanceType.Cold, 15, 25);
SetResistance(ResistanceType.Poison, 15, 25);
SetResistance(ResistanceType.Energy, 15, 25);
SetSkill(SkillName.Wrestling, 90.1, 100.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 120.4, 160.0);
SetSkill(SkillName.Anatomy, 50.5, 100.0);
SetSkill(SkillName.Swords, 90.1, 100.0);
SetSkill(SkillName.Macing, 90.1, 100.0);
SetSkill(SkillName.Fencing, 90.1, 100.0);
SetSkill(SkillName.Magery, 90.1, 100.0);
SetSkill(SkillName.EvalInt, 90.1, 100.0);
SetSkill(SkillName.Meditation, 90.1, 100.0);
Fame = 10000;
Karma = -10000;
VirtualArmor = 50;
if (Utility.RandomDouble() < 0.2)
{
Body = 0x2F3;
BaseSoundID = 0x174;
SetStr(760, 850);
SetDex(102, 150);
SetInt(152, 200);
SetHits(482, 485);
SetDamage(7, 14);
SetResistance(ResistanceType.Physical, 40, 60);
SetResistance(ResistanceType.Fire, 60, 70);
SetResistance(ResistanceType.Cold, 15, 25);
SetResistance(ResistanceType.Poison, 15, 25);
SetResistance(ResistanceType.Energy, 15, 25);
SetSkill(SkillName.Wrestling, 90.1, 100.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 120.4, 160.0);
SetSkill(SkillName.Anatomy, 50.5, 100.0);
SetSkill(SkillName.Swords, 90.1, 100.0);
SetSkill(SkillName.Macing, 90.1, 100.0);
SetSkill(SkillName.Fencing, 90.1, 100.0);
SetSkill(SkillName.Magery, 90.1, 100.0);
SetSkill(SkillName.EvalInt, 90.1, 100.0);
SetSkill(SkillName.Meditation, 90.1, 100.0);
Fame = 10000;
Karma = -10000;
VirtualArmor = 50;
if (Utility.RandomDouble() < 0.2)
{
PackItem(new GargoylesPickaxe());
}
}
public GargoyleDestroyer(Serial serial) : base(serial)
{
}
public override string CorpseName => "a gargoyle corpse";
public override string DefaultName => "a gargoyle destroyer";
public override bool BardImmune => !Core.AOS;
public override int Meat => 1;
public override bool CanFly => true;
public override void GenerateLoot()
{
AddLoot(LootPack.FilthyRich);
AddLoot(LootPack.Rich);
AddLoot(LootPack.MedScrolls);
AddLoot(LootPack.Gems, 2);
}
public override void OnDamagedBySpell(Mobile from, int damage)
{
if (from?.Alive == true && Utility.RandomDouble() < 0.4)
{
ThrowHatchet(from);
}
}
public override void OnGotMeleeAttack(Mobile attacker, int damage)
{
base.OnGotMeleeAttack(attacker, damage);
if (attacker?.Alive == true && attacker.Weapon is BaseRanged && Utility.RandomDouble() < 0.4)
{
ThrowHatchet(attacker);
}
}
public void ThrowHatchet(Mobile to)
{
var damage = 50;
MovingEffect(to, 0xF43, 10, 0, false, false);
DoHarmful(to);
AOS.Damage(to, this, damage, 100, 0, 0, 0, 0);
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
PackItem(new GargoylesPickaxe());
}
}
public GargoyleDestroyer(Serial serial) : base(serial)
{
}
public override string CorpseName => "a gargoyle corpse";
public override string DefaultName => "a gargoyle destroyer";
public override bool BardImmune => !Core.AOS;
public override int Meat => 1;
public override bool CanFly => true;
private static MonsterAbility[] _abilities = { MonsterAbility.ThrowHatchetCounter };
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
public override void GenerateLoot()
{
AddLoot(LootPack.FilthyRich);
AddLoot(LootPack.Rich);
AddLoot(LootPack.MedScrolls);
AddLoot(LootPack.Gems, 2);
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -1,158 +1,118 @@
using System;
using Server.Items;
using Server.Network;
namespace Server.Mobiles
namespace Server.Mobiles;
public class Juggernaut : BaseCreature
{
public class Juggernaut : BaseCreature
[Constructible]
public Juggernaut() : base(AIType.AI_Melee)
{
private bool m_Stunning;
Body = 768;
[Constructible]
public Juggernaut() : base(AIType.AI_Melee)
SetStr(301, 400);
SetDex(51, 70);
SetInt(51, 100);
SetHits(181, 240);
SetDamage(12, 19);
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Fire, 25);
SetDamageType(ResistanceType.Energy, 25);
SetResistance(ResistanceType.Physical, 65, 75);
SetResistance(ResistanceType.Fire, 35, 45);
SetResistance(ResistanceType.Cold, 35, 45);
SetResistance(ResistanceType.Poison, 15, 25);
SetResistance(ResistanceType.Energy, 10, 20);
SetSkill(SkillName.Anatomy, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 140.1, 150.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.Wrestling, 90.1, 100.0);
Fame = 12000;
Karma = -12000;
VirtualArmor = 70;
if (Utility.RandomDouble() < 0.1)
{
Body = 768;
SetStr(301, 400);
SetDex(51, 70);
SetInt(51, 100);
SetHits(181, 240);
SetDamage(12, 19);
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Fire, 25);
SetDamageType(ResistanceType.Energy, 25);
SetResistance(ResistanceType.Physical, 65, 75);
SetResistance(ResistanceType.Fire, 35, 45);
SetResistance(ResistanceType.Cold, 35, 45);
SetResistance(ResistanceType.Poison, 15, 25);
SetResistance(ResistanceType.Energy, 10, 20);
SetSkill(SkillName.Anatomy, 90.1, 100.0);
SetSkill(SkillName.MagicResist, 140.1, 150.0);
SetSkill(SkillName.Tactics, 90.1, 100.0);
SetSkill(SkillName.Wrestling, 90.1, 100.0);
Fame = 12000;
Karma = -12000;
VirtualArmor = 70;
if (Utility.RandomDouble() < 0.1)
{
PackItem(new PowerCrystal());
}
if (Utility.RandomDouble() < 0.4)
{
PackItem(new ClockworkAssembly());
}
PackItem(new PowerCrystal());
}
public Juggernaut(Serial serial) : base(serial)
if (Utility.RandomDouble() < 0.4)
{
PackItem(new ClockworkAssembly());
}
}
public override string CorpseName => "a juggernaut corpse";
public Juggernaut(Serial serial) : base(serial)
{
}
public override string DefaultName => "a blackthorn juggernaut";
public override string CorpseName => "a juggernaut corpse";
public override bool AlwaysMurderer => true;
public override bool BardImmune => !Core.AOS;
public override bool BleedImmune => true;
public override Poison PoisonImmune => Poison.Lethal;
public override int Meat => 1;
public override int TreasureMapLevel => 5;
public override string DefaultName => "a blackthorn juggernaut";
public override void OnDeath(Container c)
public override bool AlwaysMurderer => true;
public override bool BardImmune => !Core.AOS;
public override bool BleedImmune => true;
public override Poison PoisonImmune => Poison.Lethal;
public override int Meat => 1;
public override int TreasureMapLevel => 5;
private static MonsterAbility[] _abilities = { MonsterAbility.ColossalBlow };
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (Utility.RandomDouble() < 0.05)
{
base.OnDeath(c);
if (Utility.RandomDouble() < 0.05)
if (!IsParagon)
{
if (!IsParagon)
if (Utility.RandomDouble() < 0.75)
{
if (Utility.RandomDouble() < 0.75)
{
c.DropItem(DawnsMusicGear.RandomCommon);
}
else
{
c.DropItem(DawnsMusicGear.RandomUncommon);
}
c.DropItem(DawnsMusicGear.RandomCommon);
}
else
{
c.DropItem(DawnsMusicGear.RandomRare);
c.DropItem(DawnsMusicGear.RandomUncommon);
}
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.Rich);
AddLoot(LootPack.Gems, 1);
}
public override int GetDeathSound() => 0x423;
public override int GetAttackSound() => 0x23B;
public override int GetHurtSound() => 0x140;
public override void OnGaveMeleeAttack(Mobile defender, int damage)
{
base.OnGaveMeleeAttack(defender, damage);
if (!m_Stunning && Utility.RandomDouble() < 0.3)
else
{
m_Stunning = true;
defender.Animate(21, 6, 1, true, false, 0);
PlaySound(0xEE);
defender.LocalOverheadMessage(
MessageType.Regular,
0x3B2,
false,
"You have been stunned by a colossal blow!"
);
if (Weapon is BaseWeapon weapon)
{
weapon.OnHit(this, defender);
}
if (defender.Alive)
{
defender.Frozen = true;
Timer.StartTimer(TimeSpan.FromSeconds(5.0), () => Recover_Callback(defender));
}
c.DropItem(DawnsMusicGear.RandomRare);
}
}
private void Recover_Callback(Mobile defender)
{
defender.Frozen = false;
defender.Combatant = null;
defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses.");
m_Stunning = false;
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.Rich);
AddLoot(LootPack.Gems, 1);
}
public override int GetDeathSound() => 0x423;
public override int GetAttackSound() => 0x23B;
public override int GetHurtSound() => 0x140;
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -90,7 +90,7 @@ namespace Server.Mobiles
}
case 1:
{
defender.SendAsciiMessage("You have been hit by a paralyzing blow!");
defender.SendLocalizedMessage(1072221); // You have been hit by a paralyzing blow!
defender.Freeze(TimeSpan.FromSeconds(3.0));
break;
}

View file

@ -1,246 +1,182 @@
using System;
using Server.Items;
using Server.Network;
namespace Server.Mobiles
namespace Server.Mobiles;
public class Golem : BaseCreature
{
public class Golem : BaseCreature
[Constructible]
public Golem(bool summoned = false, double scalar = 1.0) : base(AIType.AI_Melee)
{
private bool m_Stunning;
Body = 752;
[Constructible]
public Golem(bool summoned = false, double scalar = 1.0) : base(AIType.AI_Melee)
if (summoned)
{
Body = 752;
if (summoned)
{
Hue = 2101;
}
SetStr((int)(251 * scalar), (int)(350 * scalar));
SetDex((int)(76 * scalar), (int)(100 * scalar));
SetInt((int)(101 * scalar), (int)(150 * scalar));
SetHits((int)(151 * scalar), (int)(210 * scalar));
SetDamage((int)(13 * scalar), (int)(24 * scalar));
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, (int)(35 * scalar), (int)(55 * scalar));
if (summoned)
{
SetResistance(ResistanceType.Fire, (int)(50 * scalar), (int)(60 * scalar));
}
else
{
SetResistance(ResistanceType.Fire, (int)(100 * scalar));
}
SetResistance(ResistanceType.Cold, (int)(10 * scalar), (int)(30 * scalar));
SetResistance(ResistanceType.Poison, (int)(10 * scalar), (int)(25 * scalar));
SetResistance(ResistanceType.Energy, (int)(30 * scalar), (int)(40 * scalar));
SetSkill(SkillName.MagicResist, 150.1 * scalar, 190.0 * scalar);
SetSkill(SkillName.Tactics, 60.1 * scalar, 100.0 * scalar);
SetSkill(SkillName.Wrestling, 60.1 * scalar, 100.0 * scalar);
if (summoned)
{
Fame = 10;
Karma = 10;
}
else
{
Fame = 3500;
Karma = -3500;
}
if (!summoned)
{
PackItem(new IronIngot(Utility.RandomMinMax(13, 21)));
if (Utility.RandomDouble() < 0.1)
{
PackItem(new PowerCrystal());
}
if (Utility.RandomDouble() < 0.15)
{
PackItem(new ClockworkAssembly());
}
if (Utility.RandomDouble() < 0.2)
{
PackItem(new ArcaneGem());
}
if (Utility.RandomDouble() < 0.25)
{
PackItem(new Gears());
}
}
ControlSlots = 3;
Hue = 2101;
}
public Golem(Serial serial) : base(serial)
SetStr((int)(251 * scalar), (int)(350 * scalar));
SetDex((int)(76 * scalar), (int)(100 * scalar));
SetInt((int)(101 * scalar), (int)(150 * scalar));
SetHits((int)(151 * scalar), (int)(210 * scalar));
SetDamage((int)(13 * scalar), (int)(24 * scalar));
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, (int)(35 * scalar), (int)(55 * scalar));
if (summoned)
{
SetResistance(ResistanceType.Fire, (int)(50 * scalar), (int)(60 * scalar));
}
else
{
SetResistance(ResistanceType.Fire, (int)(100 * scalar));
}
public override string CorpseName => "a golem corpse";
SetResistance(ResistanceType.Cold, (int)(10 * scalar), (int)(30 * scalar));
SetResistance(ResistanceType.Poison, (int)(10 * scalar), (int)(25 * scalar));
SetResistance(ResistanceType.Energy, (int)(30 * scalar), (int)(40 * scalar));
public override bool IsScaredOfScaryThings => false;
public override bool IsScaryToPets => true;
SetSkill(SkillName.MagicResist, 150.1 * scalar, 190.0 * scalar);
SetSkill(SkillName.Tactics, 60.1 * scalar, 100.0 * scalar);
SetSkill(SkillName.Wrestling, 60.1 * scalar, 100.0 * scalar);
public override bool IsBondable => false;
public override FoodType FavoriteFood => FoodType.None;
public override bool CanBeDistracted => false;
public override string DefaultName => "a golem";
public override bool DeleteOnRelease => true;
public override bool AutoDispel => !Controlled;
public override bool BleedImmune => true;
public override bool BardImmune => !Core.AOS || Controlled;
public override Poison PoisonImmune => Poison.Lethal;
public override void OnDeath(Container c)
if (summoned)
{
base.OnDeath(c);
Fame = 10;
Karma = 10;
}
else
{
Fame = 3500;
Karma = -3500;
}
if (Utility.RandomDouble() < 0.05)
if (!summoned)
{
PackItem(new IronIngot(Utility.RandomMinMax(13, 21)));
if (Utility.RandomDouble() < 0.1)
{
if (!IsParagon)
PackItem(new PowerCrystal());
}
if (Utility.RandomDouble() < 0.15)
{
PackItem(new ClockworkAssembly());
}
if (Utility.RandomDouble() < 0.2)
{
PackItem(new ArcaneGem());
}
if (Utility.RandomDouble() < 0.25)
{
PackItem(new Gears());
}
}
ControlSlots = 3;
}
public Golem(Serial serial) : base(serial)
{
}
public override string CorpseName => "a golem corpse";
public override bool IsScaredOfScaryThings => false;
public override bool IsScaryToPets => true;
public override bool IsBondable => false;
public override FoodType FavoriteFood => FoodType.None;
public override bool CanBeDistracted => false;
public override string DefaultName => "a golem";
public override bool DeleteOnRelease => true;
public override bool AutoDispel => !Controlled;
public override bool BleedImmune => true;
public override bool BardImmune => !Core.AOS || Controlled;
public override Poison PoisonImmune => Poison.Lethal;
private static MonsterAbility[] _abilities = { MonsterAbility.ColossalBlow };
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (Utility.RandomDouble() < 0.05)
{
if (!IsParagon)
{
if (Utility.RandomDouble() < 0.75)
{
if (Utility.RandomDouble() < 0.75)
{
c.DropItem(DawnsMusicGear.RandomCommon);
}
else
{
c.DropItem(DawnsMusicGear.RandomUncommon);
}
c.DropItem(DawnsMusicGear.RandomCommon);
}
else
{
c.DropItem(DawnsMusicGear.RandomRare);
c.DropItem(DawnsMusicGear.RandomUncommon);
}
}
}
public override int GetAngerSound() => 541;
public override int GetIdleSound()
{
if (!Controlled)
else
{
return 542;
c.DropItem(DawnsMusicGear.RandomRare);
}
return base.GetIdleSound();
}
public override int GetDeathSound()
{
if (!Controlled)
{
return 545;
}
return base.GetDeathSound();
}
public override int GetAttackSound() => 562;
public override int GetHurtSound()
{
if (Controlled)
{
return 320;
}
return base.GetHurtSound();
}
public override void OnGaveMeleeAttack(Mobile defender, int damage)
{
base.OnGaveMeleeAttack(defender, damage);
if (!m_Stunning && Utility.RandomDouble() < 0.3)
{
m_Stunning = true;
defender.Animate(21, 6, 1, true, false, 0);
PlaySound(0xEE);
defender.LocalOverheadMessage(
MessageType.Regular,
0x3B2,
false,
"You have been stunned by a colossal blow!"
);
if (Weapon is BaseWeapon weapon)
{
weapon.OnHit(this, defender);
}
if (defender.Alive)
{
defender.Frozen = true;
Timer.StartTimer(TimeSpan.FromSeconds(5.0), () => Recover_Callback(defender));
}
}
}
private void Recover_Callback(Mobile defender)
{
defender.Frozen = false;
defender.Combatant = null;
defender.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You recover your senses.");
m_Stunning = false;
}
public override void OnDamage(int amount, Mobile from, bool willKill)
{
if (Controlled || Summoned)
{
var master = ControlMaster ?? SummonMaster;
if (master?.Player == true && master.Map == Map && master.InRange(Location, 20))
{
if (master.Mana >= amount)
{
master.Mana -= amount;
}
else
{
amount -= master.Mana;
master.Mana = 0;
master.Damage(amount);
}
}
}
base.OnDamage(amount, from, willKill);
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}
public override int GetAngerSound() => 541;
public override int GetIdleSound() => !Controlled ? 542 : base.GetIdleSound();
public override int GetDeathSound() => !Controlled ? 545 : base.GetDeathSound();
public override int GetAttackSound() => 562;
public override int GetHurtSound() => Controlled ? 320 : base.GetHurtSound();
public override void OnDamage(int amount, Mobile from, bool willKill)
{
if (Controlled || Summoned)
{
var master = ControlMaster ?? SummonMaster;
if (master?.Player == true && master.Map == Map && master.InRange(Location, 20))
{
if (master.Mana >= amount)
{
master.Mana -= amount;
}
else
{
amount -= master.Mana;
master.Mana = 0;
master.Damage(amount);
}
}
}
base.OnDamage(amount, from, willKill);
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -1,74 +1,75 @@
using Server.Items;
namespace Server.Mobiles
namespace Server.Mobiles;
public class BronzeElemental : BaseCreature
{
public class BronzeElemental : BaseCreature
[Constructible]
public BronzeElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
[Constructible]
public BronzeElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
// TODO: Gas attack
Body = 108;
BaseSoundID = 268;
Body = 108;
BaseSoundID = 268;
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetHits(136, 153);
SetHits(136, 153);
SetDamage(9, 16);
SetDamage(9, 16);
SetDamageType(ResistanceType.Physical, 30);
SetDamageType(ResistanceType.Fire, 70);
SetDamageType(ResistanceType.Physical, 30);
SetDamageType(ResistanceType.Fire, 70);
SetResistance(ResistanceType.Physical, 30, 40);
SetResistance(ResistanceType.Fire, 30, 40);
SetResistance(ResistanceType.Cold, 10, 20);
SetResistance(ResistanceType.Poison, 70, 80);
SetResistance(ResistanceType.Energy, 20, 30);
SetResistance(ResistanceType.Physical, 30, 40);
SetResistance(ResistanceType.Fire, 30, 40);
SetResistance(ResistanceType.Cold, 10, 20);
SetResistance(ResistanceType.Poison, 70, 80);
SetResistance(ResistanceType.Energy, 20, 30);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
Fame = 5000;
Karma = -5000;
Fame = 5000;
Karma = -5000;
VirtualArmor = 29;
VirtualArmor = 29;
Item ore = new BronzeOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
Item ore = new BronzeOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
public BronzeElemental(Serial serial) : base(serial)
{
}
public BronzeElemental(Serial serial) : base(serial)
{
}
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a bronze elemental";
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a bronze elemental";
public override bool BleedImmune => true;
public override bool AutoDispel => true;
public override int TreasureMapLevel => 1;
public override bool BleedImmune => true;
public override bool AutoDispel => true;
public override int TreasureMapLevel => 1;
public override void GenerateLoot()
{
AddLoot(LootPack.Average);
AddLoot(LootPack.Gems, 2);
}
private static MonsterAbility[] _abilities = { MonsterAbility.PoisonGasCounter };
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void GenerateLoot()
{
AddLoot(LootPack.Average);
AddLoot(LootPack.Gems, 2);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -1,77 +1,76 @@
using Server.Items;
namespace Server.Mobiles
namespace Server.Mobiles;
public class CopperElemental : BaseCreature
{
public class CopperElemental : BaseCreature
[Constructible]
public CopperElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
[Constructible]
public CopperElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
Body = 109;
BaseSoundID = 268;
Body = 109;
BaseSoundID = 268;
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetHits(136, 153);
SetHits(136, 153);
SetDamage(9, 16);
SetDamage(9, 16);
SetDamageType(ResistanceType.Physical, 100);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 30, 40);
SetResistance(ResistanceType.Fire, 30, 40);
SetResistance(ResistanceType.Cold, 30, 40);
SetResistance(ResistanceType.Poison, 20, 30);
SetResistance(ResistanceType.Energy, 10, 20);
SetResistance(ResistanceType.Physical, 30, 40);
SetResistance(ResistanceType.Fire, 30, 40);
SetResistance(ResistanceType.Cold, 30, 40);
SetResistance(ResistanceType.Poison, 20, 30);
SetResistance(ResistanceType.Energy, 10, 20);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
Fame = 4800;
Karma = -4800;
Fame = 4800;
Karma = -4800;
VirtualArmor = 26;
VirtualArmor = 26;
Item ore = new CopperOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
Item ore = new CopperOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
public CopperElemental(Serial serial) : base(serial)
{
}
public CopperElemental(Serial serial) : base(serial)
{
}
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a copper elemental";
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a copper elemental";
public override bool BleedImmune => true;
public override bool AutoDispel => true;
public override int TreasureMapLevel => 1;
public override bool BleedImmune => true;
public override bool AutoDispel => true;
public override int TreasureMapLevel => 1;
public override void GenerateLoot()
{
AddLoot(LootPack.Average);
AddLoot(LootPack.Gems, 2);
}
public override void GenerateLoot()
{
AddLoot(LootPack.Average);
AddLoot(LootPack.Gems, 2);
}
public override void CheckReflect(Mobile caster, ref bool reflect)
{
reflect = true; // Every spell is reflected back to the caster
}
public override void CheckReflect(Mobile caster, ref bool reflect)
{
reflect = true; // Every spell is reflected back to the caster
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -1,72 +1,74 @@
using Server.Items;
namespace Server.Mobiles
namespace Server.Mobiles;
public class DullCopperElemental : BaseCreature
{
public class DullCopperElemental : BaseCreature
[Constructible]
public DullCopperElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
[Constructible]
public DullCopperElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
Body = 110;
BaseSoundID = 268;
Body = 110;
BaseSoundID = 268;
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetHits(136, 153);
SetHits(136, 153);
SetDamage(9, 16);
SetDamage(9, 16);
SetDamageType(ResistanceType.Physical, 100);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 30, 40);
SetResistance(ResistanceType.Fire, 30, 40);
SetResistance(ResistanceType.Cold, 10, 20);
SetResistance(ResistanceType.Poison, 20, 30);
SetResistance(ResistanceType.Energy, 20, 30);
SetResistance(ResistanceType.Physical, 30, 40);
SetResistance(ResistanceType.Fire, 30, 40);
SetResistance(ResistanceType.Cold, 10, 20);
SetResistance(ResistanceType.Poison, 20, 30);
SetResistance(ResistanceType.Energy, 20, 30);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
Fame = 3500;
Karma = -3500;
Fame = 3500;
Karma = -3500;
VirtualArmor = 20;
VirtualArmor = 20;
Item ore = new DullCopperOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
Item ore = new DullCopperOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
public DullCopperElemental(Serial serial) : base(serial)
{
}
public DullCopperElemental(Serial serial) : base(serial)
{
}
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a dull copper elemental";
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a dull copper elemental";
public override bool AutoDispel => true;
public override bool BleedImmune => true;
public override int TreasureMapLevel => 1;
public override bool AutoDispel => true;
public override bool BleedImmune => true;
public override int TreasureMapLevel => 1;
public override void GenerateLoot()
{
AddLoot(LootPack.Average);
AddLoot(LootPack.Gems, 2);
}
private static MonsterAbility[] _abilities = { MonsterAbility.DeathExplosion };
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void GenerateLoot()
{
AddLoot(LootPack.Average);
AddLoot(LootPack.Gems, 2);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -1,92 +1,93 @@
using Server.Items;
namespace Server.Mobiles
namespace Server.Mobiles;
public class ValoriteElemental : BaseCreature
{
public class ValoriteElemental : BaseCreature
[Constructible]
public ValoriteElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
[Constructible]
public ValoriteElemental(int oreAmount = 2) : base(AIType.AI_Melee)
Body = 112;
BaseSoundID = 268;
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetHits(136, 153);
SetDamage(28);
SetDamageType(ResistanceType.Physical, 25);
SetDamageType(ResistanceType.Fire, 25);
SetDamageType(ResistanceType.Cold, 25);
SetDamageType(ResistanceType.Energy, 25);
SetResistance(ResistanceType.Physical, 65, 75);
SetResistance(ResistanceType.Fire, 50, 60);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 50, 60);
SetResistance(ResistanceType.Energy, 40, 50);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
Fame = 3500;
Karma = -3500;
VirtualArmor = 38;
Item ore = new ValoriteOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
public ValoriteElemental(Serial serial) : base(serial)
{
}
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a valorite elemental";
public override bool AutoDispel => true;
public override bool BleedImmune => true;
public override int TreasureMapLevel => 1;
private static MonsterAbility[] _abilities = { MonsterAbility.PoisonGasCounter, MonsterAbility.DestroyEquipment };
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
public override void GenerateLoot()
{
AddLoot(LootPack.FilthyRich);
AddLoot(LootPack.Gems, 4);
}
public override void AlterMeleeDamageFrom(Mobile from, ref int damage)
{
if (from is BaseCreature bc)
{
// TODO: Gas attack
Body = 112;
BaseSoundID = 268;
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetHits(136, 153);
SetDamage(28);
SetDamageType(ResistanceType.Physical, 25);
SetDamageType(ResistanceType.Fire, 25);
SetDamageType(ResistanceType.Cold, 25);
SetDamageType(ResistanceType.Energy, 25);
SetResistance(ResistanceType.Physical, 65, 75);
SetResistance(ResistanceType.Fire, 50, 60);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 50, 60);
SetResistance(ResistanceType.Energy, 40, 50);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
Fame = 3500;
Karma = -3500;
VirtualArmor = 38;
Item ore = new ValoriteOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
public ValoriteElemental(Serial serial) : base(serial)
{
}
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a valorite elemental";
public override bool AutoDispel => true;
public override bool BleedImmune => true;
public override int TreasureMapLevel => 1;
public override void GenerateLoot()
{
AddLoot(LootPack.FilthyRich);
AddLoot(LootPack.Gems, 4);
}
public override void AlterMeleeDamageFrom(Mobile from, ref int damage)
{
if (from is BaseCreature bc)
if (bc.Controlled || bc.BardTarget == this)
{
if (bc.Controlled || bc.BardTarget == this)
{
damage = 0; // Immune to pets and provoked creatures
}
damage = 0; // Immune to pets and provoked creatures
}
}
}
public override void CheckReflect(Mobile caster, ref bool reflect)
{
reflect = true; // Every spell is reflected back to the caster
}
public override void CheckReflect(Mobile caster, ref bool reflect)
{
reflect = true; // Every spell is reflected back to the caster
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -1,73 +1,75 @@
using Server.Items;
namespace Server.Mobiles
namespace Server.Mobiles;
public class VeriteElemental : BaseCreature
{
public class VeriteElemental : BaseCreature
[Constructible]
public VeriteElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
[Constructible]
public VeriteElemental(int oreAmount = 2) : base(AIType.AI_Melee)
{
Body = 113;
BaseSoundID = 268;
Body = 113;
BaseSoundID = 268;
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetStr(226, 255);
SetDex(126, 145);
SetInt(71, 92);
SetHits(136, 153);
SetHits(136, 153);
SetDamage(9, 16);
SetDamage(9, 16);
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Energy, 50);
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Energy, 50);
SetResistance(ResistanceType.Physical, 30, 40);
SetResistance(ResistanceType.Fire, 10, 20);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 50, 60);
SetResistance(ResistanceType.Energy, 50, 60);
SetResistance(ResistanceType.Physical, 30, 40);
SetResistance(ResistanceType.Fire, 10, 20);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 50, 60);
SetResistance(ResistanceType.Energy, 50, 60);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
SetSkill(SkillName.MagicResist, 50.1, 95.0);
SetSkill(SkillName.Tactics, 60.1, 100.0);
SetSkill(SkillName.Wrestling, 60.1, 100.0);
Fame = 3500;
Karma = -3500;
Fame = 3500;
Karma = -3500;
VirtualArmor = 35;
VirtualArmor = 35;
Item ore = new VeriteOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
Item ore = new VeriteOre(oreAmount);
ore.ItemID = 0x19B9;
PackItem(ore);
}
public VeriteElemental(Serial serial) : base(serial)
{
}
public VeriteElemental(Serial serial) : base(serial)
{
}
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a verite elemental";
public override string CorpseName => "an ore elemental corpse";
public override string DefaultName => "a verite elemental";
public override bool AutoDispel => true;
public override bool BleedImmune => true;
public override int TreasureMapLevel => 1;
public override bool AutoDispel => true;
public override bool BleedImmune => true;
public override int TreasureMapLevel => 1;
public override void GenerateLoot()
{
AddLoot(LootPack.Rich);
AddLoot(LootPack.Gems, 2);
}
private static MonsterAbility[] _abilities = { MonsterAbility.DestroyEquipment };
public override MonsterAbility[] GetMonsterAbilities() => _abilities;
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void GenerateLoot()
{
AddLoot(LootPack.Rich);
AddLoot(LootPack.Gems, 2);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
}
}

View file

@ -169,9 +169,9 @@ namespace Server.Mobiles
public class LevianthanBreath : FireBreath
{
public override int BreathPhysicalDamage => 70;
public override int BreathColdDamage => 30;
public override int BreathFireDamage => 0;
public override int PhysicalDamage => 70;
public override int ColdDamage => 30;
public override int FireDamage => 0;
public override int BreathEffectHue => 0x1ED;
public override double BreathDamageScalar => 0.05;
public override TimeSpan MinTriggerCooldown => TimeSpan.FromSeconds(5.0);