Difficulty scaling: Difference between revisions

From ZeldaMods (Breath of the Wild)
Jump to navigation Jump to search
(Marked this version for translation)
(Detailing probability and effect of each modifier. I calculated these odds from the algorithm and had them verified through in-game testing.)
Line 54: Line 54:
Note: Weapons that are bought from a shop cannot receive modifiers because they do not fit into any of the above cases.
Note: Weapons that are bought from a shop cannot receive modifiers because they do not fit into any of the above cases.


== Weapon bonuses == <!--T:275-->  
== Weapon modifiers == <!--T:275-->  


<!--T:276-->
<!--T:276-->
Line 62: Line 62:
There are two bonus tiers in the game: one for low-level types (which appear in blue/white in the game UI) and another for high-level types (yellow). Those that belong to the Yellow tier are usually superior to the other ones. For instance, ''Attack Up +'' is the superior variant of ''Attack Up'' and it typically grants a higher attack power boost compared to ''Attack Up''.
There are two bonus tiers in the game: one for low-level types (which appear in blue/white in the game UI) and another for high-level types (yellow). Those that belong to the Yellow tier are usually superior to the other ones. For instance, ''Attack Up +'' is the superior variant of ''Attack Up'' and it typically grants a higher attack power boost compared to ''Attack Up''.


=== Bonus types === <!--T:277-->  
=== Modifier types === <!--T:277-->


<!--T:278-->
<!--T:278-->
Weapon bonuses (e.g. Durability Up, Attack Up) are entirely random. Each bonus has equal probability.
Which modifier a weapon receives is random each time Link obtains it. Which modifiers a weapon can possibly have is specific for each in [[ActorParam/GeneralParamList]], and is based on the weapon's type and the modifier tier. Note that certain modifiers can only appear at certain tiers— in particular, this means once a weapon is scaled to yellow modifiers, it can no longer receive the Critical Hit buff.
 
The odds for each type of modifier is determined by an algorithm in actWeapon which depends on the possible modifiers for a given weapon at a given tier. As such, this algorithm yields the following odds for different types of weapons:
</translate>
</translate>
 
{|class="wikitable" style="text-align: center;"
{|class="wikitable"
! rowspan=2|Weapon !! rowspan=2|Modifier Tier !! AddAtk !! AddLife !! AddCrit !! AddGuard !! AddThrow !! AddSpreadFire !! AddZoomRapid !! AddRapidFire !! AddSurfMaster
! <translate><!--T:279--> Bonus</translate> !! <translate><!--T:280--> Available in bonus tiers</translate>
|-
|-
| <translate><!--T:281--> Attack Up</translate> || <translate><!--T:283--> Durability Up</translate> || <translate><!--T:295--> Critical Hit</translate> || <translate><!--T:293--> Shield Guard Up</translate> || <translate><!--T:285--> Long Throw</translate> || <translate><!--T:287--> 5-Shot Burst</translate> || <translate><!--T:297--> ''Unused''<sup>[[#Notes|[a] ]]</sup></translate> || <translate><!--T:289--> Quick Shot</translate> || ''Unused''<sup>[[#Notes|[b] ]]</sup>
|-
|-
| <translate><!--T:281--> Attack up</translate> || <translate><!--T:282--> Blue/White and Yellow</translate>
| Sword || White/Blue || 25% || 33.3̅3̅%|| 41.6̅6̅% || - || - || - || - || - || -
|-
|-
| <translate><!--T:283--> Durability up</translate> || <translate><!--T:284--> Blue/White and Yellow</translate>
| Sword || Yellow || 25% || 33.3̅3̅% || - || - || 41.6̅6̅% || - || - || - || -
|-
|-
| <translate><!--T:285--> Long throw</translate> || <translate><!--T:286--> Yellow</translate>
| Shield || White/Blue || - || 50% || - || 50%<sup>[[#Notes|[c] ]]</sup> || - || - || - || - || -
|-
|-
| <translate><!--T:287--> Multi-shot burst (bows)</translate> || <translate><!--T:288--> Yellow</translate>
| Shield || Yellow || - || 50% || - || 50%<sup>[c]</sup> || - || - || - || - || -
|-
|-
| <translate><!--T:289--> Quick shot (bows)</translate> || <translate><!--T:290--> Yellow</translate>
| Bow || White/Blue || 50% || 50% || - || - || - || - || - || - || -
|-
|-
| <translate><!--T:291--> AddSurfMaster</translate> || <translate><!--T:292--> Yellow</translate>
| Normal Bow || Yellow || 25% || 33.3̅3̅% || - || - || - || - || - || 41.6̅6̅% || -
|-
|-
| <translate><!--T:293--> Shield guard up</translate> || <translate><!--T:294--> Blue/White and Yellow</translate>
| Multi-Shot Bow<sup>[[#Notes|[d] ]]</sup> || Yellow || 12.5% || 22.2̅2̅% || - || - || - || 29.16̅% || - || 36.1̅1̅% || -
|-
|-
| <translate><!--T:295--> Critical Hit</translate> || <translate><!--T:296--> Blue/White</translate>
|-
| <translate><!--T:297--> ZoomRapid</translate> || <translate><!--T:298--> Yellow</translate>
|}
|}


<translate>
<translate>
<!--T:299-->
==== Notes ==== <!--T:299-->
Notes:
* <small>[a]</small> AddSurfMaster is a bonus that only applies to shields and gives them a lower friction for shield surfing. That bonus type is unused in the game.
* "Critical Hit" can only be selected if weaponCommonSharpWeaponAddCrit is true ''and'' if the weapon modifier tier is Blue/White. This means that it becomes impossible to get a weapon with a Critical Hit bonus after enough enemies have been killed.
* <small>[b]</small> AddZoomRapid is another unused bonus that gives bows a zoom when aimed, similar to the property inherent to the Golden and Phrenic Bows.
* AddSurfMaster is a bonus that only applies to shields and gives them a lower friction for shield surfing. That bonus type is unused in the game.
* <small>[c]</small> Due to a bug, if "Shield Guard Up" is rolled for an amiibo weapon, "Durability Up" will be applied instead.<ref name="amiiboShield">The bugged code is in function {{addr|a=0x71002df7d8|ver=nx-1.5.0}}.</ref>
* <small>[d]</small> These are for bows which can have the 5-Shot Burst modifier, which are the Forest Dweller's Bow, Mighty Lynel Bow, and the Savage Lynel Bow. (Despite shooting 2 arrows, the Duplex Bow cannot have this modifier.)


<!--T:397-->
=== Modifier values === <!--T:300-->  
'''"Shield Guard Up" does not appear for amiibo weapons because of a game bug.'''
 
=== Bonus values === <!--T:300-->  


<!--T:301-->
<!--T:301-->
Bonus values (e.g. the durability or attack power increase) are determined from [[ActorParam/GeneralParamList]] (with a copy of the information in [[ActorInfoData]]). Valid ranges and bonuses for each weapon are configured in the WeaponCommon section.
Bonus values (e.g. the actual durability or attack power increase) are determined from [[ActorParam/GeneralParamList]] (with a copy of the information in [[ActorInfoData]]). Valid ranges and bonuses for each weapon are configured in the WeaponCommon section. The possible values for a bonus are generally higher for a yellow tier.
 
==== amiibo ==== <!--T:302-->
 
<!--T:398-->
Because of a bug in the game code<ref>The bugged code is in function {{addr|a=0x71002df7d8|ver=nx-1.5.0}}.</ref>, any time the game randomly chooses the "Shield Guard Up" bonus, the actual bonus that gets assigned to the weapon and shows up in the user interface is "Durability Up". For this reason, the extra durability value that is used for shields with the "Durability Up" bonus is either addLifeMax or addGuardMax, depending on which bonus was chosen.


==== Non-amiibo weapons ==== <!--T:315-->
</translate>
</translate>
{|class="wikitable"
{|class="wikitable" style="text-align: center;"
! <translate><!--T:303--> Bonus</translate> !! <translate><!--T:304--> Value that is used for the bonus effect</translate>
! <translate><!--T:316--> Modifier chosen</translate> !! Effect if applied !! Bonus Value (White/Blue) !! Bonus Value (Yellow)
|-
| <translate><!--T:318--> None</translate> || - || - || -
|-
|-
| <translate><!--T:305--> None</translate> || -
| <translate><!--T:319--> Attack Up</translate> || Attack value boosted by: || Random integer between [SharpWeaponAddAtkMin, SharpWeaponAddAtkMax] || Random integer between [PoweredSharpAddAtkMin, PoweredSharpAddAtkMax]
|-
|-
| <translate><!--T:306--> Attack up</translate> || addAtkMax
| <translate><!--T:321--> Durability Up</translate> || Durability value boosted by: || Random integer between [SharpWeaponAddLifeMin, SharpWeaponAddLifeMax] || Random integer between [PoweredSharpAddLifeMin, PoweredSharpAddLifeMax]
|-
|-
| <translate><!--T:307--> Durability up</translate> || addLifeMax or addGuardMax
| Critical Hit || Last hit of a chain does double damage/staggers enemies || - || N/A
|-
|-
| <translate><!--T:308--> Long throw</translate> || addThrowMax
| <translate><!--T:331--> Shield Guard Up</translate> || Shield guard value boosted by: || Random integer between [SharpWeaponAddGuardMin, SharpWeaponAddGuardMax] || Random integer between [PoweredSharpWeaponAddGuardMin, PoweredSharpWeaponAddGuardMax]
|-
|-
| <translate><!--T:309--> Multi-shot burst (bows)</translate> || <translate><!--T:310--> 5-shot burst</translate>
| <translate><!--T:323--> Long Throw</translate> || Throw distance multiplied by: || - || Random float between [PoweredSharpAddThrowMin, PoweredSharpAddThrowMax]
|-
|-
| <translate><!--T:311--> Quick shot (bows)</translate> || addRapidFireMin
| <translate><!--T:325--> Multi-Shot Burst</translate> || Bow shoots multiple arrows: || - || 5
|-
|-
| <translate><!--T:312--> AddSurfMaster</translate> || [[bgparamlist#Global|GlobalParameter]]::shieldSurfMasterFrictionRatio
| ''AddZoomRapid'' || Reticle zooms when aiming || - || Unknown {{check}}
|-
|-
| <translate><!--T:313--> Shield guard up</translate> || addGuardMax
| <translate><!--T:327--> Quick Shot</translate> || Firing rate multiplied by: || - || Random float between [PoweredSharpAddRapidFireMin, PoweredSharpAddRapidFireMax]
|-
| <translate><!--T:329--> ''AddSurfMaster''</translate> || Shield surfing friction multiplied by: || - || 0.2 (from [[GlobalParameter]]::ShieldSurfMasterFrictionRatio)
|}
|}


<translate>
<translate>
<!--T:314-->
<!--T:333-->
In summary, for amiibo weapons, an attack up always brings it to the greatest possible attack power.
In summary, for non-amiibo weapons, a modifier bonus results in a randomized additional value in a certain range for each item.
No randomness is involved.
 
==== amiibo weapons ==== <!--T:302-->


==== Non-amiibo ==== <!--T:315-->  
<!--T:398-->
Because of a bug in the game code<ref name="amiiboShield"></ref>, any time the game randomly chooses the "Shield Guard Up" bonus, the actual bonus that gets assigned to the weapon and shows up in the user interface is "Durability Up". For this reason, the extra durability value that is used for shields with the "Durability Up" bonus is either addLifeMax or addGuardMax, depending on which bonus was chosen.
</translate>
</translate>


{|class="wikitable"
{|class="wikitable" style="text-align: center;"
! <translate><!--T:316--> Bonus</translate> !! <translate><!--T:317--> Value that is used for the bonus effect</translate>
! <translate><!--T:303--> Modifier chosen</translate> !! Effect if applied !! Bonus Value (White/Blue) !! Bonus Value (Yellow)
|-
| <translate><!--T:305--> None</translate> || - || - || -
|-
| <translate><!--T:306--> Attack Up</translate> || Attack value boosted by: || SharpWeaponAddAtkMax || PoweredSharpAddAtkMax
|-
|-
| <translate><!--T:318--> None</translate> || -
| <translate><!--T:307--> Durability Up</translate> || Durability value boosted by: || SharpWeaponAddLifeMax || PoweredSharpAddLifeMax
|-
|-
| <translate><!--T:319--> Attack up</translate> || <translate><!--T:320--> Random integer between addAtkMin and addAtkMax</translate>
| Critical Hit || Last hit of a chain does double damage/staggers enemies || - || N/A
|-
|-
| <translate><!--T:321--> Durability up</translate> || <translate><!--T:322--> Random integer between addLifeMin and addLifeMax</translate>
| <translate><!--T:313--> Shield Guard Up</translate> || '''Durability''' value boosted by: || SharpWeaponAddGuardMax || PoweredSharpWeaponAddGuardMax
|-
|-
| <translate><!--T:323--> Long throw</translate> || <translate><!--T:324--> Random float between addThrowMin and addThrowMax</translate>
| <translate><!--T:308--> Long Throw</translate> || Throw distance multiplied by: || - ||  PoweredSharpAddThrowMax
|-
|-
| <translate><!--T:325--> Multi-shot burst (bows)</translate> || <translate><!--T:326--> 5-shot burst</translate>
| <translate><!--T:309--> Multi-Shot Burst</translate> || Bow shoots multiple arrows: || - || 5
|-
|-
| <translate><!--T:327--> Quick shot (bows)</translate> || <translate><!--T:328--> Random float between addRapidFireMin and addRapidFireMax</translate>
| ''AddZoomRapid'' || Reticle zooms when aiming || - || Unknown {{check}}
|-
|-
| <translate><!--T:329--> AddSurfMaster</translate> || <translate><!--T:330--> [[bgparamlist#Global|GlobalParameter]]::shieldSurfMasterFrictionRatio</translate>
| <translate><!--T:311--> Quick Shot</translate> || Firing rate multiplied by: || - || PoweredSharpAddRapidFireMin
|-
|-
| <translate><!--T:331--> Shield guard up</translate> || <translate><!--T:332--> Random integer between addGuardMin and addGuardMax</translate>
| <translate><!--T:312--> ''AddSurfMaster''</translate> || Shield surfing friction multiplied by: || - || 0.2 (from [[GlobalParameter]]::ShieldSurfMasterFrictionRatio)
|}
|}


<translate>
<translate>
<!--T:333-->
<!--T:314-->
In summary, for non-amiibo weapons, an attack up results in a randomized attack power.
In summary, for amiibo weapons, a modifier always yields the highest possible value for that weapon as a bonus, except Quick Shot, which will use the ''lowest'' value.
No randomness is involved, aside from whether the Durability Up bonus comes from the AddLifeMax or AddGuardMax value.


== Enemies == <!--T:334-->  
== Enemies == <!--T:334-->  

Revision as of 02:44, 3 February 2023

Other languages:

Difficulty scaling is a mechanic in Breath of the Wild that results in enemies and weapons being progressively replaced by more powerful variants during a playthrough.

Points

The scaling system is based on a point system. Killing enemies is the only way to receive points.

Whenever an enemy dies, the game increments a flag 'Defeated_{SameGroupActorName}_Num' if all of the following conditions are satisfied:

  • The current kill count is < 10.
  • The actor does not have the NotCountDefeatedNum actor tag.
  • For Monk Maz Koshia: 'Defeated_Priest_Boss_Normal_Num' is 0.
  • For Dark Beast Ganon: It is the first time the boss is beaten. (Ganon's Defeated flag has 1 as the maximum value.)
  • For Blights: It is the first time the blight is beaten in the Divine Beast, or in the Illusory Realm. Blights fought in Hyrule Castle do not count.

This happens every time any enemy dies, even if they don't necessarily play a role in the point system (see below) and even if the player is not responsible for their death.

Because enemies have to be killed throughout the main quest and bosses are considered as enemies too, difficulty scaling is unavoidable.

Only the defeated counter flags are stored in the save file. The Ecosystem::LevelSensor subsystem is responsible for converting these kill counts to points using a configuration file.

The subsystem provides two functions (scaleWeapon and scaleActor) that may be called when a weapon or enemy actor is created.

Scaling inhibitors

Both scaling functions will immediately return without doing anything if:

  • WorldMgr::sInstance->stageType == 1 (Open World stage)
  • and WorldMgr::sInstance->isAocField (current map is Trial of the Sword)
  • and WorldMgr::sInstance->disableScaling (set to true when entering Trial of the Sword)

This means that scaling is always disabled in the Trial of the Sword.

Scaling will also be skipped if the current map area is 28. This corresponds to "HateruSea", which is the Eventide Island area.

Weapons

'scaleWeapon' is called (i.e. weapons may be scaled) for a weapon if:

  • For standalone weapons: The actor property 'LevelSensorMode' is higher than 1 and it wasn't already picked up.
  • For treasure chest drops: If SharpWeaponJudgeType is not 4, when AIDef:AI/TreasureBox initialises the drop actor.
  • For Hinox weapons: The flag {MapName}_Necklace_{i}_{HinoxName}_{ID} is false.
  • For other enemy drops: The flag {MapName}_WeaponDrop_{ID} is false, and [the actor property 'LevelSensorMode' is higher than 1 or the enemy is a Guardian Scout ('Enemy_Guardian_Mini')].

Note: Weapons that are bought from a shop cannot receive modifiers because they do not fit into any of the above cases.

Weapon modifiers

Weapon scaling results in weapons being replaced by a different weapon (e.g. a Soldier's Bow which becomes a Royal Bow), or weapons gaining a random, bonus stat boost (e.g. Attack Up, Durability Up, etc.). The range of those boosts is also affected by weapon scaling.

There are two bonus tiers in the game: one for low-level types (which appear in blue/white in the game UI) and another for high-level types (yellow). Those that belong to the Yellow tier are usually superior to the other ones. For instance, Attack Up + is the superior variant of Attack Up and it typically grants a higher attack power boost compared to Attack Up.

Modifier types

Which modifier a weapon receives is random each time Link obtains it. Which modifiers a weapon can possibly have is specific for each in bgparamlist, and is based on the weapon's type and the modifier tier. Note that certain modifiers can only appear at certain tiers— in particular, this means once a weapon is scaled to yellow modifiers, it can no longer receive the Critical Hit buff.

The odds for each type of modifier is determined by an algorithm in actWeapon which depends on the possible modifiers for a given weapon at a given tier. As such, this algorithm yields the following odds for different types of weapons:

Weapon Modifier Tier AddAtk AddLife AddCrit AddGuard AddThrow AddSpreadFire AddZoomRapid AddRapidFire AddSurfMaster
Attack Up Durability Up Critical Hit Shield Guard Up Long Throw 5-Shot Burst Unused[a] Quick Shot Unused[b]
Sword White/Blue 25% 33.3̅3̅% 41.6̅6̅% - - - - - -
Sword Yellow 25% 33.3̅3̅% - - 41.6̅6̅% - - - -
Shield White/Blue - 50% - 50%[c] - - - - -
Shield Yellow - 50% - 50%[c] - - - - -
Bow White/Blue 50% 50% - - - - - - -
Normal Bow Yellow 25% 33.3̅3̅% - - - - - 41.6̅6̅% -
Multi-Shot Bow[d] Yellow 12.5% 22.2̅2̅% - - - 29.16̅% - 36.1̅1̅% -

Notes

  • [a] AddSurfMaster is a bonus that only applies to shields and gives them a lower friction for shield surfing. That bonus type is unused in the game.
  • [b] AddZoomRapid is another unused bonus that gives bows a zoom when aimed, similar to the property inherent to the Golden and Phrenic Bows.
  • [c] Due to a bug, if "Shield Guard Up" is rolled for an amiibo weapon, "Durability Up" will be applied instead.[1]
  • [d] These are for bows which can have the 5-Shot Burst modifier, which are the Forest Dweller's Bow, Mighty Lynel Bow, and the Savage Lynel Bow. (Despite shooting 2 arrows, the Duplex Bow cannot have this modifier.)

Modifier values

Bonus values (e.g. the actual durability or attack power increase) are determined from bgparamlist (with a copy of the information in ActorInfoData). Valid ranges and bonuses for each weapon are configured in the WeaponCommon section. The possible values for a bonus are generally higher for a yellow tier.

Non-amiibo weapons

Modifier chosen Effect if applied Bonus Value (White/Blue) Bonus Value (Yellow)
None - - -
Attack Up Attack value boosted by: Random integer between [SharpWeaponAddAtkMin, SharpWeaponAddAtkMax] Random integer between [PoweredSharpAddAtkMin, PoweredSharpAddAtkMax]
Durability Up Durability value boosted by: Random integer between [SharpWeaponAddLifeMin, SharpWeaponAddLifeMax] Random integer between [PoweredSharpAddLifeMin, PoweredSharpAddLifeMax]
Critical Hit Last hit of a chain does double damage/staggers enemies - N/A
Shield Guard Up Shield guard value boosted by: Random integer between [SharpWeaponAddGuardMin, SharpWeaponAddGuardMax] Random integer between [PoweredSharpWeaponAddGuardMin, PoweredSharpWeaponAddGuardMax]
Long Throw Throw distance multiplied by: - Random float between [PoweredSharpAddThrowMin, PoweredSharpAddThrowMax]
Multi-Shot Burst Bow shoots multiple arrows: - 5
AddZoomRapid Reticle zooms when aiming - Unknown [check]
Quick Shot Firing rate multiplied by: - Random float between [PoweredSharpAddRapidFireMin, PoweredSharpAddRapidFireMax]
AddSurfMaster Shield surfing friction multiplied by: - 0.2 (from GlobalParameter::ShieldSurfMasterFrictionRatio)

In summary, for non-amiibo weapons, a modifier bonus results in a randomized additional value in a certain range for each item.

amiibo weapons

Because of a bug in the game code[1], any time the game randomly chooses the "Shield Guard Up" bonus, the actual bonus that gets assigned to the weapon and shows up in the user interface is "Durability Up". For this reason, the extra durability value that is used for shields with the "Durability Up" bonus is either addLifeMax or addGuardMax, depending on which bonus was chosen.

Modifier chosen Effect if applied Bonus Value (White/Blue) Bonus Value (Yellow)
None - - -
Attack Up Attack value boosted by: SharpWeaponAddAtkMax PoweredSharpAddAtkMax
Durability Up Durability value boosted by: SharpWeaponAddLifeMax PoweredSharpAddLifeMax
Critical Hit Last hit of a chain does double damage/staggers enemies - N/A
Shield Guard Up Durability value boosted by: SharpWeaponAddGuardMax PoweredSharpWeaponAddGuardMax
Long Throw Throw distance multiplied by: - PoweredSharpAddThrowMax
Multi-Shot Burst Bow shoots multiple arrows: - 5
AddZoomRapid Reticle zooms when aiming - Unknown [check]
Quick Shot Firing rate multiplied by: - PoweredSharpAddRapidFireMin
AddSurfMaster Shield surfing friction multiplied by: - 0.2 (from GlobalParameter::ShieldSurfMasterFrictionRatio)

In summary, for amiibo weapons, a modifier always yields the highest possible value for that weapon as a bonus, except Quick Shot, which will use the lowest value. No randomness is involved, aside from whether the Durability Up bonus comes from the AddLifeMax or AddGuardMax value.

Enemies

When loading enemies, the game will always try to scale enemies.

However, the scaling function won't do anything if 'LevelSensorMode' is < 1 and will leave the enemy and any weapons they may hold unscaled.

Note: Enemies that are not in any upgrade list (such as elemental Lizalfos) will not be scaled, but their weapon can still receive upgrades if:

  • 'LevelSensorMode' is non zero.
  • Weapon point requirements are satisfied
  • or the modifier tier is overridden using 'SharpWeaponJudgeType'.

[1.3.0] In Master Mode, all enemies are automatically ranked up one tier by default post scaling, independently of 'LevelSensorMode'. Actors can receive two additional parameters:

Parameter Default Description
IsHardModeActor false Controls whether an enemy only shows up in Master Mode.
DisableRankUpForHardMode false Controls whether the automatic rankup applies to an enemy.

In Master Mode, IsHardModeActor, DisableRankUpForHardMode and LevelSensorMode are combined on some actors to keep low-level enemies in the overworld (e.g. Red Bokoblin south of the Great Plateau).

Properties

LevelSensorMode

This actor property controls whether scaling is enabled for an enemy or weapon. Also applies to any weapons held by an enemy since 'scaleWeapon' is called when an enemy drops their weapon.

Note that this doesn't apply to weapons that are attached to a Hinox's necklace, because Hinoxes use a different underlying enemy actor which overrides the 'on weapon dropped' function and ignores 'LevelSensorMode'.

SharpWeaponJudgeType

This actor property controls the minimum modifier tier that a weapon can receive.

Internally and in assets such as map units, the following values are used for modifiers:

Value Description
0 None: No modifiers.
1 RandomBlue: Weapon will randomly get at least a blue modifier (with weaponCommonSharpWeaponPer being the probability).
2 Blue: Weapon will get at least a blue modifier.
3 Yellow: Weapon will get at least a yellow modifier.
4 NoneForced (chests only): Weapon will never spawn with any modifiers. This overrides regular scaling.

If scaling is enabled, the weapon may receive modifiers from an even higher tier if point requirements are met.

Otherwise, the weapon will get modifiers from exactly the specified tier.

For example, 0 ('None') doesn't mean a weapon will never receive a modifier. It just means that the developers haven't forced the weapon to spawn with a blue/yellow modifier. If scaling requirements are satisfied, the weapon will receive blue or yellow modifiers.

Scaling algorithm

Ecosystem::LevelSensor::loadByml

This function is called by Ecosystem::init from ksys::InitializeApp

Sets up byml structures for reading Ecosystem/LevelSensor.byml.

Ecosystem::LevelSensor::calculatePoints

Called by PlacementMgr when spawning actors.

Calculates weapon and enemy scaling points using a list of flags and configuration values.

All flags that are referenced in the configuration file are of the form Defeated_%s_Num, but technically the configuration format allows for other flags to be specified.

Interestingly, the game calculates a single point value based on the kill counter flags but calculates two separate values for weapons and enemies with two different multipliers. This format makes it possible to easily change the scaling.

float points = 0.0;
for (kill_flag : this->byml["flag"])
    int kill_count = GameData::getIntegerFlag(kill_flag["name"]);
    points += kill_count * kill_flag["point"];

this->points = points;
this->weapon_points = points * this->byml["setting"].Level2WeaponPower;
this->enemy_points = points * this->byml["setting"].Level2EnemyPower;

In practice, settings have never been modified. 1.5.0 (which will likely be the last game update) still has the same Level2WeaponPower and Level2EnemyPower.

Ecosystem::LevelSensor::scaleWeapon

Called from treasure chest code, enemy actors[check], Ecosystem::LevelSensor::scaleActor

Given a weapon name, its modifier and current point status, this function returns the weapon to actually spawn and the modifier to use (if possible).

If the algorithm fails to find an appropriate weapon that satisfies all conditions (point requirements, weapon series, modifier), the originally specified weapon and modifier will be used directly.

Pseudocode (1.0.0):

bool Ecosystem::LevelSensor::scaleWeapon(const sead::SafeString& weapon_to_look_up,
                                         WeaponModifier required_modifier,
                                         const char** weapon_to_use_name,
                                         WeaponModifier* modifier_to_use,
                                         void* unknown)
{
  // some checks using 'unknown' here which seems to be a pointer to the actor
  //
  for (weapon_table : this->byml["weapon"]) {
    // find the first weapon entry for which the player has enough points
    // with the specified name and modifier
    i = -1;
    for (j = 0; j < weapon_table["actors"].size; ++j) {
      entry = weapon_table["actors"][j];
      float points_for_next_transition = entry["value"];
      //
      if (this->weapon_points > points_for_next_transition &&
          weapon_to_look_up == entry["name"] &&
          convert_to_modifier(entry["plus"]) == required_modifier) {
        i = j;
        break;
      }
    }
    //
    if (i == -1)
      continue;
    //
    do {
      entry = weapon_table["actors"][i];
      //
      // not_rank_up means there is no link between weapons;
      // this table is just used to look up modifiers.
      // so go down the list until there are no more entries for the requested weapon
      // or until we reach a modifier that requires more points.
      if (weapon_table["not_rank_up"] && entry["name"] != weapon_to_look_up)
        break;
      //
      // otherwise, just go down the list until we reach the end or a weapon which
      // requires more points. this will possibly upgrade the weapon (e.g. Knight -> Royal).
      if (this->weapon_points <= entry["value"])
        break;
      //
      ++i;
    } while (i < weapon_table["actors"].size);
    //
    *weapon_to_use_name = entry["name"];
    *modifier_to_use = convert_to_modifier(entry["plus"]);
    return true;
  }
  return false;  // cannot scale up
}

Ecosystem::LevelSensor::scaleActor

Analogous to LevelSensor::scaleWeapon.

Pseudocode (1.0.0):

if (actor->params["LevelSensorMode"] < 1)
  return false;
//
if (actor_name.contains("Enemy")) {
  for (enemy_table : this->byml["enemy"]) {
    i = -1;
    for (j = 0; j < enemy_table["actors"].size; ++j) {
      entry = enemy_table["actors"][j];
      if (entry["name"] == actor_name && this->enemy_points > entry["value"]) {
        i = j;
        break;
      }
    }
    //
    if (i == -1)
      continue;
    //
    do {
      entry = enemy_table["actors"][i];
      if (this->enemy_points <= entry["value"])
        break;
      ++i;
    } while (i < enemy_table["actors"].size);
    //
    *actor_to_use = entry["name"];
    return true;
  }
  return false;  // cannot scale up
}
//
if (actor_name.contains("Weapon")) {
  weapon_name = actor->getWeaponName();
  modifier = actor->params["SharpWeaponJudgeType"];
  if (modifier == WeaponModifier::RandomBlue)
    modifier = get_random_blue_modifier(actor->getWeaponName());
  //
  if (scaleWeapon(weapon_name, &weapon_to_use, &modifier_to_use)) {
    actor->setProperty("SharpWeaponJudgeType", modifier_to_use);
    *actor_to_use = weapon_to_use;
    return true;
  }
  return false;  // cannot scale up
}

The Data

To make things easier to understand, here are links to:

This makes it possible to see both the required points for enemy/weapon upgrades, as well as all of the special cases extremely easily.

Ganon Blights

Ganon blights also have varying difficulty but follow a different system. Their health is determined by the base HP (set in bgparamlist) and blight defeat flags.

__int64 SiteBoss::getInitialHP(SiteBoss *this) // 0x71002D01F4
{
  const int baseHp = Enemy::getInitialHP(this);
  const int halfBaseHp = baseHp >> 1;
  const bool dieGanonWind = hasFlag_Die_PGanonWind(0);
  const bool dieGanonWater = hasFlag_Die_PGanonWater(0);
  const bool dieGanonFire = hasFlag_Die_PGanonFire(0);
  const bool dieGanonElectric = hasFlag_Die_PGanonElectric(0);
  const int flags = this->siteBossFlags & 0xFFFFFFFC;
  int multiplier;
  if ( flags == 4 )
    multiplier = 3;
  else if ( flags == 8 )
    multiplier = 4;
  else
    multiplier = dieGanonFire + dieGanonWind + dieGanonWater + dieGanonElectric;
  return baseHp + multiplier * halfBaseHp;
}

Effectively, this means that the first blight Link fights will have 800+0×400 = 800 HP, the second will have 800+1×400 = 1200 HP, the third 800+2×400 = 1600 HP and the last one 800+3×400 = 2000 HP.

Special case 1: Castle Blights

Castle blights have IsRemainBoss set to false in their root AI parameters (see AIDef:AI/SiteBossSpearRoot for example), which sets flag 4.

Thus, blights that are fought in the Castle always have 800+3×400 = 2000 HP regardless of story progression.

If flag 4 is set, the AIDef:Action/SiteBossDie code will NOT increment the "defeated" counter. This means castle blights do not give any scaling points.

Special case 2: DLC2 Blights

Illusory Realm blights possess the EnemySiteBoss_R actor tag. This causes flag 8 to be set. So they will always have 500+4×250 = 1500 HP.

Interestingly, the Windblight AI function doesn't check the actor tag but the actor name instead. For flag 8 to be set, the actor name must be Enemy_SiteBoss_Bow_R.


  1. 1.0 1.1 The bugged code is in function 0x71002df7d8 [nx-1.5.0 executable].