예제 #1
0
파일: Player_Death.cs 프로젝트: Zegeger/ACE
        /// <summary>
        /// Broadcasts the player death animation, updates vitae, and sends network messages for player death
        /// Queues the action to call TeleportOnDeath and enter portal space soon
        /// </summary>
        protected override void Die(WorldObject lastDamager, WorldObject topDamager)
        {
            UpdateVital(Health, 0);
            NumDeaths++;
            DeathLevel  = Level; // for calculating vitae XP
            VitaeCpPool = 0;     // reset vitae XP earned

            // killer = top damager for looting rights
            if (topDamager != null)
            {
                Killer = topDamager.Guid.Full;
            }

            // broadcast death animation
            var deathAnim = new UniversalMotion(MotionStance.Standing, new MotionItem(MotionCommand.Dead));

            CurrentLandblock?.EnqueueBroadcastMotion(this, deathAnim);

            // killer death message = last damager
            var killerMsg           = lastDamager != null ? " to " + lastDamager.Name : "";
            var currentDeathMessage = $"died{killerMsg}.";

            // create network messages for player death
            var msgHealthUpdate = new GameMessagePrivateUpdateAttribute2ndLevel(this, Vital.Health, 0);

            // TODO: death sounds? seems to play automatically in client
            // var msgDeathSound = new GameMessageSound(Guid, Sound.Death1, 1.0f);
            var msgYourDeath         = new GameEventYourDeath(Session, $"You have {currentDeathMessage}");
            var msgNumDeaths         = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.NumDeaths, NumDeaths ?? 0);
            var msgDeathLevel        = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.DeathLevel, DeathLevel ?? 0);
            var msgVitaeCpPool       = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.VitaeCpPool, VitaeCpPool.Value);
            var msgPurgeEnchantments = new GameEventPurgeAllEnchantments(Session);

            // update vitae
            var vitae = EnchantmentManager.UpdateVitae();

            var spellID             = (uint)Network.Enum.Spell.Vitae;
            var spellBase           = DatManager.PortalDat.SpellTable.Spells[spellID];
            var spell               = DatabaseManager.World.GetCachedSpell(spellID);
            var vitaeEnchantment    = new Enchantment(this, Guid, spellID, (double)spell.Duration, 0, spell.StatModType, vitae);
            var msgVitaeEnchantment = new GameEventMagicUpdateEnchantment(Session, vitaeEnchantment);

            // send network messages for player death
            Session.Network.EnqueueSend(msgHealthUpdate, msgYourDeath, msgNumDeaths, msgDeathLevel, msgVitaeCpPool, msgPurgeEnchantments, msgVitaeEnchantment);

            // wait for the death animation to finish
            var dieChain   = new ActionChain();
            var animLength = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId).GetAnimationLength(MotionCommand.Dead);

            dieChain.AddDelaySeconds(animLength + 1.0f);

            // enter portal space
            dieChain.AddAction(this, CreateCorpse);
            dieChain.AddAction(this, TeleportOnDeath);
            dieChain.EnqueueChain();

            // if the player's lifestone is in a different landblock, also broadcast their demise to that landblock
            if (Sanctuary != null && Location.Landblock != Sanctuary.Landblock)
            {
                var killerGuid = lastDamager != null ? lastDamager.Guid : Guid;
                ActionBroadcastKill($"{Name} has {currentDeathMessage}", Guid, killerGuid);
            }
            DamageHistory.Reset();
        }
예제 #2
0
파일: Creature.cs 프로젝트: ValidusAC/ACE
        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 = WieldedObjects.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));
            }
        }
예제 #3
0
파일: Creature.cs 프로젝트: ValidusAC/ACE
        public void HandleSwitchToMeleeCombatMode(CombatMode olCombatMode)
        {
            // TODO and FIXME: GetInventoryItem doesn't work for this so this function is effectively broke
            bool shieldEquiped      = false;
            bool weaponInShieldSlot = false;

            // Check to see if we were in missile combat and have an arrow hanging around we might need to remove.
            HandleUnloadMissileAmmo(olCombatMode);

            HeldItem mEquipedShieldSlot = Children.Find(s => s.EquipMask == EquipMask.Shield);

            if (mEquipedShieldSlot != null)
            {
                WorldObject itemInShieldSlot = GetInventoryItem(new ObjectGuid(mEquipedShieldSlot.Guid));
                if (itemInShieldSlot != null)
                {
                    if (itemInShieldSlot.ItemType == ItemType.Armor)
                    {
                        shieldEquiped = true;
                    }
                    else
                    {
                        weaponInShieldSlot = true;
                    }
                }
            }

            HeldItem     mEquipedMelee     = Children.Find(s => s.EquipMask == EquipMask.MeleeWeapon);
            HeldItem     mEquipedTwoHanded = Children.Find(s => s.EquipMask == EquipMask.TwoHanded);
            MotionStance ms = MotionStance.Invalid;
            CombatStyle  cs = CombatStyle.Undef;

            // are we unarmed?   If so, do we have a shield?
            if (mEquipedMelee == null && mEquipedTwoHanded == null && !weaponInShieldSlot)
            {
                if (!shieldEquiped)
                {
                    ms = MotionStance.UaNoShieldAttack;
                }
                else
                {
                    ms = MotionStance.MeleeShieldAttack;
                }
            }
            else if (weaponInShieldSlot)
            {
                ms = MotionStance.DualWieldAttack;
            }

            if (mEquipedTwoHanded != null)
            {
                WorldObject twoHandedWeapon = GetInventoryItem(new ObjectGuid(mEquipedTwoHanded.Guid));
                if (twoHandedWeapon.DefaultCombatStyle != null)
                {
                    cs = twoHandedWeapon.DefaultCombatStyle.Value;
                    // ms = MotionStance.TwoHandedSwordAttack;
                    // ms = MotionStance.TwoHandedStaffAttack; ?
                    switch (cs)
                    {
                    // case CombatStyle.???
                    // ms = MotionStance.TwoHandedStaffAttack;
                    // break;
                    default:
                        ms = MotionStance.TwoHandedSwordAttack;
                        break;
                    }
                }
            }

            // Let's see if we are melee single handed / two handed with our without shield as appropriate.
            if (mEquipedMelee?.Guid != null && ms != MotionStance.DualWieldAttack)
            {
                WorldObject meleeWeapon = GetInventoryItem(new ObjectGuid(mEquipedMelee.Guid));

                if (meleeWeapon == null)
                {
                    log.InfoFormat("Changing combat mode for {0} - could not locate wielded weapon {1}", Guid, mEquipedMelee.Guid);
                    return;
                }

                if (!shieldEquiped)
                {
                    if (meleeWeapon.DefaultCombatStyle != null)
                    {
                        cs = meleeWeapon.DefaultCombatStyle.Value;
                        switch (cs)
                        {
                        case CombatStyle.Atlatl:
                            ms = MotionStance.AtlatlCombat;
                            break;

                        case CombatStyle.Sling:
                            ms = MotionStance.SlingAttack;
                            break;

                        case CombatStyle.ThrownWeapon:
                            ms = MotionStance.ThrownWeaponAttack;
                            break;

                        default:
                            ms = MotionStance.MeleeNoShieldAttack;
                            break;
                        }
                    }
                }
                else
                {
                    switch (meleeWeapon.DefaultCombatStyle)
                    {
                    case CombatStyle.Unarmed:
                    case CombatStyle.OneHanded:
                    case CombatStyle.OneHandedAndShield:
                    case CombatStyle.TwoHanded:
                    case CombatStyle.DualWield:
                    case CombatStyle.Melee:
                        ms = MotionStance.MeleeShieldAttack;
                        break;

                    case CombatStyle.ThrownWeapon:
                        ms = MotionStance.ThrownShieldCombat;
                        break;

                    ////case CombatStyle.Unarmed:
                    ////    ms = MotionStance.MeleeShieldAttack;
                    ////    break;
                    default:
                        log.InfoFormat(
                            "Changing combat mode for {0} - unable to determine correct combat stance for weapon {1}", Guid, mEquipedMelee.Guid);
                        return;
                    }
                }
            }
            if (ms != MotionStance.Invalid)
            {
                UniversalMotion mm = new UniversalMotion(ms);
                mm.MovementData.CurrentStyle = (ushort)ms;
                SetMotionState(this, mm);
                CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessagePrivateUpdatePropertyInt(Sequences, PropertyInt.CombatMode, (int)CombatMode.Melee));
            }
            else
            {
                log.InfoFormat("Changing combat mode for {0} - wielded item {1} has not be assigned a default combat style", Guid, mEquipedMelee?.Guid ?? mEquipedTwoHanded?.Guid);
            }
        }
예제 #4
0
        /// <summary>
        /// Method used for handling player targeted spell casts
        /// </summary>
        public void CreatePlayerSpell(ObjectGuid guidTarget, uint spellId)
        {
            Player         player         = CurrentLandblock.GetObject(Guid) as Player;
            WorldObject    target         = CurrentLandblock.GetObject(guidTarget);
            TargetCategory targetCategory = TargetCategory.WorldObject;

            if (target == null)
            {
                target         = GetWieldedItem(guidTarget);
                targetCategory = TargetCategory.Wielded;
            }
            if (target == null)
            {
                target         = GetInventoryItem(guidTarget);
                targetCategory = TargetCategory.Inventory;
            }
            if (target == null)
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.TargetNotAcquired));
                targetCategory = TargetCategory.UnDef;
                return;
            }

            SpellTable spellTable = DatManager.PortalDat.SpellTable;

            if (!spellTable.Spells.ContainsKey(spellId))
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicInvalidSpellType));
                return;
            }

            SpellBase spell = spellTable.Spells[spellId];

            if (IsInvalidTarget(spell, target))
            {
                player.Session.Network.EnqueueSend(new GameEventCommunicationTransientString(player.Session, $"{spell.Name} cannot be cast on {target.Name}."));
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.None));
                return;
            }

            Database.Models.World.Spell spellStatMod = DatabaseManager.World.GetCachedSpell(spellId);
            if (spellStatMod == null)
            {
                player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{spell.Name} spell not implemented, yet!", ChatMessageType.System));
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicInvalidSpellType));
                return;
            }

            if (player.IsBusy == true)
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YoureTooBusy));
                return;
            }
            else
            {
                player.IsBusy = true;
            }

            uint targetEffect = spell.TargetEffect;

            // Grab player's skill level in the spell's Magic School
            var magicSkill = player.GetCreatureSkill(spell.School).Current;

            if (targetCategory == TargetCategory.WorldObject)
            {
                if (guidTarget != Guid)
                {
                    float distanceTo = Location.Distance2D(target.Location);

                    if (distanceTo > spell.BaseRangeConstant + magicSkill * spell.BaseRangeMod)
                    {
                        player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.MagicTargetOutOfRange),
                                                           new GameMessageSystemChat($"{target.Name} is out of range!", ChatMessageType.Magic));
                        player.IsBusy = false;
                        return;
                    }
                }
            }

            // Ensure that a harmful spell isn't being cast on a player target that doesn't have the same PK status
            if (target.WeenieClassId == 1 && player.PlayerKillerStatus != ACE.Entity.Enum.PlayerKillerStatus.NPK)
            {
                bool isSpellHarmful = IsSpellHarmful(spell);
                if (player.PlayerKillerStatus != target.PlayerKillerStatus && isSpellHarmful)
                {
                    player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.InvalidPkStatus));
                    player.IsBusy = false;
                    return;
                }
            }

            float scale   = SpellAttributes(player.Session.Account, spellId, out float castingDelay, out MotionCommand windUpMotion, out MotionCommand spellGesture);
            var   formula = SpellTable.GetSpellFormula(spellTable, spellId, player.Session.Account);

            bool spellCastSuccess = false || ((Physics.Common.Random.RollDice(0.0f, 1.0f) > (1.0f - SkillCheck.GetMagicSkillChance((int)magicSkill, (int)spell.Power))) &&
                                              (magicSkill >= (int)spell.Power - 50) && (magicSkill > 0));

            // Calculating mana usage
            #region
            CreatureSkill mc = player.GetCreatureSkill(Skill.ManaConversion);
            double        z  = mc.Current;
            double        baseManaPercent = 1;
            if (z > spell.Power)
            {
                baseManaPercent = spell.Power / z;
            }
            double preCost;
            uint   manaUsed;
            if ((int)Math.Floor(baseManaPercent) == 1)
            {
                preCost  = spell.BaseMana;
                manaUsed = (uint)preCost;
            }
            else
            {
                preCost = spell.BaseMana * baseManaPercent;
                if (preCost < 1)
                {
                    preCost = 1;
                }
                manaUsed = (uint)Physics.Common.Random.RollDice(1, (int)preCost);
            }
            if (spell.MetaSpellType == SpellType.Transfer)
            {
                uint vitalChange, casterVitalChange;
                vitalChange = (uint)(player.GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source) * spellStatMod.Proportion);
                if (spellStatMod.TransferCap != 0)
                {
                    if (vitalChange > spellStatMod.TransferCap)
                    {
                        vitalChange = (uint)spellStatMod.TransferCap;
                    }
                }
                casterVitalChange = (uint)(vitalChange * (1.0f - spellStatMod.LossPercent));
                vitalChange       = (uint)(casterVitalChange / (1.0f - spellStatMod.LossPercent));

                if (spellStatMod.Source == (int)PropertyAttribute2nd.Mana && (vitalChange + 10 + manaUsed) > player.Mana.Current)
                {
                    ActionChain resourceCheckChain = new ActionChain();

                    resourceCheckChain.AddAction(this, () =>
                    {
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                    });

                    resourceCheckChain.AddDelaySeconds(2.0f);
                    resourceCheckChain.AddAction(this, () =>
                    {
                        player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YouDontHaveEnoughManaToCast));
                        player.IsBusy = false;
                    });

                    resourceCheckChain.EnqueueChain();

                    return;
                }
                else if ((vitalChange + 10) > player.GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source))
                {
                    ActionChain resourceCheckChain = new ActionChain();

                    resourceCheckChain.AddAction(this, () =>
                    {
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                    });

                    resourceCheckChain.AddDelaySeconds(2.0f);
                    resourceCheckChain.AddAction(this, () => player.IsBusy = false);
                    resourceCheckChain.EnqueueChain();

                    return;
                }
            }
            else if (manaUsed > player.Mana.Current)
            {
                ActionChain resourceCheckChain = new ActionChain();

                resourceCheckChain.AddAction(this, () =>
                {
                    CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                });

                resourceCheckChain.AddDelaySeconds(2.0f);
                resourceCheckChain.AddAction(this, () =>
                {
                    player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.YouDontHaveEnoughManaToCast));
                    player.IsBusy = false;
                });

                resourceCheckChain.EnqueueChain();

                return;
            }
            else
            {
                player.UpdateVital(player.Mana, player.Mana.Current - manaUsed);
            }
            #endregion

            ActionChain spellChain = new ActionChain();

            uint fastCast = (spell.Bitfield >> 14) & 0x1u;
            if (fastCast != 1)
            {
                spellChain.AddAction(this, () =>
                {
                    var motionWindUp = new UniversalMotion(MotionStance.Spellcasting);
                    motionWindUp.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                    motionWindUp.MovementData.ForwardCommand = (uint)windUpMotion;
                    motionWindUp.MovementData.ForwardSpeed   = 2;
                    DoMotion(motionWindUp);
                });
            }

            spellChain.AddAction(this, () =>
            {
                CurrentLandblock.EnqueueBroadcast(Location, new GameMessageCreatureMessage(SpellComponentsTable.GetSpellWords(DatManager.PortalDat.SpellComponentsTable,
                                                                                                                              formula), Name, Guid.Full, ChatMessageType.Magic));
            });

            spellChain.AddAction(this, () =>
            {
                var motionCastSpell = new UniversalMotion(MotionStance.Spellcasting);
                motionCastSpell.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                motionCastSpell.MovementData.ForwardCommand = (uint)spellGesture;
                motionCastSpell.MovementData.ForwardSpeed   = 2;
                DoMotion(motionCastSpell);
            });

            if (fastCast == 1)
            {
                spellChain.AddDelaySeconds(castingDelay * 0.26f);
            }
            else
            {
                spellChain.AddDelaySeconds(castingDelay);
            }

            if (spellCastSuccess == false)
            {
                spellChain.AddAction(this, () => CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f)));
            }
            else
            {
                spellChain.AddAction(this, () =>
                {
                    bool targetDeath;
                    string message;

                    switch (spell.School)
                    {
                    case MagicSchool.WarMagic:
                        WarMagic(target, spell, spellStatMod);
                        break;

                    case MagicSchool.VoidMagic:
                        VoidMagic(target, spell, spellStatMod);
                        break;

                    case MagicSchool.CreatureEnchantment:
                        if (IsSpellHarmful(spell))
                        {
                            // Retrieve player's skill level in the Magic School
                            var playerMagicSkill = player.GetCreatureSkill(spell.School).Current;

                            // Retrieve target's Magic Defense Skill
                            Creature creature           = (Creature)target;
                            var targetMagicDefenseSkill = creature.GetCreatureSkill(Skill.MagicDefense).Current;

                            if (MagicDefenseCheck(playerMagicSkill, targetMagicDefenseSkill))
                            {
                                CurrentLandblock.EnqueueBroadcastSound(player, Sound.ResistSpell);
                                player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{creature.Name} resists {spell.Name}", ChatMessageType.Magic));
                                break;
                            }
                        }
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale));
                        message = CreatureMagic(target, spell, spellStatMod);
                        if (message != "")
                        {
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic));
                        }
                        break;

                    case MagicSchool.LifeMagic:
                        if (spell.MetaSpellType != SpellType.LifeProjectile)
                        {
                            if (IsSpellHarmful(spell))
                            {
                                // Retrieve player's skill level in the Magic School
                                var playerMagicSkill = player.GetCreatureSkill(spell.School).Current;

                                // Retrieve target's Magic Defense Skill
                                Creature creature           = (Creature)target;
                                var targetMagicDefenseSkill = creature.GetCreatureSkill(Skill.MagicDefense).Current;

                                if (MagicDefenseCheck(playerMagicSkill, targetMagicDefenseSkill))
                                {
                                    CurrentLandblock.EnqueueBroadcastSound(player, Sound.ResistSpell);
                                    player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{creature.Name} resists {spell.Name}", ChatMessageType.Magic));
                                    break;
                                }
                            }
                        }
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale));
                        targetDeath = LifeMagic(target, spell, spellStatMod, out message);
                        if (message != null)
                        {
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic));
                        }
                        if (targetDeath == true)
                        {
                            Creature creatureTarget = (Creature)target;
                            creatureTarget.Die();
                            Strings.DeathMessages.TryGetValue(DamageType.Base, out var messages);
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(string.Format(messages[0], target.Name), ChatMessageType.Broadcast));
                            player.GrantXp((long)target.XpOverride, true);
                        }
                        break;

                    case MagicSchool.ItemEnchantment:
                        if (guidTarget == Guid)
                        {
                            CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, (PlayScript)spell.CasterEffect, scale));
                        }
                        else
                        {
                            CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(target.Guid, (PlayScript)spell.TargetEffect, scale));
                        }
                        message = ItemMagic(target, spell, spellStatMod);
                        if (message != "")
                        {
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(message, ChatMessageType.Magic));
                        }
                        break;

                    default:
                        break;
                    }
                });
            }

            spellChain.AddAction(this, () =>
            {
                var motionReturnToCastStance = new UniversalMotion(MotionStance.Spellcasting);
                motionReturnToCastStance.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                motionReturnToCastStance.MovementData.ForwardCommand = (uint)MotionCommand.Invalid;
                DoMotion(motionReturnToCastStance);
            });

            spellChain.AddDelaySeconds(1.0f);

            spellChain.AddAction(this, () =>
            {
                player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session, errorType: WeenieError.None));
                player.IsBusy = false;
            });

            spellChain.EnqueueChain();

            return;
        }
예제 #5
0
        /// <summary>
        /// Method used for handling player untargeted spell casts
        /// </summary>
        public void CreatePlayerSpell(uint spellId)
        {
            if (IsBusy == true)
            {
                Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.YoureTooBusy));
                return;
            }
            else
            {
                IsBusy = true;
            }

            SpellTable spellTable = DatManager.PortalDat.SpellTable;

            if (!spellTable.Spells.ContainsKey(spellId))
            {
                Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.MagicInvalidSpellType));
                IsBusy = false;
                return;
            }

            SpellBase spell = spellTable.Spells[spellId];

            Database.Models.World.Spell spellStatMod = DatabaseManager.World.GetCachedSpell(spellId);
            if (spellStatMod == null)
            {
                Session.Network.EnqueueSend(new GameMessageSystemChat($"{spell.Name} spell not implemented, yet!", ChatMessageType.System));
                Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.MagicInvalidSpellType));
                IsBusy = false;
                return;
            }

            // Grab player's skill level in the spell's Magic School
            var magicSkill = GetCreatureSkill(spell.School);

            float scale   = SpellAttributes(Session.Account, spellId, out float castingDelay, out MotionCommand windUpMotion, out MotionCommand spellGesture);
            var   formula = SpellTable.GetSpellFormula(spellTable, spellId, Session.Account);

            bool spellCastSuccess = false || ((Physics.Common.Random.RollDice(0.0f, 1.0f) > (1.0f - SkillCheck.GetMagicSkillChance((int)magicSkill.Current, (int)spell.Power))) &&
                                              (magicSkill.Current >= (int)spell.Power - 50) && (magicSkill.Current > 0));

            // Calculating mana usage
            #region
            if (spellCastSuccess == true)
            {
                CreatureSkill mc = GetCreatureSkill(Skill.ManaConversion);
                double        z  = mc.Current;
                double        baseManaPercent = 1;
                if (z > spell.Power)
                {
                    baseManaPercent = spell.Power / z;
                }
                double preCost;
                uint   manaUsed;
                if ((int)Math.Floor(baseManaPercent) == 1)
                {
                    preCost  = spell.BaseMana;
                    manaUsed = (uint)preCost;
                }
                else
                {
                    preCost = spell.BaseMana * baseManaPercent;
                    if (preCost < 1)
                    {
                        preCost = 1;
                    }
                    manaUsed = (uint)Physics.Common.Random.RollDice(1, (int)preCost);
                }
                if (spell.MetaSpellType == SpellType.Transfer)
                {
                    uint vitalChange, casterVitalChange;
                    vitalChange = (uint)(GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source) * spellStatMod.Proportion);
                    if (spellStatMod.TransferCap != 0)
                    {
                        if (vitalChange > spellStatMod.TransferCap)
                        {
                            vitalChange = (uint)spellStatMod.TransferCap;
                        }
                    }
                    casterVitalChange = (uint)(vitalChange * (1.0f - spellStatMod.LossPercent));
                    vitalChange       = (uint)(casterVitalChange / (1.0f - spellStatMod.LossPercent));

                    if (spellStatMod.Source == (int)PropertyAttribute2nd.Mana && (vitalChange + 10 + manaUsed) > Mana.Current)
                    {
                        ActionChain resourceCheckChain = new ActionChain();

                        resourceCheckChain.AddAction(this, () =>
                        {
                            CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                        });

                        resourceCheckChain.AddDelaySeconds(2.0f);
                        resourceCheckChain.AddAction(this, () =>
                        {
                            Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.YouDontHaveEnoughManaToCast));
                            IsBusy = false;
                        });

                        resourceCheckChain.EnqueueChain();

                        return;
                    }

                    if ((vitalChange + 10) > GetCurrentCreatureVital((PropertyAttribute2nd)spellStatMod.Source))
                    {
                        ActionChain resourceCheckChain = new ActionChain();

                        resourceCheckChain.AddAction(this, () =>
                        {
                            CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                        });

                        resourceCheckChain.AddDelaySeconds(2.0f);
                        resourceCheckChain.AddAction(this, () => IsBusy = false);
                        resourceCheckChain.EnqueueChain();

                        return;
                    }
                }
                else if (manaUsed > Mana.Current)
                {
                    ActionChain resourceCheckChain = new ActionChain();

                    resourceCheckChain.AddAction(this, () =>
                    {
                        CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f));
                    });

                    resourceCheckChain.AddDelaySeconds(2.0f);
                    resourceCheckChain.AddAction(this, () =>
                    {
                        Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.YouDontHaveEnoughManaToCast));
                        IsBusy = false;
                    });

                    resourceCheckChain.EnqueueChain();

                    return;
                }
                else
                {
                    UpdateVital(Mana, Mana.Current - manaUsed);
                }
            }
            #endregion

            ActionChain spellChain = new ActionChain();

            uint fastCast = (spell.Bitfield >> 14) & 0x1u;
            if (fastCast != 1)
            {
                spellChain.AddAction(this, () =>
                {
                    var motionWindUp = new UniversalMotion(MotionStance.Spellcasting);
                    motionWindUp.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                    motionWindUp.MovementData.ForwardCommand = (uint)windUpMotion;
                    motionWindUp.MovementData.ForwardSpeed   = 2;
                    DoMotion(motionWindUp);
                });
            }

            spellChain.AddAction(this, () =>
            {
                CurrentLandblock.EnqueueBroadcast(Location, new GameMessageCreatureMessage(SpellComponentsTable.GetSpellWords(DatManager.PortalDat.SpellComponentsTable,
                                                                                                                              formula), Name, Guid.Full, ChatMessageType.Magic));
            });

            spellChain.AddAction(this, () =>
            {
                var motionCastSpell = new UniversalMotion(MotionStance.Spellcasting);
                motionCastSpell.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                motionCastSpell.MovementData.ForwardCommand = (uint)spellGesture;
                motionCastSpell.MovementData.ForwardSpeed   = 2;
                DoMotion(motionCastSpell);
            });

            if (fastCast == 1)
            {
                spellChain.AddDelaySeconds(castingDelay * 0.26f);
            }
            else
            {
                spellChain.AddDelaySeconds(castingDelay);
            }

            if (spellCastSuccess == false)
            {
                spellChain.AddAction(this, () => CurrentLandblock.EnqueueBroadcast(Location, new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Fizzle, 0.5f)));
            }
            else
            {
                // TODO - Successful spell casting code goes here for untargeted spells to replace line below
                Session.Network.EnqueueSend(new GameMessageSystemChat("Targeted SpellID " + spellId + " not yet implemented!", ChatMessageType.System));
            }

            spellChain.AddAction(this, () =>
            {
                var motionReturnToCastStance = new UniversalMotion(MotionStance.Spellcasting);
                motionReturnToCastStance.MovementData.CurrentStyle   = (ushort)((uint)MotionStance.Spellcasting & 0xFFFF);
                motionReturnToCastStance.MovementData.ForwardCommand = (uint)MotionCommand.Invalid;
                DoMotion(motionReturnToCastStance);
            });

            spellChain.AddDelaySeconds(1.0f);

            spellChain.AddAction(this, () =>
            {
                Session.Network.EnqueueSend(new GameEventUseDone(Session, errorType: WeenieError.None));
                IsBusy = false;
            });

            spellChain.EnqueueChain();

            return;
        }
예제 #6
0
        /// <summary>
        /// This is raised when we drop an item. It can be a wielded item, or an item in our inventory.
        /// </summary>
        public void HandleActionDropItem(ObjectGuid itemGuid)
        {
            // Goody Goody -- lets build  drop chain
            // First start drop animation
            new ActionChain(this, () =>
            {
                // check packs of item.
                WorldObject item;

                if (!TryRemoveFromInventory(itemGuid, out item))
                {
                    // check to see if this item is wielded
                    if (TryDequipObject(itemGuid, out item))
                    {
                        Children.Remove(Children.Find(s => s.Guid == item.Guid.Full));

                        Session.Network.EnqueueSend(
                            new GameMessageSound(Guid, Sound.WieldObject, 1.0f),
                            new GameMessageObjDescEvent(this),
                            new GameMessageUpdateInstanceId(Guid, new ObjectGuid(0), PropertyInstanceId.Wielder));
                    }
                }

                if (item == null)
                {
                    log.Error("Player_Inventory HandleActionDropItem item is null");
                    return;
                }

                item.SetPropertiesForWorld(this);

                // It's important that we save an item after it's been removed from inventory.
                // We want to avoid the scenario where the server crashes and a player has too many items.
                item.SaveBiotaToDatabase();

                var motion = new UniversalMotion(MotionStance.Standing);
                motion.MovementData.ForwardCommand = (uint)MotionCommand.Pickup;
                Session.Network.EnqueueSend(new GameMessageUpdateInstanceId(itemGuid, new ObjectGuid(0), PropertyInstanceId.Container));

                // Set drop motion
                CurrentLandblock.EnqueueBroadcastMotion(this, motion);

                // Now wait for Drop Motion to finish -- use ActionChain
                var chain = new ActionChain();

                // Wait for drop animation
                var motionTable           = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId);
                var pickupAnimationLength = motionTable.GetAnimationLength(MotionCommand.Pickup);
                chain.AddDelaySeconds(pickupAnimationLength);

                // Play drop sound
                // Put item on landblock
                chain.AddAction(this, () =>
                {
                    motion = new UniversalMotion(MotionStance.Standing);
                    CurrentLandblock.EnqueueBroadcastMotion(this, motion);
                    Session.Network.EnqueueSend(
                        new GameMessageSound(Guid, Sound.DropItem, (float)1.0),
                        new GameMessagePutObjectIn3d(Session, this, itemGuid),
                        new GameMessageUpdateInstanceId(itemGuid, new ObjectGuid(0), PropertyInstanceId.Container),
                        new GameMessagePrivateUpdatePropertyInt(Sequences, PropertyInt.EncumbranceVal, EncumbranceVal ?? 0));

                    // This is the sequence magic - adds back into 3d space seem to be treated like teleport.
                    item.Sequences.GetNextSequence(SequenceType.ObjectTeleport);
                    item.Sequences.GetNextSequence(SequenceType.ObjectVector);

                    CurrentLandblock.AddWorldObject(item);

                    Session.Network.EnqueueSend(new GameMessageUpdateObject(item));
                });

                chain.EnqueueChain();
            }).EnqueueChain();
        }
예제 #7
0
        /// <summary>
        /// Launches a projectile from player to target
        /// </summary>
        public WorldObject LaunchProjectile(WorldObject target, out float time)
        {
            var ammo  = GetEquippedAmmo();
            var arrow = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId);

            arrow.ProjectileSource = this;
            arrow.ProjectileTarget = target;

            var origin = Location.GlobalPos;

            origin.Z += Height;

            var dest = target.Location.GlobalPos;

            //var dest = target.Location.Pos;
            dest.Z += target.Height / GetAimHeight(target);

            var speed = 35.0f;
            var dir   = GetDir2D(origin, dest);

            origin += dir * 2.0f;

            var velocity = GetProjectileVelocity(target, origin, dir, dest, speed, out time);

            arrow.Velocity = new AceVector3(velocity.X, velocity.Y, velocity.Z);

            origin = Location.FromGlobal(origin).Pos;
            var rotation = Location.Rotation;

            arrow.Location = new Position(Location.LandblockId.Raw, origin.X, origin.Y, origin.Z, rotation.X, rotation.Y, rotation.Z, rotation.W);
            SetProjectilePhysicsState(arrow, target);

            // TODO: Get correct aim level based on arrow velocity and add aim motion delay.
            var motion = new UniversalMotion(CurrentMotionState.Stance);

            motion.MovementData.CurrentStyle   = (uint)CurrentMotionState.Stance;
            motion.MovementData.ForwardCommand = (uint)MotionCommand.AimLevel;
            CurrentMotionState = motion;

            DoMotion(motion);
            //actionChain.AddDelaySeconds(animLength);

            LandblockManager.AddObject(arrow);
            CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePickupEvent(ammo));

            var player = this as Player;

            // TODO: Add support for monster ammo depletion. For now only players will use up ammo.
            if (player != null)
            {
                UpdateAmmoAfterLaunch(ammo);
            }
            // Not sure why this would be needed but it is sent in retail pcaps.
            CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessageSetStackSize(arrow));

            if (player != null)
            {
                CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePublicUpdatePropertyInt(
                                                      arrow, PropertyInt.PlayerKillerStatus, (int)(player.PlayerKillerStatus ?? ACE.Entity.Enum.PlayerKillerStatus.NPK)));
            }
            else
            {
                CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePublicUpdatePropertyInt(
                                                      arrow, PropertyInt.PlayerKillerStatus, (int)ACE.Entity.Enum.PlayerKillerStatus.Creature));
            }

            CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessageScript(arrow.Guid, ACE.Entity.Enum.PlayScript.Launch, 0f));

            // detonate point-blank projectiles immediately
            var radsum = target.PhysicsObj.GetRadius() + arrow.PhysicsObj.GetRadius();
            var dist   = Vector3.Distance(origin, dest);

            if (dist < radsum)
            {
                arrow.OnCollideObject(target);
            }

            return(arrow);
        }
예제 #8
0
        /// <summary>
        /// Launches a projectile from player to target
        /// </summary>
        public WorldObject LaunchProjectile(WorldObject target, out float time)
        {
            var ammo  = GetEquippedAmmo();
            var arrow = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId);

            var origin = Location.ToGlobal();

            origin.Z += Height;

            var dest = target.Location.ToGlobal();

            dest.Z += target.Height / GetAimHeight(target);

            var speed = 35.0f;
            var dir   = Vector3.Normalize(dest - origin);

            origin += dir * 2.0f;

            arrow.Velocity = GetProjectileVelocity(target, origin, dir, dest, speed, out time);

            var loc = Location;

            origin         = Position.FromGlobal(origin).Pos;
            arrow.Location = new Position(loc.LandblockId.Raw, origin.X, origin.Y, origin.Z, loc.Rotation.X, loc.Rotation.Y, loc.Rotation.Z, loc.RotationW);
            SetProjectilePhysicsState(arrow);

            var actionChain = new ActionChain();

            // TODO: Get correct aim level based on arrow velocity and add aim motion delay.
            var motion = new UniversalMotion(CurrentMotionState.Stance);

            motion.MovementData.CurrentStyle   = (uint)CurrentMotionState.Stance;
            motion.MovementData.ForwardCommand = (uint)MotionCommand.AimLevel;
            CurrentMotionState = motion;

            actionChain.AddAction(this, () => DoMotion(motion));
            //actionChain.AddDelaySeconds(animLength);

            actionChain.AddAction(this, () => LandblockManager.AddObject(arrow));
            actionChain.AddAction(this, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePickupEvent(ammo)));

            var player = this as Player;

            // TODO: Add support for monster ammo depletion. For now only players will use up ammo.
            if (player != null)
            {
                actionChain.AddAction(this, () => UpdateAmmoAfterLaunch(ammo));
            }
            // Not sure why this would be needed but it is sent in retail pcaps.
            actionChain.AddAction(arrow, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessageSetStackSize(arrow)));

            if (player != null)
            {
                actionChain.AddAction(arrow, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePublicUpdatePropertyInt(
                                                                                         arrow, PropertyInt.PlayerKillerStatus, (int)(player.PlayerKillerStatus ?? ACE.Entity.Enum.PlayerKillerStatus.NPK))));
            }
            else
            {
                actionChain.AddAction(arrow, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessagePublicUpdatePropertyInt(
                                                                                         arrow, PropertyInt.PlayerKillerStatus, (int)ACE.Entity.Enum.PlayerKillerStatus.Creature)));
            }

            actionChain.AddAction(arrow, () => CurrentLandblock.EnqueueBroadcast(arrow.Location, new GameMessageScript(arrow.Guid, ACE.Entity.Enum.PlayScript.Launch, 0f)));
            actionChain.AddDelaySeconds(time);
            // todo: landblock broadcast?

            if (player != null)
            {
                actionChain.AddAction(arrow, () => player.Session.Network.EnqueueSend(new GameMessageSound(arrow.Guid, Sound.Collision, 1.0f)));
            }

            actionChain.AddAction(arrow, () => CurrentLandblock.RemoveWorldObject(arrow.Guid, false));
            actionChain.EnqueueChain();

            return(arrow);
        }
예제 #9
0
파일: Player.cs 프로젝트: zarlant/ACE
        private void SetEphemeralValues()
        {
            BaseDescriptionFlags |= ObjectDescriptionFlag.Player;

            IgnoreCollisions = true; ReportCollisions = false; Hidden = true;

            // This is the default send upon log in and the most common. Anything with a velocity will need to add that flag.
            PositionFlag |= UpdatePositionFlag.ZeroQx | UpdatePositionFlag.ZeroQy | UpdatePositionFlag.Contact | UpdatePositionFlag.Placement;

            CurrentMotionState = new UniversalMotion(MotionStance.Standing);

            // radius for object updates
            ListeningRadius = 5f;

            if (Common.ConfigManager.Config.Server.Accounts.OverrideCharacterPermissions)
            {
                if (Session.AccessLevel == AccessLevel.Admin)
                {
                    IsAdmin = true;
                }
                if (Session.AccessLevel == AccessLevel.Developer)
                {
                    IsArch = true;
                }
                if (Session.AccessLevel == AccessLevel.Envoy)
                {
                    IsEnvoy = true;
                }
                // TODO: Need to setup and account properly for IsSentinel and IsAdvocate.
                // if (Session.AccessLevel == AccessLevel.Sentinel)
                //    character.IsSentinel = true;
                // if (Session.AccessLevel == AccessLevel.Advocate)
                //    character.IsAdvocate= true;
            }

            ContainerCapacity = 7;

            if ((AdvocateQuest ?? false) && IsAdvocate) // Advocate permissions are per character regardless of override
            {
                if (Session.AccessLevel == AccessLevel.Player)
                {
                    Session.SetAccessLevel(AccessLevel.Advocate); // Elevate to Advocate permissions
                }
                if (AdvocateLevel > 4)
                {
                    IsPsr = true; // Enable AdvocateTeleport via MapClick
                }
            }

            UpdateCoinValue(false);

            IsOnline = true;

            return; // todo

            /* todo fix for new EF model
             * TrackedContracts = new Dictionary<uint, ContractTracker>();
             * // Load the persisted tracked contracts into the working dictionary on player object.
             * foreach (var trackedContract in AceObject.TrackedContracts)
             * {
             *  ContractTracker loadContract = new ContractTracker(trackedContract.Value.ContractId, Guid.Full)
             *  {
             *      DeleteContract = trackedContract.Value.DeleteContract,
             *      SetAsDisplayContract = trackedContract.Value.SetAsDisplayContract,
             *      Stage = trackedContract.Value.Stage,
             *      TimeWhenDone = trackedContract.Value.TimeWhenDone,
             *      TimeWhenRepeats = trackedContract.Value.TimeWhenRepeats
             *  };
             *
             *  TrackedContracts.Add(trackedContract.Key, loadContract);
             * }*/

            LastUseTracker = new Dictionary <int, DateTime>();

            // =======================================
            // This code was taken from the old Load()
            // =======================================

            /*AceCharacter character;
             *
             * if (Common.ConfigManager.Config.Server.Accounts.OverrideCharacterPermissions)
             * {
             *  if (Session.AccessLevel == AccessLevel.Admin)
             *      character.IsAdmin = true;
             *  if (Session.AccessLevel == AccessLevel.Developer)
             *      character.IsArch = true;
             *  if (Session.AccessLevel == AccessLevel.Envoy)
             *      character.IsEnvoy = true;
             *  // TODO: Need to setup and account properly for IsSentinel and IsAdvocate.
             *  // if (Session.AccessLevel == AccessLevel.Sentinel)
             *  //    character.IsSentinel = true;
             *  // if (Session.AccessLevel == AccessLevel.Advocate)
             *  //    character.IsAdvocate= true;
             * }*/

            FirstEnterWorldDone = false;

            IsAlive = true;
        }
예제 #10
0
        public void HandleMovementEvent(WorldObject sender, UniversalMotion motion)
        {
            BroadcastEventArgs args = BroadcastEventArgs.CreateMovementEvent(sender, motion);

            Broadcast(args, true, Quadrant.All);
        }
예제 #11
0
        private void HandleGameAction(QueuedGameAction action, Player player)
        {
            switch (action.ActionType)
            {
            case GameActionType.TalkDirect:
            {
                // TODO: remove this hack (using TalkDirect) ASAP
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                DeathMessageArgs d = new DeathMessageArgs(action.ActionBroadcastMessage, new ObjectGuid(action.ObjectId), new ObjectGuid(action.SecondaryObjectId));
                HandleDeathMessage(obj, d);
                break;
            }

            case GameActionType.TeleToHouse:
            case GameActionType.TeleToLifestone:
            case GameActionType.TeleToMansion:
            case GameActionType.TeleToMarketPlace:
            case GameActionType.TeleToPkArena:
            case GameActionType.TeleToPklArena:
            {
                player.Teleport(action.ActionLocation);
                break;
            }

            case GameActionType.ApplyVisualEffect:
            {
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                var particleEffect = (PlayScript)action.SecondaryObjectId;
                HandleParticleEffectEvent(obj, particleEffect);
                break;
            }

            case GameActionType.ApplySoundEffect:
            {
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                var soundEffect = (Sound)action.SecondaryObjectId;
                HandleSoundEvent(obj, soundEffect);
                break;
            }

            case GameActionType.PutItemInContainer:
            {
                var playerId    = new ObjectGuid(action.ObjectId);
                var inventoryId = new ObjectGuid(action.SecondaryObjectId);
                if (playerId.IsPlayer())
                {
                    Player      aPlayer       = null;
                    WorldObject inventoryItem = null;

                    if (worldObjects.ContainsKey(playerId) && worldObjects.ContainsKey(inventoryId))
                    {
                        aPlayer       = (Player)worldObjects[playerId];
                        inventoryItem = worldObjects[inventoryId];
                    }

                    if ((aPlayer != null) && (inventoryItem != null))
                    {
                        if (aPlayer.PhysicsData.Position.SquaredDistanceTo(inventoryItem.PhysicsData.Position)
                            > Math.Pow(inventoryItem.GameData.UseRadius, 2))
                        {
                            // This is where I need to hook in the move to object code.
                            // TODO: Og II work on this soon.
                        }
                        var motion = new UniversalMotion(MotionStance.Standing);
                        motion.MovementData.ForwardCommand = (ushort)MotionCommand.Pickup;
                        aPlayer.Session.Network.EnqueueSend(new GameMessageUpdatePosition(aPlayer),
                                                            new GameMessageUpdateMotion(aPlayer, aPlayer.Session, motion),
                                                            new GameMessageSound(aPlayer.Guid, Sound.PickUpItem, (float)1.0));

                        // Add to the inventory list.
                        aPlayer.AddToInventory(inventoryItem);
                        LandblockManager.RemoveObject(inventoryItem);

                        motion = new UniversalMotion(MotionStance.Standing);
                        aPlayer.Session.Network.EnqueueSend(new GameMessagePrivateUpdatePropertyInt(aPlayer.Session,
                                                                                                    PropertyInt.EncumbVal,
                                                                                                    aPlayer.GameData.Burden),
                                                            new GameMessagePutObjectInContainer(aPlayer.Session, aPlayer, inventoryId),
                                                            new GameMessageUpdateMotion(aPlayer, aPlayer.Session, motion),
                                                            new GameMessageUpdateInstanceId(inventoryId, playerId),
                                                            new GameMessagePickupEvent(aPlayer.Session, inventoryItem));

                        aPlayer.TrackObject(inventoryItem);
                        // This may not be needed when we fix landblock update object -
                        // TODO: Og II - check this later to see if it is still required.
                        aPlayer.Session.Network.EnqueueSend(new GameMessageUpdateObject(inventoryItem));
                    }
                }
                break;
            }

            case GameActionType.DropItem:
            {
                var g = new ObjectGuid(action.ObjectId);
                // ReSharper disable once InconsistentlySynchronizedField
                if (worldObjects.ContainsKey(g))
                {
                    var playerId    = new ObjectGuid(action.ObjectId);
                    var inventoryId = new ObjectGuid(action.SecondaryObjectId);
                    if (playerId.IsPlayer())
                    {
                        Player      aPlayer       = null;
                        WorldObject inventoryItem = null;

                        if (worldObjects.ContainsKey(playerId))
                        {
                            aPlayer       = (Player)worldObjects[playerId];
                            inventoryItem = aPlayer.GetInventoryItem(inventoryId);
                            aPlayer.RemoveFromInventory(inventoryId);
                        }

                        if ((aPlayer != null) && (inventoryItem != null))
                        {
                            var targetContainer = new ObjectGuid(0);
                            aPlayer.Session.Network.EnqueueSend(
                                new GameMessagePrivateUpdatePropertyInt(
                                    aPlayer.Session,
                                    PropertyInt.EncumbVal,
                                    (uint)aPlayer.Session.Player.GameData.Burden));

                            var motion = new UniversalMotion(MotionStance.Standing);
                            motion.MovementData.ForwardCommand = (ushort)MotionCommand.Pickup;
                            aPlayer.Session.Network.EnqueueSend(
                                new GameMessageUpdateMotion(aPlayer, aPlayer.Session, motion),
                                new GameMessageUpdateInstanceId(inventoryId, targetContainer));

                            motion = new UniversalMotion(MotionStance.Standing);
                            aPlayer.Session.Network.EnqueueSend(
                                new GameMessageUpdateMotion(aPlayer, aPlayer.Session, motion),
                                new GameMessagePutObjectIn3d(aPlayer.Session, aPlayer, inventoryId),
                                new GameMessageSound(aPlayer.Guid, Sound.DropItem, (float)1.0),
                                new GameMessageUpdateInstanceId(inventoryId, targetContainer));

                            // This is the sequence magic - adds back into 3d space seem to be treated like teleport.
                            inventoryItem.Sequences.GetNextSequence(SequenceType.ObjectTeleport);
                            inventoryItem.Sequences.GetNextSequence(SequenceType.ObjectVector);
                            LandblockManager.AddObject(inventoryItem);

                            // This may not be needed when we fix landblock update object -
                            // TODO: Og II - check this later to see if it is still required.
                            aPlayer.Session.Network.EnqueueSend(new GameMessageUpdateObject(inventoryItem));

                            aPlayer.Session.Network.EnqueueSend(new GameMessageUpdatePosition(inventoryItem));
                        }
                    }
                }
                break;
            }

            case GameActionType.MovementEvent:
            {
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                var motion = action.Motion;
                HandleMovementEvent(obj, motion);
                break;
            }

            case GameActionType.ObjectCreate:
            {
                this.AddWorldObject(action.WorldObject);
                break;
            }

            case GameActionType.ObjectDelete:
            {
                this.RemoveWorldObject(action.WorldObject.Guid, false);
                break;
            }

            case GameActionType.QueryHealth:
            {
                if (action.ObjectId == 0)
                {
                    // Deselect the formerly selected Target
                    player.SelectedTarget = 0;
                    break;
                }

                object target   = null;
                var    targetId = new ObjectGuid(action.ObjectId);

                // Remember the selected Target
                player.SelectedTarget = action.ObjectId;

                // TODO: once items are implemented check if there are items that can trigger
                //       the QueryHealth event. So far I believe it only gets triggered for players and creatures
                if (targetId.IsPlayer() || targetId.IsCreature())
                {
                    if (this.worldObjects.ContainsKey(targetId))
                    {
                        target = this.worldObjects[targetId];
                    }

                    if (target == null)
                    {
                        // check adjacent landblocks for the targetId
                        foreach (var block in adjacencies)
                        {
                            if (block.Value != null)
                            {
                                if (block.Value.worldObjects.ContainsKey(targetId))
                                {
                                    target = block.Value.worldObjects[targetId];
                                }
                            }
                        }
                    }
                    if (target != null)
                    {
                        float healthPercentage = 0;

                        if (targetId.IsPlayer())
                        {
                            Player tmpTarget = (Player)target;
                            healthPercentage = (float)tmpTarget.Health.Current / (float)tmpTarget.Health.MaxValue;
                        }
                        if (targetId.IsCreature())
                        {
                            Creature tmpTarget = (Creature)target;
                            healthPercentage = (float)tmpTarget.Health.Current / (float)tmpTarget.Health.MaxValue;
                        }
                        var updateHealth = new GameEventUpdateHealth(player.Session, targetId.Full, healthPercentage);
                        player.Session.Network.EnqueueSend(updateHealth);
                    }
                }

                break;
            }

            case GameActionType.Use:
            {
                var g = new ObjectGuid(action.ObjectId);
                if (worldObjects.ContainsKey(g))
                {
                    WorldObject obj = worldObjects[g];

                    switch (obj.Type)
                    {
                    case Enum.ObjectType.Portal:
                    {
                        // TODO: When Physics collisions are implemented, this logic should be switched there, as normal portals are not onUse.

                        (obj as Portal).OnCollide(player);

                        break;
                    }

                    case Enum.ObjectType.LifeStone:
                    {
                        (obj as Lifestone).OnUse(player);
                        break;
                    }
                    }
                }
                break;
            }
            }
        }
예제 #12
0
파일: EmoteManager.cs 프로젝트: Zegeger/ACE
        public void ExecuteEmote(BiotaPropertiesEmote emote, BiotaPropertiesEmoteAction emoteAction, ActionChain actionChain, WorldObject sourceObject = null, WorldObject targetObject = null)
        {
            var player         = targetObject as Player;
            var creature       = sourceObject as Creature;
            var targetCreature = targetObject as Creature;

            var emoteType = (EmoteType)emoteAction.Type;

            //if (emoteType != EmoteType.Motion && emoteType != EmoteType.Turn && emoteType != EmoteType.Move)
            //Console.WriteLine($"ExecuteEmote({emoteType})");

            var text = emoteAction.Message;

            switch ((EmoteType)emoteAction.Type)
            {
            case EmoteType.Act:
                // short for 'acting' text
                var message = Replace(text, sourceObject, targetObject);
                sourceObject?.EnqueueBroadcast(new GameMessageSystemChat(message, ChatMessageType.Broadcast));
                break;

            case EmoteType.Activate:
                actionChain.AddDelaySeconds(emoteAction.Delay);
                actionChain.AddAction(sourceObject, () =>
                {
                    if (creature != null && (creature.ActivationTarget ?? 0) > 0)
                    {
                        var activationTarget = creature.CurrentLandblock?.GetObject(creature.ActivationTarget ?? 0);
                        activationTarget?.ActOnUse(creature);
                    }
                });
                break;

            case EmoteType.AddCharacterTitle:

                // emoteAction.Stat == null for all EmoteType.AddCharacterTitle entries in current db?
                if (player != null)
                {
                    player.AddTitle((CharacterTitle)emoteAction.Stat);
                }
                break;

            case EmoteType.AddContract:

                //if (player != null)
                //Contracts werent in emote table
                //player.AddContract(emoteAction.Stat);
                break;

            case EmoteType.AdminSpam:

                var players = WorldManager.GetAll();
                foreach (var onlinePlayer in players)
                {
                    onlinePlayer.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.AdminTell));
                }
                break;

            case EmoteType.AwardLevelProportionalSkillXP:

                if (player != null)
                {
                    player.GrantLevelProportionalSkillXP((Skill)emoteAction.Stat, emoteAction.Percent ?? 0, (ulong)emoteAction.Max);
                }
                break;

            case EmoteType.AwardLevelProportionalXP:

                if (player != null)
                {
                    player.GrantLevelProportionalXp(emoteAction.Percent ?? 0, (ulong)emoteAction.Max);
                }
                break;

            case EmoteType.AwardLuminance:

                if (player != null)
                {
                    player.GrantLuminance((long)emoteAction.Amount);
                }
                break;

            case EmoteType.AwardNoShareXP:

                actionChain.AddDelaySeconds(emoteAction.Delay);
                actionChain.AddAction(sourceObject, () =>
                {
                    if (player != null)
                    {
                        player.EarnXP((long)emoteAction.Amount64);
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat("You've earned " + emoteAction.Amount64 + " experience.", ChatMessageType.Broadcast));
                    }
                });
                break;

            case EmoteType.AwardSkillPoints:

                if (player != null)
                {
                    player.AwardSkillPoints((Skill)emoteAction.Stat, (uint)emoteAction.Amount, true);
                }
                break;

            case EmoteType.AwardSkillXP:

                if (player != null)
                {
                    player.RaiseSkillGameAction((Skill)emoteAction.Stat, (uint)emoteAction.Amount, true);
                }
                break;

            case EmoteType.AwardTrainingCredits:

                if (player != null)
                {
                    player.AddSkillCredits((int)emoteAction.Amount, true);
                }
                break;

            case EmoteType.AwardXP:

                actionChain.AddDelaySeconds(emoteAction.Delay);
                actionChain.AddAction(sourceObject, () =>
                {
                    if (player != null)
                    {
                        player.EarnXP((long)emoteAction.Amount64);
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat("You've earned " + emoteAction.Amount64 + " experience.", ChatMessageType.Broadcast));
                    }
                });
                break;

            case EmoteType.BLog:
                // only one test drudge used this emoteAction.
                break;

            case EmoteType.CastSpell:

                if (WorldObject is Player)
                {
                    (WorldObject as Player).CreatePlayerSpell((uint)emoteAction.SpellId);
                }

                else if (WorldObject is Creature)
                {
                    (WorldObject as Creature).CreateCreatureSpell(player.Guid, (uint)emoteAction.SpellId);
                }

                break;

            case EmoteType.CastSpellInstant:

                var spellTable = DatManager.PortalDat.SpellTable;
                var spell      = spellTable.Spells[(uint)emoteAction.SpellId];
                actionChain.AddAction(sourceObject, () =>
                {
                    if (spell.TargetEffect > 0)
                    {
                        creature.CreateCreatureSpell(targetObject.Guid, (uint)emoteAction.SpellId);
                    }
                    else
                    {
                        creature.CreateCreatureSpell((uint)emoteAction.SpellId);
                    }
                });
                break;

            case EmoteType.CloseMe:
                targetObject.Close(WorldObject);
                break;

            case EmoteType.CreateTreasure:
                break;

            case EmoteType.DecrementIntStat:

                var id   = (PropertyInt)emoteAction.Stat;
                var prop = player.GetProperty(id);
                if (prop != null)
                {
                    player.SetProperty(id, prop.Value - 1);
                }
                break;

            case EmoteType.DecrementMyQuest:
                break;

            case EmoteType.DecrementQuest:
                // Used as part of the test drudge for events
                break;

            case EmoteType.DeleteSelf:
                sourceObject.CurrentLandblock?.RemoveWorldObject(sourceObject.Guid, false);
                break;

            case EmoteType.DirectBroadcast:
                text = Replace(emoteAction.Message, WorldObject, targetObject);
                if (player != null)
                {
                    player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Broadcast));
                }
                break;

            case EmoteType.EraseMyQuest:
                break;

            case EmoteType.EraseQuest:

                if (player != null)
                {
                    player.QuestManager.Erase(emoteAction.Message);
                }
                break;

            case EmoteType.FellowBroadcast:

                text = emoteAction.Message;
                if (player != null)
                {
                    var fellowship = player.Fellowship;
                    if (fellowship == null)
                    {
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Broadcast));
                    }
                    else
                    {
                        foreach (var fellow in fellowship.FellowshipMembers)
                        {
                            fellow.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Broadcast));
                        }
                    }
                }
                break;

            case EmoteType.Generate:

                uint wcid = (uint)emoteAction.WeenieClassId;
                var  item = WorldObjectFactory.CreateNewWorldObject((wcid));
                break;

            case EmoteType.Give:

                bool success = false;
                if (player != null && emoteAction.WeenieClassId != null)
                {
                    actionChain.AddAction(sourceObject, () =>
                    {
                        item          = WorldObjectFactory.CreateNewWorldObject((uint)emoteAction.WeenieClassId);
                        var stackSize = emoteAction.StackSize ?? 1;
                        var stackMsg  = "";
                        if (stackSize > 1)
                        {
                            item.StackSize = (ushort)stackSize;
                            stackMsg       = stackSize + " ";   // pluralize?
                        }
                        success = player.TryCreateInInventoryWithNetworking(item);

                        // transaction / rollback on failure?
                        if (success)
                        {
                            var msg   = new GameMessageSystemChat($"{WorldObject.Name} gives you {stackMsg}{item.Name}.", ChatMessageType.Broadcast);
                            var sound = new GameMessageSound(player.Guid, Sound.ReceiveItem, 1);
                            player.Session.Network.EnqueueSend(msg, sound);
                        }
                    });
                }
                break;

            case EmoteType.Goto:

                var rng        = Physics.Common.Random.RollDice(0.0f, 1.0f);
                var firstEmote = sourceObject.Biota.BiotaPropertiesEmote.FirstOrDefault(e => e.Category == (uint)EmoteCategory.GotoSet && rng < e.Probability);
                foreach (var action in firstEmote.BiotaPropertiesEmoteAction)
                {
                    actionChain.AddAction(player, () =>
                    {
                        ExecuteEmote(firstEmote, action, actionChain, sourceObject, targetObject);
                    });
                }
                break;

            case EmoteType.IncrementIntStat:

                if (player == null || emoteAction.Stat == null)
                {
                    break;
                }

                id   = (PropertyInt)emoteAction.Stat;
                prop = player.GetProperty(id);
                if (prop != null)
                {
                    player.SetProperty(id, prop.Value + 1);
                }
                break;

            case EmoteType.IncrementMyQuest:
                break;

            case EmoteType.IncrementQuest:

                if (player != null)
                {
                    player.QuestManager.Increment(emoteAction.Message);
                }
                break;

            case EmoteType.InflictVitaePenalty:
                if (player != null)
                {
                    player.VitaeCpPool++;                       // TODO: full path
                }
                break;

            case EmoteType.InqAttributeStat:

                if (targetCreature != null)
                {
                    var attr = targetCreature.GetCreatureAttribute((PropertyAttribute)emoteAction.Stat);
                    success = attr != null && attr.Ranks >= emoteAction.Min && attr.Ranks <= emoteAction.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqBoolStat:
                // This is only used with NPC's 24944 and 6386, which are dev tester npc's. Not worth the current effort.
                // Could also be post-ToD
                break;

            case EmoteType.InqContractsFull:
                // not part of the game at PY16?
                //if (player != null)
                //{
                //    var contracts = player.TrackedContracts;
                //    InqCategory(contracts.Count != 0 ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                //}
                break;

            case EmoteType.InqEvent:

                var started = EventManager.IsEventStarted(emoteAction.Message);
                InqCategory(started ? EmoteCategory.EventSuccess : EmoteCategory.EventFailure, emoteAction, sourceObject, targetObject, actionChain);
                break;

            case EmoteType.InqFellowNum:
                InqCategory(player != null && player.Fellowship != null ? EmoteCategory.TestSuccess : EmoteCategory.TestNoFellow, emoteAction, sourceObject, targetObject, actionChain);
                break;

            case EmoteType.InqFellowQuest:
                // focusing on 1 person quests to begin with
                break;

            case EmoteType.InqFloatStat:
                //InqProperty(target.GetProperty((PropertyFloat)emote.Stat), emote);
                break;

            case EmoteType.InqInt64Stat:
                //InqProperty(target.GetProperty((PropertyInt64)emote.Stat), emote);
                break;

            case EmoteType.InqIntStat:

                if (emoteAction.Stat != 25)
                {
                    break;                              // ??
                }
                success = player.Level >= emoteAction.Min && player.Level <= emoteAction.Max;

                // rng for failure case?
                var useRNG = !success;

                InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emoteAction, sourceObject, targetObject, actionChain, useRNG);
                break;

            case EmoteType.InqMyQuest:
                break;

            case EmoteType.InqMyQuestBitsOff:
                break;

            case EmoteType.InqMyQuestBitsOn:
                break;

            case EmoteType.InqMyQuestSolves:
                break;

            case EmoteType.InqNumCharacterTitles:

                //if (player != null)
                //InqCategory(player.NumCharacterTitles != 0 ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                break;

            case EmoteType.InqOwnsItems:

                //if (player != null)
                //InqCategory(player.Inventory.Count > 0 ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                break;

            case EmoteType.InqPackSpace:

                //if (player != null)
                //{
                //    var freeSpace = player.ContainerCapacity > player.ItemCapacity;
                //    InqCategory(freeSpace ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                //}
                break;

            case EmoteType.InqQuest:

                if (player != null)
                {
                    var hasQuest = player.QuestManager.HasQuest(emoteAction.Message);
                    InqCategory(hasQuest ? EmoteCategory.QuestSuccess : EmoteCategory.QuestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqQuestBitsOff:
                break;

            case EmoteType.InqQuestBitsOn:
                break;

            case EmoteType.InqQuestSolves:

                // should this be different from InqQuest?
                if (player != null)
                {
                    var hasQuest = player.QuestManager.HasQuest(emoteAction.Message);
                    InqCategory(hasQuest ? EmoteCategory.QuestSuccess : EmoteCategory.QuestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqRawAttributeStat:

                if (targetCreature != null)
                {
                    var attr = targetCreature.GetCreatureAttribute((PropertyAttribute)emoteAction.Stat);
                    success = attr != null && attr.Base >= emoteAction.Min && attr.Base <= emoteAction.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqRawSecondaryAttributeStat:

                if (targetCreature != null)
                {
                    var vital = targetCreature.GetCreatureVital((PropertyAttribute2nd)emoteAction.Stat);
                    success = vital != null && vital.Base >= emoteAction.Min && vital.Base <= emoteAction.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqRawSkillStat:

                if (targetCreature != null)
                {
                    var skill = targetCreature.GetCreatureSkill((Skill)emoteAction.Stat);
                    success = skill != null && skill.Base >= emoteAction.Min && skill.Base <= emoteAction.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqSecondaryAttributeStat:

                if (targetCreature != null)
                {
                    var vital = targetCreature.GetCreatureVital((PropertyAttribute2nd)emoteAction.Stat);
                    success = vital != null && vital.Ranks >= emoteAction.Min && vital.Ranks <= emoteAction.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqSkillSpecialized:

                if (targetCreature != null)
                {
                    var skill = targetCreature.GetCreatureSkill((Skill)emoteAction.Stat);
                    //InqProperty(skill.Status == SkillStatus.Specialized, emoteAction);
                }
                break;

            case EmoteType.InqSkillStat:

                if (targetCreature != null)
                {
                    var skill = targetCreature.GetCreatureSkill((Skill)emoteAction.Stat);
                    success = skill != null && skill.Ranks >= emoteAction.Min && skill.Ranks <= emoteAction.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqSkillTrained:

                if (targetCreature != null)
                {
                    var skill = targetCreature.GetCreatureSkill((Skill)emoteAction.Stat);
                    // TestNoQuality?
                    InqProperty(skill.AdvancementClass == SkillAdvancementClass.Trained || skill.AdvancementClass == SkillAdvancementClass.Specialized, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.InqStringStat:

                //InqProperty(targetCreature.GetProperty((PropertyString)emoteAction.Stat), emote);
                break;

            case EmoteType.InqYesNo:
                ConfirmationManager.ProcessConfirmation((uint)emoteAction.Stat, true);
                break;

            case EmoteType.Invalid:
                break;

            case EmoteType.KillSelf:

                if (targetCreature != null)
                {
                    targetCreature.Smite(targetCreature);
                }
                break;

            case EmoteType.LocalBroadcast:
                if (actionChain != null)
                {
                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    actionChain.AddAction(sourceObject, () =>
                    {
                        sourceObject?.EnqueueBroadcast(new GameMessageCreatureMessage(emoteAction.Message, sourceObject.Name, sourceObject.Guid.Full, ChatMessageType.Broadcast));
                    });
                }
                else
                {
                    sourceObject.EnqueueBroadcast(new GameMessageCreatureMessage(emoteAction.Message, sourceObject.Name, sourceObject.Guid.Full, ChatMessageType.Broadcast));
                }
                break;

            case EmoteType.LocalSignal:
                break;

            case EmoteType.LockFellow:

                if (player != null && player.Fellowship != null)
                {
                    player.HandleActionFellowshipChangeOpenness(false);
                }

                break;

            case EmoteType.ForceMotion:     // TODO: figure out the difference
            case EmoteType.Motion:

                if (sourceObject == null || sourceObject.CurrentMotionState == null)
                {
                    break;
                }

                if (emote.Category != (uint)EmoteCategory.Vendor && emote.Style != null)
                {
                    var startingMotion = new UniversalMotion((MotionStance)emote.Style, new MotionItem((MotionCommand)emote.Substyle));
                    var motion         = new UniversalMotion((MotionStance)emote.Style, new MotionItem((MotionCommand)emoteAction.Motion, emoteAction.Extent));

                    if (sourceObject.CurrentMotionState.Stance != startingMotion.Stance)
                    {
                        if (sourceObject.CurrentMotionState.Stance == MotionStance.Invalid)
                        {
                            actionChain.AddDelaySeconds(emoteAction.Delay);
                            actionChain.AddAction(sourceObject, () =>
                            {
                                sourceObject.DoMotion(startingMotion);
                                sourceObject.CurrentMotionState = startingMotion;
                            });
                        }
                    }
                    else
                    {
                        if (sourceObject.CurrentMotionState.Commands.Count > 0 && sourceObject.CurrentMotionState.Commands[0].Motion == startingMotion.Commands[0].Motion)
                        {
                            actionChain.AddDelaySeconds(emoteAction.Delay);
                            actionChain.AddAction(sourceObject, () =>
                            {
                                sourceObject.DoMotion(motion);
                                sourceObject.CurrentMotionState = motion;
                            });
                            actionChain.AddDelaySeconds(DatManager.PortalDat.ReadFromDat <DatLoader.FileTypes.MotionTable>(sourceObject.MotionTableId).GetAnimationLength((MotionCommand)emoteAction.Motion));
                            if (motion.Commands[0].Motion != MotionCommand.Sleeping && motion.Commands[0].Motion != MotionCommand.Sitting)     // this feels like it can be handled better, somehow?
                            {
                                actionChain.AddAction(sourceObject, () =>
                                {
                                    sourceObject.DoMotion(startingMotion);
                                    sourceObject.CurrentMotionState = startingMotion;
                                });
                            }
                        }
                    }
                }
                else
                {
                    var motion = new UniversalMotion(MotionStance.Standing, new MotionItem((MotionCommand)emoteAction.Motion, emoteAction.Extent));

                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    actionChain.AddAction(sourceObject, () =>
                    {
                        sourceObject.DoMotion(motion);
                        sourceObject.CurrentMotionState = motion;
                    });
                }

                break;

            case EmoteType.Move:

                // what is the difference between this and MoveToPos?
                // using MoveToPos logic for now...
                if (targetCreature != null)
                {
                    var currentPos = targetCreature.Location;

                    var newPos = new Position();
                    newPos.LandblockId = new LandblockId(currentPos.LandblockId.Raw);
                    newPos.Pos         = new Vector3(emoteAction.OriginX ?? currentPos.Pos.X, emoteAction.OriginY ?? currentPos.Pos.Y, emoteAction.OriginZ ?? currentPos.Pos.Z);

                    if (emoteAction.AnglesX == null || emoteAction.AnglesY == null || emoteAction.AnglesZ == null || emoteAction.AnglesW == null)
                    {
                        newPos.Rotation = new Quaternion(currentPos.Rotation.X, currentPos.Rotation.Y, currentPos.Rotation.Z, currentPos.Rotation.W);
                    }
                    else
                    {
                        newPos.Rotation = new Quaternion(emoteAction.AnglesX ?? 0, emoteAction.AnglesY ?? 0, emoteAction.AnglesZ ?? 0, emoteAction.AnglesW ?? 1);
                    }

                    if (emoteAction.ObjCellId != null)
                    {
                        newPos.LandblockId = new LandblockId(emoteAction.ObjCellId.Value);
                    }

                    targetCreature.MoveTo(newPos, targetCreature.GetRunRate());
                }
                break;

            case EmoteType.MoveHome:

                // TODO: call MoveToManager on server
                if (targetCreature != null)
                {
                    targetCreature.MoveTo(targetCreature.Home, targetCreature.GetRunRate());
                }
                break;

            case EmoteType.MoveToPos:

                if (targetCreature != null)
                {
                    var currentPos = targetCreature.Location;

                    var newPos = new Position();
                    newPos.LandblockId = new LandblockId(currentPos.LandblockId.Raw);
                    newPos.Pos         = new Vector3(emoteAction.OriginX ?? currentPos.Pos.X, emoteAction.OriginY ?? currentPos.Pos.Y, emoteAction.OriginZ ?? currentPos.Pos.Z);

                    if (emoteAction.AnglesX == null || emoteAction.AnglesY == null || emoteAction.AnglesZ == null || emoteAction.AnglesW == null)
                    {
                        newPos.Rotation = new Quaternion(currentPos.Rotation.X, currentPos.Rotation.Y, currentPos.Rotation.Z, currentPos.Rotation.W);
                    }
                    else
                    {
                        newPos.Rotation = new Quaternion(emoteAction.AnglesX ?? 0, emoteAction.AnglesY ?? 0, emoteAction.AnglesZ ?? 0, emoteAction.AnglesW ?? 1);
                    }

                    if (emoteAction.ObjCellId != null)
                    {
                        newPos.LandblockId = new LandblockId(emoteAction.ObjCellId.Value);
                    }

                    targetCreature.MoveTo(newPos, targetCreature.GetRunRate());
                }
                break;

            case EmoteType.OpenMe:

                sourceObject.Open(sourceObject);
                break;

            case EmoteType.PetCastSpellOnOwner:

                if (creature != null)
                {
                    creature.CreateCreatureSpell(targetObject.Guid, (uint)emoteAction.SpellId);
                }
                break;

            case EmoteType.PhysScript:

                // TODO: landblock broadcast
                if (sourceObject != null)
                {
                    sourceObject.PhysicsObj.play_script((PlayScript)emoteAction.PScript, 1.0f);
                }
                break;

            case EmoteType.PopUp:
                if (player != null)
                {
                    if ((ConfirmationType)emoteAction.Stat == ConfirmationType.Undefined)
                    {
                        player.Session.Network.EnqueueSend(new GameEventPopupString(player.Session, emoteAction.Message));
                    }
                    else
                    {
                        Confirmation confirm = new Confirmation((ConfirmationType)emoteAction.Stat, emoteAction.Message, sourceObject.Guid.Full, targetObject.Guid.Full);
                        ConfirmationManager.AddConfirmation(confirm);
                        player.Session.Network.EnqueueSend(new GameEventConfirmationRequest(player.Session, (ConfirmationType)emoteAction.Stat, confirm.ConfirmationID, confirm.Message));
                    }
                }
                break;

            case EmoteType.RemoveContract:

                if (player != null)
                {
                    player.HandleActionAbandonContract((uint)emoteAction.Stat);
                }
                break;

            case EmoteType.RemoveVitaePenalty:

                if (player != null)
                {
                    player.VitaeCpPool = 0;                         // TODO: call full path
                }
                break;

            case EmoteType.ResetHomePosition:

                //creature = sourceObject as Creature;
                //if (creature != null)
                //    creature.Home = emoteAction.Position;
                break;

            case EmoteType.Say:

                actionChain.AddDelaySeconds(emoteAction.Delay);
                actionChain.AddAction(sourceObject, () =>
                {
                    sourceObject?.EnqueueBroadcast(new GameMessageCreatureMessage(emoteAction.Message, sourceObject.Name, sourceObject.Guid.Full, ChatMessageType.Emote));
                });
                break;

            case EmoteType.SetAltRacialSkills:
                break;

            case EmoteType.SetBoolStat:
                targetObject.SetProperty((PropertyBool)emoteAction.Stat, emoteAction.Amount == 0 ? false : true);
                break;

            case EmoteType.SetEyePalette:
                if (creature != null)
                {
                    creature.EyesPaletteDID = (uint)emoteAction.Display;
                }
                break;

            case EmoteType.SetEyeTexture:
                if (creature != null)
                {
                    creature.EyesTextureDID = (uint)emoteAction.Display;
                }
                break;

            case EmoteType.SetFloatStat:
                targetObject.SetProperty((PropertyFloat)emoteAction.Stat, (float)emoteAction.Amount);
                break;

            case EmoteType.SetHeadObject:
                if (creature != null)
                {
                    creature.HeadObjectDID = (uint)emoteAction.Display;
                }
                break;

            case EmoteType.SetHeadPalette:
                break;

            case EmoteType.SetInt64Stat:
                player.SetProperty((PropertyInt)emoteAction.Stat, (int)emoteAction.Amount);
                break;

            case EmoteType.SetIntStat:
                player.SetProperty((PropertyInt)emoteAction.Stat, (int)emoteAction.Amount);
                break;

            case EmoteType.SetMouthPalette:
                break;

            case EmoteType.SetMouthTexture:
                creature = sourceObject as Creature;
                if (creature != null)
                {
                    creature.MouthTextureDID = (uint)emoteAction.Display;
                }
                break;

            case EmoteType.SetMyQuestBitsOff:
                break;

            case EmoteType.SetMyQuestBitsOn:
                break;

            case EmoteType.SetMyQuestCompletions:
                break;

            case EmoteType.SetNosePalette:
                break;

            case EmoteType.SetNoseTexture:
                creature = sourceObject as Creature;
                if (creature != null)
                {
                    creature.NoseTextureDID = (uint)emoteAction.Display;
                }
                break;

            case EmoteType.SetQuestBitsOff:
                break;

            case EmoteType.SetQuestBitsOn:
                break;

            case EmoteType.SetQuestCompletions:
                break;

            case EmoteType.SetSanctuaryPosition:

                //if (player != null)
                //player.Sanctuary = emote.Position;
                break;

            case EmoteType.Sound:
                targetObject.CurrentLandblock?.EnqueueBroadcastSound(targetObject, (Sound)emoteAction.Sound);
                break;

            case EmoteType.SpendLuminance:
                if (player != null)
                {
                    player.SpendLuminance((long)emoteAction.Amount);
                }
                break;

            case EmoteType.StampFellowQuest:
                break;

            case EmoteType.StampMyQuest:
                break;

            case EmoteType.StampQuest:

                // work needs to be done here
                if (player != null)
                {
                    player.QuestManager.Add(emoteAction.Message);
                }
                break;

            case EmoteType.StartBarber:
                break;

            case EmoteType.StartEvent:

                EventManager.StartEvent(emoteAction.Message);
                break;

            case EmoteType.StopEvent:

                EventManager.StopEvent(emoteAction.Message);
                break;

            case EmoteType.TakeItems:

                if (player != null && emoteAction.WeenieClassId != null)
                {
                    item = WorldObjectFactory.CreateNewWorldObject((uint)emoteAction.WeenieClassId);
                    if (item == null)
                    {
                        break;
                    }

                    success = player.TryRemoveItemFromInventoryWithNetworking(item, (ushort)emoteAction.Amount);
                }
                break;

            case EmoteType.TeachSpell:

                if (player != null)
                {
                    player.LearnSpellWithNetworking((uint)emoteAction.SpellId);
                }
                break;

            case EmoteType.TeleportSelf:

                //if (WorldObject is Player)
                //(WorldObject as Player).Teleport(emote.Position);
                break;

            case EmoteType.TeleportTarget:

                //if (player != null)
                //player.Teleport(emote.Position);
                break;

            case EmoteType.Tell:
                actionChain.AddDelaySeconds(emoteAction.Delay);
                actionChain.AddAction(sourceObject, () =>
                {
                    player.Session.Network.EnqueueSend(new GameMessageHearDirectSpeech(sourceObject, emoteAction.Message, player, ChatMessageType.Tell));
                });
                break;

            case EmoteType.TellFellow:

                text = emoteAction.Message;
                if (player != null)
                {
                    var fellowship = player.Fellowship;
                    if (fellowship == null)
                    {
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Tell));
                    }
                    else
                    {
                        foreach (var fellow in fellowship.FellowshipMembers)
                        {
                            fellow.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Tell));
                        }
                    }
                }
                break;

            case EmoteType.TextDirect:

                if (player != null)
                {
                    // should these delays be moved to 1 place??
                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    text = emoteAction.Message;         // no known instances of replace tokens in current text, but could be added in future
                    actionChain.AddAction(player, () =>
                    {
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Broadcast));
                    });
                }
                break;

            case EmoteType.Turn:

                if (creature != null)
                {
                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    var pos = new Position(creature.Location.Cell, creature.Location.PositionX, creature.Location.PositionY, creature.Location.PositionZ, emoteAction.AnglesX ?? 0, emoteAction.AnglesY ?? 0, emoteAction.AnglesZ ?? 0, emoteAction.AnglesW ?? 0);
                    actionChain.AddAction(creature, () =>
                    {
                        creature.TurnTo(pos);
                    });
                    var rotateTime = creature.GetRotateDelay(pos);
                    actionChain.AddDelaySeconds(rotateTime);
                }
                break;

            case EmoteType.TurnToTarget:

                if (creature != null && targetCreature != null)
                {
                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    actionChain.AddAction(creature, () =>
                    {
                        creature.Rotate(targetCreature);
                    });
                    var rotateTime = creature.GetRotateDelay(targetCreature);
                    actionChain.AddDelaySeconds(rotateTime);
                }
                break;

            case EmoteType.UntrainSkill:

                if (player != null)
                {
                    player.UntrainSkill((Skill)emoteAction.Stat, 1);
                }
                break;

            case EmoteType.UpdateFellowQuest:
                break;

            case EmoteType.UpdateMyQuest:
                break;

            case EmoteType.UpdateQuest:

                // only delay seems to be with test NPC here
                // still, unsafe to use any emotes directly outside of a chain,
                // as they could be executed out-of-order
                if (player != null)
                {
                    var questName = emoteAction.Message;
                    player.QuestManager.Add(questName);
                    var hasQuest = player.QuestManager.HasQuest(questName);
                    InqCategory(hasQuest ? EmoteCategory.QuestSuccess : EmoteCategory.QuestFailure, emoteAction, sourceObject, targetObject, actionChain);
                }
                break;

            case EmoteType.WorldBroadcast:
                if (player != null)
                {
                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    actionChain.AddAction(sourceObject, () =>
                    {
                        player.Session.Network.EnqueueSend(new GameMessageHearDirectSpeech(sourceObject, emoteAction.Message, player, ChatMessageType.WorldBroadcast));
                    });
                }
                break;

            default:
                log.Debug($"EmoteManager.Execute - Encountered Unhandled EmoteType {(EmoteType)emoteAction.Type} for {sourceObject.Name} ({sourceObject.WeenieClassId})");
                break;
            }
        }
예제 #13
0
        public void ExecuteEmote(BiotaPropertiesEmote emote, BiotaPropertiesEmoteAction emoteAction, ActionChain actionChain, WorldObject sourceObject = null, WorldObject targetObject = null)
        {
            var player = targetObject as Player;

            switch ((EmoteType)emoteAction.Type)
            {
            case EmoteType.Say:

                actionChain.AddDelaySeconds(emoteAction.Delay);
                actionChain.AddAction(sourceObject, () =>
                {
                    sourceObject.CurrentLandblock.EnqueueBroadcast(sourceObject.Location, new GameMessageCreatureMessage(emoteAction.Message, sourceObject.Name, sourceObject.Guid.Full, ChatMessageType.Emote));
                });
                break;

            case EmoteType.Motion:

                if (emote.Category != (uint)EmoteCategory.Vendor && emote.Style != null)
                {
                    var startingMotion = new UniversalMotion((MotionStance)emote.Style, new MotionItem((MotionCommand)emote.Substyle));
                    var motion         = new UniversalMotion((MotionStance)emote.Style, new MotionItem((MotionCommand)emoteAction.Motion, emoteAction.Extent));

                    if (sourceObject.CurrentMotionState.Stance != startingMotion.Stance)
                    {
                        if (sourceObject.CurrentMotionState.Stance == MotionStance.Invalid)
                        {
                            actionChain.AddDelaySeconds(emoteAction.Delay);
                            actionChain.AddAction(sourceObject, () =>
                            {
                                sourceObject.DoMotion(startingMotion);
                                sourceObject.CurrentMotionState = startingMotion;
                            });
                        }
                    }
                    else
                    {
                        if (sourceObject.CurrentMotionState.Commands.Count > 0 && sourceObject.CurrentMotionState.Commands[0].Motion == startingMotion.Commands[0].Motion)
                        {
                            actionChain.AddDelaySeconds(emoteAction.Delay);
                            actionChain.AddAction(sourceObject, () =>
                            {
                                sourceObject.DoMotion(motion);
                                sourceObject.CurrentMotionState = motion;
                            });
                            actionChain.AddDelaySeconds(DatManager.PortalDat.ReadFromDat <DatLoader.FileTypes.MotionTable>(sourceObject.MotionTableId).GetAnimationLength((MotionCommand)emoteAction.Motion));
                            if (motion.Commands[0].Motion != MotionCommand.Sleeping && motion.Commands[0].Motion != MotionCommand.Sitting)     // this feels like it can be handled better, somehow?
                            {
                                actionChain.AddAction(sourceObject, () =>
                                {
                                    sourceObject.DoMotion(startingMotion);
                                    sourceObject.CurrentMotionState = startingMotion;
                                });
                            }
                        }
                    }
                }
                else
                {
                    var motion = new UniversalMotion(MotionStance.Standing, new MotionItem((MotionCommand)emoteAction.Motion, emoteAction.Extent));

                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    actionChain.AddAction(sourceObject, () =>
                    {
                        sourceObject.DoMotion(motion);
                        sourceObject.CurrentMotionState = motion;
                    });
                }

                break;

            case EmoteType.Tell:
                actionChain.AddDelaySeconds(emoteAction.Delay);
                actionChain.AddAction(sourceObject, () =>
                {
                    player.Session.Network.EnqueueSend(new GameMessageHearDirectSpeech(sourceObject, emoteAction.Message, player, ChatMessageType.Tell));
                });
                break;

            case EmoteType.TurnToTarget:
                var creature = sourceObject is Creature ? (Creature)sourceObject : null;
                actionChain.AddDelaySeconds(creature.Rotate(player));
                break;

            case EmoteType.AwardXP:
                actionChain.AddAction(sourceObject, () =>
                {
                    if (player != null)
                    {
                        player.EarnXP((long)emoteAction.Amount64);
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat("You've earned " + emoteAction.Amount64 + " experience.", ChatMessageType.System));
                    }
                });
                break;

            case EmoteType.Give:
                actionChain.AddAction(sourceObject, () =>
                {
                    if (player != null)
                    {
                        uint weenie      = (uint)emoteAction.WeenieClassId;
                        WorldObject item = WorldObjectFactory.CreateNewWorldObject(weenie);
                        if (emoteAction.WeenieClassId != null)
                        {
                            if (emoteAction.StackSize > 1)
                            {
                                item.StackSize = (ushort)emoteAction.StackSize;
                                player.Session.Network.EnqueueSend(new GameMessageSystemChat(WorldObject.Name + " gives you " + emoteAction.StackSize + " " + item.Name + ".", ChatMessageType.System));
                            }
                            else
                            {
                                player.Session.Network.EnqueueSend(new GameMessageSystemChat(WorldObject.Name + " gives you " + item.Name + ".", ChatMessageType.System));
                            }
                            var success = player.TryCreateInInventoryWithNetworking(item);
                        }
                    }
                });
                break;

            case EmoteType.UpdateQuest:
                //This is for the quest NPC's. This will be filled out when quests are added.
                break;

            default:
                log.Debug($"EmoteManager.Execute - Encountered Unhandled EmoteType {(EmoteType)emoteAction.Type} for {sourceObject.Name} ({sourceObject.WeenieClassId})");
                break;
            }
        }
예제 #14
0
        public static void UseObjectOnTarget(Player player, WorldObject source, WorldObject target)
        {
            var recipe = DatabaseManager.World.GetCachedCookbook(source.WeenieClassId, target.WeenieClassId);

            if (recipe == null)
            {
                var message = new GameMessageSystemChat($"The {source.Name} cannot be used on the {target.Name}.", ChatMessageType.Craft);
                player.Session.Network.EnqueueSend(message);
                player.SendUseDoneEvent();
                return;
            }

            ActionChain   craftChain     = new ActionChain();
            CreatureSkill skill          = null;
            bool          skillSuccess   = true; // assume success, unless there's a skill check
            double        percentSuccess = 1;

            UniversalMotion motion = new UniversalMotion(MotionStance.NonCombat, new MotionItem(MotionCommand.ClapHands));

            craftChain.AddAction(player, () => player.EnqueueBroadcastMotion(motion));
            var motionTable          = DatManager.PortalDat.ReadFromDat <MotionTable>(player.MotionTableId);
            var craftAnimationLength = motionTable.GetAnimationLength(MotionCommand.ClapHands);

            craftChain.AddDelaySeconds(craftAnimationLength);

            craftChain.AddAction(player, () =>
            {
                if (recipe.Recipe.Skill > 0 && recipe.Recipe.Difficulty > 0)
                {
                    // there's a skill associated with this
                    Skill skillId = (Skill)recipe.Recipe.Skill;

                    // this shouldn't happen, but sanity check for unexpected nulls
                    skill = player.GetCreatureSkill(skillId);

                    if (skill == null)
                    {
                        log.Warn("Unexpectedly missing skill in Recipe usage");
                        player.SendUseDoneEvent();
                        return;
                    }

                    percentSuccess = skill.GetPercentSuccess(recipe.Recipe.Difficulty); //FIXME: Pretty certain this is broken
                }

                if (skill != null)
                {
                    if (skill.AdvancementClass == SkillAdvancementClass.Untrained)
                    {
                        var message = new GameEventWeenieError(player.Session, WeenieError.YouAreNotTrainedInThatTradeSkill);
                        player.Session.Network.EnqueueSend(message);
                        player.SendUseDoneEvent(WeenieError.YouAreNotTrainedInThatTradeSkill);
                        return;
                    }
                }

                // straight skill check, if applicable
                if (skill != null)
                {
                    skillSuccess = _random.NextDouble() < percentSuccess;
                }


                if (skillSuccess)
                {
                    bool destroyTarget = _random.NextDouble() < recipe.Recipe.SuccessDestroyTargetChance;
                    bool destroySource = _random.NextDouble() < recipe.Recipe.SuccessDestroySourceChance;

                    if (destroyTarget)
                    {
                        if (target.OwnerId == player.Guid.Full || player.GetInventoryItem(target.Guid) != null)
                        {
                            player.TryRemoveItemFromInventoryWithNetworking(target, (ushort)recipe.Recipe.SuccessDestroyTargetAmount);
                        }
                        else if (target.WielderId == player.Guid.Full)
                        {
                            if (!player.TryRemoveItemWithNetworking(target))
                            {
                                throw new Exception($"Failed to remove {target.Name} from player inventory.");
                            }
                        }
                        else
                        {
                            target.Destroy();
                        }

                        if (!String.IsNullOrEmpty(recipe.Recipe.SuccessDestroyTargetMessage))
                        {
                            var destroyMessage = new GameMessageSystemChat(recipe.Recipe.SuccessDestroyTargetMessage, ChatMessageType.Craft);
                            player.Session.Network.EnqueueSend(destroyMessage);
                        }
                    }

                    if (destroySource)
                    {
                        if (source.OwnerId == player.Guid.Full || player.GetInventoryItem(target.Guid) != null)
                        {
                            player.TryRemoveItemFromInventoryWithNetworking(source, (ushort)recipe.Recipe.SuccessDestroySourceAmount);
                        }
                        else if (source.WielderId == player.Guid.Full)
                        {
                            if (!player.TryRemoveItemWithNetworking(source))
                            {
                                throw new Exception($"Failed to remove {source.Name} from player inventory.");
                            }
                        }
                        else
                        {
                            source.Destroy();
                        }

                        if (!String.IsNullOrEmpty(recipe.Recipe.SuccessDestroySourceMessage))
                        {
                            var destroyMessage = new GameMessageSystemChat(recipe.Recipe.SuccessDestroySourceMessage, ChatMessageType.Craft);
                            player.Session.Network.EnqueueSend(destroyMessage);
                        }
                    }

                    if (recipe.Recipe.SuccessWCID > 0)
                    {
                        var wo = WorldObjectFactory.CreateNewWorldObject(recipe.Recipe.SuccessWCID);

                        if (wo != null)
                        {
                            if (recipe.Recipe.SuccessAmount > 1)
                            {
                                wo.StackSize = (ushort)recipe.Recipe.SuccessAmount;
                            }

                            player.TryCreateInInventoryWithNetworking(wo);
                        }
                    }

                    var message = new GameMessageSystemChat(recipe.Recipe.SuccessMessage, ChatMessageType.Craft);
                    player.Session.Network.EnqueueSend(message);
                }
                else
                {
                    bool destroyTarget = _random.NextDouble() < recipe.Recipe.FailDestroyTargetChance;
                    bool destroySource = _random.NextDouble() < recipe.Recipe.FailDestroySourceChance;

                    if (destroyTarget)
                    {
                        if (target.OwnerId == player.Guid.Full || player.GetInventoryItem(target.Guid) != null)
                        {
                            player.TryRemoveItemFromInventoryWithNetworking(target, (ushort)recipe.Recipe.FailDestroyTargetAmount);
                        }
                        else if (target.WielderId == player.Guid.Full)
                        {
                            if (!player.TryRemoveItemWithNetworking(target))
                            {
                                throw new Exception($"Failed to remove {target.Name} from player inventory.");
                            }
                        }
                        else
                        {
                            target.Destroy();
                        }

                        if (!String.IsNullOrEmpty(recipe.Recipe.FailDestroyTargetMessage))
                        {
                            var destroyMessage = new GameMessageSystemChat(recipe.Recipe.FailDestroyTargetMessage, ChatMessageType.Craft);
                            player.Session.Network.EnqueueSend(destroyMessage);
                        }
                    }

                    if (destroySource)
                    {
                        if (source.OwnerId == player.Guid.Full || player.GetInventoryItem(target.Guid) != null)
                        {
                            player.TryRemoveItemFromInventoryWithNetworking(source, (ushort)recipe.Recipe.FailDestroySourceAmount);
                        }
                        else if (source.WielderId == player.Guid.Full)
                        {
                            if (!player.TryRemoveItemWithNetworking(source))
                            {
                                throw new Exception($"Failed to remove {source.Name} from player inventory.");
                            }
                        }
                        else
                        {
                            source.Destroy();
                        }

                        if (!String.IsNullOrEmpty(recipe.Recipe.FailDestroySourceMessage))
                        {
                            var destroyMessage = new GameMessageSystemChat(recipe.Recipe.FailDestroySourceMessage, ChatMessageType.Craft);
                            player.Session.Network.EnqueueSend(destroyMessage);
                        }
                    }

                    if (recipe.Recipe.FailWCID > 0)
                    {
                        var wo = WorldObjectFactory.CreateNewWorldObject(recipe.Recipe.FailWCID);

                        if (wo != null)
                        {
                            if (recipe.Recipe.FailAmount > 1)
                            {
                                wo.StackSize = (ushort)recipe.Recipe.FailAmount;
                            }

                            player.TryCreateInInventoryWithNetworking(wo);
                        }
                    }

                    var message = new GameMessageSystemChat(recipe.Recipe.FailMessage, ChatMessageType.Craft);
                    player.Session.Network.EnqueueSend(message);
                }

                player.SendUseDoneEvent();
            });

            craftChain.EnqueueChain();
        }
예제 #15
0
        private static void HandleHealingRecipe(Player player, WorldObject source, WorldObject target, Recipe recipe)
        {
            ActionChain chain = new ActionChain();

            // skill will be null since the difficulty is calculated manually
            if (recipe.SkillId == null)
            {
                log.Warn($"healing recipe has null skill id (should almost certainly be healing, but who knows).  recipe id {recipe.RecipeGuid}.");
                player.SendUseDoneEvent();
                return;
            }

            if (!(target is Player))
            {
                var message = new GameMessageSystemChat($"The {source.Name} cannot be used on {target.Name}.", ChatMessageType.Craft);
                player.Session.Network.EnqueueSend(message);
                player.SendUseDoneEvent();
                return;
            }

            Player  targetPlayer = target as Player;
            Ability vital        = (Ability?)recipe.HealingAttribute ?? Ability.Health;

            // there's a skill associated with this
            Skill skillId = (Skill)recipe.SkillId.Value;

            // this shouldn't happen, but sanity check for unexpected nulls
            if (!player.Skills.ContainsKey(skillId))
            {
                log.Warn("Unexpectedly missing skill in Recipe usage");
                player.SendUseDoneEvent();
                return;
            }

            CreatureSkill skill = player.Skills[skillId];

            // at this point, we've validated that the target is a player, and the target is below max health

            if (target.Guid != player.Guid)
            {
                // TODO: validate range
            }

            MotionCommand cmd = MotionCommand.SkillHealSelf;

            if (target.Guid != player.Guid)
            {
                cmd = MotionCommand.Woah; // guess?  nothing else stood out
            }
            // everything pre-validatable is validated.  action will be attempted unless cancelled, so
            // queue up the animation and action
            UniversalMotion motion = new UniversalMotion(MotionStance.Standing, new MotionItem(cmd));

            chain.AddAction(player, () => player.HandleActionMotion(motion));
            chain.AddDelaySeconds(0.5);

            chain.AddAction(player, () =>
            {
                // TODO: revalidate range if other player (they could have moved)

                double difficulty = 2 * (targetPlayer.Vitals[vital].MaxValue - targetPlayer.Vitals[vital].Current);
                if (difficulty <= 0)
                {
                    // target is at max (or higher?) health, do nothing
                    var text = "You are already at full health.";

                    if (target.Guid != player.Guid)
                    {
                        text = $"{target.Name} is already at full health";
                    }

                    player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Craft));
                    player.SendUseDoneEvent();
                    return;
                }

                if (player.CombatMode != CombatMode.NonCombat && player.CombatMode != CombatMode.Undef)
                {
                    difficulty *= 1.1;
                }

                uint boost        = source.Boost ?? 0;
                double multiplier = source.HealkitMod ?? 1;

                double playerSkill = skill.ActiveValue + boost;
                if (skill.Status == SkillStatus.Trained)
                {
                    playerSkill *= 1.1;
                }
                else if (skill.Status == SkillStatus.Specialized)
                {
                    playerSkill *= 1.5;
                }

                // usage is inevitable at this point, consume the use
                if ((recipe.ResultFlags & (uint)RecipeResult.SourceItemUsesDecrement) > 0)
                {
                    if (source.Structure <= 1)
                    {
                        player.DestroyInventoryItem(source);
                    }
                    else
                    {
                        source.Structure--;
                        source.SendPartialUpdates(player.Session, _updateStructure);
                    }
                }

                double percentSuccess = CreatureSkill.GetPercentSuccess((uint)playerSkill, (uint)difficulty);

                if (_random.NextDouble() <= percentSuccess)
                {
                    string expertly = "";

                    if (_random.NextDouble() < 0.1d)
                    {
                        expertly    = "expertly ";
                        multiplier *= 1.2;
                    }

                    // calculate amount restored
                    uint maxRestore = targetPlayer.Vitals[vital].MaxValue - targetPlayer.Vitals[vital].Current;

                    // TODO: get actual forumula for healing.  this is COMPLETELY wrong.  this is 60 + random(1-60).
                    double amountRestored = 60d + _random.Next(1, 61);
                    amountRestored       *= multiplier;

                    uint actualRestored = (uint)Math.Min(maxRestore, amountRestored);
                    targetPlayer.Vitals[vital].Current += actualRestored;

                    var updateVital = new GameMessagePrivateUpdateAttribute2ndLevel(player.Session, vital.GetVital(), targetPlayer.Vitals[vital].Current);
                    player.Session.Network.EnqueueSend(updateVital);

                    if (targetPlayer.Guid != player.Guid)
                    {
                        // tell the other player they got healed
                        var updateVitalToTarget = new GameMessagePrivateUpdateAttribute2ndLevel(targetPlayer.Session, vital.GetVital(), targetPlayer.Vitals[vital].Current);
                        targetPlayer.Session.Network.EnqueueSend(updateVitalToTarget);
                    }

                    string name = "yourself";
                    if (targetPlayer.Guid != player.Guid)
                    {
                        name = targetPlayer.Name;
                    }

                    string vitalName = "Health";

                    if (vital == Ability.Stamina)
                    {
                        vitalName = "Stamina";
                    }
                    else if (vital == Ability.Mana)
                    {
                        vitalName = "Mana";
                    }

                    string uses = source.Structure == 1 ? "use" : "uses";

                    var text    = string.Format(recipe.SuccessMessage, expertly, name, actualRestored, vitalName, source.Name, source.Structure, uses);
                    var message = new GameMessageSystemChat(text, ChatMessageType.Craft);
                    player.Session.Network.EnqueueSend(message);

                    if (targetPlayer.Guid != player.Guid)
                    {
                        // send text to the other player too
                        text    = string.Format(recipe.AlternateMessage, player.Name, expertly, actualRestored, vitalName);
                        message = new GameMessageSystemChat(text, ChatMessageType.Craft);
                        targetPlayer.Session.Network.EnqueueSend(message);
                    }
                }

                player.SendUseDoneEvent();
            });

            chain.EnqueueChain();
        }
예제 #16
0
파일: Player.cs 프로젝트: zarlant/ACE
        /// <summary>
        /// Method used to perform the animation, sound, and vital update on consumption of food or potions
        /// </summary>
        /// <param name="consumableName">Name of the consumable</param>
        /// <param name="sound">Either Sound.Eat1 or Sound.Drink1</param>
        /// <param name="buffType">ConsumableBuffType.Spell,ConsumableBuffType.Health,ConsumableBuffType.Stamina,ConsumableBuffType.Mana</param>
        /// <param name="boostAmount">Amount the Vital is boosted by; can be null, if buffType = ConsumableBuffType.Spell</param>
        /// <param name="spellDID">Id of the spell cast by the consumable; can be null, if buffType != ConsumableBuffType.Spell</param>
        public void ApplyComsumable(string consumableName, Sound sound, ConsumableBuffType buffType, uint?boostAmount, uint?spellDID)
        {
            GameMessageSystemChat buffMessage;
            MotionCommand         motionCommand;

            if (sound == Sound.Eat1)
            {
                motionCommand = MotionCommand.Eat;
            }
            else
            {
                motionCommand = MotionCommand.Drink;
            }

            var soundEvent = new GameMessageSound(Guid, sound, 1.0f);
            var motion     = new UniversalMotion(MotionStance.Standing, new MotionItem(motionCommand));

            DoMotion(motion);

            if (buffType == ConsumableBuffType.Spell)
            {
                // Null check for safety
                if (spellDID == null)
                {
                    spellDID = 0;
                }

                // TODO: Handle spell cast
                buffMessage = new GameMessageSystemChat($"Consuming {consumableName} not yet fully implemented.", ChatMessageType.System);
            }
            else
            {
                CreatureVital creatureVital;
                string        vitalName;

                // Null check for safety
                if (boostAmount == null)
                {
                    boostAmount = 0;
                }

                switch (buffType)
                {
                case ConsumableBuffType.Health:
                    creatureVital = Health;
                    vitalName     = "Health";
                    break;

                case ConsumableBuffType.Mana:
                    creatureVital = Mana;
                    vitalName     = "Mana";
                    break;

                default:
                    creatureVital = Stamina;
                    vitalName     = "Stamina";
                    break;
                }

                uint updatedVitalAmount = creatureVital.Current + (uint)boostAmount;

                if (updatedVitalAmount > creatureVital.MaxValue)
                {
                    updatedVitalAmount = creatureVital.MaxValue;
                }

                boostAmount = updatedVitalAmount - creatureVital.Current;

                UpdateVital(creatureVital, updatedVitalAmount);

                buffMessage = new GameMessageSystemChat($"You regain {boostAmount} {vitalName}.", ChatMessageType.Craft);
            }

            Session.Network.EnqueueSend(soundEvent, buffMessage);

            // Wait for animation
            var motionChain           = new ActionChain();
            var motionTable           = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId);
            var motionAnimationLength = motionTable.GetAnimationLength(MotionCommand.Eat);

            motionChain.AddDelaySeconds(motionAnimationLength);

            // Return to standing position after the animation delay
            motionChain.AddAction(this, () => DoMotion(new UniversalMotion(MotionStance.Standing)));
            motionChain.EnqueueChain();
        }
예제 #17
0
        private static void HandleCreateItemRecipe(Player player, WorldObject source, WorldObject target, Recipe recipe)
        {
            ActionChain   craftChain     = new ActionChain();
            CreatureSkill skill          = null;
            bool          skillSuccess   = true; // assume success, unless there's a skill check
            double        percentSuccess = 1;

            UniversalMotion motion = new UniversalMotion(MotionStance.Standing, new MotionItem(MotionCommand.ClapHands));

            craftChain.AddAction(player, () => player.HandleActionMotion(motion));
            float craftAnimationLength = MotionTable.GetAnimationLength((uint)player.MotionTableId, MotionCommand.ClapHands);

            craftChain.AddDelaySeconds(craftAnimationLength);
            // craftChain.AddDelaySeconds(0.5);

            craftChain.AddAction(player, () =>
            {
                if (recipe.SkillId != null && recipe.SkillDifficulty != null)
                {
                    // there's a skill associated with this
                    Skill skillId = (Skill)recipe.SkillId.Value;

                    // this shouldn't happen, but sanity check for unexpected nulls
                    if (!player.Skills.ContainsKey(skillId))
                    {
                        log.Warn("Unexpectedly missing skill in Recipe usage");
                        player.SendUseDoneEvent();
                        return;
                    }

                    skill          = player.Skills[skillId];
                    percentSuccess = skill.GetPercentSuccess(recipe.SkillDifficulty.Value);
                }

                // straight skill check, if applciable
                if (skill != null)
                {
                    skillSuccess = _random.NextDouble() < percentSuccess;
                }

                if ((recipe.ResultFlags & (uint)RecipeResult.SourceItemDestroyed) > 0)
                {
                    player.DestroyInventoryItem(source);
                }

                if ((recipe.ResultFlags & (uint)RecipeResult.TargetItemDestroyed) > 0)
                {
                    player.DestroyInventoryItem(target);
                }

                if ((recipe.ResultFlags & (uint)RecipeResult.SourceItemUsesDecrement) > 0)
                {
                    if (source.Structure <= 1)
                    {
                        player.DestroyInventoryItem(source);
                    }
                    else
                    {
                        source.Structure--;
                        source.SendPartialUpdates(player.Session, _updateStructure);
                    }
                }

                if ((recipe.ResultFlags & (uint)RecipeResult.TargetItemUsesDecrement) > 0)
                {
                    if (target.Structure <= 1)
                    {
                        player.DestroyInventoryItem(target);
                    }
                    else
                    {
                        target.Structure--;
                        target.SendPartialUpdates(player.Session, _updateStructure);
                    }
                }

                if (skillSuccess)
                {
                    WorldObject newObject1 = null;
                    WorldObject newObject2 = null;

                    if ((recipe.ResultFlags & (uint)RecipeResult.SuccessItem1) > 0 && recipe.SuccessItem1Wcid != null)
                    {
                        newObject1 = player.AddNewItemToInventory(recipe.SuccessItem1Wcid.Value);
                    }

                    if ((recipe.ResultFlags & (uint)RecipeResult.SuccessItem2) > 0 && recipe.SuccessItem2Wcid != null)
                    {
                        newObject2 = player.AddNewItemToInventory(recipe.SuccessItem2Wcid.Value);
                    }

                    var text    = string.Format(recipe.SuccessMessage, source.Name, target.Name, newObject1?.Name, newObject2?.Name);
                    var message = new GameMessageSystemChat(text, ChatMessageType.Craft);
                    player.Session.Network.EnqueueSend(message);
                }
                else
                {
                    WorldObject newObject1 = null;
                    WorldObject newObject2 = null;

                    if ((recipe.ResultFlags & (uint)RecipeResult.FailureItem1) > 0 && recipe.FailureItem1Wcid != null)
                    {
                        newObject1 = player.AddNewItemToInventory(recipe.FailureItem1Wcid.Value);
                    }

                    if ((recipe.ResultFlags & (uint)RecipeResult.FailureItem2) > 0 && recipe.FailureItem2Wcid != null)
                    {
                        newObject2 = player.AddNewItemToInventory(recipe.FailureItem2Wcid.Value);
                    }

                    var text    = string.Format(recipe.FailMessage, source.Name, target.Name, newObject1?.Name, newObject2?.Name);
                    var message = new GameMessageSystemChat(text, ChatMessageType.Craft);
                    player.Session.Network.EnqueueSend(message);
                }

                player.SendUseDoneEvent();
            });

            craftChain.EnqueueChain();
        }
예제 #18
0
        // =====================================
        // Helper Functions - Inventory Movement
        // =====================================
        // Used by HandleActionPutItemInContainer, HandleActionDropItem

        /// <summary>
        /// This method is used to pick items off the world - out of 3D space and into our inventory or to a wielded slot.
        /// It checks the use case needed, sends the appropriate response messages.
        /// In addition, it will move to objects that are out of range in the attemp to pick them up.
        /// It will call update apperiance if needed and you have wielded an item from the ground. Og II
        /// </summary>
        private void PickupItemWithNetworking(Container container, ObjectGuid itemGuid, int placementPosition, PropertyInstanceId iidPropertyId)
        {
            ActionChain pickUpItemChain = new ActionChain();

            // Move to the object
            pickUpItemChain.AddChain(CreateMoveToChain(itemGuid, PickUpDistance));

            // Pick up the object
            // Start pickup animation
            pickUpItemChain.AddAction(this, () =>
            {
                var motion = new UniversalMotion(MotionStance.Standing);
                motion.MovementData.ForwardCommand = (uint)MotionCommand.Pickup;
                CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange,
                                                  new GameMessageUpdatePosition(this),
                                                  new GameMessageUpdateMotion(Guid, Sequences.GetCurrentSequence(SequenceType.ObjectInstance), Sequences, motion));
            });

            // Wait for animation to progress
            var motionTable           = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId);
            var pickupAnimationLength = motionTable.GetAnimationLength(MotionCommand.Pickup);

            pickUpItemChain.AddDelaySeconds(pickupAnimationLength);

            // Grab a reference to the item before its removed from the CurrentLandblock
            var item = CurrentLandblock.GetObject(itemGuid);

            // Queue up an action that wait for the landblock to remove the item. The action that gets queued, when fired, will be run on the landblocks ActionChain, not this players.
            CurrentLandblock.QueueItemRemove(pickUpItemChain, itemGuid);

            // Finish pickup animation
            pickUpItemChain.AddAction(this, () =>
            {
                // If the item still has a location, CurrentLandblock failed to remove it
                if (item.Location != null)
                {
                    log.Error("Player_Inventory PickupItemWithNetworking item.Location != null");
                    return;
                }

                // If the item has a ContainerId, it was probably picked up by someone else before us
                if (item.ContainerId != null && item.ContainerId != 0)
                {
                    log.Error("Player_Inventory PickupItemWithNetworking item.ContainerId != 0");
                    return;
                }

                item.SetPropertiesForContainer();

                // FIXME(ddevec): I'm not 100% sure which of these need to be broadcasts, and which are local sends...

                if (iidPropertyId == PropertyInstanceId.Container)
                {
                    if (!container.TryAddToInventory(item, placementPosition, true))
                    {
                        log.Error("Player_Inventory PickupItemWithNetworking TryAddToInventory failed");
                        return;
                    }

                    // If we've put the item to a side pack, we must increment our main EncumbranceValue and Value
                    if (container != this)
                    {
                        EncumbranceVal += item.EncumbranceVal;
                        Value          += item.Value;
                        // todo CoinValue
                    }

                    if (item is Container itemAsContainer)
                    {
                        Session.Network.EnqueueSend(new GameEventViewContents(Session, itemAsContainer));

                        foreach (var packItem in itemAsContainer.Inventory)
                        {
                            Session.Network.EnqueueSend(new GameMessageCreateObject(packItem.Value));
                        }
                    }

                    Session.Network.EnqueueSend(
                        new GameMessageSound(Guid, Sound.PickUpItem, 1.0f),
                        new GameMessageUpdateInstanceId(itemGuid, container.Guid, iidPropertyId),
                        new GameMessagePutObjectInContainer(Session, container.Guid, item, placementPosition));
                }
                else if (iidPropertyId == PropertyInstanceId.Wielder)
                {
                    if (!TryEquipObject(item, placementPosition))
                    {
                        log.Error("Player_Inventory PickupItemWithNetworking TryEquipObject failed");
                        return;
                    }

                    if (((EquipMask)placementPosition & EquipMask.Selectable) != 0)
                    {
                        SetChild(item, placementPosition, out _, out _);
                    }

                    // todo I think we need to recalc our SetupModel here. see CalculateObjDesc()

                    Session.Network.EnqueueSend(
                        new GameMessageSound(Guid, Sound.WieldObject, (float)1.0),
                        new GameMessageObjDescEvent(this),
                        new GameMessageUpdateInstanceId(container.Guid, itemGuid, PropertyInstanceId.Wielder),
                        new GameEventWieldItem(Session, itemGuid.Full, placementPosition));
                }

                Session.Network.EnqueueSend(new GameMessagePrivateUpdatePropertyInt(Session.Player.Sequences, PropertyInt.EncumbranceVal, EncumbranceVal ?? 0));

                var motion = new UniversalMotion(MotionStance.Standing);

                CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange,
                                                  new GameMessageUpdateMotion(Guid, Sequences.GetCurrentSequence(SequenceType.ObjectInstance), Sequences, motion),
                                                  new GameMessagePickupEvent(item));

                if (iidPropertyId == PropertyInstanceId.Wielder)
                {
                    CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessageObjDescEvent(this));
                }

                // TODO: Og II - check this later to see if it is still required.
                Session.Network.EnqueueSend(new GameMessageUpdateObject(item));

                // Was Item controlled by a generator?
                // TODO: Should this be happening this way? Should the landblock notify the object of pickup or the generator...

                /*if (item.GeneratorId > 0)
                 * {
                 *  WorldObject generator = GetObject(new ObjectGuid((uint)item.GeneratorId));
                 *
                 *  item.GeneratorId = null;
                 *
                 *  generator.NotifyGeneratorOfPickup(item.Guid.Full);
                 * }*/

                item.SaveBiotaToDatabase();
            });
            // Set chain to run
            pickUpItemChain.EnqueueChain();
        }