Mundo Maker
¡Bienvenid@ a Mundo Maker!

¿Quieres aprender todo sobre el RPG Maker?



Regístrate y forma parte de Mundo Maker.

[XP] EMSTA - Lleva el editor de mapas al límite

Ver el tema anterior Ver el tema siguiente Ir abajo

RPG Maker XP [XP] EMSTA - Lleva el editor de mapas al límite

Mensaje por Wecoc el 2018-02-15, 18:57

Me retaron a hacer esta locura y yo a un reto así no puedo decir que no.
Este script hecho entre Eron y yo hace que puedas poner un sprite de un tile o autotile al mapa, más o menos como cuando asignas un tile como gráfico de evento, pero en este caso sin evento alguno.

No afecta a la pasabilidad de ningún modo, pero a parte de eso es como un tile completamente normal. Además en cuanto a la pasabilidad se puede solucionar fácilmente asignando un tile vacío pero no pasable.

Hasta ahí tampoco parece gran cosa, pero ¿qué ventajas tiene esto entonces?

- Más de 3 tiles por coordenada sin tener que usar un evento "vacío" para ello (es decir, menos lag)
- Más de 4 tiles por coordenada; ahora no hay límite
- Más prioridades de tile; ahora ilimado, y también acepta valores negativos
- Más de 7 autotiles por tileset/mapa, solo hay que cargarlo de otro tileset
- [Complejo] Animaciones de batalla aplicadas en esos sprites de tiles o autotiles, entre otras cosas

En el script encontraréis de modo detallado como usar este monstruo.

Código:
#==============================================================================
# ** [XP] Extended Map Sprite Tiles & Autotiles (EMSTA)
#------------------------------------------------------------------------------
# Autores: Wecoc & Eron (créditos opcionales)
# Versión: 1.0
#==============================================================================
# Este script permite insertar sprites de tiles y autotiles en el mapa.
# Se verán como tiles normales, aunque no afectan a la pasabilidad.
# Su ventaja es que se pueden definir tantos como se quiera en una coordenada,
# además pueden sacarse de otro tileset, por lo que se rompe el límite de
# autotiles por mapa. Aún así es algo complicado de usar así que se recomienda
# limitarlo para aquellos casos en los que realmente sea necesario.
#------------------------------------------------------------------------------
# Nota: Al colocar sprites de Tile o Autotile se insertan asignándoles una ID
# concreta, como si se tratara de un evento. Usándola de referencia luego se
# puede controlar diretamente ese sprite concreto, por ejemplo para borrarlo.
#------------------------------------------------------------------------------
# 1) Definir un sprite de tile en el mapa:
# $game_map.set_sprite_tile(x, y, tile_id)
# $game_map.set_sprite_tile(x, y, tileset_id, tile_id)
# $game_map.set_sprite_tile(x, y, tileset_id, tile_id, z)
#     tile_id - ID del tile a insertar (posición dentro del tileset)
#     tileset_id - ID del tileset (base de datos), si no se define es el actual
#     z - Prioridad del tile, si no se define se usa el asignado en el tileset
# Ejemplo: $game_map.set_sprite_tile(4, 10, 3, 384)
#------------------------------------------------------------------------------
# 2) Definir un sprite de autotile en el mapa:
# $game_map.set_sprite_autotile(x, y, autotile_id, tile_id)
# $game_map.set_sprite_autotile(x, y, tileset_id, autotile_id, tile_id)
# $game_map.set_sprite_autotile(x, y, tileset_id, autotile_id, tile_id, z)
#     autotile_id - ID del autotile a insertar, de 1 a 7
#     tile_id - ID del subtile actual, de 0 a 47
#     tileset_id - ID del tileset (base de datos), si no se define es el actual
#     z - Prioridad del tile, si no se define se usa el asignado en el tileset
# Ejemplo: $game_map.set_sprite_autotile(4, 10, 3, 1, 24)
#------------------------------------------------------------------------------
# 3) Cambiar un autotile del mapa por un sprite de Autotile:
# (usará tile_id y z de el autotile de referencia)
# $game_map.change_autotile_sprite(x, y, layer, autotile_id)
# $game_map.change_autotile_sprite(x, y, layer, tileset_id, autotile_id)
#     layer - Capa del mapa, de 0 a 2
#     Además se pueden añadir dos argumentos extra después del autotile_id:
#       clear_tile_id - ID del tile que se usará para borrar el autotile de ref.
#       clear - Valor true/false según si quieres que quite o no el autotile
#       Por defecto sus valores son 0, true respectivamente
#------------------------------------------------------------------------------
# 4) Cambiar un autotile del mapa por un sprite de Autotile, toda la capa:
# $game_map.change_autotile_layer(autotile, layer, autotile_id)
# $game_map.change_autotile_layer(autotile, layer, tileset_id, autotile_id)
#     autotile - ID del autotile de referencia, de 1 a 7
#     Funciona exactamente como el caso anterior (incluyendo clear) pero
#     asignado en toda una capa entera directamente, en vez de una sola coord.
#==============================================================================
# Preguntas frecuentes:
#
# - ¿Cómo obtener un sprite concreto de Tile o Autotile previamente insertado?
#
# Llamada de script para Tile:
# $game_map.sprite_tiles[ID]
# Llamada de script para Autotile:
# $game_map.sprite_autotiles[ID]
#
# - ¿Cómo obtenerlo si no sé su ID concreta pero sí su coordenada y tile_id?
# Ejemplo hecho con Tile. Cambiar X, Y e TILE_ID por los valores correctos
#
# tiles = $game_map.sprite_tiles.values
# tile = tiles.select do |sprite|
#   sprite[0] == X
#   sprite[1] == Y
#   sprite[3] == TILE_ID
# end[0]
#
# Si tile vale nil es que no había ninguno con esos parámetros
#
# - ¿Cómo obtener su ID concreta (partiendo de lo anterior)?
# id = $game_map.sprite_tiles.key(tile)
#
# - ¿Qué incompatibilidades tiene el script?
# Debería ser compatible con prácticamente todo
#==============================================================================

#==============================================================================
# ** EronAutotileCache
#==============================================================================

module EronAutotileCache
  @@hash = {}
  module_function
  def hash
    @@hash
  end
end

#==============================================================================
# ** Hash
#==============================================================================

class Hash
  def key(value)
    for k in self.keys
      return k if self[k] == value
    end
    return nil
  end
end

#==============================================================================
# ** Game_Map
#==============================================================================

class Game_Map
  #--------------------------------------------------------------------------
  attr_accessor :sprite_tiles, :sprite_autotiles
  #--------------------------------------------------------------------------
  # * Setup
  #--------------------------------------------------------------------------
  alias sprite_tile_setup setup unless $@
  def setup(*args)
    sprite_tile_setup(*args)
    @sprite_tiles = {}
    @sprite_autotiles = {}
  end
  #--------------------------------------------------------------------------
  # * [Interno] Obtener el próximo índice no usado de Tile o Autotile
  #--------------------------------------------------------------------------
  def get_next_sprite_id(hash)
    return 1 if hash.size == 0
    for i in 1..(hash.size + 1)
      return i if hash[i].nil?
    end
  end
  #--------------------------------------------------------------------------
  # * Mostrar un sprite de Tile en el mapa
  #--------------------------------------------------------------------------
  def set_sprite_tile(x, y, *args)
    case args.size
    when 1 # tile_id
      tileset_id = @map.tileset_id
      tile_id = args[0]
      z = nil
    else # tileset_id, tile_id[, z]
      tileset_id = args[0]
      tile_id = args[1]
      z = args[2]
    end
    id = get_next_sprite_id(@sprite_tiles)
    if z == nil
      tileset = $data_tilesets[tileset_id]
      z = tileset.priorities[tile_id]
    end
    return if @sprite_tiles.values.include?([x, y, tileset_id, tile_id, z])
    @sprite_tiles[id] = [x, y, tileset_id, tile_id, z]
    return true
  end
  #--------------------------------------------------------------------------
  # * Mostrar un sprite de Autotile en el mapa
  #--------------------------------------------------------------------------
  def set_sprite_autotile(x, y, *args)
    case args.size
    when 2 # autotile_id, tile_id
      tileset_id = @map.tileset_id
      autotile_id = args[0]
      tile_id = args[1]
    else # tileset_id, autotile_id, tile_id[, z]
      tileset_id = args[0]
      autotile_id = args[1]
      tile_id = args[2]
      z = args[3]
    end
    id = get_next_sprite_id(@sprite_autotiles)
    if z == nil
      tileset = $data_tilesets[tileset_id]
      z = tileset.priorities[autotile_id * 48 + tile_id]
    end
    ary = @sprite_autotiles.values
    return if ary.include?([x, y, tileset_id, autotile_id, tile_id, z])
    @sprite_autotiles[id] = [x, y, tileset_id, autotile_id, tile_id, z]
    return true
  end
  #--------------------------------------------------------------------------
  # * Cambiar un autotile normal del mapa por un sprite de Autotile
  #--------------------------------------------------------------------------
  def change_autotile_sprite(x, y, layer, *args)
    current_autotile = self.data[x, y, layer]
    return if current_autotile == 0 or current_autotile >= 384
    clear = true
    clear_tile = 0
    if args[-1].is_a?(TrueClass) or args[-1].is_a?(FalseClass)
      clear = args.pop
      clear_tile = args.pop
    end
    case args.size
    when 1 # autotile_id
      tileset_id = @map.tileset_id
      autotile_id = args[0]
    else # tileset_id, autotile_id
      tileset_id = args[0]
      autotile_id = args[1]
    end
    tile_id = current_autotile % 48
    z = $data_tilesets[tileset_id].priorities[current_autotile]
    set_sprite_autotile(x, y, tileset_id, autotile_id, tile_id, z)
    self.data[x, y, layer] = clear_tile if clear
  end
  #--------------------------------------------------------------------------
  # * Cambiar un autotile normal del mapa por un sprite de Autotile a lo largo
  # de toda una determinada capa
  #--------------------------------------------------------------------------
  def change_autotile_layer(autotile, layer, *args)
    for iy in 0...self.height
      for ix in 0...self.width
        current = (self.data[ix, iy, layer].to_f / 48).floor
        if current == autotile
          change_autotile_sprite(ix, iy, layer, *args)
        end
      end
    end
  end
end

#==============================================================================
# ** Sprite_Tile
#==============================================================================

class Sprite_Tile < RPG::Sprite
  #--------------------------------------------------------------------------
  attr_accessor :real_x, :real_y, :real_z
  #--------------------------------------------------------------------------
  # * Update
  #--------------------------------------------------------------------------
  def update
    super
    self.x = (@real_x - $game_map.display_x + 3) / 4 + 16
    self.y = (@real_y - $game_map.display_y + 3) / 4 + 32
    self.z = @real_z + (@real_y - $game_map.display_y + 3) / 4 + 32
  end
end

#==============================================================================
# ** Sprite_Autotile
#==============================================================================

class Sprite_Autotile < Sprite_Tile
  #--------------------------------------------------------------------------
  attr_accessor :complete_bitmap, :frame, :frames
  #--------------------------------------------------------------------------
  # * Update
  #--------------------------------------------------------------------------
  def update
    super
    if @frames > 1 && @current_frame != @frame
      @current_frame = @frame
      refresh_bitmap
    end
  end
  #--------------------------------------------------------------------------
  # * Refresh Bitmap
  #--------------------------------------------------------------------------
  def refresh_bitmap
    self.bitmap = Bitmap.new(32, 32)
    self.bitmap.blt(0, 0, @complete_bitmap, Rect.new(@frame * 32, 0, 32, 32))
  end
end

#==============================================================================
# ** Spriteset_Map
#==============================================================================

class Spriteset_Map
  #--------------------------------------------------------------------------
  # * Initialize
  #--------------------------------------------------------------------------
  alias sprite_tile_ini initialize unless $@
  def initialize
    @sprite_tiles = []
    @sprite_autotiles = []
    @sprite_tile_copy = []
    @sprite_autotile_copy = []
    sprite_tile_ini
  end
  #--------------------------------------------------------------------------
  # * Dispose
  #--------------------------------------------------------------------------
  alias sprite_tile_dis dispose unless $@
  def dispose
    sprite_tile_dis
    @sprite_tiles.each {|sprite| sprite.dispose}
    @sprite_autotiles.each {|sprite| sprite.dispose}
  end
  #--------------------------------------------------------------------------
  # * Refresh Sprite Tiles
  #--------------------------------------------------------------------------
  def refresh_sprite_tiles
    @sprite_tiles.clear
    for i in $game_map.sprite_tiles.keys
      tile = $game_map.sprite_tiles[i]
      sprite = Sprite_Tile.new(@viewport1)
      sprite.real_x = tile[0] * 128
      sprite.real_y = tile[1] * 128
      sprite.ox = 16
      sprite.oy = 32
      tileset = $data_tilesets[tile[2]]
      sprite.bitmap = RPG::Cache.tile(tileset.tileset_name, tile[3], 0)
      sprite.real_z = tile[4] * 32
      @sprite_tiles.push(sprite)
    end
  end
  #--------------------------------------------------------------------------
  DECONSTRUCT_AUTOTILE_PARTS =
    [27, 28,  5, 28, 27,  6,  5,  6, 27, 28,  5, 28, 27,  6,  5,  6,
     33, 34, 33, 34, 33, 34, 33, 34, 33, 12, 33, 12, 33, 12, 33, 12,
     27, 28,  5, 28, 27,  6,  5,  6, 27, 28,  5, 28, 27,  6,  5,  6,
     11, 34, 11, 34, 11, 34, 11, 34, 11, 12, 11, 12, 11, 12, 11, 12,
     25, 26, 25,  6, 25, 26, 25,  6, 15, 16, 15, 16, 15, 16, 15, 16,
     31, 32, 31, 32, 31, 12, 31, 12, 21, 22, 21, 12, 11, 22, 11, 12,
     29, 30, 29, 30,  5, 30,  5, 30, 39, 40,  5, 40, 39,  6,  5,  6,
     35, 36, 11, 36, 35, 36, 11, 36, 45, 46, 45, 46, 45, 46, 45, 46,
     25, 30, 15, 16, 13, 14, 13, 14, 17, 18, 17, 18, 41, 42,  5, 42,
     31, 36, 45, 46, 19, 20, 19, 12, 23, 24, 11, 24, 47, 48, 47, 48,
     37, 38, 37,  6, 13, 18, 13, 14, 37, 42, 17, 18, 13, 18,  1,  2,
     43, 44, 43, 44, 19, 24, 43, 44, 43, 48, 47, 48, 43, 48,  7,  8]
  #--------------------------------------------------------------------------
  # * Refresh Sprite Autotiles
  #--------------------------------------------------------------------------
  def refresh_sprite_autotiles
    @sprite_autotiles.clear
    for i in $game_map.sprite_autotiles.keys
      autotile = $game_map.sprite_autotiles[i]
      sprite = Sprite_Autotile.new(@viewport1)
      sprite.real_x = autotile[0] * 128
      sprite.real_y = autotile[1] * 128
      sprite.ox = 16
      sprite.oy = 32
      sprite.frame = 0
      tileset = $data_tilesets[autotile[2]]
      autotile_name = tileset.autotile_names[autotile[3] - 1]
      bitmap = RPG::Cache.autotile(autotile_name)
      case bitmap.height
      when 32
        sprite.complete_bitmap = bitmap
        sprite.frames = bitmap.width / 32
      when 128
        frames = [bitmap.width / 96, 1].max
        if EronAutotileCache.hash.include?(autotile_name)
          result = EronAutotileCache.hash[autotile_name]
        else
          result = Bitmap.new(256, 192 * frames)
          deconstruct_autotile(bitmap, result, frames)
          EronAutotileCache.hash[autotile_name] = result
        end
        bitmap = Bitmap.new(32 * frames, 32)
        for f in 0...frames
          ix = (autotile[4] % 8) * 32
          iy = ((autotile[4].to_f / 8).floor) * 32
          bitmap.blt(f * 32, 0, result, Rect.new(ix, iy + 192 * f, 32, 32))
        end
        sprite.complete_bitmap = bitmap
        sprite.frames = frames
      end
      sprite.bitmap = sprite.complete_bitmap if sprite.frames == 1
      sprite.real_z = autotile[5] * 32
      @sprite_autotiles.push(sprite)
    end
  end
  #--------------------------------------------------------------------------
  # * [Interno] Deconstruct Autotile
  #--------------------------------------------------------------------------
  def deconstruct_autotile(image, result, frames)
    t = DECONSTRUCT_AUTOTILE_PARTS
    for f in 0...frames
      fx = 96 * f
      fy = 192 * f
      bitmaps = [nil]
      for iy in 0...8
        for ix in 0...6
          bitmap = Bitmap.new(16, 16)
          bitmap.blt(0, 0, image, Rect.new(fx + 16 * ix, 16 * iy, 16, 16))
          bitmaps << bitmap
        end
      end
      for iy in 0...12
        for ix in 0...16
          index = ix + iy * 16
          bitmap = bitmaps[t[index]]
          result.blt(ix * 16, fy + iy * 16, bitmap, bitmap.rect)
        end
      end
    end
    return result
  end
  #--------------------------------------------------------------------------
  # * Update
  #--------------------------------------------------------------------------
  alias sprite_tile_upd update unless $@
  def update
    if @sprite_tile_copy != $game_map.sprite_tiles
      @sprite_tile_copy = $game_map.sprite_tiles.clone
      refresh_sprite_tiles
    end
    if @sprite_autotile_copy != $game_map.sprite_autotiles
      @sprite_autotile_copy = $game_map.sprite_autotiles.clone
      refresh_sprite_autotiles
    end
    @autotile_frame = 0 if @autotile_frame.nil?
    @autotile_frame += 1
    if @autotile_frame % 16 == 0
      @sprite_autotiles.each do |sprite|
        sprite.frame = (@autotile_frame / 16) % sprite.frames
      end
    end
    for sprite in @sprite_tiles + @sprite_autotiles
      sprite.update
    end
    sprite_tile_upd
  end
end

Cualquier duda la posteáis aquí.
avatar
Wecoc
Administrador
Administrador



Créditos 12208

Gracias : 632

Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba


Permisos de este foro:
No puedes responder a temas en este foro.