Esempio n. 1
0
        public bool Move(int x, int y, uint ticks, TravelType travelType, out bool eventTriggered,
                         bool displayOuchIfBlocked       = true, CharacterDirection?prevDirection = null,
                         bool updateDirectionIfNotMoving = true) // x,y in tiles
        {
            eventTriggered = false;

            if (player.MovementAbility == PlayerMovementAbility.NoMovement)
            {
                return(false);
            }

            bool canMove = true;
            var  map     = Map.Map;
            int  newX    = Position.X + x;
            int  newY    = Position.Y + y;

            Map.Tile tile = null;

            if (!map.IsWorldMap)
            {
                // Don't leave the map.
                if (newX < 0 || newY < 0 || newX >= map.Width || newY >= map.Height)
                {
                    canMove = false;
                }
                else
                {
                    tile = Map[(uint)newX, (uint)newY];
                }
            }
            else
            {
                while (newX < 0)
                {
                    newX += map.Width;
                }
                while (newY < 0)
                {
                    newY += map.Height;
                }

                tile = Map[(uint)newX, (uint)newY];
            }

            if (canMove)
            {
                var tileset = mapManager.GetTilesetForMap(map);
                canMove = tile.AllowMovement(tileset, travelType);

                if (!canMove && travelType == TravelType.Swim && tile.AllowMovement(tileset, TravelType.Walk))
                {
                    canMove = true; // go on land
                }
                if (!travelType.IgnoreEvents())
                {
                    // check if there is a place, teleport, riddlemouth, chest
                    // or door event at the new position
                    var mapEventId = Map[(uint)newX, (uint)newY]?.MapEventId;

                    if (mapEventId > 0 && game.CurrentSavegame.IsEventActive(map.Index, mapEventId.Value - 1))
                    {
                        var  trigger         = EventTrigger.Move;
                        bool lastEventStatus = false;

                        bool HasSpecialEvent(Event ev, out EventType?eventType)
                        {
                            eventType = null;

                            if (ev.Type == EventType.EnterPlace ||
                                (ev is TeleportEvent teleportEvent && teleportEvent.Transition != TeleportEvent.TransitionType.WindGate) ||
                                ev.Type == EventType.Riddlemouth ||
                                (ev.Type == EventType.Chest && Map.Map.IsWorldMap) ||
                                (ev is DoorEvent doorEvent && game.CurrentSavegame.IsDoorLocked(doorEvent.DoorIndex)))
                            {
                                eventType = ev.Type;
                                return(true);
                            }

                            if (ev.Next == null)
                            {
                                return(false);
                            }

                            if (ev is ConditionEvent conditionEvent)
                            {
                                ev = conditionEvent.ExecuteEvent(map, game, ref trigger, (uint)Position.X,
                                                                 (uint)Position.Y, game.CurrentTicks, ref lastEventStatus, out bool aborted, out _);

                                if (aborted || ev == null)
                                {
                                    return(false);
                                }
                            }

                            if (ev.Next == null)
                            {
                                return(false);
                            }

                            return(HasSpecialEvent(ev.Next, out eventType));
                        }

                        var mapAtNewPosition = Map.GetMapFromTile((uint)newX, (uint)newY);

                        if (HasSpecialEvent(mapAtNewPosition.EventList[(int)mapEventId.Value - 1], out var type))
                        {
                            if ((type != EventType.Teleport || !travelType.BlockedByTeleport()) &&
                                EventExtensions.TriggerEventChain(mapAtNewPosition, game, EventTrigger.Move, (uint)x, (uint)y, ticks,
                                                                  mapAtNewPosition.EventList[(int)mapEventId.Value - 1]))
                            {
                                eventTriggered = true;
                                return(false);
                            }
                            else
                            {
                                canMove = false;
                            }
                        }
                    }
                }

                if (canMove && tile.Type == Data.Map.TileType.Water && travelType.BlockedByWater())
                {
                    canMove = false;
                }
            }

            if (canMove)
            {
                var oldMap  = map;
                int scrollX = 0;
                int scrollY = 0;
                prevDirection ??= Direction;
                var newDirection       = CharacterDirection.Down;
                var lastPlayerPosition = new Position(player.Position);

                if (x > 0 && (map.IsWorldMap || (newX >= 6 && Map.ScrollX < Map.Map.Width - RenderMap2D.NUM_VISIBLE_TILES_X)))
                {
                    scrollX = 1;
                }
                else if (x < 0 && (map.IsWorldMap || (newX <= map.Width - 7 && Map.ScrollX > 0)))
                {
                    scrollX = -1;
                }

                if (y > 0 && (map.IsWorldMap || (newY >= 5 && Map.ScrollY < Map.Map.Height - RenderMap2D.NUM_VISIBLE_TILES_Y)))
                {
                    scrollY = 1;
                }
                else if (y < 0 && (map.IsWorldMap || (newY <= map.Height - 6 && Map.ScrollY > 0)))
                {
                    scrollY = -1;
                }

                if (y > 0)
                {
                    newDirection = CharacterDirection.Down;
                }
                else if (y < 0)
                {
                    newDirection = CharacterDirection.Up;
                }
                else if (x > 0)
                {
                    newDirection = CharacterDirection.Right;
                }
                else if (x < 0)
                {
                    newDirection = CharacterDirection.Left;
                }

                player.Direction = newDirection;

                Map.Scroll(scrollX, scrollY);

                if (oldMap == Map.Map)
                {
                    bool frameReset = NumFrames == 1 || newDirection != prevDirection;
                    var  prevState  = CurrentState;

                    MoveTo(oldMap, (uint)newX, (uint)newY, ticks, frameReset, null);

                    if (travelType == TravelType.Walk)
                    {
                        Map.TriggerEvents(this, EventTrigger.Move, (uint)newX,
                                          (uint)newY, mapManager, ticks, game.CurrentSavegame);
                    }

                    if (oldMap == Map.Map) // might have changed by map change events
                    {
                        if (!frameReset && CurrentState == prevState)
                        {
                            SetCurrentFrame((CurrentFrame + 1) % NumFrames);
                        }

                        player.Position.X = Position.X;
                        player.Position.Y = Position.Y;

                        tile    = Map[(uint)player.Position.X, (uint)player.Position.Y];
                        Visible = travelType != TravelType.Walk || tile.Type != Data.Map.TileType.Invisible;

                        game.PlayerMoved(false, lastPlayerPosition);
                    }
                }
                else
                {
                    // adjust player position on map transition
                    var position = Map.GetCenterPosition();

                    MoveTo(Map.Map, (uint)position.X, (uint)position.Y, ticks, false, player.Direction);

                    if (travelType == TravelType.Walk)
                    {
                        Map.TriggerEvents(this, EventTrigger.Move, (uint)position.X,
                                          (uint)position.Y, mapManager, ticks, game.CurrentSavegame);
                    }

                    if (Map.Map.Type == MapType.Map2D)
                    {
                        player.Position.X = Position.X;
                        player.Position.Y = Position.Y;

                        // Note: For 3D maps the game/3D map will handle player position updating.

                        tile    = Map[(uint)player.Position.X, (uint)player.Position.Y];
                        Visible = travelType != TravelType.Walk || tile.Type != Data.Map.TileType.Invisible;

                        game.PlayerMoved(true, null, true, oldMap);
                    }
                }
            }
            else
            {
                if (displayOuchIfBlocked)
                {
                    game.DisplayOuch();
                }

                if (updateDirectionIfNotMoving)
                {
                    // If not able to move, the direction should be adjusted
                    var newDirection = Direction;

                    if (y > 0)
                    {
                        newDirection = CharacterDirection.Down;
                    }
                    else if (y < 0)
                    {
                        newDirection = CharacterDirection.Up;
                    }
                    else if (x > 0)
                    {
                        newDirection = CharacterDirection.Right;
                    }
                    else if (x < 0)
                    {
                        newDirection = CharacterDirection.Left;
                    }

                    if (newDirection != Direction)
                    {
                        MoveTo(Map.Map, (uint)Position.X, (uint)Position.Y, ticks, true, newDirection);
                        player.Direction = newDirection;
                        game.CurrentSavegame.CharacterDirection = newDirection;
                        UpdateAppearance(game.CurrentTicks);
                    }
                }
            }

            return(canMove);
        }