Files
infinitefusion-e18/Data/Scripts/001_Technical/003_Intl_Messages.rb
2025-09-28 15:53:01 -04:00

784 lines
20 KiB
Ruby

def pbAddScriptTexts(items, script)
script.force_encoding(Encoding::UTF_8)
script.scan(/(?:_I)\s*\(\s*\"((?:[^\\\"]*\\\"?)*[^\"]*)\"/) do |s|
string = s[0]
string.gsub!(/\\\"/, "\"")
string.gsub!(/\\\\/, "\\")
items.push(string)
end
end
def pbAddRgssScriptTexts(items, script)
script.force_encoding(Encoding::UTF_8)
script.scan(/(?:_INTL|_ISPRINTF)\s*\(\s*\"((?:[^\\\"]*\\\"?)*[^\"]*)\"/) do |s|
string = s[0]
string.gsub!(/\\r/, "\r")
string.gsub!(/\\n/, "\n")
string.gsub!(/\\1/, "\1")
string.gsub!(/\\\"/, "\"")
string.gsub!(/\\\\/, "\\")
items.push(string)
end
end
def pbSetTextMessages
Graphics.update
begin
t = System.uptime
texts = []
# Get script texts from Scripts.rxdata
$RGSS_SCRIPTS.each do |script|
if System.uptime - t >= 5
t += 5
Graphics.update
end
scr = Zlib::Inflate.inflate(script[2])
pbAddRgssScriptTexts(texts, scr)
end
# If Scripts.rxdata only has 1 section, scripts have been extracted. Get
# script texts from .rb files in Data/Scripts
if $RGSS_SCRIPTS.length == 1
Dir.all("Data/Scripts").each do |script_file|
if System.uptime - t >= 5
t += 5
Graphics.update
end
File.open(script_file, "rb") do |f|
pbAddRgssScriptTexts(texts, f.read)
end
end
end
# Must add messages because this code is used by both game system and Editor
MessageTypes.addMessagesAsHash(MessageTypes::ScriptTexts, texts)
commonevents = load_data("Data/CommonEvents.rxdata")
items = []
choices = []
for event in commonevents.compact
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
begin
neednewline = false
lastitem = ""
for j in 0...event.list.size
list = event.list[j]
if neednewline && list.code != 401
if lastitem != ""
lastitem.gsub!(/([^\.\!\?])\s\s+/) { |m| $1 + " " }
items.push(lastitem)
lastitem = ""
end
neednewline = false
end
if list.code == 101
lastitem += "#{list.parameters[0]}"
neednewline = true
elsif list.code == 102
for k in 0...list.parameters[0].length
choices.push(list.parameters[0][k])
end
neednewline = false
elsif list.code == 401
lastitem += " " if lastitem != ""
lastitem += "#{list.parameters[0]}"
neednewline = true
elsif list.code == 355 || list.code == 655
pbAddScriptTexts(items, list.parameters[0])
elsif list.code == 111 && list.parameters[0] == 12
pbAddScriptTexts(items, list.parameters[1])
elsif list.code == 209
route = list.parameters[1]
for k in 0...route.list.size
if route.list[k].code == 45
pbAddScriptTexts(items, route.list[k].parameters[0])
end
end
end
end
if neednewline
if lastitem != ""
items.push(lastitem)
lastitem = ""
end
end
end
end
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
items |= []
choices |= []
items.concat(choices)
MessageTypes.setMapMessagesAsHash(0, items)
mapinfos = pbLoadMapInfos
mapnames = []
for id in mapinfos.keys
mapnames[id] = mapinfos[id].name
end
MessageTypes.setMessages(MessageTypes::MapNames, mapnames)
for id in mapinfos.keys
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
filename = sprintf("Data/Map%03d.rxdata", id)
next if !pbRgssExists?(filename)
map = load_data(filename)
items = []
choices = []
for event in map.events.values
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
begin
for i in 0...event.pages.size
neednewline = false
lastitem = ""
for j in 0...event.pages[i].list.size
list = event.pages[i].list[j]
if neednewline && list.code != 401
if lastitem != ""
lastitem.gsub!(/([^\.\!\?])\s\s+/) { |m| $1 + " " }
items.push(lastitem)
lastitem = ""
end
neednewline = false
end
if list.code == 101
lastitem += "#{list.parameters[0]}"
neednewline = true
elsif list.code == 102
for k in 0...list.parameters[0].length
choices.push(list.parameters[0][k])
end
neednewline = false
elsif list.code == 401
lastitem += " " if lastitem != ""
lastitem += "#{list.parameters[0]}"
neednewline = true
elsif list.code == 355 || list.code == 655
pbAddScriptTexts(items, list.parameters[0])
elsif list.code == 111 && list.parameters[0] == 12
pbAddScriptTexts(items, list.parameters[1])
elsif list.code == 209
route = list.parameters[1]
for k in 0...route.list.size
if route.list[k].code == 45
pbAddScriptTexts(items, route.list[k].parameters[0])
end
end
end
end
if neednewline
if lastitem != ""
items.push(lastitem)
lastitem = ""
end
end
end
end
end
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
items |= []
choices |= []
items.concat(choices)
MessageTypes.setMapMessagesAsHash(id, items)
if Time.now.to_i - t >= 5
t = Time.now.to_i
Graphics.update
end
end
rescue Hangup
end
Graphics.update
end
def pbEachIntlSection(file)
lineno = 1
re = /^\s*\[\s*([^\]]+)\s*\]\s*$/
havesection = false
sectionname = nil
lastsection = []
file.each_line { |line|
if lineno == 1 && line[0].ord == 0xEF && line[1].ord == 0xBB && line[2].ord == 0xBF
line = line[3, line.length - 3]
end
if !line[/^\#/] && !line[/^\s*$/]
if line[re]
if havesection
yield lastsection, sectionname
end
lastsection.clear
sectionname = $~[1]
havesection = true
else
if sectionname == nil
raise _INTL("Expected a section at the beginning of the file (line {1})", lineno)
end
lastsection.push(line.gsub(/\s+$/, ""))
end
end
lineno += 1
if lineno % 500 == 0
Graphics.update
end
}
if havesection
yield lastsection, sectionname
end
end
def pbGetText(infile)
begin
file = File.open(infile, "rb")
rescue
raise _INTL("Can't find {1}", infile)
end
intldat = []
begin
pbEachIntlSection(file) { |section, name|
next if section.length == 0
if !name[/^([Mm][Aa][Pp])?(\d+)$/]
raise _INTL("Invalid section name {1}", name)
end
ismap = $~[1] && $~[1] != ""
id = $~[2].to_i
itemlength = 0
if section[0][/^\d+$/]
intlhash = []
itemlength = 3
if ismap
raise _INTL("Section {1} can't be an ordered list (section was recognized as an ordered list because its first line is a number)", name)
end
if section.length % 3 != 0
raise _INTL("Section {1}'s line count is not divisible by 3 (section was recognized as an ordered list because its first line is a number)", name)
end
else
intlhash = OrderedHash.new
itemlength = 2
if section.length % 2 != 0
raise _INTL("Section {1} has an odd number of entries (section was recognized as a hash because its first line is not a number)", name)
end
end
i = 0
loop do break unless i < section.length
if itemlength == 3
if !section[i][/^\d+$/]
raise _INTL("Expected a number in section {1}, got {2} instead", name, section[i])
end
key = section[i].to_i
i += 1
else
key = MessageTypes.denormalizeValue(section[i])
end
intlhash[key] = MessageTypes.denormalizeValue(section[i + 1])
i += 2 end
if ismap
intldat[0] = [] if !intldat[0]
intldat[0][id] = intlhash
else
intldat[id] = intlhash
end
}
ensure
file.close
end
return intldat
end
def pbCompileText
outfile = File.open("intl.dat", "wb")
begin
intldat = pbGetText("intl.txt")
Marshal.dump(intldat, outfile)
rescue
raise
ensure
outfile.close
end
end
class OrderedHash < Hash
def initialize
@keys = []
super
end
def keys
return @keys.clone
end
def inspect
str = "{"
for i in 0...@keys.length
str += ", " if i > 0
str += @keys[i].inspect + "=>" + self[@keys[i]].inspect
end
str += "}"
return str
end
alias :to_s :inspect
def []=(key, value)
oldvalue = self[key]
if !oldvalue && value
@keys.push(key)
elsif !value
@keys |= []
@keys -= [key]
end
return super(key, value)
end
def self._load(string)
ret = self.new
keysvalues = Marshal.load(string)
keys = keysvalues[0]
values = keysvalues[1]
for i in 0...keys.length
ret[keys[i]] = values[i]
end
return ret
end
def _dump(_depth = 100)
values = []
for key in @keys
values.push(self[key])
end
return Marshal.dump([@keys, values])
end
end
class Messages
def initialize(filename = nil, delayLoad = false)
@messages = nil
@filename = filename
if @filename && !delayLoad
loadMessageFile(@filename)
end
end
def delayedLoad
if @filename && !@messages
loadMessageFile(@filename)
@filename = nil
end
end
def self.stringToKey(str)
if str && str[/[\r\n\t\1]|^\s+|\s+$|\s{2,}/]
key = str.clone
key.gsub!(/^\s+/, "")
key.gsub!(/\s+$/, "")
key.gsub!(/\s{2,}/, " ")
return key
end
return str
end
def self.normalizeValue(value)
if value[/[\r\n\t\x01]|^[\[\]]/]
ret = value.clone
ret.gsub!(/\r/, "<<r>>")
ret.gsub!(/\n/, "<<n>>")
ret.gsub!(/\t/, "<<t>>")
ret.gsub!(/\[/, "<<[>>")
ret.gsub!(/\]/, "<<]>>")
ret.gsub!(/\x01/, "<<1>>")
return ret
end
return value
end
def self.denormalizeValue(value)
if value[/<<[rnt1\[\]]>>/]
ret = value.clone
ret.gsub!(/<<1>>/, "\1")
ret.gsub!(/<<r>>/, "\r")
ret.gsub!(/<<n>>/, "\n")
ret.gsub!(/<<\[>>/, "[")
ret.gsub!(/<<\]>>/, "]")
ret.gsub!(/<<t>>/, "\t")
return ret
end
return value
end
def self.writeObject(f, msgs, secname, origMessages = nil)
return if !msgs
if msgs.is_a?(Array)
f.write("[#{secname}]\r\n")
for j in 0...msgs.length
next if nil_or_empty?(msgs[j])
value = Messages.normalizeValue(msgs[j])
origValue = ""
if origMessages
origValue = Messages.normalizeValue(origMessages.get(secname, j))
else
origValue = Messages.normalizeValue(MessageTypes.get(secname, j))
end
f.write("#{j}\r\n")
f.write(origValue + "\r\n")
f.write(value + "\r\n")
end
elsif msgs.is_a?(OrderedHash)
f.write("[#{secname}]\r\n")
keys = msgs.keys
for key in keys
next if nil_or_empty?(msgs[key])
value = Messages.normalizeValue(msgs[key])
valkey = Messages.normalizeValue(key)
# key is already serialized
f.write(valkey + "\r\n")
f.write(value + "\r\n")
end
end
end
def messages
return @messages || []
end
def extract(outfile)
# return if !@messages
origMessages = Messages.new("Data/messages.dat")
File.open(outfile, "wb") { |f|
f.write(0xef.chr)
f.write(0xbb.chr)
f.write(0xbf.chr)
f.write("# To localize this text for a particular language, please\r\n")
f.write("# translate every second line of this file.\r\n")
if origMessages.messages[0]
for i in 0...origMessages.messages[0].length
msgs = origMessages.messages[0][i]
Messages.writeObject(f, msgs, "Map#{i}", origMessages)
end
end
for i in 1...origMessages.messages.length
msgs = origMessages.messages[i]
Messages.writeObject(f, msgs, i, origMessages)
end
}
end
def setMessages(type, array)
@messages = [] if !@messages
arr = []
for i in 0...array.length
arr[i] = (array[i]) ? array[i] : ""
end
@messages[type] = arr
end
def addMessages(type, array)
@messages = [] if !@messages
arr = (@messages[type]) ? @messages[type] : []
for i in 0...array.length
arr[i] = (array[i]) ? array[i] : (arr[i]) ? arr[i] : ""
end
@messages[type] = arr
end
def self.createHash(_type, array)
arr = OrderedHash.new
for i in 0...array.length
if array[i]
key = Messages.stringToKey(array[i])
arr[key] = array[i]
end
end
return arr
end
def self.addToHash(_type, array, hash)
hash = OrderedHash.new if !hash
for i in 0...array.length
if array[i]
key = Messages.stringToKey(array[i])
hash[key] = array[i]
end
end
return hash
end
def setMapMessagesAsHash(type, array)
@messages = [] if !@messages
@messages[0] = [] if !@messages[0]
@messages[0][type] = Messages.createHash(type, array)
end
def addMapMessagesAsHash(type, array)
@messages = [] if !@messages
@messages[0] = [] if !@messages[0]
@messages[0][type] = Messages.addToHash(type, array, @messages[0][type])
end
def setMessagesAsHash(type, array)
@messages = [] if !@messages
@messages[type] = Messages.createHash(type, array)
end
def addMessagesAsHash(type, array)
@messages = [] if !@messages
@messages[type] = Messages.addToHash(type, array, @messages[type])
end
def saveMessages(filename = nil)
filename = "Data/messages.dat" if !filename
File.open(filename, "wb") { |f| Marshal.dump(@messages, f) }
end
def loadMessageFile(filename)
begin
pbRgssOpen(filename, "rb") { |f| @messages = Marshal.load(f) }
if !@messages.is_a?(Array)
@messages = nil
raise "Corrupted data"
end
return @messages
rescue
@messages = nil
return nil
end
end
def set(type, id, value)
delayedLoad
return if !@messages
return if !@messages[type]
@messages[type][id] = value
end
def getCount(type)
delayedLoad
return 0 if !@messages
return 0 if !@messages[type]
return @messages[type].length
end
def get(type, id)
delayedLoad
return "" if !@messages
return "" if !@messages[type]
return "" if !@messages[type][id]
return @messages[type][id]
end
def getFromHash(type, key)
delayedLoad
return key if !@messages || !@messages[type] || !key
id = Messages.stringToKey(key)
return key if !@messages[type][id]
return @messages[type][id]
end
def getFromMapHash(type, key)
delayedLoad
return key if !@messages
return key if !@messages[0]
return key if !@messages[0][type] && !@messages[0][0]
id = Messages.stringToKey(key)
if @messages[0][type] && @messages[0][type][id]
return @messages[0][type][id]
elsif @messages[0][0] && @messages[0][0][id]
return @messages[0][0][id]
end
return key
end
end
module MessageTypes
# Value 0 is used for common event and map event text
Species = 1
Kinds = 2
Entries = 3
FormNames = 4
Moves = 5
MoveDescriptions = 6
Items = 7
ItemPlurals = 8
ItemDescriptions = 9
Abilities = 10
AbilityDescs = 11
Types = 12
TrainerTypes = 13
TrainerNames = 14
BeginSpeech = 15
EndSpeechWin = 16
EndSpeechLose = 17
RegionNames = 18
PlaceNames = 19
PlaceDescriptions = 20
MapNames = 21
PhoneMessages = 22
TrainerLoseText = 23
ScriptTexts = 24
RibbonNames = 25
RibbonDescriptions = 26
@@messages = Messages.new
@@messagesFallback = Messages.new("Data/messages.dat", true)
def self.stringToKey(str)
return Messages.stringToKey(str)
end
def self.normalizeValue(value)
return Messages.normalizeValue(value)
end
def self.denormalizeValue(value)
Messages.denormalizeValue(value)
end
def self.writeObject(f, msgs, secname)
Messages.denormalizeValue(str)
end
def self.extract(outfile)
@@messages.extract(outfile)
end
def self.setMessages(type, array)
@@messages.setMessages(type, array)
end
def self.addMessages(type, array)
@@messages.addMessages(type, array)
end
def self.createHash(type, array)
Messages.createHash(type, array)
end
def self.addMapMessagesAsHash(type, array)
@@messages.addMapMessagesAsHash(type, array)
end
def self.setMapMessagesAsHash(type, array)
@@messages.setMapMessagesAsHash(type, array)
end
def self.addMessagesAsHash(type, array)
@@messages.addMessagesAsHash(type, array)
end
def self.setMessagesAsHash(type, array)
@@messages.setMessagesAsHash(type, array)
end
def self.saveMessages(filename = nil)
@@messages.saveMessages(filename)
end
def self.loadMessageFile(filename)
@@messages.loadMessageFile(filename)
end
def self.get(type, id)
ret = @@messages.get(type, id)
if ret == ""
ret = @@messagesFallback.get(type, id)
end
return ret
end
def self.getCount(type)
c1 = @@messages.getCount(type)
c2 = @@messagesFallback.getCount(type)
return c1 > c2 ? c1 : c2
end
def self.getOriginal(type, id)
return @@messagesFallback.get(type, id)
end
def self.getFromHash(type, key)
@@messages.getFromHash(type, key)
end
def self.getFromMapHash(type, key)
@@messages.getFromMapHash(type, key)
end
end
def pbLoadMessages(file)
return MessageTypes.loadMessageFile(file)
end
def pbGetMessageCount(type)
return MessageTypes.getCount(type)
end
def pbGetMessage(type, id)
return MessageTypes.get(type, id)
end
def pbGetMessageFromHash(type, id)
return MessageTypes.getFromHash(type, id)
end
# Replaces first argument with a localized version and formats the other
# parameters by replacing {1}, {2}, etc. with those placeholders.
def _INTL(*arg)
begin
string = MessageTypes.getFromHash(MessageTypes::ScriptTexts, arg[0])
rescue
string = arg[0]
end
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\}/, "#{arg[i]}")
end
return string
end
# Replaces first argument with a localized version and formats the other
# parameters by replacing {1}, {2}, etc. with those placeholders.
# This version acts more like sprintf, supports e.g. {1:d} or {2:s}
def _ISPRINTF(*arg)
begin
string = MessageTypes.getFromHash(MessageTypes::ScriptTexts, arg[0])
rescue
string = arg[0]
end
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
next sprintf("%" + $1, arg[i])
}
end
return string
end
def _I(str)
return _MAPINTL($game_map.map_id, str)
end
def _MAPINTL(mapid, *arg)
string = MessageTypes.getFromMapHash(mapid, arg[0])
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\}/, "#{arg[i]}")
end
return string
end
def _MAPISPRINTF(mapid, *arg)
string = MessageTypes.getFromMapHash(mapid, arg[0])
string = string.clone
for i in 1...arg.length
string.gsub!(/\{#{i}\:([^\}]+?)\}/) { |m|
next sprintf("%" + $1, arg[i])
}
end
return string
end