Skip to content

Instantly share code, notes, and snippets.

@masked-rpgmaker
Created June 6, 2022 00:20
Show Gist options
  • Save masked-rpgmaker/d2f86dc3b07acd42ddde13770b190f1d to your computer and use it in GitHub Desktop.
Save masked-rpgmaker/d2f86dc3b07acd42ddde13770b190f1d to your computer and use it in GitHub Desktop.
Script de sequência de combo para RPG Maker VX Ace.
#==============================================================================
# Combo machine | v1.0.0 | por Brandt
#
# para RPG Maker VX Ace
#------------------------------------------------------------------------------
# Permite a criação de "combos" ativados por ação do jogador no mapa.
#
# Para habilitar ou desabilitar a execução de combos no mapa, use o script
# call:
# $game_system.combo_disabled = false # Combos habilitados (padrão)
# $game_system.combo_disabled = true # Combos desabilitados
#
# Desabilitar o combo interrompe qualquer combo em execução.
#
# Analogamente, para habilitar a janela de sequência de combo:
# $game_system.combo_log_enabled = false # Janela desabilitada (padrão)
# $game_system.combo_log_enabled = true # Janela habilitada
#
# Para interromper o combo do jogador, use o seguinte script:
# $game_combo.reset
#==============================================================================
#==============================================================================
# ** ComboMachine
#------------------------------------------------------------------------------
# Módulo geral do script.
#==============================================================================
module ComboMachine
VERSION = [1, 0, 0]
end
#==============================================================================
# ** ComboMachine::Config
#------------------------------------------------------------------------------
# Módulo de configuração geral do script.
#==============================================================================
module ComboMachine::Config
#--------------------------------------------------------------------------
# * Atraso máximo para considerar um input como parte de um combo em
# progresso (em frames).
#--------------------------------------------------------------------------
MAX_DELAY = 15
#--------------------------------------------------------------------------
# * Intervalo máximo de para considerar um input feito antes do fim de uma
# ação de um combo como parte dele (em frames).
#--------------------------------------------------------------------------
MAX_PREINPUT = 10
#--------------------------------------------------------------------------
# * Definição dos combos.
# A função combo cria um combo com a sequência dada que executa o bloco
# passado.
# O bloco do combo é executado dentro de um contexto de combo (ver
# ComboMachine::ComboContext para referência dos métodos e variáveis
# disponíveis).
#--------------------------------------------------------------------------
def combos
# Meias-luas
quarter_r = [:DOWN, :RIGHT]
quarter_l = [:DOWN, :LEFT]
prepare1 = combo [quarter_r, :X] do
common_event 1
end
prepare2 = combo [prepare1, quarter_l, :X] do
common_event 1
end
# Fire punch
combo [prepare1, :Z] do
wait_for { common_event 2 }
end
# Multiple hits
c1 = combo [prepare2, :Y] do
wait_for { common_event 3 }
end
prepare3 = combo [c1, prepare1] do
common_event 1
end
# Multiple hits+
combo [prepare3, :Y] do
wait_for { common_event 8 }
end
# Slash
c2 = combo [quarter_r, :Y] do
requires { $game_party.leader.wtype_equipped?(4) } # Espada equipada
wait_for { common_event 4 }
end
# Fire slash
combo [c2, :Z] do
requires { $game_party.leader.wtype_equipped?(4) }
# Tem a skill "Fire weapon"
requires { $game_party.leader.skill_learn?($data_skills[76]) }
wait_for { common_event 5 }
end
# Double slash
c3 = combo [c2, quarter_l, :Y] do
requires { $game_party.leader.wtype_equipped?(4) }
wait_for { common_event 6 }
end
# Ouka Mugen jin (a skill maneira de ninja)
combo [c3, quarter_r, :Y] do
requires { $game_party.leader.wtype_equipped?(4) }
wait_for { common_event 7}
end
end
#--------------------------------------------------------------------------
# * Mapa de símbolos de input para texto usado na janela de sequência de
# combo. Aceita as sequências de escape visuais usadas na janela de
# mensagem (\C, \I, \{, \}).
# Caso algum símbolo não seja definido, será mostrado na janela as-is.
#--------------------------------------------------------------------------
LOG_KEY_MAP = {
:LEFT => '←',
:RIGHT => '→',
:UP => '↑',
:DOWN => '↓',
:X => '\I[27]',
:Y => '\I[143]',
:Z => '\I[117]',
:A => 'Shift',
:B => 'X',
:C => 'Z'
}
end
#==============================================================================
# ** ComboMachine::Config::Callbacks
#------------------------------------------------------------------------------
# Módulo de configuração do script. Define callbacks usados em situações
# comuns da execução de combos.
# Todas as funções são executadas dentro do contexto do combo em questão.
#==============================================================================
module ComboMachine::Config::Callbacks
#--------------------------------------------------------------------------
# * Rotina executada quando um combo não é executado por falha de
# pré-requisito (bloco requires).
#--------------------------------------------------------------------------
def on_failed_requirement
Sound.play_buzzer
end
#--------------------------------------------------------------------------
# * Rotina executada quando um combo começa a ser executado.
#--------------------------------------------------------------------------
def on_combo_start
wait 5 # Espera 5 frames antes de começar a execução do combo
end
#--------------------------------------------------------------------------
# * Rotina executada quando um combo é interrompido.
#--------------------------------------------------------------------------
def on_combo_interrupted
Sound.play_cancel
end
#--------------------------------------------------------------------------
# * Rotina executada quando um combo termina de ser executado.
#--------------------------------------------------------------------------
def on_combo_end
# puts "Finished combo: #{combo.sequence}"
RPG::SE.new('Flash1').play # Sinal indicativo para continuar o combo
end
end
#==============================================================================
# ** ComboMachine::Combos
#------------------------------------------------------------------------------
# Este módulo define a função de construção de combos usada nas configurações
# e agrega os combos definidos.
#==============================================================================
module ComboMachine::Combos
extend ComboMachine::Config
#--------------------------------------------------------------------------
# * Estrutura de dados para o combo.
#--------------------------------------------------------------------------
Combo = Struct.new(:sequence, :effect)
class << self
#----------------------------------------------------------------------
# * Obtém a lista de combos definidos no script.
#----------------------------------------------------------------------
def list
@combos = []
combos
@combos
end
#----------------------------------------------------------------------
# * Cria um combo com uma sequência e efeito dados.
#----------------------------------------------------------------------
def combo(sequence, &effect)
raise 'combo sequence must not be empty' if sequence.empty?
raise 'combo must have an effect' if effect.nil?
sequence = sequence.flat_map do |it|
next it.sequence if it.is_a? Combo
next it if it.is_a? Array
next [it]
end
combo = Combo.new(sequence, effect)
@combos << combo
combo
end
end
end
#==============================================================================
# ** ComboMachine::ComboFSM
#------------------------------------------------------------------------------
# Esta classe manipula a lógica de uma FSM de combo.
#==============================================================================
class ComboMachine::ComboFSM
#--------------------------------------------------------------------------
# * Estrutura interna representando um estado da FSM.
#--------------------------------------------------------------------------
TrieNode = Struct.new(:next, :combo) do
#----------------------------------------------------------------------
# * Construtor.
# delta : Mapa de transições para o estado.
# combo : Combo associado ao estado.
#----------------------------------------------------------------------
def initialize(delta = Hash.new, combo = nil)
super
end
end
#--------------------------------------------------------------------------
# * Construtor.
# combos : Lista de combos permitidos pela FSM.
#--------------------------------------------------------------------------
def initialize(combos)
build_trie(combos)
reset
end
#--------------------------------------------------------------------------
# * Constrói a trie de estados para a lista de combos dada.
# combos : Lista de combos permitidos pela FSM.
#--------------------------------------------------------------------------
def build_trie(combos)
@initial_state = TrieNode.new
for combo in combos
node = @initial_state
for sym in combo.sequence
node = node.next[sym] ||= TrieNode.new
end
raise "ambiguous sequence: #{combo.sequence}" unless node.combo.nil?
node.combo = combo
end
end
#--------------------------------------------------------------------------
# * Reinicia a FSM, retornando ao estado inicial.
#--------------------------------------------------------------------------
def reset
@state = @initial_state
end
#--------------------------------------------------------------------------
# * Obtém a lista de inputs aceitáveis para o estado atual.
#--------------------------------------------------------------------------
def acceptable_inputs
@state.next.keys
end
#--------------------------------------------------------------------------
# * Entrega um input à FSM, realizando uma transição de estado.
# input : Input a ser processado pela FSM.
#--------------------------------------------------------------------------
def transition(input)
@state = @state.next[input]
end
#--------------------------------------------------------------------------
# * Obtém o combo associado ao estado atual da FSM.
#--------------------------------------------------------------------------
def combo
@state.combo
end
#--------------------------------------------------------------------------
# * Verifica se a FSM está no estado inicial.
#--------------------------------------------------------------------------
def initial_state?
@state == @initial_state
end
end
#==============================================================================
# ** ComboMachine::ComboContext
#------------------------------------------------------------------------------
# Contexto de execução para um combo. Fornece funções úteis para a definição
# dos efeitos de combo e gerencia a fiber onde o efeito do combo é executado.
#==============================================================================
class ComboMachine::ComboContext
include ComboMachine::Config::Callbacks
#--------------------------------------------------------------------------
# * Atribuitos públicos
#--------------------------------------------------------------------------
attr_reader :character
attr_reader :combo
#--------------------------------------------------------------------------
# * Construtor.
# character : Game_Character executando o combo.
# combo : Combo a ser executado no contexto.
#--------------------------------------------------------------------------
def initialize(character, combo)
@character = character
@combo = combo
@wait = false
create_fiber
end
#--------------------------------------------------------------------------
# * Cria a fiber do combo associado ao contexto.
#--------------------------------------------------------------------------
def create_fiber
@fiber = Fiber.new do
on_combo_start
instance_eval(&@combo.effect)
on_combo_end
Fiber.yield
@fiber = nil
end
end
#--------------------------------------------------------------------------
# * Atualiza a execução do contexto.
#--------------------------------------------------------------------------
def update
@fiber.resume if @fiber != nil
end
#--------------------------------------------------------------------------
# * Verifica se o contexto está ativo (i.e. o combo está sendo executado).
#--------------------------------------------------------------------------
def active?
@fiber != nil
end
#--------------------------------------------------------------------------
# * Verifica se o contexto está executando um trecho que deve ser
# executado até o fim antes de continuar a sequência na FSM.
#--------------------------------------------------------------------------
def wait?
@wait
end
#--------------------------------------------------------------------------
# * Interrompe a execução do combo.
#--------------------------------------------------------------------------
def interrupt
return unless active?
@fiber = nil
on_combo_interrupted
end
#--------------------------------------------------------------------------
# * Tempo de espera.
# duration : duração.
#--------------------------------------------------------------------------
def wait(duration)
duration.times { Fiber.yield }
end
#--------------------------------------------------------------------------
# * Executa um evento comum.
# event_id : Id do evento comum.
#--------------------------------------------------------------------------
def common_event(event_id)
event = $data_common_events[event_id]
if event
interpreter = Game_Interpreter.new(0)
interpreter.setup(event.list, character.id)
interpreter.run
end
end
#--------------------------------------------------------------------------
# * Executa um bloco com espera.
# block : Bloco a ser executado.
#--------------------------------------------------------------------------
def wait_for(&block)
raise 'wait_for requires a block' if block.nil?
@wait = true
yield
@wait = false
end
#--------------------------------------------------------------------------
# * Para a execução do combo.
#--------------------------------------------------------------------------
def halt
@fiber = nil
Fiber.yield
end
#--------------------------------------------------------------------------
# * Verifica uma condição. Se for falsa, não executa o resto do combo.
# block : Bloco condicional.
#--------------------------------------------------------------------------
def requires(&block)
raise 'requires needs a conditional block' if block.nil?
return if block.call
on_failed_requirement
halt
end
end
#==============================================================================
# ** ComboMachine::Game_Combo
#------------------------------------------------------------------------------
# Esta classe gerencia um combo sendo executado por um Game_Character.
#==============================================================================
class ComboMachine::Game_Combo
#--------------------------------------------------------------------------
# * Atributos públicos.
#--------------------------------------------------------------------------
attr_reader :sequence
#--------------------------------------------------------------------------
# * Construtor.
# combos : Lista de combos que podem ser executados.
# character : Game_Character executando o combo.
# input : Interface de entrada.
#--------------------------------------------------------------------------
def initialize(combos, character, input)
@fsm = ComboMachine::ComboFSM.new(combos)
@character = character
@input = input
reset
end
#--------------------------------------------------------------------------
# * Atualização do objeto.
#--------------------------------------------------------------------------
def update
update_input
update_transition
update_timers
update_context
end
#--------------------------------------------------------------------------
# * Atualização da entrada.
#--------------------------------------------------------------------------
def update_input
input = read_input
return if input.nil?
log_input(input)
@buffered_input = input
@preinput_timer = ComboMachine::Config::MAX_PREINPUT
end
#--------------------------------------------------------------------------
# * Registra uma entrada na sequência do combo.
#--------------------------------------------------------------------------
def log_input(input)
if @buffered_input.nil?
@sequence << input
else
@sequence[-1] = input
end
end
#--------------------------------------------------------------------------
# * Atualização da transição de estados.
#--------------------------------------------------------------------------
def update_transition
return unless should_transition?
reset_timers
@fsm.transition(@buffered_input)
combo = @fsm.combo
if combo != nil
@context = ComboMachine::ComboContext.new(@character, combo)
else
@delay_timer = ComboMachine::Config::MAX_DELAY
end
@buffered_input = nil
end
#--------------------------------------------------------------------------
# * Verifica se a FSM deveria realizar uma transição de estado.
#--------------------------------------------------------------------------
def should_transition?
return false if @buffered_input.nil?
return false if @context != nil && @context.wait?
return true
end
#--------------------------------------------------------------------------
# * Atualização dos timers de entrada.
#--------------------------------------------------------------------------
def update_timers
update_delay_timer
update_preinput_timer
end
#--------------------------------------------------------------------------
# * Atualização do timer de entrada atrasada.
#--------------------------------------------------------------------------
def update_delay_timer
return if @delay_timer.zero?
@delay_timer -= 1
reset if @delay_timer.zero?
end
#--------------------------------------------------------------------------
# * Atualização do timer de entrada adiantada.
#--------------------------------------------------------------------------
def update_preinput_timer
return if @preinput_timer.zero?
@preinput_timer -= 1
if @preinput_timer.zero?
@buffered_input = nil
@sequence.pop
end
end
#--------------------------------------------------------------------------
# * Atualização do contexto de execução do combo.
#--------------------------------------------------------------------------
def update_context
return if @context.nil?
@context.update
return if @context.active?
@context = nil
@delay_timer = ComboMachine::Config::MAX_DELAY
end
#--------------------------------------------------------------------------
# * Interrompe e reinicia o estado do combo.
#--------------------------------------------------------------------------
def reset
@fsm.reset
@sequence = []
@context.interrupt unless @context.nil?
@context = nil
@buffered_input = nil
reset_timers
end
#--------------------------------------------------------------------------
# * Reinicia o estado dos timers de entrada do combo.
#--------------------------------------------------------------------------
def reset_timers
@preinput_timer = 0
@delay_timer = 0
end
#--------------------------------------------------------------------------
# * Obtém um input aceitável (que tem transição mapeada na FSM no estado
# atual), ou nil caso não exista.
#--------------------------------------------------------------------------
def read_input
@fsm.acceptable_inputs.find do |key|
@input.trigger?(key)
end
end
end
#==============================================================================
# ** ComboMachine::Window_ComboLog
#------------------------------------------------------------------------------
# Esta classe gerencia um combo sendo executado por um Game_Character.
#==============================================================================
class ComboMachine::Window_ComboLog < Window_Base
#--------------------------------------------------------------------------
# * Construtor.
# combo : ComboMachine::Game_Combo cuja sequência deve ser exibida.
#--------------------------------------------------------------------------
def initialize(combo)
super(0, 0, window_width, window_height)
self.opacity = 0
self.openness = 0
@combo = combo
refresh
end
#--------------------------------------------------------------------------
# * Largura da janela.
#--------------------------------------------------------------------------
def window_width
32 + standard_padding * 2
end
#--------------------------------------------------------------------------
# * Altura da janela.
#--------------------------------------------------------------------------
def window_height
Graphics.height
end
#--------------------------------------------------------------------------
# * Atualização da janela.
#--------------------------------------------------------------------------
def update
super
if $game_system.combo_log_enabled
open
else
close
end
refresh if changed?
end
#--------------------------------------------------------------------------
# * (Re)desenho do conteúdo da janela.
#--------------------------------------------------------------------------
def refresh
@sequence = @combo.sequence.dup
contents.clear
draw_text_ex(0, 0, sequence_text)
end
#--------------------------------------------------------------------------
# * Determina se a sequência do combo foi alterada.
#--------------------------------------------------------------------------
def changed?
@combo.sequence != @sequence
end
#--------------------------------------------------------------------------
# * Texto para a sequência de combo.
#--------------------------------------------------------------------------
def sequence_text
@sequence.last(contents_height / line_height).collect do |key|
ComboMachine::Config::LOG_KEY_MAP[key] || key.to_s
end.join("\n")
end
end
#==============================================================================
# ** DataManager
#------------------------------------------------------------------------------
# Este módulo gerencia o jogo e objetos do banco de dados utilizados no jogo.
# Quase todas as variáveis globais são inicializadas no módulo.
# Alterado para criar a variável $game_combo que gerencia o combo do jogador
# no início do jogo e após o carregamento de um arquivo salvo.
#==============================================================================
class << DataManager
#--------------------------------------------------------------------------
# * Criação dos objetos do jogo
#--------------------------------------------------------------------------
alias combo_machine_create_game_objects create_game_objects
def create_game_objects(*args)
combo_machine_create_game_objects(*args)
create_combo
end
#--------------------------------------------------------------------------
# * Extrair conteúdo salvo
#--------------------------------------------------------------------------
alias combo_machine_extract_save_contents extract_save_contents
def extract_save_contents(*args)
combo_machine_extract_save_contents(*args)
$game_combo = create_combo
end
#--------------------------------------------------------------------------
# * Criação do objeto de combo
#--------------------------------------------------------------------------
def create_combo
combos = ComboMachine::Combos.list
$game_combo = ComboMachine::Game_Combo.new(combos, $game_player, Input)
end
end
#==============================================================================
# ** Game_System
#------------------------------------------------------------------------------
# Esta classe gerencia os dados relacionados ao sistema. Também gerencia
# veículos, BGM, etc.
# Alterada para incluir atributos de configuração do combo.
#==============================================================================
class Game_System
#--------------------------------------------------------------------------
# * Atributos públicos.
#--------------------------------------------------------------------------
attr_accessor :combo_log_enabled # Log de combo habilitado
attr_reader :combo_disabled # Combo desabilitado
#--------------------------------------------------------------------------
# * Inicialização do objeto
#--------------------------------------------------------------------------
alias combo_machine_initialize initialize
def initialize
combo_machine_initialize
@combo_disabled = false
@combo_log_enabled = false
end
#--------------------------------------------------------------------------
# * Define se o combo do jogador está desabilitado.
#--------------------------------------------------------------------------
def combo_disabled=(disabled)
$game_combo.reset if disabled
@combo_disabled = disabled
end
end
#==============================================================================
# ** Scene_Map
#------------------------------------------------------------------------------
# Esta classe executa o processamento da tela de mapa.
# Alterada para incluir a janela de sequência do combo e atualizar o objeto de
# combo.
#==============================================================================
class Scene_Map < Scene_Base
#--------------------------------------------------------------------------
# * Criação de todas as janelas
#--------------------------------------------------------------------------
alias combo_machine_create_all_windows create_all_windows
def create_all_windows
combo_machine_create_all_windows
create_combo_log_window
end
#--------------------------------------------------------------------------
# * Criação da janela de log de combo.
#--------------------------------------------------------------------------
def create_combo_log_window
@combo_log_window = ComboMachine::Window_ComboLog.new($game_combo)
end
#--------------------------------------------------------------------------
# * Atualização da tela
#--------------------------------------------------------------------------
alias combo_machine_update update
def update
combo_machine_update
$game_combo.update unless $game_system.combo_disabled
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment