Код:
#-------------------------------------------------------------------------------
# * [XP] Офигенные световые эффекты Кхаса
#-------------------------------------------------------------------------------
# * By Khas Arcthunder - arcthunder.site40.net
# * Переведен и конвертирован под XP - caveman
# * Версия: 1.1 RU
# * Создан: 17/04/2013
# *
# * Изменение 1.0 -> 1.1 от 19/04/2013 от caveman
# * В настройки добавлен параметр R_G, отвечающий за грубость теней => за
# скорость работы скрипта.
#
#-------------------------------------------------------------------------------
# * Лицензии и благодарности автору, то есть Кхасу
#-------------------------------------------------------------------------------
# При использовании данного скрипта вы автоматически соглашаетесь с тем, что:
# 1. Вы должны упомянуть в титрах автора;
# 2. Все скрипты Кхаса находятся под защитой Creative Commons license;
# 3. Все скрипты Кхаса только для некоммерческого использования.
# Если вы хотите использовать скритпы для вашего коммерческого проекта,
# пошлите письмо на nilokruch@live.com с заявкой, и Великий, быть может
# одобрит ваш проект
# 4. Все скрипты Кхаса только для личного использования, вы можете использовать
# и редактировать их для под свои нужды, но вам нельзя публиковать
# модифицированные версии скрипта.
# FUCK YOU, Khas!!!
# 5. Если вы постите скрипт Кхаса, вы не должны ставить себя в создатели. О как;
# 6. Если вы хотите запостить скрипт Кхаса - то постите только прямой линк
# на сайт Великого arcthunder.site40.net
#
#-------------------------------------------------------------------------------
# * Фичи
#-------------------------------------------------------------------------------
# - Реалистичный свет
# - Свет не проходит через стены, потолки и препятствия (при условии настройки тегов)
# - Статические истончники света
# - Динамические источники света (типа игрока с лампой)
# - Множественные эффекты (подразумевается, что можно подвесить несколько
# световых эффектов на разные положения события - например, реализовать фонарик)
# - Легкость в использовании
#
#-------------------------------------------------------------------------------
# * ВНИМАНИЕ - могут быть проблемы с производительностью
#-------------------------------------------------------------------------------
# Тут Кхас утверждает, что скрипт может тормозить на старых процессорах.
# Как и автор, я тестил только на i5, все летает - приветствуются комменты
# от счастливых обладателей различных музейных экспонатов.
#
# Возможные источники проблем:
#
# 1. Размер карты
# Так как скрипт бегает по поверхностям карты для обрезания света стенами
# и прочим, то размер карты влияет на результат - там больше поверхностей.
# Это верно только для динамических источников света.
#
# Имхо, прямыми руками можно таки смотреть не всю карту, а экран + максимальный
# размер света - но делать, конечно же лень.
#
# 2. Число эффектов
# Великий все-таки проверяет на попадание в экран статики, но попробуйте запихнуть
# в один экран кучу источников и посмотрите на тормоза.
#
# 3. Размер картинок эффектов
# Тут все просто, чем больше размер картинок - тем медленнее работают
# динамические источники. Автор рекомендует максимум 200x200 пикселей
#
#-------------------------------------------------------------------------------
# * ВНИМАНИЕ - О картинках для света
#-------------------------------------------------------------------------------
# Чтобы скрипт работал корректно, картинки для света долны удовлетворять
# следующим условиям:
# 1. Размеры картинки делятся на 2. Например: 150x150
# 2. Картинки поддерживаются только квадратные (это печаль :(). Например: 156x156
# 3. Цвета картинок должны быть инвертированы! Черный - прозрачный и наоборот.
#
#-------------------------------------------------------------------------------
# * Инструкция - часть 1. Установите ваши эффекты!
#-------------------------------------------------------------------------------
# Для того, чтобы установить статические эффекты, идете в часть установки
# где-то с 200 строки и заполняете хеш-таблицу как-то так:
#
# X => [picture,opacity,variation,cut], <= не забудьте про запятую в конце
#
# Где:
# picture => название картинки внутри папки Graphics/Lights;
# opacity => НЕпрозрачность эффекта;
# variation => Колебания непрозрачности (например, создает эффект дерганья света факела);
# cut => true - обрезаем эффект на препятствиях;
# X => ID эффекта (пригодится для установки на события).
#
#-------------------------------------------------------------------------------
# * Инструкция - часть 2 Используйте ваши эффекты!
# (похоже, автор имеет в виду статику)
#-------------------------------------------------------------------------------
# Чтобы использовать эффект на событии - просто оставьте в нем коммент:
#
# [light x]
#
# Где x - ID эффекта.
#
#-------------------------------------------------------------------------------
# * Инструкция - часть 3. Используйте офигительные лампы.
# (тут, очевидно, динамика)
#-------------------------------------------------------------------------------
# Лампа (ага! а автор все время динамику во множественном числе упоминает!
# но, подозреваю, шаловливые ручки могут и это исправить :))
# по умолчанию невидима.
# Вам доступны следущие команды (вводите в событии скриптом):
#
# l = $game_map.lantern
# Поместить лампу в переменную
# l.set_graphic(i)
# Проставить лампе графику, i - название файла света в папке Graphics/Lights
#
# l.set_multiple_graphics(h)
# Проставить графику лампе из h, где h - хеш таблица следующей структуры:
#
# h = {2=>"ld",4=>"ll",6=>"lr",8=>"lu"}
#
# Где:
# "ld" название картинки, если событие смотрит вниз;
# "ll" название картинки, если событие смотрит влево;
# "lr" название картинки, если событие смотрит вправо;
# "lu" название картинки, если событие смотрит вверх;
#
# l.change_owner(char)
# Проставить обладателя лампы. Char - одна из следующих команд:
# $game_player <= игрок;
# self_event <= событие, из которого вызвали эту команду;
# $game_map.events[x] <= ID некоторого события;
#
# l.set_opacity(o,p)
# Проставить лампе непрозрачность:
# o непрозрачность эффекта;
# p некий рандом - для "живого" моргания света.
#
# l.show
# Сделать, наконец, эффект видимым
#
# l.hide
# Сделать эффект невидимым
#
#-------------------------------------------------------------------------------
# * Инструкция - часть 4. Используйте эффекты поверхностей!
#-------------------------------------------------------------------------------
# Офигенные световые эффекты Кхаса могут применять некоторые эффекты поверхности к карте,
# естественно, для этого поверхность должна быть видимой.
# Поверхность инициализируется с непрозрачностью = 0, но вы можете вызвать следующие команды
# (caveman: в общем это нечто вроде картинки поверх (как настроите Surface_Z) карты, на которой
# и будет рисоваться свет и тени
#
# s = $game_map.effect_surface
# Поместить поверхность в переменную
#
# s.set_color(r,g,b)
# Задать поверхности цвет
# r => красный;
# g => зеленый;
# b => синий;
#
# s.set_alpha(a)
# Изменить непрозрачность поверхности
#
# s.change_color(time,r,g,b)
# Постепенно изменить цвет поверхности (за время time)
# time => время изменения (в фреймах);
# r => красный;
# g => зеленый;
# b => синий;
#
# s.change_color(time,r,g,b,a)
# Постепенно изменить цвет поверхности и её непрозрачность (за время time)
# time => время изменения (в фреймах);
# r => красный;
# g => зеленый;
# b => синий;
# a => непрозрачность;
#
# s.change_alpha(time,a)
# Постепенно изменить непрозрачность поверхности (за время time)
# time => время изменения (в фреймах);
# a => непрозрачность;
#
#-------------------------------------------------------------------------------
# * Инструкция - часть 5. Используйте эффект поверхности с комендой Tone!
#-------------------------------------------------------------------------------
# Если вы проставите в настройках скрипта Surface_UE = true, то можете
# доступаться до эффекта поверхности при помощи обычной команды "Screen Tone",
# а не дергать скрипты руками
#
# Некоторые замечания:
# 1. Значения цветов должны лежать между 0 и 255;
# 2. Время - в фреймах;
# 3. Серый цвет (полоска внизу) означает непрозрачность
#
#-------------------------------------------------------------------------------
# * Инструкция - часть 5. Проставьте теги вашим тайлсетам!
#-------------------------------------------------------------------------------
# Чтобы нормально обрезать свет и показывать тени, в вашем тайлсете нужно отметить тегами,
# что есть стена, что - крыша, а что просто блок
# Стена генерирует тени, как реальная стена, блоки как блоки и крыша как крыша.
# В стандартной настройке надо стенам проставить 5, крыше - 6 и блокам - 7
#
#-------------------------------------------------------------------------------
# * Настройки
#-------------------------------------------------------------------------------
module Light_Core
Effects = { # <= Не изменяйте это!
#-------------------------------------------------------------------------------
# Если хотите добавить свои эффекты - то дополняйте список! (см "Инструкция - часть 1.")
#-------------------------------------------------------------------------------
0 => ["light",255,0,true],
1 => ["torch",180,20,true],
2 => ["torch_m",180,30,true],
3 => ["light_s",255,0,true],
#-------------------------------------------------------------------------------
# Конец настроек эффектов
#-------------------------------------------------------------------------------
} # <= Не изменяйте это!
# Z координата поверхности
Surface_Z = 180
# см "Инструкция - часть 5."
Surface_UE = true
# Тег крыши
Roof_Tag = 5
# Тег стены - свет падает на стену и стена генерирует тени
Wall_Tag = 6
# Тег блока, через который свет не пройдет.
# Судя по использованию в VX, в XP нужно этот тег проставлять автотайлу "крыши".
# Например, в подземелье черный обрис вокруг комнаты.
Block_Tag = 7
# Не изменяйте это!
ACC = Math.tan(Math::PI/26)
# грубость теней (1 - идеал, чем больше - тем хуже и быстрей)
R_G = 1
end
# всякие вспомогательные штуки
module Cache
#--------------------------------------------------------------------------
# ● загрузка картинки по пути
#--------------------------------------------------------------------------
def self.load_bitmap(folder_name, filename, hue = 0)
@cache ||= {}
if filename.empty?
empty_bitmap
elsif hue == 0
normal_bitmap(folder_name + filename)
else
hue_changed_bitmap(folder_name + filename, hue)
end
end
#--------------------------------------------------------------------------
# ● Пустая картинка, вместо nil
#--------------------------------------------------------------------------
def self.empty_bitmap
Bitmap.new(32, 32)
end
#--------------------------------------------------------------------------
# ● Загрузка обычной картинки
#--------------------------------------------------------------------------
def self.normal_bitmap(path)
@cache[path] = Bitmap.new(path) unless include?(path)
@cache[path]
end
#--------------------------------------------------------------------------
# ● Загрузка с измененной HUE
#--------------------------------------------------------------------------
def self.hue_changed_bitmap(path, hue)
key = [path, hue]
unless include?(key)
@cache[key] = normal_bitmap(path).clone
@cache[key].hue_change(hue)
end
@cache[key]
end
#--------------------------------------------------------------------------
# ● include?
#--------------------------------------------------------------------------
def self.include?(key)
@cache[key] && !@cache[key].disposed?
end
#--------------------------------------------------------------------------
# ● Очистка
#--------------------------------------------------------------------------
def self.clear
@cache ||= {}
@cache.clear
GC.start # хоть кто-то юзает в руби GC!!!
end
end
class Game_Map
alias kdi_setup setup
def setup(map_id)
@map_id = map_id
@map = load_data(sprintf("Data/Map%03d.rxdata", @map_id))
tileset = $data_tilesets[@map.tileset_id]
@tileset_name = tileset.tileset_name
@autotile_names = tileset.autotile_names
@panorama_name = tileset.panorama_name
@panorama_hue = tileset.panorama_hue
$game_system.scroll_x = 0
$game_system.scroll_y = 0
@fog_name = tileset.fog_name
@fog_hue = tileset.fog_hue
@fog_opacity = tileset.fog_opacity
@fog_blend_type = tileset.fog_blend_type
@fog_zoom = tileset.fog_zoom
@fog_sx = tileset.fog_sx
@fog_sy = tileset.fog_sy
@battleback_name = tileset.battleback_name
@passages = tileset.passages
@priorities = tileset.priorities
@terrain_tags = tileset.terrain_tags
@display_x = 0
@display_y = 0
@need_refresh = false
# вынесено в отдельный метод, чтобы в главном скрипте переопределить
setup_events
@fog_ox = 0
@fog_oy = 0
@fog_tone = Tone.new(0, 0, 0, 0)
@fog_tone_target = Tone.new(0, 0, 0, 0)
@fog_tone_duration = 0
@fog_opacity_duration = 0
@fog_opacity_target = 0
@scroll_direction = 2
@scroll_rest = 0
@scroll_speed = 4
end
def setup_events
@events = {}
for i in @map.events.keys
@events[i] = Game_Event.new(@map_id, @map.events[i])
end
@common_events = {}
for i in 1...$data_common_events.size
@common_events[i] = Game_CommonEvent.new(i)
end
end
#--------------------------------------------------------------------------
# ● число тайлов на экране по X
#--------------------------------------------------------------------------
def screen_tile_x
20 #Graphics.width / 32
end
#--------------------------------------------------------------------------
# ● число тайлов на экране по Y
#--------------------------------------------------------------------------
def screen_tile_y
15 #Graphics.height / 32
end
#--------------------------------------------------------------------------
# ● Маленькая выравнивалка карты по X
#--------------------------------------------------------------------------
def adjust_x(x)
d_x = @display_x
if x < d_x - (width - screen_tile_x) * 128
return x - d_x + @map.width * 128
else
return x - d_x
end
end
#--------------------------------------------------------------------------
# ● Маленькая выравнивалка карты по Y
#--------------------------------------------------------------------------
def adjust_y(y)
d_y = @display_y
if y < d_y - (height - screen_tile_y) * 128
return y - d_y + @map.height * 128
else
return y - d_y
end
end
end
#-------------------------------------------------------------------------------
# Скрипт
#-------------------------------------------------------------------------------
module Cache
def self.light(filename)
load_bitmap("Graphics/Lights/", filename)
end
end
module Light_Bitcore
include Light_Core
def self.initialize
@@buffer = {}
Effects.values.each { |effect| Light_Bitcore.push(effect[0])}
end
def self::[](key)
return @@buffer[key]
end
def self.push(key)
return if @@buffer.keys.include?(key)
@@buffer[key] = Cache.light(key)
end
end
Light_Bitcore.initialize
#-------------------------------------------------------------------------------
# Класс - статический источник света
#-------------------------------------------------------------------------------
class Light_SSource
attr_reader :real_x
attr_reader :real_y
attr_reader :range
attr_accessor :bitmap
attr_reader :w
attr_reader :h
attr_reader :hs
def initialize(char,bitmap,opacity,plus,hs)
sync(char)
@key = bitmap
@bitmap = Light_Bitcore[@key].clone
@range = @bitmap.width/2
@w = @bitmap.width
@h = @bitmap.height
@mr = @range - 16
@opacity = opacity
@plus = plus
@hs = hs
render if @hs
end
def render
tx = x
ty = y
tsx = x + @range
tsy = y + @range
dr = @range*2
#p tx.to_s + " " + ty.to_s
for s in $game_map.surfaces
next if !s.visible?(tsx,tsy) || !s.within?(tx,tx+dr,ty,ty+dr)
s.render_shadow(tx,ty,tsx,tsy,@range,@bitmap)
end
end
def restore
return unless @bitmap.nil?
@bitmap = Light_Bitcore[@key].clone
render if @hs
end
def opacity
@plus == 0 ? @opacity : (@opacity + rand(@plus))
end
def sx
return $game_map.adjust_x(@real_x) / 4 - @mr
end
def sy
return $game_map.adjust_y(@real_y) / 4 - @mr
end
def sync(char)
@real_x = char.real_x
@real_y = char.real_y
end
def x
return (@real_x/4 - @mr).to_f
end
def y
return (@real_y/4 - @mr).to_f
end
def dispose
return if @bitmap.nil?
@bitmap.dispose
@bitmap = nil
end
end
#-------------------------------------------------------------------------------
# Класс - динамический источник света
#-------------------------------------------------------------------------------
class Light_DSource < Light_SSource
attr_reader :bitmap
attr_reader :visible
def initialize
@key = nil
@bitmap = nil
@opacity = 255
@plus = 0
@char = $game_player
@visible = false
end
def set_opacity(o,p)
@opacity = o
@plus = p
end
def set_graphic(sb)
dispose
@key = {2=>sb,4=>sb,6=>sb,8=>sb}
Light_Bitcore.push(sb)
@bitmap = {2=>Light_Bitcore[@key[2]].clone,4=>Light_Bitcore[@key[4]].clone,6=>Light_Bitcore[@key[6]].clone,8=>Light_Bitcore[@key[8]].clone}
@range = @bitmap[2].width/2
@w = @bitmap[2].width
@h = @bitmap[2].height
@mr = @range - 16
end
def set_multiple_graphics(ba)
dispose
@key = ba
@key.values.each {|key| Light_Bitcore.push(key)}
@bitmap = {2=>Light_Bitcore[@key[2]].clone,4=>Light_Bitcore[@key[4]].clone,6=>Light_Bitcore[@key[6]].clone,8=>Light_Bitcore[@key[8]].clone}
@range = @bitmap[2].width/2
@w = @bitmap[2].width
@h = @bitmap[2].height
@mr = @range - 16
end
def get_graphic
return @bitmap[@char.direction].clone
end
def show
return if @bitmap.nil?
@visible = true
end
def hide
@visible = false
end
def restore
return if @key.nil?
@key.values.each {|key| Light_Bitcore.push(key)}
@bitmap = {2=>Light_Bitcore[@key[2]].clone,4=>Light_Bitcore[@key[4]].clone,6=>Light_Bitcore[@key[6]].clone,8=>Light_Bitcore[@key[8]].clone}
end
def dispose
return if @bitmap.nil?
@bitmap.values.each { |b| b.dispose }
@bitmap = nil
end
def change_owner(char)
@char = char
end
def render
end
def sx
return $game_map.adjust_x(@char.real_x) / 4 - @mr
end
def sy
return $game_map.adjust_y(@char.real_y) / 4 - @mr
end
def x
return (@char.real_x/4- @mr).to_f
end
def y
return (@char.real_y/4 - @mr).to_f
end
end
#-------------------------------------------------------------------------------
# Класс поверхности
#-------------------------------------------------------------------------------
class Light_Surface
def initialize
@ta = @a = 0
@tr = @r = 255
@tg = @g = 255
@tb = @b = 255
@va = @vr = @vg = @vb = 0.0
@timer = 0
end
def refresh
return if @timer == 0
@a += @va
@r += @vr
@g += @vg
@b += @vb
$game_map.light_surface.opacity = @a
@timer -= 1
end
def change_color(time,r,g,b,a=nil)
r = 0 if r < 0; r = 255 if r > 255
g = 0 if g < 0; g = 255 if g > 255
b = 0 if b < 0; b = 255 if b > 255
unless a.nil?
a = 0 if a < 0; a = 255 if a > 255
end
@timer = time
@tr = 255-r
@tg = 255-g
@tb = 255-b
@va = (a.nil? ? 0 : (a-@a).to_f/@timer)
@vr = (@tr - @r).to_f/@timer
@vg = (@tg - @g).to_f/@timer
@vb = (@tb - @b).to_f/@timer
end
def change_alpha(time,a)
a = 0 if a < 0; a = 255 if a > 255
@timer = time
@ta = a
@vr = @vg = @vb = 0.0
@va = (a-@a).to_f/@timer
end
def set_color(r,g,b)
r = 0 if r < 0; r = 255 if r > 255
g = 0 if g < 0; g = 255 if g > 255
b = 0 if b < 0; b = 255 if b > 255
@tr = @r = 255-r
@tg = @g = 255-g
@tb = @b = 255-b
@va = @vr = @vg = @vb = 0.0
@timer = 0
end
def set_alpha(a)
a = 0 if a < 0; a = 255 if a > 255
@ta = @a = a
$game_map.light_surface.opacity = @a
@va = @vr = @vg = @vb = 0.0
@timer = 0
end
def alpha
return @a
end
def color
return Color.new(@r,@g,@b)
end
end
class Game_Map
include Light_Core
attr_accessor :light_surface
attr_accessor :light_sources
attr_accessor :surfaces
attr_accessor :effect_surface
attr_accessor :lantern
alias kbl_setup_events setup_events
alias kbl_initialize initialize
alias kbl_update update
def initialize
kbl_initialize
@effect_surface = Light_Surface.new
@lantern = Light_DSource.new
end
def update
# TODO тут был аргумент
@effect_surface.refresh
kbl_update
end
def first_tag(x,y)
tag = terrain_tag(x,y)
return tag > 0 ? tag : 0
end
def setup_events
@light_sources.nil? ? @light_sources = [] : @light_sources.clear
setup_surfaces
merge_surfaces
kbl_setup_events
end
def tile_id(x, y, z)
@map.data[x, y, z] || 0
end
def tile_pass?(x, y, d, k)
unless valid?(x, y)
return false
end
bit = (1 << (d / 2 - 1)) & 0x0f
tile_id = data[x, y, k]
if tile_id == nil
return false
elsif @passages[tile_id] & bit != 0
return false
elsif @passages[tile_id] & 0x0f == 0x0f
return false
elsif @priorities[tile_id] == 0
return true
end
return true
end
def tile_pass2?(x, y, k)
unless valid?(x, y)
return false
end
tile_id = data[x, y, k]
if tile_id == nil
return false
elsif @priorities[tile_id] != 0
return false
end
return true
end
def setup_surfaces
@surfaces = []
for k in 0..2
for x in 0..(width-1)
for y in 0..(height-1)
tag = first_tag(x,y)
if tag == Wall_Tag
if y > 0
tagU = first_tag(x,y-1)
if tagU == Block_Tag
@surfaces << Block_SD.new(x*32,y*32,x*32+32,y*32)
end
end
if x > 0
tagL = first_tag(x-1,y)
if tagL != Wall_Tag
@surfaces << Block_WL.new(x*32,y*32,x*32,y*32+32)
@surfaces << Block_IR.new(x*32-1,y*32,x*32-1,y*32+32)
end
end
if x < width-1
tagR = first_tag(x+1,y)
if tagR != Wall_Tag
@surfaces << Block_IL.new(x*32+32,y*32,x*32+32,y*32+32)
@surfaces << Block_WR.new(x*32+31,y*32,x*32+31,y*32+32)
end
end
elsif tag == Roof_Tag # не представляю, что это, пилите, Шура
i = tile_id(x,y,k)
#@surfaces << Block_SD.new(x*32,y*32,x*32+32,y*32) if tile_pass?(x, y, 2, k)
@surfaces << Block_SU.new(x*32,y*32,x*32+32,y*32) if tile_pass?(x, y, 8, k)
@surfaces << Block_SR.new(x*32+31,y*32,x*32+31,y*32+32) if tile_pass?(x, y, 6, k)
@surfaces << Block_SL.new(x*32,y*32,x*32,y*32+32) if tile_pass?(x, y, 4, k)
elsif tag == Block_Tag
if y < height-1
tagD = first_tag(x,y+1)
if tagD != Block_Tag
@surfaces << Block_SD.new(x*32,y*32+31,x*32+32,y*32+31)
end
end
if y > 0
tagU = first_tag(x,y-1)
if tagU != Block_Tag
@surfaces << Block_SU.new(x*32,y*32,x*32+32,y*32)
end
end
if x > 0
tagL = first_tag(x-1,y)
if tagL != Block_Tag
@surfaces << Block_SL.new(x*32,y*32,x*32,y*32+32)
end
end
if x < width-1
tagR = first_tag(x+1,y)
if tagR != Block_Tag
@surfaces << Block_SR.new(x*32+31,y*32,x*32+31,y*32+32)
end
end
# @surfaces << Block_SD.new(x*32,y*32+31,x*32+32,y*32+31)
# @surfaces << Block_SL.new(x*32,y*32,x*32,y*32+32)
# @surfaces << Block_SR.new(x*32+31,y*32,x*32+31,y*32+32)
# @surfaces << Block_SU.new(x*32,y*32,x*32+32,y*32)
end
end
end
end
end
def merge_surfaces
new_surfaces = []
hs = []; vs = []
ws = []; is = []
for surface in @surfaces
if surface.type & 0x05 == 0
hs << surface
else
if surface.type & 0x010 == 0
vs << surface
else
if surface.type & 0x08 == 0
ws << surface
else
is << surface
end
end
end
end
for surface in hs
surface.ready ? next : surface.ready = true
for s in hs
next if s.ready || s.y1 != surface.y1 || surface.type != s.type
if s.x2 == surface.x1
surface.x1 = s.x1
s.trash = true
s.ready = true
surface.ready = false
elsif s.x1 == surface.x2
surface.x2 = s.x2
s.trash = true
s.ready = true
surface.ready = false
end
end
end
hs.each { |s| @surfaces.delete(s) if s.trash}
for surface in vs
surface.ready ? next : surface.ready
for s in vs
next if s.ready || s.x1 != surface.x1
if s.y2 == surface.y1
surface.y1 = s.y1
s.trash = true
s.ready = true
surface.ready = false
elsif s.y1 == surface.y2
surface.y2 = s.y2
s.trash = true
s.ready = true
surface.ready = false
end
end
end
vs.each { |s| @surfaces.delete(s) if s.trash}
for surface in ws
surface.ready ? next : surface.ready
for s in ws
next if s.ready || s.x1 != surface.x1
if s.y2 == surface.y1
surface.y1 = s.y1
s.trash = true
s.ready = true
surface.ready = false
elsif s.y1 == surface.y2
surface.y2 = s.y2
s.trash = true
s.ready = true
surface.ready = false
end
end
end
ws.each { |s| @surfaces.delete(s) if s.trash}
for surface in is
surface.ready ? next : surface.ready
for s in is
next if s.ready || s.x1 != surface.x1
if s.y2 == surface.y1
surface.y1 = s.y1
s.trash = true
s.ready = true
surface.ready = false
elsif s.y1 == surface.y2
surface.y2 = s.y2
s.trash = true
s.ready = true
surface.ready = false
end
end
end
is.each { |s| @surfaces.delete(s) if s.trash}
end
end
class Game_Event < Game_Character
alias kbl_initialize initialize
alias kbl_refresh refresh
def initialize(m,e)
@light = nil
kbl_initialize(m,e)
end
def refresh
kbl_refresh
setup_light(@page.nil?)
end
def setup_light(dispose)
unless @light.nil?
$game_map.light_sources.delete(self)
@light.dispose
@light = nil
end
unless dispose && @list.nil?
for command in @list
if command.code == 108 && command.parameters[0].include?("[light")
command.parameters[0].scan(/\[light ([0.0-9.9]+)\]/)
effect = Light_Core::Effects[$1.to_i]
@light = Light_SSource.new(self,effect[0],effect[1],effect[2],effect[3])
$game_map.light_sources << self
return
end
end
end
end
def draw_light
sx = @light.sx
sy = @light.sy
w = @light.w
h = @light.h
return if sx > 640 && sy > 480 && sx + w < 0 && sy + h < 0
$game_map.light_surface.bitmap.blt(sx, sy,
@light.bitmap, Rect.new(0,0,w,h), @light.opacity)
end
def dispose_light
@light.dispose
end
def restore_light
@light.restore
end
end
if Light_Core::Surface_UE
class Game_Interpreter
def command_223
$game_map.effect_surface.change_color(@params[1],@params[0].red,@params[0].green,@params[0].blue,@params[0].gray)
wait(@params[1]) if @params[2]
end
end
end
class Game_Interpreter
def self_event
return $game_map.events[@event_id]
end
end
#-------------------------------------------------------------------------------
# Этот метод написан в качестве замены VX-овскому clear_rect у битмапа
#-------------------------------------------------------------------------------
def clear_rect(bitmap, x1, y1, x2, y2)
if bitmap != nil
empty = Color.new(0,0,0,0)
bitmap.fill_rect(Rect.new(x1, y1, x2, y2), empty)
end
end
#-------------------------------------------------------------------------------
# Базовый класс для блока. Блок есть тайл на карте, который обрезает свет и генерит тень.
#-------------------------------------------------------------------------------
class Block_Surface
include Light_Core
attr_accessor :x1
attr_accessor :y1
attr_accessor :x2
attr_accessor :y2
attr_accessor :ready
attr_accessor :trash
def initialize(x1,y1,x2,y2)
@x1 = x1
@y1 = y1
@x2 = x2
@y2 = y2
@ready = false
@trash = false
end
def within?(min_x,max_x,min_y,max_y)
return @x2 > min_x && @x1 < max_x && @y2 > min_y && @y1 < max_y
end
end
class Block_SL < Block_Surface
attr_reader :type
def initialize(x1,y1,x2,y2)
super(x1,y1,x2,y2)
@type = 0x01
end
def visible?(sx,sy)
return sx < @x1
end
def render_shadow(phx,phy,sx,sy,range,bitmap)
@m1 = (@y1-sy)/(@x1-sx)
@n1 = sy - @m1*sx
@m2 = (@y2-sy)/(@x2-sx)
@n2 = sy - @m2*sx
i1 = (sx + range - @x1) / R_G
for i in 0..i1
x = R_G*i + @x1
init = shadow_iy(x)
clear_rect(bitmap, x-phx, init-phy, R_G, shadow_fy(x)-init+3)
end
end
def shadow_iy(x)
return @m1*x+@n1
end
def shadow_fy(x)
return @m2*x+@n2
end
end
class Block_SR < Block_Surface
attr_reader :type
def initialize(x1,y1,x2,y2)
super(x1,y1,x2,y2)
@type = 0x04
end
def visible?(sx,sy)
return sx > @x1
end
def render_shadow(phx,phy,sx,sy,range,bitmap)
@m1 = (@y1-sy)/(@x1-sx)
@n1 = sy - @m1*sx
@m2 = (@y2-sy)/(@x2-sx)
@n2 = sy - @m2*sx
i1 = ((sx-range).to_i - @x1) / R_G
for i in i1..0
x = @x1 + R_G*i
init = shadow_iy(x)
clear_rect(bitmap, x-phx, init-phy, R_G, shadow_fy(x)-init+3)
end
end
def shadow_iy(x)
return @m1*x+@n1
end
def shadow_fy(x)
return @m2*x+@n2
end
end
class Block_IL < Block_Surface
attr_reader :type
def initialize(x1,y1,x2,y2)
super(x1,y1,x2,y2)
@type = 0x019
end
def visible?(sx,sy)
return sx < @x1 && sy > @y1
end
def render_shadow(phx,phy,sx,sy,range,bitmap)
@m1 = (@y1-sy)/(@x1-sx)
@n1 = @y1 - @m1*@x1
@m2 = (@y2-sy)/(@x2-sx)
@m2 = 0 if @m2 > 0
@n2 = @y2 - @m2*@x2
i1 = (sx + range - @x1) / R_G
for i in 0..i1
x = R_G*i + @x1
init = shadow_iy(x).floor
clear_rect(bitmap, x-phx, init-3-phy, R_G, shadow_fy(x)-init+3)
end
end
def shadow_iy(x)
return @m1*x+@n1
end
def shadow_fy(x)
return @m2*x+@n2
end
end
class Block_IR < Block_Surface
attr_reader :type
def initialize(x1,y1,x2,y2)
super(x1,y1,x2,y2)
@type = 0x01c
end
def visible?(sx,sy)
return sx > @x1 && sy > @y1
end
def render_shadow(phx,phy,sx,sy,range,bitmap)
@m1 = (@y1-sy)/(@x1-sx)
@n1 = @y1 - @m1*@x1
@m2 = (@y2-sy)/(@x2-sx)
@m2 = 0 if @m2 < 0
@n2 = @y2 - @m2*@x2
i1 = ((sx-range).to_i - @x1) / R_G
for i in i1..0
x = @x1 + R_G*i
init = shadow_iy(x).floor
clear_rect(bitmap, x-phx,init-3-phy,R_G,shadow_fy(x)-init+3)
end
end
def shadow_iy(x)
return @m1*x+@n1
end
def shadow_fy(x)
return @m2*x+@n2
end
end
class Block_WL < Block_Surface
attr_reader :type
def initialize(x1,y1,x2,y2)
super(x1,y1,x2,y2)
@type = 0x011
end
def visible?(sx,sy)
return sx < @x1 && sy < @y2
end
def render_shadow(phx,phy,sx,sy,range,bitmap)
@m1 = (@y1-sy)/(@x1-sx)
@n1 = sy - @m1*sx
@m2 = (@y2-sy)/(@x2-sx)
@n2 = sy - @m2*sx
i1 = (sx + range - @x1) / R_G
for i in 0..i1
x = R_G*i + @x1
init = shadow_iy(x)
clear_rect(bitmap, x-phx,init-phy,R_G,shadow_fy(x)-init+2)
end
end
def shadow_iy(x)
return @m1*x+@n1
end
def shadow_fy(x)
return @m2*x+@n2
end
end
class Block_WR < Block_Surface
attr_reader :type
def initialize(x1,y1,x2,y2)
super(x1,y1,x2,y2)
@type = 0x014
end
def visible?(sx,sy)
return sx > @x1 && sy < @y2
end
def render_shadow(phx,phy,sx,sy,range,bitmap)
@m1 = (@y1-sy)/(@x1-sx)
@n1 = sy - @m1*sx
@m2 = (@y2-sy)/(@x2-sx)
@n2 = sy - @m2*sx
i1 = ((sx-range).to_i - @x1) / R_G
for i in i1..0
x = @x1 + R_G*i
init = shadow_iy(x)
clear_rect(bitmap, x-phx,init-phy,R_G,shadow_fy(x)-init+2)
end
end
def shadow_iy(x)
return @m1*x+@n1
end
def shadow_fy(x)
return @m2*x+@n2
end
end
class Block_SU < Block_Surface
attr_reader :type
def initialize(x1,y1,x2,y2)
super(x1,y1,x2,y2)
@type = 0x02
end
def visible?(sx,sy)
return sy < @y1
end
def render_shadow(phx,phy,sx,sy,range,bitmap)
if @x1 == sx
@m1 = nil
else
@m1 = (@y1-sy)/(@x1-sx)
@m1 += ACC if @m1 < -ACC
@n1 = @y1 - @m1*@x1
end
if @x2 == sx
@m2 = nil
else
@m2 = (@y2-sy)/(@x2-sx)
@n2 = sy - @m2*sx
end
i1 = (sy + range - @y1) / R_G
for i in 0..i1
y = R_G*i + @y1
init = shadow_ix(y)
clear_rect(bitmap, init-phx,y-phy,shadow_fx(y)-init+1,R_G)
end
end
def shadow_ix(y)
return @m1.nil? ? @x1 : (y-@n1)/@m1
end
def shadow_fx(y)
return @m2.nil? ? @x2 : (y-@n2)/@m2
end
end
class Block_SD < Block_Surface
attr_reader :type
def initialize(x1,y1,x2,y2)
super(x1,y1,x2,y2)
@type = 0x08
end
def visible?(sx,sy)
return sy > @y1
end
def render_shadow(phx,phy,sx,sy,range,bitmap)
if @x1 == sx
@m1 = nil
else
@m1 = (@y1-sy)/(@x1-sx)
@m1 -= ACC if @m1 > ACC
@n1 = sy - @m1*sx
end
if x2 == sx
@m2 = nil
else
@m2 = (@y2-sy)/(@x2-sx)
@n2 = sy - @m2*sx
end
i1 = ((sy-range).to_i - @y1) / R_G
for i in i1..0
y = @y1 + R_G*i
init = shadow_ix(y)
clear_rect(bitmap, init-phx,y-phy,shadow_fx(y)-init+1,R_G)
end
end
def shadow_ix(y)
return @m1.nil? ? @x1 : (y-@n1)/@m1
end
def shadow_fx(y)
return @m2.nil? ? @x2 : (y-@n2)/@m2
end
end
class Spriteset_Map
include Light_Core
alias kbl_initialize initialize
alias kbl_update update
alias kbl_dispose dispose
def initialize
setup_lights
kbl_initialize
end
def update
kbl_update
update_lights
end
def dispose
kbl_dispose
dispose_lights
end
def dispose_lights
$game_map.lantern.dispose
$game_map.light_sources.each { |source| source.dispose_light }
$game_map.light_surface.bitmap.dispose
$game_map.light_surface.dispose
$game_map.light_surface = nil
end
def update_lights
$game_map.light_surface.bitmap.clear
$game_map.light_surface.bitmap.fill_rect(0,0,640,4 80,$game_map.effect_surface.color)
$game_map.light_sources.each { |source| source.draw_light }
return unless $game_map.lantern.visible
@btr = $game_map.lantern.get_graphic
x = $game_map.lantern.x
y = $game_map.lantern.y
r = $game_map.lantern.range
sx = x + r
sy = y + r
dr = r*2
$game_map.surfaces.each { |s| s.render_shadow(x,y,sx,sy,r,@btr) if s.visible?(sx,sy) && s.within?(x,x+dr,y,y+dr) }
$game_map.light_surface.bitmap.blt($game_map.lante rn.sx, $game_map.lantern.sy,
@btr,Rect.new(0,0,dr,dr), $game_map.lantern.opacity)
end
def setup_lights
@btr = nil
$game_map.lantern.restore
$game_map.light_sources.each { |source| source.restore_light }
$game_map.light_surface = Sprite.new
$game_map.light_surface.bitmap = Bitmap.new(640,480)
$game_map.light_surface.bitmap.fill_rect(0,0,640,4 80,$game_map.effect_surface.color)
$game_map.light_surface.blend_type = 2
$game_map.light_surface.opacity = $game_map.effect_surface.alpha
$game_map.light_surface.z = Surface_Z
end
end
Социальные закладки