예제 #1
0
        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))
                    {
                        Session.Network.EnqueueSend(
                            new GameMessageSound(Guid, Sound.WieldObject, 1.0f),
                            new GameMessageObjDescEvent(this),
                            new GameMessageUpdateInstanceId(Guid, new ObjectGuid(0), PropertyInstanceId.Wielder));
                    }
                }

                item.SetPropertiesForWorld(this);

                UniversalMotion 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
                ActionChain 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));

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

                    CurrentLandblock.AddWorldObject(item);

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

                chain.EnqueueChain();
                // Removed SaveSession - this was causing items that were dropped to not be removed from inventory.
                // If this causes a problem with vendor, we need to fix vendor.  Og II
            }).EnqueueChain();
        }
예제 #2
0
        /// <summary>
        /// Handles the eviction process for a player house
        /// </summary>
        public static void HandleEviction(House house, uint playerGuid, bool multihouse = false, bool force = false)
        {
            // clear out slumlord inventory
            var slumlord = house.SlumLord;

            slumlord.ClearInventory(true);

            var player = PlayerManager.FindByGuid(playerGuid, out bool isOnline);

            if (!PropertyManager.GetBool("house_rent_enabled", true).Item&& !multihouse && !force)
            {
                // rent disabled, push forward
                var purchaseTime = (uint)(player.HousePurchaseTimestamp ?? 0);
                var nextRentTime = house.GetRentDue(purchaseTime);
                player.HouseRentTimestamp = (int)nextRentTime;

                log.Debug($"[HOUSE] HouseManager.HandleRentPaid({player.Name}): house rent disabled via config");

                // re-add item to queue
                AddRentQueue(player, house);
                return;
            }

            // handle eviction
            house.HouseOwner     = null;
            house.MonarchId      = null;
            house.HouseOwnerName = null;

            house.ClearPermissions();

            house.SaveBiotaToDatabase();

            // relink
            house.UpdateLinks();

            if (house.HasDungeon)
            {
                var dungeonHouse = house.GetDungeonHouse();
                if (dungeonHouse != null)
                {
                    dungeonHouse.UpdateLinks();
                }
            }

            // player slumlord 'off' animation
            slumlord.Off();

            // reset slumlord name
            slumlord.SetAndBroadcastName();

            slumlord.SaveBiotaToDatabase();

            // if evicting a multihouse owner's previous house,
            // no update for player properties
            if (player.HouseInstance == house.Guid.Full)
            {
                player.HouseId       = null;
                player.HouseInstance = null;
                //player.HousePurchaseTimestamp = null;
                player.HouseRentTimestamp = null;
            }
            else
            {
                log.Warn($"[HOUSE] HouseManager.HandleRentEviction({house.Guid}, {player.Name}, {multihouse}): house guids don't match {player.HouseInstance}");
            }

            house.ClearRestrictions();

            log.Debug($"[HOUSE] HouseManager.HandleRentEviction({player.Name})");

            if (multihouse)
            {
                RemoveRentQueue(house.Guid.Full);

                player.SaveBiotaToDatabase();

                return;
            }

            if (!isOnline)
            {
                // inform player of eviction when they log in
                var offlinePlayer = PlayerManager.GetOfflinePlayer(playerGuid);
                if (offlinePlayer == null)
                {
                    log.Warn($"[HOUSE] {player.Name}.HandleEviction(): couldn't find offline player");
                    return;
                }
                offlinePlayer.SetProperty(PropertyBool.HouseEvicted, true);
                offlinePlayer.SaveBiotaToDatabase();
                return;
            }

            var onlinePlayer = PlayerManager.GetOnlinePlayer(playerGuid);

            onlinePlayer.House = null;

            // send text message
            onlinePlayer.Session.Network.EnqueueSend(new GameMessageSystemChat("You've been evicted from your house!", ChatMessageType.Broadcast));
            onlinePlayer.RemoveDeed();

            onlinePlayer.SaveBiotaToDatabase();

            // clear house panel for online player
            var actionChain = new ActionChain();

            actionChain.AddDelaySeconds(3.0f);  // wait for slumlord inventory biotas above to save
            actionChain.AddAction(onlinePlayer, onlinePlayer.HandleActionQueryHouse);
            actionChain.EnqueueChain();
        }
예제 #3
0
파일: Creature.cs 프로젝트: cydrith/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));
            }
        }
예제 #4
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($"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, () =>
                            {
                                sourceObject.EnqueueBroadcastMotion(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.EnqueueBroadcastMotion(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.EnqueueBroadcastMotion(startingMotion);
                                    sourceObject.CurrentMotionState = startingMotion;
                                });
                            }
                        }
                    }
                }
                else
                {
                    var motion = new UniversalMotion(MotionStance.NonCombat, new MotionItem((MotionCommand)emoteAction.Motion, emoteAction.Extent));

                    actionChain.AddDelaySeconds(emoteAction.Delay);
                    actionChain.AddAction(sourceObject, () =>
                    {
                        sourceObject.EnqueueBroadcastMotion(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.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;
            }
        }
예제 #5
0
파일: Monster_Melee.cs 프로젝트: haeal/ACE
        /// <summary>
        /// Performs a melee attack for the monster
        /// </summary>
        /// <returns>The length in seconds for the attack animation</returns>
        public float MeleeAttack()
        {
            var target       = AttackTarget as Creature;
            var targetPlayer = AttackTarget as Player;
            var targetPet    = AttackTarget as CombatPet;
            var combatPet    = this as CombatPet;

            if (target == null || !target.IsAlive)
            {
                FindNextTarget();
                return(0.0f);
            }

            if (CurrentMotionState.Stance == MotionStance.NonCombat)
            {
                DoAttackStance();
            }

            // select combat maneuver
            var motionCommand = GetCombatManeuver();

            if (motionCommand == null)
            {
                return(0.0f);
            }

            DoSwingMotion(AttackTarget, motionCommand.Value, out float animLength, out var attackFrames);
            PhysicsObj.stick_to_object(AttackTarget.PhysicsObj.ID);

            var numStrikes = attackFrames.Count;

            var actionChain = new ActionChain();

            var prevTime = 0.0f;

            for (var i = 0; i < numStrikes; i++)
            {
                actionChain.AddDelaySeconds(attackFrames[i] * animLength - prevTime);
                prevTime = attackFrames[i] * animLength;

                actionChain.AddAction(this, () =>
                {
                    if (AttackTarget == null || IsDead)
                    {
                        return;
                    }

                    if (WeenieType == WeenieType.GamePiece)
                    {
                        target.TakeDamage(this, DamageType.Slash, target.Health.Current);
                        (this as GamePiece).OnDealtDamage();
                        return;
                    }

                    var weapon      = GetEquippedWeapon();
                    var damageEvent = DamageEvent.CalculateDamage(this, target, weapon, motionCommand);

                    //var damage = CalculateDamage(ref damageType, maneuver, bodyPart, ref critical, ref shieldMod);

                    if (damageEvent.HasDamage)
                    {
                        if (combatPet != null || targetPet != null)
                        {
                            // combat pet inflicting or receiving damage
                            //Console.WriteLine($"{target.Name} taking {Math.Round(damage)} {damageType} damage from {Name}");
                            target.TakeDamage(this, damageEvent.DamageType, damageEvent.Damage);
                            EmitSplatter(target, damageEvent.Damage);
                        }
                        else if (targetPlayer != null)
                        {
                            // this is a player taking damage
                            targetPlayer.TakeDamage(this, damageEvent);

                            if (damageEvent.ShieldMod != 1.0f)
                            {
                                var shieldSkill = targetPlayer.GetCreatureSkill(Skill.Shield);
                                Proficiency.OnSuccessUse(targetPlayer, shieldSkill, shieldSkill.Current); // ?
                            }
                        }
                    }
                    else
                    {
                        target.OnEvade(this, CombatType.Melee);
                    }

                    if (combatPet != null)
                    {
                        combatPet.PetOnAttackMonster(target);
                    }
                });
            }
            actionChain.EnqueueChain();

            // TODO: figure out exact speed / delay formula
            var meleeDelay = ThreadSafeRandom.Next(MeleeDelayMin, MeleeDelayMax);

            NextAttackTime = Timers.RunningTime + animLength + meleeDelay;
            return(animLength);
        }
예제 #6
0
파일: Player.cs 프로젝트: Cloudxtreme/ACE-1
        /// <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();
        }
예제 #7
0
        private void FinalizeTrade(Player target)
        {
            if (!VerifyTrade_BusyState(target) || !VerifyTrade_Inventory(target))
            {
                return;
            }

            IsBusy        = true;
            target.IsBusy = true;

            TradeTransferInProgress        = true;
            target.TradeTransferInProgress = true;

            Session.Network.EnqueueSend(new GameEventCommunicationTransientString(Session, "The items are being traded"));
            target.Session.Network.EnqueueSend(new GameEventCommunicationTransientString(target.Session, "The items are being traded"));

            var tradedItems = new Collection <(Biota biota, ReaderWriterLockSlim rwLock)>();

            var myEscrow     = new List <WorldObject>();
            var targetEscrow = new List <WorldObject>();

            foreach (ObjectGuid itemGuid in ItemsInTradeWindow)
            {
                if (TryRemoveFromInventoryWithNetworking(itemGuid, out var wo, RemoveFromInventoryAction.TradeItem) || TryDequipObjectWithNetworking(itemGuid, out wo, DequipObjectAction.TradeItem))
                {
                    targetEscrow.Add(wo);

                    tradedItems.Add((wo.Biota, wo.BiotaDatabaseLock));
                }
            }

            foreach (ObjectGuid itemGuid in target.ItemsInTradeWindow)
            {
                if (target.TryRemoveFromInventoryWithNetworking(itemGuid, out var wo, RemoveFromInventoryAction.TradeItem) || target.TryDequipObjectWithNetworking(itemGuid, out wo, DequipObjectAction.TradeItem))
                {
                    myEscrow.Add(wo);

                    tradedItems.Add((wo.Biota, wo.BiotaDatabaseLock));
                }
            }

            var actionChain = new ActionChain();

            actionChain.AddDelaySeconds(0.5f);
            actionChain.AddAction(CurrentLandblock, () =>
            {
                foreach (var wo in myEscrow)
                {
                    TryCreateInInventoryWithNetworking(wo);
                }

                foreach (var wo in targetEscrow)
                {
                    target.TryCreateInInventoryWithNetworking(wo);
                }

                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.TradeComplete));
                target.Session.Network.EnqueueSend(new GameEventWeenieError(target.Session, WeenieError.TradeComplete));

                TradeTransferInProgress        = false;
                target.TradeTransferInProgress = false;

                IsBusy        = false;
                target.IsBusy = false;

                DatabaseManager.Shard.SaveBiotasInParallel(tradedItems, null);

                HandleActionResetTrade(Guid);
                target.HandleActionResetTrade(target.Guid);
            });

            actionChain.EnqueueChain();
        }
예제 #8
0
        /// <summary>
        /// Launches a missile attack from player to target
        /// </summary>
        public void LaunchMissile(WorldObject target)
        {
            var weapon = GetEquippedMissileWeapon();

            if (weapon == null || CombatMode == CombatMode.NonCombat)
            {
                return;
            }

            var ammo = weapon.IsAmmoLauncher ? GetEquippedAmmo() : weapon;

            if (ammo == null)
            {
                return;
            }

            var creature = target as Creature;

            if (!IsAlive || MissileTarget == null || !creature.IsAlive)
            {
                MissileTarget = null;
                return;
            }

            // launch animation
            var actionChain = new ActionChain();
            var launchTime  = EnqueueMotion(actionChain, MotionCommand.AimLevel);

            // launch projectile
            actionChain.AddAction(this, () =>
            {
                var sound = GetLaunchMissileSound(weapon);
                EnqueueBroadcast(new GameMessageSound(Guid, sound, 1.0f));

                // stamina usage
                // TODO: ensure enough stamina for attack
                // TODO: verify formulas - double/triple cost for bow/xbow?
                var staminaCost = GetAttackStamina(GetAccuracyRange());
                UpdateVitalDelta(Stamina, -staminaCost);

                float targetTime = 0.0f;
                var projectile   = LaunchProjectile(ammo, target, out targetTime);
                UpdateAmmoAfterLaunch(ammo);
            });

            // ammo remaining?
            if (ammo.StackSize == 1)
            {
                actionChain.AddAction(this, () =>
                {
                    SetCombatMode(CombatMode.NonCombat);
                });

                actionChain.EnqueueChain();
                return;
            }

            // reload animation
            var reloadTime = EnqueueMotion(actionChain, MotionCommand.Reload);

            // reset for next projectile
            EnqueueMotion(actionChain, MotionCommand.Ready);
            var linkTime = MotionTable.GetAnimationLength(MotionTableId, CurrentMotionState.Stance, MotionCommand.Reload, MotionCommand.Ready);

            //var cycleTime = MotionTable.GetCycleLength(MotionTableId, CurrentMotionState.Stance, MotionCommand.Ready);

            actionChain.AddAction(this, () => EnqueueBroadcast(new GameMessageParentEvent(this, ammo, (int)ACE.Entity.Enum.ParentLocation.RightHand,
                                                                                          (int)ACE.Entity.Enum.Placement.RightHandCombat)));

            actionChain.AddDelaySeconds(linkTime);

            actionChain.AddAction(this, () =>
            {
                Session.Network.EnqueueSend(new GameEventAttackDone(Session));

                if (creature.IsAlive && GetCharacterOption(CharacterOption.AutoRepeatAttacks))
                {
                    Session.Network.EnqueueSend(new GameEventCombatCommenceAttack(Session));
                    Session.Network.EnqueueSend(new GameEventAttackDone(Session));

                    var nextAttack = new ActionChain();
                    nextAttack.AddDelaySeconds(AccuracyLevel + 0.1f);

                    // perform next attack
                    nextAttack.AddAction(this, () => { LaunchMissile(target); });
                    nextAttack.EnqueueChain();
                }
                else
                {
                    MissileTarget = null;
                }
            });

            actionChain.EnqueueChain();
        }
예제 #9
0
        /// <summary>
        /// This is raised by Player.HandleActionUseItem.<para />
        /// The item does not exist in the players possession.<para />
        /// If the item was outside of range, the player will have been commanded to move using DoMoveTo before ActOnUse is called.<para />
        /// When this is called, it should be assumed that the player is within range.
        /// </summary>
        public override void ActOnUse(WorldObject activator)
        {
            if (!(activator is Player player))
            {
                return;
            }

            if (AllowedActivator != null)
            {
                // do nothing / in use error msg?
                return;
            }

            if (player.IsAdvocate || player.AdvocateQuest || player.AdvocateState)
            {
                // Advocates cannot change their PK status
                if (PkLevelModifier == 1)
                {
                    return; // maybe send error msg to tell PK to ask another advocate to @remove them (or maybe make the @remove command support self removal)
                }
                // letting it fall through for the NpkSwitch because it will not change status and error properly.
            }

            //if (player.PkLevelModifier == 0) // wrong check but if PkTimestamp(? maybe different timestamp) + MINIMUM_TIME_SINCE_PK_FLOAT < Time.GetUnixTimestamp proceed else fail
            //{
            if (player.PkLevelModifier != PkLevelModifier)
            {
                AllowedActivator = ObjectGuid.Invalid.Full;

                var useMotion = UseTargetSuccessAnimation != MotionCommand.Invalid ? UseTargetSuccessAnimation : MotionCommand.Twitch1;
                EnqueueBroadcastMotion(new Motion(this, useMotion));

                var motionTable = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId);
                var useTime     = motionTable.GetAnimationLength(useMotion);

                player.LastUseTime += useTime;

                var actionChain = new ActionChain();

                actionChain.AddDelaySeconds(useTime);

                actionChain.AddAction(player, () =>
                {
                    player.Session.Network.EnqueueSend(new GameMessageSystemChat(GetProperty(PropertyString.UseMessage), ChatMessageType.Broadcast));
                    player.PkLevelModifier = PkLevelModifier;

                    if (player.PkLevelModifier == 1)
                    {
                        player.PlayerKillerStatus = PlayerKillerStatus.PK;
                    }
                    else
                    {
                        player.PlayerKillerStatus = PlayerKillerStatus.NPK;
                    }

                    player.EnqueueBroadcast(new GameMessagePublicUpdatePropertyInt(player, PropertyInt.PlayerKillerStatus, (int)player.PlayerKillerStatus));

                    Reset();
                });

                actionChain.EnqueueChain();
            }
            else
            {
                if (UseTargetFailureAnimation != MotionCommand.Invalid)
                {
                    EnqueueBroadcastMotion(new Motion(this, UseTargetFailureAnimation));
                }

                player.Session.Network.EnqueueSend(new GameMessageSystemChat(GetProperty(PropertyString.ActivationFailure), ChatMessageType.Broadcast));
            }
        }
예제 #10
0
파일: Scroll.cs 프로젝트: cydrith/ACE
        public override void OnUse(Session session)
        {
            bool   success    = true;
            string failReason = "You are unable to read the scroll.";

            switch (Power)
            {
            // research: http://asheron.wikia.com/wiki/Announcements_-_2002/06_-_Castling
            case spellLevel2:     // Level 2
            case spellLevel3:     // Level 3
            case spellLevel4:     // Level 4
            case spellLevel5:     // Level 5
            case spellLevel6:     // Level 6
                if (session.Player.CanReadScroll(School, Power))
                {
                    success = true;
                }
                else
                {
                    success    = false;
                    failReason = "You are not skilled enough in the inscribed spell's school of magic to understand the writing on this scroll.";
                }
                break;

            default:     // Level 1 or Level 7+ never fail
                success = true;
                break;
            }

            if (!session.Player.UnknownSpell(SpellId))
            {
                success    = false;
                failReason = "You already know the spell inscribed upon this scroll.";
            }

            ActionChain readScrollChain = new ActionChain();

            readScrollChain.AddAction(session.Player, () => session.Player.HandleActionMotion(motionReading));
            readScrollChain.AddDelaySeconds(2);

            if (success)
            {
                readScrollChain.AddAction(session.Player, () => session.Player.LearnSpell(SpellId));
                readScrollChain.AddAction(session.Player, () => session.Player.HandleActionMotion(motionReady));
                var removeObjMessage = new GameMessageRemoveObject(this);
                var destroyMessage   = new GameMessageSystemChat("The scroll is destroyed.", ChatMessageType.Magic);
                readScrollChain.AddAction(session.Player, () => session.Network.EnqueueSend(destroyMessage, removeObjMessage));
                readScrollChain.AddAction(session.Player, () => session.Player.RemoveWorldObjectFromInventory(Guid));
            }
            else
            {
                readScrollChain.AddDelaySeconds(2);
                readScrollChain.AddAction(session.Player, () => session.Player.HandleActionMotion(motionReady));
                var failMessage = new GameMessageSystemChat($"{failReason}", ChatMessageType.Magic);
                readScrollChain.AddAction(session.Player, () => session.Network.EnqueueSend(failMessage));
            }
            var sendUseDoneEvent = new GameEventUseDone(session.Player.Session);

            readScrollChain.AddAction(session.Player, () => session.Network.EnqueueSend(sendUseDoneEvent));
            readScrollChain.EnqueueChain();
        }
예제 #11
0
        public void HandleActionRecallAllegianceHometown()
        {
            //Console.WriteLine($"{Name}.HandleActionRecallAllegianceHometown()");

            if (PKTimerActive)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YouHaveBeenInPKBattleTooRecently));
                return;
            }

            if (RecallsDisabled)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.ExitTrainingAcademyToUseCommand));
                return;
            }

            // check if player is in an allegiance
            if (Allegiance == null)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YouAreNotInAllegiance));
                return;
            }

            if (Allegiance.Sanctuary == null)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YourAllegianceDoesNotHaveHometown));
                return;
            }

            if (CombatMode != CombatMode.NonCombat)
            {
                // this should be handled by a different thing, probably a function that forces player into peacemode
                var updateCombatMode = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.CombatMode, (int)CombatMode.NonCombat);
                SetCombatMode(CombatMode.NonCombat);
                Session.Network.EnqueueSend(updateCombatMode);
            }

            EnqueueBroadcast(new GameMessageSystemChat($"{Name} is going to the Allegiance hometown.", ChatMessageType.Recall), 96.0f);
            EnqueueBroadcastMotion(motionAllegianceHometownRecall);

            var startPos = new Position(Location);

            // Wait for animation
            var actionChain = new ActionChain();

            // Then do teleport
            var animLength = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId).GetAnimationLength(MotionCommand.AllegianceHometownRecall);

            actionChain.AddDelaySeconds(animLength);
            actionChain.AddAction(this, () =>
            {
                var endPos = new Position(Location);
                if (startPos.SquaredDistanceTo(endPos) > RecallMoveThresholdSq)
                {
                    Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YouHaveMovedTooFar));
                    return;
                }

                if (Allegiance != null)
                {
                    Teleport(Allegiance.Sanctuary);
                }
            });

            actionChain.EnqueueChain();
        }
예제 #12
0
        public void CreateMoveToChain(WorldObject target, Action <bool> callback, float?useRadius = null, bool rotate = true)
        {
            if (FastTick)
            {
                CreateMoveToChain2(target, callback, useRadius, rotate);
                return;
            }

            var thisMoveToChainNumber = GetNextMoveToChainNumber();

            if (target.Location == null)
            {
                StopExistingMoveToChains();
                log.Error($"{Name}.CreateMoveToChain({target.Name}): target.Location is null");

                callback(false);
                return;
            }

            // fix bug in magic combat mode after walking to target,
            // crouch animation steps out of range
            if (useRadius == null)
            {
                useRadius = target.UseRadius ?? 0.6f;
            }

            if (CombatMode == CombatMode.Magic)
            {
                useRadius = Math.Max(0.0f, useRadius.Value - 0.2f);
            }

            // already within use distance?
            var withinUseRadius = CurrentLandblock.WithinUseRadius(this, target.Guid, out var targetValid, useRadius);

            if (withinUseRadius)
            {
                if (rotate)
                {
                    // send TurnTo motion
                    var rotateTime  = Rotate(target);
                    var actionChain = new ActionChain();
                    actionChain.AddDelaySeconds(rotateTime);
                    actionChain.AddAction(this, () =>
                    {
                        lastCompletedMove = thisMoveToChainNumber;
                        callback(true);
                    });
                    actionChain.EnqueueChain();
                }
                else
                {
                    lastCompletedMove = thisMoveToChainNumber;
                    callback(true);
                }
                return;
            }

            if (target.WeenieType == WeenieType.Portal)
            {
                MoveToPosition(target.Location);
            }
            else
            {
                MoveToObject(target, useRadius);
            }

            moveToChainStartTime = DateTime.UtcNow;

            MoveToChain(target, thisMoveToChainNumber, callback, useRadius);
        }
예제 #13
0
        public void PlayerEnterWorld()
        {
            PlayerManager.SwitchPlayerFromOfflineToOnline(this);
            Teleporting = true;

            // Save the the LoginTimestamp
            var lastLoginTimestamp = Time.GetUnixTime();

            LoginTimestamp             = lastLoginTimestamp;
            LastTeleportStartTimestamp = lastLoginTimestamp;

            Character.LastLoginTimestamp = lastLoginTimestamp;
            Character.TotalLogins++;
            CharacterChangesDetected = true;

            Sequences.SetSequence(SequenceType.ObjectInstance, new UShortSequence((ushort)Character.TotalLogins));

            if (BarberActive)
            {
                BarberActive = false;
            }

            if (AllegianceNode != null)
            {
                AllegianceRank = (int)AllegianceNode.Rank;
            }
            else
            {
                AllegianceRank = null;
            }

            if (!Account15Days)
            {
                var accountTimeSpan = DateTime.UtcNow - Account.CreateTime;
                if (accountTimeSpan.TotalDays >= 15)
                {
                    Account15Days = true;
                }
            }

            // SendSelf will trigger the entrance into portal space
            SendSelf();

            // Update or override certain properties sent to client.
            SendPropertyUpdatesAndOverrides();

            // Init the client with the chat channel ID's, and then notify the player that they've choined the associated channels.
            UpdateChatChannels();

            var general  = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveEnteredThe_Channel, "General");
            var trade    = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveEnteredThe_Channel, "Trade");
            var lfg      = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveEnteredThe_Channel, "LFG");
            var roleplay = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveEnteredThe_Channel, "Roleplay");

            Session.Network.EnqueueSend(general, trade, lfg, roleplay);

            // check if vassals earned XP while offline
            HandleAllegianceOnLogin();
            HandleHouseOnLogin();

            // retail appeared to send the squelch list very early,
            // even before the CreatePlayer, but doing it here
            if (SquelchManager.HasSquelches)
            {
                SquelchManager.SendSquelchDB();
            }

            AuditItemSpells();

            HandleMissingXp();
            HandleSkillCreditRefund();

            if (PlayerKillerStatus == PlayerKillerStatus.PKLite && !PropertyManager.GetBool("pkl_server").Item)
            {
                var actionChain = new ActionChain();
                actionChain.AddDelaySeconds(3.0f);
                actionChain.AddAction(this, () =>
                {
                    UpdateProperty(this, PropertyInt.PlayerKillerStatus, (int)PlayerKillerStatus.NPK, true);

                    Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YouAreNonPKAgain));
                });
                actionChain.EnqueueChain();
            }

            HandleDBUpdates();
        }
예제 #14
0
        public static void HandleHouseSelect(Session session, bool confirmed, params string[] parameters)
        {
            if (!int.TryParse(parameters[0], out var houseIdx))
            {
                return;
            }

            // ensure current multihouse owner
            if (!session.Player.IsMultiHouseOwner(false))
            {
                log.Warn($"{session.Player.Name} tried to /house-select {houseIdx}, but they are not currently a multi-house owner!");
                return;
            }

            // get house info for this index
            var multihouses = session.Player.GetMultiHouses();

            if (houseIdx < 1 || houseIdx > multihouses.Count)
            {
                session.Network.EnqueueSend(new GameMessageSystemChat($"Please enter a number between 1 and {multihouses.Count}.", ChatMessageType.Broadcast));
                return;
            }

            var keepHouse = multihouses[houseIdx - 1];

            // show confirmation popup
            if (!confirmed)
            {
                var houseType = $"{keepHouse.HouseType}".ToLower();;
                var loc       = HouseManager.GetCoords(keepHouse.SlumLord.Location);

                var msg = $"Are you sure you want to keep the {houseType} at\n{loc}?";
                session.Player.ConfirmationManager.EnqueueSend(new Confirmation_Custom(session.Player.Guid, () => HandleHouseSelect(session, true, parameters)), msg);
                return;
            }

            // house to keep confirmed, abandon the other houses
            var abandonHouses = new List <House>(multihouses);

            abandonHouses.RemoveAt(houseIdx - 1);

            foreach (var abandonHouse in abandonHouses)
            {
                var house = session.Player.GetHouse(abandonHouse.Guid.Full);

                HouseManager.HandleEviction(house, house.HouseOwner ?? 0, true);
            }

            // set player properties for house to keep
            var player = PlayerManager.FindByGuid(keepHouse.HouseOwner ?? 0, out bool isOnline);

            if (player == null)
            {
                log.Error($"{session.Player.Name}.HandleHouseSelect({houseIdx}) - couldn't find HouseOwner {keepHouse.HouseOwner} for {keepHouse.Name} ({keepHouse.Guid})");
                return;
            }

            player.HouseId       = keepHouse.HouseId;
            player.HouseInstance = keepHouse.Guid.Full;

            player.SaveBiotaToDatabase();

            // update house panel for current player
            var actionChain = new ActionChain();

            actionChain.AddDelaySeconds(3.0f);  // wait for slumlord inventory biotas above to save
            actionChain.AddAction(session.Player, session.Player.HandleActionQueryHouse);
            actionChain.EnqueueChain();

            Console.WriteLine("OK");
        }
예제 #15
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.Standing, new MotionItem(MotionCommand.ClapHands));

            craftChain.AddAction(player, () => player.HandleActionMotion(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();
        }
예제 #16
0
        public void Decay(TimeSpan elapsed)
        {
            // http://asheron.wikia.com/wiki/Item_Decay

            if (decayCompleted)
            {
                return;
            }

            var previousTTR = TimeToRot;

            if (!TimeToRot.HasValue)
            {
                TimeToRot = DefaultTimeToRot.TotalSeconds;

                if (this is Corpse && Level.HasValue)
                {
                    log.Info($"{Name} (0x{Guid.ToString()}).Decay: TimeToRot had no value, set to {TimeToRot}");
                }

                return;
            }

            var corpse = this as Corpse;

            if (corpse != null)
            {
                if (!corpse.InventoryLoaded)
                {
                    return;
                }

                if (corpse.Inventory.Count == 0 && TimeToRot.Value > Corpse.EmptyDecayTime)
                {
                    TimeToRot = Corpse.EmptyDecayTime;
                    if (Level.HasValue && PropertyManager.GetBool("corpse_decay_tick_logging").Item)
                    {
                        log.Info($"{corpse.Name} (0x{corpse.Guid.ToString()}).Decay({elapsed.ToString()}): InventoryLoaded = {corpse.InventoryLoaded} | Inventory.Count = {corpse.Inventory.Count} | previous TimeToRot: {previousTTR} | current TimeToRot: {TimeToRot}");
                    }
                    return;
                }
            }

            if (TimeToRot > 0)
            {
                TimeToRot -= elapsed.TotalSeconds;

                if (this is Corpse && Level.HasValue && PropertyManager.GetBool("corpse_decay_tick_logging").Item)
                {
                    log.Info($"{corpse.Name} (0x{corpse.Guid.ToString()}).Decay({elapsed.ToString()}): previous TimeToRot: {previousTTR} | current TimeToRot: {TimeToRot}");
                }

                // Is there still time left?
                if (TimeToRot > 0)
                {
                    return;
                }

                TimeToRot = -2; // We force it to -2 to make sure it doesn't end up at 0 or -1. 0 indicates instant rot. -1 indicates no rot. 0 and -1 can be found in weenie defaults

                if (this is Corpse && Level.HasValue && PropertyManager.GetBool("corpse_decay_tick_logging").Item)
                {
                    log.Info($"{corpse.Name} (0x{corpse.Guid.ToString()}).Decay({elapsed.ToString()}): previous TimeToRot: {previousTTR} | current TimeToRot: {TimeToRot}");
                }
            }

            if (this is Container container && container.IsOpen)
            {
                // If you wanted to add a grace period to the container to give Player B more time to open it after Player A closes it, it would go here.

                return;
            }

            // Time to rot has elapsed, time to disappear...
            decayCompleted = true;

            // If this is a player corpse, puke out the corpses contents onto the landblock
            if (corpse != null && !corpse.IsMonster)
            {
                var inventoryGUIDs = corpse.Inventory.Keys.ToList();

                var pukedItems = "";

                foreach (var guid in inventoryGUIDs)
                {
                    if (corpse.TryRemoveFromInventory(guid, out var item))
                    {
                        item.Location  = new Position(corpse.Location);
                        item.Placement = ACE.Entity.Enum.Placement.Resting; // This is needed to make items lay flat on the ground.
                        CurrentLandblock.AddWorldObject(item);
                        item.SaveBiotaToDatabase();
                        pukedItems += $"{item.Name} (0x{item.Guid.Full.ToString("X8")}), ";
                    }
                }

                if (pukedItems.EndsWith(", "))
                {
                    pukedItems = pukedItems.Substring(0, pukedItems.Length - 2);
                }

                log.Info($"{corpse.Name} (0x{corpse.Guid.ToString()}) at {corpse.Location.ToLOCString()} has decayed{((pukedItems == "") ? "" : $" and placed the following items on the landblock: {pukedItems}")}.");
            }

            if (corpse != null)
            {
                EnqueueBroadcast(new GameMessageScript(Guid, ACE.Entity.Enum.PlayScript.Destroy));

                var actionChain = new ActionChain();
                actionChain.AddDelaySeconds(1.0f);
                actionChain.AddAction(this, () => Destroy());
                actionChain.EnqueueChain();
            }
            else
            {
                Destroy();
            }
        }
예제 #17
0
        public void LogOut_Inner(bool clientSessionTerminatedAbruptly = false)
        {
            IsLoggingOut = true;

            if (Fellowship != null)
            {
                FellowshipQuit(false);
            }

            if (IsTrading && TradePartner != null)
            {
                var tradePartner = PlayerManager.GetOnlinePlayer(TradePartner);

                if (tradePartner != null)
                {
                    tradePartner.HandleActionCloseTradeNegotiations();
                }
            }

            if (!clientSessionTerminatedAbruptly)
            {
                if (PropertyManager.GetBool("use_turbine_chat").Item)
                {
                    if (GetCharacterOption(CharacterOption.ListenToGeneralChat))
                    {
                        LeaveTurbineChatChannel("General");
                    }
                    if (GetCharacterOption(CharacterOption.ListenToTradeChat))
                    {
                        LeaveTurbineChatChannel("Trade");
                    }
                    if (GetCharacterOption(CharacterOption.ListenToLFGChat))
                    {
                        LeaveTurbineChatChannel("LFG");
                    }
                    if (GetCharacterOption(CharacterOption.ListenToRoleplayChat))
                    {
                        LeaveTurbineChatChannel("Roleplay");
                    }
                    if (GetCharacterOption(CharacterOption.ListenToAllegianceChat) && Allegiance != null)
                    {
                        LeaveTurbineChatChannel("Allegiance");
                    }
                    if (GetCharacterOption(CharacterOption.ListenToSocietyChat) && Society != FactionBits.None)
                    {
                        LeaveTurbineChatChannel("Society");
                    }
                }
            }

            if (CurrentActivePet != null)
            {
                CurrentActivePet.Destroy();
            }

            if (CurrentLandblock != null)
            {
                var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut);
                EnqueueBroadcastMotion(logout);

                EnqueueBroadcastPhysicsState();

                var logoutChain = new ActionChain();

                var   motionTable           = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId);
                float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut);
                logoutChain.AddDelaySeconds(logoutAnimationLength);

                // remove the player from landblock management -- after the animation has run
                logoutChain.AddAction(this, () =>
                {
                    if (CurrentLandblock == null)
                    {
                        log.Debug($"0x{Guid}:{Name}.LogOut_Inner.logoutChain: CurrentLandblock is null, unable to remove from a landblock...");
                        if (Location != null)
                        {
                            log.Debug($"0x{Guid}:{Name}.LogOut_Inner.logoutChain: Location is not null, Location = {Location.ToLOCString()}");
                        }
                    }

                    CurrentLandblock?.RemoveWorldObject(Guid, false);
                    SetPropertiesAtLogOut();
                    SavePlayerToDatabase();
                    PlayerManager.SwitchPlayerFromOnlineToOffline(this);
                });

                // close any open landblock containers (chests / corpses)
                if (LastOpenedContainerId != ObjectGuid.Invalid)
                {
                    var container = CurrentLandblock.GetObject(LastOpenedContainerId) as Container;

                    if (container != null)
                    {
                        container.Close(this);
                    }
                }

                logoutChain.EnqueueChain();
            }
            else
            {
                log.Debug($"0x{Guid}:{Name}.LogOut_Inner: CurrentLandblock is null");
                if (Location != null)
                {
                    log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Location is not null, Location = {Location.ToLOCString()}");
                    var validLoadedLandblock = LandblockManager.GetLandblock(Location.LongObjCellID, false);
                    if (validLoadedLandblock.GetObject(Guid.Full) != null)
                    {
                        log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Player is still on landblock, removing...");
                        validLoadedLandblock.RemoveWorldObject(Guid, false);
                    }
                    else
                    {
                        log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Player is not found on the landblock Location references.");
                    }
                }
                else
                {
                    log.Debug($"0x{Guid}:{Name}.LogOut_Inner: Location is null");
                }
                SetPropertiesAtLogOut();
                SavePlayerToDatabase();
                PlayerManager.SwitchPlayerFromOnlineToOffline(this);
            }
        }
예제 #18
0
        public void SwitchToMeleeAttack()
        {
            if (IsDead)
            {
                return;
            }

            var weapon = GetEquippedMissileWeapon();
            var ammo   = GetEquippedAmmo();

            if (weapon == null && ammo == null)
            {
                return;
            }

            var actionChain = new ActionChain();

            EnqueueMotion_Force(actionChain, MotionStance.NonCombat, MotionCommand.Ready, (MotionCommand)CurrentMotionState.Stance);

            EnqueueMotion_Force(actionChain, MotionStance.HandCombat, MotionCommand.Ready, MotionCommand.NonCombat);

            actionChain.AddAction(this, () =>
            {
                if (IsDead)
                {
                    return;
                }

                // actually destroys the missile weapon + ammo here,
                // to ensure they can't be re-selected from inventory
                if (weapon != null)
                {
                    TryUnwieldObjectWithBroadcasting(weapon.Guid, out _, out _);
                    weapon.Destroy();
                }

                if (ammo != null)
                {
                    TryUnwieldObjectWithBroadcasting(ammo.Guid, out _, out _);
                    ammo.Destroy();
                }

                EquipInventoryItems(true);

                var innerChain = new ActionChain();

                EnqueueMotion_Force(innerChain, MotionStance.NonCombat, MotionCommand.Ready, (MotionCommand)CurrentMotionState.Stance);

                innerChain.AddAction(this, () =>
                {
                    if (IsDead)
                    {
                        return;
                    }

                    //DoAttackStance();

                    // inlined DoAttackStance() / slightly modified -- do not rely on SetCombatMode() for stance swapping time in 1 action,
                    // as it doesn't support that anymore

                    var newStanceTime = SetCombatMode(CombatMode.Melee);

                    NextMoveTime = NextAttackTime = Timers.RunningTime + newStanceTime;

                    PrevAttackTime = NextMoveTime - (AiUseMagicDelay ?? 3.0f);

                    PhysicsObj.StartTimer();

                    // end inline

                    ResetAttack();

                    SwitchWeaponsPending = false;

                    // this is an unfortunate hack to fix the following scenario:

                    // since this function can be called at any point in time now,
                    // including when LaunchMissile -> EnqueueMotion is in the middle of an action queue,
                    // CurrentMotionState.Stance can get reset to the previous combat stance if that happens

                    var newStance = CurrentMotionState.Stance;

                    var swapChain = new ActionChain();
                    swapChain.AddDelaySeconds(2.0f);
                    swapChain.AddAction(this, () => CurrentMotionState.Stance = newStance);
                    swapChain.EnqueueChain();
                });
                innerChain.EnqueueChain();
            });
            actionChain.EnqueueChain();
        }
예제 #19
0
파일: Player_Tick.cs 프로젝트: hooper82/ACE
        /// <summary>
        /// Called every ~5 secs for equipped mana consuming items
        /// </summary>
        public void ManaConsumersTick()
        {
            if (!EquippedObjectsLoaded)
            {
                return;
            }

            var EquippedManaConsumers = EquippedObjects.Where(k =>
                                                              (k.Value.IsAffecting ?? false) &&
                                                              //k.Value.ManaRate.HasValue &&
                                                              k.Value.ItemMaxMana.HasValue &&
                                                              k.Value.ItemCurMana.HasValue &&
                                                              k.Value.ItemCurMana.Value > 0).ToList();

            foreach (var k in EquippedManaConsumers)
            {
                var item = k.Value;

                // this was a bug in lootgen until 7/11/2019, mostly for clothing/armor/shields
                // tons of existing items on servers are in this bugged state, where they aren't ticking mana.
                // this retroactively fixes them when equipped
                // items such as Impious Staff are excluded from this via IsAffecting

                if (item.ManaRate == null)
                {
                    item.ManaRate = LootGenerationFactory.GetManaRate(item);
                    log.Warn($"{Name}.ManaConsumersTick(): {k.Value.Name} ({k.Value.Guid}) fixed missing ManaRate");
                }

                var rate = item.ManaRate.Value;

                if (LumAugItemManaUsage != 0)
                {
                    rate *= GetNegativeRatingMod(LumAugItemManaUsage * 5);
                }

                if (!item.ItemManaConsumptionTimestamp.HasValue)
                {
                    item.ItemManaConsumptionTimestamp = DateTime.UtcNow;
                }
                DateTime mostRecentBurn = item.ItemManaConsumptionTimestamp.Value;

                var timePerBurn = -1 / rate;

                var secondsSinceLastBurn = (DateTime.UtcNow - mostRecentBurn).TotalSeconds;

                var delta = secondsSinceLastBurn / timePerBurn;

                var deltaChopped = (int)Math.Floor(delta);
                var deltaExtra   = delta - deltaChopped;

                if (deltaChopped <= 0)
                {
                    continue;
                }

                var timeToAdd = (int)Math.Floor(deltaChopped * timePerBurn);
                item.ItemManaConsumptionTimestamp = mostRecentBurn + new TimeSpan(0, 0, timeToAdd);
                var manaToBurn = Math.Min(item.ItemCurMana.Value, deltaChopped);
                deltaChopped      = Math.Clamp(deltaChopped, 0, 10);
                item.ItemCurMana -= deltaChopped;

                if (item.ItemCurMana < 1 || item.ItemCurMana == null)
                {
                    item.IsAffecting = false;
                    var msg   = new GameMessageSystemChat($"Your {item.Name} is out of Mana.", ChatMessageType.Magic);
                    var sound = new GameMessageSound(Guid, Sound.ItemManaDepleted);
                    Session.Network.EnqueueSend(msg, sound);
                    if (item.WielderId != null)
                    {
                        if (item.Biota.BiotaPropertiesSpellBook != null)
                        {
                            // unsure if these messages / sounds were ever sent in retail,
                            // or if it just purged the enchantments invisibly
                            // doing a delay here to prevent 'SpellExpired' sounds from overlapping with 'ItemManaDepleted'
                            var actionChain = new ActionChain();
                            actionChain.AddDelaySeconds(2.0f);
                            actionChain.AddAction(this, () =>
                            {
                                for (int i = 0; i < item.Biota.BiotaPropertiesSpellBook.Count; i++)
                                {
                                    RemoveItemSpell(item, (uint)item.Biota.BiotaPropertiesSpellBook.ElementAt(i).Spell);
                                }
                            });
                            actionChain.EnqueueChain();
                        }
                    }
                }
                else
                {
                    // get time until empty
                    var secondsUntilEmpty = ((item.ItemCurMana - deltaExtra) * timePerBurn);
                    if (secondsUntilEmpty <= 120 && (!item.ItemManaDepletionMessageTimestamp.HasValue || (DateTime.UtcNow - item.ItemManaDepletionMessageTimestamp.Value).TotalSeconds > 120))
                    {
                        item.ItemManaDepletionMessageTimestamp = DateTime.UtcNow;
                        Session.Network.EnqueueSend(new GameMessageSystemChat($"Your {item.Name} is low on Mana.", ChatMessageType.Magic));
                    }
                }
            }
        }
예제 #20
0
        /// <summary>
        /// Vendor has validated the transactions and sent a list of items for processing.
        /// </summary>
        public void FinalizeBuyTransaction(Vendor vendor, List <WorldObject> uqlist, List <WorldObject> genlist, uint goldcost, uint altcost)
        {
            // vendor accepted the transaction

            var valid = ValidateBuyTransaction(vendor, goldcost, altcost);

            if (valid)
            {
                if (altcost > 0)
                {
                    var altCurrencyWCID = vendor.AlternateCurrency ?? 0;

                    SpendCurrency(altCurrencyWCID, altcost, true);
                }
                else
                {
                    SpendCurrency(Vendor.CoinStackWCID, goldcost, true);
                }

                foreach (WorldObject wo in uqlist)
                {
                    wo.RemoveProperty(PropertyFloat.SoldTimestamp);
                    TryCreateInInventoryWithNetworking(wo);
                }

                foreach (var gen in genlist)
                {
                    var service = gen.GetProperty(PropertyBool.VendorService) ?? false;

                    if (!service)
                    {
                        TryCreateInInventoryWithNetworking(gen);
                    }
                    else
                    {
                        var spell = new Spell(gen.SpellDID ?? 0);
                        if (!spell.NotFound)
                        {
                            var preCastTime = vendor.PreCastMotion(this);
                            vendor.IsBusy = true;

                            var castChain = new ActionChain();
                            castChain.AddDelaySeconds(preCastTime);
                            castChain.AddAction(vendor, () =>
                            {
                                vendor.TryCastSpell(spell, this, vendor);
                                vendor.PostCastMotion();
                            });

                            var postCastTime = vendor.GetPostCastTime();

                            castChain.AddDelaySeconds(postCastTime);
                            castChain.AddAction(vendor, () => vendor.IsBusy = false);

                            castChain.EnqueueChain();
                        }
                        else if (gen.GetProperty(PropertyInt.HomeRealm).HasValue)
                        {
                            var realmId = gen.GetProperty(PropertyInt.HomeRealm).Value;
                            RealmManager.SetHomeRealm(this, realmId);
                        }
                    }
                }

                Session.Network.EnqueueSend(new GameMessageSound(Guid, Sound.PickUpItem));

                if (PropertyManager.GetBool("player_receive_immediate_save").Item)
                {
                    RushNextPlayerSave(5);
                }
            }

            vendor.BuyItems_FinalTransaction(this, uqlist, valid, altcost);
        }
예제 #21
0
        /// <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(DamageHistoryInfo lastDamager, DamageHistoryInfo topDamager)
        {
            if (topDamager?.Guid == Guid && IsPKType)
            {
                var topDamagerOther = DamageHistory.GetTopDamager(false);

                if (topDamagerOther != null && topDamagerOther.IsPlayer)
                {
                    topDamager = topDamagerOther;
                }
            }

            UpdateVital(Health, 0);
            NumDeaths++;
            suicideInProgress = false;

            // TODO: instead of setting IsBusy here,
            // eventually all of the places that check for states such as IsBusy || Teleporting
            // might want to use a common function, and IsDead should return a separate error
            IsBusy = true;

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

            // broadcast death animation
            var deathAnim = new Motion(MotionStance.NonCombat, MotionCommand.Dead);

            EnqueueBroadcastMotion(deathAnim);

            // 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 msgNumDeaths = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.NumDeaths, NumDeaths);

            // send network messages for player death
            Session.Network.EnqueueSend(msgHealthUpdate, msgNumDeaths);

            if (lastDamager?.Guid == Guid) // suicide
            {
                var msgSelfInflictedDeath = new GameEventWeenieError(Session, WeenieError.YouKilledYourself);
                Session.Network.EnqueueSend(msgSelfInflictedDeath);
            }

            // update vitae
            // players who died in a PKLite fight do not accrue vitae
            if (!IsPKLiteDeath(topDamager))
            {
                InflictVitaePenalty();
            }

            if (IsPKDeath(topDamager) || AugmentationSpellsRemainPastDeath == 0)
            {
                var msgPurgeEnchantments = new GameEventMagicPurgeEnchantments(Session);
                EnchantmentManager.RemoveAllEnchantments();
                Session.Network.EnqueueSend(msgPurgeEnchantments);
            }

            // 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);

            dieChain.AddAction(this, () =>
            {
                CreateCorpse(topDamager);

                ThreadSafeTeleportOnDeath(); // enter portal space

                SetLifestoneProtection();

                if (IsPKDeath(topDamager) || IsPKLiteDeath(topDamager))
                {
                    SetMinimumTimeSincePK();
                }

                IsBusy = false;
            });

            dieChain.EnqueueChain();
        }
예제 #22
0
        /// <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++;
            suicideInProgress = false;

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

            // broadcast death animation
            var deathAnim = new Motion(MotionStance.NonCombat, MotionCommand.Dead);

            EnqueueBroadcastMotion(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 msgNumDeaths = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.NumDeaths, NumDeaths);

            // send network messages for player death
            Session.Network.EnqueueSend(msgHealthUpdate, msgNumDeaths);

            if (lastDamager.Guid == Guid) // suicide
            {
                var msgSelfInflictedDeath = new GameEventWeenieError(Session, WeenieError.YouKilledYourself);
                Session.Network.EnqueueSend(msgSelfInflictedDeath);
            }

            // update vitae
            // players who died in a PKLite fight do not accrue vitae
            if (!IsPKLiteDeath(topDamager))
            {
                InflictVitaePenalty();
            }

            if (IsPKDeath(topDamager) || AugmentationSpellsRemainPastDeath == 0)
            {
                var msgPurgeEnchantments = new GameEventMagicPurgeEnchantments(Session);
                EnchantmentManager.RemoveAllEnchantments();
                Session.Network.EnqueueSend(msgPurgeEnchantments);
            }

            // 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);

            dieChain.AddAction(this, () =>
            {
                CreateCorpse(topDamager);
                TeleportOnDeath();      // enter portal space
                SetLifestoneProtection();
                SetMinimumTimeSincePK();
            });

            dieChain.EnqueueChain();
        }
예제 #23
0
        /// <summary>
        /// Recalls you to your allegiance's Mansion or Villa
        /// </summary>
        public void HandleActionTeleToMansion()
        {
            //Console.WriteLine($"{Name}.HandleActionTeleToMansion()");

            if (RecallsDisabled)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.ExitTrainingAcademyToUseCommand));
                return;
            }

            // check if player is in an allegiance
            if (Allegiance == null)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YouAreNotInAllegiance));
                return;
            }

            var allegianceHouse = Allegiance.GetHouse();

            if (allegianceHouse == null)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YourMonarchDoesNotOwnAMansionOrVilla));
                return;
            }

            if (allegianceHouse.HouseType < ACE.Entity.Enum.HouseType.Villa)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YourMonarchsHouseIsNotAMansionOrVilla));
                return;
            }

            // ensure allegiance housing has allegiance permissions enabled
            if (allegianceHouse.MonarchId == null)
            {
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YourMonarchHasClosedTheMansion));
                return;
            }

            if (CombatMode != CombatMode.NonCombat)
            {
                // this should be handled by a different thing, probably a function that forces player into peacemode
                var updateCombatMode = new GameMessagePrivateUpdatePropertyInt(this, PropertyInt.CombatMode, (int)CombatMode.NonCombat);
                SetCombatMode(CombatMode.NonCombat);
                Session.Network.EnqueueSend(updateCombatMode);
            }

            EnqueueBroadcast(new GameMessageSystemChat($"{Name} is recalling to the Allegiance housing.", ChatMessageType.Recall), 96.0f);
            EnqueueBroadcastMotion(motionHouseRecall);

            var startPos = new Position(Location);

            // Wait for animation
            var actionChain = new ActionChain();

            // Then do teleport
            var animLength = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId).GetAnimationLength(MotionCommand.HouseRecall);

            actionChain.AddDelaySeconds(animLength);
            actionChain.AddAction(this, () =>
            {
                var endPos = new Position(Location);
                if (startPos.SquaredDistanceTo(endPos) > RecallMoveThresholdSq)
                {
                    Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YouHaveMovedTooFar));
                    return;
                }

                Teleport(allegianceHouse.SlumLord.Location);
            });

            actionChain.EnqueueChain();
        }
예제 #24
0
        public void LogOut_Inner(bool clientSessionTerminatedAbruptly = false)
        {
            if (Fellowship != null)
            {
                FellowshipQuit(false);
            }

            if (IsTrading && TradePartner != null)
            {
                var tradePartner = PlayerManager.GetOnlinePlayer(TradePartner);

                if (tradePartner != null)
                {
                    tradePartner.HandleActionCloseTradeNegotiations();
                }
            }

            if (!clientSessionTerminatedAbruptly)
            {
                // Thie retail server sends a ChatRoomTracker 0x0295 first, then the status message, 0x028B. It does them one at a time for each individual channel.
                // The ChatRoomTracker message doesn't seem to change at all.
                // For the purpose of ACE, we simplify this process.
                var general  = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "General");
                var trade    = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "Trade");
                var lfg      = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "LFG");
                var roleplay = new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, "Roleplay");
                Session.Network.EnqueueSend(general, trade, lfg, roleplay);
            }

            if (CurrentActiveCombatPet != null)
            {
                CurrentActiveCombatPet.Destroy();
            }

            if (CurrentLandblock != null)
            {
                var logout = new Motion(MotionStance.NonCombat, MotionCommand.LogOut);
                EnqueueBroadcastMotion(logout);

                EnqueueBroadcastPhysicsState();

                var logoutChain = new ActionChain();

                var   motionTable           = DatManager.PortalDat.ReadFromDat <MotionTable>((uint)MotionTableId);
                float logoutAnimationLength = motionTable.GetAnimationLength(MotionCommand.LogOut);
                logoutChain.AddDelaySeconds(logoutAnimationLength);

                // remove the player from landblock management -- after the animation has run
                logoutChain.AddAction(this, () =>
                {
                    CurrentLandblock?.RemoveWorldObject(Guid, false);
                    SetPropertiesAtLogOut();
                    SavePlayerToDatabase();
                    PlayerManager.SwitchPlayerFromOnlineToOffline(this);
                });

                // close any open landblock containers (chests / corpses)
                if (LastOpenedContainerId != ObjectGuid.Invalid)
                {
                    var container = CurrentLandblock.GetObject(LastOpenedContainerId) as Container;

                    if (container != null)
                    {
                        container.Close(this);
                    }
                }

                logoutChain.EnqueueChain();
            }
            else
            {
                SetPropertiesAtLogOut();
                SavePlayerToDatabase();
                PlayerManager.SwitchPlayerFromOnlineToOffline(this);
            }
        }
예제 #25
0
        /// <summary>
        /// Called on player login
        /// If a player has any skills trained that require updates from ACE-World-16-Patches,
        /// ensure these updates are installed, and if they aren't, send a helpful message to player with instructions for installation
        /// </summary>
        public void HandleDBUpdates()
        {
            // dirty fighting
            var dfSkill = GetCreatureSkill(Skill.DirtyFighting);

            if (dfSkill.AdvancementClass >= SkillAdvancementClass.Trained)
            {
                foreach (var spellID in SpellExtensions.DirtyFightingSpells)
                {
                    var spell = new Server.Entity.Spell(spellID);
                    if (spell.NotFound)
                    {
                        var actionChain = new ActionChain();
                        actionChain.AddDelaySeconds(3.0f);
                        actionChain.AddAction(this, () =>
                        {
                            Session.Network.EnqueueSend(new GameMessageSystemChat("To install Dirty Fighting, please apply the latest patches from https://github.com/ACEmulator/ACE-World-16PY-Patches", ChatMessageType.Broadcast));
                        });
                        actionChain.EnqueueChain();
                    }
                    break;  // performance improvement: only check first spell
                }
            }

            // void magic
            var voidSkill = GetCreatureSkill(Skill.VoidMagic);

            if (voidSkill.AdvancementClass >= SkillAdvancementClass.Trained)
            {
                foreach (var spellID in SpellExtensions.VoidMagicSpells)
                {
                    var spell = new Server.Entity.Spell(spellID);
                    if (spell.NotFound)
                    {
                        var actionChain = new ActionChain();
                        actionChain.AddDelaySeconds(3.0f);
                        actionChain.AddAction(this, () =>
                        {
                            Session.Network.EnqueueSend(new GameMessageSystemChat("To install Void Magic, please apply the latest patches from https://github.com/ACEmulator/ACE-World-16PY-Patches", ChatMessageType.Broadcast));
                        });
                        actionChain.EnqueueChain();
                    }
                    break;  // performance improvement: only check first spell (measured 102ms to check 75 uncached void spells)
                }
            }

            // summoning
            var summoning = GetCreatureSkill(Skill.Summoning);

            if (summoning.AdvancementClass >= SkillAdvancementClass.Trained)
            {
                uint essenceWCID = 48878;
                var  weenie      = DatabaseManager.World.GetCachedWeenie(essenceWCID);
                if (weenie == null)
                {
                    var actionChain = new ActionChain();
                    actionChain.AddDelaySeconds(3.0f);
                    actionChain.AddAction(this, () =>
                    {
                        Session.Network.EnqueueSend(new GameMessageSystemChat("To install Summoning, please apply the latest patches from https://github.com/ACEmulator/ACE-World-16PY-Patches", ChatMessageType.Broadcast));
                    });
                    actionChain.EnqueueChain();
                }
            }
        }
예제 #26
0
        /// <summary>
        /// This is raised by Player.HandleActionUseItem.<para />
        /// The item should be in the players possession.
        /// </summary>
        public override void UseItem(Player player)
        {
            bool   success    = true;
            string failReason = "You are unable to read the scroll.";

            switch (Power)
            {
            // research: http://asheron.wikia.com/wiki/Announcements_-_2002/06_-_Castling
            case spellLevel2:     // Level 2
            case spellLevel3:     // Level 3
            case spellLevel4:     // Level 4
            case spellLevel5:     // Level 5
            case spellLevel6:     // Level 6
                if (!player.CanReadScroll(School, Power))
                {
                    success    = false;
                    failReason = "You are not skilled enough in the inscribed spell's school of magic to understand the writing on this scroll.";
                }
                break;
            }

            if (player.SpellIsKnown(SpellId))
            {
                success    = false;
                failReason = "You already know the spell inscribed upon this scroll.";
            }

            var actionChain = new ActionChain();

            actionChain
            .AddAction(player, () => player.EnqueueBroadcastMotion(motionReading))
            .AddDelaySeconds(2);

            if (success)
            {
                actionChain.AddAction(player, () =>
                {
                    player.LearnSpellWithNetworking(SpellId);
                    player.EnqueueBroadcastMotion(motionReady);

                    if (player.TryRemoveFromInventoryWithNetworking(this))
                    {
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat("The scroll is destroyed.", ChatMessageType.Magic));
                        Destroy();
                    }
                });
            }
            else
            {
                actionChain
                .AddDelaySeconds(2)
                .AddAction(player, () =>
                {
                    player.EnqueueBroadcastMotion(motionReady);
                    player.Session.Network.EnqueueSend(new GameMessageSystemChat($"{failReason}", ChatMessageType.Magic));
                });
            }

            actionChain
            .AddAction(player, () => player.Session.Network.EnqueueSend(new GameEventUseDone(player.Session)));

            actionChain.EnqueueChain();
        }
예제 #27
0
        /// <summary>
        /// Launches a missile attack from monster to target
        /// </summary>
        public void LaunchMissile()
        {
            //IsTurning = false;

            var weapon = GetEquippedMissileWeapon();

            if (weapon == null || AttackTarget == null)
            {
                return;
            }

            var ammo = weapon.IsAmmoLauncher ? GetEquippedAmmo() : weapon;

            if (ammo == null)
            {
                return;
            }

            // ensure direct line of sight
            if (!IsDirectVisible(AttackTarget))
            {
                NextAttackTime = Timers.RunningTime + 1.0f;
                return;
            }

            // should this be called each launch?
            AttackHeight = ChooseAttackHeight();

            var dist = GetDistanceToTarget();

            //Console.WriteLine("RangeAttack: " + dist);

            if (DebugMove)
            {
                Console.WriteLine($"[{Timers.RunningTime}] - {Name} ({Guid}) - LaunchMissile");
            }

            // get z-angle for aim motion
            var aimVelocity = GetAimVelocity(AttackTarget);

            var aimLevel = GetAimLevel(aimVelocity);

            // calculate projectile spawn pos and velocity
            var localOrigin = GetProjectileSpawnOrigin(ammo.WeenieClassId, aimLevel);

            var velocity = CalculateProjectileVelocity(localOrigin, AttackTarget, out Vector3 origin, out Quaternion orientation);

            //Console.WriteLine($"Velocity: {velocity}");

            // launch animation
            var actionChain = new ActionChain();
            var launchTime  = EnqueueMotion(actionChain, aimLevel);

            //Console.WriteLine("LaunchTime: " + launchTime);

            // launch projectile
            actionChain.AddAction(this, () =>
            {
                if (IsDead)
                {
                    return;
                }

                var sound = GetLaunchMissileSound(weapon);
                EnqueueBroadcast(new GameMessageSound(Guid, sound, 1.0f));

                // TODO: monster stamina usage

                if (AttackTarget != null)
                {
                    var projectile = LaunchProjectile(weapon, ammo, AttackTarget, origin, orientation, velocity);
                    UpdateAmmoAfterLaunch(ammo);
                }
            });

            // will ammo be depleted?

            /*if (ammo.StackSize == null || ammo.StackSize <= 1)
             * {
             *  // compare monsters: lugianmontokrenegade /  sclavusse / zombielichtowerarcher
             *  actionChain.EnqueueChain();
             *  NextMoveTime = NextAttackTime = Timers.RunningTime + launchTime + MissileDelay;
             *  return;
             * }*/

            // reload animation
            var animSpeed  = GetAnimSpeed();
            var reloadTime = EnqueueMotion(actionChain, MotionCommand.Reload, animSpeed);

            //Console.WriteLine("ReloadTime: " + reloadTime);

            // reset for next projectile
            EnqueueMotion(actionChain, MotionCommand.Ready);

            var linkTime = MotionTable.GetAnimationLength(MotionTableId, CurrentMotionState.Stance, MotionCommand.Reload, MotionCommand.Ready);

            if (weapon.IsThrownWeapon)
            {
                actionChain.EnqueueChain();

                actionChain = new ActionChain();
                actionChain.AddDelaySeconds(linkTime);
            }
            //Console.WriteLine($"Reload time: launchTime({launchTime}) + reloadTime({reloadTime}) + linkTime({linkTime})");

            actionChain.AddAction(this, () => EnqueueBroadcast(new GameMessageParentEvent(this, ammo, ACE.Entity.Enum.ParentLocation.RightHand,
                                                                                          ACE.Entity.Enum.Placement.RightHandCombat)));

            actionChain.EnqueueChain();

            var timeOffset = launchTime + reloadTime + linkTime;

            var missileDelay = MissileDelay;

            if (!weapon.IsAmmoLauncher)
            {
                missileDelay *= 1.5f;
            }

            NextMoveTime = NextAttackTime = Timers.RunningTime + timeOffset + missileDelay;
        }
예제 #28
0
        public void ActOnJoin(ObjectGuid playerId)
        {
            if (active)
            {
                return;
            }

            active = true;
            Player player = CurrentLandblock.GetObject(playerId) as Player;

            // team is either 0 or 1. -1 means failed to join
            var msgJoinResponse = new GameEventJoinGameResponse(player.Session, Guid.Full, 1);

            // 0 or 1 for winning team. -1 is used for stalemate, -2 (and gameId of 0) is used to exit game mode in client
            // var msgGameOver = new GameEventGameOver(player.Session, 0, -2);

            // player.Session.Network.EnqueueSend(msgJoinResponse, msgGameOver);
            player.Session.Network.EnqueueSend(msgJoinResponse);

            // 0xA9B2002E [135.97 133.313 94.4447] 1 0 0 0 (holtburg game location)

            var drudgeRook1 = WorldObjectFactory.CreateNewWorldObject(14343) as GamePiece;

            drudgeRook1.Location = new Position(Location.Cell, Location.PositionX - 3.5f, Location.PositionY - 3.5f, Location.PositionZ - 0.09788f, 0, 0, 0, 1);
            drudgeRook1.EnterWorld();

            var drudgeKnight1 = WorldObjectFactory.CreateNewWorldObject(14344) as GamePiece;

            drudgeKnight1.Location = new Position(Location.Cell, Location.PositionX - 2.5f, Location.PositionY - 3.5f, Location.PositionZ - 0.09771f, 0, 0, 0, 1);
            drudgeKnight1.EnterWorld();

            var drudgeBishop1 = WorldObjectFactory.CreateNewWorldObject(14345) as GamePiece;

            drudgeBishop1.Location = new Position(Location.Cell, Location.PositionX - 1.5f, Location.PositionY - 3.5f, Location.PositionZ - 0.09753f, 0, 0, 0, 1);
            drudgeBishop1.EnterWorld();

            var drudgeQueen = WorldObjectFactory.CreateNewWorldObject(14346) as GamePiece;

            drudgeQueen.Location = new Position(Location.Cell, Location.PositionX - 0.5f, Location.PositionY - 3.5f, Location.PositionZ - 0.09735f, 0, 0, 0, 1);
            drudgeQueen.EnterWorld();

            var drudgeKing = WorldObjectFactory.CreateNewWorldObject(14347) as GamePiece;

            drudgeKing.Location = new Position(Location.Cell, Location.PositionX + 0.5f, Location.PositionY - 3.5f, Location.PositionZ - 0.09718f, 0, 0, 0, 1);
            drudgeKing.EnterWorld();

            var drudgeBishop2 = WorldObjectFactory.CreateNewWorldObject(14345) as GamePiece;

            drudgeBishop2.Location = new Position(Location.Cell, Location.PositionX + 1.5f, Location.PositionY - 3.5f, Location.PositionZ - 0.09753f, 0, 0, 0, 1);
            drudgeBishop2.EnterWorld();

            var drudgeKnight2 = WorldObjectFactory.CreateNewWorldObject(14344) as GamePiece;

            drudgeKnight2.Location = new Position(Location.Cell, Location.PositionX + 2.5f, Location.PositionY - 3.5f, Location.PositionZ - 0.09771f, 0, 0, 0, 1);
            drudgeKnight2.EnterWorld();

            var drudgeRook2 = WorldObjectFactory.CreateNewWorldObject(14343) as GamePiece;

            drudgeRook2.Location = new Position(Location.Cell, Location.PositionX + 3.5f, Location.PositionY - 3.5f, Location.PositionZ - 0.09788f, 0, 0, 0, 1);
            drudgeRook2.EnterWorld();

            var drudgePawn1 = WorldObjectFactory.CreateNewWorldObject(14342) as GamePiece;

            drudgePawn1.Location = new Position(Location.Cell, Location.PositionX - 3.5f, Location.PositionY - 2.5f, Location.PositionZ - 0.09788f, 0, 0, 0, 1);
            drudgePawn1.EnterWorld();

            var drudgePawn2 = WorldObjectFactory.CreateNewWorldObject(14342) as GamePiece;

            drudgePawn2.Location = new Position(Location.Cell, Location.PositionX - 2.5f, Location.PositionY - 2.5f, Location.PositionZ - 0.09771f, 0, 0, 0, 1);
            drudgePawn2.EnterWorld();

            var drudgePawn3 = WorldObjectFactory.CreateNewWorldObject(14342) as GamePiece;

            drudgePawn3.Location = new Position(Location.Cell, Location.PositionX - 1.5f, Location.PositionY - 2.5f, Location.PositionZ - 0.09753f, 0, 0, 0, 1);
            drudgePawn3.EnterWorld();

            var drudgePawn4 = WorldObjectFactory.CreateNewWorldObject(14342) as GamePiece;

            drudgePawn4.Location = new Position(Location.Cell, Location.PositionX - 0.5f, Location.PositionY - 2.5f, Location.PositionZ - 0.09735f, 0, 0, 0, 1);
            drudgePawn4.EnterWorld();

            var drudgePawn5 = WorldObjectFactory.CreateNewWorldObject(14342) as GamePiece;

            drudgePawn5.Location = new Position(Location.Cell, Location.PositionX + 0.5f, Location.PositionY - 2.5f, Location.PositionZ - 0.09718f, 0, 0, 0, 1);
            drudgePawn5.EnterWorld();

            var drudgePawn6 = WorldObjectFactory.CreateNewWorldObject(14342) as GamePiece;

            drudgePawn6.Location = new Position(Location.Cell, Location.PositionX + 1.5f, Location.PositionY - 2.5f, Location.PositionZ - 0.09753f, 0, 0, 0, 1);
            drudgePawn6.EnterWorld();

            var drudgePawn7 = WorldObjectFactory.CreateNewWorldObject(14342) as GamePiece;

            drudgePawn7.Location = new Position(Location.Cell, Location.PositionX + 2.5f, Location.PositionY - 2.5f, Location.PositionZ - 0.09771f, 0, 0, 0, 1);
            drudgePawn7.EnterWorld();

            var drudgePawn8 = WorldObjectFactory.CreateNewWorldObject(14342) as GamePiece;

            drudgePawn8.Location = new Position(Location.Cell, Location.PositionX + 3.5f, Location.PositionY - 2.5f, Location.PositionZ - 0.09788f, 0, 0, 0, 1);
            drudgePawn8.EnterWorld();

            // Nobody ever actually started a game so the database is currently missing the mosswart versions of the above pieces. :(

            // For HellsWrath...
            ActionChain gdlChain = new ActionChain();

            gdlChain.AddDelaySeconds(5);
            gdlChain.AddAction(this, () =>
            {
                drudgeRook1.Kill();
                drudgeBishop1.Kill();
                drudgeKnight1.Kill();
                drudgeQueen.Kill();
                drudgeKing.Kill();
                drudgeBishop2.Kill();
                drudgeKnight2.Kill();
                drudgeRook2.Kill();

                drudgePawn1.Kill();
                drudgePawn2.Kill();
                drudgePawn3.Kill();
                drudgePawn4.Kill();
                drudgePawn5.Kill();
                drudgePawn6.Kill();
                drudgePawn7.Kill();
                drudgePawn8.Kill();

                var msgGameOver = new GameEventGameOver(player.Session, Guid.Full, 0);
                player.Session.Network.EnqueueSend(msgGameOver);
            });
            gdlChain.AddDelaySeconds(2);
            gdlChain.AddAction(this, () =>
            {
                byte[] msg       = Convert.FromBase64String("Z2FtZXNkZWFkbG9s");
                var popupGDL     = new GameEventPopupString(player.Session, System.Text.Encoding.UTF8.GetString(msg, 0, msg.Length));
                var msgGameOver2 = new GameEventGameOver(player.Session, 0, -2);
                player.Session.Network.EnqueueSend(popupGDL, msgGameOver2);
                player.ChessGamesLost++;
                player.ChessTotalGames++;
                active = false;
            });
            gdlChain.EnqueueChain();
        }
예제 #29
0
        public void PlayerEnterWorld()
        {
            PlayerManager.SwitchPlayerFromOfflineToOnline(this);
            Teleporting = true;

            // Save the the LoginTimestamp
            var lastLoginTimestamp = Time.GetUnixTime();

            LoginTimestamp             = lastLoginTimestamp;
            LastTeleportStartTimestamp = lastLoginTimestamp;

            Character.LastLoginTimestamp = lastLoginTimestamp;
            Character.TotalLogins++;
            CharacterChangesDetected = true;

            Sequences.SetSequence(SequenceType.ObjectInstance, new UShortSequence((ushort)Character.TotalLogins));

            if (BarberActive)
            {
                BarberActive = false;
            }

            if (AllegianceNode != null)
            {
                AllegianceRank = (int)AllegianceNode.Rank;
            }
            else
            {
                AllegianceRank = null;
            }

            if (!Account15Days)
            {
                var accountTimeSpan = DateTime.UtcNow - Account.CreateTime;
                if (accountTimeSpan.TotalDays >= 15)
                {
                    Account15Days = true;
                }
            }

            // SendSelf will trigger the entrance into portal space
            SendSelf();

            // Update or override certain properties sent to client.

            // bugged: do not send this here, or else a freshly loaded acclient will overrwrite the values
            // wait until first enter world is completed

            //SendPropertyUpdatesAndOverrides();

            if (PropertyManager.GetBool("use_turbine_chat").Item)
            {
                // Init the client with the chat channel ID's, and then notify the player that they've joined the associated channels.
                Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.TurbineChatIsEnabled));

                if (GetCharacterOption(CharacterOption.ListenToAllegianceChat) && Allegiance != null)
                {
                    JoinTurbineChatChannel("Allegiance");
                }
                if (GetCharacterOption(CharacterOption.ListenToGeneralChat))
                {
                    JoinTurbineChatChannel("General");
                }
                if (GetCharacterOption(CharacterOption.ListenToTradeChat))
                {
                    JoinTurbineChatChannel("Trade");
                }
                if (GetCharacterOption(CharacterOption.ListenToLFGChat))
                {
                    JoinTurbineChatChannel("LFG");
                }
                if (GetCharacterOption(CharacterOption.ListenToRoleplayChat))
                {
                    JoinTurbineChatChannel("Roleplay");
                }
                if (GetCharacterOption(CharacterOption.ListenToSocietyChat) && Society != FactionBits.None)
                {
                    JoinTurbineChatChannel("Society");
                }
            }

            // check if vassals earned XP while offline
            HandleAllegianceOnLogin();
            HandleHouseOnLogin();

            // retail appeared to send the squelch list very early,
            // even before the CreatePlayer, but doing it here
            if (SquelchManager.HasSquelches)
            {
                SquelchManager.SendSquelchDB();
            }

            AuditItemSpells();
            AuditEquippedItems();

            HandleMissingXp();
            HandleSkillCreditRefund();
            HandleSkillTemplesReset();
            HandleSkillSpecCreditRefund();
            HandleFreeSkillResetRenewal();
            HandleFreeAttributeResetRenewal();

            if (PlayerKillerStatus == PlayerKillerStatus.PKLite && !PropertyManager.GetBool("pkl_server").Item)
            {
                var actionChain = new ActionChain();
                actionChain.AddDelaySeconds(3.0f);
                actionChain.AddAction(this, () =>
                {
                    UpdateProperty(this, PropertyInt.PlayerKillerStatus, (int)PlayerKillerStatus.NPK, true);

                    Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YouAreNonPKAgain));
                });
                actionChain.EnqueueChain();
            }

            HandleDBUpdates();
        }
예제 #30
0
        /// <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>
        /// <param name="container"></param>
        /// <param name="itemGuid"></param>
        /// <param name="placement"></param>
        /// <param name="iidPropertyId"></param>
        private void PickupItem(Container container, ObjectGuid itemGuid, int placement, PropertyInstanceId iidPropertyId)
        {
            // Logical operations:
            // !! FIXME: How to handle repeat on condition?
            // while (!objectInRange)
            //   try Move to object
            // !! FIXME: How to handle conditional
            // Try acquire from landblock
            // if acquire successful:
            //   add to container
            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);

            // Ask landblock to transfer item
            // pickUpItemChain.AddAction(CurrentLandblock, () => CurrentLandblock.TransferItem(itemGuid, containerGuid));
            if (container.Guid.IsPlayer())
            {
                CurrentLandblock.QueueItemTransfer(pickUpItemChain, itemGuid, container.Guid);
            }
            else
            {
                CurrentLandblock.ScheduleItemTransferInContainer(pickUpItemChain, itemGuid, (Container)GetInventoryItem(container.Guid));
            }

            // Finish pickup animation
            pickUpItemChain.AddAction(this, () =>
            {
                // If success, the item is in our inventory:
                WorldObject item = GetInventoryItem(itemGuid);

                if (item.ContainerId != Guid.Full)
                {
                    //Burden += item.Burden ?? 0;

                    if (item.WeenieType == WeenieType.Coin)
                    {
                        UpdateCurrencyClientCalculations(WeenieType.Coin);
                    }
                }

                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));
                        UpdateCurrencyClientCalculations(WeenieType.Coin);
                    }
                }

                // Update all our stuff if we succeeded
                if (item != null)
                {
                    item.SetPropertiesForContainer(placement);
                    // FIXME(ddevec): I'm not 100% sure which of these need to be broadcasts, and which are local sends...
                    var motion = new UniversalMotion(MotionStance.Standing);
                    if (iidPropertyId == PropertyInstanceId.Container)
                    {
                        Session.Network.EnqueueSend(
                            ////new GameMessagePrivateUpdatePropertyInt(Session.Player.Sequences, PropertyInt.EncumbranceVal, UpdateBurden()),
                            new GameMessageSound(Guid, Sound.PickUpItem, 1.0f),
                            new GameMessageUpdateInstanceId(itemGuid, container.Guid, iidPropertyId),
                            new GameMessagePutObjectInContainer(Session, container.Guid, item, placement));
                    }
                    else
                    {
                        AddToWieldedObjects(item, container, (EquipMask)placement);
                        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, placement));
                    }

                    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));
                }
                // If we didn't succeed, just stand up and be ashamed of ourself
                else
                {
                    var motion = new UniversalMotion(MotionStance.Standing);

                    CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange,
                                                      new GameMessageUpdateMotion(Guid,
                                                                                  Sequences.GetCurrentSequence(SequenceType.ObjectInstance),
                                                                                  Sequences, motion));
                    // CurrentLandblock.EnqueueBroadcast(self shame);
                }
            });
            // Set chain to run
            pickUpItemChain.EnqueueChain();
        }