public void ApplyEffects(NWCreature user, NWItem item, NWObject target, Location targetLocation, CustomData customData) { DateTime now = DateTime.UtcNow; DateTime unlockDateTime = now; if (string.IsNullOrWhiteSpace(GetLocalString(user, "GRENADE_UNLOCKTIME"))) { unlockDateTime = unlockDateTime.AddSeconds(-1); } else { unlockDateTime = DateTime.ParseExact(GetLocalString(user, "GRENADE_UNLOCKTIME"), "yyyy-MM-dd hh:mm:ss", CultureInfo.InvariantCulture); } //Console.WriteLine("IsValidTarget - Current Time = " + now.ToString("yyyy-MM-dd hh:mm:ss", CultureInfo.InvariantCulture)); //Console.WriteLine("IsValidTarget - Unlocktime = " + unlockDateTime.ToString("yyyy-MM-dd hh:mm:ss", CultureInfo.InvariantCulture)); //Console.WriteLine("IsValidTarget - DateTime.Compare = " + DateTime.Compare(unlockDateTime, now)); // Check if we've passed the unlock date. Exit early if we have not. if (DateTime.Compare(unlockDateTime, now) > 0 || unlockDateTime > now) { string timeToWait = TimeService.GetTimeToWaitLongIntervals(now, unlockDateTime, false); //Console.WriteLine("IsValidTarget - That ability can be used in " + timeToWait + "."); SendMessageToPC(user, "That ability can be used in " + timeToWait + "."); return; } Effect impactEffect = null; var spellId = Spell.Invalid; string soundName = null; int perkLevel = 1 + PerkService.GetCreaturePerkLevel(user, PerkType.GrenadeProficiency); int skillLevel = 5 + SkillService.GetPCSkillRank((NWPlayer)user, SkillType.Throwing); if (perkLevel == 0) { perkLevel += 1; } if (GetIsObjectValid(target) == true) { targetLocation = GetLocation(target); } string grenadeType = item.GetLocalString("TYPE"); //Console.WriteLine("Throwing " + grenadeType + " grenade at perk level " + perkLevel); Location originalLocation = targetLocation; int roll = RandomService.D100(1); SendMessageToPC(user, roll + " vs. DC " + (100 - skillLevel)); if (roll < (100 - skillLevel)) { if (RandomService.D20(1) == 1) { SendMessageToPC(user, "You threw... poorly."); //targetLocation = VectorService.MoveLocation(targetLocation, GetFacing(user), (RandomService.D6(4) - 10) * 1.0f, targetLocation = VectorService.MoveLocation(user.Location, RandomService.D100(1) + RandomService.D100(1) + RandomService.D100(1) + 60, RandomService.D4(2) * 1.0f, RandomService.D100(1) + RandomService.D100(1) + RandomService.D100(1)); int count = 0; while ((GetSurfaceMaterial(targetLocation) == 0 || LineOfSightVector(GetPositionFromLocation(targetLocation), GetPosition(user)) == false) && count < 10) { count += 1; targetLocation = VectorService.MoveLocation(user.Location, RandomService.D100(1) + RandomService.D100(1) + RandomService.D100(1) + 60, RandomService.D4(2) * 1.0f, RandomService.D100(1) + RandomService.D100(1) + RandomService.D100(1)); } } else { SendMessageToPC(user, "Your throw was a bit off the mark."); //targetLocation = VectorService.MoveLocation(targetLocation, GetFacing(user), (RandomService.D6(4) - 10) * 1.0f, targetLocation = VectorService.MoveLocation(targetLocation, RandomService.D100(1) + RandomService.D100(1) + RandomService.D100(1) + 60, RandomService.D4(2) /*(RandomService.D6(4) - 10) */ * 1.0f, RandomService.D100(1) + RandomService.D100(1) + RandomService.D100(1)); int count = 0; while ((GetSurfaceMaterial(targetLocation) == 0 || LineOfSightVector(GetPositionFromLocation(targetLocation), GetPosition(user)) == false) && count < 10) { count += 1; targetLocation = VectorService.MoveLocation(targetLocation, RandomService.D100(1) + RandomService.D100(1) + RandomService.D100(1) + 60, RandomService.D4(2) /*(RandomService.D6(4) - 10) */ * 1.0f, RandomService.D100(1) + RandomService.D100(1) + RandomService.D100(1)); } } if (GetSurfaceMaterial(targetLocation) == 0 || LineOfSightVector(GetPositionFromLocation(targetLocation), GetPosition(user)) == false) { targetLocation = originalLocation; } } switch (grenadeType) { case "FRAG": impactEffect = EffectVisualEffect(VisualEffect.Fnf_Fireball); // force a specific spell id (for projectile model) for this grenade. spellId = Spell.Grenade10; soundName = "explosion2"; break; case "CONCUSSION": impactEffect = EffectVisualEffect(VisualEffect.Vfx_Fnf_Sound_Burst_Silent); impactEffect = EffectLinkEffects(EffectVisualEffect(VisualEffect.Vfx_Fnf_Screen_Shake), impactEffect); spellId = Spell.Grenade10; soundName = "explosion1"; break; case "FLASHBANG": impactEffect = EffectVisualEffect(VisualEffect.Vfx_Fnf_Mystical_Explosion); spellId = Spell.Grenade10; soundName = "explosion1"; break; case "ION": impactEffect = EffectVisualEffect(VisualEffect.Vfx_Fnf_Electric_Explosion); spellId = Spell.Grenade10; soundName = "explosion1"; break; case "BACTA": impactEffect = EffectVisualEffect(VisualEffect.Vfx_Fnf_Gas_Explosion_Nature); spellId = Spell.Grenade10; //soundName = "explosion1"; break; case "ADHESIVE": impactEffect = EffectVisualEffect(VisualEffect.Fnf_Dispel_Greater); spellId = Spell.Grenade10; //soundName = "explosion1"; break; case "SMOKE": impactEffect = null; spellId = Spell.Grenade10; //soundName = "explosion1"; break; case "BACTABOMB": impactEffect = null; spellId = Spell.Grenade10; //soundName = "explosion1"; break; case "INCENDIARY": impactEffect = null; spellId = Spell.Grenade10; //soundName = "explosion1"; break; case "GAS": impactEffect = null; spellId = Spell.Grenade10; //soundName = "explosion1"; break; default: throw new ArgumentOutOfRangeException(nameof(grenadeType)); } if (spellId == 0) { // start 974 through 979 in spells.2da for grenades // lets randomly assign a projectile appearance for flavor? spellId = (Spell)(RandomService.D6(1) + 973); } float delay = GetDistanceBetweenLocations(user.Location, targetLocation) / 18.0f + 0.75f; delay += 0.4f; // added for animation user.ClearAllActions(); //user.AssignCommand(() => _.ActionPlayAnimation(32)); //user.DelayAssignCommand(() => _.ActionPlayAnimation(32), 0.0f); user.AssignCommand(() => { ActionPlayAnimation(Animation.LoopingCustom12); ActionCastSpellAtLocation(spellId, targetLocation, MetaMagic.Any, true, ProjectilePathType.Ballistic, true); //ActionCastFakeSpellAtLocation(spellId, targetLocation, PROJECTILE_PATH_TYPE_BALLISTIC); }); if (soundName != null) { user.DelayAssignCommand(() => { PlaySound(soundName); }, delay); } if (impactEffect != null) { user.DelayAssignCommand(() => { ApplyEffectAtLocation(DurationType.Instant, impactEffect, targetLocation); }, delay); } user.DelayAssignCommand( () => { DoImpact(user, targetLocation, grenadeType, perkLevel, RadiusSize.Large, ObjectType.Creature); }, delay + 0.75f); perkLevel = PerkService.GetCreaturePerkLevel(user, PerkType.GrenadeProficiency); now = DateTime.UtcNow; DateTime unlockTime = now; if (perkLevel < 5) { unlockTime = unlockTime.AddSeconds(6); } else if (perkLevel < 10) { unlockTime = unlockTime.AddSeconds(3); } else { unlockTime = unlockTime.AddSeconds(2); } SetLocalString(user, "GRENADE_UNLOCKTIME", unlockTime.ToString("yyyy-MM-dd hh:mm:ss", CultureInfo.InvariantCulture)); //Console.WriteLine("StartUseItem - Current Time = " + now.ToString("yyyy-MM-dd hh:mm:ss", CultureInfo.InvariantCulture)); //Console.WriteLine("StartUseItem - Unlocktime Set To = " + unlockTime.ToString("yyyy-MM-dd hh:mm:ss", CultureInfo.InvariantCulture)); if (user.IsCreature) { DurabilityService.RunItemDecay((NWPlayer)user, item, 1.0f); } }