#==============================================================================
# ** Sprite Shadow (Sprite_Ombre )
#------------------------------------------------------------------------------
# Based on Genzai Kawakami's shadows
# dynamisme & features by Rataime
# extra features Boushy
# New Edits by DerVVulfman
# Modified for VX by Syvkal
# Fixes by Painhurt
# October 14, 2008
#
#------------------------------------------------------------------------------
#
# Introduction:
#
# This system allows you and all 'prepared' events to generate shadows while
# on the field map. The player can move around a 'light source' event and
# display a shadow. Likewise, events with a special comment within their
# event list can also generate shadows.
#
#------------------------------------------------------------------------------
#
# Instructions:
#
# -- The Light Source
# To create a light source, you need to create a map event that is to be
# used 'as' the light source. Most of the time, these could be events
# that sport 'torch' or 'lantern' charactersets. Just examples
#
# To make one of these events a light source, you need to insert a few
# things into that event's "List of Event Commands". These things are
# nothing more than comments.
#
# The first comment to add is "begin Shadow Source" (without quotes). It
# informs the system that this event is a light source. The remaining
# three values are optional and have default values in the configuration
# section (only just added into the script). They too are added as
# comments.
#
# anglemin 'number' --- Starting position of a lightsource's arc.
# anglemax 'number' --- Ending position of a lightsource's arc.
# distancemax 'number' --- How far away from the 'source' you can go
# self_opacity 'number' --- How dark the shadow will grow.
#
# After that, your characters can now move about and generate shadows.
#
# -- Other Events
# Events do not know that they can generate shadows. To let them gene-
# rate a shadow, all you need to do is add a special comment into their
# "List of Event Commands". This comment needed is merely the phrase
# 'begin Shadow' (again, without quotes).
#
#
# -- Blocking Shadows
# To prevent shadows from passing through solid objects such as doors,
# walls, cabinets or other forms of furniture, you will want to apply a
# priority flag of '1' or higher on these items. Normally, walls in the
# default database do not have a priority flag as they merely block the
# player from passing through.
#
#
#------------------------------------------------------------------------------
#
# Revisions to note:
#
# 1) Added formatted headers and comments throughout the script.
# 2) Encapsulated a comment/parameter code in an XPML module.
# 3) Set the shadow array into an instance value to lower resource costs.
# 4) Compatability with Near Fantastica's Squad Movement systems.
# 5) Compatability with Ccoa's Caterpillar system.
# 6) Compatability with Trickster's Caterpillar system.
# 7) Added default shadow settings into the configuration section.
#
#==============================================================================
#========================================================================
# ** C O N F I G U R A T I O N S Y S T E M ** #
#========================================================================
# Caterpillar Systems
CATERPILLAR_COMPATIBLE = true # Toggle for Fukuyama's original
SQUAD_MOVE_COMPATIBLE = false # Toggle for Near Fantastica's SBABS
CCOA_CATER_COMPATIBLE = false # Toggle for Ccoa's Caterpillar
TRICKSTER_CATER_COMPATIBLE = false # Toggle for Trickster's Caterpillar
# Shadow Specific Systems
SHADOW_WARN = true # Checks for older shadow system
SHADOW_MIN = 0 # Start setting of shadow arc *
SHADOW_MAX = 0 # Ending setting of shadow arc *
SHADOW_OPACITY = 150 # Darkness level of shadow
SHADOW_DISTANCE = 350 # Maximum range in pixels
# * SHADOW ARC: Set in degrees, this controls whether a light source
# can 'force' shadows in certain directions. Useful if
# a light source is hanging on a wall so it cannot make
# a shadow THROUGH a wall.
#
# It may take some practice to set the desired angles
# as it recognizes 90° being the top most part of an
# arc, 180° being the leftmost side and so on... pro-
# ceeding in a counter-clockwise motion.
#========================================================================
# **** E N D O F C O N F I G U R A T I O N S Y S T E M **** #
#========================================================================
#==============================================================================
# ** Game_Temp
#------------------------------------------------------------------------------
# This class handles temporary data that is not included with save data.
# Refer to "$game_temp" for the instance of this class.
#==============================================================================
class Game_Temp
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :shadow_spriteset # holds shadow spritesets
end
#==============================================================================
# ** Game_Party
#------------------------------------------------------------------------------
# This class handles the party. It includes information on amount of gold
# and items. Refer to "$game_party" for the instance of this class.
#==============================================================================
class Game_Party
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_reader :characters
end
#==============================================================================
# ** Sprite_Shadow
#------------------------------------------------------------------------------
# This sprite is used to display the character's shadow. It observes the
# Game_Character class and automatically changes sprite conditions.
#==============================================================================
class Sprite_Shadow < Sprite_Base
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :character
#--------------------------------------------------------------------------
# * Object Initialization
# viewport : viewport
# character : character (Game_Character)
# id : id
#--------------------------------------------------------------------------
def initialize(viewport, character = nil, id = 0)
super(viewport)
params = $game_temp.shadow_spriteset.shadows[id]
@source = params[0]
# Default settings
@anglemin = SHADOW_MIN
@anglemax = SHADOW_MAX
@self_opacity = SHADOW_OPACITY
@distancemax = SHADOW_DISTANCE
# Settings changed by parameters
@anglemin = params[1] if params.size > 1
@anglemax = params[2] if params.size > 2
@distancemax = params[3] if params.size > 3
@self_opacity = params[4] if params.size > 4
@character = character
update
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
# If shadow not in range of light source
if !in_range?(@character, @source, @distancemax)
self.opacity = 0
return
end
super
# If tile ID, file name, or hue are different from current ones
if @tile_id != @character.tile_id or
@character_name != @character.character_name or
@character_index != @character.character_index
@tile_id = @character.tile_id
@character_name = @character.character_name
@character_index = @character.character_index
if @tile_id > 0
sx = (@tile_id / 128 % 2 * 8 + @tile_id % 8) * 32;
sy = @tile_id % 256 / 8 % 16 * 32;
set_number = @tile_id / 256
self.bitmap = Cache.system("TileB") if set_number == 0
self.bitmap = Cache.system("TileC") if set_number == 1
self.bitmap = Cache.system("TileD") if set_number == 2
self.bitmap = Cache.system("TileE") if set_number == 3
self.src_rect.set(sx, sy, 32, 32)
self.ox = 16
self.oy = 32
else
self.bitmap = Cache.character(@character_name)
sign = @character_name[/^[\!\$]./]
if sign != nil and sign.include?('$')
@cw = bitmap.width / 3
@ch = bitmap.height / 4
else
@cw = bitmap.width / 12
@ch = bitmap.height / 8
end
self.ox = @cw / 2
self.oy = @ch
end
end
# Set visible situation
self.visible = (not @character.transparent)
# If graphic is character
if @tile_id == 0
index = @character.character_index
pattern = @character.pattern < 3 ? @character.pattern : 1
# Set rectangular transfer
sx = (index % 4 * 3 + pattern) * @cw
sy = (index / 4 * 4 + (@character.direction - 2) / 2) * @ch
if self.angle > 90 or angle < -90
sy = ( 4 - 2) / 2 * @ch if @character.direction == 6
sy = ( 6 - 2) / 2 * @ch if @character.direction == 4
sy = ( 8 - 2) / 2 * @ch if @character.direction == 2
sy = ( 2 - 2) / 2 * @ch if @character.direction == 8
end
self.src_rect.set(sx, sy, @cw, @ch)
end
# Set sprite coordinates
self.x = @character.screen_x
self.y = @character.screen_y-5
self.z = 10#@character.screen_z-1
# Set blend method and bush depth
self.blend_type = @character.blend_type
self.bush_depth = @character.bush_depth
# Animation
if @character.animation_id != 0
animation = $data_animations[@character.animation_id]
animation(animation, true)
@character.animation_id = 0
end
@deltax = @source.screen_x - self.x
@deltay = @source.screen_y - self.y
self.color = Color.new(0, 0, 0)
@distance = ((@deltax ** 2) + (@deltay ** 2))
# Set opacity level based on light source distance
self.opacity = @self_opacity * 13000 /
((@distance * 370 / @distancemax) + 6000)
self.angle = 57.3 * Math.atan2(@deltax, @deltay )
@angle_trigo = self.angle+90
if @angle_trigo < 0
@angle_trigo = 360 + @angle_trigo
end
if @anglemin != 0 or @anglemax != 0
if (@angle_trigo < @anglemin or @angle_trigo > @anglemax) and
@anglemin < @anglemax
self.opacity = 0
return
end
if (@angle_trigo < @anglemin and @angle_trigo > @anglemax) and
@anglemin > @anglemax
self.opacity=0
return
end
end
end
#--------------------------------------------------------------------------
# * In Range? (From Near's Anti Lag Script, edited)
# element : element
# object : object
# range : range in tiles
#--------------------------------------------------------------------------
def in_range?(element, object, range)
x = (element.screen_x - object.screen_x) * (element.screen_x - object.screen_x)
y = (element.screen_y - object.screen_y) * (element.screen_y - object.screen_y)
r = x + y
if r <= (range * range)
return true
else
return false
end
end
end
#==============================================================================
# ** Sprite_Character
#------------------------------------------------------------------------------
# This sprite is used to display the character.It observes the Game_Character
# class and automatically changes sprite conditions.
#==============================================================================
class Sprite_Character < Sprite_Base
#--------------------------------------------------------------------------
# * Alias Listings
#--------------------------------------------------------------------------
alias shadow_initialize initialize
alias shadow_update update
#--------------------------------------------------------------------------
# * Object Initialization
# viewport : viewport
# character : character (Game_Character)
#--------------------------------------------------------------------------
def initialize(viewport, character = nil)
@viewport0 = Viewport.new(0, 0, 544, 416)
@viewport0.z = 1
@character = character
super(viewport)
@ombrelist = Array.new
@ombrelist = []
if character.is_a?(Game_Event) and $game_temp.shadow_spriteset.shadows != []
params = XPML.XPML_read("Shadow", @character.id, 5)
if params != nil
for i in 0...$game_temp.shadow_spriteset.shadows.size
@ombrelist.push(Sprite_Shadow.new(@viewport0, @character,i))
end
end
end
if character.is_a?(Game_Player) and $game_temp.shadow_spriteset.shadows != []
for i in 0...$game_temp.shadow_spriteset.shadows.size
@ombrelist.push(Sprite_Shadow.new(@viewport0, $game_player,i))
end
#===================================================
# * Compatibility with Caterpillar Functions
#===================================================
if CATERPILLAR_COMPATIBLE and $game_party.characters != nil
for member in $game_party.characters
for i in 0...$game_temp.shadow_spriteset.shadows.size
@ombrelist.push(Sprite_Shadow.new(@viewport0, member, i))
end
end
end
if SQUAD_MOVE_COMPATIBLE and $game_allies.values != nil
for member in $game_allies.values
for i in 0...$game_temp.shadow_spriteset.shadows.size
@ombrelist.push(Sprite_Shadow.new(@viewport0, member, i))
end
end
end
if CCOA_CATER_COMPATIBLE and $game_train.actors != nil
for member in $game_train.actors
for i in 0...$game_temp.shadow_spriteset.shadows.size
@ombrelist.push(Sprite_Shadow.new(@viewport0, member, i))
end
end
end
if TRICKSTER_CATER_COMPATIBLE and $game_party.followers != nil
for member in $game_party.followers
for i in 0...$game_temp.shadow_spriteset.shadows.size
@ombrelist.push(Sprite_Shadow.new(@viewport0, member, i))
end
end
end
#===================================================
# ** End of the compatibility
#===================================================
end
# Perform the original call
shadow_initialize(viewport, @character)
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
shadow_update
if @ombrelist != []
for i in 0...@ombrelist.size
@ombrelist[i].update
end
end
end
end
#==============================================================================
# ** Game_Event
#------------------------------------------------------------------------------
# This class deals with events. It handles functions including event page
# switching via condition determinants, and running parallel process events.
# It's used within the Game_Map class.
#==============================================================================
class Game_Event < Game_Character
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :id
end
#==============================================================================
# ** Spriteset_Map
#------------------------------------------------------------------------------
# This class brings together map screen sprites, tilemaps, etc.
# It's used within the Scene_Map class.
#==============================================================================
class Spriteset_Map
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :shadows
#--------------------------------------------------------------------------
# * Alias Listings
#--------------------------------------------------------------------------
alias shadow_initialize initialize
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
$game_temp.shadow_spriteset = self
@shadows = []
warn = false
for k in $game_map.events.keys.sort
if ($game_map.events[k].list != nil and
$game_map.events[k].list[0].code == 108 and
($game_map.events[k].list[0].parameters == ["s"] or
$game_map.events[k].list[0].parameters == ["o"]))
warn = true
end
params = XPML.XPML_read("Shadow Source", k, 5)
if params != nil
$game_temp.shadow_spriteset.shadows.push([$game_map.events[k]] + params)
end
end
if warn == true and SHADOW_WARN
p "Warning : At least one event on this map uses an obsolete way to add shadows"
end
# Perform the original call
shadow_initialize
end
end
#==============================================================================
# ** module XPML
#------------------------------------------------------------------------------
# This module handles the reading and passing of 'comment' parameters
#
# The main XPML method is used to check and read event comments.
# * It returns 'nil' if the markup 'check' text isn't even present.
# * It returns [] if no parameters are passed
# * It returns a parameter list with "int" converted as int.
# eg :
# begin first
# begin second
# param1 1
# param2 two
# begin third
# anything 3
#
# p XPML_read("first", event_id) -> []
# p XPML_read("second", event_id) -> [1,"two"]
# p XPML_read("third", event_id) -> [3]
# p XPML_read("forth", event_id) -> nil
#===================================================
module XPML
module_function
#--------------------------------------------------------------------------
# * XPML_read
# markup : text in event comment to check
# event_id : event ID
# max_param_number : maximum number of parameter/comments to load
#--------------------------------------------------------------------------
def XPML_read(markup, event_id, max_param_number = 0)
parameter_list = nil
event = $game_map.events[event_id]
return if event.list == nil
for i in 0...event.list.size
if event.list[i].code == 108 and
event.list[i].parameters[0].downcase == "begin " + markup.downcase
parameter_list = [] if parameter_list == nil
for j in i + 1...event.list.size
if event.list[j].code == 108
parts = event.list[j].parameters[0].split
if parts.size != 1 and parts[0].downcase != "begin"
if parts[1].to_i != 0 or parts[1] == "0"
parameter_list.push(parts[1].to_i)
else
parameter_list.push(parts[1])
end
else
return parameter_list
end
else
return parameter_list
end
if max_param_number != 0 and j == i + max_param_number
return parameter_list
end
end
end
end
return parameter_list
end
end