2019-03-19 08:56:38 +00:00
local Items = require ' database.items '
2018-12-19 04:06:41 +00:00
local TscFile = require ' tsc_file '
2019-03-19 08:56:38 +00:00
local WorldGraph = require ' database.world_graph '
2020-03-03 05:02:23 +00:00
local Music = require ' database.music '
2018-12-19 04:06:41 +00:00
local C = Class : extend ( )
local TSC_FILES = { }
do
2019-03-20 12:37:07 +00:00
for key , location in ipairs ( WorldGraph ( Items ( ) ) : getLocations ( ) ) do
if location.map ~= nil and location.event ~= nil then
local filename = location.map
if not _.contains ( TSC_FILES , filename ) then
table.insert ( TSC_FILES , filename )
end
2018-12-19 04:06:41 +00:00
end
end
2020-03-03 05:02:23 +00:00
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
2018-12-19 04:06:41 +00:00
end
2019-09-11 10:39:10 +00:00
local csdirectory
2019-03-25 08:23:29 +00:00
local function mkdir ( path )
local mkdir_str
if package.config : sub ( 1 , 1 ) == ' \\ ' then -- Windows
mkdir_str = ' mkdir "%s" '
else -- *nix
mkdir_str = " mkdir -p '%s' "
end
os.execute ( mkdir_str : format ( path ) ) -- HERE BE DRAGONS!!!
end
2018-12-29 08:23:24 +00:00
function C : new ( )
self._isCaveStoryPlus = false
2019-03-19 08:56:38 +00:00
self.itemDeck = Items ( )
2019-03-20 12:37:07 +00:00
self.worldGraph = WorldGraph ( self.itemDeck )
2020-03-03 05:02:23 +00:00
self.music = Music ( )
2019-09-12 02:51:48 +00:00
self.customseed = nil
2020-02-26 04:54:19 +00:00
self.puppy = false
2020-02-28 00:21:21 +00:00
self.obj = " "
2020-02-28 09:20:05 +00:00
self.sharecode = " "
2020-02-28 13:48:45 +00:00
self.mychar = " "
2020-03-03 05:52:39 +00:00
self.shuffleMusic = false
2021-04-06 03:15:11 +00:00
self.completableLogic = true
2021-04-06 07:11:47 +00:00
self.spheres = { }
2018-12-29 08:23:24 +00:00
end
2019-09-11 10:39:10 +00:00
function C : setPath ( path )
csdirectory = path
end
2019-09-11 23:03:27 +00:00
function C : ready ( )
return csdirectory ~= nil
end
2019-09-11 10:39:10 +00:00
function C : randomize ( )
2018-12-19 21:39:40 +00:00
resetLog ( )
2018-12-29 02:27:25 +00:00
logNotice ( ' === Cave Story Randomizer v ' .. VERSION .. ' === ' )
2019-09-11 10:39:10 +00:00
local success , dirStage = self : _mountDirectory ( csdirectory )
2018-12-19 04:06:41 +00:00
if not success then
return " Could not find \" data \" subfolder. \n \n Maybe try dropping your Cave Story \" data \" folder in directly? "
end
2019-03-24 16:16:13 +00:00
2020-02-28 09:20:05 +00:00
self : _logSettings ( )
2021-03-02 00:54:05 +00:00
local seed = self : _seedRngesus ( self.obj ) -- append obj string in order to shuffle differently depending on the objective
2020-02-28 09:20:05 +00:00
self : _updateSharecode ( seed )
2018-12-19 04:06:41 +00:00
local tscFiles = self : _createTscFiles ( dirStage )
2020-03-03 05:52:39 +00:00
2019-03-19 08:56:38 +00:00
self : _shuffleItems ( tscFiles )
2020-03-07 07:58:03 +00:00
self : _generateHash ( )
2020-03-03 05:52:39 +00:00
if self.shuffleMusic then self.music : shuffleMusic ( tscFiles ) end
2020-03-03 05:02:23 +00:00
2021-04-06 07:11:47 +00:00
self : _logSpheres ( )
2021-04-06 05:58:00 +00:00
self : _generateRoute ( )
2019-03-20 12:37:07 +00:00
self : _writeModifiedData ( tscFiles )
2018-12-29 19:28:20 +00:00
self : _writePlaintext ( tscFiles )
2018-12-19 21:39:40 +00:00
self : _writeLog ( )
2020-02-28 13:48:45 +00:00
self : _copyMyChar ( )
2019-09-11 10:39:10 +00:00
self : _unmountDirectory ( csdirectory )
2020-02-28 05:54:37 +00:00
self : _updateSettings ( )
2020-02-28 09:20:05 +00:00
return self : _getStatusMessage ( seed , self.sharecode )
2018-12-19 04:06:41 +00:00
end
function C : _mountDirectory ( path )
local mountPath = ' mounted-data '
assert ( lf.mount ( path , mountPath ) )
local dirStage = ' / ' .. mountPath
local items = lf.getDirectoryItems ( dirStage )
local containsData = _.contains ( items , ' data ' )
if containsData then
dirStage = dirStage .. ' /data '
end
2018-12-19 23:39:08 +00:00
-- For Cave Story+
local items = lf.getDirectoryItems ( dirStage )
local containsBase = _.contains ( items , ' base ' )
if containsBase then
dirStage = dirStage .. ' /base '
2018-12-29 08:23:24 +00:00
self._isCaveStoryPlus = true
2018-12-19 23:39:08 +00:00
end
2018-12-19 04:06:41 +00:00
local items = lf.getDirectoryItems ( dirStage )
local containsStage = _.contains ( items , ' Stage ' )
if containsStage then
dirStage = dirStage .. ' /Stage '
else
return false , ' '
end
return true , dirStage
end
2021-03-02 00:54:05 +00:00
function C : _seedRngesus ( suffix )
2019-09-15 23:38:09 +00:00
local seedstring = self.customseed or tostring ( os.time ( ) )
2021-03-02 00:54:05 +00:00
local seed = ld.encode ( ' string ' , ' hex ' , ld.hash ( ' sha256 ' , seedstring .. suffix ) )
2019-09-15 23:38:09 +00:00
local s1 = tonumber ( seed : sub ( - 8 , - 1 ) , 16 ) -- first 32 bits (from right)
local s2 = tonumber ( seed : sub ( - 16 , - 9 ) , 16 ) -- next 32 bits
love.math . setRandomSeed ( s1 , s2 )
2019-09-12 03:04:14 +00:00
logNotice ( ( ' Offering seed "%s" to RNGesus ' ) : format ( seedstring ) )
return seedstring
2019-03-28 05:45:22 +00:00
end
2018-12-19 04:06:41 +00:00
function C : _createTscFiles ( dirStage )
local tscFiles = { }
for _ , filename in ipairs ( TSC_FILES ) do
2019-03-25 09:26:40 +00:00
local path = dirStage .. ' / ' .. filename .. " .tsc "
2018-12-19 04:06:41 +00:00
tscFiles [ filename ] = TscFile ( path )
2019-03-20 12:37:07 +00:00
tscFiles [ filename ] . mapName = filename
2018-12-19 04:06:41 +00:00
end
return tscFiles
end
2018-12-20 05:07:01 +00:00
function C : _writePlaintext ( tscFiles )
local sourcePath = lf.getSourceBaseDirectory ( )
-- Create /data/Plaintext if it doesn't already exist.
2019-03-25 08:23:29 +00:00
mkdir ( sourcePath .. ' /data/Plaintext ' )
2018-12-20 05:07:01 +00:00
-- Write modified files.
for filename , tscFile in pairs ( tscFiles ) do
2019-03-20 12:37:07 +00:00
local path = sourcePath .. ' /data/Plaintext/ ' .. filename .. ' .txt '
2018-12-20 05:07:01 +00:00
tscFile : writePlaintextTo ( path )
end
end
2020-02-28 00:21:21 +00:00
function C : getObjective ( )
return { self.itemDeck : getByKey ( self.obj ) }
2020-02-26 07:34:19 +00:00
end
2018-12-19 04:06:41 +00:00
function C : _shuffleItems ( tscFiles )
2020-02-28 23:23:21 +00:00
local obj = self : getObjective ( ) [ 1 ]
obj.name = obj.name .. ( " , %s " ) : format ( self.worldGraph . spawn )
obj.script = obj.script .. self.worldGraph : getSpawnScript ( )
2020-03-01 10:38:13 +00:00
if self.worldGraph . seqbreak and self.worldGraph . dboosts.rocket . enabled then obj.script = " <FL+6400 " .. obj.script end
2020-07-16 20:39:32 +00:00
if self.worldGraph . noFallingBlocks then obj.script = " <FL+1351 " .. obj.script end
2020-02-28 00:21:21 +00:00
-- place the objective scripts in Start Point
2020-02-28 23:23:21 +00:00
self : _fastFillItems ( { obj } , self.worldGraph : getObjectiveSpot ( ) )
2020-02-28 05:19:21 +00:00
2020-02-28 22:58:29 +00:00
if self.worldGraph : StartPoint ( ) then
-- first, fill one of the first cave spots with a weapon that can break blocks
2021-03-02 00:54:05 +00:00
_.shuffle ( self.worldGraph : getFirstCaveSpots ( ) ) [ 1 ] : setItem ( _.shuffle ( self.itemDeck : getItemsByAttribute ( " weaponSN " ) ) [ 1 ] )
2020-02-28 22:58:29 +00:00
elseif self.worldGraph : Camp ( ) then
-- give Dr. Gero a strong weapon... you'll need it
2021-03-02 00:54:05 +00:00
self.worldGraph : getCamp ( ) [ 1 ] : setItem ( _.shuffle ( self.itemDeck : getItemsByAttribute ( " weaponStrong " ) ) [ 1 ] )
2020-02-29 10:29:03 +00:00
-- and some HP once you fight your way past the first few enemies
self.worldGraph : getCamp ( ) [ 2 ] : setItem ( self.itemDeck : getByKey ( " capsule5G " ) )
2020-02-28 22:58:29 +00:00
end
2020-02-26 07:34:19 +00:00
2020-02-28 05:19:21 +00:00
-- place the bomb on MALCO for bad end
if self.obj == " objBadEnd " then
self.worldGraph : getMALCO ( ) [ 1 ] : setItem ( self.itemDeck : getByKey ( " bomb " ) )
end
2021-03-02 00:54:05 +00:00
local mandatory = _.compact ( _.shuffle ( self.itemDeck : getMandatoryItems ( true ) ) )
local optional = _.compact ( _.shuffle ( self.itemDeck : getOptionalItems ( true ) ) )
local puppies = _.compact ( _.shuffle ( self.itemDeck : getItemsByAttribute ( " puppy " ) ) )
2020-02-26 04:54:19 +00:00
if not self.puppy then
2020-02-28 00:53:22 +00:00
-- then fill puppies, for normal gameplay
2021-03-02 00:54:05 +00:00
self : _fastFillItems ( puppies , _.shuffle ( self.worldGraph : getPuppySpots ( ) ) )
2020-02-26 04:54:19 +00:00
else
-- for puppysanity, shuffle puppies in with the mandatory items
2021-03-02 00:54:05 +00:00
mandatory = _.shuffle ( _.append ( mandatory , puppies ) )
2020-02-28 00:53:22 +00:00
puppies = { }
2020-02-26 04:54:19 +00:00
end
2019-03-21 05:46:22 +00:00
2019-03-19 08:56:38 +00:00
-- next fill hell chests, which cannot have mandatory items
2021-04-06 03:15:11 +00:00
if not self.completableLogic then
self : _fastFillItems ( optional , _.shuffle ( self.worldGraph : getHellSpots ( ) ) )
end
2018-12-19 23:49:40 +00:00
2020-03-06 11:51:28 +00:00
-- add map system AFTER filling hell chests so that it gets placed somewhere accessible in every objective
optional = _.append ( optional , self.itemDeck : getByKey ( " mapSystem " ) )
2020-02-28 00:53:22 +00:00
-- place mandatory items with assume fill
2021-03-02 00:54:05 +00:00
self : _fillItems ( mandatory , _.shuffle ( _.reverse ( self.worldGraph : getEmptyLocations ( ) ) ) )
2020-02-28 00:53:22 +00:00
-- place optional items with a simple random fill
local opt = # optional
local loc = # self.worldGraph : getEmptyLocations ( )
if opt > loc then
logWarning ( ( " Trying to fill more optional items than there are locations! Items: %d Locations: %d " ) : format ( opt , loc ) )
end
2021-03-02 00:54:05 +00:00
self : _fastFillItems ( optional , _.shuffle ( self.worldGraph : getEmptyLocations ( ) ) )
2020-03-03 14:20:04 +00:00
self : _generateHints ( )
2019-03-10 05:41:37 +00:00
2020-03-08 22:24:11 +00:00
if tscFiles ~= nil then
self.worldGraph : writeItems ( tscFiles )
self.worldGraph : logLocations ( )
end
2019-03-19 08:56:38 +00:00
end
2018-12-19 20:15:26 +00:00
2019-03-21 05:46:22 +00:00
function C : _fillItems ( items , locations )
assert ( # items > 0 , ( " No items provided! Trying to fill %s locations. " ) : format ( # locations ) )
2019-03-20 12:37:07 +00:00
assert ( # items <= # locations , string.format ( " Trying to fill more items than there are locations! Items: %d Locations: %d " , # items , # locations ) )
2019-03-15 04:05:08 +00:00
2019-03-21 05:46:22 +00:00
local itemsLeft = _.clone ( items )
2019-03-21 08:21:30 +00:00
repeat
local item = _.pop ( itemsLeft )
local assumed = self.worldGraph : collect ( itemsLeft )
2021-04-06 03:15:11 +00:00
local filter = function ( k , v ) return not v : hasItem ( ) and v : canAccess ( assumed ) end
2021-04-06 05:58:00 +00:00
if self.completableLogic and self.worldGraph : canBeatGame ( assumed , self.obj ) then
2021-04-06 03:15:11 +00:00
filter = function ( k , v ) return not v : hasItem ( ) end
end
local fillable = _.filter ( locations , filter )
2019-03-21 08:21:30 +00:00
2019-03-21 10:14:56 +00:00
if # fillable > 0 then
logDebug ( ( " Placing %s at %s " ) : format ( item.name , fillable [ 1 ] . name ) )
fillable [ 1 ] : setItem ( item )
else
logError ( ( " No available locations for %s! Items left: %d " ) : format ( item.name , # itemsLeft ) )
end
2019-03-21 08:21:30 +00:00
until # itemsLeft == 0
2019-03-19 08:56:38 +00:00
end
2019-03-15 04:05:08 +00:00
2019-03-19 08:56:38 +00:00
function C : _fastFillItems ( items , locations )
2019-03-21 05:46:22 +00:00
assert ( # items > 0 , ( " No items provided! Attempting to fast fill %s locations. " ) : format ( # locations ) )
2019-03-20 12:37:07 +00:00
for key , location in ipairs ( locations ) do
2019-03-21 05:46:22 +00:00
local item = _.pop ( items )
2019-03-20 12:37:07 +00:00
if item == nil then break end -- no items left to place, but there are still locations open
location : setItem ( item )
2019-03-10 05:41:37 +00:00
end
2018-12-19 04:06:41 +00:00
end
2021-04-06 07:11:47 +00:00
function C : _analyzeSpheres ( forceUpdate )
if not forceUpdate and # self.spheres > 0 then
return self.spheres
end
self.spheres = { }
2021-04-06 05:58:00 +00:00
local items = { }
local locations
repeat
local collected
collected , locations = self.worldGraph : collect ( items , locations , true )
local sphereItems = _.difference ( collected , items )
items = collected
2021-04-06 07:11:47 +00:00
local sphere = { }
for k , v in pairs ( sphereItems ) do
table.insert ( sphere , v )
end
if # sphere == 0 then break end
table.insert ( self.spheres , sphere )
until false
if self.obj ~= " objBadEnd " and self.obj ~= " objNormalEnd " then
-- add the hell sphere at the very end, shh it works trust me
local sphere = { }
table.insert ( sphere , self.worldGraph . regions.endgame . locations.hellB1 . item )
table.insert ( sphere , self.worldGraph . regions.endgame . locations.hellB3 . item )
table.insert ( self.spheres , sphere )
end
return self.spheres
end
2021-04-06 05:58:00 +00:00
2021-04-06 07:11:47 +00:00
function C : _logSpheres ( )
local total = 0
for i , sphere in ipairs ( self : _analyzeSpheres ( ) ) do
2021-04-06 05:58:00 +00:00
logSphere ( ( " Sphere %i " ) : format ( i ) )
2021-04-06 07:11:47 +00:00
for i2 , item in ipairs ( sphere ) do
if not _.contains ( item.attributes , " abstract " ) then
total = total + 1
end
if not _.contains ( item.attributes , " objective " ) then
logSphere ( ( " \t %s: %s " ) : format ( item.location_name , item.name ) )
2021-04-06 05:58:00 +00:00
end
end
2021-04-06 07:11:47 +00:00
end
logSphere ( ( " Maximum items to collect: %i " ) : format ( total ) )
2021-04-06 05:58:00 +00:00
end
function C : _generateRoute ( )
return
end
2020-03-03 14:20:04 +00:00
function C : _generateHints ( )
local toHint = _.shuffle ( self.worldGraph : getHintableLocations ( self.obj ) )
for k , hintLocation in ipairs ( _.shuffle ( self.worldGraph : getHintLocations ( ) ) ) do
hintLocation.item = self.worldGraph . items : createHint ( _.pop ( toHint ) )
end
2020-03-06 06:01:39 +00:00
self.worldGraph . hintregion.locations . mrsLittle.item = self.worldGraph . items : prebuiltHint ( self.worldGraph . regions.outerWall . locations.littleHouse )
self.worldGraph . hintregion.locations . malco.item = self.worldGraph . items : prebuiltHint ( self.worldGraph . regions.grasstownEast . locations.malco )
2021-03-30 11:20:03 +00:00
self.worldGraph . hintregion.locations . numahachi1.item = self.worldGraph . items : prebuiltHint ( self.worldGraph . regions.endgame . locations.hellB1 , " <CLR<EVE0302 " )
self.worldGraph . hintregion.locations . numahachi2.item = self.worldGraph . items : prebuiltHint ( self.worldGraph . regions.endgame . locations.hellB3 , " <CLR<EVE0303 " )
self.worldGraph . hintregion.locations . jenka.item = self.worldGraph . items : prebuiltHint ( self.worldGraph . regions.lowerSandZone . locations.jenka )
2020-03-03 14:20:04 +00:00
end
2018-12-19 04:06:41 +00:00
function C : _writeModifiedData ( tscFiles )
2018-12-29 08:23:24 +00:00
local basePath = self : _getWritePathStage ( )
2018-12-19 04:06:41 +00:00
for filename , tscFile in pairs ( tscFiles ) do
2019-03-20 12:37:07 +00:00
local path = basePath .. ' / ' .. filename .. ' .tsc '
2018-12-19 04:06:41 +00:00
tscFile : writeTo ( path )
end
end
2018-12-19 20:15:26 +00:00
function C : _copyModifiedFirstCave ( )
2018-12-29 08:23:24 +00:00
local cavePxmPath = self : _getWritePathStage ( ) .. ' /Cave.pxm '
2018-12-19 20:15:26 +00:00
local data = lf.read ( ' database/Cave.pxm ' )
assert ( data )
U.writeFile ( cavePxmPath , data )
end
2018-12-19 21:39:40 +00:00
function C : _writeLog ( )
2018-12-29 08:23:24 +00:00
local path = self : _getWritePath ( ) .. ' /log.txt '
2018-12-19 21:39:40 +00:00
local data = getLogText ( )
U.writeFile ( path , data )
end
2020-02-28 13:48:45 +00:00
function C : _copyMyChar ( )
2020-12-06 22:07:48 +00:00
local path = self : _getWritePath ( ) .. ' /MyChar.bmp '
2021-07-27 03:03:50 +00:00
if self.mychar then
local data = lf.read ( self.mychar )
U.writeFile ( path , data )
else
U.eraseFile ( path )
end
2020-02-28 13:48:45 +00:00
end
2020-03-07 07:58:03 +00:00
function C : _generateHash ( )
2021-07-27 02:32:12 +00:00
local serialized = table.concat ( self.worldGraph : serialize ( ) )
2021-04-06 02:04:06 +00:00
local hashed = ld.encode ( ' string ' , ' hex ' , ld.hash ( ' sha256 ' , serialized ) )
hashed = tonumber ( hashed : sub ( - 8 , - 1 ) , 16 )
hashed = hashed % ( 39 ^ 5 )
local h = { }
for i = 1 , 5 do
2021-07-27 02:32:12 +00:00
table.insert ( h , ( hashed % 39 ) + 1 )
2021-04-06 02:04:06 +00:00
hashed = math.floor ( hashed / 39 )
end
2020-03-07 07:58:03 +00:00
local path = self : _getWritePath ( ) .. ' /hash.txt '
U.writeFile ( path , ( " %04d,%04d,%04d,%04d,%04d " ) : format ( h [ 1 ] , h [ 2 ] , h [ 3 ] , h [ 4 ] , h [ 5 ] ) )
2020-03-08 22:24:11 +00:00
return h
2020-03-07 07:58:03 +00:00
end
2018-12-29 08:23:24 +00:00
function C : _getWritePath ( )
return select ( 1 , self : _getWritePaths ( ) )
end
function C : _getWritePathStage ( )
return select ( 2 , self : _getWritePaths ( ) )
end
function C : _getWritePaths ( )
if self._writePath == nil then
local sourcePath = lf.getSourceBaseDirectory ( )
self._writePath = sourcePath .. ' /data '
self._writePathStage = ( self._isCaveStoryPlus )
and ( self._writePath .. ' /base/Stage ' )
or ( self._writePath .. ' /Stage ' )
end
2019-09-13 05:40:26 +00:00
-- Create /data(/base)/Stage if it doesn't already exist.
mkdir ( self._writePathStage )
2018-12-29 08:23:24 +00:00
return self._writePath , self._writePathStage
end
2018-12-19 04:06:41 +00:00
function C : _unmountDirectory ( path )
assert ( lf.unmount ( path ) )
2018-12-19 21:39:40 +00:00
end
2020-02-28 09:20:05 +00:00
function C : _logSettings ( )
2020-02-28 23:23:21 +00:00
-- these random calls are a hacky way to make sure that
-- randomization changes between seeds if settings change
2020-02-28 09:20:05 +00:00
local obj = " Best Ending "
if self.obj == " objBadEnd " then
obj = " Bad Ending "
elseif self.obj == " objNormalEnd " then
obj = " Normal Ending "
elseif self.obj == " objAllBosses " then
obj = " All Bosses "
end
2020-02-28 23:23:21 +00:00
local spawn = ( " , %s " ) : format ( self.worldGraph . spawn )
2020-02-28 09:20:05 +00:00
local puppy = self.puppy and " , Puppysanity " or " "
2020-02-28 23:23:21 +00:00
logNotice ( ( " Game settings: %s " ) : format ( obj .. spawn .. puppy ) )
2020-02-28 09:20:05 +00:00
end
2020-02-28 05:54:37 +00:00
function C : _updateSettings ( )
Settings.settings . puppy = self.puppy
Settings.settings . obj = self.obj
2020-02-28 13:48:45 +00:00
Settings.settings . mychar = self.mychar
2020-02-28 23:50:30 +00:00
Settings.settings . spawn = self.worldGraph . spawn
2020-03-01 09:32:16 +00:00
Settings.settings . seqbreaks = self.worldGraph . seqbreak
Settings.settings . dboosts = _.map ( self.worldGraph . dboosts , function ( k , v ) return v.enabled end )
2020-03-03 07:21:07 +00:00
Settings.settings . musicShuffle = self.shuffleMusic
Settings.settings . musicBeta = self.music . betaEnabled
Settings.settings . musicFlavor = self.music . flavor
2020-07-16 20:39:32 +00:00
Settings.settings . noFallingBlocks = self.worldGraph . noFallingBlocks
2021-04-06 03:15:11 +00:00
Settings.settings . completableLogic = self.completableLogic
2020-02-28 05:54:37 +00:00
Settings : update ( )
end
2020-02-28 09:20:05 +00:00
function C : _updateSharecode ( seed )
2021-07-27 02:32:39 +00:00
local settings = 0 -- 0b0000000000000000
2020-02-28 09:20:05 +00:00
-- P: single bit used for puppysanity
2020-03-01 10:03:00 +00:00
-- O: three bits used for objective
-- S: three bits used for spawn location
-- B: single bit used for sequence breaks
2020-07-16 20:39:32 +00:00
-- F: single bit used for falling blocks in Hell
2021-07-27 02:32:39 +00:00
-- C: single bit used for completeable logic
-- 0b000000CFBSSSOOOP
2020-02-28 09:20:05 +00:00
2020-02-28 23:50:30 +00:00
-- bitshift intervals
2020-03-01 10:03:00 +00:00
local obj = 1
local pup = 0
local spn = 4
local brk = 7
2020-07-16 20:39:32 +00:00
local nfb = 8
2021-07-27 02:32:39 +00:00
local cpl = 9
2020-02-28 23:50:30 +00:00
2020-02-28 09:20:05 +00:00
if self.obj == " objBadEnd " then
2020-02-28 23:50:30 +00:00
settings = bit.bor ( settings , bit.blshift ( 1 , obj ) )
2020-02-28 09:20:05 +00:00
elseif self.obj == " objNormalEnd " then
2020-02-28 23:50:30 +00:00
settings = bit.bor ( settings , bit.blshift ( 2 , obj ) )
2020-02-28 09:20:05 +00:00
elseif self.obj == " objAllBosses " then
2020-02-28 23:50:30 +00:00
settings = bit.bor ( settings , bit.blshift ( 3 , obj ) )
2020-03-06 09:48:33 +00:00
elseif self.obj == " obj100Percent " then
settings = bit.bor ( settings , bit.blshift ( 4 , obj ) )
2020-02-28 23:50:30 +00:00
end
if self.puppy then settings = bit.bor ( settings , bit.blshift ( 1 , pup ) ) end
if self.worldGraph : StartPoint ( ) then
settings = bit.bor ( settings , bit.blshift ( 0 , spn ) )
elseif self.worldGraph : Arthur ( ) then
settings = bit.bor ( settings , bit.blshift ( 1 , spn ) )
elseif self.worldGraph : Camp ( ) then
settings = bit.bor ( settings , bit.blshift ( 2 , spn ) )
2020-02-28 09:20:05 +00:00
end
2020-03-01 10:03:00 +00:00
local seq = 0
if self.worldGraph . seqbreak then
settings = bit.bor ( settings , bit.blshift ( 1 , brk ) )
if self.worldGraph . dboosts.cthulhu . enabled then seq = bit.bor ( seq , 1 ) end
if self.worldGraph . dboosts.chaco . enabled then seq = bit.bor ( seq , 2 ) end
if self.worldGraph . dboosts.paxChaco . enabled then seq = bit.bor ( seq , 4 ) end
if self.worldGraph . dboosts.flightlessHut . enabled then seq = bit.bor ( seq , 8 ) end
if self.worldGraph . dboosts.camp . enabled then seq = bit.bor ( seq , 16 ) end
if self.worldGraph . dboosts.sisters . enabled then seq = bit.bor ( seq , 32 ) end
if self.worldGraph . dboosts.plantation . enabled then seq = bit.bor ( seq , 64 ) end
if self.worldGraph . dboosts.rocket . enabled then seq = bit.bor ( seq , 128 ) end
end
2020-07-16 20:39:32 +00:00
if self.worldGraph . noFallingBlocks then
settings = bit.bor ( settings , bit.blshift ( 1 , nfb ) )
end
2021-07-27 02:32:39 +00:00
if self.completableLogic then
settings = bit.bor ( settings , bit.blshift ( 1 , cpl ) )
end
2020-07-16 20:39:32 +00:00
2020-02-28 09:20:05 +00:00
if # seed < 20 then
seed = seed .. ( " " ) : rep ( 20 -# seed )
end
2020-07-16 20:39:32 +00:00
local packed = love.data . pack ( " data " , " <s1I2B " , seed , settings , seq )
2020-02-28 09:20:05 +00:00
self.sharecode = love.data . encode ( " string " , " base64 " , packed )
logNotice ( ( " Sharecode: %s " ) : format ( self.sharecode ) )
end
function C : _getStatusMessage ( seed , sharecode )
2018-12-19 21:39:40 +00:00
local warnings , errors = countLogWarningsAndErrors ( )
local line1
if warnings == 0 and errors == 0 then
2020-02-28 09:20:05 +00:00
line1 = ( " Randomized data successfully created! \n Seed: %s \n Sharecode: %s " ) : format ( seed , sharecode )
2018-12-19 21:39:40 +00:00
elseif warnings ~= 0 and errors == 0 then
line1 = ( " Randomized data was created with %d warning(s). " ) : format ( warnings )
else
return ( " Encountered %d error(s) and %d warning(s) when randomizing data! " ) : format ( errors , warnings )
end
local line2 = " Next overwrite the files in your copy of Cave Story with the versions in the newly created \" data \" folder. Don't forget to save a backup of the originals! "
local line3 = " Then play and have a fun! "
2020-02-28 09:20:05 +00:00
local status = ( " %s \n %s \n %s " ) : format ( line1 , line2 , line3 )
2018-12-19 21:39:40 +00:00
return status
2018-12-19 04:06:41 +00:00
end
return C