public bool isSpellTargetViable(int spellId, [NotNull] DefaultEntityActorStateContainer actorState) { if (actorState == null) { throw new ArgumentNullException(nameof(actorState)); } if (spellId <= 0) { throw new ArgumentOutOfRangeException(nameof(spellId)); } SpellDefinitionDataModel definition = SpellDataCollection.GetSpellDefinition(spellId); foreach (var effect in SpellDataCollection.GetEffectsForSpell(spellId)) { ISpellEffectTargetValidator effectTargetValidator = ValidatorFactory.Create(effect); //One effect's targets failed given the context. So this fails. if (!effectTargetValidator.ValidateTargetContext(definition, effect, actorState)) { return(false); } } return(true); }
protected override void HandleEvent(ActionBarButtonStateChangedEventArgs args) { //TODO: Check actionbar index and handle multiple rows. if (ActionBarRow.ContainsKey(args.Index)) { IUIActionBarButton barButton = ActionBarRow[args.Index]; if (args.ActionType == ActionBarIndexType.Empty) { barButton.SetElementActive(false); } else { barButton.SetElementActive(true); //TODO: Refactor for spell/item if (args.ActionType == ActionBarIndexType.Spell) { //TODO: Abstract the icon content loading //TODO: Don't assume we have the content icon. Throw/log better exception SpellDefinitionDataModel definition = SpellDataCollection.GetSpellDefinition(args.ActionId); ContentIconInstanceModel icon = ContentIconCollection[definition.SpellIconId]; ProjectVersionStage.AssertAlpha(); //TODO: Load async Texture2D iconTexture = Resources.Load <Texture2D>(Path.Combine("Icon", Path.GetFileNameWithoutExtension(icon.IconPathName))); barButton.ActionBarImageIcon.SetSpriteTexture(iconTexture); } else { throw new InvalidOperationException($"TODO: Implement empty/item action bar support"); } } } }
protected override bool ValidateTargeting(SpellDefinitionDataModel spellDefinition, SpellEffectDefinitionDataModel spellEffect, DefaultEntityActorStateContainer actorState) { if (spellDefinition == null) { throw new ArgumentNullException(nameof(spellDefinition)); } if (spellEffect == null) { throw new ArgumentNullException(nameof(spellEffect)); } if (actorState == null) { throw new ArgumentNullException(nameof(actorState)); } NetworkEntityGuid guid = GetEntityTarget(actorState); //Does the entity exist, small window of time between valid cast start and now where entity can despawn //so minor chance it doesn't exist anymore. if (!KnownEntitySet.isEntityKnown(guid)) { return(false); } //TODO: We shouldn't assume they are enemies just because they aren't use. We need a system for hostility masking for entities return(guid != NetworkEntityGuid.Empty && guid.EntityType == EntityType.Creature && guid != actorState.EntityGuid); }
protected override bool ValidateTargeting(SpellDefinitionDataModel spellDefinition, SpellEffectDefinitionDataModel spellEffect, DefaultEntityActorStateContainer actorState) { //Ally targeting is always valid. Even if targeting an enemy //This is because we'll just cast it on ourselves if we're //targeting an enemy. return(true); }
public BarCastingState(bool isSpellCasting, [CanBeNull][NotNull] SpellDefinitionDataModel spellDefinition, long startTimeStamp) { if (startTimeStamp < 0) { throw new ArgumentOutOfRangeException(nameof(startTimeStamp)); } this.isSpellCasting = isSpellCasting; SpellDefinition = spellDefinition ?? throw new ArgumentNullException(nameof(spellDefinition)); StartTimeStamp = startTimeStamp; }
public ApplySpellEffectMessage Create([NotNull] SpellEffectApplicationMessageCreationContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } SpellDefinitionDataModel spellDefinition = SpellDataCollection.GetSpellDefinition(context.SpellId); SpellEffectDefinitionDataModel effectDefinition = SpellDataCollection.GetSpellEffectDefinition(spellDefinition.GetSpellEffectId(context.EffectIndex)); return(new ApplySpellEffectMessage(context.ApplicationSource, spellDefinition, effectDefinition)); }
public ApplySpellEffectMessage([NotNull] NetworkEntityGuid sourceCaster, [NotNull] SpellDefinitionDataModel spell, [NotNull] SpellEffectDefinitionDataModel spellEffect) { SourceCaster = sourceCaster ?? throw new ArgumentNullException(nameof(sourceCaster)); Spell = spell ?? throw new ArgumentNullException(nameof(spell)); SpellEffect = spellEffect ?? throw new ArgumentNullException(nameof(spellEffect)); //TODO: Expand this to validate additional effects. if (spell.SpellEffectIdOne != SpellEffect.SpellEffectId) { throw new InvalidOperationException($"Cannot apply spell effect for Spell: {spell.SpellId} with Effect: {spellEffect.SpellEffectId} because the spell is not linked to that effect."); } }
public bool AddSpellDefinition([NotNull] SpellDefinitionDataModel spellData) { if (spellData == null) { throw new ArgumentNullException(nameof(spellData)); } if (ContainsSpellDefinition(spellData.SpellId)) { return(false); } SpellMap.Add(spellData.SpellId, spellData); return(true); }
public PendingSpellCastData Create([NotNull] PendingSpellCastCreationContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } ICancelable pendingSpellCastCancelable = new Cancelable(ActorScheduler); SpellDefinitionDataModel definition = SpellDataCollection.GetSpellDefinition(context.SpellId); //We need to compute a timespan for the pending cast from the definition casting time. TimeSpan castTimeSpan = definition.CastTime == 0 ? TimeSpan.Zero : TimeSpan.FromMilliseconds(definition.CastTime); long startCastTime = TimeService.CurrentLocalTime; long expectedFinishTime = startCastTime + castTimeSpan.Ticks; return(new PendingSpellCastData(startCastTime, expectedFinishTime, context.SpellId, pendingSpellCastCancelable, castTimeSpan, context.CurrentTarget)); }
public bool ValidateTargetContext([NotNull] SpellDefinitionDataModel spellDefinition, [NotNull] SpellEffectDefinitionDataModel spellEffect, [NotNull] DefaultEntityActorStateContainer actorState) { if (spellDefinition == null) { throw new ArgumentNullException(nameof(spellDefinition)); } if (spellEffect == null) { throw new ArgumentNullException(nameof(spellEffect)); } if (actorState == null) { throw new ArgumentNullException(nameof(actorState)); } //We don't validate effect targeting matching the validators effect targeting //because a validator may have MULTIPLE targeting handling. return(ValidateTargeting(spellDefinition, spellEffect, actorState)); }
public void DispatchSpellCast([NotNull] IPendingSpellCastData pendingSpellCast, DefaultEntityActorStateContainer casterData) { if (pendingSpellCast == null) { throw new ArgumentNullException(nameof(pendingSpellCast)); } if (!SpellDataCollection.ContainsSpellDefinition(pendingSpellCast.SpellId)) { throw new InvalidOperationException($"Tried to cast Spell: {pendingSpellCast.SpellId} but no definition exists."); } IActorRef casterActorReference = ActorReferenceMappable.RetrieveEntity(casterData.EntityGuid); SpellDefinitionDataModel spellDefinition = SpellDataCollection.GetSpellDefinition(pendingSpellCast.SpellId); //Each spell can have N effects with individual unique targeting attributes. //So we need to handle each spell effect seperately, compute their effects/targets //and send an effect application message to the involved actors. foreach (SpellEffectIndex effectIndex in spellDefinition.EnumerateSpellEffects()) { SpellEffectDefinitionDataModel effectDefinition = SpellDataCollection.GetSpellEffectDefinition(spellDefinition.GetSpellEffectId(effectIndex)); SpellEffectTargetContext targetContext = EffectTargetSelectorFactory .Create(effectDefinition) .CalculateTargets(spellDefinition, effectDefinition, casterData, pendingSpellCast); ApplySpellEffectMessage spellEffectApplicationMessage = SpellEffectApplicationMessageFactory.Create(new SpellEffectApplicationMessageCreationContext(casterData.EntityGuid, pendingSpellCast.SpellId, effectIndex)); //For each actor target in the target context //we need to send the spell application message for handling foreach (var target in targetContext.SpellEffectTargets) { if (Logger.IsDebugEnabled) { Logger.Debug($"Entity: {casterData.EntityGuid} casted spell with effect that targets Target: {target.Path.Name}"); } target.Tell(spellEffectApplicationMessage, casterActorReference); } } }
public override SpellEffectTargetContext CalculateTargets([NotNull] SpellDefinitionDataModel spellDefinition, [NotNull] SpellEffectDefinitionDataModel spellEffect, [NotNull] DefaultEntityActorStateContainer actorState, [NotNull] IPendingSpellCastData pendingSpellCast) { if (spellDefinition == null) { throw new ArgumentNullException(nameof(spellDefinition)); } if (spellEffect == null) { throw new ArgumentNullException(nameof(spellEffect)); } if (actorState == null) { throw new ArgumentNullException(nameof(actorState)); } if (pendingSpellCast == null) { throw new ArgumentNullException(nameof(pendingSpellCast)); } return(new SpellEffectTargetContext(ComputeAllyTargets(pendingSpellCast, actorState))); }
protected override void OnEventFired(object source, SpellCastingStateChangedEventArgs args) { if (Logger.IsInfoEnabled) { Logger.Info($"Player started casting Spell: {args.CastingSpellId}"); } //Spell casting stopped. Disable the bar. if (!args.isCasting) { CastingBar.SetElementActive(false); CastingBar.CastingBarFillable.FillAmount = 0; CastingState = new BarCastingState(false); } else { SpellDefinitionDataModel spellDefinition = SpellDataCollection.GetSpellDefinition(args.CastingSpellId); CastingState = new BarCastingState(true, spellDefinition, args.CastingStartTimeStamp); CastingBar.CastingBarSpellNameText.Text = spellDefinition.SpellName; CastingBar.SetElementActive(true); } }
public abstract SpellEffectTargetContext CalculateTargets(SpellDefinitionDataModel spellDefinition, SpellEffectDefinitionDataModel spellEffect, DefaultEntityActorStateContainer actorState, IPendingSpellCastData pendingSpellCast);
/// <summary> /// Parameters are never null. /// </summary> /// <param name="spellDefinition"></param> /// <param name="spellEffect"></param> /// <param name="actorState"></param> /// <returns></returns> protected abstract bool ValidateTargeting(SpellDefinitionDataModel spellDefinition, SpellEffectDefinitionDataModel spellEffect, DefaultEntityActorStateContainer actorState);