Wiki

Clone wiki

pyrel / Item generation

Introduction

For examples of any of the data structures described on this page (object records, affixes, themes, loot templates, etc.), please see the data_files page.

Pyrel generates items using a system of loot templates. Loot templates are extremely flexible and can adjust any aspect of item generation, so first we'll examine the default process, if you don't supply any template at all.

Item generation without a template only uses one variable (argument, whatever) - an itemLevel. It's normally the dungeon level you're currently on (which Pyrel calls mapLevel, since you might not be in a dungeon), but can be any number.

Base objects (i.e. all consumables and all unenchanted wearables) use the same allocation table approach as in V. So when generating an item at any given itemLevel, you create an allocation table containing all items which can possibly be generated at that level, where each item has a number of entries according to its "commonness" rating. So an item with commonness 10 will have ten times as many entries as an item with commonness 1, and is therefore 10x more likely to be chosen from the table. The commonness of items can vary with level, so an item might have commonness 10 at levels 1 to 50, and commonness 5 at 51 to 75, and then not appear at all beyond that. Note that commonness can be less than 1 (e.g. commonness of .01 is 100x less common than commonness of 1).

These groupings of levels and commonness are called "allocation rules", and they're defined in object.txt. Note that the game will not crash if you specify overlapping allocation rules - at the overlapping levels, the highest commonness rating will be used. The allocation rules also specify the quantities in which the item is found - so e.g. scrolls of Phase Door could be found singly at levels 1 to 20, then in increasingly larger stacks at deeper levels.

Once an item is chosen from the allocation table, its quantity is rolled. Without a loot template, that's it, job done. No plusses, no ego, nothing.

Loot Templates

So, loot templates. These are defined in their own file - loot_template.txt. There are two sets of modifiers in loot templates - the 'base' modifiers and the 'boosts'. The base modifiers set the main parameters - allowed item types, affixes, etc. - and the boosts control the degree of randomness and level-dependence of a template. So the 'normal', 'good' and 'great' templates will produce items of those qualities relative to your current depth - you don't need to use different templates for different depths.

The first base modifiers used are:

  • itemLevel - this will override the mapLevel argument, if for any reason you want to divorce the item generation level from the current mapLevel (e.g. for a specific dungeon feature). Can be an integer or a boostedDie formula. Not to be confused with the boost itemLevel modifier, which is explained below.
  • itemType - this is a dictionary that limits the items that can be placed in the allocation table. The keys are item types (potion, scroll, magic book, prayer book, hard armor, soft armor, boots, sword, wand, etc. etc.), and the values are lists of allowed items. You can specify any combination of items, using "all" and "all except" to avoid typing out long lists. You can also use "none" to disallow an item type completely - this then inverts the logic of the itemType dictionary and permits everything else (since if you specify anything positively, any type not specified is assumed to be "none"). This is useful for re-creating V's ONLY_ITEM flag with { "money": "none" }

Affixes

Once the base item is chosen, any magic specified in the loot template is applied. Magic and ego items use the affix-and-theme system, which is based on the one in v4. Affixes use a similar allocation table approach to that used for items. Like items, affixes have the commonness-at-depth feature, and this is the basis for their place in the allocation table of affixes available to enchant any given item, but affixes have a lot more flexibility. They are detailed in object_affix.txt

1. You can specify which items they may or may not be applied to (at each depth). This uses an identical itemType dictionary to the one used in loot templates.

2. You can specify global minima and maxima for affixes of each type and goodness rating at any given itemLevel (i.e. each ego item between levels 50 and 75 shall have no more than one "bad" affix and at least one "arcane" affix, or whatever). These global minima and maxima rules are specified in affix_meta.txt

3. You can specify explicit conflicts (so the affix "Rusty" will never be applied to anything which already has the affix "Sharp"). You can specify that an affix conflicts with itself, so that it can only be applied once.

Loot templates define the affixes present on an item (remember that no loot template means no affixes). The base modifiers are:

  • affixes - this is a list of affixes that are automatically applied to the item, ignoring any conflicts or other restrictions. This obviously isn't used in the standard normal/good/great templates, but could be used for specific dungeon templates (e.g. applying "Orcish" to every item in an orc lair).
  • numAffixes - after any specified affixes are applied, this is the number of other affixes the item may have. This must be nonzero to get any magic items. Can be an integer or a boostedDie formula. The 'normal' template specifies -1+d2 which means a 50% chance of one affix.
  • magicLevel - this is the level at which affixes are generated. It defaults to itemLevel, but can be specified separately here, as an integer or boostedDie.
  • minAffixLevel - this is the minimum quality level of any affix that can be applied (defaults to the lowest level)
  • maxAffixLevel - this is the maximum quality level (defaults to the highest level)
  • affixType - this limits the affixes that can be in the allocation table for the item, above and beyond the itemType limitations of individual affixes. It's a dictionary like the itemType ones, where the keys are affix types (make, material, quality etc.) and the values are lists of affixes of those types. Again you can use "all" or "all except" to keep lists short. Note that this will not override the affixes' own itemType limitations: if the affixes Sharp and Keen are in this dict but the item chosen is a hat, they won't be available to it, because that would be silly.
  • affixLimits - this overrides the global minima and maxima for this template, allowing you to have more (or fewer) than the usual number of affixes of any given type or level.

The loot template 'boosts' can change any of the numerical values: itemLevel, magicLevel, numAffixes. (Although minAffixLevel and maxAffixLevel are specified as words for ease of use, they are translated into numerical ranks and can therefore be boosted.) Boosts are lists of pairs, where a pair is the chance of a boost and the amount of the boost (which can be a boostedDie). The chance can be a formula that includes itemLevel, which approximates the v4 system of making more and better affixes more likely at higher itemLevels. (In fact the evaluator can process any variable, but itemLevel is the only one that makes any sense to use.)

Themes

Once an item receives two or more affixes, it has a chance of acquiring a theme. Themes are basically collections of affixes which make flavourful sense together, resulting in items like Defenders or Holy Avengers. Themed items will have more affixes than non-themed items of the same magicLevel, but they're predetermined - and once a theme is acquired, no further affixes can be applied. Themes are described in object_theme.txt.

Themes are chosen using an allocation table system like items and affixes, and like affixes they have allocation rules which specify the min and max depths at which they can be applied, and the allowed items. But unlike items and affixes, they have no set commonness. The commonness value that goes into the allocation table is calculated according to how many of the theme's affixes are already on the item. If it has fewer than two, it is not eligible for that theme at all. If it has two or more, we look at the 'weighting' given to each affix (because some affixes are more important to a theme than others - Holy Avengers without slays are nothing, yet you might not notice the lack of a sustain).

The formula for theme commonness is (c * x^2) / (y * k). This looks complicated, but it's not really, and it achieves a lot.

  • x is the total weighting of all the relevant affixes on the item (itemWeight).
  • y is the total weighting of all the affixes germane to the theme (themeWeight).
  • c is a constant. It is the percentage chance of obtaining the theme if it's the only one in the allocation table. (Unlike item and affix allocation, theme allocation does not always return a theme, even if the allocation table is non-empty. Themes are rare.)
  • k is a constant. It is the themeWeight which would result in a c% chance of obtaining the theme if all required affixes are present (itemWeight == themeWeight).

The constant c defaults to 100 but can be modified in the loot template. k is set at a value of 25. There is little point allowing this to be modified, as it merely calibrates the weightings in object_theme.txt, it doesn't of itself play a part in the generation probability. This means that if a theme's affix weightings add up to less than 25, the theme might not be applied even if they're all present (this is not a desired outcome in flavour terms, but wouldn't affect gameplay). If they add up to more than 25, the likelihood of the theme being applied will hit 100% before all the affixes are on the item (this is probably fine for themes with lots of affixes). Note that rare themes have a "Null" affix whose weighting serves to reduce the chances of it occurring (as it cannot be obtained, so its weighting is always in y but never in x).

A check for a theme is made every time an affix is added (apart from the first). There are three values in the lootTemplate which affect themes:

  • theme - this is the name of a theme that will automatically be applied to the item (and will therefore curtail any further modification). Obviously useful only for specific drops (e.g. if we decide that Azog will always carry a weapon of *slay troll*).
  • themes - this is a list of themes which can be allowed in the allocation table. (Can use "all except" to keep it short.)
  • themeChance - this is the percentage modifier to the chance of obtaining a lone theme in an allocation table - it's the constant 'c' above.

Once a theme is returned from the allocation table, any affixes which are not already on the item are applied, if they pass their chance roll. This chance is usually 100%, but lower chances allow for some variation in themed items - so the chance of a sustain on a holy avenger might be only 50%, but there might also be a chance of an extra hit/dam boost. Once all the theme's affixes are applied (or not), item generation is finished.

Artifacts

These are of course the most powerful items of all, but as far as pyrel is aware, they're just like any other base item. They are subject to the same itemType filter in the loot template, and they have the same minDepth / maxDepth / commonness rules which govern their appearance in the allocation table. The only difference is a check to see whether they've already been created, in which case they can't be picked again.

Pyrel generates artifacts directly, without generating a base item first. This means that there is no need for "INSTA_ART" items which have no non-artifact versions. So there is no need to put the likes of the Phial, Star and Arkenstone into object.txt. It also means that Doomcaller can still be called a Blade of Chaos even though there is no longer any base item of that name. (At the moment. This may change as we now have to match artifact subtypes with those of base items, for the filtering to work, unless we also change name handling.)

Once an artifact is generated, it cannot receive any affixes or theme. Note that although all artifact stats are fixed in V, pyrel allows for random stats. So if you want to make Soulkeeper's AC vary according to 50+4d5M20, you can.

Note that you can specify a particular artifact by name in a loot template with the "artifact" key, though of course it can only be used once. This is useful only for specific monster drops (e.g. Morgoth).

At the moment we use the loot template's artifactChance field to scale the commonness of artifacts in the allocation table by a percentage, which works the same way as themeChance. Derakon wishes to achieve this by procs though, so it will change.

Item naming

Affixes and themes are either prefixes or suffices. Artifact names are always suffices. A theme will always feature in the object's name. If an item has more than one affix in the same position and no theme in that position, we look up the "genus" of each affix as defined in object_affix.txt. The most common genus is used for that part of the name. If no two affixes have the same genus, the name of the last affix to be applied is used.

Pyrel currently uses the same article and pluralisation conventions as V: & denotes the position of the article, and ~ that of the plural. Artifacts have "The" hard-coded into their names, as they are the only unique items in the game. (This may change.)

Monster drops

All the monster drop flags in V (think of DROP_FOO, ONLY_GOLD, ONLY_ITEM etc.) have been replaced by loot templates. These are listed in the monster record as its "drops" field, which is a list of loot templates. There are three final loot template fields which are relevant to drops:

  • templates - this is a list of templates to inherit from loot_template.txt, to save specifying more than necessary
  • numDrops - this is the number of items to be dropped using this template
  • dropChance - this is the chance of a drop using this template (defaults to 100%, so usually used in conjunction with numDrops = 1)

So there you go

So that's how it works. Loot templates can do anything. A "food" template could specify that only mushrooms, rations and potions will be allowed in the allocation table. An "orc lair" template specifies that only certain types of Orcish armour and weapons can be generated, and most will have bad or average affixes (always including "Orcish"). Templates also affect the chances of items becoming themed or artifacts.

Most monsters will use the normal (/good/great) template most of the time, but some will use others too (e.g. a spellbook template for casters). You'll be able to put local overrides to a template into particular monster drop profiles - so an archmage will never drop Magic For Beginners.

Dungeon floor items will also use the same system, and will also be able to override template values - so an orc lair at dl99 will have significantly better quality items than the standard orc lair template, while sticking to the same types ... it will presumably have tougher orcs too ...

The basic issue is that rarity in pyrel is relative - it depends what else is in the allocation table - i.e. what else can be generated at this depth. We'll use stats to tune the overall appearance of things.

What's left

There are a few things that loot templates can't yet do:

  • they can't alter the commonness of some items relative to others - so you can't allow all items but ensure that priestly items (prayer books, blunt/blessed weapons, Holy Avengers) are more likely to drop than without a template. You can do this by setting up two parallel templates (one normal one and one of priestly items) and adjusting dropChance in each, but that's not quite perfect because ...
  • ... they can't handle conditional drops: if we've dropped X then don't drop Y, or increase the prob of dropping Z.
  • they can't change the commonness of some but not all artifacts, other than by using the multiple-drop method above.

Derakon says all these are achievable with procs.

Other than those refinements to loot template operation, there are some more basic to-dos:

4. Write a stats generator for testing large-scale item generation (should be the foundation of a full stats framework). Myshkin is working on this.

5. Write a nice item tweaker UI that offers a menu of tweaks like re-roll, add or remove valid affixes, add or remove any affixes, edit stats directly, etc. Noz is working on this.

6a. Write the monsterPower algorithm for rating the deadliness of monsters. This is a necessary precursor to objectPower.

6b. Write the objectPower algorithm, and implement some sort of power checking. This could be UnAngband style, where we limit object power in proportion with itemLevel, or we could just have a hard cap as in V/v4 and let the RNG rule below that. At the moment we have no way of capping an item's power (which could be fine, if we balance the generator properly!)

11. Implement randarts. Artifact records have a "randomize" field, which is set to False for Morgoth's artifacts and for the artifact spellbooks. It defaults to True in all other cases.

13. Shrink the data files by using templates for commonly-occurring values in affixes and themes - such as "all weapons"

Updated