Difficulty scaling/fr: Difference between revisions

From ZeldaMods (Breath of the Wild)
Jump to navigation Jump to search
(Created page with "Visée rapide (arcs)")
(Created page with "<source lang="c++"> if (actor->params["LevelSensorMode"] < 1) return false; // if (actor_name.contains("Enemy")) { for (enemy_table : this->byml["enemy"]) { i = -1;...")
 
(116 intermediate revisions by 3 users not shown)
Line 10: Line 10:
* Le nombre de kills est strictement inférieur à 10.
* Le nombre de kills est strictement inférieur à 10.
* L'acteur n'a pas le flag NotCountDefeatedNum.
* L'acteur n'a pas le flag NotCountDefeatedNum.
* '''Pour Maz Koshia''' : 'Defeated_Priest_Boss_Normal_Num' est 0.
* '''Pour Miz'Kyosia''' : 'Defeated_Priest_Boss_Normal_Num' est 0.
* '''Pour Dark Beast Ganon''' : C'est la première fois que le boss final est battu. (Son flag Defeated a pour valeur maximale 1.)  
* '''Pour Ganon, Créature Maléfique''' : C'est la première fois que le boss final est battu. (Son flag Defeated a pour valeur maximale 1.)  
* '''Pour les Ombres de Ganon''' : C'est la première fois que l'Ombre est battue au sein de la créature divine, ou dans l'univers onirique (DLC2). Les Ombres que vous battez au château d'Hyrule ne comptent pas.
* '''Pour les Ombres de Ganon''' : C'est la première fois que l'Ombre est battue au sein de la créature divine, ou dans l'univers onirique (DLC2). Les Ombres que vous battez au château d'Hyrule ne comptent pas.
Cela se produit à chaque fois qu'un ennemi ''quelconque'' meurt, même s'il ne joue pas forcément de rôle dans le système de points (voir ci-dessous) et même si le joueur n'est pas responsable pour leur mort.
Cela se produit à chaque fois qu'un ennemi ''quelconque'' meurt, même s'il ne joue pas forcément de rôle dans le système de points (voir ci-dessous) et même si le joueur n'est pas responsable pour leur mort.
Line 17: Line 17:
Vu que des ennemis doivent être tués tout au long de la quête principale et que les boss sont considérés comme des ennemis, le nivellement de la difficulté est inévitable.
Vu que des ennemis doivent être tués tout au long de la quête principale et que les boss sont considérés comme des ennemis, le nivellement de la difficulté est inévitable.


Only the defeated counter flags are stored in the save file. The <code>Ecosystem::LevelSensor</code> subsystem is responsible for [[Difficulty scaling#Ecosystem::LevelSensor::calculatePoints|converting these kill counts to points]] using a [[Difficulty scaling#Ecosystem::LevelSensor::loadByml|configuration file]].
Seulement les flags d'ennemis battus sont stockés dans le fichier de sauvegarde. Le sous-système <code>Ecosystem::LevelSensor</code> est responsable de la [[#Ecosystem::LevelSensor::calculatePoints|conversion de ces décomptes en points]] en utilisant un [[#Ecosystem::LevelSensor::loadByml|fichier de configuration]].


The subsystem provides two functions ([[Difficulty scaling#Ecosystem::LevelSensor::scaleWeapon|<code>scaleWeapon</code>]] and [[Difficulty scaling#Ecosystem::LevelSensor::scaleActor|<code>scaleActor</code>]]) that may be called when a weapon or enemy actor is created.
Le sous-système fournit deux fonctions ([[#Ecosystem::LevelSensor::scaleWeapon|<code>scaleWeapon</code>]] et [[#Ecosystem::LevelSensor::scaleActor|<code>scaleActor</code>]]), appelées lorsque l'acteur d'un ennemi ou d'une arme est créé.


== Inhibiteurs du nivellement ==  
== Inhibiteurs du nivellement ==  
Line 27: Line 27:
* and WorldMgr::sInstance-&#x3E;isAocField (la map actuelle est les épreuves de l'épée)
* and WorldMgr::sInstance-&#x3E;isAocField (la map actuelle est les épreuves de l'épée)
* and WorldMgr::sInstance-&#x3E;disableScaling (réglée à true à l'entrée des épreuves de l'épée)
* and WorldMgr::sInstance-&#x3E;disableScaling (réglée à true à l'entrée des épreuves de l'épée)
Cela signifie que le nivellement est toujours désactivé lors des Épreuves de l'Épée.
Il sera également désactivé lorsque le [[map area]] actuel est 28. Cela correspond à "HateruSea" qui est la zone de l'Île Finalis.


== Armes ==  
== Armes ==  


'scaleWeapon' is called (i.e. weapons may be scaled) for a weapon if:
'scaleWeapon' est appelée (autrement dit, les armes peuvent être nivellées) pour une arme si:
* '''For standalone weapons''': The actor property 'LevelSensorMode' is higher than 1 '''and''' it wasn't already picked up.
* '''Pour les armes telles quelles''': Le paramètre 'LevelSensorMode' de l'acteur est supérieur à 1 '''et''' si elle n'ont pas déjà été récupérées.
* '''For treasure chest drops''': If SharpWeaponJudgeType is not 4, when [[AIDef:AI/TreasureBox]] initialises the drop actor.
* '''Pour les armes issues des coffres''': Si SharpWeaponJudgeType n'est pas 4, au moment où [[AIDef:AI/TreasureBox]] initialise le drop actor.
* '''For Hinox weapons''': The flag <code>{MapName}_Necklace_{i}_{HinoxName}_{ID}</code> is false.
* '''Pour les armes de Hinox''': Le flag <code>{MapName}_Necklace_{i}_{HinoxName}_{ID}</code> est faux.
* '''For other enemy drops''': The flag <code>{MapName}_WeaponDrop_{ID}</code> is false, '''and''' [the actor property 'LevelSensorMode' is higher than 1 ''or'' the enemy is a Guardian Scout ('Enemy_Guardian_Mini')].
* '''Pour les autres armes issues des ennemis''': Le flag <code>{MapName}_WeaponDrop_{ID}</code> est faux, '''et''' si [le paramètre 'LevelSensorMode' de l'acteur est supérieur à 1 ''ou'' l'ennemi est un Nano-Gardien ('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.
Remarque : les armes achetées dans une boutique ne peuvent pas recevoir de bonus car elles ne rentrent dans aucun des cas mentionnés ci-dessus.


== Bonus des armes ==  
== Bonus des armes ==  


Scaling of weapons are divided into three steps: Does the weapon get replaced by a different (better weapon)?
Le nivellement des armes fait que les armes sont remplacées par une arme différente (par exemple, un Arc de soldat qui devient un Arc royal), ou que les armes gagnent une augmentation de statistique bonus aléatoire (par exemple Attaque+, Durabilité+, etc.). L'intervalle des valeurs de ces bonus est aussi affectée par le nivellement des armes.
Which of the stats (among attack, guard, durability etc) is increased?
 
And how much it is increased.
Il y a deux rangs de bonus dans le jeu: un pour les types de faible niveau (qui apparaissent en bleu ou en blanc dans l'IU du jeu) and un autre pour ceux de meilleur niveau (jaune). Ceux qui appartiennent au rang jaune sont en général supérieurs aux autres. Par exemple, ''Attaque ↑↑'' est la version supérieure de ''Attaque ↑'' et fournit un plus grand boost d'attaque comparé à ''Attaque ↑''.


=== Types de bonus ===  
=== Types de bonus ===  


Weapon bonuses (e.g. Durability Up, Attack Up) are entirely random. Each bonus has equal probability.
Pour les armes, les bonus (par exemple Durabilité ↑ ou Attaque ↑) sont entièrement aléatoires. Chaque type de bonus est équiprobable.


{|class="wikitable"
{|class="wikitable"
Line 60: Line 64:
| Tirs x N (arcs) || Jaune
| Tirs x N (arcs) || Jaune
|-
|-
| Visée rapide (arcs) || Yellow
| Visée rapide (arcs) || Jaune
|-
|-
| AddSurfMaster || Yellow
| Glisse ↑ || Jaune
|-
|-
| Shield guard up || Blue/White and Yellow
| Garde ↑ || Bleu/blanc et jaune
|-
|-
| Critical Hit || Blue/White
| Coup de grâce || Bleu/blanc
|-
|-
| ZoomRapid || Yellow
| ZoomRapid || Jaune
|}
|}


Notes:
Remarques :
* "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.
* ''Coup de grâce'' ne peut être sélectionné que si weaponCommonSharpWeaponAddCrit est true ''et'' le palier est bleu/blanc. Cela signifie qu'il devient impossible d'obtenir une arme avec le bonus ''Coup de grâce'' après avoir tué un nombre suffisant d'ennemis.
* 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.
* ''Glisse ↑'' (AddSurfMaster) est un bonus qui ne s'applique qu'aux boucliers et qui leur donne un coefficient de frottement plus faible pour la glisse sur bouclier. Ce type de bonus n'est pas utilisé dans le jeu.
 
'''"Garde ↑" n'apparaît pas pour les boucliers issus des Amiibo à cause d'un bug du jeu.'''


=== Bonus values ===  
=== Valeurs de bonus ===  


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.
La valeur des bonus (par exemple l'augmentation de puissance ou de durabilité) est déterminée à partir de [[ActorParam/GeneralParamList]] (avec une copie de l'information dans [[ActorInfoData]]). Les intervalles corrects et les bonus de chaque arme est configurée dans la partie WeaponCommon.


==== amiibo ====  
==== amiibo ====  
À cause d'un bug dans le code du jeu<ref>Le code buggué est dans la fonction {{addr|a=0x71002df7d8|ver=nx-1.5.0}}.</ref>, à chaque fois que le jeu choisit aléatoirement le bonus "Garde ↑", le vrai bonus qui est assigné à l'arme et qui apparaît dans l'interface utilisateur est "Durabilité ↑". Pour cette raison, la valeur de la durabilité supplémentaire qui est utilisée pour les boucliers avec le bonus "Durabilité ↑" est soit addLifeMax, soit addGuardMax, suivant le bonus choisi.
{|class="wikitable"
{|class="wikitable"
! Bonus !! Value that is used for the bonus effect
! Bonus !! Valeur qui est utilisée pour l'effet bonus
|-
|-
| None || -
| Aucun || -
|-
|-
| Attack up || addAtkMax
| Attaque ↑ || addAtkMax
|-
|-
| Durability up || addLifeMax
| Durabilité ↑ || addLifeMax or addGuardMax
|-
|-
| Long throw || addThrowMax
| Distance lancers ↑ || addThrowMax
|-
|-
| Multi-shot burst (bows) || 5-shot burst
| Tirs x N (arcs) || Tirs x 5
|-
|-
| Quick shot (bows) || addRapidFireMin
| Visée rapide (arcs) || addRapidFireMin
|-
|-
| AddSurfMaster || [[bgparamlist#Global|GlobalParameter]]::shieldSurfMasterFrictionRatio
| Glisse ↑ || [[bgparamlist#Global|GlobalParameter]]::shieldSurfMasterFrictionRatio
|-
|-
| Shield guard up || addGuardMax
| Garde ↑ || addGuardMax
|}
|}


In summary, for amiibo weapons, an attack up always brings it to the greatest possible attack power.
En résumé, pour les armes amiibo, Attaque ↑ donne toujours le pouvoir d'attaque maximum. Il n'y a pas d'aléatoire.
No randomness is involved.


==== Non-amiibo ====  
==== Non amiibo ====  


{|class="wikitable"
{|class="wikitable"
! Bonus !! Value that is used for the bonus effect
! Bonus !! Valeur qui est utilisée pour l'effet bonus
|-
|-
| None || -
| Aucun || -
|-
|-
| Attack up || Random integer between addAtkMin and addAtkMax
| Attaque ↑ || Entier aléatoire entre addAtkMin et addAtkMax
|-
|-
| Durability up || Random integer between addLifeMin and addLifeMax
| Durabilité ↑ || Entier aléatoire entre addLifeMin et addLifeMax
|-
|-
| Long throw || Random float between addThrowMin and addThrowMax
| Distance lancers ↑ || Flottant aléatoire entre addThrowMin et addThrowMax
|-
|-
| Multi-shot burst (bows) || 5-shot burst
| Tirs x N (arcs) || Tirs x 5
|-
|-
| Quick shot (bows) || Random float between addRapidFireMin and addRapidFireMax
| Visée rapide (arcs) || Flottant aléatoire entre addRapidFireMin et addRapidFireMax
|-
|-
| AddSurfMaster || [[bgparamlist#Global|GlobalParameter]]::shieldSurfMasterFrictionRatio
| Glisse ↑ || [[bgparamlist#Global|GlobalParameter]]::shieldSurfMasterFrictionRatio
|-
|-
| Shield guard up || Random integer between addGuardMin and addGuardMax
| Garde ↑ || Entier aléatoire entre addGuardMin et addGuardMax
|}
|}


In summary, for non-amiibo weapons, an attack up results in a randomized attack power.
En résumé, pour les armes non issues d'amiibo, Attaque ↑ donne un pouvoir d'attaque aléatoire.


== Enemies ==  
== Ennemis ==  


When loading enemies, the game will always try to scale enemies.
Lorsque le jeu charge des ennemis, il essayera toujours de les niveler.


However, the scaling function won't do anything if 'LevelSensorMode' is &#x3C; 1 and will leave the enemy and any weapons they may hold unscaled.
Cependant, la fonction de nivellement ne fera rien si 'LevelSensorMode' est &#x3C; 1 et elle laissera dans ce cas l'ennemi et toute arme qu'il pourrait détenir à leurs états initiaux.


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:
Remarque : Les ennemis qui ne sont sur aucune liste de mise à niveau (tels que les Lézalfos élémentaux) ne seront pas nivelés, mais leurs armes peuvent malgré tout recevoir des mises à niveau si :
* 'LevelSensorMode' is non zero.
* 'LevelSensorMode' est non nul et la condition qui porte sur le nombre de points d'arme est satisfaite
* Weapon point requirements are satisfied
* ''ou alors'' le palier de bonus est outrepassé par 'SharpWeaponJudgeType'.
* ''or'' the modifier tier is overridden using 'SharpWeaponJudgeType'.
[1.3.0] En mode expert, '''tous''' les ennemis sont automatiquement montés d'un palier par défaut, ''à l'issue du nivellement'', et ce indépendamment de 'LevenSensorMode'. Les [[Actor|acteurs]] peuvent recevoir deux paramètres supplémentaires :
[1.3.0] In Master Mode, '''all''' enemies are automatically ranked up one tier by default '''post scaling''', independently of 'LevelSensorMode'. [[Actor]]s can receive two additional parameters:
{| class="wikitable"
{| class="wikitable"
! Parameter
! Paramètre
! Default
! Valeur par défaut
! Description
! Description
|-
|-
| IsHardModeActor
| IsHardModeActor
| false
| false
| Controls whether an enemy only shows up in Master Mode.
| Contrôle l'apparition ou non d'un ennemi dans le Mode Expert.
|-
|-
| DisableRankUpForHardMode
| DisableRankUpForHardMode
| false
| false
| Controls whether the automatic rankup applies to an enemy.
| Détermine si l'ennemi est automatiquement monté d'un palier ou non.
|}
|}
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).
En mode expert, IsHardModeActor, DisableRankUpForHardMode and LevelSensorMode sont combinés sur quelques acteurs pour garder des ennemis de bas niveau dans le monde (par exemple pour garder un Bokoblin rouge au sud du Plateau du Prélude.)


== Properties ==  
== Propriétés ==  


=== <code>LevelSensorMode</code> ===
=== <code>LevelSensorMode</code> ===
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.
Cette propriété [[actor]] détermine si le nivellement est activé pour un ennemi ou une arme. Elle s'applique également à toute arme que possède un ennemi puisque  'scaleWeapon' est appelée lorsqu'un ennemi lâche son arme.


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'.
Remarquez que ceci ne s'applique pas aux armes qui sont attachées au collier d'un Hinox, car les Hinox utilisent un acteur ennemi différent qui redéfinit (override) la fonction 'on weapon dropped' et ignore 'LevelSensorMode'.


=== <code>SharpWeaponJudgeType</code> ===
=== <code>SharpWeaponJudgeType</code> ===
This actor property controls the ''minimum'' modifier tier that a weapon can receive.
Cette propriété acteur détermine le palier minimum de bonus qu'une arme peut recevoir.


Internally and in assets such as [[Map unit|map units]], the following values are used for modifiers:
En interne, et dans des ressources telles que les [[map unit]]s, les valeurs suivantes sont utilisées pour régler les paliers :


{| class="wikitable"
{| class="wikitable"
! Value
! Valeur
! Description
! Description
|-
|-
| 0
| 0
| '''None''': No modifiers.
| '''None''': Pas de bonus.
|-
|-
| 1
| 1
| '''RandomBlue''': Weapon will randomly get at least a blue modifier (with <code>weaponCommonSharpWeaponPer</code> being the probability).
| '''RandomBlue''': L'arme aura aléatoirement au moins un bonus bleu / blanc (avec <code>weaponCommonSharpWeaponPer</code> faisant office de probabilité).
|-
|-
| 2
| 2
| '''Blue''': Weapon will get at least a blue modifier.
| '''Blue''': L'arme aura au moins un bonus bleu.
|-
|-
| 3
| 3
| '''Yellow''': Weapon will get at least a yellow modifier.
| '''Yellow''': L'arme aura au moins un bonus jaune.
|-
|-
| 4
| 4
| '''NoneForced''' (chests only): Weapon will ''never'' spawn with any modifiers. ''This overrides regular scaling.''
| '''NoneForced''' (uniquement pour les coffres): L'arme n'apparaîtra ''jamais'' avec un bonus. ''Ceci est prioritaire sur le nivellement normal.''
|}
|}


If [[Difficulty scaling#LevelSensorMode|scaling]] is enabled, the weapon may receive modifiers from an even higher tier if point requirements are met.
Si [[#LevelSensorMode|le nivellement]] est activé, l'arme peut recevoir des bonus d'un palier supérieur à celui configuré si le joueur a assez de points.


Otherwise, the weapon will get modifiers from exactly the specified tier.
Sinon, l'arme recevra un bonus qui appartient exactement au palier configuré.


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.
Par exemple, 0 ('None') ne signifie pas qu'une arme ne recevra jamais de bonus. Cela veut juste dire que les développeurs n'ont pas forcé l'apparition d'un bonus bleu ou jaune. Si le joueur dispose d'un nombre suffisant de points, l'arme recevra des bonus bleus ou jaunes.


== Scaling algorithm ==  
== Algorithme de nivellement ==  


=== <code>Ecosystem::LevelSensor::loadByml</code> ===  
=== <code>Ecosystem::LevelSensor::loadByml</code> ===  


This function is called by <code>Ecosystem::init</code> from <code>ksys::InitializeApp</code>
Cette fonction est appelée par <code>Ecosystem::init</code> depuis <code>ksys::InitializeApp</code>


Sets up byml structures for reading Ecosystem/[[LevelSensor.byml]].
Met en place les structures byml pour la lecture de Ecosystem/[[LevelSensor.byml]].


=== <code>Ecosystem::LevelSensor::calculatePoints</code> ===  
=== <code>Ecosystem::LevelSensor::calculatePoints</code> ===  


Called by [[PlacementMgr]] when spawning actors.
Appelée par [[PlacementMgr]] au moment du spawn des acteurs.


Calculates weapon and enemy scaling points using a list of flags and configuration values.
Calcule les points d'ennemi et d'arme en utilisant une liste de flags et de valeurs de configuration.


All flags that are referenced in the configuration file are of the form <code>Defeated_%s_Num</code>, but technically the configuration format allows for other flags to be specified.
Tous les flags auxquels le fichier de configuration fait référence sont de la forme <code>Defeated_%s_Num</code>, mais techniquement le format de configuration permet l'utilisation d'autres flags.


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.
Fait intéressant : le jeu calcule un seul total de points à partir des flags "kill counter", mais calcule deux valeurs distinctes pour les armes et les ennemis avec deux facteurs différents. Ce format permet de changer le nivellement facilement.


<source lang="c++">
<source lang="c++">
Line 220: Line 227:
</source>
</source>


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.
En pratique, ces paramètres n'ont jamais été modifiés. 1.5.0 (qui sera sans doute la dernière mise à jour du jeu) a toujours les mêmes Level2WeaponPower et Level2EnemyPower.


=== <code>Ecosystem::LevelSensor::scaleWeapon</code> ===  
=== <code>Ecosystem::LevelSensor::scaleWeapon</code> ===  


Called from treasure chest code, enemy actors{{Check}}, <code>Ecosystem::LevelSensor::scaleActor</code>
Appelée par le code des coffres ou par les acteurs d'ennemi{{Check}}, <code>Ecosystem::LevelSensor::scaleActor</code>


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).
Suivant le nom de l'arme, ses bonus et le compte actuel des points, cette fonction renvoie l'arme à faire apparaître, et le bonus à utiliser, si 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.
Si l'algorithme échoue à trouver une arme qui satisfait toutes les conditions (nombre de points requis, série de l'arme, bonus), l'arme spécifiée et les bonus en entrée seront utilisés à la place.


Pseudocode (1.0.0):
Pseudocode (1.0.0) :


<source lang="c++">
<source lang="c++">
Line 239: Line 246:
                                         void* unknown)
                                         void* unknown)
{
{
   // some checks using 'unknown' here which seems to be a pointer to the actor
   // quelques checks utilisant 'unknown' ici qui semble être un pointeur vers l'acteur
   //
   //
   for (weapon_table : this->byml["weapon"]) {
   for (weapon_table : this->byml["weapon"]) {
     // find the first weapon entry for which the player has enough points
     // trouve la première arme pour laquelle le joueur a assez de points
     // with the specified name and modifier
     // avec le nom spécifié et les bonus
     i = -1;
     i = -1;
     for (j = 0; j < weapon_table["actors"].size; ++j) {
     for (j = 0; j < weapon_table["actors"].size; ++j) {
Line 263: Line 270:
       entry = weapon_table["actors"][i];
       entry = weapon_table["actors"][i];
       //
       //
       // not_rank_up means there is no link between weapons;
       // not_rank_up signifie qu'il n'y a pas de lien entre les armes;
       // this table is just used to look up modifiers.
       // ce tableau est juste utilisé pour parcourir les bonus.
       // so go down the list until there are no more entries for the requested weapon
       // donc parcourt la liste jusqu'à ce qu'il n'y ait plus d'entrée pour l'arme demandée
       // or until we reach a modifier that requires more points.
       // ou jusqu'à ce que l'on atteigne un bonus qui nécessite plus de points.
       if (weapon_table["not_rank_up"] && entry["name"] != weapon_to_look_up)
       if (weapon_table["not_rank_up"] && entry["name"] != weapon_to_look_up)
         break;
         break;
       //
       //
       // otherwise, just go down the list until we reach the end or a weapon which
       // sinon, parcourt juste la liste jusqu'à atteindre la fin ou une arme qui
       // requires more points. this will possibly upgrade the weapon (e.g. Knight -> Royal).
       // requiert plus de points. Cela peut améliorer l'arme (par ex. Chevalier -> Royal).
       if (this->weapon_points <= entry["value"])
       if (this->weapon_points <= entry["value"])
         break;
         break;
Line 282: Line 289:
     return true;
     return true;
   }
   }
   return false;  // cannot scale up
   return false;  // ne peut pas niveller
}
}
</source>
</source>
Line 288: Line 295:
=== <code>Ecosystem::LevelSensor::scaleActor</code> ===  
=== <code>Ecosystem::LevelSensor::scaleActor</code> ===  


Analogous to <code>LevelSensor::scaleWeapon</code>.
Analogue à <code>LevelSensor::scaleWeapon</code>.


Pseudocode (1.0.0):
Pseudocode (1.0.0) :


<source lang="c++">
<source lang="c++">
Line 320: Line 327:
     return true;
     return true;
   }
   }
   return false;  // cannot scale up
   return false;  // ne peut pas niveller
}
}
//
//
Line 334: Line 341:
     return true;
     return true;
   }
   }
   return false;  // cannot scale up
   return false;  // ne peut pas niveller
}
}
</source>
</source>


== The Data ==  
== Les données ==  


To make things easier to understand, here are links to:
Pour rendre tout cela plus facile à comprendre, voici des liens vers :
* [https://docs.google.com/spreadsheets/d/e/2PACX-1vRSlyOD7FLAn1TUBn64Pu8Pld-WOfgcVByuywHMWvBTEV0j8potD1wkBs-MJJXf-gvEkpfItUCMqMk6/pubhtml kill point, enemy scaling and weapon scaling tables]
* [https://docs.google.com/spreadsheets/d/e/2PACX-1vRSlyOD7FLAn1TUBn64Pu8Pld-WOfgcVByuywHMWvBTEV0j8potD1wkBs-MJJXf-gvEkpfItUCMqMk6/pubhtml des tableaux de points, de nivellement des ennemis et des armes]
* an [https://objmap.zeldamods.org object map with scaling information].
* une [https://objmap.zeldamods.org carte objets (object map) avec les infos de nivellement].
This makes it possible to see both the required points for enemy/weapon upgrades, as well as all of the special cases extremely easily.
Cela permet de voir très aisément à la fois les points nécessaires pour mettre à niveau les ennemis ou les armes, ainsi que tous les cas spéciaux.


== Ganon Blights ==  
== Ombres de Ganon ==  


Ganon blights also have varying difficulty but follow a different system. Their health is determined by the base HP (set in [[ActorParam/GeneralParamList|GeneralParamList]]) and blight defeat flags.
Les Ombres de Ganon varient elles aussi en difficulté mais suivent un système différent. Leur HP est déterminé par le HP de base (réglé dans [[ActorParam/GeneralParamList|GeneralParamList]]) et les flags de défaite des ombres.


<source lang="c++">__int64 SiteBoss::getInitialHP(SiteBoss *this) // 0x71002D01F4
<source lang="c++">__int64 SiteBoss::getInitialHP(SiteBoss *this) // 0x71002D01F4
Line 368: Line 375:
}</source>
}</source>


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.
En pratique, cela signifie que la première ombre que Link bat disposera de 800+0×400 = 800 HP, la seconde aura 800+1×400 = 1200 HP, la troisième 800+2×400 = 1600 HP et la dernière 800+3×400 = 2000 HP.


=== Special case 1: Castle Blights ===  
=== Cas spécial 1 : Les ombres du château ===  


Castle blights have <code>IsRemainBoss</code> set to false in their root AI parameters (see [[AIDef:AI/SiteBossSpearRoot]] for example), which sets flag 4.
Les ombres du château d'Hyrule ont <code>IsRemainBoss</code> réglé sur false dans les paramètres de leur AI root (voir [[AIDef:AI/SiteBossSpearRoot]] par exemple), ce qui active le flag 4.


Thus, blights that are fought in the Castle always have 800+3×400 = 2000 HP regardless of story progression.
Ainsi, les ombres combattues au château disposent toujours de 800+3×400 = 2000 HP quelle que soit la progression de l'histoire.


If flag 4 is set, the [[AIDef:Action/SiteBossDie]] code will NOT increment the &#x22;defeated&#x22; counter. This means castle blights do not give any scaling points.
Si le flag 4 est activé, le code [[AIDef:Action/SiteBossDie]] n'incrémenta PAS le compteur Defeated. Cela signifie que les ombres du château ne donnent aucun point de nivellement.


=== Special case 2: DLC2 Blights ===  
=== Cas spécial 2 : Les ombres du DLC2 ===  


Illusory Realm blights possess the <code>EnemySiteBoss_R</code> actor tag. This causes flag 8 to be set. So they will always have 500+4×250 = 1500 HP.
Les ombres dans l'univers onirique possèdent le tag acteur <code>EnemySiteBoss_R</code>. Cela conduit à l'activation du flag 8. Donc celles-ci auront toujours 500+4×250 = 1500 HP.


Interestingly, the Windblight AI function relies doesn't check the actor tag but the actor name instead. For flag 8 to be set, the actor name must be <code>Enemy_SiteBoss_Bow_R</code>.
Fait intéressant, la fonction AI de l'ombre de vent de Ganon (Windblight) ne vérifie pas le tag acteur mais plutôt le nom d'acteur. Pour que le flag 8 soit activé, le nom doit absolument être <code>Enemy_SiteBoss_Bow_R</code>.




<references />
<references />
[[Category:Internals]]
[[Category:Internals{{#translation:}}]]
[[Category:Game mechanics]]
[[Category:Game mechanics{{#translation:}}]]

Latest revision as of 12:57, 14 June 2022

Other languages:

Difficulty scaling (nivellement de la difficulté) est un mécanisme dans Breath of the Wild qui fait que les ennemis et les armes sont progressivement remplacés par des variantes plus puissantes au cours d'une partie de jeu.

Points

Le système de nivellement se base sur un système de points. Tuer des ennemis est la seule manière d'en recevoir.

Quand un ennemi meurt, le jeu incrémente un flag 'Defeated_{SameGroupActorName}_Num' si toutes les conditions suivantes sont remplies :

  • Le nombre de kills est strictement inférieur à 10.
  • L'acteur n'a pas le flag NotCountDefeatedNum.
  • Pour Miz'Kyosia : 'Defeated_Priest_Boss_Normal_Num' est 0.
  • Pour Ganon, Créature Maléfique : C'est la première fois que le boss final est battu. (Son flag Defeated a pour valeur maximale 1.)
  • Pour les Ombres de Ganon : C'est la première fois que l'Ombre est battue au sein de la créature divine, ou dans l'univers onirique (DLC2). Les Ombres que vous battez au château d'Hyrule ne comptent pas.

Cela se produit à chaque fois qu'un ennemi quelconque meurt, même s'il ne joue pas forcément de rôle dans le système de points (voir ci-dessous) et même si le joueur n'est pas responsable pour leur mort.

Vu que des ennemis doivent être tués tout au long de la quête principale et que les boss sont considérés comme des ennemis, le nivellement de la difficulté est inévitable.

Seulement les flags d'ennemis battus sont stockés dans le fichier de sauvegarde. Le sous-système Ecosystem::LevelSensor est responsable de la conversion de ces décomptes en points en utilisant un fichier de configuration.

Le sous-système fournit deux fonctions (scaleWeapon et scaleActor), appelées lorsque l'acteur d'un ennemi ou d'une arme est créé.

Inhibiteurs du nivellement

Les deux fonctions de nivellement ne feront absolument rien si :

  • WorldMgr::sInstance->stageType == 1 (Open World stage)
  • and WorldMgr::sInstance->isAocField (la map actuelle est les épreuves de l'épée)
  • and WorldMgr::sInstance->disableScaling (réglée à true à l'entrée des épreuves de l'épée)

Cela signifie que le nivellement est toujours désactivé lors des Épreuves de l'Épée.

Il sera également désactivé lorsque le map area actuel est 28. Cela correspond à "HateruSea" qui est la zone de l'Île Finalis.

Armes

'scaleWeapon' est appelée (autrement dit, les armes peuvent être nivellées) pour une arme si:

  • Pour les armes telles quelles: Le paramètre 'LevelSensorMode' de l'acteur est supérieur à 1 et si elle n'ont pas déjà été récupérées.
  • Pour les armes issues des coffres: Si SharpWeaponJudgeType n'est pas 4, au moment où AIDef:AI/TreasureBox initialise le drop actor.
  • Pour les armes de Hinox: Le flag {MapName}_Necklace_{i}_{HinoxName}_{ID} est faux.
  • Pour les autres armes issues des ennemis: Le flag {MapName}_WeaponDrop_{ID} est faux, et si [le paramètre 'LevelSensorMode' de l'acteur est supérieur à 1 ou l'ennemi est un Nano-Gardien ('Enemy_Guardian_Mini')]

Remarque : les armes achetées dans une boutique ne peuvent pas recevoir de bonus car elles ne rentrent dans aucun des cas mentionnés ci-dessus.

Bonus des armes

Le nivellement des armes fait que les armes sont remplacées par une arme différente (par exemple, un Arc de soldat qui devient un Arc royal), ou que les armes gagnent une augmentation de statistique bonus aléatoire (par exemple Attaque+, Durabilité+, etc.). L'intervalle des valeurs de ces bonus est aussi affectée par le nivellement des armes.

Il y a deux rangs de bonus dans le jeu: un pour les types de faible niveau (qui apparaissent en bleu ou en blanc dans l'IU du jeu) and un autre pour ceux de meilleur niveau (jaune). Ceux qui appartiennent au rang jaune sont en général supérieurs aux autres. Par exemple, Attaque ↑↑ est la version supérieure de Attaque ↑ et fournit un plus grand boost d'attaque comparé à Attaque ↑.

Types de bonus

Pour les armes, les bonus (par exemple Durabilité ↑ ou Attaque ↑) sont entièrement aléatoires. Chaque type de bonus est équiprobable.

Bonus Disponible pour les paliers
Attaque ↑ Bleu/blanc et jaune
Durabilité ↑ Bleu/blanc et jaune
Distance lancers ↑ Jaune
Tirs x N (arcs) Jaune
Visée rapide (arcs) Jaune
Glisse ↑ Jaune
Garde ↑ Bleu/blanc et jaune
Coup de grâce Bleu/blanc
ZoomRapid Jaune

Remarques :

  • Coup de grâce ne peut être sélectionné que si weaponCommonSharpWeaponAddCrit est true et le palier est bleu/blanc. Cela signifie qu'il devient impossible d'obtenir une arme avec le bonus Coup de grâce après avoir tué un nombre suffisant d'ennemis.
  • Glisse ↑ (AddSurfMaster) est un bonus qui ne s'applique qu'aux boucliers et qui leur donne un coefficient de frottement plus faible pour la glisse sur bouclier. Ce type de bonus n'est pas utilisé dans le jeu.

"Garde ↑" n'apparaît pas pour les boucliers issus des Amiibo à cause d'un bug du jeu.

Valeurs de bonus

La valeur des bonus (par exemple l'augmentation de puissance ou de durabilité) est déterminée à partir de bgparamlist (avec une copie de l'information dans ActorInfoData). Les intervalles corrects et les bonus de chaque arme est configurée dans la partie WeaponCommon.

amiibo

À cause d'un bug dans le code du jeu[1], à chaque fois que le jeu choisit aléatoirement le bonus "Garde ↑", le vrai bonus qui est assigné à l'arme et qui apparaît dans l'interface utilisateur est "Durabilité ↑". Pour cette raison, la valeur de la durabilité supplémentaire qui est utilisée pour les boucliers avec le bonus "Durabilité ↑" est soit addLifeMax, soit addGuardMax, suivant le bonus choisi.

Bonus Valeur qui est utilisée pour l'effet bonus
Aucun -
Attaque ↑ addAtkMax
Durabilité ↑ addLifeMax or addGuardMax
Distance lancers ↑ addThrowMax
Tirs x N (arcs) Tirs x 5
Visée rapide (arcs) addRapidFireMin
Glisse ↑ GlobalParameter::shieldSurfMasterFrictionRatio
Garde ↑ addGuardMax

En résumé, pour les armes amiibo, Attaque ↑ donne toujours le pouvoir d'attaque maximum. Il n'y a pas d'aléatoire.

Non amiibo

Bonus Valeur qui est utilisée pour l'effet bonus
Aucun -
Attaque ↑ Entier aléatoire entre addAtkMin et addAtkMax
Durabilité ↑ Entier aléatoire entre addLifeMin et addLifeMax
Distance lancers ↑ Flottant aléatoire entre addThrowMin et addThrowMax
Tirs x N (arcs) Tirs x 5
Visée rapide (arcs) Flottant aléatoire entre addRapidFireMin et addRapidFireMax
Glisse ↑ GlobalParameter::shieldSurfMasterFrictionRatio
Garde ↑ Entier aléatoire entre addGuardMin et addGuardMax

En résumé, pour les armes non issues d'amiibo, Attaque ↑ donne un pouvoir d'attaque aléatoire.

Ennemis

Lorsque le jeu charge des ennemis, il essayera toujours de les niveler.

Cependant, la fonction de nivellement ne fera rien si 'LevelSensorMode' est < 1 et elle laissera dans ce cas l'ennemi et toute arme qu'il pourrait détenir à leurs états initiaux.

Remarque : Les ennemis qui ne sont sur aucune liste de mise à niveau (tels que les Lézalfos élémentaux) ne seront pas nivelés, mais leurs armes peuvent malgré tout recevoir des mises à niveau si :

  • 'LevelSensorMode' est non nul et la condition qui porte sur le nombre de points d'arme est satisfaite
  • ou alors le palier de bonus est outrepassé par 'SharpWeaponJudgeType'.

[1.3.0] En mode expert, tous les ennemis sont automatiquement montés d'un palier par défaut, à l'issue du nivellement, et ce indépendamment de 'LevenSensorMode'. Les acteurs peuvent recevoir deux paramètres supplémentaires :

Paramètre Valeur par défaut Description
IsHardModeActor false Contrôle l'apparition ou non d'un ennemi dans le Mode Expert.
DisableRankUpForHardMode false Détermine si l'ennemi est automatiquement monté d'un palier ou non.

En mode expert, IsHardModeActor, DisableRankUpForHardMode and LevelSensorMode sont combinés sur quelques acteurs pour garder des ennemis de bas niveau dans le monde (par exemple pour garder un Bokoblin rouge au sud du Plateau du Prélude.)

Propriétés

LevelSensorMode

Cette propriété actor détermine si le nivellement est activé pour un ennemi ou une arme. Elle s'applique également à toute arme que possède un ennemi puisque 'scaleWeapon' est appelée lorsqu'un ennemi lâche son arme.

Remarquez que ceci ne s'applique pas aux armes qui sont attachées au collier d'un Hinox, car les Hinox utilisent un acteur ennemi différent qui redéfinit (override) la fonction 'on weapon dropped' et ignore 'LevelSensorMode'.

SharpWeaponJudgeType

Cette propriété acteur détermine le palier minimum de bonus qu'une arme peut recevoir.

En interne, et dans des ressources telles que les map units, les valeurs suivantes sont utilisées pour régler les paliers :

Valeur Description
0 None: Pas de bonus.
1 RandomBlue: L'arme aura aléatoirement au moins un bonus bleu / blanc (avec weaponCommonSharpWeaponPer faisant office de probabilité).
2 Blue: L'arme aura au moins un bonus bleu.
3 Yellow: L'arme aura au moins un bonus jaune.
4 NoneForced (uniquement pour les coffres): L'arme n'apparaîtra jamais avec un bonus. Ceci est prioritaire sur le nivellement normal.

Si le nivellement est activé, l'arme peut recevoir des bonus d'un palier supérieur à celui configuré si le joueur a assez de points.

Sinon, l'arme recevra un bonus qui appartient exactement au palier configuré.

Par exemple, 0 ('None') ne signifie pas qu'une arme ne recevra jamais de bonus. Cela veut juste dire que les développeurs n'ont pas forcé l'apparition d'un bonus bleu ou jaune. Si le joueur dispose d'un nombre suffisant de points, l'arme recevra des bonus bleus ou jaunes.

Algorithme de nivellement

Ecosystem::LevelSensor::loadByml

Cette fonction est appelée par Ecosystem::init depuis ksys::InitializeApp

Met en place les structures byml pour la lecture de Ecosystem/LevelSensor.byml.

Ecosystem::LevelSensor::calculatePoints

Appelée par PlacementMgr au moment du spawn des acteurs.

Calcule les points d'ennemi et d'arme en utilisant une liste de flags et de valeurs de configuration.

Tous les flags auxquels le fichier de configuration fait référence sont de la forme Defeated_%s_Num, mais techniquement le format de configuration permet l'utilisation d'autres flags.

Fait intéressant : le jeu calcule un seul total de points à partir des flags "kill counter", mais calcule deux valeurs distinctes pour les armes et les ennemis avec deux facteurs différents. Ce format permet de changer le nivellement facilement.

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;

En pratique, ces paramètres n'ont jamais été modifiés. 1.5.0 (qui sera sans doute la dernière mise à jour du jeu) a toujours les mêmes Level2WeaponPower et Level2EnemyPower.

Ecosystem::LevelSensor::scaleWeapon

Appelée par le code des coffres ou par les acteurs d'ennemi[check], Ecosystem::LevelSensor::scaleActor

Suivant le nom de l'arme, ses bonus et le compte actuel des points, cette fonction renvoie l'arme à faire apparaître, et le bonus à utiliser, si possible.

Si l'algorithme échoue à trouver une arme qui satisfait toutes les conditions (nombre de points requis, série de l'arme, bonus), l'arme spécifiée et les bonus en entrée seront utilisés à la place.

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)
{
  // quelques checks utilisant 'unknown' ici qui semble être un pointeur vers l'acteur
  //
  for (weapon_table : this->byml["weapon"]) {
    // trouve la première arme pour laquelle le joueur a assez de points
    // avec le nom spécifié et les bonus
    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 signifie qu'il n'y a pas de lien entre les armes;
      // ce tableau est juste utilisé pour parcourir les bonus.
      // donc parcourt la liste jusqu'à ce qu'il n'y ait plus d'entrée pour l'arme demandée
      // ou jusqu'à ce que l'on atteigne un bonus qui nécessite plus de points.
      if (weapon_table["not_rank_up"] && entry["name"] != weapon_to_look_up)
        break;
      //
      // sinon, parcourt juste la liste jusqu'à atteindre la fin ou une arme qui
      // requiert plus de points. Cela peut améliorer l'arme (par ex. Chevalier -> 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;  // ne peut pas niveller
}

Ecosystem::LevelSensor::scaleActor

Analogue à 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;  // ne peut pas niveller
}
//
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;  // ne peut pas niveller
}

Les données

Pour rendre tout cela plus facile à comprendre, voici des liens vers :

Cela permet de voir très aisément à la fois les points nécessaires pour mettre à niveau les ennemis ou les armes, ainsi que tous les cas spéciaux.

Ombres de Ganon

Les Ombres de Ganon varient elles aussi en difficulté mais suivent un système différent. Leur HP est déterminé par le HP de base (réglé dans bgparamlist) et les flags de défaite des ombres.

__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;
}

En pratique, cela signifie que la première ombre que Link bat disposera de 800+0×400 = 800 HP, la seconde aura 800+1×400 = 1200 HP, la troisième 800+2×400 = 1600 HP et la dernière 800+3×400 = 2000 HP.

Cas spécial 1 : Les ombres du château

Les ombres du château d'Hyrule ont IsRemainBoss réglé sur false dans les paramètres de leur AI root (voir AIDef:AI/SiteBossSpearRoot par exemple), ce qui active le flag 4.

Ainsi, les ombres combattues au château disposent toujours de 800+3×400 = 2000 HP quelle que soit la progression de l'histoire.

Si le flag 4 est activé, le code AIDef:Action/SiteBossDie n'incrémenta PAS le compteur Defeated. Cela signifie que les ombres du château ne donnent aucun point de nivellement.

Cas spécial 2 : Les ombres du DLC2

Les ombres dans l'univers onirique possèdent le tag acteur EnemySiteBoss_R. Cela conduit à l'activation du flag 8. Donc celles-ci auront toujours 500+4×250 = 1500 HP.

Fait intéressant, la fonction AI de l'ombre de vent de Ganon (Windblight) ne vérifie pas le tag acteur mais plutôt le nom d'acteur. Pour que le flag 8 soit activé, le nom doit absolument être Enemy_SiteBoss_Bow_R.


  1. Le code buggué est dans la fonction 0x71002df7d8 [nx-1.5.0 executable].