public static int GetCustomEffectLevel(NWCreature creature, CustomEffectType customEffectType) { int effectLevel = 0; if (creature.IsNPC) { var effect = AppCache.NPCEffects.SingleOrDefault(x => x.Key.Target.Equals(creature) && x.Key.CustomEffectID == (int)customEffectType); if (effect.Key != null) { effectLevel = effect.Key.EffectiveLevel; } } else if (creature.IsPlayer) { PCCustomEffect dbEffect = DataService.PCCustomEffect.GetByPlayerIDAndCustomEffectIDOrDefault(creature.GlobalID, (int)customEffectType); if (dbEffect != null) { if (!AppCache.PCEffectsForRemoval.Contains(dbEffect.ID)) { effectLevel = dbEffect.EffectiveLevel; } } } else { return(0); } return(effectLevel); }
private static void ProcessPCCustomEffects() { foreach (var player in NWModule.Get().Players) { if (!player.IsInitializedAsPlayer) { continue; // Ignored to prevent a timing issue where new characters would be included in this processing. } List <PCCustomEffect> effects = DataService.PCCustomEffect.GetAllByPlayerID(player.GlobalID).Where(x => x.StancePerkID == null).ToList(); foreach (var effect in effects) { if (player.CurrentHP <= -11) { CustomEffectService.RemovePCCustomEffect(player, effect.CustomEffectID); return; } PCCustomEffect result = RunPCCustomEffectProcess(player, effect); if (result == null) { ICustomEffectHandler handler = CustomEffectService.GetCustomEffectHandler(effect.CustomEffectID); string message = handler.WornOffMessage; player.SendMessage(message); player.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + effect.CustomEffectID); DataService.SubmitDataChange(effect, DatabaseActionType.Delete); handler.WearOff(null, player, effect.EffectiveLevel, effect.Data); } else { DataService.SubmitDataChange(effect, DatabaseActionType.Update); } } } }
public static void ApplyStance(NWCreature creature, CustomEffectType customEffect, PerkType perkType, int effectiveLevel, string data) { // Can't process NPC stances at the moment. Need to do some more refactoring before this is possible. // todo: handle NPC stances. if (!creature.IsPlayer) { return; } var pcStanceEffect = DataService.PCCustomEffect.GetByPlayerStanceOrDefault(creature.GlobalID); int customEffectID = (int)customEffect; // Player selected to cancel their stance. Cancel it and end. if (pcStanceEffect != null && pcStanceEffect.CustomEffectID == customEffectID && pcStanceEffect.EffectiveLevel == effectiveLevel) { RemoveStance(creature, pcStanceEffect); return; } // Otherwise remove existing stance else if (pcStanceEffect != null) { RemoveStance(creature, pcStanceEffect, false); } // Player selected to switch stances pcStanceEffect = new PCCustomEffect { PlayerID = creature.GlobalID, Ticks = -1, CustomEffectID = customEffectID, CasterNWNObjectID = _.ObjectToString(creature), EffectiveLevel = effectiveLevel, StancePerkID = (int)perkType }; DataService.SubmitDataChange(pcStanceEffect, DatabaseActionType.Insert); ICustomEffectHandler handler = GetCustomEffectHandler(customEffect); if (string.IsNullOrWhiteSpace(data)) { data = handler.Apply(creature, creature, effectiveLevel); } if (!string.IsNullOrWhiteSpace(handler.StartMessage)) { creature.SendMessage(handler.StartMessage); } if (string.IsNullOrWhiteSpace(data)) { data = string.Empty; } pcStanceEffect.Data = data; DataService.SubmitDataChange(pcStanceEffect, DatabaseActionType.Update); // Was already queued for removal, but got cast again. Take it out of the list to be removed. if (AppCache.PCEffectsForRemoval.Contains(pcStanceEffect.ID)) { AppCache.PCEffectsForRemoval.Remove(pcStanceEffect.ID); } }
private static PCCustomEffect RunPCCustomEffectProcess(NWPlayer oPC, PCCustomEffect effect) { NWCreature caster = oPC; if (!string.IsNullOrWhiteSpace(effect.CasterNWNObjectID)) { var obj = NWNXObject.StringToObject(effect.CasterNWNObjectID); if (obj.IsValid) { caster = obj.Object; } } if (effect.Ticks > 0) { effect.Ticks = effect.Ticks - 1; } if (effect.Ticks == 0) { return(null); } ICustomEffectHandler handler = CustomEffectService.GetCustomEffectHandler(effect.CustomEffectID); if (!string.IsNullOrWhiteSpace(handler.ContinueMessage) && effect.Ticks % 6 == 0) // Only show the message once every six seconds { oPC.SendMessage(handler.ContinueMessage); } handler?.Tick(caster, oPC, effect.Ticks, effect.EffectiveLevel, effect.Data); return(effect); }
public static bool RemoveStance(NWCreature creature, PCCustomEffect stanceEffect = null, bool sendMessage = true) { // Can't process NPC stances at the moment. Need to do some more refactoring before this is possible. // todo: handle NPC stances. if (!creature.IsPlayer) { return(false); } if (stanceEffect == null) { stanceEffect = DataService.PCCustomEffect.GetByPlayerStanceOrDefault(creature.GlobalID); } if (stanceEffect == null) { return(false); } if (sendMessage) { creature.SendMessage("You return to your normal stance."); } int effectiveLevel = stanceEffect.EffectiveLevel; string data = stanceEffect.Data; DataService.SubmitDataChange(stanceEffect, DatabaseActionType.Delete); ICustomEffectHandler handler = GetCustomEffectHandler(stanceEffect.CustomEffectID); handler?.WearOff(creature, creature, effectiveLevel, data); return(true); }
public bool RemoveStance(NWPlayer player, PCCustomEffect stanceEffect = null, bool sendMessage = true) { if (stanceEffect == null) { stanceEffect = _data.SingleOrDefault <PCCustomEffect>(x => { var customEffect = _data.Get <Data.Entity.CustomEffect>(x.CustomEffectID); return(x.PlayerID == player.GlobalID && customEffect.CustomEffectCategoryID == (int)CustomEffectCategoryType.Stance); }); } if (stanceEffect == null) { return(false); } if (sendMessage) { player.SendMessage("You return to your normal stance."); } int effectiveLevel = stanceEffect.EffectiveLevel; string data = stanceEffect.Data; var stanceCustomEffect = _data.Get <Data.Entity.CustomEffect>(stanceEffect.CustomEffectID); string scriptHandler = stanceCustomEffect.ScriptHandler; _data.SubmitDataChange(stanceEffect, DatabaseActionType.Delete); App.ResolveByInterface <ICustomEffect>("CustomEffect." + scriptHandler, handler => { handler?.WearOff(player, player, effectiveLevel, data); }); return(true); }
public int GetCustomEffectLevel(NWCreature creature, CustomEffectType customEffectType) { int effectLevel = 0; if (creature.IsNPC) { var effect = _cache.NPCEffects.SingleOrDefault(x => x.Key.Target.Equals(creature) && x.Key.CustomEffectID == (int)customEffectType); if (effect.Key != null) { effectLevel = effect.Key.EffectiveLevel; } } else if (creature.IsPlayer) { PCCustomEffect dbEffect = _data.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == creature.GlobalID && x.CustomEffectID == (int)customEffectType); if (dbEffect != null) { if (!_cache.PCEffectsForRemoval.Contains(dbEffect.ID)) { effectLevel = dbEffect.EffectiveLevel; } } } else { return(0); } return(effectLevel); }
public static bool RemoveStance(NWPlayer player, PCCustomEffect stanceEffect = null, bool sendMessage = true) { if (stanceEffect == null) { stanceEffect = DataService.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == player.GlobalID && x.StancePerkID != null); } if (stanceEffect == null) { return(false); } if (sendMessage) { player.SendMessage("You return to your normal stance."); } int effectiveLevel = stanceEffect.EffectiveLevel; string data = stanceEffect.Data; DataService.SubmitDataChange(stanceEffect, DatabaseActionType.Delete); ICustomEffectHandler handler = GetCustomEffectHandler(stanceEffect.CustomEffectID); handler?.WearOff(player, player, effectiveLevel, data); return(true); }
public void OnPlayerHeartbeat(NWPlayer oPC) { List <PCCustomEffect> effects = _db.PCCustomEffects.Where(x => x.PlayerID == oPC.GlobalID).ToList(); string areaResref = oPC.Area.Resref; foreach (PCCustomEffect effect in effects) { if (oPC.CurrentHP <= -11 || areaResref == "death_realm") { RemovePCCustomEffect(oPC, effect.CustomEffectID); return; } PCCustomEffect result = RunPCCustomEffectProcess(oPC, effect); if (result == null) { string message = effect.CustomEffect.WornOffMessage; string scriptHandler = effect.CustomEffect.ScriptHandler; oPC.SendMessage(message); oPC.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + effect.CustomEffectID); _db.PCCustomEffects.Remove(effect); _db.SaveChanges(); ICustomEffect handler = App.ResolveByInterface <ICustomEffect>("CustomEffect." + scriptHandler); handler?.WearOff(null, oPC); } else { _db.SaveChanges(); } } }
public static void ApplyStance(NWPlayer player, CustomEffectType customEffect, PerkType perkType, int effectiveLevel, string data) { var pcStanceEffect = DataService.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == player.GlobalID && x.StancePerkID != null); int customEffectID = (int)customEffect; // Player selected to cancel their stance. Cancel it and end. if (pcStanceEffect != null && pcStanceEffect.CustomEffectID == customEffectID && pcStanceEffect.EffectiveLevel == effectiveLevel) { RemoveStance(player, pcStanceEffect); return; } // Otherwise remove existing stance else if (pcStanceEffect != null) { RemoveStance(player, pcStanceEffect, false); } // Player selected to switch stances pcStanceEffect = new PCCustomEffect { PlayerID = player.GlobalID, Ticks = -1, CustomEffectID = customEffectID, CasterNWNObjectID = _.ObjectToString(player), EffectiveLevel = effectiveLevel, StancePerkID = (int)perkType }; DataService.SubmitDataChange(pcStanceEffect, DatabaseActionType.Insert); ICustomEffectHandler handler = GetCustomEffectHandler(customEffect); if (string.IsNullOrWhiteSpace(data)) { data = handler.Apply(player, player, effectiveLevel); } if (!string.IsNullOrWhiteSpace(handler.StartMessage)) { player.SendMessage(handler.StartMessage); } if (string.IsNullOrWhiteSpace(data)) { data = string.Empty; } pcStanceEffect.Data = data; DataService.SubmitDataChange(pcStanceEffect, DatabaseActionType.Update); // Was already queued for removal, but got cast again. Take it out of the list to be removed. if (AppCache.PCEffectsForRemoval.Contains(pcStanceEffect.ID)) { AppCache.PCEffectsForRemoval.Remove(pcStanceEffect.ID); } }
public static ForceSpreadDetails GetForceSpreadDetails(NWPlayer player) { PCCustomEffect spreadEffect = DataService.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == player.GlobalID && x.CustomEffectID == (int)CustomEffectType.ForceSpread); ForceSpreadDetails details = new ForceSpreadDetails(); string spreadData = spreadEffect?.Data ?? string.Empty; details.Level = spreadEffect?.EffectiveLevel ?? 0; details.Uses = spreadEffect == null ? 0 : Convert.ToInt32(spreadData.Split(',')[0]); details.Range = spreadEffect == null ? 0 : Convert.ToSingle(spreadData.Split(',')[1]); return(details); }
public void GetByID_OneItem_ReturnsPCCustomEffect() { // Arrange var id = Guid.NewGuid(); PCCustomEffect entity = new PCCustomEffect { ID = id }; // Act MessageHub.Instance.Publish(new OnCacheObjectSet <PCCustomEffect>(entity)); // Assert Assert.AreNotSame(entity, _cache.GetByID(id)); }
public void RemovePCCustomEffect(NWPlayer oPC, long customEffectID) { PCCustomEffect effect = _db.PCCustomEffects.SingleOrDefault(x => x.PlayerID == oPC.GlobalID && x.CustomEffectID == customEffectID); oPC.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + customEffectID); if (effect == null) { return; } _db.PCCustomEffects.Remove(effect); oPC.SendMessage(effect.CustomEffect.WornOffMessage); }
public static bool DoesPCHaveCustomEffect(NWPlayer oPC, int customEffectID) { PCCustomEffect effect = DataService.PCCustomEffect.GetByPlayerIDAndCustomEffectIDOrDefault(oPC.GlobalID, customEffectID); if (effect == null) { return(false); } else if (AppCache.PCEffectsForRemoval.Contains(effect.ID)) { return(false); } return(true); }
public bool DoesPCHaveCustomEffect(NWPlayer oPC, int customEffectID) { PCCustomEffect effect = _data.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == oPC.GlobalID && x.CustomEffectID == customEffectID); if (effect == null) { return(false); } else if (_cache.PCEffectsForRemoval.Contains(effect.ID)) { return(false); } return(true); }
private void ProcessPCCustomEffects() { foreach (var player in NWModule.Get().Players) { if (!player.IsInitializedAsPlayer) { continue; // Ignored to prevent a timing issue where new characters would be included in this processing. } List <PCCustomEffect> effects = _data.Where <PCCustomEffect>(x => { var customEffect = _data.Get <Data.Entity.CustomEffect>(x.CustomEffectID); return(x.PlayerID == player.GlobalID && customEffect.CustomEffectCategoryID != (int)CustomEffectCategoryType.Stance); }).ToList(); foreach (var effect in effects) { if (player.CurrentHP <= -11) { _customEffect.RemovePCCustomEffect(player, effect.CustomEffectID); return; } PCCustomEffect result = RunPCCustomEffectProcess(player, effect); if (result == null) { var customEffect = _data.Get <Data.Entity.CustomEffect>(effect.CustomEffectID); string message = customEffect.WornOffMessage; string scriptHandler = customEffect.ScriptHandler; player.SendMessage(message); player.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + effect.CustomEffectID); _data.SubmitDataChange(effect, DatabaseActionType.Delete); App.ResolveByInterface <ICustomEffect>("CustomEffect." + scriptHandler, (handler) => { handler?.WearOff(null, player, effect.EffectiveLevel, effect.Data); }); } else { _data.SubmitDataChange(effect, DatabaseActionType.Update); } } } }
public void RemovePCCustomEffect(NWPlayer oPC, int customEffectID) { PCCustomEffect effect = _data.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == oPC.GlobalID && x.CustomEffectID == customEffectID); oPC.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + customEffectID); // Doesn't exist in DB or is already marked for removal if (effect == null || _cache.PCEffectsForRemoval.Contains(effect.ID)) { return; } var customEffect = _data.Get <Data.Entity.CustomEffect>(effect.CustomEffectID); oPC.SendMessage(customEffect.WornOffMessage); _cache.PCEffectsForRemoval.Add(effect.ID); }
public static void RemovePCCustomEffect(NWPlayer oPC, int customEffectID) { PCCustomEffect effect = DataService.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == oPC.GlobalID && x.CustomEffectID == customEffectID); oPC.DeleteLocalInt("CUSTOM_EFFECT_ACTIVE_" + customEffectID); // Doesn't exist in DB or is already marked for removal if (effect == null || AppCache.PCEffectsForRemoval.Contains(effect.ID)) { return; } var handler = GetCustomEffectHandler(customEffectID); oPC.SendMessage(handler.WornOffMessage); AppCache.PCEffectsForRemoval.Add(effect.ID); }
private PCCustomEffect RunPCCustomEffectProcess(NWPlayer oPC, PCCustomEffect effect) { effect.Ticks = effect.Ticks - 1; if (effect.Ticks < 0) { return(null); } if (!string.IsNullOrWhiteSpace(effect.CustomEffect.ContinueMessage)) { oPC.SendMessage(effect.CustomEffect.ContinueMessage); } ICustomEffect handler = App.ResolveByInterface <ICustomEffect>("CustomEffect." + effect.CustomEffect.ScriptHandler); handler?.Tick(null, oPC); return(effect); }
public void GetByID_TwoItems_ReturnsCorrectObject() { // Arrange var id1 = Guid.NewGuid(); var id2 = Guid.NewGuid(); PCCustomEffect entity1 = new PCCustomEffect { ID = id1 }; PCCustomEffect entity2 = new PCCustomEffect { ID = id2 }; // Act MessageHub.Instance.Publish(new OnCacheObjectSet <PCCustomEffect>(entity1)); MessageHub.Instance.Publish(new OnCacheObjectSet <PCCustomEffect>(entity2)); // Assert Assert.AreNotSame(entity1, _cache.GetByID(id1)); Assert.AreNotSame(entity2, _cache.GetByID(id2)); }
public void OnImpact(NWPlayer player, NWObject target, int level) { var effectiveStats = _playerStat.GetPlayerItemEffectiveStats(player); int lightBonus = effectiveStats.LightAbility; PCCustomEffect spreadEffect = _data.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == player.GlobalID && x.CustomEffectID == (int)CustomEffectType.ForceSpread); string spreadData = spreadEffect?.Data ?? string.Empty; int spreadLevel = spreadEffect?.EffectiveLevel ?? 0; int spreadUses = spreadEffect == null ? 0 : Convert.ToInt32(spreadData.Split(',')[0]); float spreadRange = spreadEffect == null ? 0 : Convert.ToSingle(spreadData.Split(',')[1]); if (spreadLevel <= 0) { HealTarget(player, target, lightBonus, level); } else { var members = player.PartyMembers.Where(x => _.GetDistanceBetween(x, target) <= spreadRange || Equals(x, target)); spreadUses--; foreach (var member in members) { HealTarget(player, member, lightBonus, level); } if (spreadUses <= 0) { _customEffect.RemovePCCustomEffect(player, CustomEffectType.ForceSpread); } else { // ReSharper disable once PossibleNullReferenceException spreadEffect.Data = spreadUses + "," + spreadRange; _data.SubmitDataChange(spreadEffect, DatabaseActionType.Update); player.SendMessage("Force Spread uses remaining: " + spreadUses); } } _skill.RegisterPCToAllCombatTargetsForSkill(player, SkillType.LightSideAbilities, target.Object); }
public void GetByID_RemovedItem_ReturnsCorrectObject() { // Arrange var id1 = Guid.NewGuid(); var id2 = Guid.NewGuid(); PCCustomEffect entity1 = new PCCustomEffect { ID = id1 }; PCCustomEffect entity2 = new PCCustomEffect { ID = id2 }; // Act MessageHub.Instance.Publish(new OnCacheObjectSet <PCCustomEffect>(entity1)); MessageHub.Instance.Publish(new OnCacheObjectSet <PCCustomEffect>(entity2)); MessageHub.Instance.Publish(new OnCacheObjectDeleted <PCCustomEffect>(entity1)); // Assert Assert.Throws <KeyNotFoundException>(() => { _cache.GetByID(id1); }); Assert.AreNotSame(entity2, _cache.GetByID(id2)); }
public static void SetForceSpreadUses(NWPlayer player, int uses) { PCCustomEffect spreadEffect = DataService.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == player.GlobalID && x.CustomEffectID == (int)CustomEffectType.ForceSpread); if (spreadEffect == null) { return; } if (uses <= 0) { RemovePCCustomEffect(player, CustomEffectType.ForceSpread); } string spreadData = spreadEffect.Data ?? string.Empty; float range = Convert.ToSingle(spreadData.Split(',')[1]); spreadEffect.Data = uses + "," + range; DataService.SubmitDataChange(spreadEffect, DatabaseActionType.Update); player.SendMessage("Force Spread uses remaining: " + uses); }
private PCCustomEffect RunPCCustomEffectProcess(NWPlayer oPC, PCCustomEffect effect) { NWCreature caster = oPC; if (!string.IsNullOrWhiteSpace(effect.CasterNWNObjectID)) { var obj = _nwnxObject.StringToObject(effect.CasterNWNObjectID); if (obj.IsValid) { caster = obj.Object; } } if (effect.Ticks > 0) { effect.Ticks = effect.Ticks - 1; } if (effect.Ticks == 0) { return(null); } var customEffect = _data.Get <Data.Entity.CustomEffect>(effect.CustomEffectID); if (!string.IsNullOrWhiteSpace(customEffect.ContinueMessage) && effect.Ticks % 6 == 0) // Only show the message once every six seconds { oPC.SendMessage(customEffect.ContinueMessage); } App.ResolveByInterface <ICustomEffect>("CustomEffect." + customEffect.ScriptHandler, (handler) => { handler?.Tick(caster, oPC, effect.Ticks, effect.EffectiveLevel, effect.Data); }); return(effect); }
private static void ApplyPCEffect(NWCreature caster, NWCreature target, int customEffectID, int ticks, int effectiveLevel, string data) { PCCustomEffect pcEffect = DataService.PCCustomEffect.GetByPlayerIDAndCustomEffectIDOrDefault(target.GlobalID, customEffectID); ICustomEffectHandler handler = GetCustomEffectHandler(customEffectID); CustomEffectCategoryType category = handler.CustomEffectCategoryType; if (category == CustomEffectCategoryType.FoodEffect) { var customEffectPC = DataService.CustomEffect.GetByID(pcEffect.CustomEffectID); if (customEffectPC != null) { var foodHandler = GetCustomEffectHandler(customEffectPC.ID); if (foodHandler.CustomEffectCategoryType == category) { caster.SendMessage("You are not hungry."); } return; } } DatabaseActionType action = DatabaseActionType.Update; if (pcEffect == null) { pcEffect = new PCCustomEffect { PlayerID = target.GlobalID }; action = DatabaseActionType.Insert; } if (pcEffect.EffectiveLevel > effectiveLevel) { caster.SendMessage("A more powerful effect already exists on your target."); return; } pcEffect.CustomEffectID = customEffectID; pcEffect.EffectiveLevel = effectiveLevel; pcEffect.Ticks = ticks; pcEffect.CasterNWNObjectID = _.ObjectToString(caster); DataService.SubmitDataChange(pcEffect, action); target.SendMessage(handler.StartMessage); if (string.IsNullOrWhiteSpace(data)) { data = handler?.Apply(caster, target, effectiveLevel); } if (string.IsNullOrWhiteSpace(data)) { data = string.Empty; } pcEffect.Data = data; DataService.SubmitDataChange(pcEffect, DatabaseActionType.Update); // Was already queued for removal, but got cast again. Take it out of the list to be removed. if (AppCache.PCEffectsForRemoval.Contains(pcEffect.ID)) { AppCache.PCEffectsForRemoval.Remove(pcEffect.ID); } }
public void ApplyStance(NWPlayer player, CustomEffectType customEffect, PerkType perkType, int effectiveLevel, string data) { var dbEffect = _data.Single <Data.Entity.CustomEffect>(x => x.ID == (int)customEffect); var pcStanceEffect = _data.SingleOrDefault <PCCustomEffect>(x => { var ce = _data.Get <Data.Entity.CustomEffect>(x.CustomEffectID); return(x.PlayerID == player.GlobalID && ce.CustomEffectCategoryID == (int)CustomEffectCategoryType.Stance); }); int customEffectID = (int)customEffect; // Player selected to cancel their stance. Cancel it and end. if (pcStanceEffect != null && pcStanceEffect.CustomEffectID == customEffectID && pcStanceEffect.EffectiveLevel == effectiveLevel) { RemoveStance(player, pcStanceEffect); return; } // Otherwise remove existing stance else if (pcStanceEffect != null) { RemoveStance(player, pcStanceEffect, false); } // Player selected to switch stances pcStanceEffect = new PCCustomEffect { PlayerID = player.GlobalID, Ticks = -1, CustomEffectID = customEffectID, CasterNWNObjectID = _.ObjectToString(player), EffectiveLevel = effectiveLevel, StancePerkID = (int)perkType }; _data.SubmitDataChange(pcStanceEffect, DatabaseActionType.Insert); App.ResolveByInterface <ICustomEffect>("CustomEffect." + dbEffect.ScriptHandler, handler => { if (string.IsNullOrWhiteSpace(data)) { data = handler?.Apply(player, player, effectiveLevel); } var stanceCustomEffect = _data.Get <Data.Entity.CustomEffect>(pcStanceEffect.CustomEffectID); if (!string.IsNullOrWhiteSpace(stanceCustomEffect.StartMessage)) { player.SendMessage(stanceCustomEffect.StartMessage); } if (string.IsNullOrWhiteSpace(data)) { data = string.Empty; } pcStanceEffect.Data = data; _data.SubmitDataChange(pcStanceEffect, DatabaseActionType.Update); // Was already queued for removal, but got cast again. Take it out of the list to be removed. if (_cache.PCEffectsForRemoval.Contains(pcStanceEffect.ID)) { _cache.PCEffectsForRemoval.Remove(pcStanceEffect.ID); } }); }
public void ApplyCustomEffect(NWCreature oCaster, NWCreature oTarget, int customEffectID, int ticks, int effectLevel) { // Can't apply the effect if the existing one is stronger. int existingEffectLevel = GetActiveEffectLevel(oTarget, customEffectID); if (existingEffectLevel > effectLevel) { oCaster.SendMessage("A more powerful effect already exists on your target."); return; } Data.Entities.CustomEffect effectEntity = _db.CustomEffects.Single(x => x.CustomEffectID == customEffectID); // PC custom effects are tracked in the database. if (oTarget.IsPlayer) { PCCustomEffect entity = _db.PCCustomEffects.SingleOrDefault(x => x.PlayerID == oTarget.GlobalID && x.CustomEffectID == customEffectID); if (entity == null) { entity = new PCCustomEffect { PlayerID = oTarget.GlobalID, CustomEffectID = customEffectID }; _db.PCCustomEffects.Add(entity); } entity.Ticks = ticks; _db.SaveChanges(); oTarget.SendMessage(effectEntity.StartMessage); } // NPCs custom effects are tracked in server memory. else { // Look for existing effect. foreach (var entry in _state.NPCEffects) { CasterSpellVO casterSpellModel = entry.Key; if (casterSpellModel.Caster.Equals(oCaster) && casterSpellModel.CustomEffectID == customEffectID && casterSpellModel.Target.Equals(oTarget)) { _state.NPCEffects[entry.Key] = ticks; return; } } // Didn't find an existing effect. Create a new one. CasterSpellVO spellModel = new CasterSpellVO { Caster = oCaster, CustomEffectID = customEffectID, EffectName = effectEntity.Name, Target = oTarget }; _state.NPCEffects[spellModel] = ticks; } ICustomEffect handler = App.ResolveByInterface <ICustomEffect>("CustomEffect." + effectEntity.ScriptHandler); handler?.Apply(oCaster, oTarget); oTarget.SetLocalInt("CUSTOM_EFFECT_ACTIVE_" + customEffectID, effectLevel); }
private void ApplyPCEffect(NWCreature caster, NWCreature target, int customEffectID, int ticks, int effectiveLevel, string data) { Data.Entity.CustomEffect customEffect = _data.Single <Data.Entity.CustomEffect>(x => x.ID == customEffectID); PCCustomEffect pcEffect = _data.SingleOrDefault <PCCustomEffect>(x => x.PlayerID == target.GlobalID && x.CustomEffectID == customEffectID); CustomEffectCategoryType category = (CustomEffectCategoryType)customEffect.CustomEffectCategoryID; if (category == CustomEffectCategoryType.FoodEffect) { var customEffectPC = _data.Get <Data.Entity.CustomEffect>(pcEffect.CustomEffectID); if (pcEffect != null && customEffectPC.CustomEffectCategoryID == (int)category) { caster.SendMessage("You are not hungry."); return; } } DatabaseActionType action = DatabaseActionType.Update; if (pcEffect == null) { pcEffect = new PCCustomEffect { PlayerID = target.GlobalID }; action = DatabaseActionType.Insert; } if (pcEffect.EffectiveLevel > effectiveLevel) { caster.SendMessage("A more powerful effect already exists on your target."); return; } pcEffect.CustomEffectID = customEffectID; pcEffect.EffectiveLevel = effectiveLevel; pcEffect.Ticks = ticks; pcEffect.CasterNWNObjectID = _.ObjectToString(caster); _data.SubmitDataChange(pcEffect, action); target.SendMessage(customEffect.StartMessage); App.ResolveByInterface <ICustomEffect>("CustomEffect." + customEffect.ScriptHandler, handler => { if (string.IsNullOrWhiteSpace(data)) { data = handler?.Apply(caster, target, effectiveLevel); } if (string.IsNullOrWhiteSpace(data)) { data = string.Empty; } pcEffect.Data = data; _data.SubmitDataChange(pcEffect, DatabaseActionType.Update); // Was already queued for removal, but got cast again. Take it out of the list to be removed. if (_cache.PCEffectsForRemoval.Contains(pcEffect.ID)) { _cache.PCEffectsForRemoval.Remove(pcEffect.ID); } }); }
/// <summary> /// Runs validation checks to ensure activator can use a perk feat. /// Activation will fail if any of the following are true: /// - Target is invalid /// - Activator is a ship /// - Feat is not a perk feat /// - Cooldown has not passed /// </summary> /// <param name="activator">The creature activating a perk feat.</param> /// <param name="target">The target of the perk feat.</param> /// <param name="featID">The ID number of the feat being used.</param> /// <returns>true if able to use perk feat on target, false otherwise.</returns> public static bool CanUsePerkFeat(NWCreature activator, NWObject target, Feat featID) { var perkFeat = DataService.PerkFeat.GetByFeatIDOrDefault((int)featID); // There's no matching feat in the DB for this ability. Exit early. if (perkFeat == null) { return(false); } // Retrieve the perk information. Data.Entity.Perk perk = DataService.Perk.GetByIDOrDefault(perkFeat.PerkID); // No perk could be found. Exit early. if (perk == null) { return(false); } // Check to see if we are a spaceship. Spaceships can't use abilities... if (activator.GetLocalInt("IS_SHIP") > 0 || activator.GetLocalInt("IS_GUNNER") > 0) { activator.SendMessage("You cannot use that ability while piloting a ship."); return(false); } // Retrieve the perk-specific handler logic. var handler = PerkService.GetPerkHandler(perkFeat.PerkID); // Get the creature's perk level. int creaturePerkLevel = PerkService.GetCreaturePerkLevel(activator, perk.ID); // If player is disabling an existing stance, remove that effect. if (perk.ExecutionTypeID == PerkExecutionType.Stance) { // Can't process NPC stances at the moment. Need to do some more refactoring before this is possible. // todo: handle NPC stances. if (!activator.IsPlayer) { return(false); } PCCustomEffect stanceEffect = DataService.PCCustomEffect.GetByStancePerkOrDefault(activator.GlobalID, perk.ID); if (stanceEffect != null) { if (CustomEffectService.RemoveStance(activator)) { return(false); } } } // Check for a valid perk level. if (creaturePerkLevel <= 0) { activator.SendMessage("You do not meet the prerequisites to use this ability."); return(false); } // Verify that this hostile action meets PVP sanctuary restriction rules. if (handler.IsHostile() && target.IsPlayer) { if (!PVPSanctuaryService.IsPVPAttackAllowed(activator.Object, target.Object)) { return(false); } } // Activator and target must be in the same area and within line of sight. if (activator.Area.Resref != target.Area.Resref || _.LineOfSightObject(activator.Object, target.Object) == false) { activator.SendMessage("You cannot see your target."); return(false); } // Run this perk's specific checks on whether the activator may use this perk on the target. string canCast = handler.CanCastSpell(activator, target, perkFeat.PerkLevelUnlocked); if (!string.IsNullOrWhiteSpace(canCast)) { activator.SendMessage(canCast); return(false); } // Calculate the FP cost to use this ability. Verify activator has sufficient FP. int fpCost = handler.FPCost(activator, handler.FPCost(activator, perkFeat.BaseFPCost, perkFeat.PerkLevelUnlocked), perkFeat.PerkLevelUnlocked); int currentFP = GetCurrentFP(activator); if (currentFP < fpCost) { activator.SendMessage("You do not have enough FP. (Required: " + fpCost + ". You have: " + currentFP + ")"); return(false); } // Verify activator isn't busy or dead. if (activator.IsBusy || activator.CurrentHP <= 0) { activator.SendMessage("You are too busy to activate that ability."); return(false); } // verify activator is commandable. https://github.com/zunath/SWLOR_NWN/issues/940#issue-467175951 if (!activator.IsCommandable) { activator.SendMessage("You cannot take actions currently."); return(false); } // If we're executing a concentration ability, check and see if the activator currently has this ability // active. If it's active, then we immediately remove its effect and bail out. // Any other ability (including other concentration abilities) execute as normal. if (perk.ExecutionTypeID == PerkExecutionType.ConcentrationAbility) { // Retrieve the concentration effect for this creature. var concentrationEffect = GetActiveConcentrationEffect(activator); if ((int)concentrationEffect.Type == perk.ID) { // It's active. Time to disable it. EndConcentrationEffect(activator); activator.SendMessage("Concentration ability '" + perk.Name + "' deactivated."); SendAOEMessage(activator, activator.Name + " deactivates concentration ability '" + perk.Name + "'."); return(false); } } // Retrieve the cooldown information and determine the unlock time. int? cooldownCategoryID = handler.CooldownCategoryID(activator, perk.CooldownCategoryID, perkFeat.PerkLevelUnlocked); DateTime now = DateTime.UtcNow; DateTime unlockDateTime = cooldownCategoryID == null ? now : GetAbilityCooldownUnlocked(activator, (int)cooldownCategoryID); // Check if we've passed the unlock date. Exit early if we have not. if (unlockDateTime > now) { string timeToWait = TimeService.GetTimeToWaitLongIntervals(now, unlockDateTime, false); activator.SendMessage("That ability can be used in " + timeToWait + "."); return(false); } // Passed all checks. Return true. return(true); }
public bool DoesPCHaveCustomEffect(NWPlayer oPC, int customEffectID) { PCCustomEffect effect = _db.PCCustomEffects.SingleOrDefault(x => x.PlayerID == oPC.GlobalID && x.CustomEffectID == customEffectID); return(effect != null); }