Extracting the dialogue of a project
Post date: Aug 13, 2009 7:19:54 PM
Here is a small script I cooked up earlier today.
It extracts all the text messages and choices of all the events in the game. One file for the map events, another for the common events and a third text file for the battle events.
It can be useful for reviewing purposes and also for simple-minded word spell-checking.
Note that since there is loss of information to the format presented you should consider it infeasible to be able to inject your modifications back into the project by automatic means.
I know there is a French project which can do this, but the text files are not as nice to read.
To use the script create a new section right above Main and run the program.
Delete the section afterwards.
You now have 3 new dialogue_xxx.txt files in the project folder.
*hugs*
def update_sprite
if @sprite.nil?
@sprite = Sprite.new
@sprite.bitmap = Bitmap.new(640, 120)
end
current = $current
unless current == $last
$last = current
@sprite.bitmap.clear
unless current.nil?
@sprite.bitmap.draw_text(8,4,600,32,$last.map)
@sprite.bitmap.draw_text(8,40,600,32,$last.event)
end
end
end
##
# A separate thread that will run and make sure the Graphics.update is updated
# every now and then.
#
Thread.new {
loop do
# Lets the thread sleep for a while to minimize CPU usage
sleep 0.1
# Update the sprite
update_sprite
# Update the graphics
Graphics.update
end
}
Current = Struct.new(:map, :event)
$current = nil
Map = Struct.new(:name, :map_id, :events)
Event = Struct.new(:name, :event_id, :pages)
Page = Struct.new(:number, :list)
ListElement = Struct.new(:message, :type)
######
######
class Map
def write_to_stream(io)
io.print "\r\n########################################"
io.print "\r\n# Map #{map_id} ~ #{name} (#{events.size} events)\r\n"
io.print "########################################\r\n"
for event in events
event.write_to_stream(io)
end
end
end
class Event
def write_to_stream(io)
io.print "\r\n-= Event #{event_id} - #{name} =-\r\n"
for page in pages
page.write_to_stream(io)
end
end
end
class Page
def write_to_stream(io)
io.print "Page #{number}:\r\n"
for element in list
element.write_to_stream(io)
io.print "\r\n"
end
end
end
class ListElement
def write_to_stream(io)
io.print message
end
end
######
def process_list(list)
# Go through the event commands in the list
rlist = [] # resulting list
command_index = 0
while command_index < list.size
command = list[command_index]
if command.code == 101
message = command.parameters[0].rstrip
loop do
break unless command_index + 1 < list.size
if list[command_index+1].code == 401
command_index += 1
message += " " + list[command_index].parameters[0].rstrip
elsif list[command_index+1].code == 102
command_index += 1
for text in list[command_index].parameters[0]
message += "\r\n" + text.rstrip
end
else
break
end
end
rlist << ListElement.new(message, 'text')
elsif command.code == 102
message = ""
for text in list[command_index].parameters[0]
message += "\r\n" + text.rstrip
end
rlist << ListElement.new(message, 'choice')
end
command_index += 1
end
return rlist
end
######
class CommonEvent < Struct.new(:name, :event_id, :list)
def write_to_stream(io)
io.print "\r\n-= Common Event #{event_id} - #{name} =-\r\n"
for element in list
element.write_to_stream(io)
io.print "\r\n"
end
end
end
common_events = load_data('Data/CommonEvents.rxdata')
ces = []
for ce in common_events.compact
# Look at which event is currently processing
cur = Current.new("Processing common events...",
"Common event #{ce.id} - #{ce.name}")
$current = cur
# Process the list
list = process_list(ce.list)
unless list.empty?
# Create struct
current_ce = CommonEvent.new(ce.name, ce.id, list)
ces << current_ce
end
end
######
######
class Troop < Event
def write_to_stream(io)
io.print "\r\n-= Troop #{event_id} - #{name} =-\r\n"
for page in pages
page.write_to_stream(io)
end
end
end
troops = load_data('Data\Troops.rxdata')
battle_events = []
for event in troops.compact
# Look at which event is currently processing
cur = Current.new("Processing battle events...",
"Troop " + event.id.to_s + " - " + event.name)
$current = cur
# Create the event struct
current_event = Troop.new(event.name, event.id, [])
# Create pages
event.pages.each_with_index do |page, page_index|
list = process_list(page.list)
unless list.empty?
current_page = Page.new(page_index+1, list)
current_event.pages << current_page
end
end
# Let's disregard useless events
battle_events << current_event unless current_event.pages.empty?
end
######
######
infos = load_data('Data\MapInfos.rxdata')
maps = []
for map_id, map_info in infos.sort
# Create map struct
current_map = Map.new(map_info.name, map_id, [])
maps << current_map
map = load_data(sprintf("Data/Map%03d.rxdata", map_id))
# Create event structs
for event_id, event in map.events.sort
# Look at which event is currently processing
cur = Current.new("Map " + map_id.to_s + " - " + map_info.name,
"Event " + event_id.to_s + " - " + event.name)
$current = cur
# Create the event struct
current_event = Event.new(event.name, event_id, [])
# Create pages
event.pages.each_with_index do |page, page_index|
list = process_list(page.list)
unless list.empty?
current_page = Page.new(page_index+1, list)
# Let's disregard useless pages
current_event.pages << current_page
end
end
# Let's disregard useless events
current_map.events << current_event unless current_event.pages.empty?
end
end
# Update status info
cur = Current.new("All maps have been processed",
"Writing to a text file")
$current = cur
File.open('Dialogue_Map.txt', 'wb') {|f|
f.print "THIS FILE CONTAINS THE DIALOGUE EXTRACTED FROM THE MAPS\r\n\r\n"
for map in maps
map.write_to_stream(f)
end
}
File.open('Dialogue_Common.txt', 'wb') {|f|
f.print "THIS FILE CONTAINS THE DIALOGUE EXTRACTED FROM THE COMMON EVENTS\r\n\r\n"
for ce in ces
ce.write_to_stream(f)
end
}
File.open('Dialogue_Battle.txt', 'wb') {|f|
f.print "THIS FILE CONTAINS THE DIALOGUE EXTRACTED FROM THE BATTLE EVENTS\r\n\r\n"
for be in battle_events
be.write_to_stream(f)
end
}
exit
I have done the syntax high lightning in hand, so don't trust it too much.
I will not do it again since it's horrible.
Edit: A big thanks to Trebor777 for the idea of using blocks instead of f = and f.close