# RFC: SWADE Predicate Specification
[Playground Link](https://www.typescriptlang.org/play?ts=4.9.5#code/PQKhAIBUAsFNwPYAdYCcCGAXBrEDNxM5wBjBAOwBMBLTai8EYAKEwE8VwB5FDbXALzgARNHQBnYeAA+IgIRjJMkQIFTZwuWuXCAfOpG7tGgDwHhJtc2bVymNHnQl4AYQo06DAN7NwiXlg4AFzcAfwA3L7goBAw8OycCAREtgDmhGKY4NTi4ABGsGmkCAC2SOiosJQANODiAK4k0OASGfDi1ABe8EktdQDW1AA2Q+A0Pbjo4Bjk-YwsfuKwQ7Ak-CHimKhpkX4xUMROmPXoowBup-XxCMVlFfDoqei2m-NRF0NXAPwh5PUlBVwsk223IqUiAF9rDFfBAAIJ1LZFIhYMaraiUWC5aAIADubWKVFo9HIuXQVGAOHAeGG9lQZMqGVRZBKDzwdOyWXutzytiqsPAAFpwAADU5DEVC3TgIYIVLUEincBwgByABEBcKxeQ2JLBdLZfLFaMuAAlTWi8gUWB6g1yhVKlVm2EsBKuUq88iBQQiclsczi8xW8iwYSRZj7BE0oYcsiknKYXK9a082zelpURAhxC4Eo4eAhzZVQkeElkilU6N03JMVgceAAMVpaHAQgA2m4AWn+LUAHT9gAUbiJnnIyibMbQAEo2wBdWfhuOvPAIBAhCcc9tRYSB2rAYCGh2jVVquo3cXUhAjPFFWAADyQlXEHQouRDxew+XiqCuUS8-jQb0QlECRhFqJYVjWYIRCqVJYCCT4SH6f0IT3YBFAJRDkPAWD4H1bJMTsagaWLM5qCmcRPlSYBxFxDE-wAvhoL0NRwOWVZ1hEGZ+jA8APiuEIAAZwFQ6JgByfAWiyFYJCyK0yOcaZyX6ZgF2sJcsjyCp12bH0223P1eP3Q9jW4U0zykmVYFkrMemSYgV2vOiwRLYlX3Ad9KEIG4CnAVlMAY5BAM4ljeIgjjmO43j+Pg8AAGYRLQiTelRGTXjgVAEAVJTZiifS-D8HcRiMg97VMk8LIvRzZWc9J70fLEX1JDzYA-Hzv1-ArwH-IKmNQYDFDC9ioP6mDKDghDGmQ4RRP3DCiHgLC2Bw8a8OlDFYCIkivLIiiqJoujKCiPwerCZjBrYyCQtwoIsC2I5qDOUNZvQ1oFqk+61ke+BcKlAjNroba+PIup9to+i-FnapVMXV9NPQTodMnPSDOKtCTKVCrxHPEZLyc28HyfJq31arzP18rZOu6xigMMVi6mGkKotqGKQgSl7koIVLrPStAspIHKVJOmmQqMIaruY8RBhGIIaVSaA6DBaLLligA2RKxIwqY5YVoopeGUYUuknmskoVWYehMBwFNVZ6npb6hmW2B+KwB5wHlJ6xyrFtazwepyC+hhncuV2NzQAdvf6sPUCnII8lXGTyB8PwNPANsWU9b0+37ONS1fWdW2pXTwz8YiBzdXoM+7KktCEYQQTSYQpwyTL8RDfEAFFUEy1ABynawU7h6YsXqGNxBCeOr2s8g50LucS8vXvU9ztyx0r9xV-EKdk4Ksu4W79A2F7HJ94wNgBxX0cp2346Cv3SoSDtjonsdnCXfsIvkfEW+-CfUfE17Egeo4hoADmDp8UOukL4byvv3LqEIcJDCWN1H+YlwEnA-u9S+JJUF-zHoA4BoD0Gu2HHncg0CRwkmvrfKEfgoRRHBpgJo0Cuxen4DfLqipkFFSGMIIIuDYDHFQGOPBADnZoHPoIaUghVCEB-LAKcuwCpcPgDuHUfCBFCJESPfB2NWQDikdMVssjKYKKUSnCQqjgyhn4V1X+gi7baIaPg8RqBJGtmkcYoQjgkFmKiFCehewrYd3fm7bBDBHjPFJFyMcRwqS+39oHMcxD7CkNXhQshIQ0lXzjgnaeKDh5aLkb+CEQA)
## The Savage Worlds ID
The Savage Worlds ID(or SWID for short) is a semi-unique string in Item documents that is generated from an Item's name. SWIDS are not automatically generated when you change the name of an item, allowing the system to identify an item without considering the name, as the SWID stays stable. SWIDs need to be manually created through a user interaction, such as a button press.
The SWID itself is a strictly typed slug, so `Hard to Kill` becomes `hard-to-kill`
The parry calculation is a good example for this. To calculate the parry score we need to find the Fighting skill, but this may be called something different in other languages. As long as the skill item has the SWID of `fighting` we can identify it regardless of name.
The `any` swid is a reserved word that signifies we are looking for some other condition on the item.
## Predicates (name subject to change)
Predicates are made up of conditions [conditions](#Conditions) and nested predicates. Each filter can start with zero or one of the following combinators:
- `all` -> logical AND, all of the following conditions need to be true
- `any` -> logical OR, at least one of the following conditions needs to be true
- `none` -> logical NOR, all of the following conditions need to be false
If a given predicate doesn't start with an explicit combinator, the `all` combinator is assumed.
## Conditions
A condition is made up of an `operator`, a `selector` and optionally a `value` to compare against.
### Selectors
There are two kinds of selectors
- Special selectors, such as `rank` or `wildcard` or `attribute`
- Item selectors, such as `skill:fighting` or `edge:any:system.isArcaneBackground`
#### Special Selectors
There are some reserved selectors. Here's a non-exhaustive list
- `rank` -> the Actor's rank
- `wildcard` -> is the Actor a wildcard?
- `attribute` -> select a specific attribute die-type, such as `attribute:strength`
#### Item Selectors
Item selectors are made up of up to three parts.
- The Item type (or `item` to select any item type)
- The SWID (or `any`)
- An attribute key
The type is used to narrow down the pool of items for. If you use `item` then all of the actor's items are considered
There are some special shortcuts as well, specifically for the `skill` type. If no special attribute key is given, the selector is considered to look at the die-type.
The attribute key is the same as used in Active Effects. This can be used to refine our selection for comparison.
### Operators
Operators tell the filter how to evaluate the filter condition, such as checking whether something is truthy or doing a numerical comparison.
> Something to consider: If no operator is given then implicitly assume the `has` operator
### Examples of Selectors and Operators
#### Has any Arcane Background
```ts
{ operator: "has", selector: "edge:any:system.isArcaneBackground"}
```
The operator is `has`, which checks if the selector is truthy. With this information we can read the condition as the following: _Has any edge that is an arcane background_
#### Has the Lucky edge
```ts
{ operator: "has", selector: "edge:lucky"}
```
#### Has a Fighting die-type of d6+
```ts
{ operator: ">=", selector: "skill:fighting", value: 6 }
```
#### Anything with a flag
```ts
{ operator: "has", selector: "item:any:flags.myModule.myFlag"}
```
This can be read as _Any item that has the `myFlag` set_