Resource icon

Terrain Tag Side Stairs

Pokémon Essentials Version
v18 ✅
Boon's Terrain Tag Side Stairs


A simple script to allow placing stair tiles that automatically perform as side stairs, with psuedo-depth effect and support for Followers.

Might conflict with some scripts if they significantly alter Game_Player.

Setup

Version 18:
Place this script above Main.
Ruby:
#-------------------------------------------------------------------------------
# Boon's Terrain Tag Side Stairs
# v1.1
# By Boonzeet
#-------------------------------------------------------------------------------
# Sideways stairs with pseudo 'depth' effect. Please credit if used
#-------------------------------------------------------------------------------
# v1.1 - Added v18 support
#-------------------------------------------------------------------------------

PluginManager.register({
  :name => "Terrain Tag Side Stairs",
  :version => "1.1",
  :credits => ["Boonzeet"],
  :link => "https://reliccastle.com/resources/397/"
})

#-------------------------------------------------------------------------------
# Config
#-------------------------------------------------------------------------------
module PBTerrain
  StairLeft       = 19  # Set these to the terrain tags you'd like to use
  StairRight      = 20
end

#-------------------------------------------------------------------------------
# Existing Class Extensions
#-------------------------------------------------------------------------------
def pbTurnTowardEvent(event,otherEvent)
  sx = 0; sy = 0
  if $MapFactory
    relativePos=$MapFactory.getThisAndOtherEventRelativePos(otherEvent,event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  return if sx == 0 and sy == 0
  if sx.abs >= sy.abs #added
    (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

  def update_move
    # Move the character (the 0.1 catches rounding errors)
    distance = move_speed_real
    # 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
    
    dest_x = @x * Game_Map::REAL_RES_X
    dest_y = @y * Game_Map::REAL_RES_Y
    if @real_x < dest_x
      @real_x += distance
      @real_x = dest_x if @real_x > dest_x - 0.1
    else
      @real_x -= distance
      @real_x = dest_x if @real_x < dest_x + 0.1
    end
    if @real_y < dest_y
      @real_y += distance
      @real_y = dest_y if @real_y > dest_y - 0.1
    else
      @real_y -= distance
      @real_y = dest_y if @real_y < dest_y + 0.1
    end
    # End of a step, so perform events that happen at this time
    Events.onStepTakenFieldMovement.trigger(self,self) if !jumping? && !moving?
    # Increment animation counter
    @anime_count += 1 if @walk_anime || @step_anime
    @moved_this_frame = true
  end

end

class Game_Character
   alias move_left_stairs move_left
   def move_left(turn_enabled = true)
    move_left_stairs(turn_enabled)
    if self.map.terrain_tag(@x,@y) == PBTerrain::StairLeft || self.map.terrain_tag(@x,@y) == PBTerrain::StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end
 
  alias move_right_stairs move_right
  def move_right(turn_enabled = true)
    move_right_stairs(turn_enabled)
    if self.map.terrain_tag(@x,@y) == PBTerrain::StairLeft || self.map.terrain_tag(@x,@y) == PBTerrain::StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end
end

class Game_Player 
  alias move_left_stairs move_left
   def move_left(turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y)
    old_through = self.through
    old_x = @x
    if old_tag == PBTerrain::StairLeft
      if passable?(@x-1, @y+1, 4) && self.map.terrain_tag(@x-1,@y+1) == PBTerrain::StairLeft
        @y += 1
        self.through = true
      end
    elsif old_tag == PBTerrain::StairRight
      if passable?(@x-1, @y-1, 6)
        @y -= 1
        self.through = true
      end
    end
    move_left_stairs(turn_enabled)
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != PBTerrain::StairLeft && new_tag == PBTerrain::StairLeft ||
        old_tag != PBTerrain::StairRight && new_tag == PBTerrain::StairRight
        self.offset_y = -16
        @y += 1 if new_tag == PBTerrain::StairLeft
      elsif old_tag == PBTerrain::StairLeft && new_tag != PBTerrain::StairLeft ||
        old_tag == PBTerrain::StairRight && new_tag != PBTerrain::StairRight
        self.offset_y = 0
      end
    end
    self.through = old_through
  end
 
  alias move_right_stairs move_right
  def move_right(turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y)
    old_through = self.through
    old_x = @x
    if old_tag == PBTerrain::StairLeft && passable?(@x+1, @y-1, 4)
      @y -= 1
      self.through = true
    elsif old_tag == PBTerrain::StairRight && passable?(@x+1, @y+1, 6)&& self.map.terrain_tag(@x+1,@y+1) == PBTerrain::StairRight
      @y += 1
      self.through = true
    end
    move_right_stairs(turn_enabled)
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != PBTerrain::StairLeft && new_tag == PBTerrain::StairLeft ||
        old_tag != PBTerrain::StairRight && new_tag == PBTerrain::StairRight
        self.offset_y = -16
        @y += 1 if new_tag == PBTerrain::StairRight
      elsif old_tag == PBTerrain::StairLeft && new_tag != PBTerrain::StairLeft ||
        old_tag == PBTerrain::StairRight && new_tag != PBTerrain::StairRight
        self.offset_y = 0
      end
    end
    self.through = old_through
  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)
    # 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
    unless $game_map.validLax?(new_x, new_y)
      # Impassable
      return false
    end
    if !$game_map.valid?(new_x, new_y)
      return false if !$MapFactory
      return $MapFactory.isPassableFromEdge?(new_x, new_y)
    end
    # If debug mode is ON and ctrl key was pressed
    if $DEBUG and Input.press?(Input::CTRL)
      # Passable
      return true
    elsif d == 8 && new_y > 0 # prevent player moving up past the top of the stairs
      if $game_map.terrain_tag(new_x, new_y) == PBTerrain::StairLeft &&
        $game_map.terrain_tag(new_x, new_y-1) != PBTerrain::StairLeft
        return false
      elsif $game_map.terrain_tag(new_x, new_y) == PBTerrain::StairRight &&
        $game_map.terrain_tag(new_x, new_y-1) != PBTerrain::StairRight
        return false
      end
    end
    super
  end
end
Version 17
Place this script above Main. This version is no longer being supported. Please upgrade Essentials to v18 to get support.
Ruby:
# ========================================================================
# Boon's Terrain Tag Side Stairs
# v1.0
# By Boonzeet
# ========================================================================
# Sideways stairs with pseudo 'depth' effect. Please credit if used
# ========================================================================

# ========================================================================
# Config
# ========================================================================
# Set these to whatever terrain tags you want to use
module PBTerrain
  StairLeft       = 19
  StairRight      = 20
end


# ========================================================================
# Existing Class Extensions
# ========================================================================
def pbTurnTowardEvent(event,otherEvent)
  sx = 0; sy = 0
  if $MapFactory
    relativePos=$MapFactory.getThisAndOtherEventRelativePos(otherEvent,event)
    sx = relativePos[0]
    sy = relativePos[1]
  else
    sx = event.x - otherEvent.x
    sy = event.y - otherEvent.y
  end
  return if sx == 0 and sy == 0
  if sx.abs >= sy.abs #added
    (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

  def update_move
    distance = 2**@move_speed
    # 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
 
    realResX = Game_Map.realResX
    realResY = Game_Map.realResY
    @real_x = [@real_x-distance,@x*realResX].max if @x*realResX<@real_x
    @real_x = [@real_x+distance,@x*realResX].min if @x*realResX>@real_x
    @real_y = [@real_y+distance,@y*realResY].min if @y*realResY>@real_y
    @real_y = [@real_y-distance,@y*realResY].max if @y*realResY<@real_y
    if !jumping? && !moving?
      Events.onStepTakenFieldMovement.trigger(self,self)
    end
    if @walk_anime
      @anime_count += 1.5
    elsif @step_anime
      @anime_count += 1
    end
  end

end

class Game_Character
   alias move_left_stairs move_left
   def move_left(turn_enabled = true)
    move_left_stairs(turn_enabled)
    if self.map.terrain_tag(@x,@y) == PBTerrain::StairLeft || self.map.terrain_tag(@x,@y) == PBTerrain::StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end

  alias move_right_stairs move_right
  def move_right(turn_enabled = true)
    move_right_stairs(turn_enabled)
    if self.map.terrain_tag(@x,@y) == PBTerrain::StairLeft || self.map.terrain_tag(@x,@y) == PBTerrain::StairRight
      @offset_y = -16
    else
      @offset_y = 0
    end
  end
end

class Game_Player
  alias move_left_stairs move_left
   def move_left(turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y)
    old_through = self.through
    old_x = @x
    if old_tag == PBTerrain::StairLeft
      if passable?(@x-1, @y+1, 4) && self.map.terrain_tag(@x-1,@y+1) == PBTerrain::StairLeft
        @y += 1
        self.through = true
      end
    elsif old_tag == PBTerrain::StairRight
      if passable?(@x-1, @y-1, 6)
        @y -= 1
        self.through = true
      end
    end
    move_left_stairs(turn_enabled)
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != PBTerrain::StairLeft && new_tag == PBTerrain::StairLeft ||
        old_tag != PBTerrain::StairRight && new_tag == PBTerrain::StairRight
        self.offset_y = -16
        @y += 1 if new_tag == PBTerrain::StairLeft
      elsif old_tag == PBTerrain::StairLeft && new_tag != PBTerrain::StairLeft ||
        old_tag == PBTerrain::StairRight && new_tag != PBTerrain::StairRight
        self.offset_y = 0
      end
    end
    self.through = old_through
  end

  alias move_right_stairs move_right
  def move_right(turn_enabled = true)
    old_tag = self.map.terrain_tag(@x, @y)
    old_through = self.through
    old_x = @x
    if old_tag == PBTerrain::StairLeft && passable?(@x+1, @y-1, 4)
      @y -= 1
      self.through = true
    elsif old_tag == PBTerrain::StairRight && passable?(@x+1, @y+1, 6)&& self.map.terrain_tag(@x+1,@y+1) == PBTerrain::StairRight
      @y += 1
      self.through = true
    end
    move_right_stairs(turn_enabled)
    new_tag = self.map.terrain_tag(@x, @y)
    if old_x != @x
      if old_tag != PBTerrain::StairLeft && new_tag == PBTerrain::StairLeft ||
        old_tag != PBTerrain::StairRight && new_tag == PBTerrain::StairRight
        self.offset_y = -16
        @y += 1 if new_tag == PBTerrain::StairRight
      elsif old_tag == PBTerrain::StairLeft && new_tag != PBTerrain::StairLeft ||
        old_tag == PBTerrain::StairRight && new_tag != PBTerrain::StairRight
        self.offset_y = 0
      end
    end
    self.through = old_through
  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)
    # 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
    unless $game_map.validLax?(new_x, new_y)
      # Impassable
      return false
    end
    if !$game_map.valid?(new_x, new_y)
      return false if !$MapFactory
      return $MapFactory.isPassableFromEdge?(new_x, new_y)
    end
    # If debug mode is ON and ctrl key was pressed
    if $DEBUG and Input.press?(Input::CTRL)
      # Passable
      return true
    elsif d == 8 && new_y > 0 # prevent player moving up past the top of the stairs
      if $game_map.terrain_tag(new_x, new_y) == PBTerrain::StairLeft &&
        $game_map.terrain_tag(new_x, new_y-1) != PBTerrain::StairLeft
        return false
      elsif $game_map.terrain_tag(new_x, new_y) == PBTerrain::StairRight &&
        $game_map.terrain_tag(new_x, new_y-1) != PBTerrain::StairRight
        return false
      end
    end
    super
  end
end

If you'd like to support followers, change this code inside the Followers script:
Underneath these lines
Ruby:
for i in 0...facings.length
        facing=facings[i]
        tile=$MapFactory.getFacingTile(facing,leader)
Add this block of code:
Ruby:
if tile[1] > $game_player.x
          tile[2] -= 1 if $MapFactory.getTerrainTag(tile[0],tile[1],tile[2]-1) == PBTerrain::StairLeft && $game_map.terrain_tag($game_player.x,$game_player.y) == PBTerrain::StairLeft
        elsif tile[1] < $game_player.x
          tile[2] += 1 if $MapFactory.getTerrainTag(tile[0],tile[1],tile[2]+1) == PBTerrain::StairLeft
        end
        if tile[1] > $game_player.x
          tile[2] += 1 if $MapFactory.getTerrainTag(tile[0],tile[1],tile[2]+1) == PBTerrain::StairRight
        elsif tile[1] < $game_player.x
          tile[2] -= 1 if $MapFactory.getTerrainTag(tile[0],tile[1],tile[2]-1) == PBTerrain::StairRight && $game_map.terrain_tag($game_player.x,$game_player.y) == PBTerrain::StairRight
        end

Then VERY IMPORTANT: set up your stair tiles with the appropriate terrain tags and this exact passability:
Stair setup.png


And it should be good to go! All the movement is handled automatically from here on.
Credits
Boonzeet
Author
boonzeet
First release
Last update
Rating
5.00 star(s) 1 ratings

More resources from boonzeet

Latest updates

  1. v1.1: Updated for v18 support

    It's been updated with v18 and PluginManager support. Enjoy!

Latest reviews

Excellent use of terrain tags, and very simple create-once-and-don't-touch-again set up.
Top