Posts: 1
Threads: 0
Joined: Jan 2014
Amazing script!!! ^_ ^ Can be used in commercial projects?
Posts: 49
Threads: 2
Joined: Jun 2011
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 ?
Posts: 713
Threads: 130
Joined: Nov 2011
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.
BLOG: JayVinci.blogspot.com
FORUM COMING SOON
Currently working on:
Ambitions: RPG Developer Bakin
Heart of Vox: RPG Developer Bakin
Posts: 4
Threads: 0
Joined: Jan 2016
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.
Posts: 12,607
Threads: 1,776
Joined: May 2009
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...)
Above are clickable links
Posts: 713
Threads: 130
Joined: Nov 2011
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.)
BLOG: JayVinci.blogspot.com
FORUM COMING SOON
Currently working on:
Ambitions: RPG Developer Bakin
Heart of Vox: RPG Developer Bakin
Posts: 12,607
Threads: 1,776
Joined: May 2009
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...)
Above are clickable links
Posts: 4
Threads: 1
Joined: Aug 2025
09-03-2025, 09:04 PM
(This post was last modified: 09-03-2025, 09:21 PM by 5Brainplay.)
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
Posts: 4
Threads: 1
Joined: Aug 2025
09-03-2025, 10:11 PM
(This post was last modified: 09-03-2025, 11:33 PM by 5Brainplay.)
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
#==============================================================================
Posts: 12,607
Threads: 1,776
Joined: May 2009
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...)
Above are clickable links
|