miyako/miyako.rb
# Miyako main
=begin
Miyako v0.6
Copyright (C) 2006 Cyross Makoto
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
=end
require 'sdl'
require 'forwardable'
require 'kconv'
require 'jcode'
require 'rbconfig'
$KCODE = 'u'
SDL.init(SDL::INIT_VIDEO | SDL::INIT_AUDIO | SDL::INIT_JOYSTICK)
=begin
=Yuki module
=end
module Yuki
=begin
=Yuki::YukiError class
=end
class YukiError < Exception
end
=begin
=Yuki::Direction class
=end
class Direction
CHAR = 0
FONTCOLOR = 1
FONTSIZE = 2
PAUSE = 3
CLEAR = 4
CR = 5
MESWAIT = 6
SLEEP = 7
LOCATE = 8
YESNO = 9
COMMAND_INIT = 10
COMMAND = 11
LABEL = 12
EXPR = 13
SOUND = 14
IMAGE_INIT = 15
DP = 16
ALPHA = 17
LAYOUT = 18
MOVE = 19
MOVE_TO = 20
SHOW = 21
HIDE = 22
PLOT_APPEND = 23
SCENARIO = 24
COMMAND_APPEND = 25
IMAGE_VIEW = 26
ANIMATION_INIT = 27
ANIMATION_START = 28
ANIMATION_STOP = 29
ANIMATION_RESET = 30
ANIMATION_CHARACTER = 31
EOT = 999
attr_reader :code, :type, :data
@@type_list = [:setting, :exec]
def initialize(c, d = nil, t = :exec)
raise YukiError.new("Illegal type Format! : \":"+t.to_s+"\"") unless @@type_list.include?(t)
@code = c
@data = d
@type = t
end
def append(s)
@data = @data + s if s.class == String
end
@@cr = Direction.new(CR)
@@eot = Direction.new(EOT)
def Direction.cr
return @@cr
end
def Direction.locate(x, y)
return Direction.new(LOCATE, [x, y], :setting)
end
def Direction.yes_no
return Direction.new(Direction::YESNO)
end
def Direction.command(label)
raise YukiError,new("Command Label is Empty!") if label == nil
return Direction.new(Direction::COMMAND, label)
end
def Direction.eot
return @@eot
end
end
=begin
=Yuki::Scenario class
=end
class Scenario
extend Forwardable
attr_reader :text, :separate
def initialize
@separate = false
@text = ""
@msg = Array.new()
@base = Array.new()
@ptr = 0
end
def setup
@base = Compiler.compile(@text, @separate)
@msg = Array.new()
@ptr = 0
end
protected :setup
def compile(str)
@text = String.new(str.toutf8())
setup
end
def text=(str)
compile(str)
end
def separate=(f)
@separate = f
setup
end
def eot?
@ptr == @base.length
end
def nextmsg
return Direction.eot if eot?
dat = @base[@ptr]
@ptr = @ptr + 1
dat
end
def copy
@msg = @base.clone
@ptr = 0
end
def append(d)
if @msg.length > 0 && d.code == Direction::CHAR && @msg.last.code == Direction::CHAR
@msg.last.append(d.data)
else
@msg.push(d)
end
end
def clear
@msg = Array.new
end
def reset(flag = true)
@msg = Array.new if flag
@ptr = 0
end
def get_ptr
return @ptr
end
def set_ptr(p)
@ptr = p if p < @base.length
end
def_delegators(:@msg, :push, :pop, :[], :[]=, :length, :size, :each, :delete, :delete_at)
def_delegators(:@msg, :shift, :unshift, :collect, :map, :select, :inject, :reject, :concat, :empty?, :first, :last)
end
=begin
=Yuki::Plot class
=end
class Plot
def initialize(plot_file)
@scnr = Hash.new
append(plot_file, :Main)
end
def append(plot_file, start = nil)
raise YukiError.new("file not found : #{fname}") unless File.exist?(plot_file)
name = start
@scnr[name] = Scenario.new
line = ""
bg = false
File.open(plot_file, "r"){|f|
while f.eof? == false
l = f.readline.chomp.toutf8
next if l =~ /^[\s\t]+/ # empty line
next if l =~ /^#/ # comment
if l =~ /^:scenario[\s\t]+(.+)$/
raise YukiError.new("not find :end!") if bg
@scnr[name].text = line if name == :Main
name = $1.intern
@scnr[name] = Scenario.new
line = ""
bg = true
elsif l =~ /^:end$/
raise YukiError.new("not find :Scenario!") unless bg
@scnr[name].text = line
bg = false
else
line += l
end
end
raise YukiError.new("not find :end!") if bg
@scnr[name].text = line if name == :Main # Main Script Only
}
end
def [](name)
raise YukiError.new("name is Not String or Symbol!") unless name.kind_of?(String) || name.kind_of?(Symbol)
name = name.intern if name.class == String
raise YukiError.new("Illegal scenario name! : "+ name.to_s) unless @scnr.include?(name)
@scnr[name].reset(false)
return @scnr[name]
end
def listup
@scnr.keys.sort.each{|n| print n.to_s+"\n" }
end
end
=begin
=Yuki::Compiler class
=end
class Compiler
def Compiler::add(cl, str, spr)
return cl if str == ""
if spr
str.split(//).each{|s| cl.push(Direction.new(Direction::CHAR, s)) }
else
cl.push(Direction.new(Direction::CHAR, str))
end
return cl
end
def Compiler::compile(c, spr)
cl = Scenario.new
ctx = c.toutf8().split(/\n/)
tmc = ""
ctx.each{|l|
while l != ""
if l =~ /\\\{/
tmc = tmc + $` if $` != nil
tmc = tmc + "{$1}"
l = $' == nil ? "" : $'
elsif l =~ /\\\}/
tmc = tmc + $` if $` != nil
tmc = tmc + "}"
l = $' == nil ? "" : $'
elsif l =~ /\{([^\}]*)\}/
tm = $` == nil ? "" : $`
com = $1
l = $' == nil ? "" : $'
if com =~ /^color[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::FONTCOLOR, Miyako::Color.to_rgb($1), :setting))
elsif com =~ /^size[=\s\t]+(\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::FONTSIZE, $1.to_i, :setting))
elsif com == "pause"
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::PAUSE))
elsif com == "clear"
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::CLEAR))
elsif com == "cr"
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::CR))
elsif com =~ /^message_wait[=\s\t]+(\d*\.?\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::MESWAIT, $1.to_f))
elsif com =~ /^sleep[=\s\t]+(\d*\.?\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::SLEEP, $1.to_f))
elsif com =~ /^locate[=\s\t]+(\d+),(\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::LOCATE, [$1 ? $1.to_i() : nil,$2 ? $2.to_i() : nil], :setting))
elsif com =~ /^yesno[=\s\t]+([^,\s]+)\s*,\s*(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::YESNO, [$1,$2]))
elsif com =~ /^command[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::COMMAND, $1))
elsif com =~ /^next[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::LABEL, $1))
elsif com =~ /^expr[=\s\t]+(.)\1(.+)\1\1$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::EXPR, [$2, true]))
elsif com =~ /^expr[=\s\t]+(.)(.+)\1$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::EXPR, [$2, false]))
elsif com =~ /^sound[=\s\t]+([^,\s]+)\s*,\s*(\d+)\s*,\s*(.+)$/
raise YukiError,new("Sound flag is 'true' or 'false' !") if $3.downcase != "true" && $3.downcase != "false"
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::SOUND, [$1,$2.to_i,eval($3)]))
elsif com =~ /^image_init[=\s\t]+([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*(.+)$/
raise YukiError,new("Transparent flag is 'true' or 'false' !") if $3.downcase != "true" && $3.downcase != "false"
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::IMAGE_INIT, [$1,$2,eval($3)]))
elsif com =~ /^image_view[=\s\t]+([^,\s]+)\s*,\s*(\d+)\s*,\s*(\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::IMAGE_VIEW, [$1,eval($2),eval($3)]))
elsif com =~ /^animation_init[=\s\t]+([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::ANIMATION_INIT, [$1, $2, eval($3)]))
elsif com =~ /^animation_start[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::ANIMATION_START, $1))
elsif com =~ /^animation_stop[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::ANIMATION_STOP, $1))
elsif com =~ /^animation_reset[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::ANIMATION_RESET, $1))
elsif com =~ /^animation_character[=\s\t]+([^,\s]+)\s*,\s*(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::ANIMATION_CHARACTER, [$1, eval($2)]))
elsif com =~ /^command_init[=\s\t]+([^,\s]+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::COMMAND_INIT, $1))
elsif com =~ /^command_append[=\s\t]+([^,\s]+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::COMMAND_APPEND, $1))
elsif com =~ /^dp[=\s\t]+([^,\s]+)\s*,\s*(\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::DP, [$1, $2.to_i]))
elsif com =~ /^move[=\s\t]+(\d+)\s*,\s*(\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::MOVE, [$1.to_i,$2.to_i]))
elsif com =~ /^move_to[=\s\t]+(\d+)\s*,\s*(\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::MOVE_TO, [$1.to_s,$2.to_s]))
elsif com =~ /^layout[=\s\t]+([^,\s]+)\s*,\s*(\[[^\]]+\])\s*,\s*(\[[^\]]+\])$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::LAYOUT, [$1, $2, $3]))
elsif com =~ /^alpha[=\s\t]+([^,\s]+)\s*,\s*(\d+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::ALPHA, [$1, $2.to_i]))
elsif com =~ /^show[=\s\t]+([^,\s]+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::SHOW, $1))
elsif com =~ /^hide[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::HIDE, $1))
elsif com =~ /^(.)\1(.+)\1\1$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::EXPR, [$2, true]))
elsif com =~ /^(.)(.+)\1$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::EXPR, [$2, false]))
elsif com =~ /^plot_append[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::PLOT_APPEND, $1))
elsif com =~ /^scenario[=\s\t]+(.+)$/
cl = add(cl, tmc + tm, spr)
tmc = ""
cl.push(Direction.new(Direction::SCENARIO, $1.intern))
else
tmc = "#{tmc}{#{com}}"
end
else
cl = add(cl, tmc + l, spr)
tmc = ""
l = ""
end
end
cl = add(cl, tmc, spr)
}
return cl
end
end
=begin
=Yuki::Variables class
=end
class Variables
attr_reader :var, :flag
def initialize
@var = Hash.new
@flag = Hash.new
end
def reset
@var = Hash.new
@flag = Hash.new
end
def [](name)
return @var[name]
end
def []=(name, value)
@var[name] = value
end
def exec(expr)
return instance_eval(expr)
end
end
=begin
=Yuki::Commands class
=end
class Commands
def initialize(filename)
@commands = Hash.new
compile(filename)
end
def [](name)
raise YukiError.new("Command name not found : #{name}") unless @commands.has_key?(name)
return @commands[name]
end
def add(name, title, cansel, clist)
@commands[name] = {:title=>title, :cansel=>cansel, :list=>clist}
end
def append(filename)
compile(filename)
end
def reset
@commands = Hash.new
end
def debug
@commands.keys.sort.each{|k|
print "-----\n"
print "name="+k.tosjis+"\n"
print "title="+@commands[k][:title].tosjis+"\n"
print " ------\n"
@commands[k][:list].each{|cd|
print ">name="+cd["name"].tosjis+"\n"
print ">cond="+cd["condition"].tosjis+"\n"
print ">next="+cd["label"].tosjis+"\n"
print ">scen="+cd["scenario"].tosjis+"\n"
print " ------\n"
}
print "-----\n"
}
end
def compile(filename)
raise YukiError.new("file not found : #{filename}") unless File.exist?(filename)
l = Array.new
label = ""
title = "コマンド?"
cansel = nil
name = ""
cond = "true"
lb = nil
scen = nil
incmd = false
lcnt = 1
File.open(filename, "r"){|f|
while f.eof? == false
line = f.readline.chomp.toutf8
lcnt += 1
next if line =~ /^#/ # comment
next if line =~ /^[\s\t\n\r]*$/ # empty-line
if line =~ /^:begin\s+([^\s]+)/
label = $1
elsif line =~ /^:title\s+([^\s]+)/
title = $1
elsif line =~ /^:cansel\s+([^\s]+)/
cansel = $1
elsif line =~ /^:command\{/
incmd = true
elsif line =~ /^name=(.+)/
name = $1
elsif line =~ /^cond=(.+)/
cond = $1
elsif line =~ /^label=(.+)/
lb = $1
elsif line =~ /^scenario=(.+)/
scen = $1
elsif line =~ /^\}/
raise YukiError.new("unexpected { .. } ! at #{lcnt}") unless incmd
tmp = Hash.new
tmp["name"] = name
tmp["condition"] = cond
tmp["label"] = lb
tmp["scenario"] = scen
l.push(tmp)
tmp = nil
name = ""
cond = "true"
lb = nil
scen = nil
incmd = false
elsif line =~ /^:end/
raise YukiError.new("unexpected :begin - :end ! at #{lcnt}") if label == ""
add(label, title, cansel, l)
label = ""
title = "コマンド?"
l = Array.new
else
raise YukiError.new("syntax error! at #{lcnt}")
end
end
}
end
protected :add, :compile
end
=begin
=Yuki::Director class
=end
class Director
extend Forwardable
@@event_name = [:select_result, :next_label, :select_scenario, :expr_result, :pause, :pause_cansel, :cansel, :cansel_scenario, :yn_scenario]
attr_accessor :var, :event
def initialize(box)
@box = box
@code2method = Hash.new
Direction.constants.each{|c| instance_eval("@code2method[Direction::"+c+"]=self.method(:process_"+c.downcase+")") }
@executing = false
@var = Variables.new
@event = Hash.new
@@event_name.each{|r| @event[r] = nil }
@anim = Hash.new
@message = nil
@wait = Miyako::WaitCounter.new(0)
@sleep = Miyako::WaitCounter.new(0)
@y = 0
@eot = true
@setting_mode = true
@selecting = false
@selects = 0
@title = ""
@cansel = nil
@select2label = nil
@select2num = nil
@select2scenario = nil
@yn2scenario = nil
@res = 0
@plot = nil
@cmds = nil
end
def set_text(str)
@box.msg.text = str
@selecting = false
end
def set_plot(plot_file)
raise YukiError.new("file not found : #{plot_file}") unless File.exist?(plot_file)
@plot = Plot.new(plot_file)
@box.msg = @plot[:Main]
@selecting = false
end
def scenario(scenario_name = :Main)
@box.msg = @plot[scenario_name]
end
def set_commands(com_file)
raise YukiError.new("file not found : #{com_file}") unless File.exist?(com_file)
@cmds = Commands.new(com_file)
end
def append_commands(com_file)
raise YukiError.new("commands is not initialized : #{com_file}") unless @cmd
raise YukiError.new("file not found : #{com_file}") unless File.exist?(plot_file)
@cmds.append(com_file)
end
def start(wait = 0)
@eot = false
@wait = Miyako::WaitCounter.new(wait)
@wait.start
end
def message_loop
begin
@message = @box.msg.nextmsg
@code2method[@message.code].call(@message.data)
end while @message.type == :setting
end
def clear_select_array
@select2scenario = nil
@select2label = nil
@select2num = nil
@yn2scinario = nil
@title = ""
@cansel = nil
@selecting = false
@selects = 0
end
def array_to_bitmap(array)
return array.inject(0){|r, i| r |= i << array.length; r >>= 1 }
end
def update
@@event_name.each{|r| @event[r] = nil }
if @selecting && @selects > 0
if Miyako::Input.pushed_all?(:btn1)
@event[:next_label] = @select2label[@select2num[@res]] if @select2label
@event[:select_result] = @select2num ? @select2num[@res] : @res
@event[:select_scenario] = @select2scenario[@select2num[@res]] if @select2scenario
@event[:yn_scenario] = @yn2scenario[@res] if @yn2scenario
@box.cursorVisible = false
@selecting = false
clear_select_array
return
elsif @cansel && Miyako::Input.pushed_all?(:btn2)
@event[:cansel_scenario] = @cansel
@event[:cansel] = true
@box.cursorVisible = false
@selecting = false
clear_select_array
return
end
dx, dy = Miyako::Input.pushedAmount
@res = (@res + @selects + dy) % @selects
@box.cursorY = @y + @res * @box.font.line_skip
elsif @box.pause?
cansel_pause if Miyako::Input.pushed_all?(:btn1)
elsif @sleep && @sleep.waiting?
return
elsif @eot
return
elsif @wait.finish?
message_loop
end
end
def execute?
return @eot == false
end
def selecting?
return @selecting
end
def text_separate?
@box.msg.separate
end
def text_separate=(f)
@box.msg.separate = f
end
def eot?
return @eot
end
def reset_select
@res = 0
end
def reset
@box.clear
@box.msg.reset
end
def cansel_pause
@box.pause = false
@event[:pause_cansel] = true
end
def yes_no(ynscenarios)
return if @selecting
@yn2scenario = ynscenarios
@box.msg.push(Direction.cr) if @box.kind_of?(Miyako::TextBox)
@box.msg.push(Direction.locate(@box.cursor_params.select_cursor[:r].w, nil))
@box.msg.push(Direction.new(Direction::CHAR, "はい"))
@box.msg.push(Direction.cr)
@box.msg.push(Direction.locate(@box.cursor_params.select_cursor[:r].w, nil))
@box.msg.push(Direction.new(Direction::CHAR, "いいえ"))
@box.msg.push(Direction.cr)
@box.cursorDir = :r # left
@y = @box.textMarginTop + @box.locateY + (@box.font.line_skip - @box.cursor_params.select_cursor[:r].h) / 2
@y += @box.font.line_skip if @box.kind_of?(Miyako::TextBox)
@box.cursorX = @box.textMarginLeft + @box.locateX
@box.cursorY = @y
@res = 0
@selects = 2
@box.cursorVisible = false
@selecting = false
end
def command_inner(c, i)
@box.msg.push(Direction.locate(@box.cursor_params.select_cursor[:r].w, nil))
@box.msg.push(Direction.new(Direction::CHAR, c["name"]))
@box.msg.push(Direction.cr)
@select2scenario.push(c["scenario"])
@select2label.push(c["label"])
@select2num.push(i)
end
def command(clabel)
return if @selecting
@select2scenario = Array.new
@select2label = Array.new
@select2num = Array.new
cnt = 0
@title = @cmds[clabel][:title]
@cansel = @cmds[clabel][:cansel]
@cmds[clabel][:list].each_with_index{|c, i|
if @var.exec(c["condition"])
command_inner(c, i)
cnt += 1
end
}
return if cnt == 0
@box.cursorDir = :r # left
@y = @box.textMarginTop + @box.locateY + (@box.font.line_skip - @box.cursor_params.select_cursor[:r].h) / 2
@box.cursorX = @box.textMarginLeft + @box.locateX
@box.cursorY = @y
@res = 0
@selects = cnt
@selecting = false
@box.cursorVisible = false
end
def process_default
@box.msg.push(@message)
end
def process_char(data)
process_default
@wait.start
end
def process_fontcolor(data)
@box.font.setColor(data)
end
def process_fontsize(data)
@box.font.size = data
end
def process_pause(data)
@box.pause = true
@event[:pause] = true
end
def process_clear(data)
@box.clear
end
def process_cr(data)
@box.cr
end
def process_meswait(data)
@wait = Miyako::WaitCounter.new(data)
@wait.start
end
def process_sleep(data)
@sleep = Miyako::WaitCounter.new(data)
@sleep.start
end
def process_locate(data)
@box.locate(data[0], data[1])
end
def process_yesno(data)
yes_no(data)
end
def process_command(data)
command(data)
end
def process_label(data)
@event[:next_label] = data
end
def process_expr(data)
r = @var.exec(data[0])
@event[:expr_result] = r
@box.msg.push(Direction.new(Direction::CHAR, r.to_s)) if data[1]
end
def process_sound(data)
snd = Miyako::Audio::SE.new(data[0])
snd.setVolume(data[1])
snd.play
if data[2]
while snd.playing? do
end
end
end
def process_show(data)
@var[data.intern].show
end
def process_hide(data)
@var[data.intern].hide
end
def process_image_init(data)
@var[data[0].intern] ||= data[2] ? Miyako::Sprite.new(data[1]) : Miyako::Sprite.new(data[1], nil)
end
def process_image_view(data)
@var[data[0].intern].ow = data[1]
@var[data[0].intern].oh = data[2]
end
def process_animation_init(data)
@var[data[0].intern] = Miyako::SpriteAnimation.new(@var[data[1].intern], data[2])
end
def process_animation_start(data)
@var[data.intern].start
@anim[data.intern] = true
end
def process_animation_stop(data)
@var[data.intern].stop
@anim[data.intern] = false
end
def process_animation_reset(data)
@var[data.intern].pattern(0)
end
def process_animation_character(data)
@var[data[0].intern].character(data[1])
end
def process_command_init(data)
set_commands(data)
end
def process_command_append(data)
append_commands(data)
end
def process_dp(data)
@var[data[0].intern].dp = data[1]
end
def process_move(data)
@var[data[0].intern].move(data[1], data[2])
end
def process_move_to(data)
@var[data[0].intern].move_to(data[1], data[2])
end
def process_alpha(data)
@var[data[0].intern].alpha = data[1]
end
def process_layout(data)
@var[data[0].intern].set_layout(eval(data[1]), eval(data[2]))
end
def process_plot_append(data)
@plot.append(data)
end
def process_scenario(data)
@box.msg = @plot[data]
end
def process_eot(data)
@eot = true
end
def dispose
@code2method = nil
@var = nil
end
protected :process_default
def show
@box.show
if @selects > 0
@selecting = true
@box.cursorVisible = true
end
end
def hide
@box.hide
if @selects > 0
@selecting = false
@box.cursorVisible = false
end
end
def_delegators(:@box, :clear, :visible)
end
end
=begin
=Miyako module
=end
module Miyako
SDL::TTF.init
SDL::Mixer.open(192000, SDL::Mixer::DEFAULT_FORMAT, 2, 16384)
=begin
=Miyako::MiyakoError class
=end
class MiyakoError < Exception
end
osn = Config::CONFIG["target_os"].downcase
@@osName = osn =~ /win/ ? "win" : (osn =~ /linux/ ? "linux" : "other")
def Miyako::getOSName
return @@osName
end
def Miyako::setTitle(title)
raise MiyakoError.new("Title is not String! : "+title.class().to_s()) if title.class != String
SDL::WM.setCaption(getOSName == "win" ? title.to_s().tosjis() : title.to_s().toeuc(), "")
end
=begin
=Miyako::Point class
=end
class Point
attr_accessor :x, :y
def initialize(x, y)
@x, @y = x, y
end
def point
return [@x, @y]
end
def to_s
return @x.to_s+","+@y.to_s
end
end
=begin
=Miyako::Size class
=end
class Size
attr_accessor :w, :h
def initialize(w, h)
@w, @h = w, h
end
def size
[@w, @h]
end
def to_s
return @w.to_s+","+@h.to_s
end
end
=begin
=Miyako::Rect class
=end
class Rect # structure class
extend Forwardable
def initialize(x, y, w, h)
@p = Point.new(x, y)
@s = Size.new(w, h)
end
def rect
[@p.x, @p.y, @s.w, @s.h]
end
def to_s
@p.to_s+","+@s.to_s
end
def_delegators(:@p, :x, :y)
def_delegators(:@s, :w, :h)
end
=begin
=Miyako::Color class
=end
class Color
ShiftX = 0x1000000
ShiftR = 0x10000
ShiftG = 0x100
# color const
BLACK = [ 0, 0, 0]
WHITE = [255,255,255]
BLUE = [ 0, 0,255]
GREEN = [ 0,255, 0]
RED = [255, 0, 0]
CYAN = [ 0,255,255]
PURPLE = [255, 0,255]
YELLOW = [255,255, 0]
LIGHT_GRAY = [200,200,200]
HALF_GRAY = [128,128,128]
HALF_BLUE = [ 0, 0,128]
HALF_GREEN = [ 0,128, 0]
HALF_RED = [128, 0, 0]
HALF_CYAN = [ 0,128,128]
HALF_PURPLE = [128, 0,128]
HALF_YELLOW = [128,128, 0]
DARK_GRAY = [ 80, 80, 80]
DARK_BLUE = [ 0, 0, 80]
DARK_GREEN = [ 0, 80, 0]
DARK_RED = [ 80, 0, 0]
DARK_CYAN = [ 0, 80, 80]
DARK_PURPLE = [ 80, 0, 80]
DARK_YELLOW = [ 80, 80, 0]
def Color::to_rgb(v)
return nil unless v
if v.kind_of?(Array)
raise MiyakoError.new("Illegal color array!") unless v.length == 3
return v
end
return cc2rgb(v) if v.kind_of?(Integer)
return str2rgb(v.to_s) if v.kind_of?(Symbol)
return str2rgb(v) if v.kind_of?(String)
raise MiyakoError.new("Illegal parameter")
end
def Color::str2rgb(str)
return eval("["+str+"]") if str =~ /^\[?(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*)\]?$/
return hex2rgb(str) if str =~ /^\#[\da-fA-F]{6}/
const_str = str.upcase
return eval("Miyako::Color::"+str.upcase) if Module.constants.include?(const_str)
raise MiyakoError.new("Illegal parameter")
end
def Color::hex2rgb(hex)
return [hex[1,2].hex, hex[3,2].hex, hex[5,2].hex]
end
def Color::cc2rgb(cc)
return [(cc % ShiftX) / ShiftR, (cc % ShiftR) / ShiftG, cc % ShiftG]
end
def Color::rgb2cc(r, g, b)
return r * ShiftR + g * ShiftG + b
end
def Color::to_s(cc)
c = to_rgb(cc)
return "["+c[0].to_s+","+c[1].to_s+","+c[2].to_s+"]"
end
end
=begin
=Miyako::SpriteList class
=end
class SpriteList
def initialize
@hash = Hash.new
@list = Array.new
end
def clear
@hash.clear
@list.clear
end
def createList
@hash = @hash.reject{|k, v| @hash[k].empty?() }
@list = Array.new
@hash.keys.sort.each{|k|
@hash[k].keys.sort.each{|kk| @list.push(@hash[k][kk]) if @hash[k][kk] } if @hash[k]
}
end
protected :createList
def add(sprite)
@hash[sprite.dp] ||= {}
@hash[sprite.dp][sprite.id] ||= sprite
createList
end
def replaceDp(sprite, old)
return unless @hash[old]
@hash[old].delete(sprite.id) if @hash[old][sprite.id]
add(sprite)
createList
end
def remove(sprite)
@hash[sprite.dp].delete(sprite.id)
createList
end
def getList
@list
end
end
=begin
=Miyako::Font class
=end
class Font
extend Forwardable
attr_reader :size, :line_skip, :height, :ascent, :descent
FONT_LIST_FILE = "./miyako.fonts"
@@font_cache = {}
@@name_2_font_path = Hash.new
@@font_base_path = Hash.new
@@font_base_path["win"] = ENV['SystemRoot'] ? ["./", ENV['SystemRoot'] + "/fonts/"] : ["./"]
@@font_base_path["linux"] = ["./", "/usr/share/fonts/", "/usr/X11R6/lib/X11/fonts/"]
@@font_base_name = Hash.new
@@font_base_name["win"] = [{:serif=>"msmincho.ttc", :sans_serif=>"msgothic.ttc"},
{:serif=>"mikachan.ttf", :sans_serif=>"mikachan.ttf"}]
@@font_base_name["linux"] = [{:serif=>"sazanami-mincho.ttf", :sans_serif=>"sazanami-gothic.ttf"},
{:serif=>"mikachan.ttf", :sans_serif=>"mikachan.ttf"}]
def Font.search_font_path_file(hash, path)
Dir.glob(path+"*"){|d|
hash = Font.search_font_path_file(hash, d+"/") if test(?d, d)
hash[$1] = d if d =~ /\/([^\/\.]+\.tt[fc])$/
}
return hash
end
def Font.create_font_path_file
unless File.exist?(FONT_LIST_FILE)
osn = Miyako::getOSName
@@font_base_path[osn].each{|p|
@@name_2_font_path = Font.search_font_path_file(@@name_2_font_path, p)
}
File.open(FONT_LIST_FILE, "w"){|f|
@@name_2_font_path.each{|k, v| f.print k+"\t"+v+"\n" }
}
else
@@name_2_font_path = Hash.new
File.open(FONT_LIST_FILE, "r"){|f|
until f.eof?
k, v = f.readline.chomp.split("\t")
@@name_2_font_path[k] = v
end
}
end
end
def Font.findFontPath(fname)
return @@name_2_font_path.fetch(fname, nil)
end
def Font.get_font_inner(fname, fpath, size=16)
@@font_cache[fname] ||= {}
@@font_cache[fname][size] ||= SDL::TTF.open(fpath, size)
return @@font_cache[fname][size]
end
def init_height
@line_skip = @font.line_skip
@height = @font.height
@ascent = @font.ascent
@descent = @font.descent
end
protected :init_height
def initialize(fname, size=16)
@size = size
@col = [255, 255, 255]
@fname = ""
@font = nil
@fname = fname
@fpath = Font.findFontPath(@fname)
raise MiyakoError.new("Cannot Find Font! : #{@fname}") unless @fpath
@font = Font.get_font_inner(@fname, @fpath, @size)
init_height
end
def size=(sz)
@size = sz
@font = Font.get_font_inner(@fname, @fpath, @size)
init_height
end
def textSize(str)
@font.textSize(str.toutf8())
end
def setColor(c)
@col = Color.to_rgb(c)
end
def getColor
@col
end
def _drawText(dst, str, x, y, c, s)
xx = x
maxh = @line_skip
if s != 0
maxh = s if s > maxh
@font.drawSolidUTF8(dst, str, xx, y, c[0], c[1], c[2])
xx = xx + @font.textSize(str)[0]
end
[xx, maxh]
end
def get_offset_x_center(width, length)
return (width - length) / 2
end
def get_offset_x_right(width, length)
return width - length
end
def get_offset_y_middle(height, size)
return (height - size + 1) / 2
end
def get_offset_y_bottom(height, size)
return height - size
end
def get_offset_x(layout_x, row)
return 0 if layout_x == :left
return instance_eval("get_offset_x_"+layout_x[0].id2name+"("+layout_x[1].to_s+","+layout_x[2][row].to_s+")")
end
def get_offset_y(layout_y, row, size)
return 0 if layout_y == :top
return instance_eval("get_offset_y_"+layout_y[0].id2name+"("+layout_y[1][row].to_s+","+size.to_s+")")
end
def drawText_with_layout(dst, str, x=0, y=0, sp=0, layout_x = :left, layout_y = :top)
str = Yuki::Compiler.compile(str, false) if str.class == String
l = ""
row = 0
xp = x + get_offset_x(layout_x, row)
yp = y
c = @col
sz = @line_skip
offset_y = get_offset_y(layout_y, row, sz)
str.each{|s|
if s.code == Yuki::Direction::CHAR
l = l + s.data
elsif s.code == Yuki::Direction::CR
xp, hh = _drawText(dst, l, xp, yp + offset_y, c, sz)
l = ""
row += 1
xp = x + get_offset_x(layout_x, row)
yp = yp + hh + sp
elsif s.code == Yuki::Direction::FONTCOLOR
xp, hh = _drawText(dst, l, xp, yp + offset_y, c, sz)
c = s.data
l = ""
elsif s.code == Yuki::Direction::FONTSIZE
xp, hh = _drawText(dst, l, xp, yp + offset_y, c, sz)
self.size = s.data
sz = @line_skip
offset_y = get_offset_y(layout_y, row, sz)
l = ""
end
}
xp, hh = _drawText(dst, l, xp, yp + offset_y, c, sz) if l != ""
[xp, yp]
end
def drawText(dst, str, x=0, y=0, sp=0)
str = Yuki::Compiler.compile(str, false) if str.class == String
l = ""
xp = x
yp = y
c = @col
sz = @line_skip
str.each{|s|
if s.code == Yuki::Direction::CHAR
l = l + s.data
elsif s.code == Yuki::Direction::CR
xp, hh = _drawText(dst, l, xp, yp, c, sz)
l = ""
xp = x
yp = yp + hh + sp
elsif s.code == Yuki::Direction::FONTCOLOR
xp, hh = _drawText(dst, l, xp, yp, c, sz)
c = s.data
l = ""
elsif s.code == Yuki::Direction::FONTSIZE
xp, hh = _drawText(dst, l, xp, yp, c, sz)
self.size = s.data
sz = @line_skip
l = ""
elsif s.code == Yuki::Direction::LOCATE
xp, hh = _drawText(dst, l, xp, yp, c, sz)
xp = x + s.data[0] if s.data[0] != nil
yp = y + s.data[1] if s.data[1] != nil
l = ""
end
}
xp, hh = _drawText(dst, l, xp, yp, c, sz) if l != ""
[xp, yp]
end
def drawTextRange(dst, str, from = 0, range = 1, x=0, y=0, sp=0)
str = Yuki::Compiler.compile(str, false) if str.class == String
return if from >= str.size
l = ""
xp = x
yp = y
c = @col
sz = @size
p = from
off = 0
loop do
s = str[p]
if s.code == Yuki::Direction::CHAR
l = l + s.data
off += 1
elsif s.code == Yuki::Direction::CR
xp, hh = _drawText(dst, l, xp, yp, c, sz)
l = ""
xp = x
yp = yp + hh + sp
elsif s.code == Yuki::Direction::FONTCOLOR
xp, hh = _drawText(dst, l, xp, yp, c, sz)
c = s.data
@col = c
l = ""
elsif s.code == Yuki::Direction::FONTSIZE
xp, hh = _drawText(dst, l, xp, yp, c, sz)
self.size = s.data
sz = @line_skip
l = ""
elsif s.code == Yuki::Direction::LOCATE
xp, hh = _drawText(dst, l, xp, yp, c, sz)
xp = x + s.data[0] if s.data[0] != nil
yp = y + s.data[1] if s.data[1] != nil
l = ""
end
p += 1
break if (range != 0 && off == range) || p == str.size
end
xp, hh = _drawText(dst, l, xp, yp, c, sz) if l != ""
[xp, yp, p]
end
def _drawTextMild(dst, str, x, y, c, s)
xx = x
maxh = @line_skip
f2 = @font
if s != 0 && s != @line_skip
maxh = s if s > maxh
f2 = Font.get_font_inner(@fname, @fpath, s)
f2.style = @style
end
if s < 24 # 何故か24ドット以下で表示させると文字が崩れるため
f2.drawSolidUTF8(dst, str, xx, y, c[0], c[1], c[2])
else
f2.drawBlendedUTF8(dst, str, xx, y, c[0], c[1], c[2])
end
xx = xx + f2.textSize(str)[0]
[xx, maxh]
end
def drawTextMild(dst, str, x=0, y=0, sp=0)
if @size < 24 # 何故か24ドット以下で表示させると文字が崩れるため
return drawText(dst, str, x, y, sp)
end
str = Yuki::Compiler.compile(str, false) if str.class == String
l = ""
xp = x
yp = y
c = @col
sz = @line_skip
str.each{|s|
if s.code == Yuki::Direction::CHAR
l = l + s.data
elsif s.code == Yuki::Direction::CR
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz)
l = ""
xp = x
yp = yp + hh + sp
elsif s.code == Yuki::Direction::FONTCOLOR
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz)
c = s.data
l = ""
elsif s.code == Yuki::Direction::FONTSIZE
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz)
self.size = s.data
sz = @line_skip
l = ""
elsif s.code == Yuki::Direction::LOCATE
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz)
xp = x + s.data[0] if s.data[0] != nil
yp = y + s.data[1] if s.data[1] != nil
l = ""
end
}
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz) if l != ""
[xp, yp]
end
def drawTextMildRange(dst, str, from = 0, range = 1, x=0, y=0, sp=0)
if @size < 24 # 何故か24ドット以下で表示させると文字が崩れるため
return drawTextRange(dst, str, from, range, x, y, sp)
end
str = Yuki::Compiler.compile(str, false) if str.class == String
return if from >= str.size
l = ""
xp = x
yp = y
c = @col
sz = @size
p = from
off = 0
loop do
s = str[p]
if s.code == Yuki::Direction::CHAR
l = l + s.data
off += 1
elsif s.code == Yuki::Direction::CR
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz)
l = ""
xp = x
yp = yp + hh + sp
elsif s.code == Yuki::Direction::FONTCOLOR
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz)
c = s.data
@col = c
l = ""
elsif s.code == Yuki::Direction::FONTSIZE
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz)
self.size = s.data
sz = @line_skip
l = ""
elsif s.code == Yuki::Direction::LOCATE
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz)
xp = x + s.data[0] if s.data[0] != nil
yp = y + s.data[1] if s.data[1] != nil
l = ""
end
p += 1
break if (range != 0 && off == range) || p == str.size
end
xp, hh = _drawTextMild(dst, l, xp, yp, c, sz) if l != ""
[xp, yp, p]
end
protected :_drawText, :_drawTextMild
Font.create_font_path_file
@@serif_base = nil
@@sans_serif_base = nil
def Font::serif
@@serif_base = @@font_base_name[Miyako::getOSName].detect{|base| Font.findFontPath(base[:serif]) }[:serif] unless @@serif_base
return Font.new(@@serif_base)
end
def Font::sans_serif
@@sans_serif_base = @@font_base_name[Miyako::getOSName].detect{|base| Font.findFontPath(base[:sans_serif]) }[:sans_serif] unless @@sans_serif_base
return Font.new(@@sans_serif_base)
end
def Font::system_font
return Font.serif
end
end
=begin
=Screenモジュール
Miyakoで表示する画面に関するモジュール
=end
module Screen
DefaultWidth = 640
DefaultHeight = 480
BPP = 0
FpsMax = 1000
WINMODES = 2
WINDOW_MODE = 0
FULLSCREEN_MODE = 1
ScreenFlag = Array.new
ScreenFlag.push(SDL::HWSURFACE | SDL::DOUBLEBUF | SDL::ANYFORMAT)
ScreenFlag.push(SDL::ANYFORMAT | SDL::FULLSCREEN)
def Screen::getFpsCnt
return @@fps == 0 ? 0 : (FpsMax + (@@fps+ 1) / 2) / @@fps
end
@@width = DefaultWidth
@@height = DefaultHeight
@@fps = 0 # fps=0 : no-limit
@@fpsView = false
@@fpscnt = Screen::getFpsCnt
@@min_interval = 5
@@min_interval_r = @@min_interval / 1000
@@t = 0
@@freezing = false
@@x = 0
@@y = 0
@@mode = WINDOW_MODE
@@screen = nil
def Screen::setScreen(f)
return false unless SDL.checkVideoMode(@@width, @@height, BPP, f)
@@screen = SDL.setVideoMode(@@width, @@height, BPP, f)
return true
end
def Screen::setSize(w, h, f=true)
return false unless SDL.checkVideoMode(w, h, BPP, ScreenFlag[@@mode])
@@width = w
@@height = h
@@screen = SDL.setVideoMode(@@width, @@height, BPP, ScreenFlag[@@mode])
@@buf = SDL::Surface.new(SDL::HWSURFACE | SDL::SRCCOLORKEY | SDL::SRCALPHA, @@width, @@height, @@screen)
@@buf = @@buf.displayFormat
if f
l = Sprite.getList
if l.length > 0
l.each{|s|
s.setViewPort(0, 0, @@width, @@height)
s.calc_layout
}
end
Plane.getList.each{|p| p.reSize } if l.length > 0
Map.getList.reverse.each{|m| m.reSize } if l.length > 0
end
return true
end
def Screen::check_mode_error
unless Screen::setScreen(ScreenFlag[@@mode])
print "Sorry, this system not supported display...\n";
exit(1)
end
end
def Screen::setMode(v)
if v.to_i == WINDOW_MODE || v.to_i == FULLSCREEN_MODE
@@mode = v.to_i
Screen::check_mode_error
end
end
def Screen::toggleMode
@@mode = (@@mode + 1) % WINMODES
Screen::check_mode_error
end
Screen::check_mode_error
@@buf = SDL::Surface.new(SDL::HWSURFACE | SDL::SRCCOLORKEY | SDL::SRCALPHA, @@width, @@height, @@screen)
@@buf = @@buf.displayFormat
def Screen::fps
@@fps
end
def Screen::fps=(val)
@@fps = val
@@fpscnt = @@fps == 0 ? 0 : Screen::getFpsCnt
end
def Screen::fpsView
@@fpsView
end
def Screen::fpsView=(val)
@@fpsView = val
end
def Screen::screen
@@screen
end
def Screen::w
@@width
end
def Screen::h
@@height
end
def Screen::x
@@x
end
def Screen::x=(v)
@@x = v
end
def Screen::y
@@y
end
def Screen::y=(v)
@@y = v
end
def Screen::update_tick
t = SDL.getTicks
cnt = @@fpscnt - (t - @@t)
if @@fps > 0 && cnt > 0
sleep(cnt > @@min_interval ? cnt / 1000.0 : @@min_interval_r)
else
sleep(@@min_interval_r)
end
t = SDL.getTicks
return t
end
def Screen::update
t = Screen::update_tick
unless @@freezing
Window.getList.each{|ww| ww.drawWindow if ww }
TextBox.getList.each{|ww| ww.drawWindow if ww }
l = Sprite.getList
@@buf.fillRect(0, 0, @@buf.w, @@buf.h, [0, 0, 0]) if l.length > 0
l.each{|s|
if s.visible
@@buf.setClipRect(s.viewPort.x, s.viewPort.y, s.viewPort.w, s.viewPort.h)
s.update
if s.bitmap
if s.effect && s.effect.effecting?
s.effect.update(@@buf)
elsif s.scaleX != 1.0 || s.scaleY != 1.0 || s.angle != 0
SDL.transformBlit(s.bitmap, @@buf, s.angle, s.scaleX, s.scaleY, s.centerX * s.scaleX, s.centerY * s.scaleY, s.x + s.centerX * s.scaleX, s.y + s.centerY * s.scaleY, 0)
else
SDL.blitSurface(s.bitmap, s.ox, s.oy, s.ow, s.oh, @@buf, s.x, s.y)
end
end
if s.font && s.textVisible && s.text && s.text != ""
x = s.x+s.textMarginLeft+s.locateX
y = s.y+s.textMarginTop+s.locateY
@@buf.setClipRect(x, y, s.textAreaW-s.textMarginLeft-s.textMarginRight, s.textAreaH-s.textMarginTop-s.textMarginBottom)
s.nowLocateX, s.nowLocateY = s.font.drawTextMild(@@buf, s.msg, x, y, 0)
end
if s.drawBlock
@@buf.lock
s.drawBlock.call(@@buf)
@@buf.unlock
end
elsif s.effect && s.effect.effecting?
s.effect.update(@@buf)
end
@@buf.setClipRect(0, 0, @@width, @@height)
@@screen.setClipRect(0, 0, @@width, @@height)
}
end
SDL.blitSurface(@@buf, 0, 0, 0, 0, @@screen, @@x, @@y)
Font.systemFont.drawText(@@screen, ((FpsMax/(t - @@t)).to_s() + " fps"), 0, 0, 0) if @@fpsView
@@t = t
@@screen.flip
@@screen.fillRect(0,0,@@screen.w,@@screen.h,[0,0,0])
end
def Screen::freeze
@@freezing = true
end
def Screen::freezing?
@@freezing
end
def Screen::trasition
@@freezing = false
end
end
=begin
=WaitCounterクラス
=end
class WaitCounter # Time to Count
SECOND2TICK = 1000
def WaitCounter.get_second_to_tick(s)
return (SECOND2TICK * s).to_i
end
def initialize(seconds)
@seconds = seconds
@wait = WaitCounter.get_second_to_tick(@seconds)
@st = 0
@counting = false
end
def start
@st = SDL.getTicks
@counting = true
end
def stop
@counting = false
@st = 0
end
def wait_inner(f)
return !f unless @counting
t = SDL.getTicks
return f unless (t - @st) >= @wait
@counting = false
return !f
end
def waiting?
return wait_inner(true)
end
def finish?
return wait_inner(false)
end
def wait
st = SDL.getTicks
t = SDL.getTicks
until (t - st) >= @wait do
t = SDL.getTicks
end
end
end
=begin
=Bitmapクラス
画像領域を示すクラス。スプライトもこのBitmapを使用して貼り付ける
実際はSDL::Surfaceクラスを継承したものなので、SDL::Surfaceクラスで定義されている描画命令を全てサポートする。
但し、実装は後述のSprite.drawBlockプロパティにブロックとして登録した方が危険性が少ない
=end
class Bitmap < SDL::Surface
def Bitmap.create(w, h)
SDL::Surface.new(SDL::HWSURFACE | SDL::SRCCOLORKEY | SDL::SRCALPHA, w, h, Screen::screen)
end
end
=begin
=Inputモジュール
Miyakoで使用している入力デバイス情報を管理しているモジュール
=end
module Input
DIRS = 4
BTNS = 12
DOWN = 0
LEFT = 1
RIGHT = 2
UP = 3
BTN1 = 4
BTN2 = 5
BTN3 = 6
BTN4 = 7
BTN5 = 8
BTN6 = 9
BTN7 = 10
BTN8 = 11
BTN9 = 12
BTN10 = 13
BTN11 = 14
BTN12 = 15
@@joy = nil
@@joy = SDL::Joystick.open(0) if SDL::Joystick.num >= 1
@@quit = false
@@exbtn = [:spc, :ent, :esc, :alt, :ctl, :sft]
@@sym2btn = Hash[SDL::Key::SPACE, :spc, SDL::Key::RETURN, :ent, SDL::Key::ESCAPE, :esc]
@@mod2btn = Hash[SDL::Key::MOD_LALT, :alt, SDL::Key::MOD_RALT, :alt, SDL::Key::MOD_LCTRL, :ctl, SDL::Key::MOD_RCTRL, :ctl, SDL::Key::MOD_LSHIFT, :sft, SDL::Key::MOD_RSHIFT, :sft]
@@trigger = Hash.new
@@pushed = Hash.new
@@pushed_pre = Hash.new
@@exbtn.each{|b|
@@trigger[b] = false
@@pushed[b] = false
@@pushed_pre[b] = false
}
@@trigger_dir = [0, 0, 0, 0]
@@trigger_btn = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
@@pushed_dir = [0, 0, 0, 0]
@@pushed_btn = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
@@pushed_dir_pre = [0, 0, 0, 0]
@@pushed_btn_pre = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
@@btn_list = [SDL::Key::Z, SDL::Key::X, SDL::Key::C,
SDL::Key::A, SDL::Key::S, SDL::Key::D,
SDL::Key::Q, SDL::Key::W, SDL::Key::E,
SDL::Key::V, SDL::Key::B, SDL::Key::N]
@@dir_list = [SDL::Key::KP2, SDL::Key::KP4, SDL::Key::KP6, SDL::Key::KP8]
@@dir_list2 = [SDL::Key::DOWN, SDL::Key::LEFT, SDL::Key::RIGHT, SDL::Key::UP]
@@move_amount_x = [0, -1, 1, 0]
@@move_amount_y = [1, 0, 0, -1]
@@input2num = {:down=>0x000001, :left=>0x000002,:right=>0x000004, :up=>0x000008,
:btn1=>0x000010, :btn2=>0x000020, :btn3=>0x000040, :btn4=>0x000080,
:btn5=>0x000100, :btn6=>0x000200, :btn7=>0x000400, :btn8=>0x000800,
:btn9=>0x001000,:btn10=>0x002000,:btn11=>0x004000,:btn12=>0x008000,
:spc=>0x010000, :ent=>0x020000, :esc=>0x040000, :alt=>0x080000,
:ctl=>0x100000}
@@pushed_bitmap = 0
@@trigger_bitmap = 0
def Input::set_btn(n)
@@trigger_btn[n] = 1
if @@pushed_btn_pre[n] == 0
@@pushed_btn[n] = 1
@@pushed_btn_pre[n] = 1
end
end
def Input::reset_btn(n)
@@trigger_btn[n] = 0
@@pushed_btn[n] = 0
@@pushed_btn_pre[n] = 0
end
def Input::set_dir(n)
@@trigger_dir[n] = 1
if @@pushed_dir_pre[n] == 0
@@pushed_dir[n] = 1
@@pushed_dir_pre[n] = 1
end
end
def Input::reset_dir(n)
@@trigger_dir[n] = 0
@@pushed_dir[n] = 0
@@pushed_dir_pre[n] = 0
end
def Input::set_ex(n)
@@trigger[n] = true
if @@pushed_pre[n] == false
@@pushed[n] = true
@@pushed_pre[n] = true
end
end
def Input::reset_ex(n)
@@trigger[n] = false
@@pushed[n] = false
@@pushed_pre[n] = false
end
def Input::array_to_bitmap(array)
return array.inject(0){|r, i| r |= i << array.length; r >>= 1 }
end
def Input::set_bitmap(dir, btn, ext)
b = array_to_bitmap(dir)
b |= array_to_bitmap(btn) << 4
[:spc, :ent, :esc, :alt, :ctl].each{|e| b |= @@input2num[e] if ext[e] }
return b
end
def Input::update
SDL::Joystick.updateAll
@@pushed_btn_pre.each_with_index{|p, i| @@pushed_btn[i] = 0 if p == 1 }
@@pushed_dir_pre.each_with_index{|p, i| @@pushed_dir[i] = 0 if p == 1 }
@@exbtn.each{|b| @@pushed[b] = false if @@pushed_pre[b] }
while e = SDL::Event2.poll
case e
when SDL::Event2::Quit
@@quit = true
when SDL::Event2::KeyDown
@@btn_list.length.times{|b| set_btn(b) if e.sym == @@btn_list[b] }
@@dir_list.length.times{|d| set_dir(d) if e.sym == @@dir_list[d] }
@@dir_list2.length.times{|d| set_dir(d) if e.sym == @@dir_list2[d] }
@@sym2btn.keys.each{|s| set_ex(@@sym2btn[s]) if e.sym == s }
@@mod2btn.keys.each{|m| set_ex(@@mod2btn[m]) if e.mod & m == m}
when SDL::Event2::KeyUp
@@btn_list.length.times{|b| reset_btn(b) if e.sym == @@btn_list[b] }
@@dir_list.length.times{|d| reset_dir(d) if e.sym == @@dir_list[d] }
@@dir_list2.length.times{|d| reset_dir(d) if e.sym == @@dir_list2[d] }
@@sym2btn.keys.each{|s| reset_ex(@@sym2btn[s]) if e.sym == s }
@@mod2btn.keys.each{|m| reset_ex(@@mod2btn[m]) if e.mod & m == m }
when SDL::Event2::JoyAxis
if e.axis == 0
if e.value >= 16384
set_dir(2)
elsif e.value < -16384
set_dir(1)
else
reset_dir(1)
reset_dir(2)
end
elsif e.axis == 1
if e.value >= 16384
set_dir(0)
elsif e.value < -16384
set_dir(3)
else
reset_dir(0)
reset_dir(3)
end
end
when SDL::Event2::JoyButtonDown
set_btn(e.button) if e.button < @@trigger_btn.length
when SDL::Event2::JoyButtonUp
reset_btn(e.button) if e.button < @@trigger_btn.length
when SDL::Event2::Quit
@@quit = true
end
if @@trigger[:alt] && @@pushed[:ent]
Screen.toggleMode
end
end
@@trigger_bitmap = set_bitmap(@@trigger_dir, @@trigger_btn, @@trigger)
@@pushed_bitmap = set_bitmap(@@pushed_dir, @@pushed_btn, @@pushed)
end
def Input::trigger?(num)
return @@trigger_btn[num - DIRS] == 1 if num >= DIRS
return @@trigger_dir[num] == 1
end
def Input::pushed?(num)
return @@pushed_btn[num - DIRS] == 1 if num >= DIRS
return @@pushed_dir[num] == 1
end
def Input::buttons_to_bitmap(inputs)
return inputs.flatten.inject(0){|r, i| r |= @@input2num[i]}
end
def Input::trigger_all?(*inputs)
return @@trigger_bitmap != 0 if inputs.length == 0
f = buttons_to_bitmap(inputs)
return @@trigger_bitmap & f == f
end
def Input::trigger_any?(*inputs)
return @@trigger_bitmap != 0 if inputs.length == 0
f = buttons_to_bitmap(inputs)
return @@trigger_bitmap & f != 0
end
def Input::pushed_all?(*inputs)
return @@pushed_bitmap != 0 if inputs.length == 0
f = buttons_to_bitmap(inputs)
return @@pushed_bitmap & f == f
end
def Input::pushed_any?(*inputs)
return @@pushed_bitmap != 0 if inputs.length == 0
f = buttons_to_bitmap(inputs)
return @@pushed_bitmap & f != 0
end
def Input::triggerDirNum
4.times{|d| return d if @@trigger_dir[d] == 1 }
return -1
end
def Input::pushedDirNum
4.times{|d| return d if @@pushed_dir[d] == 1 }
return -1
end
def Input::triggerAmount
amt_x = 0
amt_y = 0
@@trigger_dir.length.times{|n|
amt_x = amt_x + @@trigger_dir[n] * @@move_amount_x[n]
amt_y = amt_y + @@trigger_dir[n] * @@move_amount_y[n]
}
return [amt_x, amt_y]
end
def Input::pushedAmount
amt_x = 0
amt_y = 0
@@pushed_dir.length.times{|n|
amt_x = amt_x + @@pushed_dir[n] * @@move_amount_x[n]
amt_y = amt_y + @@pushed_dir[n] * @@move_amount_y[n]
}
return [amt_x, amt_y]
end
def Input::amountX(dir)
return @@move_amount_x[dir]
end
def Input::amountY(dir)
return @@move_amount_y[dir]
end
def Input::triggerDir
return @@trigger_dir
end
def Input::pushedDir
return @@pushed_dir
end
def Input::triggerBtn
return @@trigger_btn
end
def Input::pushedBtn
return @@pushed_btn
end
def Input::triggerSpc?
return @@trigger[:spc]
end
def Input::triggerEnter?
return @@trigger[:ent]
end
def Input::triggerEscape?
return @@trigger[:esc]
end
def Input::triggerAlt?
return @@trigger[:alt]
end
def Input::triggerCtrl?
return @@trigger[:ctl]
end
def Input::triggerShift?
return @@trigger[:sft]
end
def Input::pushedSpc?
return @@pushed[:spc]
end
def Input::pushedEnter?
return @@pushed[:ent]
end
def Input::pushedEscape?
return @@pushed[:esc]
end
def Input::pushedAlt?
return @@pushed[:alt]
end
def Input::pushedCtrl?
return @@pushed[:ctl]
end
def Input::pushedShift?
return @@pushed[:sft]
end
def Input::quit?
return @@quit
end
end
=begin
=Audioモジュール
音楽関連のモジュール
==Audio::BGMクラス
BGMを管理するクラス
==Audio::SEクラス
効果音を管理するクラス。
=end
module Audio
class BGM
def initialize(fname, loops = true)
@bgm = SDL::Mixer::Music.load(fname)
@loops = loops
end
def setVolume(v)
SDL::Mixer.setVolumeMusic(v)
end
def play
l = @loops ? -1 : 0
SDL::Mixer.playMusic(@bgm, l).to_s()
end
def fadeIn(msec=5000)
l = @loops ? -1 : 0
SDL::Mixer.fadeInMusic(@bgm, l, msec)
end
def playing?
SDL::Mixer.playMusic?
end
def pause
SDL::Mixer.pauseMusic if SDL::Mixer.playMusic?
end
def resume
SDL::Mixer.resumeMusic if SDL::Mixer.pauseMusic?
end
def stop
SDL::Mixer.haltMusic if SDL::Mixer.playMusic?
end
def fadeOut(msec = 5000, wmode = false)
if SDL::Mixer.playMusic?
SDL::Mixer.fadeOutMusic(msec)
SDL::delay(msec) if wmode
end
end
end
class SE
def initialize(fname)
@wave = SDL::Mixer::Wave.load(fname)
@channel = -1
end
def play
@channel = SDL::Mixer.playChannel(-1, @wave, 0)
end
def playing?
return SDL::Mixer.play?(@channel) if @channel != -1
return false
end
def stop
SDL::Mixer.halt(@channel) if @channel != -1
end
def setVolume(v)
@wave.setVolume(v)
end
end
end
def Miyako::update
Input::update
Screen::update
end
=begin
=Spriteクラス
スプライト全般を管理するクラス
=end
class Sprite
extend Forwardable
attr_accessor :ox, :oy, :visible, :angle, :centerX, :centerY
attr_accessor :textAreaW, :textAreaH
attr_accessor :font, :drawBlock, :textVisible
attr_accessor :nowLocateX, :nowLocateY, :effect
attr_reader :x, :y, :ow, :oh
attr_reader :dp, :id, :alpha, :scaleX, :scaleY
attr_reader :textMarginLeft, :textMarginTop, :textMarginRight, :textMarginBottom
attr_reader :locateX, :locateY, :msg, :tr_color
@@sprites = SpriteList.new
@@idcnt = 1
@@draw_list = {:line => {:normal=>"@img.draw_line", :fill=>"@img.draw_line"},
:rect => {:normal=>"@img.draw_rect", :fill=>"@img.fill_rect"},
:circle => {:normal=>"@img.draw_circle", :fill=>"@img.draw_filled_circle"},
:ellipse => {:normal=>"@img.draw_ellipse", :fill=>"@img.draw_filled_ellipse"}}
def setup
@img=nil
@viewport = Rect.new(0, 0, Screen.w, Screen.h)
@ow = 0
@oh = 0
@alpha = 255
@aa = false
@tr_color = Color::BLACK
@angle = 0
@scaleX = 1.0
@scaleY = 1.0
@font = nil
@msg = Yuki::Scenario.new()
@drawBlock = nil
@update = nil
@effect = nil
@x = 0
@y = 0
@w = 0
@h = 0
@dp = 0
@ox = 0
@oy = 0
@centerX = 0
@centerY = 0
@collisionX = 0
@collisionY = 0
@collisionW = 0
@collisionH = 0
@textAreaW = 0
@textAreaH = 0
@textMarginLeft = 0
@textMarginTop = 0
@textMarginRight = 0
@textMarginBottom = 0
@locateX = 0
@locateY = 0
@nowLocateX = 0
@nowLocateY = 0
@visible = false
@textVisible = false
@enable_layout = true
@layoutX = :left
@layoutY = :top
@layoutXi = 0
@layoutYi = 0
@layoutXf = 0.0
@layoutYf = 0.0
@base_x = 0
@base_y = 0
@base_width = nil
@base_height = nil
@layout_offset_x = 0
@layout_offset_y = 0
@layout_side_x = :inside
@layout_side_y = :inside
@snap_sprite = nil
@snap_children = Array.new
end
protected :setup
def initialize(img_data, tr_data = Color::BLACK, alpha = 255, is_fill = false)
setup()
bitmap = nil
if img_data.kind_of?(Size)
bitmap = Bitmap.create(img_data.w, img_data.h)
is_fill = true
elsif img_data.kind_of?(Array)
bitmap = Bitmap.create(img_data[0], img_data[1])
is_fill = true
elsif img_data.kind_of?(SDL::Surface)
bitmap = img_data
elsif img_data.kind_of?(String)
bitmap = Bitmap.load(img_data)
tr_data = Point.new(0, 0) if tr_data
else
raise MiyakoError.new("Illegal Sprite parameter!")
end
@tr_color = nil
if tr_data.class == Point
@tr_color = Color.to_rgb(bitmap.getPixel(tr_data.x, tr_data.y))
elsif tr_data
@tr_color = Color.to_rgb(tr_data)
end
bitmap.fill_rect(0, 0, bitmap.w, bitmap.h, @tr_color) if @tr_color && is_fill
bitmap.setColorKey(SDL::SRCCOLORKEY|SDL::RLEACCEL, @tr_color) if tr_data
bitmap.setAlpha(SDL::SRCALPHA|SDL::RLEACCEL, alpha)
self.bitmap = bitmap.displayFormat
self.alpha = alpha
@id = @@idcnt
@@idcnt = @@idcnt + 1
@@sprites.add(self)
end
def Sprite.create_plane(bmp, w, h, tr_data=[0,0,0], alpha=255)
img=Bitmap.create(w, h)
(h / bmp.h).times{|y|
(w / bmp.w).times{|x|
SDL.blitSurface(bmp, 0, 0, 0, 0, img, x * bmp.w, y * bmp.h)
}
}
spr = Sprite.new(img, tr_data, alpha)
spr.ow = Screen::screen.w
spr.oh = Screen::screen.h
return spr
end
def crate_transform_sprite(xscale, yscale, angle)
return Sprite.new(@img.transformSurface(org_spr.tr_color,angle,xscale,yscale,SDL::TRANSFORM_AA), @tr_color, @alpha)
end
def_delegators(:@img, :w, :h)
def x=(v)
@x = v
@enable_layout = false
end
def y=(v)
@y = v
@enable_layout = false
end
def scaleX=(v)
@scaleX = v.to_f()
end
def scaleY=(v)
@scaleY = v.to_f()
end
def bitmap
@img
end
def bitmap=(bmp)
@img = bmp
@ow = @img.w
@oh = @img.h
@w = @img.w
@h = @img.h
@collisionW = @ow
@collisionH = @oh
end
def draw_line(rect, color, attribute = :normal)
instance_eval(@@draw_list[:line][attribute]+"("+rect.to_s+","+Color.to_s(color)+")") if @@draw_list[:line][attribute]
end
def draw_rect(rect, color, attribute = :normal)
instance_eval(@@draw_list[:rect][attribute]+"("+rect.to_s+","+Color.to_s(color)+")") if @@draw_list[:rect][attribute]
end
def draw_circle(point, r, color, attribute = :normal)
instance_eval(@@draw_list[:circle][attribute]+"("+point.to_s+","+r.to_s+","+Color.to_s(color)+")") if @@draw_list[:circle][attribute]
end
def draw_ellipse(rect, color, attribute = :normal)
instance_eval(@@draw_list[:ellipse][attribute]+"("+rect.to_s+","+Color.to_s(color)+")") if @@draw_list[:ellipse][attribute]
end
def draw_text(str, x = 0, y = 0, sp = 0)
raise MiyakoError.new("Sprite object is not regist font!") unless @font
@font.drawTextMild(self.bitmap, str, x, y, sp)
end
def alpha=(val)
@alpha = val
@img.setAlpha(SDL::SRCALPHA|SDL::RLEACCEL, @alpha)
end
def dp=(val)
odp = @dp
@dp = val
@@sprites.replaceDp(self, odp)
end
def ow=(v)
@ow = v
@collisionW = @ow
end
def oh=(v)
@oh = v
@collisionH = @oh
end
def get_base_x
return @base_width == nil ? 0 : @base_x
end
def get_base_y
return @base_height == nil ? 0 : @base_y
end
def get_base_width
return @base_width == nil ? Screen.w : @base_width
end
def get_base_height
return @base_height == nil ? Screen.h : @base_height
end
def layout_left_inside
return get_base_x + (get_base_width * @layoutXf + @layoutXi).to_i + @layout_offset_x
end
def layout_center_inside
return get_base_x + ((get_base_width - @ow) / 2 + @layoutXi).to_i + @layout_offset_x
end
def layout_right_inside
return get_base_x + (get_base_width * (1.0 - @layoutXf) - @layoutXi - @ow).to_i + @layout_offset_x
end
def layout_top_inside
return get_base_y + (get_base_height * @layoutYf + @layoutYi).to_i + @layout_offset_y
end
def layout_middle_inside
return get_base_y + ((get_base_height - @oh) / 2 + @layoutYi).to_i + @layout_offset_y
end
def layout_bottom_inside
return get_base_y + (get_base_height * (1.0 - @layoutYf) - @layoutYi - @oh).to_i + @layout_offset_y
end
def layout_left_outside
return get_base_x - (get_base_width * @layoutXf + @layoutXi).to_i - @ow + @layout_offset_x
end
def layout_center_outside
return get_base_x + (get_base_width / 2 + @layoutXi).to_i + @layout_offset_x
end
def layout_right_outside
return get_base_x + get_base_width + (get_base_width * @layoutXf + @layoutXi).to_i + @layout_offset_x
end
def layout_top_outside
return get_base_y - (get_base_height * @layoutYf + @layoutYi).to_i - @oh + @layout_offset_y
end
def layout_middle_outside
return get_base_y + (get_base_height / 2 + @layoutYi).to_i + @layout_offset_y
end
def layout_bottom_outside
return get_base_y + get_base_height + (get_base_height * @layoutYf + @layoutYi).to_i + @layout_offset_y
end
def calc_layout
return unless @enable_layout
instance_eval("@x = layout_"+@layoutX.id2name+"_"+@layout_side_x.id2name)
instance_eval("@y = layout_"+@layoutY.id2name+"_"+@layout_side_y.id2name)
@snap_children.each{|sc|
sc.snap
}
end
protected :layout_left_inside, :layout_right_inside, :layout_center_inside
protected :layout_top_inside, :layout_middle_inside, :layout_bottom_inside
protected :layout_left_outside, :layout_right_outside, :layout_center_outside
protected :layout_top_outside, :layout_middle_outside, :layout_bottom_outside
protected :get_base_width, :get_base_height
protected :get_base_x, :get_base_y
@@layout_list_x = [:left, :center, :right]
@@layout_list_y = [:top, :middle, :bottom]
@@layout_side_list = [:inside, :outside]
def set_side_x(xside)
@layout_side_x = xside if @@layout_side_list.include?(xside)
end
def set_side_y(yside)
@layout_side_y = yside if @@layout_side_list.include?(yside)
end
def set_side(xside, yside)
set_side_x(xside)
set_side_y(yside)
calc_layout
end
def get_side
[@layout_side_x, @layout_side_y]
end
def set_base_size(w, h)
@base_width, @base_height = [w, h]
calc_layout
end
def reset_base_size
@base_width, @base_height = [nil, nil]
calc_layout
end
def set_base_point(x, y)
@base_x = x if x != nil
@base_y = y if y != nil
calc_layout
end
def snap(spr = nil)
unless spr == nil
@snap_sprite.delete_snap_child(self) unless @snap_sprite == nil
@snap_sprite = spr
spr.add_snap_child(self)
end
@base_x, @base_y, @base_width, @base_height = @snap_sprite.rect.rect unless @snap_sprite == nil
calc_layout
end
def reset_snap
@snap_sprite = nil
@snap_children = Array.new
calc_layout
end
def add_snap_child(spr)
@snap_children.push(spr) unless @snap_children.include?(spr)
calc_layout
end
def delete_snap_child(spr)
@snap_children.delete(spr) if @snap_children.include?(spr)
calc_layout
end
def get_snap_children
return @snap_children
end
def set_snap_children(cs)
@snap_children.each{|c|
c.set_snap_sprite(nil)
}
@snap_children = cs
@snap_children.each{|c|
c.set_snap_sprite(self)
}
calc_layout
end
def get_snap_sprite
return @snap_sprite
end
def set_snap_sprite(ss)
@snap_sprite.delete_snap_child(self) unless @snap_sprite == nil
@snap_sprite = ss
@snap_sprite.add_snap_child(self) unless @snap_sprite == nil
calc_layout
end
def set_base(x, y, w, h)
@base_x = x if x != nil
@base_y = y if y != nil
@base_width = w if w != nil
@base_height = h if h != nil
calc_layout
end
def reset_base
@base_x, @base_y, @base_width, @base_height = [0, 0, nil, nil]
calc_layout
end
def get_base
return [@base_x, @base_y, @base_w, @base_h]
end
def set_offset_x(x)
@layout_offset_x = x
calc_layout
end
def set_offset_y(y)
@layout_offset_y = y
calc_layout
end
def set_offset(x, y)
set_offset_x(x) if x != nil
set_offset_y(y) if y != nil
end
def get_offset_x
return @layout_offset_x
end
def get_offset_y
return @layout_offset_y
end
def get_offset
return [get_offset_x, get_offset_y]
end
def reset_offset
@layout_offset_x = 0
@layout_offset_y = 0
calc_layout
end
def enable_layout
@enable_layout = true
calc_layout
end
def enable_layout?
return @enable_layout
end
def disenable_layout
@enable_layout = false
end
def set_layout(x, y)
if x.class == Symbol
@layoutX = x
@layoutXi, @layoutXf = [0, 0.0]
elsif x.class == Array
x.each{|v|
@layoutX = v if v.kind_of?(Symbol) && @@layout_list_x.include?(v)
@layout_side_x = v if v.kind_of?(Symbol) && @@layout_side_list.include?(v)
@layoutXi = v if v.kind_of?(Integer)
@layoutXf = v if v.kind_of?(Float)
}
end
if y.class == Symbol
@layoutY = y
@layoutYi, @layoutYf = [0, 0.0]
elsif y.class == Array
y.each{|v|
@layoutY = v if v.kind_of?(Symbol) && @@layout_list_y.include?(v)
@layout_side_y = v if v.kind_of?(Symbol) && @@layout_side_list.include?(v)
@layoutYi = v if v.kind_of?(Integer)
@layoutYf = v if v.kind_of?(Float)
}
end
@enable_layout = true
calc_layout
end
def reset_layout
@layoutX, @layoutXi, @layoutXf = [:left, 0, 0.0]
@layoutY, @layoutXi, @layoutXf = [:top, 0, 0.0]
reset_base
reset_offset
end
def get_layout_x
[@layoutX, @layoutXf, @layoutXi]
end
def get_layout_y
[@layoutY, @layoutYf, @layoutYi]
end
def get_layout
[get_layout_x, get_layout_y]
end
def centering
set_layout(:center, :middle)
end
def move(x, y)
if @enable_layout
@layout_offset_x += x
@layout_offset_y += y
calc_layout
else
@x += x
@y += y
end
end
def move_to(x, y)
move(x - @x, y - @y)
end
def setCollisionMargin(x, y, w, h)
@collisionX = x
@collisionY = y
@collisionW = w
@collisionH = h
end
def getCollisionMargin
Rect.new(@x + @collisionX, @y + @collisionY, @collisionW, @collisionH)
end
def viewPort
@viewport
end
def setViewPort(x, y, w, h)
@viewport = Rect.new(x, y, w, h)
end
def in_bounds?(dx, dy, flag = true)
return [in_bounds_x?(dx, flag), in_bounds_y?(dy, flag)]
end
def in_bounds_x?(dx, flag = true)
nx = @x + dx
return false if flag & (nx == @viewport.x | ((nx + @ow) == (@viewport.x + @viewport.w)))
return nx > @viewport.x & (nx + @ow) < (@viewport.x + @viewport.w)
end
def in_bounds_y?(dy, flag = true)
ny = @y + dy
return false if flag & (ny == @viewport.y | ((ny + @oh) == (@viewport.y + @viewport.h)))
return ny > @viewport.y & (ny + @oh) < (@viewport.y + @viewport.h)
end
def in_bounds_ex?(dx, dy, flag = true)
return [in_bounds_ex_x?(dx, flag), in_bounds_ex_y?(dy, flag)]
end
def in_bounds_ex_x?(dx, flag = true)
nx = @x + dx
return -1 if (nx < @viewport.x) | (flag & (nx == @viewport.x))
r = @viewport.x + @viewport.w
return 1 if ((nx + @ow) > r) | (flag & ((nx + @ow) == r))
return 0
end
def in_bounds_ex_y?(dy, flag = true)
ny = @y + dy
return -1 if (ny < @viewport.y) | (flag & (ny == @viewport.y))
b = @viewport.y + @viewport.h
return 1 if ((ny + @oh) > b) | (flag & ((ny + @oh) == b))
return 0
end
def round(dx, dy, flag = true)
return [round_x(dx, flag), round_y(dy, flag)]
end
def round_x(dx, flag = true)
fx = in_bounds_ex_x?(dx, flag)
case fx
when -1
self.move_to(0, @y)
when 0
self.move_to(@x + dx, @y)
when 1
self.move_to(@viewport.x + @viewport.w - @ow, @y)
end
return fx
end
def round_y(dy, flag = true)
fy = in_bounds_ex_y?(dy, flag)
case fy
when -1
self.move_to(@x, 0)
when 0
self.move_to(@x, @y + dy)
when 1
self.move_to(@x, @viewport.y + @viewport.h - @oh)
end
return fy
end
def_delegators(:@msg, :compile, :text, :text=, :separate, :separate=)
def_delegators(:@msg, :copy, :nextmsg, :append)
def_delegators(:@msg, :clear, :reset, :next, :append)
def_delegators(:@msg, :push, :pop, :[], :[]=, :length, :size, :each)
def getDirection
@msg
end
def setDirection(cx)
@msg = cx
end
def setTextArea(w, h)
@textAreaW = w
@textAreaH = h
end
def textMarginLeft=(v)
@textMarginLeft = v
end
def textMarginTop=(v)
@textMarginTop = v
end
def textMarginRight=(v)
@textMarginRight = v
end
def textMarginBottom=(v)
@textMarginBottom = v
end
def setTextMargin(l, t, r, b)
@textMarginLeft = l
@textMarginTop = t
@textMarginRight = r
@textMarginBottom = b
end
def locateX=(x)
@locateX = x if x != nil
end
def locateY=(y)
@locateY = y if y != nil
end
def locate(x, y)
@locateX = x if x != nil
@locateY = y if y != nil
end
def getLocate
[@locateX, @locateY]
end
def rect
Rect.new(@x, @y, @ow, @oh)
end
def update
if @update != nil
@update.call(self)
end
if block_given?
yield self
end
end
def update=(u)
@update = u
end
def collision?(spr)
r1 = getCollisionMargin
r2 = spr.getCollisionMargin
return SDL::CollisionMap.boundingBoxCheck(r1.x, r1.y, r1.w, r1.h, r2.x, r2.y, r2.w, r2.h)
end
def show
@visible = true
end
def hide
@visible = false
end
@@backup_list = [:@x, :@y, :@enable_layout, :@layoutX, :@layoutY, :@layoutXi, :@layoutYi,
:@layoutXf, :@layoutYf, :@base_x, :@base_y, :@base_width, :@base_height,
:@layout_offset_x, :@layout_offset_y, :@layout_side_x, :@layout_side_y,
:@snap_sprite, :@snap_children]
def backup
bdata = Hash.new
@@backup_list.each{|d| instance_eval("bdata[\""+d.id2name+"\"] = "+d.id2name) }
return bdata
end
def restore(bdata)
bdata.keys.each{|k| instance_eval(k + " = bdata[\""+k+"\"]") }
snap(@snap_sprite) unless @snap_sprite == nil
@snap_children.each{|c| c.snap(self) }
end
def dispose(delete_node = true)
@snap_sprite.delete_snap_child(self) unless @snap_sprite == nil
@snap_children.each{|sc| sc.reset_snap }
@@sprites.remove(self)
@img = nil
end
def Sprite::getList
@@sprites.getList
end
end
class Shape
class ShapeParameter
@@method_list = [:text, :box, :roundbox, :circle, :ellipse, :arrow]
@@dir_list = [:left, :right, :up, :down]
@@type_list = [:normal, :edge, :trcolor, :layout]
def ShapeParameter.collect_method?(m)
return @@method_list.include?(m)
end
def ShapeParameter.collect_dir?(d)
return @@dir_list.include?(d)
end
def ShapeParameter.collect_type?(t)
return @@type_list.include?(t)
end
def initialize
@type = nil
@params = Hash.new
init_type(:normal)
end
def init_type(t)
@type = t
@params[@type] = Array.new
end
def append(d)
@params[@type].push(d)
end
def edge?
@params.has_key?(:edge)
end
def trcolor?
@params.has_key?(:trcolor)
end
def layout?
@params.has_key?(:layout)
end
def get_param(type)
return nil unless @params.has_key?(type)
return @params[type]
end
def to_s
s = ""
@params.keys.each{|k|
s += "#{k} : "
@params[k].each{|v| s += "#{v} " }
s += "\n"
}
return s
end
end
def Shape.get_trcolor(sp)
return sp.get_param(:trcolor)[0] if sp.trcolor?
return Color::BLACK
end
def Shape.text(sp)
p = sp.get_param(:normal)
str, font, size, color, layout_method_x, layout_method_y = p[0..5]
osz = font.size
ocl = font.getColor
sz2 = size
font.size = size unless size == 0
font.setColor(color) unless color == []
sz = font.line_skip
w = 0
ww = 0
h = 0
s = nil
m = Yuki::Scenario.new
m.separate = false
m.text = str
w_list = Array.new
h_list = Array.new
until m.eot? do
c = m.nextmsg
case c.code
when Yuki::Direction::FONTSIZE
sz2 = c.data if c.data > sz2
font.size = sz1
sz = font.line_skip
m.push(c)
when Yuki::Direction::FONTCOLOR
m.push(c)
when Yuki::Direction::CR
w_list.push(ww)
h_list.push(sz)
h += sz
w = ww if ww > w
ww = 0
m.push(c)
when Yuki::Direction::CHAR
ww += font.textSize(c.data)[0]
m.push(c)
end
end
if ww != 0
w_list.push(ww)
h_list.push(sz)
h += sz
w = ww if ww > w
end
font.size = size unless size == 0
font.setColor(color) unless color == []
s = Sprite.new([w, h], get_trcolor(sp))
layout_list_x = layout_method_x
layout_list_y = layout_method_y
layout_list_x = [layout_method_x, w, w_list] unless layout_method_x == :left
layout_list_y = [layout_method_y, h_list] unless layout_method_y == :top
font.drawText_with_layout(s.bitmap, m, 0, 0, 0, layout_list_x, layout_list_y)
font.size = osz
font.setColor(ocl)
return s
end
def Shape.box(sp)
p = sp.get_param(:normal)
w, h, c = p[0..2]
s = Sprite.new([w, h], get_trcolor(sp))
if sp.edge?
et, ec = sp.get_param(:edge)[0..1]
s.bitmap.fill_rect(0, 0, w-1, h-1, ec)
s.bitmap.fill_rect(et, et, w-et*2-1, h-et*2-1, c)
else
s.bitmap.fill_rect(0, 0, w-1, h-1, c)
end
return s
end
def Shape.roundbox_basic(s, x, y, w, h, r, c)
s.bitmap.fill_rect(x, y+r, w-x*2, h-y*2-r*2, c)
s.bitmap.fill_rect(x+r, y, w-x*2-r*2, h-x*2, c)
s.bitmap.draw_filled_circle(r+x, r+y, r, c)
s.bitmap.draw_filled_circle(w-r-x-1, r+y, r, c)
s.bitmap.draw_filled_circle(r+x, h-r-y-1, r, c)
s.bitmap.draw_filled_circle(w-r-x-1, h-r-y-1, r, c)
end
def Shape.roundbox(sp)
p = sp.get_param(:normal)
w, h, r, c = p[0..3]
s = Sprite.new([w, h], get_trcolor(sp))
if sp.edge?
et, ec = sp.get_param(:edge)[0..1]
roundbox_basic(s, 0, 0, w, h, r, ec)
roundbox_basic(s, et, et, w, h, r, c)
else
roundbox_basic(s, 0, 0, w, h, r, c)
end
return s
end
def Shape.circle(sp)
p = sp.get_param(:normal)
r, c = p[0..1]
s = Sprite.new([r * 2 + 1, r * 2 + 1], get_trcolor(sp))
if sp.edge?
et, ec = sp.get_param(:edge)[0..1]
s.bitmap.draw_filled_circle(r, r, r, ec)
s.bitmap.draw_filled_circle(r, r, r-et, c)
else
s.bitmap.draw_filled_circle(r, r, r, c)
end
return s
end
def Shape.ellipse(sp)
p = sp.get_param(:normal)
rx, ry, c = p[0..2]
s = Sprite.new([rx * 2 + 1, ry * 2 + 1], get_trcolor(sp))
if sp.edge?
et, ec = sp.get_param(:edge)[0..1]
s.bitmap.draw_filled_ellipse(rx, ry, rx, ry, ec)
s.bitmap.draw_filled_ellipse(rx, ry, rx-et, ry-et, c)
else
s.bitmap.draw_filled_ellipse(rx, ry, rx, ry, c)
end
return s
end
def Shape.create(method, params)
return nil unless ShapeParameter.collect_method?(method)
shape = nil
sp = ShapeParameter.new
params.each{|p|
if ShapeParameter.collect_type?(p)
sp.init_type(p)
else
sp.append(p)
end
}
instance_eval("shape = "+method.id2name+"(sp)")
return shape
end
end
class SpriteAnimation
def initialize(sprite, wait = 0)
@spr = sprite
@pats = @spr.h / @spr.oh
if wait.kind_of?(Integer)
@waits = Array.new
@waits.fill(wait, 0, @pats)
elsif wait.kind_of?(Float)
@waits = Array.new
@waits.fill(WaitCounter.new(wait), 0, @pats)
elsif wait.kind_of?(Array)
@waits = wait.collect{|w| w.kind_of?(Float) ? WaitCounter.new(w) : w }
else
# Error!
end
@pats = @waits.length if @pats > @waits.length
@chrs = @spr.w / @spr.ow
@cnum = 0
@pnum = 0
@cnt = 0
@exec = false
end
def pattern(pnum)
@pnum = pnum if pnum < @pats
@spr.oy = @spr.oh * @pnum
@cnt = @waits[@pnum] if @exec
end
def get_pattern
return @pnum
end
def character(cnum)
@cnum = cnum if cnum < @chrs
@spr.ox = @spr.ow * @cnum
end
def move_character(d)
@cnum = (@cnum + d) % @chrs
@cnum = @cnum + @chrs if @cnum < 0
@spr.ox = @spr.ow * @cnum
end
def get_character
return @cnum
end
def show
@spr.show
end
def hide
@spr.hide
end
def toggle_visible
if @spr.visible
hide
else
show
end
end
def start
return if @exec
@cnt = @waits[@pnum]
@exec = true
end
def stop
return unless @exec
@cnt.stop if @cnt.kind_of?(WaitCounter)
@exec = false
end
def toggle_exec
if @exec
stop
else
start
end
end
def update
return unless @exec
if @cnt.kind_of?(Integer)
update_frame
else
update_wait_counter
end
end
def update_frame
if @cnt == 0
@pnum = (@pnum + 1) % @pats
@spr.oy = @spr.oh * @pnum
@cnt = @waits[@pnum]
else
@cnt -= 1
end
end
def update_wait_counter
unless @cnt.waiting?
@pnum = (@pnum + 1) % @pats
@spr.oy = @spr.oh * @pnum
@cnt = @waits[@pnum]
@cnt.start
end
end
def reset
@pnum = 0
@cnt = 0
end
def visible?
@spr.visible
end
def exec?
@exec
end
end
=begin
=Effectクラス
スプライトに効果を与えるクラス(基本クラス)
=end
class Effect
def initialize(sspr, dspr = nil)
@src = sspr
@dst = dspr
@effecting = false
@wait = 0
@cnt = 0
@params = Array.new
end
def start(w, *param)
return if @effecting
@wait = w
@cnt = @wait
@param = param
@effecting = true
end
def effecting?
@effecting
end
def update(screen)
@effecting = false # dummy code
end
def stop
@effecting = false
end
def dispose
@dst = nil
end
end
=begin
=Planeクラス
ビットマップイメージを敷き詰めたような表示を実装するクラス
=end
class Plane
extend Forwardable
@@planes = Array.new
def reSize
@rw = ((Screen.w + @img.w) / @img.w + 1) * @img.w # real width
@rh = ((Screen.h + @img.h) / @img.h + 1) * @img.h # real height
v = false
d = 0
ox = 0
oy = 0
if @spr != nil
@spr.dispose
v = @spr.visible
d = @spr.dp
ox = @spr.ox
oy = @spr.oy
end
@spr = Sprite.create_plane(@img, @rw, @rh, Point.new(@px, @py))
@spr.dp = d
@spr.ox = ox
@spr.oy = oy
@spr.visible = v
end
def initialize(fname, px = 0, py = 0)
@img = Bitmap.load(fname)
@px = px
@py = py
@rw = 0
@rh = 0
@spr = nil
reSize
@spr.dp = -1
@x = 0
@y = 0
@@planes.push(self)
end
def x
@x
end
def x=(v)
@x = v
@spr.ox = @x % @img.w
end
def y
@y
end
def y=(v)
@y = v
@spr.oy = @y % @img.h
end
def drawBlock
@drawBlock
end
def drawBlock=(b)
@drawBlock = b
end
def dispose
@spr.dispose
@@planes.delete(self)
end
def Plane::getList
@@planes
end
def_delegators(:@spr, :visible, :visible=, :dp, :dp=, :show, :hide)
end
=begin
=WindowParameterクラス
ウィンドウ用に表示する書くグラフィックの範囲を格納するクラス
=end
class WindowParameter # structure class
FR_LEFT_T = 0
FR_TOP = 1
FR_RIGHT_T = 2
FR_LEFT = 3
FR_RIGHT = 4
FR_LEFT_B = 5
FR_BOTTOM = 6
FR_RIGHT_B = 7
def initialize(fn, lt, top, rt, left, right, lb, bottom, rb, client)
@filename = fn
@frame = [lt, top, rt, left, right, lb, bottom, rb]
@client = client
@w = @frame[FR_LEFT].w
@h = @frame[FR_TOP].h
end
@@default_parameter = WindowParameter.new(
"window.png", # ウィンドウイメージ名
Rect.new( 0, 0, 32, 32), # 左上
Rect.new( 32, 0, 32, 32), # 上
Rect.new( 64, 0, 32, 32), # 右上
Rect.new( 0, 32, 32, 32), # 左
Rect.new( 64, 32, 32, 32), # 右
Rect.new( 0, 64, 32, 32), # 左下
Rect.new( 32, 64, 32, 32), # 下
Rect.new( 64, 64, 32, 32), # 右下
Rect.new( 96, 0,128,128) # クライアント
)
@@part = {:lt=>FR_LEFT_T, :t=>FR_TOP, :rt=>FR_RIGHT_T,
:l=>FR_LEFT, :r=>FR_RIGHT,
:lb=>FR_LEFT_B, :b=>FR_BOTTOM, :rb=>FR_RIGHT_B}
attr_reader :filename
attr_reader :frame
attr_reader :client
attr_reader :w, :h
def WindowParameter::default
return @@default_parameter
end
def [](part)
return @@part.key?(part) ? @frame[@@part[part]] : @client
end
def get_parts
return WindowParts.new(self) unless @parts
end
end
=begin
=CursorParameterクラス
カーソル用に表示する書くグラフィックの範囲を格納するクラス
=end
class CursorParameter # structure class
DOWN = 0
LEFT = 1
RIGHT = 2
UP = 3
DIRS = 4
@@dir2symbol = {UP=>:u,
LEFT=>:l, RIGHT=>:r,
DOWN=>:d}
@@part = {:u=>UP,
:l=>LEFT, :r=>RIGHT,
:d=>DOWN}
def initialize(fn, wait, wp, cr, cp, pg, pp)
@filename = fn
@wait = wait
@cursor = Hash.new
x = cr.x
DIRS.times{|d|
@cursor[@@dir2symbol[d]]=Rect.new(x, cr.y, cr.w, cr.h)
x += cr.w
}
@page = Hash.new
x = pg.x
DIRS.times{|d|
@page[@@dir2symbol[d]]=Rect.new(x, pg.y, pg.w, pg.h)
x += pg.w
}
@waitpat, @cursorpat, @pagepat = [wp, cp, pp]
@ww = @wait.w
@wh = @wait.h
@cw = @cursor[:l].w
@ch = @cursor[:l].h
end
@@default_parameter = CursorParameter.new(
"window.png", # ウィンドウイメージ名
Rect.new(224, 0, 32, 32), 4, # ウェイト、パターン数
Rect.new( 0,128, 32, 32), 4, # カーソル、パターン数
Rect.new(128,128, 32, 32), 4 # ページカーソル、パターン数
)
attr_reader :filename
attr_reader :wait, :waitpat
attr_reader :cursor, :cursorpat
attr_reader :page, :pagepat
attr_reader :ww, :wh, :cw, :ch
def CursorParameter::default
return @@default_parameter
end
def select_cursor
return @cursor
end
def scroll_cursor
return @page
end
def get_parts
return CursorParts.new(self) unless @parts
end
end
=begin
=WindowPartsクラス
ウィンドウ用に描画する各パーツをスプライト単位で管理するクラス
=end
class WindowParts
attr_reader :tr_color
attr_reader :client
attr_reader :frame_t, :frame_l, :frame_r, :frame_b
attr_reader :frame_lt, :frame_rt, :frame_lb, :frame_rb
def copy_rect(base, x, y, w, h)
return Sprite.new(base.bitmap.copyRect(x, y, w, h), @tr_color)
end
def get_copy(base, param, part)
fr = param[part]
return copy_rect(base, fr.x, fr.y, fr.w, fr.h)
end
def initialize(param)
@base = Sprite.new(param.filename, nil)
@tr_color = Color.to_rgb(@base.bitmap.getPixel(0, 0))
cl_rect = param.client
@client = Sprite.new([cl_rect.w, cl_rect.h], @tr_color)
SDL.blitSurface(@base.bitmap, cl_rect.x, cl_rect.y, cl_rect.w, cl_rect.h, @client.bitmap, 0, 0)
@frame_t = get_copy(@base, param, :t)
@frame_l = get_copy(@base, param, :l)
@frame_r = get_copy(@base, param, :r)
@frame_b = get_copy(@base, param, :b)
@frame_lt = get_copy(@base, param, :lt)
@frame_rt = get_copy(@base, param, :rt)
@frame_lb = get_copy(@base, param, :lb)
@frame_rb = get_copy(@base, param, :rb)
end
end
=begin
=CursorPartsクラス
カーソル用に描画する各パーツをスプライト単位で管理するクラス
=end
class CursorParts
DOWN = 0
LEFT = 1
RIGHT = 2
UP = 3
DIRS = 4
attr_reader :wait_cursor, :tr_color
@@part = {:u=>UP,
:l=>LEFT, :r=>RIGHT,
:d=>DOWN}
def copy_rect(base, x, y, w, h)
return Sprite.new(base.bitmap.copyRect(x, y, w, h), @tr_color)
end
def get_copy(base, param, part)
fr = param.get_frame(part)
return copy_rect(base, fr.x, fr.y, fr.w, fr.h)
end
def initialize(param)
@base = Sprite.new(param.filename, nil)
@tr_color = Color.to_rgb(@base.bitmap.getPixel(0, 0))
@wait_cursor = copy_rect(@base, param.wait.x, param.wait.y, param.wait.w, param.wait.h * param.waitpat)
@wait_cursor.oh = param.wait.h
@select_cursor = Array.new
[:d, :l, :r, :u].each{|t|
rect = param.select_cursor[t]
tmp = copy_rect(@base, rect.x, rect.y, rect.w, rect.h * param.cursorpat)
tmp.oh = rect.h
@select_cursor.push(tmp)
}
@scroll_cursor = Array.new
[:d, :l, :r, :u].each{|t|
rect = param.scroll_cursor[t]
tmp = copy_rect(@base, rect.x, rect.y, rect.w, rect.h * param.pagepat)
tmp.oh = rect.h
@scroll_cursor.push(tmp)
}
end
def select_cursor(part)
return @select_cursor[@@part[part]]
end
def scroll_cursor(part)
return @scroll_cursor[@@part[part]]
end
end
=begin
=Windowクラス
ウィンドウを管理するクラス
=end
class Window
extend Forwardable
@@windows = Array.new
def drawWindow
end
def createWindow
@back=Sprite.new([@cw+@params.w*2, @ch+@params.h*2])
lw = @params[:lt].w
lh = @params[:lt].h
cl = @parts.client
if @isTile
w = (@cw + lw * (1-@margin) + @params[:rb].w * (1-@margin)).to_i()
h = (@ch + lh * (1-@margin) + @params[:rb].h * (1-@margin)).to_i()
x = (lw * @margin).to_i()
y = (lh * @margin).to_i()
tx = w / cl.w
mx = w % cl.w
ty = h / cl.h
my = h % cl.h
ty.times{|t1|
tx.times{|t2| SDL.blitSurface(cl.bitmap, 0, 0, 0, 0, @back.bitmap, x + t2 * cl.w, y + t1 * cl.h) }
SDL.blitSurface(cl.bitmap, 0, 0, mx, cl.h, @back.bitmap, x + tx * cl.w, y + t1 * cl.h) if mx > 0
}
tx.times{|t2| SDL.blitSurface(cl.bitmap, 0, 0, cl.h, my, @back.bitmap, x + t2 * cl.w, y + ty * cl.h) } if my > 0
SDL.blitSurface(cl.bitmap, 0, 0, mx, my, @back.bitmap, x + tx * cl.w, y + ty * cl.h) if mx > 0 && my > 0
else
SDL.transform(cl.bitmap, @back.bitmap, 0, @back.w / cl.w + 2, @back.h / cl.h + 2, 0, 0, 0, 0, SDL::TRANSFORM_AA) # why + 2 ???
@back.bitmap.fillRect(0, 0, lw * @margin, @back.h, @back.tr_color)
@back.bitmap.fillRect(lw + @cw + @params[:rb].w * (1-@margin), 0, @params[:rt].w * @margin, @back.h, @back.tr_color)
@back.bitmap.fillRect(0, 0, @back.w, lh * @margin, @back.tr_color)
@back.bitmap.fillRect(0, lh + @ch + @params[:rb].h * (1-@margin), @back.w, @params[:lb].h * @margin, @back.tr_color)
end
@back.alpha = @balpha
@window=Sprite.new([@cw+@params.w*2, @ch+@params.h*2], nil)
@window.bitmap.setColorKey(SDL::SRCCOLORKEY|SDL::RLEACCEL, @parts.tr_color)
@window.bitmap.fillRect(0, 0, @window.w, @window.h, @parts.tr_color)
SDL.blitSurface(@parts.frame_lt.bitmap, 0, 0, 0, 0, @window.bitmap, 0, 0)
SDL.blitSurface(@parts.frame_rt.bitmap, 0, 0, 0, 0, @window.bitmap, lw+@cw, 0)
SDL.blitSurface(@parts.frame_lb.bitmap, 0, 0, 0, 0, @window.bitmap, 0, lh+@ch)
SDL.blitSurface(@parts.frame_rb.bitmap, 0, 0, 0, 0, @window.bitmap, lw+@cw, lh+@ch)
f = @parts.frame_t
tx = @cw / f.w
mx = @cw % f.w
tx.times{|t| SDL.blitSurface(f.bitmap, 0, 0, 0, 0, @window.bitmap, lw + t * f.w, 0) }
SDL.blitSurface(f.bitmap, 0, 0, mx, f.h, @window.bitmap, lw + tx * f.w, 0) if mx > 0
f = @parts.frame_l
tx = @ch / f.h
mx = @ch % f.h
tx.times{|t| SDL.blitSurface(f.bitmap, 0, 0, 0, 0, @window.bitmap, 0, lh + t * f.h) }
SDL.blitSurface(f.bitmap, 0, 0, f.w, mx, @window.bitmap, 0, lh + tx * f.h) if mx > 0
f = @parts.frame_r
tx = @ch / f.h
mx = @ch % f.h
tx.times{|t| SDL.blitSurface(f.bitmap, 0, 0, 0, 0, @window.bitmap, lw + @cw, lh + t * f.h) }
SDL.blitSurface(f.bitmap, 0, 0, f.w, mx, @window.bitmap, lw + @cw, lh + tx * f.h) if mx > 0
f = @parts.frame_b
tx = @cw / f.w
mx = @cw % f.w
tx.times{|t| SDL.blitSurface(f.bitmap, 0, 0, 0, 0, @window.bitmap, lw + t * f.w, lh + @ch) }
SDL.blitSurface(f.bitmap, 0, 0, mx, f.h, @window.bitmap, lw + tx * f.w, lh + @ch) if mx > 0
@window.snap(nil)
@window.get_snap_children.each{|c| c.snap(nil) }
@window.calc_layout
end
def setMargin(v)
if v > 1.0
return 1.0
elsif v < 0.0
return 0.0
end
return v
end
protected :createWindow, :setMargin
def initialize(size = Size.new(256, 256), params = WindowParameter::default, cparams = CursorParameter::default, balpha = 255, istile = true, margin = 0.5)
@size = size.kind_of?(Array) ? Size.new(size[0], size[1]) : size
@params = params
@parts = @params.get_parts
@balpha = balpha
@isTile = istile
@ccol = Color::BLACK
@margin = setMargin(margin)
@cw = @size.w
@ch = @size.h
@back = nil
@client = nil
@window = nil
createWindow()
@client = TextBox.new(size, cparams, @balpha, @istile, @margin)
@client.visible = false
@x = 0
@y = 0
@dp = 0
@client.x = @x + @params[:lt].w
@client.y = @y + @params[:lt].w
@@windows.push(self)
end
def msg
@client.msg
end
def msg=(m)
raise MiyakoError("Parameter is not Yuki::Scenario class!") unless m.kind_of?(Yuki::Scenario)
@client.msg = m
end
def margin
@margin
end
def margin=(v)
@margin = setMargin(v)
end
def_delegators(:@client, :clientX, :clientX=)
def_delegators(:@client, :clientY, :clientY=)
def clientW
@cw
end
def clientH
@ch
end
def clientSize
[@cw, @ch]
end
def clientLeft
@params[:lt].w
end
def clientTop
@params[:lt].h
end
def_delegators(:@client, :setClient)
def_delegators(:@client, :pauseWait, :pauseWait=)
def_delegators(:@client, :pauseType, :pauseType=)
def_delegators(:@client, :cusrsorVisible, :cursorVisible=)
def_delegators(:@client, :cursorWait, :cursorWait=)
def_delegators(:@client, :cursorDir, :cursorDir=)
def_delegators(:@client, :cursorX, :cursorX=)
def_delegators(:@client, :cursorY, :cursorY=)
def_delegators(:@client, :pageWait, :pageWait=)
def_delegators(:@client, :pause=, :pause?)
def_delegators(:@client, :clear, :cr)
def x=(v)
@back.x = v
@client.x = v + @params[:lt].w
@window.x = v
end
def y=(v)
@back.y = v
@client.y = v + @params[:lt].h
@window.y = v
end
def calc_layout
@back.calc_layout
@client.calc_layout
@window.calc_layout
end
def set_layout(x, y)
@back.set_layout(x, y)
@client.set_layout(x, y)
@client.set_layout([@back.get_layout_x[2]+@params[:lt].w], [@back.get_layout_y[2]+@params[:lt].h])
@window.set_layout(x, y)
end
def enable_layout
@back.enable_layout
@client.enable_layout
@window.enable_layout
end
def disenable_layout
@back.disenable_layout
@client.disenable_layout
@window.disenable_layout
end
def set_side_x(xside)
@back.set_side_x(xside)
@client.set_side_x(xside)
@window.set_side_x(xside)
end
def set_side_y(yside)
@back.set_side_y(yside)
@client.set_side_y(yside)
@window.set_side_y(yside)
end
def set_side(xside, yside)
@back.set_side(xside, yside)
@client.set_side(xside, yside)
@window.set_side(xside, yside)
end
def set_base_size(w, h)
@back.set_base_size(w, h)
@client.set_base_size(w, h)
@window.set_base_size(w, h)
end
def reset_base_size
@back.reset_base_size
@client.reset_base_size
@window.reset_base_size
end
def set_base_point(x, y)
@back.set_base_point(x, y)
@client.set_base_point(x, y)
@window.set_base_point(x, y)
end
def snap(spr = nil)
@window.snap(spr)
end
def reset_snap
@window.reset_snap
end
def add_snap_child(spr)
@window.add_snap_child(spr)
end
def delete_snap_child(spr)
@window.delete_snap_child(spr)
end
def set_base(x, y, w, h)
@back.set_base(x, y, w, h)
@client.set_base(x, y, w, h)
@window.set_base(x, y, w, h)
end
def reset_base
@back.reset_base(x, y, w, h)
@client.reset_base(x, y, w, h)
@window.reset_base(x, y, w, h)
end
def set_offset_x(x)
@back.set_offset_x(x)
@client.set_offset_x(x)
@window.set_offset_x(x)
end
def set_offset_y(y)
@back.set_offset_y(y)
@client.set_offset_y(y)
@window.set_offset_y(y)
end
def set_offset(x, y)
@back.set_offset(x, y)
@client.set_offset(x, y)
@window.set_offset(x, y)
end
def reset_offset
@back.reset_offset
@client.reset_offset
@window.reset_offset
end
def reset_layout
@back.reset_layout
@client.reset_layout
@client.set_layout([@back.get_layout_x[2]+@params[:lt].w], [@back.get_layout_y[2]+@params[:lt].h])
@window.reset_layout
end
def centering
@back.centering
@client.centering
@window.centering
end
def move(x, y)
@back.move(x, y)
@client.move(x, y)
@window.move(x, y)
end
def move_to(x, y)
dx = x - @window.x
dy = y - @window.y
@back.move(dx, dy)
@client.move(dx, dy)
@window.move(dx, dy)
end
def_delegators(:@window, :get_layout_x, :get_layout_y, :get_layout, :get_side, :get_base)
def_delegators(:@window, :get_offset, :get_offset_x, :get_offset_y)
def dp
@window.dp
end
def dp=(v)
@back.dp = v
@client.dp = v + 1
@window.dp = v + 2
end
def visible=(f)
@back.visible = f
@client.textVisible = f
@window.visible = f
end
def show
@back.show
@client.show_text
@window.show
end
def hide
@back.hide
@client.hide_text
@window.hide
end
def clientVisible
@client.visible
end
def clientVisible=(v)
@client.visible = f
end
def bgAlpha
@balpha
end
def bgAlpha=(b)
@balpha = b
@back.alpha = @balpha
end
def rect
return Rect.new(@window.x, @window.y, @window.w, @window.h)
end
def window_params
return @params
end
def dispose
@back.dispose
@back = nil
@window.dispose
@window = nil
@params = nil
@parts = nil
@base = nil
@@windows.delete(self)
end
def Window::getList
@@windows
end
def_delegators(:@window, :visible, :x, :y)
def_delegators(:@client, :text, :text=)
def_delegators(:@client, :font, :font=)
def_delegators(:@client, :textVisible, :textVisible=)
def_delegators(:@client, :drawBlock, :drawBlock=)
def_delegators(:@client, :textMarginLeft, :textMarginTop, :textMarginRight, :textMarginBottom)
def_delegators(:@client, :textMarginLeft=, :textMarginTop=, :textMarginRight=, :textMarginBottom=)
def_delegators(:@client, :setTextMargin)
def_delegators(:@client, :locateX, :locateY, :nowLocateX, :nowLocateY, :locate)
def_delegators(:@client, :cursor_params)
end
class TextBox
extend Forwardable
DIRS = [:d, :l, :r, :u]
@@windows = Array.new
attr_accessor :font
attr_reader :msg
def setPauseLocate
case @waittype
when 0
@wait_cursor.x = @textarea.x + (@size.w - @params.wait.w) / 2
@wait_cursor.y = @textarea.y + @size.h - @params.wait.h
when 1
@wait_cursor.x = @textarea.x + @textarea.nowLocateX
@wait_cursor.y = @textarea.y + @textarea.nowLocateY
end
end
protected :setPauseLocate
def drawWindow
@client.bitmap.fillRect(0, 0, @size.w, @size.h, @bcol)
if @font != nil && @msgpos < @msg.size
x = @textarea.textMarginLeft + @textarea.locateX
y = @textarea.textMarginTop + @textarea.locateY
dat = @msg[@msgpos].data
dat = dat.tosjis if dat.class == String
@textarea.nowLocateX, @textarea.nowLocateY, @msgpos = @font.drawTextRange(@textarea.bitmap, @msg, @msgpos, 0, x, y, 0)
@textarea.locateX = @textarea.nowLocateX - @textarea.textMarginLeft
@textarea.locateY = @textarea.nowLocateY - @textarea.textMarginTop
end
SDL.blitSurface2(@clientimg, [@cx, @cy, @size.w, @size.h], @client.bitmap, [0, 0, @size.w, @size.h]) if @clientimg
if @waiting
if @waitwait.finish?
@waitpat = (@waitpat + 1) % @params.waitpat
@wait_cursor.oy = @params.wait.h * @waitpat
setPauseLocate()
@waitwait.start
end
else
DIRS.each{|dir| @parts.scroll_cursor(dir).visible = false }
if @clientimg
pdir = nil
pdir = :d if @clientimg.h > (@cy + @size.h)
pdir = :l if @cx > 0
pdir = :r if @clientimg.w > (@cx + @size.w)
pdir = :u if @cy > 0
if pdir
@parts.scroll_cursor(pdir).visible = true
if @pagewait.finish?
@pagepat = (@pagepat + 1) % @params.pagepat
@parts.scroll_cursor(pdir).oy = @page[pdir].oh * @pagepat
case pdir
when :d
x = @textarea.x + (@size.w - @params.scroll_cursor(:d).w) / 2
y = @textarea.y + @size.h - @params.scroll_cursor(:d).h
when :l
x = @textarea.x
y = @textarea.y + (@size.h - @params.scroll_cursor(:l).h) / 2
when :r
x = @textarea.x + @size.w - @params.scroll_cursor(:r).w
y = @textarea.y + (@size.h - @params.scroll_cursor(:r).h) / 2
when :u
x = @textarea.x + (@size.w - @params.scroll_cursor(:u).w) / 2
y = @textarea.y
end
@parts.scroll_cursor(pdir).x = x
@parts.scroll_cursor(pdir).y = y
@pagewait.start
end
end
end
if @cursorvisible
rect = @params.select_cursor[@cursordir]
if @cursorwait.finish?
@cursorpat = (@cursorpat + 1) % @params.cursorpat
@parts.select_cursor(@cursordir).oy = rect.h * @cursorpat
@parts.select_cursor(@cursordir).x = @cursorx
@parts.select_cursor(@cursordir).y = @cursory
@cursorwait.start
end
end
end
end
def setPointerDP
@wait_cursor.dp = @client.dp + 1
DIRS.each{|p|
@parts.scroll_cursor(p).dp = @wait_cursor.dp
@parts.select_cursor(p).dp = @wait_cursor.dp
}
end
def createWindow
@client=Sprite.new(@size, @parts.tr_color, @balpha, true)
@textarea=Sprite.new(@size, @parts.tr_color, 255, true)
setPointerDP
@client.snap(nil)
@client.get_snap_children.each{|c| c.snap(nil) }
@client.calc_layout
end
def setMargin(v)
if v > 1.0
return 1.0
elsif v < 0.0
return 0.0
end
return v
end
protected :createWindow, :setMargin
def initialize(size = Size.new(256, 256), params = CursorParameter::default, balpha = 255, istile = true, margin = 0.5)
@size = size.kind_of?(Array) ? Size.new(size[0], size[1]) : size
@params = params
@parts = @params.get_parts
@wait_cursor = @parts.wait_cursor
@balpha = balpha
@isTile = istile
@cx = 0
@cy = 0
@waiting = false
@waitvisible = false
@waitwait = WaitCounter.new(0)
@waitpat = 0
@waittype = 0
@cursorvisible = false
@cursorwait = WaitCounter.new(0)
@cursorpat = 0
@cursordir = :r
@cursorx = 0
@cursory = 0
@pagewait = WaitCounter.new(0)
@pagepat = 0
@textMarginLeft = 0
@textMarginTop = 0
@textMarginRight = 0
@textMarginBottom = 0
@clientimg = nil
@bcol = Color::BLACK
@margin = setMargin(margin)
@font = nil
@msg = Yuki::Scenario.new
@msgpos = 0
@client = nil
@textarea = nil
createWindow()
drawWindow()
@x = 0
@y = 0
@cx = 0
@cy = 0
@dp = 0
@textarea.setTextArea(@size.w, @size.h)
@cursorx = @textarea.x
@cursory = @textarea.y
@@windows.push(self)
end
def msg=(m)
raise MiyakoError("Parameter is not Yuki::Scenario class!") unless m.kind_of?(Yuki::Scenario)
tsp = @msg.separate
@msg = m
@msg.separate = tsp
end
def margin
@margin
end
def margin=(v)
@margin = setMargin(v)
end
def clientX
@cx
end
def clientX=(v)
@cx = v
end
def clientY
@cy
end
def clientY=(v)
@cy = v
end
def clientW
return @size.w
end
def clientH
return @size.h
end
def clientSize
return @size
end
def setClient(spr)
@clientimg=spr
drawWindow()
end
def pauseWait=(v)
@waitwait = WaitCounter.new(v)
@waitwait.start
@waitvisible = true if @waiting
end
def pauseType
@waittype
end
def pauseType=(v)
@waittype = v
end
def cursorVisible
@cursorvisible
end
def cursorVisible=(v)
@cursorvisible = v
@parts.select_cursor(@cursordir).x = @cursorx
@parts.select_cursor(@cursordir).y = @cursory
@parts.select_cursor(@cursordir).visible = @cursorvisible
end
def cursorWait=(v)
@cursorwait = WaitCounter.new(v)
@cursorwait.start
end
def cursorDir
@cursordir
end
def cursorDir=(v)
raise MiyakoError,new("cursorDir parameter is not Symbol!") unless DIRS.include?(v)
@cursordir = v
DIRS.each{|p| @parts.select_cursor(p).hide }
@parts.select_cursor(v).show
end
def cursorX
@cursorx - @textarea.x
end
def cursorX=(v)
@cursorx = @textarea.x + v
end
def cursorY
@cursory - @textarea.y
end
def cursorY=(v)
@cursory = @textarea.y + v
end
def cursorSize
[@parts.select_cursor(@cursordir).ow, @parts.select_cursor(@cursordir).oh]
end
def pageWait=(v)
@pagewait = WaitCounter.new(v)
@pagewait.start
end
def pause=(v)
@waiting = v
setPauseLocate()
@wait_cursor.visible = @waiting
end
def pause?
@waiting
end
def x=(v)
@client.x = v
@textarea.x = v
@cursorx = @textarea.x + v
end
def y=(v)
@client.y = v
@textarea.y = v
@cursory = @textarea.y + v
end
def calc_layout
@client.calc_layout
@textarea.calc_layout
end
def set_layout(x, y)
@client.set_layout(x, y)
@textarea.set_layout(x, y)
end
def enable_layout
@client.enable_layout
@textarea.enable_layout
end
def disenable_layout
@client.disenable_layout
@textarea.disenable_layout
end
def set_side_x(xside)
@client.set_side_x(xside)
@textarea.set_side_x(xside)
end
def set_side_y(yside)
@client.set_side_y(yside)
@textarea.set_side_y(yside)
end
def set_side(xside, yside)
set_side_x(xside)
set_side_y(yside)
end
def set_base_size(w, h)
@client.set_base_size(w, h)
@textarea.set_base_size(w, h)
end
def reset_base_size
@client.reset_base_size
@textarea.reset_base_size
end
def set_base_point(x, y)
@client.set_base_point(x, y)
@textarea.set_base_point(x, y)
end
def snap(spr = nil)
@client.snap(spr)
end
def reset_snap
@client.reset_snap(spr)
end
def add_snap_child(spr)
@client.add_snap_child(spr)
end
def delete_snap_child(spr)
@client.delete_snap_child(spr)
end
def set_base(x, y, w, h)
@client.set_base(x, y, w, h)
@textarea.set_base(x, y, w, h)
end
def reset_base
@client.reset_base
@textarea.reset_base
end
def set_offset_x(x)
@client.set_offset_x(x)
@textarea.set_offset_x(x)
end
def set_offset_y(y)
@client.set_offset_y(y)
@textarea.set_offset_y(y)
end
def set_offset(x, y)
@client.set_offset(x, y)
@textarea.set_offset(x, y)
end
def reset_offset
@client.reset_offset
@textarea.reset_offset
end
def reset_layout
@client.reset_layout
@textarea.reset_layout
end
def centering
@client.centering
@textarea.centering
end
def move(x, y)
@client.move(x, y)
@textarea.move(x, y)
end
def move_to(x, y)
@client.move_to(x, y)
@textarea.move_to(x, y)
end
def_delegators(:@client, :get_layout_x, :get_layout_y, :get_layout, :get_side, :get_base)
def_delegators(:@client, :get_offset, :get_offset_x, :get_offset_y)
def dp
@client.dp
end
def dp=(v)
@client.dp = v
@textarea.dp = v
setPointerDP
end
def visible=(f)
@client.visible = f
end
def bgAlpha
@balpha
end
def bgAlpha=(b)
@balpha = b
@client.alpha = @balpha
end
def bgColor
@bcol
end
def bgColor=(c)
@bcol = c if Color.to_rgb(c)
@client.bitmap.fillRect(0, 0, @client.w, @client.h, @bcol)
end
def clear
@msg.clear
@textarea.bitmap.fillRect(0, 0, @size.w, @size.h, @parts.tr_color)
@textarea.locateX = 0
@textarea.locateY = 0
@msgpos = 0
end
def cr
@msg.push(Yuki::Direction.cr)
@textarea.locateX = 0
end
def textVisible
@textarea.visible
end
def textVisible=(f)
@textarea.visible = f
end
def show
@client.show
@textarea.show
end
def hide
@client.hide
@textarea.hide
end
def show_text
@textarea.show
end
def hide_text
@textarea.hide
end
def show_client
@client.show
end
def hide_clientt
@client.hide
end
def cursor_params
return @params
end
def rect
return Rect.new(@client.x, @client.y, @client.w, @client.h)
end
def dispose
@client.dispose
@client = nil
@textarea.dispose
@textarea = nil
@clientimg = nil
@params = nil
@parts = nil
@base = nil
@src = nil
@@windows.delete(self)
end
def TextBox::getList
@@windows
end
def_delegators(:@client, :visible, :x, :y)
def_delegators(:@client, :drawBlock, :drawBlock=)
def_delegators(:@textarea, :textMarginLeft, :textMarginTop, :textMarginRight, :textMarginBottom)
def_delegators(:@textarea, :textMarginLeft=, :textMarginTop=, :textMarginRight=, :textMarginBottom=)
def_delegators(:@textarea, :setTextMargin)
def_delegators(:@textarea, :locateX, :locateY, :nowLocateX, :nowLocateY, :locate)
end
=begin
=MParamクラス
=end
class MParam
attr_accessor :name, :tsize, :tpixels
attr_accessor :px, :py
attr_accessor :csv, :blist
def initialize
@name = ""
@tsize = 0
@tpixels = 0
@px = -1
@py = -1
@csv = ""
@blist = []
end
end
=begin
=Mapクラス
所定のマップチップとマップデータを元にマップ画像を作成するクラス
=MapLayerクラス
実際のマップデータと表示画像(レイヤ)を扱うクラス
=end
class Map
@@maps = Array.new
class MapLayer
extend Forwardable
attr_reader :x, :y, :w, :h
def copyRect(bmp, x, y, w, h)
src = bmp.copyRect(x, y, w, h)
src.setColorKey(SDL::SRCCOLORKEY|SDL::RLEACCEL, @bcol)
src.displayFormat
end
def draw_chip(buf, x, y, rx, ry)
SDL.blitSurface(@chipdb[@mapdat[@pos_y[y]][@pos_x[x]]], 0, 0, 0, 0, buf, rx, ry)
end
def draw(s)
@buf.fillRect(0, 0, @buf.w, @buf.h, @bcol)
tx = @param.tpixels
@ch.times{|y| @cw.times{|x| draw_chip(@buf, x, y, x * tx, y * tx) } }
SDL.blitSurface(@buf, 0, 0, 0, 0, s.bitmap, -@mx, -@my)
end
def cdraw(s) # with clipping
@buf2.fillRect(0, 0, @buf2.w, @buf2.h, @bcol)
lft, rgt = @dx < 0 ? [-@dx, 0] : [0, @dx]
top, btm = @dy < 0 ? [-@dy, 0] : [0, @dy]
tx = @param.tpixels
SDL.blitSurface(@buf, rgt * tx, btm * tx, @buf.w - @dx.abs * tx, @buf.h - @dy.abs * tx, @buf2, lft * tx, top * tx)
(0..(top-1)).each{|y| @cw.times{|x| draw_chip(@buf2, x, y, x * tx, y * tx) } } if top != 0
(top..(@ch-btm-1)).each{|y|
(0..(lft-1)).each{|x| draw_chip(@buf2, x, y, x * tx, y * tx) } if lft != 0
((@cw-rgt)..(@cw-1)).each{|x| draw_chip(@buf2, x, y, x * tx, y * tx) } if rgt != 0
}
((@ch-btm)..(@ch-1)).each{|y| @cw.times{|x| draw_chip(@buf2, x, y, x * tx, y * tx) } } if btm != 0
@buf, @buf2 = [@buf2, @buf]
SDL.blitSurface(@buf, 0, 0, 0, 0, s.bitmap, -@mx, -@my)
end
protected :copyRect, :draw, :cdraw
def update_position_x
@pos_x.fill(0,@cw){|i| (@cx + i) % @w}
end
def update_position_y
@pos_y.fill(0,@ch){|i| (@cy + i) % @h}
end
def update_position
update_position_x
update_position_y
end
def reSize
tx = @param.tpixels
@cw = (Screen.w + tx - 1) / tx + 1
@ch = (Screen.h + tx - 1) / tx + 1
if @baseimg != nil
f = @spr != nil
v = false
d = 0
x = 0
y = 0
ox = 0
oy = 0
if f
v = @spr.visible
d = @spr.dp
x = @spr.x
y = @spr.y
ox = @spr.ox
oy = @spr.oy
@spr.dispose
@buf = nil
@buf2 = nil
end
@spr = Sprite.new([Screen.w, Screen.h], nil)
@spr.visible = v
@spr.dp = d
@spr.x = x
@spr.y = y
@spr.ox = ox
@spr.oy = oy
@buf = Bitmap.create((@cw + 1) * tx, (@ch + 1) * tx)
@buf2 = Bitmap.create((@cw + 1) * tx, (@ch + 1) * tx)
if @px != -1 || @py != -1
@bcol = @baseimg.getPixel(@param.px, @param.py)
@spr.bitmap.setColorKey(SDL::SRCCOLORKEY|SDL::RLEACCEL, @bcol)
end
update_position
draw(@spr) if f
@spr.update = Proc.new{|o|
return if @eventlayer
dx = @dx.abs
dy = @dy.abs
if dx == 0 && dy == 0
SDL.blitSurface(@buf, 0, 0, 0, 0, o.bitmap, -@mx, -@my)
elsif dx < @cw && dy < @ch
cdraw(o)
else
draw(o)
end
@dx = 0
@dy = 0
}
end
end
def initialize(param, mapdat, w, h, basedat)
@param = param
@x = 0
@cx = 0
@mx = 0
@dx = 0
@y = 0
@cy = 0
@my = 0
@dy = 0
@mapdat = mapdat
@baseimg = nil
if basedat != nil
img = Bitmap.load(basedat)
imgsize = img.w > img.h ? img.w : img.h
@baseimg = Bitmap.create(imgsize , imgsize)
@baseimg.fillRect(0, 0, imgsize, imgsize, img.get_pixel(@param.px, @param.py))
SDL.blit_surface(img, 0, 0, 0, 0, @baseimg, 0, 0)
end
@eventlayer = @baseimg == nil ? true : false
@w = w
@h = h
@cw = 0
@ch = 0
@bcol = 0 # black
@spr = nil
@buf = nil
@buf2 = nil
@pos_x = Array.new
@pos_y = Array.new
reSize
if @baseimg != nil
@chipdb = Hash.new()
th = @baseimg.h / @param.tpixels
tw = @baseimg.w / @param.tpixels
px = @param.tpixels
th.times{|y|
tw.times{|x|
@chipdb[y * @param.tsize + x] = copyRect(@baseimg, px * x, px * y, px, px)
}
}
draw(@spr)
end
end
def getCode(x, y)
@mapdat[y][x]
end
def x=(v)
tx = @param.tpixels
@x = v
ocx = @cx
@cx = @x / tx
@mx = @x % tx
@dx = @cx - ocx
update_position_x
end
def y=(v)
tx = @param.tpixels
@y = v
ocy = @cy
@cy = @y / tx
@my = @y % tx
@dy = @cy - ocy
update_position_y
end
def dispose
@mapdat = nil
@baseimg = nil
@spr.dispose if @spr != nil
end
def eventLayer?
@eventlayer
end
def_delegators(:@spr, :visible, :visible=, :dp, :dp=)
end
attr_reader :name, :layers, :x, :y, :w, :h
def initialize(param)
@param = param
if @param.tsize != 16 && @param.tsize != 256 then
raise Miyakorror.new("MapChip size is 16 or 256!")
end
@layers = nil
@visible = false
@x = 0
@y = 0
h = 0
# llistの座標軸が逆になるので注意!
llist = Array.new()
File.open(@param.csv, "r"){|f|
mlist = Array.new()
while !(f.eof?()) do
l = f.readline()
if l =~ /^[\r\n]+$/
h = mlist.length if h == 0
llist.push(mlist)
mlist = Array.new()
next
end
mlist.push(l.split(",").collect{|v| v.to_i()})
end
h = mlist.length if h == 0
llist.push(mlist) if mlist.length != 0
}
w = llist[0].length
brlist = @param.blist.reverse
@layers = Array.new
llist.each_with_index{|l, i| @layers.push(MapLayer.new(@param, l, w, h, brlist[i])) }
@layers = @layers.reverse
@w = @layers[0].w
@h = @layers[0].h
@@maps.push(self)
end
def x=(v)
wp = @w * @param.tpixels
@x = v
if wp - @x <= Screen.w
@x = @x % wp
elsif @x < 0
@x = wp + @x
end
@layers.each{|l| l.x = @x }
end
def y=(v)
hp = @h * @param.tpixels
@y = v
if hp - @y <= Screen.h
@y = @y % hp
elsif @y < 0
@y = hp + @y
end
@layers.each{|l| l.y = @y }
end
def dp
@layers.collect{|l| l.eventLayer? ? nil : l.dp }
end
def dp=(d)
@layers.each{|l| l.dp = d }
end
def setDPs(*dl)
l = dl.length
l = @layers.length if l > @layers.length
l.length.each_with_index{|l, d| l.dp = dl[d] }
end
def layer(idx)
@layers[idx]
end
def visible
@visible
end
def visible=(f)
@visible = f
@layers.each{|ll| ll.visible = @visible if ll.eventLayer? == false }
end
def getCodeReal(idx, x, y)
@layers[idx].getCode(x % @param.tpixels, y % @param.tpixels)
end
def getCode(idx, x, y)
@layers[idx].getCode(x, y)
end
def chipSize
@tpixels
end
def dispose
@layers.each{|l|
l.dispose
l = nil
}
@layers = Array.new
@@maps.delete(self)
end
def reSize
@layers.reverse.each{|l| l.reSize }
end
def Map::getList
@@maps
end
end
module Story
@@class_prefix = "Scene"
@@sub_prefix = "Sub"
@@script_list = Hash.new
@@prev_label = nil
@@next_label = nil
@@stack = Array.new
@@scene_cache = Hash.new
@@scene_cache_list = Array.new
@@scene_cache_max = 20
def Story.class_prefix
@@class_prefix
end
def Story.sub_prefix
@@sub_prefix
end
def Story.class_prefix=(n)
@@class_prefix = n
end
def Story.sub_prefix=(n)
@@sub_prefix = n
end
def Story.script_list
@@script_list
end
def Story.prev_label
@@prev_label
end
def Story.next_label
@@next_label
end
def Story.upper_label
return @@stack.empty? ? nil : @@stack.last[0]
end
class Scene
def Scene.inherited(c)
name = c.to_s.split(/::/).last
clname = ""
prefix = ""
if name =~ /^#{Story.class_prefix}\_(.+)/
clname = $1
prefix = Story.class_prefix
elsif name =~ /^#{Story.sub_prefix}\_(.+)/
clname = $1
prefix = Story.sub_prefix
else
raise MiyakoError.new("Illegal Class Name! use only #{Story.class_prefix} or #{Story.sub_prefix}!")
end
raise MiyakoError.new("Redefine Class Name! : #{name}") if Story.script_list.has_key?(clname)
Story.script_list[clname] = prefix
end
def initialize(n)
@now = n
@prev = nil
@upper = nil
self.init
end
def init_inner(p, u)
@prev = p
@upper = u
end
def init
end
def setup
end
def view_in
return false
end
def update
return @now
end
def view_out
return false
end
def final
end
def interrupt
return nil
end
def Scene.notice
return ""
end
end
def initialize
end
def get_scene(pf, n, s)
class_name = pf.to_s+"_"+n.to_s
class_symbol = (class_name+"_"+s.to_s).intern
if @@scene_cache_list.length == @@scene_cache_max
del_symbol = @@scene_cache_list.shift
@@scene_cache.delete(del_symbol)
end
@@scene_cache_list.delete(class_symbol)
@@scene_cache_list.push(class_symbol)
@@scene_cache[class_symbol] ||= instance_eval(class_name+".new(\""+n.to_s+"\")")
return @@scene_cache[class_symbol]
end
def run(n)
return nil if n == nil
u = nil
on = nil
@@stack = Array.new # reset
while n != nil
@@prev_label = on
on = n
inp = nil
raise MiyakoError.new("Illegal Script-label name! : "+n.to_s) if @@script_list.has_key?("#{n}") == false
pref = @@script_list[n.to_s]
u = get_scene(pref.to_s, n, @@stack.size) if u == nil
u.init_inner(@@prev_label, Story.upper_label)
u.setup
Miyako::Input.update
while inp == nil && u.view_in
inp = u.interrupt
break if inp != nil
Miyako::Screen.update
Miyako::Input.update
end
while inp == nil && n != nil && on.to_s == n.to_s
Miyako::Input.update
inp = u.interrupt
break if inp != nil
n = u.update
Miyako::Screen.update
end
@@next_label = n
Miyako::Input.update
while inp == nil && u.view_out
inp = u.interrupt
break if inp != nil
Miyako::Screen.update
Miyako::Input.update
end
u.final
if inp != nil
n = inp
@@next_label = inp
@@stack.push([on, u]) if @@script_list[n.to_s] == Story.sub_prefix
u = nil
elsif n.to_s == "return" # return from subroutine is only return-label is "return"
if @@stack.empty? == false
n, u = @@stack.pop
else
return # when stack is empty is same as return nil
end
elsif n == nil
return
elsif @@script_list[n.to_s] == Story.sub_prefix
@@stack.push([on, u])
u = nil
else
u = nil
end
end
end
def listup
list = Array.new
@@script_list.keys.sort.each{|k|
pref = @@script_list["#{k}"]
s = instance_eval("#{pref}_#{k}.notice")
list.push("#{k}, #{pref}_#{k}, \"#{s}\"\n")
}
return list
end
def listup2csv(csvfname)
csvfname += ".csv" if csvfname !~ /\.csv$/
list = listup
File.open(csvfname, "w"){|f| list.each{|l| f.print l } }
end
end
end