feat: Adds monster ability groups with weights (#1267)
This commit is contained in:
parent
8b5bd9ec13
commit
02cee4815e
2 changed files with 170 additions and 3 deletions
155
Projects/UOContent/Mobiles/Abilities/MonsterAbilityGroup.cs
Normal file
155
Projects/UOContent/Mobiles/Abilities/MonsterAbilityGroup.cs
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
using System;
|
||||
using Server.Random;
|
||||
using WeightedMonsterAbility = Server.Random.WeightedValue<Server.Mobiles.MonsterAbility>;
|
||||
|
||||
namespace Server.Mobiles;
|
||||
|
||||
public class MonsterAbilityGroup : MonsterAbility
|
||||
{
|
||||
private WeightedMonsterAbility[] _weightedAbilities;
|
||||
private WeightedMonsterAbility[] _availableToTrigger;
|
||||
private int _availableToTriggerCount;
|
||||
private MonsterAbilityTrigger _triggers;
|
||||
|
||||
public MonsterAbilityGroup(params WeightedMonsterAbility[] weightedAbilities)
|
||||
{
|
||||
_weightedAbilities = weightedAbilities;
|
||||
_availableToTrigger = new WeightedMonsterAbility[weightedAbilities.Length];
|
||||
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
var weightedAbility = _weightedAbilities[i];
|
||||
_triggers |= weightedAbility.Value.AbilityTrigger;
|
||||
}
|
||||
}
|
||||
|
||||
public override MonsterAbilityTrigger AbilityTrigger => _triggers;
|
||||
|
||||
public bool HasAbility(MonsterAbility ability)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
if (_weightedAbilities[i].Value == ability)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Note: Does not get an ability randomly by weight
|
||||
// This is used for passives or lookups
|
||||
public MonsterAbility GetAbilityWithType(MonsterAbilityType type)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
var ability = _weightedAbilities[i].Value;
|
||||
if (ability.AbilityType == type)
|
||||
{
|
||||
return ability;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool CanTrigger(BaseCreature source, MonsterAbilityTrigger trigger)
|
||||
{
|
||||
if (!base.CanTrigger(source, trigger))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_availableToTriggerCount = 0;
|
||||
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
var weightedAbility = _weightedAbilities[i];
|
||||
if (weightedAbility.Value.WillTrigger(trigger) && weightedAbility.Value.CanTrigger(source, trigger))
|
||||
{
|
||||
_availableToTrigger[_availableToTriggerCount++] = weightedAbility;
|
||||
}
|
||||
}
|
||||
|
||||
return _availableToTriggerCount > 0;
|
||||
}
|
||||
|
||||
// Note: Trigger will choose an ability at random by weight
|
||||
public override void Trigger(MonsterAbilityTrigger trigger, BaseCreature source, Mobile target)
|
||||
{
|
||||
if (_availableToTriggerCount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var slice = new ReadOnlySpan<WeightedValue<MonsterAbility>>(_availableToTrigger, 0, _availableToTriggerCount);
|
||||
var chosenAbility = slice.RandomWeightedElement().Value;
|
||||
|
||||
// Just in case?
|
||||
if (chosenAbility == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
base.Trigger(trigger, source, target);
|
||||
chosenAbility.Trigger(trigger, source, target);
|
||||
_availableToTriggerCount = 0; // Just in case trigger is called without CanTrigger
|
||||
}
|
||||
|
||||
public override void AlterMeleeDamageFrom(BaseCreature source, Mobile target, ref int damage)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
_weightedAbilities[i].Value.AlterMeleeDamageFrom(source, target, ref damage);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AlterMeleeDamageTo(BaseCreature source, Mobile target, ref int damage)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
_weightedAbilities[i].Value.AlterMeleeDamageTo(source, target, ref damage);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AlterSpellDamageScalarFrom(BaseCreature source, Mobile target, ref double scalar)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
_weightedAbilities[i].Value.AlterSpellDamageScalarFrom(source, target, ref scalar);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AlterSpellDamageScalarTo(BaseCreature source, Mobile target, ref double scalar)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
_weightedAbilities[i].Value.AlterSpellDamageScalarTo(source, target, ref scalar);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AlterSpellDamageFrom(BaseCreature source, Mobile target, ref int damage)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
_weightedAbilities[i].Value.AlterSpellDamageFrom(source, target, ref damage);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AlterSpellDamageTo(BaseCreature source, Mobile target, ref int damage)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
_weightedAbilities[i].Value.AlterSpellDamageTo(source, target, ref damage);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Move(BaseCreature creature, Direction d)
|
||||
{
|
||||
for (var i = 0; i < _weightedAbilities.Length; i++)
|
||||
{
|
||||
_weightedAbilities[i].Value.Move(creature, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1130,7 +1130,15 @@ namespace Server.Mobiles
|
|||
for (var i = 0; i < abilities.Length; i++)
|
||||
{
|
||||
var ability = abilities[i];
|
||||
if (ability.AbilityType == type)
|
||||
if (ability is MonsterAbilityGroup group)
|
||||
{
|
||||
ability = group.GetAbilityWithType(type);
|
||||
if (ability != null)
|
||||
{
|
||||
return ability;
|
||||
}
|
||||
}
|
||||
else if (ability.AbilityType == type)
|
||||
{
|
||||
return ability;
|
||||
}
|
||||
|
|
@ -1141,6 +1149,11 @@ namespace Server.Mobiles
|
|||
|
||||
public virtual bool HasAbility(MonsterAbility ability)
|
||||
{
|
||||
if (ability == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var abilities = GetMonsterAbilities();
|
||||
|
||||
if (abilities == null)
|
||||
|
|
@ -1150,7 +1163,7 @@ namespace Server.Mobiles
|
|||
|
||||
for (var i = 0; i < abilities.Length; i++)
|
||||
{
|
||||
if (abilities[i] == ability)
|
||||
if (abilities[i] == ability || (ability as MonsterAbilityGroup)?.HasAbility(ability) == true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -4290,7 +4303,6 @@ namespace Server.Mobiles
|
|||
|
||||
public virtual void OnActionCombat()
|
||||
{
|
||||
TriggerAbility(MonsterAbilityTrigger.CombatAction, null);
|
||||
}
|
||||
|
||||
public virtual void OnActionGuard()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue