mirror of
https://github.com/cave-story-randomizer/cave-story-randomizer
synced 2025-03-24 19:09:22 +00:00
Item Randomizer works! Need full database though!!
This commit is contained in:
parent
768895badc
commit
510be9a9a1
|
@ -1,3 +1,7 @@
|
||||||
Cave Story Randomizer
|
Cave Story Randomizer
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
Issues
|
||||||
|
------
|
||||||
|
|
||||||
|
- Bubbler (and other weapons?) can't break blocks in the First Cave.
|
||||||
|
|
41
src/conf.lua
Normal file
41
src/conf.lua
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
if io then
|
||||||
|
io.stdout:setvbuf("no")
|
||||||
|
end
|
||||||
|
|
||||||
|
local seed = os.time()
|
||||||
|
math.randomseed(seed)
|
||||||
|
|
||||||
|
function love.conf(t)
|
||||||
|
t.window = {
|
||||||
|
title = "Cave Story Randomizer",
|
||||||
|
-- icon = 'icon.png',
|
||||||
|
width = 640,
|
||||||
|
height = 480,
|
||||||
|
resizable = false,
|
||||||
|
}
|
||||||
|
t.version = '11.1'
|
||||||
|
t.console = false
|
||||||
|
t.identity = 'CaveStoryRandomizer'
|
||||||
|
t.accelerometerjoystick = false
|
||||||
|
t.gammacorrect = false
|
||||||
|
|
||||||
|
-- t.releases = {
|
||||||
|
-- -- This is the name of the zip archive which contains your game.
|
||||||
|
-- title = 'Cave Story Randomizer',
|
||||||
|
-- -- This is the name of your game's executable.
|
||||||
|
-- package = 'Cave Story Randomizer',
|
||||||
|
-- loveVersion = '11.1',
|
||||||
|
-- version = nil,
|
||||||
|
-- author = 'shru',
|
||||||
|
-- email = nil,
|
||||||
|
-- description = nil,
|
||||||
|
-- homepage = 'https://shru.itch.io/cave-story-randomizer',
|
||||||
|
-- -- MacOS needs this.
|
||||||
|
-- identifier = 'CaveStoryRandomizer',
|
||||||
|
-- excludeFileList = {
|
||||||
|
-- -- '.+%.ase',
|
||||||
|
-- },
|
||||||
|
-- compile = false,
|
||||||
|
-- releaseDirectory = 'releases',
|
||||||
|
-- }
|
||||||
|
end
|
|
@ -1,5 +1,21 @@
|
||||||
return {
|
return {
|
||||||
-- Weapons
|
-- Weapons
|
||||||
|
-- wXXX = {
|
||||||
|
-- name = "",
|
||||||
|
-- map = "",
|
||||||
|
-- getText = "",
|
||||||
|
-- command = "",
|
||||||
|
-- displayCmd = "",
|
||||||
|
-- kind = "weapon",
|
||||||
|
-- },
|
||||||
|
wBubbler = {
|
||||||
|
name = "Bubbler",
|
||||||
|
map = "Comu",
|
||||||
|
getText = "Got the =Bubbler=!",
|
||||||
|
command = "<AM+0007:0100",
|
||||||
|
displayCmd = "<GIT0007",
|
||||||
|
kind = "weapon",
|
||||||
|
},
|
||||||
wPolar = {
|
wPolar = {
|
||||||
name = "Polar Star",
|
name = "Polar Star",
|
||||||
map = "Pole",
|
map = "Pole",
|
||||||
|
@ -12,10 +28,21 @@ return {
|
||||||
iPanties = {
|
iPanties = {
|
||||||
name = "Curly's Panties",
|
name = "Curly's Panties",
|
||||||
map = "CurlyS",
|
map = "CurlyS",
|
||||||
-- getText = "Found =Curly's Underwear=.",
|
getText = "Found =Curly's Underwear=.",
|
||||||
getText = "Found =Curly's Panties=.",
|
-- getText = "Found =Curly's Panties=.", -- Grrr
|
||||||
command = "<IT+0035",
|
command = "<IT+0035",
|
||||||
displayCmd = "<GIT1035",
|
displayCmd = "<GIT1035",
|
||||||
kind = "item",
|
kind = "item",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- #0200
|
||||||
|
-- <KEY<FLJ1640:0201<FL+1640<SOU0022<CNP0200:0021:0000
|
||||||
|
-- <MSGOpened the chest.<NOD<GIT0002<AM+0002:0000<CLR
|
||||||
|
-- <CMU0010Got the =Polar Star=!<WAI0160<NOD<GIT0000<CLO<RMU
|
||||||
|
-- <MSG
|
||||||
|
-- From somewhere, a transmission...<FAO0004<NOD<TRA0018:0501:0002:0000
|
||||||
|
|
||||||
|
-- #0420
|
||||||
|
-- <KEY<DNP0420<MSG<GIT1035<IT+0035
|
||||||
|
-- Found Curly's Panties.<NOD<END
|
||||||
|
|
|
@ -4,11 +4,9 @@ local ITEM_DATA = require 'database.items'
|
||||||
|
|
||||||
function C:new()
|
function C:new()
|
||||||
self._left = {}
|
self._left = {}
|
||||||
self._indexMap = {}
|
|
||||||
for k, v in pairs(ITEM_DATA) do
|
for k, v in pairs(ITEM_DATA) do
|
||||||
local item = _.clone(v)
|
local item = _.clone(v)
|
||||||
table.insert(self._left, item)
|
table.insert(self._left, item)
|
||||||
self._indexMap[item] = #self._left
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -26,18 +24,19 @@ end
|
||||||
function C:_getItem(filterFn)
|
function C:_getItem(filterFn)
|
||||||
-- Filter down to only applicable items.
|
-- Filter down to only applicable items.
|
||||||
local applicable = {}
|
local applicable = {}
|
||||||
for _, item in ipairs(self._left) do
|
local indexMap = {}
|
||||||
|
for index, item in ipairs(self._left) do
|
||||||
if filterFn(item) then
|
if filterFn(item) then
|
||||||
table.insert(applicable, item)
|
table.insert(applicable, item)
|
||||||
|
indexMap[item] = index
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
assert(#applicable >= 1, 'No applicable items!')
|
assert(#applicable >= 1, 'No applicable items!')
|
||||||
|
|
||||||
-- Select an item.
|
-- Select an item.
|
||||||
local selected = _.sample(applicable)
|
local selected = _.sample(applicable)
|
||||||
local index = self._indexMap[selected]
|
local index = indexMap[selected]
|
||||||
table.remove(self._left, index)
|
table.remove(self._left, index)
|
||||||
self._indexMap[selected] = nil
|
|
||||||
|
|
||||||
return selected
|
return selected
|
||||||
end
|
end
|
||||||
|
|
62
src/main.lua
62
src/main.lua
|
@ -1,5 +1,3 @@
|
||||||
io.stdout:setvbuf("no")
|
|
||||||
|
|
||||||
require 'lib.strict'
|
require 'lib.strict'
|
||||||
|
|
||||||
Class = require 'lib.classic'
|
Class = require 'lib.classic'
|
||||||
|
@ -8,7 +6,7 @@ Serpent = require 'lib.serpent'
|
||||||
|
|
||||||
lf = love.filesystem
|
lf = love.filesystem
|
||||||
|
|
||||||
local LOG_LEVEL = 5
|
local LOG_LEVEL = 4
|
||||||
local function _log(level, prefix, text, ...)
|
local function _log(level, prefix, text, ...)
|
||||||
if LOG_LEVEL >= level then
|
if LOG_LEVEL >= level then
|
||||||
print(prefix .. text, ...)
|
print(prefix .. text, ...)
|
||||||
|
@ -20,9 +18,16 @@ function logNotice(...) _log(3, 'NOTICE: ', ...) end
|
||||||
function logInfo(...) _log(4, 'INFO: ', ...) end
|
function logInfo(...) _log(4, 'INFO: ', ...) end
|
||||||
function logDebug(...) _log(5, 'DEBUG: ', ...) end
|
function logDebug(...) _log(5, 'DEBUG: ', ...) end
|
||||||
|
|
||||||
local TSC_FILES = {
|
local TSC_FILES = {}
|
||||||
'Pole.tsc',
|
do
|
||||||
}
|
local ITEM_DATA = require 'database.items'
|
||||||
|
for k, v in pairs(ITEM_DATA) do
|
||||||
|
local filename = v.map .. '.tsc'
|
||||||
|
if _.contains(TSC_FILES, filename) == false then
|
||||||
|
table.insert(TSC_FILES, filename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- function love.load()
|
-- function love.load()
|
||||||
-- -- readPXM('Pole.pxm')
|
-- -- readPXM('Pole.pxm')
|
||||||
|
@ -32,32 +37,42 @@ local TSC_FILES = {
|
||||||
-- end
|
-- end
|
||||||
|
|
||||||
function love.directorydropped(path)
|
function love.directorydropped(path)
|
||||||
-- Mount
|
-- Mount.
|
||||||
assert(lf.mount(path, 'data'))
|
local mountPath = 'mounted-data'
|
||||||
local items = lf.getDirectoryItems('/data')
|
assert(lf.mount(path, mountPath))
|
||||||
|
local items = lf.getDirectoryItems('/' .. mountPath)
|
||||||
local containsStage = _.contains(items, 'Stage')
|
local containsStage = _.contains(items, 'Stage')
|
||||||
assert(containsStage)
|
assert(containsStage)
|
||||||
local dirStage = '/data/Stage'
|
local dirStage = '/' .. mountPath .. '/Stage'
|
||||||
|
|
||||||
local tscFiles = {}
|
local tscFiles = {}
|
||||||
for _, filename in ipairs(TSC_FILES) do
|
for _, filename in ipairs(TSC_FILES) do
|
||||||
local path = dirStage .. '/' .. filename
|
local path = dirStage .. '/' .. filename
|
||||||
local TscFile = require 'tsc_file'
|
local TscFile = require 'tsc_file'
|
||||||
tscFiles[filename] = TscFile(path)
|
tscFiles[filename] = TscFile(path)
|
||||||
|
|
||||||
-- decoded = stringReplace(decoded, ITEM_DATA.wPolar.command, ITEM_DATA.iPanties.command)
|
|
||||||
-- decoded = stringReplace(decoded, ITEM_DATA.wPolar.getText, ITEM_DATA.iPanties.getText)
|
|
||||||
-- decoded = stringReplace(decoded, ITEM_DATA.wPolar.displayCmd, ITEM_DATA.iPanties.displayCmd)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Create ItemDeck.
|
||||||
local ItemDeck = require 'item_deck'
|
local ItemDeck = require 'item_deck'
|
||||||
local itemDeck = ItemDeck()
|
local itemDeck = ItemDeck()
|
||||||
print(Serpent.line(itemDeck:getWeapon()))
|
|
||||||
print(Serpent.line(itemDeck:getAny()))
|
|
||||||
|
|
||||||
tscFiles['Pole.tsc']:writeTo('Testing.tsc')
|
-- Place random weapon in Hermit Gunsmith.
|
||||||
|
tscFiles['Pole.tsc']:replaceItem(itemDeck:getWeapon())
|
||||||
|
|
||||||
-- Unmount
|
-- Replace all items.
|
||||||
|
for _, tscFile in pairs(tscFiles) do
|
||||||
|
while tscFile:hasUnreplacedItems() do
|
||||||
|
tscFile:replaceItem(itemDeck:getAny())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Write modified files.
|
||||||
|
for filename, tscFile in pairs(tscFiles) do
|
||||||
|
local path = '/data/Stage/' .. filename
|
||||||
|
tscFile:writeTo(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Unmount.
|
||||||
assert(lf.unmount(path))
|
assert(lf.unmount(path))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -66,14 +81,3 @@ function love.keypressed(key)
|
||||||
love.event.push('quit')
|
love.event.push('quit')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- #0200
|
|
||||||
-- <KEY<FLJ1640:0201<FL+1640<SOU0022<CNP0200:0021:0000
|
|
||||||
-- <MSGOpened the chest.<NOD<GIT0002<AM+0002:0000<CLR
|
|
||||||
-- <CMU0010Got the =Polar Star=!<WAI0160<NOD<GIT0000<CLO<RMU
|
|
||||||
-- <MSG
|
|
||||||
-- From somewhere, a transmission...<FAO0004<NOD<TRA0018:0501:0002:0000
|
|
||||||
|
|
||||||
-- #0420
|
|
||||||
-- <KEY<DNP0420<MSG<GIT1035<IT+0035
|
|
||||||
-- Found Curly's Panties.<NOD<END
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
local C = Class:extend()
|
local C = Class:extend()
|
||||||
|
|
||||||
-- local MODE_READ_BINARY = 'rb'
|
-- https://www.lua.org/manual/5.1/manual.html#5.7
|
||||||
local MODE_WRITE_BINARY = 'wb'
|
-- w+: Update mode, all previous data is erased;
|
||||||
|
-- b: Binary mode, forces Windows to save with Unix endings.
|
||||||
|
MODE_WRITE_ERASE_EXISTING = 'w+b'
|
||||||
|
|
||||||
|
local ITEM_DATA = require 'database.items'
|
||||||
|
|
||||||
function C:new(path)
|
function C:new(path)
|
||||||
logInfo('reading TSC: ' .. path)
|
logInfo('reading TSC: ' .. path)
|
||||||
|
@ -14,16 +18,61 @@ function C:new(path)
|
||||||
|
|
||||||
assert(file:close())
|
assert(file:close())
|
||||||
assert(file:release())
|
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()
|
||||||
|
return #self._unreplaced >= 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function _stringReplace(text, needle, replacement)
|
||||||
|
local i = text:find(needle, 1, true)
|
||||||
|
if i == nil then
|
||||||
|
logWarning(('Unable to replace "%s" with "%s"'):format(needle, replacement))
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
local len = needle:len()
|
||||||
|
local j = i + len - 1
|
||||||
|
assert((i % 1 == 0) and (i > 0) and (i <= j), tostring(i))
|
||||||
|
assert((j % 1 == 0), tostring(j))
|
||||||
|
local a = text:sub(1, i - 1)
|
||||||
|
local b = text:sub(j + 1)
|
||||||
|
return a .. replacement .. b
|
||||||
|
end
|
||||||
|
|
||||||
|
function C:replaceItem(replacement)
|
||||||
|
assert(self:hasUnreplacedItems())
|
||||||
|
local original = table.remove(self._unreplaced)
|
||||||
|
self._text = _stringReplace(self._text, original.command, replacement.command)
|
||||||
|
self._text = _stringReplace(self._text, original.getText, replacement.getText)
|
||||||
|
self._text = _stringReplace(self._text, original.displayCmd, replacement.displayCmd)
|
||||||
|
|
||||||
|
local template = "[%s] %s -> %s"
|
||||||
|
logNotice(template:format(self._mapName, original.name, replacement.name))
|
||||||
end
|
end
|
||||||
|
|
||||||
function C:writeTo(path)
|
function C:writeTo(path)
|
||||||
local encoded = self:_codec(self._text, 'encode')
|
local encoded = self:_codec(self._text, 'encode')
|
||||||
|
|
||||||
local tmpFile, err = io.open(path, MODE_WRITE_BINARY)
|
local filepath = lf.getSourceBaseDirectory() .. path
|
||||||
|
logInfo('writing TSC to: ' .. filepath)
|
||||||
|
|
||||||
|
local file, err = io.open(filepath, MODE_WRITE_ERASE_EXISTING)
|
||||||
assert(err == nil, err)
|
assert(err == nil, err)
|
||||||
tmpFile:write(encoded)
|
file:write(encoded)
|
||||||
tmpFile:flush()
|
file:flush()
|
||||||
tmpFile:close()
|
file:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
function C:_codec(text, mode)
|
function C:_codec(text, mode)
|
||||||
|
@ -66,18 +115,4 @@ function C:_codec(text, mode)
|
||||||
return decoded
|
return decoded
|
||||||
end
|
end
|
||||||
|
|
||||||
local function stringReplace(text, needle, replacement)
|
|
||||||
local i = text:find(needle, 1, true)
|
|
||||||
if i == nil then
|
|
||||||
return text
|
|
||||||
end
|
|
||||||
local len = needle:len()
|
|
||||||
local j = i + len - 1
|
|
||||||
assert((i % 1 == 0) and (i > 0) and (i <= j), tostring(i))
|
|
||||||
assert((j % 1 == 0), tostring(j))
|
|
||||||
local a = text:sub(1, i - 1)
|
|
||||||
local b = text:sub(j + 1)
|
|
||||||
return a .. replacement .. b
|
|
||||||
end
|
|
||||||
|
|
||||||
return C
|
return C
|
||||||
|
|
Loading…
Reference in a new issue