adds music randomization

This commit is contained in:
duncathan 2020-03-02 23:02:23 -06:00
parent a09179fc56
commit 46eb8dc016
5 changed files with 282 additions and 110 deletions

View file

@ -1 +1 @@
0-FSS\S0-_pqd_idlSSSS_hqg0-FSS\T0-_pqd_idlSSST_hqg0-FSS\U0-_pqd_idlSSSU_hqg0-FSS\V0-_pqd_idlSSSV_hqg0-FSS\W0-_pqd_idlSSSW_hqg0-FSS\X0-_nh|0-_iomTXVU]SUSS_idlSSSV0-_iomTXXS]SUST_hqg0-FSS\Y0-_nh|_p|eSSSU_zdlSSSU_sul_idlSSST_hqg0-FSTSS0-_sul_idrSSST_wudSS[T]SS\X]STXT]SSTV0-FSTTS0-_sul_irpSSTY_idrSSSV0-_zdlSSVS0-_iomTXVW]STTT0-_wudSS[W]SS\X]SSTS]SSSU0-FSTTT0-_wudSS[X]SS\X]SSTS]SSSU0-FSUSS0-_fqsSUSS]SVUS]SSSS0-_ioPTXVU_ioNTXVV0-_zdlSSSU_idlSSSV_iomTXXS]SUST_hqg0-FSUST0-_gqsSUST0-_fpsSSSZ]SSTW]SSST0-_fpsSSS[]SSTW]SSST0-_fpsSSS\]SSTW]SSST0-_fpsSSTS]SSTW]SSST0-_fpsSSTT]SSTW]SSST0-_fpsSSTU]SSTW]SSST0-_fpsSSTV]SSTW]SSST_hqg0-FSUWS0-FSUWT0-_gqsSUWT_dqsSUWS]SSTS]SSSV_hqg0-FSUWU0-FSUWV0-_gqsSUWV_dqsSUWU]SSTS]SSSV_hqg0-FSUWW0-FSUWX0-_gqsSUWX_dqsSUWW]SSTS]SSSV_hqg0-FSUXS0-FSUXT0-_gqsSUXT_dqsSUXS]SSTS]SSST_hqg0-FSUXU0-#SUXV0-_gqsSUXV_dqsSUXU]SSTS]SSSV_hqg0-FSUXW0-FSUXX0-_gqsSUXX_dqsSUXW]SSTS]SSST_hqg0-FSUXY0-FSUXZ0-_gqsSUXZ_dqsSUXY]SSTS]SSSV_hqg0-FSU\S0-_gqsSU\S_vrxSSTU0-_fpsSTTZ]SSS\]SSU[0-_fpsSTTZ]SSTS]SSU[0-_fpsSTTZ]SSTT]SSU[0-_hqg0-FSU\T0-_gqsSU\T_vrxSSTU0-_fpsSS\X]SSSV]SSU[0-_fpsSS\X]SSSW]SSU[0-_fpsSS\X]SSSX]SSU[0-_fpsSS\X]SSSY]SSU[0-_hqg0-FSU\U0-_gqsSU\U_vrxSSTU0-_fpsSSSS]SSSS]SSU[0-_fpsSSSS]SSSS]SSU[0-_fpsSSSS]SSSS]SSU[0-_hqg0-FSVSS0-_gqsSVSS_gqdSVS\_gqdSVTT_gqdSVTZ0-_irqSVST]SSTY0-_fpxSSSZ_evoSSSS0-_fpsSSUS]SSTT]SSST0-_fpsSSUS]SSTU]SSST0-_erdSTSS0-_fqsTSST]SVVS]SSSS0-_fqsTSSU]SVVS]SSSU0-_vrxSSTU0-_hqg0-FSVST0-FSVSU0-_prySST[]SSTS_hqg0-FSV\S0-_sul_iomTXXT]SSST_ioNTXXT0-_vrxSSUU_fqsSV\S]SSUT]SSSS_hyhSWSS0-FSWSS0-_hyhSSVX0-FS\SS0-_gqsS\SS_hqg0-FS\ST0-_gqsS\ST_hqg0-FTSSS0-_erdSXSS_fpxSSSS_ioPTXXS_hqg0-FTSST0-FTSSU
>;Taaja>;m~rmt~<7E>adgmwrzaaaamvu>;Taajb>;m~rmt~<7E>adgmwrzaaabmvu>;Taajc>;m~rmt~<7E>adgmwrzaaacmvu>;Taajd>;m~rmt~<7E>adgmwrzaaadmvu>;Taaje>;m~rmt~<7E>adgmwrzaaaemvu>;Taajf>;m|v<>>;mw}{bfdckacaamwrzaaad>;mw}{bffakacabmvu>;Taajg>;m|v確~郭aaacm<63>zaaacmzmwrzaaabmvu>;Tabaa>;mzmwr€aaabm<62>raaibkaajfkabfbkaabd>;Tabba>;mzmw€~aabgmwr€aaad>;m<>zaada>;mw}{bfdekabbb>;m<>raaiekaajfkaabakaaac>;Tabbb>;m<>raaifkaajfkaabakaaac>;Tacaa>;mt∥caakadcakaaaa>;mw}^bfdcmw}\bfdd>;m<>zaaacmwrzaaadmw}{bffakacabmvu>;Tacab>;mu∥cab>;mt~∥aahkaabekaaab>;mt~∥aaikaabekaaab>;mt~∥aajkaabekaaab>;mt~∥abakaabekaaab>;mt~∥abbkaabekaaab>;mt~∥abckaabekaaab>;mt~∥abdkaabekaaabmvu>;Tacea>;Taceb>;mu∥cebmr∥ceakaabakaaadmvu>;Tacec>;Taced>;mu∥cedmr∥ceckaabakaaadmvu>;Tacee>;Tacef>;mu∥cefmr∥ceekaabakaaadmvu>;Tacfa>;Tacfb>;mu∥cfbmr∥cfakaa1akaaabmvu>;Tacfc>;Tacfd>;mu∥cfdmr∥cfckaabakaaadmvu>;Tacfe>;Tacff>;mu∥cffmr∥cfekaabakaaabmvu>;Tacfg>;Tacfh>;mu∥cfhmr∥cfgkaabakaaadmvu>;Tacja>;mu∥cjamо<6D>abc>;mt~∥bbhkaaajkaaci>;mt~∥bbhkaabakaaci>;mt~∥bbhkaabbkaaci>;mvu>;Tacjb>;mu∥cjbmо<6D>abc>;mt~∥ajfkaaadkaaci>;mt~∥ajfkaaaekaaci>;mt~∥ajfkaaafkaaci>;mt~∥ajfkaaagkaaci>;mvu>;Tacjc>;mu∥cjcmо<6D>abc>;mt~∥aaakaaaakaaci>;mt~∥aaakaaaakaaci>;mt~∥aaakaaaakaaci>;mvu>;Tadaa>;mu∥daamuradajmuradbbmuradbh>;mw€adabkaabg>;mt~<7E>aahmsмaaaa>;mt~∥acakaabbkaaab>;mt~∥acakaabckaaab>;ms€rabaa>;mtaabkaddakaaaa>;mtaackaddakaaac>;mо<6D>abc>;mvu>;Tadab>;Tadac>;m~€㌢abikaabamvu>;Tadja>;mzmw}{bffbkaaabmw}\bffb>;mо<6D>accmt∥djakaacbkaaaamv<6D>aeaa>;Taeaa>;mv<6D>aadf>;Tajaa>;mu∥jaamvu>;Tajab>;mu∥jabmvu>;Tbaaa>;ms€rafaamt~<7E>aaamw}^bffamvu>;Tbaab>;Tbaac

View file

@ -1,14 +1,14 @@
#0090
<MNA<FAI0000<END
<MNA<CMU0036<FAI0000<END
#0091
<MNA<FAI0001<END
<MNA<CMU0036<FAI0001<END
#0092
<MNA<FAI0002<END
<MNA<CMU0036<FAI0002<END
#0093
<MNA<FAI0003<END
<MNA<CMU0036<FAI0003<END
#0094
<MNA<FAI0004<END
<MNA<CMU0036<FAI0004<END
#0095
<KEY

227
src/database/music.lua Normal file
View file

@ -0,0 +1,227 @@
local song = Class:extend()
function song:new(name, id, jingle, beta)
self.name = name
self.id = id
self.jingle = jingle or false
self.beta = beta or false
end
local songs = {
xxxx = song("XXXX", "0000", true),
mischievousRobot = song("Mischievous Robot", "0001"),
safety = song("Safety", "0002"),
gameOver = song("Game Over", "0003", true),
gravity = song("Gravity", "0004"),
onToGrasstown = song("On to Grasstown", "0005"),
meltdown = song("Meltdown 2", "0006"),
eyesOfFlame = song("Eyes of Flame", "0007"),
gestation = song("Gestation", "0008"),
mimigaTown = song("Mimiga Town", "0009"),
getItem = song("Get Item!", "0010", true),
balrogsTheme = song("Balrog's Theme", "0011"),
cemetary = song("Cemetary", "0012"),
plant = song("Plant", "0013"),
pulse = song("Pulse", "0014"),
victory = song("Victory!", "0015", true),
getLifeCapsule = song("Get Life Capsule!", "0016", true),
tyrant = song("Tyrant", "0017"),
run = song("Run!", "0018"),
jenka1 = song("Jenka 1", "0019"),
labyrinthFight = song("Labyrinth Fight", "0020"),
access = song("Access", "0021"),
oppression = song("Oppression", "0022"),
geothermal = song("Geothermal", "0023"),
caveStory = song("Cave Story", "0024"),
moonsong = song("Moonsong", "0025"),
herosEnd = song("Hero's End", "0026"),
scorchingBack = song("Scorching Back", "0027"),
quiet = song("Quiet", "0028"),
finalCave = song("Final Cave", "0029"),
balcony = song("Balcony", "0030"),
charge = song("Charge", "0031"),
lastBattle = song("Last Battle", "0032"),
theWayBackHome = song("The Way Back Home", "0033"),
zombie = song("Zombie", "0034"),
breakDown = song("Break Down", "0035"),
runningHell = song("Running Hell", "0036"),
jenka2 = song("Jenka 2", "0037"),
livingWaterway = song("Living Waterway", "0038"),
sealChamber = song("Seal Chamber", "0039"),
torokosTheme = song("Toroko's Theme", "0040"),
white = song('"White"', "0041"),
windFortress = song("Wind Fortress", "0042", false, true),
halloween2 = song("Halloween 2", "0043", false, true),
peopleOfTheRoot = song("People of the Root", "0044", false, true),
pierWalk = song("Pier Walk", "0045", false, true),
snoopyCake = song("Snoopy Cake", "0046", false, true)
}
local cue = Class:extend()
function cue:new(map, events, default)
self.map = map
self.events = events
self.songid = default
self.default = default
end
local cues = {
cue("Pens1", {"0090", "0091", "0092", "0093", "0094", "0099"}, "0002"),
cue("Pens1", {"0095", "0098"}, "0014"),
cue("Eggs", {"0090", "0091", "0092", "0093", "0094", "0095", "0099", "0503"}, "0001"),
cue("Eggs", {"0600"}, "0004"),
cue("EggX", {"0095"}, "0014"),
cue("EggR", {"0090", "0091", "0092", "0093", "0094"}, "0008"),
cue("Weed", {"0090", "0091", "0092", "0093", "0094", "0098", "0099"}, "0005"),
cue("Santa", {"0090", "0091", "0092", "0093", "0094"}, "0002"),
cue("Santa", {"0099"}, "0028"),
cue("Chako", {"0090", "0091", "0092", "0093", "0094"}, "0002"),
cue("Chako", {"0099"}, "0028"),
cue("MazeI", {"0090", "0091", "0092", "0093", "0094", "0400", "0601"}, "0019"),
cue("Sand", {"0090", "0091", "0092", "0093", "0094", "0099", "0210", "0601"}, "0006"),
cue("Sand", {"0202"}, "0007"),
cue("Mimi", {"0090", "0091", "0092", "0093", "0094", "0302"}, "0009"),
cue("Mimi", {"0095", "0096", "0097", "0098", "0099"}, "0028"),
cue("Cave", {"0090", "0091", "0092", "0093", "0094"}, "0008"),
cue("Start", {"0090", "0091", "0092", "0093", "0094"}, "0008"),
cue("Barr", {"0090", "0091", "0092", "0093", "0094", "0402", "1001"}, "0008"),
cue("Barr", {"1000"}, "0011"),
cue("Barr", {"1000"}, "0004"),
cue("Pool", {"0090", "0091", "0092", "0093", "0094"}, "0009"),
cue("Pool", {"0095", "0096", "0097", "0098", "0099", "0410"}, "0028"),
cue("Cemet", {"0090", "0091", "0092", "0093", "0094"}, "0012"),
cue("Plant", {"0090", "0091", "0092", "0093", "0094"}, "0013"),
cue("Plant", {"0095", "0096", "0097", "0098", "0099"}, "0028"),
cue("Shelt", {"0090", "0091", "0092", "0093", "0094", "0099"}, "0008"),
cue("Comu", {"0090", "0091", "0092", "0093", "0094"}, "0009"),
cue("Comu", {"0095", "0096", "0097", "0098", "0099"}, "0028"),
cue("Cthu", {"0090", "0091", "0092", "0093", "0094"}, "0008"),
cue("Malco", {"0090", "0091", "0092", "0093", "0094", "0203"}, "0008"),
cue("Malco", {"0200", "0204"}, "0004"),
cue("Malco", {"0200"}, "0011"),
cue("Frog", {"0090", "0091", "0092", "0093", "0094", "1000"}, "0008"),
cue("Frog", {"0202"}, "0011"),
cue("Frog", {"0202"}, "0007"),
cue("Curly", {"0090", "0091", "0092", "0093", "0094"}, "0002"),
cue("Curly", {"0300"}, "0004"),
cue("WeedB", {"0302"}, "0004"),
cue("Stream", {"0090", "0091", "0092", "0093", "0094"}, "0018"),
cue("Jenka1", {"0090", "0091", "0092", "0093", "0094"}, "0019"),
cue("Gard", {"0502"}, "0017"),
cue("Gard", {"0502"}, "0018"),
cue("Gard", {"0502"}, "0004"),
cue("Jenka2", {"0090", "0091", "0092", "0093", "0095", "0200"}, "0019"),
cue("Jenka2", {"0094"}, "0011"),
cue("SandE", {"0090", "0091", "0092", "0093", "0094", "0600"}, "0006"),
cue("SandE", {"0600"}, "0011"),
cue("MazeH", {"0090", "0091", "0092", "0093", "0094"}, "0019"),
cue("MazeW", {"0090", "0091", "0092", "0093", "0094", "1000"}, "0037"),
cue("MazeW", {"0302"}, "0007"),
cue("MazeO", {"0090", "0091", "0092", "0093", "0094"}, "0002"),
cue("MazeD", {"0400"}, "0004"),
cue("MazeA", {"0090", "0091", "0092", "0093", "0094", "0301"}, "0008"),
cue("MazeB", {"0090", "0091", "0092", "0093", "0094", "0099"}, "0008"),
cue("MazeS", {"0090", "0091", "0092", "0093", "0094", "0310", "0600"}, "0008"),
cue("MazeS", {"0321"}, "0011"),
cue("MazeS", {"0321"}, "0004"),
cue("MazeM", {"0090", "0091", "0092", "0093", "0094", "0301"}, "0020"),
cue("Drain", {"0090", "0091", "0092", "0093", "0094", "0150"}, "0008"),
cue("Drain", {"0095", "0096", "0097"}, "0023"),
cue("Almond", {"0090", "0091", "0092", "0093", "0094", "0361"}, "0023"),
cue("Almond", {"0452", "0500"}, "0022"),
cue("River", {"0090", "0091", "0092", "0093", "0094", "0095"}, "0038"),
cue("Eggs2", {"0090", "0091", "0092", "0093", "0094", "0099"}, "0027"),
cue("Cthu2", {"0090", "0091", "0092", "0093", "0094"}, "0008"),
cue("EggR2", {"0090", "0091", "0092", "0093", "0094", "1000"}, "0008"),
cue("EggR2", {"0304"}, "0004"),
cue("EggX2", {"0090", "0091", "0092", "0093", "0095"}, "0014"),
cue("Oside", {"0090", "0091", "0092", "0093", "0094"}, "0025"),
cue("Oside", {"0402"}, "0026"),
cue("Itoh", {"0090", "0091", "0092", "0093", "0094", "0095"}, "0008"),
cue("Cent", {"0090", "0091", "0092", "0093", "0094"}, "0024"),
cue("Jail1", {"0090", "0091", "0092", "0093", "0094", "0220"}, "0008"),
cue("Momo", {"0090", "0091", "0092", "0093", "0094"}, "0002"),
cue("lounge", {"0090", "0091", "0092", "0093", "0094"}, "0002"),
cue("Jail2", {"0090", "0091", "0092", "0093", "0094", "0099"}, "0008"),
cue("Blcny1", {"0090", "0091", "0092", "0093", "0094"}, "0030"),
cue("Priso1", {"0090", "0091", "0092", "0093", "0094"}, "0029"),
cue("Ring1", {"0090", "0091", "0092", "0093", "0094", "0097", "0098", "0402"}, "0030"),
cue("Ring1", {"0502", "0503"}, "0007"),
cue("Ring1", {"0099"}, "0018"),
cue("Ring2", {"0090", "0091", "0092", "0093", "0094", "0098", "0420"}, "0030"),
cue("Ring2", {"0502"}, "0007"),
cue("Ring2", {"0410"}, "0031"),
cue("Prefa1", {"0090", "0091", "0092", "0093", "0094"}, "0030"),
cue("Priso2", {"0090", "0091", "0092", "0093", "0094", "0250"}, "0029"),
cue("Priso2", {"0241"}, "0004"),
cue("Ring3", {"0502"}, "0034"),
cue("Ring3", {"0502"}, "0032"),
cue("Ring3", {"0600"}, "0018"),
cue("Little", {"0090", "0091", "0092", "0093", "0094"}, "0002"),
cue("Blcny2", {"0090", "0091", "0092", "0093", "0094"}, "0018"),
cue("Blcny2", {"0400"}, "0035"),
cue("Pixel", {"0090", "0091", "0092", "0093", "0094", "0253"}, "0014"),
cue("Hell1", {"0090", "0091", "0092", "0094", "0096"}, "0036"),
cue("Hell2", {"0090", "0091", "0092", "0093", "0094"}, "0036"),
cue("Hell3", {"0090", "0091", "0092", "0093", "0094"}, "0036"),
cue("Hell3", {"0300"}, "0007"),
cue("Mapi", {"0420"}, "0004"),
cue("Ballo1", {"0095"}, "0039"),
cue("Ballo1", {"0500"}, "0004"),
cue("Ballo1", {"0900"}, "0007"),
cue("Ballo1", {"1000"}, "0032"),
cue("Pole", {"0090", "0091", "0092", "0093", "0094", "0095"}, "0008"),
cue("Ballo2", {"0500"}, "0034")
}
local music = Class:extend()
function music:new()
self.betaEnabled = false
self.songs = songs
self.cues = cues
end
local _isValid = function(key, song, self)
return not song.jingle and (not song.beta or self.betaEnabled)
end
function music:getShuffledSongs()
return _.shuffle(_.filter(self.songs, _isValid, self))
end
function music:getCues()
return self.cues
end
-- SHUFFLE songs: every cue with a given song becomes the same, new song
function music:shuffle(tscFiles)
local shuffled = self:getShuffledSongs()
local idmap = _.map(self.songs, function (k,v)
-- don't remap any invalid songs
if not _isValid(k,v,self) then return v.id, v.id end
return v.id, _.pop(shuffled).id
end)
for k,cue in pairs(self.cues) do
cue.songid = idmap[cue.songid]
end
self:writeCues(tscFiles)
end
-- RANDOMIZE songs: any cue can play any song
function music:randomize(tscFiles)
for k,cue in pairs(self.cues) do
cue.songid = self:getShuffledSongs()[1].id
end
self:writeCues(tscFiles)
end
function music:writeCues(tscFiles)
for k,cue in pairs(self.cues) do
for k,event in ipairs(cue.events) do
tscFiles[cue.map]:placeSongAtCue(cue.songid, event, cue.map, cue.default)
end
end
end
return music

View file

@ -1,6 +1,7 @@
local Items = require 'database.items'
local TscFile = require 'tsc_file'
local WorldGraph = require 'database.world_graph'
local Music = require 'database.music'
local C = Class:extend()
@ -14,6 +15,12 @@ do
end
end
end
for key, cue in pairs(Music():getCues()) do
local filename = cue.map
if not _.contains(TSC_FILES, filename) then
table.insert(TSC_FILES, filename)
end
end
end
local csdirectory
@ -32,6 +39,8 @@ function C:new()
self._isCaveStoryPlus = false
self.itemDeck = Items()
self.worldGraph = WorldGraph(self.itemDeck)
self.music = Music()
self.customseed = nil
self.puppy = false
self.obj = ""
@ -61,8 +70,10 @@ function C:randomize()
self:_updateSharecode(seed)
local tscFiles = self:_createTscFiles(dirStage)
-- self:_writePlaintext(tscFiles)
self:_shuffleItems(tscFiles)
self.music:randomize(tscFiles)
self:_writeModifiedData(tscFiles)
self:_writePlaintext(tscFiles)
self:_writeLog()

View file

@ -19,20 +19,6 @@ function C:new(path)
assert(file:close())
assert(file:release())
-- Determine set of items which can be replaced later.
--[[
self._unreplaced = {}
self._mapName = path:match("^.+/(.+)$")
for k, v in pairs(ITEM_DATA) do repeat
if (v.map .. '.tsc') ~= self._mapName then
break -- continue
end
local item = _.clone(v)
table.insert(self._unreplaced, item)
until true end
self._unreplaced = _.shuffle(self._unreplaced)
]]
end
function C:hasUnreplacedItems()
@ -48,103 +34,51 @@ function C:placeItemAtLocation(item, location)
end
end
function C:replaceItem(replacement)
assert(self:hasUnreplacedItems())
local key = self._unreplaced[#self._unreplaced].key
self:replaceSpecificItem(key, replacement)
function C:placeSongAtCue(songid, event, map, originalid)
local wasChanged
self._text, wasChanged = self:_stringReplace(self._text, "<CMU" .. originalid, "<CMU" .. songid, event, {"<CMU0015", "<CMU0000"})
if not wasChanged then
local template = "Unable to replace [%s] event #%s's music cue with %q."
logWarning(template:format(map, event, songid))
end
end
function C:replaceSpecificItem(originalKey, replacement)
-- Fetch item with key matching originalKey.
local original
for index, item in ipairs(self._unreplaced) do
if item.key == originalKey then
original = item
table.remove(self._unreplaced, index)
break
function C:_stringReplace(text, needle, replacement, label, overrides)
overrides = overrides or {}
local pStart, pEnd = self:_getLabelPositionRange(label)
local i, o = -1, -1
while(o <= i) do
o = nil
i = text:find(needle, pStart)
if i == nil then
logDebug(('Unable to replace "%s" with "%s"'):format(needle, replacement))
return text, false
elseif i > pEnd then
-- This is totally normal and can be ignored.
logDebug(('Found "%s", but was outside of label.'):format(needle, replacement))
return text, false
end
end
assert(original, 'No unreplaced item with key: ' .. originalKey)
-- Log change
local template = "[%s] %s -> %s"
logNotice(template:format(self._mapName, original.name, replacement.name))
-- Replace before.
if original.replaceBefore then
for needle, replacement in pairs(original.replaceBefore) do
local wasChanged
self._text, wasChanged = self:_stringReplace(self._text, needle, replacement, original.label)
-- Log error if replace was not optional.
if wasChanged == false then
local wasOptional = false
for _, pattern in ipairs(OPTIONAL_REPLACES) do
if needle:find(pattern, 1, true) then
wasOptional = true
break
end
end
if wasOptional == false then
local template = 'Unable to replace [%s] "%s" with "%s".'
logError(template:format(original.map, needle, replacement))
-- find the earliest occurence of an override
for k,v in ipairs(overrides) do
local over = text:find(v, pStart)
if over ~= nil then
if o ~= nil then
o = math.min(o, over)
else
o = over
end
end
end
-- no overrides found
if o == nil then break end
pStart = o+1
end
-- Replace attributes.
self:_replaceAttribute(original, replacement, 'command')
self:_replaceAttribute(original, replacement, 'getText')
self:_replaceAttribute(original, replacement, 'displayCmd')
self:_replaceAttribute(original, replacement, 'music')
end
function C:_replaceAttribute(original, replacement, attribute)
local originalTexts = original[attribute]
if originalTexts == nil or originalTexts == '' then
return
elseif type(originalTexts) == 'string' then
originalTexts = {originalTexts}
end
local replaceText = replacement[attribute] or ''
if type(replaceText) == 'table' then
replaceText = replaceText[1]
end
-- Fix: After collecting Curly's Panties or Chako's Rouge, music would go silent.
if attribute == 'music' and replaceText == '' then
replaceText = "<CMU0010"
end
-- Loop through each possible original value until we successfully replace one.
for _, originalText in ipairs(originalTexts) do repeat
if originalText == "" then
break -- continue
end
local changed
self._text, changed = self:_stringReplace(self._text, originalText, replaceText, original.label)
if changed then
return
end
until true end
local logMethod = (attribute == 'command') and logError or logWarning
local template = 'Unable to replace original "%s" for [%s] %s.'
logMethod(template:format(attribute, original.map, original.name))
end
function C:_stringReplace(text, needle, replacement, label)
local pStart, pEnd = self:_getLabelPositionRange(label)
local i = text:find(needle, pStart)
if i == nil then
logNotice(('Unable to replace "%s" with "%s"'):format(needle, replacement))
return text, false
elseif i > pEnd then
-- This is totally normal and can be ignored.
logNotice(('Found "%s", but was outside of label.'):format(needle, replacement))
return text, false
end
local len = needle:len()
local j = i + len - 1
assert((i % 1 == 0) and (i > 0) and (i <= j), tostring(i))
@ -170,7 +104,7 @@ function C:_getLabelPositionRange(label)
assert(type(label) == 'string')
assert(#label == 4)
assert(tonumber(label) >= 1)
assert(tonumber(label) >= 0)
assert(tonumber(label) <= 9999)
local i = 1