Example #1
0
        /// <summary>
        /// Gets the cell ID for a position within a landblock
        /// </summary>
        public static uint GetCell(this Position p)
        {
            var landblock = LScape.get_landblock(p.LandblockId.Raw);

            // dungeons
            // TODO: investigate dungeons that are below actual traversable overworld terrain
            // ex., 010AFFFF
            //if (landblock.IsDungeon)
            if (p.Indoors)
            {
                return(GetIndoorCell(p));
            }

            // outside - could be on landscape, in building, or underground cave
            var cellID   = GetOutdoorCell(p);
            var landcell = LScape.get_landcell(cellID) as LandCell;

            if (landcell == null)
            {
                return(cellID);
            }

            if (landcell.has_building())
            {
                var envCells = landcell.Building.get_building_cells();
                foreach (var envCell in envCells)
                {
                    if (envCell.point_in_cell(p.Pos))
                    {
                        return(envCell.ID);
                    }
                }
            }

            // handle underground areas ie. caves
            // get the terrain Z-height for this X/Y
            Physics.Polygon walkable    = null;
            var             terrainPoly = landcell.find_terrain_poly(p.Pos, ref walkable);

            if (walkable != null)
            {
                Vector3 terrainPos = p.Pos;
                walkable.Plane.set_height(ref terrainPos);

                // are we below ground? if so, search all of the indoor cells for this landblock
                if (terrainPos.Z > p.Pos.Z)
                {
                    var envCells = landblock.get_envcells();
                    foreach (var envCell in envCells)
                    {
                        if (envCell.point_in_cell(p.Pos))
                        {
                            return(envCell.ID);
                        }
                    }
                }
            }

            return(cellID);
        }
Example #2
0
        public void HandlePreTeleportVisibility(ACE.Entity.Position newPosition)
        {
            // repro steps without this function:

            // - /teleloc 0x8A0201C2 [59.822445 -59.574703 0.005000] 0.999998 0.000000 0.000000 -0.002014 for 2 players
            // - click minimap to teleport player 1 elsewhere in world
            // - /teleto <player 1 name> for player 2
            // - use facility hub portal gem for player 2 (49563)
            // - player 2 runs down the stairs, into the room with the torch
            // - player 1 waits 25s+ -- /knownplayers from player 1 to confirm once player 2 has exited the destruction queue
            // - player 1 uses facility hub portal gem, runs to player 2
            // - expected: consistent visibility for both players on each others screens
            // - actual: player 2's dot will be on radar for player 1, but they will be invisible in 3d game world, floating weapon if they are wielding

            // after analyzing this bug from many different perspectives, i believe this is some kind of odd client bug
            // even resending the CO does nothing, as player 1's client does indeed know about player 2
            // a DO and then a CO is the only thing that fixes this issue (/objsend can help with this)
            // this part probably deviates from retail a bit, but is the equivalent automated fix

            //var fixLevel = PropertyManager.GetLong("teleport_visibility_fix").Item;

            var fixLevel = 3;   // instanced mode always uses level 3

            // disabled by default
            if (fixLevel < 1)
            {
                return;
            }

            if (Location.LongObjCellID == newPosition.LongObjCellID)
            {
                return;
            }

            var knownObjs = GetKnownObjects();

            if (fixLevel == 1)
            {
                // filter to players only
                knownObjs = knownObjs.Where(i => i is Player).ToList();
            }
            else if (fixLevel == 2)
            {
                // filter to creatures only
                knownObjs = knownObjs.Where(i => i is Creature).ToList();
            }

            foreach (var knownObj in knownObjs)
            {
                knownObj.PhysicsObj.ObjMaint.RemoveObject(PhysicsObj);

                if (knownObj is Player knownPlayer)
                {
                    knownPlayer.RemoveTrackedObject(this, false);
                }

                ObjMaint.RemoveObject(knownObj.PhysicsObj);
                RemoveTrackedObject(knownObj, false);
            }
        }
Example #3
0
        /// <summary>
        /// NOTE: Cannot be sent while objects are moving (the physics/motion portion of WorldManager)! depends on object positions not changing, and objects not moving between landblocks
        /// </summary>
        private void SendBroadcasts()
        {
            while (!broadcastQueue.IsEmpty)
            {
                bool success = broadcastQueue.TryDequeue(out var tuple);
                if (!success)
                {
                    log.Error("Unexpected TryDequeue Failure!");
                    break;
                }
                Position    pos      = tuple.Item1;
                float       distance = tuple.Item2;
                GameMessage msg      = tuple.Item3;

                // NOTE: Doesn't need locking -- players cannot change while in "Act" SendBroadcasts is the last thing done in Act
                // foreach player within range, do send

                List <Landblock> landblocksInRange = GetLandblocksInRange(pos, distance);
                foreach (Landblock lb in landblocksInRange)
                {
                    List <Player> allPlayers = lb.worldObjects.Values.OfType <Player>().ToList();
                    foreach (Player p in allPlayers)
                    {
                        if (p.Location.SquaredDistanceTo(pos) < distance * distance)
                        {
                            p.Session.Network.EnqueueSend(msg);
                        }
                    }
                }
            }

            // Sets broadcastQueued to 0, so we're ready to re-queue broadcasts later
            broadcastQueued = 0;
        }
Example #4
0
        public static Position FromGlobal(this Position p, Vector3 pos)
        {
            var landblock = LScape.get_landblock(p.LandblockId.Raw);

            // TODO: investigate dungeons that are below actual traversable overworld terrain
            // ex., 010AFFFF
            //if (landblock.IsDungeon)
            if (p.Indoors)
            {
                var iPos = new Position();
                iPos.LandblockId = p.LandblockId;
                iPos.Pos         = new Vector3(pos.X, pos.Y, pos.Z);
                iPos.Rotation    = p.Rotation;
                iPos.LandblockId = new LandblockId(GetCell(iPos));
                return(iPos);
            }

            var blockX = (uint)pos.X / Position.BlockLength;
            var blockY = (uint)pos.Y / Position.BlockLength;

            var localX = pos.X % Position.BlockLength;
            var localY = pos.Y % Position.BlockLength;

            var landblockID = blockX << 24 | blockY << 16 | 0xFFFF;

            var position = new Position();

            position.LandblockId = new LandblockId((byte)blockX, (byte)blockY);
            position.PositionX   = localX;
            position.PositionY   = localY;
            position.PositionZ   = pos.Z;
            position.Rotation    = p.Rotation;
            position.LandblockId = new LandblockId(GetCell(position));
            return(position);
        }
Example #5
0
        /// <summary>
        /// Returns the greatest single-dimension square distance between 2 positions
        /// </summary>
        public static uint CellDist(this Position p1, Position p2)
        {
            if (!p1.Indoors && !p2.Indoors)
            {
                return(Math.Max(p1.GlobalCellX, p1.GlobalCellY));
            }

            // handle dungeons

            /*var block1 = LScape.get_landblock(p1.LandblockId.Raw);
             * var block2 = LScape.get_landblock(p2.LandblockId.Raw);
             * if (block1.IsDungeon || block2.IsDungeon)
             * {
             *  // 2 separate dungeons = infinite distance
             *  if (block1.ID != block2.ID)
             *      return uint.MaxValue;
             *
             *  return GetDungeonCellDist(p1, p2);
             * }*/

            var _p1 = new Position(p1);
            var _p2 = new Position(p2);

            if (_p1.Indoors)
            {
                _p1.LandblockId = new LandblockId(_p1.GetOutdoorCell());
            }
            if (_p2.Indoors)
            {
                _p2.LandblockId = new LandblockId(_p2.GetIndoorCell());
            }

            return(Math.Max(_p1.GlobalCellX, _p2.GlobalCellY));
        }
        public static Position FromGlobal(this Position p, Vector3 pos)
        {
            // TODO: Is this necessary? It seemed to be loading rogue physics landblocks. Commented out 2019-04 Mag-nus
            //var landblock = LScape.get_landblock(p.LandblockId.Raw);

            // TODO: investigate dungeons that are below actual traversable overworld terrain
            // ex., 010AFFFF
            //if (landblock.IsDungeon)
            if (p.Indoors)
            {
                var iPos = new Position(p.ObjCellID, pos, p.Rotation, false, p.Instance);
                iPos.ObjCellID = GetCell(iPos);
                return(iPos);
            }

            var blockX = (uint)pos.X / Position.BlockLength;
            var blockY = (uint)pos.Y / Position.BlockLength;

            var localX = pos.X % Position.BlockLength;
            var localY = pos.Y % Position.BlockLength;

            var landblock = (uint)(blockX << 24 | blockY << 16);

            var position = new Position();

            position.Instance  = p.Instance;
            position.ObjCellID = landblock;
            position.Pos       = new Vector3(localX, localY, pos.Z);
            position.Rotation  = p.Rotation;
            position.ObjCellID = GetCell(position);
            return(position);
        }
Example #7
0
        public static Position FromGlobal(this Position p, Vector3 pos)
        {
            var landblock = LScape.get_landblock(p.LandblockId.Raw);

            if (landblock.IsDungeon)
            {
                var iPos = new Position();
                iPos.LandblockId = p.LandblockId;
                iPos.Pos         = new Vector3(pos.X, pos.Y, pos.Z);
                iPos.Rotation    = p.Rotation;
                iPos.LandblockId = new LandblockId(GetCell(iPos));
                return(iPos);
            }

            var blockX = (uint)pos.X / Position.BlockLength;
            var blockY = (uint)pos.Y / Position.BlockLength;

            var localX = pos.X % Position.BlockLength;
            var localY = pos.Y % Position.BlockLength;

            var landblockID = blockX << 24 | blockY << 16 | 0xFFFF;

            var position = new Position();

            position.LandblockId = new LandblockId((byte)blockX, (byte)blockY);
            position.PositionX   = localX;
            position.PositionY   = localY;
            position.PositionZ   = pos.Z;
            position.Rotation    = p.Rotation;
            position.LandblockId = new LandblockId(GetCell(position));
            return(position);
        }
        public static Position ACEPosition(this Physics.Common.Position pos, Position source)
        {
            var newPos = new Position(pos.ObjCellID, pos.Frame.Origin, pos.Frame.Orientation, false, source.Instance);

            newPos.Instance = source.Instance;

            return(newPos);
        }
Example #9
0
        /// <summary>
        /// This signature services MoveToObject and TurnToObject
        /// Update Position prior to start, start them moving or turning, set statemachine to moving.
        /// Moved from player - we need to be able to move creatures as well.   Og II
        /// </summary>
        /// <param name="worldObjectPosition">Position in the world</param>
        /// <param name="sequence">Sequence for the object getting the message.</param>
        /// <param name="movementType">What type of movement are we about to execute</param>
        /// <param name="targetGuid">Who are we moving or turning toward</param>
        public void OnAutonomousMove(ACE.Entity.Position worldObjectPosition, SequenceManager sequence, MovementTypes movementType, ObjectGuid targetGuid)
        {
            UniversalMotion newMotion = new UniversalMotion(MotionStance.Standing, worldObjectPosition, targetGuid);

            newMotion.DistanceFrom  = 0.60f;
            newMotion.MovementTypes = movementType;
            CurrentLandblock.EnqueueBroadcast(Location, Landblock.MaxObjectRange, new GameMessageUpdatePosition(this));
            CurrentLandblock.EnqueueBroadcastMotion(this, newMotion);
        }
Example #10
0
        public void HandleActionJump(JumpPack jump)
        {
            StartJump = new ACE.Entity.Position(Location);
            //Console.WriteLine($"JumpPack: Velocity: {jump.Velocity}, Extent: {jump.Extent}");

            var strength = Strength.Current;
            var capacity = EncumbranceSystem.EncumbranceCapacity((int)strength, AugmentationIncreasedCarryingCapacity);
            var burden   = EncumbranceSystem.GetBurden(capacity, EncumbranceVal ?? 0);

            // calculate stamina cost for this jump
            var extent      = Math.Clamp(jump.Extent, 0.0f, 1.0f);
            var staminaCost = MovementSystem.JumpStaminaCost(extent, burden, PKTimerActive);

            //Console.WriteLine($"Strength: {strength}, Capacity: {capacity}, Encumbrance: {EncumbranceVal ?? 0}, Burden: {burden}, StaminaCost: {staminaCost}");

            // ensure player has enough stamina to jump

            /*if (staminaCost > Stamina.Current)
             * {
             *  // get adjusted power
             *  extent = MovementSystem.GetJumpPower(Stamina.Current, burden, false);
             *
             *  staminaCost = (int)Stamina.Current;
             *
             *  // adjust jump velocity
             *  var velocityZ = MovementSystem.GetJumpHeight(burden, GetCreatureSkill(Skill.Jump).Current, extent, 1.0f);
             *
             *  jump.Velocity.Z = velocityZ;
             * }*/

            IsJumping    = true;
            LastJumpTime = DateTime.UtcNow;

            UpdateVitalDelta(Stamina, -staminaCost);

            IsJumping = false;

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

            // set jump velocity
            // TODO: have server verify / scale magnitude
            PhysicsObj.set_velocity(jump.Velocity, true);

            // this shouldn't be needed, but without sending this update motion / simulated movement event beforehand,
            // running forward and then performing a charged jump does an uncharged shallow arc jump instead
            // this hack fixes that...
            var movementData = new MovementData(this);

            movementData.IsAutonomous = true;
            movementData.MovementType = MovementType.Invalid;
            movementData.Invalid      = new MovementInvalid(movementData);
            EnqueueBroadcast(new GameMessageUpdateMotion(this, movementData));

            // broadcast jump
            EnqueueBroadcast(new GameMessageVectorUpdate(this));
        }
Example #11
0
        /// <summary>
        /// Saves a CharacterPosition to the character position dictionary
        /// </summary>
        public void SetCharacterPosition(PositionType type, Position newPosition)
        {
            // reset the landblock id
            if (newPosition.LandblockId.Landblock == 0 && newPosition.Cell > 0)
            {
                newPosition.LandblockId = new LandblockId(newPosition.Cell);
            }

            Positions[type] = newPosition;
        }
Example #12
0
        /// <summary>
        /// Gets an outdoor cell ID for a position within a landblock
        /// </summary>
        public static uint GetOutdoorCell(this Position p)
        {
            var cellX = (uint)p.PositionX / Position.CellLength;
            var cellY = (uint)p.PositionY / Position.CellLength;

            var cellID = cellX * Position.CellSide + cellY + 1;

            var blockCellID = (uint)((p.LandblockId.Raw & 0xFFFF0000) | cellID);

            return(blockCellID);
        }
Example #13
0
        /// <summary>
        /// Processes physics objects in all active landblocks for updating
        /// </summary>
        private static IEnumerable <WorldObject> HandlePhysics(double timeTick)
        {
            ConcurrentQueue <WorldObject> movedObjects = new ConcurrentQueue <WorldObject>();

            // Access ActiveLandblocks should be safe here, but sometimes crashes with
            // System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
            try
            {
                Parallel.ForEach(LandblockManager.ActiveLandblocks.Keys, landblock =>
                {
                    foreach (WorldObject wo in landblock.GetPhysicsWorldObjects())
                    {
                        Position newPosition = null;

                        // detect player movement
                        // TODO: handle players the same as everything else
                        var player = wo as Player;
                        if (player != null)
                        {
                            newPosition = HandlePlayerPhysics(player, timeTick);

                            if (newPosition != null)
                            {
                                movedObjects.Enqueue(wo);

                                // update position through physics engine
                                wo.UpdatePlayerPhysics(newPosition);
                            }
                        }
                        else if (wo.Missile.HasValue && wo.Missile.Value)
                        {
                            // physics minimum quantum?
                            var isMoved = wo.UpdateObjectPhysics();
                            if (isMoved)
                            {
                                movedObjects.Enqueue(wo);   // send update?
                            }
                        }
                    }
                });

                foreach (var wo in UpdateLandblock)
                {
                    wo.PreviousLocation = wo.Location;
                    LandblockManager.RelocateObjectForPhysics(wo);
                }
                UpdateLandblock.Clear();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);   // FIXME: concurrency
            }
            return(movedObjects);
        }
Example #14
0
        private List <WorldObject> GetWorldObjectsInRange(Position pos, float distance)
        {
            List <Landblock> landblocksInRange = GetLandblocksInRange(pos, distance);

            List <WorldObject> ret = new List <WorldObject>();

            foreach (Landblock lb in landblocksInRange)
            {
                ret.AddRange(lb.worldObjects.Values.Where(x => x.Location.SquaredDistanceTo(pos) < distance * distance).ToList());
            }

            return(ret);
        }
Example #15
0
        /// <summary>
        /// Enqueues a message for broadcast, thread safe
        /// </summary>
        public void EnqueueBroadcast(Position pos, params GameMessage[] msgs)
        {
            // Atomically checks and sets the broadcastQueued bit --
            //    guarantees that if we need a broadcast it will be enqueued in the world-managers broadcast queue exactly once
            if (Interlocked.CompareExchange(ref broadcastQueued, 1, 0) == 0)
            {
                WorldManager.BroadcastQueue.EnqueueAction(new ActionEventDelegate(() => SendBroadcasts()));
            }

            foreach (GameMessage msg in msgs)
            {
                broadcastQueue.Enqueue(new Tuple <Position, float, GameMessage>(pos, MaxObjectRange, msg));
            }
        }
Example #16
0
        /// <summary>
        /// Gets an indoor cell ID for a position within a dungeon
        /// </summary>
        private static uint GetIndoorCell(this Position p)
        {
            var adjustCell = AdjustCell.Get(p.Landblock);
            var envCell    = adjustCell.GetCell(p.Pos);

            if (envCell != null)
            {
                return(envCell.Value);
            }
            else
            {
                return(p.Cell);
            }
        }
Example #17
0
        public static Vector3 ToGlobal(this Position p)
        {
            var landblock = LScape.get_landblock(p.LandblockId.Raw);

            if (landblock.IsDungeon)
            {
                return(p.Pos);
            }

            var x = p.LandblockId.LandblockX * Position.BlockLength + p.PositionX;
            var y = p.LandblockId.LandblockY * Position.BlockLength + p.PositionY;
            var z = p.PositionZ;

            return(new Vector3(x, y, z));
        }
Example #18
0
        public static string GetMapCoordStr(this Position pos)
        {
            var mapCoords = pos.GetMapCoords();

            if (mapCoords == null)
            {
                return(null);
            }

            var northSouth = mapCoords.Value.Y >= 0 ? "N" : "S";
            var eastWest   = mapCoords.Value.X >= 0 ? "E" : "W";

            return(string.Format("{0:0.0}", Math.Abs(mapCoords.Value.Y) - 0.05f) + northSouth + ", "
                   + string.Format("{0:0.0}", Math.Abs(mapCoords.Value.X) - 0.05f) + eastWest);
        }
Example #19
0
        // End wrappers

        /// <summary>
        /// Runs an action on all players within a certain distance from a point.
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="distance"></param>
        /// <param name="delegateAction"></param>
        public void EnqueueActionBroadcast(Position pos, float distance, Action <Player> delegateAction)
        {
            List <Landblock> landblocksInRange = GetLandblocksInRange(pos, distance);

            foreach (Landblock lb in landblocksInRange)
            {
                List <Player> allPlayers = lb.worldObjects.Values.OfType <Player>().ToList();
                foreach (Player p in allPlayers)
                {
                    if (p.Location.SquaredDistanceTo(pos) < distance * distance)
                    {
                        p.EnqueueAction(new ActionEventDelegate(() => delegateAction(p)));
                    }
                }
            }
        }
Example #20
0
        public static void Translate(this Position pos, uint blockCell)
        {
            var newBlockX = blockCell >> 24;
            var newBlockY = (blockCell >> 16) & 0xFF;

            var xDiff = (int)newBlockX - pos.LandblockX;
            var yDiff = (int)newBlockY - pos.LandblockY;

            //pos.Origin.X -= xDiff * 192;
            pos.PositionX -= xDiff * 192;
            //pos.Origin.Y -= yDiff * 192;
            pos.PositionY -= yDiff * 192;

            //pos.ObjCellID = blockCell;
            pos.LandblockId = new LandblockId(blockCell);
        }
Example #21
0
        public static Vector3 ToGlobal(this Position p)
        {
            var landblock = LScape.get_landblock(p.LandblockId.Raw);

            // TODO: investigate dungeons that are below actual traversable overworld terrain
            // ex., 010AFFFF
            //if (landblock.IsDungeon)
            if (p.Indoors)
            {
                return(p.Pos);
            }

            var x = p.LandblockId.LandblockX * Position.BlockLength + p.PositionX;
            var y = p.LandblockId.LandblockY * Position.BlockLength + p.PositionY;
            var z = p.PositionZ;

            return(new Vector3(x, y, z));
        }
Example #22
0
        public static bool AttemptToFixRotation(this Position pos, WorldObject wo, PositionType positionType)
        {
            log.Warn($"detected bad quaternion x y z w for {wo.Name} (0x{wo.Guid}) | WCID: {wo.WeenieClassId} | WeenieType: {wo.WeenieType} | PositionType: {positionType}");
            log.Warn($"before fix: {pos.ToLOCString()}");

            var normalized = Quaternion.Normalize(pos.Rotation);

            var success = IsRotationValid(normalized);

            if (success)
            {
                pos.Rotation = normalized;
            }

            log.Warn($" after fix: {pos.ToLOCString()}");

            return(success);
        }
Example #23
0
        public static Vector3 ToGlobal(this Position p, bool skipIndoors = true)
        {
            // TODO: Is this necessary? It seemed to be loading rogue physics landblocks. Commented out 2019-04 Mag-nus
            //var landblock = LScape.get_landblock(p.LandblockId.Raw);

            // TODO: investigate dungeons that are below actual traversable overworld terrain
            // ex., 010AFFFF
            //if (landblock.IsDungeon)
            if (p.Indoors && skipIndoors)
            {
                return(p.Pos);
            }

            var x = p.LandblockId.LandblockX * Position.BlockLength + p.PositionX;
            var y = p.LandblockId.LandblockY * Position.BlockLength + p.PositionY;
            var z = p.PositionZ;

            return(new Vector3(x, y, z));
        }
Example #24
0
        /// <summary>
        /// Returns TRUE if outdoor position is located on walkable slope
        /// </summary>
        public static bool IsWalkable(this Position p)
        {
            if (p.Indoors)
            {
                return(true);
            }

            var landcell = (LandCell)LScape.get_landcell(p.Cell);

            Physics.Polygon walkable    = null;
            var             terrainPoly = landcell.find_terrain_poly(p.Pos, ref walkable);

            if (walkable == null)
            {
                return(false);
            }

            return(Physics.PhysicsObj.is_valid_walkable(walkable.Plane.Normal));
        }
Example #25
0
        /// <summary>
        /// Detects if player has moved through ForcedLocation or RequestedLocation
        /// </summary>
        private static Position HandlePlayerPhysics(Player player)
        {
            Position newPosition = null;

            if (player.ForcedLocation != null)
            {
                newPosition = player.ForcedLocation;
            }
            else if (player.RequestedLocation != null)
            {
                newPosition = player.RequestedLocation;
            }

            if (newPosition != null)
            {
                player.ClearRequestedPositions();
            }

            return(newPosition);
        }
Example #26
0
        private static IEnumerable <WorldObject> HandlePhysics(double timeTick)
        {
            ConcurrentQueue <WorldObject> movedObjects = new ConcurrentQueue <WorldObject>();

            // Accessing ActiveLandblocks is safe here -- nothing can modify the landblocks at this point
            // This crashes sometimes with the following exception: System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
            try
            {
                Parallel.ForEach(LandblockManager.ActiveLandblocks, landblock =>
                {
                    foreach (WorldObject wo in landblock.GetPhysicsWorldObjects())
                    {
                        Position newPosition = wo.Location;

                        if (wo.ForcedLocation != null)
                        {
                            newPosition = wo.ForcedLocation;
                            movedObjects.Enqueue(wo);
                        }
                        else if (wo.RequestedLocation != null)
                        {
                            newPosition = wo.RequestedLocation;
                            movedObjects.Enqueue(wo);
                        }

                        if (newPosition != wo.Location)
                        {
                            wo.PhysicsUpdatePosition(newPosition);
                        }

                        wo.ClearRequestedPositions();
                    }
                });
            }
            catch (Exception e)
            {
                Console.WriteLine(e);   // FIXME: concurrency
            }

            return(movedObjects);
        }
Example #27
0
        public static float GetTerrainZ(this Position p)
        {
            var cellID   = GetOutdoorCell(p);
            var landcell = (LandCell)LScape.get_landcell(cellID);

            if (landcell == null)
            {
                return(p.Pos.Z);
            }

            Physics.Polygon walkable = null;
            if (!landcell.find_terrain_poly(p.Pos, ref walkable))
            {
                return(p.Pos.Z);
            }

            Vector3 terrainPos = p.Pos;

            walkable.Plane.set_height(ref terrainPos);

            return(terrainPos.Z);
        }
Example #28
0
        public static void AdjustMapCoords(this Position pos)
        {
            // adjust Z to terrain height
            pos.PositionZ = pos.GetTerrainZ();

            // adjust to building height, if applicable
            var sortCell = LScape.get_landcell(pos.Cell) as SortCell;

            if (sortCell != null && sortCell.has_building())
            {
                var building = sortCell.Building;

                var minZ = building.GetMinZ();

                if (minZ > 0 && minZ < float.MaxValue)
                {
                    pos.PositionZ += minZ;
                }

                pos.LandblockId = new LandblockId(pos.GetCell());
            }
        }
Example #29
0
        public static Vector2?GetMapCoords(this Position pos)
        {
            // no map coords available for dungeons / indoors?
            if ((pos.Cell & 0xFFFF) >= 0x100)
            {
                return(null);
            }

            var globalPos = pos.ToGlobal();

            // 1 landblock = 192 meters
            // 1 landblock = 0.8 map units

            // 1 map unit = 1.25 landblocks
            // 1 map unit = 240 meters

            var mapCoords = new Vector2(globalPos.X / 240, globalPos.Y / 240);

            // dereth is 204 map units across, -102 to +102
            mapCoords -= Vector2.One * 102;

            return(mapCoords);
        }
Example #30
0
        public static void HandlePhysicsLandblock(Landblock landblock, double timeTick, ConcurrentQueue <WorldObject> movedObjects)
        {
            foreach (WorldObject wo in landblock.GetPhysicsWorldObjects())
            {
                Position newPosition = null;

                // set to TRUE if object changes landblock
                var landblockUpdate = false;

                // detect player movement
                // TODO: handle players the same as everything else
                var player = wo as Player;
                if (player != null)
                {
                    wo.InUpdate = true;

                    newPosition = HandlePlayerPhysics(player, timeTick);

                    // update position through physics engine
                    if (newPosition != null)
                    {
                        landblockUpdate = wo.UpdatePlayerPhysics(newPosition);
                    }

                    wo.InUpdate = false;
                }
                else
                {
                    landblockUpdate = wo.UpdateObjectPhysics();
                }

                if (landblockUpdate)
                {
                    movedObjects.Enqueue(wo);
                }
            }
        }