• Do not use Discord to host any images you post, these links expire quickly! You can learn how to add images to your posts here.
  • The Eevee Expo Game Jam has concluded! 🎉 Head on over to the game jam forum to play through the games.
    Don't forget to come back September 21st to vote for your favorites!
  • Reminder: AI-generated content is not allowed on the forums per the Rules and Regulations. Please contact us if you have any questions!
Resource icon

Resource Terrain Tag Side Stairs 1.5a

I'm loving the script! It's working really well for my character but my following Pokemon (using Following Pokemon EX) is walking a little weirdly up the stairs. Any ideas?
ezgif-5-4ae726a56c.gif
 
Not a big deal but I'll mention it anyways.

The player's y-position stays offset if you're in debug & are holding CTRL while on a staircase and move up/down.
Replicate by getting on a left or right staircase. While in debug, hold CTRL and move in the northern or southern direction.
Your y-position will remain offset since you never exited through the intended terrain tag.
This isn’t a bug. This is how the system works and should never occur in a real playthrough if the instructions are followed.
 
I’m looking into the weirdness with followers on stairs and will post a fix when I’ve resolved it.
I'm loving the script! It's working really well for my character but my following Pokemon (using Following Pokemon EX) is walking a little weirdly up the stairs. Any ideas?View attachment 9908
 
Thank you very much for this script and for share your work.

I am having a lot of problems with the Following EX script for V20.1.

While I get a nice compatibility, my follower is going crazy.

Any ideas?

1658119801038.gif
 
While it works fantastic with 1 tile altitude stairs, with 2+ altitude it gets stuck when it tries to go down from the bottom half, the upper half works just fine but the bottom half gets stuck.

The tags and passage are setup this way.
Oion5df.png
EXutfkC.png
 
While it works fantastic with 1 tile altitude stairs, with 2+ altitude it gets stuck when it tries to go down from the bottom half, the upper half works just fine but the bottom half gets stuck.

The tags and passage are setup this way.
Oion5df.png
EXutfkC.png

Same problem here...

The best way, at the moment, is to make two separate stairs one tile apart. It gives the same feeling of height, but yes, it is an inelegant temporary solution.
 
Hi I just re-installed this plugin on v20.1 but the part of the followers is a little tricky, What file from that plugin do I need to edit because I don't find the line you specified on any of the files from the followers plugin.
 
Hi! There are plans to update this script?, in the process of updating my project I realized that almost all my side stairs work under this logic. T_T Thanks again!

I tried to play with the values and although I managed to make the character move forward without being blocked, the effect does not work well.
 
Last edited:
Hi! There are plans to update this script?, in the process of updating my project I realized that almost all my side stairs work under this logic. T_T Thanks again!

I tried to play with the values and although I managed to make the character move forward without being blocked, the effect does not work well.
How far along did you get in updating it?
 
How far along did you get in updating it?

I simply played with some values to allow the character to not get stuck eternally on the tile (which was, at least, the problem I had) However, the depth effect is hinted at, but not achieved. I have the feeling that it's a value thing, but frankly I don't have enough knowledge to be able to go further. There are probably things I haven't tried. I leave the script here if anyone wants to try it.


Ruby:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------

def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end


class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move


  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto


  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -8 #16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    move_upper_left_stairs
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -8 #16
    else
      @offset_y = 0
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    move_upper_right_stairs
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -8 #16
    else
      @offset_y = 0
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    move_lower_left_stairs
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -8 #16
    else
      @offset_y = 0
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    move_lower_right_stairs
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -8 #16
    else
      @offset_y = 0
    end
  end
end

class Game_Player

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y).id
    old_x = @x
    if dir == 4
      if old_tag == :StairLeft
        # if passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft
        if passable?(@x - 3, @y + 3, 4) && self.map.terrain_tag(@x - 3, @y + 3) == :StairLeft
          @y += 3 #1
        end
      elsif old_tag == :StairRight
        #if passable?(@x - 1, @y - 1, 6)
        if passable?(@x - 3, @y - 3, 6)
          @y -= 3 #1
        end
      end
    elsif dir == 6
      #RIGHT UP
      #if old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4)
      if old_tag == :StairLeft && passable?(@x + 3, @y - 3, 4)
        @y -= 3 #1
      #elsif old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight
      elsif old_tag == :StairRight && passable?(@x + 3, @y + 3, 6) && self.map.terrain_tag(@x + 3, @y + 3) == :StairRight
        @y += 3 #1
      end
    end
    move_generic_stairs(dir, turn_enabled)
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != :StairLeft && new_tag == :StairLeft ||
         old_tag != :StairRight && new_tag == :StairRight
        self.offset_y = -8
        #self.offset_y = -16
        @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
      elsif old_tag == :StairLeft && new_tag != :StairLeft ||
            old_tag == :StairRight && new_tag != :StairRight
        self.offset_y = 0
      end
    end
  end


  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
    # Get new coordinates
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    # If coordinates are outside of map
    return false if !$game_map.validLax?(new_x, new_y)
    if !$game_map.valid?(new_x, new_y)
      return false if !$map_factory
      return $map_factory.isPassableFromEdge?(new_x, new_y)
    end
    # If debug mode is ON and Ctrl key was pressed
    return true if $DEBUG && Input.press?(Input::CTRL)
    # insertion from this script
    if d == 8 && new_y > 0 # prevent player moving up past the top of the stairs
      if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
         $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
        return false
      elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
            $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
        return false
      end
    end
    #end
    return super
  end

end


class Game_Follower
  def move_through(direction)
    old_through = @through
    @through = true
    case direction
    when 1 then move_lower_left
    when 2 then move_down
    when 3 then move_lower_right
    when 4 then move_left
    when 6 then move_right
    when 7 then move_upper_left
    when 8 then move_up
    when 9 then move_upper_right
    end
    @through = old_through
  end

  def move_fancy(direction,leader)
    delta_x = (direction == 6) ? 1 : (direction == 4) ? -1 : 0
    delta_y = (direction == 2) ? 1 : (direction == 8) ? -1 : 0
    dir = direction
    old_tag = self.map.terrain_tag(self.x, self.y).id
    old_x = self.x
    if direction == 4
      if old_tag == :StairLeft
        if passable?(self.x - 3, self.y + 3, 4) && self.map.terrain_tag(self.x - 3, self.y + 3) == :StairLeft
          delta_y += 3
          dir = 3
        end
      elsif old_tag == :StairRight
        if passable?(self.x - 3, self.y - 3, 6)
          delta_y -= 3
          dir = 7
        end
      end
    elsif direction == 6
      if old_tag == :StairLeft && passable?(self.x + 3, self.y - 3, 4)
        delta_y -= 3
        dir = 9
      elsif old_tag == :StairRight && passable?(self.x + 3, self.y + 3, 6) && self.map.terrain_tag(self.x + 3, self.y + 3) == :StairRight
        delta_y += 3
        dir = 3
      end
    end
    new_x = self.x + delta_x
    new_y = self.y + delta_y
    # Move if new position is the player's, or the new position is passable,
    # or self's current position is not passable
    if ($game_player.x == new_x && $game_player.y == new_y) ||
       location_passable?(new_x, new_y, 10 - direction) ||
       !location_passable?(self.x, self.y, direction)
      move_through(dir)
    end
    new_tag = self.map.terrain_tag(self.x, self.y)
    if old_x != self.x
      if old_tag != :StairLeft && new_tag == :StairLeft ||
         old_tag != :StairRight && new_tag == :StairRight
        self.offset_y = -16
        @y += 1 if (new_tag == :StairLeft && direction == 4) || (new_tag == :StairRight && direction == 6)
      elsif old_tag == :StairLeft && new_tag != :StairLeft ||
            old_tag == :StairRight && new_tag != :StairRight
        self.offset_y = 0
      end
    end
    turn_towards_leader(leader)
  end

  def jump_fancy(direction, leader)
    delta_x = (direction == 6) ? 2 : (direction == 4) ? -2 : 0
    delta_y = (direction == 2) ? 2 : (direction == 8) ? -2 : 0
    half_delta_x = delta_x / 2
    half_delta_y = delta_y / 2
    if location_passable?(self.x + half_delta_x, self.y + half_delta_y, 10 - direction)
      # Can walk over the middle tile normally; just take two steps
      move_fancy(direction,leader)
      move_fancy(direction,leader)
    elsif location_passable?(self.x + delta_x, self.y + delta_y, 10 - direction)
      # Can't walk over the middle tile, but can walk over the end tile; jump over
      if location_passable?(self.x, self.y, direction)
        if leader.jumping?
          @jump_speed_real = leader.jump_speed_real
        else
          # This is doubled because self has to jump 2 tiles in the time it
          # takes the leader to move one tile.
          @jump_speed_real = leader.move_speed_real * 2
        end
        jump(delta_x, delta_y)
      else
        # self's current tile isn't passable; just take two steps ignoring passability
        move_through(direction)
        move_through(direction)
      end
    end
  end

  def fancy_moveto(new_x, new_y, leader)
    if self.x - new_x == 1 && (-1..1).include?(self.y - new_y)
      move_fancy(4,leader)
    elsif self.x - new_x == -1 && (-1..1).include?(self.y - new_y)
      move_fancy(6,leader)
    elsif self.x == new_x && self.y - new_y == 1
      move_fancy(8,leader)
    elsif self.x == new_x && self.y - new_y == -1
      move_fancy(2,leader)
    elsif self.x - new_x == 2 && self.y == new_y
      jump_fancy(4, leader)
    elsif self.x - new_x == -2 && self.y == new_y
      jump_fancy(6, leader)
    elsif self.x == new_x && self.y - new_y == 2
      jump_fancy(8, leader)
    elsif self.x == new_x && self.y - new_y == -2
      jump_fancy(2, leader)
    elsif self.x != new_x || self.y != new_y
      moveto(new_x, new_y)
    end
  end

end

Edit: The same thing happens with the followers. Although they are advancing, it does not work as it should.
 
Sorry to revive this. I have managed to make a small port of this script to 21.1 and it works almost perfectly...

The only problem I still have is that when going up the stairs in the right or left direction there is a jump in the screen (similar to what happened with ledges in 20.1). I have tried to solve it without success. I tried to test it in a new project without other scripts that could generate conflicts and the problem persists.

If someone is able to take a look it would be of great help.

Port to 21.1 W.I.P:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end

class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move

  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto

  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(7)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(9)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(1)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(3)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end
end

class Game_Player
  alias move_generic_stairs move_generic

def move_generic(dir, turn_enabled = true)
  old_tag = self.map.terrain_tag(@x, @y).id
  old_x = @x
  old_y = @y
  new_x = @x
  new_y = @y

  if dir == 4
    if old_tag == :StairLeft && passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft
      new_x = @x - 1
      new_y = @y + 1
  elsif old_tag == :StairRight && passable?(@x - 1, @y - 1, 6)
      new_x = @x - 1
      new_y = @y - 1
    end
  elsif dir == 6
    if old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4)
      new_x = @x + 1
      new_y = @y - 1
    elsif old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight
      new_x = @x + 1
      new_y = @y + 1
    end
  end
  if old_x != new_x || old_y != new_y
    moveto(new_x, new_y)
  else
    move_generic_stairs(dir, turn_enabled)
  end
  new_tag = self.map.terrain_tag(@x, @y)
  if old_x != @x
    if old_tag != :StairLeft && new_tag == :StairLeft ||
       old_tag != :StairRight && new_tag == :StairRight
      self.offset_y = -16
      @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
    elsif old_tag == :StairLeft && new_tag != :StairLeft ||
          old_tag == :StairRight && new_tag != :StairRight
      self.offset_y = 0
    end
  end
end

  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
    # Get new coordinates
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    # If coordinates are outside of map
    return false if !$game_map.validLax?(new_x, new_y)
    if !$game_map.valid?(new_x, new_y)
      return false if !$map_factory
      return $map_factory.isPassableFromEdge?(new_x, new_y)
    end
    # If debug mode is ON and Ctrl key was pressed
    return true if $DEBUG && Input.press?(Input::CTRL)
    # insertion from this script
    if d == 8 && new_y > 0 # prevent player moving up past the top of the stairs
      if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
         $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
        return false
      elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
            $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
        return false
      end
    end
    #end
    return super
  end
end

class Game_Follower
  def move_through(direction)
    old_through = @through
    @through = true
    case direction
    when 1 then move_lower_left
    when 2 then move_down
    when 3 then move_lower_right
    when 4 then move_left
    when 6 then move_right
    when 7 then move_upper_left
    when 8 then move_up
    when 9 then move_upper_right
    end
    @through = old_through
  end

def move_fancy(direction, leader)
  delta_x = (direction == 6) ? 1 : (direction == 4) ? -1 : 0
  delta_y = (direction == 2) ? 1 : (direction == 8) ? -1 : 0
  dir = direction
  old_tag = self.map.terrain_tag(self.x, self.y).id
  old_x = self.x

  if direction == 4
    if old_tag == :StairLeft
      if passable?(self.x - 1, self.y + 1, 4) && self.map.terrain_tag(self.x - 1, self.y + 1) == :StairLeft
        delta_y += 1
        dir = 1
      end
    elsif old_tag == :StairRight
      if passable?(self.x - 1, self.y - 1, 6)
        delta_y -= 1
        dir = 7
      end
    end
  elsif direction == 6
    if old_tag == :StairLeft && passable?(self.x + 1, self.y - 1, 4)
      delta_y -= 1
      dir = 9
    elsif old_tag == :StairRight && passable?(self.x + 1, self.y + 1, 6) && self.map.terrain_tag(self.x + 1, self.y + 1) == :StairRight
      delta_y += 1
      dir = 3
    end
  end

  new_x = self.x + delta_x
  new_y = self.y + delta_y

  if ($game_player.x == new_x && $game_player.y == new_y) ||
     location_passable?(new_x, new_y, 10 - direction) ||
     !location_passable?(self.x, self.y, direction)
    move_through(dir)
  end

  new_tag = self.map.terrain_tag(self.x, self.y)
  if old_x != self.x
    if old_tag != :StairLeft && new_tag == :StairLeft ||
       old_tag != :StairRight && new_tag == :StairRight
      self.offset_y = -16
      @y += 1 if (new_tag == :StairLeft && direction == 4) || (new_tag == :StairRight && direction == 6)
    elsif old_tag == :StairLeft && new_tag != :StairLeft ||
          old_tag == :StairRight && new_tag != :StairRight
      self.offset_y = 0
    end
  end

  turn_towards_leader(leader)
end


  def jump_fancy(direction, leader)
    delta_x = (direction == 6) ? 2 : (direction == 4) ? -2 : 0
    delta_y = (direction == 2) ? 2 : (direction == 8) ? -2 : 0
    half_delta_x = delta_x / 2
    half_delta_y = delta_y / 2
    if location_passable?(self.x + half_delta_x, self.y + half_delta_y, 10 - direction)
      # Can walk over the middle tile normally; just take two steps
      move_fancy(direction,leader)
      move_fancy(direction,leader)
    elsif location_passable?(self.x + delta_x, self.y + delta_y, 10 - direction)
      # Can't walk over the middle tile, but can walk over the end tile; jump over
      if location_passable?(self.x, self.y, direction)
        if leader.jumping?
          @jump_speed_real = leader.jump_speed_real
        else
          # This is doubled because self has to jump 2 tiles in the time it
          # takes the leader to move one tile.
          @jump_speed_real = leader.move_speed_real * 2
        end
        jump(delta_x, delta_y)
      else
        # self's current tile isn't passable; just take two steps ignoring passability
        move_through(direction)
        move_through(direction)
      end
    end
  end

  def fancy_moveto(new_x, new_y, leader)
    if self.x - new_x == 1 && (-1..1).include?(self.y - new_y)
      move_fancy(4,leader)
    elsif self.x - new_x == -1 && (-1..1).include?(self.y - new_y)
      move_fancy(6,leader)
    elsif self.x == new_x && self.y - new_y == 1
      move_fancy(8,leader)
    elsif self.x == new_x && self.y - new_y == -1
      move_fancy(2,leader)
    elsif self.x - new_x == 2 && self.y == new_y
      jump_fancy(4, leader)
    elsif self.x - new_x == -2 && self.y == new_y
      jump_fancy(6, leader)
    elsif self.x == new_x && self.y - new_y == 2
      jump_fancy(8, leader)
    elsif self.x == new_x && self.y - new_y == -2
      jump_fancy(2, leader)
    elsif self.x != new_x || self.y != new_y
      moveto(new_x, new_y)
    end
  end

end
 
Sorry to revive this. I have managed to make a small port of this script to 21.1 and it works almost perfectly...

The only problem I still have is that when going up the stairs in the right or left direction there is a jump in the screen (similar to what happened with ledges in 20.1). I have tried to solve it without success. I tried to test it in a new project without other scripts that could generate conflicts and the problem persists.

If someone is able to take a look it would be of great help.

Port to 21.1 W.I.P:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end

class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move

  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto

  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(7)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(9)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(1)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(3)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end
end

class Game_Player
  alias move_generic_stairs move_generic

def move_generic(dir, turn_enabled = true)
  old_tag = self.map.terrain_tag(@x, @y).id
  old_x = @x
  old_y = @y
  new_x = @x
  new_y = @y

  if dir == 4
    if old_tag == :StairLeft && passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft
      new_x = @x - 1
      new_y = @y + 1
  elsif old_tag == :StairRight && passable?(@x - 1, @y - 1, 6)
      new_x = @x - 1
      new_y = @y - 1
    end
  elsif dir == 6
    if old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4)
      new_x = @x + 1
      new_y = @y - 1
    elsif old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight
      new_x = @x + 1
      new_y = @y + 1
    end
  end
  if old_x != new_x || old_y != new_y
    moveto(new_x, new_y)
  else
    move_generic_stairs(dir, turn_enabled)
  end
  new_tag = self.map.terrain_tag(@x, @y)
  if old_x != @x
    if old_tag != :StairLeft && new_tag == :StairLeft ||
       old_tag != :StairRight && new_tag == :StairRight
      self.offset_y = -16
      @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
    elsif old_tag == :StairLeft && new_tag != :StairLeft ||
          old_tag == :StairRight && new_tag != :StairRight
      self.offset_y = 0
    end
  end
end

  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
    # Get new coordinates
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    # If coordinates are outside of map
    return false if !$game_map.validLax?(new_x, new_y)
    if !$game_map.valid?(new_x, new_y)
      return false if !$map_factory
      return $map_factory.isPassableFromEdge?(new_x, new_y)
    end
    # If debug mode is ON and Ctrl key was pressed
    return true if $DEBUG && Input.press?(Input::CTRL)
    # insertion from this script
    if d == 8 && new_y > 0 # prevent player moving up past the top of the stairs
      if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
         $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
        return false
      elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
            $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
        return false
      end
    end
    #end
    return super
  end
end

class Game_Follower
  def move_through(direction)
    old_through = @through
    @through = true
    case direction
    when 1 then move_lower_left
    when 2 then move_down
    when 3 then move_lower_right
    when 4 then move_left
    when 6 then move_right
    when 7 then move_upper_left
    when 8 then move_up
    when 9 then move_upper_right
    end
    @through = old_through
  end

def move_fancy(direction, leader)
  delta_x = (direction == 6) ? 1 : (direction == 4) ? -1 : 0
  delta_y = (direction == 2) ? 1 : (direction == 8) ? -1 : 0
  dir = direction
  old_tag = self.map.terrain_tag(self.x, self.y).id
  old_x = self.x

  if direction == 4
    if old_tag == :StairLeft
      if passable?(self.x - 1, self.y + 1, 4) && self.map.terrain_tag(self.x - 1, self.y + 1) == :StairLeft
        delta_y += 1
        dir = 1
      end
    elsif old_tag == :StairRight
      if passable?(self.x - 1, self.y - 1, 6)
        delta_y -= 1
        dir = 7
      end
    end
  elsif direction == 6
    if old_tag == :StairLeft && passable?(self.x + 1, self.y - 1, 4)
      delta_y -= 1
      dir = 9
    elsif old_tag == :StairRight && passable?(self.x + 1, self.y + 1, 6) && self.map.terrain_tag(self.x + 1, self.y + 1) == :StairRight
      delta_y += 1
      dir = 3
    end
  end

  new_x = self.x + delta_x
  new_y = self.y + delta_y

  if ($game_player.x == new_x && $game_player.y == new_y) ||
     location_passable?(new_x, new_y, 10 - direction) ||
     !location_passable?(self.x, self.y, direction)
    move_through(dir)
  end

  new_tag = self.map.terrain_tag(self.x, self.y)
  if old_x != self.x
    if old_tag != :StairLeft && new_tag == :StairLeft ||
       old_tag != :StairRight && new_tag == :StairRight
      self.offset_y = -16
      @y += 1 if (new_tag == :StairLeft && direction == 4) || (new_tag == :StairRight && direction == 6)
    elsif old_tag == :StairLeft && new_tag != :StairLeft ||
          old_tag == :StairRight && new_tag != :StairRight
      self.offset_y = 0
    end
  end

  turn_towards_leader(leader)
end


  def jump_fancy(direction, leader)
    delta_x = (direction == 6) ? 2 : (direction == 4) ? -2 : 0
    delta_y = (direction == 2) ? 2 : (direction == 8) ? -2 : 0
    half_delta_x = delta_x / 2
    half_delta_y = delta_y / 2
    if location_passable?(self.x + half_delta_x, self.y + half_delta_y, 10 - direction)
      # Can walk over the middle tile normally; just take two steps
      move_fancy(direction,leader)
      move_fancy(direction,leader)
    elsif location_passable?(self.x + delta_x, self.y + delta_y, 10 - direction)
      # Can't walk over the middle tile, but can walk over the end tile; jump over
      if location_passable?(self.x, self.y, direction)
        if leader.jumping?
          @jump_speed_real = leader.jump_speed_real
        else
          # This is doubled because self has to jump 2 tiles in the time it
          # takes the leader to move one tile.
          @jump_speed_real = leader.move_speed_real * 2
        end
        jump(delta_x, delta_y)
      else
        # self's current tile isn't passable; just take two steps ignoring passability
        move_through(direction)
        move_through(direction)
      end
    end
  end

  def fancy_moveto(new_x, new_y, leader)
    if self.x - new_x == 1 && (-1..1).include?(self.y - new_y)
      move_fancy(4,leader)
    elsif self.x - new_x == -1 && (-1..1).include?(self.y - new_y)
      move_fancy(6,leader)
    elsif self.x == new_x && self.y - new_y == 1
      move_fancy(8,leader)
    elsif self.x == new_x && self.y - new_y == -1
      move_fancy(2,leader)
    elsif self.x - new_x == 2 && self.y == new_y
      jump_fancy(4, leader)
    elsif self.x - new_x == -2 && self.y == new_y
      jump_fancy(6, leader)
    elsif self.x == new_x && self.y - new_y == 2
      jump_fancy(8, leader)
    elsif self.x == new_x && self.y - new_y == -2
      jump_fancy(2, leader)
    elsif self.x != new_x || self.y != new_y
      moveto(new_x, new_y)
    end
  end

end


Yo, no idea if you already fixed it but I got back to making my own game after a long break and Im using v21.1 as well. I fixed the bug but you have to be aware of 2 things: 1.) The code I put below doesnt have the Follower Class because I dont use follower pkmn in my game, therefore make sure to not delete the class in your own code (at the very bottom) and I cant guarantee that it does work for follower (prob doesnt). 2.) You have to place events - for "staircase left" the event has to be at the right of the staircase tile, for "staircase right" it has to be at the left tile of the staircase (examples are attached). Make sure that youre facing right or left in the conditional branch as well.

Maybe you have to adapt the size of your stairs a little bit. Also Im sure there is a more elegant way to fix these problems but Im not very good with ruby code, so its whatever - what works, works I guess.

Have a good one

Code:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end

class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move

  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto

  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(7)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(9)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(1)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(3)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end
end

class Game_Player
  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y).id
    old_x = @x
    old_y = @y
    new_x = @x
    new_y = @y
 
    if dir == 4
      if (old_tag == :StairLeft && passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft) ||
         (old_tag == :StairRight && passable?(@x - 1, @y - 1, 6) && self.map.terrain_tag(@x - 1, @y - 1) == :StairRight)
        new_x = @x - 1
        new_y = @y + 1
      end
    elsif dir == 6
      if (old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4) && self.map.terrain_tag(@x + 1, @y - 1) == :StairLeft) ||
         (old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight)
        new_x = @x + 1
        new_y = @y - 1
      end
    end
    if old_x != new_x || old_y != new_y
      moveto(new_x, new_y)
    else
      move_generic_stairs(dir, turn_enabled)
    end
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != :StairLeft && new_tag == :StairLeft ||
         old_tag != :StairRight && new_tag == :StairRight
        self.offset_y = -16
        @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
      elsif old_tag == :StairLeft && new_tag != :StairLeft ||
            old_tag == :StairRight && new_tag != :StairRight
        self.offset_y = 0
      end
    end
  end

  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
      # Get new coordinates
      new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
      new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
      # If coordinates are outside of map
      return false if !$game_map.validLax?(new_x, new_y)
      if !$game_map.valid?(new_x, new_y)
        return false if !$map_factory
        return $map_factory.isPassableFromEdge?(new_x, new_y)
      end
      # If debug mode is ON and Ctrl key was pressed
      return true if $DEBUG && Input.press?(Input::CTRL)
      # insertion from this script
      if (d == 8 && new_y > 0) # prevent player moving up past the top of the stairs
        if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
           $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
          return false
        elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
              $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
          return false
        end
      end
      #end
      return super
  end
end
 

Attachments

  • staircase-left.png
    staircase-left.png
    38.8 KB · Views: 52
  • staircase-right.png
    staircase-right.png
    34.2 KB · Views: 52
Yo, no idea if you already fixed it but I got back to making my own game after a long break and Im using v21.1 as well. I fixed the bug but you have to be aware of 2 things: 1.) The code I put below doesnt have the Follower Class because I dont use follower pkmn in my game, therefore make sure to not delete the class in your own code (at the very bottom) and I cant guarantee that it does work for follower (prob doesnt). 2.) You have to place events - for "staircase left" the event has to be at the right of the staircase tile, for "staircase right" it has to be at the left tile of the staircase (examples are attached). Make sure that youre facing right or left in the conditional branch as well.

Maybe you have to adapt the size of your stairs a little bit. Also Im sure there is a more elegant way to fix these problems but Im not very good with ruby code, so its whatever - what works, works I guess.

Have a good one

Code:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end

class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move

  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto

  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(7)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(9)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(1)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(3)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end
end

class Game_Player
  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y).id
    old_x = @x
    old_y = @y
    new_x = @x
    new_y = @y
 
    if dir == 4
      if (old_tag == :StairLeft && passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft) ||
         (old_tag == :StairRight && passable?(@x - 1, @y - 1, 6) && self.map.terrain_tag(@x - 1, @y - 1) == :StairRight)
        new_x = @x - 1
        new_y = @y + 1
      end
    elsif dir == 6
      if (old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4) && self.map.terrain_tag(@x + 1, @y - 1) == :StairLeft) ||
         (old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight)
        new_x = @x + 1
        new_y = @y - 1
      end
    end
    if old_x != new_x || old_y != new_y
      moveto(new_x, new_y)
    else
      move_generic_stairs(dir, turn_enabled)
    end
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != :StairLeft && new_tag == :StairLeft ||
         old_tag != :StairRight && new_tag == :StairRight
        self.offset_y = -16
        @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
      elsif old_tag == :StairLeft && new_tag != :StairLeft ||
            old_tag == :StairRight && new_tag != :StairRight
        self.offset_y = 0
      end
    end
  end

  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
      # Get new coordinates
      new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
      new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
      # If coordinates are outside of map
      return false if !$game_map.validLax?(new_x, new_y)
      if !$game_map.valid?(new_x, new_y)
        return false if !$map_factory
        return $map_factory.isPassableFromEdge?(new_x, new_y)
      end
      # If debug mode is ON and Ctrl key was pressed
      return true if $DEBUG && Input.press?(Input::CTRL)
      # insertion from this script
      if (d == 8 && new_y > 0) # prevent player moving up past the top of the stairs
        if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
           $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
          return false
        elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
              $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
          return false
        end
      end
      #end
      return super
  end
end
Thank you for this.

At least it is a functional solution and that is already a great advance.

I imagine that there must be some way to do it without the events via script, but I don't know how (I'm quite amateur in scripting).

Eventually the code for the followers complies with this version, except for slight positioning errors it is more or less playable.

It's a great improvement! Thank you!
 
Yo, no idea if you already fixed it but I got back to making my own game after a long break and Im using v21.1 as well. I fixed the bug but you have to be aware of 2 things: 1.) The code I put below doesnt have the Follower Class because I dont use follower pkmn in my game, therefore make sure to not delete the class in your own code (at the very bottom) and I cant guarantee that it does work for follower (prob doesnt). 2.) You have to place events - for "staircase left" the event has to be at the right of the staircase tile, for "staircase right" it has to be at the left tile of the staircase (examples are attached). Make sure that youre facing right or left in the conditional branch as well.

Maybe you have to adapt the size of your stairs a little bit. Also Im sure there is a more elegant way to fix these problems but Im not very good with ruby code, so its whatever - what works, works I guess.

Have a good one

Code:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end

class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move

  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto

  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(7)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(9)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(1)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(3)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end
end

class Game_Player
  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y).id
    old_x = @x
    old_y = @y
    new_x = @x
    new_y = @y
 
    if dir == 4
      if (old_tag == :StairLeft && passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft) ||
         (old_tag == :StairRight && passable?(@x - 1, @y - 1, 6) && self.map.terrain_tag(@x - 1, @y - 1) == :StairRight)
        new_x = @x - 1
        new_y = @y + 1
      end
    elsif dir == 6
      if (old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4) && self.map.terrain_tag(@x + 1, @y - 1) == :StairLeft) ||
         (old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight)
        new_x = @x + 1
        new_y = @y - 1
      end
    end
    if old_x != new_x || old_y != new_y
      moveto(new_x, new_y)
    else
      move_generic_stairs(dir, turn_enabled)
    end
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != :StairLeft && new_tag == :StairLeft ||
         old_tag != :StairRight && new_tag == :StairRight
        self.offset_y = -16
        @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
      elsif old_tag == :StairLeft && new_tag != :StairLeft ||
            old_tag == :StairRight && new_tag != :StairRight
        self.offset_y = 0
      end
    end
  end

  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
      # Get new coordinates
      new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
      new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
      # If coordinates are outside of map
      return false if !$game_map.validLax?(new_x, new_y)
      if !$game_map.valid?(new_x, new_y)
        return false if !$map_factory
        return $map_factory.isPassableFromEdge?(new_x, new_y)
      end
      # If debug mode is ON and Ctrl key was pressed
      return true if $DEBUG && Input.press?(Input::CTRL)
      # insertion from this script
      if (d == 8 && new_y > 0) # prevent player moving up past the top of the stairs
        if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
           $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
          return false
        elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
              $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
          return false
        end
      end
      #end
      return super
  end
end

Sorry to bug you, but is there any chance you could repost the event examples? Embedded images are all broken at the moment.
 
Sorry to revive this. I have managed to make a small port of this script to 21.1 and it works almost perfectly...

The only problem I still have is that when going up the stairs in the right or left direction there is a jump in the screen (similar to what happened with ledges in 20.1). I have tried to solve it without success. I tried to test it in a new project without other scripts that could generate conflicts and the problem persists.

If someone is able to take a look it would be of great help.

Port to 21.1 W.I.P:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end

class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move

  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto

  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(7)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(9)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(1)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(3)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end
end

class Game_Player
  alias move_generic_stairs move_generic

def move_generic(dir, turn_enabled = true)
  old_tag = self.map.terrain_tag(@x, @y).id
  old_x = @x
  old_y = @y
  new_x = @x
  new_y = @y

  if dir == 4
    if old_tag == :StairLeft && passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft
      new_x = @x - 1
      new_y = @y + 1
  elsif old_tag == :StairRight && passable?(@x - 1, @y - 1, 6)
      new_x = @x - 1
      new_y = @y - 1
    end
  elsif dir == 6
    if old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4)
      new_x = @x + 1
      new_y = @y - 1
    elsif old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight
      new_x = @x + 1
      new_y = @y + 1
    end
  end
  if old_x != new_x || old_y != new_y
    moveto(new_x, new_y)
  else
    move_generic_stairs(dir, turn_enabled)
  end
  new_tag = self.map.terrain_tag(@x, @y)
  if old_x != @x
    if old_tag != :StairLeft && new_tag == :StairLeft ||
       old_tag != :StairRight && new_tag == :StairRight
      self.offset_y = -16
      @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
    elsif old_tag == :StairLeft && new_tag != :StairLeft ||
          old_tag == :StairRight && new_tag != :StairRight
      self.offset_y = 0
    end
  end
end

  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
    # Get new coordinates
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    # If coordinates are outside of map
    return false if !$game_map.validLax?(new_x, new_y)
    if !$game_map.valid?(new_x, new_y)
      return false if !$map_factory
      return $map_factory.isPassableFromEdge?(new_x, new_y)
    end
    # If debug mode is ON and Ctrl key was pressed
    return true if $DEBUG && Input.press?(Input::CTRL)
    # insertion from this script
    if d == 8 && new_y > 0 # prevent player moving up past the top of the stairs
      if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
         $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
        return false
      elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
            $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
        return false
      end
    end
    #end
    return super
  end
end

class Game_Follower
  def move_through(direction)
    old_through = @through
    @through = true
    case direction
    when 1 then move_lower_left
    when 2 then move_down
    when 3 then move_lower_right
    when 4 then move_left
    when 6 then move_right
    when 7 then move_upper_left
    when 8 then move_up
    when 9 then move_upper_right
    end
    @through = old_through
  end

def move_fancy(direction, leader)
  delta_x = (direction == 6) ? 1 : (direction == 4) ? -1 : 0
  delta_y = (direction == 2) ? 1 : (direction == 8) ? -1 : 0
  dir = direction
  old_tag = self.map.terrain_tag(self.x, self.y).id
  old_x = self.x

  if direction == 4
    if old_tag == :StairLeft
      if passable?(self.x - 1, self.y + 1, 4) && self.map.terrain_tag(self.x - 1, self.y + 1) == :StairLeft
        delta_y += 1
        dir = 1
      end
    elsif old_tag == :StairRight
      if passable?(self.x - 1, self.y - 1, 6)
        delta_y -= 1
        dir = 7
      end
    end
  elsif direction == 6
    if old_tag == :StairLeft && passable?(self.x + 1, self.y - 1, 4)
      delta_y -= 1
      dir = 9
    elsif old_tag == :StairRight && passable?(self.x + 1, self.y + 1, 6) && self.map.terrain_tag(self.x + 1, self.y + 1) == :StairRight
      delta_y += 1
      dir = 3
    end
  end

  new_x = self.x + delta_x
  new_y = self.y + delta_y

  if ($game_player.x == new_x && $game_player.y == new_y) ||
     location_passable?(new_x, new_y, 10 - direction) ||
     !location_passable?(self.x, self.y, direction)
    move_through(dir)
  end

  new_tag = self.map.terrain_tag(self.x, self.y)
  if old_x != self.x
    if old_tag != :StairLeft && new_tag == :StairLeft ||
       old_tag != :StairRight && new_tag == :StairRight
      self.offset_y = -16
      @y += 1 if (new_tag == :StairLeft && direction == 4) || (new_tag == :StairRight && direction == 6)
    elsif old_tag == :StairLeft && new_tag != :StairLeft ||
          old_tag == :StairRight && new_tag != :StairRight
      self.offset_y = 0
    end
  end

  turn_towards_leader(leader)
end


  def jump_fancy(direction, leader)
    delta_x = (direction == 6) ? 2 : (direction == 4) ? -2 : 0
    delta_y = (direction == 2) ? 2 : (direction == 8) ? -2 : 0
    half_delta_x = delta_x / 2
    half_delta_y = delta_y / 2
    if location_passable?(self.x + half_delta_x, self.y + half_delta_y, 10 - direction)
      # Can walk over the middle tile normally; just take two steps
      move_fancy(direction,leader)
      move_fancy(direction,leader)
    elsif location_passable?(self.x + delta_x, self.y + delta_y, 10 - direction)
      # Can't walk over the middle tile, but can walk over the end tile; jump over
      if location_passable?(self.x, self.y, direction)
        if leader.jumping?
          @jump_speed_real = leader.jump_speed_real
        else
          # This is doubled because self has to jump 2 tiles in the time it
          # takes the leader to move one tile.
          @jump_speed_real = leader.move_speed_real * 2
        end
        jump(delta_x, delta_y)
      else
        # self's current tile isn't passable; just take two steps ignoring passability
        move_through(direction)
        move_through(direction)
      end
    end
  end

  def fancy_moveto(new_x, new_y, leader)
    if self.x - new_x == 1 && (-1..1).include?(self.y - new_y)
      move_fancy(4,leader)
    elsif self.x - new_x == -1 && (-1..1).include?(self.y - new_y)
      move_fancy(6,leader)
    elsif self.x == new_x && self.y - new_y == 1
      move_fancy(8,leader)
    elsif self.x == new_x && self.y - new_y == -1
      move_fancy(2,leader)
    elsif self.x - new_x == 2 && self.y == new_y
      jump_fancy(4, leader)
    elsif self.x - new_x == -2 && self.y == new_y
      jump_fancy(6, leader)
    elsif self.x == new_x && self.y - new_y == 2
      jump_fancy(8, leader)
    elsif self.x == new_x && self.y - new_y == -2
      jump_fancy(2, leader)
    elsif self.x != new_x || self.y != new_y
      moveto(new_x, new_y)
    end
  end

end
It should be speed instead of speed_real in essentials v21.1 btw.
 
Sorry to revive this. I have managed to make a small port of this script to 21.1 and it works almost perfectly...

The only problem I still have is that when going up the stairs in the right or left direction there is a jump in the screen (similar to what happened with ledges in 20.1). I have tried to solve it without success. I tried to test it in a new project without other scripts that could generate conflicts and the problem persists.

If someone is able to take a look it would be of great help.

Port to 21.1 W.I.P:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end

class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move

  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto

  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(7)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(9)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(1)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(3)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end
end

class Game_Player
  alias move_generic_stairs move_generic

def move_generic(dir, turn_enabled = true)
  old_tag = self.map.terrain_tag(@x, @y).id
  old_x = @x
  old_y = @y
  new_x = @x
  new_y = @y

  if dir == 4
    if old_tag == :StairLeft && passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft
      new_x = @x - 1
      new_y = @y + 1
  elsif old_tag == :StairRight && passable?(@x - 1, @y - 1, 6)
      new_x = @x - 1
      new_y = @y - 1
    end
  elsif dir == 6
    if old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4)
      new_x = @x + 1
      new_y = @y - 1
    elsif old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight
      new_x = @x + 1
      new_y = @y + 1
    end
  end
  if old_x != new_x || old_y != new_y
    moveto(new_x, new_y)
  else
    move_generic_stairs(dir, turn_enabled)
  end
  new_tag = self.map.terrain_tag(@x, @y)
  if old_x != @x
    if old_tag != :StairLeft && new_tag == :StairLeft ||
       old_tag != :StairRight && new_tag == :StairRight
      self.offset_y = -16
      @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
    elsif old_tag == :StairLeft && new_tag != :StairLeft ||
          old_tag == :StairRight && new_tag != :StairRight
      self.offset_y = 0
    end
  end
end

  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
    # Get new coordinates
    new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
    new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
    # If coordinates are outside of map
    return false if !$game_map.validLax?(new_x, new_y)
    if !$game_map.valid?(new_x, new_y)
      return false if !$map_factory
      return $map_factory.isPassableFromEdge?(new_x, new_y)
    end
    # If debug mode is ON and Ctrl key was pressed
    return true if $DEBUG && Input.press?(Input::CTRL)
    # insertion from this script
    if d == 8 && new_y > 0 # prevent player moving up past the top of the stairs
      if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
         $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
        return false
      elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
            $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
        return false
      end
    end
    #end
    return super
  end
end

class Game_Follower
  def move_through(direction)
    old_through = @through
    @through = true
    case direction
    when 1 then move_lower_left
    when 2 then move_down
    when 3 then move_lower_right
    when 4 then move_left
    when 6 then move_right
    when 7 then move_upper_left
    when 8 then move_up
    when 9 then move_upper_right
    end
    @through = old_through
  end

def move_fancy(direction, leader)
  delta_x = (direction == 6) ? 1 : (direction == 4) ? -1 : 0
  delta_y = (direction == 2) ? 1 : (direction == 8) ? -1 : 0
  dir = direction
  old_tag = self.map.terrain_tag(self.x, self.y).id
  old_x = self.x

  if direction == 4
    if old_tag == :StairLeft
      if passable?(self.x - 1, self.y + 1, 4) && self.map.terrain_tag(self.x - 1, self.y + 1) == :StairLeft
        delta_y += 1
        dir = 1
      end
    elsif old_tag == :StairRight
      if passable?(self.x - 1, self.y - 1, 6)
        delta_y -= 1
        dir = 7
      end
    end
  elsif direction == 6
    if old_tag == :StairLeft && passable?(self.x + 1, self.y - 1, 4)
      delta_y -= 1
      dir = 9
    elsif old_tag == :StairRight && passable?(self.x + 1, self.y + 1, 6) && self.map.terrain_tag(self.x + 1, self.y + 1) == :StairRight
      delta_y += 1
      dir = 3
    end
  end

  new_x = self.x + delta_x
  new_y = self.y + delta_y

  if ($game_player.x == new_x && $game_player.y == new_y) ||
     location_passable?(new_x, new_y, 10 - direction) ||
     !location_passable?(self.x, self.y, direction)
    move_through(dir)
  end

  new_tag = self.map.terrain_tag(self.x, self.y)
  if old_x != self.x
    if old_tag != :StairLeft && new_tag == :StairLeft ||
       old_tag != :StairRight && new_tag == :StairRight
      self.offset_y = -16
      @y += 1 if (new_tag == :StairLeft && direction == 4) || (new_tag == :StairRight && direction == 6)
    elsif old_tag == :StairLeft && new_tag != :StairLeft ||
          old_tag == :StairRight && new_tag != :StairRight
      self.offset_y = 0
    end
  end

  turn_towards_leader(leader)
end


  def jump_fancy(direction, leader)
    delta_x = (direction == 6) ? 2 : (direction == 4) ? -2 : 0
    delta_y = (direction == 2) ? 2 : (direction == 8) ? -2 : 0
    half_delta_x = delta_x / 2
    half_delta_y = delta_y / 2
    if location_passable?(self.x + half_delta_x, self.y + half_delta_y, 10 - direction)
      # Can walk over the middle tile normally; just take two steps
      move_fancy(direction,leader)
      move_fancy(direction,leader)
    elsif location_passable?(self.x + delta_x, self.y + delta_y, 10 - direction)
      # Can't walk over the middle tile, but can walk over the end tile; jump over
      if location_passable?(self.x, self.y, direction)
        if leader.jumping?
          @jump_speed_real = leader.jump_speed_real
        else
          # This is doubled because self has to jump 2 tiles in the time it
          # takes the leader to move one tile.
          @jump_speed_real = leader.move_speed_real * 2
        end
        jump(delta_x, delta_y)
      else
        # self's current tile isn't passable; just take two steps ignoring passability
        move_through(direction)
        move_through(direction)
      end
    end
  end

  def fancy_moveto(new_x, new_y, leader)
    if self.x - new_x == 1 && (-1..1).include?(self.y - new_y)
      move_fancy(4,leader)
    elsif self.x - new_x == -1 && (-1..1).include?(self.y - new_y)
      move_fancy(6,leader)
    elsif self.x == new_x && self.y - new_y == 1
      move_fancy(8,leader)
    elsif self.x == new_x && self.y - new_y == -1
      move_fancy(2,leader)
    elsif self.x - new_x == 2 && self.y == new_y
      jump_fancy(4, leader)
    elsif self.x - new_x == -2 && self.y == new_y
      jump_fancy(6, leader)
    elsif self.x == new_x && self.y - new_y == 2
      jump_fancy(8, leader)
    elsif self.x == new_x && self.y - new_y == -2
      jump_fancy(2, leader)
    elsif self.x != new_x || self.y != new_y
      moveto(new_x, new_y)
    end
  end

end
It turns out that the moveto method is now instantaneous, there is no longer a smooth movement of the character to the desired location. Before it was useful for these animations.

To help, I tested the follower being an event in Essentials v21, and also in the development versions, if you do a "down right-up" or any diagonal movement, the follower uses the moveto method that generates this jump.
So, even if we do porting, we would have to delete moveto and start handling all the ways of movement.
 
Last edited:
I took some time to fix the jumps caused by moveto, which was used to handle exceptions when it was not known which path the follower should take. Although new_x, new_y seem confusing, I made an adaptation so that going up and down stairs with or without this Script works smoothly.

Everything in the fancy_moveto method of the Game_Follower class.
Ruby:
Expand Collapse Copy
def fancy_moveto(new_x, new_y, leader)
    if self.x - new_x == 1 && (-1..1).include?(self.y - new_y)
      # Left-Up
      if self.y - new_y == 1 && passable?(new_x, new_y, 4)
        move_through(7)
        # New
      elsif self.y - new_y == 1 && passable?(self.x, self.y, 4)
        move_through(7)
      # Left-Down
      elsif self.y - new_y == -1 && passable?(new_x, self.y, 4)
        move_through(1)
        # New
      elsif self.y - new_y == -1 && passable?(self.x, self.y, 4)
        move_through(1)
      else
        move_fancy(4,leader)
      end
    elsif self.x - new_x == -1 && (-1..1).include?(self.y - new_y)
      # Right-Down
      if self.y - new_y == -1 && passable?(new_x, new_y, 6)
        move_through(3)
        # New
        elsif self.y - new_y == -1 && passable?(self.x, self.y, 6)
          move_through(3)
      # Right-Up
      elsif self.y - new_y == 1 && passable?(new_x, self.y, 6)
        move_through(9)
        # New
        elsif self.y - new_y == 1 && passable?(self.x, self.y, 6)
          move_through(9)
      else
        move_fancy(6,leader)
      end
    elsif self.x == new_x && self.y - new_y == 1
      move_fancy(8,leader)
    elsif self.x == new_x && self.y - new_y == -1
      move_fancy(2,leader)
    elsif self.x - new_x == 2 && self.y == new_y
      jump_fancy(4, leader)
    elsif self.x - new_x == -2 && self.y == new_y
      jump_fancy(6, leader)
    elsif self.x - new_x == 2 && self.y == new_y + 1
      jump_fancy(4, leader)
    elsif self.x - new_x == -2 && self.y == new_y  + 1
      jump_fancy(6, leader)
    #------------------------------------------------
    # New coordinates.
    #------------------------------------------------
    elsif self.x == new_x && self.y - new_y == 2
      jump_fancy(8, leader)
    elsif self.x == new_x && self.y - new_y == -2
      jump_fancy(2, leader)
    #------------------------------------------------
    # Diagonal floors
    #------------------------------------------------
    elsif self.x == new_x + 1 && self.y - new_y == 2
      move_through(7)
    elsif self.x == new_x + 1 && self.y - new_y == -2
      move_through(1)
    elsif self.x == new_x - 1 && self.y - new_y == -2
      move_through(3)
    elsif self.x == new_x - 1 && self.y - new_y == 2
      move_through(9)
    elsif self.x != new_x || self.y != new_y
      moveto(new_x, new_y)
    end
  end

Edit: Code updated 28-01-2025 to read coordinates on small stairs. Here I have been using stairs via event, as the Wiki says.

Edit: This is my code with some personal changes, I should improve it further soon.
 
Last edited:
Yo, no idea if you already fixed it but I got back to making my own game after a long break and Im using v21.1 as well. I fixed the bug but you have to be aware of 2 things: 1.) The code I put below doesnt have the Follower Class because I dont use follower pkmn in my game, therefore make sure to not delete the class in your own code (at the very bottom) and I cant guarantee that it does work for follower (prob doesnt). 2.) You have to place events - for "staircase left" the event has to be at the right of the staircase tile, for "staircase right" it has to be at the left tile of the staircase (examples are attached). Make sure that youre facing right or left in the conditional branch as well.

Maybe you have to adapt the size of your stairs a little bit. Also Im sure there is a more elegant way to fix these problems but Im not very good with ruby code, so its whatever - what works, works I guess.

Have a good one

Code:
Expand Collapse Copy
#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
GameData::TerrainTag.register({
  :id => :StairLeft,
  :id_number => 32,
})
GameData::TerrainTag.register({
  :id => :StairRight,
  :id_number => 33,
})
#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event, otherEvent)
  sx = 0
  sy = 0
  if $map_factory
    relativePos = $map_factory.getThisAndOtherEventRelativePos(otherEvent, event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  sx += (event.width - otherEvent.width) / 2.0
  sy -= (event.height - otherEvent.height) / 2.0
  return if sx == 0 && sy == 0
  if sx.abs >= sy.abs # changed to >=
    (sx > 0) ? event.turn_left : event.turn_right
  else
    (sy > 0) ? event.turn_up : event.turn_down
  end
end

class Game_Character
  alias initialize_stairs initialize
  attr_accessor :offset_x
  attr_accessor :offset_y
  attr_accessor :real_offset_x
  attr_accessor :real_offset_y

  def initialize(*args)
    @offset_x = 0
    @offset_y = 0
    @real_offset_x = 0
    @real_offset_y = 0
    initialize_stairs(*args)
  end

  alias screen_x_stairs screen_x

  def screen_x
    @real_offset_x = 0 if @real_offset_x == nil
    return screen_x_stairs + @real_offset_x
  end

  alias screen_y_stairs screen_y

  def screen_y
    @real_offset_y = 0 if @real_offset_y == nil
    return screen_y_stairs + @real_offset_y
  end

  alias updatemovestairs update_move

  def update_move
    # compatibility with existing saves
    if @real_offset_x == nil || @real_offset_y == nil || @offset_y == nil || @offset_x == nil
      @real_offset_x = 0
      @real_offset_y = 0
      @offset_x = 0
      @offset_y = 0
    end
    if @real_offset_x != @offset_x || @real_offset_y != @offset_y
      @real_offset_x = @real_offset_x - 2 if @real_offset_x > @offset_x
      @real_offset_x = @real_offset_x + 2 if @real_offset_x < @offset_x
      @real_offset_y = @real_offset_y + 2 if @real_offset_y < @offset_y
      @real_offset_y = @real_offset_y - 2 if @real_offset_y > @offset_y
    end
    updatemovestairs
  end

  alias movetostairs moveto

  def moveto(x, y)
    # start edits
    @real_offset_x = 0
    @real_offset_y = 0
    @offset_x = 0
    @offset_y = 0
    # end
    @x = x % self.map.width
    @y = y % self.map.height
    @real_x = @x * Game_Map::REAL_RES_X
    @real_y = @y * Game_Map::REAL_RES_Y
    @prelock_direction = 0
    @moveto_happened = true
    calculate_bush_depth
    triggerLeaveTile
    movetostairs(x, y)
  end

  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    move_generic_stairs(dir, turn_enabled)
    if self.map.terrain_tag(@x, @y) == :StairLeft || self.map.terrain_tag(@x, @y) == :StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_upper_left_stairs move_upper_left
  def move_upper_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(7)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_upper_right_stairs move_upper_right
  def move_upper_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 2 ? 8 : @direction)
    end
    if can_move_in_direction?(9)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y -= 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_left_stairs move_lower_left
  def move_lower_left
    unless @direction_fix
      @direction = (@direction == 6 ? 4 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(1)
      @move_initial_x = @x
      @move_initial_y = @y
      @x -= 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end

  alias move_lower_right_stairs move_lower_right
  def move_lower_right
    unless @direction_fix
      @direction = (@direction == 4 ? 6 : @direction == 8 ? 2 : @direction)
    end
    if can_move_in_direction?(3)
      @move_initial_x = @x
      @move_initial_y = @y
      @x += 1
      @y += 1
      @move_timer = 0.0
      increase_steps
    end
  end
end

class Game_Player
  alias move_generic_stairs move_generic

  def move_generic(dir, turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y).id
    old_x = @x
    old_y = @y
    new_x = @x
    new_y = @y
 
    if dir == 4
      if (old_tag == :StairLeft && passable?(@x - 1, @y + 1, 4) && self.map.terrain_tag(@x - 1, @y + 1) == :StairLeft) ||
         (old_tag == :StairRight && passable?(@x - 1, @y - 1, 6) && self.map.terrain_tag(@x - 1, @y - 1) == :StairRight)
        new_x = @x - 1
        new_y = @y + 1
      end
    elsif dir == 6
      if (old_tag == :StairLeft && passable?(@x + 1, @y - 1, 4) && self.map.terrain_tag(@x + 1, @y - 1) == :StairLeft) ||
         (old_tag == :StairRight && passable?(@x + 1, @y + 1, 6) && self.map.terrain_tag(@x + 1, @y + 1) == :StairRight)
        new_x = @x + 1
        new_y = @y - 1
      end
    end
    if old_x != new_x || old_y != new_y
      moveto(new_x, new_y)
    else
      move_generic_stairs(dir, turn_enabled)
    end
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != :StairLeft && new_tag == :StairLeft ||
         old_tag != :StairRight && new_tag == :StairRight
        self.offset_y = -16
        @y += 1 if (new_tag == :StairLeft && dir == 4) || (new_tag == :StairRight && dir == 6)
      elsif old_tag == :StairLeft && new_tag != :StairLeft ||
            old_tag == :StairRight && new_tag != :StairRight
        self.offset_y = 0
      end
    end
  end

  alias center_stairs center

  def center(x, y)
    center_stairs(x, y)
    self.map.display_x = self.map.display_x + (@offset_x || 0)
    self.map.display_y = self.map.display_y + (@offset_y || 0)
  end

  def passable?(x, y, d, strict = false)
      # Get new coordinates
      new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
      new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
      # If coordinates are outside of map
      return false if !$game_map.validLax?(new_x, new_y)
      if !$game_map.valid?(new_x, new_y)
        return false if !$map_factory
        return $map_factory.isPassableFromEdge?(new_x, new_y)
      end
      # If debug mode is ON and Ctrl key was pressed
      return true if $DEBUG && Input.press?(Input::CTRL)
      # insertion from this script
      if (d == 8 && new_y > 0) # prevent player moving up past the top of the stairs
        if $game_map.terrain_tag(new_x, new_y) == :StairLeft &&
           $game_map.terrain_tag(new_x, new_y - 1) != :StairLeft
          return false
        elsif $game_map.terrain_tag(new_x, new_y) == :StairRight &&
              $game_map.terrain_tag(new_x, new_y - 1) != :StairRight
          return false
        end
      end
      #end
      return super
  end
end
The images aren't loading here - can anyone help me with the event code? It looks like it might be similar to the Wiki code but the instructions don't make sense for when the stairs are only one tile across.
 
Back
Top