Skip to content

Commit 54bb571

Browse files
authored
Merge pull request #56 from ManualForArchipelago/docs-requirement-functions
Docs: Syntax -> Requires for Locations and Regions
2 parents 999a9bf + 037bedd commit 54bb571

File tree

3 files changed

+121
-3
lines changed

3 files changed

+121
-3
lines changed

docs/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ _How does that work?!_ Well, you'll just have to read more below!
4747
- [Location syntax](syntax/location.md)
4848
- [Categories for Items and Locations](syntax/categories-for-items-and-locations.md)
4949
- [Region syntax](syntax/region.md)
50-
- [Requires for Locations and Regions](syntax/requires-for-locations-and-regions.md)
50+
- [Requires for Locations and Regions](syntax/requires.md)
51+
- [Boolean Logic (AND/OR)](syntax/requires.md#boolean-logic)
5152
- [Item Counts](syntax/requires.md#item-counts)
5253
- [Requiring Categories](syntax/requires.md#requiring-categories)
53-
- [Boolean Logic (AND/OR)](syntax/requires.md#boolean-logic)
54+
- [Requirement Functions](syntax/requires.md#requirement-functions)
5455
- [Category syntax](syntax/category.md)
5556
- [Hooks](syntax/hooks.md)
5657
- [World Hooks](syntax/hooks.md#world-hooks)

docs/syntax/requires-for-locations-and-regions.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/syntax/requires.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Requires for Locations and Regions
2+
3+
_Let's start with the bad:_
4+
5+
If you don't put requires on your locations and/or regions, every location in your world will be in sphere 0. As in, any multiworld you play in will expect you to complete your entire world as soon as the multi starts.
6+
7+
So it's really important to have requires! But what are they?
8+
9+
Location/region requires tell the world what the logic is for accessing that location or region. Example: If you're playing Link to the Past and you have a region for Thieves Town, one of the dungeons in the Dark World. Your requires for that region would say that it requires Moon Pearl (for navigating the Dark World in human form) and either Hammer + Power Glove or just Titan's Mitt (for getting to the Dark World at all). Until you get the bare minimum of those items, that location will not be in logic, so the multi will not expect you to do that location yet.
10+
11+
Okay, so we know what requires are. Let's talk about the different ways you can write out those requirements!
12+
13+
## Boolean Logic (AND/OR)
14+
15+
**Boolean logic is the default way to write requires in Manual.** It's called "boolean logic" because you're writing your logic much like you'd describe it normally: with a series of AND/OR combos.
16+
17+
For example, from the example above about Link to the Past and Thieves Town in the Dark World, let's assume that the first chest location in the dungeon has no additional requirements. So, we'd describe our logic for that first chest location as being "Moon Pearl and (either (Hammer and Power Glove) or Titan's Mitt)", same as the region itself. In Manual's boolean logic syntax, that would be:
18+
19+
```json
20+
{
21+
"name": "First chest in Thieves Town",
22+
"requires": "|Moon Pearl| and ((|Hammer| and |Power Glove|) or |Titan's Mitt|)"
23+
}
24+
```
25+
26+
**You use `|pipes|` around item names and `(parentheses)` around your layers of nesting, if needed.**
27+
28+
- Pipes tell Manual where to look for entire item names.
29+
- Parentheses tell Manual exactly how you're grouping your logic, since there's a difference between "Hammer and Power Glove or Titan's Mitt" and "(Hammer and Power Glove) or Titan's Mitt".
30+
- The former essentially evaluates to "Hammer and either Power Glove or Titan's Mitt", while the latter is very explicit about what the logic should be and evaluates correctly.
31+
- There's no theoretical limit to how many parentheses you can use, but try to not get past the practical limit of how many sets of parentheses you can reliably keep track of.
32+
33+
### Additional Examples of Boolean Logic
34+
35+
Boss 1 Requires Ladder and Gloves, OR Sword and Shield, OR Bow and Quiver and Arrow (separate items): a simple case of various successful item sets. It's a few sets of ANDs separated by ORs.
36+
```json
37+
{
38+
"name": "Boss 1",
39+
"requires": "(|Ladder| and |Gloves|) or (|Sword| and |Shield|) or (|Bow| and |Quiver| and |Arrow|)"
40+
}
41+
```
42+
43+
Boss 2 simply requires one heart, a way to strike it (Sword, Spear or Club) and a way to dodge it (Double Jump, Dash or Slide): we're looking at different sets, and picking one item from which. It's many ORs inside a big set of ANDs.
44+
```json
45+
{
46+
"name": "Boss 2",
47+
"requires": "|Heart| and (|Sword| or |Spear| or |Club|) and (|Double Jump| or |Dash| or |Slide|)"
48+
}
49+
```
50+
51+
Now, say the final boss is a big dragon with a glaring weakness to Blizzard. However, if you don't have blizzard, you will need a spear for its reach and a way to dodge it, which is one of the three mobility from before. This is an OR (the mobility), inside an AND (Spear and Mobility), inside an OR (Blizzard it or fight it legitimately). Layered logic is as such:
52+
```json
53+
{
54+
"name": "Final Boss",
55+
"requires": "|Blizzard| or (|Spear| and (|Double Jump| or |Dash| or |Slide|))",
56+
"victory": true
57+
}
58+
```
59+
60+
## Item Counts
61+
62+
As demonstrated in the [Making Items: Count](making/items.md#count) docs, you can configure an item to have more than one copy of that item in the world's item pool. Sometimes, you want to use multiple copies of an item as a requirement for accessing a location or region, and Manual supports this as well.
63+
64+
The way to do this is a short suffix added to the end of any required item name separated by a colon, like this: `|Coin:25|`.
65+
66+
- That will tell Manual that the location/region requires 25 of that Coin item.
67+
68+
Now that we know how to require multiple of an item, we can revise our Boss 2 example from above to make the boss a little easier to handle in-logic:
69+
70+
> Boss 2 simply requires **FIVE hearts**, a way to strike it (Sword, Spear or Club) and a way to dodge it (Double Jump, Dash or Slide): we're looking at different sets, and picking one item from which. It's many ORs inside a big set of ANDs.
71+
> ```json
72+
>{
73+
> "name": "Boss 2",
74+
> "requires": "|Heart:5| and (|Sword| or |Spear| or |Club|) and (|Double Jump| or |Dash| or |Slide|)"
75+
>}
76+
> ```
77+
78+
In addition to specific item counts, you can also specify a broad relative amount like "all of this item" or "half of this item", or even percentages of that item versus the total in the pool. We'll demonstrate those briefly below as well.
79+
80+
- `|Coin:ALL|` will make a location/region require every `Coin` item in the world's item pool before being accessible. So, if you have 50 Coins in the pool, it will require all 50. (The "ALL" is not case sensitive, so it can be lowercase too.)
81+
- `|Coin:HALF|` will make a location/region require half of the `Coin` items in the world's item pool before being accessible. So, if you have 50 Coins in the pool, it will require 25. (The "HALF" is not case sensitive, so it can be lowercase too.)
82+
- `|Coin:90%|` will make a location/region require 90% of the `Coin` items in the world's item pool before being accessible. So, if you have 50 Coins in the pool, it will require 45. (Supports percentages between 0 and 100.)
83+
84+
## Requiring Categories
85+
86+
As demonstrated in the [Making Items: Category](making/items.md#categories) docs, you can configure an item to belong to a category, potentially with other related items. Sometimes, you want to use a category of items as a requirement for accessing a location or region, and Manual supports this as well.
87+
88+
The way to do this is a short ampersand prefix added to the beginning of any required item name, like this: `|@Coins Category|`
89+
90+
- That will tell Manual that the location/region requires 1 item from the "Coins Category" category.
91+
92+
Additionally, you can use counts as described above for required categories, just as you would use them for required item names. Let's see the demonstrated counts from above in category form:
93+
94+
- `|@Coins Category:ALL|` will make a location/region require every item in the `Coins Category` category before being accessible. So, if you have 50 items in the `Coins Category` category, it will require all 50. (The "ALL" is not case sensitive, so it can be lowercase too.)
95+
- `|@Coins Category:HALF|` will make a location/region require half of the items in the `Coins Category` category before being accessible. So, if you have 50 items in the `Coins Category` category, it will require any 25 of them. (The "HALF" is not case sensitive, so it can be lowercase too.)
96+
- `|@Coins Category:90%|` will make a location/region require 90% of the items in the `Coins Category` category before being accessible. So, if you have 50 items in the `Coins Category` category, it will require any 45 of them. (Supports percentages between 0 and 100.)
97+
98+
## Requirement Functions
99+
100+
Requirement functions are functions that you write in the Rules hook file and can use in requires in locations/regions. We do provide a couple of default ones as examples, but only a couple of generic ones for very specific cases (more on that below \*). In most cases, you'll be working with hooks to take advantage of requirement functions.
101+
102+
You'd typically use requirement functions if you have requirements that are too cumbersome to type out by hand, have requirements that rely on some dynamic piece of information, or have requirements that don't fit into the templating syntax that Manual provides for requirements.
103+
104+
The way to do this is using curly braces around the function name that you want to call, like this: `{myFunction()}`
105+
106+
- Note the lack of pipes (`|`). Functions are processed entirely differently than items/categories used as requirements.
107+
- Doing this will tell Manual that the function will either return a requires string to be processed, or will return true/false based on whether this requirement was met.
108+
109+
Requirement functions can have no function arguments, or have any number of function arguments separated by commas.
110+
111+
- Example with no function arguments: https://github.com/ManualForArchipelago/Manual/blob/main/src/hooks/Rules.py#L8-L15.
112+
- Example with one argument, add str arguments to the end of the function for more: https://github.com/ManualForArchipelago/Manual/blob/main/src/hooks/Rules.py#L17-L24
113+
114+
Additionally, those functions can themselves return a dynamically-created requires string, which would then be processed normally in the spot where the function call was.
115+
116+
- Example of a returned requires string: https://github.com/ManualForArchipelago/Manual/blob/main/src/hooks/Rules.py#L26-L29
117+
118+
\* By default, the only two generic requirement functions that we provide are the OptOne and OptAll, which are both focused on allowing a required item or items to pass the requirement even if the item(s) have been disabled through defined category options. The rest of the functions in the Rules hook file are examples.

0 commit comments

Comments
 (0)