Part II · Artifacts & accessories
The numbers behind an artifact
Levels, ranks, formula strings, and the separate paths into descriptions and play.
3 min read
An artifact's level and rank feed arithmetic expressions stored as text. Those expressions supply descriptions and runtime values through separate paths. Understanding that distinction explains both ordinary progression and some surprisingly fragile behavior.
Level and rank are separate inputs
The formula variable level is the artifact's level. The variable stage is its cultivation rank. It is not the current world, wave, or Endless level.
All 38 artifacts refer to the same cultivation table. Level upgrades run from 1 through 29, producing a maximum level of 30. Rank upgrades require levels 10, 20, and 30, respectively. Buying rank 4 unlocks no further level in that table.11Ranks, levels, and the shared Endless counterArtifactInfo rank is the stage variable; level is separate. The shared cultivation table has level upgrades 1–29 and rank upgrades requiring levels 10, 20, and 30. The board stores one ArtifactData. Endless’s GetArtifactLeftTimes reads one manager int32, without an artifact key; localized rules describe carry-over and switching between levels. The per-artifact common-data use count and this Endless pool are separate quantities.0x1002736fc0x10026f7ac0x100f9c4a0
The rank requirements constrain which level/rank pairs normal progression produces. Evaluating a passive at an arbitrary lower level can produce a negative number even though that pair does not belong to the progression where the passive becomes available.
A decimal point changes the arithmetic
The formula engine supports addition, subtraction, multiplication, division, and parentheses. It substitutes integer values for level and stage, then evaluates the expression.
Its choice of numeric domain comes from the text: an expression without a decimal point uses signed integer arithmetic. With a decimal point, it uses floating-point arithmetic. Consequently, 2+level/ and 2.0+level/ can produce different values from the same level.22Display and runtime paths share arithmeticDisplay reads go through the bounds-checked field helper 0x10026fb5c, with a near-zero guard on the final MainField entry. The runtime helper 0x100272790 selects through 0x1002728a8, substitutes via 0x1002736fc, and calls the same arithmetic engine 0x10026e73c. That second array selector lacks the display helper’s element bounds check. Arithmetic uses signed integers when the converted expression has no dot and float32 otherwise. The broader display-only claim in the framework report is superseded by this runtime call chain.0x10026ec9c0x10026e73c0x10026fb5c0x1002727900x1002728a8
Bowling's 2+level/ gives 2 at levels 1–9, 3 at 10–19, 4 at 20–29, and 5 at 30. This stepwise behavior comes from integer division. A visually small edit to the formula's punctuation can change its numerical meaning.
2+level/10 in ink and 2.0+level/10 in green, at rank 1. Each value holds until the next level.2+level/10 → signed integer arithmetic · 2.0+level/10 → float32 arithmeticThe variable-replacement helper replaces only the first occurrence of each variable. Repeating a variable would leave unsupported text for the parser. The shipped expressions avoid that case, but the evaluator has no structured way to report malformed input to its caller.
Descriptions and runtime values take different routes
The display helper selects an expression with an element bounds check. It evaluates the string and applies a special adjustment to the last Main element: a value sufficiently close to zero becomes 1.
The runtime helper selects an expression through another function, substitutes the artifact's variables, and reaches the same arithmetic engine. That selector does not have the display helper's element bounds check. Sharing arithmetic does not mean sharing all the surrounding validation.
The last two Main entries conventionally contain cooldown and uses. Runtime common-data setup reads those positions, converts the use count, applies its own minimum behavior, and then passes through further adjustments. Cooldown and use-count boosts act later.33Two guards and later modifiersFor stage*1.0-1.0, rank 1 evaluates to zero. The description helper adjusts a near-zero final MainField value to 1; the runtime common-data path separately converts and changes values 0 and 1 to 1 before later rescaling and use-count boosts. Thus the bare expression does not establish a displayed zero. MainField’s preceding entry supplies the runtime cooldown, with a later cooldown boost.0x10026fde00x100272b180x100972c20
For stage*1., rank 1 gives a raw zero. The display adjustment turns it into 1; the runtime common-data path also turns zero into 1 before subsequent modifiers. The bare formula therefore does not support the claim that the description shows zero uses.
This distinction matters when reading the reference: a formula value, a displayed value, and a final runtime value are different steps in a calculation.
Endless has another use counter
A board holds one active artifact record. Ordinary Endless also has a use counter on its own manager. The getter reads a single integer, without an artifact id.
The mode's rules describe active uses as a shared total across artifacts, with switching between levels and passives continuing after the active total is exhausted. That shared total is a different quantity from the common-data count attached to an individual artifact.
A field named capacity can describe boost configuration rather than the number of artifacts on a board. Field names are useful navigation aids, but the type and reader establish what a value means.
Follow a field to its consumer
Evolution gives a useful example. Its Targetable list is read by passive-rate getters; its plant filters generated results. Neither name alone explains its role.
An entry can also be parsed and then never used. Evolution stores two duration-named passive fields that its class does not subsequently read. Its rank-4 behavior instead uses a fixed rank check and an empty-cell scan. Changing an unused number does not change that behavior.44Three separate passive pathsThe two rank-2 rate getters consult the 26-entry TargetablePlantTypes whitelist. The rank-3 timer advances one interval per due update and draws rows 0–4. Rank 4 scans empty cells before the deferred removals, selecting plants with Cost <= 100. Its level fold starts at 1 and takes a minimum, so ordinary positive packet levels cannot raise it. The report traces the rate getters; their callers into final plant statistics need separate attribution.0x1009a77280x1009a78c00x1009a75d00x1009a6d1c0x1009a90b0
The artifact reference keeps the formula fields and lists available for inspection. The Evolution article follows the consumers through a complete active skill.
Notes
The evidence behind each claim: the code path, and the native addresses where it was traced.
- 1
Ranks, levels, and the shared Endless counter
ArtifactInfo rank is the stage variable; level is separate. The shared cultivation table has level upgrades 1–29 and rank upgrades requiring levels 10, 20, and 30. The board stores one ArtifactData. Endless’s GetArtifactLeftTimes reads one manager int32, without an artifact key; localized rules describe carry-over and switching between levels. The per-artifact common-data use count and this Endless pool are separate quantities.
0x1002736fc0x10026f7ac0x100f9c4a0 - 2
Display and runtime paths share arithmetic
Display reads go through the bounds-checked field helper 0x10026fb5c, with a near-zero guard on the final MainField entry. The runtime helper 0x100272790 selects through 0x1002728a8, substitutes via 0x1002736fc, and calls the same arithmetic engine 0x10026e73c. That second array selector lacks the display helper’s element bounds check. Arithmetic uses signed integers when the converted expression has no dot and float32 otherwise. The broader display-only claim in the framework report is superseded by this runtime call chain.
0x10026ec9c0x10026e73c0x10026fb5c0x1002727900x1002728a8 - 3
Two guards and later modifiers
For stage*1.0-1.0, rank 1 evaluates to zero. The description helper adjusts a near-zero final MainField value to 1; the runtime common-data path separately converts and changes values 0 and 1 to 1 before later rescaling and use-count boosts. Thus the bare expression does not establish a displayed zero. MainField’s preceding entry supplies the runtime cooldown, with a later cooldown boost.
0x10026fde00x100272b180x100972c20 - 4
Three separate passive paths
The two rank-2 rate getters consult the 26-entry TargetablePlantTypes whitelist. The rank-3 timer advances one interval per due update and draws rows 0–4. Rank 4 scans empty cells before the deferred removals, selecting plants with Cost <= 100. Its level fold starts at 1 and takes a minimum, so ordinary positive packet levels cannot raise it. The report traces the rate getters; their callers into final plant statistics need separate attribution.
0x1009a77280x1009a78c00x1009a75d00x1009a6d1c0x1009a90b0