sets up the actual filling algorithm - how badly is this gonna fail?

This commit is contained in:
duncathan 2019-03-19 02:56:38 -06:00
parent b10433be2a
commit 56b057d027
10 changed files with 944 additions and 873 deletions

View file

@ -1 +1 @@
IF_llulIFx<EFBFBD>}x<78>llmnx<6E><78>lllx<6C><78>IF_llumIFx<46>}x<78>llmnx<6E><78>llmx<6D><78>IF_llunIFx<46>}x<78>llmnx<6E><78>llnx<6E><78>IF_lluoIFx<46>}x<78>llmnx<6E><78>llox<6F><78>IF_llupIFx<46>}x<78>llmnx<6E><78>llpx<70><78>IF_lmllIFx<46><78><EFBFBD>嚯lllx<6C>}llmmvllulvllqrvllooIF_lmmlIFx<46>𡣘<EFBFBD>𡡣lmmx}<7D>lmmlvllllvlllnIFx<46>嚯llpx<70>}lltovllupvlllsvllmlIF_lnllIFx<46><78>Fx<46><78>osmvlnlmIFx<46><78><EFBFBD>廾\㨩<><E3A8A9><EFBFBD>\<5C>狐{x<><78>x<EFBFBD><78>IF_lnlmIFx<46><78><EFBFBD><EFBFBD>垮\<5C>琵延\野╮c珮走咩左cIF◤娉屆{<<3C><>x<78>IF衮𤪓h\筍帷恣\恭ㄓ退x<E98080><78>IF<49>䔉泌豹鱝〞\井屆\左\𩄼酗巨】x<E38091><78>IF}悅奴什h\陞屆\鬥\ㄚjx<6A><78>x<EFBFBD>都lonx<6E><78>lnllx<78>𧞄帷恣\ㄚ牧𩄼<E789A7>均\屆\陘︺IF哈\駚戛砥{x<><78>x<EFBFBD><78>ltnIF_lollIFx<78>lollvllllvllllx<6C><78>oulvlolnx<6E>gloulx<6C><78>olmIF_lolmIFx<46><78>lqmIF_lolnIFx<46><78><EFBFBD><EFBFBD>扇仃宮珮ㄝ𨮙】x<E38091><78>IF𨫡︷珮陵弘左α囿\陘F鬥<46>秣囿」x<E3808D><78>x<78>x<EFBFBD><78><EFBFBD><EFBFBD>祠﹛炫\陘﹏物𠸊﹏}扇仃屑IF乾情\丑悍\鬥\陘竉岩<E7AB89>疽x<E796BD><78>x<78>x<EFBFBD><78>
0==F=IZ[NIPZb==>?ISNV====IR[Q0==F>IZ[NIPZb==>?ISNV===>IR[Q0==F?IZ[NIPZb==>?ISNV===?IR[Q0==F@IZ[NIPZb==>?ISNV===@IR[Q0==FAIZ[NIPZb==>?ISNV===AIR[Q0=>==I]_VISN\====Ia_N==>>G==F=G==BCG==@@0=>>=IXRfI`\b==>>IN[]=>>=G====G===?ISN\===AIa_N==E@G==FAG===DG==>=0=?==I]_VISYW>@D>G=?=>IZ`TfrnuL-dunqqn†n-„n{<7B>LI[\QIR[Q0=?=>I]_VIZ`Tf|-€n†-z†-„vsr4€-y||xv{4s|-zrLI[\QIPY_ frnu9-†|4r-vtu<74>9I[\QV-nv{4<>-orr{-u|zr-v{-n-„uvyr;I[\QNvtu<74>9-<2D>vzr-<2D>|-t|;I[\QITVa>=@?IQ[]=?==IPY_f|4r-t|{{n-<2D>nxr-zr-<2D>urr9|s-p|€rLI[\QIRcR=?=?0=?=?IRcR==E?0=@==IP[]=@==G====G====ISYW=@F=G=@=?ISY8=@F=IRcR=@=>0=@=>IRcR==B>0=@=?I]_VIZ`TN<4E>u4€-tn<7F>r;I[\Qaurr4€-„v<7F>v{t-|{-<2D>ur<17>|zo€<6F>|{rGI[\QIPY_IZ`TIab_Urr-€yrr}€-<2D>ur-{|oyr-N<4E>u9<17>r-ur|-<2D>|-<2D>ur-Zvzvtn€;I[\QIPY_IR[Q

View file

@ -28,7 +28,9 @@ for me?<NOD<CLR
Yeah, you're right,<NOD
I ain't been home in a while.<NOD
Arright, time to go.<NOD<GIT1032<DNP0200<CLRYou're gonna take me there,
of course?<NOD<EVE0082
of course?<NOD<EVE0202
#0202
<EVE0082
#0300
<CNP0300:0000:0000<FLJ0390:0302<FL+0390<EVE0301

View file

@ -1,296 +1,355 @@
function item(t)
return t
end
function weapon(t)
return item(t)
end
function inventory(t)
return item(t)
end
function lifeCapsule3()
return item({
local function lifeCapsule3()
return {
name = "Life Capsule",
script = "<EVE0012"
})
script = "<EVE0012",
attributes = {"nonProgressive"}
}
end
function lifeCapsule4()
return item({
local function lifeCapsule4()
return {
name = "Life Capsule",
script = "<EVE0013"
})
script = "<EVE0013",
attributes = {"nonProgressive"}
}
end
function lifeCapsule5()
return item({
local function lifeCapsule5()
return {
name = "Life Capsule",
script = "<EVE0014"
})
script = "<EVE0014",
attributes = {"nonProgressive"}
}
end
function missiles()
return weapon({
local function missiles()
return {
name = "Missile Expansion",
script = "<EVE0030",
attributes = {"weaponSN", "missileLauncher"}
})
attributes = {"missileLauncher", "nonProgressive"}
}
end
local data = {
-------------
-- WEAPONS --
-------------
polarStar = weapon({
name = "Polar Star",
script = "<EVE0002",
attributes = {"weaponBoss", "weaponSN"}
}),
spur = weapon({
name = "Spur",
script = "<EVE0002",
attributes = {"weaponBoss", "weaponSN", "polarStar"}
}),
missileLauncher = missiles(),
superMissileLauncher = weapon({
name = "Super Missile Launcher",
script = "<EVE0033",
attributes = {"weaponSN", "missileLauncher"}
}),
fireball = weapon({
name = "Fireball",
script = "<EVE0004",
attributes = {"weaponBoss"}
}),
snake = weapon({
name = "Snake",
script = "<EVE0005",
attributes = {"weaponBoss"}
}),
bubbler = weapon({
name = "Bubbler",
script = "<EVE0007",
attributes = {"weaponBoss", "weaponSN"} -- have fun grinding to lv3 to get out of the first cave :)
}),
machineGun = weapon({
name = "Machine Gun",
script = "<EVE0008",
attributes = {"weaponBoss", "flight"}
}),
blade = weapon({
name = "Blade",
script = "<EVE0009",
attributes = {"weaponBoss", "weaponSN"}
}),
nemesis = weapon({
name = "Nemesis",
script = "<EVE0010",
attributes = {"weaponBoss", "weaponSN"}
}),
---------------
-- INVENTORY --
---------------
mapSystem = {
name = "Map System",
script = "<EVE0052"
},
locket = {
name = "Silver Locket",
script = "<EVE0054"
},
arthurKey = {
name = "Arthur's Key",
script = "<EVE0051"
},
idCard = {
name = "ID Card",
script = "<EVE0057"
},
santaKey = {
name = "Santa's Key",
script = "<EVE0053"
},
lipstick = {
name = "Chaco's Lipstick",
script = "<EVE0087"
},
juice = {
name = "Jellyfish Juice",
script = "<EVE0058"
},
charcoal = {
name = "Charcoal",
script = "<EVE0062"
},
rustyKey = {
name = "Rusty Key",
script = "<EVE0039"
},
gumKey = {
name = "Gum Key",
script = "<EVE0060"
},
gumBase = {
name = "Gum Base",
script = "<EVE0061"
},
bomb = {
name = "Bomb",
script = "<EVE0063"
},
panties = {
name = "Curly's Panties",
script = "<EVE0085"
},
puppy1 = {
name = "Hajime",
script = "<EVE0064",
attributes = {"puppy"}
},
puppy2 = {
name = "Kakeru",
script = "<EVE0064",
attributes = {"puppy"}
},
puppy3 = {
name = "Mick",
script = "<EVE0064",
attributes = {"puppy"}
},
puppy4 = {
name = "Nene",
script = "<EVE0064",
attributes = {"puppy"}
},
puppy5 = {
name = "Shinobu",
script = "<EVE0064",
attributes = {"puppy"}
},
lifepot = {
name = "Life Pot",
script = "<EVE0065"
},
turbocharge = {
name = "Turbocharge",
script = "<EVE0070"
},
clinicKey = {
name = "Clinic Key",
script = "<EVE0067"
},
armsBarrier = {
name = "Arms Barrier",
script = "<EVE0069"
},
cureAll = {
name = "Cure-All",
script = "<EVE0066"
},
booster1 = {
name = "Booster 0.8",
script = "<EVE0068",
attributes = {"flight"}
},
booster2 = {
name = "Booster 2.0",
script = "<EVE0073",
attributes = {"flight", "booster1"}
},
towRope = {
name = "Tow Rope",
script = "<EVE0080"
},
airTank = {
name = "Curly's Air Tank",
script = "<EVE0071"
},
alienMedal = {
name = "Alien Medal",
script = "<EVE0086"
},
whimsicalStar = {
name = "Whimsical Star",
script = "<EVE0088"
},
nikumaru = {
name = "Nikumaru Counter",
script = "<EVE0072"
},
teleportKey = {
name = "Teleporter Room Key",
script = "<EVE0075"
},
letter = {
name = "Sue's Letter",
script = "<EVE0076"
},
mask = {
name = "Mimiga Mask",
script = "<EVE0074"
},
brokenSprinkler = {
name = "Broken Sprinkler",
script = "<EVE0078"
},
newSprinkler = {
name = "Sprinkler",
script = "<EVE0079"
},
controller = {
name = "Controller",
script = "<EVE0077"
},
mushroomBadge = {
name = "Mushroom Badge",
script = "<EVE0083"
},
maPignon = {
name = "Ma Pignon",
script = "<EVE0084"
},
little = {
name = "Little Man",
script = "<EVE0082"
},
ironBond = {
name = "Iron Bond",
script = "<EVE0089"
},
-------------------
-- LIFE CAPSULES --
-------------------
capsule3A = lifeCapsule3(), -- First Cave
capsule3B = lifeCapsule3(), -- Yamashita Farm
capsule3C = lifeCapsule3(), -- Egg Corridor (Basil)
capsule4A = lifeCapsule4(), -- Egg Corridor (Cthulhu)
capsule5A = lifeCapsule5(), -- Grasstown
capsule5B = lifeCapsule5(), -- Execution Chamber
capsule5C = lifeCapsule5(), -- Sand Zone (Upper)
capsule5D = lifeCapsule5(), -- Sand Zone (Lower)
capsule5E = lifeCapsule5(), -- Labyrinth
capsule5F = lifeCapsule5(), -- Plantation (West)
capsule4B = lifeCapsule4(), -- Plantation (Puppy)
capsule5G = lifeCapsule5(), -- Sacred Grounds
--------------
-- MISSILES --
--------------
missileA = missiles(), -- Grasstown
missileB = missiles(), -- Grasstown Hut
missileC = missiles(), -- Egg Corridor?
missileD = missiles(), -- Egg Observation Room?
missileHell = weapon({
name = "Missile Expansion",
script = "<EVE0035",
attributes = {"weaponSN", "missileLauncher"}
})
}
for k, t in pairs(data) do
t.key = k
local function event(n)
return {
name = "Event: " .. n,
attributes = {"event"}
}
end
return data
local function _itemData()
local data = {
-------------
-- WEAPONS --
-------------
polarStar1 = {
name = "Polar Star",
script = "<EVE0002",
attributes = {"weaponBoss", "weaponSN", "polarStar"}
},
polarStar2 = {
name = "Polar Star",
script = "<EVE0002",
attributes = {"weaponBoss", "weaponSN", "polarStar"}
},
missileLauncher = {
name = "Missile Launcher",
script = "<EVE0030",
attributes = {"weaponSN", "nonProgressive"}
},
superMissileLauncher = {
name = "Super Missile Launcher",
script = "<EVE0033",
attributes = {"weaponSN", "missileLauncher", "nonProgressive"}
},
fireball = {
name = "Fireball",
script = "<EVE0004",
attributes = {"weaponBoss"}
},
snake = {
name = "Snake",
script = "<EVE0005",
attributes = {"weaponBoss", "nonProgressive"}
},
bubbler = {
name = "Bubbler",
script = "<EVE0007",
attributes = {"weaponBoss", "weaponSN", "nonProgressive"} -- have fun grinding to lv3 to get out of the first cave :)
},
machineGun = {
name = "Machine Gun",
script = "<EVE0008",
attributes = {"weaponBoss", "flight"}
},
blade = {
name = "Blade",
script = "<EVE0009",
attributes = {"weaponBoss", "weaponSN"}
},
nemesis = {
name = "Nemesis",
script = "<EVE0010",
attributes = {"weaponBoss", "weaponSN", "nonProgressive"}
},
---------------
-- INVENTORY --
---------------
mapSystem = {
name = "Map System",
script = "<EVE0052",
attributes = {"nonProgressive"}
},
locket = {
name = "Silver Locket",
script = "<EVE0054"
},
arthurKey = {
name = "Arthur's Key",
script = "<EVE0051"
},
idCard = {
name = "ID Card",
script = "<EVE0057"
},
santaKey = {
name = "Santa's Key",
script = "<EVE0053"
},
lipstick = {
name = "Chaco's Lipstick",
script = "<EVE0087",
attributes = {"nonProgressive"}
},
juice = {
name = "Jellyfish Juice",
script = "<EVE0058"
},
charcoal = {
name = "Charcoal",
script = "<EVE0062"
},
rustyKey = {
name = "Rusty Key",
script = "<EVE0039"
},
gumKey = {
name = "Gum Key",
script = "<EVE0060"
},
gumBase = {
name = "Gum Base",
script = "<EVE0061"
},
bomb = {
name = "Bomb",
script = "<EVE0063"
},
panties = {
name = "Curly's Panties",
script = "<EVE0085",
attributes = {"nonProgressive"}
},
puppy1 = {
name = "Hajime",
script = "<EVE0064",
attributes = {"puppy"}
},
puppy2 = {
name = "Kakeru",
script = "<EVE0064",
attributes = {"puppy"}
},
puppy3 = {
name = "Mick",
script = "<EVE0064",
attributes = {"puppy"}
},
puppy4 = {
name = "Nene",
script = "<EVE0064",
attributes = {"puppy"}
},
puppy5 = {
name = "Shinobu",
script = "<EVE0064",
attributes = {"puppy"}
},
lifepot = {
name = "Life Pot",
script = "<EVE0065",
attributes = {"nonProgressive"}
},
turbocharge = {
name = "Turbocharge",
script = "<EVE0070",
attributes = {"nonProgressive"}
},
clinicKey = {
name = "Clinic Key",
script = "<EVE0067"
},
armsBarrier = {
name = "Arms Barrier",
script = "<EVE0069",
attributes = {"nonProgressive"}
},
cureAll = {
name = "Cure-All",
script = "<EVE0066"
},
booster1 = {
name = "Booster",
script = "<EVE0068",
attributes = {"flight", "booster"}
},
booster2 = {
name = "Booster",
script = "<EVE0068",
attributes = {"flight", "booster"}
},
towRope = {
name = "Tow Rope",
script = "<EVE0080"
},
airTank = {
name = "Curly's Air Tank",
script = "<EVE0071"
},
alienMedal = {
name = "Alien Medal",
script = "<EVE0086",
attributes = {"nonProgressive"}
},
whimsicalStar = {
name = "Whimsical Star",
script = "<EVE0088",
attributes = {"nonProgressive"}
},
nikumaru = {
name = "Nikumaru Counter",
script = "<EVE0072",
attributes = {"nonProgressive"}
},
teleportKey = {
name = "Teleporter Room Key",
script = "<EVE0075"
},
letter = {
name = "Sue's Letter",
script = "<EVE0076"
},
mask = {
name = "Mimiga Mask",
script = "<EVE0074"
},
brokenSprinkler = {
name = "Broken Sprinkler",
script = "<EVE0078"
},
newSprinkler = {
name = "Sprinkler",
script = "<EVE0079"
},
controller = {
name = "Controller",
script = "<EVE0077"
},
mushroomBadge = {
name = "Mushroom Badge",
script = "<EVE0083"
},
maPignon = {
name = "Ma Pignon",
script = "<EVE0084"
},
mrLittle = {
name = "Little Man",
script = "<EVE0082",
attributes = {"event"}
},
ironBond = {
name = "Iron Bond",
script = "<EVE0089"
},
-------------------
-- LIFE CAPSULES --
-------------------
capsule3A = lifeCapsule3(), -- First Cave
capsule3B = lifeCapsule3(), -- Yamashita Farm
capsule3C = lifeCapsule3(), -- Egg Corridor (Basil)
capsule4A = lifeCapsule4(), -- Egg Corridor (Cthulhu)
capsule5A = lifeCapsule5(), -- Grasstown
capsule5B = lifeCapsule5(), -- Execution Chamber
capsule5C = lifeCapsule5(), -- Sand Zone (Upper)
capsule5D = lifeCapsule5(), -- Sand Zone (Lower)
capsule5E = lifeCapsule5(), -- Labyrinth
capsule5F = lifeCapsule5(), -- Plantation (West)
capsule4B = lifeCapsule4(), -- Plantation (Puppy)
capsule5G = lifeCapsule5(), -- Sacred Grounds
--------------
-- MISSILES --
--------------
missileA = missiles(), -- Grasstown
missileB = missiles(), -- Grasstown Hut
missileC = missiles(), -- Egg Corridor?
missileD = missiles(), -- Egg Observation Room?
missileHell = {
name = "Missile Expansion",
script = "<EVE0035",
attributes = {"missileLauncher", "nonProgressive"}
},
------------
-- EVENTS --
------------
eventSue = event("Saved Sue"),
eventFans = event("Activated Fans"),
eventKazuma = event("Saved Kazuma"),
eventOmega = event("Defeated Omega"),
eventToroko = event("Defeated Toroko+"),
eventCore = event("Defeated the Core"),
eventCurly = event("Saved Curly"),
eventRocket = event("Built Rocket")
}
for k, t in pairs(data) do
t.key = k
table.insert(t.attributes, k)
end
end
local C = Class:extend()
function C:new()
self.itemData = _itemData()
end
function C:getByKey(key)
for k, v in ipairs(self.itemData) do
if k == key then return v end
end
end
function C:getItemsByAttribute(attribute)
local items = {}
for item in ipairs(self.itemData) do
if _.contains(item.attributes, attribute) then table.insert(items, item) end
end
return items
end
function C:getEvents()
return self:getItemsByAttribute("event")
end
function C:getOptionalItems()
return self:getItemsByAttribute("nonProgressive")
end
function C:getMandatoryItems()
return _.difference(self.items, _.union(self:getOptionalItems(), self:getEvents()))
end
return C

37
src/database/location.lua Normal file
View file

@ -0,0 +1,37 @@
local C = Class:extend()
function C:new(name, map, event, region)
self.name = name
self.map = map
self.event = event
self.region = region
end
function C:fill(item, items)
local old = self.item
self:setItem(item)
if self:canAccess(items) then return true end
self:setItem(old)
return false
end
function C:canAccess(items)
if not self.region:canAccess(items) then return false end
return self.requirements == nil or self:requirements(items)
end
function C:hasItem()
return self.item ~= nil
end
function C:setItem(item)
self.item = item
end
function C:writeItem(tscFiles, item)
item = item or self.item
if self.map == nil or self.event == nil or item.script == nil then return end
tscFiles[self.map .. '.tsc']:placeItemAtLocation(item.script, self.event)
end
return C

View file

@ -1,549 +0,0 @@
local data = {
firstCave1 = { -- locations available at the absolute beginning of the game. can't be returned to, but can't be left without obtaining both items
connections = {
mimigaVillage = {{"weaponSN"}}
},
locations = {
firstCapsule = {
requirements = {},
map = "Cave",
event = "#0401"
},
gunsmithChest = {
requirements = {},
map = "Pole",
event = "#0402"
}
}
},
firstCave2 = { -- locations available on the return trip to first cave
connections = {
mimigaVillage = {{"weaponSN"}}
},
locations = {
gunsmith = {
requirements = {"polarStar", "eventCore"},
map = "Pole",
event = "#0303"
}
}
}
mimigaVillage = {
connections = {
firstCave2 = {{"weaponSN", "flight"}},
arthur = {{"arthursKey"}}
},
locations = {
yamashita = {
requirements = {},
map = "Plant",
event = "#0401"
},
reservoir = {
requirements = {},
map = "Pool",
event = "#0301"
},
mapChest = {
requirements = {},
map = "Mimi",
event = "#0202"
},
assemblyHall = {
requirements = {{"juice"}},
map = "Comu",
event = "#0303"
},
mrLittle = { -- guaranteed to have the little man item, for simplicity's sake (more of an escort quest than fetch quest imo)
requirements = {{"locket"}},
map = "Cemet",
event = "#0301"
},
graveyard = {
requirements = {{"locket"}},
map = "Cemet",
event = "#0301"
},
mushroom = { -- placed in a chest, can't open unless curly has been saved
requirements = {{"locket", "eventCurly", "flight"}},
map = "Mapi",
event = "#0202"
},
maPignon = { -- no need to check the mushroom badge, just need to have it
requirements = {{"locket", "mushroomBadge", "weaponBoss", "flight"}},
map = "Mapi",
event = "#0501"
}
}
}
arthur = {
connections = {
mimigaVillage = {{"arthursKey"}},
eggCorridor1 = {},
eggCorridor2 = {{"eventCore"}, -- also unlocks if you have access to the teleporter between grasstown and plantation, but that's logically redundant
grasstownWest = {},
upperSandZone = {{"weaponSN"}},
labyrinthB = {},
plantation = {{"teleportKey"}}
},
locations = {
risenBooster = {
requirements = {{"eventCore"}},
map = "Pens1",
event = "#0652"
}
}
},
eggCorridor1 = {
connections = {
arthur = {}
},
locations = {
basil = {
requirements = {},
map = "Eggs",
event = "#0403"
},
cthulhu = {
requirements = {},
map = "Eggs",
event = "#0404"
},
eggItem = {
requirements = {},
map = "Egg6",
event = "#0201"
},
observationChest = {
requirements = {},
map = "EggR",
event = "#0301"
}
},
events = {
eventSue = {
requirements = {{"idCard", "weaponBoss"}}
}
}
},
grasstownWest = {
connections = {
arthur = {},
grasstownEast = {{"juice"}, {"flight"}} -- can also sequence break over with a damage boost!
},
locations = {
keySpot = {
requirements = {},
map = "Weed",
event = "#0700"
},
jellyCapsule = {
requirements = {},
map = "Weed",
event = "#0701"
},
santa = {
requirements = {{"santaKey"}},
map = "Santa",
event = "#0501"
},
charcoal = {
requirements = {{"santaKey", "juice"}},
map = "Santa",
event = "#0302"
}
chaco = {
requirements = {{"santaKey"}},
map = "Chako",
event = "#0211"
},
kulala = {
requirements = {{"santaKey", "weaponBoss"}},
map = "Weed",
event = "0702"
}
}
},
grasstownEast = {
connections = {
grasstownWest = {{"eventFans"}, {"flight"}},
plantation = {{"bomb", "weaponSN"}}
},
locations = {
kazuma1 = {
requirements = {},
map = "Weed",
event = "#0800"
},
kazuma2 = {
requirements = {{"eventFans"}},
map = "Weed",
event = "#0801"
},
execution = {
requirements = {{"weaponSN"}},
map = "WeedD",
event = "#0305"
},
outsideHut = {
requirements = {},
map = "Weed",
event = "#0303"
},
hutChest = {
requirements = {{"eventFans"}, {"flight"}},
map = "WeedB",
event = "#0301"
},
gumChest = {
requirements = {{"eventFans", "gumKey", "weaponBoss"}, {"flight", "gumKey", "weaponBoss"}},
map = "Frog",
event = "#0300"
},
malco = {
requirements = {{"eventFans", "juice", "charcoal", "gum"}},
map = "Malco",
event = "#0350"
}
},
events = {
eventFans = {
requirements = {{"rustyKey", "weaponBoss"}}
}
}
},
upperSandZone = {
connections = {
arthur = {},
lowerSandZone = {{"eventOmega"}}
},
locations = {
curly = {
requirements = {{"polarStar"}},
map = "Curly",
event = "#0518"
},
panties = {
requirements = {},
map = "CurlyS",
event = "#0421"
},
curlyPup = {
requirements = {},
map = "CurlyS",
event = "#0401"
},
sandCapsule = {
requirements = {},
map = "Sand",
event = "#0502"
}
},
events = {
eventOmega = {
requirements = {}
}
}
},
lowerSandZone = {
connections = {
upperSandZone = {{"eventOmega"}},
labyrinthW = {{"puppy1", "puppy2", "puppy3", "puppy4", "puppy5", "weaponBoss"}, {"flight"}}
},
locations = {
chestPup = {
requirements = {},
map = "Sand",
event = "#0421"
},
pupCapsule = {
requirements = {},
map = "Sand",
event = "#0503"
},
darkPup = {
requirements = {},
map = "Dark",
event = "#0401"
},
runPup = {
requirements = {},
map = "Sand",
event = "#0422"
},
sleepyPup = {
requirements = {},
map = "Sand",
event = "#0421"
},
jenka = {
requirements = {{"puppy:5"}},
map = "Jenka2",
event = "#0221"
},
king = {
requirements = {{"puppy:5", "weaponBoss"}},
map = "Gard",
event = "#0602"
}
}
},
labyrinthB = {
connections = {
labyrinthW = {{"flight", "weaponBoss"}},
boulder = {{"flight"}},
arthur = {}
},
locations = {
fallenBooster = {
requirements = {},
map = "MazeB",
event = "#0502"
}
}
},
labyrinthW = {
connections = {
lowerSandZone = {},
labyrinthB = {{"weaponBoss"}},
boulder = {},
labyrinthM = {{"flight"}}
},
locations = {
critterCapsule = {
requirements = {{"weaponBoss"}},
map = "MazeI",
event = "#0301"
},
turboChaba = {
requirements = {{"machineGun"}},
map = "MazeA",
event = "#0502"
},
snakeChaba = {
requirements = {{"fireball"}},
map = "MazeA",
event = "#0512"
},
whimChaba = {
requirements = {{"polarStar:2"}},
map = "MazeA",
event = "#0522"
},
armsBarrier = {
requirements = {{"flight"}},
map = "MazeO",
event = "#0401"
},
physician = {
requirements = {},
map = "MazeO",
event = "#0305"
},
puuBlack = {
requirements = {{"clinicKey", "weaponBoss"}},
map = "MazeD",
event = "#0401"
}
}
},
boulder = {
connections = {
labyrinthB = {},
labyrinthW = {},
labyrinthM = {{"cureAll", "weaponBoss"}}
},
locations = {
boulderChest = {
requirements = {{"cureAll", "weaponBoss"}},
map = "MazeS",
event = "#0202"
}
}
},
labyrinthM = {
connections = {
labyrinthW = {},
boulder = {{"cureAll", "weaponBoss"}},
darkPlace = {}
},
},
darkPlace = {
connections = {
waterway = {{"airTank"}},
core = {{"cureAll"}},
labyrinthM = {}
}
},
core = {
connections = {
darkPlace = {}
},
locations = {
ropeSpot = {
requirements = {},
map = "Almond",
event = "#0243"
},
curlyCorpse = {
requirements = {{"eventCore"},
map = "Almond",
event = "#1111"
}
},
events = {
eventCore = {
requirements = {{"weaponBoss"}}
}
}
},
waterway = {
connections = {
darkPlace = {},
mimigaVillage = {{"weaponSN"}}
},
locations = {
ironhead = {
requirements = {{"weaponSN"}},
map = "Pool",
event = "#0412"
}
},
events = {
eventCurly = {
requirements = {{"eventCore", "towRope"}}
}
}
},
eggCorridor2 = {
connections = {
arthur = {},
outerWall = {{"bomb"}}
},
locations = {
dragonChest = {
requirements = {{"weaponBoss"}},
map = "Eggs2",
event = "#0321"
},
sisters = {
requirements = {{"weaponBoss"}},
map = "EggR2",
event = "#0303"
}
}
},
outerWall = {
connections = {
eggCorridor2 = {{"bomb"}},
plantation = {{"flight"}}
},
locations = {
clock = {
requirements = {}, --eventCurly? works like that in vanilla
map = "Clock",
event = "#0300"
},
littleHouse = {
requirements = {{"little", "flight"}},
map = "Little",
event = "#0204"
}
}
},
plantation = {
connections = {
arthur = {{"teleportKey"}},
outerWall = {},
grasstownEast = {{"bomb", "weaponSN"}},
lastCave = {{"eventRocket", "booster:2", "weaponBoss"}}
},
locations = {
kanpachi = {
requirements = {},
map = "Cent",
event = "#0268"
},
jail1 = {
requirements = {{"teleportKey"}},
map = "Jail1",
event = "#0301"
},
momorin = {
requirements = {{"letter", "booster1"}},
map = "Momo",
event = "#0201"
},
sprinkler = {
requirements = {{"mask"}},
map = "Cent",
event = "#0417"
},
megane = {
requirements = {{"brokenSprinkler", "mask"}},
map = "lounge",
event = "#0204"
},
itoh = {
requirements = {{"letter"}},
map = "Itoh",
event = "#0405"
},
topCapsule = {
requirements = {{"flight"}},
map = "Cent",
event = "#0501"
},
plantPup = {
requirements = {{"eventRocket"}},
map = "Cent",
event = "#0452"
},
curlyShroom = {
requirements = {{"eventCurly", "maPignon"}},
map = "Cent",
event = "#0324"
}
},
events = {
eventRocket = {
requirements = {{"newSprinkler", "booster", "controller"}}
}
}
},
lastCave = {
connections = {
plantation = {},
balcony = {{"eventSue", "ironBond"}} --required to get into the endgame boss rush
},
locations = {
redDemon = {
requirements = {},
map = "Priso2",
event = "#0300",
}
}
},
balcony = {
connections = {
lastCave = {}
},
locations = {
hellCapsule = {
requirements = {},
map = "Hell1",
event = "#0401"
},
hellChest = {
requirements = {},
map = "Hell3",
event = "#0400"
}
},
events = {
eventHellCurly = { --do you get to take curly with you in hell?
requirements = {{"eventCurly"}}
}
}
}
}

33
src/database/region.lua Normal file
View file

@ -0,0 +1,33 @@
local C = Class:extend()
function C:new(worldGraph, name)
self.locations = {}
self.world = worldGraph
self.name = name
end
function C:canAccess(items)
return self.requirements == nil or self.requirements(items)
end
function C:getLocation(key)
return self.locations[key]
end
function C:getLocations()
return self.locations
end
function C:getEmptyLocations()
return _.filter(self.locations, function(k,v) return not v:hasItem() end)
end
function C:getFilledLocations()
return _.filter(self.locations, function(k,v) return v:hasItem() end)
end
function C:writeItems(tscFiles)
for location in ipairs(self.locations) do location:writeItem(tscFiles) end
end
return C

View file

@ -0,0 +1,479 @@
local Region = require 'region'
local Location = require 'location'
local firstCave = Region:extend()
function firstCave:new(worldGraph)
firstCave.super.new(self, worldGraph, "firstCave")
self.locations = {
"firstCapsule" = Location("First Cave Life Capsule", "Cave", "0401", self),
"gunsmithChest" = Location("Hermit Gunsmith Chest", "Pole", "0402", self),
"gunsmith" = Location("Tetsuzou", "Pole", "0303", self)
}
self.locations.gunsmith.requirements = function(items)
return self.world.regions.mimigaVillage:canAccess(items) and items:has("flight", "polarStar", "eventCore")
end
end
local mimigaVillage = Region:extend()
function mimigaVillage:new(worldGraph)
mimigaVillage.super.new(self, worldGraph, "mimigaVillage")
self.locations = {
"yamashita" = Location("Yamashita Farm", "Plant", "0401", self),
"reservoir" = Location("Reservoir", "Pool", "0301", self),
"mapChest" = Location("Mimiga Village Chest", "Mimi", "0202", self),
"assembly" = Location("Assembly Hall Fireplace", "Comu", "0303", self),
"mrLittle" = Location("Mr. Little (Graveyard)", "Cemet", "0202", self),
"grave" = Location("Arthur's Grave", "Cemet", "0301", self),
"mushroomChest" = Location("Storage? Chest", "Mapi", "0202", self),
"maPignon" = Location("Ma Pignon Boss", "Mapi", "0501", self)
}
self.requirements = function(items)
if self.world.regions.firstCave:canAccess(items) and items:has("weaponSN") then return true end
return false
end
self.locations.assembly.requirements = function(items) return items:has("juice") end
self.locations.mrLittle.requirements = function(items)
return self.world.regions.outerWall:canAccess(items) and items:has("flight", "locket")
end
self.locations.grave.requirements = function(items) return items:has("locket") end
self.locations.mushroomChest.requirements = function(items)
return items:has("flight", "locket", "eventCurly")
end
self.locations.maPignon.requirements = function(items)
-- stupid mushroom is invincible to the blade and machinegun for some reason
if items:has("flight", "locket", "mushroomBadge") then
if items:has("polarStar") or items:has("fireball") or items:has("bubbler")
or items:has("machineGun") or items:has("snake") or items:has("nemesis") then
return true
end
end
return false
end
self.locations.mrLittle:setItem(self.world.items:getByKey("mrLittle"))
end
local arthur = Region:extend()
function arthur:new(worldGraph)
arthur.super.new(self, worldGraph, "arthur")
self.locations = {
"risenBooster" = Location("Professor Booster", "Pens1", "0652", self)
}
self.requirements = function(items)
if self.world.regions.mimigaVillage:canAccess(items) and items:has("arthursKey") then return true end
return false
end
self.locations.booster.requirements = function(items) return items:has("eventCore") end
end
local eggCorridor1 = Region:extend()
function eggCorridor1:new(worldGraph)
eggCorridor1.super.new(self, worldGraph, "eggCorridor1")
self.locations = {
"basil" = Location("Basil Spot", "Eggs", "0403", self),
"cthulhu" = Location("Cthulhu's Abode", "Eggs", "0404", self),
"eggItem" = Location("Egg Chest", "Egg6", "0201", self),
"observationChest" = Location("Egg Observation Room Chest", "EggR", "0301", self),
"eventSue" = Location("Saved Sue", nil, nil, self)
}
self.requirements = function(items) return self.world.regions.arthur:canAccess(items) end
self.locations.eventSue.requirements = function(items) return items:has("idCard", "weaponBoss") end
self.locations.eventSue:setItem(self.world.items:getByKey("eventSue"))
end
local grasstownWest = Region:extend()
function grasstownWest:new(worldGraph)
grasstownWest.super.new(self, worldGraph, "grasstownWest")
self.locations = {
"keySpot" = Location("West Grasstown Floor", "Weed", "0700", self),
"jellyCapsule" = Location("West Grasstown Ceiling", "Weed", "0701", self),
"santa" = Location("Santa", "Santa", "0501", self),
"charcoal" = Location("Santa's Fireplace", "Santa", "0302", self),
"chaco" = Location("Chaco's Bed, where you two Had A Nap", "Chako", "0211", self),
"kulala" = Location("Kulala Chest", "Weed", "0702", self)
}
self.requirements = function(items)
if self.world.regions.arthur:canAccess(items) then return true end
return false
end
self.locations.santa.requirements = function(items) return items:has("santaKey") end
self.locations.charcoal.requirements = function(items) return items:has("santaKey", "juice") end
self.locations.chaco.requirements = function(items) return items:has("santaKey") end
self.locations.kulala.requirements = function(items) return items:has("santaKey", "weapon") end
end
local grasstownEast = Region:extend()
function grasstownEast:new(worldGraph)
grasstownEast.super.new(self, worldGraph, "grasstownEast")
self.locations = {
"kazuma1" = Location("Kazuma (Rusty Key)", "Weed", "0800", self),
"kazuma2" = Location("Kazuma (Gum Key)", "Weed", "0801", self),
"execution" = Location("Execution Chamber", "WeedD", "0305", self),
"outsideHut" = Location("Grasstown East Chest", "Weed", "0303", self),
"hutChest" = Location("Grasstown Hut", "WeedB", "0301", self),
"gumChest" = Location("Gum Chest", "Frog", "0300", self),
"malco" = Location("MALCO", "Malco", "0350", self),
"eventFans" = Location("Activated Grasstown Fans", nil, nil, self),
"eventKazuma" = Location("Saved Kazuma", nil, nil, self)
}
self.requirements = function(items)
if self.world.regions.grasstownWest:canAccess(items) then
if items:has("flight") or items:has("juice") then return true end
end
if self.world.regions.plantation:canAccess(items) and items:has("eventKazuma", "weaponSN") then return true end
return false
end
self.locations.kazuma2.requirements = function(items) return items:has("eventFans") end
self.locations.execution.requirements = function(items) return items:has("weaponSN") end
self.locations.hutChest.requirements = function(items) return items:has("eventFans") or items:has("flight") end
self.locations.gumChest.requirements = function(items)
if items:has("gumKey", "weaponBoss") then
if items:has("eventFans") or items:has("flight") then return true end
end
return false
end
self.locations.malco.requirements = function(items) return items:has("eventFans", "juice", "charcoal", "gum") end
self.locations.eventFans.requirements = function(items) return items:has("rustyKey", "weaponBoss")
self.locations.eventFans:setItem(self.world.items:getByKey("eventFans"))
self.locations.eventKazuma.requirements = function(items) return items:has("bomb") end
self.locations.eventKazuma:setItem(self.world.items:getByKey("eventKazuma"))
end
local upperSandZone = Region:extend()
function upperSandZone:new(worldGraph)
upperSandZone.super.new(self, worldGraph, "upperSandZone")
self.locations = {
"curly" = Location("Curly Boss", "Curly", "0518", self),
"panties" = Location("Curly's Closet", "CurlyS", "0421", self),
"curlyPup" = Location("Puppy (Curly)", "CurlyS", "0401", self),
"sandCapsule" = Location("Polish Spot", "Sand", "0502", self),
"eventOmega" = Location("Defeated Omega", nil, nil, self)
}
self.requirements = function(items)
if self.world.regions.arthur:canAccess(items) and items:has("weaponSN") then return true end
return false
end
self.locations.curly.requirements = function(items) return items:has("polarStar") end
self.locations.eventOmega.requirements = function(items) return items:has("weaponBoss") end
self.locations.eventOmega.setItem(self.world.items:getByKey("eventOmega"))
end
local lowerSandZone = Region:extend()
function lowerSandZone:new(worldGraph)
lowerSandZone.super.new(self, worldGraph, "lowerSandZone")
self.locations = {
"chestPup" = Location("Puppy (Chest)", "Sand", "0421", self),
"darkPup" = Location("Puppy (Dark)", "Dark", "0401", self),
"runPup" = Location("Puppy (Run)", "Sand", "0422", self),
"sleepyPup" = Location("Puppy (Sleep)", "Sand", "0421", self),
"pawCapsule" = Location("Pawprint Spot", "Sand", "0503", self),
"jenka" = Location("Jenka", "Jenka2", "0221", self),
"king" = Location("King", "Gard", "0602", self),
"eventToroko" = Location("Defeated Toroko+", nil, nil, self)
}
self.requirements = function(items)
if self.world.regions.upperSandZone:canAccess(items) and items:has("eventOmega") then return true end
return false
end
self.locations.jenka.requirements = function(items) return items:count("puppy") == 5 end
self.locations.king.requirements = function(items) return items:has("eventToroko") end
self.locations.eventToroko.requirements = function(items)
return items:count("puppy") == 5 and items:has("weaponBoss")
end
self.locations.eventToroko:setItem(self.world.items:getByKey("eventToroko"))
end
local labyrinthW = Region:extend()
function labyrinthW:new(worldGraph)
labyrinthW.super.new(self, worldGraph, "labyrinthW")
self.locations = {
"mazeCapsule" = Location("Labyrinth Life Capsule", "MazeI", "0301", self),
"turboChaba" = Location("Chaba Chest (Machine Gun)", "MazeA", "0502", self),
"snakeChaba" = Location("Chaba Chest (Fireball)", "MazeA", "0512", self),
"whimChaba" = Location("Chaba Chest (Spur)", "MazeA", "0522", self),
"campChest" = Location("Camp Chest", "MazeO", "0401", self),
"physician" = Location("Dr. Gero", "MazeO", "0305", self),
"puuBlack" = Location("Puu Black Boss", "MazeD", "0401", self)
}
self.requirements = function(items)
if self.world.regions.lowerSandZone:canAccess(items) and items:has("eventToroko") then return true end
if self.world.regions.labyrinthB:canAccess(items) and items:has("flight") then return true end
return false
end
self.locations.mazeCapsule.requirements = function(items) return items:has("weapon") end
self.locations.turboChaba.requirements = function(items) return items:has("machineGun") end
self.locations.snakeChaba.requirements = function(items) return items:has("fireball") end
self.locations.whimChaba.requirements = function(items) return items:count("polarStar") == 2 end
self.locations.campChest.requirements = function(items) return items:has("flight") end
self.locations.puuBlack.requirements = function(items) return items:has("clinicKey", "weaponBoss") end
end
local labyrinthB = Region:extend()
function labyrinthB:new(worldGraph)
labyrinthB.super.new(self, worldGraph, "labyrinthB")
self.locations = {
"fallenBooster" = Location("Booster Chest", "MazeB", "0502", self)
}
self.requirements = function(items)
if self.world.regions.arthur:canAccess(items) then return true end
if self.world.regions.labyrinthW:canAccess(items) then return true end
return false
end
end
local boulder = Region:extend()
function boulder:new(worldGraph)
boulder.super.new(self, worldGraph, "boulder")
self.locations = { --include core locations since core access reqs are identical to boulder chamber
"boulderChest" = Location("Boulder Chest", "MazeS", "0202", self),
"coreSpot" = Location("Robot's Arm", "Almond", "0243", self),
"curlyCorpse" = Location("Drowned Curly", "Almond", "1111", self),
"eventCore" = Location("Defeated Core", nil, nil, self)
}
self.requirements = function(items)
if items:has("cureAll", "weaponBoss") then
if self.world.regions.labyrinthW:canAccess(items) then return true end
if self.world.regions.labyrinthB:canAccess(items) and items:has("flight") then return true end
end
return false
end
self.locations.eventCore.setItem(self.world.items:getByKey("eventCore"))
end
local labyrinthM = Region:extend()
function labyrinthM:new(worldGraph)
labyrinthM.super.new(self, worldGraph, "labyrinthM")
self.requirements = function(items)
if self.world.regions.boulder:canAccess(items) then return true end
if self.world.regions.labyrinthW:canAccess(items) and items:has("flight") then return true end
return false
end
end
local waterway = Region:extend()
function waterway:new(worldGraph)
waterway.super.new(self, worldGraph, "waterway")
self.locations = {
"ironhead" = Location("Ironhead Boss", "Pool", "0412", self),
"eventCurly" = Location("Saved Curly", nil, nil, self)
}
self.requirements = function(items) return self.world.regions.labyrinthM:canAccess(items) and items:has("airTank", "weaponBoss") end
self.locations.eventCurly.requirements = function(items) return items:has("eventCore", "towRope") end
self.locations.eventCurly.setItem(self.world.items:getByKey("eventCurly"))
end
local eggCorridor2 = Region:extend()
function eggCorridor2:new(worldGraph)
eggCorridor2.super.new(self, worldGraph, "eggCorridor2")
self.locations = {
"dragonChest" = Location("Dragon Chest", "Eggs2", "0321", self),
"sisters" = Location("Sisters Boss", "EggR2", "0303", self)
}
self.requirements = function(items)
if items:has("eventCore") and self.world.regions.arthur:canAccess(items) then return true end
if items:has("eventKazuma") and self.world.regions.outerWall:canAccess(items) then return true end
return false
end
self.locations.dragonChest.requirements = function(items) return items:has("weapon") end
self.locations.sisters.requirements = function(items) return items:has("weaponBoss") end
end
local outerWall = Region:extend()
function outerWall:new(worldGraph)
outerWall.super.new(self, worldGraph, "outerWall")
self.locations = {
"clock" = Location("Clock Room", "Clock", "0300", self),
"littleHouse" = Location("Little House", "Little", "0204", self)
}
self.requirements = function(items)
if items:has("eventKazuma", "flight") and self.world.regions.eggCorridor2:canAccess(items) then return true end
if items:has("teleportKey") and self.world.regions.plantation:canAccess(items) then return true end
return false
end
self.locations.littleHouse.requirements = function(items) return items:has("flight") end
end
local plantation = Region:extend()
function plantation:new(worldGraph)
plantation.super.new(self, worldGraph, "plantation")
self.locations = {
"kanpachi" = Location("Kanpachi's Bucket", "Cent", "0268", self),
"jail1" = Location("Jail no. 1", "Jail1", "0301", self),
"momorin" = Location("Chivalry Sakamoto's Wife", "Momo", "0201", self),
"sprinkler" = Location("Broken Sprinkler", "Cent", "0417", self),
"megane" = Location("Megane", "lounge", "0204", self),
"itoh" = Location("Itoh", "Itoh", "0405", self),
"plantCeiling" = Location("Plantation Platforming Spot", "Cent", "0501", self),
"plantPup" = Location("Plantation Puppy", "Cent", "0452", self),
"curlyShroom" = Location("Jammed it into Curly's Mouth" "Cent", "0324", self),
"eventRocket" = Location("Built Rocket", nil, nil, self)
}
self.requirements = function(items)
if items:has("teleportKey") and self.world.regions.arthur:canAccess(items) then return true end
if self.world.regions.outerWall:canAccess(items) then return true end
return false
end
self.locations.jail1.requirements = function(items) return items:has("letter") end
self.locations.momorin.requirements = function(items) return items:has("letter", "booster") end
self.locations.sprinkler.requirements = function(items) return items:has("mask") end
self.locations.megane.requirements = function(items) return items:has("brokenSprinkler", "mask") end
self.locations.itoh.requirements = function(items) return items:has("letter") end
self.locations.plantCeiling.requirements = function(items) return items:has("flight") end
self.locations.plantPup.requirements = function(items) return items:has("eventRocket") end
self.locations.curlyShroom.requirements = function(items) return items:has("eventCurly", "maPignon") end
self.locations.eventRocket.requirements = function(items)
return items:has("letter", "booster", "controller", "sprinkler")
end
self.locations.eventRocket.setItem(self.world.items:getByKey("eventRocket"))
end
local lastCave = Region:extend()
function lastCave:new(worldGraph)
lastCave.super.new(self, worldGraph, "lastCave")
self.locations = {
"redDemon" = Location("Red Demon Boss", "Priso2", "0300", self)
}
self.requirements = function(items) return items:has("eventRocket", "weaponBoss") end
end
local endgame = Region:extend()
function endgame:new(worldGraph)
endgame.super.new(self, worldGraph, "endgame")
self.locations = {
"hellB1" = Location("Hell B1 Spot", "Hell1", "0401", self),
"hellB3" = Location("Hell B3 Chest", "Hell3", "0400", self)
}
self.requirements = function(items)
return items:has("eventSue", "ironBond") and self.world.regions.lastCave:canAccess(items) end
end
end
local worldGraph = Class:extend()
function worldGraph:new(items)
self.regions = {
firstCave = firstCave(self),
mimigaVillage = mimigaVillage(self),
arthur = arthur(self),
eggCorridor1 = eggCorridor1(self),
grasstownWest = grasstownWest(self),
grasstownEast = grasstownEast(self),
upperSandZone = upperSandZone(self),
lowerSandZone = lowerSandZone(self),
labyrinthW = labyrinthW(self),
labyrinthB = labyrinthB(self),
boulder = boulder(self),
labyrinthM = labyrinthM(self),
waterway = waterway(self),
eggCorridor2 = eggCorridor2(self),
outerWall = outerWall(self),
plantation = plantation(self),
lastCave = lastCave(self),
endgame = endgame(self)
}
self.items = items
end
function worldGraph:getLocations()
local locations = {}
for region in ipairs(self.regions) do
locations = _.union(locations, region:getLocations())
end
return locations
end
function worldGraph:getLocationsByRegion(...)
local locations = {}
for region in ipairs(self.regions) do
if _.contains({...}, region.name) then locations = _.union(locations, region:getLocations()) end
end
return locations
end
function worldGraph:getEmptyLocations()
local locations = {}
for region in ipairs(self.regions) do
locations = _.union(locations, region:getEmptyLocations())
end
return locations
end
function worldGraph:getFilledLocations()
local locations = {}
for region in ipairs(self.regions) do
locations = _.union(locations, region:getFilledLocations())
end
return locations
end
function worldGraph:writeItems(tscFiles)
for region in ipairs(self.regions) do region:writeItems(tscFiles) end
end
function worldGraph:collect(preCollectedItems)
local collected = preCollectedItems or {}
local availableLocations = self:getFilledLocations()
local foundItems
repeat
local accessible = {}
for location in ipairs(availableLocations) do
if location:canAccess(collected) then table.insert(accessible, location) end
end
availableLocations = _.difference(availableLocations, accessible)
foundItems = #accesible
for location in ipairs(accessible) do
table.insert(collected, location.item)
end
until foundItems == 0
return collected
end
return worldGraph

View file

@ -12,6 +12,7 @@ lg = love.graphics
U = require 'util'
local LOG_LEVEL, _logCounts, _logLines = 3, nil, nil
local function _log(level, prefix, text, ...)
if LOG_LEVEL >= level then

View file

@ -1,15 +1,14 @@
local ItemDeck = require 'item_deck'
local Items = require 'database.items'
local TscFile = require 'tsc_file'
local WorldGraph = require 'database.locations'
local WorldGraph = require 'database.world_graph'
local C = Class:extend()
local TSC_FILES = {}
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
for location in ipairs(WorldGraph():getLocations()) do
local filename = location.map .. '.tsc'
if not _.contains(TSC_FILES, filename) then
table.insert(TSC_FILES, filename)
end
end
@ -17,6 +16,8 @@ end
function C:new()
self._isCaveStoryPlus = false
self.itemDeck = Items()
self.worldGraph = WorldGraph(itemDeck)
end
function C:randomize(path)
@ -29,12 +30,9 @@ function C:randomize(path)
self:_seedRngesus()
local tscFiles = self:_createTscFiles(dirStage)
-- self:_writePlaintext(tscFiles)
local canNotBreakBlocks = self:_shuffleItems(tscFiles)
self:_writeModifiedData(tscFiles)
self:_shuffleItems(tscFiles)
-- self:_writeModifiedData(tscFiles)
self:_writePlaintext(tscFiles)
if canNotBreakBlocks then
self:_copyModifiedFirstCave()
end
self:_writeLog()
self:_unmountDirectory(path)
return self:_getStatusMessage()
@ -100,37 +98,43 @@ function C:_writePlaintext(tscFiles)
end
function C:_shuffleItems(tscFiles)
local itemDeck = ItemDeck()
local worldGraph = WorldGraph()
-- first fill puppies
local puppies = self.itemDeck:getItemsByAttribute("puppy")
local sandZone = _.shuffle(self.worldGraph:getLocationsByRegion("upperSandZone", "lowerSandZone"))
self:_fastFillItems(puppies, sandZone)
-- first, place puppies in the sand zone
for i=1, 5 do
local puppy = itemDeck:placeAnyByAttributes({"puppy"})
local puppySpot = worldGraph:getAnyByRegion({"lowerSandZone", "upperSandZone"})
local mandatory = _.shuffle(self.itemDeck:getMandatoryItems())
local optional = _.shuffle(self.itemDeck:getOptionalItems())
placeItem(puppySpot, puppy)
-- next fill hell chests, which cannot have mandatory items
self:_fastFillItems(optional, self.worldGraph:getLocationsByRegion("endgame"))
self:_fillItems(mandatory, _.shuffle(self.worldGraph:getEmptyLocations()))
self:_fastFillItems(optional, _.shuffle(self.worldGraph:getEmptyLocations()))
worldGraph:writeItems()
end
function C:_fillItems(items, locations)
local itemsLeft = _.clone(items)
assert(#items <= #locations, 'Trying to fill more items than there are locations!')
for item in ipairs(items) do
local assumed = self.worldGraph:collect(_.remove(itemsLeft, item))
local fillable = _.filter(locations, function(location, assumed) do
return not location:hasItem() and location:canAccess(assumed) end)
assert(#fillable > 0, 'No available locations!')
fillable[1]:setItem(item)
end
end
-- next, place weapon at hermit gunsmith and random item in first cave
placeItem(worldGraph:get("gunsmithChest"), itemDeck:placeAnyByAttributes({"weaponSN"}))
placeItem(worldGraph:get("firstCapsule"), itemDeck:placeAny())
-- for now, just implementing a forward fill - will do a better fill later
while itemDeck:remaining() > 0 do
local location = worldGraph:getAnyAccessible(itemDeck:getPlacedItems())
local item, itemIndex
while ~location do
item, itemIndex = itemDeck:getAnyByAttributes({"progression"})
location = worldGraph:getAnyAccessible(itemDeck:getPlacedItems(item))
function C:_fastFillItems(items, locations)
for location in ipairs(locations) do
if not location:hasItem() then
local item = _.pop(items)
if item == nil then break end -- no items left to place, but there are still locations open
location:setItem(item)
end
if ~item then
item, itemIndex = itemDeck:getAny()
end
itemDeck:place(item, itemIndex)
tscFiles[location.map]:placeItem(location.event, itemData.item.script)
end
end

View file

@ -1,8 +1,8 @@
local C = Class:extend()
local ITEM_DATA = require 'database.items'
-- local ITEM_DATA = require 'database.items'
local OPTIONAL_REPLACES = {
-- local OPTIONAL_REPLACES = {
'Max health increased by ',
'Max life increased by ',
'<ACH0041', -- Cave Story+ only, trigger achievement.
@ -37,6 +37,11 @@ function C:hasUnreplacedItems()
return #self._unreplaced >= 1
end
function C:placeItemAtLocation(script, event)
local labelStart = self:_getLabelPositionRange(event)
self:_stringReplace(self._text, "<EVE$%d%d%d%d", script, event)
end
function C:replaceItem(replacement)
assert(self:hasUnreplacedItems())
local key = self._unreplaced[#self._unreplaced].key