Ejemplo n.º 1
0
        public static void Handle(ClientMessage message, Session session)
        {
            var objectGuid          = new ObjectGuid(message.Payload.ReadUInt32());
            QueuedGameAction action = new QueuedGameAction(session.Player.Guid.Full, objectGuid.Full, GameActionType.DropItem);

            session.Player.AddToActionQueue(action);
        }
Ejemplo n.º 2
0
        public static void Handle(ClientMessage message, Session session)
        {
            uint vendorID  = message.Payload.ReadUInt32();
            uint itemcount = message.Payload.ReadUInt32();

            List <ItemProfile> items = new List <ItemProfile>();

            while (itemcount > 0)
            {
                itemcount--;
                ItemProfile item = new ItemProfile();
                item.Amount = message.Payload.ReadUInt32();
                item.Amount = item.Amount & 0xFFFFFF;

                item.Iid = message.Payload.ReadUInt32();
                items.Add(item);
            }

            // curancy 0 default, if else then currancy is set other then money
            uint i_alternateCurrencyID = message.Payload.ReadUInt32();

            // todo: take into account other currencyIds other then assuming default
            QueuedGameAction action = new QueuedGameAction(vendorID, items, GameActionType.Buy);

            session.Player.AddToActionQueue(action);
            return;
        }
Ejemplo n.º 3
0
        public void Kill(Session session)
        {
            IsAlive = false;

            // Create and send the death notice
            string killMessage        = $"{session.Player.Name} has killed {Name}.";
            var    creatureDeathEvent = new GameEventDeathNotice(session, killMessage);

            session.Network.EnqueueSend(creatureDeathEvent);

            // MovementEvent: (Hand-)Combat or in the case of smite: from Standing to Death
            // TODO: Check if the duration of the motion can somehow be computed
            GeneralMotion    motionDeath = new GeneralMotion(MotionStance.Standing, new MotionItem(MotionCommand.Dead));
            QueuedGameAction actionDeath = new QueuedGameAction(this.Guid.Full, motionDeath, 2.0f, true, GameActionType.MovementEvent);

            session.Player.AddToActionQueue(actionDeath);

            // Create Corspe and set a location on the ground
            // TODO: set text of killer in description and find a better computation for the location, some corpse could end up in the ground
            var corpse = CorpseObjectFactory.CreateCorpse(this, this.Location);

            corpse.Location.PositionY -= corpse.PhysicsData.ObjScale;
            corpse.Location.PositionZ -= corpse.PhysicsData.ObjScale / 2;

            // Remove Creature from Landblock and add Corpse in that location via the ActionQueue to honor the motion delays
            QueuedGameAction removeCreature = new QueuedGameAction(this.Guid.Full, this, true, true, GameActionType.ObjectDelete);
            QueuedGameAction addCorpse      = new QueuedGameAction(this.Guid.Full, corpse, true, GameActionType.ObjectCreate);

            session.Player.AddToActionQueue(removeCreature);
            session.Player.AddToActionQueue(addCorpse);
        }
Ejemplo n.º 4
0
        public static void Handle(ClientMessage message, Session session)
        {
            var id = message.Payload.ReadUInt32();
            QueuedGameAction action = new QueuedGameAction(id, GameActionType.IdentifyObject);

            session.Player.AddToExaminationQueue(action);
        }
Ejemplo n.º 5
0
        public static void Handle(ClientMessage message, Session session)
        {
            uint fullId = message.Payload.ReadUInt32();

            QueuedGameAction action = new QueuedGameAction(fullId, GameActionType.QueryHealth);

            session.Player.AddToActionQueue(action);
        }
Ejemplo n.º 6
0
        public static void Handle(ClientMessage message, Session session)
        {
            var itemGuid            = new ObjectGuid(message.Payload.ReadUInt32());
            var containerGuid       = new ObjectGuid(message.Payload.ReadUInt32());
            QueuedGameAction action = new QueuedGameAction(containerGuid.Full, itemGuid.Full, GameActionType.PutItemInContainer);

            session.Player.AddToActionQueue(action);
        }
Ejemplo n.º 7
0
        public static void Handle(ClientMessage message, Session session)
        {
            uint             fullId = message.Payload.ReadUInt32();
            QueuedGameAction action = new QueuedGameAction(fullId, GameActionType.EvtInventoryUseEvent);

            session.Player.AddToActionQueue(action);
            return;
        }
Ejemplo n.º 8
0
        public virtual void OnKill(Session session)
        {
            IsAlive = false;
            // This will determine if the derived type is a player
            var isDerivedPlayer = Guid.IsPlayer();

            // TODO: Implement some proper respawn timers, check the generators for that
            RespawnTime = WorldManager.PortalYearTicks + 10;

            if (!isDerivedPlayer)
            {
                // Create and send the death notice
                string killMessage        = $"{session.Player.Name} has killed {Name}.";
                var    creatureDeathEvent = new GameEventDeathNotice(session, killMessage);
                session.Network.EnqueueSend(creatureDeathEvent);
            }

            // MovementEvent: (Hand-)Combat or in the case of smite: from Standing to Death
            // TODO: Check if the duration of the motion can somehow be computed
            UniversalMotion  motionDeath = new UniversalMotion(MotionStance.Standing, new MotionItem(MotionCommand.Dead));
            QueuedGameAction actionDeath = new QueuedGameAction(this.Guid.Full, motionDeath, 2.0f, true, GameActionType.MovementEvent);

            session.Player.AddToActionQueue(actionDeath);

            // Create Corspe and set a location on the ground
            // TODO: set text of killer in description and find a better computation for the location, some corpse could end up in the ground
            var corpse = CorpseObjectFactory.CreateCorpse(this, this.Location);

            corpse.Location.PositionY -= corpse.PhysicsData.ObjScale;
            corpse.Location.PositionZ -= corpse.PhysicsData.ObjScale / 2;

            // Corpses stay on the ground for 5 * player level but minimum 1 hour
            // corpse.DespawnTime = Math.Max((int)session.Player.PropertiesInt[Enum.Properties.PropertyInt.Level] * 5, 360) + WorldManager.PortalYearTicks; // as in live
            corpse.DespawnTime = 20 + WorldManager.PortalYearTicks; // only for testing

            // If the object is a creature, Remove it from from Landblock
            if (!isDerivedPlayer)
            {
                QueuedGameAction removeCreature = new QueuedGameAction(this.Guid.Full, this, true, true, GameActionType.ObjectDelete);
                session.Player.AddToActionQueue(removeCreature);
            }

            // Add Corpse in that location via the ActionQueue to honor the motion delays
            QueuedGameAction addCorpse = new QueuedGameAction(this.Guid.Full, corpse, true, GameActionType.ObjectCreate);

            session.Player.AddToActionQueue(addCorpse);
        }
Ejemplo n.º 9
0
        private void HandleGameAction(QueuedGameAction action, Player player)
        {
            switch (action.ActionType)
            {
            case GameActionType.TalkDirect:
            {
                // TODO: remove this hack (using TalkDirect) ASAP
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                DeathMessageArgs d = new DeathMessageArgs(action.ActionBroadcastMessage, new ObjectGuid(action.ObjectId), new ObjectGuid(action.SecondaryObjectId));
                HandleDeathMessage(obj, d);
                break;
            }

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

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

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

            case GameActionType.IdentifyObject:
            {
                // TODO: Throttle this request. The live servers did this, likely for a very good reason, so we should, too.
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                var identifyResponse = new GameEventIdentifyObjectResponse(player.Session, action.ObjectId, obj);
                player.Session.Network.EnqueueSend(identifyResponse);
                break;
            }

            case GameActionType.Buy:
            {
                // todo: lots, need vendor list, money checks, etc.

                var money            = new GameMessagePrivateUpdatePropertyInt(player.Session, PropertyInt.CoinValue, 4000);
                var sound            = new GameMessageSound(player.Guid, Sound.PickUpItem, 1);
                var sendUseDoneEvent = new GameEventUseDone(player.Session);
                player.Session.Network.EnqueueSend(money, sound, sendUseDoneEvent);

                // send updated vendor inventory.
                player.Session.Network.EnqueueSend(new GameEventApproachVendor(player.Session, action.ObjectId));

                // this is just some testing code for now.
                foreach (ItemProfile item in action.ProfileItems)
                {
                    // todo: something with vendor id and profile list... iid list from vendor dbs.
                    // todo: something with amounts..

                    if (item.Iid == 5)
                    {
                        while (item.Amount > 0)
                        {
                            item.Amount--;
                            WorldObject loot = LootGenerationFactory.CreateTestWorldObject(5090);
                            LootGenerationFactory.AddToContainer(loot, player);
                            player.TrackObject(loot);
                        }
                        var rudecomment = "Who do you think you are, Johny Apple Seed ?";
                        var buyrudemsg  = new GameMessageSystemChat(rudecomment, ChatMessageType.Tell);
                        player.Session.Network.EnqueueSend(buyrudemsg);
                    }
                    else if (item.Iid == 10)
                    {
                        while (item.Amount > 0)
                        {
                            item.Amount--;
                            WorldObject loot = LootGenerationFactory.CreateTestWorldObject(30537);
                            LootGenerationFactory.AddToContainer(loot, player);
                            player.TrackObject(loot);
                        }
                        var rudecomment = "That smells awful, Enjoy eating it!";
                        var buyrudemsg  = new GameMessageSystemChat(rudecomment, ChatMessageType.Tell);
                        player.Session.Network.EnqueueSend(buyrudemsg);
                    }
                }
                break;
            }

            case GameActionType.PutItemInContainer:
            {
                var playerGuid    = new ObjectGuid(action.ObjectId);
                var inventoryGuid = new ObjectGuid(action.SecondaryObjectId);

                // Has to be a player so need to check before I make the cast.
                // If he is not a player, something is bad wrong. Og II
                if (playerGuid.IsPlayer())
                {
                    var aPlayer       = (Player)GetWorldObject(playerGuid);
                    var inventoryItem = GetWorldObject(inventoryGuid);

                    float arrivedRadiusSquared = 0.00f;
                    bool  validGuids;
                    if (WithinUseRadius(playerGuid, inventoryGuid, out arrivedRadiusSquared, out validGuids))
                    {
                        aPlayer.NotifyAndAddToInventory(inventoryItem);
                    }
                    else
                    {
                        if (validGuids)
                        {
                            aPlayer.SetDestinationInformation(inventoryItem.PhysicsData.Position, arrivedRadiusSquared);
                            aPlayer.BlockedGameAction = action;
                            aPlayer.OnAutonomousMove(inventoryItem.PhysicsData.Position,
                                                     aPlayer.Sequences, MovementTypes.MoveToObject, inventoryGuid);
                        }
                    }
                }
                break;
            }

            case GameActionType.DropItem:
            {
                var g = new ObjectGuid(action.ObjectId);
                if (worldObjects.ContainsKey(g))
                {
                    var playerId    = new ObjectGuid(action.ObjectId);
                    var inventoryId = new ObjectGuid(action.SecondaryObjectId);
                    if (playerId.IsPlayer())
                    {
                        var aPlayer = (Player)worldObjects[playerId];
                        aPlayer.NotifyAndDropItem(inventoryId);
                    }
                }
                break;
            }

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

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

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

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

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

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

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

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

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

                break;
            }

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

                    if ((obj.DescriptionFlags & ObjectDescriptionFlag.LifeStone) != 0)
                    {
                        (obj as Lifestone).OnUse(player);
                    }
                    else if ((obj.DescriptionFlags & ObjectDescriptionFlag.Portal) != 0)
                    {
                        // TODO: When Physics collisions are implemented, this logic should be switched there, as normal portals are not onUse.
                        (obj as Portal).OnCollide(player);
                    }
                    else if ((obj.DescriptionFlags & ObjectDescriptionFlag.Door) != 0)
                    {
                        (obj as Door).OnUse(player);
                    }

                    else if ((obj.DescriptionFlags & ObjectDescriptionFlag.Vendor) != 0)
                    {
                        (obj as Vendor).OnUse(player);
                    }

                    // switch (obj.Type)
                    // {
                    //    case Enum.ObjectType.Portal:
                    //        {
                    //            // TODO: When Physics collisions are implemented, this logic should be switched there, as normal portals are not onUse.
                    //
                    //            (obj as Portal).OnCollide(player);
                    //
                    //            break;
                    //        }
                    //    case Enum.ObjectType.LifeStone:
                    //        {
                    //            (obj as Lifestone).OnUse(player);
                    //            break;
                    //        }
                    // }
                }
                break;
            }
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// main game loop
        /// </summary>
        public void UseTime()
        {
            while (running)
            {
                // here we'd move server objects in motion (subject to landscape) and do physics collision detection

                List <WorldObject> allworldobj    = null;
                List <Player>      allplayers     = null;
                List <Creature>    allcreatures   = null;
                List <WorldObject> movedObjects   = null;
                List <WorldObject> despawnObjects = null;
                List <Creature>    deadCreatures  = null;

                lock (objectCacheLocker)
                {
                    allworldobj = worldObjects.Values.ToList();
                }

                // all players on this land block
                allplayers   = allworldobj.OfType <Player>().ToList();
                allcreatures = allworldobj.OfType <Creature>().ToList();

                despawnObjects = allworldobj.ToList();
                despawnObjects = despawnObjects.Where(x => x.DespawnTime > -1).ToList();

                deadCreatures = allworldobj.OfType <Creature>().ToList();
                deadCreatures = deadCreatures.Where(x => x.IsAlive == false).ToList();

                // flag them as updated now in order to reduce chance of missing an update
                // this is only for moving objects across landblocks.
                movedObjects = allworldobj.ToList();
                movedObjects = movedObjects.Where(p => p.LastUpdatedTicks >= p.LastMovementBroadcastTicks).ToList();
                movedObjects.ForEach(m => m.LastMovementBroadcastTicks = WorldManager.PortalYearTicks);

                if (id.MapScope == Enum.MapScope.Outdoors)
                {
                    // check to see if a player or other mutable object "roamed" to an adjacent landblock
                    var objectsToRelocate = movedObjects.Where(m => m.Location.LandblockId.IsAdjacentTo(id) && m.Location.LandblockId != id).ToList();

                    // so, these objects moved to an adjacent block.  they could have recalled to that block, died and bounced to a lifestone on that block, or
                    // just simply walked accross the border line.  in any case, we won't delete them, we'll just transfer them.  the trick, though, is to
                    // figure out how to treat it in adjacent landblocks.  if the player walks across the southern border, the north adjacency needs to remove
                    // them, but the south is actually getting them.  we need to avoid sending Delete+Create to clients that already know about it, though.

                    objectsToRelocate.ForEach(o => Log($"attempting to relocate object {o.Name} ({o.Guid.Full.ToString("X")})"));

                    // RelocateObject will put them in the right landblock
                    objectsToRelocate.ForEach(o => LandblockManager.RelocateObject(o));

                    // Remove has logic to make sure it doesn't double up the delete+create when "true" is passed.
                    objectsToRelocate.ForEach(o => RemoveWorldObject(o.Guid, true));
                }

                // for all players on landblock.
                Parallel.ForEach(allplayers, player =>
                {
                    // Process Action Queue for player.
                    QueuedGameAction action = player.ActionQueuePop();
                    if (action != null)
                    {
                        HandleGameAction(action, player);
                    }

                    // Process Examination Queue for player
                    QueuedGameAction examination = player.ExaminationQueuePop();
                    if (examination != null)
                    {
                        HandleGameAction(examination, player);
                    }
                });
                UpdateStatus(allplayers.Count);

                double tickTime = WorldManager.PortalYearTicks;
                // per-creature update on landblock.
                Parallel.ForEach(allworldobj, wo =>
                {
                    // Process the creatures
                    wo.Tick(tickTime);
                });

                // broadcast moving objects to the world..
                // players and creatures can move.
                Parallel.ForEach(movedObjects, mo =>
                {
                    // detect all world objects in ghost range
                    List <WorldObject> woproxghost = new List <WorldObject>();
                    woproxghost.AddRange(GetWorldObjectsInRange(mo, maxobjectGhostRange, true));

                    // for all objects in rang of this moving object or in ghost range of moving object update them.
                    Parallel.ForEach(woproxghost, wo =>
                    {
                        if (mo.Guid.IsPlayer())
                        {
                            // if world object is in active zone then.
                            if (wo.Location.SquaredDistanceTo(mo.Location) <= maxobjectRange)
                            {
                                // if world object is in active zone.
                                if (!(mo as Player).GetTrackedObjectGuids().Contains(wo.Guid))
                                {
                                    (mo as Player).TrackObject(wo);
                                }
                            }
                            // if world object is in ghost zone and outside of active zone
                            else
                            if ((mo as Player).GetTrackedObjectGuids().Contains(wo.Guid))
                            {
                                (mo as Player).StopTrackingObject(wo, true);
                            }
                        }
                    });

                    if (mo.Location.LandblockId == id)
                    {
                        // update if it's still here
                        Broadcast(BroadcastEventArgs.CreateAction(BroadcastAction.AddOrUpdate, mo), true, Quadrant.All);
                    }
                    else
                    {
                        // remove and readd if it's not
                        RemoveWorldObject(mo.Guid, false);
                        LandblockManager.AddObject(mo);
                    }
                });

                // despawn objects
                despawnObjects.ForEach(deo =>
                {
                    if (deo.DespawnTime < WorldManager.PortalYearTicks)
                    {
                        RemoveWorldObject(deo.Guid, false);
                    }
                });

                // respawn creatures
                deadCreatures.ForEach(dc =>
                {
                    if (dc.RespawnTime < WorldManager.PortalYearTicks)
                    {
                        dc.IsAlive = true;
                        // HandleParticleEffectEvent(dc, PlayScript.Create);
                        AddWorldObject(dc);
                    }
                });

                Thread.Sleep(1);
            }

            // TODO: release resources
        }
Ejemplo n.º 11
0
        private void HandleGameAction(QueuedGameAction action, Player player)
        {
            switch (action.ActionType)
            {
            case GameActionType.TalkDirect:
            {
                // TODO: remove this hack (using TalkDirect) ASAP
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                DeathMessageArgs d = new DeathMessageArgs(action.ActionBroadcastMessage, new ObjectGuid(action.ObjectId), new ObjectGuid(action.SecondaryObjectId));
                HandleDeathMessage(obj, d);
                break;
            }

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

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

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

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

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

                    if ((aPlayer != null) && (inventoryItem != null))
                    {
                        var motion = new GeneralMotion(MotionStance.Standing);
                        motion.MovementData.ForwardCommand = (ushort)MotionCommand.Pickup;
                        aPlayer.Session.Network.EnqueueSend(new GameMessageUpdatePosition(aPlayer),
                                                            new GameMessageUpdateMotion(aPlayer, aPlayer.Session, motion),
                                                            new GameMessageSound(aPlayer.Guid, Sound.PickUpItem, (float)1.0));

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

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

                        aPlayer.TrackObject(inventoryItem);
                    }
                }
                break;
            }

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

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

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

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

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

                            // This is the sequence magic - adds back into 3d space seem to be treated like teleport.
                            inventoryItem.Sequences.GetNextSequence(SequenceType.ObjectTeleport);
                            inventoryItem.Sequences.GetNextSequence(SequenceType.ObjectVector);
                            LandblockManager.AddObject(inventoryItem);
                            aPlayer.Session.Network.EnqueueSend(new GameMessageUpdatePosition(inventoryItem));
                        }
                    }
                }
                break;
            }

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

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

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

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

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

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

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

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

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

                break;
            }

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

                    switch (obj.Type)
                    {
                    case Enum.ObjectType.Portal:
                    {
                        // validate within use range :: set to a fixed value as static Portals are normally OnCollide usage
                        float rangeCheck = 5.0f;

                        if (player.Location.SquaredDistanceTo(obj.Location) < rangeCheck)
                        {
                            PortalDestination portalDestination = DatabaseManager.World.GetPortalDestination(obj.WeenieClassid);

                            if (portalDestination != null)
                            {
                                player.Session.Player.Teleport(portalDestination.Position);
                                // always send useDone event
                                var sendUseDoneEvent = new GameEventUseDone(player.Session);
                                player.Session.Network.EnqueueSend(sendUseDoneEvent);
                            }
                            else
                            {
                                string serverMessage    = "Portal destination for portal ID " + obj.WeenieClassid + " not yet implemented!";
                                var    usePortalMessage = new GameMessageSystemChat(serverMessage, ChatMessageType.System);
                                // always send useDone event
                                var sendUseDoneEvent = new GameEventUseDone(player.Session);
                                player.Session.Network.EnqueueSend(usePortalMessage, sendUseDoneEvent);
                            }
                        }
                        else
                        {
                            // always send useDone event
                            var sendUseDoneEvent = new GameEventUseDone(player.Session);
                            player.Session.Network.EnqueueSend(sendUseDoneEvent);
                        }

                        break;
                    }

                    case Enum.ObjectType.LifeStone:
                    {
                        string serverMessage = null;
                        // validate within use range
                        float radiusSquared = obj.GameData.UseRadius * obj.GameData.UseRadius;

                        var motionSanctuary = new GeneralMotion(MotionStance.Standing, new MotionItem(MotionCommand.Sanctuary));

                        var animationEvent = new GameMessageUpdateMotion(player, player.Session, motionSanctuary);

                        // This event was present for a pcap in the training dungeon.. Why? The sound comes with animationEvent...
                        var soundEvent = new GameMessageSound(obj.Guid, Sound.LifestoneOn, 1);

                        if (player.Location.SquaredDistanceTo(obj.Location) >= radiusSquared)
                        {
                            serverMessage = "You wandered too far to attune with the Lifestone!";
                        }
                        else
                        {
                            player.SetCharacterPosition(PositionType.Sanctuary, player.Location);

                            // create the outbound server message
                            serverMessage = "You have attuned your spirit to this Lifestone. You will resurrect here after you die.";
                            player.EnqueueMovementEvent(motionSanctuary, player.Guid);
                            player.Session.Network.EnqueueSend(soundEvent);
                        }

                        var lifestoneBindMessage = new GameMessageSystemChat(serverMessage, ChatMessageType.Magic);
                        // always send useDone event
                        var sendUseDoneEvent = new GameEventUseDone(player.Session);
                        player.Session.Network.EnqueueSend(lifestoneBindMessage, sendUseDoneEvent);

                        break;
                    }
                    }
                }
                break;
            }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// main game loop
        /// </summary>
        public void UseTime()
        {
            while (running)
            {
                // here we'd move server objects in motion (subject to landscape) and do physics collision detection

                // for now, we'll move players around
                List <WorldObject> movedObjects = null;
                List <Player>      players      = null;

                lock (objectCacheLocker)
                {
                    movedObjects = this.worldObjects.Values.OfType <WorldObject>().ToList();
                    players      = this.worldObjects.Values.OfType <Player>().ToList();
                }

                movedObjects = movedObjects.Where(p => p.LastUpdatedTicks >= p.LastMovementBroadcastTicks).ToList();

                // flag them as updated now in order to reduce chance of missing an update
                movedObjects.ForEach(m => m.LastMovementBroadcastTicks = WorldManager.PortalYearTicks);

                if (this.id.MapScope == Enum.MapScope.Outdoors)
                {
                    // check to see if a player or other mutable object "roamed" to an adjacent landblock
                    var objectsToRelocate = movedObjects.Where(m => m.Location.LandblockId.IsAdjacentTo(this.id) && m.Location.LandblockId != this.id).ToList();

                    // so, these objects moved to an adjacent block.  they could have recalled to that block, died and bounced to a lifestone on that block, or
                    // just simply walked accross the border line.  in any case, we won't delete them, we'll just transfer them.  the trick, though, is to
                    // figure out how to treat it in adjacent landblocks.  if the player walks across the southern border, the north adjacency needs to remove
                    // them, but the south is actually getting them.  we need to avoid sending Delete+Create to clients that already know about it, though.

                    objectsToRelocate.ForEach(o => Log($"attempting to relocate object {o.Name} ({o.Guid.Full.ToString("X")})"));

                    // RelocateObject will put them in the right landblock
                    objectsToRelocate.ForEach(o => LandblockManager.RelocateObject(o));

                    // Remove has logic to make sure it doesn't double up the delete+create when "true" is passed.
                    objectsToRelocate.ForEach(o => RemoveWorldObject(o.Guid, true));
                }

                // broadcast
                Parallel.ForEach(movedObjects, mo =>
                {
                    if (mo.Location.LandblockId == this.id)
                    {
                        // update if it's still here
                        Broadcast(BroadcastEventArgs.CreateAction(BroadcastAction.AddOrUpdate, mo), true, Quadrant.All);
                    }
                    else
                    {
                        // remove and readd if it's not
                        this.RemoveWorldObject(mo.Guid, false);
                        LandblockManager.AddObject(mo);
                    }
                });

                // TODO: figure out if this landblock can be unloaded

                // process player action queues
                foreach (Player p in players)
                {
                    QueuedGameAction action = p.ActionQueuePop();

                    if (action != null)
                    {
                        HandleGameAction(action, p);
                    }
                }

                Thread.Sleep(1);
            }

            // TODO: release resources
        }
Ejemplo n.º 13
0
        private void HandleGameAction(QueuedGameAction action, Player player)
        {
            switch (action.ActionType)
            {
            case GameActionType.TalkDirect:
            {
                // TODO: remove this hack (using TalkDirect) ASAP
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                DeathMessageArgs d = new DeathMessageArgs(action.ActionBroadcastMessage, new ObjectGuid(action.ObjectId), new ObjectGuid(action.SecondaryObjectId));
                HandleDeathMessage(obj, d);
                break;
            }

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

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

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

            case GameActionType.IdentifyObject:
            {
                // TODO: Throttle this request. The live servers did this, likely for a very good reason, so we should, too.
                var         g   = new ObjectGuid(action.ObjectId);
                WorldObject obj = (WorldObject)player;
                if (worldObjects.ContainsKey(g))
                {
                    obj = worldObjects[g];
                }
                var identifyResponse = new GameEventIdentifyObjectResponse(player.Session, action.ObjectId, obj);
                player.Session.Network.EnqueueSend(identifyResponse);
                break;
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                break;
            }

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

                    if ((obj.DescriptionFlags & ObjectDescriptionFlag.LifeStone) != 0)
                    {
                        (obj as Lifestone).OnUse(player);
                    }
                    else if ((obj.DescriptionFlags & ObjectDescriptionFlag.Portal) != 0)
                    {
                        // TODO: When Physics collisions are implemented, this logic should be switched there, as normal portals are not onUse.
                        (obj as Portal).OnCollide(player);
                    }
                    else if ((obj.DescriptionFlags & ObjectDescriptionFlag.Door) != 0)
                    {
                        (obj as Door).OnUse(player);
                    }

                    // switch (obj.Type)
                    // {
                    //    case Enum.ObjectType.Portal:
                    //        {
                    //            // TODO: When Physics collisions are implemented, this logic should be switched there, as normal portals are not onUse.
                    //
                    //            (obj as Portal).OnCollide(player);
                    //
                    //            break;
                    //        }
                    //    case Enum.ObjectType.LifeStone:
                    //        {
                    //            (obj as Lifestone).OnUse(player);
                    //            break;
                    //        }
                    // }
                }
                break;
            }
            }
        }