/// <summary> /// Called every ~5 secs for equipped mana consuming items /// </summary> public void ManaConsumersTick() { if (EquippedObjectsLoaded) { var EquippedManaConsumers = EquippedObjects.Where(k => (k.Value.IsAffecting ?? false) && k.Value.ManaRate.HasValue && k.Value.ItemMaxMana.HasValue && k.Value.ItemCurMana.HasValue && k.Value.ItemCurMana.Value > 0).ToList(); EquippedManaConsumers.ForEach(k => { var item = k.Value; var rate = item.ManaRate.Value; if (!item.ItemManaConsumptionTimestamp.HasValue) { item.ItemManaConsumptionTimestamp = DateTime.Now; } DateTime mostRecentBurn = item.ItemManaConsumptionTimestamp.Value; var timePerBurn = -1 / rate; var secondsSinceLastBurn = (DateTime.Now - mostRecentBurn).TotalSeconds; var delta = secondsSinceLastBurn / timePerBurn; var deltaChopped = (int)Math.Floor(delta); var deltaExtra = delta - deltaChopped; if (deltaChopped > 0) { var timeToAdd = (int)Math.Floor(deltaChopped * timePerBurn); item.ItemManaConsumptionTimestamp = mostRecentBurn + new TimeSpan(0, 0, timeToAdd); var manaToBurn = Math.Min(item.ItemCurMana.Value, deltaChopped); deltaChopped = Math.Clamp(deltaChopped, 0, 10); item.ItemCurMana -= deltaChopped; if (item.ItemCurMana < 1 || item.ItemCurMana == null) { item.IsAffecting = false; Session.Network.EnqueueSend(new GameMessageSystemChat($"Your {item.Name} is out of mana.", ChatMessageType.Magic)); if (item.WielderId != null) { if (item.Biota.BiotaPropertiesSpellBook != null) { for (int i = 0; i < item.Biota.BiotaPropertiesSpellBook.Count; i++) { // TODO: layering RemoveItemSpell(item.Guid, (uint)item.Biota.BiotaPropertiesSpellBook.ElementAt(i).Spell); } } } } else { // get time until empty var secondsUntilEmpty = ((item.ItemCurMana - deltaExtra) * timePerBurn); if (secondsUntilEmpty <= 30 && (!item.ItemManaDepletionMessageTimestamp.HasValue || (DateTime.Now - item.ItemManaDepletionMessageTimestamp.Value).TotalSeconds > 30)) { item.ItemManaDepletionMessageTimestamp = DateTime.Now; Session.Network.EnqueueSend(new GameMessageSystemChat($"Your {item.Name} is almost out of mana.", ChatMessageType.Magic)); } } } }); } }
/// <summary> /// Called every ~5 secs for equipped mana consuming items /// </summary> public void ManaConsumersTick() { if (!EquippedObjectsLoaded) { return; } var EquippedManaConsumers = EquippedObjects.Where(k => (k.Value.IsAffecting ?? false) && //k.Value.ManaRate.HasValue && k.Value.ItemMaxMana.HasValue && k.Value.ItemCurMana.HasValue && k.Value.ItemCurMana.Value > 0).ToList(); foreach (var k in EquippedManaConsumers) { var item = k.Value; // this was a bug in lootgen until 7/11/2019, mostly for clothing/armor/shields // tons of existing items on servers are in this bugged state, where they aren't ticking mana. // this retroactively fixes them when equipped // items such as Impious Staff are excluded from this via IsAffecting if (item.ManaRate == null) { item.ManaRate = LootGenerationFactory.GetManaRate(item); log.Warn($"{Name}.ManaConsumersTick(): {k.Value.Name} ({k.Value.Guid}) fixed missing ManaRate"); } var rate = item.ManaRate.Value; if (LumAugItemManaUsage != 0) { rate *= GetNegativeRatingMod(LumAugItemManaUsage * 5); } if (!item.ItemManaConsumptionTimestamp.HasValue) { item.ItemManaConsumptionTimestamp = DateTime.UtcNow; } DateTime mostRecentBurn = item.ItemManaConsumptionTimestamp.Value; var timePerBurn = -1 / rate; var secondsSinceLastBurn = (DateTime.UtcNow - mostRecentBurn).TotalSeconds; var delta = secondsSinceLastBurn / timePerBurn; var deltaChopped = (int)Math.Floor(delta); var deltaExtra = delta - deltaChopped; if (deltaChopped <= 0) { continue; } var timeToAdd = (int)Math.Floor(deltaChopped * timePerBurn); item.ItemManaConsumptionTimestamp = mostRecentBurn + new TimeSpan(0, 0, timeToAdd); var manaToBurn = Math.Min(item.ItemCurMana.Value, deltaChopped); deltaChopped = Math.Clamp(deltaChopped, 0, 10); item.ItemCurMana -= deltaChopped; if (item.ItemCurMana < 1 || item.ItemCurMana == null) { item.IsAffecting = false; var msg = new GameMessageSystemChat($"Your {item.Name} is out of Mana.", ChatMessageType.Magic); var sound = new GameMessageSound(Guid, Sound.ItemManaDepleted); Session.Network.EnqueueSend(msg, sound); if (item.WielderId != null) { if (item.Biota.PropertiesSpellBook != null) { // unsure if these messages / sounds were ever sent in retail, // or if it just purged the enchantments invisibly // doing a delay here to prevent 'SpellExpired' sounds from overlapping with 'ItemManaDepleted' var actionChain = new ActionChain(); actionChain.AddDelaySeconds(2.0f); actionChain.AddAction(this, () => { foreach (var spellId in item.Biota.GetKnownSpellsIds(item.BiotaDatabaseLock)) { RemoveItemSpell(item, (uint)spellId); } }); actionChain.EnqueueChain(); } } } else { // get time until empty var secondsUntilEmpty = ((item.ItemCurMana - deltaExtra) * timePerBurn); if (secondsUntilEmpty <= 120 && (!item.ItemManaDepletionMessageTimestamp.HasValue || (DateTime.UtcNow - item.ItemManaDepletionMessageTimestamp.Value).TotalSeconds > 120)) { item.ItemManaDepletionMessageTimestamp = DateTime.UtcNow; Session.Network.EnqueueSend(new GameMessageSystemChat($"Your {item.Name} is low on Mana.", ChatMessageType.Magic)); } } } }
/// <summary> /// Called every ~5 secs for equipped mana consuming items /// </summary> public void ManaConsumersTick() { if (!EquippedObjectsLoaded) { return; } var EquippedManaConsumers = EquippedObjects.Where(k => (k.Value.IsAffecting ?? false) && k.Value.ManaRate.HasValue && k.Value.ItemMaxMana.HasValue && k.Value.ItemCurMana.HasValue && k.Value.ItemCurMana.Value > 0).ToList(); foreach (var k in EquippedManaConsumers) { var item = k.Value; var rate = item.ManaRate.Value; if (LumAugItemManaUsage != 0) { rate *= GetNegativeRatingMod(LumAugItemManaUsage); } if (!item.ItemManaConsumptionTimestamp.HasValue) { item.ItemManaConsumptionTimestamp = DateTime.Now; } DateTime mostRecentBurn = item.ItemManaConsumptionTimestamp.Value; var timePerBurn = -1 / rate; var secondsSinceLastBurn = (DateTime.Now - mostRecentBurn).TotalSeconds; var delta = secondsSinceLastBurn / timePerBurn; var deltaChopped = (int)Math.Floor(delta); var deltaExtra = delta - deltaChopped; if (deltaChopped <= 0) { continue; } var timeToAdd = (int)Math.Floor(deltaChopped * timePerBurn); item.ItemManaConsumptionTimestamp = mostRecentBurn + new TimeSpan(0, 0, timeToAdd); var manaToBurn = Math.Min(item.ItemCurMana.Value, deltaChopped); deltaChopped = Math.Clamp(deltaChopped, 0, 10); item.ItemCurMana -= deltaChopped; if (item.ItemCurMana < 1 || item.ItemCurMana == null) { item.IsAffecting = false; var msg = new GameMessageSystemChat($"Your {item.Name} is out of Mana.", ChatMessageType.Magic); var sound = new GameMessageSound(Guid, Sound.ItemManaDepleted); Session.Network.EnqueueSend(msg, sound); if (item.WielderId != null) { if (item.Biota.BiotaPropertiesSpellBook != null) { // unsure if these messages / sounds were ever sent in retail, // or if it just purged the enchantments invisibly // doing a delay here to prevent 'SpellExpired' sounds from overlapping with 'ItemManaDepleted' var actionChain = new ActionChain(); actionChain.AddDelaySeconds(2.0f); actionChain.AddAction(this, () => { for (int i = 0; i < item.Biota.BiotaPropertiesSpellBook.Count; i++) { RemoveItemSpell(item, (uint)item.Biota.BiotaPropertiesSpellBook.ElementAt(i).Spell); } }); actionChain.EnqueueChain(); } } } else { // get time until empty var secondsUntilEmpty = ((item.ItemCurMana - deltaExtra) * timePerBurn); if (secondsUntilEmpty <= 120 && (!item.ItemManaDepletionMessageTimestamp.HasValue || (DateTime.Now - item.ItemManaDepletionMessageTimestamp.Value).TotalSeconds > 120)) { item.ItemManaDepletionMessageTimestamp = DateTime.Now; Session.Network.EnqueueSend(new GameMessageSystemChat($"Your {item.Name} is low on Mana.", ChatMessageType.Magic)); } } } }