Skybook
The Inventory Slot Transfer Simulator Project
中文版 | English Version
Getting started
- How to use the simulator
- Brief Overview of Inventory Slot Transfer
- Contributing to Translations
- Technical details for developers
Having an issue?
Please provide feedback, bug reports and feature requests on GitHub. Alternatively, you can join the communities below for discussion in general.
Discord
I prefer discussion in public channel over DMs for visibility, in case someone else may have the same problems as you. Please only DM me for privacy or other concerns.
Join my Discord
and get the BOTW Tools
role to get access to the #botw-ist
channel to ask
questions about or discuss features of the IST Simulator App.
Join the BOTW Speedrunning Discord and use the #glitch-hunting
channel
to discuss IST in general, or get help with the glitch in #general-help
, or
the category channel that you are running.
History
Discovery
Inventory Slot Transfer (IST) was discovered in June 2022 by zxrobbin ( Video 1, Video 2 ). It initially manifested as an innocent glitch to quickly duplicate items in Breath of the Wild. Little did we know that IST will become the most complicated glitch to ever exist in BOTW.
Around June 17, 2022, as the news spread, glitch hunters from the BOTW speedrunning community started to investigate and quickly found some patterns to the glitch.
Hundo Duplication Simulator
Meanwhile, speedrunners of the 100% category started to incorporate it into the route. However, even the simplest form of this glitch required tracking the exact state of the player’s inventory for every action executed, such as picking up or dropping an item. The rules and patterns of this glitch then needs to be applied at each of these steps. It was a painstaking process to manually track all the information.
Luckily, tasks that are difficult for humans are often easy for computers.
On June 18, 2022, the Hundo Duplication Simulator was born. Users could
type actions such as get 1 core
into the simulator. The simulator app
will display the inventory state and allow the user to quickly navigate between the steps.
This was a massive help for optimizing setups for speedruns because people can change one step and the app will re-calculate
the state for every step afterwards. This model is still used by the simulator today.
V2 - IST Simulator
As more applications of IST are found, the glitch has found its use in categories outside of the 100% category, for example in All Shrines and All Dungeons. One of such application is Direct Inventory Corruption. However, the simulator was built in one day and did not support any cases other than the very basic rules that were initially discovered.
Now that this glitch is not specific to 100-percent, the project was renamed
to IST Simulator. V2 of the simulator added GameData
Inventory and more items
to simulate the inventory state closer to how the game handles it. Direct Inventory Corruption
support was added. People were happy.
V3 - IST + Weapon Modifier Corruption
…Until more applications of IST are found again, and the simulator being a simulator, did not support these new exploits because I couldn’t predict the future.
Every time a new discovery is made, it almost certainly invalidates assumptions previously made when coding the simulator, and the core has to be re-designed to incorporate the new knowledge. In November 2022, I started re-designing the core by referencing the BOTW decompilation project. This massively improved the accuracy of the simulator and supported new applications such as Weapon Modifier Corruption. The UI was also revamped, adding syntax highlighting to commands and displaying modifier information for items.
V4 - Skybook
After the V3 update, a few small fixes were submitted, but no big re-architecture was made for 2 years.
While V3 was mostly accurate for setups viable for speedruns, it was still far from being perfect:
- It didn’t handle special cases for champion abilities or Travel Medallion.
- It didn’t handle cases where tabs aren’t discovered
- It couldn’t reliably detect and warn user when an action is not possible in game,
such as interacting with the inventory when
mCount
is0
. - …
It was clear that we can not chase these edge cases forever. Something needs to be remade from the ground up, again. Sometime in 2022-2023, I have theorized to build a mini-emulator, to run the simulator from a small part of the game itself. I submitted this idea as a proposal for senior project at my college, and got a student team who was interested in it. I lead the team as the advisor to build a prototype that would later become BlueFlame, the new core for V4.
At the same time as BlueFlame was being developed by the students, I worked on everything else - a new command system, new simulated systems like Overworld and Screens… And finally, in July 2025, Skybook was born.
For the first time, the IST simulator project is ahead of the game. The simulator is so accurate, it could replicate setups that I didn’t know would be possible (and thought they were bugs, but they are not).
FAQ
What is IST? What is this app?
Inventory Slot Transfer, or IST, is a glitch in BOTW that desyncs the number of items you have in the inventory and number of items the game thinks you have. For more details, check out history of the app and an overview of the glitch.
I am new to IST; how do I use this tool?
You definitely don’t need to be a master of IST to find this tool useful. If you are looking at a speedrun setup made by someone else, you can view the setup in the tool as a step-by-step guide for how to perform the glitch. If you are a glitch hunter or are interested in investigating the glitch in more details, the user manual has everything you need to unlock the full potential of the simulator.
In any case, it might be helpful to understand the basic concepts of IST to get started.
I can’t understand IST, but I still want to speedrun
Don’t worry; IST is very complicated. Most people (including WR holders!) don’t fully understand the glitch. This is exactly why this tool exists.
If your goal is to do the setup in a speedrun, what most people do is simply following each action in the setup exactly, either from memory, or by looking at the steps while they do it. Many categories also have tutorials made for the IST section. For example, here is one for All Dungeons made by Player 5.
I just want to play with IST as a casual player
Be cautious to use IST with your casual file, as effects of IST can persist in saves and may cause the saves to be corrupted or non-loadable.
There are generalized guides for how to achieve certain things with IST
in a casual file (for example, 999 korok seeds
). You can follow
these steps. A good place to look for those steps is the #general-help
channel of the speedrunning discord.
There are also tutorials online on YouTube (or Bilibili if you are from China)
for using IST in a casual file.
How is the simulator made?
V1 to V3 of the simulator was developed by understanding the outcome and patterns of IST, and by referencing the decompilation project. It was a white-box approach, similar to a person that understood everything ever discovered about IST. V4 took the black-box approach, where sections of the real code of the game (not decompiled code) is executed in a sandbox orchestrated by the simulator app. This means the simulator might even be possible to support use cases that are not discovered yet.
Can I contribute?
Certainly! If you see some bugs and want to take a shot at fixing them, feel free to open a PR on GitHub. If you want to add features, please discuss with me first. A decent level of programming knowledge is needed.
Most of this project is open-source and use publicly-available data of the game. However, some parts require that you own a copy of the game to develop.
Please refer to the contributing guide for more information.
If your goal is to add extra functionality, you might be able to do that through an extension. See Extensions.
If you are not familiar with programming, you can still contribute to the test suite by providing your (complicated) scripts as test cases. These test cases help ensure future updates to the simulator don’t introduce bugs. See Snapshot Testing.
If you are not able to generate the snapshot locally, simply make sure the output for every step
is correct in the App, then open a PR with just the new .txt
script file.
Inventory Slot Transfer
What is IST
Believe it or not, Infinite Stuff Trick is NOT the name of the glitch
IST stands for Inventory Slot Transfer. It is a glitch in Breath of the Wild that exploits behavior of the inventory when the variable tracking the number of the items in the inventory is less than the number of items actually in the inventory.
The developers made sure that these two values are kept in sync during normal gameplay. However, in very specific scenarios, the game removes the item slot from the inventory while subtracting the number of items twice, resulting in the game tracking 1 fewer item slots in the inventory. By repeating the action, we can make the game track fewer and fewer items.
The difference between the number of items in the inventory and number
tracked by the game is called Offset
or number of Broken Slots
.
Offset
is technically more correct, but because it’s ambiguous in some contexts,
this manual will refer to this number as Broken Slots
.
The action to create the Broken Slots is referred to as Breaking Slots
.
Broken Slots
is the name used by the glitch hunting community before
the underlying concepts of the glitch were fully understood. There’s nothing
actually broken about the slots.
The variable that tracks the number of items is commonly referred to by
the glitch hunters as mCount
- a reference to the name of the variable
in the BOTW decompilation project.
This variable is needed because the inventory is stored as a (doubly-)linked list, which has a O(N) time complexity for calculating its length.
The different counts have this relation:
mCount + Number of broken slots = Actual number of items
Inventory Representation
The inventory that you see when opening the inventory in-game - the Visible Inventory
- is
stored as a (doubly-)linked list. In this list representation, items in different categories
are “concatenated” into the same list. For example, in normal inventory order,
the list may have all the weapons, followed by all the bows, followed by
all the arrows, etc, and at the end are all the key items. In one page
of the item in the in-game UI, the top-left corner is first,
and it follows row-major order (i.e. the item in row 1 column 2 is after the item
in row 1 column 1 in the list), and the bottom-right corner is last,
followed by the upper-left corner item of the next page.
The items are also stored at the same time in GameData
, which is the game’s flag system.
The relevant flags are stored with an array type. For example, PorchItem
is a flag that
stored an array of 420 strings, each string correspond to one item’s name.
Other properties of the items are stored each in a different flag, for example
PorchItem_EquipFlag
is an array of 420 bool
s (whether the item is equipped),
and PorchItem_Value1
is an array of 420 s32
s (the value/durability of the item).
Whenever the Visible Inventory
changes, the change is synchronized to GameData
.
We call this process Sync GameData
or simply Sync
. The GameData
is also
what is stored in the save files.
When mCount
is 0, you won’t be able to see the items in the inventory when you open it.
This is because the game thinks
the inventory is empty since the number of items is 0.
However, the items are still there. You can throw a weapon or pick up any item -
as long as mCount is no longer 0, you will be able to access the inventory again.
Why is it called IST - The main mechanism
The huge number of glitches that are derived from IST all rely on the core mechanism - transferring slots, which is how the glitch got its name.
This all happens when the inventory is Reload
-ed, either when loading a save,
or restoring the inventory from a quest that takes away your items (i.e.
Trial of the Sword, Stranded on Eventide, or any of the Blight Refights).
When restoring the inventory, the game needs to do 3 things:
- Delete all of your current items in
Visible Inventory
. - Load the data of the inventory to restore into
GameData
.- In case of reloading a save, it is loaded from the save file.
- In case of quests, it is already stored in
GameData
.
- Add the items in
GameData
one-by-one into theVisible Inventory
.
The magic happens in step 1. Since mCount
is less than the actual number
of items, the game does not fully delete all the items in inventory.
These leftover items will still be there after the reload, effectively
being transferred from one save to another.
Derivative Glitches
The following glitches depend on IST. Click on the link for more information about each of them.
- Direct Inventory Corruption (DIC)
- Weapon Modifier Corruption (WMC)
- Prompt Entanglement (PE)
- Item Stack Underflow
Direct Inventory Corruption (DIC)
Inventory Corruption is a form of Durability Transfer.
In the game, durability is stored as a fixed-point integer,
with 1
being 0.015
. For example, a weapon with durability 10
has the internal
value of 1000
. In the case of corruption, the durability is transferred
from an equipment - not to another equipment, but to an item. The value
then becomes the count of items. This is very useful, since
you can get a LOT of items from an equipment with relatively low durability
that’s easy to get.
This form of corruption was previously only possible using Memory Storage - another very complex glitch with a lengthy setup. With IST, however, Inventory Corruption is much easier, hence the name Direct Inventory Corruption.
We will go over a few game mechanics first in order to understand why DIC happens.
Setting Durability on Equipment
The game sometimes need to set the durability of the equipment in the inventory from the overworld weapon actor in order to keep the durability in sync. This could happen in a few scenarios, including:
- Using an equipment, such as attacking with weapon, shield surf and shooting an arrow (which uses both bow and arrow)
- Switching equipment
- After reloading from a save
The algorithm to do this is:
- Find the first item in the inventory list that is both equipped and is the same item that is trying to be set (for example, Master Sword)
- Set the value of that item
If you remember from Inventory Representation,
the game also need to sync this change to GameData
. However, syncing the whole
inventory whenever one value changes seem inefficient. Therefore, this form
of sync is done by directly taking the position of the item in the inventory list,
and setting the value of the item in the same position in GameData
.
This is correct if the GameData
is always in-sync with Visible Inventory
,
which would be the case most of the time. Therefore, all the inventory corruption
aims to do is cause GameData
to be desynced, then trigger a durability set.
Note that this is only one form of desync, which is the primary one used for inventory corruption. There is another form of desync used by inventory corruption using Inventory Storage, which is a derivative of Map Storage. We will not be going into the details for that.
GameData Corruption with IST
All it takes for corruption now is 2 things:
- Desyncing GameData
- Apply durability while GameData is desynced.
IST makes desyncing GameData trivial. Recall the 3 steps for reloading:
- Delete all items
- Load GameData
- Add items in GameData to Inventory
After these steps, the game doesn’t actually sync GameData
. Therefore,
whenever items are transferred, the GameData
is automatically desynced
after a reload.
Remember that reloading a save also causes durability to be applied?
This means inventory corruption automatically happens after a reload.
All the player needs to do to exploit this, is to transfer specific items
to desync the GameData
in the way so that equipped items are aligned
to the item to corrupt. This is why different IST setups exist to corrupt
different things in different speedruns.
This is also why it is important to follow the setup to unequip/equip
certain items before reloading, because the equipped item slot is what is
used for corruption. To be exact, the durability of the last equipped slot
is transferred into the first equipped slot in both Visible Inventory
and GameData
.
Aligning the Items
In a DIC setup, we need to align the equipped equipment with the item to corrupt. This is done by transferring the right number of Swords, Shields, Bows, and Arrows. Transferring anything after Arrows typically has no effect, because they don’t affect the positions of equipments since those categories are after equipments in inventory order.
Recall that transferring an item means it is not removed in the inventory. Since the items from GameData are then added on top of that, the transferred items will appear before the items that are loaded in. Effectively, transferred equipments will push items from the save to slots after it.
To determine the right type of equipment to transfer, consider the order of the categories:
- Since Shield is last, transferring any type of equipment will affect the position of shields
- Since Weapon is first, only transferring weapon will affect the position of weapons.
- The rest follow the same concept
For example, transferring 1 Bow, 1 Arrow, 1 Shield, will:
- Not change position of Weapons
- Push Bows by 1 slot
- Push Arrows by 2 slots
- Push Shields by 3 slots
Unsorted Inventory and Leftward Corruption
Note that GameData desynced in this way can only push the items to the right, not left. For example, Weapons can corrupt everything, but Bows cannot corrupt Weapons, and Shields cannot corrupt Weapons, Bows, or Arrows.
Corrupting items that are not possible to corrupt in normal inventory order is known as Leftward Corruption
,
or sometimes Forward Corruption
.
This is done by making the inventory into an order that is not normal. For example, to transfer
durability from a Shield to a Sword, the Sword must be put after the Shield. This state is typically known
as Unsorted Inventory
and opens up a whole different glitch category.
Achieving Unsorted Inventory
is relatively easy. All we need to look at is how the game
put (sort) the item into the correct category when you get something:
- The game always adds the item to the end of the inventory
- The game then sorts the inventory with the following rules:
- Two items should not change their relative order (if A is before B, A must also be before B after sorting)
- Two items that have the same category are considered equal
- Items that should appear in a category before other categories have lower values (say Sword is 0, Bow is 1, etc)
- The list is sorted from lowest value to highest
This type of sort is referred to as a stable sort using a predicate that only compares the category of the items.
The sorting itself cannot achieve the unsorted state, but absence of sort can.
The list code has one more optimization, that sort operations are skipped if
the list has no more than one element. Normally, having 0 or 1 element in the list
means the list is trivially sorted. However, mCount
is used for this optimization
and we know mCount
is not the actual number of items in the inventory.
All it needs for the sort to be skipped is to make your mCount
less than or equal to
one.
Unsorted Inventory can also be used to transfer more equipment with fewer Broken Slots by
putting Weapons after Key Items. This is typically used in speedrun setups where it could be
faster to not break as many slots. This is why some setups require dropping some weapons, then
immediately pick them up again. While picking up the weapons, the mCount
never surpasses
1
, causing the weapons you pick up remain at the end of the inventory.
Weapon Modifier Corruption (WMC)
A Weapon Modifier refers to the power-ups that can be found
on an equipment, such as Attack Up
or Durability Up
.
Weapon Modifier Corruption is a glitch enabled by IST
to transfer data from a cooked item to a weapon, interpreting the memory
as a Weapon Modifier.
During this corruption:
- The
Health Recover
value of the cooked item becomes theValue
of the modifier.- For regular food, this value is the number of quarter-hearts recovered. Between 0 and 120.
- For hearty food, this is the number of yellow hearts.
- The
Sell Price
value of the cooked item becomes theType
of the modifier.- The
Type
is a bit-flag, so WMC can enable multiple modifiers on the same equipment. - See
actWeapon.h
for values for each modifier type.
- The
You will see Prompt Entanglement (PE) often brought up together with WMC. This is because WMC relies on the data from a cooked item, and you can only get a very limited subset of possible cook data values by cooking with normal ingredients. PE allows cooking with unusual ingredients, which is required to get some modifier value/flag. However, WMC and PE are 2 separate glitches, and neither is required to perform the other.
Base Mechanism
WMC is possible because:
- The data for cooked item and the data for modifier is in the same memory
location for each item. i.e. if the item is a food, then the data is used
as cooked data, and if the item is a weapon, then it is used as modifier data.
- This is only true for
Visible Inventory
, notGameData
.
- This is only true for
- The data for cooked item is added separately from the item itself.
In step 2, the cook data is added after adding the cook item, and the game assumes the last added item is the cook item that is supposed to receive the data.
Therefore, a WMC setup typically involves:
- Making sure the last added item is the weapon to receive the corrupted modifier
- Make the cooked item that donates the data fail to load while the last added item is still the weapon, transferring the data to the weapon
Note that #2 essentially means that no item should be loaded between the weapon and the cook item.
Depending on how these 2 conditions are satisfied, the WMC setups can be further categorized.
In general, WMC can refer to any of the cases where the last added item is not the item that is supposed to receive the data.
You can technically corrupt any item in Visible Inventory
,
but only Equipments and Foods will have the data saved to GameData
.
It is not possible to transfer modifier between Weapons, because unlike food, the data for weapons are added in the same step as the item itself (condition 2 from above).
Currently, WMC is only possible when reloading the inventory from GameData
(for example
when reloading a save). This is because there is no known way to trigger adding a cook item
during normal game play while at the same time making it so the cook item doesn’t get added
successfully.
Food Limit
Using the food limit was one of the first methods to WMC. This WMC setup uses the fact that during a reload, any food after the first 60 will not load (under normal circumstances). This can be achieved by transferring 60 food into a save with a weapon, followed by the donor meal.
Example script:
get 1 hammer 1 wild-green[hp=120, price=113]
save
eat wild-green
get 60 dubious-food
!break 60 slots
reload
The step-by-step explanation:
- Note that in the save, the items are 1
hammer
and the donor meal: these are what will be added during reload. - Note that we are transferring 60
dubious-food
. - During the reload, the
hammer
loads in first. - When loading the donor meal, since there are already 60 food, it fails to load.
- Since the last-added item was the
hammer
, the data from the donor meal is transferred to the hammer.
The main drawback for this method is that it requires 60 food and 60 broken slots. Getting 60 broken slots is very tedious.
Stackable Food Limit
The reason why the previous setup required 60 broken slots, is because if we don’t transfer 60 food, then there will be food items that get loaded after the hammer. As a result, the cook data will be transferred to that item, instead of the weapon.
But wait! What if that’s exactly what we wanted? Instead of transferring the modifier directly to the weapon, we can do 2 transfers:
- Using the Food Limit method, transfer the data from the donor meal to a Stackable food (i.e. a roasted/baked/frozen food)
- Using Direct Inventory Corruption, corrupt the food value to >=500
- When loading a stackable item slot, if the value being loaded - plus the value of the item in the inventory - is greater than 999, the stack will fail to load (this is why we need >=500 in the previous step)
- When the stackable food fails to load, it can trigger WMC
Example script
# Setup
get 1 hammer
!break 1 slots
get 58 dubious 1 roasted-endura-carrot 1 wild-green[hp=120, price=113]
# This will make only the last food fail to load, transferring the data to the carrot
save; reload
# Clean up the foods now
eat wild-green; eat all dubious
save
# Corrupt the carrot stack
unequip hammer
eat roasted-endura-carrot
reload
save
# Finally transfer the data to the hammer
reload
As you can see, this method can work with a minimum of 1 broken slots, which is a big improvements over 60 broken slots. In speedruns, typically we use more broken slots anyway to corrupt other stuff and for duplicating food to quickly reach the 60 food required for the first transfer.
The Nullptr Exploit
Both previous setups require 60 food to make the first transfer happen. It would be really nice if that’s not the case. This is where the Nullptr Exploit comes in.
Recall that after adding the cook item (or fails to add), the game applies the cook data to the last added item without checking if it’s the cook item. However, when there is no last added item, the data is not added, and crucially, the game does not advance to the next cook data slot. This means when the next food loads, it will keep using the cook data of the previous food!
This can happen because in the GameData
, the cook data and the item themselves are not stored in the same array:
- The item name array has 420 strings, one for each item.
- The cook data array has 60 elements, one for each food.
When the Nullptr Exploit is triggered, the counter for the item array increments, but not the cook data array.
Using this exploit, 60 food is no longer required. However, this exploit is pretty tricky to trigger;
this is because mLastAddedItem
is only nullptr
before any item is added (with one exception being the Master Sword).
Master Sword (MSWMC)
This setup triggers the Nullptr Exploit using the fact that Master Sword cannot be duplicated.
The condition for this trigger is somewhat complicated:
- A Master Sword is transferred (can be broken or not broken)
- The save being loaded doesn’t have Master Sword being the first item
- This is because adding the first item skips the part check we rely on to trigger the exploit
- The Master Sword Recharge Timer in the save being loaded is non-zero
- The save being loaded has a Master Sword (either broken or not broken)
- 3 and 4 usually means the save has a broken Master Sword
In one sentence, this means to “transfer a Master Sword into a save with a broken Master Sword”.
When all of the above conditions are met, the last-added item is set to nullptr
, enabling the exploit.
The whole setup would be:
- Enable the exploit as described above
- In the same reload, load a food unsuccessfully, without loading any item in between
- This uses the exploit described in the previous section to cause the reuse of cook data
- Now any food that loads after will have the data that’s supposed to be on the food before it
- Continue the Stackable Food Limit setup
Travel Medallion (TMWMC)
This section is WIP and may contain inaccurate information. If you see any issues, or want to improve this section, please create a Pull Request.
The Travel Medallion is added in the Master Trials DLC. Unlike any other DLC items, it gets removed if you uninstall the DLC.
This can be used to trigger the Nullptr Exploit:
- Make a save with Travel Medallion being the first item, and food after it (using Unsorted Inventory )
- Close the game and uninstall the DLC
- If you have physical game without DLC + digital game with DLC, this can be done by ejecting the Virtual Game Card
- Otherwise, follow the steps on this Nintendo Support Article
- Reload the save, setup IST again to transfer some food to make the food fail to load
- Reload the save again, the Travel Medallion will not load as the first item since DLC is uninstalled, and the next food will fail to load because of the transfer
- Now any food that loads after will have the data that’s supposed to be on the food before it
- Continue the Stackable Food Limit setup
Unlike MSWMC, Travel Medallion does not set last added item to nullptr
, so it has very limited usefulness.
Zelda Notes (ZNWMC)
This section is WIP and may contain inaccurate information. If you see any issues, or want to improve this section, please create a Pull Request.
This method has not be verified. It is only theorized based on reverse engineering of version 1.8.0 of the Switch 1 Edition.
Zelda Notes is an item exclusive to the Nintendo Switch 2 Edition. When you uninstall NS2E, it gets removed from your inventory and can be used to trigger the Nullptr Exploit:
- Make a save with the Daily Bonus and Deposit Item being the first 2 items, and food after it (using Unsorted Inventory )
- Close the game and uninstall NS2E
- If you have the physical NS2E Game Card and the NS1E game (physical or digital), this can be done by removing the physical NS2E Game Card (then inserting the NS1E Game Card if you have a physical copy)
- If you only have the physical NS2E Game Card, this is not possible.
- Otherwise, follow the steps on this Nintendo Support Article to download the game without NS2E
- The rest is similar to TMWMC
Prompt Entanglement (PE)
This glitch is related to the Pouch Screen, which has not been reversed engineered. Most of the concepts are based on experiments, and may not reflect the actual implementation in the game.
This section is WIP and may contain inaccurate information. If you see any issues, or want to improve this section, please edit this file and open a Pull Request.
Prompt Entanglement, or PE, is a glitch that allows you to apply a prompt (like “Equip”, “Drop”, “Hold”, etc) from one item to another item that is not supposed to have that prompt. For example:
- Holding a Food (only Materials are normally holdable)
- Equipping a Material
- Eating a Key Item
Invalid Star Tab
To activate PE, the first step is to activate a state known as Invalid Star Tab. This is a state that allows the cursor (the box that highlights which item is currently selected in the inventory) to go to the “Key Items” icon.
Currently, the only known way to activate Invalid Star Tab is by having items in a category that you have not discovered. For example, have a material without picking up any material.
At first this seems impossible. However, the catch is “picking up” - you can obtain items without picking them up with IST. In an Invalid Star Tab setup, there are 3 general steps:
- Save with the tab you want to use undiscovered
- Pick up an item in that tab, which discovers the tab and gets you the item
- Use IST to transfer that item back into the save you made
Once the setup is done, you can verify Invalid Star Tab is active if any of the following is true:
- When you scroll to the right very quickly, the cursor ends up on the Star.
- When you go to the “System” screen, the cursor remains on the left screen. You can only see the cursor when you press “Right”, which moves it on to the “Save” button.
Cursor Glitch
The Cursor Glitch is not fully understood, since the inventory screen system is not reversed engineered. This section may contain inaccurate information.
When Invalid Star Tab is active, you can now perform the Cursor Glitch to achieve PE. This glitch uses a sequence of controller inputs to quickly move the cursor while Invalid Star Tab is active to confuse the inventory code, and puts the cursor on a tab that’s not the current tab you are viewing.
|- you are looking at this page
v
MATERIAL FOOD
[ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ] [ ] [ ] [X] [ ] [ ] <- cursor (X) is on another page
[ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]
[ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]
^
|- (this is where Link's model usually is on screen)
Typically, we refer to the position of the cursor by the Row and Column.
In the example above, we say the Cursor Glitch is active at Row 2, Column 3
,
or simply Row 2 Column 3 is activated
.
Since the Cursor Glitch is not fully understood, the community has put together a spreadsheet of different input sequences you can use to active each slot.
When Cursor Glitch is active, you can keep it active by moving tabs in groups of 3 (tap right-stick right 3 times, or left 3 times), without pausing too long between them. Pausing while not on a multiple of 3 tabs from where the slot is activated will reset the cursor’s position, losing the glitched state.
Capturing the Prompt
What the Cursor Glitch enables, is that we can now move the cursor to another item, while the inventory screen still “thinks” we are on the original item, so it opens the prompt of the original item when we trigger it.
When we trigger the prompt (pressing A
), the prompt used
comes from the item that is currently showing the description on the screen:
|- you are looking at this page
v
MATERIAL
[ ] [ ] [ ] [ ] [ ] Link is displayed here
[ ] [ ] [ ] [ ] [ ] [X] <- cursor (X) is on another page
[ ] [ ] [ ] [ ] [ ] ===================
[ ] [ ] [ ] [ ] [ ] <The item's name and description is displayed here>
When moving tabs in groups of 3, the Cursor Glitch causes the prompt
to be locked, meaning it will not update the name/description of the item.
You can force update it by going to the System screen and back (pressing R
then L
).
This is often referred to as “resetting” or “capturing” the prompt.
With the prompt locked, you can now move the cursor 3 tabs left or right,
which will change which item the cursor is on, but will not update the prompt.
Now, you can press A
to trigger and use the prompt.
In general, these are the steps to do any PE setup:
- Use the input sequence (the Cheat Code) to activate a slot
- Ensure the right prompt is captured by moving tabs in groups of 3, and optionally go to the System screen and back to reset the prompt
- Move tabs in groups of 3 to the target item, and use the prompt
Since you can only keep the glitch by moving tabs in groups of 3, this means PE can only be used between 2 items that are multiple of 3 tabs apart (i.e. have 2 other tabs between the source and target items).
Applications
Weapon Modifier Corruption
With PE, you can hold ingredients like stackable food that aren’t holdable normally. When these ingredients are cooked, their properties gets processed by the complex cooking system and produces meal values that aren’t obtainable by cooking normal ingredients, which can give better values for Weapon Modifier Corruption.
You can hold stackable food by either using “Hold” prompt from material,
pressing X
while locked to a material, or using the “Drop” prompt
from equipments. Using the “Drop” prompt will not put Link in the holding
state in inventory screen, allowing you to perform other actions while technically
holding.
Note that if you try to hold items that do not have a model (Food, or some Key Items), the game will crash when trying to render it in the inventory. You can workaround this with Super Hold Smuggle or some other method, which we will not go into depth here.
The simulator allows you to hold anything without crashing.
Removing Arrow Slots and Permanent Items
When you obtain a type of arrow, that arrow slot is stuck in the inventory
forever, even if you shoot the arrow to 0. With PE, you can entangle
a material prompt with the arrow prompt. Now you can press X
and use
hold to remove arrows. When you have 0
arrows, you can use
the eat
prompt to remove the slot completely.
Similar to removing arrow slots, you can remove permanent items like Sheikah Slate, Glider, Zora Armor, etc, by eating it.
Duplicate Materials
When using PE to hold, it subtracts the amount from the item you are holding, but checks the amount of the original item to see if you can keep holding. Since the amount of original item never decreases in the process, you can keep holding the item even if the stack is at 0. You can either unhold, or drop the items on the ground to realize the gain.
Note that if you use this method to duplicate material, you need at least 4 tabs of materials.
Durability Transfer and Desync Equipment
You can use PE to change equipment, while not changing the equipped status of the slot. This is very similar to Desyncing with Menu Overload.
To transfer durability:
- Equip the item to receive the durability
- Activate the slot with the item to give the durability
- Use the “Equip” prompt of that item on something else (for example, a material)
- Close Inventory
This will switch the equipment in the overworld while not in the inventory. The change equip action will cause a durability update, which transfers the durability.
Note that unlike durability transfer with Menu Overload, you do not need to use the equipment to update the durability. This is because the desync achieved by PE is the exact opposite of Menu Overload:
- Menu Overload desyncs by switching the equipment in the Inventory, but not in overworld
- PE desyncs by switching the equipment in the overworld, but not in the inventory
Since with Menu Overload, you do not switch equipment in the overworld, which does not trigger the change equip action. Therefore, using the equipment manually is required to update the durability.
You can also use this to unequip the One-hit Obliterator, which is more consistent than using Menu Overload. After performing the steps above, you will be able to unequip the OHO from the DPad Quick Menu.
User Manual
This section covers how to use the Simulator App. While not required, understanding IST itself could make it easier to understand some of the concepts here. You can read about IST here.
How the Simulator works
The Simulator runs on a Script, which is a text file that contains Commands for the simulator. Usually, the commands are the steps or actions you perform in the IST setup.
Here’s an example of such script; each line is a command.
get 1 pot-lid 1 apple 1 slate 1 glider
equip Shield
!break 3 slots
save
unequip shield
hold apple; drop
reload
save
drop apple
reload
To learn more about commands, see Command Syntax and Command Reference.
In the simulator UI, you can edit the script in the Script Editor. Whenever the script changes, the simulation will automatically rerun in the background. You can navigate different steps of the simulation by moving your cursor in the editor. The UI will display the state of the inventory after the command the cursor is on.
Modes
The simulator app has 3 editing modes:
Auto Saved
: This is the default mode. Any change you make to the script will be saved locally in your browser, so the same script will be there when you open the app the next time.Not Saving
: When editing script in this mode, the changes won’t be saved to your browser.View Only
: This is the default mode when you open a URL that directly loads a script. The script is read-only in this mode. You can switch toNot Saving
to enable editing. Note that errors will NOT show in the editor in this mode.
You can switch the mode anytime in the top-left corner of the header.
When switching to Auto Saved
, your locally-saved script will be overwritten with whatever
script that’s currently in the script editor!
If you accidentally overwrite your local script and you need it, you can still recover it by open the devtool console (F12) and type in the following:
console.log(localStorage.getItem("Skybook.AutoBackupScript"))
Press enter, and copy the output.
This entry is updated whenever you switch to Auto Saved
from the other modes. If the backup is
lost, your script will be lost forever.
Migration from V3
URLs with a V3 script embedded (one that starts with https://ist.itntpiston.app
)
can be migrated automatically to V4, by simply replacing itntpiston
with pistonite
in the URL.
Since the script is mechanically converted, it might not work out of the box.
You can change the mode to Not Saving
(see above), and see if there are any errors
in the script. Or, you can simply check if the last step has the correct outcome.
Notable differences:
drop
in V4 only allows dropping droppable items. For example,drop hasty-elixir
will not work.- Workaround: Manually change to
!remove
oreat
.
- Workaround: Manually change to
pick up
is translated toget
, sincepick-up
in V4 specifically targets items that are on the ground. This won’t lead to errors, but there will be extra items on the ground.- Workaround: Add a
!system [clear-ground]
at the end of the script.
- Workaround: Add a
- For setups with Prompt Entanglement, you need to activate PE in V4 with
entangle
command.
While it’s technically more consistent to translate the old script using supercommands
like !remove
that mimics the old behavior more consistently, supercommands
are not meant to be overused, so it’s not worth to change the semantic of the script
just for the edge cases.
Command Syntax
The simulator script is used to describe the steps to setup IST. The script is made up of commands. Most commands describe one or more actions in game, such as getting an item, dropping some items, or equip something.
The commands can be divided into 3 groups:
- Actions: These correspond to actions you do in game, such as
get
,pick-up
andhold
- Annotations: These commands start with
:
and are used to change the current configuration, such as:slots
- Supercommands: These command start with
!
and are more powerful than the actions. They often interact directly with the game’s state in a way that’s not possible with a regular action.
Whitespaces are insignificant in the syntax, including new lines.
This means one command can be broken into multiple lines and more than one command
can be put on the same line.
Commands can also have an optional trailing ;
.
# These 2 commands are equivalent
get 1 apple 2 pot-lid hammer;
get
1 apple
2 pot-lid
hammer
# Trailing ; is optional even for multiple commands on the same line
hold 2 apples drop
# but it's clearer if you separate them with a ;
hold 2 apples; drop
In general, the syntax is case-sensitive. Although some features like item search is case-insensitive, it’s recommended to keep everything lower-case, unless upper-case is needed (for example when specifying actor name or GDT flag name).
In the simulator, the inventory displayed are the state after executing the command the cursor is on.
The simulator parses the commands by span, not by line. You can view the state for each command even if multiple of them are on the same line.
Item Syntax
Item syntax is used to specify items for commands like get
or drop
.
See Item Syntax.
Meta Syntax
The meta syntax is a versatile syntax used to specify additional contextual metadata, in the form of ordered key-value pairs, the syntax is:
[key1=value1, key2=value2, ...]
# `:` and `=` are interchangeable
[key1:value1, key2:value2, ...]
Generally, key
s are kebab-case
words, and value
s can be one of:
bool
- either the keywordtrue
orfalse
.true
can be omitted, i.e.[equip]
is the same as[equip=true]
integer
- an integer in decimal, or hex prefixed with0x
, like10
or0xa
.float
- a floating point number in decimal, like1.2
(scientific notation not supported).words
- one or more words consisted of alphabetical characters,-
and_
, with spaces allowed in between, likehello my-world
quoted
- a quoted string where any character is allowed"你好世界"
.angled
- likewords
, but surrounded by<
and>
and no spaces are allowed, like<Foo>
.
Generally, the 3 string formats are all accepted and can be interchangeable. In some cases however, the formats can have different meanings.
Item Syntax
The Item Syntax has 3 components: amount
, name
, and metadata
get 3 pot-lid [durability=3]
# ^ amount ^ name ^ metadata
To specify multiple items in the same command, simply write them one after another with an optional
comma (,
) between each item. Also, when the amount is 1
, you can omit it.
More examples:
get 2 apples 3 bananas
# The following are all equivalent
get apple banana 2 core
get apple, 1 banana 2 cores
get 1 apple banana, 2 cores
The item syntax could be used in 3 scenarios, depending on the command:
-
FINITE_ITEM_LIST
- The amount must be a number, not keywords like
all
. - The name must be an item, not category.
- The metadata is used to describe extra properties of the item.
- Generally used by commands for adding items, such as
get
.
- The amount must be a number, not keywords like
-
INFINITE_ITEM_LIST
- The amount could be a number or the keyword
infinite
. - The name could be an item or a category.
- The metadata is used to describe extra properties of the item.
- Currently, this form is not used by any command.
- The amount could be a number or the keyword
-
CONSTRAINED_ITEM_LIST
- The amount could be a number, or:
- The keyword
all
- In the form
all but X
, whereX
is a number.
- The keyword
- The name could be an item or a category.
- The metadata is used to match from items in some existing list (such as your inventory).
- Generally used by commands that targets some item, such as
hold
andeat
. - Position properties can be used.
- The amount could be a number, or:
Amount
The amount of item may have different meaning in different commands. For example,
when using the eat
command, the amount is always the internal value (i.e. the stack size),
since you can eat from corrupted food or decrease armor value/durability by eating. When using sell
,
however, the amount means how many slots for unstackable items.
In CONSTRAINED_ITEM_LIST
, you can use 2 special amount forms: all
and all but
:
all
will repeatedly find the item and perform the action on the item, until the item cannot be found.all but X
will first count the total number of times the action can be performed, then perform the actioncount - X
times. How the total number is counted depends on the command, similar to the eat vs sell situation mentioned earlier.
The implementation may vary slightly based on the command, but the concepts are the same.
One notable example is that all
in dnp
is implemented as all but 0
, since
otherwise it will be stuck in an infinite loop.
In rare cases, all but
could be inaccurate, if the total number of items changes unexpectedly due to the action.
Please report if you encounter this issue.
Name
You can specify the name of the item in 4 ways:
- By
Identifier
- An Item Identifier is multiple english words (A
toZ
, case-insensitive), combined with-
or_
. For example,royal-claymore
andtrav-bow
are both valid identifiers. There is a fixed algorithm for resolving the identifier to an item.- The result is an item that contains all the individual words, for example
trav-bow
results in traveller’s bow. - You can add an effect before a food item to specify the cook effect. For example
hasty-elixir
,sneaky-wild-greens
- Plural forms with
-s
,-es
,-ies
postfixes are supported. They don’t affect the amount of the item, only makes the command sounds more natural in English. - Some shorthands are supported in this form. For example,
geb
forgreat-eagle-bow
,aa
forancient-arrow
.
- The result is an item that contains all the individual words, for example
- By
Actor
- You can use angle brackets (<>
) to specify the internal actor name directly, for exampleget <Weapon_Sword_070>
. You cannot specify cook effect in this way. - By
Localization
- If English is not your preferred language, you can specify items by their localized name using a quoted-string. For example,"espadon royal"
or"王族双手剑"
.- The string is fuzzy-searched in all languages.
- To lock the language, prepend the query with the language and a colon, for example,
"fr:espadon royal"
. This could be useful if the query is short, and is matching in another language that you didn’t expect. - Localized search only applies to items, not commands (like
get
,hold
, etc).
- By
Category
- When selecting items from inventory or some other list of items, you can also use a category in the place of the item name to match the first item of that category. This can be useful in situations likeunequip shield
where you don’t need to care what shield is currently equipped, orpick-up 3 weapons
, where it doesn’t matter which weapons are picked up.
See token for possible category values.
Metadata
The Meta Syntax is used to specify additional properties for the item:
- In
FINITE_ITEM_LIST
, it is used to specify extra data on the item to be added.- For example,
get pot-lid[durability=1]
gets a newpot-lid
with1
durability
- For example,
- In
CONSTRAINED_ITEM_LIST
, it is used to specify extra data used to match the item to operate on.- For example, if you have multiple
pot-lids
,drop pot-lid[durability=1]
targets the one with exactly1
durability.
- For example, if you have multiple
Available metadata properties:
Property | Aliases | Description |
---|---|---|
durability | dura | (int ) Sets value to 100 times the specified number |
effect | (int or string ) Sets the effect ID for cooked-food. Integer values are used directly (even when invalid), and string values are converted. See Cook Effects for possible values | |
equipped | equip | (bool ) If the item is equipped (May not have effect when adding item) |
held | hold , holding | (bool ) |
ingr | (string ) Set the ingredient of the cooked-food. The string must be an item identifier (see above). The property can be specified multiple times to add multiple ingredients. | |
level | (int ) Sets the level of the effect for cooked-food | |
life-recover | hp , modpower | (int ) Sets the number of quarter-hearts cooked-food recovers, or value of a weapon modifier |
modifier | modtype | (int or string ) Set weapon modifier. Cannot be used to set food effect type. Integer values are the same as price . String values can be specified multiple times to build up the weapon modifier. When used for matching, if only one modifier is specified, it will match any modifier flag that includes the specified one (i.e. other modifiers are allowed), if more than one bit is specified, the modifier flag must match exactly. See Weapon Modifiers for possible values |
price | (int ) Sets the price of the cooked-food. This can also be used to set multiple weapon modifiers as a bit mask | |
star | (int ) Armor star (upgrade) number, valid range is 0-4 , inclusive. Note that this is syntactic sugar to change the name of the item, as armor with different star numbers are different items. | |
time | (int ) Sets the duration of the food effect in seconds | |
value | life | (int ) The value of the item, which is the count for stackables or durability multiplied by 100 for equipments. Note: not to be confused with life-recover |
Selecting from multiple matches
In CONSTRAINED_ITEM_LIST
, there could be the case where there are multiple items that are exactly the same. There are additional meta properties that you can use
to pick exactly which slot to select.
With from-slot
property, you can pick the i
-th matched item. For example,
if there are 3 Pot Lids, you can use drop pot-lid[from-slot=2]
to drop the second Pot Lid. The number is 1-indexed.
You can also target an item by its position in the inventory directly with one of the following methods:
# This is the same as using `from-slot`
# If there are >=2 slots of apple, this will eat from the second slot
eat 2 apple[slot=2]
# Category can be used as the name
# This eats the second slot in the entire inventory that is a material
eat 2 material[slot=2]
# Eat 2 apples from the material tab, in the first row and second column
# When using `category`, the indices are 1-indexed
eat 2 apple[category=material, row=1, col=2]
# Eat 2 apples from the second material tab, in the first row and second column
eat 2 apple[category=material, tab=2, row=1, col=2]
# Eat 2 apples from the second material tab, in the 0-th slot.
# The tab is 1-indexed.
# The slot is the 0-indexed slot in that tab, arranged like this:
# 00 01 02 03 04
# 05 06 07 08 09
# 10 11 12 13 14
# 15 16 17 18 19
eat 2 apple[category=material, tab=2, slot=0]
# Eat 2 apples from the 0-th tab, in the 3rd slot
# The tab index here is the 0-based index in the entire tab array
# The slot is the 0-indexed slot in that tab, see above
eat 2 apple[tab=0, slot=3]
- If the slot selected by position has a different item, you will receive an error.
- When using
row
andcol
, they must be specified aftercategory
ortab
.
The positions are calculated right before the simulator tries to find the item to target. This means if the action performed on previous items in the same command changes the inventory, the position you need to specify to target the correct item could be different from what you see in the inventory in the previous step. For this reason, it’s not recommended to specify position when performing an action on multiple items. Separate the position-dependent action to its own command instead.
Comments and Notes
Comments and Notes are text in the script that don’t affect the output of the command.
Comments
Comments are lines that start with #
or //
. They are completely ignored.
# This is a comment
// This is also a comment
In the script editor, you can use the hotkey Ctrl + /
to quick toggle
selected lines between commented/uncommented.
Block Literals
Block Literal is a multi-line block that starts and ends with '''
(triple single-quotes).
'''
This is a block literal
It can have multiple lines
'''
Addtionally, a block literal can have a tag
, which is a string after the '''
that starts the block. For example, the note
tag can be used to add
notes to blocks of commands, which can be viewed in the Notes
extension.
'''note
Drop these in the same pile
'''
drop all weapons
drop all shields
Systems in the Simulator
Skybook aims to be a 100% accurate IST simulator. To achieve that, it emulates subsystems of the game as much as possible. However, not all subsystems can be emulated, especially those that are not reversed-engineered fully or not at all. Some subsystems also may not be worth to emulate since a simulation is good enough.
The systems that are involved in the simulator include:
Screen System
The Screen
system simulates different dialogs and pause menus in the game.
For example, when pausing to access the inventory, or when selling items by talking
to a shop keeper.
Most of the time, the simulator can switch between screens automatically depending on the actions, so the effect of this system should be transparent to those who are used to previous versions of the simulator.
Understanding this system could be useful, if you want to explicitly control when you open a screen, which can be helpful when optimizing and verifying IST setups.
The simulator UI has a little icon next to the “Visible Inventory” title to indicate which screen you are currently on.
Game State
While not technically a screen, the Game itself can also have 2 different states:
Running
and, well, not Running
(closed).
The initial state of the simulation is similar to a new game. When executing most commands, the game will keep running, unless:
- You manually closed the game with the
close-game
command. - The game crashes.
When you encounter a game crash, note that it’s also possible it’s a bug in the simulator. Please report it on GitHub if the simulator crashes on a step that you don’t think is supposed to crash in game.
You can also view the detail of the crash in the Crash Viewer
Extension.
Whenever the game is closed in the middle of a simulation (either closed manually or crashed), it will not automatically restart. You have to use either of the commands below:
new-game
to start a new gamereload
orreload SAVE_NAME
to start the game and reload a saveSAVE_NAME
is the name of the save, see Save Files
Screen Types
While in game, there are 4 screens that are simulated:
Overworld
:- The default state when you start a game.
- Player is able to move
- You can get/drop items
- … all the other things you can do in the overworld
Inventory
:- When you pause the game with the
+
button - Player can interact with items in the inventory
- When you pause the game with the
Shop Selling
:- When talking to a shop owner to sell items
- Player can select items in the inventory to sell
Shop Buying
:- When talking to Beedle or some other NPC to buy items
- Player can select from a list of items to buy
The Screen
system works like a state machine; when an action needs a certain
screen, it will try to transition to that screen state if possible, and display
an error if it couldn’t. The transition looks something like this:
Overworld
/---------|---------\
/ | \
/ | \
Inventory Shop Buying --- Shop Selling
For example, if you are in the inventory menu and need to talk to a shop owner to sell something
(i.e. to execute the sell
command):
- The simulator first checks if you are already in the
Shop Selling
screen - Since you are in the inventory screen, the simulator must return to
Overworld
by closing the inventory menu - Then, it simulates talking to a shop owner by transitioning to the
Shop
screen - Finally, it sells the item
- After all of that, it will stay in the
Shop
screen until it has to transition again
That all happens in a single sell
command!
Manually switching screens
The following actions count as manually switching the screen. If the screen has been manually switched, the simulator will prevent certain automatic screen switches.
Inventory
:pause
to open the inventory- No automatic screen switches can happen until returned to overworld
unpause
to close the inventory and return to overworld
Shop
(buying and selling):talk-to NPC
to start buying or selling (NPC
can be any-
or_
connected word)- Screen can be automatically switched between
Buying
andSelling
, but not toOverworld
- When returned to overworld, screen can be automatically switched again to all types
- Screen can be automatically switched between
untalk
orclose-dialog
to return to overworld
Note that annotations for screen switching like :pause-during get
do
not count as manually switching screens, and the simulator
will still automatically switch screens afterward.
Overworld System
The Overworld
system simulates objects that the player interacts in the overworld,
known as Actor
s. However, the actual overworld in the game is very complex, and
most of the actors don’t even have anything to do with the inventory.
Therefore, the Overworld
system is a ultra-simplified simulation of only
the actors that are involved in inventory glitches:
- The player’s equipment (Weapon, Bow and Shield)
- Any items currently being held by the player in the overworld
- Any items (including materials and equipments) dropped by the player
Material Drop Limit
In the game, you can drop at most 10
items on the ground at a time.
When you drop the 11
-th item, the least-recent dropped item will despawn.
This limit is simulated by the Overworld
system in the following way:
- When dropping material with the
drop
command, or auto-dropped from a smuggled state, it gets added to the list of items on the ground - The least-recently dropped items will be removed from the list, until there are at most 10 items on the ground
- The removed items are not deleted immediately. You will see
Will despawn
in the tooltip text of the item in the simulator UI. - If you perform any action that takes some time so it’s impossible to preserve the despawning item, the item will be deleted.
It is implemented like this because it is possible to drop more than 10 items, but pick up the items fast enough before it despawns to keep the materials on the ground under the limit. This can be used to optimize IST steps.
For example, the following script will result in 15
apples in the overworld,
5
of which are in the Will despawn
state.
hold 5 apples; drop
hold 5 apples; drop
hold 5 apples; drop
Then:
- If you
pick-up 5 apples
right after, there will be10
apples left on the ground, and5
are added to the inventory. - If you
pause
, there will still be15
apples on the ground, since you couldunpause
and pick them up. - If you
get 3 bananas
, the despawning items will now be deleted, and there will be10
apples left on the ground. This is because it’s unlikely the apples are still there after you pick up some other item.
Resetting the Overworld
In a long IST setup, there might be times where you travel between different areas in the game, or exit/enter shrines, that cause the overworld to change without necessarily any inventory-related action. There are a few ways you can simulate this:
- Any action that is supposed to reset the overworld will do so automatically,
for example
reload
.- The
!system [loading-screen]
supercommand can be used to simulate regenerating the game stage with a loading screen, if none of the action commands match your needs.
- The
- The
!system [clear-ground]
supercommand can be used to delete all items on the ground. Use this if you are traveling to another area without a loading screen.
Command Reference
This is the full list of commands sorted in alphabetical order. Clicking on a command will take you to the corresponding documentation page.
Command | Description |
---|---|
:accurately-simulate for ( get , sort ) | Turn off optimizations that may be inaccurate |
!arrowless-smuggle | Perform Arrowless Smuggle with the items currently held (use this if :smug is not an option) |
!add-slot | Adding a new slot to the inventory list by editing memory, bypassing all checks |
!break | Edit memory to simulate generating Broken Slots |
buy | Buying items |
close-dialog | Alias for untalk |
close-inv | Alias for unpause |
close-inventory | Alias for unpause |
close-game | Close the game |
:discovered | Change whether a tab is discovered |
dnp | Drop material or equipment, then pick them up |
:dpad | Specify change equipment should be done using DPad menu |
drop | Drop material or equipment |
eat | Eat an item |
entangle | Activates Prompt Entanglement |
equip | Equips an item |
get | Getting an item |
hold | Hold materials |
!init | Resets the inventory memory to the list of items |
new-game | Starts a new game |
open-inv | Alias for pause |
open-inventory | Alias for pause |
overload | Activate Menu Overload |
:overworld | Specify the next action to be performed in the overworld |
pause | Open the inventory |
:pause-during | Open the inventory during certain operations |
:per-use | Change the durability to decrease per use |
pick-up | Pick up an item from the ground |
!remove | Forcefully remove items from inventory, even non-interactable ones |
reload | Reload a manual or named save |
:same-dialog (for buy , sort ) | Specify the next action should be in the same dialog sequence |
save | Make a manual save |
save-as | Make a named save |
!set-gdt | Set any GDT flag |
:slot | Alias for :slots |
:slots | Change number of equipment slots |
:smug | Perform Arrowless Smuggle with the next hold or drop command |
sort | Sort a category of items |
spawn | Spawn Items in the Overworld |
!swap | Swap two item nodes |
!system | System operations |
talk-to | Talk to an NPC for buying or selling |
:targeting | Changes the target for Prompt Entanglement |
!trial-end | End trial and restore inventory |
!trial-start | Start trial and clear inventory |
unequip | Unequip an item |
unhold | Stop holding materials |
unoverload | Cancel Menu Overload |
unpause | Close the inventory |
untalk | Closes buying or selling dialog |
use | Use equipments or materials in the overworld |
!write | Edit inventory item data |
Get Items
Adding new items to the inventory.
get
command adds new items from an unspecified source (makes the item from thin air).pick-up
can only be used to get items previously dropped on the ground.buy
is similar toget
, but has additionally functionality to simulate buying from an NPC in the same dialog as selling.
Syntax
get
FINITE_ITEM_LIST
buy
FINITE_ITEM_LIST
pick-up
CONSTRAINED_ITEM_LIST
Annotations:
Examples
get diamond # 1 Diamond
get 2 apple 2 banana # 1 Diamond, 2 Apples, 2 Bananas
drop all apples # 1 Diamond, 2 Bananas. 2 Apples on the ground
pick-up all materials # 1 Diamond, 2 Bananas, 2 Apples
buy 5 eggs
Picking up previously dropped Items
The only difference between get
and pick-up
is that pick-up
is used to target items previously dropped
on the ground.
You cannot pick-up
items that aren’t on the ground. Use get
instead.
Buying from NPC
Normally, you buy items in this game by “talking” to the item directly in the overworld. Certain NPCs are exceptions, such as Beedle, Travelling Merchants, and Kilton. For these NPCs, you need to talk to them, and buy from a separate dialog.
By default, buy
will ALWAYS assume you are buying from overworld, unless
you tell it to not do so.
To talk to an NPC and buy, use the talk-to
command.
talk-to beedle # Opens Shop Buying screen
buy 5 arrows
shoot # Automatically close the screen and shoot arrow
# To manually close the screen, use `untalk` or `close-dialog`
To sell, then buy within the same dialog sequence, use the :same-dialog
annotation
sell ruby # Opens Shop Selling screen
:same-dialog buy 5 arrows # Without exiting dialog, opens Shop Buying screen
close-dialog
Also see Selling.
Pause on Item Text Boxes
During get
, pick-up
, or buy
, you may
encounter a “New Item” text box that allows you to open the inventory.
The :pause-during
annotation can be used to simulate this action.
The simulator does NOT check if you are allowed to open the pause menu when you get an item, nor does it check if normal pause menu operations can be performed.
For example, usually you can eat something immediately in the text box that you got it, but you cannot hold another item. Currently, this situation is too complex to simulate correctly.
One use case is to force hold items during an item text box by performing Item Smuggle for Arrowless Offset, then get an item text box (similar to performing Arrowless Offset).
get 2 shrooms
:smug hold 2 shrooms
# Open a chest, for example
:pause-during get lynel-shield
# Here, you are in pause screen while holding 2 shrooms
unpause
# Now the 2 shrooms will drop to the ground because of how the smuggle works
You can also use this feature to explicitly annotate optimizations for speedruns.
:pause-during get zora-armor; equip zora-armor
Performance
The preferred way to simulate getting multiple stackable items, is by invoking the function for adding the item to inventory repeatedly. However, when the number of items to get is large, this is a very expensive operation and can slow down script execution significantly.
Therefore, when the amount specified is greater than some internally determined amount, the implementation switches to a single call of the function with a value. Functionally, it turns:
get 999 apple
into:
get apple[value=999]
Most of the time (if not all), this will not cause inaccuracies. However, if it matters,
you can use the :accurately-simulate
annotation to force the more accurate implementation.
# This may take 30 seconds or more to execute, depending on your hardware
:accurately-simulate get 999 apples
Detail
get
,pick-up
andbuy
all requireOverworld
screen.- You cannot get new items while holding items in the overworld
- with
:smug
, the held items will be dropped after getting the item
- with
Material Operations
Performing actions on materials in the inventory. Some actions may apply to non-materials.
hold
command performs the “hold” prompt.- When used without a list of items, it enters holding state in inventory screen without holding anything.
unhold
command stops holding in inventory, or put away the items in overworld.drop
command is used to hold and drop items- When used without a list of items, it drops the currently-held items on the ground.
dnp
command is a shorthand fordrop
andpick-up
.eat
command performs the “eat” prompt.
Syntax
hold
hold
CONSTRAINED_ITEM_LIST
unhold
drop
drop
CONSTRAINED_ITEM_LIST
dnp
CONSTRAINED_ITEM_LIST
eat
CONSTRAINED_ITEM_LIST
Annotations:
:smug
- Enable Smuggling for Arrowless Offset
Examples
hold apple
hold 2 apple
hold 1 shroom 1 pepper
unhold
:smug hold 1 shroom 1 pepper
unhold
eat all materials all food
dnp 5 weapons
Smuggle State for Arrowless Offset
The :smug
annotation can be used to activate the item smuggle
state required for Arrowless Offset
(also known as Arrowless Smuggle
),
for the next hold
command, which is when the held materials are attached
to Link’s right hand instead of being held in front of him.
To do this in the simulator, put :smug
right before the hold
command.
:smug
hold 2 shrooms
# Now you are in Overworld, and held items are attached to Link's hand
You can also put :smug hold
on the same line (which sounds like smuggled, hehe).
To do this in the game, you need:
- A Shield
- A one-handed Weapon
To perform this:
- Enable Weapon Smuggle and make sure a shield is equipped
- Hold the
ZL
button - Hold items from up to 5 slots
- Switch to a one-handed weapon
- Switch to another one-handed weapon, or to something else and back if you are already equipping a one-handed weapon
- Jump and let go of
ZL
button, after landing, when the shield is to Link’s side, unequip the shield
While in this state, you can perform actions which are not normally possible, such as getting items or talking to NPC. While doing so, the simulator will delay-drop the items. This is essential to generate offsets. In game, you can do this by either:
- Whistle and perform the action (
Dpad Down > A
) quickly before the items drop - Pull out Bow and perform the action (
ZR > A
) quickly before the items drop
The :smug
annotation can also be used with drop
, for example,
when using Prompt Entanglement to drop-hold some item:
# Activate PE
entangle apple
# Suppose Torch is entangled with Apple
# This will drop-hold the Apple, then close inventory and perform Arrowless Smuggle
:smug drop torch
:smug
requires automatically switching to Overworld
screen. If the screen
was manually switched, the operation will fail. In this case, you can use the
!arrowless-smuggle
supercommand to manually activate the state
while already holding items in the overworld.
pause
# This will fail, because screen was manually switched
:smug hold 1 apple
# Do this instead (if removing the `pause` is not an option)
pause
hold 1 apple
unpause
!arrowless-smuggle
Dropping Items
The drop
is also used for dropping equipments, which has
a slightly different semantic. The description here only applies to materials.
When using drop
without any items, it means to drop
whatever is currently being held to the ground.
When using drop
with items, it will attempt to hold the items in up to
groups of 5, and drop them. This may not work as expected in rare cases, like
if you hit mCount=0
in the middle of dropping, you will no longer be able to hold
more items. In this case, you will get an error.
The dnp
command is equivalent to drop
, then pick-up
the same items. Note that dropped items will not despawn after pick-up
.
Detail
hold
requiresInventory
screen, and you can only hold a maximum of 5 items.drop
requiresOverworld
screen when dropping held items. When a list of items is specified, it may switch screens multiple times to facilitate the action.- Certain actions are not possible when you are holding items.
Equipment Operations
Operations on equipments in inventory.
equip
andunequip
changes the equipped status.drop
drops the equipment from the inventory.
Syntax
equip
CONTRAINED_ITEM_LIST
unequip
CONTRAINED_ITEM_LIST
drop
CONTRAINED_ITEM_LIST
Annotations:
:dpad
- Use the DPad menu instead of inventory menu to change equipments.
Change equipments
Example
# Equip the first weapon
equip weapon
# Unequip the first **equipped** weapon
unequip weapon
# Equip multiple items
equip 1 royal-claymore 1 hylian-shield
# Unequip multiple items
unequip all shields all bows
# Unequip the second equipped Hylian Shield
unequip hylian-shield[slot=2]
# You can also equip armors and champion abilities
equip champion-tunic
unequip gale
# You cannot unequip arrows
unequip fire-arrow # Error! cannot unequip arrow
When using from-slot
or slot
for unequip
,
note that unequip
only targets the equipped items.
So slot=2
means the second equipped item. equip
and other commands target all items, so equip weapon[slot=3]
equips the third weapon in the inventory, regardless of which weapon
is currently equipped. If the third weapon is already equipped, you will
get an error.
This may seem like a weird design choice, but it makes intuitive sense when you use the command in most cases.
Normally, you would omit the amount for equip
or use 1
for multiple categories, since equipping another item
of the same category would
just unequip the previous one. However, in some configurations, the items won’t be auto-unequipped.
If you actually want to equip more than one item, you have to specify [equipped=false]
.
Otherwise, it will error when it hits an item that’s already equipped.
For example, equip all weapons[equipped=false]
.
unequip all
should always work as expected.
By default, changing equipments are assumed to be done in the pause menu. This should be ok in most cases. However, there are edge cases where action must be done through the DPad Quick Menu, examples include:
- You are holding items in the pause menu.
- The item slot is not visible in the pause menu, only in quick menu.
In these scenarios, you can use the :dpad
annotation to specify the equipment change should be
done via the quick menu.
Example
# Switch equipments with DPad quick menu
:dpad equip fire-arrow
:dpad unequip weapon
Note that :dpad unequip
can only be used to unequip the first equipped item in the quick menu,
and cannot be used to unequip arrows.
Dropping Equipments from Inventory
Use the drop
command to drop equipments, which deletes the item in inventory,
and spawns the item in overworld when the inventory is closed.
The game has a limitation on how many weapons can be dropped, but this is not implemented in the simulator.
Examples
drop all shields
drop all but 1 axe
Overworld Operations
Things you can do in the overworld:
use
command uses and decreases durability of equipments, or can be used to remove items while in the overworld, e.g.use fairy
.shoot
is an alias ofuse bow
.:overworld drop
command drops equipped equipments.
Also, the spawn
command can be used to add items directly to the overworld (i.e. on the ground).
Syntax
use CATEGORY_OR_ITEM
(defaults to 1 time)
use CATEGORY_OR_ITEM X times
shoot
shoot X times
:overworld drop
CONTRAINED_ITEM_LIST
Annotations:
:per-use X
- sets the value to decrease per use:overworld
- changes the semantic ofdrop
Using Equipments
To use
an equipped weapon, you can either specify the category,
or the item name (given the item is equipped).
# Use the currently-equipped weapon to hit something
use weapon
# Use the currently-equipped weapon to hit something 5 times
use weapon 5 times
# Shoot with Royal Bow. Royal Bow must be the currently equipped bow
use royal-bow
# Shoot with currently equipped bow
shoot
The :per-use
annotation changes how much durability is consumed
per use. The default is 100
.
# Bombing the shield takes 30 durability off
:per-use 3000 use shield
Special cases:
- Using a weapon with
IsLifeInfinite=true
will not decrease durability - Using Bow of Light/Twilight Bow will not decrease arrows
- Using MasterSword while the GDT
Open_MasterSword_FullPower=true
will consume0.2x
specified value, if its value is currently>=300
Using Non-equipments
When the item specified for use
is not an equipment,
it will attempt to remove the item instead. The only legitimate use
of this is use fairy
. However, the simulator will permit
any item to be used this way.
For example, create Broken Slot with fairy:
hold fairy; use fairy; drop
Dropping the Overworld Equipment
In some cases, you can drop the equipment in the overworld without interacting with the inventory; for example, when getting shocked.
get axe
:overworld drop weapon
Spawning Items in the Overworld
The spawn
command lets you create new items on the ground.
Items created this way does not count in the drop limit. Furthermore, spawning
items this way will work even when menu overloaded.
# Simulate shooting a bomb arrow on the ground that doesn't explode
shoot
spawn bomb-arrow
Detail
use
requiresOverworld
.- In Arrowless Smuggle state,
using a
weapon
orshield
willunhold
the item, while using abow
willdrop
the items.
Selling Items
The sell
command simulates selling items to a shop keeper,
or trading away Spirit Orbs or Korok Seeds.
Syntax
Example
talk-to beedle
sell all shroom all pepper
:same-dialog buy 5 arrows
close-dialog
Also see Buy.
Break Slots
Breaking Slots refers to the action of generating offsets to enable IST. See Inventory Slot Transfer for more info.
You can either break slots by simulating actions, like what you do in the game,
or use the !break
supercommand to directly edit the memory.
Arrowless Offset
References for commands used for Arrowless Offset:
The most commonly used method of breaking slots is known as Arrowless Offset
,
which requires a shield, a one-handed weapon and a shop keeper and can break up to 5 slots at once:
- Enter the
Arrowless Smuggle
state. - Talk to a shop keeper (by pressing
Dpad Down > A
orZR > A
quickly). - Sell all the items from slots that are being held.
- Close the dialog.
Example script for Arrowless Offset in the simulator:
get 2 shroom 2 pepper 1 banana
:smug hold shroom pepper
sell all materials[held]
close-dialog
Hold Smuggle Offset
Hold Smuggle Offset is similar to Arrowless Offset, by selling smuggled items and dropping them after.
- Activate Hold Smuggle (By Menu Overloading, for example with Shock Arrows).
- Sell the items that are smuggled.
- Hold another item, to cancel the smuggle.
- Drop held items.
Since it is required to hold another item after selling, this method can only make up to 4 Broken Slots at a time.
get 2 shroom 2 pepper 1 banana
overload
hold shroom pepper
unoverload
sell all materials[held]
close-dialog
hold banana
drop
Other than selling the held slots, you can also do this by entering a trial, such as Trial of the Sword. This will remove the slot in the inventory. Now you can get a new item, hold it to cancel hold smuggle, and drop the items. Note that since getting a new item will take out one held slot out, you can also only make up to 4 slots at a time with this method.
This is also how IST was initially discovered.
Fairy Offset
You can use fairies to break slots by using the last fairy while holding one.
Example script:
hold all but 1 fairy;
use fairy; # by bombing yourself, or stand on fire, etc...
drop; # drop the held fairy
Eat and Hold Offset
With Prompt Entanglement, you can eat and hold the same slot to make offsets.
- Eat all of the material in the slot you are using PE with
- Since targeting a translucent slot with PE will target the first slot, you need to either make sure you are eating the first slot, or eat the slot you are using AND the first slot.
- Use a “drop” prompt to hold the slot you ate.
- Unpause and drop the items in your hand.
The example script below uses the 3rd slot in a tab (shroom
)
so it also needs to eat all of the first slot (apple
).
:discovered [bow, shield] # spacing for PE
get
1 torch 1 axe 1 hammer
1 apple 1 banana 1 shroom
eat all apple all shroom
entangle hammer
:targeting <empty>[category=material, row=1, col=3]
drop hammer
drop
Entangle
Activate Prompt Entanglement and perform actions on a slot using prompts from another.
entangle
activates PE and sets the target item:targeting
changes the target item, or allows you to target empty slots
Syntax
Activate PE
While the Cursor Glitch is active, you can switch tabs in groups of 3 to keep the glitch active. Therefore, conceptually, when you activate a slot, all slots that are 3 tabs apart can be considered activated as well.
This action is simulated by the entangle
command.
# Targets the Pot Lid, and activates that slot, as well as all slots that
# are 3 tabs apart
entangle pot-lid
While a slot is activated, you will see a “Link” icon next to it.
If a slot that’s supposed to be activated does’t exist in a tab (i.e the tab doesn’t have enough items), there will be a phantom slot displayed in that location when in Tabbed View. This is only a visual effect of the simulator.
The effect of the activation will last until the inventory is closed. You can also
use another entangle
command to change which slot is activated.
Targeting an Item
The second step to using PE is to select a target item that will receive the prompt.
The :targeting
annotation is used to do that.
# If the item is in an activated slot, you can use the name to select it
:targeting apple
# You can also select the slot directly
# This is useful if you are targeting an empty slot (which can't be selected
# by item name, since there's no item there)
# Note that specifying the first item directly will not work, if the activated
# slot is not in row 1 and col 1.
:targeting <empty>[category=material, tab=1, row=1, col=3]
# ^ the name is ignored while targeting a slot directly, so it
# doesn't matter what you put here
:targeting
currently also searches slots that are not activated.
If there are multiple matches, you might need to use a Position Property
to specify the activated slot.
Finally, in the next command after :targeting
, you can perform
an action on a PE-enabled slot. If the target item can be reached by the item
in the action, the action will be performed on the target item instead.
entangle roasted-endura-carrot :targeting roasted-endura-carrot
drop pot-lid # will hold the roasted endura carrot
Since it can be redundant to activate, then target the same item,
entangle
will also target the item by default.
The command above can be shortened as:
entangle roasted-endura-carrot
drop pot-lid # will hold the roasted endura carrot
However, sometimes it might be clearer to write it as entangle
then :targeting
.
For example, during speedrun, it’s usually faster to entangle
the source item, to skip resetting the prompt, which means the item to setup
the entangle
is different from the item to target.
However, it’s up to your preference how to write the command.
The effect of :targeting
will only last until the next command,
but you can use multiple :targeting
within the same entangle
.
Save Files
Handling game’s running and closed state, and simulation of save files:
save
command saves to the manual save slot.save-as file-name
command saves to a named save slot. You can later reload this save by its name. This is used to simulate auto-saves, but you can have unlimited number of them.reload
command reloads a manual or named save.new-game
reloads an imaginary save with the state of a new game.close-game
closes the game.
Syntax
save
save-as FILE-NAME
reload
reload FILE-NAME
close-game
new-game
FILE-NAME
can either be the same format as item identifier (like-this
, or with _
instead of -
), or a quoted string. Spaces and non-alphabetical characters are also
allowed in quoted names, like "Outside of Shrine"
or "神庙外"
.
Example
# Save to the manual save slot
save
# Save to a named save called `my-save`
save-as my-save
# Reload the manual save
reload
# Reload a named save
reload my-save
Inspecting Save Files in the App
Amongst other things, a save file for the game includes a copy of savable flags in GameData, which contains the items in the save. Therefore, the simulator displays save files similar to how it displays GameData.
Using the Save Files
extension, you will see a list of save names available at the
current step in the simulation. Clicking on a save will then display the items in that save.
Note that you can inspect saves even on steps where the game isn’t open.
New Game and Restarting the Game
The reload
and new-game
are the only 2 commands that can
restart the game after it’s closed, either due to crash or was manually closed.
Currently, new-game
is implemented as reloading an imaginary save
made at new game. The implementation is as follows:
Game State | Action | Implementation |
---|---|---|
Running | reload | Reload the save |
Running | new-game | Reload the “new game” save |
Closed | reload | Start a new game, then reload the save |
Closed | new-game | Start a new game |
This is not 100% accurate to what the game does, but should be close enough.
Simulating the System menu
save
(and save-as
if in inventory) will currently automatically unhold
the currently held items, similar to how the game does that when you switch to the System menu.
Detail
save
requiresInventory
screen.save-as
can be performed in eitherInventory
orOverworld
.reload
requiresInventory
screen if the game is running.new-game
is similar, see implementation detail above.
Sorting
The sort
command can be used to sort items in a category.
Syntax
sort CATEGORY
sort CATEGORY X times
Annotations:
Examples:
sort weapons
sort materials 2 times
talk-to shop-keeper
sell all apples
:same-dialog sort material
untalk
Sorting Order for Equipments
For Weapon
, Bow
, Shield
, and Armor
categories, the game has 2 modes to sort them
that it toggles every time you sort.
For Weapon
, the modes are:
- By weapon type first, then weapon power, then weapon modifier, and finally item name.
- By item name first, then weapon type, then weapon power, and finally weapon modifier.
For Bow
and Shield
, the modes are:
- By power first, then modifier, then item name.
- By item name first, then weapon power or guard power, then modifier.
For Armor
, the modes are:
- By armor type first, then item name.
- By item name first, then armor type.
By default, the first time you sort one of these categories, it will be the first sorting
mode (not by item name first). You can toggle this with the !set-gdt
supercommand.
sort armors # will sort by armor type first (SortTypeArmorPouch changes from false to true)
sort armors # will sort by item name first (SortTypeArmorPouch changes from true to false)
!set-gdt <SortTypeArmorPouch>[bool=true] # manually set the flag to true
sort armors # will sort by item name first
sort armors # will sort by armor type first
# Flag name for other categories:
# - SortTypeWeaponPouch
# - SortTypeBowPouch
# - SortTypeShieldPouch
Sorting in Selling Screen
You can sort Armor
, Material
and Food
while selling items. By default, sort
assumes you want to sort in inventory screen, and it will closes the shop screen
and open inventory screen even if the category specified would allow you to sort in shop screen.
This would cause less confusion with automatic screen switch.
To actually sort in selling screen, you need to use the :same-dialog
annotation,
similar to buying from the same NPC without exiting dialog:
talk-to beedle
sort materials # error: cannot auto switch to inventory
:same-dialog sort materials # ok: opens selling screen
Performance
For performance, the number of times is capped at an internal max, since sorting an already-sorted
list should have no effect. Use :accurately-simulate
to override this behavior.
# actually press Y 300 times for some reason
:accurately-simulate sort materials 300 times
Detail
sort
requiresInventory
screen- unless
:same-dialog
is used in eitherShop Buying
orShop Selling
screen, in which case it will automatically switch toShop Selling
.
- unless
- Sorting will attempt to remove translucent items. If
mCount
is0
afterward in inventory screen, the inventory will become inaccessible. - Only
Armor
,Material
andFood
categories are allowed to be sorted while selling. - Sorting any armor subtype has the same effect as the armor type.
- Sorting category with broken slots may not fully sort it the first time. This is related to how the merge sort is implemented by the game, and is not a bug in the simulator.
Menu Overload
In the game, when spawning more actors then the limit within the actor system,
new actors will fail to be created. This is known as Menu Overload
.
Since the simulator does not have an actor system like the game, there are only commands for simulating entering and leaving the overloaded state.
overload
for triggering overload.unoverload
for canceling overload.
Syntax
overload
unoverload
Hole Smuggle
If menu is overloaded while closing inventory, the held items won’t be spawned
in the overworld. This is known as Hold Smuggle
.
# Get some random items
get 2 apple 2 banana 2 core
# Activate menu overload
overload
# Hold some items and close
hold 1 apple 1 banana 1 core
unpause
# Since we have hold smuggle, we can get items normally
get diamond
Item Transmutation
Hold smuggling can be used to perform Item Transmutation.
# Get sacrificial items, overload, and hold 5 of them
get 6 apple; overload hold 5 apple
# Sell the last item in the slot
sell apple
# Get the item you want to transmutate into
get giant-ancient-core
unhold # Now have 6 giant ancient cores!
Breaking Slots
Hold Smuggle can be used to make Broken Slots
, see Breaking Slots.
Durability Transfer
Menu Overload allows you to switch inventory equipment without switching it in the overworld. This desynced state allows for transfering durability within the same type of equipments.
# Transfer the durability of Axe to Royal Guard Claymore
get axe royal-guard-claymore
overload
equip royal-guard-claymore
unoverload
use weapon
Details
overload
can be used in any screen.unoverload
requiresOverworld
screen.- This is because it is not possible to cancel menu overload while the inventory is open.
Trials
Trials are special quests in the game where the game takes away your items, and give you a temporary inventory until the trial is completed.
The trials in the game include:
- Trial of the Sword
- Stranded on Eventide
- 4 Blight Refights for Champion’s Ballad
Since each trial has a event flow associated with it, it would
be too complex to try to simulate every possible interaction with the trials.
Therefore, the simulator only provides !trial-start
and !trial-end
commands to put the inventory in or out of the trial mode.
Syntax
!trial-start
!trial-end
- Starting a trial will:
- delete all items except key-items, and set the trial mode flag.
- re-create equipments in overworld.
- Leaving the trial will reset the trial flag and reload your items from GDT.
- Most of the time
reload
a save to exit the trial should work as expected with no issues.
- Most of the time
Most of the time, a single !trial-start
or !trial-end
is accurate enough and you don’t need to worry about the specific details
for each trial. See below if you are in an edge case where the specific event flow matters.
You should almost always make sure you are in the overworld to start a trial. Starting trial with inventory open is supported but may have unintended results. The simulator will NOT automatically switch the screen for you.
Eventide
When walking on eventide, the held items will be dropped if Arrowless Smuggle is active, or unheld if not. You should handle this manually
# Make sure you are not holding items (hold smuggle is fine)
unhold
# Make sure you are in the overworld to walk onto Eventide
unpause
# Trigger the trial
!trial-start
If you give up the Eventide challenge, there will be a loading screen. However there will NOT be one if you complete the challenge.
!trial-end
!system [loading-screen]
Trial of the Sword
Trial of the sword event is more complicated to simulate correctly:
# Make sure you are not holding items (hold smuggle is fine)
unhold
# The event flow will automatically equip master sword, remove it, then add it back
# This is also not fully accurate
equip master-sword; unpause; !remove master-sword; get master-sword
# enter trial mode
!trial-start
# there's a loading screen that sends you to TOTS map
!system [loading-screen]
Leaving TOTS:
# First end the trial and go through the loading screen
!trial-end
!system [loading-screen]
# The game automatically gives you a master sword
get master-sword
# If All 3 trials are completed, set the MS full power flag
!set-gdt <Open_MasterSword_FullPower>[bool=true]
Game Flags
Change flag values in GameData (GDT), such as number of upgrade slots, whether a tab is discovered, and quest flags.
:slots
can be used to change the flag value for how many slots are available for Weapons, Bows and Shields:discovered
can be used to change which tabs are discovered
Moreover, !set-gdt
can be used to set any GDT flag.
Syntax
:slots [CATEGORY=NUM]
:discovered [CATEGORY=true|false]
!set-gdt <FLAG>[GDT_META]
Number of Slots (i.e. Hestu Upgrade)
:slots
or :slot
sets these GDT flags
WeaponPorchStockNum
, BowPorchStockNum
and ShieldPorchStockNum
,
according to the category that is specified.
Examples:
# sets the number of weapon slots to 20 (singular/plural forms are both accepted)
:slots [weapon=20]
# sets the number of weapon slots to 10, and number of bow slots to 8
:slots [weapons=10, bows=8]
# you will get an error if the number is out of range
:slots [weapons=21, bows=4, shields=3]
# Ranges: (inclusive)
# Weapon: 8-20
# Bow: 5-14
# Shields: 4-20
Discovered Tabs
:discovered
edits the IsOpenItemCategory
flag array.
The category is parsed in the same way as item categories.
With a few minor differences:
arrow
andarrows
are allowed, and they are the same asbow
/bows
- Specific armor subtype (Upper/Lower/Head) is not allowed, use
armor
/armors
instead
You can turn a tab to discovered with true
and to undiscovered with false
,
unspecified tabs are unchanged.
Examples
# Discover the weapon, bow, shield tabs
:discovered [weapon, bow, shield]
# Undiscover the armor tab
:discovered [armor=false]
When changing a tab from undiscovered to discovered, the inventory will not automatically
update until it is changed (i.e. when updateInventoryInfo()
is called again).
Any Flag
!set-gdt
can set any flag by name.
The name is specified with angled brackets (e.g. <PorchItem>
), to indicate the value should
be interpreted literally, just like with angled-bracketed item names.
The meta is where you specify the value. First, you need to specify one of the property keys:
bool
s32
(alias:i32
)f32
str32
(alias:string32
)str64
(alias:string64
)str256
(alias:string256
)vec2f
(alias:vector2f
)vec3f
(alias:vector3f
)
For non-vector types, the meta value is the value to set. Examples:
# Make Master Sword stay in True Form
!set-gdt <Open_MasterSword_FullPower>[bool=true]
# Sets Master Sword cool down timer
!set-gdt <MasterSwordRecoverTime>[f32=10.0]
For array values, use the index
property to specify the array index (alias: i
or idx
):
# Set the first item in GDT to Travel Medallion
# String values work without quotes if it only contains alphabetical characters and _ or -
!set-gdt <PorchItem>[str64="Obj_WrapDLC", i=0]
# Set the value of the 20-th item in GDT (0-indexed) to 1000
!set-gdt <PorchItem_Value1>[s32=1000, idx=20]
# Set the modifier value of the 10-th shield in GDT (0-indexed) to 1000
!set-gdt <PorchShield_ValueSp>[s32=1000, idx=10]
For vector values, instead of specifying the value with the vec2f
or vec3f
key,
use x
, y
, z
keys to specify each component. Only the components that
are specified will be changed
# Set the effect level of the first food to 3, leaving effect id unchanged
!set-gdt <CookEffect0>[vec2f, i=0, y=3]
# Set the sell price of the second food to 101, and the unused y value to 500
!set-gdt <CookEffect1>[vec2f, i=1, x=101, y=500.0]
Low Level Operations
These supercommands allow directly editing memory for prototyping or testing, or to workaround limitations of the simulator.
Because these commands edit memory directly, instead of mimicking what the game does, they could be very inconsistent with the behavior of the game sometimes!
Make sure you read the doc carefully before using them!
Syntax
Examples are available at each section below.
!break X slots
!init
FINITE_ITEM_LIST
!add-slot
FINITE_ITEM_LIST
!remove
CONSTRAINED_ITEM_LIST
Generate Broken Slots
The simulator supports breaking slots using actions you would do in-game. See Break Slots.
The !break
command edits mCount
of list1
and list2
directly
to effectively break slots “by magic”.
Example
!break 20 slots
Add Item Slots
The !init
and !add-slot
command will directly
push a new item from list2
to list1
, and set the memory according
to the item you specified. This will bypass ALL checks for adding item to inventory.
Note that it will still prevent adding items when list2.mCount
is 0
.
Furthermore, !init
will reset list1
and list2
to the initial state
(where list2
has 420
items and list1
has 0
). This means all broken slots
will be cleared as well.
Example:
# setting items without sorting
!init 1 slate 1 glider 5 apples
# adding items not addable (doesn't have CanGetPouch flag)
!add-slot <DgnObj_EntanceElevator_A_01>
# when adding stackable items with [value=...], the "amount" becomes
# how many slots to add. e.g. the command below will add 5 slots of 300x arrows
!add-slot 5 arrow[value=300]
The inventory state and GameData will be synced. This will also
set the corresponding IsGet
flag for the item, and the IsOpenItemCategory
for the corresponding category.
If !init
or !add-slot
is used while the inventory screen
is open, the new items may not be accessible until the inventory
screen is closed and opened again!
While we could implement a force resync, doing that would change some internals of the pouch state that you may not want - for example, which item nodes correspond to the equipments in the overworld.
Forcefully Remove Items
The !remove
supercommand lets you forcefully delete items from the inventory:
- For Arrows, Materials, Foods, and Key Items, the value of the slot will decrease by the amount.
- For the rest, the amount in the command corresponds to how many slots of this item you want to remove.
Inventory and GameData state are fixed and synced afterward.
Example:
!remove all cores
This command can target items that are normally inaccessible in the pouch screen.
For example, when mCount
is 0
, or when the item slot is over the maximum available slots
for Weapon/Bow/Arrow/Shield.
Change Item Data
The !write
supercommand lets you edit the data for an item using the
Item Meta Syntax. Inventory is fixed afterward,
but GameData is NOT synced (for historical reason).
Currently, changing the ingredients
is not supported.
Examples:
# Change the value of the Master Sword to 0
# NOTE THAT THIS DOES NOT BREAK IT
# to break Master Sword properly (allowing MSWMC), you have to use the `use` command
!write [value=0] to master-sword
# Change the price of wild greens with price 102 to 101
!write [price=101] to wild-greens[price=102]
# When targeting the item by position, you can also change the item name
# Change the item in material tab 1, row 1, column 2, to royal-claymore
# with durability 20 (no matter what the item at that position is)
!write [dura=20] to royal-claymore[category=material, row=1, col=1]
This command can target items that are normally inaccessible in the pouch screen.
For example, when mCount
is 0
, or when the item slot is over the maximum available slots
for Weapon/Bow/Arrow/Shield.
The !swap
supercommands targets 2 items, and swap their nodes in the list.
Inventory is fixed afterward, but GameData is NOT synced (for historical reason).
Examples:
# Swap the first apple stack and the first banana stack
!swap apple and banana
# Swap the equipped royal claymore and the equipped bow (whatever the bow is)
!swap royal-claymore[equipped] and bow[equipped]
If !write
or !swap
is used while the inventory screen
is open, some inventory state may not reflect immediately until the inventory
is closed and opened again! (For example, when writing [equip=false]
.
While we could implement a force resync, doing that would change some internals of the pouch state that you may not want - for example, which item nodes correspond to the equipments in the overworld.
System Operations
The !system
command provides low-level access to the simulated systems.
Since these commands expose internals of the simulator, they should be considered unstable.
If the simulator internals change in the future, the !system
command could break without warning.
Syntax
!system [SYSTEM_META]
The SYSTEM_META
meta properties are parsed into a list of “system commands”, then executed in order.
Property | Description |
---|---|
dlc | (int or string ) Change the DLC version stored in AocManager in the game memory. Note that due to implementation detail, DLC version can only be changed while the game is running. See the example below. Numbers 0 , 1 , and 2 correspond to No DLC, Day-1 (ver1), and Master Trials (ver2). Any other value means Champion’s Ballad (ver3). See DLC version for supported string values. |
delete-save | (omit value or string ) Delete save data. A save name should be specified (omit value to mean manual save). |
clear-ground | (omit value) Delete all items on the ground, including the ones that are being spawned. |
clear-overworld | (omit value) Delete all items in the overworld, including the ones equipped by the player. |
sync-overworld | (omit value) Sync (i.e. re-create) player equipments in the overworld. |
reload-gdt | (omit value or string ) Load save data into GDT, but do not load the inventory. A save name should be specified (omit value to mean manual save). |
loading-screen | (omit value or string ) Trigger loading screen. The special value no-remove-translucent means trigger a loading screen without first attempting to remove translucent items. |
Examples:
# Get Travel Medallion, save, then uninstall DLC and reload
get travel-medallion; save;
# Simulate a state where only DLC pack 1 is installed
# Note that due to implementation details, !system only works
# when the game is still running, so close-game needs to be after
!system [dlc=master-trials]
close-game
reload # Travel Medallion is gone!
# Simulate entering a shrine and clearing it
!system [loading-screen]
get spirit-orb
!system [loading-screen]
Constant Values
These are non-keyword constants that can be matched by commands in the right context.
When parsing, _
, -
, and spaces (
) are ignored.
So for example resist-cold
is the same as resistcold
.
Cook Effects
These values can be used for the effect
item meta property
to specify cook effect for a food.
Constant | Description |
---|---|
allspeed | Alias for hasty |
attack | Alias for mighty |
attackup | Alias for mighty |
chill | Alias for chilly |
chilly | “Chilly” Cook Effect Internal Value: Some(4) |
defense | Alias for tough |
defenseup | Alias for tough |
electro | “Electro” Cook Effect Internal Value: Some(6) |
endur | Alias for endura |
endura | “Enduring” (Yellow Stamina) Cook Effect Internal Value: Some(15) |
enduring | Alias for endura |
energizing | Alias for stamina |
exguts | Alias for endura |
exgutsmaxup | Alias for endura |
fire | “Fireproof” Cook Effect Internal Value: Some(16) |
fireproof | Alias for fire |
guts | Alias for stamina |
gutsrecover | Alias for stamina |
hasty | “Hasty” (Speed Up) Cook Effect Internal Value: Some(13) |
hearty | “Hearty” Cook Effect Internal Value: Some(2) |
lifemaxup | Alias for hearty |
mighty | “Mighty” (Attack Up) Cook Effect Internal Value: Some(10) |
movingspeed | Alias for hasty |
none | No cook effect Internal Value: Some(-1) |
quiet | Alias for sneaky |
quietness | Alias for sneaky |
resistcold | Alias for spicy |
resistelectric | Alias for electro |
resistfire | Alias for fire |
resistflame | Alias for fire |
resisthot | Alias for chilly |
sneaky | “Sneaky” (Stealth Up) Cook Effect Internal Value: Some(12) |
speed | Alias for hasty |
speedup | Alias for hasty |
spicy | “Spicy” Cook Effect Internal Value: Some(5) |
stam | Alias for stamina |
stamina | “Energizing” (Stamina Up) Cook Effect Internal Value: Some(14) |
staminaup | Alias for stamina |
stamup | Alias for stamina |
stealth | Alias for sneaky |
stealthup | Alias for sneaky |
tough | “Tough” (Defense Up) Cook Effect Internal Value: Some(11) |
Weapon Modifiers
These values can be used for the modifier
/modtype
item meta property
to specify modifier for an equipment.
Constant | Description |
---|---|
addguard | Alias for guard |
addguardplus | Shield Guard Up+ Internal Value: Some(0x80000100u32 as i32) |
addlife | Alias for durability |
addlifeplus | Durability Up+ Internal Value: Some(0x80000002u32 as i32) |
addpower | Alias for attack |
addpowerplus | Attack Up+ (Weapon or Bow) Internal Value: Some(0x80000001u32 as i32) |
attack | Attack Up (Weapon or Bow) Internal Value: Some(0x1) |
attackup | Alias for attack |
critical | Critical Hit Internal Value: Some(0x4) |
criticalhit | Alias for critical |
durability | Durability Up Internal Value: Some(0x2) |
durabilityup | Alias for durability |
guard | Shield Guard Up Internal Value: Some(0x100) |
guardup | Alias for guard |
longthrow | Long Throw Internal Value: Some(0x8) |
multishot | Bow Multishot Internal Value: Some(0x10) |
none | No modifier Internal Value: Some(0) |
plus | Make the modifier “Yellow” Internal Value: Some(0x80000000u32 as i32) |
quickshot | Bow Quickshot Internal Value: Some(0x40) |
rapidfire | Alias for quickshot |
shieldsurf | Alias for surfmaster |
shieldsurfup | Alias for surfmaster |
spreadfire | Alias for multishot |
surf | Alias for surfmaster |
surfmaster | Shield Surf Up Internal Value: Some(0x80) |
surfup | Alias for surfmaster |
throw | Alias for longthrow |
yellow | Alias for plus |
zoom | Bow Zoom Internal Value: Some(0x20) |
DLC Version
These values can be used for the dlc
system property
in the !system
command.
Constant | Description |
---|---|
all | Alias for ver3 |
championballad | Alias for ver3 |
championsballad | Alias for ver3 |
day1 | Alias for ver1 |
mastertrial | Alias for ver2 |
mastertrials | Alias for ver2 |
nodlc | Alias for none |
none | No DLC Internal Value: Some(0) |
plateau | Alias for ver1 |
ver1 | “Day 1” DLC Internal Value: Some(1) |
ver2 | Master Trials (DLC Pack 1, ver 2.0) Internal Value: Some(2) |
ver3 | Champion’s Ballad (DLC Pack 2, ver 3.0) Internal Value: Some(3) |
Custom Image
When running into code outside the normal inventory logic using glitches like Item Stack Underflow, the simulator will probably crash because it does not contain the full game to be able to execute setups that involves code outside of the normal inventory code.
BUT, the simulator is capable of executing the whole game’s code
if it is given access. This is referred to as the Full Mode or Custom Image Mode.
To do this, you need to create a BlueFlame image (a .bfi
file) from the
game files.
Create Image
To create the image, you need the following things:
- Dump of the game (only some files are needed, not all of them)
- A Nightly Rust toolchain
- If you don’t have rust installed, see here
For detailed instructions on what is needed and steps to create the image, see
the uking-relocate
tool. Follow the instruction on the tool’s README.
The env
Block
To tell the simulator to use a custom image instead of the default image,
put an env
block literal at the beginning of the script.
The env
block must be at the beginning, before any lines and comments.
Empty lines are allowed before the block.
The env
block should contain one <key> = <value>
per line. Here is an example:
'''env
image = 1.5
dlc = champions-ballad
program-start = 0x0000001234500000
stack-start = 0x0000005678900000
stack-size = 0x40000
heap-free-size = 0x40000
pmdm-addr = 0x0000003456789ab0
'''
If a value is invalid, it’s equivalent to that value being not specified. At the same time, you will see an error in the script editor.
The image
key specifies the version of the game.
Allowed values are 1.5
and 1.6
.
Currently, only 1.5
is supported. 1.6
is recognized but
not supported. Newer versions won’t be recognized by either
the simulator or uking-relocate
.
The rest of the keys are optional. If not specified, the simulator will use the internal default values.
Key | Value | Description |
---|---|---|
dlc | a DLC specifier (see below) | Specify the DLC version to simulate |
program-start | Region Address | The physical memory address of the start of the program region. This is checked against the program-start of the image file. The simulator cannot start if this doesn’t match. If this is not specified, any program-start will work. |
stack-start | Region Address | The physical memory address of the start of the stack |
stack-size | Size | The size of the stack, must be aligned to 4KB |
heap-free-size | Size | Size of the free region of the heap for the simulator to allocate memory |
pmdm-addr | Physical Address | The address of the PauseMenuDataMgr (in other words, the value of PauseMenuDataMgr* ). This is used to calculate heap start |
Large stack/heap size can slow down simulator start-up. It is recommended to only change these if the default does not work for you.
DLC specifier can be any string that contains 0
, 1
, 2
, or 3
, which correspond
to no DLC installed, DLC ver1.0 (Day 1)
, DLC ver2.0 (Master Trials)
and DLC ver3.0 (Champions' Ballad)
.
One of the following shorthand is recommended:
DLC Version | Possible Specifiers |
---|---|
No DLC | nodlc , none , uninstalled |
ver 1.0 | dlc-1 , ver1.0 , day-1 |
ver 2.0 | dlc-2 , ver2.0 , master-trials |
ver 3.0 | dlc-3 , ver3.0 , champions-ballad |
Invalid DLC version specifier defaults to ver3.0
.
A Region Address must be a hexadecimal string aligned to 0x100000
,
the most significant 6 hex-digits must be all 0
.
A Size must be a 32-bit positive integer, aligned to 0x1000
.
A size of 0
is the same as unspecified, and the internal defaults will be used.
pmdm-addr
must be aligned to 0x8
.
Furthermore, the program, stack, and heap regions must not overlap.
Upload the Custom Image
Once image
is specified in the env
block, refresh the page.
You should see a prompt that asks if you want to upload
a custom image. Select Setup
and follow the on-screen instructions
to upload the .bfi
file you created.
If the custom image fails to load, you can always select Use Default Image
in the prompt to start the application normally and fix your script.
The uploaded image is stored in your local browser.
Use Custom Image By Default
You can opt-in to always use your custom image for you own script, even when
the env
block doesn’t specify a custom image.
To enable this, check the box that says Use Custom Image by default for my scripts
when uploading the custom image.
Delete Uploaded Custom Image
You can open the
3-dot menu on the top of the app and select Delete Custom Image
.
This clears the custom image file that is stored in your local browser.
Developer Manual
This section is highly technical and only intended for people who work with, or are interested in, the IST simulator as a developer. For example:
- Contributing to the project
- Building extensions for the simulator
- Integrating components of the simulator to other things
The following chapters assume you have basic programming knowledge. The IST Simulator is built with TypeScript, Rust and some Python scripts for data processing. Familiarity in at least one of these languages will help with understanding.
It is recommended that you start with Architecture
if you want to contribute code.
Architecture
Skybook can be divided conceptually into 5 layers (or systems, or components, whatever you want to call them):
- The
Core
: The Core is namedBlueFlame
. This layer is essentially a stripped-down, mini-emulator that interprets the game’s code. The core’s functionality is not limited to simulating IST, but can be expanded to other areas of the game if enough research is put into it. - The
Runtime
: The Runtime layer parses the script into steps and keeps track of the memory state of those steps in a simulation. It orchestrates the core for most of the simulation, and implements some sub-systems that are not supported by the core. The Runtime layer also manages multiple Cores to utilize multiple processors efficiently. - The
Worker
: This is the front-end of the Runtime. The Runtime layer is implemented in Rust, which is bad at handling async processes and requests. However, TypeScript is very good at that. So, the Worker layer essentially wraps the native interface with a TypeScript interface that the Application works with. - The
Application
: This is the main UI of the simulator web app, such as Pouch and GameData display. - The
Extensions
: The extensions are extra UI widgets that interface with the Application to easily add new features without changing the underlying architecture.
For the web application, there is also a server that handles DirectLoad - loading script from another source such as GitHub or embedded URL. The server doesn’t really have anything to do with the core functionality, so it’s not discussed here.
These layers can be composed based on different requirements for endpoints. For example, the configuration for the web app is:
Core
andRuntime
are built into WASMWorker
is bundled into a WebWorker that loads the WASMApplication
is bundled into the main entry pointindex.html
Extensions
are both bundled into the main entry point (for displaying directly in the page), and secondary entry pointpopout.html
for displaying as popouts.
Restricted imports in the UI Application
To simplify bundling, all UI code is in the app
package.
However, be careful when importing from a different part of the package,
since that can affect the code splitting for bundling.
Current endpoints and what they import:
main
:application/extension
application/runtime
application/store
extensions
ui/components
ui/components
popout
:extensions
ui
Getting Started
The first step to contributing is to setup a development environment locally on your PC.
I aim to make the setup process as streamlined as possible. If you encounter any issues, please feel free to reach out and suggest to me how it can be improved!
Before starting the setup, follow the mono-dev
Standard
to setup the required tools:
- Rust Toolchain
- Node, PNPM, and Bun
- Python
- Task
- Magoo
Coreutils is required for Windows development.
Clone repository and one-time setup
Run the following commands:
git clone [email protected]:Pistonite/botw-ist --depth 1
cd botw-ist
magoo install
task exec -- research:install
task install-cargo-extra-tools
task build-artifacts
task install
task check
This will:
- Clone the repository to your PC using your GitHub account
- If you don’t have GitHub account or don’t have SSH key setup, use
https://github.com/Pistonite/botw-ist
as the URL instead
- If you don’t have GitHub account or don’t have SSH key setup, use
magoo
will setup the submodules for you- Research scripts will be ran to ensure data files are setup
- Data artifacts will be built from the data files
- Dependency packages will be downloaded
- Configuration files will be generated
Keeping up-to-date
After pulling, you need to update the repo locally to sync tools to the latest state.
Run:
task install
That’s it!
Building Runtime
The setup above will let you build and run the web app without building the Runtime locally. To build the Runtime, you need to either:
- Set up uking-relocate,
and put the game files in
packages/runtime-tests/data/botw150
.- Then, run
task exec -- runtime-tests:build-mini
to build the mini image.
- Then, run
- Set up a BlueFlame image,
and put the image file at
packages/runtime-tests/data/program-mini.bfi
. This will use whatever image you provide as the default runtime image.
Now, you can build the runtime WASM module:
task exec runtime-wasm:build
After that, the local build of the app will use the locally built Runtime.
Build and Run
This applies to development of:
- The Web App
- The Manual (this thing you are reading)
- The Server
For all the commands like this:
task exec -- app:dev
You can also cd
to the package and execute the task:
cd packages/app
task dev
Web Application
Running the web app locally requires Secure Origin, which means either running from localhost
or setting up HTTPS, see here.
To run the web application:
task exec -- app:dev
The UI will automatically reload as you make changes.
Note that DirectLoad will not work when running the application locally since it’s a server feature.
Manual
To run the manual (this website):
task exec -- manual:dev
The manual will automatically reload when making changes.
Server
Currently, running the server locally also requires building the runtime as part of the assets, which requires a dump of the game to build.
To run the server, first build and pull the application assets locally:
task exec -- server:pull-local
Then the dev workflow can be started with:
task exec -- server:dev
Changes in the server code will reload the server automatically. However, changes in the client code requires re-running the client build and restarting the server (sometimes).
Building the Runtime
While you can make changes and build the runtime packages locally, to run it, you must have a BlueFlame image.
Building the BlueFlame image requires you to dump some parts of the game. See uking-relocate for more info.
Once you have the game files prepared, put them in /packages/runtime-tests/data/botw150
:
The directory structure should be like
packages/
runtime-tests/
data/
botw150/
romfs/
main.elf
rtld.elf
sdk.elf
subsdk0.elf
Then run task exec -- runtime-tests:build-mini
to setup the mini image
used for running the runtime locally.
Alternatively, you can put the built BlueFlame image at /packages/runtime-tests/data/program-full.bfi
, then run:
cd packages/runtime-tests
task update-trace-hash
python scripts/relocate.py
This will also produce program-mini.bfi
.
Once you have the mini image, you can now make changes to the runtime packages, and rebuild the WASM package:
cd packages/runtime-wasm
task build
After building the WASM package, run the web app (or reload if already running) for it to pick up the newly built changes.
Checking Testing
You should make sure your changes are properly checked and tested.
Most of the time, this means you should at least manually tested the change, and if needed, add at least one Snapshot Test if the runtime is changed.
Checking
Running task check
in the root of the repo will run a handful of checks and lints.
You can also run task exec -- XXX:check
to only run checks for one package.
When there are formatting issues, task exec -- XXX:fix
can automatically fix that.
skybook-api
modification checks
If you changed code that affects the generated skybook-api
code, you need
to commit those changes to git for skybook-api
checks to pass.
localization
checks
Certain changes require adding keys to localization (e.g. new error types). Please reach out to me for adding localizations.
The modification check also requires the changes to be committed to pass.
Unit and Manual Tests
We use Vitest for unit testing TypeScript code and standard Cargo test for Rust.
Also make sure to test your changes manually in the app. See Build and Run for how to run the app locally.
Snapshot Tests
Snapshot tests are the most important tests in the project. These tests are simulator scripts that the test tool runs and captures the state at each step, and saves them to a text file in a human readable format. Any diff in the snapshot is considered a failure.
To add a snapshot test, put a .txt
file containing the script in /packages/runtime-tests/src/script_tests/
,
then run task exec -- runtime-tests:run-full
(or run-mini
).
This will generate a new snapshot in snapshots/
. Open the file
and make sure the state is what you expect at every step.
If a snapshot test fails, the new snapshot will be saved to snapshots/wip
.
You can diff the snapshot with task diff -- NAME_OF_TEST
. (Requires
the delta
tool).
When you think the new snapshot is ready, copy it to snapshots
and replace the old snapshot.
You can also run the ust
task to update all snapshots.
Translations
The translation files are located in packages/localization/src/ui/*.yaml
.
Here’s what you need to know when modifying the translation files:
- Each translation entry is in the format of
<key>: "<value>"
- To escape
"
inside the value, put\"
. - Tokens like
{{data}}
are placeholders that will be replaced with the actual text in the app. Keep this in mind if you can’t find the entry you are looking for.
To add new translations, follow these steps:
- Add the new key and English value in
en-US.yaml
- Prepare a translation file like this:
# en-US is optional and will be ignored, en-US: button.ok: "OK" # order of languages/keys below does not matter # you can also include multiple keys de-DE: button.ok: "OK" es-ES: button.ok: "Aceptar" ko-KR: button.ok: "확인" zh-CN: button.ok: "好的"
- Go to the
localization
package (cd packages/localization
) - Run the
edit
task and pass in your file:task edit -- path/to/your/file
This will apply the edits to the translation files and make sure everything is formatted. Note that existing values will be overridden and values not found in English will be deleted.
To change the translation for one language, simply modify the language files.