03-08-2008, 04:31 AM
Introduction
This script allows you to create a light source on your maps which can generate shadows for your events and characters. I have left in all the Caterpillar Script Compatability incase those creators make their scripts for VX too. Look at Author's Notes for bug fixing.
Screenshots
Script
Sprite Shadow
Code:
#==============================================================================
# ** 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
# April 16, 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 = []
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
Instructions
Contained within the script.
Add the script in Author's Notes to fix problems cause by both Sprite Shadow VX and Sprite Sun VX.
Compatibility
I'm not entirely sure about compatability, like I said I have left in all the Caterpillar Script Compatability incase those creators make their scripts for VX too (that is fukuyama's Train Actor system, Near Fantastica's SBABS and Squad Movment systems, Ccoa's Caterpillar and Trickster's Caterpillar).
Credits and Thanks
Thanks goes to Rataime for creating this system, and (if you want to) me for editing it.
Author's Notes
When using this script double 'autoshadows' will be created, I've developed a script that fixes this.
This script also stops the shadow sprites created by this script from going over walls and houses.
Script
Code:
#==============================================================================
# ** Spriteset_Map
#------------------------------------------------------------------------------
# This class edits problems cause by Sprite_Shadow and Sprite_Sun
#==============================================================================
class Spriteset_Map
#--------------------------------------------------------------------------
# * Alias Listings
#--------------------------------------------------------------------------
alias create_viewports_original create_viewports
alias dispose_viewports_original dispose_viewports
alias update_viewports_original update_viewports
alias update_tilemap_original update_tilemap
alias dispose_tilemap_original dispose_tilemap
alias create_tilemap_original create_tilemap
#--------------------------------------------------------------------------
# * Create Viewport
#--------------------------------------------------------------------------
def create_viewports
create_viewports_original
@viewport0 = Viewport.new(0, 0, 544, 416)
@viewport0.z = 1
@viewport1.z = 20
end
#--------------------------------------------------------------------------
# * Create Tilemap
#--------------------------------------------------------------------------
def create_tilemap
create_tilemap_original
@tilemap0 = Tilemap.new(@viewport0)
@tilemap0.bitmaps[0] = Cache.system("TileA1")
@tilemap0.bitmaps[1] = Cache.system("TileA2")
@tilemap0.bitmaps[4] = Cache.system("TileA5")
@tilemap = Tilemap.new(@viewport1)
@tilemap.bitmaps[2] = Cache.system("TileA3")
@tilemap.bitmaps[3] = Cache.system("TileA4")
@tilemap.bitmaps[5] = Cache.system("TileB")
@tilemap.bitmaps[6] = Cache.system("TileC")
@tilemap.bitmaps[7] = Cache.system("TileD")
@tilemap.bitmaps[8] = Cache.system("TileE")
@tilemaps = [@tilemap, @tilemap0]
@tilemaps.each {|x| x.map_data = $game_map.data}
@tilemaps.each {|x| x.passages = $game_map.passages}
reset_shadows
end
#--------------------------------------------------------------------------
# * Reset Auto Shadows
#--------------------------------------------------------------------------
def reset_shadows
data = @tilemap0.map_data
# Every square on the map
for x in 0...data.xsize
for y in 0...data.ysize
# Check for Auto Shadow
if data[x,y,1] == 0
# Replace Auto Shadow
@tilemap0.map_data[x,y,1] = data[x,y,0] == 0 ? 25 : @tilemap0.map_data[x,y,0]
end
end
end
end
#--------------------------------------------------------------------------
# * Dispose of Tilemap
#--------------------------------------------------------------------------
def dispose_tilemap
dispose_tilemap_original
@tilemap0.dispose
end
#--------------------------------------------------------------------------
# * Dispose of Viewport
#--------------------------------------------------------------------------
def dispose_viewports
@viewport0.dispose
dispose_viewports_original
end
#--------------------------------------------------------------------------
# * Update Tilemap
#--------------------------------------------------------------------------
def update_tilemap
update_tilemap_original
@tilemap0.ox = $game_map.display_x / 8
@tilemap0.oy = $game_map.display_y / 8
@tilemap0.update
end
#--------------------------------------------------------------------------
# * Update Viewport
#--------------------------------------------------------------------------
def update_viewports
update_viewports_original
@viewport0.tone = $game_map.screen.tone
@viewport0.ox = $game_map.screen.shake
@viewport0.update
end
end