Últimos temas
» (DEMO) "¿Quién es el cazador?" [XP]
por Fiquei Ayer a las 2:23 pm

» Heroe Retirado
por Fiquei Ayer a las 2:20 pm

» ¿Cómo hago que un NPC huya del jugador?
por MCarlos15 Jue Jul 19, 2018 9:24 pm

» Trampas a gogó (2ª Parte
por fran0090 Jue Jul 19, 2018 7:43 pm

» Suceso extraño con eventos en proceso automático
por Fiquei Jue Jul 19, 2018 6:05 pm

» El juego del foro volvió en forma de fichas NUEVOS 1
por luistop12 Jue Jul 19, 2018 5:55 am

» [Juego completo] Heroes del Crimen - Jetopia
por Doble D Jue Jul 19, 2018 3:14 am

» Trampas a gogó (1ª Parte)
por fran0090 Dom Jul 15, 2018 4:33 am

» Un Scripts de Celular
por Keilu Lopez Dom Jul 15, 2018 12:34 am

» Plugins y usos comerciales
por Muzgar Sáb Jul 14, 2018 1:14 pm

» [XP] Descent: Journeys in the Dark
por Fiquei Vie Jul 13, 2018 12:30 pm

» [VNMaker] Without You (DEMO!)
por JapoZero Vie Jul 13, 2018 7:58 am


[Vx Ace] Theo-Insane Anti Lag (versión 1.1)

Ir abajo

[Vx Ace] Theo-Insane Anti Lag (versión 1.1)

Mensaje por GameMaster el Lun Mayo 25, 2015 1:23 pm

Bueno Bueno, no he tardado ni 5s en postearlo despues de haberlo testeado personalmente.
Es simplemente maravilloso, Hace bastante que llevo teniendo problemas de Lag en TBM y este script me lo ha solucionado completamente.



Aquí os dejo el script:

Código:

   #===============================================================================
# TheoAllen - Insane Anti Lag
# Version : 1.1
# Language : English
#-------------------------------------------------------------------------------
# With help from following people :
# - Tsukihime
# - KilloZapit
# - Galv
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Contact :
#-------------------------------------------------------------------------------
# *> http://www.rpgmakerid.com
# *> http://www.rpgmakervxace.net
# *> http://www.theolized.com
#===============================================================================
($imported ||= {})[:Theo_AntiLag] = true
#===============================================================================
# Change Logs:
# ------------------------------------------------------------------------------
# 2015.02.20 - Added page check enhancer to work with parallel process
# 2015.01.25 - Compatibility with Shaz's Mouse Script. def events_xy now should
#              always return array,
#            - Avoid error 'undefined method delete_sprite for nilClass'
# 2015.01.01 - Avoid unexpected error 'undefined method spriteset for scene'
# 2014.12.05 - Finished
#===============================================================================
=begin

  ------------------------------------------
  *) Introduction :
  ------------------------------------------
  As most of you already know, lag is common problem in RPG Maker games. You may
  started to think it was because you have many events on map. And so, to avoid
  lag, you split your map into part and limiting the event as well.
 
  It's not entirely wrong because when you have a lot of events, program need
  to checks all events. However, it wasn't done efficienly. This script
  increase the efficiency on how default script works and prevent unecessary
  update when it's not needed to gain speed.
    
  However, I can not guarantee that it will have high compatibility since I
  overwrite most of stuff. I will likely to make compatibility with my own
  scripts. But I'm not sure about someone's script.
  
  ------------------------------------------
  *) How to use :
  ------------------------------------------
  Put this script below material but above main. And it's recommended to put
  this above most of custom script.
  
  Set the type of optimization that you like in config
  You may disable some kind of optimization if you have compatibility issues
  
  ------------------------------------------
  *) Terms of use :
  ------------------------------------------
  Credit me, TheoAllen. You are free to edit this script by your own. As long
  as you don't claim it's yours. For commercial purpose, don't forget to give me
  a free copy of the game.
  
  Additional people to put in credit credit list are listed in header above.
  You should give them a free copy of your game as well if it's commercial ;)
  
=end
#==============================================================================
# Configurations :
#==============================================================================
module Theo
  module AntiLag
    
  #=============================================================================
  # *) Normal optimization
  #-----------------------------------------------------------------------------
  # This kind of optimization is for normal usage. These optimization may works
  # only if the total events on map is around 200 - 300.
  #=============================================================================
  
  #-----------------------------------------------------------------------------
    Optimize_XY     = true
  #-----------------------------------------------------------------------------
  # By default, event position checking is to check ALL the events on the map.
  # If you want to check an event is in x,y position, it ask EVERY event if
  # their position is match. By using this optimization, all events registered
  # to the map table so that the engine won't check all events on map. Instead,
  # it checks if there's event on a certain table.
  #
  # This kind of optimization is recommended to set it to true. However, it may
  # not compatible with any pixel movement since they using box collider instead
  # of using grid.
  #-----------------------------------------------------------------------------
  
  #-----------------------------------------------------------------------------
    Optimize_Event  = true
  #-----------------------------------------------------------------------------
  # By default, if the engine want to check if there's event starting, they
  # checked ALL the events on map. They did it in every frame. If you have 200
  # events in map, they checked 60 x 200 events per second.
  #
  # By using this optimization, if event is triggered, it will be registered
  # into a record. And then engine checked if there is event on the record
  #-----------------------------------------------------------------------------
  
  #-----------------------------------------------------------------------------
    Optimize_Sprite = true
  #-----------------------------------------------------------------------------
  # By default, the engine still update every sprites which located off screen.
  # This might waste the time since updating it is not necessary sometimes. By
  # using this optimization, it ignores character sprite that already off screen
  #-----------------------------------------------------------------------------
    
  #=============================================================================
  # *) Insane optimization
  #-----------------------------------------------------------------------------
  # This kind of optimization is to overcome the problem of using event beyond
  # 230 on the map which normal optimization is failed to do. This optimization
  # uses insane algorithm like table search and dispose any unecessary sprite on
  # the fly.
  #=============================================================================
    
  #-----------------------------------------------------------------------------
    Table_Limit_Search = 230
  #-----------------------------------------------------------------------------
  # Table search is a custom algorithm to grab events based on the map table.
  # Instead of iterating all events and checked them if they're on the screen,
  # it checked the visible map table instead. So, event that located far away
  # from the player won't be updated. But any parallel process or autorun events
  # or move route for an event will still updated.
  #
  # Table limit search means that if the total of events on map is above the
  # limit, this script will switch event update algorithm to table search. So
  # you will not worrying about having 999 or even 10.000 events on map.
  #
  # Table search required Optimize_XY to set to true.
  #
  # If you don't want to use table search algorithm, just put the parameter
  # to nil.
  #-----------------------------------------------------------------------------
  
  #-----------------------------------------------------------------------------
    Table_Range_Search = 2
  #-----------------------------------------------------------------------------
  # This determine how far table search will perform check. Putting 3 means that
  # it will update the event that located 3 tiles away from the screen.
  #
  # Keep in mind that the longer range search will affect the performance as
  # well. It's recommended to put it between 2 - 4
  #-----------------------------------------------------------------------------
  
  #-----------------------------------------------------------------------------
    Dispose_Sprite  = true
  #-----------------------------------------------------------------------------
  # Sometimes, limiting the events which is being updated is not enough. Sprite
  # objects is still being performace killer. Disposing sprite which is already
  # off screen will greatly affect the performance. This kind of optimization
  # is enabled only if the table search is used.
  #
  # Disposing sprite on the fly might be problematic sometimes. When something
  # wrong happened, you can disable dispose sprite be setting this to false.
  #-----------------------------------------------------------------------------
  
  #-----------------------------------------------------------------------------
    PageCheck_Enchancer = true
  #-----------------------------------------------------------------------------
  # When a lot of events put together in one map, and each has 20 pages, and
  # you have parallel process to change the variable or switches, you will see
  # noticable lag.
  #
  # This kind of enhancer only refresh the visible events on the screen or when
  # the event is on the visible range. So that it prevents to refresh all events
  # This concept is a fool proof to the player since they will never know what
  # is in their visible range
  #
  # However, this may ruin some system since this concept is still experimental.
  #-----------------------------------------------------------------------------
  
  end
end

#===============================================================================
# *) Final note :
#-------------------------------------------------------------------------------
# After all, these are just my attempt to speed up the game. Performance are
# still under influence by many factors. These include but may not limited to
#
# - Your CPU speed
# - Your laptop / PC temperature
# - How much power do you give for your CPU
# - Multi tasking
# - Someone's script
#
# I once used RM in old computer. When I switched to more advanced laptop, I
# saw that 60 FPS is really smooth.
#
# If your CPU seems overheat, turn off your laptop / PC for a while for cooling.
# My laptop was once overheat due to broken fan. When I played my own game I
# got 10 FPS. I made my own antilag and no one of them worked until I realized
# my laptop was overheat.
#
# Power saver mode in laptop may affect performance. Try to go high performance
# instead and let see if the lag gone. Once my friend played my game using power
# saver mode, and he got 15 FPS.
#
# If you have many programs running at same time, it may cause a little lag in
# RPG Maker games. Something like the screen won't be updated for a while.
#
# Some scripts can affect performance if it's not done right. This antilag
# script is tested using default script without additional scripts which
# directly affect something on map.
#
#-------------------------------------------------------------------------------
# *) Below this line is sacred place to visit. Unless you have enough skill,
# do not try to enter or any risk is yours.
#===============================================================================

#===============================================================================
# ** MapTable
#-------------------------------------------------------------------------------
#  This class used to register the event into 2D table to increase performance
#===============================================================================

class MapTable
  #-----------------------------------------------------------------------------
  # * Initialize
  #-----------------------------------------------------------------------------
  def initialize
    @table = []
    ($game_map.width + 1).times do |x|
      @table[x] = []
      ($game_map.height + 1).times do |y|
        @table[x][y] = []
      end
    end
  end
  #-----------------------------------------------------------------------------
  # * Set value
  #-----------------------------------------------------------------------------
  def set(x,y,val)
    @table[x][y] << val
  end
  #-----------------------------------------------------------------------------
  # * Get array
  #-----------------------------------------------------------------------------
  def get(x,y)
    @table[x][y]
  end
  
end

#===============================================================================
# ** Array
#===============================================================================

class Array
  
  # Just a fool proof
  def values
    return self
  end
  
end

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

class Game_Map
  #-----------------------------------------------------------------------------
  # * Public attributes
  #-----------------------------------------------------------------------------
  attr_accessor :event_redirect     # Redirect events
  attr_reader :forced_update_events # To keep force move route updated
  attr_reader :keep_update_events   # To keep parallel process updated
  attr_reader :cached_events        # To store event that need to be updated
  attr_reader :starting_events      # To store activated event
  attr_reader :table                # 2D Map table
  #-----------------------------------------------------------------------------
  # * Constant
  #-----------------------------------------------------------------------------
  EVENT_LIMIT = Theo::AntiLag::Table_Limit_Search
  RANGE = Theo::AntiLag::Table_Range_Search
  #-----------------------------------------------------------------------------
  # * Alias method : Setup Events
  #-----------------------------------------------------------------------------
  alias theo_antilag_setup_events setup_events
  def setup_events
    @table = MapTable.new
    @forced_update_events = []
    @keep_update_events = []
    @starting_events = []
    @refreshed_events = []
    theo_antilag_setup_events
    select_on_screen_events
  end
  #-----------------------------------------------------------------------------
  # * Overwrite method : Events
  #-----------------------------------------------------------------------------
  def events
    @event_redirect ? @cached_events : @events
  end
#///////////////////////////////////////////////////////////////////////////////
  if Theo::AntiLag::Optimize_XY
#///////////////////////////////////////////////////////////////////////////////
  #-----------------------------------------------------------------------------
  # * Overwrite method : Event XY
  #-----------------------------------------------------------------------------
  def events_xy(x, y)
    @table.get(x,y) || []
  end
  #-----------------------------------------------------------------------------
  # * Overwrite method : Event XY nt
  #-----------------------------------------------------------------------------
  def events_xy_nt(x, y)
    @table.get(x,y).select do |event|
      event.pos_nt?(x, y)
    end
  end
#///////////////////////////////////////////////////////////////////////////////
  end
#///////////////////////////////////////////////////////////////////////////////
  if Theo::AntiLag::Optimize_Event
#///////////////////////////////////////////////////////////////////////////////
  #-----------------------------------------------------------------------------
  # * Overwrite method : Setup starting event
  #-----------------------------------------------------------------------------
  def setup_starting_map_event
    event = @starting_events[0]
    event.clear_starting_flag if event
    @interpreter.setup(event.list, event.id) if event
    event
  end
  #-----------------------------------------------------------------------------
  # * Overwrite method : Any event starting?
  #-----------------------------------------------------------------------------
  def any_event_starting?
    !@starting_events.empty?
  end
#///////////////////////////////////////////////////////////////////////////////
  end
#///////////////////////////////////////////////////////////////////////////////
  #-----------------------------------------------------------------------------
  # * Overwrite method : Refresh
  #-----------------------------------------------------------------------------
  def refresh
    return table_refresh if table_update? && Theo::AntiLag::PageCheck_Enchancer
    @events.each_value {|event| next if event.never_refresh; event.refresh }
    @common_events.each {|event| event.refresh }
    refresh_tile_events
    @need_refresh = false
  end
  #-----------------------------------------------------------------------------
  # * New method : Refresh event by table search
  #-----------------------------------------------------------------------------
  def table_refresh
    @refreshed_events = []
    @tile_events = []
    @common_events.each {|event| event.refresh }
    @need_refresh = false
  end
  #-----------------------------------------------------------------------------
  # * Overwrite method : Update events
  #-----------------------------------------------------------------------------
  def update_events
    last_events = (@cached_events.dup rescue @events.values)
    select_on_screen_events
    events = @cached_events | @keep_update_events | @forced_update_events
    if Theo::AntiLag::Dispose_Sprite
      offscreen_events = last_events - events
      offscreen_events.each {|event| event.delete_sprite}
    end
    events.each {|event| event.update}
    @common_events.each {|event| event.update}
  end
  #-----------------------------------------------------------------------------
  # * New method : Select on screen events
  #-----------------------------------------------------------------------------
  def select_on_screen_events
    unless table_update?
      @cached_events = @events.values
      return
    end
    #---------------------------------------------------------------------------
    # * Table search algorithm
    #---------------------------------------------------------------------------
    new_dpx = display_x.to_i
    new_dpy = display_y.to_i
    dpx = loop_horizontal? ? new_dpx - RANGE : [new_dpx - RANGE, 0].max
    dpy = loop_vertical? ? new_dpy - RANGE : [new_dpy - RANGE, 0].max
    sw = (Graphics.width >> 5) + RANGE * 2
    sh = (Graphics.height >> 5) + RANGE * 2
    @cached_events = []
    sw.times do |x|
      sh.times do |y|
        xpos = loop_horizontal? ? (x + dpx) % width : x + dpx
        ypos = loop_vertical? ? (y + dpy) % height : y + dpy
        next if xpos >= width || ypos >= height
        ary = @table.get(xpos, ypos)
        ary.each do |ev|
          unless @refreshed_events.include?(ev.id)
            ev.refresh
            @tile_events << ev if ev.tile?
            @refreshed_events << ev.id
          end
        end if Theo::AntiLag::PageCheck_Enchancer
        @cached_events += ary
      end
    end
    @cached_events.uniq!
  end
  #-----------------------------------------------------------------------------
  # * Check if table search need to be performed or not
  #-----------------------------------------------------------------------------
  def table_update?
    EVENT_LIMIT && @events.size > EVENT_LIMIT && Theo::AntiLag::Optimize_XY
  end
  
end

#===============================================================================
# ** Game_Temp
#===============================================================================

class Game_Temp
  attr_reader :event_sprites
  #-----------------------------------------------------------------------------
  # * Alias method : Initialize
  #-----------------------------------------------------------------------------
  alias theo_antilag_init initialize
  def initialize
    theo_antilag_init
    @event_sprites = {}
  end
  
end

#===============================================================================
# ** Game_CharacterBase
#===============================================================================

class Game_CharacterBase
  #-----------------------------------------------------------------------------
  # * Empty method : Sprite
  #-----------------------------------------------------------------------------
  def sprite
    return nil
  end
  #-----------------------------------------------------------------------------
  # * Empty method : Sprite =
  #-----------------------------------------------------------------------------
  def sprite=(spr)
  end
  
end

#===============================================================================
# ** Game_Event
#===============================================================================

class Game_Event
  #-----------------------------------------------------------------------------
  # * Never refesh flag
  #-----------------------------------------------------------------------------
  attr_reader :never_refresh
  #-----------------------------------------------------------------------------
  # * Alias method : Initialize
  #-----------------------------------------------------------------------------
  alias theo_antilag_init initialize
  def initialize(map_id, event)
    theo_antilag_init(map_id, event)
    $game_map.table.set(x,y,self)
    @last_x = @x
    @last_y = @y
  end
  #-----------------------------------------------------------------------------
  # * Alias method : Update
  #-----------------------------------------------------------------------------
  alias theo_antilag_update update
  def update
    if (sprite && sprite.disposed?) || sprite.nil?
      spriteset = SceneManager.scene.spriteset
      return unless spriteset
      spriteset.add_sprite(self)
    end
    theo_antilag_update
    if Theo::AntiLag::Optimize_XY && (@last_x != @x || @last_y != @y)
      $game_map.table.get(@last_x, @last_y).delete(self)
      $game_map.table.set(@x,@y,self)
      @last_x = @x
      @last_y = @y
    end
  end
  #-----------------------------------------------------------------------------
  # * Alias method : Start
  #-----------------------------------------------------------------------------
  alias theo_antilag_start start
  def start
    theo_antilag_start
    return unless Theo::AntiLag::Optimize_Event
    $game_map.starting_events << self if @starting
  end
  #-----------------------------------------------------------------------------
  # * Alias method : Clear starting flag
  #-----------------------------------------------------------------------------
  alias theo_antilag_clear_start clear_starting_flag
  def clear_starting_flag
    theo_antilag_clear_start
    return unless Theo::AntiLag::Optimize_Event
    $game_map.starting_events.delete(self)
  end
  #-----------------------------------------------------------------------------
  # * Alias method : Setup page setting
  #-----------------------------------------------------------------------------
  alias theo_antilag_setup_page_settings setup_page_settings
  def setup_page_settings
    theo_antilag_setup_page_settings
    if @event.pages.size == 1 && no_condition?(@event.pages[0].condition)
      @never_refresh = true
    end
    if @trigger == 3 || @interpreter
      $game_map.keep_update_events << self
      $game_map.keep_update_events.uniq!
    else
      $game_map.keep_update_events.delete(self)
    end
  end
  #-----------------------------------------------------------------------------
  # * Check if the events has no page condition
  #-----------------------------------------------------------------------------
  def no_condition?(page)
    !page.switch1_valid && !page.switch2_valid && !page.variable_valid &&
      !page.self_switch_valid && !page.item_valid && !page.actor_valid
  end
  #-----------------------------------------------------------------------------
  # * Delete sprite
  #-----------------------------------------------------------------------------
  def delete_sprite
    sprset = SceneManager.scene.spriteset
    return unless sprset
    SceneManager.scene.spriteset.delete_sprite(sprite)
  end
  #-----------------------------------------------------------------------------
  # * Overwrite method : Force move route
  #-----------------------------------------------------------------------------
  def force_move_route(move_route)
    super
    $game_map.forced_update_events << self
    $game_map.forced_update_events.uniq!
  end
  #-----------------------------------------------------------------------------
  # * Overwrite method : Restore move route
  #-----------------------------------------------------------------------------
  def restore_move_route
    super
    $game_map.forced_update_events.delete(self)
  end
  #-----------------------------------------------------------------------------
  # * Overwrite method : Sprite
  #-----------------------------------------------------------------------------
  def sprite
    $game_temp.event_sprites[@id]
  end
  #-----------------------------------------------------------------------------
  # * Overwrite method : Sprite =
  #-----------------------------------------------------------------------------
  def sprite=(spr)
    $game_temp.event_sprites[@id] = spr
  end
  
end

#===============================================================================
# ** Sprite Character
#===============================================================================

class Sprite_Character
  #-----------------------------------------------------------------------------
  # * Alias method : Initialize
  #-----------------------------------------------------------------------------
  alias theo_antilag_init initialize
  def initialize(viewport, character = nil)
    character.sprite = self if character
    theo_antilag_init(viewport, character)
  end
  #-----------------------------------------------------------------------------
  # * Alias method : Update
  #-----------------------------------------------------------------------------
  alias theo_antilag_update update
  def update
    @sx = @character.screen_x
    @sy = @character.screen_y
    if Theo::AntiLag::Optimize_Sprite && !need_update?
      self.visible = false
      return
    end  
    theo_antilag_update
  end
  #-----------------------------------------------------------------------------
  # * New method : Determine if on screen
  #-----------------------------------------------------------------------------
  def need_update?
    return true if graphic_changed?
    return true if @character.animation_id > 0
    return true if @balloon_sprite
    return true if @character.balloon_id != 0
    w = Graphics.width
    h = Graphics.height
    cw = @cw || 32
    ch = @ch || 32
    @sx.between?(-cw,w+cw) && @sy.between?(0,h+ch)
  end
  #-----------------------------------------------------------------------------
  # * Overwrite update position.
  # To limit screen_x and screen_y to be called many times
  #-----------------------------------------------------------------------------
  def update_position
#    move_animation(@sx - x, @sy - y)
    self.x = @sx
    self.y = @sy
    self.z = @character.screen_z
  end
  #-----------------------------------------------------------------------------
  # * Overwrite animation origin
  # Since X and Y axis of sprite is not updated when off screen
  #-----------------------------------------------------------------------------
  def set_animation_origin
    if @animation.position == 3
      if viewport == nil
        @ani_ox = Graphics.width / 2
        @ani_oy = Graphics.height / 2
      else
        @ani_ox = viewport.rect.width / 2
        @ani_oy = viewport.rect.height / 2
      end
    else
      @ani_ox = @sx - ox + width / 2
      @ani_oy = @sy - oy + height / 2
      if @animation.position == 0
        @ani_oy -= height / 2
      elsif @animation.position == 2
        @ani_oy += height / 2
      end
    end
  end
  
end

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

class Spriteset_Map
  #-----------------------------------------------------------------------------
  # * Alias method : create character
  #-----------------------------------------------------------------------------
  alias theo_antilag_create_characters create_characters
  def create_characters
    $game_map.event_redirect = Theo::AntiLag::Dispose_Sprite
    theo_antilag_create_characters
    $game_map.event_redirect = false
  end
  #-----------------------------------------------------------------------------
  # * New method : delete sprite
  #-----------------------------------------------------------------------------
  def delete_sprite(spr)
    return unless spr
    return if spr.disposed?
    @character_sprites.delete(spr)
    spr.dispose
  end
  #-----------------------------------------------------------------------------
  # * New method : add sprite
  #-----------------------------------------------------------------------------
  def add_sprite(char)
    spr = Sprite_Character.new(@viewport1, char)
    @character_sprites.push(spr)
  end
  
end

#===============================================================================
# ** Scene_Base
#===============================================================================

class Scene_Base
  attr_reader :spriteset
end

Y tambien el post del que he sacado el script por si quereis pasaros o teneis dudas 

Spoiler:
http://www.rpgmakervxace.net/topic/28492-theo-insane-anti-lag-version-11-added-page-check-enhancer/

Creditos a Theo


(He mirado por la sección de scripts si estaba posteado y no lo he visto, en caso de que esté borradme el post :S)

Saludos
avatar
GameMaster
PJ Principal
PJ Principal

Masculino
España
RPG Maker : Ace
Mensajes : 184
Monedas : 1127
Reputación : 18
Localización : En algún lugar del Omniverso

Volver arriba Ir abajo

Re: [Vx Ace] Theo-Insane Anti Lag (versión 1.1)

Mensaje por Turbiosoft.acho el Lun Mayo 25, 2015 2:25 pm

Ya podrían hacer este tipo de scripts para el VX, porque ninguno funciona y si funciona tiene bugs aleatorios xD

Gracias por el aporte, Game. Estoy segura de que le servirá a muchos. Te llevas un +1.

Un saludo

_________________

¡Apoya PCII colocando esta barrita en tu firma!

Turbiosoft.acho apoya a...:






Y a los juegos de Zoro y Japo (?)


avatar
Turbiosoft.acho
Admin
Admin

Femenino
Rmakercom
RPG Maker : Vx
Mensajes : 1218
Monedas : 4291
Reputación : 173
Localización : En el glorioso y magistral Zulo.

Volver arriba Ir abajo

Volver arriba

- Temas similares

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