Introduction
This script is designed to search throughout your RPGMaker XP's project to find any missing audio or graphic resources. It will search through both your project's database and through each map and map event, cataloging all media in your project, and then will perform tests to ensure each piece is in your project. If something is not present, it will be made available in a report entitled "Missing Resources.Txt" within your project's folder.
Script
The Script
Code:
#==============================================================================
# ** Missing Resources Report Generator
#------------------------------------------------------------------------------
# version 1.1
# by DerVVulfman
# 07-16-2014
# RGSS and ReGaL Compliant
#==============================================================================
#
# INTRODUCTION:
#
# This script is designed to search throughout your RPGMaker XP's project to
# find any missing audio or graphic resources. It will search through both
# your project's database and through each map and map event, cataloging all
# media in your project, and then will perform tests to ensure each piece is
# in your project. If something is not present, it will be made available
# in a report entitled "Missing Resources.Txt" within your project's folder.
#
#
#------------------------------------------------------------------------------
#
# INSTRUCTIONS:
#
# * Insert below your scripts.
# * Run project.
# * Read report when you're done.
#
#
#------------------------------------------------------------------------------
#
# NOTE:
#
# It only searches through the database and map systems. It does not search
# through out custom scripts.
#
#
#==============================================================================
#==============================================================================
# ** Resource_List
#------------------------------------------------------------------------------
# This is a superclass for the save screen and load screen.
#==============================================================================
module Resource_List
#--------------------------------------------------------------------------
# * Main Processing
#--------------------------------------------------------------------------
def self.main
set_resource_arrays
set_resource_database
search_resource_actors
search_resource_animations
search_resource_common
search_resource_enemy
search_resource_icons(@armor_list)
search_resource_icons(@item_list)
search_resource_icons(@skill_list)
search_resource_icons(@weapon_list)
search_resource_system
search_resource_tiles
search_resource_troop
search_resource_map
# SE Specific Search
search_resource_se_use(@item_list)
search_resource_se_use(@skill_list)
sort_resources
sift_resources
extract_resources
print_resources
end
#--------------------------------------------------------------------------
# * Resource Arrays
#--------------------------------------------------------------------------
def self.set_resource_arrays
# Graphic Arrays
@grabbed_anim, @sorted_anim, @missing_anim = [], [], []
@grabbed_auto, @sorted_auto, @missing_auto = [], [], []
@grabbed_backs, @sorted_backs, @missing_backs = [], [], []
@grabbed_bat, @sorted_bat, @missing_bat = [], [], []
@grabbed_char, @sorted_char, @missing_char = [], [], []
@grabbed_fogs, @sorted_fogs, @missing_fogs = [], [], []
@grabbed_game, @sorted_game, @missing_game = [], [], []
@grabbed_icon, @sorted_icon, @missing_icon = [], [], []
@grabbed_pan, @sorted_pan, @missing_pan = [], [], []
@grabbed_pics, @sorted_pics, @missing_pics = [], [], []
@grabbed_tiles, @sorted_tiles, @missing_tiles = [], [], []
@grabbed_title, @sorted_title, @missing_title = [], [], []
@grabbed_trans, @sorted_trans, @missing_trans = [], [], []
@grabbed_skin, @sorted_skin, @missing_skin = [], [], []
# Audio Arrays
@grabbed_bgm, @sorted_bgm, @missing_bgm = [], [], []
@grabbed_bgs, @sorted_bgs, @missing_bgs = [], [], []
@grabbed_me, @sorted_me, @missing_me = [], [], []
@grabbed_se, @sorted_se, @missing_se = [], [], []
end
#--------------------------------------------------------------------------
# * Project Database Values
#--------------------------------------------------------------------------
def self.set_resource_database
@actor_list = load_data("Data/Actors.rxdata")
@anim_list = load_data("Data/Animations.rxdata")
@armor_list = load_data("Data/Armors.rxdata")
@common_list = load_data("Data/CommonEvents.rxdata")
@enemy_list = load_data("Data/Enemies.rxdata")
@item_list = load_data("Data/Items.rxdata")
@skill_list = load_data("Data/Skills.rxdata")
@tiles_list = load_data("Data/Tilesets.rxdata")
@troop_list = load_data("Data/Troops.rxdata")
@map_list = load_data("Data/MapInfos.rxdata")
@system_list = load_data("Data/System.rxdata")
@weapon_list = load_data("Data/Weapons.rxdata")
end
#--------------------------------------------------------------------------
# * Actor Database Search
#--------------------------------------------------------------------------
def self.search_resource_actors
for actor in @actor_list
next if actor.nil?
unless actor.character_name == ''
@grabbed_char.push(actor.character_name)
end
unless actor.battler_name == ''
@grabbed_bat.push(actor.battler_name)
end
end
end
#--------------------------------------------------------------------------
# * Animation Database Search
#--------------------------------------------------------------------------
def self.search_resource_animations
for anim in @anim_list
next if anim.nil?
unless anim.animation_name == ''
@grabbed_anim.push(anim.animation_name)
end
times = anim.timings
for timed in times
next if timed.nil?
unless timed.se.name == ''
@grabbed_se.push(timed.se.name)
end
end
end
end
#--------------------------------------------------------------------------
# * Common Events Database Search
#--------------------------------------------------------------------------
def self.search_resource_common
for event in @common_list
next if event.nil?
list = event.list
search_resource_page_item(list)
end
end
#--------------------------------------------------------------------------
# * Enemy Database Search
#--------------------------------------------------------------------------
def self.search_resource_enemy
for enemy in @enemy_list
next if enemy.nil?
unless enemy.battler_name == ''
@grabbed_bat.push(enemy.battler_name)
end
end
end
#--------------------------------------------------------------------------
# * Icon Database Search
#--------------------------------------------------------------------------
def self.search_resource_icons(list_array)
for list_item in list_array
next if list_item.nil?
unless list_item.icon_name == ''
@grabbed_icon.push(list_item.icon_name)
end
end
end
#--------------------------------------------------------------------------
# * SE Database Search
#--------------------------------------------------------------------------
def self.search_resource_se_use(list_array)
for list_item in list_array
next if list_item.nil?
unless list_item.menu_se.name == ''
@grabbed_se.push(list_item.menu_se.name)
end
end
end
#--------------------------------------------------------------------------
# * System Database Search
#--------------------------------------------------------------------------
def self.search_resource_system
list = ['cursor_se', 'decision_se', 'cancel_se', 'buzzer_se', 'equip_se',
'shop_se', 'save_se', 'load_se', 'battle_start_se', 'escape_se',
'actor_collapse_se', 'enemy_collapse_se']
unless @system_list.gameover_name == ''
@grabbed_game.push(@system_list.gameover_name)
end
unless @system_list.title_name == ''
@grabbed_title.push(@system_list.title_name)
end
unless @system_list.battle_transition == ''
@grabbed_trans.push(@system_list.battle_transition)
end
unless @system_list.windowskin_name == ''
@grabbed_skin.push(@system_list.windowskin_name)
end
unless @system_list.title_bgm.name == ''
@grabbed_bgm.push(@system_list.title_bgm.name)
end
unless @system_list.battle_bgm.name == ''
@grabbed_bgm.push(@system_list.battle_bgm.name)
end
unless @system_list.battle_end_me.name == ''
@grabbed_me.push(@system_list.battle_end_me.name)
end
unless @system_list.gameover_me.name == ''
@grabbed_me.push(@system_list.gameover_me.name)
end
for item in list
eval_txt = '@system_list.' + item + '.name'
filename = eval(eval_txt)
@grabbed_se.push(filename) unless filename == ''
end
end
#--------------------------------------------------------------------------
# * Tileset Database Search
#--------------------------------------------------------------------------
def self.search_resource_tiles
for tile in @tiles_list
next if tile.nil?
autotiles = tile.autotile_names
for auto in autotiles
@grabbed_auto.push(auto) unless auto == ''
end
unless tile.battleback_name == ''
@grabbed_backs.push(tile.battleback_name)
end
unless tile.fog_name == ''
@grabbed_fogs.push(tile.fog_name)
end
unless tile.panorama_name == ''
@grabbed_pan.push(tile.panorama_name)
end
unless tile.tileset_name == ''
@grabbed_tiles.push(tile.tileset_name)
end
end
end
#--------------------------------------------------------------------------
# * Troop Database Search
#--------------------------------------------------------------------------
def self.search_resource_troop
for troop in @troop_list
next if troop.nil?
for page in troop.pages.reverse
list = page.list
search_resource_page_item(list)
end
end
end
#--------------------------------------------------------------------------
# * Map Database Search
#--------------------------------------------------------------------------
def self.search_resource_map
for map in @map_list
# Get map ID
id = map[0]
# Get Individual Map Data
map_data = load_data(sprintf("Data/Map%03d.rxdata", id))
# Get Map's Background Music and BGS
unless map_data.bgm.name == ''
@grabbed_bgm.push(map_data.bgm.name)
end
unless map_data.bgs.name == ''
@grabbed_bgs.push(map_data.bgs.name)
end
# Set map event data
events = {}
for i in map_data.events.keys
events[i] = map_data.events[i]
end
# Sorth through Event Array
for event in events
# Sort through Event Pages
for page in event[1].pages.reverse
unless page.graphic.character_name == ''
@grabbed_char.push(page.graphic.character_name)
end
list = page.list
# Sort through event list options
search_resource_page_item(list)
end
end
end
end
#--------------------------------------------------------------------------
# * Page List Search (whether troop or map pages)
#--------------------------------------------------------------------------
def self.search_resource_page_item(list)
for list_item in list
if list_item.code == 132
unless list_item.parameters[0].name == ''
@grabbed_bgm.push(list_item.parameters[0].name)
end
end
if list_item.code == 133
unless list_item.parameters[0].name == ''
@grabbed_me.push(list_item.parameters[0].name)
end
end
if list_item.code == 241
unless list_item.parameters[0].name == ''
@grabbed_bgm.push(list_item.parameters[0].name)
end
end
if list_item.code == 245
unless list_item.parameters[0].name == ''
@grabbed_bgs.push(list_item.parameters[0].name)
end
end
if list_item.code == 249
unless list_item.parameters[0].name == ''
@grabbed_me.push(list_item.parameters[0].name)
end
end
if list_item.code == 250
unless list_item.parameters[0].name == ''
@grabbed_me.push(list_item.parameters[0].name)
end
end
if list_item.code == 131
unless list_item.parameters[0] == ''
@grabbed_skin.push(list_item.parameters[0])
end
end
if list_item.code == 204
case list_item.parameters[0]
when 0;
unless list_item.parameters[1] == ''
@grabbed_pan.push(list_item.parameters[1])
end
when 1
unless list_item.parameters[1] == ''
@grabbed_fogs.push(list_item.parameters[1])
end
when 2
unless list_item.parameters[1] == ''
@grabbed_backs.push(list_item.parameters[1])
end
end
end
if list_item.code == 222
unless list_item.parameters[0] == ''
@grabbed_trans.push(list_item.parameters[0])
end
end
if list_item.code == 231
unless list_item.parameters[1] == ''
@grabbed_pics.push(list_item.parameters[1])
end
end
if list_item.code == 322
unless list_item.parameters[1] == ''
@grabbed_char.push(list_item.parameters[1])
end
end
if list_item.code == 322
unless list_item.parameters[3] == ''
@grabbed_bat.push(list_item.parameters[3])
end
end
# Detect Move Route Set - Charset Only
if list_item.code == 209
move_list = list_item.parameters[1].list
for move_item in move_list
if move_item.code == 41
unless move_item.parameters[0] == ''
@grabbed_char.push(list_item.parameters[0])
end
end
end
end
end
end
#--------------------------------------------------------------------------
# * Sort Resources Alphabetically
#--------------------------------------------------------------------------
def self.sort_resources
@grabbed_anim.sort!
@grabbed_auto.sort!
@grabbed_bat.sort!
@grabbed_char.sort!
@grabbed_fogs.sort!
@grabbed_game.sort!
@grabbed_icon.sort!
@grabbed_pan.sort!
@grabbed_pics.sort!
@grabbed_tiles.sort!
@grabbed_title.sort!
@grabbed_trans.sort!
@grabbed_skin.sort!
@grabbed_bgm.sort!
@grabbed_bgs.sort!
@grabbed_me.sort!
@grabbed_se.sort!
end
#--------------------------------------------------------------------------
# * Remove Duplications in Project Lists
#--------------------------------------------------------------------------
def self.sift_resources
self.sift_main(@grabbed_anim, @sorted_anim)
self.sift_main(@grabbed_auto, @sorted_auto)
self.sift_main(@grabbed_backs, @sorted_backs)
self.sift_main(@grabbed_bat, @sorted_bat)
self.sift_main(@grabbed_char, @sorted_char)
self.sift_main(@grabbed_fogs, @sorted_fogs)
self.sift_main(@grabbed_game, @sorted_game)
self.sift_main(@grabbed_icon, @sorted_icon)
self.sift_main(@grabbed_pan, @sorted_pan)
self.sift_main(@grabbed_pics, @sorted_pics)
self.sift_main(@grabbed_tiles, @sorted_tiles)
self.sift_main(@grabbed_title, @sorted_title)
self.sift_main(@grabbed_trans, @sorted_trans)
self.sift_main(@grabbed_skin, @sorted_skin)
self.sift_main(@grabbed_bgm, @sorted_bgm)
self.sift_main(@grabbed_bgs, @sorted_bgs)
self.sift_main(@grabbed_me, @sorted_me)
self.sift_main(@grabbed_se, @sorted_se)
end
#--------------------------------------------------------------------------
# * Resource Duplication Main Routine
#--------------------------------------------------------------------------
def self.sift_main(input, output)
temp = ''
for char in input
next if temp == char
output.push(char)
temp = char
end
end
#--------------------------------------------------------------------------
# * Extract Resources not in project
#--------------------------------------------------------------------------
def self.extract_resources
# Graphics
self.extract_graphics(@sorted_anim, @missing_anim, "Animations")
self.extract_graphics(@sorted_auto, @missing_auto, "Autotiles")
self.extract_graphics(@sorted_backs,@missing_backs,"Battlebacks")
self.extract_graphics(@sorted_bat, @missing_bat, "Battlers")
self.extract_graphics(@sorted_char, @missing_char, "Characters")
self.extract_graphics(@sorted_fogs, @missing_fogs, "Fogs")
self.extract_graphics(@sorted_game, @missing_game, "Gameovers")
self.extract_graphics(@sorted_icon, @missing_icon, "Icons")
self.extract_graphics(@sorted_pan, @missing_pan, "Panoramas")
self.extract_graphics(@sorted_pics, @missing_pics, "Pictures")
self.extract_graphics(@sorted_tiles,@missing_tiles,"Tilesets")
self.extract_graphics(@sorted_title,@missing_title,"Titles")
self.extract_graphics(@sorted_trans,@missing_trans,"Transitions")
self.extract_graphics(@sorted_skin, @missing_skin, "Windowskins")
# Audio
self.extract_audio(@sorted_bgm, @missing_bgm, "BGM")
self.extract_audio(@sorted_bgs, @missing_bgs, "BGS")
self.extract_audio(@sorted_me, @missing_me, "ME")
self.extract_audio(@sorted_se, @missing_se, "SE")
end
#--------------------------------------------------------------------------
# * Extract Graphic Resources Main Routine
#--------------------------------------------------------------------------
def self.extract_graphics(input, output, folder)
for entry in input
filename = "Graphics//"+folder+"//"+entry+".png"
file_exist = FileTest.exist?(filename)
output.push(entry) unless file_exist
end
end
#--------------------------------------------------------------------------
# * Extract Audio Resources Main Routine
#--------------------------------------------------------------------------
def self.extract_audio(input, output, folder)
for entry in input
filename = "Audio//"+folder+"//"+entry
file_exist = extract_audio_name_tester(filename)
output.push(entry) unless file_exist
end
end
#--------------------------------------------------------------------------
# * Filename Tester (adds the file extension)
#--------------------------------------------------------------------------
def self.extract_audio_name_tester(filename)
if FileTest.exist?(filename + ".mp3")
return true
elsif FileTest.exist?(filename + ".ogg")
return true
elsif FileTest.exist?(filename + ".wma")
return true
elsif FileTest.exist?(filename + ".wav")
return true
elsif FileTest.exist?(filename + ".mid")
return true
elsif FileTest.exist?(filename + ".mod")
return true if (RUBY_VERSION[0] == 2) # Ruby 2+ Automated for ReGaL
end
return false
end
#--------------------------------------------------------------------------
# * Render Lists
#--------------------------------------------------------------------------
def self.print_resources
f = File.new("Missing Resources.txt", "w+")
f.puts "MISSING RESOURCES LIST (" +print_tally.to_s+") missing"
f.puts ""
f.puts "GRAPHICS PORTION:"
f.puts ""
print_resource_object(f, "ANIMATIONS:", @missing_anim)
print_resource_object(f, "AUTOTILES:", @missing_auto)
print_resource_object(f, "BATTLEBACKS:", @missing_backs)
print_resource_object(f, "BATTLERS:", @missing_bat)
print_resource_object(f, "CHARACTERS:", @missing_char)
print_resource_object(f, "FOGS:", @missing_fogs)
print_resource_object(f, "GAMEOVERS:", @missing_game)
print_resource_object(f, "ICONS:", @missing_icon)
print_resource_object(f, "PANORAMAS:", @missing_pan)
print_resource_object(f, "PICTURES:", @missing_pics)
print_resource_object(f, "TILESETS:", @missing_tiles)
print_resource_object(f, "TITLES:", @missing_title)
print_resource_object(f, "TRANSITIONS:", @missing_trans)
print_resource_object(f, "WINDOWSKINS:", @missing_skin)
f.puts ""
f.puts "AUDIO PORTION:"
f.puts ""
print_resource_object(f, "BACKGROUND MUSIC:", @missing_bgm)
print_resource_object(f, "BACKGROUND SOUND:", @missing_bgs)
print_resource_object(f, "MUSIC EFFECT:", @missing_me)
print_resource_object(f, "SOUND EFFECT:", @missing_se)
end
#--------------------------------------------------------------------------
# * Generate Missing Resources tally
#--------------------------------------------------------------------------
def self.print_tally
value = 0
value += @missing_anim.size
value += @missing_auto.size
value += @missing_backs.size
value += @missing_bat.size
value += @missing_char.size
value += @missing_fogs.size
value += @missing_game.size
value += @missing_icon.size
value += @missing_pan.size
value += @missing_pics.size
value += @missing_tiles.size
value += @missing_title.size
value += @missing_trans.size
value += @missing_skin.size
value += @missing_bgm.size
value += @missing_bgs.size
value += @missing_me.size
value += @missing_se.size
return value
end
#--------------------------------------------------------------------------
# * Render Individual List per List Type (include final blank line)
#--------------------------------------------------------------------------
def self.print_resource_object(file, name, list)
file.puts name
file.puts "(none missing)" if list == []
for item in list; file.puts item.to_s ; end
file.puts " "
end
end
Very nice indeed, lol. Unfortunately I just did two entire playthroughs of a game on normal mode and once in an easter egg mode doing this manually XD. Also, the fact that ReGaL handles *.mod format music has not a thing to do with ruby 2.1.2; it has to do with the multimedia libs used (SDL_audio, libmodplug) instead of what RMXP uses (directsound [audio equivalent of M$'s directX])
So similar to that File missing error preventer script by Woratana? Only I'm assuming this does one allround check at the startup, where that one showed up while playing?
*tests*
Hm. It did not show up as expected, but that does not mean the record was not isntant.
...However...XD' It went a little overboard XD
I just added it into a blank game, added and removed one audio file, to give it sometihng to find and now I have a report of 425 files missing Xb It found the missing audio file just fine, but it also reported many rtp file as missing XD' http://pastebin.com/hc7CrfLk
I wonder how much work it'd take to turn this into an event code patcher; not very much, it looks like. I just spent 5 hours yesterday copy-pasting bugged events with their correct version and it made me wish for a way to do it by code.
Your game's database has all the default animations? Then it found and logged all animation graphics you have in your database that aren't in your project's folder. Ditto with the tilesets. It would find any and all tileset files, autotiles, fogs and panoramas you don't have in your project. So unless you cut back on your tilesets and animations in your project, you will have a large number of files. Likewise with audio effects within the animations.
It will be pretty much instant. It SHOULD run before the game starts, searching your entire database and through every map and map event.
But is that not somewhat ineficient, if it lists all the things that use the RTP, even if you don't use them in your game?
So unless the project removes everything the RTP sets up and has 100% usuage of custom recources, this will generate a large list to look trough that cound as missing even if they are not.
But for those who use their own recorces for everything, this might me nice.
One may question it's efficiency. But I feel it as a necessary evil. This system cannot check any resources garnered by any other script, so it won't detect the bell chime effect when an AT bar is filled, nor the AT bar graphic itself. However, these are moot as the designer would certainly have these in their project anyway.
At the same time, some custom scripts may draw upon resources defined in the database such as battle animations. Custom teleportation and battlesystem scripts may access animations by a mere animation_id value being applied to an event or the player itself. As such, I feel the game designer should eliminate unwanted animations if they don't wish them to show in the resource list.
Again, it probably depends on how you design your game. This will be more usefull for some then it will be for others, but that's the beauty of all the things one can do with the makers =)