ModernUO/Projects/UOContent/Items/Traps/FlameSpurtTrap.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

155 lines
3.3 KiB
C#

using System;
using ModernUO.Serialization;
using Server.Spells;
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class FlameSpurtTrap : BaseTrap
{
[SerializableField(0)]
private Item _spurt;
private TimerExecutionToken _timerToken;
[Constructible]
public FlameSpurtTrap() : base(0x1B71) => Visible = false;
public virtual void StartTimer()
{
if (!_timerToken.Running)
{
Timer.StartTimer(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), Refresh, out _timerToken);
}
}
public virtual void StopTimer()
{
_timerToken.Cancel();
}
public virtual void CheckTimer()
{
var map = Map;
if (map?.GetSector(GetWorldLocation()).Active == true)
{
StartTimer();
}
else
{
StopTimer();
}
}
public override void OnLocationChange(Point3D oldLocation)
{
base.OnLocationChange(oldLocation);
CheckTimer();
}
public override void OnMapChange()
{
base.OnMapChange();
CheckTimer();
}
public override void OnSectorActivate()
{
base.OnSectorActivate();
StartTimer();
}
public override void OnSectorDeactivate()
{
base.OnSectorDeactivate();
StopTimer();
}
public override void OnDelete()
{
base.OnDelete();
_spurt?.Delete();
}
public virtual void Refresh()
{
if (Deleted)
{
return;
}
foreach (var mob in GetMobilesInRange(3))
{
if (mob.Player && mob.Alive && mob.AccessLevel <= AccessLevel.Player && Z + 8 >= mob.Z && mob.Z + 16 > Z)
{
if (_spurt?.Deleted != false)
{
_spurt = new Static(0x3709);
// This MoveToWorld is generally not safe in a range loop, except we return after this on L100
_spurt.MoveToWorld(Location, Map);
Effects.PlaySound(GetWorldLocation(), Map, 0x309);
}
return;
}
}
_spurt?.Delete();
_spurt = null;
}
public override bool OnMoveOver(Mobile m)
{
if (m.AccessLevel > AccessLevel.Player)
{
return true;
}
if (!(m.Player && m.Alive))
{
return false;
}
CheckTimer();
SpellHelper.Damage(TimeSpan.FromTicks(1), m, m, Utility.RandomMinMax(1, 30));
m.PlaySound(m.Female ? 0x327 : 0x437);
return false;
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
if (m.Location == oldLocation || !m.Player || !m.Alive || m.AccessLevel > AccessLevel.Player
|| !CheckRange(m.Location, oldLocation, 1))
{
return;
}
CheckTimer();
SpellHelper.Damage(TimeSpan.FromTicks(1), m, m, Utility.RandomMinMax(1, 10));
m.PlaySound(m.Female ? 0x327 : 0x437);
if (m.Body.IsHuman)
{
m.Animate(20, 1, 1, true, false, 0);
}
}
[AfterDeserialization(false)]
private void AfterDeserialization()
{
_spurt?.Delete();
CheckTimer();
}
}