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.
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