using System; using WeightedMonsterAbility = Server.Random.WeightedValue; namespace Server.Mobiles; public class MonsterAbilityGroup : MonsterAbility { private readonly WeightedMonsterAbility[] _weightedAbilities; private readonly WeightedMonsterAbility[] _availableToTrigger; private readonly MonsterAbilityTrigger _triggers; private int _availableToTriggerCount; public MonsterAbilityGroup(params WeightedMonsterAbility[] weightedAbilities) { _weightedAbilities = weightedAbilities; _availableToTrigger = new WeightedMonsterAbility[weightedAbilities.Length]; for (var i = 0; i < _weightedAbilities.Length; i++) { _triggers |= _weightedAbilities[i].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.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(_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); } } }