using System;
using ModernUO.CodeGeneratedEvents;
namespace Server.Mobiles;
///
/// Abstract class used to build singletons for managing a specific monster ability.
///
public abstract class MonsterAbility
{
public virtual MonsterAbilityType AbilityType => MonsterAbilityType.Generic;
public virtual MonsterAbilityTrigger AbilityTrigger => MonsterAbilityTrigger.None;
public virtual double ChanceToTrigger => 1.0;
public virtual TimeSpan MinTriggerCooldown => TimeSpan.Zero;
public virtual TimeSpan MaxTriggerCooldown => TimeSpan.Zero;
///
/// Returns true if ability is not on cooldown, and the chance to trigger succeeds.
///
/// Boolean indicating the ability can trigger.
public virtual bool CanTrigger(BaseCreature source, MonsterAbilityTrigger trigger)
{
if ((AbilityTrigger & trigger) == 0 || source is not { Alive: true, Deleted: false })
{
return false;
}
if (source.IsAbilityOnCooldown(this))
{
return false;
}
var c = ChanceToTrigger;
return c >= 1 || c > 0 && c > Utility.RandomDouble();
}
///
/// Triggers the monster's ability. Override this and call `base.Trigger(source);` to make sure
/// the cooldown is tracked.
/// Note: This can fire after a monster is killed/deleted (map is null)
///
public virtual void Trigger(MonsterAbilityTrigger trigger, BaseCreature source, Mobile target)
{
if (MinTriggerCooldown <= TimeSpan.Zero && MaxTriggerCooldown <= TimeSpan.Zero)
{
return;
}
var randomAmount = MinTriggerCooldown == MaxTriggerCooldown
? MinTriggerCooldown
: Utility.RandomMinMax(MinTriggerCooldown, MaxTriggerCooldown);
source.SetAbilityCooldown(this, randomAmount);
}
public virtual void AlterMeleeDamageFrom(BaseCreature source, Mobile target, ref int damage)
{
}
public virtual void AlterMeleeDamageTo(BaseCreature source, Mobile target, ref int damage)
{
}
public virtual void AlterSpellDamageScalarFrom(BaseCreature source, Mobile target, ref double scalar)
{
}
public virtual void AlterSpellDamageScalarTo(BaseCreature source, Mobile target, ref double scalar)
{
}
public virtual void AlterSpellDamageFrom(BaseCreature source, Mobile target, ref int damage)
{
}
public virtual void AlterSpellDamageTo(BaseCreature source, Mobile target, ref int damage)
{
}
public virtual void Move(BaseCreature source, Direction d)
{
}
[OnEvent(nameof(CreatureEvents.CreatureDeathEvent))]
public static void ResetCooldownsOnDeath(BaseCreature source) => source.ClearAbilityCooldowns();
}