Audit technique — revue de code
Revue statique du bundle client déployé sur la bêta, avec reconstruction des tables de données et des formules d'équilibrage.
La fonctionnalité est cohérente dans son intention et son interface, mais elle repose sur un jeu de données qui n'a été migré qu'à 17 % (13 objets sur 78). Cette migration inachevée rend une ou plusieurs statistiques non forgeables sur 36 objets sur 78, dont les quatre armes mythiques de niveau 80–100 et les cinq Reliques. Par ailleurs, une erreur d'algèbre dans la formule de rendement du recyclage neutralise complètement la pondération de rareté des runes, ce qui produit un écart de coût réel de 1 à 270 entre statistiques.
Aucun de ces deux points n'est visible en jouant quelques minutes : la forge ne renvoie pas d'erreur, elle omet simplement les statistiques concernées, et l'objet disparaît parfois entièrement de la liste. C'est ce silence qui les rend prioritaires.
| ID | Constat | Sévérité | Nature |
|---|---|---|---|
| RS-01 | Clés de statistiques non normalisées dans la forge — 36/78 objets amputés | Majeur | Bug de données |
| RS-02 | Le poids de rune s'annule dans la formule de rendement | Majeur | Bug d'équilibrage |
| RS-03 | Bêta injouable pour la fonctionnalité auditée | Majeur | Exploitation |
| RS-04 | Rune de Précision : valeur marchande à 0, invendable au PNJ | Moyen | Donnée |
| RS-05 | Gain de critique invisible à l'écran (format + arrondi) | Moyen | Affichage |
| RS-06 | Progression Runiste : 0,09 % de l'XP débloque 100 % du contenu | Moyen | Design |
| RS-07 | Confirmations asymétriques sur les actions destructrices | Moyen | UX |
| RS-08 | Notes de version : noms de runes inexistants ou trompeurs | Mineur | Communication |
| RS-09 | Erreur trompeuse quand l'objet n'a pas d'instanceId | Mineur | Bug |
| RS-10 | Poids 0.5 de la Rune de Vigueur entièrement inopérant | Mineur | Donnée morte |
| RS-11 | Code et chaînes résiduels | Mineur | Propreté |
| RS-12 | Détection OVER impossible sur une fourchette fixe | Latent | Piège futur |
Ordre de traitement suggéré : RS-03 en premier (sans quoi la fenêtre de test de 72 h ne produira aucun retour terrain), puis RS-01 et RS-02 qui touchent le cœur de la fonctionnalité, puis RS-04 et RS-05 qui sont des corrections courtes à fort effet perçu.
/play/assets/index-GWYEpY4N.js (1 738 266 octets, minifié).O() / be(), puis les trois passes de surcharge Gg → Dg → Wg/Ug) : 78 équipements, 235 fourchettes de jets.window.__VALORA_I18N (locale fr).Le serveur est autoritaire. Le client se contente d'émettre deux RPC :
recycle(e,t){ return this.call("econ_recycle", t!=null?{id:e,instanceId:t}:{id:e}) }
upgrade(e,t){ return this.call("econ_upgrade", {instanceId:e, stat:t}) }
Le tirage de succès, la destruction, la dégradation et l'attribution réelle des runes se décident côté serveur, hors de portée de cet audit. Deux conséquences pratiques :
La vérification empirique n'a pas pu être menée : les deux personnages de bêta disponibles (niveau 100) ont un sac vide ou sans équipement, et 0 et 18 pièces d'or respectivement. Voir RS-03. Tous les constats ci-dessous sont donc issus de l'analyse statique ; ils sont reproductibles par lecture du bundle, et chacun indique la donnée exacte permettant de le rejouer.
Le bundle est minifié : les identifiants cités (Eo, Ax, Lx, Fm…) sont des noms générés par le build, pas des noms de source. Chaque citation est accompagnée de la description sémantique de la fonction pour permettre de la retrouver dans le dépôt.
Configuration Ix : maxTier: 4, overmaxStepPct: 800. Chaque palier réussi ajoute 8 % du maximum de base de la statistique ; un objet mené au palier 4 dépasse donc son plafond de 32 %.
| Palier | Succès | Runes | Or | Destruction | Runiste requis |
|---|---|---|---|---|---|
| 1 | 100 % | 2 × poids | 2 000 | — | 1 |
| 2 | 85 % | 3 × poids | 6 000 | — | 5 |
| 3 | 65 % | 5 × poids | 15 000 | — | 12 |
| 4 | 45 % | 8 × poids | 35 000 | 25 % | 20 |
Dans tout ce document, « chaîne » désigne la montée complète d'une statistique d'un objet, du palier 1 au palier 4 : 2+3+5+8 = 18 × poids en runes, et 58 000 or.
Le poids (weight) est le multiplicateur de coût en forge ; sell est le prix payé par le marchand PNJ.
| Rune | Nom en jeu | Statistique | Rareté | Poids | Valeur PNJ |
|---|---|---|---|---|---|
| rune_might | Rune de Puissance | Force | Commune | 1 | 2 |
| rune_wisdom | Rune de Sagesse | Savoir | Commune | 1 | 2 |
| rune_swiftness | Rune de Célérité | Agilité | Commune | 1 | 2 |
| rune_fortune | Rune de Fortune | Flux | Commune | 1 | 2 |
| rune_vigor | Rune de Vigueur | Vitalité | Commune | 0.5 | 1 |
| rune_ward_* | Rune de Garde (×4) | Résistances | Peu commune | 3 | 3 |
| rune_power | Rune de Frappe | Dégâts | Peu commune | 5 | 6 |
| rune_precision | Rune de Précision | Critique | Rare | 30 | 0 |
// rendement du recyclage, par statistique — fonction Ax rendement = niveauObjet × valeurStat × poids × (6000/10000) / (40 × poids) // crit : valeurStat est multipliée par 100 en amont // pas de progression par palier — fonction Px pas = max(1, round(maxDeBase × 800/10000)) // stats entières pas = max(0.001, round(maxDeBase × 0.08 × 1000)/1000) // crit // coût en runes d'un palier — fonction Rx coût = max(1, round(runeCount × max(1, poids))) // XP de métier pour passer du niveau n à n+1 — fonction at xp = 4 × n²
Le moteur maintient deux vocabulaires pour les mêmes statistiques. Un vocabulaire historique — esprit, intelligence, adresse, chance — et le vocabulaire courant — savoir, agilite, flux. La fonction Ot() traduit le premier vers le second :
function Ot(o){
if(!o) return {};
const e = {...o};
return e.esprit != null && (e.savoir = (e.savoir ??0)+e.esprit, delete e.esprit),
e.intelligence != null && (e.savoir = (e.savoir ??0)+e.intelligence, delete e.intelligence),
e.adresse != null && (e.agilite = (e.agilite??0)+e.adresse, delete e.adresse),
e.chance != null && (e.flux = (e.flux ??0)+e.chance, delete e.chance),
e
}
Le recyclage l'applique. La forge, non. Les deux fonctions sont voisines dans le même module :
// recyclage — passe par lu(), donc par Ot()
function Lx(o,e,t,i){ … const n = lu(o,t); for(const a of Object.keys(n)){ … } }
function lu(o,e){ return Ot(e ?? S[o]?.bonuses) }
// forge — lit les clés brutes de la définition d'objet
function Eo(o){
const e = S[o];
return …: Object.keys(e.bonuses).filter(t => bl(o,t)!=null && Zs(t)!=null)
}
function bl(o,e){ … const t = S[o]?.bonusRange?.[e]; return t ? t[1] : void 0 }
Mode A — clé historique des deux côtés. bonuses et bonusRange disent tous les deux chance ou intelligence. Ils sont cohérents entre eux, bl() répond correctement, mais aucune rune n'est enregistrée sous ces clés : la table xi indexe flux et savoir. C'est le test Zs(t)!=null qui rejette.
relic_whisper bonuses {chance:14} bonusRange {chance:[10,18]} Eo() → []
mystic_ring bonuses {intelligence:3} bonusRange {intelligence:[2,4]} Eo() → []
Mode B — désaccord entre les deux tables. bonuses dit adresse, bonusRange dit agilite. C'est bl() qui renvoie undefined.
veilleur_dagger bonuses {attack:16, adresse:34, force:12, crit:.14}
bonusRange {force:[9,15], agilite:[25,43], attack:[12,20], crit:[.1,.18]}
Eo() → ["attack","force","crit"] // agilité absente
La construction de la liste latérale filtre les objets sans statistique forgeable :
gearCells(e){
for(const i of this.player.inventory){
…|| e==="upgrade" && Eo(i.id).length===0 || t.push({…})
}
}
Conséquence : la Relique du Murmure et l'Anneau mystique ne sont pas affichés du tout dans l'onglet Forgemagie. Le joueur ne voit pas le message ui.runesmith.no_upgradable_stats — il ne voit rien. Cette chaîne est de fait du code mort pour ces objets.
| Niv. | Objet | Statistique perdue | Mode | Reste forgeable |
|---|---|---|---|---|
| 100 | Colossus Blade mythique | Agilité | B | attack, force, vitalité, crit |
| 100 | Watcher's Dagger mythique | Agilité (34 — sa plus grosse statistique) | B | attack, force, crit |
| 80 | Obsidian Glaive mythique | Agilité | B | attack, force, crit |
| 80 | Bloodstone Dagger mythique | Agilité (21–35) | B | attack, force, crit |
| 60 | Cobalt Blade mythique | Flux | A | agilité, attack, crit |
| 60 | Opal Dagger épique | Flux | A | agilité, attack, crit |
| 20 | Relique du Murmure | Flux | A | aucune — objet absent de la liste |
| 10 | Anneau mystique | Savoir | A | aucune — objet absent de la liste |
Les cinq Reliques sont touchées. La liste complète des 36 objets figure en annexe A.
L'indice qui explique tout. La table Wg/Ug — 13 objets — utilise les clés courantes et ne présente aucun défaut. Les 65 autres objets ne sont jamais passés par cette table et ont conservé leurs clés historiques. Il s'agit d'une migration de données commencée puis interrompue, pas d'une erreur de logique.
Pour les objets en mode A, la même absence de normalisation touche l'affichage : mi() cherche bonusRange['flux'] sur un jet déjà normalisé, alors que la table dit chance. Ces objets perdent donc aussi leur fourchette (min–max) et leur couleur de qualité de jet, en infobulle comme à l'hôtel des ventes. Le joueur ne peut pas juger si son arme a bien roulé.
Les deux moitiés sont nécessaires, corriger une seule laisse l'autre mode actif :
Ot() à bonuses et à bonusRange au moment de la construction du catalogue, une fois pour toutes. C'est le correctif structurel : il supprime les deux modes et prévient toute récidive sur un futur objet.Eo() itère sur Object.keys(Ot(e.bonuses)) et bl() résout la clé via Ot() avant lecture.Test de non-régression suggéré : pour chaque objet du catalogue, vérifier que Eo(id) retourne exactement les clés de Ot(bonuses) qui possèdent une rune. L'assertion tient en cinq lignes et couvre définitivement la classe de bug.
La fonction de rendement du recyclage multiplie puis divise par le même terme :
function Ax(o,e,t,i){
const s = xi[Zs(e) ?? ""];
if(!s) return 0;
const r = S[o],
n = Math.max(1, Math.floor(r?.levelReq ?? 1)),
a = e === "crit" ? Math.abs(t)*100 : Math.abs(t);
return a <= 0 ? 0 : n*a*s.weight*(i.yieldPct/1e4)/(i.levelDiv*s.weight);
}
L'évaluation se faisant de gauche à droite, s.weight se simplifie exactement. Le rendement se réduit à niveau × valeur × 0,015, quelle que soit la rareté de la rune. Or le coût, lui, applique bien le poids (Rx). La rareté ne joue donc que d'un côté de l'équation.
Écart mesuré sur des objets réels du catalogue, en nombre d'objets à recycler pour financer une chaîne complète de la même statistique :
| Objet | Statistique | Recyclage rend | Chaîne coûte | Ratio |
|---|---|---|---|---|
| Amulette du Gardien (72) | Flux 45 | 49 | 18 | 1 objet finance 2,7 chaînes |
| Ceinturon du Fossoyeur (66) | Force 24 | 24 | 18 | 1 objet finance 1,3 chaîne |
| Capuche du Fossoyeur (58) | Agilité 7 | 6 | 18 | 3,0 objets par chaîne |
| Amulette du Gardien (72) | Dégâts 6 | 6 | 90 | 15,0 objets par chaîne |
| Amulette du Gardien (72) | Critique 6,3 % | 7 | 540 | 77,1 objets par chaîne |
| Anneau spectral (38) | Critique 4,3 % | 2 | 540 | 270,0 objets par chaîne |
Un facteur 730 entre le flux et le critique de l'Anneau spectral. En pratique : les statistiques principales passent OVER quasi gratuitement — un seul objet recyclé en finance deux ou trois montées complètes — pendant que le critique est hors d'atteinte.
L'or ne rééquilibre rien : les 58 000 or d'une chaîne sont identiques quelle que soit la statistique. Une chaîne de critique et une chaîne de vitalité coûtent le même or, pour un rapport de 1 à 30 en runes.
Argument en faveur de l'hypothèse « bug » plutôt que « choix ». En retirant uniquement le s.weight du dénominateur, l'échelle se resserre entre 0,4 et 2,8 objets par chaîne pour toutes les statistiques. Cette cohérence retrouvée suggère fortement que le facteur au dénominateur est un reliquat, et non une intention.
Note de portée : l'encart « Vous obtiendrez » du panneau de recyclage est calculé côté client par Lx(itemId, $x, rolled), donc avec cette formule. Si le serveur applique une formule corrigée, l'aperçu affiché au joueur est faux — ce qui reste un défaut à corriger, simplement pas au même endroit.
Trancher d'abord l'intention de design, puis aligner client et serveur sur la même constante :
s.weight du dénominateur.s.weight du numérateur, et documenter que weight est un multiplicateur de coût seulement.Dans les deux cas, écrire la formule sans terme simplifiable rend l'intention lisible à la relecture.
Les notes de version annoncent : « Pour cette bêta, tout le monde joue au niveau 100 : tu accèdes directement à la fin de partie et tu testes les nouveaux systèmes sans farmer. »
État constaté des deux personnages disponibles, tous deux niveau 100 :
| Personnage | Classe | Équipement porté | Sac | Or | PV |
|---|---|---|---|---|---|
| BetaTestDuck | Arcaniste | Aucun | Vide | 0 | 1 / 1040 |
| drsd | Sentinelle | Aucun | 25 consommables, aucun équipement | 18 | 2 / 1040 |
Or la fonctionnalité exige d'abord de l'équipement à recycler, puis 2 000 or pour le premier palier — le plus modeste. Un testeur qui se connecte pour la fenêtre de 72 h doit donc farmer avant de pouvoir toucher au système qu'on lui demande de tester, ce que la note de version présente précisément comme évité.
Point annexe à vérifier : les deux personnages apparaissent à 1 et 2 points de vie sur 1040 à la connexion, sans avoir combattu.
Doter les personnages de bêta d'un lot de départ : quelques pièces d'équipement de niveau 60–100 couvrant des statistiques variées (dont au moins une arme mythique et une Relique, qui sont justement les objets touchés par RS-01), une réserve de runes, et de quoi couvrir plusieurs chaînes complètes en or. Sans cela, la fenêtre de test ne produira que des retours sur l'interface, pas sur l'équilibrage.
La signature du constructeur d'objets est T(id, nom, rareté, kind, icône, stack, sell, description). Les valeurs marchandes des runes suivent une série cohérente avec leur poids — jusqu'à la dernière :
rune_vigor poids 0.5 sell 1
rune_might poids 1 sell 2
rune_ward_* poids 3 sell 3
rune_power poids 5 sell 6
rune_precision poids 30 sell 0 ← rupture de série
La conséquence n'est pas seulement cosmétique. Le prédicat de vendabilité est Pu(o) = fn(o) > 0, et il filtre la grille du marchand :
const t = this.player.inventory.filter(i => { if(!Pu(i.id)) return !1; … });
La rune la plus rare du jeu n'apparaît donc pas dans la liste de vente au PNJ : elle est invendable. L'hôtel des ventes n'est pas affecté — sourceItems() ne filtre que sur quest — donc l'affirmation « Toutes s'échangent librement à l'hôtel des ventes » des notes de version reste vraie. En revanche « la rare Rune de Précision […] vaut plus » est contredite par la donnée.
Attribuer une valeur cohérente avec la série. L'extrapolation du rapport poids/valeur des quatre autres paliers place la Rune de Précision autour de 30. Si le 0 est volontaire et signifie « non vendable au PNJ », l'exprimer par un champ dédié plutôt que par un prix nul, sans quoi l'intention est indistinguable d'un oubli.
Le critique est stocké en fraction (0,063 pour 6,3 %) et formaté en pourcentage entier :
const h = r === "crit",
p = b => h ? `${Math.round(b*100)}%` : String(Math.round(b));
Mais le pas de progression vaut 8 % du maximum de base, soit un demi-point de pourcentage sur les objets réels. Deux défauts se cumulent.
a) L'arrondi masque la progression. Séquence complète sur l'Anneau funéraire (max 0,071, pas +0,006) :
0.057 → "6%" 0.063 → "6%" 0.069 → "7%" 0.075 → "8%" 0.081 → "8%"
Le joueur paie 6 000 or et 90 Runes de Précision pour un palier 2 qui affiche 6 % → 6 %. Sur la Relique d'Ambre, trois paliers sur quatre sont invisibles.
b) Le chiffre du gain n'est pas formaté. Le bandeau central utilise la valeur brute, sans passer par p() :
${m > 0 ? `<div class="rd-rs-ba-gain">${F(l("ui.runesmith.stat_gain", {n: m}))}</div>` : ""}
La chaîne ui.runesmith.stat_gain valant +{n}, l'écran affiche +0.006 au lieu de +0,6 pt. Le message de succès (applyUpgradeOutcome) reproduit le même arrondi entier.
Afficher le critique avec une décimale (6,3 % → 6,9 %) et faire passer le gain par le même formateur que les valeurs avant/après. Le pas étant par construction inférieur à un point de pourcentage, un affichage entier ne peut structurellement pas rendre compte d'un palier.
Le texte affiché dans le panneau des métiers (ui.jobs.runist_level_b) annonce :
« Recycler et perfectionner rapportent de l'XP de Runiste. Un niveau plus élevé débloque des paliers de forgemagie supérieurs. »
Le panneau affiche Niveau Runiste {n} / 200 avec une barre calculée sur e/200*100. Or les prérequis de la table de forge sont jobReq: 1, 1, 5, 12, 20 : le dernier palier — le seul comportant un risque de destruction — est débloqué au niveau 20.
La courbe d'XP des métiers d'artisanat est 4n² par niveau, soit en cumulé :
| Jalon | XP cumulée | Part du total |
|---|---|---|
| Niveau 20 — dernier palier débloqué | 9 880 | 0,09 % |
| Niveau 200 — plafond du métier | 10 586 800 | 100 % |
Autrement dit, 0,09 % de la progression du métier débloque 100 % du contenu mécanique. Par ailleurs, jobLevel("runesmith") n'apparaît que quatre fois dans tout le bundle : l'affichage du badge de métier, deux notifications de montée de niveau, et le test G < b.jobReq. Rien d'autre ne dépend du niveau — ni bonus de réussite, ni réduction de coût.
Deux lectures possibles, à trancher côté design. Soit il manque un palier supplémentaire — l'interface l'annonce déjà : ui.runesmith.max_tier_reached dit « Palier maximum atteint · le palier exo arrive bientôt » et exo_soon_body évoque un palier ultime brûlant du $VALORA. Soit le plafond du métier devrait être aligné sur son contenu réel, autour de 20–25.
À court terme, reformuler la phrase pour ne plus promettre une progression qui s'arrête à 10 % de la barre. À moyen terme, donner un effet continu au niveau de métier — par exemple quelques points de base de réussite ou une réduction du coût en runes par tranche de niveaux — de sorte que la barre affichée corresponde à un gain réel.
Deux gardes différentes, aucune des deux alignée sur le coût réel de l'erreur.
// recyclage : confirmation à partir de « rare » seulement
onRecycleClick(e){ this.busy || (St[e.def.rarity] >= 2 ? this.openRecycleConfirm(e) : this.doRecycle(e)) }
// forge : confirmation seulement si l'objet peut être détruit
onUpgradeClick(e,t,i){ this.busy || !i || (i.def.destroyChanceBps > 0 ? this.openUpgradeConfirm(e,t,i) : this.doUpgrade(e,t)) }
Conséquences :
15 000 or et 5 runes par tentative, échec entraînant une baisse de la statistique — passe sans aucune confirmation, puisqu'il ne comporte pas de risque de destruction. C'est pourtant la tentative la plus coûteuse à rater après le palier 4.Indexer la confirmation sur la valeur en jeu plutôt que sur la rareté ou le seul risque de destruction : confirmer dès qu'une tentative peut échouer (paliers 2 à 4) et pour tout recyclage. Un simple seuil en or ou une case « ne plus demander pour cet objet » suffit à ne pas alourdir le geste répétitif.
La note annonce : « les Runes de Puissance, de Protection et la rare Rune de Précision sont plus rares et valent plus ».
| Nom cité | Objet réel | Écart |
|---|---|---|
| Rune de Puissance | rune_might — Force, commune, poids 1 | Ce nom existe en jeu, mais désigne la rune la plus abondante. Le texte visait probablement rune_power, nommée « Rune de Frappe ». |
| Rune de Protection | N'existe pas | Les runes de résistance s'appellent « Rune de Garde Terre / Flamme / Glace / Foudre ». |
| Rune de Précision | rune_precision — rare, poids 30 | Correct, mais valeur marchande à 0 (voir RS-04). |
Un joueur suivant la note à la lettre cherchera « Rune de Puissance », trouvera la rune commune de Force, et en conclura qu'elle est rare. Aligner le texte sur les noms réellement affichés en jeu.
La liste latérale accepte les objets sans instance (gearCells ne teste pas instanceId), mais la forge les refuse et réutilise le message d'indisponibilité du service :
if(!this.econ?.authoritative() || e.instanceId == null){ w.cue("ui_error"), this.setStatus(l("ui.runesmith.err_disabled"), "bad"); // « L'Atelier des Runes est momentanément indisponible. » … }
Un objet listé mais non instancié produit donc un message annonçant une panne de service. Soit exclure ces objets de la liste, soit leur donner un message spécifique.
La Rune de Vigueur est la seule à porter un poids inférieur à 1. Ce poids n'a d'effet nulle part :
Rx calcule max(1, round(runeCount × max(1, poids))).La vitalité coûte donc exactement le même nombre de runes qu'une statistique commune de poids 1. Soit l'écrêtage doit disparaître, soit le poids doit valoir 1 — en l'état la donnée exprime une intention que le code n'applique pas. À traiter avec RS-02, dont il est le corollaire.
Ix.tiers[0] (succès 100 %, coût nul) n'est jamais atteignable : tc() calcule floor(tier)+1 et démarre donc à l'indice 1. Entrée morte, source de confusion à la lecture de la table.Tx(o,e) se réduit à Math.round(o) pour tout o positif, et son second paramètre n'est pas utilisé.ui.runesmith.over_tag et ui.runesmith.overcap_tag, portent la même valeur « OVER » et sont utilisées dans des modules différents. Un renommage de l'une ne suivra pas l'autre.ui.runesmith.upgrade_soon_title / upgrade_soon_body (« La forgemagie arrive bientôt ») datent de l'état antérieur et ne sont plus atteignables.La fonction qui qualifie un jet, et donc décide de l'affichage du marqueur OVER, sort avant d'avoir testé le dépassement :
function Fm(o,e,t){ // o = valeur du jet, e = min, t = max
if(!(t > e)) return "none"; // sortie anticipée
if(o > t) return "exo"; // test OVER — jamais atteint si min == max
if(o >= t) return "perfect";
const i = (o-e)/(t-e);
return i >= 2/3 ? "high" : i >= 1/3 ? "mid" : "low";
}
Le jour où un objet à statistique garantie est ajouté — fourchette [5,5] —, la forge fonctionnera mais le marqueur OVER restera invisible partout : sac, hôtel des ventes, échange. Le symptôme sera silencieux et difficile à rattacher à sa cause. Déplacer le test o > t avant la garde clôt le sujet définitivement.
Reconstruction du catalogue final après application du pipeline de fusion du bundle. « Mode A » : clé historique cohérente des deux côtés, rejet par Zs(). « Mode B » : désaccord entre bonuses et bonusRange, rejet par bl().
| Niv. | Rareté | Emplacement | Objet | Perdu | Reste forgeable |
|---|---|---|---|---|---|
| 100 | mythique | arme | Colossus Blade | agilité | attack, force, vitalité, crit |
| 100 | mythique | arme | Watcher's Dagger | agilité | attack, force, crit |
| 80 | mythique | arme | Obsidian Glaive | agilité | attack, force, crit |
| 80 | mythique | arme | Bloodstone Dagger | agilité | attack, force, crit |
| 60 | mythique | arme | Cobalt Blade | flux | agilité, attack, crit |
| 60 | épique | arme | Opal Dagger | flux | agilité, attack, crit |
| 40 | mythique | arme | Lame du Serment | agilité | attack, force, vitalité, crit |
| 40 | mythique | arme | Lame du Titan | agilité | attack, force, crit |
| 32 | épique | arme | Glaive doré | agilité | attack, force, crit |
| 30 | épique | arme | Tranchant d'améthyste | flux | agilité, attack, crit |
| 28 | épique | arme | Dague sanglante | agilité | attack, force, crit |
| 22 | épique | bouclier | Bouclier radieux | savoir | vitalité, resFlamme, resGlace |
| 22 | épique | bottes | Jambières du seigneur | agilité | vitalité |
| 22 | épique | arme | Lame d'ébène | agilité | attack, force, crit |
| 20 | épique | amulette | Amulette d'émeraude | savoir | vitalité |
| 20 | épique | cape | Cape d'ombre | agilité | vitalité |
| 20 | relique | relic2 | Relique d'Ambre | agilité | force, crit |
| 20 | relique | relic3 | Relique du Glas Noir | savoir, flux | vitalité, force, agilité |
| 20 | relique | relic4 | Relique du Veilleur | flux | agilité |
| 20 | relique | relic5 | Relique du Trône Brisé | savoir | force |
| 20 | relique | relic6 | Relique du Murmure | flux | aucune — absente de la liste |
| 20 | rare | arme | Épée d'argent | flux | attack, crit |
| 16 | rare | bottes | Bottes du chasseur | agilité | force |
| 15 | rare | amulette | Amulette d'esprit | savoir | vitalité |
| 14 | rare | ceinture | Ceinture mystique | savoir | vitalité |
| 12 | peu commun | bottes | Bottes de l'Apprenti | agilité | vitalité |
| 11 | peu commun | bottes | Bottes d'éclaireur | agilité | vitalité |
| 10 | rare | anneau | Anneau mystique | savoir | aucune — absent de la liste |
| 8 | rare | anneau | Anneau d'os | savoir | vitalité |
| 8 | peu commun | casque | Béguin de l'Apprenti | agilité | vitalité |
| 8 | peu commun | amulette | Talisman des bois | savoir | vitalité, agilité |
| 7 | rare | casque | Chapeau ensorcelé | savoir | vitalité |
| 7 | peu commun | cape | Cape de soie Azurine | agilité | vitalité |
| 6 | peu commun | cape | Cape du voyageur | agilité | vitalité |
| 6 | commun | bottes | Bottes de voyage | agilité | vitalité |
| 6 | peu commun | cape | Cape de l'Apprenti | savoir | vitalité |
Rendement du recyclage et coût d'une chaîne complète (paliers 1 à 4), calculés avec les formules du bundle sur les valeurs de référence de Wg.
| Objet | Statistique | Valeur | Rendement | Coût chaîne | Ratio |
|---|---|---|---|---|---|
| Amulette du Gardien niv. 72, mythique | Vitalité | 23 | 25 | 18 | 1 objet = 1,4 chaîne |
| Flux | 45 | 49 | 18 | 1 objet = 2,7 chaînes | |
| Dégâts | 6 | 6 | 90 | 15,0 objets / chaîne | |
| Critique | 6,3 % | 7 | 540 | 77,1 objets / chaîne | |
| Anneau funéraire niv. 62, épique | Vitalité | 12 | 11 | 18 | 1,6 objet / chaîne |
| Force | 31 | 29 | 18 | 1 objet = 1,6 chaîne | |
| Savoir | 8 | 7 | 18 | 2,6 objets / chaîne | |
| Critique | 5,7 % | 5 | 540 | 108,0 objets / chaîne | |
| Ceinturon du Fossoyeur niv. 66, épique | Vitalité | 25 | 25 | 18 | 1 objet = 1,4 chaîne |
| Force | 24 | 24 | 18 | 1 objet = 1,3 chaîne | |
| Dégâts | 6 | 6 | 90 | 15,0 objets / chaîne | |
| Anneau spectral niv. 38, mythique | Vitalité | 10 | 6 | 18 | 3,0 objets / chaîne |
| Agilité | 24 | 14 | 18 | 1,3 objet / chaîne | |
| Force | 6 | 3 | 18 | 6,0 objets / chaîne | |
| Critique | 4,3 % | 2 | 540 | 270,0 objets / chaîne |
Valeur interne et rendu à l'écran, pour les quatre objets du catalogue portant du critique dans une fourchette. Les paliers dont l'affichage ne bouge pas sont ceux où le joueur ne voit aucun retour de son investissement.
| Objet | Max | Pas | Base → palier 1 → 2 → 3 → 4 |
|---|---|---|---|
| Anneau spectral | 0,054 | +0,004 | 4% → 5% → 5% → 6% → 6% |
| Anneau funéraire | 0,071 | +0,006 | 6% → 6% → 7% → 8% → 8% |
| Amulette du Gardien | 0,079 | +0,006 | 6% → 7% → 8% → 8% → 9% |
| Relique d'Ambre | 0,040 | +0,003 | 3% → 3% → 4% → 4% → 4% |