Site Tools


dev:adding_a_new_flag

Adding a new flag

Overview

Even before making any modifications to the randomisation logic itself, there are a few things that need to be done to have generation recognise your new flag and make it available for use in any logic updates. The most important of these is flagspec.txt, although you will also likely want to update uispec.txt to make the new flag available on the website.

flagspec.txt

flagspec.txt, present in the FreeEnt directory, sets out the schema for flag strings. There are three major sections to flagspec.txt - SPEC, IMPLICIT, and SLUGS.

SPEC

Each line in SPEC contains a list of (usually) related flags as they appear in the flag string. As an example, here is the single line showing the K flags:

Kvanilla Kmain Ksummon Kmoon Kmiab Knofree Kunsafe Kforce:magma/Kforce:hook

The / indicates flags that are directly mutually exclusive.

“Numeric” flags are sets of separate internal flags; as an example of this, here is one of the sets of C flags:

Cj:spells Cj:abilities Cnekkie Cnodupes Cparty:1/Cparty:2/Cparty:3/Cparty:4 Cbye Cpermajoin Cpermadeath/Cpermadeader Chero

We can see that Cparty is actually four separate flags.

Objective specs

Note that SPEC contains an AUTO_OBJECTIVES subsection which maps conventional objectives to each of the O1: through O8: flagsets. This section is automatically generated from the separate objective_spec.txt by the usual process of updating autogenerated files documented below. In most cases you won't have to worry about this, particularly since “mode” objectives are handled largely separately from this file (except in cases where the objective doesn't line up with an already extant objective, as you can see from the internal_dkmatter objective present in objective_spec.txt for Omode:dkmatter purposes).

IMPLICIT

IMPLICIT specifies additional flag logic, usually indicating that certain flags cannot be active when certain flags are specified. As an example, here is a line related to Tvanilla:

Tvanilla : ~Tshuffle & ~Tstandard & ~Tpro & ~Twild & ~Twildish & ~Tempty

The ~ indicates “not”, and the & indicates “and”; the above line therefore specifies that if Tvanilla is active that none of Tshuffle, Tstandard, Tpro, Twild, Twildish, or Tempty can be active.

Regular expressions are also supported to an extent, per the O and G lines which are respectively:

Onone    : ~/^O(mode|\d+|random):/
Gnone    : ~/^G(?!none)/

respectively indicating that if Onone is active that no Omode or Orandom can be active and that if Gnone is active that no other G flags can be active.

SLUGS

SLUGS maps flag string names to their respective identifiers in the randomiser code. As an example, here is the line for Omode:classicforge:

Omode:classicforge objective_mode_classicforge

This indicates that if the Omode:classicforge flag is set then this will be indicated by env.options.flags containing objective_mode_classicforge and also allowing the flag to be checked by that name in f4c scripts. Here is an example from adamant.f4c:

//%flag objective_mode_classicforge on%
text(map #SmithyHouseMainFloor message $05) {
It's done!



__I'm gonna keep it.
}
//%end%

And one from core_rando.py:

        if env.options.flags.has('objective_mode_classicforge'):
            keyitem_assigner.item_tier(3).append(ItemReward('#item.Excalibur'))

flagsetcore.py

flagsetcore.py (in the FreeEnt directory) contains much of the logic for parsing flagsets; it is of particular interest here because of the fix function which contains additional logic that cannot be captured by flagspec.txt. To illustrate, here are the first two such checks in fix:

        if flagset.has_any('Ksummon', 'Kmoon', 'Kmiab') and not flagset.has('Kmain'):
            flagset.set('Kmain')
            self._lib.push(log, ['correction', 'Advanced key item randomizations are enabled; forced to add Kmain'])

        if flagset.has('Kvanilla'):
            self._simple_disable(flagset, log, 'Key items not randomized', ['Kunsafe'])

If your flag has advanced interactions with other flags, you will need to incorporate that here.

uispec.txt

uispec.txt (in the FreeEnt/server directory) specifies how your flag is displayed on the website. As an example, here is the KEY ITEMS section:

== KEY ITEMS
<>* Key Items
.[Kvanilla]- No key item randomization
..[Knofree]! No free key item in Toroia
.[Kmain] Randomize key items
..[Ksummon]! Mix with summon quest rewards
..[Kmoon]! Mix with moon boss rewards
..[Kmiab]! Mix with monster-in-a-box chests
..[Knofree]! No free key item in Toroia
..<> Underworld access
...(Kforce:magma) Guarantee underworld access via Magma Key
...(Kforce:hook)! Force underworld access via Hook route
..[Kunsafe]! No safety checks

The . indicates level of indentation; indented items appear as a dropdown below their parent item. <> indicates a section or subsection that is not itself a flag. [] maps a line to its associated flag as an individually selectable item. () at the same level of indentation indicates mutually exclusive flags. ! indicates a red (dangerous) flag.

uispec_flagdescriptions.txt

uispec_flagdescriptions.txt (in the FreeEnt/server directory) maps flag names to their descriptions on the website.

Updating the autogenerated files

You may notice that just updating all of the above files is insufficient to have the generator and website recognise your new flag. This is because they depend upon information that is compiled / transpiled from these files as opposed to the files directly.

For convenience, there is a compile_all_specs.bat (Windows) / compile_all_specs.sh (other operating systems) script available that runs all of the steps necessary to update the compiled files from the base specs. Once you've made all of the changes you need to the above files, simply run this script to make your flag available on the website and to the generator.

dev/adding_a_new_flag.txt · Last modified: 2024/05/30 02:09 by sgrunt