class CustomTilemapBitmaps attr_accessor :changed def initialize @changed=true @tiles=[nil,nil,nil,nil,nil,nil,nil,nil,nil] end def []=(i,value) @tiles[i]=value @changed=true end def [](i) return @tiles[i] end end class TilemapSprite < Sprite attr_accessor :id attr_reader :useanim def initialize(id,viewport) super(viewport) @id=id @useanim=(id>=0x800&&id<0x860)|| (id>=0x8C0&&id<0x8F0)|| (id>=0x920&&id<0x950)|| (id>=0x980&&id<0x9B0)|| (id>=0x9E0&&id<0xA10)|| (id>=0xA40&&id<0xA70)|| (id>=0xAA0&&id<0xAD0) end def id=(id) @id=id @useanim=(id>=0x800&&id<0x860)|| (id>=0x8C0&&id<0x8F0)|| (id>=0x920&&id<0x950)|| (id>=0x980&&id<0x9B0)|| (id>=0x9E0&&id<0xA10)|| (id>=0xA40&&id<0xA70)|| (id>=0xAA0&&id<0xAD0) end end class Tilemap Animated_Autotiles_Frames = 25 # for frame rate of 60 FPS Autotiles = [ [18,17,14,13],[2,17,14,13],[18,3,14,13],[2,3,14,13],[18,17,14,7],[2,17,14,7], [18,3,14,7],[2,3,14,7],[18,17,6,13],[2,17,6,13],[18,3,6,13],[2,3,6,13], [18,17,6,7],[2,17,6,7],[18,3,6,7],[2,3,6,7],[16,17,12,13],[16,3,12,13], [16,17,12,7],[16,3,12,7],[10,9,14,13],[10,9,14,7],[10,9,6,13],[10,9,6,7], [18,19,14,15],[18,19,6,15],[2,19,14,15],[2,19,6,15],[18,17,22,21],[2,17,22,21], [18,3,22,21],[2,3,22,21],[16,19,12,15],[10,9,22,21],[8,9,12,13],[8,9,12,7], [10,11,14,15],[10,11,6,15],[18,19,22,23],[2,19,22,23],[16,17,20,21],[16,3,20,21], [8,11,12,15],[8,9,20,21],[16,19,20,23],[10,11,22,23],[8,11,20,23],[0,1,4,5] ] RoofTiles = [ [10,9,6,5],[8,9,4,5],[2,1,6,5],[0,1,4,5],[10,11,6,7],[8,11,4,7], [2,3,6,7],[0,3,4,7],[10,9,14,13],[8,9,12,13],[2,1,14,13],[0,1,12,13], [10,11,14,15],[8,11,12,15],[2,3,14,15],[0,3,12,15] ] FlashOpacity=[100,90,80,70,80,90] attr_reader :bitmaps attr_reader :map_data attr_accessor :flash_data attr_accessor :passages attr_reader :visible attr_accessor :ox attr_accessor :oy attr_reader :viewport attr_accessor :tone attr_accessor :color attr_accessor :zoom def graphicsHeight return 480 end def graphicsWidth return 640 end def initialize(viewport) @bitmaps = CustomTilemapBitmaps.new @map_data = nil # Refers to 3D Array Of Tile Settings @flash_data = nil # Refers to 3D Array of Tile Flashdata @passages = nil @visible = true # Refers to Tileset Visibleness @ox = 0 # Bitmap Offsets @oy = 0 # bitmap Offsets @plane = false @tone=Tone.new(0,0,0,0) @color=Color.new(0,0,0,0) @oldtone=Tone.new(0,0,0,0) @oldcolor=Color.new(0,0,0,0) @selfviewport=Viewport.new(0,0,graphicsWidth,graphicsHeight) @viewport=viewport ? viewport : @selfviewport @tiles=[] @autotileInfo={} @regularTileInfo=[] @oldOx=0 @oldOy=0 @layer0=Sprite.new(viewport) @layer0.visible=true @nowshown=false @layer0.bitmap=Bitmap.new([graphicsWidth*2,1].max,[graphicsHeight*2,1].max) @flash=nil @layer0.ox=0 @layer0.oy=0 @oxLayer0=0 @oyLayer0=0 @oxFlash=0 @oyFlash=0 @layer0.z=0 @priotiles=[] @prioautotiles=[] @autosprites=[] @framecount=[] @tilesetChanged=true @flashChanged=false @firsttime=true @disposed=false @usedsprites=false @layer0clip=true @firsttimeflash=true @fullyrefreshed=false @fullyrefreshedautos=false @zoom = 1 end def disposed? return @disposed end def flash_data=(value) @flash_data=value @flashChanged=true end def update @layer0.zoom_x = @zoom @layer0.zoom_y = @zoom if @oldtone!=@tone @layer0.tone=@tone @flash.tone=@tone if @flash for sprite in @autosprites sprite.tone=@tone end for sprite in @tiles sprite.tone=@tone if sprite.is_a?(Sprite) end @oldtone=@tone.clone end if @oldcolor!=@color @layer0.color=@color @flash.color=@color if @flash for sprite in @autosprites sprite.color=@color end for sprite in @tiles sprite.color=@color if sprite.is_a?(Sprite) end @oldcolor=@color.clone end if @bitmaps.changed || @tilesetChanged refresh_autotiles repaintAutotiles refresh_tileset end if @flashChanged refresh_flash end if @flash @flash.opacity=FlashOpacity[(Graphics.frame_count/2) % 6] end if !(@oldOx==@ox && @oldOy==@oy && !@tilesetChanged && !@bitmaps.changed) refresh end if (Graphics.frame_count % Animated_Autotiles_Frames == 0) repaintAutotiles refresh(true) end @nowshown=false @bitmaps.changed=false @tilesetChanged=false end def passages=(value) @passages=value @tilesetChanged=true end def shown? return false if !@visible ysize=@map_data.ysize xsize=@map_data.xsize xStart=(@ox/32)-1 xEnd=((@ox+@viewport.rect.width)/32)+1 yStart=(@oy/32)-1 yEnd=((@oy+@viewport.rect.height)/32)+1 xStart=0 if xStart<0 xStart=xsize-1 if xStart>=xsize xEnd=0 if xEnd<0 xEnd=xsize-1 if xEnd>=xsize yStart=0 if yStart<0 yStart=ysize-1 if yStart>=ysize yEnd=0 if yEnd<0 yEnd=ysize-1 if yEnd>=ysize return (xStart=0x1880&&id<0x1a00)|| (id>=0x1B80&&id<0x1D00)|| (id>=0x1E80&&id<0x2000)|| (id>=0x1100&&id<0x1700) end def isFourFrameAutotile(id) return (id>=0x800&&id<0x860)|| (id>=0x8C0&&id<0x8F0)|| (id>=0x920&&id<0x950)|| (id>=0x980&&id<0x9B0)|| (id>=0x9E0&&id<0xA10)|| (id>=0xA40&&id<0xA70)|| (id>=0xAA0&&id<0xAD0) end def isCounterAutotile(id) return (id>=0xc50&&id<0xc80)|| (id>=0xdd0&&id<0xe00)|| (id>=0xf50&&id<0xf80)|| (id>=0x10d0&&id<0x1100) end def getTileBitmap(id) return -1 if id==0 return 5 if id<0x100 return 6 if id<0x200 return 7 if id<0x300 return 8 if id<0x400 return 0 if id<0x430 return -1 if id<0x500 return 1 if id<0x530 return -1 if id<0x600 return 4 if id<0x680 return -1 if id<0x700 return 4 if id<0x780 return -1 if id<0x800 return 0 if id<0xb00 return 1 if id<0x1100 return 2 if id<0x1700 return 3 if id<0x2000 return -1 end AutotileXY=[ [0,0],[0,96],[192,0],[192,96], [256,0],[448,0],[256,96],[448,96], [0,192],[192,192],[0,288],[192,288], [256,192],[448,192],[256,288],[448,288] ] def getTileXY(id) bitmap=getTileBitmap(id) return nil if bitmap<0 if bitmap>=4 id&=0xFF y=((id>>3)&15)<<5 if (id>0x80) x=256+((id&7)<<5) else x=((id&7)<<5) end return [x,y] else if id>=0x800 && id<0xb00 # Part 1 id=(id-0x800)/48 return AutotileXY[id] elsif id>=0xb00 && id<0x1100 # Part 2 id=(id-0xb00)/48 return [(id%8)*64,(id/8)*96] elsif id>=0x1100 && id<0x1700 # Part 3 id=(id-0x1100)/48 return [(id%8)*64,(id/8)*64] elsif id>=0x1700 && id<0x2000 id=(id-0x1700)/48 row=id>>3 return [(id%8)*64,[0,96,160,256,320,416][row]] elsif id>=0x400 && id<0x500 id=(id-0x400) return [(id%8)*64,(id/8)*64] elsif id>=0x500 && id<0x600 id=(id-0x500) return [(id%8)*64,(id/8)*64] else return nil end end end def bltRegularTile(bitmap,x,y,id) bitmapID=getTileBitmap(id) bitmapXY=getTileXY(id) return if !bitmapXY if id>=0x400 && id<0x600 rect=Rect.new(bitmapXY[0],bitmapXY[1],64,64) bitmap.stretch_blt(Rect.new(x,y,32,32),@bitmaps[bitmapID],rect) else rect=Rect.new(bitmapXY[0],bitmapXY[1],32,32) bitmap.blt(x,y,@bitmaps[bitmapID],rect) end end def bltAutotile(bitmap,x,y,id,frame) return if frame<0 if id>=0x800 && id<0x2000 bitmapID=getTileBitmap(id) bitmapXY=getTileXY(id) tileid=id return if !bitmapXY autotile=@bitmaps[bitmapID] return if !autotile counterAuto=isCounterAutotile(id) if isSmallAutotile(id) id=(id-0x800)%48 tiles=(id>=16) ? [0,0,0,0] : RoofTiles[id] else id=(id-0x800)%48 tiles=Autotiles[id] end animX=bitmapXY[0]+[0,1,2,1][frame]*64 animY=bitmapXY[1] src=Rect.new(0,0,0,0) for i in 0...4 tile_position = tiles[i] if counterAuto && tile_position>=8 yPos=[0,16,32,46,60,74] src.set( (tile_position & 3)*16+animX, yPos[(tile_position >> 2)]+animY, 16, 14) bitmap.stretch_blt( Rect.new(i%2*16+x,i/2*16+y,16,16), autotile, src) else src.set( (tile_position & 3)*16+animX, (tile_position >> 2)*16+animY, 16, 16) bitmap.blt(i%2*16+x,i/2*16+y, autotile, src) end end end end def autotileNumFrames(id) bitmap=getTileBitmap(id) return 0 if bitmap<0 frames=(isFourFrameAutotile(id)) ? 4 : 1 return frames end def autotileFrame(id) bitmap=getTileBitmap(id) return -1 if bitmap<0 frames=(isFourFrameAutotile(id)) ? 4 : 1 return (Graphics.frame_count/Animated_Autotiles_Frames)%frames end def repaintAutotiles i=0;len=@autosprites.length;while i=0x800 && id<0x2000 if count>=tiles.length sprite=TilemapSprite.new(id,@viewport) tiles.push(sprite,0) else sprite=tiles[count] sprite.id=id tiles[count+1]=0 end sprite.visible=@visible sprite.x=xpos sprite.y=ypos sprite.tone=@tone sprite.color=@color getAutotile(sprite,id) spriteZ=((@passages[id]&0x10)!=0) ? 200 : 0 sprite.z=spriteZ count+=2 else if count>=tiles.length sprite=TilemapSprite.new(id,@viewport) tiles.push(sprite,1) else sprite=tiles[count] sprite.id=id tiles[count+1]=1 end sprite.visible=@visible sprite.x=xpos sprite.y=ypos sprite.tone=@tone sprite.color=@color getRegularTile(sprite,id) spriteZ=((@passages[id]&0x10)!=0) ? 200 : 0 sprite.z=spriteZ count+=2 end return count end def refresh_tileset i=0;len=@regularTileInfo.length;while i100 || ysize>100 @fullyrefreshed=false else for z in 0...zsize for y in 0...ysize for x in 0...xsize id = @map_data[x, y, z] next if id==0 || (@passages[id]&0x10)==0 @priotiles.push([x,y,z,id]) end end end @fullyrefreshed=true end end def refresh_flash if @flash_data && !@flash @flash=Sprite.new(viewport) @flash.visible=true @flash.z=1 @flash.blend_type=1 @flash.bitmap=Bitmap.new([graphicsWidth*2,1].max,[graphicsHeight*2,1].max) @firsttimeflash=true elsif !@flash_data && @flash @flash.bitmap.dispose if @flash.bitmap @flash.dispose @flash=nil @firsttimeflash=false end end def refresh_autotiles i=0;len=@autotileInfo.length;while i100 || ysize>100 @fullyrefreshedautos=false else for y in 0...ysize for x in 0...xsize haveautotile=false for z in 0...zsize id = @map_data[x, y, z] next if id<0x800 || id>=0x2000 || (@passages[id]&0x10)!=0 || !@passages[id] next if autotileNumFrames(id)<2 haveautotile=true break end @prioautotiles.push([x,y]) if haveautotile end end @fullyrefreshedautos=true end else @fullyrefreshedautos=true end end def map_data=(value) @map_data=value @tilesetChanged=true end def refreshFlashSprite return if !@flash || @flash_data.nil? ptX=@ox-@oxFlash ptY=@oy-@oyFlash if !@firsttimeflash && !@usedsprites && ptX>=0 && ptX+@viewport.rect.width<=@flash.bitmap.width && ptY>=0 && ptY+@viewport.rect.height<=@flash.bitmap.height @flash.ox=0 @flash.oy=0 @flash.src_rect.set(ptX.round,ptY.round, @viewport.rect.width,@viewport.rect.height) return end width=@flash.bitmap.width height=@flash.bitmap.height bitmap=@flash.bitmap ysize=@map_data.ysize xsize=@map_data.xsize zsize=@map_data.zsize @firsttimeflash=false @oxFlash=@ox-(width>>2) @oyFlash=@oy-(height>>2) @flash.ox=0 @flash.oy=0 @flash.src_rect.set(width>>2,height>>2, @viewport.rect.width,@viewport.rect.height) @flash.bitmap.clear @oxFlash=@oxFlash.floor @oyFlash=@oyFlash.floor xStart=(@oxFlash>>5) xStart=0 if xStart<0 yStart=(@oyFlash>>5) yStart=0 if yStart<0 xEnd=xStart+(width>>5)+1 yEnd=yStart+(height>>5)+1 xEnd=xsize if xEnd>=xsize yEnd=ysize if yEnd>=ysize if xStart>8)&15 g=(id>>4)&15 b=(id)&15 tmpcolor.set(r<<4,g<<4,b<<4) bitmap.fill_rect(xpos,ypos,32,32,tmpcolor) end end end end SPRITETHRESHOLD=2000 def refreshLayer0(autotiles=false) if autotiles return true if !shown? end ptX=@ox-@oxLayer0 ptY=@oy-@oyLayer0 if !autotiles && !@firsttime && !@usedsprites && ptX>=0 && ptX+@viewport.rect.width<=@layer0.bitmap.width && ptY>=0 && ptY+@viewport.rect.height<=@layer0.bitmap.height if @layer0clip @layer0.ox=0 @layer0.oy=0 @layer0.src_rect.set(ptX.round,ptY.round, @viewport.rect.width,@viewport.rect.height) else @layer0.ox=ptX.round @layer0.oy=ptY.round @layer0.src_rect.set(0,0,@layer0.bitmap.width,@layer0.bitmap.height) end return true end width=@layer0.bitmap.width height=@layer0.bitmap.height bitmap=@layer0.bitmap ysize=@map_data.ysize xsize=@map_data.xsize zsize=@map_data.zsize if autotiles return true if @fullyrefreshedautos && @prioautotiles.length==0 xStart=(@oxLayer0>>5) xStart=0 if xStart<0 yStart=(@oyLayer0>>5) yStart=0 if yStart<0 xEnd=xStart+(width>>5)+1 yEnd=yStart+(height>>5)+1 xEnd=xsize if xEnd>xsize yEnd=ysize if yEnd>ysize return true if xStart>=xEnd || yStart>=yEnd trans=Color.new(0,0,0,0) temprect=Rect.new(0,0,0,0) tilerect=Rect.new(0,0,32,32) range=0...zsize overallcount=0 count=0 if !@fullyrefreshedautos for y in yStart..yEnd for x in xStart..xEnd haveautotile=false for z in range id = @map_data[x, y, z] next if id<0x800 || id>=0x2000 || (@passages[id]&0x10)!=0 || !@passages[id] next if @framecount[id/48-1]<2 if !haveautotile haveautotile=true overallcount+=1 xpos=(x<<5)-@oxLayer0 ypos=(y<<5)-@oyLayer0 bitmap.fill_rect(xpos,ypos,0,0,trans) if overallcount<=SPRITETHRESHOLD break end end for z in range id = @map_data[x,y,z] next if id==0 || (@passages[id]&0x10)!=0 || !@passages[id] if overallcount>2000 xpos=(x<<5)-@oxLayer0 ypos=(y<<5)-@oyLayer0 count=addTile(@autosprites,count,xpos,ypos,id) next elsif id<0x800 xpos=(x<<5)-@oxLayer0 ypos=(y<<5)-@oyLayer0 bltRegularTile(bitmap,xpos,ypos,id) elsif id<0x2000 xpos=(x<<5)-@oxLayer0 ypos=(y<<5)-@oyLayer0 bltCachedAutotile(bitmap,xpos,ypos,id) end end end end Graphics.frame_reset if overallcount>SPRITETHRESHOLD else for tile in @prioautotiles x=tile[0] y=tile[1] next if xxEnd next if yyEnd overallcount+=1 xpos=(x<<5)-@oxLayer0 ypos=(y<<5)-@oyLayer0 bitmap.fill_rect(xpos,ypos,0,0,trans) if overallcount<=SPRITETHRESHOLD for z in range id = @map_data[x,y,z] next if id==0 || (@passages[id]&0x10)!=0 || !@passages[id] if overallcount>SPRITETHRESHOLD count=addTile(@autosprites,count,xpos,ypos,id) next elsif id<0x800 bltRegularTile(bitmap,xpos,ypos,id) elsif id<0x2000 bltCachedAutotile(bitmap,xpos,ypos,id) end end end Graphics.frame_reset end @usedsprites=false return true end return false if @usedsprites @firsttime=false @oxLayer0=@ox-(width>>2) @oyLayer0=@oy-(height>>2) if @layer0clip @layer0.ox=0 @layer0.oy=0 @layer0.src_rect.set(width>>2,height>>2, @viewport.rect.width,@viewport.rect.height) else @layer0.ox=(width>>2) @layer0.oy=(height>>2) end @layer0.bitmap.clear @oxLayer0=@oxLayer0.floor @oyLayer0=@oyLayer0.floor xStart=(@oxLayer0>>5) xStart=0 if xStart<0 yStart=(@oyLayer0>>5) yStart=0 if yStart<0 xEnd=xStart+(width>>5)+1 yEnd=yStart+(height>>5)+1 xEnd=xsize if xEnd>=xsize yEnd=ysize if yEnd>=ysize if xStart=xsize maxX=0 if maxX<0 maxX=xsize-1 if maxX>=xsize minY=0 if minY<0 minY=ysize-1 if minY>=ysize maxY=0 if maxY<0 maxY=ysize-1 if maxY>=ysize count=0 if minXmaxX next if ymaxY id=prio[3] xpos=(x<<5)-@ox ypos=(y<<5)-@oy count=addTile(@tiles,count,xpos,ypos,id) end else for z in 0...@map_data.zsize for y in minY..maxY for x in minX..maxX id = @map_data[x, y, z] next if id==0 || (@passages[id]&0x10)==0 || !@passages[id] xpos=(x<<5)-@ox ypos=(y<<5)-@oy count=addTile(@tiles,count,xpos,ypos,id) end end end end end if count<@tiles.length bigchange=(count<=(@tiles.length*2/3)) && (@tiles.length*2/3)>25 j=count;len=@tiles.length;while j