ModernUO/Projects/UOContent/Mobiles/Special/Barracoon.cs
Kamron Batman 28c06c1cc0
fix: Changes Map.Sector.Mobiles to link list & Fixes various related crash bugs (#1553)
### Summary

Eliminates `IPooledEnumerable<T>` and `eable.Free()` from `Map` for mobiles. This drastically simplifies code that iterates in range, for example:

```cs
foreach (var m in m.GetMobilesInRange(5))
{
}
```
The code above no longer requires an eable and calling `Free()`.

- [X] Fixed several locations where an NPC that was damaged would cause a server crash.
- [X] Removed an unnecessary allocation in guard fake calls (NPCs calling guards on you)
- [X] Fixes damage precision loss in Poison Strike Spell
- [X] BogThing no longer attempts to "search" for boglings to eat when it is at full health
2023-10-29 22:42:46 -07:00

227 lines
5.6 KiB
C#

using System;
using ModernUO.Serialization;
using Server.Engines.CannedEvil;
using Server.Items;
using Server.Spells.Fifth;
using Server.Spells.Seventh;
namespace Server.Mobiles;
[SerializationGenerator(0, false)]
public partial class Barracoon : BaseChampion
{
[Constructible]
public Barracoon() : base(AIType.AI_Melee)
{
Title = "the piper";
Body = 0x190;
Hue = 0x83EC;
SetStr(305, 425);
SetDex(72, 150);
SetInt(505, 750);
SetHits(4200);
SetStam(102, 300);
SetDamage(25, 35);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 60, 70);
SetResistance(ResistanceType.Fire, 50, 60);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 40, 50);
SetResistance(ResistanceType.Energy, 40, 50);
SetSkill(SkillName.MagicResist, 100.0);
SetSkill(SkillName.Tactics, 97.6, 100.0);
SetSkill(SkillName.Wrestling, 97.6, 100.0);
Fame = 22500;
Karma = -22500;
VirtualArmor = 70;
AddItem(new FancyShirt(Utility.RandomGreenHue()));
AddItem(new LongPants(Utility.RandomYellowHue()));
AddItem(new JesterHat(Utility.RandomPinkHue()));
AddItem(new Cloak(Utility.RandomPinkHue()));
AddItem(new Sandals());
HairItemID = 0x203B; // Short Hair
HairHue = 0x94;
}
public override ChampionSkullType SkullType => ChampionSkullType.Greed;
public override Type[] UniqueList => new[] { typeof(FangOfRactus) };
public override Type[] SharedList => new[]
{
typeof(EmbroideredOakLeafCloak),
typeof(DjinnisRing),
typeof(DetectiveBoots),
typeof(GuantletsOfAnger)
};
public override Type[] DecorativeList => new[] { typeof(SwampTile), typeof(MonsterStatuette) };
public override MonsterStatuetteType[] StatueTypes => new[] { MonsterStatuetteType.Slime };
public override string DefaultName => "Barracoon";
public override bool AlwaysMurderer => true;
public override bool AutoDispel => true;
public override double AutoDispelChance => 1.0;
public override bool BardImmune => !Core.SE;
public override bool Unprovokable => Core.SE;
public override bool Uncalmable => Core.SE;
public override Poison PoisonImmune => Poison.Deadly;
public override bool ShowFameTitle => false;
public override bool ClickTitle => false;
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 3);
}
public void Polymorph(Mobile m)
{
if (!m.CanBeginAction<PolymorphSpell>() || !m.CanBeginAction<IncognitoSpell>() || m.IsBodyMod)
{
return;
}
var mount = m.Mount;
if (mount != null)
{
mount.Rider = null;
}
if (m.Mounted)
{
return;
}
if (m.BeginAction<PolymorphSpell>())
{
var disarm = m.FindItemOnLayer(Layer.OneHanded);
if (disarm?.Movable == true)
{
m.AddToBackpack(disarm);
}
disarm = m.FindItemOnLayer(Layer.TwoHanded);
if (disarm?.Movable == true)
{
m.AddToBackpack(disarm);
}
m.BodyMod = 42;
m.HueMod = 0;
new ExpirePolymorphTimer(m).Start();
}
}
public void SpawnRatmen(Mobile target)
{
var map = Map;
if (map == null)
{
return;
}
var rats = 0;
foreach (var m in GetMobilesInRange<BaseCreature>(10))
{
if (m is Ratman or RatmanArcher or RatmanMage && ++rats >= 16)
{
return;
}
}
PlaySound(0x3D);
rats = Utility.RandomMinMax(3, 6);
for (var i = 0; i < rats; ++i)
{
var rat = Utility.Random(5) switch
{
2 => (BaseCreature)new RatmanArcher(),
3 => new RatmanArcher(),
4 => new RatmanMage(),
_ => new Ratman()
};
rat.Team = Team;
rat.MoveToWorld(map.GetRandomNearbyLocation(Location), map);
rat.Combatant = target;
}
}
public void DoSpecialAbility(Mobile target)
{
if (target?.Deleted != false) // sanity
{
return;
}
if (Utility.RandomDouble() < 0.6) // 60% chance to polymorph attacker into a ratman
{
Polymorph(target);
}
if (Utility.RandomDouble() < 0.2) // 20% chance to spawn more ratmen
{
SpawnRatmen(target);
}
if (Hits < 500 && !IsBodyMod) // Baracoon is low on life, polymorph into a ratman
{
Polymorph(this);
}
}
public override void OnGotMeleeAttack(Mobile attacker, int damage)
{
base.OnGotMeleeAttack(attacker, damage);
DoSpecialAbility(attacker);
}
public override void OnGaveMeleeAttack(Mobile defender, int damage)
{
base.OnGaveMeleeAttack(defender, damage);
DoSpecialAbility(defender);
}
private class ExpirePolymorphTimer : Timer
{
private readonly Mobile m_Owner;
public ExpirePolymorphTimer(Mobile owner) : base(TimeSpan.FromMinutes(3.0))
{
m_Owner = owner;
}
protected override void OnTick()
{
if (!m_Owner.CanBeginAction<PolymorphSpell>())
{
m_Owner.BodyMod = 0;
m_Owner.HueMod = -1;
m_Owner.EndAction<PolymorphSpell>();
}
}
}
}