/// <summary>
        /// 指定したモーションの再生を開始する。
        /// </summary>
        /// <param name="motion">再生するモーション</param>
        /// <param name="priority">モーションの優先度。高いほど優先される。</param>
        /// <param name="loop_enabled">trueのときループが有効なモーションではループを有効にする</param>
        /// <returns>再生が開始された場合はCubismMotionQueueEntryを返す</returns>
        public CubismMotionQueueEntry StartMotion(ICubismMotion motion, bool loop_enabled = false)
        {
            var queue_entry = new CubismMotionQueueEntry();

            queue_entry.Motion      = motion;
            queue_entry.LoopEnabled = motion.CanLoop && loop_enabled;
            MotionQueue.Add(queue_entry);
            return(queue_entry);
        }
        /// <summary>
        /// モーションを更新して、モデルにパラメータ値を反映する。
        /// </summary>
        /// <param name="elapsed_time">経過時間[秒]</param>
        public void Update(double elapsed_time)
        {
            foreach (var queue_entry in MotionQueue)
            {
                // モーションを計算する
                string[] event_data;
                if (queue_entry.Update(elapsed_time, out event_data) == false)
                {
                    continue;
                }

                // イベントが発生していればコールバックを呼ぶ
                if (EventCallbak != null)
                {
                    foreach (string event_value in event_data)
                    {
                        EventCallbak(this, event_value, EventParameter);
                    }
                }
            }

            // 終了したモーションをキューから除く
            MotionQueue.RemoveAll(x => x.Finished);
        }
Ejemplo n.º 3
0
        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($"{WorldObject.Name}.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), 30.0f);
                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, () =>
                            {
                                //Console.WriteLine($"{sourceObject.Name} running starting motion {(MotionStance)emote.Style}, {(MotionCommand)emote.Substyle}");
                                sourceObject.ExecuteMotion(startingMotion);
                            });
                        }
                    }
                    else
                    {
                        if (sourceObject.CurrentMotionState.Commands.Count > 0 && sourceObject.CurrentMotionState.Commands[0].Motion == startingMotion.Commands[0].Motion)
                        {
                            actionChain.AddDelaySeconds(emoteAction.Delay);
                            actionChain.AddAction(sourceObject, () =>
                            {
                                //Console.WriteLine($"{sourceObject.Name} running motion {(MotionStance)emote.Style}, {(MotionCommand)emoteAction.Motion}");

                                float?maxRange = ClientMaxAnimRange;
                                if (MotionQueue.Contains((MotionCommand)emoteAction.Motion))
                                {
                                    maxRange = null;
                                }

                                sourceObject.ExecuteMotion(motion, true, maxRange);
                            });
                            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, () =>
                                {
                                    //Console.WriteLine($"{sourceObject.Name} running starting motion again {(MotionStance)emote.Style}, {(MotionCommand)emote.Substyle}");
                                    sourceObject.ExecuteMotion(startingMotion);
                                });
                            }
                        }
                    }
                }
                else
                {
                    var motion = new UniversalMotion(MotionStance.NonCombat, new MotionItem((MotionCommand)emoteAction.Motion, emoteAction.Extent));

                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    actionChain.AddAction(sourceObject, () =>
                    {
                        //Console.WriteLine($"{sourceObject.Name} running motion (block 2) {(MotionStance)emote.Style}, {(MotionCommand)emoteAction.Motion}");
                        sourceObject.ExecuteMotion(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.EnqueueBroadcast(new GameMessageSound(targetObject.Guid, (Sound)emoteAction.Sound, 1.0f));
                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;
            }
        }