示例#1
0
        public void HandleActionQueryItemMana(ObjectGuid queryId)
        {
            if (queryId.Full == 0)
            {
                ManaQueryTarget = null;
                return;
            }

            // the object could be in the world or on the player, first check player
            WorldObject wo = GetInventoryItem(queryId);

            if (wo != null)
            {
                wo.QueryItemMana(Session);
            }
            else
            {
                // We could be wielded - let's check that next.
                if (EquippedObjects.TryGetValue(queryId, out wo))
                {
                    wo.QueryItemMana(Session);
                }
            }

            ManaQueryTarget = queryId.Full;
        }
示例#2
0
文件: Creature.cs 项目: zarlant/ACE
        /// <summary>
        /// This method sets us into peace mode.   It checks our current state to see if we have missle ammo equipped
        /// it will make the call to hid the "ammo" as we switch to peace mode.   It will then send the message switch our stance. Og II
        /// </summary>
        /// <param name="oldCombatMode"></param>
        /// <param name="isAutonomous"></param>
        public void HandleSwitchToPeaceMode(CombatMode oldCombatMode, bool isAutonomous = false)
        {
            HandleUnloadMissileAmmo(oldCombatMode);

            // FIXME: (Og II)<this is a hack for now to be removed.> Placement has an issue we have not figured out.   It has to do with animation frame. Og II
            PositionFlag &= ~UpdatePositionFlag.Placement;
            // End hack
            CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessageUpdatePosition(this));
            UniversalMotion mm = new UniversalMotion(MotionStance.Standing);

            mm.MovementData.CurrentStyle = (uint)MotionStance.Standing;
            SetMotionState(this, mm);
            var mEquipedAmmo = EquippedObjects.FirstOrDefault(s => s.Value.CurrentWieldedLocation == EquipMask.MissileAmmo).Value;
            var player       = this as Player;

            if (mEquipedAmmo != null)
            {
                CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectGhostRange, new GameMessagePickupEvent(mEquipedAmmo));
            }
            if (player != null)
            {
                player.stance = MotionStance.Standing;
                player.Session.Network.EnqueueSend(new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.CombatMode, (int)CombatMode.NonCombat));
            }
        }
示例#3
0
        public void AuditItemSpells()
        {
            // cleans up bugged chars with dangling item set spells
            // from previous bugs

            // this is a legacy method, but is still a decent failsafe to catch any existing issues

            // get active item enchantments
            var enchantments = Biota.GetEnchantments(BiotaDatabaseLock).Where(i => i.Duration == -1 && i.SpellId != (int)SpellId.Vitae).ToList();

            foreach (var enchantment in enchantments)
            {
                // if this item is not equipped, remove enchantment

                if (!EquippedObjects.TryGetValue(new ObjectGuid(enchantment.CasterObjectId), out var item))
                {
                    // this can fail for item sets, so disabling this section

                    /*var spell = new Spell(enchantment.SpellId, false);
                     * log.Error($"{Name}.AuditItemSpells(): removing spell {spell.Name} from non-equipped item");
                     *
                     * EnchantmentManager.Dispel(enchantment);*/
                    continue;
                }

                // is this item part of a set?
                if (!item.HasItemSet)
                {
                    continue;
                }

                // get all of the equipped items in this set
                var setItems = EquippedObjects.Values.Where(i => i.HasItemSet && i.EquipmentSetId == item.EquipmentSetId).ToList();

                // get all of the spells currently active from this set
                var currentSpells = GetSpellSet(setItems);

                // get all of the spells possible for this item set
                var possibleSpells = GetSpellSetAll((EquipmentSet)item.EquipmentSetId);

                // get the difference between them
                var inactiveSpells = possibleSpells.Except(currentSpells).ToList();

                // remove any item set spells that shouldn't be active
                foreach (var inactiveSpell in inactiveSpells)
                {
                    var removeSpells = enchantments.Where(i => i.SpellSetId == (uint)item.EquipmentSetId && i.SpellId == inactiveSpell.Id).ToList();

                    foreach (var removeSpell in removeSpells)
                    {
                        log.Error($"{Name}.AuditItemSpells(): removing spell {inactiveSpell.Name} from {item.EquipmentSetId}");

                        EnchantmentManager.Dispel(removeSpell);
                    }
                }
            }
        }
示例#4
0
        /// <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));
                    }
                }
            }
        }
示例#5
0
        /// <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));
                            }
                        }
                    }
                });
            }
        }
示例#6
0
        /// <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));
                    }
                }
            }
        }
示例#7
0
        public override ACE.Entity.ObjDesc CalculateObjDesc()
        {
            ACE.Entity.ObjDesc objDesc = new ACE.Entity.ObjDesc();
            ClothingTable      item;

            AddBaseModelData(objDesc);

            var coverage = new List <uint>();

            foreach (var w in EquippedObjects.OrderBy(x => x.Value.Priority))
            {
                // We can wield things that are not part of our model, only use those items that can cover our model.
                if ((w.Value.CurrentWieldedLocation & (EquipMask.Clothing | EquipMask.Armor | EquipMask.Cloak)) != 0)
                {
                    if (w.Value.ClothingBase.HasValue)
                    {
                        item = DatManager.PortalDat.ReadFromDat <ClothingTable>((uint)w.Value.ClothingBase);
                    }
                    else
                    {
                        continue;
                    }

                    if (item.ClothingBaseEffects.ContainsKey(SetupTableId))
                    // Check if the player model has data. Gear Knights, this is usually you.
                    {
                        // Add the model and texture(s)
                        ClothingBaseEffect clothingBaseEffec = item.ClothingBaseEffects[SetupTableId];
                        foreach (CloObjectEffect t in clothingBaseEffec.CloObjectEffects)
                        {
                            byte partNum = (byte)t.Index;
                            objDesc.AnimPartChanges.Add(new ACE.Entity.AnimationPartChange {
                                PartIndex = (byte)t.Index, PartID = t.ModelId
                            });
                            //AddModel((byte)t.Index, (ushort)t.ModelId);
                            coverage.Add(partNum);
                            foreach (CloTextureEffect t1 in t.CloTextureEffects)
                            {
                                objDesc.TextureChanges.Add(new ACE.Entity.TextureMapChange {
                                    PartIndex = (byte)t.Index, OldTexture = t1.OldTexture, NewTexture = t1.NewTexture
                                });
                            }
                            //AddTexture((byte)t.Index, (ushort)t1.OldTexture, (ushort)t1.NewTexture);
                        }

                        if (item.ClothingSubPalEffects.Count > 0)
                        {
                            int size     = item.ClothingSubPalEffects.Count;
                            int palCount = size;

                            CloSubPalEffect itemSubPal;
                            int             palOption = 0;
                            if (w.Value.PaletteTemplate.HasValue)
                            {
                                palOption = (int)w.Value.PaletteTemplate;
                            }
                            if (item.ClothingSubPalEffects.ContainsKey((uint)palOption))
                            {
                                itemSubPal = item.ClothingSubPalEffects[(uint)palOption];
                            }
                            else
                            {
                                itemSubPal = item.ClothingSubPalEffects[item.ClothingSubPalEffects.Keys.ElementAt(0)];
                            }

                            //if (itemSubPal.Icon > 0)
                            //    IconId = itemSubPal.Icon;

                            float shade = 0;
                            if (w.Value.Shade.HasValue)
                            {
                                shade = (float)w.Value.Shade;
                            }
                            for (int i = 0; i < itemSubPal.CloSubPalettes.Count; i++)
                            {
                                var    itemPalSet = DatManager.PortalDat.ReadFromDat <PaletteSet>(itemSubPal.CloSubPalettes[i].PaletteSet);
                                ushort itemPal    = (ushort)itemPalSet.GetPaletteID(shade);

                                for (int j = 0; j < itemSubPal.CloSubPalettes[i].Ranges.Count; j++)
                                {
                                    uint palOffset = itemSubPal.CloSubPalettes[i].Ranges[j].Offset / 8;
                                    uint numColors = itemSubPal.CloSubPalettes[i].Ranges[j].NumColors / 8;
                                    objDesc.SubPalettes.Add(new ACE.Entity.SubPalette {
                                        SubID = itemPal, Offset = palOffset, NumColors = numColors
                                    });
                                    //AddPalette(itemPal, (ushort)palOffset, (ushort)numColors);
                                }
                            }
                        }
                    }
                }
            }

            // Add the "naked" body parts. These are the ones not already covered.
            if (SetupTableId > 0)
            {
                var baseSetup = DatManager.PortalDat.ReadFromDat <SetupModel>(SetupTableId);
                for (byte i = 0; i < baseSetup.Parts.Count; i++)
                {
                    if (!coverage.Contains(i) && i != 0x10) // Don't add body parts for those that are already covered. Also don't add the head, that was already covered by AddCharacterBaseModelData()
                    {
                        objDesc.AnimPartChanges.Add(new ACE.Entity.AnimationPartChange {
                            PartIndex = i, PartID = baseSetup.Parts[i]
                        });
                    }
                    //AddModel(i, baseSetup.Parts[i]);
                }
            }

            if (coverage.Count == 0 && ClothingBase.HasValue)
            {
                return(base.CalculateObjDesc());
            }

            return(objDesc);
        }
示例#8
0
        public void HandleSwitchToMissileCombatMode(ActionChain combatModeChain)
        {
            // TODO and FIXME: GetInventoryItem doesn't work for this so this function is effectively broke
            HeldItem mEquipedMissile = Children.Find(s => s.EquipMask == EquipMask.MissileWeapon);

            if (mEquipedMissile?.Guid != null)
            {
                WorldObject missileWeapon = GetInventoryItem(new ObjectGuid(mEquipedMissile.Guid));
                if (missileWeapon == null)
                {
                    log.InfoFormat("Changing combat mode for {0} - could not locate wielded weapon {1}", Guid, mEquipedMissile.Guid);
                    return;
                }

                var mEquipedAmmo = EquippedObjects.First(s => s.Value.CurrentWieldedLocation == EquipMask.MissileAmmo).Value;

                MotionStance ms;
                CombatStyle  cs;

                if (missileWeapon.DefaultCombatStyle != null)
                {
                    cs = missileWeapon.DefaultCombatStyle.Value;
                }
                else
                {
                    log.InfoFormat("Changing combat mode for {0} - wielded item {1} has not be assigned a default combat style", Guid, mEquipedMissile.Guid);
                    return;
                }

                switch (cs)
                {
                case CombatStyle.Bow:
                    ms = MotionStance.BowAttack;
                    break;

                case CombatStyle.Crossbow:
                    ms = MotionStance.CrossBowAttack;
                    break;

                default:
                    ms = MotionStance.Invalid;
                    break;
                }

                UniversalMotion mm = new UniversalMotion(ms);
                mm.MovementData.CurrentStyle = (ushort)ms;
                if (mEquipedAmmo == null)
                {
                    CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessageUpdatePosition(this));
                    SetMotionState(this, mm);
                }
                else
                {
                    CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessageUpdatePosition(this));
                    SetMotionState(this, mm);
                    mm.MovementData.ForwardCommand = (uint)MotionCommand.Reload;
                    SetMotionState(this, mm);
                    CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessageUpdatePosition(this));
                    // FIXME: (Og II)<this is a hack for now to be removed. Need to pull delay from dat file
                    combatModeChain.AddDelaySeconds(0.25);
                    // System.Threading.Thread.Sleep(250); // used for debugging
                    mm.MovementData.ForwardCommand = (ushort)MotionCommand.Invalid;
                    SetMotionState(this, mm);
                    // FIXME: (Og II)<this is a hack for now to be removed. Need to pull delay from dat file
                    combatModeChain.AddDelaySeconds(0.40);
                    combatModeChain.AddAction(this, () => CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessageParentEvent(this, mEquipedAmmo, 1, 1)));
                    // CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessageParentEvent(this, ammo, 1, 1)); // used for debugging
                }
                CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessagePrivateUpdatePropertyInt(Sequences, PropertyInt.CombatMode, (int)CombatMode.Missile));
            }
        }