MMR Text File Plando - isghj5/mm-rando GitHub Wiki
The 1.16 release now has plando merged in to it, go download the latest version to try it.
The Isghj fork of MMR, released as the Actorizer/Enemizer test builds, comes with a built-in text file based plando system that lets you tell the rando where you want items to be placed, with strict or loose rules.
Link to the fork releases:
https://github.com/isghj5/mm-rando/releases
"Plando" is terminology used in the randomizer community for planned randomizer seeds, where the randomizer is given item placements ahead of time preventing some (or all) items to be completely randomized.
An example of a basic plando [single item single check] would be:
Forcing [Zora mask (item)] to be at the end of Snowhead Temple after defeating Goht and receiving [Goht's HeartContainer (check)].
My plando system was designed to be less strict though, being forced to plando all items can ruin the experience so my plando allows you to plando only one item/check and let MMR randomize everything else for minor rando adjustments.
My plando also allows more than one item or check per plando shuffle (I call them "plando events") so you can specify large lists of possible items and/or multiple possible locations for the items, providing the ability to restrict rando while keeping the outcome random enough to be playable, even by the plando creator.
An example of [single item multiple check] would be:
Forcing [Zora mask] to be at the end of Snowhead Temple [Goht's HeartContainer] or the end of Woodfall Temple[Odolwa's HeartContainer].
An example of [multiple item single check] would be:
Forcing [Zora mask] or [Deku Mask] to be at the end of Snowhead Temple [Goht's HeartContainer].
An example of [multiple item multiple check] would be:
Forcing [Zora mask] and [Deku Mask] to be at the end of Snowhead Temple [Goht's HeartContainer] and the end of Woodfall Temple[Odolwa's HeartContainer], but which one is placed in which check is random.
An example of [multiple item multiple check with draw limit] would be:
Forcing [Zora mask] or [Deku Mask] to be at the end of Snowhead Temple [Goht's HeartContainer] or the end of Woodfall Temple[Odolwa's HeartContainer], but only one is chosen at random, the other is not chosen for plando and is free to be randomized by rando (or another later plando event).
With the text based plando system, you create a json file with a name like <Filename>_ItemPlando.json
. You can create a new file or reuse the example json that comes with my builds (if you downloaded my actorizer build), and place this file in the main MMR folder. MMR will automatically detect it and use it in every seed. MMR supports multiple item plando files existing and being used at the same time. The file has to have ItemPlando.json
in the actual filename for MMR to find it. You can add an underscore _
at the start of the filename and add extra text to help organize the files. Do not use multiple underscores it will confuse the parser.
Example acceptable file names
ChatouInGoronShop_ItemPlando.json # text can be added before the underscore to name the plando files
BottleRewardInOceanSpiderHouse_ItemPlando.json # long, but acceptable
ItemPlando.json # if you only want to have one, you can ignore the names entirely
Each ItemPlando file is a json formatted file that can contain multiple item plando "events". Each event includes a list of items and a list of checks to be randomized amongst themselves at once, where "check" is randomizer terminology for the slot in which the item will be placed. You can make a single plando file that only has one event or you can stuff the file with every check in the game (not recommended though).
Format of the JSON format
[
{
"Name": "this is the name of the event",
"Notes": "this field does nothing in-rando, it exists so you can leave notes as to why events were added, or anything really
Both name and notes field are optional, you can remove them and plando will still work
but, it makes debugging plando issues 100x harder, please do not do this.
Below is the list of items, and the list of checks for this one event",
"ItemList": [ "Item1", "Item2", ... ],
"CheckList": [ "Check1", "Check2", ... ]
},
]
Each event has to be surrounded by curly brackets {
}
and if there are multiple all but the last item has to have a comma after ,
.
The whole file has to have a top level square brackets [
]
because the file is of type list of events where the square brackets mark the start and end of a list of objects.
Example of a file that has two events:
[
{
"Name": "name1",
"Notes": "notes1",
"ItemList": [ "Item1" ],
"CheckList": [ "Check1" ]
},
{
"Name": "name2",
"notes": "notes2",
"ItemList": [ "Item2" ],
"CheckList": [ "Check2" ]
}
]
Names and notes are completely optional fields and can be left out... but if the plando fails it's almost impossible to debug what is wrong without the name fields at least. Please use these fields for your own benefit.
The plando files use the names of the items from the rando Item Enum (A list of details about each item rando uses for data centralization) found here: https://github.com/ZoeyZolotova/mm-rando/blob/dev/MMR.Randomizer/GameObjects/Item.cs
The Enum contains lots of data we do not need, we only really need the name of the item for our plando, and the rest of the data sits right above the item name and is ignorable.
For instance, the bunny hood is MaskBunnyHood
found on this line
https://github.com/ZoeyZolotova/mm-rando/blob/dev/MMR.Randomizer/GameObjects/Item.cs#L797
The Checks in the checklist use the same names as the items, which might be confusing, but to rando they are the same thing, every check in the game has a vanilla item, so each item has a check and visa-versa.
Examples of Item name and what the check is in MMR:
MaskBunnyHood:
The item name: "Bunny Hood"
The location name: "Grog"
Defined in the enum at this location:
https://github.com/ZoeyZolotova/mm-rando/blob/dev/MMR.Randomizer/GameObjects/Item.cs#L797
ItemFireArrow:
The item name: "Fire Arrow"
The location name: "Fire Arrow Chest"
Defined in the enum at this location:
https://github.com/ZoeyZolotova/mm-rando/blob/dev/MMR.Randomizer/GameObjects/Item.cs#L40
ItemPictobox
The item name: "Pictograph Box"
The location name: "Koume"
Defined in the enum at this location:
https://github.com/ZoeyZolotova/mm-rando/blob/dev/MMR.Randomizer/GameObjects/Item.cs#L102
If the list has only one item and one check, it will force that one item into that one check, which is how most people think plando works.
{
"Name": "example of single item",
"Notes": "this places a single item in a specific check",
"ItemList": ["MaskBunnyHood"],
"CheckList": ["HeartPieceSouthClockTown"]
},
In that example bunny hood is always placed on the clocktower steps.
You don't have to use single-to-single though, If you give it a whole list of checks, it will place the one item in any of the list of checks using the normal randomizer code.
Example puts the royal wallet in an early easy to get check:
{
"Name": "example of single item random multiple checks",
"Notes": "this places a single item in one random check from a list",
"ItemList": [ "UpgradeRoyalWallet"],
"CheckList": ["HeartPieceDodong", "ChestGreatBayCoastGrotto", "ChestTerminaStumpRedRupee",
"MundaneItemHoneyAndDarlingPurpleRupee", "HeartPieceNorthClockTown",
"ShopItemTradingPostStick", "ShopItemTradingPostRedPotion",
"ShopItemTradingPostArrow30", "ChestBomberHideoutSilverRupee",
"ChestGreatBayCapeGrotto", "ChestEastClockTownSilverRupee"]
},
Using multiple checks has multiple advantages:
If you have multiple plando events, in one file or in multiple, you can sometimes forget you already specified an item has to go in a specific check. If plando is told to place a second item in an already claimed check it will stop with an error. If you give plando multiple locations, because the specific location is not important, plando will identify that checks have already been filled and reduce the size of the list, and continue. This gives plando fallback locations and reduces plando failures. Using multiple checks also means you don't know immediately where an item is placed, which can allow the plando maker to play their own settings without knowing the outcome because there is still some level of randomization per plando seed.
If you don't care about about a specific location, this can keep some level of randomness allowing the plando author themselves to play their own plando without knowing the exact location of every item. For instance, you can specify that you want Hookshot
to be on one of the boss heart containers, rando will select them at random per-seed, so you won't know which boss has the item until you play the seed, and the seed could be very different depending on which boss it is on.
You can also specify multiple items and multiple checks at the same time as well, plando will attempt to place every single item in the itemList in a check.
Example: Place the Remains on healing mask checks (where you would normally get a powerful mask). So you have to heal everyone to beat the seed.
{
"Name": "remains on song of healing locations",
"Notes": "this places remains on song of healing locations",
"ItemList": [ "RemainsOdolwa", "RemainsGoht", "RemainsGyorg", "RemainsTwinmold" ],
"CheckList": [ "MaskKamaro", "MaskGoron", "MaskZora", "MaskGibdo" ],
},
Example 2: Place all of the BossRemains back in the dungeons, but they could be on any check in the dungeons, not just vanilla boss remains, and they could all be in one dungeon, not spread out. This would make dungeons heavier in the logic, where as remains randomized among the world often makes dungeons barren.
{
"Name": "remains in any dungeon",
"Notes": "this places all four remains in any dungeon",
"ItemList": [ "RemainsOdolwa", "RemainsGoht", "RemainsGyorg", "RemainsTwinmold" ],
"CheckList": [ "ItemBow", "ItemFireArrow", "ItemIceArrow", "ItemLightArrow", "ItemHookshot", "UpgradeMirrorShield", "HeartPieceCastle", "ItemWoodfallKey1", "ItemWoodfallCompass", "ItemWoodfallMap", "CollectibleStrayFairyWoodfall10", "CollectibleStrayFairyWoodfall11", "CollectibleStrayFairyWoodfall12", "ItemSnowheadMap", "ItemSnowheadCompass", "ItemSnowheadKey1", "ItemSnowheadKey2", "ItemSnowheadKey3", "CollectibleStrayFairySnowhead8", "CollectibleStrayFairySnowhead9", "CollectibleStrayFairySnowhead10", "CollectibleStrayFairySnowhead11", "CollectibleStrayFairySnowhead14", "CollectibleStrayFairySnowhead13", "CollectibleStrayFairySnowhead12", "ItemGreatBayMap", "ItemGreatBayCompass", "ItemGreatBayKey1", "CollectibleStrayFairyGreatBay5", "CollectibleStrayFairyGreatBay6", "CollectibleStrayFairyGreatBay7", "CollectibleStrayFairyGreatBay8", "CollectibleStrayFairyGreatBay9", "CollectibleStrayFairyGreatBay10", "ItemStoneTowerMap", "ItemStoneTowerCompass", "ItemStoneTowerKey1", "ItemStoneTowerKey2", "ItemStoneTowerKey3", "ItemStoneTowerKey4", "CollectibleStrayFairyStoneTower1", "CollectibleStrayFairyStoneTower2", "CollectibleStrayFairyStoneTower3", "CollectibleStrayFairyStoneTower4", "CollectibleStrayFairyStoneTower5", "CollectibleStrayFairyStoneTower6", "CollectibleStrayFairyStoneTower7", "CollectibleStrayFairyStoneTower8", "CollectibleStrayFairyStoneTower9", "CollectibleStrayFairyStoneTower10", "CollectibleStrayFairyStoneTower11", "CollectibleStrayFairyStoneTower12", "CollectibleStrayFairyStoneTower13", "CollectibleStrayFairyStoneTower14", "CollectibleStrayFairyStoneTower15", "HeartContainerWoodfall", "HeartContainerSnowhead", "HeartContainerGreatBay", "HeartContainerStoneTower", "RemainsOdolwa", "RemainsGoht", "RemainsGyorg", "RemainsTwinmold", "ChestPiratesFortressRedRupee1", "ChestPiratesFortressRedRupee2", "ChestInsidePiratesFortressTankRedRupee", "ChestInsidePiratesFortressGuardSilverRupee", "ChestInsidePiratesFortressHeartPieceRoomRedRupee", "ChestInsidePiratesFortressHeartPieceRoomBlueRupee", "ChestInsidePiratesFortressMazeRedRupee", "ChestPiratesFortressEntranceRedRupee1", "HeartPiecePiratesFortress", "ChestPiratesFortressEntranceRedRupee2", "ChestPiratesFortressEntranceRedRupee3", "ChestWellRightPurpleRupee", "ChestWellLeftPurpleRupee" ],
},
(although if you wanted to force one remain per dungeon, spreading them out, just copy the event and split into 4 separate events with the checks-per-event cut down to per-dungeon and add a Limited Item Draw of 1 per event, see below)
If you want only a specific number of items from the item list, you can add a parameter to the event called itemDrawCount
which allows you to control how many items are drawn from the itemList to put in the checkList:
Example of single item from multiple:
{
"Name": "example of random single to random multiple",
"Notes": "this places one randomly selected item from a list in a check randomly selected from a list",
"ItemList": [ "SongEpona", "MaskGoron", "MaskBunnyHood"],
"CheckList": [ "ChestSwampGrotto", "ChestToSwampGrotto", "ItemBottleWitch", "HeartPiecePeahat", "HeartPieceDogRace", "HeartPieceDodong", "ShopItemTradingPostNut10" , "HeartContainerWoodfall"],
"ItemDrawCount": 1
},
The above plando will choose Epona song OR Goron Mask OR Bunny hood on an early check in the game. This plando could be used to speed up the characters movements to prevent the game from starting too slow, but only one is given per seed and the location is still not known outright. (of course, if you don't plando the items, they could also show up early because rando will still put them in completely random locations)
WARNING: Plando will fail if you set the itemDrawCount higher than the number of items available in the list, and if items in the itemList have already been placed somewhere else by another plando that means the itemList will be smaller by the time this event is being randomized.
Because JSON does not allow code comments, we cannot disable an event by commenting it out. Instead, if you want to temporarily (without deleting) the event you can set itemDrawCount
to 0, and the event will be ignored.
You could also split one large plando file into parts and move the one event you want to disable to another file and disable the file, see below.
MMR will not find it unless s the filename includes ItemPlando.json
so you can just inject .disabled
before (or after) the file extension and get *_ItemPlando.disabled.json
or *_ItemPlando.json.disabled
and it will not be found.
(Only issue with the later is windows will bark at you every time you change a filetype, which is annoying)
Isghj's actorizer branch now supports plando files having regions defined, so instead of every item listed directly, you can use "SnowheadTemple" and all checks in that area that are randomized will auto-fill into a list for you.
What if I don't care about where an item goes specifically, I just want to stop and item from going to one location?
Isghj's actorizer branch now supports inverted check lists, allowing you to say "I want this item to go anywhere else than [This location]", to use this feature create a CheckListInverted
instead of CheckList
. Works for item list too, ItemListInverted
.
I cannot recommend plandoing that many items, it is a mess to debug all of the issues you will have, and I will not help you. Please try to plando < 50% of the items for your own sanity.
Version 1.16 (currently in beta) will have this plando functionality build it.
If you had an old plando file it needs to be updated to use double quotes around the fields "Name" and "ItemList" and so forth. The old format wasn't technically json compatible, it was jobject and I didn't notice, when it was merged with 1.16 we switched so we can use one library for all json in the whole project.