public void OnImpact(NWCreature player, NWObject target, int perkLevel, int spellTier) { NWItem weapon = player.RightHand; int iDamage; int iRange = 15; int iCount = 1; float fDelay = 0; int saberDamage = player.RightHand.DamageBonus; if (saberDamage > 40) { saberDamage = 40; } if (weapon.CustomItemType == CustomItemType.Lightsaber || weapon.CustomItemType == CustomItemType.Saberstaff) { iDamage = saberDamage + RandomService.D6(2) + player.StrengthModifier; } else { iDamage = (int)weapon.Weight + player.StrengthModifier + (saberDamage / 2); } NWObject oObject; // If player is in stealth mode, force them out of stealth mode. if (_.GetActionMode(player.Object, ActionMode.Stealth) == true) { _.SetActionMode(player.Object, ActionMode.Stealth, false); } // Make the player face their target. _.ClearAllActions(); BiowarePosition.TurnToFaceObject(target, player); player.AssignCommand(() => _.ActionPlayAnimation(Animation.LoopingCustom10, 2)); var result = CombatService.CalculateAbilityResistance(player, target.Object, SkillType.ForceAlter, ForceBalanceType.Universal); float delta = 0.01f * result.Delta; /* * // reset phenotype * player.DelayAssignCommand(() => * { * _.SetPhenoType(4, player); * }, 2.0f); * * player.DelayAssignCommand(() => * { * _.SetPhenoType(iPheno, player); * }, 2.5f); */ // Handle effects for differing spellTier values switch (spellTier) { case 1: iDamage = (int)(iDamage * 1.0); iDamage = iDamage + (int)(iDamage * delta); fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(DurationType.Instant, _.EffectLinkEffects(_.EffectVisualEffect(VisualEffect.Vfx_Imp_Sonic), _.EffectDamage(iDamage, DamageType.BaseWeapon)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } break; case 2: iDamage = (int)(iDamage * 1.25); iDamage = iDamage + (int)(iDamage * delta); fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(DurationType.Instant, _.EffectLinkEffects(_.EffectVisualEffect(VisualEffect.Vfx_Imp_Sonic), _.EffectDamage(iDamage, DamageType.BaseWeapon)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } break; case 3: iDamage = (int)(iDamage * 1.5); iDamage = iDamage + (int)(iDamage * delta); fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(DurationType.Instant, _.EffectLinkEffects(_.EffectVisualEffect(VisualEffect.Vfx_Imp_Sonic), _.EffectDamage(iDamage, DamageType.BaseWeapon)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } break; case 4: iDamage = (int)(iDamage * 1.6); iDamage = iDamage + (int)(iDamage * delta); // apply to target fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(DurationType.Instant, _.EffectLinkEffects(_.EffectVisualEffect(VisualEffect.Vfx_Imp_Sonic), _.EffectDamage(iDamage, DamageType.BaseWeapon)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } iCount += 1; // apply to next nearest creature in the spellcylinder oObject = _.GetFirstObjectInShape(Shape.SpellCone, iRange, target.Location, true, ObjectType.Creature, _.GetPosition(player)); while (oObject.IsValid && iCount < 3) { if (oObject != target && oObject != player) { fDelay = _.GetDistanceBetween(player, oObject) / 10.0f; var creature = oObject; player.DelayAssignCommand(() => { _.ApplyEffectToObject(DurationType.Instant, _.EffectLinkEffects(_.EffectVisualEffect(VisualEffect.Vfx_Imp_Sonic), _.EffectDamage(iDamage, DamageType.BaseWeapon)), creature); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, oObject, SkillType.ForceAlter); } iCount += 1; } oObject = _.GetNextObjectInShape(Shape.SpellCone, iRange, target.Location, true, ObjectType.Creature, _.GetPosition(player)); } break; case 5: iDamage = (int)(iDamage * 1.75); iDamage = iDamage + (int)(iDamage * delta); // apply to target fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(DurationType.Instant, _.EffectLinkEffects(_.EffectVisualEffect(VisualEffect.Vfx_Imp_Sonic), _.EffectDamage(iDamage, DamageType.BaseWeapon)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } iCount += 1; // apply to next nearest creature in the spellcylinder oObject = _.GetFirstObjectInShape(Shape.SpellCylinder, iRange, target.Location, true, ObjectType.Creature, _.GetPosition(player)); while (oObject.IsValid && iCount < 4) { if (oObject != target && oObject != player) { fDelay = _.GetDistanceBetween(player, oObject) / 10.0f; var creature = oObject; player.DelayAssignCommand(() => { _.ApplyEffectToObject(DurationType.Instant, _.EffectLinkEffects(_.EffectVisualEffect(VisualEffect.Vfx_Imp_Sonic), _.EffectDamage(iDamage, DamageType.BaseWeapon)), creature); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, oObject, SkillType.ForceAlter); } iCount += 1; } oObject = _.GetNextObjectInShape(Shape.SpellCylinder, iRange, target.Location, true, ObjectType.Creature, _.GetPosition(player)); } break; default: throw new ArgumentOutOfRangeException(nameof(spellTier)); } }
/// <summary> /// Handles casting abilities. These can be combat-related or casting-related and may or may not have a casting delay. /// Requirement reductions (MP, STM, etc) are applied after the casting has completed. /// In the event there is no casting delay, the reductions are applied immediately. /// </summary> /// <param name="activator">The creature activating the ability.</param> /// <param name="target">The target of the ability</param> /// <param name="ability">The ability details</param> /// <param name="effectivePerkLevel">The activator's effective perk level</param> private static void ActivateAbility(uint activator, uint target, AbilityDetail ability, int effectivePerkLevel) { // Activation delay is increased if player is equipped with heavy or light armor. float CalculateActivationDelay() { const float HeavyArmorPenalty = 2.0f; const float LightArmorPenalty = 1.5f; var armorPenalty = 1.0f; var penaltyMessage = string.Empty; for (var slot = 0; slot < NumberOfInventorySlots; slot++) { var item = GetItemInSlot((InventorySlot)slot, activator); for (var ip = GetFirstItemProperty(item); GetIsItemPropertyValid(ip); ip = GetNextItemProperty(item)) { if (GetItemPropertyType(ip) != ItemPropertyType.ArmorType) { continue; } var armorType = (ArmorType)GetItemPropertySubType(ip); if (armorType == ArmorType.Heavy) { armorPenalty = HeavyArmorPenalty; penaltyMessage = "Heavy armor slows your casting speed by 100%."; break; } else if (armorType == ArmorType.Light) { armorPenalty = LightArmorPenalty; penaltyMessage = "Light armor slows your casting speed by 50%."; } } // If we found heavy armor, we can exit early. Anything else requires us to iterate over the rest of the items. if (armorPenalty >= HeavyArmorPenalty) { break; } } // Notify player if needed. if (!string.IsNullOrWhiteSpace(penaltyMessage)) { SendMessageToPC(activator, penaltyMessage); } var abilityDelay = ability.ActivationDelay?.Invoke(activator, target, effectivePerkLevel) ?? 0.0f; return(abilityDelay * armorPenalty); } // Handles displaying animation and visual effects. void ProcessAnimationAndVisualEffects(float delay) { // Force out of stealth if (GetActionMode(activator, ActionMode.Stealth)) { SetActionMode(activator, ActionMode.Stealth, false); } AssignCommand(activator, () => ClearAllActions()); BiowarePosition.TurnToFaceObject(target, activator); // Display a casting visual effect if one has been specified. if (ability.ActivationVisualEffect != VisualEffect.None) { var vfx = TagEffect(EffectVisualEffect(ability.ActivationVisualEffect), "ACTIVATION_VFX"); ApplyEffectToObject(DurationType.Temporary, vfx, activator, delay + 0.2f); } // Casted types play an animation of casting. if (ability.ActivationType == AbilityActivationType.Casted && ability.AnimationType != Animation.Invalid) { AssignCommand(activator, () => ActionPlayAnimation(ability.AnimationType, 1.0f, delay - 0.2f)); } } // Recursive function which checks if player has moved since starting the casting. void CheckForActivationInterruption(string activationId, Vector3 originalPosition) { if (!GetIsPC(activator)) { return; } // Completed abilities should no longer run. var status = GetLocalInt(activator, activationId); if (status == (int)ActivationStatus.Completed || status == (int)ActivationStatus.Invalid) { return; } var currentPosition = GetPosition(activator); if (currentPosition.X != originalPosition.X || currentPosition.Y != originalPosition.Y || currentPosition.Z != originalPosition.Z) { RemoveEffectByTag(activator, "ACTIVATION_VFX"); Player.StopGuiTimingBar(activator, string.Empty); SendMessageToPC(activator, "Your ability has been interrupted."); return; } DelayCommand(0.5f, () => CheckForActivationInterruption(activationId, originalPosition)); } // This method is called after the delay of the ability has finished. void CompleteActivation(string id, float abilityRecastDelay) { DeleteLocalInt(activator, id); // Moved during casting or activator died. Cancel the activation. if (GetLocalInt(activator, id) == (int)ActivationStatus.Interrupted || GetCurrentHitPoints(activator) <= 0) { return; } ApplyRequirementEffects(activator, ability); ability.ImpactAction?.Invoke(activator, target, effectivePerkLevel); ApplyRecastDelay(activator, ability.RecastGroup, abilityRecastDelay); } // Begin the main process var activationId = Guid.NewGuid().ToString(); var activationDelay = CalculateActivationDelay(); var recastDelay = ability.RecastDelay(activator); var position = GetPosition(activator); ProcessAnimationAndVisualEffects(activationDelay); CheckForActivationInterruption(activationId, position); SetLocalInt(activator, activationId, (int)ActivationStatus.Started); if (GetIsPC(activator)) { if (activationDelay > 0.0f) { Player.StartGuiTimingBar(activator, activationDelay, string.Empty); } } DelayCommand(activationDelay, () => CompleteActivation(activationId, recastDelay)); }
private static void ActivateAbility( NWCreature activator, NWObject target, Data.Entity.Perk entity, IPerkHandler perkHandler, int pcPerkLevel, PerkExecutionType executionType, int spellTier) { string uuid = Guid.NewGuid().ToString(); float baseActivationTime = perkHandler.CastingTime(activator, (float)entity.BaseCastingTime, spellTier); float activationTime = baseActivationTime; var vfxID = VisualEffect.Invalid; var animationID = Animation.Invalid; if (baseActivationTime > 0f && activationTime < 1.0f) { activationTime = 1.0f; } // Force ability armor penalties float armorPenalty = 0.0f; if (executionType == PerkExecutionType.ForceAbility || executionType == PerkExecutionType.ConcentrationAbility) { string penaltyMessage = string.Empty; foreach (var item in activator.EquippedItems) { if (item.CustomItemType == CustomItemType.HeavyArmor) { armorPenalty = 2; penaltyMessage = "Heavy armor slows your force cooldown by 100%."; break; } else if (item.CustomItemType == CustomItemType.LightArmor) { armorPenalty = 1.25f; penaltyMessage = "Light armor slows your force cooldown by 25%."; } } // If there's an armor penalty, send a message to the player. if (armorPenalty > 0.0f) { activator.SendMessage(penaltyMessage); } } // If player is in stealth mode, force them out of stealth mode. if (_.GetActionMode(activator.Object, ActionMode.Stealth)) { _.SetActionMode(activator.Object, ActionMode.Stealth, false); } // Make the player face their target. _.ClearAllActions(); BiowarePosition.TurnToFaceObject(target, activator); // Force and Concentration Abilities will display a visual effect during the casting process. if (executionType == PerkExecutionType.ForceAbility || executionType == PerkExecutionType.ConcentrationAbility) { vfxID = VisualEffect.Vfx_Dur_Iounstone_Yellow; animationID = Animation.LoopingConjure1; } if (executionType == PerkExecutionType.ConcentrationAbility) { activator.SetLocalObject("CONCENTRATION_TARGET", target); } // If a VFX ID has been specified, play that effect instead of the default one. if (vfxID != VisualEffect.Invalid) { var vfx = _.EffectVisualEffect(vfxID); vfx = _.TagEffect(vfx, "ACTIVATION_VFX"); _.ApplyEffectToObject(DurationType.Temporary, vfx, activator.Object, activationTime + 0.2f); } // If an animation has been specified, make the player play that animation now. // bypassing if perk is throw saber due to couldn't get the animation to work via db table edit if (animationID != Animation.Invalid && entity.ID != (int)PerkType.ThrowSaber) { activator.AssignCommand(() => _.ActionPlayAnimation(animationID, 1.0f, activationTime - 0.1f)); } // Mark player as busy. Busy players can't take other actions (crafting, harvesting, etc.) activator.IsBusy = true; // Non-players can't be interrupted via movement. if (!activator.IsPlayer) { // Begin the check for spell interruption. If the activator moves, the spell will be canceled. CheckForSpellInterruption(activator, uuid, activator.Position); } activator.SetLocalInt(uuid, (int)SpellStatusType.Started); // If there's a casting delay, display a timing bar on-screen. if (activationTime > 0) { NWNXPlayer.StartGuiTimingBar(activator, (int)activationTime, string.Empty); } // Run the FinishAbilityUse event at the end of the activation time. int perkID = entity.ID; var @event = new OnFinishAbilityUse(activator, uuid, perkID, target, pcPerkLevel, spellTier, armorPenalty); activator.DelayEvent(activationTime + 0.2f, @event); }
public void OnImpact(NWCreature player, NWObject target, int perkLevel, int spellTier) { NWItem weapon = player.RightHand; int iDamage; int iRange = 15; int iCount = 1; float fDelay = 0; if (weapon.CustomItemType == CustomItemType.Lightsaber || weapon.CustomItemType == CustomItemType.Saberstaff) { iDamage = player.RightHand.DamageBonus + RandomService.D6(2) + player.IntelligenceModifier + player.StrengthModifier; } else { iDamage = (int)weapon.Weight + player.StrengthModifier; } NWObject oObject; // If player is in stealth mode, force them out of stealth mode. if (_.GetActionMode(player.Object, ACTION_MODE_STEALTH) == 1) { _.SetActionMode(player.Object, ACTION_MODE_STEALTH, 0); } // Make the player face their target. _.ClearAllActions(); BiowarePosition.TurnToFaceObject(target, player); player.AssignCommand(() => _.ActionPlayAnimation(30, 2)); _.SendMessageToPC(player, "Level " + spellTier); // Handle effects for differing spellTier values switch (spellTier) { case 1: iDamage = (int)(iDamage * 1.6); fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(_.DURATION_TYPE_INSTANT, _.EffectLinkEffects(_.EffectVisualEffect(VFX_IMP_SONIC), _.EffectDamage(iDamage, _.DAMAGE_TYPE_BASE_WEAPON)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } break; case 2: iDamage = (int)(iDamage * 1.25); fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(_.DURATION_TYPE_INSTANT, _.EffectLinkEffects(_.EffectVisualEffect(VFX_IMP_SONIC), _.EffectDamage(iDamage, _.DAMAGE_TYPE_BASE_WEAPON)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } break; case 3: iDamage = (int)(iDamage * 1.6); fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(_.DURATION_TYPE_INSTANT, _.EffectLinkEffects(_.EffectVisualEffect(VFX_IMP_SONIC), _.EffectDamage(iDamage, _.DAMAGE_TYPE_BASE_WEAPON)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } break; case 4: iDamage = (int)(iDamage * 2.0); // apply to target fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(_.DURATION_TYPE_INSTANT, _.EffectLinkEffects(_.EffectVisualEffect(VFX_IMP_SONIC), _.EffectDamage(iDamage, _.DAMAGE_TYPE_BASE_WEAPON)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } iCount += 1; // apply to next nearest creature in the spellcylinder oObject = _.GetFirstObjectInShape(_.SHAPE_SPELLCONE, iRange, target.Location, 1, _.OBJECT_TYPE_CREATURE, _.GetPosition(player)); while (oObject.IsValid && iCount < 3) { if (oObject != target && oObject != player) { fDelay = _.GetDistanceBetween(player, oObject) / 10.0f; var creature = oObject; player.DelayAssignCommand(() => { _.ApplyEffectToObject(_.DURATION_TYPE_INSTANT, _.EffectLinkEffects(_.EffectVisualEffect(VFX_IMP_SONIC), _.EffectDamage(iDamage, _.DAMAGE_TYPE_BASE_WEAPON)), creature); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, oObject, SkillType.ForceAlter); } iCount += 1; } oObject = _.GetNextObjectInShape(_.SHAPE_SPELLCONE, iRange, target.Location, 1, _.OBJECT_TYPE_CREATURE, _.GetPosition(player)); } break; case 5: iDamage = (int)(iDamage * 2.5); // apply to target fDelay = _.GetDistanceBetween(player, target) / 10.0f; player.DelayAssignCommand(() => { _.ApplyEffectToObject(_.DURATION_TYPE_INSTANT, _.EffectLinkEffects(_.EffectVisualEffect(VFX_IMP_SONIC), _.EffectDamage(iDamage, _.DAMAGE_TYPE_BASE_WEAPON)), target); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, target, SkillType.ForceAlter); } iCount += 1; // apply to next nearest creature in the spellcylinder oObject = _.GetFirstObjectInShape(_.SHAPE_SPELLCYLINDER, iRange, target.Location, 1, _.OBJECT_TYPE_CREATURE, _.GetPosition(player)); while (oObject.IsValid && iCount < 4) { if (oObject != target && oObject != player) { fDelay = _.GetDistanceBetween(player, oObject) / 10.0f; var creature = oObject; player.DelayAssignCommand(() => { _.ApplyEffectToObject(_.DURATION_TYPE_INSTANT, _.EffectLinkEffects(_.EffectVisualEffect(VFX_IMP_SONIC), _.EffectDamage(iDamage, _.DAMAGE_TYPE_BASE_WEAPON)), creature); }, fDelay); if (player.IsPlayer) { SkillService.RegisterPCToNPCForSkill(player.Object, oObject, SkillType.ForceAlter); } iCount += 1; } oObject = _.GetNextObjectInShape(_.SHAPE_SPELLCYLINDER, iRange, target.Location, 1, _.OBJECT_TYPE_CREATURE, _.GetPosition(player)); } break; default: throw new ArgumentOutOfRangeException(nameof(spellTier)); } }
private static void ActivateAbility(NWPlayer pc, NWObject target, Data.Entity.Perk entity, IPerkHandler perkHandler, int pcPerkLevel, PerkExecutionType executionType, int spellFeatID) { string uuid = Guid.NewGuid().ToString(); var effectiveStats = PlayerStatService.GetPlayerItemEffectiveStats(pc); int itemBonus = effectiveStats.CastingSpeed; float baseActivationTime = perkHandler.CastingTime(pc, (float)entity.BaseCastingTime, spellFeatID); float activationTime = baseActivationTime; int vfxID = -1; int animationID = -1; // Activation Bonus % - Shorten activation time. if (itemBonus > 0) { float activationBonus = Math.Abs(itemBonus) * 0.01f; activationTime = activationTime - activationTime * activationBonus; } // Activation Penalty % - Increase activation time. else if (itemBonus < 0) { float activationPenalty = Math.Abs(itemBonus) * 0.01f; activationTime = activationTime + activationTime * activationPenalty; } if (baseActivationTime > 0f && activationTime < 1.0f) { activationTime = 1.0f; } // Force ability armor penalties if (executionType == PerkExecutionType.ForceAbility) { float armorPenalty = 0.0f; string penaltyMessage = string.Empty; foreach (var item in pc.EquippedItems) { if (item.CustomItemType == CustomItemType.HeavyArmor) { armorPenalty = 2; penaltyMessage = "Heavy armor slows your force activation speed by 100%."; break; } else if (item.CustomItemType == CustomItemType.LightArmor) { armorPenalty = 1.25f; penaltyMessage = "Light armor slows your force activation speed by 25%."; } } if (armorPenalty > 0.0f) { activationTime = baseActivationTime * armorPenalty; pc.SendMessage(penaltyMessage); } } if (_.GetActionMode(pc.Object, ACTION_MODE_STEALTH) == 1) { _.SetActionMode(pc.Object, ACTION_MODE_STEALTH, 0); } _.ClearAllActions(); BiowarePosition.TurnToFaceObject(target, pc); if (executionType == PerkExecutionType.ForceAbility) { vfxID = VFX_DUR_IOUNSTONE_YELLOW; animationID = ANIMATION_LOOPING_CONJURE1; } if (vfxID > -1) { var vfx = _.EffectVisualEffect(vfxID); vfx = _.TagEffect(vfx, "ACTIVATION_VFX"); _.ApplyEffectToObject(DURATION_TYPE_TEMPORARY, vfx, pc.Object, activationTime + 0.2f); } if (animationID > -1) { pc.AssignCommand(() => _.ActionPlayAnimation(animationID, 1.0f, activationTime - 0.1f)); } pc.IsBusy = true; CheckForSpellInterruption(pc, uuid, pc.Position); pc.SetLocalInt(uuid, (int)SpellStatusType.Started); NWNXPlayer.StartGuiTimingBar(pc, (int)activationTime, ""); int perkID = entity.ID; pc.DelayEvent <FinishAbilityUse>(activationTime + 0.2f, pc, uuid, perkID, target, pcPerkLevel, spellFeatID); }