using System; using Server.Items; using Server.Network; namespace Server.Mobiles { public class PlagueBeast : BaseCreature, IDevourer { public override string CorpseName => "a plague beast corpse"; private int m_DevourTotal; private int m_DevourGoal; private bool m_HasMetalChest = false; [CommandProperty( AccessLevel.GameMaster )] public int TotalDevoured { get => m_DevourTotal; set => m_DevourTotal = value; } [CommandProperty( AccessLevel.GameMaster )] public int DevourGoal { get => ( IsParagon ? m_DevourGoal + 25 : m_DevourGoal ); set => m_DevourGoal = value; } [CommandProperty( AccessLevel.GameMaster )] public bool HasMetalChest => m_HasMetalChest; public override string DefaultName => "a plague beast"; [Constructible] public PlagueBeast() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) { Body = 775; SetStr( 302, 500 ); SetDex( 80 ); SetInt( 16, 20 ); SetHits( 318, 404 ); SetDamage( 20, 24 ); SetDamageType( ResistanceType.Physical, 60 ); SetDamageType( ResistanceType.Poison, 40 ); SetResistance( ResistanceType.Physical, 45, 55 ); SetResistance( ResistanceType.Fire, 40, 50 ); SetResistance( ResistanceType.Cold, 25, 35 ); SetResistance( ResistanceType.Poison, 65, 75 ); SetResistance( ResistanceType.Energy, 25, 35 ); SetSkill( SkillName.MagicResist, 35.0 ); SetSkill( SkillName.Tactics, 100.0 ); SetSkill( SkillName.Wrestling, 100.0 ); Fame = 13000; Karma = -13000; VirtualArmor = 30; PackArmor( 1, 5 ); if ( Utility.RandomDouble() < 0.80 ) PackItem( new PlagueBeastGland() ); if ( Core.ML && Utility.RandomDouble() < 0.33 ) PackItem( Engines.Plants.Seed.RandomPeculiarSeed(4) ); m_DevourTotal = 0; m_DevourGoal = Utility.RandomMinMax( 15, 25 ); // How many corpses must be devoured before a metal chest is awarded } public override void GenerateLoot() { AddLoot( LootPack.FilthyRich ); AddLoot( LootPack.Gems, Utility.Random( 1, 3 ) ); // TODO: dungeon chest, healthy gland } public override void OnGaveMeleeAttack( Mobile defender ) { base.OnGaveMeleeAttack( defender ); defender.ApplyPoison( this, IsParagon ? Poison.Lethal : Poison.Deadly ); defender.FixedParticles( 0x374A, 10, 15, 5021, EffectLayer.Waist ); defender.PlaySound( 0x1CB ); } public override void OnDamagedBySpell( Mobile caster ) { if ( Map != null && caster != this && 0.25 > Utility.RandomDouble() ) { BaseCreature spawn = new PlagueSpawn( this ); spawn.Team = Team; spawn.MoveToWorld( Location, Map ); spawn.Combatant = caster; Say( 1053034 ); // * The plague beast creates another beast from its flesh! * } base.OnDamagedBySpell( caster ); } public override bool AutoDispel => true; public override Poison PoisonImmune => Poison.Lethal; public override void OnGotMeleeAttack( Mobile attacker ) { if ( Map != null && attacker != this && 0.25 > Utility.RandomDouble() ) { BaseCreature spawn = new PlagueSpawn( this ); spawn.Team = Team; spawn.MoveToWorld( Location, Map ); spawn.Combatant = attacker; Say( 1053034 ); // * The plague beast creates another beast from its flesh! * } base.OnGotMeleeAttack( attacker ); } public PlagueBeast( Serial serial ) : base( serial ) { } public override int GetIdleSound() { return 0x1BF; } public override int GetAttackSound() { return 0x1C0; } public override int GetHurtSound() { return 0x1C1; } public override int GetDeathSound() { return 0x1C2; } public override void Serialize( GenericWriter writer ) { base.Serialize( writer ); writer.Write( (int) 1 ); writer.Write( m_HasMetalChest ); writer.Write( m_DevourTotal ); writer.Write( m_DevourGoal ); } public override void Deserialize( GenericReader reader ) { base.Deserialize( reader ); int version = reader.ReadInt(); switch( version ) { case 1: { m_HasMetalChest = reader.ReadBool(); m_DevourTotal = reader.ReadInt(); m_DevourGoal = reader.ReadInt(); break; } } } public override void OnThink() { base.OnThink(); // Check to see if we need to devour any corpses IPooledEnumerable eable = GetItemsInRange( 3 ); // Get all corpses in range foreach( Corpse item in eable ) { // Ensure that the corpse was killed by us if ( item.Killer == this && item.Owner != null ) { if ( !item.DevourCorpse() && !item.Devoured ) PublicOverheadMessage( MessageType.Emote, 0x3B2, 1053032 ); // * The plague beast attempts to absorb the remains, but cannot! * } } eable.Free(); } #region IDevourer Members public bool Devour( Corpse corpse ) { if ( corpse?.Owner == null ) // sorry we can't devour because the corpse's owner is null return false; if ( corpse.Owner.Body.IsHuman ) corpse.TurnToBones(); // Not bones yet, and we are a human body therefore we turn to bones. IncreaseHits( (int)Math.Ceiling( (double)corpse.Owner.HitsMax * 0.75 ) ); m_DevourTotal++; PublicOverheadMessage( MessageType.Emote, 0x3B2, 1053033 ); // * The plague beast absorbs the fleshy remains of the corpse * if ( !m_HasMetalChest && m_DevourTotal >= DevourGoal ) { PackItem( new MetalChest() ); m_HasMetalChest = true; } return true; } #endregion private void IncreaseHits( int hp ) { int maxhits = 2000; if ( IsParagon ) maxhits = (int)(maxhits * Paragon.HitsBuff); if ( hp < 1000 && !Core.AOS ) hp = (hp * 100) / 60; if ( HitsMaxSeed >= maxhits ) { HitsMaxSeed = maxhits; int newHits = Hits + hp + Utility.RandomMinMax( 10, 20 ); // increase the hp until it hits if it goes over it'll max at 2000 Hits = Math.Min( maxhits, newHits ); // Also provide heal for each devour on top of the hp increase } else { int min = (hp / 2) + 10; int max = hp + 20; int hpToIncrease = Utility.RandomMinMax( min, max ); HitsMaxSeed += hpToIncrease; Hits += hpToIncrease; // Also provide heal for each devour } } } }