Example #1
0
        /// <summary>
        /// Launches a projectile from player to target
        /// </summary>
        public WorldObject LaunchProjectile(WorldObject weapon, WorldObject ammo, WorldObject target, Vector3 origin, Quaternion orientation, Vector3 velocity)
        {
            var player = this as Player;

            if (!velocity.IsValid())
            {
                if (player != null)
                {
                    player.SendWeenieError(WeenieError.YourAttackMisfired);
                }

                return(null);
            }

            var proj = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId);

            proj.ProjectileSource = this;
            proj.ProjectileTarget = target;

            proj.ProjectileLauncher = weapon;

            proj.Location = new Position(Location.ObjCellID, origin, orientation, false, Location.Instance);

            SetProjectilePhysicsState(proj, target, velocity);

            var success = LandblockManager.AddObject(proj);

            if (!success || proj.PhysicsObj == null)
            {
                if (!proj.HitMsg && player != null)
                {
                    player.Session.Network.EnqueueSend(new GameMessageSystemChat("Your missile attack hit the environment.", ChatMessageType.Broadcast));
                }

                return(null);
            }

            if (!IsProjectileVisible(proj))
            {
                proj.OnCollideEnvironment();
                return(null);
            }

            var pkStatus = player?.PlayerKillerStatus ?? PlayerKillerStatus.Creature;

            proj.EnqueueBroadcast(new GameMessagePublicUpdatePropertyInt(proj, PropertyInt.PlayerKillerStatus, (int)pkStatus));
            proj.EnqueueBroadcast(new GameMessageScript(proj.Guid, PlayScript.Launch, 0f));

            // detonate point-blank projectiles immediately

            /*var radsum = target.PhysicsObj.GetRadius() + proj.PhysicsObj.GetRadius();
             * var dist = Vector3.Distance(origin, dest);
             * if (dist < radsum)
             * {
             *  Console.WriteLine($"Point blank");
             *  proj.OnCollideObject(target);
             * }*/

            return(proj);
        }
Example #2
0
        /// <summary>
        /// Launches a projectile from player to target
        /// </summary>
        public WorldObject LaunchProjectile(WorldObject weapon, WorldObject ammo, WorldObject target, out float time)
        {
            var proj = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId);

            proj.ProjectileSource = this;
            proj.ProjectileTarget = target;

            proj.ProjectileLauncher = weapon;

            var matchIndoors = Location.Indoors == target.Location.Indoors;
            var origin       = matchIndoors ? Location.ToGlobal() : Location.Pos;

            origin.Z += Height;

            var dest = matchIndoors ? target.Location.ToGlobal() : target.Location.Pos;

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

            var speed = 35.0f;  // TODO: get correct speed
            var dir   = GetDir2D(origin, dest);

            origin += dir * 2.0f;

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

            proj.Velocity = velocity;

            proj.Location = matchIndoors ? Location.FromGlobal(origin) : new Position(Location.Cell, origin, Location.Rotation);
            if (!matchIndoors)
            {
                proj.Location.LandblockId = new LandblockId(proj.Location.GetCell());
            }

            SetProjectilePhysicsState(proj, target);

            var result = LandblockManager.AddObject(proj);

            if (proj.PhysicsObj == null)
            {
                return(null);
            }

            var player   = this as Player;
            var pkStatus = player?.PlayerKillerStatus ?? PlayerKillerStatus.Creature;

            proj.EnqueueBroadcast(new GameMessagePublicUpdatePropertyInt(proj, PropertyInt.PlayerKillerStatus, (int)pkStatus));
            proj.EnqueueBroadcast(new GameMessageScript(proj.Guid, ACE.Entity.Enum.PlayScript.Launch, 0f));

            // detonate point-blank projectiles immediately

            /*var radsum = target.PhysicsObj.GetRadius() + proj.PhysicsObj.GetRadius();
             * var dist = Vector3.Distance(origin, dest);
             * if (dist < radsum)
             * {
             *  Console.WriteLine($"Point blank");
             *  proj.OnCollideObject(target);
             * }*/

            return(proj);
        }
Example #3
0
        public static void TestSpell(Session session, params string[] parameters)
        {
            uint  templatid;
            float x, y, z;
            float friction;
            float electicity;

            try
            {
                templatid  = Convert.ToUInt32(parameters[0]);
                x          = float.Parse(parameters[1], CultureInfo.InvariantCulture.NumberFormat);
                y          = float.Parse(parameters[2], CultureInfo.InvariantCulture.NumberFormat);
                z          = float.Parse(parameters[3], CultureInfo.InvariantCulture.NumberFormat);
                friction   = float.Parse(parameters[4], CultureInfo.InvariantCulture.NumberFormat);
                electicity = float.Parse(parameters[5], CultureInfo.InvariantCulture.NumberFormat);
            }
            catch (Exception)
            {
                ChatPacket.SendServerMessage(session, $"Invalid Spell Parameters", ChatMessageType.Broadcast);
                return;
            }

            AceVector3 velocity = new AceVector3(x, y, z);

            LandblockManager.AddObject(SpellObjectFactory.CreateSpell(templatid, session.Player.Location.InFrontOf(2.0f), velocity, friction, electicity));
        }
Example #4
0
        // This is throw away code to understand the world object creation process.

        public static void Spawn(WorldObject inventoryItem, Position position)
        {
            inventoryItem.Sequences.GetNextSequence(SequenceType.ObjectTeleport);
            inventoryItem.Sequences.GetNextSequence(SequenceType.ObjectVector);
            inventoryItem.Location = position.InFrontOf(1.00f);
            inventoryItem.PhysicsDescriptionFlag |= PhysicsDescriptionFlag.Position;
            LandblockManager.AddObject(inventoryItem);
        }
Example #5
0
 public void EnterWorld()
 {
     if (Location != null)
     {
         LandblockManager.AddObject(this);
         if (SuppressGenerateEffect != true)
         {
             ApplyVisualEffects(ACE.Entity.Enum.PlayScript.Create);
         }
     }
 }
        /// <summary>
        /// creates a portal of the specified weenie at the position provided
        /// </summary>
        public static void SpawnPortal(PortalWcid weenieClassId, Position newPosition, float despawnTime)
        {
            WorldObject portal = WorldObjectFactory.CreateNewWorldObject((uint)weenieClassId);

            portal.Positions.Add(PositionType.Location, newPosition);

            LandblockManager.AddObject(portal);

            // Create portal decay
            ActionChain despawnChain = new ActionChain();

            despawnChain.AddDelaySeconds(despawnTime);
            despawnChain.AddAction(portal, () => portal.CurrentLandblock.RemoveWorldObject(portal.Guid, false));
            despawnChain.EnqueueChain();
        }
Example #7
0
        /// <summary>
        /// Launches a projectile from player to target
        /// </summary>
        public WorldObject LaunchProjectile(WorldObject ammo, WorldObject target, out float time)
        {
            var proj = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId);

            proj.ProjectileSource = this;
            proj.ProjectileTarget = target;

            var origin = Location.ToGlobal();

            origin.Z += Height;

            var dest = target.Location.ToGlobal();

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

            var speed = 35.0f;  // TODO: get correct speed
            var dir   = GetDir2D(origin, dest);

            origin += dir * 2.0f;

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

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

            proj.Location = Location.FromGlobal(origin);

            SetProjectilePhysicsState(proj, target);

            LandblockManager.AddObject(proj);

            var player   = this as Player;
            var pkStatus = player == null ? PlayerKillerStatus.Creature : player.PlayerKillerStatus;

            proj.EnqueueBroadcast(new GameMessagePublicUpdatePropertyInt(proj, PropertyInt.PlayerKillerStatus, (int)pkStatus));
            proj.EnqueueBroadcast(new GameMessageScript(proj.Guid, ACE.Entity.Enum.PlayScript.Launch, 0f));

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

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

            return(proj);
        }
Example #8
0
        /// <summary>
        /// creates a portal of the specified weenie at the position provided
        /// </summary>
        public static void SpawnPortal(PortalWcid weenieClassId, Position newPosition, float despawnTime)
        {
            AceObject aceO = DatabaseManager.World.GetAceObjectByWeenie((ushort)weenieClassId);

            aceO.AceObjectPropertiesPositions.Add(PositionType.Location, newPosition);

            WorldObject portal = new Portal(aceO);

            portal.Guid = GuidManager.NewItemGuid();

            LandblockManager.AddObject(portal);

            // Create portal decay
            ActionChain despawnChain = new ActionChain();

            despawnChain.AddDelaySeconds(despawnTime);
            despawnChain.AddAction(portal, () => portal.CurrentLandblock.RemoveWorldObject(portal.Guid, false));
            despawnChain.EnqueueChain();
        }
Example #9
0
        public static void CreateStaticCreature(Session session, params string[] parameters)
        {
            Creature newC = null;

            if (!(parameters?.Length > 0))
            {
                ChatPacket.SendServerMessage(session, "Usage: @createcreature [static] weenieClassId",
                                             ChatMessageType.Broadcast);
                return;
            }
            if (parameters?[0] == "static")
            {
                if (parameters?.Length > 1)
                {
                    uint weenie = Convert.ToUInt32(parameters[1]);
                    newC = MonsterFactory.SpawnCreature(weenie, true, session.Player.Location.InFrontOf(2.0f));
                }
                else
                {
                    ChatPacket.SendServerMessage(session, "Specify a valid weenieClassId after the static option.",
                                                 ChatMessageType.Broadcast);
                    return;
                }
            }
            else
            {
                uint weenie = Convert.ToUInt32(parameters[0]);
                newC = MonsterFactory.SpawnCreature(weenie, false, session.Player.Location.InFrontOf(2.0f));
            }

            if (newC != null)
            {
                ChatPacket.SendServerMessage(session, $"Now spawning {newC.Name}.",
                                             ChatMessageType.Broadcast);
                LandblockManager.AddObject(newC);
            }
            else
            {
                ChatPacket.SendServerMessage(session, "Couldn't find that creature in the database or save it's location.",
                                             ChatMessageType.Broadcast);
            }
        }
Example #10
0
        /// <summary>
        /// Launches a projectile from player to target
        /// </summary>
        public float LaunchProjectile(WorldObject target)
        {
            var ammo  = GetEquippedAmmo();
            var arrow = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId);

            var origin = Location.ToGlobal();

            origin.Z += Height;

            var dest = target.Location.ToGlobal();

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

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

            origin += dir * 2.0f;

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

            var loc = Location;

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

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

            var actionChain = new ActionChain();

            actionChain.AddDelaySeconds(time);
            actionChain.AddAction(arrow, () => Session.Network.EnqueueSend(new GameMessageSound(arrow.Guid, Sound.Collision, 1.0f)));
            actionChain.AddAction(arrow, () => CurrentLandblock.RemoveWorldObject(arrow.Guid, false));
            actionChain.EnqueueChain();

            return(time);
        }
Example #11
0
        public static void CreateStaticCreature(Session session, params string[] parameters)
        {
            if (!(parameters?.Length > 0))
            {
                ChatPacket.SendServerMessage(session, "Usage: @createstaticcreature weenieClassId",
                                             ChatMessageType.Broadcast);
                return;
            }
            uint     weenie = Convert.ToUInt32(parameters[0]);
            Creature newC   = MonsterFactory.SpawnStaticCreature(weenie, session.Player.Location.InFrontOf(2.0f));

            if (newC != null)
            {
                ChatPacket.SendServerMessage(session, $"Now spawning {newC.Name}",
                                             ChatMessageType.Broadcast);
                LandblockManager.AddObject(newC);
            }
            else
            {
                ChatPacket.SendServerMessage(session, "Couldn't find that creature in the database or save it's location.",
                                             ChatMessageType.Broadcast);
            }
        }
Example #12
0
        public static void CreateTrainingWand(Session session, params string[] parameters)
        {
            if (!(parameters?.Length > 0))
            {
                ChatPacket.SendServerMessage(session, "Usage: @ctw me or @ctw ground",
                                             ChatMessageType.Broadcast);
                return;
            }
            string location = parameters[0];

            if (location == "me" | location == "ground")
            {
                WorldObject loot = LootGenerationFactory.CreateTrainingWand(session.Player);
                switch (location)
                {
                case "me":
                {
                    LootGenerationFactory.AddToContainer(loot, session.Player);
                    session.Player.TrackObject(loot);
                    // TODO: Have to send game message CFS
                    break;
                }

                case "ground":
                {
                    LootGenerationFactory.Spawn(loot, session.Player.Location.InFrontOf(1.0f));
                    LandblockManager.AddObject(loot);
                    break;
                }
                }
            }
            else
            {
                ChatPacket.SendServerMessage(session, "Usage: @ctw me or @ctw ground",
                                             ChatMessageType.Broadcast);
            }
        }
Example #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.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;
            }
            }
        }
Example #14
0
        /// <summary>
        /// Launches a projectile from player to target
        /// </summary>
        public WorldObject LaunchProjectile(WorldObject target, out float time)
        {
            var ammo  = GetEquippedAmmo();
            var arrow = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId);

            var origin = Location.ToGlobal();

            origin.Z += Height;

            var dest = target.Location.ToGlobal();

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

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

            origin += dir * 2.0f;

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

            var loc = Location;

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

            var actionChain = new ActionChain();

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

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

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

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

            var player = this as Player;

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

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

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

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

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

            return(arrow);
        }
Example #15
0
        private void CreateCorpse()
        {
            if (NoCorpse ?? false)
            {
                return;
            }

            var corpse = WorldObjectFactory.CreateNewWorldObject(DatabaseManager.World.GetCachedWeenie("corpse")) as Corpse;

            corpse.SetupTableId   = SetupTableId;
            corpse.MotionTableId  = MotionTableId;
            corpse.SoundTableId   = SoundTableId;
            corpse.PaletteBaseDID = PaletteBaseDID;
            corpse.ClothingBase   = ClothingBase;
            corpse.PhysicsTableId = PhysicsTableId;

            if (ObjScale.HasValue)
            {
                corpse.ObjScale = ObjScale;
            }
            if (PaletteTemplate.HasValue)
            {
                corpse.PaletteTemplate = PaletteTemplate;
            }
            if (Shade.HasValue)
            {
                corpse.Shade = Shade;
            }
            //if (Translucency.HasValue) // Shadows have Translucency but their corpses do not, videographic evidence can be found on YouTube.
            //    corpse.Translucency = Translucency;

            if (EquippedObjects.Values.Where(x => (x.CurrentWieldedLocation & (EquipMask.Clothing | EquipMask.Armor | EquipMask.Cloak)) != 0).ToList().Count > 0) // If creature is wearing objects, we need to save the appearance
            {
                var objDesc = CalculateObjDesc();

                foreach (var animPartChange in objDesc.AnimPartChanges)
                {
                    corpse.Biota.BiotaPropertiesAnimPart.Add(new Database.Models.Shard.BiotaPropertiesAnimPart {
                        ObjectId = corpse.Guid.Full, AnimationId = animPartChange.PartID, Index = animPartChange.PartIndex
                    });
                }

                foreach (var subPalette in objDesc.SubPalettes)
                {
                    corpse.Biota.BiotaPropertiesPalette.Add(new Database.Models.Shard.BiotaPropertiesPalette {
                        ObjectId = corpse.Guid.Full, SubPaletteId = subPalette.SubID, Length = (ushort)subPalette.NumColors, Offset = (ushort)subPalette.Offset
                    });
                }

                foreach (var textureChange in objDesc.TextureChanges)
                {
                    corpse.Biota.BiotaPropertiesTextureMap.Add(new Database.Models.Shard.BiotaPropertiesTextureMap {
                        ObjectId = corpse.Guid.Full, Index = textureChange.PartIndex, OldId = textureChange.OldTexture, NewId = textureChange.NewTexture
                    });
                }
            }

            //corpse.Location = Location;
            corpse.Location = DatManager.PortalDat.ReadFromDat <MotionTable>(MotionTableId).GetAnimationFinalPositionFromStart(Location, ObjScale ?? 1, MotionCommand.Dead);
            //corpse.Location.PositionZ = corpse.Location.PositionZ - .5f; // Adding BaseDescriptionFlags |= ObjectDescriptionFlag.Corpse to Corpse objects made them immune to gravity.. this seems to fix floating corpse...

            corpse.Name = $"Corpse of {Name}";

            string killerName = null;

            if (Killer.HasValue && Killer != 0)
            {
                var killer = CurrentLandblock.GetObject(new ObjectGuid(Killer ?? 0));

                if (killer != null)
                {
                    killerName = killer.Name;
                }
            }

            if (String.IsNullOrEmpty(killerName))
            {
                killerName = "misadventure";
            }

            corpse.LongDesc = $"Killed by {killerName}";

            if (Killer.HasValue)
            {
                corpse.SetProperty(PropertyInstanceId.AllowedActivator, Killer.Value); // Think this will be what limits corpses to Killer first.
            }
            // Transfer of generated treasure from creature to corpse here

            var random = new Random((int)DateTime.UtcNow.Ticks);
            int level  = (int)this.Level;
            int tier;

            if (level < 16)
            {
                tier = 1;
            }
            else if (level < 31)
            {
                tier = 2;
            }
            else if (level < 60)
            {
                tier = 3;
            }
            else if (level < 80)
            {
                tier = 4;
            }
            else if (level < 115)
            {
                tier = 5;
            }
            else if (level < 160)
            {
                tier = 6;
            }
            else
            {
                tier = 7;
            }
            ////Tier 8 is reserved for special creatures, usually based on which landblock they were on...Not level based. to be added later
            foreach (var trophy in Biota.BiotaPropertiesCreateList.Where(x => x.DestinationType == (int)DestinationType.Contain || x.DestinationType == (int)DestinationType.Treasure || x.DestinationType == (int)DestinationType.ContainTreasure || x.DestinationType == (int)DestinationType.ShopTreasure || x.DestinationType == (int)DestinationType.WieldTreasure).OrderBy(x => x.Shade))
            {
                if (random.NextDouble() < trophy.Shade || trophy.Shade == 1 || trophy.Shade == 0) // Shade in this context is Probability
                // Should there be rolls for each item or one roll to rule them all?
                {
                    if (trophy.WeenieClassId == 0) // Randomized Loot
                    {
                        var wo = LootGenerationFactory.CreateRandomLootObjects(tier);

                        corpse.TryAddToInventory(wo);

                        //var book = WorldObjectFactory.CreateNewWorldObject("parchment") as Book;

                        //if (book == null)
                        //    continue;

                        //book.SetProperties("IOU", "An IOU for a random loot.", "Sorry about that chief...", "ACEmulator", "prewritten");
                        //book.AddPage(corpse.Guid.Full, "ACEmulator", "prewritten", false, $"Sorry but at this time we do not have randomized and mutated loot in ACEmulator, you can ignore this item as it's meant only to be placeholder");

                        //corpse.TryAddToInventory(book);
                    }
                    else // Trophy Loot
                    {
                        var wo = WorldObjectFactory.CreateNewWorldObject(trophy.WeenieClassId);

                        if (wo == null)
                        {
                            continue;
                        }

                        if (trophy.StackSize > 1)
                        {
                            wo.StackSize = (ushort)trophy.StackSize;
                        }

                        if (trophy.Palette > 0)
                        {
                            wo.PaletteTemplate = trophy.Palette;
                        }

                        corpse.TryAddToInventory(wo);
                    }
                }
            }
            corpse.RemoveProperty(PropertyInt.Value);
            LandblockManager.AddObject(corpse);
        }
Example #16
0
 public static void CreatePortal(Session session, params string[] parameters)
 {
     LandblockManager.AddObject(PortalObjectFactory.CreatePortal(1234, session.Player.Location.InFrontOf(3.0f), "Test Portal", PortalType.Purple));
 }
Example #17
0
 public static void CreateLifeStone(Session session, params string[] parameters)
 {
     LandblockManager.AddObject(LifestoneObjectFactory.CreateLifestone(509, session.Player.Location.InFrontOf(3.0f), LifestoneType.Original));
 }
Example #18
0
        /// <summary>
        /// Launches a projectile from player to target
        /// </summary>
        public WorldObject LaunchProjectile(WorldObject target, out float time)
        {
            var ammo  = GetEquippedAmmo();
            var arrow = WorldObjectFactory.CreateNewWorldObject(ammo.WeenieClassId);

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

            var origin = Location.ToGlobal();

            origin.Z += Height;

            var dest = target.Location.ToGlobal();

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

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

            origin += dir * 2.0f;

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

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

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

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

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

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

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

            LandblockManager.AddObject(arrow);
            arrow.EnqueueBroadcast(new GameMessagePickupEvent(ammo));

            var player = this as Player;

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

            var pkStatus = player == null ? PlayerKillerStatus.Creature : player.PlayerKillerStatus;

            arrow.EnqueueBroadcast(new GameMessagePublicUpdatePropertyInt(arrow, PropertyInt.PlayerKillerStatus, (int)pkStatus));
            arrow.EnqueueBroadcast(new GameMessageScript(arrow.Guid, ACE.Entity.Enum.PlayScript.Launch, 0f));

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

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

            return(arrow);
        }
Example #19
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
        }
Example #20
0
        /// <summary>
        /// Creates the Magic projectile spells for Life, War, and Void Magic
        /// </summary>
        /// <param name="caster"></param>
        /// <param name="target"></param>
        /// <param name="spellId"></param>
        /// <param name="projectileWcid"></param>
        /// <param name="lifeProjectileDamage"></param>
        private void CreateSpellProjectile(WorldObject caster, WorldObject target, uint spellId, uint projectileWcid, uint lifeProjectileDamage = 0)
        {
            SpellProjectile spellProjectile = WorldObjectFactory.CreateNewWorldObject(projectileWcid) as SpellProjectile;

            spellProjectile.Setup(spellId);

            var origin = caster.Location.ToGlobal();

            if (spellProjectile.SpellType == SpellProjectile.ProjectileSpellType.Arc)
            {
                origin.Z += caster.Height;
            }
            else
            {
                origin.Z += caster.Height * 2.0f / 3.0f;
            }

            var dest = target.Location.ToGlobal();

            dest.Z += target.Height / 2.0f;

            var direction = Vector3.Normalize(dest - origin);

            // This is not perfect but is close to values that retail used. TODO: revisit this later.
            origin += direction * (caster.PhysicsObj.GetRadius() + spellProjectile.PhysicsObj.GetRadius());

            float time;
            var   dist  = (dest - origin).Length();
            float speed = 15f;

            if (spellProjectile.SpellType == SpellProjectile.ProjectileSpellType.Bolt)
            {
                speed = GetStationaryVelocity(15f, dist);
            }
            else if (spellProjectile.SpellType == SpellProjectile.ProjectileSpellType.Streak)
            {
                speed = GetStationaryVelocity(45f, dist);
            }
            else if (spellProjectile.SpellType == SpellProjectile.ProjectileSpellType.Arc)
            {
                speed = GetStationaryVelocity(40f, dist);
            }

            // TODO: Implement target leading for non arc spells
            // Also: velocity seems to increase when target is moving away from the caster and decrease when
            // the target is moving toward the caster. This still needs more research.

            var velocity = direction * speed;

            if (spellProjectile.SpellType == SpellProjectile.ProjectileSpellType.Arc)
            {
                spellProjectile.Velocity = GetSpellProjectileVelocity(origin, dest, speed, out time);
            }
            else
            {
                spellProjectile.Velocity = new AceVector3(velocity.X, velocity.Y, velocity.Z);
                var velocityLength = spellProjectile.Velocity.Get().Length();
                time = dist / velocityLength;
            }
            spellProjectile.FlightTime = time;

            var loc = caster.Location;

            origin = loc.Pos;
            if (spellProjectile.SpellType == SpellProjectile.ProjectileSpellType.Arc)
            {
                origin.Z += caster.Height;
            }
            else
            {
                origin.Z += caster.Height * 2.0f / 3.0f;
            }
            origin += direction * (caster.PhysicsObj.GetRadius() + spellProjectile.PhysicsObj.GetRadius());

            spellProjectile.Location             = new ACE.Entity.Position(loc.LandblockId.Raw, origin.X, origin.Y, origin.Z, loc.Rotation.X, loc.Rotation.Y, loc.Rotation.Z, loc.RotationW);
            spellProjectile.ParentWorldObject    = (Creature)this;
            spellProjectile.TargetGuid           = target.Guid;
            spellProjectile.LifeProjectileDamage = lifeProjectileDamage;

            LandblockManager.AddObject(spellProjectile);
            CurrentLandblock.EnqueueBroadcast(spellProjectile.Location, new GameMessageScript(spellProjectile.Guid, ACE.Entity.Enum.PlayScript.Launch, spellProjectile.PlayscriptIntensity));

            // TODO : removed when real server projectile tracking and collisions are implemented
            var actionChain = new ActionChain();

            actionChain.AddDelaySeconds(spellProjectile.FlightTime);
            actionChain.AddAction(spellProjectile, () => spellProjectile.HandleOnCollide(spellProjectile.TargetGuid));
            actionChain.EnqueueChain();
        }
Example #21
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;
            }
            }
        }
Example #22
0
 public static void CreateLifeStone(Session session, params string[] parameters)
 {
     LandblockManager.AddObject(AdminObjectFactory.CreateLifestone(session.Player.Position.InFrontOf(3.0f)));
 }
Example #23
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
        }