Rycochet

New Tile Swap

Sep 17th, 2013
182
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 32.65 KB | None | 0 0
  1. =begin
  2. ================================================================================
  3.   Title: Tile Swap
  4.  Author: Tsukihime, Rycochet
  5.    Date: Sep 20, 2013
  6. --------------------------------------------------------------------------------
  7.  ** Change log
  8.  3.0 --- WIP
  9.      -TODO auto-layer from "A13" style tile id
  10.      -TODO documentation update, including the new Map_Mask usage
  11.  3.0b1 September 20 2013 by Rycochet
  12.      -Added Map_Mask class and several shape functions - can replace everything
  13.       except positions if needed
  14.      -Various bugfixes and speedups
  15.  2.5 September 19 2013 by Rycochet
  16.      -Yet more speedups, can now handle an entire 250k map in under 2 seconds
  17.      -Fixed accidental bug in convert_tid
  18.  2.4 September 17 2013 by Rycochet
  19.      -major performance boosts, dirty map change flag, bitfield mask
  20.  2.3 May 5
  21.      -fixed bug where A5 tiles were not being swapped properly. This is because
  22.         they were treated as auto-tiles instead of normal tiles
  23.  2.2 May 4
  24.      -updated to support overlay maps
  25.  2.1 Apr 11
  26.      -fixed bug where B-E pages weren't handled properly
  27.  2.0 Feb 17
  28.      -removed use of a new map. Should be more compatible now
  29.      -fixed bug where last row of page A4 tiles were skipped
  30.      -revised input format
  31.      -proper autotile swapping
  32.  1.2 Jan 22, 2013
  33.      -fixed bug where swap by position didn't handle layers properly
  34.  1.1 May 20
  35.      -Added support for reverting tiles
  36.  1.0 May 16, 2012
  37.      -Initial release
  38. --------------------------------------------------------------------------------
  39.  ** Terms of Use
  40.  * Free to use in commercial/non-commercial projects
  41.  * The script is provided as-is
  42.  * Cannot guarantee that it is compatible with other scripts
  43.  * Preserve this header
  44. --------------------------------------------------------------------------------
  45.  ** Description
  46.  
  47.  This script allows you to change the tiles on a map, and also revert the
  48.  changes.
  49. --------------------------------------------------------------------------------
  50.  ** Compatibility
  51.  
  52.  Let me know.
  53. --------------------------------------------------------------------------------
  54.  ** Usage
  55.  
  56.  Please refer to the reference section to understand what a tileID is and
  57.  how these script calls should be made.
  58.  
  59.  There are three types of tile swaps
  60.  
  61.  1. Change by tile id
  62.      -All tiles on the map with the specified ID will be changed to a new tile
  63.  
  64.         Usage: tile_swap(old_tileID, new_tileID, layer, map_id)
  65.  
  66.  2. Change by region id
  67.      -All tiles that are covered by the specified region ID will be changed
  68.         to a new tile
  69.  
  70.         Usage: region_swap(regionID, tileID, layer, map_id)
  71.  
  72.  3. Change by position
  73.      -The tile at the specified position will be changed to a new tile
  74.  
  75.         Usage: pos_swap(x, y, tileID, layer, map_id)
  76.  
  77.  You can undo tile swaps using analogous functions
  78.  
  79.      tile_revert(tid, layer, map_id)
  80.      pos_revert(x, y, tid, layer, map_id)
  81.      region_revert(rid, layer, map_id)
  82.      revert_all(map_id)
  83.  
  84. --------------------------------------------------------------------------------
  85.  ** Reference
  86.  
  87.  This script uses the concept of a "tile ID", which is a special string
  88.  that represents a particular tile on your tileset.
  89.  
  90.  The format of this tile ID is a letter, followed by a number.
  91.  The letters available are based on the tileset names
  92.  
  93.      A, B, C, D, E
  94.  
  95.  The number represents the ID of the tile.
  96.  So for example, "A1" would be the the first tile in tileset A, whereas
  97.  "B12" would be the 12th tile of tileset B.
  98.  
  99.  To determine the ID of a tile, it is easy: simply look at your tileset and
  100.  number the top-left tile as 1. Then, number them from left-to-right,
  101.  top-to-bottom as such
  102.  
  103.      1  2  3  4  5  6  7  8
  104.      9 10 11 12 13 14 15 16
  105.      ...
  106.  
  107.  The ID that you want is exactly as it appears on your tileset.
  108. --------------------------------------------------------------------------------
  109.  ** Credits
  110.  
  111.  KilloZapit, for the excellent auto-tile generation code
  112. ================================================================================
  113. =end
  114. $imported = {} if $imported.nil?
  115. $imported["TH_TileSwap"] = true
  116. #===============================================================================
  117. # ** Rest of the script.
  118. #===============================================================================
  119.  
  120. class Game_System
  121.  
  122.     attr_accessor :swapped_tiles, :swapped_pos_tiles, :swapped_region_tiles, :swapped_mask_tiles
  123.  
  124.     #-----------------------------------------------------------------------------
  125.     # New. Convert my tileID to an internal tile ID.
  126.     # If passed an [x,y] array then get a tile from the current map instead.
  127.     #-----------------------------------------------------------------------------
  128.     def convert_tid(tileID, layer=0)
  129.         return $game_map.tile_id(tileID[0], tileID[1], [layer, 0].max) if tileID.kind_of?(Array)
  130.         page = tileID[0].upcase
  131.         tid = tileID[1..-1].to_i - 1
  132.         if page == 'A'
  133.             # page A has autotiles
  134.             return tid * 48 + 2048 if tid < 128
  135.             return tid - 128 + 1536
  136.         end
  137.         # pages B, C, D, and E all have 256 icons per page.
  138.         return tid if page == 'B'
  139.         return tid + 256 if page == 'C' # 1 x 256
  140.         return tid + 512 if page == 'D' # 2 x 256
  141.         return tid + 768 if page == 'E' # 3 x 256
  142.     end
  143.  
  144.     def layer_tid(tileID)
  145.         tileID = (tileID - 2048) / 48
  146.         return 2 if tileID < 0
  147.         return 1 if tileID == 2 || tileID == 3 || tileID == 17 || tileID >= 19 && tileID <= 23 || tileID == 25 || tileID >= 27 && tileID <= 31 || tileID == 33 || tileID >= 35 && tileID <= 39 || tileID == 41 || tileID >= 43 && tileID <= 47
  148.         return 0
  149.     end
  150.  
  151.     #==============================================================================
  152.     # ■ Tiles
  153.     #==============================================================================
  154.  
  155.     #-----------------------------------------------------------------------------
  156.     # New.
  157.     #-----------------------------------------------------------------------------
  158.     def initialize_tile_list(map_id, layer)
  159.         @swapped_tiles = [] if @swapped_tiles.nil?
  160.         @swapped_tiles[map_id] = [] if @swapped_tiles[map_id].nil?
  161.         @swapped_tiles[map_id][layer] = [] if @swapped_tiles[map_id][layer].nil?
  162.     end
  163.  
  164.     #-----------------------------------------------------------------------------
  165.     # New.
  166.     #-----------------------------------------------------------------------------
  167.     def add_tile_id(map_id, layer, old_tid, new_tid)
  168.         initialize_tile_list(map_id, layer)
  169.         old_tid = convert_tid(old_tid, layer)
  170.         new_tid = convert_tid(new_tid, layer)
  171.         layer = layer_tid(new_tid) if layer < 0
  172.         @swapped_tiles[map_id][layer][old_tid] = new_tid
  173.         $game_map.load_new_map_data
  174.     end
  175.  
  176.     #-----------------------------------------------------------------------------
  177.     # New.
  178.     #-----------------------------------------------------------------------------
  179.     def has_swap_tiles?(map_id, layer)
  180.         return false if @swapped_tiles.nil?
  181.         return false if @swapped_tiles[map_id].nil? || @swapped_tiles[map_id].empty?
  182.         return false if @swapped_tiles[map_id][layer].nil? || @swapped_tiles[map_id][layer].empty?
  183.         return true
  184.     end
  185.  
  186.     #-----------------------------------------------------------------------------
  187.     # New. Remove all custom tiles on the map for a given layer and tileID
  188.     #-----------------------------------------------------------------------------
  189.     def revert_tile(map_id, layer, tid)
  190.         initialize_tile_list(map_id, layer)
  191.         tid = convert_tid(tid, layer)
  192.         @swapped_tiles[map_id][layer].delete_at(tid)
  193.         $game_map.reload_map
  194.     end
  195.  
  196.     #==============================================================================
  197.     # ■ Positions
  198.     #==============================================================================
  199.  
  200.     #-----------------------------------------------------------------------------
  201.     # New.
  202.     #-----------------------------------------------------------------------------
  203.     def initialize_pos_list(map_id, layer)
  204.         @swapped_pos_tiles = [] if @swapped_pos_tiles.nil?
  205.         @swapped_pos_tiles[map_id] = [] if @swapped_pos_tiles[map_id].nil?
  206.         @swapped_pos_tiles[map_id][layer] = [] if @swapped_pos_tiles[map_id][layer].nil?
  207.     end
  208.  
  209.     #-----------------------------------------------------------------------------
  210.     # New.
  211.     #-----------------------------------------------------------------------------
  212.     def add_position_tile(map_id, x, y, layer, tid)
  213.         initialize_pos_list(map_id, layer)
  214.         tid = convert_tid(tid, layer)
  215.         layer = layer_tid(tid) if layer < 0
  216.         @swapped_pos_tiles[map_id][layer][y] = [] if @swapped_pos_tiles[map_id][layer][y].nil?
  217.         @swapped_pos_tiles[map_id][layer][y][x] = tid
  218.         $game_map.load_new_map_data
  219.     end
  220.  
  221.     #-----------------------------------------------------------------------------
  222.     # New.
  223.     #-----------------------------------------------------------------------------
  224.     def has_swap_pos?(map_id, layer)
  225.         return false if @swapped_pos_tiles.nil?
  226.         return false if @swapped_pos_tiles[map_id].nil? || @swapped_pos_tiles[map_id].empty?
  227.         return false if @swapped_pos_tiles[map_id][layer].nil? || @swapped_pos_tiles[map_id][layer].empty?
  228.         return true
  229.     end
  230.  
  231.     #-----------------------------------------------------------------------------
  232.     # New. Remove all custom tiles on the map for a given layer and position
  233.     #-----------------------------------------------------------------------------
  234.     def revert_pos(map_id, x, y, layer)
  235.         initialize_pos_list(map_id, layer)
  236.         unless @swapped_pos_tiles[map_id][layer][y].nil?
  237.             @swapped_pos_tiles[map_id][layer][y].delete_at(x)
  238.             @swapped_pos_tiles[map_id][layer].delete_at(y) if @swapped_pos_tiles[map_id][layer][y].empty?
  239.         end
  240.         $game_map.reload_map
  241.     end
  242.  
  243.     #==============================================================================
  244.     # ■ Regions
  245.     #==============================================================================
  246.  
  247.     #-----------------------------------------------------------------------------
  248.     # New.
  249.     #-----------------------------------------------------------------------------
  250.     def initialize_region_list(map_id, layer)
  251.         @swapped_region_tiles = [] if @swapped_region_tiles.nil?
  252.         @swapped_region_tiles[map_id] = [] if @swapped_region_tiles[map_id].nil?
  253.         @swapped_region_tiles[map_id][layer] = [] if @swapped_region_tiles[map_id][layer].nil?
  254.     end
  255.  
  256.     #-----------------------------------------------------------------------------
  257.     # New.
  258.     #-----------------------------------------------------------------------------
  259.     def add_region_tile(map_id, rid, layer, tid)
  260.         initialize_region_list(map_id, layer)
  261.         tid = convert_tid(tid, layer)
  262.         layer = layer_tid(tid) if layer < 0
  263.         @swapped_region_tiles[map_id][layer][rid] = tid
  264.         $game_map.load_new_map_data
  265.     end
  266.  
  267.     #-----------------------------------------------------------------------------
  268.     # New.
  269.     #-----------------------------------------------------------------------------
  270.     def has_swap_region?(map_id, layer)
  271.         return false if @swapped_region_tiles.nil?
  272.         return false if @swapped_region_tiles[map_id].nil? || @swapped_region_tiles[map_id].empty?
  273.         return false if @swapped_region_tiles[map_id][layer].nil? || @swapped_region_tiles[map_id][layer].empty?
  274.         return true
  275.     end
  276.  
  277.     #-----------------------------------------------------------------------------
  278.     # New. Remove all custom tiles on the map for a given layer and region
  279.     #-----------------------------------------------------------------------------
  280.     def revert_region(map_id, layer, rid)
  281.         initialize_region_list(map_id, layer)
  282.         @swapped_region_tiles[map_id][layer].delete_at(rid)
  283.         $game_map.reload_map
  284.     end
  285.  
  286.     #==============================================================================
  287.     # ■ Masks
  288.     #==============================================================================
  289.  
  290.     #-----------------------------------------------------------------------------
  291.     # New.
  292.     #-----------------------------------------------------------------------------
  293.     def initialize_mask_list(map_id, layer)
  294.         @swapped_mask_tiles = [] if @swapped_mask_tiles.nil?
  295.         @swapped_mask_tiles[map_id] = [] if @swapped_mask_tiles[map_id].nil?
  296.         @swapped_mask_tiles[map_id][layer] = {} if @swapped_mask_tiles[map_id][layer].nil?
  297.     end
  298.  
  299.     #-----------------------------------------------------------------------------
  300.     # New.
  301.     #-----------------------------------------------------------------------------
  302.     def add_mask_tile(map_id, mask, layer, tid)
  303.         initialize_mask_list(map_id, layer)
  304.         tid = convert_tid(tid, layer)
  305.         layer = layer_tid(tid) if layer < 0
  306.         @swapped_mask_tiles[map_id][layer][mask] = tid
  307.         $game_map.load_new_map_data
  308.     end
  309.  
  310.     #-----------------------------------------------------------------------------
  311.     # New.
  312.     #-----------------------------------------------------------------------------
  313.     def has_swap_mask?(map_id, layer)
  314.         return false if @swapped_mask_tiles.nil?
  315.         return false if @swapped_mask_tiles[map_id].nil? || @swapped_mask_tiles[map_id].empty?
  316.         return false if @swapped_mask_tiles[map_id][layer].nil? || @swapped_mask_tiles[map_id][layer].empty?
  317.         return true
  318.     end
  319.  
  320.     #-----------------------------------------------------------------------------
  321.     # New. Remove all custom tiles on the map for a given layer and region
  322.     #-----------------------------------------------------------------------------
  323.     def revert_mask(map_id, layer, mask)
  324.         initialize_mask_list(map_id, layer)
  325.         @swapped_mask_tiles[map_id][layer].delete(mask)
  326.         $game_map.reload_map
  327.     end
  328.  
  329.     #==============================================================================
  330.     # ■ Revert All
  331.     #==============================================================================
  332.  
  333.     #-----------------------------------------------------------------------------
  334.     # New. Remove all custom tiles from the given map
  335.     #-----------------------------------------------------------------------------
  336.     def revert_all(map_id)
  337.         @swapped_tiles[map_id] = nil unless @swapped_tiles.nil?
  338.         @swapped_pos_tiles[map_id] = nil unless @swapped_pos_tiles.nil?
  339.         @swapped_mask_tiles[map_id] = nil unless @swapped_mask_tiles.nil?
  340.         @swapped_region_tiles[map_id] = nil unless @swapped_region_tiles.nil?
  341.         $game_map.reload_map
  342.     end
  343. end
  344.  
  345. class Map_Mask
  346.     attr_accessor :width, :height, :priority
  347.     #attr @mask # array, each row is in reverse order, bit 0 is the left-most bit
  348.     #attr @mask_width # 0b1111111 - a mask to & with a row to ensure it stays within the width
  349.  
  350.     def initialize(max_width = $game_map.width, max_height = $game_map.height, priority = 0)
  351.         @width = max_width
  352.         @height = max_height
  353.         @priority = priority
  354.         @mask_width = (1 << max_width) - 1
  355.         clear!
  356.     end
  357.  
  358.     #--------------------------------------------------------------------------
  359.     # * clone
  360.     # Clone this mask
  361.     #--------------------------------------------------------------------------
  362.     def clone
  363.         mask = Map_Mask.new(self.width, self.height, self.priority)
  364.         mask.copy(self)
  365.         return mask
  366.     end
  367.  
  368.     #--------------------------------------------------------------------------
  369.     # * !! Print the mask for debugging !!
  370.     #--------------------------------------------------------------------------
  371.     def debug
  372.         print "Current mask:\n"
  373.         for y in 0...@height
  374.             print "#{(@mask[y] || 0).to_s(2).reverse}\n"
  375.         end
  376.     end
  377.  
  378.     #--------------------------------------------------------------------------
  379.     # * update
  380.     # Updates the map
  381.     #--------------------------------------------------------------------------
  382.     def update
  383. #       $game_map.load_new_map_data
  384.         $game_map.reload_map
  385.     end
  386.  
  387.     #--------------------------------------------------------------------------
  388.     # * valid?(x, y)
  389.     # Check if a coordinate is valid
  390.     #--------------------------------------------------------------------------
  391.     def valid?(x, y)
  392.         return x >= 0 && x < @width && y >= 0 && y < @height
  393.     end
  394.  
  395.     #--------------------------------------------------------------------------
  396.     # * empty?
  397.     # Checks if the mask is empty
  398.     #--------------------------------------------------------------------------
  399.     def empty?
  400.         return true if @mask.empty?
  401.         for y in 0...@height
  402.             return false if @mask[y]
  403.         end
  404.         return true
  405.     end
  406.  
  407.     #--------------------------------------------------------------------------
  408.     # * clear!
  409.     # Clears the entire mask
  410.     #--------------------------------------------------------------------------
  411.     def clear!
  412.         @mask = []
  413.     end
  414.  
  415.     #--------------------------------------------------------------------------
  416.     # * mask[x, y] = boolean
  417.     # Marks or clears a single coordinate in the mask
  418.     # Access as an array, but with a true/false value type
  419.     #--------------------------------------------------------------------------
  420.     def []=(x, y, set)
  421.         return unless valid?(x, y)
  422.         if set
  423.             @mask[y] = ((@mask[y] || 0) | (1 << x)) & @mask_width
  424.         else
  425.             @mask[y] = (@mask[y] || 0) & (@mask_width ^ (1 << x))
  426.         end
  427.     end
  428.  
  429.     #--------------------------------------------------------------------------
  430.     # * mask[x, y]
  431.     # Checks if a single coordinate in the mask is set
  432.     #--------------------------------------------------------------------------
  433.     def [](x, y)
  434.         return (@mask[y] || 0) & (1 << x) != 0
  435.     end
  436.  
  437.     #--------------------------------------------------------------------------
  438.     # * mask**y
  439.     # Get the full line data for a single row
  440.     #--------------------------------------------------------------------------
  441.     def **(y)
  442.         return (@mask[y] || 0)
  443.     end
  444.    
  445.     #--------------------------------------------------------------------------
  446.     # * or(mask)
  447.     # OR with another mask, tiles that are set in either mask will be kept
  448.     #--------------------------------------------------------------------------
  449.     def or(mask)
  450.         for y in 0...[mask.height, @height].min
  451.             @mask[y] = ((@mask[y] || 0) | (mask ** y)) & @mask_width
  452.         end
  453.     end
  454.  
  455.     #--------------------------------------------------------------------------
  456.     # * xor(mask)
  457.     # XOR with another mask, only tiles that are set in a single mask will be
  458.     # kept
  459.     #--------------------------------------------------------------------------
  460.     def xor(mask)
  461.         for y in 0...[mask.height, @height].min
  462.             @mask[y] = ((@mask[y] || 0) ^ (mask ** y)) & @mask_width
  463.         end
  464.     end
  465.  
  466.     #--------------------------------------------------------------------------
  467.     # * and(mask)
  468.     # AND with another mask, only tiles that are set in both masks will be kept
  469.     #--------------------------------------------------------------------------
  470.     def and(mask)
  471.         for y in 0...[mask.height, @height].min
  472.             @mask[y] = ((@mask[y] || 0) & (mask ** y)) & @mask_width
  473.         end
  474.     end
  475.  
  476.     #--------------------------------------------------------------------------
  477.     # * invert
  478.     # Inverts a mask
  479.     #--------------------------------------------------------------------------
  480.     def invert
  481.         for y in 0...@height
  482.             @mask[y] = (@mask[y] || 0) ^ @mask_width
  483.         end
  484.     end
  485.  
  486.     #--------------------------------------------------------------------------
  487.     # * copy(mask)
  488.     # Copy another mask
  489.     #--------------------------------------------------------------------------
  490.     def copy(mask)
  491.         clear!
  492.         for y in 0...[mask.height, @height].min
  493.             @mask[y] = (mask ** y) & @mask_width
  494.         end
  495.     end
  496.  
  497.     #--------------------------------------------------------------------------
  498.     # * from_region(rid)
  499.     # Copy a region from the current map
  500.     #--------------------------------------------------------------------------
  501.     def from_region(rid)
  502.         for y in 0...[@height, $game_map.height].min
  503.             for x in 0...[@width, $game_map.width].min
  504.                 if rid == $game_map.data[x, y, 3] >> 8
  505.                     @mask[y] = ((@mask[y] || 0) | (1 << x)) # @mask[x,y] = true
  506.                 end
  507.             end
  508.         end
  509.     end
  510.  
  511.     #--------------------------------------------------------------------------
  512.     # * from_tile(tid)
  513.     # Copy a tile mask from the current map - uses autotile generic tiles
  514.     #--------------------------------------------------------------------------
  515.     def from_tile(tid, layer = 0)
  516.         tid = $game_system.convert_tid(tid)
  517.         for y in 0...[@height, $game_map.height].min
  518.             for x in 0...[@width, $game_map.width].min
  519.                 old_tid = $game_map.data[x, y, layer]
  520.                 old_tid = old_tid - ((old_tid - 2048) % 48) if old_tid >= 2048
  521.                 if tid == old_tid
  522.                     @mask[y] = ((@mask[y] || 0) | (1 << x)) # @mask[x,y] = true
  523.                 end
  524.             end
  525.         end
  526.     end
  527.  
  528.     #--------------------------------------------------------------------------
  529.     # * rectangle(width, height, left, top)
  530.     # Draw a rectangle in the mask
  531.     #--------------------------------------------------------------------------
  532.     def rectangle(width, height, left = 0, top = 0)
  533.         mask = (((1 << (width + 1)) - 1) << left) & @mask_width
  534.         for y in top...[(top + width), @height].min
  535.             @mask[y] = (@mask[y] || 0) | mask
  536.         end
  537.     end
  538.  
  539.     #--------------------------------------------------------------------------
  540.     # * shift(right, down)
  541.     # Shift a mask, use negative numbers for left / up
  542.     #--------------------------------------------------------------------------
  543.     def shift(right, down)
  544.         mask = []
  545.         for y in 0...@height
  546.             if @mask[y + down]
  547.                 if !right
  548.                     mask[y] = @mask[y + down]
  549.                 elsif right < 0
  550.                     mask[y] = @mask[y + down] >> -right
  551.                 elsif right > 0
  552.                     mask[y] = (@mask[y + down] << right) & @mask_width
  553.                 end
  554.             end
  555.         end
  556.         @mask = mask
  557.     end
  558.  
  559.     #--------------------------------------------------------------------------
  560.     # * grow
  561.     # Grow the outline of a mask, every filled coordinate is surrounded in a
  562.     # 3x3 grid
  563.     #--------------------------------------------------------------------------
  564.     def grow
  565.         mask = []
  566.         for y in 0...@height
  567.             if @mask[y]
  568.                 mask[y] = @mask[y] |= (@mask[y] << 1) | (@mask[y] >> 1)
  569.             end
  570.             if y > 0
  571.                 mask[y-1] = (mask[y-1] || 0) | @mask[y] unless @mask[y].nil?
  572.                 mask[y] = (mask[y] || 0) | @mask[y-1] unless @mask[y-1].nil?
  573.             end
  574.         end
  575.         @mask = mask
  576.     end
  577.  
  578.     #--------------------------------------------------------------------------
  579.     # * shrink
  580.     # Shrink the outline of a mask, will reduce the size of a mask in a * shape
  581.     #--------------------------------------------------------------------------
  582.     def shrink
  583.         invert
  584.         grow
  585.         invert
  586.     end
  587.  
  588.     #--------------------------------------------------------------------------
  589.     # * blur
  590.     # Similar to grow, but doesn't grow diagonally
  591.     #--------------------------------------------------------------------------
  592.     def blur
  593.         mask = []
  594.         for y in 0...@height
  595.             if @mask[y]
  596.                 mask[y] = @mask[y] | (@mask[y] << 1) | (@mask[y] >> 1)
  597.             end
  598.             if y > 0
  599.                 mask[y-1] = (mask[y-1] || 0) | @mask[y] unless @mask[y].nil?
  600.                 mask[y] = (mask[y] || 0) | @mask[y-1] unless @mask[y-1].nil?
  601.             end
  602.         end
  603.         @mask = mask
  604.     end
  605.  
  606.     #--------------------------------------------------------------------------
  607.     # * unblur
  608.     # Shrink the outline of a mask, will reduce the size of a mask in a + shape
  609.     #--------------------------------------------------------------------------
  610.     def unblur
  611.         invert
  612.         blur
  613.         invert
  614.     end
  615.  
  616.     #--------------------------------------------------------------------------
  617.     # * each {|x, y, valid_left, valid_top, valid_right, valid_bottom| ... }
  618.     # Perform operations on every valid square in the mask, the valid_*
  619.     # variables state whether the coordinate is against the edge (in a more
  620.     # efficient manner)
  621.     #--------------------------------------------------------------------------
  622.     def each
  623.         for y in 0...@height
  624.             next if !@mask[y]
  625.             valid_top = y > 0
  626.             valid_bottom = y < @height-1
  627.             val = @mask[y]
  628.             for x in 0...@width
  629.                 break if !val
  630.                 unless val & 1 == 0
  631.                     valid_left = x > 0
  632.                     valid_right = x < @width-1
  633.                     yield x, y, valid_left, valid_top, valid_right, valid_bottom
  634.                 end
  635.                 val >>= 1
  636.             end
  637.         end
  638.     end
  639. end
  640.  
  641. class Game_Map
  642.  
  643.     #-----------------------------------------------------------------------------
  644.     # Aliased. Load new map data after the original map is loaded
  645.     #-----------------------------------------------------------------------------
  646.     alias :tsuki_tile_swap_setup_map :setup
  647.     def setup(map_id)
  648.         tsuki_tile_swap_setup_map(map_id)
  649.         @updated_tiles = Map_Mask.new(width, height)
  650.         load_new_map_data
  651.     end
  652.  
  653.     #-----------------------------------------------------------------------------
  654.     # New. Grab the original map data and load that up
  655.     #-----------------------------------------------------------------------------
  656.     def reload_map
  657.         new_map = load_data(sprintf("Data/Map%03d.rvdata2", @map_id))
  658.         @map.data = new_map.data
  659.         load_new_map_data
  660.         update
  661.     end
  662.  
  663.     #-----------------------------------------------------------------------------
  664.     # New. Load custom map data on top of our map
  665.     #-----------------------------------------------------------------------------
  666.     def load_new_map_data
  667.         @need_load_new_map_data = true
  668.     end
  669.  
  670.     #-----------------------------------------------------------------------------
  671.     # Aliased. Refresh the map if we've got pending changes
  672.     #-----------------------------------------------------------------------------
  673.     alias :tsuki_tile_swap_update_map :update
  674.     def update(main = false)
  675.         if @need_load_new_map_data
  676.             @need_load_new_map_data = false
  677. #print "Game_Map.update()\n"; Benchmark.bm(20) do |x| x.report("swap_all") {
  678.             #-----------------------------------------------------------------------------
  679.             # New. Swap tiles by tile ID
  680.             #-----------------------------------------------------------------------------
  681.             tiles = $game_system.swapped_tiles[map_id]
  682.             regions = $game_system.swapped_region_tiles[map_id]
  683.             masks = $game_system.swapped_mask_tiles[map_id]
  684.             positions = $game_system.swapped_pos_tiles[map_id]
  685.             if tiles or regions or masks or positions
  686.                 for z in 0...3
  687.                     @updated_tiles.clear!
  688.                     tilesz = tiles && $game_system.swapped_tiles[map_id][z]
  689.                     regionsz = regions && $game_system.swapped_region_tiles[map_id][z]
  690.                     masksz = masks && $game_system.swapped_mask_tiles[map_id][z]
  691.                     positionz = positions && $game_system.swapped_pos_tiles[map_id][z]
  692.                     next unless tilesz or regionsz or masksz or positionsz
  693.                     for y in 0...height
  694.                         positionszy = positionsz || positionsz[y]
  695.                         for x in 0...width
  696.                             new_tile = nil
  697.                             if positionszy
  698.                                 new_tile = positionszy[x]
  699.                             end
  700.                             if new_tile.nil? and masksz
  701.                                 priority = nil
  702.                                 masksz.each {|mask, tid|
  703.                                     if (priority.nil? or mask.priority > priority) and mask[x,y]
  704.                                         new_tile = tid
  705.                                         priority = mask.priority
  706.                                     end
  707.                                 }
  708.                             end
  709.                             if new_tile.nil? and regionsz
  710.                                 new_tile = regionsz[tile_id(x, y, 3) >> 8] # region_id(x,y) - but without the extra valid?(x,y) overhead
  711.                             end
  712.                             if new_tile.nil? and tilesz
  713.                                 old_tid = tile_id(x, y, z)
  714.                                 old_tid = old_tid - ((old_tid - 2048) % 48) if old_tid >= 2048
  715.                                 new_tile = tilesz[old_tid]
  716.                             end
  717.                             next if new_tile.nil?
  718.                             old_tid = tile_id(x, y, z)
  719.                             old_tid = old_tid - ((old_tid - 2048) % 48) if old_tid >= 2048
  720.                             next if new_tile == old_tid # quicker than the autotile recalibration overhead for a single tile
  721.                             @map.data[x, y, z] = new_tile
  722.                             next unless new_tile < 2048 || z # autotiles only normally appear on layer 0
  723.                             @updated_tiles[x, y] = true
  724.                         end
  725.                     end
  726.                 end
  727.                 next if @updated_tiles.empty?
  728.                 @updated_tiles.grow
  729.                 #-----------------------------------------------------------------------------
  730.                 # The following was originally based on auto-tile generation code by KilloZapit
  731.                 #-----------------------------------------------------------------------------
  732.                 @updated_tiles.each { |x, y, valid_left, valid_top, valid_right, valid_bottom|
  733.                     autotile = (tile_id(x, y, z) - 2048) / 48
  734.                     next if autotile < 0
  735.                     index = 0
  736.                     if autotile == 5 or autotile == 7 or autotile == 9 or autotile == 11 or autotile == 13 or autotile == 15
  737.                         # waterfall
  738.                         index |= 1 if valid_left && autotile_edge(autotile, x - 1, y, z)
  739.                         index |= 2 if valid_right && autotile_edge(autotile, x + 1, y, z)
  740.                     elsif autotile >= 48 and autotile <= 79 or autotile >= 88 and autotile <= 95 or autotile >= 104 and autotile <= 111 or autotile >= 120 and autotile <= 127
  741.                         # wall
  742.                         index |= 1 if valid_left && autotile_wall_edge(autotile, x - 1, y, z)
  743.                         index |= 2 if valid_top && autotile_edge(autotile, x, y - 1, z)
  744.                         index |= 4 if valid_right && autotile_wall_edge(autotile, x + 1, y, z)
  745.                         index |= 8 if valid_bottom && autotile_edge(autotile, x, y + 1, z)
  746.                     else
  747.                         # normal
  748.                         edge = 0
  749.                         edge |= 1 if valid_left && autotile_edge(autotile, x - 1, y, z)
  750.                         edge |= 2 if valid_top && autotile_edge(autotile, x, y - 1, z)
  751.                         edge |= 4 if valid_right && autotile_edge(autotile, x + 1, y, z)
  752.                         edge |= 8 if valid_bottom && autotile_edge(autotile, x, y + 1, z)
  753.                         if edge == 0 # -
  754.                             index |= 1 if valid_top && valid_left && autotile_edge(autotile, x - 1, y - 1, z)
  755.                             index |= 2 if valid_top && valid_right && autotile_edge(autotile, x + 1, y - 1, z)
  756.                             index |= 4 if valid_bottom && valid_right && autotile_edge(autotile, x + 1, y + 1, z)
  757.                             index |= 8 if valid_bottom && valid_left && autotile_edge(autotile, x - 1, y + 1, z)
  758.                         elsif edge == 1 # l
  759.                             index |= 1 if valid_top && valid_right && autotile_edge(autotile, x + 1, y - 1, z)
  760.                             index |= 2 if valid_bottom && valid_right && autotile_edge(autotile, x + 1, y + 1, z)
  761.                             index |= 16
  762.                         elsif edge == 2 # u
  763.                             index |= 1 if valid_bottom && valid_right && autotile_edge(autotile, x + 1, y + 1, z)
  764.                             index |= 2 if valid_bottom && valid_left && autotile_edge(autotile, x - 1, y + 1, z)
  765.                             index |= 20
  766.                         elsif edge == 3 # lu
  767.                             index = valid_bottom && valid_right && autotile_edge(autotile, x + 1, y + 1, z) ? 35 : 34
  768.                         elsif edge == 4 # r
  769.                             index |= 1 if valid_bottom && valid_left && autotile_edge(autotile, x - 1, y + 1, z)
  770.                             index |= 2 if valid_top && valid_left && autotile_edge(autotile, x - 1, y - 1, z)
  771.                             index |= 24
  772.                         elsif edge == 5 # lr
  773.                             index = 32
  774.                         elsif edge == 6 # ur
  775.                             index = valid_bottom && valid_left && autotile_edge(autotile, x - 1, y + 1, z) ? 37 : 36
  776.                         elsif edge == 7 # lur
  777.                             index = 42
  778.                         elsif edge == 8 # d
  779.                             index |= 1 if valid_top && valid_left && autotile_edge(autotile, x - 1, y - 1, z)
  780.                             index |= 2 if valid_top && valid_right && autotile_edge(autotile, x + 1, y - 1, z)
  781.                             index |= 28
  782.                         elsif edge == 9 # ld
  783.                             index = valid_top && valid_right && autotile_edge(autotile, x + 1, y - 1, z) ? 41 : 40
  784.                         elsif edge == 10 # ud
  785.                             index = 33
  786.                         elsif edge == 11 # lud
  787.                             index = 43
  788.                         elsif edge == 12 # rd
  789.                             index = valid_top && valid_left && autotile_edge(autotile, x - 1, y - 1, z) ? 39 : 38
  790.                         elsif edge == 13 # lrd
  791.                             index = 44
  792.                         elsif edge == 14 # urd
  793.                             index = 45
  794.                         elsif edge == 15 # lurd
  795.                             index = 46
  796.                         else # wtf
  797.                             index = 47
  798.                         end
  799.                     end
  800.                     @map.data[x, y, z]= 2048 + (48 * autotile) + index
  801.                 }
  802. #} end # Benchmark
  803.             end
  804.         end
  805.         tsuki_tile_swap_update_map(main)
  806.     end
  807.  
  808.     # Special dungeon logic
  809.     # makes overlay grass tiles "grow" out of walls.
  810.     def autotile_edge(autotile, x, y, z)
  811.         return autotile != (tile_id(x, y, z) - 2048) / 48
  812.     end
  813.  
  814.     def autotile_wall_edge(autotile, x, y, z)
  815.         return false if autotile & 8 and (tile_id(x, y, z) - 2048) / 48 + 8 == autotile
  816.         return autotile_edge(autotile, x, y, z)
  817.     end
  818. end
  819.  
  820. class Game_Interpreter
  821.  
  822.     #swaps the tile at x,y to the specified tile_id
  823.     def tile_swap(old_tid, new_tid, layer=-1, map_id=$game_map.map_id)
  824.         $game_system.add_tile_id(map_id, layer, old_tid, new_tid)
  825.     end
  826.  
  827.     def pos_swap(x, y, tid, layer=-1, map_id=$game_map.map_id)
  828.         $game_system.add_position_tile(map_id, x, y, layer, tid)
  829.     end
  830.  
  831.     def region_swap(rid, tid, layer=-1, map_id=$game_map.map_id)
  832.         $game_system.add_region_tile(map_id, rid, layer, tid)
  833.     end
  834.  
  835.     def mask_swap(mask, tid, layer=-1, map_id=$game_map.map_id)
  836.         $game_system.add_mask_tile(map_id, mask, layer, tid)
  837.     end
  838.  
  839.     def tile_revert(tid, layer=-1, map_id=$game_map.map_id)
  840.         $game_system.revert_tile(map_id, layer, tid)
  841.     end
  842.  
  843.     def pos_revert(x, y, layer=-1, map_id=$game_map.map_id)
  844.         $game_system.revert_pos(map_id, x, y, layer)
  845.     end
  846.  
  847.     def region_revert(rid, layer=-1, map_id=$game_map.map_id)
  848.         $game_system.revert_region(map_id, layer, rid)
  849.     end
  850.  
  851.     def mask_revert(mask, layer=-1, map_id=$game_map.map_id)
  852.         $game_system.revert_mask(map_id, layer, mask)
  853.     end
  854.  
  855.     def revert_all(map_id=$game_map.map_id)
  856.         $game_system.revert_all(map_id)
  857.     end
  858. end
  859.  
  860. #-------------------------------------------------------------------------------
  861. # Add-on for Overlay Maps
  862. #-------------------------------------------------------------------------------
  863. class Game_Map
  864.  
  865.     alias :th_overlay_naps_load_new_map_data :load_new_map_data
  866.     def load_new_map_data
  867.         th_overlay_naps_load_new_map_data
  868.         @overlay_maps.each {|map| map.load_new_map_data} unless self.is_a?(Game_OverlayMap)
  869.     end
  870.  
  871.     alias :th_overlay_maps_reload_map :reload_map
  872.     def reload_map
  873.         th_overlay_maps_reload_map
  874.         @overlay_maps.each {|map| map.reload_map} unless self.is_a?(Game_OverlayMap)
  875.     end
  876. end if $imported["TH_OverlayMaps"]
Advertisement
Add Comment
Please, Sign In to add comment