Advertisement
deadelf79

Hime/Rycochet Tile Swap 3.3de

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