FPLE : First Person Labyrinth Explorer
#61
Amazing script!!! ^_ ^ Can be used in commercial projects?
Reply
#62
Hello.
Can I change wall's height by editing in script, or it was modified in DLL ?
Is there any solution to make autotile working ?
Reply
#63
it's all in DLL in the render. There's no height to adjust, sorry. To be honest I feel this script is flawed due to not even being able to have events be taller than wall height. However, with that being said, if you check the H-Mode 7 script here in the forum, someon is doing some interesting frst person stuff with it.

Alternatively, the FPLE 2, while not allowing Events to be interacted with normally offers a lot of options for wall height that might be up your alley.
[Image: AVvXsEga1vIr5Rx3FkoFbGo1OoMJAqgq6TeqcbpF...L3AWg=s752]

BLOG: JayVinci.blogspot.com
FORUM COMING SOON
Currently working on:
Ambitions: RPG Developer Bakin
Heart of Vox: RPG Developer Bakin
Reply
#64
Hello. Concerning this script, I know it's not possible to edit wall height (although it's possible to change wall distance). However, is there a way to change or adjust the camera height or viewport, so that the perspective is closer to the ground, or even higher that it? This could be used so that, while not changing wall height, it would seem walls were higher (even if it meant the player was lower), or even to simulate going up stairs (assuming it would be possible to have the engine render the ceiling tiles as if they were at ground level, due to a higher viewport).
Thanks in advance.
Reply
#65
Yeah. Most anything that renders the labyrinth (wall heights, etc) is controlled solely by a DLL supplied within the demo itself. So... that cannot be changed. However, I did come up with a cheat you may like. You can find it (>HERE<). I cranked out this 'Camera Height' add-on just today.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)

[Image: QrnbKlx.jpg]
[Image: sGz1ErF.png]    [Image: liM4ikn.png]    [Image: fdzKgZA.png]    [Image: sj0H81z.png]
[Image: QL7oRau.png]    [Image: uSqjY09.png]    [Image: GAA3qE9.png]    [Image: 2Hmnx1G.png]    [Image: BwtNdKw.png%5B]
  Above are clickable links
Reply
#66
ALSO!!! Just to let you know, Even though wall heights are set to a certain height, I NOW know you can use something like SephirothSpawn's Event Spawner to spawn events that are wall pieces at certain areas, so basically, if you have an event that mimics a LOWER wall, and want another event to jump to that same position, you can Sephiroth spawn an opposing wall, to build lower than wall height "fake" corners that can mimic multi height, as long as that fake wall appears as something convex form your "eye..."

With the right work, and careful understanding of events X & Y from the PLAYER X & Y, you can FAKE most things like shapes and angles. It takes a lot of work but you can render pictures and fog layers in 3d programs or something, and then apply them to your map. Event A is left of player by 1? angle him out a little bit, by 2? angle him out a bit more. Need a Dominant OVER THE WALL sized piece? Create it in some other image program and make it your own non-moving panorama.

So, say Character is at 5,2, and you know he should have a nice shot of the big castlepiece, and it will be slightly off center and take up THIS amount of space. Well you can create a panorama that acts as a skybox for your map that shows that piece as being larger than life in the center of the room.

This too will take a lot of work, but if you really want jaw-dropping visuals for your map, it's worth the gring. Remember FOGS and PANORAMAS are by essence going to move and scroll with your character movement, so if you don't want THAT to happen, you might find the node in the script that pans fogs and panoramas and click that off. Then, maybe even get rid of the movement factor so it's less like a Wolfenstein, and more like an Eye of the Beholder style of transition to the other position.

Basically, if you don't mind drawing, (or in my case rendering) all the positions on your map to give that immersive experience, you can have a rich world that's full of adventure.

(BTW, the fogs and PANORAMAS don't even have to be memory hogs, Panoramas can be JPGS, and FOG can be PNG but set to like 64 colors and a transparency layer, and they still look fine, matching up nicely with the already gritty nature of the FPLE.)
[Image: AVvXsEga1vIr5Rx3FkoFbGo1OoMJAqgq6TeqcbpF...L3AWg=s752]

BLOG: JayVinci.blogspot.com
FORUM COMING SOON
Currently working on:
Ambitions: RPG Developer Bakin
Heart of Vox: RPG Developer Bakin
Reply
#67
OPEN SOURCE CODE
FOR THE DLL NOW AVAILABLE

This isn't a conventional bump as no changes have been made to the system, either in the RGSS code nor the DLL. And just as he did for the HMode7 system, finalholylight contacted MGC who had uploaded the dll source code for the system. So like HMode7, the dll's source code is now available in this thread's first post and is now open source.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)

[Image: QrnbKlx.jpg]
[Image: sGz1ErF.png]    [Image: liM4ikn.png]    [Image: fdzKgZA.png]    [Image: sj0H81z.png]
[Image: QL7oRau.png]    [Image: uSqjY09.png]    [Image: GAA3qE9.png]    [Image: 2Hmnx1G.png]    [Image: BwtNdKw.png%5B]
  Above are clickable links
Reply
#68
I upgraded FPLE, Integrated a 4-Side & 6-Side box comment, which can create buildings/grass boxes/objects.
6 Side had type2+d1 & type1+d1)) but changed it to a type 0 to save FPS, you can add it back if you want.

For below/Above, type 0 objects you want to walk over add, 1-Side, to them.
I added code the following code so these player facing objects without 1-Side push forward, for NPCs.
if dy == 0 && dx == 0 && surface.character.fple_type == 0 && surface.character.fple_one_side == false.

(Fit,Type1,D1,1Side,V2) objects have a side profile added to them, but should always be, same not below/above.
you can jump over these with a moveset thuf-on/step forward step forward thur-off, they are a type of ledge.

You may have to code in your own.  (Fit,Type2,D1,1Side,V2), I'm not currently tested to check its same function.

I'm still working a fix for rotation letting you see events thur walls briefly, here is the 1st rough draft of the script.
I would have posted a few days sooner, but was having issues with strafing crashing the game for some reason.

The resolution is also no longer Default, it's 608x417, you can place it back with the original script, or pick Res 2.

Code:
#===============================================================================
# First Person Labyrinth Explorer (FPLE) Engine - VX Ace version
# v.1.5
# Author: MGC
#===============================================================================
# This script allows the map to be displayed in first-person view,
# while maintaining tile-by-tile movement, similar to the
# Etrian Odyssey series (Nintendo DS/3DS). # THIS IS NOT A SCRIPT FOR MAKING AN FPS, BUT AN FPRPG.
#
# This is a port of version 1.5 of the FPLE for RPG Maker XP, with
# a few small additions.
#
# Features:
# - Can only be enabled on certain maps in the project
# - Forward/backward movement, left/right movement
# and 90° rotation
# - Ability to lower quality while moving to reduce lag
# - Translucency and blend type support
# for events
#
# Limitations:
# - Not really suitable for moving events from one tile to another.
# This should work, but use sparingly. # - Animations are displayed above everything
# - The player cannot jump or move diagonally
# - The resolution must be the default, i.e., 544px x 416px
# - No transparency for walls
# - No different heights: a single level for the floor and ceiling
#
# Instructions:
# This script must be placed below the original scripts but above "Main"
# It requires the MGC_FPLE_Ace_1_1.dll file
#
# - Map Creation
# Maps must be exported into the project from the dedicated editor,
# present in the Marta project starting with version 1.0.0
#
# - Events
# Events with a graphical representation are displayed
# vertically (like walls), centered, and always facing the
# player. The "Comment..." command allows you to control this display:
# "Type 0": Always faces the player (default)
# "Type 1": Horizontally oriented in the RM editor view (top view)
# "Type 2": Vertically oriented in the RM editor view (top view)
# "Stretch": The image is stretched to the dimensions of a wall (square)
# "Fit": The image is stretched to fit within the dimensions of a wall, the
# aspect ratio is maintained. Automatically applied if
# the dimensions exceed those of a wall (new in VX Ace)
# "Zoom X.X": zoom the image (new in VX Ace), for example, to double
# the dimensions, write: "Zoom 2.0"
# "V-Align 0": vertical alignment at the top (at ceiling level)
# "V-Align 1": vertical alignment in the center (default)
# "V-Align 2": vertical alignment at the bottom (at floor level)
# "D-Align 0": depth alignment in front/left, for types 1 and 2
# "D-Align 1": depth alignment in the center, for types 1 and 2 (default)
# "D-Align 2": depth alignment in the back/right, for types 1 and 2
# "1-Side": texture applied to one side only => appears mirrored behind
# "2-Side": texture applied to two side only => appears mirrored behind #Extra Unused Call To Code#
# "4-Side": texture applied to four sides to create the illusion of box
# "6-Side":  texture applied to four sides to create the illusion of grass.
# - Technical Parameters
# In the CONFIGURATION section at the beginning of the script, you will find the
# following constants whose values ​​can be modified:
# - VIEW_DISTANCE: "Surfaces" (textured square polygons of fixed
# dimensions representing tiles and events) are only
# displayed within a certain distance around
# the player. This constant represents this distance,
# expressed in tiles (default value: 6). The higher
# this value, the greater the risk of lag.
# - RESOLUTION: Drawing the entire screen every frame requires
# a lot of resources. During movement, it is
# possible to use a lower screen resolution and the
# Render will then be zoomed to fit 544px x 416px.
# 0: Maximum resolution (544px*416px) Changed to (840px*560px)
# 1: Medium resolution (408px*312px)  Changed to (608px*417px)
# 2: Low resolution (272px*208px) Changed to (544px*417px)
# 3: Minimum resolution (204px*156px) Changed to (408px*278px)
# 4: Test resolution (204px*156px) Changed to (332px*222px)
# - ALWAYS_SAME_RES: If true, the same resolution will be used when stationary
# as when moving (see RESOLUTION)
# If false, the maximum resolution will be used when stationary
# (default value)
# - LIGHT_DISTANCE: To prevent surfaces from suddenly appearing on the screen,
# this constant represents the distance in tiles beyond
# which the opacity of the surfaces will be zero.
# The opacity change is gradual. If there is
# no parallax, the screen background is black and the
# surfaces will become increasingly darker with distance.
# A value of 0 disables this feature.
#
# - Commands that can be used in scripts (possible via the "Script..."
# command of an event):
# - $game_temp.set_view(new_view_distance)
# - $game_temp.set_light(new_light_distance)
# - $game_temp.increase_light
# - $game_temp.decrease_light
#============================================================================
module FPLE
  #--------------------------------------------------------------------------
  # * CONFIGURATION
  #--------------------------------------------------------------------------
  VIEW_DISTANCE = 22 # in tiles, > 0
  LIGHT_DISTANCE = 11 # in tiles, >=0, 0=deactivated
  RESOLUTION = 1 # quality when moving, 0=max, 1=medium, 2=low, 3=ugly
  ALWAYS_SAME_RES = true # if true, quality at stand = quality when moving
                          # if false, quality at stand = quality max
  SKIP_DISTANT_CHARS = true  # Skip character updates beyond view distance
  BATCH_SURFACE_UPDATES = false  # Update surfaces in batches
  AGGRESSIVE_CULLING = true     # More aggressive visibility culling
end
#==============================================================================
# ** FPLE Core
#==============================================================================
module FPLE
  #--------------------------------------------------------------------------
  # * Constantes
  #--------------------------------------------------------------------------
  MAP_SIDES = [4, 3, 5, 2]
  MAP_SIDES_LEFT = [5, 4, 2, 3]
  MAP_SIDES_RIGHT = [3, 2, 4, 5]
  PLAYER_MOVE_FORWARD = [[0, 1], [-1, 0], [1, 0], [0, -1]]
  PLAYER_MOVE_SPEED = [0, 1, 2, 4, 6, 8, 12]
  TURN_LEFT = [6, 2, 8, 4]
  COS_TABLE = [4096, 4095, 4094, 4090, 4086,
  4080, 4074, 4065, 4056, 4046, 4034, 4021, 4006, 3991, 3974,
  3956, 3937, 3917, 3896, 3873, 3849, 3824, 3798, 3770, 3742,
  3712, 3681, 3650, 3617, 3582, 3547, 3511, 3474, 3435, 3396,
  3355, 3314, 3271, 3228, 3183, 3138, 3091, 3044, 2996, 2946,
  2896, 2845, 2793, 2741, 2687, 2633, 2578, 2522, 2465, 2408,
  2349, 2290, 2231, 2171, 2110, 2048, 1986, 1923, 1860, 1796,
  1731, 1666, 1600, 1534, 1468, 1401, 1334, 1266, 1198, 1129,
  1060, 991, 921, 852, 782, 711, 641, 570, 499, 428,
  357, 286, 214, 143, 71, 0]
  RENDER = Win32API.new("MGC_FPLE_Ace_1_2", "RenderFPLE", "lll", "l") # [1.5]
  RENDER_ROT = Win32API.new("MGC_FPLE_Ace_1_2", "RenderFPLErot", "lll", "l") # [1.5]
  #--------------------------------------------------------------------------
  # * Retourne l'angle d'orientation
  # return Integer
  #--------------------------------------------------------------------------
  def self.angle
    return @angle
  end
  #--------------------------------------------------------------------------
  # * Retourne le décalage horizontal
  # return Integer
  #--------------------------------------------------------------------------
  def self.offset_x
    return @offset_x
  end
  #--------------------------------------------------------------------------
  # * Retourne le décalage en profondeur
  # return Integer
  #--------------------------------------------------------------------------
  def self.offset_y
    return @offset_y
  end
  #--------------------------------------------------------------------------
  # * Initialisation
  # param spriteset : FPLE::Spriteset_Map
  # param viewport : Viewport
  #--------------------------------------------------------------------------
  def self.initialize_fple(spriteset, viewport)
    @spriteset = spriteset
    @sprite_screen = Sprite.new(viewport)
    @sprite_move = Sprite.new(viewport)
    self.initialize_bitmaps
    @offset_x = 0
    @offset_y = 0
    @sprite_move.visible = false
    @lux_distance = $game_system.fple_light_distance << 5
    @angle = 0
    @trig = 0
    self.refresh_trig
    @count = 0
    $game_temp.force_render = true
    self.update
  end
  #--------------------------------------------------------------------------
  # * Création des objets Bitmap devant contenir le rendu 3D
  #--------------------------------------------------------------------------
  def self.initialize_bitmaps
    case $game_system.fple_resolution
    when 0
      width = 840
      height = 560
      coefficient_resolution = 0.75
    when 1
      width = 608
      height = 417
      coefficient_resolution = 1
    when 2
      width = 544
      height = 417
      coefficient_resolution = 1.133
    when 3
      width = 408
      height = 278
      coefficient_resolution = 1.5
    when 4
      width = 332
      height = 222
      coefficient_resolution = 2
    end
    if $game_system.fple_always_same_res
      @sprite_screen.bitmap = Bitmap.new(width, height)
      @sprite_screen.zoom_x = coefficient_resolution
      @sprite_screen.zoom_y = coefficient_resolution
    else
      @sprite_screen.bitmap = Bitmap.new(608, 417)
    end
    @sprite_move.bitmap = Bitmap.new(width, height)
    @sprite_move.zoom_x = coefficient_resolution
    @sprite_move.zoom_y = coefficient_resolution
  end
  #--------------------------------------------------------------------------
  # * Cherche les valeurs de sinus et cosinus en focntion de l'angle
  #--------------------------------------------------------------------------
  def self.refresh_trig
    @cos = FPLE::COS_TABLE[@angle]
    @sin = FPLE::COS_TABLE[91 - @angle]
  end
  #--------------------------------------------------------------------------
  # * Dispose
  #--------------------------------------------------------------------------
  def self.dispose
    @sprite_screen.dispose
    @sprite_move.dispose
  end
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
def self.update
  # Run garbage collection periodically during non-movement to reduce memory spikes.
  if !$game_temp.movement && Graphics.frame_count % 120 == 0
    GC.start
  end
 
  # Check if the player is actively moving or changing the view.
  if $game_temp.movement
    case $game_temp.movement_dir
    when 0 # fading distance + 1
      self.increase_fading_distance
    when 1 # fading distance - 1
      self.decrease_fading_distance
    when 3 # set fading distance
      self.set_fading_distance
    when 2 # Move backward
      self.move_backward
    when 4 # Strafe left
      self.strafe_left
    when 6 # Strafe right
      self.strafe_right
    when 8 # Move forward
      self.move_forward
    when 9 # Turn right
      self.turn_right
    when 10 # turn left
      self.turn_left
    end
   
    # If the player is still moving, use the lower-resolution sprite.
    if $game_temp.movement
      @sprite_screen.visible = false
      @sprite_move.visible = true
      @sprite_move.bitmap.clear
      if @angle == 0
        FPLE::RENDER.call(
        @sprite_move.bitmap.__id__,
        $game_map.surfaces.__id__,
        [@offset_y, @offset_x, @lux_distance, $game_player.direction,
        $game_map.fple_map.texturesets].__id__)
      else
        FPLE::RENDER_ROT.call(
        @sprite_move.bitmap.__id__,
        $game_map.surfaces.__id__,
        [@offset_y, @offset_x, @lux_distance, $game_player.direction,
        @trig, @cos, @sin, $game_map.fple_map.texturesets].__id__)
      end
    else
      # If movement just finished, render the final high-res frame.
      @sprite_screen.visible = true
      @sprite_move.visible = false
      @sprite_screen.bitmap.clear
      FPLE::RENDER.call(
      @sprite_screen.bitmap.__id__,
      $game_map.surfaces.__id__,
      [@offset_y, @offset_x, @lux_distance, $game_player.direction,#@lux_distance#
      $game_map.fple_map.texturesets].__id__)
      if $game_temp.last_moving
        $game_player.update_nonmoving($game_temp.last_moving)
      end
    end
    # The redundant if block was removed.
  # This block handles rendering when the player is not moving, but other
  # events or conditions (like character surfaces) need updating.
  elsif $game_player.moving? || $game_temp.force_render
    # Process updates for characters and events.
    $game_map.refresh_surfaces
   
    # === START OF BATCH AND CULLING FIX ===
    # Updates characters in batches to avoid lag spikes, with optional distance skipping.
    if FPLE::BATCH_SURFACE_UPDATES
      $game_map.events.values.each_with_index do |event, i|
        # Only update a fraction of the events each frame.
        if @count % 5 == i % 5
          if FPLE::SKIP_DISTANT_CHARS
            dist_x = ($game_player.real_x / 32) - (event.x)
            dist_y = ($game_player.real_y / 32) - (event.y)
            distance = Math.sqrt(dist_x**2 + dist_y**2)
            next if distance > FPLE::VIEW_DISTANCE
          end
          event.update_fple_surface unless FPLE::SKIP_DISTANT_CHARS == false
        end
      end
    else
      # Fallback for no batching.
      $game_map.events.each_value do |event|
        if FPLE::SKIP_DISTANT_CHARS
          dist_x = ($game_player.real_x / 32) - (event.x)
          dist_y = ($game_player.real_y / 32) - (event.y)
          distance = Math.sqrt(dist_x**2 + dist_y**2)
          next if distance > FPLE::VIEW_DISTANCE
        end
        event.update_fple_surface unless FPLE::SKIP_DISTANT_CHARS == false
      end
    end
    # === END OF BATCH AND CULLING FIX ===
   
    $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
    @sprite_screen.bitmap.clear
    FPLE::RENDER.call(
    @sprite_screen.bitmap.__id__,
    $game_map.surfaces.__id__,
    [@offset_y, @offset_x, @lux_distance, $game_player.direction,
    $game_map.fple_map.texturesets].__id__)
    $game_temp.force_render = false
    @count += 1
  end
end
  #--------------------------------------------------------------------------
  # * Frame Update - Augmentation de la distance d'éclairage
  #--------------------------------------------------------------------------
  def self.increase_fading_distance
    @count += 2
    @lux_distance += 2
    if @count == 32
      @count = 0
      $game_temp.movement = false
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Diminution de la distance d'éclairage
  #--------------------------------------------------------------------------
  def self.decrease_fading_distance
    if @lux_distance == 0
      @count = 0
      $game_temp.movement = false
    else
      @count += 2
      @lux_distance -= 2
      if @count == 32
        @count = 0
        $game_temp.movement = false
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Définition d'une nouvelle distance d'éclairage
  #--------------------------------------------------------------------------
  def self.set_fading_distance
    @lux_distance = $game_system.fple_light_distance << 5
    $game_temp.movement = false
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Déplacement en arrière
  #--------------------------------------------------------------------------
  def self.move_backward
    unless $game_temp.movement_init
      $game_map.refresh_surfaces
      $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
      $game_temp.movement_init = true
      @offset_y = 128
    end
    @offset_y -= $game_player.move_speed_fple
    if @offset_y <= 0
      @offset_y = 0
      $game_temp.movement = false
      $game_temp.last_moving = true
      $game_map.refresh_surfaces
      $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Déplacement latéral vers la gauche
  #--------------------------------------------------------------------------
  def self.strafe_left
    unless $game_temp.movement_init
      $game_map.refresh_surfaces
      $game_map.refresh_surfaces_strafe(0)
      $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
      $game_temp.movement_init = true
      @offset_x = 128
    end
    @offset_x -= $game_player.move_speed_fple
    if @offset_x <= 0
      @offset_x = 0
      $game_temp.movement = false
      $game_temp.last_moving = true
      $game_map.refresh_surfaces
      $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Déplacement latéral vers la droite
  #--------------------------------------------------------------------------
  def self.strafe_right
    unless $game_temp.movement_init
      $game_map.refresh_surfaces_strafe(-1)
      $game_temp.movement_init = true
    end
    @offset_x += $game_player.move_speed_fple
    if @offset_x >= 128
      @offset_x = 0
      $game_temp.movement = false
      $game_temp.last_moving = true
      $game_map.refresh_surfaces
      $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Déplacement en avant
  #--------------------------------------------------------------------------
  def self.move_forward
    @offset_y += $game_player.move_speed_fple
    if @offset_y >= 128
      @offset_y = 0
      $game_temp.movement = false
      $game_temp.last_moving = true
      $game_map.refresh_surfaces
      $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Rotation vers la droite
  #--------------------------------------------------------------------------
  def self.turn_right
    unless $game_temp.movement_init
      $game_map.refresh_surfaces_turn_right(@spriteset.character_surfaces)
      $game_temp.movement_init = true
    end
    @angle += 5
    @trig = 1
    refresh_trig
    if @angle == 90
      @angle = 0
      $game_temp.movement = false
      $game_map.refresh_surfaces
      $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
    end
  end
  #--------------------------------------------------------------------------
  # * Frame Update - Rotation vers la gauche
  #--------------------------------------------------------------------------
  def self.turn_left
    unless $game_temp.movement_init
      $game_map.refresh_surfaces_turn_left(@spriteset.character_surfaces)
      $game_temp.movement_init = true
      @angle = 90
    end
    @angle -= 5
    @trig = 0
    refresh_trig
    if @angle == 0
      $game_temp.movement = false
      $game_map.refresh_surfaces
      $game_map.refresh_character_surfaces(@spriteset.character_surfaces)
    end
  end
end
#==============================================================================
# ** DataManager
#==============================================================================
module DataManager
  #--------------------------------------------------------------------------
  # * Aliased methods (F12 compatibility)
  #--------------------------------------------------------------------------
  class << self
    unless @already_aliased_fple
      alias save_game_without_rescue_fple save_game_without_rescue
      @already_aliased_fple = true
    end
  end
  #--------------------------------------------------------------------------
  # * Execute Save (No Exception Processing)
  #--------------------------------------------------------------------------
  def self.save_game_without_rescue(index)
    if $game_map.fple_map # [1.2]
      textureset = $game_map.fple_map.textureset
      texturesets = $game_map.fple_map.texturesets
      $game_map.fple_map.textureset = nil
      $game_map.fple_map.texturesets = nil
    end
    rc = save_game_without_rescue_fple(index)
    if $game_map.fple_map # [1.2]
      $game_map.fple_map.texturesets = texturesets
      $game_map.fple_map.textureset = textureset
    end
    return rc
  end
end
#============================================================================
# ** Game_System
#============================================================================
class Game_System
  #--------------------------------------------------------------------------
  # * Aliased methods (F12 compatibility)
  #--------------------------------------------------------------------------
  unless @already_aliased_fple
    alias initialize_fple initialize
    @already_aliased_fple = true
  end
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :fple # Boolean
  attr_accessor :fple_view_distance # Integer (>0)
  attr_accessor :fple_light_distance # Integer (>=0, 0:deactivated)
  attr_accessor :fple_resolution # Integer (0:max, 1:medium, 2:low, 3:ugly)
  attr_accessor :fple_always_same_res # Boolean
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    initialize_fple
    self.fple = false
    self.fple_view_distance = FPLE::VIEW_DISTANCE
    self.fple_light_distance = FPLE::LIGHT_DISTANCE
    self.fple_resolution = FPLE::RESOLUTION
    self.fple_always_same_res = FPLE::ALWAYS_SAME_RES
  end
end
#==============================================================================
# ** Game_Temp
#==============================================================================
class Game_Temp
  #--------------------------------------------------------------------------
  # * Aliased methods (F12 compatibility)
  #--------------------------------------------------------------------------
  unless @already_aliased_fple
    alias initialize_fple initialize
    @already_aliased_fple = true
  end
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :movement_init # Boolean
  attr_accessor :movement # Boolean
  attr_accessor :movement_dir # Integer {2, 4, 6, 8}
  attr_accessor :last_moving # Boolean
  attr_accessor :force_render # Boolean
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    initialize_fple
    self.movement_init = false
    self.movement = false
    self.movement_dir = 8
    self.last_moving = false
    self.force_render = false
  end
  #--------------------------------------------------------------------------
  # * Set view distance
  # param distance : Integer
  #--------------------------------------------------------------------------
  def set_view(distance)
    if distance < 0 then distance = 0 end
    $game_system.fple_view_distance = distance
    self.force_render = true
  end
  #--------------------------------------------------------------------------
  # * Set light distance
  # param distance : Integer
  #--------------------------------------------------------------------------
  def set_light(distance)
    if distance < 0 then distance = 0 end
    $game_system.fple_light_distance = distance
    self.movement = true
    self.movement_dir = 3
  end
  #--------------------------------------------------------------------------
  # * Increase light distance
  #--------------------------------------------------------------------------
  def increase_light
    $game_system.fple_light_distance += 1
    self.movement = true
    self.movement_dir = 0
  end
  #--------------------------------------------------------------------------
  # * Decrease light distance
  #--------------------------------------------------------------------------
  def decrease_light
    if $game_system.fple_light_distance > 0
      $game_system.fple_light_distance -= 1
    end
    self.movement = true
    self.movement_dir = 1
  end
end
#============================================================================
# ** Game_Map
#============================================================================
class Game_Map
  #--------------------------------------------------------------------------
  # * Aliased methods (F12 compatibility)
  #--------------------------------------------------------------------------
  unless @already_aliased_fple
    alias initialize_fple initialize
    alias setup_fple setup
    alias refresh_fple refresh
    @already_aliased_fple = true
  end
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_accessor :surfaces # Array<Array<Integer>>
  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  def initialize
    initialize_fple
    self.surfaces = []
    @x_ref = 0
    @y_ref = 0
  end
  #--------------------------------------------------------------------------
  # * Setup
  # param map_id : Integer
  #--------------------------------------------------------------------------
  def setup(map_id)
    @map_id = map_id
    @map = load_data(sprintf("Data/Map%03d.rvdata2", @map_id))
    if is_fple?
      load_fple_map
      $game_system.fple = true
    elsif $game_system.fple
      $game_system.fple = false
    end
    setup_fple(map_id)
  end
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    refresh_fple
    if is_fple?
      unless @fple_map.textureset
        load_fple_map
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Vérifie s'il s'agit d'une carte FPLE
  # return String
  #--------------------------------------------------------------------------
  def is_fple?
    return @map.note[/\[fple:\w+\]/]
  end
  #--------------------------------------------------------------------------
  # * Charge la carte FPLE associée
  #--------------------------------------------------------------------------
  def load_fple_map
    if @fple_map then @fple_map.dispose end
    @map.note[/\[fple:(\w+)\]/]
    File.open('Data_FPLE/' + $1 + '.fple', "rb") {|file|
      map_data = Marshal.load(file)
      @fple_map = FPLE::Map.new(map_data.width, map_data.height,
      map_data.map_name, map_data.tileset_name, map_data.data,
      map_data.subsets_mapping, map_data.textureset_data)
    }
  end
  #--------------------------------------------------------------------------
  # * Retourne la carte FPLE associée
  # return FPLE::Map
  #--------------------------------------------------------------------------
  def fple_map
    @fple_map
  end
  #--------------------------------------------------------------------------
  # * Retourne le nom du tileset
  # return String
  #--------------------------------------------------------------------------
  def tileset_name
    if $game_system.fple
      return @fple_map.tileset_name
    else
      return ""
    end
  end
  end
     def add_character_surfaces_down_with_rotation_fix(character_surfaces)
    surfaces_temp = []
    i = $game_system.fple_view_distance
    character_surfaces.each do |surface|
      next if surface.displayed # Skip if already processed
      dy = surface.dy - ($game_player.y << 7)
      dx = ($game_player.x << 7) - surface.dx
      add_character_surfaces(surface, dy, dx, surfaces_temp, i, 2)
    end
    return surfaces_temp
  end
  def add_character_surfaces_up_with_rotation_fix(character_surfaces)
    surfaces_temp = []
    i = $game_system.fple_view_distance
    character_surfaces.each do |surface|
      next if surface.displayed # Skip if already processed
      dy = ($game_player.y << 7) - surface.dy
      dx = surface.dx - ($game_player.x << 7)
      add_character_surfaces(surface, dy, dx, surfaces_temp, i, 8)
    end
    return surfaces_temp
  end
  def add_character_surfaces_left_with_rotation_fix(character_surfaces)
    surfaces_temp = []
    i = $game_system.fple_view_distance
    character_surfaces.each do |surface|
      next if surface.displayed # Skip if already processed
      dy = ($game_player.x << 7) - surface.dx
      dx = ($game_player.y << 7) - surface.dy
      add_character_surfaces(surface, dy, dx, surfaces_temp, i, 4)
    end
    return surfaces_temp
  end
  def add_character_surfaces_right_with_rotation_fix(character_surfaces)
    surfaces_temp = []
    i = $game_system.fple_view_distance
    character_surfaces.each do |surface|
      next if surface.displayed # Skip if already processed
      dy = surface.dx - ($game_player.x << 7)
      dx = surface.dy - ($game_player.y << 7)
      add_character_surfaces(surface, dy, dx, surfaces_temp, i, 6)
    end
    return surfaces_temp
  end
  #--------------------------------------------------------------------------
  # * Add surfaces for single-sided events only during rotation
  #--------------------------------------------------------------------------
  def add_character_surfaces_down_single_only(character_surfaces)
    surfaces_temp = []
    i = $game_system.fple_view_distance
    character_surfaces.each do |surface|
      next if surface.displayed # Skip if already processed
      # Only process single-sided events
      #next if surface.character.fple_four_side || surface.character.fple_six_side || surface.character.fple_two_side
      dy = surface.dy - ($game_player.y << 7)
      dx = ($game_player.x << 7) - surface.dx
      add_character_surfaces(surface, dy, dx, surfaces_temp, i, 2)
    end
    return surfaces_temp
  end
  def add_character_surfaces_up_single_only(character_surfaces)
    surfaces_temp = []
    i = $game_system.fple_view_distance
    character_surfaces.each do |surface|
      next if surface.displayed # Skip if already processed
      # Only process single-sided events
      #next if surface.character.fple_four_side || surface.character.fple_six_side || surface.character.fple_two_side
      dy = ($game_player.y << 7) - surface.dy
      dx = surface.dx - ($game_player.x << 7)
      add_character_surfaces(surface, dy, dx, surfaces_temp, i, 8)
    end
    return surfaces_temp
  end
def add_character_surfaces_left_single_only(character_surfaces)
    surfaces_temp = []
    i = $game_system.fple_view_distance
    character_surfaces.each do |surface|
      next if surface.displayed # Skip if already processed
      # Only process single-sided events
      #next if surface.character.fple_four_side || surface.character.fple_six_side || surface.character.fple_two_side
      dy = ($game_player.x << 7) - surface.dx
      dx = ($game_player.y << 7) - surface.dy
      add_character_surfaces(surface, dy, dx, surfaces_temp, i, 4)
    end
    return surfaces_temp
  end
  def add_character_surfaces_right_single_only(character_surfaces)
    surfaces_temp = []
    i = $game_system.fple_view_distance
    character_surfaces.each do |surface|
      next if surface.displayed # Skip if already processed
      # Only process single-sided events
      #next if surface.character.fple_four_side || surface.character.fple_six_side || surface.character.fple_two_side
      dy = surface.dx - ($game_player.x << 7)
      dx = surface.dy - ($game_player.y << 7)
      add_character_surfaces(surface, dy, dx, surfaces_temp, i, 6)
    end
    return surfaces_temp
  end
 
      def add_two_sided_surfaces(surface, dy, dx, surfaces_temp, i, dir)
    # Handle special case where player is at same position as box
        j = i << 7
    if dy.between?(128, j) && dx.between?(-j, j)
    event_id = surface.character.id rescue 0
    base_z_offset = (event_id % 1000) * 0.0001
    distance = Math.sqrt(dy * dy + dx * dx)
   
    # Determine visible faces based on position
      faces_to_render = []
   
    # Front face (player looking at object)
    if dy > 32
      faces_to_render << {type: 1, d_align: 0, z_priority: 5, name: :front}
    end
   
    # Back face
    if dy < -32
      faces_to_render << {type: 1, d_align: 2, z_priority: 0, name: :back}
    end
   
    # Left face - FIXED: Use proper alignment values
    if dx < -32
      faces_to_render << {type: 2, d_align: 0, z_priority: 4, name: :left}
    end
   
    # Right face - FIXED: Use proper alignment values 
    if dx > 32
      faces_to_render << {type: 2, d_align: 2, z_priority: 1, name: :right}
    end
   
    # For very close viewing, always show some faces
    if distance < 96
      if faces_to_render.empty?
        faces_to_render << {type: 1, d_align: 0, z_priority: 5, name: :front}
        faces_to_render << {type: 2, d_align: 0, z_priority: 4, name: :left}
      end
    end
   
    # Render at least one face
    if faces_to_render.empty?
      faces_to_render << {type: 1, d_align: 0, z_priority: 5, name: :front}
    end
    end
   
    # Render the faces
    faces_to_render.each_with_index do |face_config, face_index|
      side_dy = dy
      side_dx = dx
     
      # FIXED: Apply position adjustments with proper bounds checking
      if face_config[:type] == 1 # Horizontal face
        if face_config[:d_align] == 0 # Front
          side_dy -= 64
        elsif face_config[:d_align] == 2 # Back
          side_dy += 64
        end
      elsif face_config[:type] == 2 # Vertical face
        if face_config[:d_align] == 0 # Left
          side_dx -= 64
        elsif face_config[:d_align] == 2 # Right
          side_dx += 64
        end
      end
     
      # Calculate z-modifier
      z_modifier = base_z_offset + (face_config[:z_priority] * 0.008) + (face_index * 0.001)
     
      surface_data = [0, side_dy, side_dx, 5, 0, 0,
                      surface.bitmap.__id__, face_config[:type],
                      surface.character.fple_v_align, surface.character.fple_stretch,
                      surface.opacity, surface.blend_type,
                      surface.fit, surface.zoom, 0, z_modifier]
     
      surfaces_temp.push(surface_data)
    end
   
    surface.displayed = true
  end
  #--------------------------------------------------------------------------
  # * FIXED: Four-sided surfaces - ensure proper type assignment
  #--------------------------------------------------------------------------
  def add_four_sided_surfaces(surface, dy, dx, surfaces_temp, i, dir)
    # Handle special case where player is at same position as box
        j = i << 7
    if dy.between?(128, j) && dx.between?(-j, j)
    event_id = surface.character.id rescue 0
    base_z_offset = (event_id % 1000) * 0.0001
   
    # Always render all 4 sides for 4-sided boxes
    faces_to_render = [
      {type: 1, d_align: 0, z_priority: 3, name: :front},  # Front
      {type: 1, d_align: 2, z_priority: 0, name: :back},   # Back
      {type: 2, d_align: 0, z_priority: 3, name: :left},     # Left
      {type: 2, d_align: 2, z_priority: 1, name: :right},    # Right
    ]
   
    # Render all faces with strafe-safe positioning
    faces_to_render.each_with_index do |face_config, face_index|
      side_dy = dy
      side_dx = dx
     
      # FIXED: Apply position adjustments with bounds checking and strafe compensation
      if face_config[:type] == 1 # Horizontal face
        if face_config[:d_align] == 0 # Front
          side_dy -= 64
        elsif face_config[:d_align] == 2 # Back
          side_dy += 64
        end
      elsif face_config[:type] == 2 # Vertical face
        if face_config[:d_align] == 0 # Left
          side_dx -= 64
        elsif face_config[:d_align] == 2 # Right
          side_dx += 64
        end
      end
     
      # Calculate z-modifier
      z_modifier = base_z_offset + (face_config[:z_priority] * 0.01) + (face_index * 0.001)
     
      surface_data = [0, side_dy, side_dx, 5, 0, 0,
                      surface.bitmap.__id__, face_config[:type],
                      surface.character.fple_v_align, surface.character.fple_stretch,
                      surface.opacity, surface.blend_type,
                      surface.fit, surface.zoom, 0, z_modifier]
     
      surfaces_temp.push(surface_data)
    end
   
    surface.displayed = true
  end
end
  #--------------------------------------------------------------------------
  # * FIXED: Six-sided surfaces - ensure proper type assignment 
  #--------------------------------------------------------------------------
def add_six_sided_surfaces(surface, dy, dx, surfaces_temp, i, dir)
    j = i << 7
    if dy.between?(128, j) && dx.between?(-j, j)
    event_id = surface.character.id rescue 0
    base_z_offset = (event_id % 1000) * 0.0001
   
    # Render all 6 sides for maximum visibility
   
      faces_to_render = [
      {type: 0, d_align: 1, z_priority: 2, name: :center_h}, # Center horizontal
      {type: 1, d_align: 0, z_priority: 4, name: :front},    # Front
      {type: 1, d_align: 2, z_priority: 0, name: :back},     # Back
      {type: 2, d_align: 0, z_priority: 3, name: :left},    # Left
      {type: 2, d_align: 2, z_priority: 1, name: :right},  # Right
    ]
    # Render all faces with strafe protection
    faces_to_render.each_with_index do |face_config, face_index|
      side_dy = dy
      side_dx = dx
     
      # FIXED: Apply position adjustments with strafe-aware bounds checking
      if face_config[:type] == 1 # Horizontal face
        if face_config[:d_align] == 0 # Front
          side_dy -= 64
        elsif face_config[:d_align] == 2 # Back
          side_dy += 64
        end
      elsif face_config[:type] == 2 # Vertical face
        if face_config[:d_align] == 0 # Left
          side_dx -= 64
        elsif face_config[:d_align] == 2 # Right
          side_dx += 64
        end
      end
     
      # Calculate z-modifier
      z_modifier = base_z_offset + (face_config[:z_priority] * 0.008) + (face_index * 0.001)
     
      surface_data = [0, side_dy, side_dx, 5, 0, 0,
                      surface.bitmap.__id__, face_config[:type],
                      surface.character.fple_v_align, surface.character.fple_stretch,
                      surface.opacity, surface.blend_type,
                      surface.fit, surface.zoom, 0, z_modifier]
     
      surfaces_temp.push(surface_data)
    end
   
    surface.displayed = true
  end 
  end
    # Render all 6 sides for maximum visibility
  #--------------------------------------------------------------------------
  # * Recherche les surfaces visibles de la carte en fonction de
  # l'orientation du joueur
  #--------------------------------------------------------------------------
def refresh_surfaces
    @current_dir = $game_player.direction
    self.surfaces = []
    @x_ref = $game_player.x
    @y_ref = $game_player.y
    case $game_player.direction
    when 2
      surfaces_temp = refresh_surfaces_down
    when 4
      surfaces_temp = refresh_surfaces_left
    when 6
      surfaces_temp = refresh_surfaces_right
    when 8
      surfaces_temp = refresh_surfaces_up
    end
   
    # set surfaces z attributes with z-fighting prevention
    surfaces_temp.each {|surface| set_surface_z(surface)}
    surfaces.concat(surfaces_temp)
   
    # Enhanced sorting with z-fighting prevention 
    if @last_surface_count != surfaces.length || $game_temp.force_render
      surfaces.sort! { |a, b|
        z_diff = b[5] - a[5]
        if z_diff.abs < 0.001 # Very close z-values
          # Use additional criteria for stable sorting
          secondary = (b[1].abs + b[2].abs) - (a[1].abs + a[2].abs)
          secondary.zero? ? b.object_id <=> a.object_id : secondary
        else
          z_diff <=> 0
        end
      }
      @last_surface_count = surfaces.length
    end
  end
 
  #--------------------------------------------------------------------------
  # * Calcul de la priorité d'affichage d'une surface
  # param surface : Array<Integer>
  #--------------------------------------------------------------------------
def set_surface_z(surface)
  if surface[3] < 5 # map surfaces
    surface[5] = (surface[1].abs << 5) + surface[2].abs
  else # character surfaces
    base_z = (surface[1].abs >> 1) + (surface[2].abs >> 6) - 2
   
    # Check if surface has z-modifier (from 4-side/6-side rendering or door boost)
    z_modifier = surface[15] || 0  # Additional z-modifier if present
   
    # Add small offset based on surface type and alignment
    type_offset = surface[7] || 0  # Surface type
    align_offset = surface[8] || 0 # V-align
   
    # Create unique z-values for different surface configurations
    z_offset = case type_offset
    when 1 # Horizontal walls
      case surface[2] <=> 0 # dx comparison
      when -1 then 0.4  # Left side
      when 0 then 0.2   # Center
      when 1 then 0.0   # Right side
      end
    when 2 # Vertical walls 
      case surface[1] <=> 0 # dy comparison
      when -1 then 0.3  # Front
      when 0 then 0.1   # Center
      when 1 then -0.1  # Back
      end
    else
      0 # Default for type 0
    end
   
    # Additional offset for vertical alignment
    v_align_offset = case align_offset
    when 0 then 0.03  # Top
    when 1 then 0.01  # Middle 
    when 2 then -32.01 # Bottom
    else 0
    end
   
    surface[5] = base_z.to_f + z_offset + v_align_offset + z_modifier
  end
end
  #--------------------------------------------------------------------------
  # * Recherche les surfaces visibles des évènements en fonction de
  # l'orientation du joueur
  # param character_surfaces : Array<FPLE::Surface_Characters>
  #--------------------------------------------------------------------------
# This method updates the list of character surfaces based on visibility and player direction.
public
def refresh_character_surfaces(character_surfaces)
    return if character_surfaces.empty?
   
    max_dist = ($game_system.fple_view_distance || 10) + 3  # Large buffer
    visible_surfaces = character_surfaces.select do |surface|
      next false unless surface.character && surface.visible && surface.opacity > 0
     
      # Very generous distance-based filtering
      char = surface.character
      dist_x = ($game_player.x - char.x).abs
      dist_y = ($game_player.y - char.y).abs
     
      dist_x <= max_dist && dist_y <= max_dist
    end
   
    visible_surfaces = character_surfaces.select { |s|
      s.character && s.visible && s.opacity > 0
    }
   
    clear_character_surfaces(visible_surfaces)
   
    # During rotation, we need to render from multiple directions
    if FPLE.angle > 0
      # For multi-sided events during rotation, only render once from current direction
      # to prevent duplicate/rotating surfaces
      current_surfaces = case $game_player.direction
      when 2 then add_character_surfaces_down_with_rotation_fix(visible_surfaces)
      when 4 then add_character_surfaces_left_with_rotation_fix(visible_surfaces)
      when 6 then add_character_surfaces_right_with_rotation_fix(visible_surfaces)
      when 8 then add_character_surfaces_up_with_rotation_fix(visible_surfaces)
      end
     
      # Only add next direction surfaces for single-sided events
      clear_character_surfaces_for_single_sided(visible_surfaces)
      next_surfaces = case $game_player.direction
      when 2 then add_character_surfaces_right_single_only(visible_surfaces)
      when 4 then add_character_surfaces_down_single_only(visible_surfaces)
      when 6 then add_character_surfaces_up_single_only(visible_surfaces)
      when 8 then add_character_surfaces_left_single_only(visible_surfaces)
      end
     
      surfaces_temp = current_surfaces + next_surfaces
    else
      # Normal rendering - single direction
      surfaces_temp = case $game_player.direction
      when 2 then add_character_surfaces_down(visible_surfaces)
      when 4 then add_character_surfaces_left(visible_surfaces)
      when 6 then add_character_surfaces_right(visible_surfaces)
      when 8 then add_character_surfaces_up(visible_surfaces)
      else []
      end
    end
    surfaces_temp.each { |surface| set_surface_z(surface) }
    @surfaces.concat(surfaces_temp)
    #Old#@surfaces.sort! { |a, b| b[5] - a[5] }
 
      # Enhanced sorting
    @surfaces.sort! do |a, b|
      z_diff = b[5] - a[5]
      if z_diff.abs < 0.0001
        (b[1].abs + b[2].abs) - (a[1].abs + a[2].abs)
      else
        z_diff <=> 0
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Réinitialise l'indicateur d'affichage des surfaces liées aux évènements
  # param character_surfaces : Array<FPLE::Surface_Characters>
  #--------------------------------------------------------------------------
  def clear_character_surfaces(character_surfaces)
    character_surfaces.each {|surface| surface.displayed = false}
  end
 
  def clear_character_surfaces_for_single_sided(character_surfaces)
    character_surfaces.each do |surface|
      # Only clear single-sided events - keep multi-sided events as displayed
      unless surface.character.fple_four_side || surface.character.fple_six_side || surface.character.fple_two_side
        surface.displayed = false
      end
    end
  end
 
  def cleanup_distant_surfaces
    return unless @surfaces
   
    # Only cleanup if we have a lot of surfaces
    max_surfaces = 300 # Very generous limit
    if @surfaces.length > max_surfaces
      # Keep only the closest surfaces
      @surfaces.sort_by! { |s| s[1].abs + s[2].abs }
      @surfaces = @surfaces.first(max_surfaces)
    end
  end
  #--------------------------------------------------------------------------
  # * Vérifie la visibilité d'une surface liée à un évènement et l'ajoute
  # à la liste des surfaces à afficher le cas échéant
  # param surface : FPLE::Surface_Characters
  # param dy : Integer
  # param dx : Integer
  # param surfaces_temp : Array<Array<integer>>
  # param i : Integer
  # param dir : Integer
  #--------------------------------------------------------------------------
# This method adds a character surface to the list for rendering if it is visible.
# `surface`: The FPLE surface object for the character.
# `dy`: The change in y-coordinate from the player.
# `dx`: The change in x-coordinate from the player.
# `surfaces_temp`: The array to which the new surface will be added.
# `i`: The view distance index used for calculation.
# `dir`: The player's direction.
def add_character_surfaces(surface, dy, dx, surfaces_temp, i, dir)
  return unless surface.character && surface.character.fple_type
 
  # Distance culling - more generous for multi-sided events
  distance_sq = dy * dy + dx * dx
  max_distance = $game_system.fple_view_distance || 10
 
  # Use larger buffer for multi-sided events to prevent edge clipping
  if surface.character.fple_four_side || surface.character.fple_six_side || surface.character.fple_two_side
    rotation_buffer = FPLE.angle > 0 ? 1.5 : 1.3
  else
    rotation_buffer = FPLE.angle > 0 ? 2.0 : 1.0
  end
 
  max_distance_sq = (max_distance * 96 * rotation_buffer) ** 2
  return if distance_sq > max_distance_sq
 
  # Early opacity check
  return if surface.opacity <= 0
 
  # Handle multi-sided boxes
  if surface.character.fple_two_side
    add_two_sided_surfaces(surface, dy, dx, surfaces_temp, i, dir)
    return
  elsif surface.character.fple_four_side
    add_four_sided_surfaces(surface, dy, dx, surfaces_temp, i, dir)
    return
  elsif surface.character.fple_six_side
    add_six_sided_surfaces(surface, dy, dx, surfaces_temp, i, dir)
    return
  end
 
  # Check if this is a door event
  is_door = is_door_event?(surface.character)
  door_z_boost = is_door ? 50.0 : 0.0
 
  # Apply door positioning offset to move it outside the wall box
  if is_door
    dy, dx = apply_door_positioning(dy, dx, surface, dir)
  end
 
  # Original single-surface logic for regular events
  j = i << 7
  if dy == 0 && dx == 0 && surface.character.fple_type == 0 && surface.character.fple_one_side == false
    surface.set_relative_attributes(dir)
    safe_dy = 128
    surface_data = [0, safe_dy, 0, 5, 0, 0,
                    surface.bitmap.__id__,
                    0, # Keep type 0 for face-player events at same position
                    surface.character.fple_v_align,
                    surface.character.fple_stretch,
                    surface.opacity,
                    surface.blend_type,
                    surface.fit,
                    surface.zoom,
                    surface.mirror,
                    door_z_boost] # Add door boost as extra parameter
    surfaces_temp.push(surface_data)
    surface.displayed = true
    elsif dy.between?(128, j) && dx.between?(-j, j)
    # Position adjustments for wall types
    if surface.v_align == 2
      dy -= 16 unless surface.fit == 1
    end
   
    surface.set_relative_attributes(dir)
   
    if surface.type == 1
      if surface.d_align == 0
        dy -= 64
      elsif surface.d_align == 2
        dy += 64
      elsif surface.d_align == 1 && surface.v_align == 2
        dy -= 16 unless $game_player.moving?
      end
    elsif surface.type == 2
      if surface.d_align == 0
        dx -= 64
      elsif surface.d_align == 2
        dx += 64
      elsif surface.d_align == 1 && surface.v_align == 2
        dx -= 16 unless $game_player.moving?
      end
    end
   
    surface_data = [0, dy, dx, 5, 0, 0,
                    surface.bitmap.__id__, surface.type,
                    surface.v_align, surface.character.fple_stretch,
                    surface.opacity, surface.blend_type,
                    surface.fit, surface.zoom, surface.mirror,
                    door_z_boost] # Add door boost as extra parameter
    surfaces_temp.push(surface_data)
    surface.displayed = true
  end
end
def apply_door_positioning(dy, dx, surface, dir)
  # Amount to push door forward (toward player)
  door_offset = -4  # Adjust this value as needed
 
  # Determine which direction to offset based on door type and player direction
  case surface.character.fple_type
  when 0 # Face player type - always push toward player
    case dir
    when 2 # Player facing down
      dy -= door_offset if dy > 0  # Push door forward if it's behind player
    when 8 # Player facing up 
      dy += door_offset if dy < 0  # Push door forward if it's behind player
    when 4 # Player facing left
      dx += door_offset if dx < 0  # Push door forward if it's behind player
    when 6 # Player facing right
      dx -= door_offset if dx > 0  # Push door forward if it's behind player
    end
   
  when 1 # Horizontal wall type
    case dir
    when 2, 8 # Player facing up/down - door is on horizontal wall
      if dy > 0 # Door is in front of player
        dy -= door_offset # Pull it even more forward
      elsif dy < 0 # Door is behind player 
        dy += door_offset # Push it less behind
      end
    when 4, 6 # Player facing left/right - treat as face-player
      if dx > 0
        dx -= door_offset
      elsif dx < 0
        dx += door_offset 
      end
    end
   
  when 2 # Vertical wall type
    case dir
    when 4, 6 # Player facing left/right - door is on vertical wall
      if dx > 0 # Door is in front of player
        dx -= door_offset # Pull it even more forward
      elsif dx < 0 # Door is behind player
        dx += door_offset # Push it less behind 
      end
    when 2, 8 # Player facing up/down - treat as face-player
      if dy > 0
        dy -= door_offset
      elsif dy < 0
        dy += door_offset
      end
    end
  end
 
  return [dy, dx]
end
def is_door_event?(character)
  return false unless character.is_a?(Game_Event)
 
  # Check event name
  event_name = character.event.name.downcase
  return true if event_name.include?('door') || event_name.include?('gate')
 
  # Check comments in event pages
  if character.event.pages[0] && character.event.pages[0].list
    character.event.pages[0].list.each do |command|
      if command.code == 108 # Comment command
        comment = command.parameters[0].downcase
        if comment.include?('door') || comment.include?('gate') || comment.include?('entrance')
          return true
        end
      end
    end
  end
 
  return false
end
  def adjust_door_depth(surface, character)
  return unless character.is_a?(Game_Event)
 
  # Check if this looks like a door event
  event_name = character.event.name.downcase
  has_door_comment = false
 
  if character.event.pages[0] && character.event.pages[0].list
    character.event.pages[0].list.each do |command|
      if command.code == 108 && command.parameters[0].downcase.include?('door')
        has_door_comment = true
        break
      end
    end
  end
 
  if event_name.include?('door') || has_door_comment
    # Force doors to render in front of walls
    surface[5] += 15000
  end
end
  #--------------------------------------------------------------------------
  def add_two_sided_surfaces(surface, dy, dx, surfaces_temp, i, dir)
    # Handle special case where player is at same position as box
    if dx == 0 && dy == 0
      # For multi-sided boxes at same position, render as face-player type
      surfaces_temp.push([0, 0, 0, 5, 0, 0,
                          surface.bitmap.__id__,
                          0, # Face player type for same position
                          surface.character.fple_v_align,
                          surface.character.fple_stretch,
                          surface.opacity,
                          surface.blend_type,
                          surface.fit,
                          surface.zoom,
                          0]) # No mirror
      surface.displayed = true
      return
    end
   
    event_id = surface.character.id rescue 0
    base_z_offset = (event_id % 1000) * 0.0001
    distance = Math.sqrt(dy * dy + dx * dx)
   
    # Determine visible faces based on position
    faces_to_render = []
   
    # Front face (player looking at object)
    if dy > 32
      faces_to_render << {type: 1, d_align: 0, z_priority: 5, name: :front}
    end
   
    # Back face
    if dy < -32
      faces_to_render << {type: 1, d_align: 2, z_priority: 0, name: :back}
    end
   
    # Left face
    if dx < -32
      faces_to_render << {type: 2, d_align: 0, z_priority: 4, name: :left}
    end
   
    # Right face
    if dx > 32
      faces_to_render << {type: 2, d_align: 2, z_priority: 1, name: :right}
    end
   
    # For very close viewing, always show some faces
    if distance < 96
      if faces_to_render.empty?
        faces_to_render << {type: 1, d_align: 0, z_priority: 5, name: :front}
        faces_to_render << {type: 2, d_align: 0, z_priority: 4, name: :left}
      end
    end
   
    # Render at least one face
    if faces_to_render.empty?
      faces_to_render << {type: 1, d_align: 0, z_priority: 5, name: :front}
    end
   
    # Render the faces
    faces_to_render.each_with_index do |face_config, face_index|
      side_dy = dy
      side_dx = dx
     
      # Apply position adjustments
      if face_config[:type] == 1 # Horizontal face
        if face_config[:d_align] == 0 # Front
          side_dy -= 64
        elsif face_config[:d_align] == 2 # Back
          side_dy += 64
        end
      elsif face_config[:type] == 2 # Vertical face
        if face_config[:d_align] == 0 # Left
          side_dx -= 64
        elsif face_config[:d_align] == 2 # Right
          side_dx += 64
        end
      end
     
      # Calculate z-modifier
      z_modifier = base_z_offset + (face_config[:z_priority] * 0.008) + (face_index * 0.001)
     
      surface_data = [0, side_dy, side_dx, 5, 0, 0,
                      surface.bitmap.__id__, face_config[:type], # NEVER type 0
                      surface.character.fple_v_align, surface.character.fple_stretch,
                      surface.opacity, surface.blend_type,
                      surface.fit, surface.zoom, 0, z_modifier] # No mirror for multi-sided
     
      surfaces_temp.push(surface_data)
    end
   
    surface.displayed = true
  end
#--------------------------------------------------------------------------
def should_render_one_side_event(character, player_dir)
  return true unless character.fple_one_side
 
  # Get the event's original type
  original_type = character.fple_type
 
  case original_type
  when 0 # Always face player - render from all directions
    return true
  when 1 # Horizontal wall in editor view
    # Only render when looking from north or south
    return [2, 8].include?(player_dir)
  when 2 # Vertical wall in editor view 
    # Only render when looking from east or west
    return [4, 6].include?(player_dir)
  end
 
  return true
end
  #--------------------------------------------------------------------------
def should_render_two_side_event(character, player_dir)
  return true unless character.fple_two_side
 
  # Get the event's original type
  original_type = character.fple_type
 
  case original_type
  when 0 # Always face player - render from all directions
    return true
  when 1 # Horizontal wall in editor view
    # Only render when looking from north or south
    return [2, 8].include?(player_dir)
  when 2 # Vertical wall in editor view 
    # Only render when looking from east or west
    return [4, 6].include?(player_dir)
  end
 
  return true
end
  #--------------------------------------------------------------------------
  # * Recherche les surfaces liées à un évènement visibles quand le joueur est
  # orienté vers le bas
  # param character_surfaces : Array<FPLE::Surface_Characters>
  # return Array<Array<Integer>>
  #-------------------------------------------------------------------------z
 
   #--------------------------------------------------------------------------
  # * Recherche les surfaces liées à un évènement visibles quand le joueur est
  # orienté vers le haut
  # param character_surfaces : Array<FPLE::Surface_Characters>
  # return Array<Array<Integer>>
  #--------------------------------------------------------------------------
def add_character_surfaces_up(character_surfaces)
  surfaces_temp = []
  i = $game_system.fple_view_distance
  character_surfaces.each {|surface|
    if surface.displayed then next end
    # Check directional visibility for 2-side events
    next unless should_render_two_side_event(surface.character, 8)
   
    dy = ($game_player.y << 7) - surface.dy
    dx = surface.dx - ($game_player.x << 7)
    add_character_surfaces(surface, dy, dx, surfaces_temp, i, 8)
  }
  return surfaces_temp
end
  #--------------------------------------------------------------------------
  # * Recherche les surfaces liées à un évènement visibles quand le joueur est
  # orienté vers le bas
  # param character_surfaces : Array<FPLE::Surface_Characters>
  # return Array<Array<Integer>>
  #--------------------------------------------------------------------------
def add_character_surfaces_down(character_surfaces)
  surfaces_temp = []
  i = $game_system.fple_view_distance
  character_surfaces.each {|surface|
    if surface.displayed then next end
    # Check directional visibility for 2-side events
    next unless should_render_two_side_event(surface.character, 2)
   
    dy = surface.dy - ($game_player.y << 7)
    dx = ($game_player.x << 7) - surface.dx
    add_character_surfaces(surface, dy, dx, surfaces_temp, i, 2)
  }
  return surfaces_temp
end
  #--------------------------------------------------------------------------
  # * Recherche les surfaces liées à un évènement visibles quand le joueur est
  # orienté vers la gauche
  # param character_surfaces : Array<FPLE::Surface_Characters>
  # return Array<Array<Integer>>
  #--------------------------------------------------------------------------
def add_character_surfaces_left(character_surfaces)
  surfaces_temp = []
  i = $game_system.fple_view_distance
  character_surfaces.each {|surface|
    if surface.displayed then next end
    # Check directional visibility for 2-side events
    next unless should_render_two_side_event(surface.character, 4)
   
    dy = ($game_player.x << 7) - surface.dx
    dx = ($game_player.y << 7) - surface.dy
    add_character_surfaces(surface, dy, dx, surfaces_temp, i, 4)
  }
  return surfaces_temp
end
  #--------------------------------------------------------------------------
  # * Recherche les surfaces liées à un évènement visibles quand le joueur est
  # orienté vers la droite
  # param character_surfaces : Array<FPLE::Surface_Characters>
  # return Array<Array<Integer>>
  #--------------------------------------------------------------------------
def add_character_surfaces_right(character_surfaces)
  surfaces_temp = []
  i = $game_system.fple_view_distance
  character_surfaces.each {|surface|
    if surface.displayed then next end
    # Check directional visibility for 2-side events
    next unless should_render_two_side_event(surface.character, 6)
   
    dy = surface.dx - ($game_player.x << 7)
    dx = surface.dy - ($game_player.y << 7)
    add_character_surfaces(surface, dy, dx, surfaces_temp, i, 6)
  }
  return surfaces_temp
end
  #--------------------------------------------------------------------------
  # * Recherche les surfaces visibles quand le joueur tourne vers la droite
  # param character_surfaces : Array<FPLE::Surface_Characters>
  #--------------------------------------------------------------------------
  def refresh_surfaces_turn_right(character_surfaces)
    @current_dir = $game_player.direction
    self.surfaces = []
    @x_ref = $game_player.x
    @y_ref = $game_player.y
    surfaces_temp = refresh_current_surface
    clear_character_surfaces(character_surfaces)
    case $game_player.direction
    when 2
      surfaces_temp1 = refresh_surfaces_down
      @current_dir = 6
      surfaces_temp2 = refresh_surfaces_right(false)
      @current_dir = 2
      surfaces_temp1 += add_character_surfaces_down(character_surfaces)
      surfaces_temp2 += add_character_surfaces_right(character_surfaces)
    when 4
      surfaces_temp1 = refresh_surfaces_left
      @current_dir = 2
      surfaces_temp2 = refresh_surfaces_down(false)
      @current_dir = 4
      surfaces_temp1 += add_character_surfaces_left(character_surfaces)
      surfaces_temp2 += add_character_surfaces_down(character_surfaces)
    when 6
      surfaces_temp1 = refresh_surfaces_right
      @current_dir = 8
      surfaces_temp2 = refresh_surfaces_up(false)
      @current_dir = 6
      surfaces_temp1 += add_character_surfaces_right(character_surfaces)
      surfaces_temp2 += add_character_surfaces_up(character_surfaces)
    when 8
      surfaces_temp1 = refresh_surfaces_up
      @current_dir = 4
      surfaces_temp2 = refresh_surfaces_left(false)
      @current_dir = 8
      surfaces_temp1 += add_character_surfaces_up(character_surfaces)
      surfaces_temp2 += add_character_surfaces_left(character_surfaces)
    end
    surfaces_temp1.each {|surface| adjust_surface_for_rotation(surface)}
    # set surfaces z attributes
    (surfaces_temp + surfaces_temp1 + surfaces_temp2).each {|surface|
      set_surface_z(surface)
    }
    surfaces.concat(surfaces_temp + surfaces_temp1 + surfaces_temp2)
    surfaces.sort! {|a, b| b[5] - a[5]}
  end
  #--------------------------------------------------------------------------
  # * Recherche les surfaces visibles quand le joueur tourne vers la gauche
  # param character_surfaces : Array<FPLE::Surface_Characters>
  #--------------------------------------------------------------------------
  def refresh_surfaces_turn_left(character_surfaces)
    @current_dir = $game_player.direction
    self.surfaces = []
    @x_ref = $game_player.x
    @y_ref = $game_player.y
    surfaces_temp = refresh_current_surface
    clear_character_surfaces(character_surfaces)
    case $game_player.direction
    when 2
      @current_dir = 4
      surfaces_temp1 = refresh_surfaces_left
      @current_dir = 2
      surfaces_temp2 = refresh_surfaces_down(false)
      surfaces_temp1 += add_character_surfaces_left(character_surfaces)
      surfaces_temp2 += add_character_surfaces_down(character_surfaces)
    when 4
      @current_dir = 8
      surfaces_temp1 = refresh_surfaces_up
      @current_dir = 4
      surfaces_temp2 = refresh_surfaces_left(false)
      surfaces_temp1 += add_character_surfaces_up(character_surfaces)
      surfaces_temp2 += add_character_surfaces_left(character_surfaces)
    when 6
      @current_dir = 2
      surfaces_temp1 = refresh_surfaces_down
      @current_dir = 6
      surfaces_temp2 = refresh_surfaces_right(false)
      surfaces_temp1 += add_character_surfaces_down(character_surfaces)
      surfaces_temp2 += add_character_surfaces_right(character_surfaces)
    when 8
      @current_dir = 6
      surfaces_temp1 = refresh_surfaces_right
      @current_dir = 8
      surfaces_temp2 = refresh_surfaces_up(false)
      surfaces_temp1 += add_character_surfaces_right(character_surfaces)
      surfaces_temp2 += add_character_surfaces_up(character_surfaces)
    end
    surfaces_temp1.each {|surface| adjust_surface_for_rotation(surface)}
    # set surfaces z attributes
    (surfaces_temp + surfaces_temp1 + surfaces_temp2).each {|surface|
      set_surface_z(surface)
    }
    surfaces.concat(surfaces_temp + surfaces_temp1 + surfaces_temp2)
    surfaces.sort! {|a, b| b[5] - a[5]}
  end
  #--------------------------------------------------------------------------
  # * Correction des attributs d'une surface visible pendant une rotation
  # param surface : Array<Integer>
  #--------------------------------------------------------------------------
  def adjust_surface_for_rotation(surface)
    if surface[3] < 5
      dy = surface[1]
      surface[1] = -surface[2]
      surface[2] = dy
      if surface[3] < 2
        surface[3] = 1 - surface[3]
      end
    else
      if surface[7] > 0
        surface[7] = 3 - surface[7]
      end   
      dy = surface[1]
      surface[1] = -surface[2]
      surface[2] = dy
    end
  end
  #--------------------------------------------------------------------------
  # * Recherche des surfaces visibles en déplacement latéral
  # param offset : Integer
  #--------------------------------------------------------------------------
  def refresh_surfaces_strafe(offset)
    @current_dir = $game_player.direction
    @x_ref = $game_player.x
    @y_ref = $game_player.y
    case $game_player.direction
    when 2
      @x_ref -= offset
      surfaces_temp = refresh_surfaces_down_strafe
    when 4
      @y_ref -= offset
      surfaces_temp = refresh_surfaces_left_strafe
    when 6
      @y_ref += offset
      surfaces_temp = refresh_surfaces_right_strafe
    when 8
      @x_ref += offset
      surfaces_temp = refresh_surfaces_up_strafe
    end
    # set surfaces z attributes
    surfaces_temp.each {|surface| set_surface_z(surface)}
    surfaces.concat(surfaces_temp)
    surfaces.sort! {|a, b| b[5] - a[5]}
  end
  #--------------------------------------------------------------------------
  # * Rafraîchit la surface à la position du joueur
  # return Array<Array<integer>>
  #--------------------------------------------------------------------------
  def refresh_current_surface
    surfaces_temp = []
    get_surface_ground(surfaces_temp, @x_ref, @y_ref, 0, 0)
    return surfaces_temp
  end
  #--------------------------------------------------------------------------
  # * Recherche les surfaces visibles de la carte quand le joueur est
  # orienté vers le haut
  # param right_ground : Boolean
  # return Array<Array<integer>>
  #--------------------------------------------------------------------------
def refresh_surfaces_up(right_ground = true)
  surfaces_temp = []
  base_distance = $game_system.fple_view_distance
  # Add extra tiles during rotation
  i = FPLE.angle > 0 ? base_distance + 1 : base_distance
 
  while i > 0
    # peripherical ground/ceiling sprites
    get_surface_ground(surfaces_temp, @x_ref - i, @y_ref - i, i << 1, -i << 1)
    if right_ground
      get_surface_ground(surfaces_temp, @x_ref + i, @y_ref - i, i << 1, i << 1)
    end
    klim = i - 1
    (-klim..klim).each {|k|
      add_surfaces(surfaces_temp, @x_ref + k, @y_ref - i, i << 1, k << 1, 0, 1)
    }
    i -= 1
  end
  return surfaces_temp
end
def refresh_surfaces_down(right_ground = true)
  surfaces_temp = []
  base_distance = $game_system.fple_view_distance
  # Add extra tiles during rotation
  i = FPLE.angle > 0 ? base_distance + 1 : base_distance
 
  while i > 0
    # peripherical ground sprites
    get_surface_ground(surfaces_temp, @x_ref + i, @y_ref + i, i << 1, -i << 1)
    if right_ground
      get_surface_ground(surfaces_temp, @x_ref - i, @y_ref + i, i << 1, i << 1)
    end
    klim = i - 1
    (-klim..klim).each {|k|
      add_surfaces(surfaces_temp, @x_ref - k, @y_ref + i, i << 1, k << 1, 0, -1)
    }
    i -= 1
  end
  return surfaces_temp
end
def refresh_surfaces_left(right_ground = true)
  surfaces_temp = []
  base_distance = $game_system.fple_view_distance
  # Add extra tiles during rotation
  i = FPLE.angle > 0 ? base_distance + 1 : base_distance
 
  while i > 0
    # peripherical ground sprites
    get_surface_ground(surfaces_temp, @x_ref - i, @y_ref + i, i << 1, -i << 1)
    if right_ground
      get_surface_ground(surfaces_temp, @x_ref - i, @y_ref - i, i << 1, i << 1)
    end
    klim = i - 1
    (-klim..klim).each {|k|
      add_surfaces(surfaces_temp, @x_ref - i, @y_ref - k, i << 1, k << 1, 1, 0)
    }
    i -= 1
  end
  return surfaces_temp
end
def refresh_surfaces_right(right_ground = true)
  surfaces_temp = []
  base_distance = $game_system.fple_view_distance
  # Add extra tiles during rotation
  i = FPLE.angle > 0 ? base_distance + 1 : base_distance
 
  while i > 0
    # peripherical ground sprites
    get_surface_ground(surfaces_temp, @x_ref + i, @y_ref - i, i << 1, -i << 1)
    if right_ground
      get_surface_ground(surfaces_temp, @x_ref + i, @y_ref + i, i << 1, i << 1)
    end
    klim = i - 1
    (-klim..klim).each {|k|
      add_surfaces(surfaces_temp, @x_ref + i, @y_ref + k, i << 1, k << 1, -1, 0)
    }
    i -= 1
  end
  return surfaces_temp
end
  #--------------------------------------------------------------------------
  # * Vérifie si un sol ou un plafond doit être affiché
  # param surfaces_temp : Array<Array<Integer>>
  # param x : Integer
  # param y : Integer
  # param dy : Integer
  # param dx : Integer
  #--------------------------------------------------------------------------
  def get_surface_ground(surfaces_temp, x, y, dy, dx)
    if @fple_map.get_data(x, y)[0] == 0 # no wall tile
      add_surface_ground(surfaces_temp, x, y, dy, dx)
    end
  end
  #--------------------------------------------------------------------------
  # * Ajoute une surface de sol ou de plafond qui doit être affichée
  # param surfaces_temp : Array<Array<Integer>>
  # param x : Integer
  # param y : Integer
  # param dy : Integer
  # param dx : Integer
  #--------------------------------------------------------------------------
  def add_surface_ground(surfaces_temp, x, y, dy, dx)
    g_texture_id = @fple_map.get_data(x, y)[1]
    c_texture_id = @fple_map.get_data(x, y)[19]
    if @fple_map.is_texture_id_valid?(g_texture_id)
      if @fple_map.is_texture_id_valid?(c_texture_id)
        surfaces_temp.push([g_texture_id, dy, dx, 4, c_texture_id, 0,
        @fple_map.get_textureset_id(g_texture_id),
        @fple_map.get_textureset_width(g_texture_id),
        @fple_map.get_textureset_id(c_texture_id),
        @fple_map.get_textureset_width(c_texture_id)])
      else
        surfaces_temp.push([g_texture_id, dy, dx, 2, 0, 0,
        @fple_map.get_textureset_id(g_texture_id),
        @fple_map.get_textureset_width(g_texture_id), 0, 8])
      end
    elsif @fple_map.is_texture_id_valid?(c_texture_id)
      surfaces_temp.push([c_texture_id, dy, dx, 3, 0, 0,
      @fple_map.get_textureset_id(c_texture_id),
      @fple_map.get_textureset_width(c_texture_id), 0, 8])
    end
  end
  #--------------------------------------------------------------------------
  # * Recherche des surfaces visibles
  # param surfaces_temp : Array<Array<Integer>>
  # param x : Integer
  # param y : Integer
  # param dy : Integer
  # param dx : Integer
  # param oy : Integer
  # param ox : Integer
  #--------------------------------------------------------------------------
  def add_surfaces(surfaces_temp, x, y, dy, dx, ox, oy)
    if @fple_map.get_data(x, y)[0] > 0 # wall tile
      if @fple_map.get_data(x + ox, y + oy)[0] == 0 # --> visible !
        texture_id = @fple_map.get_data(x, y)[
        FPLE::MAP_SIDES[@current_dir - 1 >> 1]]
        if @fple_map.is_texture_id_valid?(texture_id)
          surfaces_temp.push([texture_id, dy - 1, dx, 1, 0, 0,
          @fple_map.get_textureset_id(texture_id),
          @fple_map.get_textureset_width(texture_id), 0, 8])
        end
      end
    else
      # ground/ceiling sprite
      add_surface_ground(surfaces_temp, x, y, dy, dx)
      # side walls
      if dx <= 0 # left
        if @fple_map.get_data(x - oy, y + ox)[0] > 0 # side wall tile
          texture_id = @fple_map.get_data(x - oy, y + ox)[
          FPLE::MAP_SIDES_LEFT[@current_dir - 1 >> 1]]
          if @fple_map.is_texture_id_valid?(texture_id)
            surfaces_temp.push([texture_id, dy, dx - 1, 0, 0, 0,
            @fple_map.get_textureset_id(texture_id),
            @fple_map.get_textureset_width(texture_id), 0, 8])
          end
        end
      end
      if dx >= 0 # right
        if @fple_map.get_data(x + oy, y - ox)[0] > 0 # side wall tile
          texture_id = @fple_map.get_data(x + oy, y - ox)[
          FPLE::MAP_SIDES_RIGHT[@current_dir - 1 >> 1]]
          if @fple_map.is_texture_id_valid?(texture_id)
            surfaces_temp.push([texture_id, dy, dx + 1, 0, 0, 0,
            @fple_map.get_textureset_id(texture_id),
            @fple_map.get_textureset_width(texture_id), 0, 8])
          end
        end
      end
    end
  end
  #--------------------------------------------------------------------------
  # * Recherche des surfaces visibles en déplacement latéral quand le
  # joueur est orienté vers le haut
  # return Array<Array<Integer>>
  #--------------------------------------------------------------------------
  def refresh_surfaces_up_strafe
    surfaces_temp = []
    i = $game_system.fple_view_distance
    while i > 0
      get_surface_ground(surfaces_temp, @x_ref + i + 1, @y_ref - i, i << 1,
      i + 1 << 1)
      add_surfaces_strafe(surfaces_temp, @x_ref + i,  @y_ref - i, i << 1, 0, 1)
      # middle side wall
      if @fple_map.get_data(@x_ref + 1, @y_ref - i)[0] == 0 # no wall tile
        if @fple_map.get_data(@x_ref, @y_ref - i)[0] > 0 # side wall tile (Left)
          texture_id = @fple_map.get_data(@x_ref, @y_ref - i)[
          FPLE::MAP_SIDES_LEFT[@current_dir - 1 >> 1]]
          if @fple_map.is_texture_id_valid?(texture_id)
            surfaces_temp.push([texture_id, i << 1, 1, 0, 0, 0,
            @fple_map.get_textureset_id(texture_id),
            @fple_map.get_textureset_width(texture_id), 0, 8])
          end
        end
      end
      i -= 1
    end
    return surfaces_temp
  end
  #--------------------------------------------------------------------------
  # * Recherche des surfaces visibles en déplacement latéral quand le
  # joueur est orienté vers le bas
  # return Array<Array<Integer>>
  #--------------------------------------------------------------------------
  def refresh_surfaces_down_strafe
    surfaces_temp = []
    i = $game_system.fple_view_distance
    while i > 0
      get_surface_ground(surfaces_temp, @x_ref - i - 1, @y_ref + i, i << 1,
      i + 1 << 1)
      add_surfaces_strafe(surfaces_temp, @x_ref - i,  @y_ref + i, i << 1, 0, -1)
      # middle side wall
      if @fple_map.get_data(@x_ref - 1, @y_ref + i)[0] == 0 # no wall tile
        if @fple_map.get_data(@x_ref, @y_ref + i)[0] > 0 # side wall tile (Left)
          texture_id = @fple_map.get_data(@x_ref, @y_ref + i)[
          FPLE::MAP_SIDES_LEFT[@current_dir - 1 >> 1]]
          if @fple_map.is_texture_id_valid?(texture_id)
            surfaces_temp.push([texture_id, i << 1, 1, 0, 0, 0,
            @fple_map.get_textureset_id(texture_id),
            @fple_map.get_textureset_width(texture_id), 0, 8])
          end
        end
      end
      i -= 1
    end
    return surfaces_temp
  end
  #--------------------------------------------------------------------------
  # * Recherche des surfaces visibles en déplacement latéral quand le
  # joueur est orienté vers la gauche
  # return Array<Array<Integer>>
  #--------------------------------------------------------------------------
  def refresh_surfaces_left_strafe
    surfaces_temp = []
    i = $game_system.fple_view_distance
    while i > 0
      get_surface_ground(surfaces_temp, @x_ref - i, @y_ref - i - 1, i << 1,
      i + 1 << 1)
      add_surfaces_strafe(surfaces_temp, @x_ref - i,  @y_ref - i, i << 1, 1, 0)
      # middle side wall
      if @fple_map.get_data(@x_ref - i, @y_ref - 1)[0] == 0 # no wall tile
        if @fple_map.get_data(@x_ref - i, @y_ref)[0] > 0 # side wall tile (Left)
          texture_id = @fple_map.get_data(@x_ref - i, @y_ref)[
          FPLE::MAP_SIDES_LEFT[@current_dir - 1 >> 1]]
          if @fple_map.is_texture_id_valid?(texture_id)
            surfaces_temp.push([texture_id, i << 1, 1, 0, 0, 0,
            @fple_map.get_textureset_id(texture_id),
            @fple_map.get_textureset_width(texture_id), 0, 8])
          end
        end
      end
      i -= 1
    end
    return surfaces_temp
  end
  #--------------------------------------------------------------------------
  # * Recherche des surfaces visibles en déplacement latéral quand le
  # joueur est orienté vers la droite
  # return Array<Array<Integer>>
  #--------------------------------------------------------------------------
  def refresh_surfaces_right_strafe
    surfaces_temp = []
    i = $game_system.fple_view_distance
    while i > 0
      get_surface_ground(surfaces_temp, @x_ref + i, @y_ref + i + 1, i << 1,
      i + 1 << 1)
      add_surfaces_strafe(surfaces_temp, @x_ref + i,  @y_ref + i, i << 1, -1, 0)
      # middle side wall
      if @fple_map.get_data(@x_ref + i, @y_ref + 1)[0] == 0 # no wall tile
        if @fple_map.get_data(@x_ref + i, @y_ref)[0] > 0 # side wall tile (Left)
          texture_id = @fple_map.get_data(@x_ref + i, @y_ref)[
          FPLE::MAP_SIDES_LEFT[@current_dir - 1 >> 1]]
          if @fple_map.is_texture_id_valid?(texture_id)
            surfaces_temp.push([texture_id, i << 1, 1, 0, 0, 0,
            @fple_map.get_textureset_id(texture_id),
            @fple_map.get_textureset_width(texture_id), 0, 8])
          end
        end
      end
      i -= 1
    end
    return surfaces_temp
  end
  #--------------------------------------------------------------------------
  # * Recherche des surfaces visibles en déplacement latéral
  # param surfaces_temp : Array<Array<Integer>>
  # param x : Integer
  # param y : Integer
  # param dxy : Integer
  # param oy : Integer
  # param ox : Integer
  #--------------------------------------------------------------------------
  def add_surfaces_strafe(surfaces_temp, x, y, dxy, ox, oy)
    if @fple_map.get_data(x, y)[0] > 0 # wall tile
      if @fple_map.get_data(x + ox, y + oy)[0] == 0 # --> visible !
        texture_id = @fple_map.get_data(x, y)[
        FPLE::MAP_SIDES[@current_dir - 1 >> 1]]
        if @fple_map.is_texture_id_valid?(texture_id)
          surfaces_temp.push([texture_id, dxy - 1, dxy, 1, 0, 0,
          @fple_map.get_textureset_id(texture_id),
          @fple_map.get_textureset_width(texture_id), 0, 8])
        end
      end
    else
      # side wall (Right)
      if @fple_map.get_data(x + oy, y - ox)[0] > 0 # side wall tile
        texture_id = @fple_map.get_data(x + oy, y - ox)[
        FPLE::MAP_SIDES_RIGHT[@current_dir - 1 >> 1]]
        if @fple_map.is_texture_id_valid?(texture_id)
          surfaces_temp.push([texture_id, dxy, dxy + 1, 0, 0, 0,
          @fple_map.get_textureset_id(texture_id),
          @fple_map.get_textureset_width(texture_id), 0, 8])
        end
      end
    end
end
#==============================================================================
# ** Game_Character
#==============================================================================
class Game_Character < Game_CharacterBase
  #--------------------------------------------------------------------------
  # * Aliased methods (F12 compatibility)
  #--------------------------------------------------------------------------
  unless @already_aliased_fple
    alias moving_fple_game_character? moving?
    @already_aliased_fple = true
  end
  #--------------------------------------------------------------------------
  # * Determine if Moving
  # return Boolean
  #--------------------------------------------------------------------------
  def moving?
    if $game_system.fple
      return $game_temp.movement || moving_fple_game_character?
    else
      return moving_fple_game_character?
    end
  end
end
#==============================================================================
# ** Game_Player
#==============================================================================
class Game_Player < Game_Character
  #--------------------------------------------------------------------------
  # * Aliased methods (F12 compatibility) - mod [1.1]
  #--------------------------------------------------------------------------
  unless @already_aliased_fple
    alias move_straight_fple_game_player move_straight
    alias move_diagonal_fple_game_player move_diagonal
    alias turn_right_90_fple_game_player turn_right_90
    alias turn_left_90_fple_game_player turn_left_90
    alias move_by_input_fple_game_player move_by_input
    alias update_nonmoving_fple_game_player update_nonmoving
    @already_aliased_fple = true
  end
  #--------------------------------------------------------------------------
  # * Initialize Public Member Variables
  #--------------------------------------------------------------------------
  def init_public_members
    super
    @direction = 8
  end
  #--------------------------------------------------------------------------
  # * Move Straight
  # param d : Integer
  # param turn_ok : Boolean
  #--------------------------------------------------------------------------
  def move_straight(d, turn_ok = true)
    if $game_system.fple
      case d
      when 2
        case $game_player.direction
        when 2
          go_forward
        when 4
          strafe_left
        when 6
          strafe_right
        when 8
          go_backward
        end
      when 4
        case $game_player.direction
        when 2
          strafe_right
        when 4
          go_forward
        when 6
          go_backward
        when 8
          strafe_left
        end
      when 6
        case $game_player.direction
        when 2
          strafe_left
        when 4
          go_backward
        when 6
          go_forward
        when 8
          strafe_right
        end
      when 8
        case $game_player.direction
        when 2
          go_backward
        when 4
          strafe_right
        when 6
          strafe_left
        when 8
          go_forward
        end
      end
    else
      move_straight_fple_game_player(d, turn_ok)
    end
  end
  #--------------------------------------------------------------------------
  # * Move Diagonally
  # param horz : Integer
  # param vert : Integer
  #--------------------------------------------------------------------------
  def move_diagonal(horz, vert)
    unless $game_system.fple
      move_diagonal_fple_game_player(horz, vert)
    end
  end
  #--------------------------------------------------------------------------
  # * Jump
  # param x_plus : Integer
  # param y_plus : Integer
  #--------------------------------------------------------------------------
  def jump(x_plus, y_plus)
    unless $game_system.fple
      super(x_plus, y_plus) # [1.1]
    end
  end
  #--------------------------------------------------------------------------
  # * Turn 90° Right
  #--------------------------------------------------------------------------
  def turn_right_90
    turn_right_90_fple_game_player
    if $game_system.fple && !@direction_fix
      $game_temp.movement_init = false
      $game_temp.movement = true
      $game_temp.movement_dir = 9
    end
  end
  #--------------------------------------------------------------------------
  # * Turn 90° Left
  #--------------------------------------------------------------------------
  def turn_left_90
    turn_left_90_fple_game_player
    if $game_system.fple && !@direction_fix
      $game_temp.movement_init = false
      $game_temp.movement = true
      $game_temp.movement_dir = 10
    end
  end
  #--------------------------------------------------------------------------
  # * Go Forward
  #--------------------------------------------------------------------------
  def go_forward
    mvt_data = FPLE::PLAYER_MOVE_FORWARD[(@direction >> 1) - 1]
    if passable?(@x, @y, @direction)
      @x += mvt_data[0]
      @y += mvt_data[1]
      increase_steps
      $game_temp.movement = true
      $game_temp.movement_dir = 8
    else
      check_event_trigger_touch(@x + mvt_data[0], @y + mvt_data[1])
    end
  end
  #--------------------------------------------------------------------------
  # * Go Backward
  #--------------------------------------------------------------------------
  def go_backward
    target_dir = 10 - @direction
    mvt_data = FPLE::PLAYER_MOVE_FORWARD[(target_dir >> 1) - 1]
    if passable?(@x, @y, target_dir)
      @x += mvt_data[0]
      @y += mvt_data[1]
      increase_steps
      $game_temp.movement_init = false
      $game_temp.movement = true
      $game_temp.movement_dir = 2
    else
      check_event_trigger_touch(@x + mvt_data[0], @y + mvt_data[1])
    end
  end
  #--------------------------------------------------------------------------
  # * Strafe Left
  #--------------------------------------------------------------------------
  def strafe_left
    target_dir = FPLE::TURN_LEFT[(@direction >> 1) - 1]
    mvt_data = FPLE::PLAYER_MOVE_FORWARD[(target_dir >> 1) - 1]
    if passable?(@x, @y, target_dir)
      @x += mvt_data[0]
      @y += mvt_data[1]
      increase_steps
      $game_temp.movement_init = false
      $game_temp.movement = true
      $game_temp.movement_dir = 4
    else
      check_event_trigger_touch(@x + mvt_data[0], @y + mvt_data[1])
    end
  end
  #--------------------------------------------------------------------------
  # * Strafe Right
  #--------------------------------------------------------------------------
  def strafe_right
    target_dir = 10 - FPLE::TURN_LEFT[(@direction >> 1) - 1]
    mvt_data = FPLE::PLAYER_MOVE_FORWARD[(target_dir >> 1) - 1]
    if passable?(@x, @y, target_dir)
      @x += mvt_data[0]
      @y += mvt_data[1]
      increase_steps
      $game_temp.movement_init = false
      $game_temp.movement = true
      $game_temp.movement_dir = 6
    else
      check_event_trigger_touch(@x + mvt_data[0], @y + mvt_data[1])
    end
  end
  #--------------------------------------------------------------------------
  # * Processing of Movement via input from the Directional Buttons
  #--------------------------------------------------------------------------
  def move_by_input
    if $game_system.fple
      if !movable? || $game_map.interpreter.running? then return end
      if Input.press?(:L)
        strafe_left
      elsif Input.press?(:R)
        strafe_right
      else
        case Input.dir4
        when 2; go_backward
        when 4; turn_left_90
        when 6; turn_right_90
        when 8; go_forward
        end
      end
    else
      move_by_input_fple_game_player
    end
  end
  #--------------------------------------------------------------------------
  # * Processing when not moving
  # param last_moving : Boolean
  #--------------------------------------------------------------------------
  def update_nonmoving(last_moving)
    if $game_map.interpreter.running? then return end
    update_nonmoving_fple_game_player(last_moving)
    if last_moving then $game_temp.last_moving = false end
  end
  #--------------------------------------------------------------------------
  # * Move speed in FPLE mode
  # return Integer
  #--------------------------------------------------------------------------
  def move_speed_fple
    return FPLE::PLAYER_MOVE_SPEED[real_move_speed]
  end
end
#==============================================================================
# ** Game_Event
#==============================================================================
class Game_Event < Game_Character
  #--------------------------------------------------------------------------
  # * Aliased methods (F12 compatibility)
  #--------------------------------------------------------------------------
  unless @already_aliased_fple
    alias refresh_fple_game_character refresh
    @already_aliased_fple = true
  end
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_reader :fple_type # Integer 0:face the player
                         #         1:horizontal wall in the RMXP editor view
                         #         2:vertical wall in the RMXP editor view
                         #         3:4-sided box (NEW)
                         #         4:6-sided box (NEW)
  attr_reader :fple_v_align # Integer - Vertical align {0:up, 1:middle, 2:down}
  attr_reader :fple_d_align # Integer - Depth align {0:front/left, 1:middle, 2:back/right}
  attr_reader :fple_stretch # Integer (0/1)
  attr_reader :fple_fit # Integer (0/1)
  attr_reader :fple_zoom # Integer (1024 <=> zoom = 1.0)
  attr_reader :fple_one_side # Boolean (0/1)
  attr_reader :fple_two_side # Boolean - NEW: indicates 6-sided box mode
  attr_reader :fple_four_side # Boolean - NEW: indicates 4-sided box mode
  attr_reader :fple_six_side # Boolean - NEW: indicates 6-sided box mode
  #--------------------------------------------------------------------------
  # * Scan the event's commands list
  # param page : RPG::Event::Page
  #--------------------------------------------------------------------------
  def check_commands(page)
    @fple_type = 0
    @fple_v_align = 1
    @fple_d_align = 1
    @fple_stretch = 0
    @fple_fit = 0
    @fple_zoom = 1024
    @fple_one_side = false # [1.5]
    @fple_two_side = false # NEW
    @fple_four_side = false # NEW
    @fple_six_side = false # NEW
    command_list = page.list
    (0..command_list.length - 2).each {|k|
      command = command_list[k]
      if command.code == 108
        comments = command.parameters[0]
        if comments[/Type/]
          @fple_type = comments[/\d+/].to_i
          if @fple_type < 0 || @fple_type > 2 then @fple_type = 0 end
        end
        if comments[/V-Align/]
          @fple_v_align = comments[/\d+/].to_i
          if @fple_v_align < 0 || @fple_v_align > 2 then @fple_v_align = 1 end
        end
        if comments[/D-Align/]
          @fple_d_align = comments[/\d+/].to_i
          if @fple_d_align < 0 || @fple_d_align > 2 then @fple_d_align = 1 end
        end
        if comments[/Stretch/]
          @fple_stretch = 1
        end
        if comments[/Fit/]
          @fple_fit = 1
        end
        if comments[/Zoom/]
          @fple_zoom = (comments[/\d+\.\d+/].to_f * 1024).round
        end
        if comments[/1-Side/] # [1.5]
          @fple_one_side = true
        end
        if comments[/2-Side/] # NEW
          @fple_four_side = true
        end
        if comments[/4-Side/] # NEW
          @fple_four_side = true
        end
        if comments[/6-Side/] # NEW
          @fple_six_side = true
        end
      end
    }
    if @fple_type == 0 then @fple_d_align = 1 end
    if @fple_stretch == 1 then @fple_v_align = 1 end
    if @fple_two_side
    elsif @fple_four_side
      @fple_type = 3 # Special type for 4-sided boxes
      @fple_d_align = 1 # Center alignment makes most sense
    elsif @fple_six_side
      @fple_type = 4 # Special type for 6-sided boxes
      @fple_d_align = 1 # Center alignment makes most sense
    end
  end
  
  #--------------------------------------------------------------------------
  # * Refresh
  #--------------------------------------------------------------------------
  def refresh
    refresh_fple_game_character
    if @page then check_commands(@page) end
  end
end
#==============================================================================
# ** FPLE::Map_Data
#==============================================================================
module FPLE
  class Map_Data
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_accessor :data, :tileset_name, :map_name
    attr_accessor :used_tiles_map, :textureset_data, :subsets_mapping
    attr_reader :map_id, :width, :height
  end
end
#==============================================================================
# ** FPLE::Map
#==============================================================================
module FPLE
  class Map
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_accessor :data, :tileset_name, :map_name
    attr_reader :map_id, :width, :height
    attr_accessor :textureset
    attr_accessor :texturesets
    #--------------------------------------------------------------------------
    # * Initialisation
    # param width : integer (largeur de la carte, donc égal à $game_map.width)
    # param height : integer (hauteur de la carte, donc égal à $game_map.height)
    # param name : String (nom du fichier de la carte FPLE)
    # param tileset_name : String (nom du tileset utilisé)
    # param map_data : Array[width * height]<Array<integer>>
    # param subsets_mapping : Hash<Integer,String> {texture_id=>subset_name}
    # param textureset_data : Array<Array> données de création du textureset
    #--------------------------------------------------------------------------
    def initialize(width, height, name, tileset_name, map_data = nil,
      subsets_mapping = nil, textureset_data = nil)
      @width = width
      @height = height
      self.map_name = name
      self.data = Array.new(width * height)
      data.each_index {|index| data[index] = map_data[index]}
      self.tileset_name = tileset_name
      @subsets_mapping = subsets_mapping
      create_textureset_from_data(textureset_data)
    end
    #--------------------------------------------------------------------------
    # * Retourne les données d'un tile par ses coordonées
    # param x : integer ([0, width[)
    # param y : integer ([0, height[)
    # return Array[10]<integer> (map_Data)
    #--------------------------------------------------------------------------
    def get_data(x, y)
      ret = data[get_index(x, y)]
      ret = [-1] unless ret
      return ret
    end
    #--------------------------------------------------------------------------
    # * Retourne l'index d'un tile par ses coordonées
    # param x : integer ([0, width[)
    # param y : integer ([0, height[)
    # return integer (> 0)
    #--------------------------------------------------------------------------
    def get_index(x, y)
      return x + y * width
    end
    #--------------------------------------------------------------------------
    # * Retourne l'abscisse d'un tile par son index
    # return integer ([0, width[)
    #--------------------------------------------------------------------------
    def get_x(index)
      return index - width * (index / width)
    end
    #--------------------------------------------------------------------------
    # * Retourne l'ordonnée d'un tile par son index
    # return integer ([0, height[)
    #--------------------------------------------------------------------------
    def get_y(index)
      return index / width
    end
    #--------------------------------------------------------------------------
    # * Création du textureset
    # param textureset_data : Array<Array> données de création du textureset
    #--------------------------------------------------------------------------
    def create_textureset_from_data(textureset_data)
      rect = Rect.new(0, 0, 32, 32)
      textureset_height = 1 + (textureset_data.size >> 3) << 5
      self.textureset = Bitmap.new(256, textureset_height)
      src = Cache.tileset(tileset_name)
      textureset_data.each_index {|texture_id|
        t_dat = textureset_data[texture_id]
        if t_dat
          x_trg = texture_id - (texture_id >> 3 << 3) << 5
          y_trg = texture_id >> 3 << 5
          rect.x = t_dat[0]
          rect.y = t_dat[1]
          if t_dat[0] == 0 && t_dat[1] == 0
            @texture_id_nil = texture_id
          end
          textureset.blt(x_trg, y_trg, src, rect)
        end
      }
      @texturesets = [textureset]
      @texturesets_widths = [8]
      @texturesets_mapping_ids = {}
      subsets_names_list = []
      if @subsets_mapping
        @subsets_mapping.each {|texture_id, subset_name|
          if subsets_names_list.include?(subset_name)
            @texturesets_mapping_ids[texture_id] =
            subsets_names_list.index(subset_name) + 1
          else
            subsets_names_list << subset_name
            subset = Cache.tileset(subset_name)
            texturesets << subset
            for k in 5..9
              if subset.width >> k == 1
                @texturesets_widths << k
                break
              end
            end
            @texturesets_mapping_ids[texture_id] = subsets_names_list.size
          end
        }
      end
    end
    #--------------------------------------------------------------------------
    # * Retourne l'index du textureset pour une texture
    # param textureset_data : Integer
    # return Integer
    #--------------------------------------------------------------------------
    def get_textureset_id(texture_id)
      if @texturesets_mapping_ids.has_key?(texture_id)
        return @texturesets_mapping_ids[texture_id]
      else
        return 0
      end
    end
    #--------------------------------------------------------------------------
    # * Retourne la largeur du textureset pour une texture
    # param textureset_data : Integer
    # return Integer
    #--------------------------------------------------------------------------
    def get_textureset_width(texture_id)
      return @texturesets_widths[get_textureset_id(texture_id)]
    end
    #--------------------------------------------------------------------------
    # * Dispose
    #--------------------------------------------------------------------------
    def dispose
      if textureset then textureset.dispose end
    end
    #--------------------------------------------------------------------------
    # * Is texture valid
    # param texture_id : Integer
    # return Boolean
    #--------------------------------------------------------------------------
    def is_texture_id_valid?(texture_id)
      return texture_id && texture_id != @texture_id_nil
    end
  end
end
#==============================================================================
# ** Spriteset_Weather
#==============================================================================
class Spriteset_Weather
  #--------------------------------------------------------------------------
  # * Modification of sprites coordinates when moving forward and backward
  #--------------------------------------------------------------------------
  def update_fple
    @sprites.each {|sprite|
      if $game_temp.movement_dir == 8
        sprite.x += (sprite.x + @ox - 272) / 8
        sprite.y += (sprite.y + @oy - 208) / 8
        sprite.opacity += 8
      elsif $game_temp.movement_dir == 2
        sprite.x -= (sprite.x + @ox - 272) / 8
        sprite.y -= (sprite.y + @oy - 139) / 8
        sprite.opacity -= 8
      end
    }
  end
end
#==============================================================================
# ** FPLE::Spriteset_Map
#==============================================================================
module FPLE
  class Spriteset_Map < ::Spriteset_Map
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_reader :character_surfaces # Array<FPLE::Surface_Characters>
    attr_reader :viewport1 # Viewport
    #--------------------------------------------------------------------------
    # * Create Tilemap
    #--------------------------------------------------------------------------
    def create_tilemap
      # do nothing
    end
    #--------------------------------------------------------------------------
    # * Create Character Surfaces
    #--------------------------------------------------------------------------
    def create_characters
      @character_surfaces = []
      $game_map.events.values.each {|event|
        character_surfaces << FPLE::Surface_Character.new(self, event)
      }
      @map_id = $game_map.map_id
      initialize_fple_rendering
    end
    #--------------------------------------------------------------------------
    # * Create Airship Shadow Sprite
    #--------------------------------------------------------------------------
    def create_shadow
      # do nothing
    end
    #--------------------------------------------------------------------------
    # * Initialize FPLE rendering
    #--------------------------------------------------------------------------
    def initialize_fple_rendering
      FPLE.initialize_fple(self, @viewport1)
    end
    #--------------------------------------------------------------------------
    # * Dispose
    #--------------------------------------------------------------------------
    def dispose
      dispose_fple_rendering
      super
    end
    #--------------------------------------------------------------------------
    # * Dispose of FPLE rendering
    #--------------------------------------------------------------------------
    def dispose_fple_rendering
      FPLE.dispose
    end
    #--------------------------------------------------------------------------
    # * Free Tilemap
    #--------------------------------------------------------------------------
    def dispose_tilemap
      # do nothing
    end
    #--------------------------------------------------------------------------
    # * Dispose of Character Surfaces
    #--------------------------------------------------------------------------
    def dispose_characters
      @character_surfaces.each {|surface| surface.dispose}
    end
    #--------------------------------------------------------------------------
    # * Free Airship Shadow Sprite
    #--------------------------------------------------------------------------
    def dispose_shadow
      # do nothing
    end
    #--------------------------------------------------------------------------
    # * Update Tileset
    #--------------------------------------------------------------------------
    def update_tileset
      # do nothing
    end
    #--------------------------------------------------------------------------
    # * Update Tilemap
    #--------------------------------------------------------------------------
    def update_tilemap
      # do nothing
    end
    #--------------------------------------------------------------------------
    # * Update Parallax
    #--------------------------------------------------------------------------
    def update_parallax
      super
      if @parallax.bitmap
        @parallax.ox += (@parallax.bitmap.width * FPLE.angle) / 90
      end
    end
    #--------------------------------------------------------------------------
    # * Update Character Sprite
    #--------------------------------------------------------------------------
    def update_characters
      unless @map_id == $game_map.map_id then refresh_characters end
      character_surfaces.each {|surface| surface.update}
      update_fple_rendering
    end
    #--------------------------------------------------------------------------
    # * Update FPLE Rendering
    #--------------------------------------------------------------------------
    def update_fple_rendering
      FPLE.update
    end
    #--------------------------------------------------------------------------
    # * Update Airship Shadow Sprite
    #--------------------------------------------------------------------------
    def update_shadow
      # do nothing
    end
    #--------------------------------------------------------------------------
    # * Update Weather
    #--------------------------------------------------------------------------
    def update_weather
      @weather.type = $game_map.screen.weather_type
      @weather.power = $game_map.screen.weather_power
      @weather.ox = $game_map.display_x * 32 +
      (Graphics.width * FPLE.angle) / 90 +
      (Graphics.width * FPLE.offset_x >> 5)
      @weather.oy = $game_map.display_y * 32
      @weather.update
      if FPLE.offset_y > 0 then @weather.update_fple end
    end
  end
end
#==============================================================================
# ** FPLE::Surface_Character
#==============================================================================
module FPLE
  class Surface_Character
    #--------------------------------------------------------------------------
    # * Public Instance Variables
    #--------------------------------------------------------------------------
    attr_accessor :character # Game_Event
    attr_accessor :bitmap_set # Bitmap
    attr_accessor :bitmap # Bitmap
    attr_accessor :visible # Boolean
    attr_accessor :opacity # Integer
    attr_accessor :blend_type # Integer
    attr_accessor :dx # Integer
    attr_accessor :dy # Integer
    attr_accessor :displayed # Boolean
    attr_reader :spriteset # FPLE::Spriteset_Map
    attr_reader :type # Integer
    attr_reader :v_align # Integer
    attr_reader :d_align # Integer
    attr_reader :fit # Integer (0/1)
    attr_reader :zoom # Integer (1024 <=> zoom = 1.0)
    attr_reader :mirror # Integer (0/1) # [1.5]
    #--------------------------------------------------------------------------
    # * Object Initialization
    # param spriteset : FPLE::Spriteset_Map
    # param character : Game_Event
    #--------------------------------------------------------------------------
    def initialize(spriteset, character = nil)
      @spriteset = spriteset
      self.character = character
      self.displayed = false
      @need_refresh = false
      @dx_old = 0
      @dy_old = 0
      @sx_old = -1
      @sy_old = -1
      @visible_old
      @opacity_old
      @blend_type_old
      @sprite_temp = nil
      @balloon_duration = 0
      if character
        @fit = character.fple_fit
        @zoom = character.fple_zoom
      else
        @fit = 0
        @zoom = 1024
      end
      @mirror = 0 # [1.5]
      update
    end
    #--------------------------------------------------------------------------
    # * Dispose
    #--------------------------------------------------------------------------
    def dispose
      if @sprite_temp
        @sprite_temp.dispose
        @sprite_temp = nil
      end
      if bitmap_set then self.bitmap_set.dispose end
      if bitmap then self.bitmap.dispose end
    end
    #--------------------------------------------------------------------------
    # * Get tile set image that includes the designated tile
    # param tile_id : Integer
    #--------------------------------------------------------------------------
    def tileset_bitmap(tile_id)
      set_number = tile_id / 256
      return Cache.system("TileB") if set_number == 0
      return Cache.system("TileC") if set_number == 1
      return Cache.system("TileD") if set_number == 2
      return Cache.system("TileE") if set_number == 3
      return nil
    end
    #--------------------------------------------------------------------------
    # * Frame Update
    #--------------------------------------------------------------------------
    def update
      update_bitmap
      update_src_rect
      update_position
      update_other
      update_balloon
      setup_new_effect
      if need_refresh? then force_render end
    end
    #--------------------------------------------------------------------------
    # * Update Transfer Origin Bitmap
    #--------------------------------------------------------------------------
    def update_bitmap
      if graphic_changed?
        @tile_id = @character.tile_id
        @character_name = @character.character_name
        @character_index = @character.character_index
        if @tile_id > 0
          set_tile_bitmap
        else
          set_character_bitmap
        end
        @need_refresh = true
      end
    end
    #--------------------------------------------------------------------------
    # * Determine if Graphic Changed
    #--------------------------------------------------------------------------
    def graphic_changed?
      @tile_id != character.tile_id ||
      @character_name != character.character_name ||
      @character_index != character.character_index
    end
    #--------------------------------------------------------------------------
    # * Set Tile Bitmap
    #--------------------------------------------------------------------------
    def set_tile_bitmap
      @sx = (@tile_id / 128 % 2 * 8 + @tile_id % 8) * 32;
      @sy = @tile_id % 256 / 8 % 16 * 32;
      self.bitmap_set = tileset_bitmap(@tile_id)
      @cw = 32
      @ch = 32
      self.bitmap = Bitmap.new(@cw, @ch)
    end
    #--------------------------------------------------------------------------
    # * Set Character Bitmap
    #--------------------------------------------------------------------------
    def set_character_bitmap
      self.bitmap_set = Cache.character(@character_name)
      sign = @character_name[/^[\!\$]./]
      if sign && sign.include?('$')
        @cw = bitmap_set.width / 3
        @ch = bitmap_set.height / 4
      else
        @cw = bitmap_set.width / 12
        @ch = bitmap_set.height / 8
      end
      self.bitmap = Bitmap.new(@cw, @ch)
    end
    #--------------------------------------------------------------------------
    # * Update Transfer Origin Rectangle
    #--------------------------------------------------------------------------
    def update_src_rect
      if @tile_id == 0
        index = character.character_index
        pattern = character.pattern < 3 ? character.pattern : 1
        @sx = (index % 4 * 3 + pattern) * @cw
        unless character.direction_fix
          case $game_player.direction
          when 2
            direction = 10 - character.direction
          when 4
            direction = 10 - FPLE::TURN_LEFT[(character.direction >> 1) - 1]
          when 6
            direction = FPLE::TURN_LEFT[(character.direction >> 1) - 1]
          when 8
            direction = character.direction
          end
        else
          direction = character.direction
        end
        @sy = ((index >> 2 << 2) + (direction - 2 >> 1)) * @ch
      end
      if @sx_old != @sx || @sy_old != @sy
        return if @sx == @sx_old && @sy == @sy_old && !@bitmap_dirty
        self.bitmap.clear
        self.bitmap.blt(0, 0, bitmap_set, Rect.new(@sx, @sy, @cw, @ch))
         @sx_old = @sx
    @sy_old = @sy
    @bitmap_dirty = false
      end
    end
    #--------------------------------------------------------------------------
    # * Update Position
    #--------------------------------------------------------------------------
    def update_position
      self.dx = (128 * character.real_x).to_i
      self.dy = (128 * character.real_y).to_i
    end
    #--------------------------------------------------------------------------
    # * Update Other
    #--------------------------------------------------------------------------
    def update_other
      self.opacity = character.opacity
      self.blend_type = character.blend_type
      self.visible = !character.transparent
    end
    #--------------------------------------------------------------------------
    # * Set New Effect
    #--------------------------------------------------------------------------
    def setup_new_effect
      if character.animation_id > 0
        if displayed
          unless @sprite_temp
            # create a temporary sprite to launch animation
            @sprite_temp = Sprite_Base.new(spriteset.viewport1)
          end
          coordinates = find_coordinates
          if coordinates
            @sprite_temp.x = coordinates[0]
            @sprite_temp.y = coordinates[1]
            animation = $data_animations[character.animation_id]
            @sprite_temp.start_animation(animation)
          else
            @sprite_temp.dispose
            @sprite_temp = nil
          end
        end
        character.animation_id = 0
      end
      if @sprite_temp
        @sprite_temp.update
        unless @sprite_temp.animation?
          @sprite_temp.dispose
          @sprite_temp = nil
        end
      end
      if !@balloon_sprite && character.balloon_id != 0
        @balloon_id = character.balloon_id
        start_balloon
      end
    end
    #--------------------------------------------------------------------------
    # * Determine if Changed
    #--------------------------------------------------------------------------
    def need_refresh?
      @need_refresh || @dx_old != dx || @dy_old != dy ||
      @sx_old != @sx || @sy_old != @sy ||
      @visible_old != visible || @opacity_old != opacity ||
      @blend_type_old != blend_type
    end
    #--------------------------------------------------------------------------
    # * Force Render
    #--------------------------------------------------------------------------
    def force_render
      if displayed then $game_temp.force_render = true end
      @dx_old = dx
      @dy_old = dy
      @sx_old = @sx
      @sy_old = @sy
      @visible_old = visible
      @opacity_old = opacity
      @blend_type_old = blend_type
      @need_refresh = false
    end
    #--------------------------------------------------------------------------
    # * Refresh FPLE attributes sepending on the relative frame of reference
    # param direction : Integer
    #--------------------------------------------------------------------------
def set_relative_attributes(direction)
      # For 4-sided and 6-sided surfaces, we don't need to change attributes
      # since all sides are rendered automatically
      if character.fple_four_side
        @type = 3 # Special identifier for 4-sided
        @d_align = character.fple_d_align
        @v_align = character.fple_v_align
        @mirror = 0 # Could add logic for different mirror states per side if needed
        return
      elsif character.fple_six_side
        @type = 4 # Special identifier for 6-sided
        @d_align = character.fple_d_align
        @v_align = character.fple_v_align
        @mirror = 0 # Could add logic for different mirror states per side if needed
        return
      end
      # Original logic for single surfaces
      case direction
      when 2
        @type = character.fple_type
        @d_align = 2 - character.fple_d_align
        if character.fple_one_side
          @mirror = 1
          if type == 2 && ($game_player.x << 7) - dx <= 0
            @mirror = 0
          end
        end
      when 4
        if character.fple_type > 0
          @type = 3 - character.fple_type
        else
          @type = 0
        end
        if character.fple_type < 2
          @d_align = character.fple_d_align
        elsif character.fple_type == 2
          @d_align = 2 - character.fple_d_align
        end
        if character.fple_one_side
          @mirror = 1
          if type == 2 && ($game_player.y << 7) - dy > 0
            @mirror = 0
          end
        end
      when 6
        if character.fple_type > 0
          @type = 3 - character.fple_type
        else
          @type = 0
        end
        if character.fple_type < 2
          @d_align = 2 - character.fple_d_align
        elsif character.fple_type == 2
          @d_align = character.fple_d_align
        end
        if character.fple_one_side
          @mirror = 0
          if type == 2 && ($game_player.y << 7) - dy < 0
            @mirror = 1
          end
        end
      when 8
        @type = character.fple_type
        @d_align = character.fple_d_align
        if character.fple_one_side
          @mirror = 0
          if type == 2 && ($game_player.x << 7) - dx >= 0
            @mirror = 1
          end
        end
      end
      @v_align = character.fple_v_align
    end
    #--------------------------------------------------------------------------
    # * Calculate screen coordinates to display animations
    # return Array[2]<Integer>
    #--------------------------------------------------------------------------
  def find_coordinates
      direction = $game_player.direction
      case direction
      when 2
        y = dy - ($game_player.y << 7)
        x = ($game_player.x << 7) - dx
      when 4
        y = ($game_player.x << 7) - dx
        x = ($game_player.y << 7) - dy
      when 6
        y = dx - ($game_player.x << 7)
        x = dy - ($game_player.y << 7)
      when 8
        y = ($game_player.y << 7) - dy
        x = dx - ($game_player.x << 7)
      end
      if y == 0 then return nil end
      offset_x = 0
      offset_y = 0
      if character.fple_v_align != 1
        x1_proj = 272 + (272 * x - (136 << 7)) / y
        x2_proj = 272 + (272 * x + (136 << 7)) / y
        offset_x = x2_proj - x1_proj >> 1
        offset_y = offset_x
        if bitmap
          offset_x -= (bitmap.width >> 1)
          offset_y -= (bitmap.height >> 1)
        end
      end
      x_proj = 272 + (272 * x) / y
      y_proj = ((544 * y) - (272 << 7)) / (y << 1)
      if character.fple_v_align == 0
        y_proj -= offset_y
      elsif character.fple_v_align == 2
        y_proj += offset_y
      end
      return [x_proj, y_proj]
    end
    #--------------------------------------------------------------------------
    # * Start Balloon Icon Display
    #--------------------------------------------------------------------------
    def start_balloon
      dispose_balloon
      @balloon_duration = 8 * balloon_speed + balloon_wait
      @balloon_sprite = ::Sprite.new(spriteset.viewport1)
      @balloon_sprite.bitmap = Cache.system("Balloon")
      @balloon_sprite.ox = -16
      @balloon_sprite.oy = +128
      update_balloon
    end
    #--------------------------------------------------------------------------
    # * Dispose of Balloon Icon
    #--------------------------------------------------------------------------
    def dispose_balloon
      if @balloon_sprite
        @balloon_sprite.dispose
        @balloon_sprite = nil
      end
    end
    #--------------------------------------------------------------------------
    # * Update Balloon Icon
    #--------------------------------------------------------------------------
    def update_balloon
      if @balloon_duration > 0
        @balloon_duration -= 1
        if @balloon_duration > 0
          coordinates = find_coordinates
          if coordinates
            @balloon_sprite.x = coordinates[0]
            @balloon_sprite.y = coordinates[1]
            @balloon_sprite.z = 9999
            sx = balloon_frame_index * 32
            sy = (@balloon_id - 1) * 32
            @balloon_sprite.src_rect.set(sx, sy, 32, 32)
          else
            end_balloon
          end
        else
          end_balloon
        end
      end
    end
    #--------------------------------------------------------------------------
    # * End Balloon Icon
    #--------------------------------------------------------------------------
    def end_balloon
      dispose_balloon
      character.balloon_id = 0
    end
    #--------------------------------------------------------------------------
    # * Balloon Icon Display Speed
    #--------------------------------------------------------------------------
    def balloon_speed
      return 8
    end
    #--------------------------------------------------------------------------
    # * Wait Time for Last Frame of Balloon
    #--------------------------------------------------------------------------
    def balloon_wait
      return 12
    end
    #--------------------------------------------------------------------------
    # * Frame Number of Balloon Icon
    #--------------------------------------------------------------------------
    def balloon_frame_index
      return 7 - [(@balloon_duration - balloon_wait) / balloon_speed, 0].max
    end
  end
end
 
#==============================================================================
# ** Scene_Map
#==============================================================================
class Scene_Map < Scene_Base
  #--------------------------------------------------------------------------
  # * Aliased methods (F12 compatibility)
  #--------------------------------------------------------------------------
  unless @already_aliased_fple
    alias create_spriteset_fple create_spriteset
    alias perform_transfer_fple perform_transfer
    alias post_transfer_fple post_transfer
    @already_aliased_fple = true
  end
  #--------------------------------------------------------------------------
  # * Create Sprite Set
  #--------------------------------------------------------------------------
  def create_spriteset
    if $game_system.fple
      @spriteset = FPLE::Spriteset_Map.new
    else
      create_spriteset_fple
    end
  end
  #--------------------------------------------------------------------------
  # * Player Transfer Processing
  #--------------------------------------------------------------------------
  def perform_transfer
    @exec_transfer = $game_player.transfer?
    @fple_old = $game_system.fple
    perform_transfer_fple
  end
  #--------------------------------------------------------------------------
  # * Post Processing for Transferring Player
  #--------------------------------------------------------------------------
  def post_transfer
    if @exec_transfer && @fple_old != $game_system.fple
      @spriteset.dispose
      create_spriteset
    end
    if $game_system.fple
      $game_temp.force_render = true
    end
    post_transfer_fple
  end
end
Reply
#69
I've not figured out a way to make events not clip through walls when rotating, it seems to be a bug from the [VXA]FPLE_Ace_1_5 build.

https://forums.rpgmakerweb.com/index.php...217/page-3

If does anyone know how to fix that, & the the rotation bleeding thru the background.
Or would that be a dll engine limitation issue, that I'll have to figure out a fix for.

Oops the above code has an private refresh call without the background addon.
Code:
#==============================================================================
# ** FPLE Background Picture Addon - Enhanced
#==============================================================================
# This addon creates a background picture that renders behind all FPLE surfaces
# but in front of the engine's default background to prevent color bleeding.
# The background now positions itself at VIEW_DISTANCE + 1 for proper depth.
#==============================================================================

module FPLE
  #--------------------------------------------------------------------------
  # * Background Picture Configuration
  #--------------------------------------------------------------------------
  BACKGROUND_ENABLED = true      # Enable/disable background picture
  BACKGROUND_COLOR = Color.new(115, 181, 212, 255)  # Default color (R,G,B,A)
  BACKGROUND_PICTURE_FILE = nil   # Optional: use "filename" for custom image
  BACKGROUND_Z_DEPTH = -500    # Z-depth (negative = behind everything)
end

#==============================================================================
# ** FPLE Core - Modified
#==============================================================================
module FPLE
  #--------------------------------------------------------------------------
  # * Aliased initialization method
  #--------------------------------------------------------------------------
  class << self
    unless @background_addon_aliased
      alias initialize_fple_background initialize_fple
      @background_addon_aliased = true
    end
  end
 
  #--------------------------------------------------------------------------
  # * Initialize with background
  #--------------------------------------------------------------------------
  def self.initialize_fple(spriteset, viewport)
    initialize_fple_background(spriteset, viewport)
    if BACKGROUND_ENABLED
      create_background_picture(viewport)
    end
  end
 
  #--------------------------------------------------------------------------
  # * Create background picture with view distance integration
  #--------------------------------------------------------------------------
  def self.create_background_picture(viewport)
    @background_sprite = Sprite.new(viewport)
    @background_sprite.z = BACKGROUND_Z_DEPTH
   
    if BACKGROUND_PICTURE_FILE && FileTest.exist?("Graphics/Pictures/#{BACKGROUND_PICTURE_FILE}.png")
      # Use custom image file
      @background_sprite.bitmap = Cache.picture(BACKGROUND_PICTURE_FILE)
    else
      # Create solid color background
      @background_sprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
      @background_sprite.bitmap.fill_rect(0, 0, Graphics.width, Graphics.height, BACKGROUND_COLOR)
    end
   
    # Position behind everything but visible
    @background_sprite.x = 0
    @background_sprite.y = 0
   
    # Add background surface to the surfaces array for proper depth rendering
    create_background_surface
  end
 
  #--------------------------------------------------------------------------
  # * Create background surface at VIEW_DISTANCE + 1
  #--------------------------------------------------------------------------
  def self.create_background_surface
    # Calculate the distance to render the background at (VIEW_DISTANCE + 1)
    background_distance = ($game_system.fple_view_distance + 1) << 7
   
    # Create a background surface that will be processed by the 3D engine
    @background_surface = [
      0,                          # texture_id (0 = no texture, use solid color)
      background_distance,        # dy (depth distance)
      0,                          # dx (horizontal offset)
      6,                          # type (6 = background plane, custom type)
      0,                          # secondary texture
      0,                          # z-order placeholder
      0,                          # textureset_id
      8,                          # textureset_width
      BACKGROUND_COLOR.red,       # red component
      BACKGROUND_COLOR.green,     # green component
      BACKGROUND_COLOR.blue,      # blue component
      BACKGROUND_COLOR.alpha      # alpha component
    ]
  end
 
  #--------------------------------------------------------------------------
  # * Add background surface to game map surfaces
  #--------------------------------------------------------------------------
  def self.add_background_to_surfaces
    return unless BACKGROUND_ENABLED && @background_surface
   
    # Calculate proper z-depth for background
    distance = ($game_system.fple_view_distance) << 1
    @background_surface[5] = distance << 5  # Set z-order
   
    # Add background surface to the main surfaces array if not already present
    unless $game_map.surfaces.any? { |surface| surface[3] == 6 }
      $game_map.surfaces.push(@background_surface.dup)
    end
  end
 
  #--------------------------------------------------------------------------
  # * Aliased dispose method
  #--------------------------------------------------------------------------
  class << self
    unless @dispose_background_aliased
      alias dispose_background dispose
      @dispose_background_aliased = true
    end
  end
 
  #--------------------------------------------------------------------------
  # * Dispose with background cleanup
  #--------------------------------------------------------------------------
  def self.dispose
    dispose_background
    if @background_sprite
      @background_sprite.dispose
      @background_sprite = nil
    end
    @background_surface = nil
  end
 
  #--------------------------------------------------------------------------
  # * Update background (called during movement/rotation)
  #--------------------------------------------------------------------------
  def self.update_background
    return unless @background_surface && BACKGROUND_ENABLED
   
    # Update the background distance based on current view distance
    background_distance = ($game_system.fple_view_distance) << 7
    @background_surface[1] = background_distance
   
    # Update z-order
    distance = ($game_system.fple_view_distance) << 1
    @background_surface[5] = distance << 5
   
    # Add parallax effects if desired
    if @angle != 0
      # Slight horizontal shift based on rotation
      @background_surface[2] = (@angle * 2)  # Adjust multiplier as needed
    else
      @background_surface[2] = 0
    end
   
    # Adjust for movement offsets if desired (subtle parallax)
    # @background_surface[2] += @offset_x / 8
  end
 
  #--------------------------------------------------------------------------
  # * Aliased update method
  #--------------------------------------------------------------------------
  class << self
    unless @update_background_aliased
      alias update_fple_background update
      @update_background_aliased = true
    end
  end
 
  #--------------------------------------------------------------------------
  # * Update with background
  #--------------------------------------------------------------------------
  def self.update
    update_fple_background
    if BACKGROUND_ENABLED
      update_background
      add_background_to_surfaces
    end
  end
end

#==============================================================================
# ** Game_Map - Background Integration
#==============================================================================
class Game_Map
  #--------------------------------------------------------------------------
  # * Aliased refresh_surfaces method
  #--------------------------------------------------------------------------
  unless @background_surfaces_aliased
    alias refresh_surfaces_background refresh_surfaces
    @background_surfaces_aliased = true
  end
 
  #--------------------------------------------------------------------------
  # * Refresh surfaces with background integration
  #--------------------------------------------------------------------------
  def refresh_surfaces
    refresh_surfaces_background
   
    # Ensure background is included if enabled
    if $game_system.fple && FPLE::BACKGROUND_ENABLED
      FPLE.add_background_to_surfaces
     
      # Re-sort surfaces to ensure proper rendering order
      surfaces.sort! { |a, b| b[5] - a[5] } if surfaces.any? { |s| s[3] == 6 }
    end
  end
end

#==============================================================================
# ** Game_Interpreter - Script Commands
#==============================================================================
class Game_Interpreter
  #--------------------------------------------------------------------------
  # * Change FPLE Background Color
  #--------------------------------------------------------------------------
  def change_fple_background_color(red, green, blue, alpha = 255)
    return unless $game_system.fple && FPLE::BACKGROUND_ENABLED
   
    # Update the background surface color
    if FPLE.instance_variable_get(:@background_surface)
      surface = FPLE.instance_variable_get(:@background_surface)
      surface[8] = red
      surface[9] = green
      surface[10] = blue
      surface[11] = alpha
    end
   
    # Also update the sprite for immediate visual feedback
    if FPLE.instance_variable_get(:@background_sprite)
      sprite = FPLE.instance_variable_get(:@background_sprite)
      color = Color.new(red, green, blue, alpha)
      sprite.bitmap.fill_rect(0, 0, Graphics.width, Graphics.height, color)
    end
   
    $game_temp.force_render = true
  end
 
  #--------------------------------------------------------------------------
  # * Change FPLE Background Picture
  #--------------------------------------------------------------------------
  def change_fple_background_picture(filename)
    return unless $game_system.fple && FPLE::BACKGROUND_ENABLED
   
    if FPLE.instance_variable_get(:@background_sprite)
      sprite = FPLE.instance_variable_get(:@background_sprite)
      sprite.bitmap.dispose if sprite.bitmap
     
      if filename && FileTest.exist?("Graphics/Pictures/#{filename}.png")
        sprite.bitmap = Cache.picture(filename)
        # When using a picture, set surface type to use texture instead of color
        if FPLE.instance_variable_get(:@background_surface)
          surface = FPLE.instance_variable_get(:@background_surface)
          surface[0] = 1  # Enable texture rendering
        end
      else
        # Fallback to solid color
        sprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
        sprite.bitmap.fill_rect(0, 0, Graphics.width, Graphics.height, FPLE::BACKGROUND_COLOR)
        # Reset to color mode
        if FPLE.instance_variable_get(:@background_surface)
          surface = FPLE.instance_variable_get(:@background_surface)
          surface[0] = 0  # Disable texture, use color
        end
      end
    end
   
    $game_temp.force_render = true
  end
 
  #--------------------------------------------------------------------------
  # * Toggle FPLE Background
  #--------------------------------------------------------------------------
  def toggle_fple_background(enabled)
    return unless $game_system.fple
   
    if FPLE.instance_variable_get(:@background_sprite)
      sprite = FPLE.instance_variable_get(:@background_sprite)
      sprite.visible = enabled
    end
   
    # Remove or add background surface based on enabled state
    if enabled
      FPLE.add_background_to_surfaces
    else
      $game_map.surfaces.reject! { |surface| surface[3] == 6 }
    end
   
    $game_temp.force_render = true
  end
 
  #--------------------------------------------------------------------------
  # * Update Background Distance (call when VIEW_DISTANCE changes)
  #--------------------------------------------------------------------------
  def update_background_distance
    return unless $game_system.fple && FPLE::BACKGROUND_ENABLED
   
    if FPLE.instance_variable_get(:@background_surface)
      FPLE.update_background
      $game_temp.force_render = true
    end
  end
end

#==============================================================================
# ** Game_Temp - Background Integration
#==============================================================================
class Game_Temp
  #--------------------------------------------------------------------------
  # * Aliased set_view method to update background distance
  #--------------------------------------------------------------------------
  unless @background_view_aliased
    alias set_view_background set_view
    @background_view_aliased = true
  end
 
  #--------------------------------------------------------------------------
  # * Set view distance with background update
  #--------------------------------------------------------------------------
  def set_view(distance)
    set_view_background(distance)
   
    # Update background distance when view distance changes
    if $game_system.fple && FPLE::BACKGROUND_ENABLED
      FPLE.update_background
    end
  end
end

#==============================================================================
# ** Usage Instructions
#==============================================================================
# Place this script below the main FPLE script but above Main.
#
# Configuration:
# - BACKGROUND_ENABLED: Set to true/false to enable/disable
# - BACKGROUND_COLOR: Set the RGB color (0-255 for each value) 
# - BACKGROUND_PICTURE_FILE: Optional - use a picture file instead of solid color
# - BACKGROUND_Z_DEPTH: Z-depth value (negative = behind surfaces)
#
# The background will automatically render at VIEW_DISTANCE + 1, providing
# a backdrop that appears behind all game surfaces but maintains proper depth.
#
# Script Commands (use in events):
# - change_fple_background_color(255, 0, 0)    # Change to red
# - change_fple_background_picture("sunset")   # Use Graphics/Pictures/sunset.png 
# - toggle_fple_background(false)              # Hide background
# - toggle_fple_background(true)               # Show background
# - update_background_distance                 # Refresh after VIEW_DISTANCE changes
#==============================================================================
Reply
#70
Sadly, MGC never posted any VX or VXAce editions of FPLE within Save-Point. And as an XP user, I have no idea how to go about that.
Up is down, left is right and sideways is straight ahead. - Cord "Circle of Iron", 1978 (written by Bruce Lee and James Coburn... really...)

[Image: QrnbKlx.jpg]
[Image: sGz1ErF.png]    [Image: liM4ikn.png]    [Image: fdzKgZA.png]    [Image: sj0H81z.png]
[Image: QL7oRau.png]    [Image: uSqjY09.png]    [Image: GAA3qE9.png]    [Image: 2Hmnx1G.png]    [Image: BwtNdKw.png%5B]
  Above are clickable links
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
   FPLE Camera Height DerVVulfman 23 41,403 07-20-2020, 01:41 AM
Last Post: rzrcoon
   [WIP] FPLE 2 MGC 17 50,407 01-08-2018, 04:06 AM
Last Post: Darkantuan
   L's Simple Main Menu #3 - 1-person Landarma 1 9,127 10-14-2010, 04:25 AM
Last Post: Landarma
   1-Person DBS Raziel 0 7,664 03-07-2008, 04:41 AM
Last Post: Raziel



Users browsing this thread: