class Scene_Map < Scene_Base
attr_accessor :geo_manager

alias geo_start start
def start
geo_start
@geo_manager = Geo_Effects.new(@viewport)
end

alias geo_update update
def update
geo_update
@geo_manager.update
end
end

class Geo_Effects
#************************************************************************
# Internal array of colors
# 0: Clear. Shows up as a white Geo Symbol. When broken, this "symbol
# color" will remove panels instead of changing their colors.
# 1: Red
# 2: Green
# 3: Blue
#************************************************************************
@@colors =
@@colors.push(Color.new(255, 255, 255)) # clear
@@colors.push(Color.new(255, 0, 0)) # red
@@colors.push(Color.new(0, 255, 0)) # green
@@colors.push(Color.new(0, 0, 255)) # blue
@@colors.push(Color.new(255, 255, 0)) # yellow
@@colors.push(Color.new(255, 0, 255)) # purple
@@colors.push(Color.new(0, 255, 255)) # cyan


#==================================================================
# PRIVATE
# Internal methods for the class to use. Do not call directly
#==================================================================
def initialize(viewport)
self.clear
@overlay = Plane.new(viewport)
@overlay.bitmap = Bitmap.new(viewport.rect.width, viewport.rect.height)
@overlay.z = 0
end

def _find_color(color)
return @grid.dup.keep_if { |pos, aColor| aColor == color}.keys
end

def _angle(y, x)
result = Math.atan2(y, x) - (Math::PI / 4)
return result if result > -Math::PI else result + Math::PI * 2
end

def _trigger(x, y, color)
val = @grid[ ]
if (val.nil?) || (val == color) then
@square_list =
@trigger_color = 0
@onBoardClear.Call() if grid.empty? && !@onBoardClear.nil?
@onChainFinished.Call() if !@onChainFinished.nil?
return
end
@square_list = _find_color(val)
@square_list.sort! { |a, b|
axDist = a - x
ayDist = a - y
bxDist = b - x
byDist = b - y

aDist = .max
bDist = .max
if aDist != bDist
next aDist - bDist
else
next _angle(ayDist, axDist) - _angle(byDist, bxDist)
end
}
@trigger_color = color
@counter = 0
end

def _dequeue
value = @change_queue.shift
return if value.nil?
_trigger(value, value, value)
end

def _flip
return if @square_list.empty? && @change_queue.empty?
@cooldown -= 1
return if @cooldown > 0
pos = @square_list.shift
if pos.nil? then
_dequeue
return
end
if @trigger_color == 0 then
@grid.delete(pos)
else
@grid = @trigger_color
end
geo_break(pos, pos) if @symbols.has_key?(pos)
@counter += 1
@cooldown = .max
@onChangePanel.Call(pos, pos) if !@onChangePanel.nil?
end

#==================================================================
# INTERNAL
# Special method that should only be called by the scene's Update
# method, as above. Do not call directly.
#==================================================================
def update
scene = SceneManager.scene
return unless scene.is_a?(Scene_Map)
_flip

dx = $game_map.display_x * 32
dy = $game_map.display_y * 32
view = @overlay.viewport
bmp = @overlay.bitmap
bmp.clear
@grid.each {|key, value|
x = (key * 32) - dx
y = (key * 32) - dy
clr = Color.new
clr.set(@@colors)
clr.alpha = @intensity
bmp.fill_rect(x, y, 32, 32, clr)
}

@symbols.each {|key, value|
x = ((key * 32) - dx) + 4
y = ((key * 32) - dy) + 4
clr = Color.new
clr.set(@@colors)
clr.alpha = 255
bmp.fill_rect(x, y, 24, 24, clr)
}

if @intensity_asc then
if @intensity >= 200 then
@intensity_asc = false
else
@intensity += 3
end
else
if @intensity <= 40 then
@intensity_asc = true
else
@intensity -= 3
end
end
end

#==================================================================
# PUBLIC
# External API to the Geo_Effects class.
#==================================================================

#************************************************************************
# Adds a single Geo Panel at map location (x, y), of the color specified
#************************************************************************
def add_color(x, y, color)
@grid[ ] = color
end

#************************************************************************
# Adds a single Geo Symbol at map location (x, y), of the color specified
#************************************************************************
def add_symbol(x, y, color)
@symbols[ ] = color
end

#************************************************************************
# Breaks a Geo Symbol at (x, y) if one exists, setting off a Geo Break
# effect and changing colors if the symbol was on a panel of a different
# color.
#************************************************************************
def geo_break(x, y)
color = @symbols[ ]
return if color.nil?
@change_queue.push()
@symbols.delete()
@onBeginRound.Call() if !@onBeginRound.nil?
end

#************************************************************************
# Resets the Geo_Effects manager, clearing all panels and symbols
#************************************************************************
def clear
@grid = {}
@symbols = {}
@intensity = 40
@intensity_asc = true
@change_queue =
@square_list =
@trigger_color = 0
@cooldown = 0
@counter = 0
@onChangePanel = nil
@onBeginRound = nil
@onChainFinished = nil
@onBoardClear = nil
end

#************************************************************************
# Allows you to set a callback that will fire every time a Geo Panel's
# color is changed.
#
# The callback must take two arguments: (x, y)
#************************************************************************
def set_onChangePanel(&handler)
if handler.nil? then
@onChangePanel = nil
else
return if handler.arity < 2
@onChangePanel = handler
end
end

#************************************************************************
# Allows you to set a callback that will fire every time a new Geo Break
# round begins, either by breaking a block or as part of a chain reaction
#
# No arguments are needed
#************************************************************************
def set_onBeginRound(&handler)
@onBeginRound = handler
end

#************************************************************************
# Allows you to set a callback that will fire when a Geo Break chain
# ends.
#
# No arguments are needed
#************************************************************************
def set_onChainFinished(&handler)
@onChainFinished = handler
end

#************************************************************************
# Allows you to set a callback that will fire when a Geo Break effect
# clears the board completely, by deleting all Geo Panels.
#
# No arguments are needed
#************************************************************************
def set_onBoardClear(&handler)
@onBoardClear = handler
end
end