StCooler
Mayst thou thy peace discover.
- 9,892
- Posts
- 5
- Years
- Seen today
Hello people of PokéCommunity,
I am releasing one of my scripts, as is, to help fangame developpers debug their games.
The most important functions are the following two:
The script:
Credits:
These scripts are made by me and only me. As always, I don't care about credits, so do as you wish. The credits are included in the script, though.
You are free to use and modify this script as you wish.
I am releasing one of my scripts, as is, to help fangame developpers debug their games.
The most important functions are the following two:
scLog(d)
which logs the inputd
into a file "errorlog.txt". Why is it useful? It's because, ifd
is an array (a list) or a hash (a dictionary), then the content will also be logged. This allows for an almost-readable logging of nested dictionaries or arrays.scSearchMenu()
lets you search some dialogues, scripts, map transfers, switches and variables into ALL of your events. It will log the results into "errorlog.txt", at the root of your project (in the same place as your Game.exe).- Then, the functions
scSearchDialogue()
,scSearchInScripts()
,scSearchSwitches()
,scSearchVariables()
,scSearchMapTransfers()
can be used individually so you can search and replace. Don't worry, a backup is automatically made!
- Copy/paste this script into one of the files above "Main".
- Put all the map IDs of the maps you want to search into
MAPS_OF_INTEREST
.MAPS_OF_INTEREST
should look likeMAPS_OF_INTEREST = [12, 26, 35, 36, 37]
, where the numbers[12, 26, 35, 36, 37]
are the IDs of the maps of your game, that you can find at the bottom right of RPG Maker XP when you're displaying that map.
scLog(d)
is meant to be use anywhere you need in your code to check the content of your variables.def scSearchMenu()
is meant to be put in an event. Then, talk to the even in game.
The script:
Spoiler:
Ruby:
###############################################################################
# StCooler's debug tools.
#
# This script was made by me (StCooler) when I developed my fangame Pokémon
# Retired Champion. I needed a tool to search scripts, dialogues, switches and
# variables into the events of the game.
###############################################################################
# These are the maps that your game uses. I suggest putting here ALL the IDs
# of the maps that your game uses. Find the IDs at the bottom right of RPG
# Maker XP, to the left of the name of the map. This is mandatory, otherwise
# the search engines will not know where to search.
MAPS_OF_INTEREST = []
#===============================================================================
# The search functions.
# Put this function in a script. The results will be written into "errorlog.txt"
#===============================================================================
# Search through all events of MAPS_OF_INTEREST.
def scSearchMenu()
index_dialogues = -10
index_scripts = -10
index_switches = -10
index_variables = -10
index_map_transfers = -10
commands = []
commands[index_dialogues = commands.length] = _INTL("Dialogues")
commands[index_scripts = commands.length] = _INTL("Scripts")
commands[index_switches = commands.length] = _INTL("Switches")
commands[index_variables = commands.length] = _INTL("Variables")
commands[index_map_transfers = commands.length] = _INTL("Map transfers")
cmd = pbMessage(_INTL("What are you looking for?"), commands)
case cmd
when index_dialogues
scSearchDialogue
when index_scripts
scSearchInScripts
when index_switches
scSearchSwitches
when index_variables
scSearchVariables
when index_map_transfers
scSearchMapTransfers
end
end
#===============================================================================
# Recursive loading tools for arrays and hashes.
#===============================================================================
# Recursively writes the given input "d" into a string.
# If d is a hash or an array, will also recursively write
# its content.
def scToStringRec(d)
if d.is_a?(Array)
s = "[ "
first_item = true
d.each { |val|
s += " ; " if !first_item
s += scToStringRec(val)
first_item = false
}
s += " ]"
return s
elsif d.is_a?(Hash)
s = "{"
# put_comma = false
d.each { |k,v|
temp = scToStringRec(v)
# s += ", " if put_comma
s += _INTL("{1} => {2}", k, temp)
s += "\n"
# put_comma = true
}
s += "}\n"
return s
elsif d.is_a?(PokeBattle_Trainer)
s = _INTL("[Trainer] {1} with ", d.fullname)
first_poke = true
d.party.each { |poke|
s += ", " if !first_poke
s += poke.speciesName
first_poke = false
}
return s
# You can add more classes to handle here.
else
return _INTL("{1}", d)
end
end
# Recursively writes the given input "d" into the given file.
# Title is optional if you want to keep your file clean.
# Set "silent" to false to get a message when the data is written.
def scToString(d, title = nil, filename = "errorlog.txt", silent = false)
File.open(filename, "a") { |f|
f.write(title + "\n") if title.is_a?(String)
f.write(scToStringRec(d) + "\n")
}
pbMessage("Done") if !silent
end
# Shortcut for scToString.
def scLog(d, title = nil)
scToString(d, title, "errorlog.txt", true)
end
#===============================================================================
# This is the base class for the search engine.
#===============================================================================
class SCSearchEngine
SearchInDialogues = 1
SearchInScripts = 2
def initialize(command_codes)
@codes = command_codes
@codes = [command_codes] if [email protected]_a?(Array)
@maps_of_interest = MAPS_OF_INTEREST.clone
end
def addResult(res, key_id, content)
res = {} if !res
res[key_id] = content
return res
end
def addResultArray(res, key_id, content)
# res[key_id] is an array.
res = {} if !res
res[key_id] = [] if !res[key_id]
res[key_id].push(content)
return res
end
def searchInEvent(search, event, map_id, replacement = nil)
res = nil
# res : page number -> list of strings.
event.pages.each_with_index { |page, p|
page.list.each_with_index { |command, c|
next if [email protected]?(command.code)
next if !command.parameters[0].is_a?(String)
if command.parameters[0].include?(search)
res = self.addResultArray(res, p+1, command.parameters[0])
if replacement && replacement.is_a?(String)
command.parameters[0].sub!(search, replacement)
end
end
}
}
return res
end
def searchInMap(search, map_id, replacement = nil)
res = nil
original_file = sprintf("Data/Map%03d.%s",map_id,($RPGVX) ? "rvdata" : "rxdata")
map = load_data(original_file)
unchanged_map = load_data(original_file)
# Note: the events here are not Game_Event but RPG::Event.
map.events.each { |id, event|
next if map_id == 33 && event.id == 11 # DEBUG
res_event = self.searchInEvent(search, event, map_id, replacement)
next if !res_event
res = self.addResult(res, _INTL("ID:{1} ; x={2} ; y={3}", event.id, event.x, event.y), res_event)
res["MAP"] = pbGetMessage(MessageTypes::MapNames,map_id) if !res["MAP"]
}
if replacement && res
num_file = 0
filename = sprintf("Data/Map%03d-%03d.%s",map_id, num_file, ($RPGVX) ? "rvdata" : "rxdata")
while safeExists?(filename)
num_file += 1
filename = sprintf("Data/Map%03d-%03d.%s",map_id, num_file, ($RPGVX) ? "rvdata" : "rxdata")
end
save_data(unchanged_map, filename)
save_data(map, original_file)
end
return res
end
def searchMapsOfInterest(txt, replacement, log_results = true)
res = nil
@maps_of_interest.each { |map_id|
res_map = self.searchInMap(txt, map_id, replacement)
next if !res_map
res = self.addResult(res, map_id, res_map)
}
if !res
pbMessage(_INTL("No result for \"{1}\".", txt))
return
end
log_text = _INTL("Results for search: \"{1}\"\n", txt)
indent_event = " "
indent_message = indent_event + indent_event
total_results = 0
# res.each { |map_id, resmap|
@maps_of_interest.each { |map_id|
resmap = res[map_id]
next if !resmap
s = _INTL("Map: {1}\n", resmap["MAP"])
log_text += s
Win32API.SetWindowText("Searching: " + s)
resmap.each { |event_id, res_event|
next if event_id == "MAP"
log_text += _INTL("Event: {1}\n", event_id)
res_event.each { |page, list_txt|
log_text += indent_event + _INTL("Page {1}: {2} results\n", page, list_txt.length)
total_results += list_txt.length
list_txt.each { |result|
log_text += indent_message + result + "\n"
}
}
}
}
scLog(log_text) if log_results
pbMessage(_INTL("Found {1} results.", total_results))
return log_text
end
end
#===============================================================================
# This is a subclass that looks for a specific text in scripts.
#===============================================================================
class SCSearchEngine_Scripts < SCSearchEngine
def initialize
super([111, 355, 655])
end
def searchInEvent(search, event, map_id, replacement = nil)
res = nil
# res : page number -> list of strings.
event.pages.each_with_index { |page, p|
page.list.each_with_index { |command, c|
next if [email protected]?(command.code)
# next if !command.parameters[0].is_a?(String)
if command.code == 111 && command.parameters[0] == 12
if command.parameters[1].include?(search)
res = self.addResultArray(res, p+1, _INTL("(Conditional Branch) {1}",command.parameters[1]))
if replacement && replacement.is_a?(String)
command.parameters[1].sub!(search, replacement)
end
end
elsif command.parameters[0].is_a?(String) && command.parameters[0].include?(search)
res = self.addResultArray(res, p+1, "(Script) " + command.parameters[0])
if replacement && replacement.is_a?(String)
command.parameters[0].sub!(search, replacement)
end
end
}
}
return res
end
end
#===============================================================================
# For "Control Switches" + scRequireClients + events that trigger with a given
# switch. To know when a switch is triggered.
#===============================================================================
class SCSearchEngine_Switches < SCSearchEngine
def initialize
super([111, 121, 355, 655])
end
def searchInEvent(searched_switch, event, map_id, replacement = nil)
res = nil
# res : page number -> list of strings.
event.pages.each_with_index { |page, p|
if page.condition.switch1_id == searched_switch ||
page.condition.switch2_id == searched_switch
res = self.addResultArray(res, p+1, "(Page condition)")
end
page.list.each_with_index { |command, c|
case command.code
when 121 # Control Switch
if command.parameters[0] == searched_switch ||
command.parameters[1] == searched_switch ||
(command.parameters[0] <= searched_switch &&
command.parameters[1] >= searched_switch)
val = (command.parameters[2] == 0 ? "ON" : "OFF")
res = self.addResultArray(res, p+1, _INTL("(Control Switch) Set to {1}.", val))
end
when 355, 655 # Script
if command.parameters[0][/scRequireClients\w*\(\s*\w+\s*,\s*(\w+)\s*.*\)/]
if $~[1].to_i == searched_switch
res = self.addResultArray(res, p+1, _INTL("(Script) {1}.", command.parameters[0]))
end
end
when 111 # Conditional branch
# Checks a switch
if command.parameters[0] == 0 && command.parameters[1] == searched_switch
res = self.addResultArray(res, p+1, "(Conditional Branch)")
end
end
}
}
return res
end
end
#===============================================================================
# Same principle as before, but for Variables.
#===============================================================================
class SCSearchEngine_Variables < SCSearchEngine
def initialize
super([111, 122, 355, 655])
end
def searchInEvent(searched_var, event, map_id, replacement = nil)
res = nil
# res : page number -> list of strings.
event.pages.each_with_index { |page, p|
if searched_var != 1 && page.condition.variable_id == searched_var
res = self.addResultArray(res, p+1, "(Page condition)")
end
page.list.each_with_index { |command, c|
case command.code
when 122 # Control Variable
if command.parameters[0] == searched_var ||
command.parameters[1] == searched_var ||
(command.parameters[0] <= searched_var &&
command.parameters[1] >= searched_var)
val = command.parameters[4]
res = self.addResultArray(res, p+1, _INTL("(Control Variables) Set to {1}.", val))
end
when 355, 655 # Script
if (command.parameters[0][/\$game_variables\[\s*(\w+)\s*\]/] ||
command.parameters[0][/\\SCVar.set\(\s*(\w+)\s*\,\s*\w+\s*\)/] ||
command.parameters[0][/\\SCVar.get\(\s*(\w+)\s*\)/])
if $~[1].to_i == searched_var
res = self.addResultArray(res, p+1, _INTL("(Script) {1}.", command.parameters[0]))
end
end
when 111 # Conditional branch
# Checks a variable
if command.parameters[0] == 1 && command.parameters[1] == searched_var
res = self.addResultArray(res, p+1, "(Conditional Branch)")
elsif command.parameters[0] == 12
if (command.parameters[1][/\$game_variables\[\s*(\w+)\s*\]/] ||
command.parameters[1][/\\SCVar.set\(\s*(\w+)\s*\,\s*\w+\s*\)/] ||
command.parameters[1][/\\SCVar.get\(\s*(\w+)\s*\)/])
if $~[1].to_i == searched_var
res = self.addResultArray(res, p+1, _INTL("(Conditional Branch) Script: {1}.", command.parameters[1]))
end
end
end
end
}
}
return res
end
end
#===============================================================================
# Map transfers.
#===============================================================================
class SCSearchEngine_MapTransfers < SCSearchEngine
def initialize
super([201, 202])
end
def searchInEvent(searched_map, event, map_id, offset = nil)
res = nil
# res : page number -> list of strings.
event.pages.each_with_index { |page, p|
page.list.each_with_index { |command, c|
case command.code
when 201 # Transfer Player
next if command.parameters[1] != searched_map
# parameters = [0 or 1, map_id, new_x, new_y, new_direction]
res = self.addResultArray(res, p+1, _INTL("(Transfer Player) Mode {1}, map_id={2}, x={3}, y={4}, dir={5}.",
command.parameters[0], command.parameters[1], command.parameters[2], command.parameters[3], command.parameters[4]))
if offset && offset.length == 2
command.parameters[2] += offset[0]
command.parameters[3] += offset[1]
end
when 202 # Set Event Location
next if map_id != searched_map
# parameters = [event, 0 or 1 or 2, new_x, new_y, new_direction]
res = self.addResultArray(res, p+1, _INTL("(Set Event Location) Event {1}, mode {2}, x={3}, y={4}, dir={5}.",
command.parameters[0], command.parameters[1], command.parameters[2], command.parameters[3], command.parameters[4]))
if offset && offset.length == 2
command.parameters[2] += offset[0]
command.parameters[3] += offset[1]
end
end
}
}
return res
end
end
#===============================================================================
# The functions that actually do the search.
#===============================================================================
def scSearchDialogue(search = nil, replacement = nil)
if !search
search = pbMessageFreeText(_INTL("What do you want to search?"),"",false,12)
end
search_engine = SCSearchEngine.new([101, 401])
log_text = search_engine.searchMapsOfInterest(search, replacement)
end
def scSearchInScripts(search = nil, replacement = nil)
loop do
break if search && search.length > 1
search = pbMessageFreeText(_INTL("What do you want to search?"),"",false,20)
if search.length < 2
pbMessage(_INTL("Cannot search such a small text."))
end
end
search_engine = SCSearchEngine_Scripts.new
log_text = search_engine.searchMapsOfInterest(search, replacement)
end
def scSearchSwitches(search = nil, replacement = nil)
if !search
params = ChooseNumberParams.new
params.setRange(0,1000)
params.setDefaultValue(200)
params.setCancelValue(0)
search=pbMessageChooseNumber(_INTL("What Switch do you want to search?"), params) { }
end
return if search == 0 || search == 1
search_engine = SCSearchEngine_Switches.new
log_text = search_engine.searchMapsOfInterest(search, replacement)
end
def scSearchVariables(search = nil, replacement = nil)
if !search
params = ChooseNumberParams.new
params.setRange(0,1000)
params.setDefaultValue(50)
params.setCancelValue(0)
search=pbMessageChooseNumber("What Variable do you want to search?", params) { }
end
return if search == 0
search_engine = SCSearchEngine_Variables.new
log_text = search_engine.searchMapsOfInterest(search, replacement)
end
def scSearchMapTransfers(search = nil, replacement = nil)
if !search
params = ChooseNumberParams.new
params.setRange(0,200)
params.setDefaultValue(33)
params.setCancelValue(0)
search=pbMessageChooseNumber("What Map do you want to search?", params) { }
end
return if search == 0
search_engine = SCSearchEngine_MapTransfers.new
log_text = search_engine.searchMapsOfInterest(search, replacement)
end
PluginManager.register({
:name => "StCooler Debugging Tools",
:version => "1.0",
:credits => ["StCooler"],
:link => "https://www.pokecommunity.com/threads/536484/"
})
Credits:
These scripts are made by me and only me. As always, I don't care about credits, so do as you wish. The credits are included in the script, though.
You are free to use and modify this script as you wish.
Attachments
Last edited: