• Hi, Guest!
    Some images might be missing as we move away from using embedded images, sorry for the mess!
    From now on, you'll be required to use a third party to host images. You can learn how to add images here, and if your thread is missing images you can request them here.
    Do not use Discord to host any images you post, these links expire quickly!
Resource icon

Resource Terrain Tag Side Stairs 1.0

dolu

Rookie
Member
Joined
Apr 18, 2022
Posts
1
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
 

boonzeet

Developer of Pokemon: Secrets of the Ages
Member
Joined
Mar 13, 2019
Posts
70
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.
 

boonzeet

Developer of Pokemon: Secrets of the Ages
Member
Joined
Mar 13, 2019
Posts
70
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
 

REALMUGEN

Trainer
Member
Joined
Jan 23, 2020
Posts
69
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
 

Fredblade

Rookie
Member
Joined
Jun 24, 2021
Posts
2
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
 

REALMUGEN

Trainer
Member
Joined
Jan 23, 2020
Posts
69
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.
 

CarlosPR

Novice
Member
Joined
Mar 6, 2022
Posts
49
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.
 

REALMUGEN

Trainer
Member
Joined
Jan 23, 2020
Posts
69
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:

Juno and Ice

Rookie
Member
Joined
Jun 14, 2018
Posts
8
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?
 

REALMUGEN

Trainer
Member
Joined
Jan 23, 2020
Posts
69
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:
#-------------------------------------------------------------------------------
# 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.
 

REALMUGEN

Trainer
Member
Joined
Jan 23, 2020
Posts
69
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:
#-------------------------------------------------------------------------------
# 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
 

Theratos

Rookie
Member
Joined
Nov 23, 2021
Posts
1
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:
#-------------------------------------------------------------------------------
# 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:
#-------------------------------------------------------------------------------
# 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

REALMUGEN

Trainer
Member
Joined
Jan 23, 2020
Posts
69
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:
#-------------------------------------------------------------------------------
# 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!
 

CNix

Rookie
Member
Joined
Jul 4, 2024
Posts
1
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:
#-------------------------------------------------------------------------------
# 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.
 
Back
Top