Kirin 37 Posted March 28, 2012 (edited) This script was not written by me! I simply translated it from Japanese and posted it here to share! Do NOT ask me for support, I'm not a scripter (I'll try, but most likely fail)! Important bit out of the way, let's get cranking. The script today is: Random Dungeon Generator Version 0.14 by Saba Kan of プãƒãƒ¬ã‚¢ - PetitRare Updated: 2012/01/21 Email asking for and being granted permission to translate and share: kirinelf ã•ん㸠ã‚ã–ã‚ã–メールã‚りãŒã¨ã†ã”ã–ã„ã¾ã™ã€‚ 日本語ã§ã™ã¿ã¾ã›ã‚“。 ã‚‚ã¡ã‚ã‚“æ“迎ã—ã¾ã™ã€ã©ã†ãžç¿»è¨³ãªã•ã£ã¦ãã ã•ã„。 > http://www.rpgmakervxace.net > http://forums.rpgmakerweb.com ãŠãŠï¼ã€€ã“れã‹ã‚‰ã‚‚ãƒã‚§ãƒƒã‚¯ã•ã›ã¦ã„ãŸã ãã¾ã™ï¼ 2012å¹´3月26æ—¥21:42 Kirin: > ã“ã‚“ã«ã¡ã¯ã€ > > 僕ã¯è‹±èªžã®RPGVXAã®ã‚³ãƒƒãƒ ニティã‹ã‚‰ã®kirinelf ã§ã™ã€‚ã‚リンã§å‘¼ã³ã¾ã™ã“㨠> ã‚‚ã„ã„ã§ã™ã€‚ã‚ã®ã€‚。。日本語ãŒã‚ã¾ã‚Šä¸Šæ‰‹ã§ã‚ã‚りã¾ã›ã‚“ã§ã™ã‹ã‚‰ç”³ã—訳ã‚り ã¾ã›ã‚“。よã‚ã—ããŠããŒã„ã—ã¾ã™ï¼ > > 今回ã®ãƒ¡ãƒ¼ãƒ«ã®ç†ç”±ã¯RPGVXAã®RGSS3スクリプトを翻訳ã—ãŸã„ã“ã¨ã§ã™ã€‚貴方様 ã®ã‚¹ã‚¯ãƒªãƒ—トを英語ã«ç¿»è¨³ã—ã¦ã‚‚ã„ã„ã§ã—ょã†ã‹ï¼Ÿã‚‚ã¡ã‚ã‚“ > 貴方様ã®è¨˜è¼‰ã‚‚゠りã¾ã™ã€‚自分を書ã„ãŸäº‹ã‚‚絶対言ã„ã¾ã›ã‚“。 > > 僕ã®ç›®çš„ã¯é¢ç™½ãã†ãªã‚¹ã‚¯ãƒªãƒ—トを翻訳ã—ã¦ã€ã“ã®ã‚µã‚¤ãƒˆã«ã»ã‹ã®è‹±èªžã®ãƒ¦ãƒ¼ã‚µ ã¨åˆ†ã‹ã¡åˆã„ã¾ã™ï¼š > > http://www.rpgmakervxace.net > http://forums.rpgmakerweb.com > > ãã®ã‚µã‚¤ãƒˆã¯è‹±èªžRPGVXAã®ä¸€ç•ªå¤§ãã„コッムニティã§ã™ã€‚ > > ãŠè¿”äº‹ã‚’æ ¹æ°—ã‚ˆãã¦å¾…ã¦ã„ã¾ã™ã€‚ > > kirinelf (ã‚リン) より。 The above, translated: To kirinelf: Thank you for going out of your way to send an email to me. Sorry for this being in Japanese. Please be my guest and translate them as you wish. > http://www.rpgmakervxace.net > http://forums.rpgmakerweb.com Oh! I'll be sure to check these sites from now on too! 2012å¹´3月26æ—¥21:42 Kirin: > Hello, > > I am kirinelf from the English speaking RMVXA community. You can call me Kirin. > I'm not very good at Japanese, so I apologize for that. Pleased to make your acquaintance! > > The purpose of this email is to ask about translating RMVXA's RGSS3 scripts. Is it alright > to translate your scripts into English? Of course, you will be credited. I will not claim > to have written any of your scripts. > > My aim is to translate scripts I find interesting and to share them with the rest of the > English speaking community, namely at these sites: > > http://www.rpgmakervxace.net > http://forums.rpgmakerweb.com > > These sites are the largest English RMVXA communities. > > I will await your reply patiently. > > From kirinelf (Kirin) So what does this script do? Think Diablo. Random dungeon generation from within the game, dynamically. No two identical dungeons. Here're two screeenshots: Setup within the editor: The result: Features Allows you to have dynamically generated dungeons in your game. Allows you to have dynamically and randomly placed events in said dungeons. Automatically places events tagged with a '*' in the name as enemies in the dungeon. Or you can have random encounters instead. Allows you to have events that show up permanently on the minimap once discovered, as well as events that have a hollow center to be more distinct. ^ Both of those can be used together! Has a sub script that makes events move after your player does, similar to dungeon crawler-roguelikes. There really are quite a few features and setting up shenanigans that you need to be aware of, and for that reason I've included a How to Use text file I wrote up myself after experimenting with the demo that I hope will help you guys. There are three scripts: A main script that handles the dungeon generation and everything within, and two sub scripts. The first sub script allows you to have events that only move/activate when the player moves, just like in a typical dungeon crawler rogue-like. The second subscript places a minimap smack bang in the middle of the screen. Without further ado, here're the three scripts: 1. Main script #============================================================================== # â– Dungeon Creation 6 # @version 0.14 12/01/21 RGSS3 # @author Saba Kan # @translator kirinelf #------------------------------------------------------------------------------ #   #============================================================================== module Saba module Dungeon # Minumum block size (Hard to explain, try it out yourself) # Default: 7 MINIMUM_RECT_SIZE = 7 # Minimum room size. # Default: 3 MINIMUM_ROOM_SIZE = 3 # Margin between rooms and 'blocks'. # Default: 2 MARGIN_BETWEEN_RECT_ROOM = 2 # The percentage of corridors made. (1/n) # Works best with lower values. # Default: 35 MORE_COUPLE_RATE = 35 # Variable that stores enemy amount. ENEMY_COUNT_VARIABLE = 1 # Debug Mode # ・Always show enemies on minimap. DEBUG_MODE = false end end #========================================================================= # Do not edit anything under this line unless you know what you're doing! #========================================================================= #============================================================================== # â– Dungeon_Rect #------------------------------------------------------------------------------ #  ダンジョンを区切ã£ãŸé ˜åŸŸã‚’表ã—ã¾ã™ã€‚ #ã€€å„ Dungeon_Rect ã«ä¸€ã¤ã¥ã¤ Room ãŒå˜åœ¨ã—ã¾ã™ã€‚ #============================================================================== class Dungeon_Rect #-------------------------------------------------------------------------- # ◠公開インスタンス変数 #-------------------------------------------------------------------------- attr_accessor :lx attr_accessor :ly attr_accessor :hx attr_accessor :hy attr_accessor :room attr_accessor :done_split_v attr_accessor :done_split_h #-------------------------------------------------------------------------- # â— ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆåˆæœŸåŒ– #-------------------------------------------------------------------------- def initialize(lx, ly, hx, hy) self.lx = lx self.ly = ly self.hx = hx self.hy = hy self.done_split_v = false self.done_split_h = false end end #============================================================================== # â– Room #------------------------------------------------------------------------------ #  部屋ã§ã™ã€‚ #============================================================================== class Room #-------------------------------------------------------------------------- # ◠公開インスタンス変数 #-------------------------------------------------------------------------- attr_accessor :lx attr_accessor :ly attr_accessor :hx attr_accessor :hy attr_accessor :mapping attr_reader :width attr_reader :height attr_reader :couple_areas # 通路ã«é¢ã—ã¦ã„ã‚‹[x, y]ã®ãƒªã‚¹ãƒˆ #-------------------------------------------------------------------------- # â— ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆåˆæœŸåŒ– #-------------------------------------------------------------------------- def initialize(lx, ly, hx, hy) self.lx = lx self.ly = ly self.hx = hx self.hy = hy @width = hx - lx @height = hy - ly @events = {} @couple_areas = [] @mapping = false end #-------------------------------------------------------------------------- # ◠イベントé…ç½®å¯èƒ½æ•°æ®‹ã‚Šã‚’å–å¾— #-------------------------------------------------------------------------- def remain return (hx - lx) * (hy - ly) - @events.size - @couple_areas.size end #-------------------------------------------------------------------------- # ◠指定ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’ã“ã®éƒ¨å±‹ã®ãƒ©ãƒ³ãƒ€ãƒ ãªå ´æ‰€ã«é…ç½® #-------------------------------------------------------------------------- def put_to_random_place(event) begin key = [rand(hx - lx) + lx, rand(hy - ly) + ly] end while @events[key] != nil || @couple_areas.include?(key) @events[key] = event event.moveto(key[0], key[1]) end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™ã‚’å«ã‚“ã§ã„ã‚‹ã‹ã‚’å–å¾— #-------------------------------------------------------------------------- def contains(x, y) return lx <= x && x < hx && ly <= y && y < hy end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™ã‚’明るãã™ã‚‹ã‹ã‚’å–å¾— #-------------------------------------------------------------------------- def right_area?(x, y) return lx-1 <= x && x < hx+1 && ly-1 <= y && y < hy+1 end end #============================================================================== # â– Couple #------------------------------------------------------------------------------ #  通路ã§ã™ã€‚ #============================================================================== class Couple #-------------------------------------------------------------------------- # ◠公開インスタンス変数 #-------------------------------------------------------------------------- attr_accessor :rect0 attr_accessor :rect1 attr_accessor :direction end class Game_Map attr_reader :map attr_accessor :new_events #-------------------------------------------------------------------------- # ◠定数 #-------------------------------------------------------------------------- COUPLE_VERTICAL = 0 COUPLE_HORIZONAL = 1 #-------------------------------------------------------------------------- # ◠セットアップ # map_id : マップ ID #-------------------------------------------------------------------------- alias saba_setup setup def setup(map_id) saba_setup(map_id) @random_dungeon = nil make_random_dungeon if dungeon? end #-------------------------------------------------------------------------- # â— ãƒ©ãƒ³ãƒ€ãƒ ãƒ€ãƒ³ã‚¸ãƒ§ãƒ³ã‚’ä½œæˆ #-------------------------------------------------------------------------- def make_random_dungeon @rect_list = [] @room_list = [] @couple_list = [] @map = load_data(sprintf("Data/Map%03d.rvdata2", @map_id)) @floor_chip_id = @map.data[0, 0, 0] @floor_chip_id1 = @map.data[1, 0, 0] @edge_chip_id = @map.data[0, 1, 0] @wall_chip_id = @map.data[0, 2, 0] @blank_chip_id = @map.data[0, 4, 0] @object_chip_id0 = @map.data[0, 3, 0] @object_chip_id1 = @map.data[0, 3, 1] @object_chip_id2 = @map.data[0, 3, 2] make_rect make_room make_couple_more @init_phase = true put_blank_tiles put_couple_tiles put_room_tiles put_shadow put_wall_tiles put_edge_tiles setup_dungeon_events @random_data = @map.data @last_moving = false end #-------------------------------------------------------------------------- # â— åŒºåˆ‡ã‚Šã‚’ä½œæˆ #-------------------------------------------------------------------------- def make_rect split_rect(add_rect(0, 1, @map.width, @map.height)) end #-------------------------------------------------------------------------- # ◠指定㮠DungeonRect を区切る #-------------------------------------------------------------------------- def split_rect(parent) if (parent.hy - parent.ly <= Saba::Dungeon::MINIMUM_RECT_SIZE * 2) parent.done_split_v = true end if (parent.hx - parent.lx <= Saba::Dungeon::MINIMUM_RECT_SIZE * 2) parent.done_split_h = true; end if ((parent.done_split_v) && (parent.done_split_h)) return end child = add_rect(parent.lx, parent.ly, parent.hx, parent.hy) unless parent.done_split_v split_coord_y = random_range(parent.ly + Saba::Dungeon::MINIMUM_RECT_SIZE, parent.hy - Saba::Dungeon::MINIMUM_RECT_SIZE) parent.hy = split_coord_y child.ly = split_coord_y parent.done_split_v = true child.done_split_v = true add_couple(COUPLE_VERTICAL, parent, child) split_rect(parent) split_rect(child) else split_coord_x = random_range(parent.lx + Saba::Dungeon::MINIMUM_RECT_SIZE, parent.hx - Saba::Dungeon::MINIMUM_RECT_SIZE) parent.hx = split_coord_x child.lx = split_coord_x parent.done_split_h = true child.done_split_h = true add_couple(COUPLE_HORIZONAL, parent, child) split_rect(parent) split_rect(child) end end #-------------------------------------------------------------------------- # â— ã•らã«é“ã‚’ä½œæˆ #-------------------------------------------------------------------------- def make_couple_more rectmap = {} for rect in @rect_list for i in rect.lx...rect.hx for j in rect.ly...rect.hy rectmap[[i, j]] = rect end end end for i in 0..(@map.width-2) for j in 1..(@map.height-2) if rectmap[[i, j]] != rectmap[[i, j + 1]] if rand(Saba::Dungeon::MORE_COUPLE_RATE) == 0 add_couple(COUPLE_VERTICAL, rectmap[[i,j]], rectmap[[i, j + 1]]) end end if rectmap[[i, j]] != rectmap[[i + 1, j]] if rand(Saba::Dungeon::MORE_COUPLE_RATE) == 0 add_couple(COUPLE_HORIZONAL, rectmap[[i, j]], rectmap[[i + 1, j]]) end end end end end #-------------------------------------------------------------------------- # ◠ランダムダンジョンã‹ï¼Ÿ #-------------------------------------------------------------------------- def dungeon? if @random_dungeon != nil return @random_dungeon end unless @map_infos @map_infos = load_data("Data/MapInfos.rvdata2") end @random_dungeon = @map_infos[@map_id].name.include?("@") return @random_dungeon end #-------------------------------------------------------------------------- # ◠指定ã®åŒºé–“ã®ä¸ã§ãƒ©ãƒ³ãƒ€ãƒ ãªå€¤ã‚’å–å¾— #-------------------------------------------------------------------------- def random_range(b, e) return (rand(e - + .to_i end #-------------------------------------------------------------------------- # â— DungeonRect を作æˆã—ã¦è¿½åŠ #-------------------------------------------------------------------------- def add_rect(lx, ly, hx, hy) rect = Dungeon_Rect.new(lx, ly, hx, hy) @rect_list.push(rect) return rect end #-------------------------------------------------------------------------- # â— Room を作æˆã—ã¦è¿½åŠ #-------------------------------------------------------------------------- def add_room(lx, ly, hx, hy) room = Room.new(lx, ly, hx, hy) @room_list.push(room) return room end #-------------------------------------------------------------------------- # â— éƒ¨å±‹ã‚’ä½œæˆ #-------------------------------------------------------------------------- def make_room for rect in @rect_list w = random_range(Saba::Dungeon::MINIMUM_ROOM_SIZE, rect.hx - rect.lx - (Saba::Dungeon::MARGIN_BETWEEN_RECT_ROOM * 2) + 1); h = random_range(Saba::Dungeon::MINIMUM_ROOM_SIZE, rect.hy - rect.ly - (Saba::Dungeon::MARGIN_BETWEEN_RECT_ROOM * 2) + 1); x = random_range(rect.lx + Saba::Dungeon::MARGIN_BETWEEN_RECT_ROOM, rect.hx - Saba::Dungeon::MARGIN_BETWEEN_RECT_ROOM - w + 1); y = random_range(rect.ly + Saba::Dungeon::MARGIN_BETWEEN_RECT_ROOM, rect.hy - Saba::Dungeon::MARGIN_BETWEEN_RECT_ROOM - h + 1); rect.room = add_room(x, y, x + w, y + h); end end #-------------------------------------------------------------------------- # ◠通路 を作æˆã—ã¦è¿½åŠ #-------------------------------------------------------------------------- def add_couple(direction, rect0, rect1) @couple_list.each {|c| if (c.rect0 == rect0 && c.rect1 == rect1) || (c.rect0 == rect1 && c.rect1 == rect0) # é‡è¤‡ã¯ã¤ãらãªã„ return end } couple = Couple.new couple.direction = direction couple.rect0 = rect0 couple.rect1 = rect1 @couple_list.push(couple) return couple end #-------------------------------------------------------------------------- # ◠空ããƒãƒƒãƒ—ã‚’é…ç½® #-------------------------------------------------------------------------- def put_blank_tiles for x in 0..@map.width for y in 0..@map.height @map.data[x, y, 0] = @blank_chip_id @map.data[x, y, 1] = 0 @map.data[x, y, 2] = 0 end end end #-------------------------------------------------------------------------- # ◠床ãƒãƒƒãƒ—ã‚’é…ç½® #-------------------------------------------------------------------------- def put_room_tiles for rect in @rect_list room = rect.room (room.hx - room.lx).times do |x| (room.hy - room.ly).times do |y| put_floor_tile(x + room.lx, y + room.ly) end end end end def put_floor_tile(x, y) if @floor_chip_id1 > 0 && rand(10) == 0 @map.data[x, y, 0] = @floor_chip_id1 else @map.data[x, y, 0] = @floor_chip_id end end #-------------------------------------------------------------------------- # ◠通路ãƒãƒƒãƒ—ã‚’é…ç½® #-------------------------------------------------------------------------- def put_couple_tiles for couple in @couple_list case couple.direction when COUPLE_HORIZONAL then unless couple.rect0.hx == couple.rect1.lx p "Errorx:" + couple.rect0.hx.to_s + couple.rect1.lx .to_s next end c0x = couple.rect0.hx c0y = random_range(couple.rect0.room.ly + 1, couple.rect0.room.hy) c1x = couple.rect1.lx c1y = random_range(couple.rect1.room.ly + 1, couple.rect1.room.hy) line(c0x, c0y, c1x, c1y); line(couple.rect0.room.hx, c0y, c0x, c0y) line(couple.rect1.room.lx, c1y, c1x, c1y) couple.rect0.room.couple_areas.push([couple.rect0.room.hx-1, c0y]) couple.rect1.room.couple_areas.push([couple.rect1.room.lx, c1y]) when COUPLE_VERTICAL then unless couple.rect0.hy == couple.rect1.ly p "Errory:" + couple.rect0.hy.to_s + " " + couple.rect1.ly .to_s next end c0x = random_range(couple.rect0.room.lx + 1, couple.rect0.room.hx) c0y = couple.rect0.hy c1x = random_range(couple.rect1.room.lx + 1, couple.rect1.room.hx) c1y = couple.rect1.ly line(c0x, c0y, c1x, c1y) line(c0x, couple.rect0.room.hy, c0x, c0y) line(c1x, couple.rect1.room.ly, c1x, c1y) couple.rect0.room.couple_areas.push([c0x, couple.rect0.room.hy-1]) couple.rect1.room.couple_areas.push([c1x, couple.rect1.room.ly]) end end end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™é–“ã§åºŠã‚’é…ç½® #-------------------------------------------------------------------------- def line(x0, y0, x1, y1) min_x = [x0, x1].min max_x = [x0, x1].max min_y = [y0, y1].min max_y = [y0, y1].max if ((x0 <= x1) && (y0 >= y1)) for i in min_x..max_x put_floor_tile(i, max_y) end for j in min_y..max_y put_floor_tile(max_x, j) end elsif ((x0 > x1) && (y0 > y1)) for i in min_x..max_x put_floor_tile(i, min_y) end for j in min_y..max_y put_floor_tile(max_x, j) end elsif ((x0 > x1) && (y0 <= y1)) for i in min_x..max_x put_floor_tile(i, min_y) end for j in min_y..max_y put_floor_tile(max_x, j) end elsif ((x0 <= x1) && (y0 < y1)) for i in min_x..max_x put_floor_tile(i, max_y) end for j in min_y..max_y put_floor_tile(min_x, j) end end end #-------------------------------------------------------------------------- # â— å£ãƒãƒƒãƒ—ã‚’é…ç½® #-------------------------------------------------------------------------- def put_wall_tiles for y in (1..@map.height).to_a.reverse for x in 0..@map.width next unless floor?(x, y) next if floor?(x, y-1) @map.data[x, y-1, 0] = @wall_chip_id + 15 end end for y in (1..@map.height).to_a.reverse for x in 0..@map.width tile = @map.data[x, y, 0] next unless tile == @wall_chip_id + 15 if floor?(x, y-1) put_object_tile(x, y) next end if floor?(x-1, y) || blank?(x-1, y) if floor?(x+1, y) || blank?(x+1, y) @map.data[x, y, 0] = @wall_chip_id + 15 else @map.data[x, y, 0] = @wall_chip_id + 11 end else if floor?(x+1, y) || blank?(x+1, y) @map.data[x, y, 0] = @wall_chip_id + 14 else @map.data[x, y, 0] = @wall_chip_id + 10 end end end end end #-------------------------------------------------------------------------- # ◠障害物ãƒãƒƒãƒ—ã‚’é…ç½® #-------------------------------------------------------------------------- def put_object_tile(x, y) @map.data[x, y, 0] = @object_chip_id0 @map.data[x, y, 1] = @object_chip_id1 @map.data[x, y, 2] = @object_chip_id2 end #-------------------------------------------------------------------------- # ◠境界ãƒãƒƒãƒ—ã‚’é…ç½® #-------------------------------------------------------------------------- def put_edge_tiles for y in (1..@map.height).to_a.reverse for x in 0..@map.width tile = @map.data[x, y, 0] next if inner?(x, y) if inner?(x, y-1) if inner?(x, y+1) if inner?(x-1, y) if inner?(x+1, y) @map.data[x, y, 0] = @edge_chip_id + 46 else @map.data[x, y, 0] = @edge_chip_id + 43 end else if inner?(x+1, y) @map.data[x, y, 0] = @edge_chip_id + 45 else @map.data[x, y, 0] = @edge_chip_id + 33 end end else if inner?(x-1, y) if inner?(x+1, y) @map.data[x, y, 0] = @edge_chip_id + 42 else @map.data[x, y, 0] = @edge_chip_id + 34 end else if inner?(x+1, y) @map.data[x, y, 0] = @edge_chip_id + 36 else @map.data[x, y, 0] = @edge_chip_id + 20 end end end else if inner?(x, y+1) if inner?(x-1, y) if inner?(x+1, y) @map.data[x, y, 0] = @edge_chip_id + 44 else @map.data[x, y, 0] = @edge_chip_id + 40 end else if inner?(x+1, y) @map.data[x, y, 0] = @edge_chip_id + 38 else @map.data[x, y, 0] = @edge_chip_id + 28 end end else if inner?(x-1, y) if inner?(x+1, y) @map.data[x, y, 0] = @edge_chip_id + 32 else @map.data[x, y, 0] = @edge_chip_id + 16 end else if inner?(x+1, y) @map.data[x, y, 0] = @edge_chip_id + 24 else if inner?(x+1, y+1) || inner?(x+1, y-1) || inner?(x-1, y-1) || inner?(x-1, y+1) @map.data[x, y, 0] = @edge_chip_id else @map.data[x, y, 0] = @blank_chip_id end end end end end end end end #-------------------------------------------------------------------------- # ◠影タイルを置ãã¾ã™ #-------------------------------------------------------------------------- def put_shadow for y in 0..@map.height for x in 0..@map.width next unless floor?(x, y) next if floor?(x-1, y-1) next unless blank?(x-1, y) @map.data[x, y, 3] = 5 end end end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™ãŒå¢ƒç•Œã®å†…å´ã‹ã©ã†ã‹ #-------------------------------------------------------------------------- def inner?(x, y) return floor?(x, y) || wall?(x, y) || object?(x, y) end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™ãŒåºŠã‹ã©ã†ã‹ #-------------------------------------------------------------------------- def floor?(x, y) return false if @map.data[x, y, 2] == @object_chip_id2 return true if @floor_chip_id1 && @map.data[x, y, 0] == @floor_chip_id1 return @map.data[x, y, 0] == @floor_chip_id end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™ãŒã‚«ãƒ©ã‹ã©ã†ã‹ #-------------------------------------------------------------------------- def blank?(x, y) return @map.data[x, y, 0] == @blank_chip_id end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™ãŒéšœå®³ç‰©ã‹ã©ã†ã‹ #-------------------------------------------------------------------------- def object?(x, y) return @map.data[x, y, 0] == @object_chip_id0 end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™ãŒå£ã‹ã©ã†ã‹ #-------------------------------------------------------------------------- def wall?(x, y) tile = @map.data[x, y, 0] return false if tile == nil || tile == 0 return tile >= @wall_chip_id && tile <= @wall_chip_id + 15 end #-------------------------------------------------------------------------- # ◠プレイヤーをランダムãªä½ç½®ã«é…ç½® #-------------------------------------------------------------------------- def setup_player_initial_position put_to_random_place($game_player) unless floor?($game_player.x, $game_player.y) end #-------------------------------------------------------------------------- # ◠ダンジョンã®ç‰¹æ®Šãªã‚¤ãƒ™ãƒ³ãƒˆã‚’ランダムãªå ´æ‰€ã«é…ç½®ã™ã‚‹ #-------------------------------------------------------------------------- def setup_dungeon_events @next_enemy_event_id = 10000 @enemy_events = [] for event in @events.values if event.event.name.include?("*") @enemy_events.push(event.event) self.events[event.id].erase else put_to_random_place(event) end end setup_enemy end #-------------------------------------------------------------------------- # ◠敵イベントã®åˆæœŸè¨å®š #-------------------------------------------------------------------------- def setup_enemy $game_variables[saba::Dungeon::ENEMY_COUNT_VARIABLE] = 0 return if @enemy_events.count == 0 @map.encounter_step.times do |i| add_random_enemy end end #-------------------------------------------------------------------------- # â— ãƒ©ãƒ³ãƒ€ãƒ ãªæ•µã‚¤ãƒ™ãƒ³ãƒˆã‚’ランダムãªå ´æ‰€ã«é…ç½®ã™ã‚‹ #-------------------------------------------------------------------------- def add_random_enemy add_enemy(rand(@enemy_events.count)) end #-------------------------------------------------------------------------- # â— æŒ‡å®šã®æ•µã‚¤ãƒ™ãƒ³ãƒˆã‚’複製ã—ã¦ãƒ©ãƒ³ãƒ€ãƒ ãªå ´æ‰€ã«é…ç½®ã™ã‚‹ #-------------------------------------------------------------------------- def add_enemy(event_id) enemy_event = @enemy_events[event_id] event = Game_Event.new(@map_id, enemy_event) # イベントã®ãƒ«ãƒ¼ãƒ—内ã§ã¯æ–°ã—ã„ã‚¤ãƒ™ãƒ³ãƒˆã‚’è¿½åŠ ã§ããªã„ã®ã§ã€ # 一旦別ã®å ´æ‰€ã«æ ¼ç´ @new_events = {} unless @new_events @new_events[@next_enemy_event_id] = event event.event_id = @next_enemy_event_id @next_enemy_event_id += 1 $game_variables[saba::Dungeon::ENEMY_COUNT_VARIABLE] += 1 end alias saba_randomdungeon_update_events update_events def update_events saba_randomdungeon_update_events if @new_events for key in @new_events.keys @events[key] = @new_events[key] put_to_random_place(@events[key]) $game_minimap.add_event(@events[key]) if $game_minimap end end @init_phase = false end #-------------------------------------------------------------------------- # ◠指定ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’ランダムãªå ´æ‰€ã«é…ç½®ã™ã‚‹ #-------------------------------------------------------------------------- def put_to_random_place(event) if @init_phase room_list = @room_list.select {|room| room.remain != 0 } else room_list = @room_list.select {|room| room.remain != 0 && room != $game_player.room } end room = room_list[rand(room_list.size)] room.put_to_random_place(event) end #-------------------------------------------------------------------------- # â— èµ·å‹•ä¸ã®ãƒžãƒƒãƒ—イベントを検出ï¼ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ— #-------------------------------------------------------------------------- def setup_starting_map_event event = @events.values.find {|event| event.starting } event.clear_starting_flag if event @interpreter.setup(event.list, event.event_id) if event event end def room(x, y) for rect in @rect_list if rect.room.contains(x, y) return rect.room end end return nil end end class Spriteset_Map #-------------------------------------------------------------------------- # â— ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆåˆæœŸåŒ– #-------------------------------------------------------------------------- alias saba_dungeon_initialize initialize def initialize saba_dungeon_initialize @dark_sprite = Sprite_Dark.new(@viewport_dark) update_dark_sprite_visible end #-------------------------------------------------------------------------- # ◠ビューãƒãƒ¼ãƒˆã®ä½œæˆ #-------------------------------------------------------------------------- alias saba_dungeon_create_viewports create_viewports def create_viewports saba_dungeon_create_viewports @viewport_dark = Viewport.new end #-------------------------------------------------------------------------- # ◠フレーム更新 #-------------------------------------------------------------------------- alias saba_dungeon_update update def update if $game_map.new_events $game_map.new_events.values.each do |event| @character_sprites.push(Sprite_Character.new(@viewport1, event)) end $game_map.new_events = nil end saba_dungeon_update update_dark_sprite_visible end #-------------------------------------------------------------------------- # ◠暗闇スプライトã®è¡¨ç¤ºæ›´æ–° #-------------------------------------------------------------------------- def update_dark_sprite_visible if @dark_sprite if $game_map.dungeon? @dark_sprite.visible = true @dark_sprite.update else @dark_sprite.visible = false end end end #-------------------------------------------------------------------------- # ◠解放 #-------------------------------------------------------------------------- alias saba_dungeon_dispose dispose def dispose @dark_sprite.dispose if @dark_sprite saba_dungeon_dispose end #-------------------------------------------------------------------------- # ◠ビューãƒãƒ¼ãƒˆã®è§£æ”¾ #-------------------------------------------------------------------------- alias saba_dungeon_dispose_viewports dispose_viewports def dispose_viewports saba_dungeon_dispose_viewports @viewport_dark.dispose end #-------------------------------------------------------------------------- # â— ã‚ャラクタースプライトã®ä½œæˆ #-------------------------------------------------------------------------- alias saba_dungeon_create_characters create_characters def create_characters saba_dungeon_create_characters $game_map.new_events = nil end end class Sprite_Character alias saba_dangeon_update update def update saba_dangeon_update return unless $game_map.dungeon? if @character.is_a?(Game_Event) #~ if @static == nil #~ @static = @character.name.to_i > 1000 #~ end #~ if @static #~ self.visible = true self.visible = false if $game_player.room self.visible = $game_player.room.contains(@character.x, @character.y) end case $game_player.distance(@character) when 1; self.visible = true @last_visible = self.visible when 2; self.visible |= @last_visible @last_visible = false end end end end class Sprite_Dark < Sprite_Base def initialize(viewport) super(viewport) self.bitmap = Bitmap.new(Graphics.width+32*32, Graphics.height+32*32) refresh update end def update super if @last_room != $game_player.room refresh @last_room = $game_player.room end if @last_room self.viewport.ox = -@start_x + $game_map.display_x*32 self.viewport.oy = -@start_y + $game_map.display_y*32 if (self.viewport.ox - self.bitmap.width / 2 + Graphics.width / 2).abs > Graphics.width / 2 || (self.viewport.oy - self.bitmap.height / 2 + Graphics.height / 2).abs > Graphics.height / 2 refresh end self.viewport.ox = -@start_x + $game_map.display_x*32 self.viewport.oy = -@start_y + $game_map.display_y*32 else self.viewport.ox = -$game_player.screen_x + self.bitmap.width / 2 self.viewport.oy = -$game_player.screen_y + self.bitmap.height / 2 + 16 end end def refresh self.bitmap.clear self.bitmap.fill_rect(0, 0, self.bitmap.width, self.bitmap.height, Color.new(0, 0, 0, 100)) room = $game_player.room if room == nil rect = Rect.new rect.x = self.bitmap.width / 2 - 48 rect.y = self.bitmap.height / 2 - 45 rect.width = 96 rect.height = 96 self.bitmap.clear_rect(rect) edge = Cache.system("dark_edge2") self.bitmap.blt(rect.x, rect.y, edge, edge.rect) else rect = Rect.new rect.x = self.bitmap.width / 2 - ($game_player.x - room.lx) * 32 rect.y = self.bitmap.height / 2 - ($game_player.y - room.ly) * 32 rect.width = (room.hx - room.lx+2) * 32 rect.height = (room.hy - room.ly+2) * 32 self.bitmap.clear_rect(rect) @start_x = $game_map.display_x*32 - self.bitmap.width / 2 + ($game_player.x - $game_map.display_x - 1)*32 @start_y = $game_map.display_y*32 - self.bitmap.height / 2 + ($game_player.y - $game_map.display_y - 1)*32 edge = Cache.system("dark_edge") self.bitmap.blt(rect.x, rect.y, edge, Rect.new(0, 0, 32, 32)) self.bitmap.blt(rect.x+rect.width-32, rect.y, edge, Rect.new(32, 0, 32, 32)) self.bitmap.blt(rect.x, rect.y+rect.height-32, edge, Rect.new(0, 32, 32, 32)) self.bitmap.blt(rect.x+rect.width-32, rect.y+rect.height-32, edge, Rect.new(32, 32, 32, 32)) end end end class Game_Event attr_reader :event attr_accessor :event_id attr_reader :erased def name @event.name end alias saba_dungeon_erase erase def erase saba_dungeon_erase return unless enemy? $game_variables[saba::Dungeon::ENEMY_COUNT_VARIABLE] -= 1 end def enemy? return name.include?("*") end end class Game_Player #-------------------------------------------------------------------------- # ◠指定ä½ç½®ã«ç§»å‹• #-------------------------------------------------------------------------- alias saba_dungeon_moveto moveto def moveto(x, y) saba_dungeon_moveto(x, y) $game_map.setup_player_initial_position if $game_map.dungeon? end def distance(event) min = $game_player.distance_xy_from(event.x, event.y) return min unless $game_player.followers.visible $game_player.followers.each do |character| dist = character.distance_xy_from(event.x, event.y) if dist < min min = dist end end return min end end class Game_Character #-------------------------------------------------------------------------- # â— è·é›¢è¨ˆç®— #-------------------------------------------------------------------------- def distance_xy_from(x, y) sx = distance_x_from(x) sy = distance_y_from(y) return [sx.abs, sy.abs].max end end 2. Sub script #1: Events Move After Player #============================================================================== # â– Modify Event Behaviour 6 # @version 0.14 12/01/21 RGSS3 # @author Saba Kan # @translator kirinelf #------------------------------------------------------------------------------ #   Makes it so events only move after player does. # ã„ã‚ã„ã‚ã¤ãりã‹ã‘ã§ã™ã€‚ <= Various things are still in the making? #============================================================================== module Saba module Dungeon # Events always move towards player? ENEMY_ALWAYS_TOWARD_PLAYER = true end end #========================================================================= # Do not edit anything under this line unless you know what you're doing! #========================================================================= class Game_Event attr_reader :event_waiting #-------------------------------------------------------------------------- # â— ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆåˆæœŸåŒ– # event : RPG::Event #-------------------------------------------------------------------------- alias saba_dungeon_initialize initialize def initialize(map_id, event) saba_dungeon_initialize(map_id, event) @event_id = event.id end #-------------------------------------------------------------------------- # â— åœæ¢æ™‚ã®æ›´æ–° #-------------------------------------------------------------------------- alias saba_dungeon_update_stop update_stop def update_stop unless $game_map.dungeon? saba_dungeon_update_stop return end super unless @move_route_forcing update_self_movement if $game_player.start_move end end def check_waiting_event if @event_waiting start end end #-------------------------------------------------------------------------- # ◠ダッシュ状態判定 #-------------------------------------------------------------------------- def dash? return super unless $game_map.dungeon? return $game_player.dash? end #-------------------------------------------------------------------------- # ◠イベント起動 #-------------------------------------------------------------------------- alias saba_dungeon_start start def start @event_waiting = false saba_dungeon_start end alias saba_dungeon_update_self_movement update_self_movement def update_self_movement if stop_by_encounter? @stop_by_encounter_turn -= 1 return end saba_dungeon_update_self_movement update_move end #-------------------------------------------------------------------------- # ◠接触イベントã®èµ·å‹•判定 #-------------------------------------------------------------------------- alias saba_dungeon_check_event_trigger_touch check_event_trigger_touch def check_event_trigger_touch(x, y) return if stop_by_encounter? return if $game_map.interpreter.running? return if @starting return if @trigger != 2 return if jumping? return unless normal_priority? if @trigger == 2 && $game_player.pos?(x, y) @event_waiting = true return end return unless $game_player.followers.visible $game_player.followers.each do |follower| if follower.pos?(x, y) @event_waiting = true return end end end #-------------------------------------------------------------------------- # ◠エンカウントã«ã‚ˆã‚Šã‚¤ãƒ™ãƒ³ãƒˆä¸€æ™‚åœæ¢ #-------------------------------------------------------------------------- def stop_by_encounter(turn) @stop_by_encounter_turn = turn end #-------------------------------------------------------------------------- # ◠エンカウントã«ã‚ˆã‚Šã‚¤ãƒ™ãƒ³ãƒˆãŒåœæ¢ã—ã¦ã„ã‚‹ã‹ï¼Ÿ #-------------------------------------------------------------------------- def stop_by_encounter? return @stop_by_encounter_turn != nil && @stop_by_encounter_turn > 0 end #-------------------------------------------------------------------------- # â— ã‚¢ãƒ‹ãƒ¡ãƒ‘ã‚¿ãƒ¼ãƒ³ã®æ›´æ–° #-------------------------------------------------------------------------- def update_anime_pattern return if stop_by_encounter? super end #-------------------------------------------------------------------------- # ◠移動タイプ : è¿‘ã¥ã #-------------------------------------------------------------------------- alias saba_dungeon_move_type_toward_player move_type_toward_player def move_type_toward_player unless Saba::Dungeon::ENEMY_ALWAYS_TOWARD_PLAYER saba_dungeon_move_type_toward_player return end if near_the_player? move_toward_player else move_random end end #-------------------------------------------------------------------------- # ◠プレイヤーã«è¿‘ã¥ã #-------------------------------------------------------------------------- def move_toward_player char = $game_player.nearest_char(x, y) move_toward_character(char) end #-------------------------------------------------------------------------- # â— ã‚ャラクターã«è¿‘ã¥ã #-------------------------------------------------------------------------- def move_toward_character(character) sx = distance_x_from(character.x) sy = distance_y_from(character.y) if sx.abs > sy.abs move_straight(sx > 0 ? 4 : 6) if !@move_succeed && sy != 0 && !@event_waiting if @last_pos == [x, y + 1] move_straight(2) elsif @last_pos == [x, y - 1] move_straight(8) else move_straight(sy > 0 ? 8 : 2) end end elsif sy != 0 move_straight(sy > 0 ? 8 : 2) if !@move_succeed && sx != 0 && !@event_waiting if @last_pos == [x + 1, y] move_straight(4) elsif @last_pos == [x + 1, y] move_straight(6) else move_straight(sx > 0 ? 4 : 6) end end end @last_pos = [x, y] if $game_map.room(x, y) == nil end end class Game_Player attr_reader :start_move #-------------------------------------------------------------------------- # â— æ–¹å‘ボタン入力ã«ã‚ˆã‚‹ç§»å‹•å‡¦ç† #-------------------------------------------------------------------------- alias saba_dungeon_move_by_input move_by_input def move_by_input unless $game_map.dungeon? saba_dungeon_move_by_input return end if !movable? || $game_map.interpreter.running? @start_move = false return end if Input.dir4 > 0 return if $game_map.wait_for_event? unless passable?(@x, @y, Input.dir4) set_direction(Input.dir4) check_event_trigger_touch_front return end move_straight(Input.dir4) @start_move = true else @start_move = false end end #-------------------------------------------------------------------------- # â—‹ 隊列ã®ã‚ャラもå«ã‚“ã§ã€ä¸€ç•ªè¿‘ã„ã‚ャラをå–å¾— #-------------------------------------------------------------------------- def nearest_char(x, y) return self unless $game_player.followers.visible min = $game_player.distance_x_from(x) + $game_player.distance_x_from(y) return self if min >= 5 min_char = self for follower in $game_player.followers dist = follower.distance_x_from(x) + follower.distance_x_from(y) if dist < min min = dist min_char = follower end end return min_char end end class Game_Map #-------------------------------------------------------------------------- # â— ã‚¤ãƒ™ãƒ³ãƒˆã®æ›´æ–° #-------------------------------------------------------------------------- alias saba_dungeon_update_events update_events def update_events saba_dungeon_update_events return unless dungeon? moving = $game_player.moving? if ! moving @events.each_value {|event| event.check_waiting_event } end @last_moving = moving end #-------------------------------------------------------------------------- # ◠エãƒãƒŸãƒ¼ã‚¤ãƒ™ãƒ³ãƒˆã®å‡¦ç†ã‚’å¾…ã£ã¦ã„ã‚‹ã‹ï¼Ÿ #-------------------------------------------------------------------------- def wait_for_event? @events.each_value {|event| return true if event.event_waiting || event.starting } return false end #-------------------------------------------------------------------------- # â— ã‚¤ãƒ™ãƒ³ãƒˆã®æ›´æ–° #-------------------------------------------------------------------------- def stop_by_encounter(event_id, turn) @events[event_id].stop_by_encounter(turn) end end class Game_Interpreter def stop(turn) $game_map.stop_by_encounter(self.event_id, turn) end end 3. Sub script #2: Minimap #============================================================================== # â– Dungeon Creation 6 (Minimap) # @version 0.14 12/01/21 RGSS3 # @author Saba Kan # @translator kirinelf #------------------------------------------------------------------------------ #   #============================================================================== module Saba module Dungeon PLAYER_COLOR_ID = 9 # Color ID of player on Minimap. FOLLOWER_COLOR_ID = 1 # Color ID of followers on Minimap. end end #========================================================================= # Do not edit anything under this line unless you know what you're doing! #========================================================================= class << DataManager #-------------------------------------------------------------------------- # â— å„種ゲームオブジェクトã®ä½œæˆ #-------------------------------------------------------------------------- alias saba_minimap_create_game_objects create_game_objects def create_game_objects saba_minimap_create_game_objects $game_minimap = Game_MiniMap.new end #-------------------------------------------------------------------------- # ◠セーブ内容ã®ä½œæˆ #-------------------------------------------------------------------------- alias saba_minimap_make_save_contents make_save_contents def make_save_contents contents = saba_minimap_make_save_contents contents[:minimap] = $game_minimap contents end #-------------------------------------------------------------------------- # ◠セーブ内容ã®å±•é–‹ #-------------------------------------------------------------------------- alias saba_minimap_extract_save_contents extract_save_contents def extract_save_contents(contents) saba_minimap_extract_save_contents(contents) $game_minimap = contents[:minimap] end end class Game_Map #-------------------------------------------------------------------------- # ◠セットアップ # map_id : マップ ID #-------------------------------------------------------------------------- alias saba_minmap_setup setup def setup(map_id) saba_minmap_setup(map_id) if dungeon? $game_minimap.setup(self) end end #-------------------------------------------------------------------------- # ◠指定ã®åº§æ¨™ã‚’マッピング #-------------------------------------------------------------------------- def mapping(x, y) return unless floor?(x, y) for rect in @rect_list if rect.room.contains(x, y) $game_player.room = rect.room $game_minimap.mapping_room(rect.room) return end end $game_player.room = nil $game_minimap.mapping(x, y) end end class Game_MiniMap BLANK = 0 # 空ãマップ FLOOR = 1 # 床 WALL = 2 # å£ PASSAGE = 3 # 通路 attr_accessor :changed_area attr_accessor :cleared attr_reader :events #-------------------------------------------------------------------------- # â— ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆåˆæœŸåŒ– #-------------------------------------------------------------------------- def initialize @map_data = {} @events = [] end #-------------------------------------------------------------------------- # â— ãƒžãƒƒãƒ—æƒ…å ±ã‚’åˆæœŸåŒ– #-------------------------------------------------------------------------- def setup(map) clear for x in 0..map.width for y in 0..map.height @map_data[[x, y]] = BLANK end end end #-------------------------------------------------------------------------- # ◠マッピングã•れã¦ã„ã‚‹ã‹ï¼Ÿ #-------------------------------------------------------------------------- def mapping?(x, y) return @map_data[[x, y]] != BLANK end def floor_type(x, y) return @map_data[[x, y]] end #-------------------------------------------------------------------------- # ◠部屋をマッピング #-------------------------------------------------------------------------- def mapping_room(room) return if room.mapping room.mapping = true for x in room.lx...room.hx for y in room.ly...room.hy @map_data[[x, y]] = FLOOR end end mapping_edge(room) @changed_area = Rect.new(room.lx-1, room.ly-1, room.width+1, room.height+1) end #-------------------------------------------------------------------------- # ◠部屋ã®å¤–å´ã‚’マッピング #-------------------------------------------------------------------------- def mapping_edge(room) for x in (room.lx-1)...(room.hx+1) mapping_internal(x, room.ly-1) mapping_internal(x, room.hy) end for y in (room.ly)...(room.hy) mapping_internal(room.lx-1, y) mapping_internal(room.hx, y) end end #-------------------------------------------------------------------------- # â— é“をマッピング #-------------------------------------------------------------------------- def mapping(x, y) mapping_internal(x, y) mapping_internal(x-1, y) mapping_internal(x+1, y) mapping_internal(x, y-1) mapping_internal(x, y+1) mapping_internal(x-1, y-1) mapping_internal(x+1, y-1) mapping_internal(x-1, y+1) mapping_internal(x+1, y+1) @changed_area = Rect.new(x-1, y-1, 3, 3) end #-------------------------------------------------------------------------- # â— é“をマッピング #-------------------------------------------------------------------------- def mapping_internal(x, y) return if mapping?(x, y) if $game_map.floor?(x, y) @map_data[[x, y]] = PASSAGE else @map_data[[x, y]] = WALL end end def add_event(event) @events.push(event) end #-------------------------------------------------------------------------- # ◠クリア #-------------------------------------------------------------------------- def clear @cleared = true @map_data = {} @events = [] end end class Game_Player attr_accessor :room #-------------------------------------------------------------------------- # ◠指定ä½ç½®ã«ç§»å‹• #-------------------------------------------------------------------------- alias saba_minimap_moveto moveto def moveto(x, y) saba_minimap_moveto(x, y) $game_map.mapping(x, y) end #-------------------------------------------------------------------------- # â— æ©æ•°å¢—åŠ #-------------------------------------------------------------------------- alias saba_minimap_increase_steps increase_steps def increase_steps saba_minimap_increase_steps $game_map.mapping(self.x, self.y) end end class Sprite_MiniMap < Sprite_Base #-------------------------------------------------------------------------- # ◠定数 #-------------------------------------------------------------------------- SQUARE_SIZE = 5 FLOOR_COLOR = Color.new(70, 70, 180, 170) PASSAGE_COLOR = Color.new(160, 80, 160, 170) WALL_COLOR = Color.new(200, 200, 200, 0) #-------------------------------------------------------------------------- # â— ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆåˆæœŸåŒ– # viewport : ビューãƒãƒ¼ãƒˆ #-------------------------------------------------------------------------- def initialize(viewport) super(viewport) @windowskin = Cache.system("Window") @event_sprites = {} create_bitmap update_position redraw_all @follower_sprites = {} if $game_player.followers.visible for follower in $game_player.followers @follower_sprites[follower] = create_character_sprite(Saba::Dungeon::FOLLOWER_COLOR_ID) end end @player_sprite = create_character_sprite(Saba::Dungeon::PLAYER_COLOR_ID) update end #-------------------------------------------------------------------------- # â— æ–‡å—色å–å¾— # n : æ–‡å—色番å·ï¼ˆ0..31) #-------------------------------------------------------------------------- def text_color(n) @windowskin.get_pixel(64 + (n % 8) * 8, 96 + (n / 8) * 8) end #-------------------------------------------------------------------------- # â— ã‚ャラクター用ビットマップã®ä½œæˆ #-------------------------------------------------------------------------- def create_character_sprite(color) if color >= 1000 hole = true color -= 1000 end if color >= 100 static = true color -= 100 end sprite_color = text_color(color) if color != 0 return Sprite_MiniMap_Character.new(viewport, sprite_color, static, hole) end #-------------------------------------------------------------------------- # ◠ビットマップã®ä½œæˆ #-------------------------------------------------------------------------- def create_bitmap self.bitmap = Bitmap.new(Graphics.width, Graphics.height) self.bitmap.font.size = 32 self.bitmap.font.color.set(255, 255, 255) end #-------------------------------------------------------------------------- # â— åº§æ¨™ã®æ›´æ–° #-------------------------------------------------------------------------- def update_position self.x = (Graphics.width - SQUARE_SIZE * $game_map.width) / 2 self.y = (Graphics.height - SQUARE_SIZE * $game_map.height) / 2 end #-------------------------------------------------------------------------- # ◠転é€å…ƒãƒ“ãƒƒãƒˆãƒžãƒƒãƒ—ã®æ›´æ–° #-------------------------------------------------------------------------- def update_bitmap rect = $game_minimap.changed_area return unless rect $game_minimap.changed_area = nil for x in rect.x..(rect.width + rect.x) for y in rect.y..(rect.height + rect.y) case $game_minimap.floor_type(x, y) when Game_MiniMap::FLOOR then color = FLOOR_COLOR when Game_MiniMap::WALL then color = WALL_COLOR when Game_MiniMap::PASSAGE then color = PASSAGE_COLOR else next end self.bitmap.fill_rect(x*SQUARE_SIZE, y*SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE, color) end end end def redraw_all self.bitmap.clear for x in 0..$game_map.width for y in 0..$game_map.height case $game_minimap.floor_type(x, y) when Game_MiniMap::FLOOR then color = FLOOR_COLOR when Game_MiniMap::PASSAGE then color = PASSAGE_COLOR when Game_MiniMap::WALL then color = WALL_COLOR else next end self.bitmap.fill_rect(x*SQUARE_SIZE, y*SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE, color) end end end #-------------------------------------------------------------------------- # ◠フレーム更新 #-------------------------------------------------------------------------- def update super clear if $game_minimap.cleared update_bitmap if $game_minimap.changed_area update_visibility update_player update_events end #-------------------------------------------------------------------------- # â— å¯è¦–çŠ¶æ…‹ã®æ›´æ–° #-------------------------------------------------------------------------- def update_visibility #self.visible = $game_timer.working? end #-------------------------------------------------------------------------- # â— ãƒ—ãƒ¬ã‚¤ãƒ¤ãƒ¼ã®æ›´æ–° #-------------------------------------------------------------------------- def update_player @player_sprite.x = self.x + $game_player.x * SQUARE_SIZE @player_sprite.y = self.y + $game_player.y * SQUARE_SIZE return unless $game_player.followers.visible for follower in $game_player.followers sprite = @follower_sprites[follower] sprite.x = self.x + follower.x * SQUARE_SIZE sprite.y = self.y + follower.y * SQUARE_SIZE end end #-------------------------------------------------------------------------- # â— å…¨ã‚¤ãƒ™ãƒ³ãƒˆã®æ›´æ–° #-------------------------------------------------------------------------- def update_events for event in $game_map.events.values if event.erased sprite = @event_sprites[event.event_id] if sprite sprite.dispose @event_sprites.delete(event.event_id) end $game_map.events.delete(event.event_id) next end update_event(event) end end #-------------------------------------------------------------------------- # â— ã‚¤ãƒ™ãƒ³ãƒˆã®æ›´æ–° #-------------------------------------------------------------------------- def update_event(event) if @event_sprites[event.event_id] sprite = @event_sprites[event.event_id] else sprite = create_character_sprite(event.name.to_i) @event_sprites[event.event_id] = sprite end if sprite.static sprite.visible = $game_minimap.mapping?(event.x, event.y) else sprite.visible = false if $game_player.room sprite.visible = $game_player.room.contains(event.x, event.y) end sprite.visible |= $game_player.distance(event) == 1 sprite.visible = true if Saba::Dungeon::DEBUG_MODE end sprite.x = self.x + event.x * SQUARE_SIZE sprite.y = self.y + event.y * SQUARE_SIZE end def next_enemy_sprite unless @spare_enemy_sprites.empty? return @spare_enemy_sprites.pop else return create_character_sprite(true) end end #-------------------------------------------------------------------------- # ◠クリア #-------------------------------------------------------------------------- def clear self.bitmap.clear update_position @event_sprites.values.each {|s| s.dispose } @event_sprites = {} $game_minimap.cleared = false end #-------------------------------------------------------------------------- # ◠解放 #-------------------------------------------------------------------------- def dispose self.bitmap.dispose @player_sprite.bitmap.dispose @player_sprite.dispose for sprite in @event_sprites.values sprite.dispose end for sprite in @follower_sprites.values sprite.dispose end super end def visible=(value) return if visible == value super @player_sprite.visible = value for sprite in @follower_sprites.values sprite.visible = value end for sprite in @event_sprites.values sprite.visible = value end end end class Sprite_MiniMap_Character < Sprite_Base attr_reader :static #-------------------------------------------------------------------------- # â— ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆåˆæœŸåŒ– # viewport : ビューãƒãƒ¼ãƒˆ #-------------------------------------------------------------------------- def initialize(viewport, color, static, hole) super(viewport) @alive = true @color = color @static = static @hole = hole if @color create_bitmap update else self.visible = false end end #-------------------------------------------------------------------------- # ◠ビットマップã®ä½œæˆ #-------------------------------------------------------------------------- def create_bitmap size = Sprite_MiniMap::SQUARE_SIZE self.bitmap = Bitmap.new(size, size) if @hole self.bitmap.fill_rect(0, 0, size, 1, @color) self.bitmap.fill_rect(0, size-1, size, 1, @color) self.bitmap.fill_rect(0, 1, 1, size-2, @color) self.bitmap.fill_rect(size-1, 1, 1, size-2, @color) else self.bitmap.fill_rect(0, 0, size, size, @color) end end #-------------------------------------------------------------------------- # ◠解放 #-------------------------------------------------------------------------- def dispose self.bitmap.dispose if self.bitmap super end end class Spriteset_Map attr_reader :character_sprites #-------------------------------------------------------------------------- # â— ã‚ªãƒ–ã‚¸ã‚§ã‚¯ãƒˆåˆæœŸåŒ– #-------------------------------------------------------------------------- alias saba_minimap_initialize initialize def initialize saba_minimap_initialize @mini_map = Sprite_MiniMap.new(@viewport2) if $game_map.dungeon? update else @mini_map.visible = false end end #-------------------------------------------------------------------------- # ◠解放 #-------------------------------------------------------------------------- alias saba_minimap_dispose dispose def dispose saba_minimap_dispose @mini_map.dispose if @mini_map end #-------------------------------------------------------------------------- # ◠フレーム更新 #-------------------------------------------------------------------------- alias saba_minimap_update update def update saba_minimap_update return unless @mini_map if $game_map.dungeon? @mini_map.visible = true @mini_map.update else @mini_map.visible = false end end #-------------------------------------------------------------------------- # ◠クリア #-------------------------------------------------------------------------- def clear_minimap @mini_map.clear end end The script also requires two images that need to be placed in the Graphics/System folder. This is a link to the images required for the script to run: [Link] I have also attached them to this post for easy access. I also highly recommend playing the demo. The link is here: [Link] This is quite a simple script IF you know what you're doing, which takes a bit of playing around. So I've included a demo to save you the trouble of accidentally ruining your current project or having to start a new project just for this. Aren't I kind? For those of you who can't be bothered downloading the demo, I'm including a copy of the documentation here. How to Use Place the three scripts in the order I've numbered them above Main and under Materials. 1 - This is the main script. It generates random dungeons dynamically according to the settings and tiles I've described below. 2 - This is a sub script. It makes it so events only move after the player does, in true rogue-like fashion. 3 - This is a sub script. It sticks a minimap on the screen, invaluable for random dungeons. My only gripe with it is that it sticks it in the middle of the screen, which is kinda annoying. Place the two images in the Graphics folder (dark_edge.png and dark_edge2.png) into your Graphics/System folder. The setup is a little hard to explain, but here goes. ******* Tiles ******* Make a completely blank map. This map should be the size of the dungeon you want, and have a name starting with '@' (Ex. @Dungeon B1F). It doesn't matter what your display name is. Starting in the top left corner (0,0, for those who want the coordinates), put a tile down (From TileA). This will be your floor tile. You can have two different floor tiles, side by side (0,0 and 1,0); the script will automatically and randomly insert them into the dungeon floor. Underneath the floor tiles will be your ceiling and wall tiles. These go in (0,1) and (0,2) respectively. Since these tiles are generally autotiles, what you need to do is hold Shift while clicking to place a seamless tile. This goes for both the ceiling tile and wall tile. Below the wall tile in (0,3) is what I like to call an obstruction tile. These are generally tiles that block the player's advance much like a wall tile, but break up the monotony by not being walls but actual objects such as rocks or pillars. The script will occasionally throw these tiles out to make things more interesting, but in my playthroughs of the demo it doesn't do that too often. The last editable tile is (0,4), under the obstruction tile. This is simply the tile to use for a blank tile, and can be left empty. The difference can be seen in the demo; with a transparent blank tile, the spaces between the walls are left blank, while with the ceiling tile in that position, it fills in all the spaces between the walls with that tile, creating a labyrinth rather than just rooms in space. Leave all other tiles blank. It should be noted that only the floor tiles can have two different tiles to choose from; the ceiling, wall, obstruction and blank tiles only accept the tiles on the far left (0,x). This is enough to generate the dungeon itself, but it will not generate anything else. No exits, entrances or enemies. To do that, you place events in the blank map that the script will auto place for you randomly. This means that yes, the entrance to the dungeon would not be in the same place twice, and once you enter you won't be able to leave without finding the exit. Now, a bit more on events. ******* Events ******* The events themselves work as they normally do, with a little extras. These extras are quite interesting, and any rogue-like player would know instantly what I mean. Basically, you place a number in the event name and if the number in a certain position is '1', that event is handled differently. There are, as far as I know, two different handling methods that can be used concurrently. Firstly, if the number in the hundred digit position is 1, the event will be registered on the minimap once discovered for the duration of the floor. This means that NPCs, treasure chests and the like can be shown on the minimap once you've discovered the room they're in, and will not disappear from the minimap once you leave the room as they usually do. As an example, placing '100' in the name of a treasure chest event means that even if I don't open the chest, I know where it is even if I've left the room and am on the other side of the dungeon. Same with NPCs and the like. Secondly, if the number in the thousand digit position is 1, the event will be shown a little differently on the minimap. The author of the script describes it as 'donut style', where the event square is hollowed out, leaving only a thick outline. Players of rogue-likes will instantly associate this with stairs that lead to the next floor of the dungeon, although this isn't its only use. As an example, placing '1042' in the event name will cause the event to be shown as a square donut on the minimap. These can be used together. For instance, in the demo, the stairs are marked '1101', and they show up as donut squares that stay even if you leave the room. The ten and one digits don't seem to matter, to my knowledge. Another thing to note is that these events respawn randomly on reentering a floor. This means that any chests, doors and whatnot that use self switches can be used indefinitely as long as the player keeps exiting and reentering. This does not apply to global switches, so if you want a chest to only be accessible once, that's the only way to do it. Finally, for move events, it doesn't matter where you transfer the player to in the map. Any random blank space works. Same for all events; you can just place them anywhere in the map. The script will handle things, and it'll never block the player off (In my ~20 runthroughs of the demo). ******* Enemies ******* And what would a rogue-like be without enemies? Unlike traditional rogue-likes, since this is just a script that generates dungeons, these enemies are more like touch encounters that will home in on the player. What this means is that enemies are generated randomly on the floor, and they then move towards the player. Upon contact with the player or any followers, battle is joined and it turns into a normal RPG using whatever battle system you're using. If you're using an ABS though, I'd recommend just setting up enemy events as usual and ignore the following since the script automatically places events anyways. Anyways. To set up an enemy event, all you gotta do is make a normal event with a battle process. In the Autonomous Movement section, set the Type to Approach, Speed to Normal and Frequency to Highest. Make the trigger Event Touch. Now there's one last thing that's very important, and the core of the whole thing. In the name of the event, there has to be a '*' symbol. This instantly registers the event as an enemy, and proceeds to have the script handle it entirely. For example, 'Slime*' or 'Bat*' or even just a random numer like '2*'. Finally, to avoid being stuck in an infinite loop of battles, have an Erase Event command under the If Win condition. You can also optionally add an animation such as a Slash animation to signify you destroying the enemy and erasing it. So what happens now that it's registered as an enemy? Well, here's what happens. The script will automatically copy the event and place it randomly around the map, where it will start to act in a typical rogue-like manner. With script #2, they will only move when the player does, and upon contact with the player, the battle process will start. Another important thing to note is how many copies of the enemy events will be placed. This is simply the average encounter rate of the map, found in the map's properties in the bottom right corner, labelled 'Steps Average'. So if it's left at the default 30, there'll be up to 30 enemies running around your map. You might think you need to set this pretty high so the player doesn't run out of enemies to fight around the map, but you'd be wrong. In line 28 of script #1, you can assign a variable to note the number of enemies on the map. At the creation of a floor, this variable will equal the Steps Average of that map, which in the demo is 5. Everytime you kill an enemy, this variable drops by 1, until it hits 0 when you've massacred every enemy on the map. What this means is that you can have a funky Parallel Process Conditional Branch checking for when this variable hits 0, then forcibly creating new enemies. This can be done by having a script call the following code: $game_map.add_random_enemy That should cover most of the random battles generated by the script. As a few additional notes, you can completely ignore what I've said above and have random encounters for the floors, or mix it up and have touch encounters on one and random encounters on another, like in the demo. You can also stop events from moving by putting the following in a script call: stop(n) where 'n' is the number of turns you want the enemy to be stopped for. This is handy for enemies you can escape from, whereupon escaping the enemy is locked in place for a few turns (5 turns in the demo) and thus allow the player to get away. With a series of conditional branches and parallel processes, it might even be possible to have the player be able to stun enemies before a fight, avoiding a battle. It'll be a pain to setup though. ******* End ******* And that should be that! Think I've covered everything. It's not easy, but not particularly hard either. If there're any questions, feel free to pop me a line. I'm not a scripter though, so don't expect too much on that note, but I might be able to help you out with debugging and figuring out what's going on. Kirin, out. FAQ Q: Where do I put these scripts? A: Above Main, under Materials. You really only need the main script; the other two are just bonuses. Q: How do I use this script? A: Read the 'How to Use.txt' file included in the demo, or refer to the same section in my post above. Q: Help! I'm getting an 'Unable to find file: Graphics/System/dark_edge2' error! A: The hint is in the error. Download the images from either this link or from the attachment and place them in the proper folder. Q: Help! I'm getting an 'undefined method 'each' for nil:NilClass' error! A: Make sure that the maps that'll be running the code have a '@' symbol before the map name (Display name doesn't matter). Credit and Thanks - Saba Kan, for making this script. - Kirin (me), for translating this. - Nelderson, for pointing out to me that you need to have a '@' symbol in the map editor name. - Enterbrain, for once again making an awesome maker. - Google Translate, for helping me with minor translations. - The makers of the Rikai-chan addon for Mozilla and the Rikai-kun extension for Chrome, for giving us an awesome Japanese translator. RandomDungeonGenerator.zip Edited March 28, 2012 by kirinelf 4 Share this post Link to post Share on other sites
Kamirl 4 Posted March 28, 2012 no demo :-) says invalid file :-) Share this post Link to post Share on other sites
Kirin 37 Posted March 28, 2012 Try it again. I was having trouble uploading stuff just now when I updated it with a tiny fix. Share this post Link to post Share on other sites
Sidbot 3 Posted March 28, 2012 (edited) I get this error in the demo: Dungeon Generation line 686: NomethodError occurred. Undefined method 'put_to_random_place' for nil:NilClass Awesome script though! This is a real time saver for creating dungeon crawling sections in a game. EDIT: I figured out the problem. If the monster variable is too high, it will just keep generating monsters which can crash the game. Edited March 28, 2012 by Sidbot Share this post Link to post Share on other sites
Kirin 37 Posted March 28, 2012 I actually found something else. Turns out that I forgot to reassign the ENEMY_COUNT variable in the script. In the editor, I labelled variable 001 as the Enemy Count variable, while in the script it was still 141. I fixed that and it hasn't thrown up any problems so far. Major derp moment. Uploading the fixed demo. Share this post Link to post Share on other sites
Co 0 Posted March 28, 2012 I've a big problem I use this generator with "Sapphire Action System IV" but it make many passability bug. For exemple I walk on a wall. So help-me. (Note for scripter: I just have "Sapphire Action System IV" script in my project.) Share this post Link to post Share on other sites
Kirin 37 Posted March 29, 2012 (edited) I'm not a scripter, so I can't help you with this. I'll see if I can take SASIV for a test run with this script later, and see if there're any easy fixes that can be done, but generally, I'd be a little doubtful of this working on ABS's. I'll give it a try later though. Edit: When I tried this, the random dungeon generates fine but my character can't move at all. Also, the script spits out an error whenever I attack an enemy, which is related to the Dungeon Generation script. I'd go to Script Support if I were you; I have no idea how to fix this. Maybe Khas or someone else would be able to come up with a fix. Edited March 29, 2012 by kirinelf Share this post Link to post Share on other sites
Shablo5 8 Posted May 23, 2012 Impressive. I really want to try this. Thank you for the port. Share this post Link to post Share on other sites
Capt. Headbag 0 Posted July 4, 2012 Hi there. I've got a lil' problem here. I've created a dungeon with 3 floors. The first goes perfectly fine, but when i enter the second floor, i get an 'undefined method 'name' for nil:NilClass' error. Or somethin like this. I think i've done everythin accordin to your instructions (my floors' name start with @) so i really don't see where is the problem. Could ya help me, please ? Thanks for translatin this script anyway. Share this post Link to post Share on other sites
Kayzee 4,066 Posted July 5, 2012 (edited) Hehe I have been using this myself, and modifying it a bit too. :3 Anyway the undefined name sounds like it's related to your events to me. It's obviously passing some nil value somewhere it shouldn't. You might want to give this backtrace script a try, as it gives you a better idea of what the error is. Except I, er... can't figure out for the life of me how you open that console. :/ I made a version that logs to a file instead :3 I bet I am missing something real obvious though. >_< I sure am using a lot of emoticons lately. O_o My avatar must be getting to me. MORE DUST! OwO Edit: HURPA DURP, I found the show console option under the game menu. >_< Edited July 5, 2012 by KilloZapit Share this post Link to post Share on other sites
thepsynergist 0 Posted July 25, 2012 I just wanted to say how awesome this script is. However, I can't seem to get it to work properly with XAS-ABS for RPG Maker VX Ace. Whenever I attack it gives me a, 'undefined method 'each' for nil:NilClass'. It thinks the map I'm on is trying to load the dungeon whenever I attack or something... Also, when I start a previously saved game, it gives me a floor type error given in the same format as the above. Any ideas on how to get this working with XAS? Share this post Link to post Share on other sites
DAVE_EBUBBLES 16 Posted July 25, 2012 My bro... is going to flip his shit over this. I would aswell but I am presently flipping my shit over something else. The scripting support has come. Suddenly I feel more comfortable with Ace. Share this post Link to post Share on other sites
ZakTheFallen 0 Posted September 1, 2012 I love the script, very interesting, but I get this error when I try to run a new project with just the first script loaded in. "line 842: NoMethodError occured. undefined method 'room' for #<Game_Player:0x3818488>" I followed the steps closely and this crash only happens after I go past the title screen. Everything seems properly named and the dungeon should generate just fine. I can't find a place where 'room' is even declared as a variable of the GamePlayer class, or its parent classes. At no point does the code seem to add it, but then it moves on to accessing it, and then crashes because it doesn't exist. Anyway, I'm just a tad confused about what I'm missing in my map, to cause such an error. Clearly it works for other people, so I must be missing something... ....Nevermind. I just noticed that the minimap script adds 'room' to the GamePlayer. Serves me right for forgetting to add all of the scripts. Share this post Link to post Share on other sites
Kayzee 4,066 Posted September 1, 2012 Yeah it's kind of weird how things are defined sometimes. The scripts aren't very modular like that, since there are things like that where things are defined in subscripts that should be in the main script. Share this post Link to post Share on other sites
Tsukihime 1,489 Posted September 1, 2012 (edited) I'm more interested in the algorithm used for drawing the auto-tiles. But...lol I can't seem to sit down and read the script. Does someone want to take the auto-tile drawing algorithm and write a separate script for it? Edited September 1, 2012 by Tsukihime Share this post Link to post Share on other sites
Kayzee 4,066 Posted September 1, 2012 (edited) It's a pretty limited algorithm if you ask me... I am not sure it will even work for anything besides walls, and assumes fixed offsets from the tile. Look at the put_wall_tiles and put_edge_tiles for Game_Map. Edited September 1, 2012 by KilloZapit Share this post Link to post Share on other sites
Tsukihime 1,489 Posted September 1, 2012 I thought the auto-tile algorithm was supposed to be limited, considering how they shrunk it down from the XP tilesets. Share this post Link to post Share on other sites
Kayzee 4,066 Posted September 1, 2012 I mean the way the script does it, it won't work for general tiles. Share this post Link to post Share on other sites
Tsukihime 1,489 Posted September 1, 2012 That's because auto-tile algorithm does not care about general tiles since general tiles are just one ID. Autotiles have 48 ID's depending on the adjacent tiles. Share this post Link to post Share on other sites
Kayzee 4,066 Posted September 1, 2012 It's not that simple I think. Walls and ground autotiles looks slightly different to me. It's likely you have to figure out what group of tiles the tile is in first Share this post Link to post Share on other sites
Tsukihime 1,489 Posted September 1, 2012 The patterns are defined for each A1, A2, A3, and A4. If you know which group of tiles you're working with, hardcoding it is not an issue. There is no reason why you would ever be working with ground and wall tiles simultaneously, and because the editor has hardcoded it like that, there is no reason why someone would design an autotile differently and expect it to work correctly. Share this post Link to post Share on other sites
Kayzee 4,066 Posted September 1, 2012 (edited) Yeah, just saying if you want to do it right for say, passing over every tile on the map, figuring out the group it's in and autotileing it, your probably going to have to write your own. Edited September 1, 2012 by KilloZapit Share this post Link to post Share on other sites
yion90 0 Posted March 28, 2013 Whenever i load my Game and visit a new added map this error happens: It's a Pain to test play the game without actually being able to play it normally. (like how strong you are in your playthrough etc.) That's why i like to play my game while designing it. Being able to load and save is a Major thing to easen it for me. So this Error is really a pain in the Nutella-bread for me. Share this post Link to post Share on other sites
Kayzee 4,066 Posted March 28, 2013 Try replacing this: def dungeon? if @random_dungeon != nil return @random_dungeon end unless @map_infos @map_infos = load_data("Data/MapInfos.rvdata2") end @random_dungeon = @map_infos[@map_id].name.include?("@") return @random_dungeon endwith this: def dungeon? if @random_dungeon.nil? @random_dungeon = $data_mapinfos[@map_id].name.include?("@") end return @random_dungeon end Share this post Link to post Share on other sites
Kwr32 0 Posted April 18, 2013 Seems like there are tons of problems around this script, though it works for some people.I'm getting this error whenever the game loads a map (any map as far as I know): The scripts are from the demo. Share this post Link to post Share on other sites