/// <summary> /// </summary> /// <param name="statusEntriesPlayers"></param> private void ProcessHealingOverTime(IEnumerable <StatusItem> statusEntriesPlayers) { foreach (StatusItem statusEntry in statusEntriesPlayers) { try { Sharlayan.Models.XIVDatabase.StatusItem statusInfo = StatusEffectLookup.GetStatusInfo((uint)statusEntry.StatusID); var statusKey = statusInfo.Name.English; switch (Constants.GameLanguage) { case "French": statusKey = statusInfo.Name.French; break; case "Japanese": statusKey = statusInfo.Name.Japanese; break; case "German": statusKey = statusInfo.Name.German; break; case "Chinese": statusKey = statusInfo.Name.Chinese; break; case "Korean": statusKey = statusInfo.Name.Korean; break; } if (string.IsNullOrWhiteSpace(statusKey)) { continue; } var amount = this.NPCEntry.Level / ((60 - this.NPCEntry.Level) * .025); var key = statusKey; ActionItem actionData = null; foreach (KeyValuePair <string, ActionItem> healingOverTimeAction in HealingOverTimeHelper.PlayerActions.ToList().Where(d => string.Equals(d.Key, key, Constants.InvariantComparer))) { actionData = healingOverTimeAction.Value; } if (actionData == null) { continue; } var zeroFoundInList = false; var regen = Regex.IsMatch(key, @"(リジェネ|récup|regen|再生|whispering|murmure|erhebendes|光の囁き|日光的低语)", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); List <KeyValuePair <string, double> > healingHistoryList = ParseHelper.LastAmountByAction.GetPlayer(this.Name).ToList(); var resolvedPotency = 350; foreach (KeyValuePair <string, double> healingAction in healingHistoryList) { if (regen) { var found = false; Dictionary <string, List <string> > cureActions = HealingOverTimeHelper.CureActions; Dictionary <string, List <string> > medicaActions = HealingOverTimeHelper.MedicaActions; KeyValuePair <string, double> action = healingAction; if (cureActions["III"].Any(cureAction => string.Equals(action.Key, cureAction, Constants.InvariantComparer))) { found = zeroFoundInList = true; resolvedPotency = 550; } if (cureActions["II"].Any(cureAction => string.Equals(action.Key, cureAction, Constants.InvariantComparer))) { found = zeroFoundInList = true; resolvedPotency = 650; } if (cureActions["I"].Any(cureAction => string.Equals(action.Key, cureAction, Constants.InvariantComparer))) { found = zeroFoundInList = true; resolvedPotency = 400; } if (medicaActions["II"].Any(medicaAction => string.Equals(action.Key, medicaAction, Constants.InvariantComparer))) { found = zeroFoundInList = true; resolvedPotency = 200; } if (medicaActions["I"].Any(medicaAction => string.Equals(action.Key, medicaAction, Constants.InvariantComparer))) { found = zeroFoundInList = true; resolvedPotency = 300; } if (found) { if (action.Value > 0) { amount = action.Value; } break; } } if (string.Equals(healingAction.Key, key, Constants.InvariantComparer)) { amount = healingAction.Value; break; } } statusKey = $"{statusKey} [•]"; if (amount == 0) { amount = 75; } resolvedPotency = zeroFoundInList ? resolvedPotency : regen ? resolvedPotency : actionData.Potency; var tickHealing = Math.Ceiling(amount / resolvedPotency * actionData.OverTimePotency / 3); if (actionData.HasNoInitialResult && !zeroFoundInList) { IEnumerable <KeyValuePair <string, double> > nonZeroActions = healingHistoryList.Where(d => !d.Key.Contains("•")); IList <KeyValuePair <string, double> > keyValuePairs = nonZeroActions as IList <KeyValuePair <string, double> > ?? nonZeroActions.ToList(); double healing = 0; switch (regen) { case true: healing = Math.Ceiling(amount / resolvedPotency * actionData.OverTimePotency / 3); break; case false: if (keyValuePairs.Any()) { amount = keyValuePairs.Sum(action => action.Value); amount = amount / keyValuePairs.Count(); } healing = Math.Ceiling(amount / resolvedPotency * actionData.OverTimePotency / 3); break; } tickHealing = healing > 0 ? healing : tickHealing; } var line = new Line { Action = statusKey, Amount = tickHealing, EventDirection = EventDirection.Unknown, EventType = EventType.Cure, EventSubject = EventSubject.Unknown, Source = this.Name, SourceEntity = this.NPCEntry, XOverTime = true }; try { List <StatGroup> players = Controller.Timeline.Party.ToList(); StatusItem entry = statusEntry; foreach (StatGroup player in players.Where(player => player.Name.Contains(entry.TargetName))) { line.Target = player.Name; break; } } catch (Exception ex) { Logging.Log(Logger, new LogItem(ex, true)); } if (string.IsNullOrWhiteSpace(line.Target)) { line.Target = $"[???] {statusEntry.TargetName}"; } Controller.Timeline.FightingRightNow = true; Controller.Timeline.FightingTimer.Stop(); switch (Settings.Default.StoreHistoryEvent) { case "Any": Controller.Timeline.StoreHistoryTimer.Stop(); break; } DispatcherHelper.Invoke( delegate { line.Hit = true; // resolve player hp each tick to ensure they are not at max try { List <ActorItem> players = XIVInfoViewModel.Instance.CurrentPCs.Select(entity => entity.Value).ToList(); if (!players.Any()) { return; } foreach (ActorItem actorEntity in players) { var playerName = actorEntity.Name; Controller.Timeline.TrySetPlayerCurable(playerName, actorEntity.HPMax - actorEntity.HPCurrent); } } catch (Exception ex) { Logging.Log(Logger, new LogItem(ex, true)); } var currentCritPercent = this.Stats.GetStatValue("HealingCritPercent"); if (new Random().NextDouble() * 3 < currentCritPercent) { line.Crit = true; line.Amount = line.Amount * 1.5; } Controller.Timeline.GetSetPlayer(line.Source).SetHealingOverTime(line); }); } catch (Exception ex) { Logging.Log(Logger, new LogItem(ex, true)); } } Controller.Timeline.FightingTimer.Start(); switch (Settings.Default.StoreHistoryEvent) { case "Any": Controller.Timeline.StoreHistoryTimer.Start(); break; } }
/// <summary> /// </summary> /// <param name="statusEntriesMonsters"></param> private void ProcessDamageOverTime(IEnumerable <StatusItem> statusEntriesMonsters) { foreach (StatusItem statusEntry in statusEntriesMonsters) { try { Sharlayan.Models.XIVDatabase.StatusItem statusInfo = StatusEffectLookup.GetStatusInfo((uint)statusEntry.StatusID); var statusKey = statusInfo.Name.English; switch (Constants.GameLanguage) { case "French": statusKey = statusInfo.Name.French; break; case "Japanese": statusKey = statusInfo.Name.Japanese; break; case "German": statusKey = statusInfo.Name.German; break; case "Chinese": statusKey = statusInfo.Name.Chinese; break; case "Korean": statusKey = statusInfo.Name.Korean; break; } if (string.IsNullOrWhiteSpace(statusKey)) { continue; } var difference = 60 - this.NPCEntry.Level; if (difference <= 0) { difference = 10; } var amount = this.NPCEntry.Level / (difference * .025); var key = statusKey; ActionItem actionData = null; foreach (KeyValuePair <string, ActionItem> damageOverTimeAction in DamageOverTimeHelper.PlayerActions.ToList().Where(d => string.Equals(d.Key, key, Constants.InvariantComparer))) { actionData = damageOverTimeAction.Value; } if (actionData == null) { continue; } var zeroFoundInList = false; var bio = Regex.IsMatch(key, @"(バイオ|bactérie|bio|毒菌)", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); var thunder = Regex.IsMatch(key, @"(サンダ|foudre|blitz|thunder|闪雷)", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); List <KeyValuePair <string, double> > lastDamageAmountByActions = ParseHelper.LastAmountByAction.GetPlayer(this.Name).ToList(); var resolvedPotency = 80; var thunderDuration = 24.0; double originalThunderDamage = 0; foreach (KeyValuePair <string, double> lastDamageAmountByAction in lastDamageAmountByActions) { if (thunder) { var found = false; Dictionary <string, List <string> > thunderActions = DamageOverTimeHelper.ThunderActions; KeyValuePair <string, double> action = lastDamageAmountByAction; if (thunderActions["III"].Any(thunderAction => string.Equals(action.Key, thunderAction, Constants.InvariantComparer))) { found = true; thunderDuration = (double)DamageOverTimeHelper.PlayerActions["thunder iii"].Duration; originalThunderDamage = action.Value; amount = action.Value / DamageOverTimeHelper.PlayerActions["thunder iii"].Potency * 30; } if (thunderActions["II"].Any(thunderAction => string.Equals(action.Key, thunderAction, Constants.InvariantComparer))) { found = true; thunderDuration = (double)DamageOverTimeHelper.PlayerActions["thunder ii"].Duration; originalThunderDamage = action.Value; amount = action.Value / DamageOverTimeHelper.PlayerActions["thunder ii"].Potency * 30; } if (thunderActions["I"].Any(thunderAction => string.Equals(action.Key, thunderAction, Constants.InvariantComparer))) { found = true; thunderDuration = (double)DamageOverTimeHelper.PlayerActions["thunder"].Duration; originalThunderDamage = action.Value; amount = action.Value; } if (found) { break; } } if (bio) { var found = false; Dictionary <string, List <string> > ruinActions = DamageOverTimeHelper.RuinActions; KeyValuePair <string, double> action = lastDamageAmountByAction; if (ruinActions["II"].Any(ruinAction => string.Equals(action.Key, ruinAction, Constants.InvariantComparer))) { found = zeroFoundInList = true; amount = action.Value; } if (ruinActions["I"].Any(ruinAction => string.Equals(action.Key, ruinAction, Constants.InvariantComparer))) { found = zeroFoundInList = true; amount = action.Value; } if (found) { break; } } if (string.Equals(lastDamageAmountByAction.Key, key, Constants.InvariantComparer)) { amount = lastDamageAmountByAction.Value; break; } } statusKey = $"{statusKey} [•]"; if (amount == 0) { amount = 75; } resolvedPotency = zeroFoundInList ? resolvedPotency : bio ? resolvedPotency : actionData.Potency; var tickDamage = Math.Ceiling(amount / resolvedPotency * actionData.OverTimePotency / 3); if (actionData.HasNoInitialResult && !zeroFoundInList) { IEnumerable <KeyValuePair <string, double> > nonZeroActions = lastDamageAmountByActions.Where(d => !d.Key.Contains("•")); IList <KeyValuePair <string, double> > keyValuePairs = nonZeroActions as IList <KeyValuePair <string, double> > ?? nonZeroActions.ToList(); double damage = 0; switch (bio) { case true: damage = Math.Ceiling(amount / resolvedPotency * actionData.OverTimePotency / 3); break; case false: if (keyValuePairs.Any()) { amount = keyValuePairs.Sum(action => action.Value); amount = amount / keyValuePairs.Count(); } damage = Math.Ceiling(amount / resolvedPotency * actionData.OverTimePotency / 3); break; } tickDamage = damage > 0 ? damage : tickDamage; } if (originalThunderDamage > 300 && thunder) { tickDamage = Math.Ceiling(originalThunderDamage / (thunderDuration + 3)); } var line = new Line { Action = statusKey, Amount = tickDamage, EventDirection = EventDirection.Unknown, EventType = EventType.Damage, EventSubject = EventSubject.Unknown, Source = this.Name, SourceEntity = this.NPCEntry, Target = statusEntry.TargetName, XOverTime = true }; Controller.Timeline.FightingRightNow = true; Controller.Timeline.FightingTimer.Stop(); Controller.Timeline.StoreHistoryTimer.Stop(); DispatcherHelper.Invoke( delegate { line.Hit = true; var currentCritPercent = this.Stats.GetStatValue("DamageCritPercent"); if (new Random().NextDouble() * 3 < currentCritPercent) { line.Crit = true; line.Amount = line.Amount * 1.5; } Controller.Timeline.GetSetPlayer(line.Source).SetDamageOverTime(line); Controller.Timeline.GetSetMonster(line.Target).SetDamageTakenOverTime(line); }); } catch (Exception ex) { Logging.Log(Logger, new LogItem(ex, true)); } } Controller.Timeline.FightingTimer.Start(); Controller.Timeline.StoreHistoryTimer.Start(); }