#=============================================================================== # El Panoramisator 2.4 # Script créé par Zeus81 # Fonction bitmap_to_buffer par Yeyinde # Utilisation : $scene = Scene_Panoramisator.new #=============================================================================== module Save_Map AUTOTILES = [ 26, 27, 32, 33, 4, 27, 32, 33, 26, 5, 32, 33, 4, 5, 32, 33, 26, 27, 32, 11, 4, 27, 32, 11, 26, 5, 32, 11, 4, 5, 32, 11, 26, 27, 10, 33, 4, 27, 10, 33, 26, 5, 10, 33, 4, 5, 10, 33, 26, 27, 10, 11, 4, 27, 10, 11, 26, 5, 10, 11, 4, 5, 10, 11, 24, 25, 30, 31, 24, 5, 30, 31, 24, 25, 30, 11, 24, 5, 30, 11, 14, 15, 20, 21, 14, 15, 20, 11, 14, 15, 10, 21, 14, 15, 10, 11, 28, 29, 34, 35, 28, 29, 10, 35, 4, 29, 34, 35, 4, 29, 10, 35, 38, 39, 44, 45, 4, 39, 44, 45, 38, 5, 44, 45, 4, 5, 44, 45, 24, 29, 30, 35, 14, 15, 44, 45, 12, 13, 18, 19, 12, 13, 18, 11, 16, 17, 22, 23, 16, 17, 10, 23, 40, 41, 46, 47, 4, 41, 46, 47, 36, 37, 42, 43, 36, 5, 42, 43, 12, 17, 18, 23, 12, 13, 42, 43, 36, 41, 42, 47, 16, 17, 46, 47, 12, 17, 42, 47, 0, 1, 6, 7] @cache = {} @autorect = Rect.new(0, 0, 32, 32) RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i') def self.bitmap_to_buffer RtlMoveMemory_pi.call(address = "\0"*4, @bitmap.object_id*2+16, 4) RtlMoveMemory_pi.call(address, address.unpack("L")[0]+8, 4) RtlMoveMemory_pi.call(address, address.unpack("L")[0]+16, 4) RtlMoveMemory_pi.call(@buffer, address.unpack("L")[0], @buffer.size) end def self.new(map_id, background_color, panorama_display, fog_display, autotiles_anime, layers_split, priorities_split, save_type) map = load_data("Data/Map%03d.rxdata" % map_id) tileset = load_data("Data/Tilesets.rxdata")[map.tileset_id] @priorities = tileset.priorities @autotiles = [""] + tileset.autotile_names @tileset = RPG::Cache.tileset(tileset.tileset_name) @data, @w, @h = map.data, map.width * 32, map.height * 32 @buffer, @bitmap = "\0" * (@w * 128), Bitmap.new(@w, 32) @panorama = load_panorama(tileset) if panorama_display and panorama_display = !tileset.panorama_name.empty? @fog = load_fog(tileset) if fog_display and fog_display = !tileset.fog_name.empty? and fog_display = (tileset.fog_opacity != 0) make_png_preparation if save_type == 1 split = (layers_split or priorities_split != 0) layers = layers_split ? [0, 1, 2] : [0] layers << -1 if split and panorama_display layers << -2 if split and fog_display thread = Thread.new {loop {Graphics.update; sleep(1)}} for layer in layers z_range = layers_split ? [layer] : 0...3 for priority in 0...(layer < 0 ? 1 : [1, 2, 6][priorities_split]) p_range = [0...6, priority == 0 ? [0] : 1...6, [priority]][priorities_split] animations = layer < 0 ? 1 : animations?(z_range, p_range, autotiles_anime) animations.times do |animation| make_filename(map_id, layers_split, layer, priorities_split, priority, animations, animation, save_type) file = File.open(@filename, "wb") file.write(make_bmp_header) if save_type == 0 @data.ysize.times do |y| y = @data.ysize-1-y if save_type == 0 @bitmap.fill_rect(@bitmap.rect, background_color) draw_panorama(y) if panorama_display and (layer == -1 or !split) draw_tiles(y, z_range, p_range, animation) if layer >= 0 draw_fog(y) if fog_display and (layer == -2 or !split) bitmap_to_buffer case save_type when 0; file.write(@buffer) when 1; make_png_data {|s| file.putc(0); file.write(s)} end end file.close make_png if save_type == 1 end end end thread.kill @bitmap.dispose @tileset.dispose @data=@w=@h=@buffer=@bitmap=@panorama=@fog=@tileset=@autotiles=@priorities=@filename=@png_range1=@png_range2 = nil end def self.make_filename(map_id, layers_split, layer, priorities_split, priority, animations, animation, save_type) @filename = "Map[%03d]" % map_id case layer when -1; @filename << "_Panorama" when -2; @filename << "_Fog" else @filename << "_Layer[#{layer}]" if layers_split @filename << "_Priority[#{priority}]" if priorities_split != 0 @filename << "_Autotile[#{animation}]" if animations != 1 end @filename << [".bmp", ".png"][save_type] end def self.make_bmp_header "BM#{[4*@w*@h+54,0,54,40,@w,@h,1,32,0,4*@w*@h,0,0,0,0].pack("L6S2L6")}" end def self.make_png_preparation @png_range1, @png_range2 = Array.new(@w*32), Array.new(32) @png_range1.size.times {|i| @png_range1[i] = i*4} @png_range2.size.times {|i| @png_range2[i] = (31-i)*@w*4} end def self.make_png_data for i in @png_range1 k = @buffer[j=i+2] @buffer[j] = @buffer[i] @buffer[i] = k end j = @w*4 @png_range2.each {|i| yield @buffer[i, j]} end def self.make_png file = File.open(@filename, "rb") chunks = ["IHDR#{[@w,@h,8,6,0,0,0].pack("N2C5")}", "IDAT#{Zlib::Deflate.deflate(file.read, 9)}", "IEND"] file.close file = File.open(@filename, "wb") file.write("\211PNG\r\n\32\n") for chunk in chunks file.write([chunk.size-4].pack("N")) file.write(chunk) file.write([Zlib.crc32(chunk)].pack("N")) end file.close end def self.animations?(z_range, p_range, autotiles_anime) if autotiles_anime values = [] @autotiles.each {|n| values << [RPG::Cache.autotile(n).width/96, 1].max} else values = Array.new(@autotiles.size, 1) end value_max, value, v = values.max, 0 z_range.each {|z| @data.ysize.times {|y| @data.xsize.times {|x| if (tile_id=@data[x, y, z]) != 0 and p_range.include?(@priorities[tile_id]) if tile_id >= 384 then value = 1 if value == 0 else value = v if value < (v = values[tile_id/48]) end return value if value == value_max end }}} return value end def self.draw_panorama(y) rect = Rect.new(0, y*32%(@panorama.height-(@panorama.height%32 != 0 ? 32 : 0)), @panorama.width, 32) (@w/rect.width.to_f).ceil.times {|i| @bitmap.blt(i*rect.width, 0, @panorama, rect)} end def self.draw_fog(y) rect = Rect.new(0, y*32%(@fog.height-32), @fog.width, 32) (@w/rect.width.to_f).ceil.times {|i| @bitmap.blt(i*rect.width, 0, @fog, rect)} end def self.draw_tiles(y, z_range, p_range, animation) tiles = [] for z in z_range @data.xsize.times do |x| next unless p_range.include?(p = @priorities[tile_id = @data[x, y, z]]) if tile_id >= 384 tiles.push([p, @tileset, load_tile(tile_id)]) elsif tile_id != 0 tiles.push([p, load_autotile(tile_id, animation, @autotiles[tile_id/48]), @autorect]) end tiles.sort! {|a, b| a[0] <=> b[0]} tiles.each {|tile| @bitmap.blt(x*32, 0, tile[1], tile[2])} tiles.clear end end end def self.load_panorama(t) unless @cache[key = [t.panorama_name, t.panorama_hue]] bmp = RPG::Cache.panorama(*key) if bmp.height % 32 != 0 @cache[key] = Bitmap.new(bmp.width, bmp.height+32) (@cache[key].height/bmp.height.to_f).ceil.times {|i| @cache[key].blt(0, bmp.height*i, bmp, bmp.rect)} bmp.dispose else @cache[key] = bmp end end return @cache[key] end def self.load_fog(t) unless @cache[key = [t.fog_name, t.fog_hue, t.fog_zoom, t.fog_opacity]] bmp = RPG::Cache.fog(key[0], key[1]) @cache[key] = Bitmap.new(bmp.width*key[2]/100, (h=bmp.height*key[2]/100)+32) (@cache[key].height/bmp.height.to_f).ceil.times do |i| @cache[key].stretch_blt(Rect.new(0, h*i, @cache[key].width, h), bmp, bmp.rect, key[3]) end bmp.dispose end return @cache[key] end def self.load_tile(tile_id) @cache[tile_id] = Rect.new(tile_id%8*32, (tile_id-384)/8*32, 32, 32) unless @cache[tile_id] return @cache[tile_id] end def self.load_autotile(tile_id, animation, name) src_bmp = RPG::Cache.autotile(name) animation = src_bmp.width > 96 ? animation % (src_bmp.width/96) * 96 : 0 unless @cache[key = [tile_id, animation, name]] @cache[key] = bmp = Bitmap.new(32, 32) tile_id = tile_id % 48 * 4 for i in 0...4 j = AUTOTILES[tile_id + i] src_rect = Rect.new(animation+j%6*16, j/6*16, 16, 16) bmp.blt(i%2*16, i/2*16, src_bmp, src_rect) end end return @cache[key] end end class Window_MapList < Window_Selectable def initialize @back_sprite = Sprite.new @back_sprite.bitmap = Bitmap.new(1, 1) @back_sprite.bitmap.set_pixel(0, 0, Color.new(64, 64, 128, 192)) super(6, 32, 324, 384) self.opacity, self.active, self.visible, self.z = 0, false, false, 120 @back_sprite.zoom_x = width-16 refresh end def dispose @back_sprite.bitmap.dispose @back_sprite.dispose super end def visible=(visible) @back_sprite.visible = super(visible) end def x=(x) @back_sprite.x = x+8; super(x) end def y=(y) @back_sprite.y = y+8; super(y) end def z=(z) @back_sprite.z = z-10; super(z) end def refresh map_infos = load_data("Data/MapInfos.rxdata") @maps_id, @item_max, @index = map_infos.keys.sort, map_infos.size, 0 self.contents.dispose if self.contents self.contents = Bitmap.new(width-32, @item_max*32) self.contents.font = Font.new("Comic Sans MS", 20) @back_sprite.zoom_y = [self.contents.height+16, height-16].min for i in 0...@maps_id.size self.contents.fill_rect(4, i*32+6, width-40, 20, Color.new(0,0,0)) self.contents.draw_text(4, i*32+6, width-40, 20, " %03d - #{map_infos[@maps_id[i]].name}" % @maps_id[i]) end end def map_id() @maps_id[@index] end def update_help() @help_window.set_text("Touche C : Valider - Touche B : Annuler", 1) end end class Window_Help_Scroll < Window_Base SPACE = " " * 8 def initialize super(0, 428, 640, 64) self.contents = Bitmap.new(1, 1) self.contents.font = Font.new("Comic Sans MS", 20) self.windowskin = nil @wait_count = @text_width = 0 end def set_text(text, align = 0) if text != @text or align != @align @text, @align, @wait_count, self.ox, font = text, align, 100, 0, self.contents.font if (w = self.contents.text_size(text).width) >= width-32 text += SPACE + text w += (@text_width = self.contents.text_size(SPACE).width + w) else @text_width, w = 0, width-32 end self.contents.dispose self.contents = Bitmap.new(w, 32) self.contents.font = font self.contents.draw_text(self.contents.rect, text, align) end self.ox = (self.ox >= @text_width ? 0 : self.ox+1) if @text_width > 0 and (@wait_count -= 1) < 0 end end class Window_Panoramisator < Window_Selectable attr_accessor :item_max, :data def initialize super(0, 0, 640, 480) self.contents = Bitmap.new(width-32, height-32) self.contents.font = Font.new("Comic Sans MS", 24) @colors = [Color.new(32,64,128), Color.new(255,255,255), Color.new(224,32,32), Color.new(128,128,128)] @item_max, @index, @data = 12, 0, [0, Color.new(0, 0, 0, 0), true, true, false, false, 0, 0] refresh end def refresh self.contents.clear self.contents.fill_rect(0, 24, 608, 1, normal_color) self.contents.fill_rect(0, 424, 608, 1, normal_color) self.contents.font.size = 28 self.contents.font.color = knockout_color self.contents.draw_text(0, -8, 608, 32, "El Panoramisator", 1) self.contents.font.size = 16 self.contents.font.color = normal_color self.contents.draw_text(0, 408, 608, 20, "Zeus81 2008 - 2010", 2) self.contents.draw_text(0, 420, 64, 20, "Aide") self.contents.font.size = 20 self.contents.draw_text(8, 64, 240, 32, "Choix de la couleur de fond :") self.contents.draw_text(352, 44, 48, 32, "Rouge", 1) self.contents.draw_text(400, 44, 48, 32, "Vert", 1) self.contents.draw_text(448, 44, 48, 32, "Bleu", 1) self.contents.draw_text(496, 44, 48, 32, "Alpha", 1) self.contents.draw_text(32, 96, 608, 32, "Afficher le panorama") self.contents.draw_text(48, 128, 608, 32, "Afficher le brouillard") self.contents.draw_text(32, 160, 608, 32, "Animer les autotiles") self.contents.draw_text(48, 192, 608, 32, "Séparer les différentes couches sur plusieurs images") self.contents.draw_text(32, 224, 608, 32, "Ne pas séparer selon la priorité de superposition") self.contents.draw_text(32, 256, 608, 32, "Séparer selon la priorité de superposition sur 2 images") self.contents.draw_text(32, 288, 608, 32, "Séparer selon la priorité de superposition sur 6 images") self.contents.draw_text(48, 320, 608, 32, "Enregistrer au format BMP 32 bits") self.contents.draw_text(48, 352, 608, 32, "Enregistrer au format PNG 32 bits") self.contents.draw_text(0, 384, 608, 32, "EXPORTER LA MAP", 1) self.contents.font.color.set(0,0,0) refresh_values end def refresh_values if @data[0] == 0 then align, text = 1, "Veuillez sélectionner une map" else align, text = 0, " %03d - #{load_data("Data/MapInfos.rxdata")[@data[0]].name}" % @data[0] end self.contents.fill_rect(10, 38, 284, 20, normal_color) self.contents.draw_text(10, 38, 284, 20, text, align) self.contents.fill_rect(356, 72, 40, 20, normal_color) self.contents.fill_rect(404, 72, 40, 20, normal_color) self.contents.fill_rect(452, 72, 40, 20, normal_color) self.contents.fill_rect(500, 72, 40, 20, normal_color) self.contents.draw_text(356, 72, 40, 20, @data[1].red.to_i.to_s, 1) self.contents.draw_text(404, 72, 40, 20, @data[1].green.to_i.to_s, 1) self.contents.draw_text(452, 72, 40, 20, @data[1].blue.to_i.to_s, 1) self.contents.draw_text(500, 72, 40, 20, @data[1].alpha.to_i.to_s, 1) self.contents.fill_rect(548, 48, 48, 48, @data[1]) draw_check_box(0, 96, @data[2]) draw_check_box(16, 128, @data[3]) draw_check_box(0, 160, @data[4]) draw_check_box(16, 192, @data[5]) draw_radio_button(0, 224, @data[6]==0) draw_radio_button(0, 256, @data[6]==1) draw_radio_button(0, 288, @data[6]==2) draw_radio_button(16, 320, @data[7]==0) draw_radio_button(16, 352, @data[7]==1) end def draw_check_box(x, y, state) self.contents.fill_rect(x+11, y+11, 10, 10, @colors[0]) self.contents.fill_rect(x+12, y+12, 8, 8, @colors[1]) self.contents.fill_rect(x+13, y+13, 6, 6, @colors[state ? 2 : 3]) end def draw_radio_button(x, y, state) 6.times {|i| self.contents.fill_rect(x+15-i, y+10+i, 2+i*2, 12-i*2, @colors[0])} 5.times {|i| self.contents.fill_rect(x+15-i, y+11+i, 2+i*2, 10-i*2, @colors[1])} 4.times {|i| self.contents.fill_rect(x+15-i, y+12+i, 2+i*2, 8-i*2, @colors[state ? 2 : 3])} end def update_cursor_rect if @item_max == 0 then self.cursor_rect.set(352+@index*48, 48, 48, 48) else self.cursor_rect.set(@index==11 ? 152 : 0, 32+@index*32, @index.between?(2,10) ? 608 : 304, 32) end end def update_help text = case @item_max == 0 ? -1 : @index when -1; "Entrée : Valider - Echap : Annuler - Touches directionnelles : Modifier" when 0; "Selectionnez la map que vous désirez transformer en image(s)." when 1; "Configurez la couleur qui remplacera les zones transparentes." when 2; "Le panorama de la map se répètera sur toute l'image." when 3; "Le brouillard de la map se répètera sur toute l'image. Attention le type de transparence n'est pas pris en compte." when 4; "Pour les autotiles animés." when 5; "Sépare les différentes couches sur plusieurs images." when 6; "Fusionne tout dans la même image." when 7; "Sauvegarde les images au dessus et au dessous du héros séparément." when 8; "Enregistre les images selon leur priorité de superposition dans 6 fichiers." when 9; "Enregistrement très rapide mais fichier lourd et transparence non supportée par certains logiciels." when 10; "Enregistrement très lent mais fichier léger et transparence directement compatible." << " (Toutefois sauf petites maps il est préférable d'enregistrer les images en BMP puis de les" << " convertir en PNG via un logiciel tiers comme Gimp, c'est plus rapide)" when 11; "Attention, cela peut prendre un certain temps selon votre configuration et la taille de la map." end @help_window.set_text(text, 1) end end class Scene_Panoramisator def initialize $data_system = load_data("Data/System.rxdata") unless $data_system $game_system = Game_System.new unless $game_system end def main @main_window = Window_Panoramisator.new @maplist_window = Window_MapList.new @help_window = Window_Help_Scroll.new @main_window.help_window = @help_window @maplist_window.help_window = @help_window Graphics.transition while ($scene == self) Graphics.update Input.update update end Graphics.freeze @main_window.dispose @maplist_window.dispose @help_window.dispose end def update @main_window.update @maplist_window.update if @maplist_window.active then update_maplist elsif @main_window.item_max == 0 then update_background_color else update_main end end def update_maplist if Input.trigger?(Input::C) $game_system.se_play($data_system.decision_se) @maplist_window.visible = @maplist_window.active = false @main_window.active = true @main_window.data[0] = @maplist_window.map_id @main_window.refresh_values elsif Input.trigger?(Input::B) $game_system.se_play($data_system.cancel_se) @maplist_window.visible = @maplist_window.active = false @main_window.active = true end end def update_main if Input.trigger?(Input::C) case @main_window.index when 0 $game_system.se_play($data_system.decision_se) @maplist_window.visible = @maplist_window.active = true @main_window.active = false when 1 $game_system.se_play($data_system.decision_se) @last_background_color = @main_window.data[1].dup @count = 1 @main_window.item_max = 0 @main_window.index = 0 when 2..10 $game_system.se_play($data_system.decision_se) if @main_window.index < 6 then @main_window.data[@main_window.index] = !@main_window.data[@main_window.index] else @main_window.data[@main_window.index/9+6] = @main_window.index%3 end @main_window.refresh_values when 11 if @main_window.data[0] != 0 $game_system.se_play($data_system.save_se) Save_Map.new(*@main_window.data) print(" Le traitement est terminé !\n", "Les images se trouvent dans le dossier de votre jeu.") else $game_system.se_play($data_system.buzzer_se) end end elsif Input.trigger?(Input::B) $game_system.se_play($data_system.cancel_se) $scene = nil end end def update_background_color color = @main_window.data[1] if Input.press?(Input::UP) == Input.press?(Input::DOWN) @count = 1 elsif Input.repeat?(Input::DOWN) $game_system.se_play($data_system.cursor_se) case @main_window.index when 0; color.red = [color.red - @count.round, 0].max when 1; color.green = [color.green - @count.round, 0].max when 2; color.blue = [color.blue - @count.round, 0].max when 3; color.alpha = [color.alpha - @count.round, 0].max end @main_window.refresh_values elsif Input.repeat?(Input::UP) $game_system.se_play($data_system.cursor_se) case @main_window.index when 0; color.red += @count.round when 1; color.green += @count.round when 2; color.blue += @count.round when 3; color.alpha += @count.round end @main_window.refresh_values end if Input.repeat?(Input::LEFT) $game_system.se_play($data_system.cursor_se) @main_window.index = (@main_window.index - 1) % 4 elsif Input.repeat?(Input::RIGHT) $game_system.se_play($data_system.cursor_se) @main_window.index = (@main_window.index + 1) % 4 elsif Input.trigger?(Input::C) $game_system.se_play($data_system.decision_se) @main_window.item_max = 12 @main_window.index = 1 elsif Input.trigger?(Input::B) $game_system.se_play($data_system.cancel_se) @main_window.data[1] = @last_background_color @main_window.item_max = 12 @main_window.index = 1 @main_window.refresh_values end @count *= 1.02 end end