Created
June 6, 2022 00:20
-
-
Save masked-rpgmaker/d2f86dc3b07acd42ddde13770b190f1d to your computer and use it in GitHub Desktop.
Script de sequência de combo para RPG Maker VX Ace.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#============================================================================== | |
# 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