Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

[Resolved] Changing a map's tiles (data)

Alright, my question is there any way to change a map's data? The data contained in Map00x.rxdata. Say that tile (12,16) is a flower and I want to change it to a rock or so. Normally I'd do it with events, but in this case, having about 400 events doesn't seem like a plausible solution. It would be best if it's only the data stored into the memory (if it is stored into memory) that is changed, so it is non-destructive for the original data. (Then probably the map should be updated - but would that be even more laggy then 400 events?)
 
ccoa made a script a while back which allowed you to change a map's tileset. Here;

Code:
class Game_System
  attr_accessor :tileset_settings
  
  alias tileset_initialize initialize
  def initialize
    tileset_initialize
    @tileset_settings = Hash.new
  end
end

class Game_Map
  attr_accessor :tileset_flag
  
  def setup(map_id)
    # Put map ID in @map_id memory
    @map_id = map_id
    # Load map from file and set @map
    @map = load_data(sprintf("Data/Map%03d.rxdata", @map_id))
    # set tile set information in opening instance variables
    if $game_system.tileset_settings[@map_id] != nil
      tileset_id = $game_system.tileset_settings[@map_id]
    else
      tileset_id = @map.tileset_id
    end
    
    tileset = $data_tilesets[tileset_id]
    @tileset_name = tileset.tileset_name
    @autotile_names = tileset.autotile_names
    @panorama_name = tileset.panorama_name
    @panorama_hue = tileset.panorama_hue
    @fog_name = tileset.fog_name
    @fog_hue = tileset.fog_hue
    @fog_opacity = tileset.fog_opacity
    @fog_blend_type = tileset.fog_blend_type
    @fog_zoom = tileset.fog_zoom
    @fog_sx = tileset.fog_sx
    @fog_sy = tileset.fog_sy
    @battleback_name = tileset.battleback_name
    @passages = tileset.passages
    @priorities = tileset.priorities
    @terrain_tags = tileset.terrain_tags
    # Initialize displayed coordinates
    @display_x = 0
    @display_y = 0
    # Clear refresh request flag
    @need_refresh = false
    # Set map event data
    @events = {}
    for i in @map.events.keys
      @events[i] = Game_Event.new(@map_id, @map.events[i])
    end
    # Set common event data
    @common_events = {}
    for i in 1...$data_common_events.size
      @common_events[i] = Game_CommonEvent.new(i)
    end
    # Initialize all fog information
    @fog_ox = 0
    @fog_oy = 0
    @fog_tone = Tone.new(0, 0, 0, 0)
    @fog_tone_target = Tone.new(0, 0, 0, 0)
    @fog_tone_duration = 0
    @fog_opacity_duration = 0
    @fog_opacity_target = 0
    # Initialize scroll information
    @scroll_direction = 2
    @scroll_rest = 0
    @scroll_speed = 4
  end
  
  def change_tileset(tileset_id)
    $game_system.tileset_settings[@map_id] = tileset_id
    
    tileset = $data_tilesets[tileset_id]
    @tileset_name = tileset.tileset_name
    @autotile_names = tileset.autotile_names
    @panorama_name = tileset.panorama_name
    @panorama_hue = tileset.panorama_hue
    @fog_name = tileset.fog_name
    @fog_hue = tileset.fog_hue
    @fog_opacity = tileset.fog_opacity
    @fog_blend_type = tileset.fog_blend_type
    @fog_zoom = tileset.fog_zoom
    @fog_sx = tileset.fog_sx
    @fog_sy = tileset.fog_sy
    @battleback_name = tileset.battleback_name
    @passages = tileset.passages
    @priorities = tileset.priorities
    @terrain_tags = tileset.terrain_tags
    
    @tileset_flag = true
  end
end

class Spriteset_Map
  alias tileset_update update
  def update
    if $game_map.tileset_flag
      @tilemap.tileset = RPG::Cache.tileset($game_map.tileset_name)
      for i in 0..6
        autotile_name = $game_map.autotile_names[i]
        @tilemap.autotiles[i] = RPG::Cache.autotile(autotile_name)
      end
      @tilemap.map_data = $game_map.data
      @tilemap.priorities = $game_map.priorities
      $game_map.tileset_flag = false
    end
    tileset_update
  end
end
 

Zeriab

Sponsor

If it is only here and there you need it which in other words mean fairly evenly spread out through the map and you won't have to many visible at the same time you could consider using my Anti Event Lag System. That is the case where it makes the biggest difference.
It's easier than having to store changes for each map since I guess you want the changes to be persistant. I.e. if you go to another map and back you want the changes to still be present.
Otherwise you would have to store the changes for each map in the save file which will increase the size of it as well as the memory usage of the game. (The memory usage may not be significant. I do not know)

*hugs*
- Zeriab
 
You can try changing the exact tile (as you would in the editor).

Try this:
Code:
#==============================================================================
# ** Change Map Data
#------------------------------------------------------------------------------
#  SephirothSpawn
#  Version 0.2
#  2008-12-09
#==============================================================================

class Game_Map
  alias_method :seph_changemapdata_gmmap_data, :data
  def data
    d = seph_changemapdata_gmmap_data
    if changed_data.has_key?(@map_id)
      changed_data[@map_id].each do |xyz, tile_id|
        x, y, z = *xyz
        d[x, y, z] = tile_id
      end
    end
    self.data = d
  end
  def data=(data)
    @map.data = data
  end
  def changed_data
    @changed_data = {} if @changed_data == nil
    return @changed_data
  end
  def change_tile(x, y, z, tile_id = 0)
    @changed_data = {} if @changed_data == nil
    @changed_data[@map_id] = {} unless @changed_data.has_key?(@map_id)
    @changed_data[@map_id][[x, y, z]] = tile_id
  end
  def clear_changed_data(map_id = 0)
    @changed_data = {} if map_id == 0
    @changed_data[@map_id] = {} if map_id != 0
  end
end

To temporarily change a tile, say 5, 4 on the second layer, you would use:
Code:
$game_map.data[5, 4, 2] = tile_id
When the map changes and you go back the tile will be back to its original form.

To premanetly change a tile, use:
Code:
$game_map.change_tile(x, y, z, tile_id)

To clear these changes, use:
Code:
$game_map.clear_changed_data(map_id)
Replace map_id with the map data you wish to clear or 0 for all maps.



To figure out what tile_id you are looking for you can either:

A) Map a new map with your tileset on it and in the [0, 0] position (1st layer), put your desired tile. Make an event with:
Code:
p $game_map.data[0, 0, 0]
and click on your event in game. That will tell you your tile.

B) Mathematics. Start with 384. For every tile (on your tileset) you go down, add 8 * number down. For every tile you go right, add 8. So for instance, in the basic grassland tileset, the pink flower.

384
2 down = 384 + 8 * 2 = 400
7 right = 400 + 7 = 407

So to change any tile to the flower, your tile_id is 407.

Let me know if you need any help.
 
Thanks for the help! Although it doesn't quite seem to work - the temporary change doesn't do anything while the permanent gives me "Script 'Seph's Map Data Change' line 31:ArgumentError occurred. Wrong number of arguments(4 for 2)"

Did I forget something stupid  :dead:?
 
That was an error on my part for the permanent change. I updated the code in my above post. Just replace your code with that.

As far as temporary goes, what was your script command? It might be a special script you are using but that works fine for me in a blank project.
 
Never mind the temporary, I made a did stupid mistake -_-.

Although the clear command does not do anything - neither with the map id's or 0. Is it supposed to an instantaneous change? (Or did I forget something again.)
 
I just wrote this up, it might be what you're looking for. Put all the tiles involved into one tileset, then make two maps; the orginal map and what the map with the transformed tiles should look like; you don't need to duplicate the events. Insert the following script above main

Code:
#Change Map
#Author: Phoenixia :)
#12/12/08

class Spriteset_Map
  def change_tile(id_n)
    temp = Game_Map.new
    @tilemap.map_data = temp.moddy(id_n)
  end
end

class Game_Map
  attr_accessor   :holder
  
  def setup
    @holder = false
  end
  
  def moddy(map_new)
    @map = load_data(sprintf("Data/Map%03d.rxdata", map_new))
    setup(map_new)
    $game_map.priorities = @priorities
    $game_map.terrain_tags = @terrain_tags
    $game_map.holder = @map.data
    return @map.data
  end
end

class Scene_Map
  def change(mappy)
    @spriteset.change_tile(mappy)
  end
end

Go into Game_Map and overwrite the mehtod named data with,

Code:
def data
    return @map.data if @holder == false
    return @holder
end

To call it, just put
Code:
$scene.change(X)
return true

with X the id of the second map.
Essentially, it just swaps the map graphics and passability stuff from one map to another, but doesn't modify the events etc. The result is instantaneous. Finally, both maps require the same tileset, so if the new tiles are from a diff one, just merge them together into one large set. Hope this is what you wanted:)

*Edit
It just occured to me that the orginal map will be displayed if you leave and come back, this can be gotten around by modifying what map you are taken back to, or by modifying this script a little.
 
This shouldn't change all instances of one tile, unless I did something really wrong(wrote it at work). It should swap maps without modifying events, fogs, etc. In other words, it does not swap the tilesets. Was in a hurry and didn't realize that this was already resolved(sorry). Lastly, did you try it and find that it actually changes all instances? Just curious :)
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top