diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..60e1a458 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# Tool-generated artifacts: keep them committed (runtime/deploy needs them), +# but collapse them in diffs/PR review and language stats. +data/**/generated/** linguist-generated -diff +data/**/overlay/** linguist-generated +# Hand-curated overlay entries must stay reviewable. +data/**/overlay/special_mods.json -linguist-generated diff +examples/demo-bd-test/builds/*/meta.json linguist-generated -diff diff --git a/.gitignore b/.gitignore index b4e04136..d40ab2db 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ /target-gate/ /target-master/ /target-dualrun/ +# vendor-delta 报告的 codeload tarball 缓存(pipeline/diff-vendor-calcs.sh) +/.cache/ # 本机相关的 cargo 配置(网络卷开发时 target-dir 重定向到本地盘) /.cargo/config.toml diff --git a/Cargo.lock b/Cargo.lock index c2cfea6e..9217c09c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -333,7 +333,7 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "lint-i18n" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-i18n", ] @@ -393,7 +393,7 @@ dependencies = [ [[package]] name = "pobr-build" -version = "0.0.2" +version = "0.0.3" dependencies = [ "base64", "criterion", @@ -410,7 +410,7 @@ dependencies = [ [[package]] name = "pobr-cli" -version = "0.0.2" +version = "0.0.3" dependencies = [ "clap", "pobr-build", @@ -424,7 +424,7 @@ dependencies = [ [[package]] name = "pobr-core" -version = "0.0.2" +version = "0.0.3" dependencies = [ "aho-corasick", "criterion", @@ -435,7 +435,7 @@ dependencies = [ [[package]] name = "pobr-data" -version = "0.0.2" +version = "0.0.3" dependencies = [ "serde", "serde_json", @@ -443,7 +443,7 @@ dependencies = [ [[package]] name = "pobr-data-adapter" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-data", "serde", @@ -452,7 +452,7 @@ dependencies = [ [[package]] name = "pobr-desktop" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-build", "pobr-core", @@ -462,7 +462,7 @@ dependencies = [ [[package]] name = "pobr-gamedata" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-core", "pobr-data", @@ -473,7 +473,7 @@ dependencies = [ [[package]] name = "pobr-i18n" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-data", "serde", @@ -483,7 +483,7 @@ dependencies = [ [[package]] name = "pobr-item" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-core", "pobr-data", @@ -491,7 +491,7 @@ dependencies = [ [[package]] name = "pobr-trade" -version = "0.0.2" +version = "0.0.3" dependencies = [ "serde", "serde_json", @@ -500,7 +500,7 @@ dependencies = [ [[package]] name = "pobr-tree" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-data", "serde", @@ -510,7 +510,7 @@ dependencies = [ [[package]] name = "pobr-wasm" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-build", "pobr-core", @@ -525,7 +525,7 @@ dependencies = [ [[package]] name = "precompile-mods" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-core", "pobr-data", @@ -699,7 +699,7 @@ dependencies = [ [[package]] name = "sync-pob-catalog" -version = "0.0.2" +version = "0.0.3" dependencies = [ "pobr-core", "pobr-data", diff --git a/Cargo.toml b/Cargo.toml index b073a0a4..ee432da2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.0.2" +version = "0.0.3" edition = "2024" [workspace.dependencies] diff --git a/apps/pobr-cli/src/lib.rs b/apps/pobr-cli/src/lib.rs index aac30be0..7acb6765 100644 --- a/apps/pobr-cli/src/lib.rs +++ b/apps/pobr-cli/src/lib.rs @@ -584,6 +584,10 @@ fn explain_tag(tag: &ModTag) -> TagExplain { kind: "SkillTypes".to_string(), detail: format!("限技能类型 {st:?}"), }, + ModTag::SkillTypesNeg(st) => TagExplain { + kind: "SkillTypesNeg".to_string(), + detail: format!("排除技能类型 {st:?}"), + }, ModTag::SkillName { names } => TagExplain { kind: "SkillName".to_string(), detail: format!("仅当主技能是 `{}` 时生效", names.join("` / `")), diff --git a/apps/pobr-desktop/src/lib.rs b/apps/pobr-desktop/src/lib.rs index f8a3c08f..09a8574e 100644 --- a/apps/pobr-desktop/src/lib.rs +++ b/apps/pobr-desktop/src/lib.rs @@ -31,6 +31,7 @@ pub fn example_build() -> Build { base: ItemBaseId::from("Iron Ring"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec![ "+25 to maximum Life".to_string(), diff --git a/apps/pobr-wasm/src/build_api/analysis.rs b/apps/pobr-wasm/src/build_api/analysis.rs index fb1cf71a..260cd18c 100644 --- a/apps/pobr-wasm/src/build_api/analysis.rs +++ b/apps/pobr-wasm/src/build_api/analysis.rs @@ -248,6 +248,7 @@ fn apply_variant( gem_level: gem.level, quality: gem.quality, stat_set_index: None, + name_spec: None, }); if let Some(effect) = data.gem_effects.get(&gem.skill_id) { group.gem_ids.push(effect.gem_id.clone()); diff --git a/apps/pobr-wasm/src/build_api/request.rs b/apps/pobr-wasm/src/build_api/request.rs index b3de7e7f..ee61a6c2 100644 --- a/apps/pobr-wasm/src/build_api/request.rs +++ b/apps/pobr-wasm/src/build_api/request.rs @@ -192,6 +192,7 @@ fn socket_group_from_input(input: &SocketGroupInput, data: &BuildData) -> Socket gem_level: gem.level, quality: gem.quality, stat_set_index: None, + name_spec: None, }); if let Some(gem_id) = gem_id { group.gem_ids.push(gem_id); diff --git a/apps/pobr-wasm/tests/contract_golden.rs b/apps/pobr-wasm/tests/contract_golden.rs index 802b4a9b..dd156dba 100644 --- a/apps/pobr-wasm/tests/contract_golden.rs +++ b/apps/pobr-wasm/tests/contract_golden.rs @@ -1135,21 +1135,30 @@ fn memory_backend_matches_dir_backend() { let request = serde_json::json!({ "pob_code": demo_code() }).to_string(); let from_dir = pobr_wasm::calculate_build_json(&request).expect("dir backend"); - // 把版本目录整体读入内存表,走 stage/init 路径重建。 + // 把版本目录整体读入内存表,走 stage/init 路径重建。版本无关策展层 + // `data/overlay-common/`(P1-3)位于版本目录的兄弟路径,内存后端按 + // `overlay-common/` 键解析(见 `pobr-gamedata::paths::overlay_common_path`), + // 生产 wasm 流程(web sync-data)同样打包该目录——staging 必须一并灌入, + // 否则内存后端静默丢失全部 curated special_mods。 let root = repo_data_root().join(pobr_data::GOLDEN_PARITY_DATA_VERSION); - for entry in walk_files(&root) { - // GameData 只读 JSON;跳过杂项文件(.DS_Store 等)。 - if entry.extension().and_then(|e| e.to_str()) != Some("json") { - continue; + let common_root = repo_data_root().join("overlay-common"); + let stage_tree = |tree_root: &std::path::Path, key_prefix: &str| { + for entry in walk_files(tree_root) { + // GameData 只读 JSON;跳过杂项文件(.DS_Store 等)。 + if entry.extension().and_then(|e| e.to_str()) != Some("json") { + continue; + } + let rel = entry + .strip_prefix(tree_root) + .unwrap() + .to_string_lossy() + .replace('\\', "/"); + let content = std::fs::read_to_string(&entry).expect("read data file"); + pobr_wasm::stage_data_file(&format!("{key_prefix}{rel}"), &content); } - let rel = entry - .strip_prefix(&root) - .unwrap() - .to_string_lossy() - .replace('\\', "/"); - let content = std::fs::read_to_string(&entry).expect("read data file"); - pobr_wasm::stage_data_file(&rel, &content); - } + }; + stage_tree(&root, ""); + stage_tree(&common_root, "overlay-common/"); pobr_wasm::init_staged_data().expect("init memory backend"); let from_memory = pobr_wasm::calculate_build_json(&request).expect("memory backend"); assert_eq!( diff --git a/apps/pobr-wasm/tests/tier_lines.rs b/apps/pobr-wasm/tests/tier_lines.rs index 62cd4b59..c09fe440 100644 --- a/apps/pobr-wasm/tests/tier_lines.rs +++ b/apps/pobr-wasm/tests/tier_lines.rs @@ -46,11 +46,16 @@ fn current_data_annotates_explicit_tiers() { } /// 优雅降级:无 tier 池字段(group/spawn_weights)的数据包不标 tier。 -/// 显式钉 4.5.0.3.4——它早于 tier 数据通道,缺池字段;golden 版(4.5.4.3 起) -/// 已含池数据会标 tier,故此降级用例不能再借 `GOLDEN_PARITY_DATA_VERSION`。 +/// 显式钉 4.5.0.3.4——这是「早于 tier 数据通道的旧格式包」的 fixture 钉(非数据 +/// 内容计数钉,不进 test_pins 快照);golden 版(4.5.4.3 起)已含池数据会标 +/// tier,故此降级用例不能借 `GOLDEN_PARITY_DATA_VERSION`。旧包被清理时跳过。 #[test] fn golden_data_without_pool_fields_omits_tiers() { let dir = repo_data_root().join("4.5.0.3.4"); + if !dir.is_dir() { + eprintln!("SKIP: 旧格式 fixture 数据包 4.5.0.3.4 不在仓库(已清理)"); + return; + } let lines = classify(dir.to_str().unwrap()); assert!( lines.iter().all(|l| l.get("tier").is_none()), diff --git a/apps/pobr-wasm/tests/unsupported_specials.rs b/apps/pobr-wasm/tests/unsupported_specials.rs index db2e36e4..b4cec050 100644 --- a/apps/pobr-wasm/tests/unsupported_specials.rs +++ b/apps/pobr-wasm/tests/unsupported_specials.rs @@ -1,6 +1,11 @@ //! 药剂/护符使用效果类词条经 special 表解析为正确机制语义,不再进未支持报表: -//! 免疫 → *Immune flag、Guard → GuardAbsorbRate/Limit(承受层真实吸收)、 -//! 瞬时回魔/魔力溢出/附身 → 结构化 mod 登记(vendor 对照与来源见 overlay source_note)。 +//! 免疫 → *Immune flag、瞬时回魔/魔力溢出/附身 → 结构化 mod 登记(vendor 对照 +//! 与来源见 overlay source_note)。 +//! +//! 例外:`Also grants N Guard` 曾被策展条目 also_grants_guard 建模为承受层吸收, +//! 但 vendor ModParser 根本不解析它——对 PoB2 golden 是幻影 Guard 池(存量 #7 +//! 摘除,ritualist EHP 1.10x→1.00x)。与 PoB2 对齐后它回到「未建模 → 响亮进 +//! unsupported 报表、不影响 hit pool」的口径。 use pobr_gamedata::repo_data_root; use serde_json::{Value, json}; @@ -53,27 +58,33 @@ fn charm_flask_use_effect_lines_are_recognized() { "Recover 295 Mana when Used", "Mana Recovery from Flasks can Overflow maximum Mana during Effect", "Possessed by Spirit Of The Stag for 19 seconds on use", - "Also grants 481 Guard", ] { assert!( !unsupported.iter().any(|u| u.contains(line)), "`{line}` 仍在未支持列表: {unsupported:?}" ); } + // guard 行未建模(vendor 同样不解析)——必须响亮上报而非静默丢弃。 + assert!( + unsupported + .iter() + .any(|u| u.contains("Also grants 481 Guard")), + "`Also grants 481 Guard` 应进未支持列表(#7 摘除幻影建模后与 PoB2 口径一致): {unsupported:?}" + ); } #[test] -fn guard_line_extends_hit_pool() { +fn guard_line_does_not_extend_hit_pool() { let dir = repo_data_root().join(pobr_gamedata::data_version()); pobr_wasm::init_data_from_dir(dir.to_str().unwrap()).expect("init data"); let without = calculate(false); let with = calculate(true); - // Guard 是生命/ES 前的全额吸收池(agent-docs/active-defences.md §2): - // 物理 max hit 应至少提高 Guard 池大小(481)。 + // #7 摘除 also_grants_guard 幻影建模后,guard 行不得再扩大 hit pool + // (vendor 不解析该行;此前的 +481 是 PoBR 单方面多建模的幻影池)。 let delta = stat(&with, "PhysicalMaxHit") - stat(&without, "PhysicalMaxHit"); assert!( - delta >= 481.0, - "Guard 481 应扩大物理 max hit(实际增量 {delta})" + delta.abs() < 1.0, + "guard 行不应改变物理 max hit(实际增量 {delta})" ); } diff --git a/crates/pobr-build/examples/dump_components.rs b/crates/pobr-build/examples/dump_components.rs index d38deb2f..a7f763d7 100644 --- a/crates/pobr-build/examples/dump_components.rs +++ b/crates/pobr-build/examples/dump_components.rs @@ -42,6 +42,36 @@ fn main() { out.action_rate, out.hit_chance ); + // POBR_DUMP_DEFENCE=1:附加防御/EHP 池分解(与 oracle mainOutput 的 + // TotalHitPool / LifeRecoverable / MaximumHitTaken 族对照)。 + if std::env::var("POBR_DUMP_DEFENCE").is_ok() { + println!( + " life={:.2} life_unres={:.2} life_recoverable={:.2} es={:.2} es_cap={:.2} ward={:.2} mana={:.2} mana_unres={:.2}", + out.life, + out.life_unreserved, + out.life_recoverable, + out.energy_shield, + out.energy_shield_recovery_cap, + out.ward, + out.mana, + out.mana_unreserved, + ); + for (i, m) in out.minions.iter().enumerate() { + println!( + " minion[{i}]: level={} life={:.2} armour={:.2} evasion={:.2} es={:.2}", + m.level, m.life, m.armour, m.evasion, m.energy_shield, + ); + } + println!( + " maxhit: phys={:.1} fire={:.1} cold={:.1} light={:.1} chaos={:.1} total_ehp={:.1}", + out.physical_max_hit_pob2, + out.fire_max_hit_pob2, + out.cold_max_hit_pob2, + out.lightning_max_hit_pob2, + out.chaos_max_hit_pob2, + out.total_ehp_pob2, + ); + } let mut sum = 0.0; for c in &out.damage_components { let avg = c.avg(); diff --git a/crates/pobr-build/src/build.rs b/crates/pobr-build/src/build.rs index 3c8e219b..93732a10 100644 --- a/crates/pobr-build/src/build.rs +++ b/crates/pobr-build/src/build.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use pobr_data::build_config::ViewMode; use pobr_data::item::{EquipmentSlot, Item}; -use pobr_data::passive_tree::{NodeId, PassiveTreeSpec}; +use pobr_data::passive_tree::PassiveTreeSpec; use crate::build_config::BuildConfig; @@ -37,6 +37,12 @@ pub struct GemSkillRef { /// `"nil"`,解析归一化为 `None`)。`statSetIndexCalcs`(calcs 页独立选择) /// M1 不做,解析忽略。 pub stat_set_index: Option, + /// PoB `` 显示名——仅当 XML 缺 `skillId`/`gemId`(lineage + /// support 如 Atziri's Communion 的序列化形态)时携带,`skill_id` 此时为空串。 + /// 编排层 `stage_build_view` 按显示名归一匹配 granted_effects 回填 + /// `skill_id`(PoB2 SkillsTab 按 nameSpec 反查 gem 的等价物);未解析成功 + /// 的引用在全部消费点因 `granted_effects.get("")` 落空而惰性跳过。 + pub name_spec: Option, } /// 一组同插槽的技能宝石(主动技能 + 其辅助)。简化等价物:用稳定 gem id 表示。 @@ -128,6 +134,7 @@ impl SocketGroup { gem_level, quality, stat_set_index: None, + name_spec: None, }); self } @@ -144,6 +151,7 @@ impl SocketGroup { gem_level, quality: 0, stat_set_index: Some(stat_set_index), + name_spec: None, }); self } @@ -211,15 +219,6 @@ pub struct Build { /// `jewels` 注入珠宝**自身**的全局词条,本列表额外按半径几何把 `also grant` 展开为 /// 「半径内已分配对应种类节点数 × 授予」的全局 mod(见 `calc_orchestrator`)。 pub radius_jewels: Vec, - /// 非激活武器组专属点(`` 中属于未激活组的已分配节点)。 - /// - /// 这些节点的**自身** mod 已在解析层 masking(不进 [`Self::tree`] 的 `allocated_nodes`, - /// 等价 PoB2 `Condition: WeaponSet` 门控);但 PoB2 仍把它们留在 `allocNodes`, - /// 因此**范围珠宝授予**(`... in Radius also grant`)按 PoB2 语义仍会落到这些节点上 - /// (CalcSetup.lua:209-228,授予源=jewel、按 jewel allocMode 门控)。此列表供 - /// `radius_jewel_expansions` 在 radius 几何里并回完整已分配集,复刻该行为。 - /// 无武器组切换的 build 此列表为空,对计算零影响。 - pub inactive_weapon_set_nodes: Vec, /// **激活态**药剂/护符的「槽名 + 物品」(M3-T4,蓝图 §7.2-2): /// `("Flask 1"|"Charm 1..3", Item)`,XML 文档序,仅 `active="true"` 的槽进入 /// (vendor CalcSetup.lua:1014-1028 `slot.active` 门控)。槽名供 flask/charm @@ -290,12 +289,6 @@ impl Build { self } - /// 设定非激活武器组专属点列表(见 [`Self::inactive_weapon_set_nodes`]),返回新副本。 - pub fn with_inactive_weapon_set_nodes(mut self, nodes: Vec) -> Self { - self.inactive_weapon_set_nodes = nodes; - self - } - /// 设定激活态药剂/护符的槽名保留列表(见 [`Self::utility_slots`]),返回新副本。 pub fn with_utility_slots(mut self, slots: Vec<(String, Item)>) -> Self { self.utility_slots = slots; @@ -335,6 +328,7 @@ mod tests { base: ItemBaseId::from("Iron Ring"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec!["+10 to maximum Life".into()], enchant_texts: vec![], diff --git a/crates/pobr-build/src/build_data.rs b/crates/pobr-build/src/build_data.rs index f40e2222..80625abc 100644 --- a/crates/pobr-build/src/build_data.rs +++ b/crates/pobr-build/src/build_data.rs @@ -752,6 +752,9 @@ impl BuildData { .get(skill_id) .map(|rows| { rows.iter() + // alt 品质 stat 仅 GemlingQuality build 生效,走 + // [`Self::alt_quality_stats`] 由消费方按 flag 叠加。 + .filter(|q| !q.alt) .map(|q| SkillDamageStat { stat: q.stat.clone(), // trunc(toward zero),对齐 math.modf 整数部分。 @@ -770,6 +773,32 @@ impl BuildData { } } + /// alt 品质 stat(vendor `altQualityStats`)在给定品质下的 trunc 值。 + /// + /// 仅当 build 带 GemlingQuality flag(Gemling 升华『Gem Quality grants + /// Socketed Skills an additional effect』)时叠加进技能 stat 集 + /// (PoB2 `CalcTools.lua:147-152` `includeAltQualityStats`)——由消费方 + /// 判定 flag 后调用([`Self::effect_stats`] 恒不含 alt 行)。 + // ponytail: 目前只有 spirit 预留效率消费此通道(gemling parity 钉值); + // offence/statmap 侧待有 fixture 逼出偏差时再接(同一 accessor,零改数据)。 + pub fn alt_quality_stats(&self, skill_id: &str, quality: u32) -> Vec { + if quality == 0 { + return Vec::new(); + } + self.gem_quality_stats + .get(skill_id) + .map(|rows| { + rows.iter() + .filter(|q| q.alt) + .map(|q| SkillDamageStat { + stat: q.stat.clone(), + value: (q.per_quality_rate * f64::from(quality)).trunc(), + }) + .collect() + }) + .unwrap_or_default() + } + /// 取某授予效果在某 (宝石等级, 品质, statSet 形态) 下**未选 set** 的 stat 快照 /// (W-J global-only merge 的取数源,PoB2 `CalcActiveSkill.lua:124-140`: /// 选中 set 之外的每个 statSet 以 `onlyGlobals=true` 参与 merge)。 @@ -816,7 +845,7 @@ impl BuildData { if quality > 0 && let Some(rows) = self.gem_quality_stats.get(skill_id) { - for q in rows { + for q in rows.iter().filter(|q| !q.alt) { // trunc(toward zero),与 effect_stats 的品质段同语义。 *acc.entry(q.stat.clone()).or_default() += (q.per_quality_rate * f64::from(quality)).trunc(); @@ -1018,6 +1047,7 @@ mod tests { vec![QualityStat { stat: "beta".into(), per_quality_rate: 0.55, + alt: false, }], ); diff --git a/crates/pobr-build/src/calc_orchestrator/buffs.rs b/crates/pobr-build/src/calc_orchestrator/buffs.rs index c628f6b3..e1045527 100644 --- a/crates/pobr-build/src/calc_orchestrator/buffs.rs +++ b/crates/pobr-build/src/calc_orchestrator/buffs.rs @@ -183,6 +183,8 @@ pub(crate) fn buff_skill_specs(build: &Build, data: &BuildData) -> Vec socket_index, is_mark: false, ignore_curse_limit: false, + local_effect_inc: 0.0, + local_effect_more: 1.0, skill_types: pobr_data::skill::SkillTypes::NONE, }); } @@ -197,6 +199,8 @@ pub(crate) fn buff_skill_specs(build: &Build, data: &BuildData) -> Vec socket_index, is_mark: false, ignore_curse_limit: false, + local_effect_inc: 0.0, + local_effect_more: 1.0, skill_types: pobr_data::skill::SkillTypes::NONE, }); } @@ -256,6 +260,8 @@ pub(crate) fn buff_skill_specs(build: &Build, data: &BuildData) -> Vec socket_index, is_mark: false, ignore_curse_limit: false, + local_effect_inc: 0.0, + local_effect_more: 1.0, // vendor per-skill skillCfg(buff_pass 乘区对域限定词条—— // 「Banner Skills have N% increased Aura Magnitudes」的 // SkillTypes(Banner) tag——按本效果类型位匹配)。 @@ -265,8 +271,12 @@ pub(crate) fn buff_skill_specs(build: &Build, data: &BuildData) -> Vec // curse 效果词条(M3-W4):statset stat 经 statmap curse 域映射 // 为敌侧 modifier(Despair→ChaosResist 减抗、Enfeeble→Damage MORE…), // buff_pass 施 CurseEffect 乘区 + Condition:Effective 后入 enemy db。 + // (存量 #7-1)取数等级 = 宝石等级 + 适用的 `+N to Level of all + // Skills`(vendor applyGemMods 对每个 gem effect 生效, + // CalcSetup.lua:410-435——EW 19+8→27,载荷 -58→-66)。 + let curse_level = gem.gem_level + additional_gem_levels(build, data, skill_id); let es = - data.effect_stats(skill_id, gem.gem_level, gem.quality, gem.stat_set_index); + data.effect_stats(skill_id, curse_level, gem.quality, gem.stat_set_index); let set_key = data.selected_set_key(skill_id, gem.stat_set_index); // vendor 注册前置(M4-l):buffList 仅由 GlobalEffect 载荷构成 // (CalcActiveSkill.lua:976-1041),curse 表项只从 buffList 构造 @@ -290,6 +300,14 @@ pub(crate) fn buff_skill_specs(build: &Build, data: &BuildData) -> Vec continue; } let mods = curse_stat_modifiers(data, &es, skill_id, set_key.as_deref()); + // (存量 #7-1)技能局部 CurseEffect 段(vendor curse 乘区 + // CalcPerform.lua:2423/:2427 读 skillModList):curse 宝石 + // 自身品质段(EW `curse_effect_+%` 0.5/q)+ 组内**兼容** + // support(Heightened Curse constantStats +25、Atziri's + // Allure MORE -20)payload,经 statmap global 段 + // `curse_local_effect` 折算预汇入 spec。 + let (local_effect_inc, local_effect_more) = + curse_local_effect_scale(group, data, gem, skill_id, curse_level); specs.push(BuffSpec { name: buff_skill_name(data, skill_id), kind: BuffKind::Curse, @@ -300,6 +318,8 @@ pub(crate) fn buff_skill_specs(build: &Build, data: &BuildData) -> Vec socket_index, is_mark, ignore_curse_limit: false, + local_effect_inc, + local_effect_more, skill_types: pobr_data::skill::SkillTypes::NONE, }); } @@ -309,6 +329,59 @@ pub(crate) fn buff_skill_specs(build: &Build, data: &BuildData) -> Vec specs } +/// (存量 #7-1)一个 curse 技能的**技能局部** CurseEffect 乘区段 +/// (vendor CalcPerform.lua:2423 `skillModList:Sum("INC", skillCfg, +/// "CurseEffect")` + :2427 `More(...)`): +/// - curse 宝石自身 effect stats(品质段携带 `curse_effect_+%`,如 EW 0.5/q); +/// - 组内**兼容** support([`judge_group_supports`] 四段裁决,与主技能支援 +/// 判定同源)的 effect stats(Heightened Curse constantStats `curse_effect_+%` +/// +25、Atziri's Allure `support_atziri_curse_effect_+%_final` MORE -20)。 +/// +/// stat → (INC, MORE) 折算走 statmap 数据([`stat_map_engine::curse_local_effect`], +/// global 段 `curse_effect_+%` → 裸 `CurseEffect INC`)。无 catalog → (0, 1)。 +fn curse_local_effect_scale( + group: &crate::build::SocketGroup, + data: &BuildData, + gem: &crate::build::GemSkillRef, + skill_id: &str, + curse_level: u32, +) -> (f64, f64) { + let Some(catalog) = resolve_stat_map_catalog(data) else { + return (0.0, 1.0); + }; + let (mut inc, mut more) = (0.0, 1.0); + let mut absorb = |effect_id: &str, level: u32, quality: u32, set_index: Option| { + let es = data.effect_stats(effect_id, level, quality, set_index); + let set_key = data.selected_set_key(effect_id, set_index); + for ds in es.all() { + if ds.value == 0.0 { + continue; + } + let (di, dm) = stat_map_engine::curse_local_effect( + &catalog, + effect_id, + set_key.as_deref(), + &ds.stat, + ds.value, + ); + inc += di; + more *= dm; + } + }; + absorb(skill_id, curse_level, gem.quality, gem.stat_set_index); + let judgement = super::triggers::judge_group_supports(group, data, skill_id); + for sup in &judgement.compatible { + let host = &group.gem_skills[sup.gem_index]; + absorb( + &sup.effect_id, + host.gem_level, + host.quality, + sup.stat_set_index(group), + ); + } + (inc, more) +} + /// (M4-G)support 授予的**玩家侧 buff** → [`BuffSpec`](kind = [`BuffKind::Buff`], /// buff_pass Buff 分支 CalcPerform.lua:1949-1962 施 BuffEffect 乘区后并入 player db)。 /// @@ -327,57 +400,65 @@ pub(crate) fn buff_skill_specs(build: &Build, data: &BuildData) -> Vec pub(crate) fn support_buff_specs(build: &Build, data: &BuildData) -> Vec { use std::collections::HashSet; let mut specs = Vec::new(); - let mut seen: HashSet<&str> = HashSet::new(); + let mut seen: HashSet = HashSet::new(); for group in build.enabled_socket_groups() { - // 组内已启用主动技能(效果已知且非 support)。 + // 组内已启用主动技能(效果已知且非 support)。含附加授予效果 + // (overlay/gem_effects.json 外键;vendor 对 additionalGrantedEffectId1..N + // 各建独立 activeSkill,support 对其同样逐个裁决——0.5.4b #5 案例: + // Charged Staff 的隐藏附加效果 ChargedStaffShockwavePlayer 是 Attack, + // Blazing Critical 借它兼容并全局授 buff)。 let active_ids: Vec<&str> = group .gem_skills .iter() - .filter(|g| { - data.granted_effects - .get(&g.skill_id) - .is_some_and(|e| !e.is_support) + .flat_map(|g| { + std::iter::once(g.skill_id.as_str()).chain( + data.gem_effects + .get(&g.skill_id) + .into_iter() + .flat_map(|l| l.additional_granted_effect_ids.iter().map(String::as_str)), + ) }) - .map(|g| g.skill_id.as_str()) + .filter(|id| data.granted_effects.get(*id).is_some_and(|e| !e.is_support)) .collect(); if active_ids.is_empty() { continue; } // 任一主动技能裁决兼容即纳入(vendor:support 对组内逐主动技能各自判定)。 - let mut compatible: HashSet = HashSet::new(); + let mut compatible: HashSet<(usize, String)> = HashSet::new(); for active_id in &active_ids { - for idx in judge_group_supports(group, data, active_id).compatible { - compatible.insert(idx); + for sup in judge_group_supports(group, data, active_id).compatible { + compatible.insert((sup.gem_index, sup.effect_id)); } } - let mut indices: Vec = compatible.into_iter().collect(); - indices.sort_unstable(); - for idx in indices { + let mut entries: Vec<(usize, String)> = compatible.into_iter().collect(); + entries.sort_unstable(); + for (idx, effect_id) in entries { let gem = &group.gem_skills[idx]; - if !seen.insert(gem.skill_id.as_str()) { + if !seen.insert(effect_id.clone()) { continue; } - let es = data.effect_stats( - &gem.skill_id, - gem.gem_level, - gem.quality, - gem.stat_set_index, - ); - let set_key = data.selected_set_key(&gem.skill_id, gem.stat_set_index); - let mods = player_buff_stat_modifiers(data, &es, &gem.skill_id, set_key.as_deref()); + // 附加授予的 support 半身不沿用宝石实例 statSetIndex(只对主效果有意义)。 + let set_index = (gem.skill_id == effect_id) + .then_some(gem.stat_set_index) + .flatten(); + let es = data.effect_stats(&effect_id, gem.gem_level, gem.quality, set_index); + let set_key = data.selected_set_key(&effect_id, set_index); + let mods = player_buff_stat_modifiers(data, &es, &effect_id, set_key.as_deref()); if mods.is_empty() { continue; } specs.push(BuffSpec { - name: buff_skill_name(data, &gem.skill_id), + name: buff_skill_name(data, &effect_id), kind: BuffKind::Buff, - skill_id: gem.skill_id.clone(), + skill_id: effect_id.clone(), mods, magnitude: 1.0, slot: group.slot.clone(), socket_index: (idx + 1) as u32, is_mark: false, ignore_curse_limit: false, + local_effect_inc: 0.0, + local_effect_more: 1.0, skill_types: pobr_data::skill::SkillTypes::NONE, }); } @@ -478,6 +559,11 @@ pub(crate) fn spirit_reservation_modifiers( &pobr_core::CalcConfig::new(), pobr_data::prelude::ModName::from("AncestralBond"), ); + // GemlingQuality(升华『Gem Quality grants Socketed Skills an additional + // effect』):激活时宝石 altQualityStats 品质 stat 生效(CalcTools.lua:147-152), + // 预留效率经此获得(如 Mirage Archer alt `base_reservation_efficiency_+%` ×2、 + // Eternal Rage alt `base_spirit_reservation_efficiency_+%` ×0.75)。 + let use_alt_quality = super::skill_resolve::gemling_quality_flag(build, data); for group in build.enabled_socket_groups() { for gem in &group.gem_skills { let Some(effect) = data.granted_effects.get(&gem.skill_id) else { @@ -495,6 +581,12 @@ pub(crate) fn spirit_reservation_modifiers( let own = level_row(data, &gem.skill_id, gem.gem_level); let mut flat = own.and_then(|r| r.spirit_reservation_flat).unwrap_or(0.0); let mut mult = 1.0 + own.and_then(|r| r.reservation_multiplier).unwrap_or(0.0) / 100.0; + // Spirit→Life 保留转换(vendor CalcDefence.lua:248-254,0.5.4b 新增; + // Atziri's Communion support 的 constant stat + // `skill_reserves_X_life_permyriad_per_spirit_instead_of_spirit` = 66, + // SkillStatMap div=100 → 每点 Spirit 保留 0.66% Life)。命中时该技能的 + // Spirit 保留整体转为 Life 百分比保留(Spirit 置 0)。 + let mut spirit_to_life = 0.0; // 同组 support:spirit flat(ExtraSpirit)+ reservation_multiplier MORE。 for sup in &group.gem_skills { if data @@ -508,27 +600,75 @@ pub(crate) fn spirit_reservation_modifiers( flat += row.spirit_reservation_flat.unwrap_or(0.0); mult *= 1.0 + row.reservation_multiplier.unwrap_or(0.0) / 100.0; } + spirit_to_life += data + .effect_stats( + &sup.skill_id, + sup.gem_level, + sup.quality, + sup.stat_set_index, + ) + .all() + .filter(|s| { + s.stat == "skill_reserves_X_life_permyriad_per_spirit_instead_of_spirit" + }) + .map(|s| s.value / 100.0) + .sum::(); } - // Blasphemy per-curse 预留(vendor CalcDefence.lua:273-284):`IsBlasphemy` - // 效果按**被包 curse 数**各加 `blasphemy_base_spirit_reservation_per_socketed_curse` - // (constant stat = 60;vendor `supportEffect.isSupporting` 计数 ≙ 同组 - // AppliesCurse 主动技能数)。被包 curse 自身预留 0(levels 无 flat, - // 进 vendor 预留循环但 baseFlat=0——两侧一致,无需额外排除)。 let es = data.effect_stats( &gem.skill_id, gem.gem_level, gem.quality, gem.stat_set_index, ); + // Blasphemy per-curse 预留(vendor CalcDefence.lua:229-239):`IsBlasphemy` + // 效果按**被包 curse 数**各加 `blasphemy_base_spirit_reservation_per_socketed_curse` + // (constant stat = 60;vendor `supportEffect.isSupporting` 计数 ≙ 同组 + // AppliesCurse 主动技能数)。0.5.4b vendor 口径 = **先并入 baseFlat 再统一 + // 缩放 round 一次**(:236-238 `values.baseFlat += flat × instances`, + // essence-drain round(180/1.1)=164 ≠ 旧的单份 round(60/1.1)=55×3=165, + // oracle spiritReservedBreakdown 钉值 164)。被包 curse 自身预留 0 + // (levels 无 flat,vendor 同——无需额外排除)。 + if has("IsBlasphemy") { + let per_curse: f64 = es + .all() + .filter(|s| s.stat == "blasphemy_base_spirit_reservation_per_socketed_curse") + .map(|s| s.value) + .sum(); + let curse_count = group + .gem_skills + .iter() + .filter(|g| { + data.granted_effects.get(&g.skill_id).is_some_and(|e| { + !e.is_support && e.skill_types.iter().any(|t| t == "AppliesCurse") + }) + }) + .count(); + flat += per_curse * curse_count as f64; + } // 预留效率(vendor :240-243/:251 `/(1 + efficiency/100)`,clamp ≥ −100): - // - 宝石自身品质 stat `base_reservation_efficiency_+%`(q20 Blasphemy=10%); + // - 宝石自身品质 stat `base_reservation_efficiency_+%` / + // `base_spirit_reservation_efficiency_+%`(q20 Blasphemy=10%;后者是 + // Spirit 池限定形,statmap → SpiritReservationEfficiency,Spirit 预留 + // 两名同入 `/(1+eff/100)`); + // - GemlingQuality build 另叠 altQualityStats 同名 stat(Mirage Archer + // ×2 / Eternal Rage ×0.75,oracle gemling 62/23 钉值); // - 树/装备词条族(`Spirit`/裸 `ReservationEfficiency` INC,域限定经 // `ModTag::SkillTypes` 匹配——per-gem cfg 带该效果的类型位,vendor // skillCfg Sum 同口径。「Meta Skills have N% increased Reservation // Efficiency」(tree 42245/63236)对 Blasphemy/Archmage 等 Meta 效果生效)。 + const EFFICIENCY_STATS: [&str; 2] = [ + "base_reservation_efficiency_+%", + "base_spirit_reservation_efficiency_+%", + ]; + let alt_quality = if use_alt_quality { + data.alt_quality_stats(&gem.skill_id, gem.quality) + } else { + Vec::new() + }; let quality_eff: f64 = es .all() - .filter(|s| s.stat == "base_reservation_efficiency_+%") + .chain(alt_quality.iter()) + .filter(|s| EFFICIENCY_STATS.contains(&s.stat.as_str())) .map(|s| s.value) .sum(); let gem_cfg = pobr_core::CalcConfig::new() @@ -574,36 +714,61 @@ pub(crate) fn spirit_reservation_modifiers( ); // PoB2 对保留倍率乘积截断到 4 位小数后再乘 base(floor(x, 4))。 let mult = (mult * 10000.0).floor() / 10000.0; - let mut reserved = (flat * mult * res_factor / (1.0 + efficiency / 100.0) / eff_more) + // Spirit→Life 转换分支(vendor CalcDefence.lua:248-254 + per-pool 循环 + // name="Life"):Life.basePercent = Spirit.baseFlat × 每点转换率; + // 因子换用 Life 池名(LifeReserved/Reserved、LifeReservationEfficiency/ + // ReservationEfficiency;宝石品质效率项 pool 无关照除);百分比 + // round 2 位(vendor :312)。产出 `LifeReservedPercent` INC 由 + // perform 预留段消费(ritualist:Eternal Rage 155×0.66×0.9 = 92.07% + // → LifeReserved 270 / LifeUnreserved 23,golden 一致)。 + if spirit_to_life > 0.0 { + let life_reserved_names = [ + pobr_data::prelude::ModName::from("LifeReserved"), + pobr_data::prelude::ModName::from("Reserved"), + ]; + let l_inc = db.sum( + pobr_data::prelude::ModType::Inc, + &gem_cfg, + &life_reserved_names, + ); + let l_more = db.more(&gem_cfg, &life_reserved_names); + let l_factor = if l_more > 0.0 && l_inc > -100.0 { + (100.0 + l_inc) / 100.0 * l_more + } else { + 0.0 + }; + let l_eff_names = [ + pobr_data::prelude::ModName::from("LifeReservationEfficiency"), + pobr_data::prelude::ModName::from("ReservationEfficiency"), + ]; + let l_eff = (quality_eff + + db.sum(pobr_data::prelude::ModType::Inc, &gem_cfg, &l_eff_names)) + .max(-100.0); + let l_eff_more = db.more(&gem_cfg, &l_eff_names); + let percent = + (flat * spirit_to_life * mult * l_factor / (1.0 + l_eff / 100.0) / l_eff_more + * 100.0) + .round() + / 100.0; + if percent > 0.0 { + let origin = ModifierSource::new(SourceId::new( + SourceKind::SkillGem, + format!("spirit.{}", gem.skill_id), + )) + .with_raw_text(format!( + "life reservation from spirit {} ({} × {spirit_to_life}%)", + gem.skill_id, flat + )); + mods.push( + Modifier::number("LifeReservedPercent", ModType::Inc, percent) + .with_origin(origin), + ); + } + continue; + } + let reserved = (flat * mult * res_factor / (1.0 + efficiency / 100.0) / eff_more) .round() .max(0.0); - // Blasphemy per-curse 预留(vendor CalcDefence.lua:273-284):`IsBlasphemy` - // 效果按**被包 curse 数**各加 `blasphemy_base_spirit_reservation_per_socketed_curse` - // (constant stat = 60;vendor `supportEffect.isSupporting` 计数 ≙ 同组 - // AppliesCurse 主动技能数)。口径 = **单份缩放后 round 再 ×instances** - // (:282-283 `blasphemyEffectiveFlat = round(...);reservedFlat += ... × - // instances`,essence-drain 60→55×3=165 ≠ round(180/1.1)=164)。被包 - // curse 自身预留 0(levels 无 flat,vendor 同——无需额外排除)。 - if has("IsBlasphemy") { - let per_curse: f64 = es - .all() - .filter(|s| s.stat == "blasphemy_base_spirit_reservation_per_socketed_curse") - .map(|s| s.value) - .sum(); - let curse_count = group - .gem_skills - .iter() - .filter(|g| { - data.granted_effects.get(&g.skill_id).is_some_and(|e| { - !e.is_support && e.skill_types.iter().any(|t| t == "AppliesCurse") - }) - }) - .count(); - reserved += (per_curse * mult * res_factor / (1.0 + efficiency / 100.0) / eff_more) - .round() - .max(0.0) - * curse_count as f64; - } if reserved <= 0.0 { continue; } @@ -623,3 +788,104 @@ pub(crate) fn spirit_reservation_modifiers( } mods } + +/// (存量 #9)把所有**已启用 warcry 主动技能**构造为 [`pobr_core::calc::WarcrySpec`], +/// 经 `session.add_warcry_skill` 注入、由 pobr-core `calc::warcry`(perform 的 +/// hand pass 之前)按 uptime 缩放消费(vendor CalcOffence.lua:3203-3256 + +/// CalcPerform.lua:2116-2142;机制分解与 oracle 钉值见 warcry.rs 模块 doc)。 +/// +/// spec 装配(全部走既有数据通道,零技能硬编码): +/// - **skill-local mods** = 自身 statSet stat(含品质段)经 statmap +/// (`mapped_stat_modifiers`——Infernal 的 per-set +/// `infernal_cry_exerted_attack_all_damage_%_to_gain_as_fire_%` → +/// `InfernalExtraFireDamageMultiplier`、常量 stat `warcry_empowers_per_X_...` → +/// `WarcryPowerPer/Cap`)+ 组内**兼容 support** 载荷(`support_modifiers`, +/// 如 Cooldown Recovery II → `CooldownRecovery INC 30`)+ `WarcryCastTime BASE` +/// (效果 `cast_time`,对位 vendor skillModList 的 "Base" 条目, +/// CalcOffence.lua:351 的求和源)。 +/// - **取数等级** = 宝石等级 + 适用的 `+N to Level of ...`(`additional_gem_levels`, +/// vendor applyGemMods——smith 的 Infernal 21+1=22 级 gain 51 + 品质 trunc(0.5×23)=11 +/// → 62,oracle 逐值)。 +/// - cooldown / storedUses = granted_effect_levels 行(`resolve_skill_level`)。 +/// +/// 同一效果多组重复按 id 去重(vendor `not globalOutput.CryCalculated` 同责)。 +pub(crate) fn warcry_skill_specs( + build: &Build, + data: &BuildData, +) -> Vec { + use std::collections::HashSet; + let mut specs = Vec::new(); + let mut seen: HashSet<&str> = HashSet::new(); + for group in build.enabled_socket_groups() { + for gem in &group.gem_skills { + let Some(effect) = data.granted_effects.get(&gem.skill_id) else { + continue; + }; + if effect.is_support || !effect.skill_types.iter().any(|t| t == "Warcry") { + continue; + } + if !seen.insert(gem.skill_id.as_str()) { + continue; + } + // 全局 +N gem levels(applyGemMods)+ 同组兼容 support 授予等级 + // (smith 的 Fire Mastery `supported_fire_skill_gem_level_+` → Infernal + // 21→22 级,gain 51+q11=62 = oracle 逐值)。 + let level = gem.gem_level + + additional_gem_levels(build, data, &gem.skill_id) + + support_granted_gem_levels(build, data, &gem.skill_id); + let es = data.effect_stats(&gem.skill_id, level, gem.quality, gem.stat_set_index); + let set_key = data.selected_set_key(&gem.skill_id, gem.stat_set_index); + let stats: Vec = es.all().cloned().collect(); + if std::env::var("POBR_DBG_WARCRY").is_ok() { + eprintln!( + "[POBR_DBG_WARCRY] specs {} level={level} q={} set_key={set_key:?} stats={:?}", + gem.skill_id, + gem.quality, + stats + .iter() + .map(|s| (s.stat.as_str(), s.value)) + .collect::>() + ); + } + let mut mods = mapped_stat_modifiers( + &stats, + SourceKind::SkillGem, + &gem.skill_id, + &gem.skill_id, + set_key.as_deref(), + ); + mods.extend(support_modifiers(group, data, &gem.skill_id)); + if let Some(ms) = effect.cast_time { + mods.push( + Modifier::number("WarcryCastTime", ModType::Base, f64::from(ms) / 1000.0) + .with_source("Base"), + ); + } + let (cooldown_base_s, stored_uses) = data + .resolve_skill_level(&gem.skill_id, level) + .map(|r| { + ( + r.cooldown_s.unwrap_or(0.0), + // vendor `skillData.storedUses or 0`(CalcOffence.lua:3236)。 + r.stored_uses.map_or(0.0, f64::from), + ) + }) + .unwrap_or((0.0, 0.0)); + // warcry 键名(vendor CalcPerform.lua:2124 gsub 链:`" Cry"`/`"'s"`/空格 + // 全剥):"Infernal Cry" → `Infernal`。 + let name = buff_skill_name(data, &gem.skill_id) + .replace(" Cry", "") + .replace("'s", "") + .replace(' ', ""); + specs.push(pobr_core::calc::WarcrySpec { + name, + skill_id: gem.skill_id.clone(), + cooldown_base_s, + stored_uses, + skill_types: skill_type_bits(&effect.skill_types), + mods, + }); + } + } + specs +} diff --git a/crates/pobr-build/src/calc_orchestrator/collect.rs b/crates/pobr-build/src/calc_orchestrator/collect.rs index 562a888d..03a7dc0c 100644 --- a/crates/pobr-build/src/calc_orchestrator/collect.rs +++ b/crates/pobr-build/src/calc_orchestrator/collect.rs @@ -309,17 +309,15 @@ pub(crate) fn radius_jewel_expansions<'a>( } // 已分配节点集合(含种类)。坐标取自 data.passive_nodes(树数据回填的 x/y)。 // - // 并入 `inactive_weapon_set_nodes`:非激活武器组专属点的**自身** mod 虽已 masking, - // 但 PoB2 仍把它们留在 allocNodes(CalcSetup.lua:209-228),范围珠宝授予照样落上去。 - // radius 几何因此须按完整已分配集筛 in-radius 节点(gemling crit jewel 实测:6 个 - // in-radius notable 中 5 个在非激活组,缺它们会把 +7×6 误算成 +7×1)。 - let allocated: std::collections::HashSet = build - .tree - .allocated_nodes - .iter() - .chain(build.inactive_weapon_set_nodes.iter()) - .map(|n| n.0) - .collect(); + // 只取**激活武器集**的已分配节点:PoB2 虽把非激活集专属点留在 allocNodes,且范围 + // 珠宝授予也会写进它们的 modList,但节点上的**每条** mod(含珠宝授予)都会被追加 + // `Condition: WeaponSet`(CalcSetup.lua:222-223,节点自身 allocMode 优先于 + // 珠宝来源的 :224-227 分支)——非激活集节点上的授予净效果为零。oracle Tabulate + // 实证(gemling crit jewel):6 个 in-radius notable 只有激活集的 1 个贡献 +7 + // (critModList 仅一条 `7 @ Tree:32763`,CritChance 8.55)。PoBR 解析层已按激活集 + // 剔除非激活专属点,这里直接用 `tree.allocated_nodes` 即等价。 + let allocated: std::collections::HashSet = + build.tree.allocated_nodes.iter().map(|n| n.0).collect(); // 位置表:socket 自身 + 全部已分配节点(候选只在已分配集合中筛)。 let mut positions: std::collections::HashMap = diff --git a/crates/pobr-build/src/calc_orchestrator/defence.rs b/crates/pobr-build/src/calc_orchestrator/defence.rs index 5c53d624..32001ad3 100644 --- a/crates/pobr-build/src/calc_orchestrator/defence.rs +++ b/crates/pobr-build/src/calc_orchestrator/defence.rs @@ -228,14 +228,15 @@ pub(crate) fn item_rolled_defence(item: &Item, data: &BuildData, level: u32) -> } else { base * (1.0 + local_pct[idx] / 100.0) * (1.0 + quality_pct / 100.0) }; - // ES(idx 2):PoB2 恒从基底物品 DB 重算 `EnergyShield = round((esBase+flat) × - // (1+localInc/100) × (1+quality/100))`(Item.lua:1994-1996),不信物品文本的 - // `Energy Shield: N` 展示行——该行可能滞后于当前数据版本的基底 ES(跨版本重算 - // 与导入期展示值分歧,titan 手套 26→28 / 靴 15→27 = 41→55 根因)。基底已知时 - // ES 优先重算;护甲/闪避仍信 rolled 行(其局部 inc 解析不保证在所有基底上完整, - // 避免回归)。 - out[idx] = if idx == 2 && default_val.is_some() { - recompute + // PoB2 恒从基底物品 DB 重算三防 `round((base+flat) × (1+localInc/100) × + // (1+quality/100))`(Item.lua:1994-1996),不信物品文本的 `Armour:/Evasion:/ + // Energy Shield: N` 展示行——该行可能滞后于当前数据版本的基底值(跨版本重算 + // 与导入期展示值分歧:titan ES 手套 26→28 / 靴 15→27 = 41→55;0.5.4b + // Runeforged 基底护甲 buff 后 titan 手套 96→101 / 盔 192→284 / 靴 58→100, + // Gear:Armour 6100→6239 = vendor)。基底已知时重算(vendor round 同口径); + // 基底不在库时回退 rolled 行(不臆造)。 + out[idx] = if default_val.is_some() { + recompute.round() } else { rolled_val.unwrap_or(recompute) }; diff --git a/crates/pobr-build/src/calc_orchestrator/granted_skills.rs b/crates/pobr-build/src/calc_orchestrator/granted_skills.rs index 33a73f9c..375b69e2 100644 --- a/crates/pobr-build/src/calc_orchestrator/granted_skills.rs +++ b/crates/pobr-build/src/calc_orchestrator/granted_skills.rs @@ -149,6 +149,7 @@ pub(crate) fn augment_item_granted_skills(build: &Build, data: &BuildData) -> Op gem_level: level, quality: 0, stat_set_index: None, + name_spec: None, }], main_active_skill: None, }); @@ -179,6 +180,9 @@ mod tests { data.base_items.insert( "Firebolt".to_string(), BaseItemDef { + req_str: 0, + req_dex: 0, + req_int: 0, id: GEM_ID.to_string(), name: "Firebolt".to_string(), item_class: "Skill Gem".to_string(), @@ -212,6 +216,7 @@ mod tests { base: ItemBaseId::from("Test Wand"), rarity: ItemRarity::Unique, quality: 0, + corrupted: false, implicit_texts: Vec::new(), modifier_texts: vec![format!("Grants Skill: Level {level} Firebolt")], enchant_texts: Vec::new(), diff --git a/crates/pobr-build/src/calc_orchestrator/mod.rs b/crates/pobr-build/src/calc_orchestrator/mod.rs index 0d6722d3..49a389c3 100644 --- a/crates/pobr-build/src/calc_orchestrator/mod.rs +++ b/crates/pobr-build/src/calc_orchestrator/mod.rs @@ -421,7 +421,16 @@ pub fn calculate_with_data_session( inject_defence_base(&mut session, build, data); // 2. 装备:归因路径注入(逐件 filter / Kalandra 镜射 / 局部词条剔除 / 槽位加成数值副本)。 - inject_items(&mut session, build, data, ctx.off_weapon.is_some())?; + let main_weapon_active = ctx + .main_effect + .is_some_and(|e| e.is_attack() && !e.is_non_weapon_attack()); + inject_items( + &mut session, + build, + data, + ctx.off_weapon.is_some(), + main_weapon_active, + )?; // 2b. 珠宝(天赋树/深渊槽):词条按全局注入。 stage_inject_jewels(&mut session, &ctx)?; @@ -478,6 +487,10 @@ pub fn calculate_with_data_session( // 6d. 来源授予的条件 flag → cfg 条件桥接(Bonded modifiers / Arcane Surge)。 inject_condition_bridges(&mut session); + // 6e. 低生命自动条件(vendor CalcDefence.lua:335-350:未预留比例 ≤ 0.35 → + // Condition:LowLife)。须在预留 mod 注入(4d)与池值可算(6c)之后。 + session.bridge_low_pool_conditions(); + // 诊断 dump(POBR_DBG_UNSUPPORTED / ALLMODS / STAT,parity 排查用)。 stage_debug_dumps(&session); @@ -592,9 +605,61 @@ fn stage_build_view<'a>(build: &'a Build, data: &BuildData) -> Cow<'a, Build> { build = Cow::Owned(adjusted); } + // nameSpec-only gem 引用 → skill_id 回填(PoB2 SkillsTab 按 nameSpec 反查 + // gem 的等价物):lineage support(如 Atziri's Communion)在 XML 里缺 + // skillId/gemId,仅有显示名。按归一化名匹配 granted_effects id;未命中 + // 保持空 id(全部消费点惰性跳过)。 + if let Some(resolved) = resolve_name_spec_gems(&build, data) { + build = Cow::Owned(resolved); + } + build } +/// 把 `GemSkillRef { skill_id: "", name_spec: Some(name) }` 的显示名解析为授予 +/// 效果 id。归一化 = 小写 + 仅保留字母数字;候选 id 剥 `Player` 后缀(含 +/// `PlayerTwo/Three` 等 lineage 变体不匹配也无妨——它们的 XML 带 skillId), +/// support id 另剥 `Support` 前缀(`SupportAtzirisCommunionPlayer` → +/// `atziriscommunion` = nameSpec "Atziri's Communion" 归一形)。无改动返回 None。 +fn resolve_name_spec_gems(build: &Build, data: &BuildData) -> Option { + fn norm(s: &str) -> String { + s.chars() + .filter(char::is_ascii_alphanumeric) + .map(|c| c.to_ascii_lowercase()) + .collect() + } + let pending: Vec = build + .socket_groups + .iter() + .flat_map(|g| &g.gem_skills) + .filter(|gem| gem.skill_id.is_empty()) + .filter_map(|gem| gem.name_spec.clone()) + .collect(); + if pending.is_empty() { + return None; + } + let mut lookup: std::collections::HashMap = std::collections::HashMap::new(); + for id in data.granted_effects.keys() { + let stem = id.strip_suffix("Player").unwrap_or(id); + let stem = stem.strip_prefix("Support").unwrap_or(stem); + lookup.insert(norm(stem), id.as_str()); + } + let mut out = build.clone(); + let mut changed = false; + for group in &mut out.socket_groups { + for gem in &mut group.gem_skills { + if gem.skill_id.is_empty() + && let Some(name) = &gem.name_spec + && let Some(id) = lookup.get(&norm(name)) + { + gem.skill_id = (*id).to_string(); + changed = true; + } + } + } + changed.then_some(out) +} + /// 阶段 1:主技能解析——分等级参数、终态 skillTypes 不动点(vendor /// CalcActiveSkill.lua:179-214)、伤害 flag / 判别位 / 伤害关键词。必须最先 /// 运行:行动速率要进 base_input(stage_weapon_bases)、类型 flag / 战斗条件 @@ -735,21 +800,28 @@ fn stage_build_cfg(ctx: &mut StageCtx<'_>) { // (编排路径暂无 FlaskBuff/CharmBuff 载荷,T4 槽位接线后生效)+ 阶段 6 // buff_expander(trigger flag 未置仍零输出)。 .with_mode_combat(true); - // DistanceRamp 的 skillDist(vendor CalcActiveSkill.lua:655 `skillCfg.skillDist = - // env.mode_effective and env.configInput.enemyDistance`):仅 effective 口径 + - // enemyDistance 的 `` **显式值**(vendor `configInput`,不含 `` - // 占位值——后者经 ConfigTab apply 只兜底 `Multiplier:enemyDistance`(命中距离惩罚), - // 不喂 skillDist)。demo 套件 18 个 build 的 enemyDistance 全是 placeholder → 此处 - // None → Close/Far Combat 距离 MORE 整条跳过,与 golden 一致(PoB2 同样不应用)。 + // DistanceRamp 的 skillDist(vendor CalcActiveSkill.lua:671+684,0.22.0): + // `effectiveRange = env.configInput.enemyDistance or env.configPlaceholder.enemyDistance`, + // `skillDist = env.mode_effective and effectiveRange`。0.22.0 起 **placeholder + // 兜底喂 skillDist**(旧 vendor 只读显式 ``——彼时 demo 套件全 placeholder + // → None → Close Combat 距离 MORE 整条跳过)。回退链对齐 vendor ConfigTab: + // 显式 `` → XML `` → 目录 `defaultPlaceholderState` + // (ConfigTab.lua:559 对缺省项预填占位默认,enemyDistance = 20)。 let skill_distance = options .mode_effective .then(|| { - build - .config - .raw_inputs - .values + let raw = &build.config.raw_inputs; + raw.values .get("enemyDistance") + .or_else(|| raw.placeholders.get("enemyDistance")) .and_then(|v| v.as_number()) + .or_else(|| { + data.config_catalog + .as_deref() + .and_then(|c| c.get("enemyDistance")) + .and_then(|def| def.default.as_ref()) + .and_then(|d| d.placeholder_number) + }) }) .flatten(); cfg = cfg.with_skill_distance(skill_distance); @@ -791,6 +863,14 @@ fn stage_build_cfg(ctx: &mut StageCtx<'_>) { if main_hand_offhand_is_shield(build, data) { cfg = cfg.with_condition("UsingShield", true); } + // 敌人在 Presence 内(vendor CalcPerform.lua:524 `condList["EnemyInPresence"] + // = PresenceRadius >= enemyDistance`):默认 Presence 半径(数米级)恒大于默认 + // 敌人距离 → 默认真,使「Enemies in your Presence ...」族敌侧词条生效。 + // ponytail: pobr 未建模 PresenceRadius/enemyDistance 数值比较,恒置真;用户 + // 拉远 enemyDistance 的口径差留 parity 点名再接。 + if !cfg.conditions.contains_key("EnemyInPresence") { + cfg = cfg.with_condition("EnemyInPresence", true); + } // 伙伴在场条件(vendor ConfigOptions.lua:1012-1014 `companionInPresence` // defaultState=true,ifSkillType=CreatesCompanion 门控):已启用技能含 // `CreatesCompanion` 时默认置真,使「while your Companion is in your @@ -833,10 +913,13 @@ fn stage_build_cfg(ctx: &mut StageCtx<'_>) { /// `CalculationSession::new`)。 fn stage_weapon_bases(ctx: &mut StageCtx<'_>) { let (build, data) = (ctx.build, ctx.data); - if let Some((skill, _, _)) = &ctx.main_skill + if let Some((skill, _, skill_id)) = &ctx.main_skill && let Some(use_time) = skill.use_time_s && use_time > 0.0 { + if std::env::var("POBR_DBG_SPEED").is_ok() { + eprintln!("[POBR_DBG_SPEED] main skill_id={skill_id} use_time={use_time}"); + } ctx.base_input.base_action_rate = 1.0 / use_time; } @@ -983,6 +1066,7 @@ fn stage_inject_jewels( session: &mut CalculationSession, ctx: &StageCtx<'_>, ) -> Result<(), BuildError> { + let adorned_inc = adorned_corrupted_magic_jewel_inc(&ctx.build.jewels); for jewel in &ctx.build.jewels { let filtered = filter_item_parseable(jewel, engine_ctx(ctx.data)); let texts: Vec<&str> = filtered @@ -992,13 +1076,70 @@ fn stage_inject_jewels( .chain(&filtered.enchant_texts) .map(String::as_str) .collect(); - session - .add_modifier_texts(texts) - .map_err(|e| BuildError::Parse(e.to_string()))?; + // The Adorned(vendor CalcSetup.lua:944-948 + :1342-1347):树插槽内的 + // **腐化魔法**珠宝全部 mod 按 `1 + N/100` 缩放注入(ScaleAddList 语义, + // 数值 = trunc(round(v×scale, 2)),ModStore.lua:70-79)。 + // ponytail: 不建模 vendor 的 sinister/containJewelSocket 插槽豁免与 + // unscalable 标记(语料无来源),parity 点名时再接。 + if let Some(inc) = adorned_inc + && jewel.rarity == pobr_data::item::ItemRarity::Magic + && jewel.corrupted + { + let scale = 1.0 + inc / 100.0; + let parse_ctx = engine_ctx(ctx.data); + let mut mods: Vec = Vec::new(); + for text in texts { + let Ok(outcome) = parse_ctx.parse(text) else { + continue; + }; + for mut m in outcome.mods { + if let pobr_core::ModValue::Number(v) = m.value { + m.value = pobr_core::ModValue::Number(scale_trunc_2dp(v, scale)); + } + mods.push(m); + } + } + session.add_modifiers(mods); + } else { + session + .add_modifier_texts(texts) + .map_err(|e| BuildError::Parse(e.to_string()))?; + } } Ok(()) } +/// 珠宝列表内 The Adorned 的「N% increased Effect of Jewel Socket Passive Skills +/// containing Corrupted Magic Jewels」数值(XML 内该词条折行为两个物理行,按 +/// 空格拼接后匹配;vendor 解析为 `JewelData{corruptedMagicJewelIncEffect}`)。 +/// 无该珠宝 → `None`。 +fn adorned_corrupted_magic_jewel_inc(jewels: &[Item]) -> Option { + const SUFFIX: &str = + "% increased Effect of Jewel Socket Passive Skills containing Corrupted Magic Jewels"; + for jewel in jewels { + if jewel.rarity != pobr_data::item::ItemRarity::Unique { + continue; + } + let joined = jewel.modifier_texts.join(" "); + if let Some(pos) = joined.find(SUFFIX) { + let head = &joined[..pos]; + let num_start = head + .rfind(|c: char| !c.is_ascii_digit()) + .map_or(0, |i| i + 1); + if let Ok(v) = head[num_start..].parse::() { + return Some(v); + } + } + } + None +} + +/// vendor `ModStore:ScaleAddMod` 数值缩放语义(ModStore.lua:70-79): +/// `m_modf(round(v × scale, 2))` —— 先四舍五入到 2 位小数,再截尾取整。 +fn scale_trunc_2dp(value: f64, scale: f64) -> f64 { + ((value * scale * 100.0).round() / 100.0).trunc() +} + /// 2b'. 范围珠宝 `... Passive Skills in Radius also grant `:按珠宝插槽**半径内 /// 已分配**对应种类节点数 × 授予,展开为全局 modifier text 注入(PoB2 几何口径)。 /// 与装备/天赋路径一致,先 skip-and-collect 过滤硬失败词条,避免单条中止整批。 @@ -1330,6 +1471,14 @@ fn inject_buffs_and_heralds(session: &mut CalculationSession, build: &Build, dat session.add_buff_skill(spec); } + // 4b'''.(存量 #9)warcry 技能 → WarcrySpec 经 `session.add_warcry_skill` 注入, + // 消费在 pobr-core `calc::warcry`(perform 的 hand pass 之前):按 + // `min((賦能次数/主技能Speed)/(冷却+喊叫时间), 1)` 折算 uptime 后把 warcry + // 进攻效果(Infernal `DamageGainAsFire`)缩放注入(CalcOffence.lua:3203-3256)。 + for spec in warcry_skill_specs(build, data) { + session.add_warcry_skill(spec); + } + // 4b''.(M4-m)herald 在场计数/条件(vendor CalcPerform.lua:1792-1805, // mode_buffs 段——本编排路径恒置 mode_buffs=true):已启用组中 // skill_types 含 Herald 的主动技能按显示名去重 → `Multiplier:Herald` @@ -1373,6 +1522,17 @@ fn inject_attribute_derivation( let str_total = session.attribute_total("Strength", cls_str); let dex_total = session.attribute_total("Dexterity", cls_dex); let int_total = session.attribute_total("Intelligence", cls_int); + // (存量 #7-4)Giant's Blood 键石「Inherent Life granted by Strength is + // halved」(vendor CalcPerform.lua:500-505:flag HalvesLifeFromStrength → + // `Life BASE = Str × 1` 而非 ×2)。CharacterBase 已烘焙职业起始段 + // `cls_str × life_per_strength`,此处增量按「目标总量 − 烘焙段」注入, + // 使 Str 派生生命总量 = str_total × 减半后系数(wolf-pack 802→401, + // oracle Life 逐源钉值)。 + let life_per_str = if session.has_flag("HalvesLifeFromStrength") { + cc.life_per_strength / 2.0 + } else { + cc.life_per_strength + }; let mk = |stat: &str, value: f64| { let origin = ModifierSource::new(SourceId::new( SourceKind::CharacterBase, @@ -1382,7 +1542,10 @@ fn inject_attribute_derivation( Modifier::number(stat, ModType::Base, value).with_origin(origin) }; session.add_modifiers([ - mk("MaximumLife", cc.life_per_strength * (str_total - cls_str)), + mk( + "MaximumLife", + str_total * life_per_str - cls_str * cc.life_per_strength, + ), mk( "MaximumMana", cc.mana_per_intelligence * (int_total - cls_int), @@ -1439,7 +1602,10 @@ fn inject_per_x_multipliers(session: &mut CalculationSession, build: &Build, dat let str_total = session.base_sum("Strength"); let dex_total = session.base_sum("Dexterity"); let int_total = session.base_sum("Intelligence"); - let spirit_total = session.base_sum("Spirit"); + // (存量 #7-4)Spirit 分母 = **最终池值**(calc_spirit_pool,含 INC/MORE 与 + // 转换扣减)——vendor PerStat 读 output.Spirit;BASE-only 会把 wolf-pack + // Perfidy「+2 Armour per 1 Spirit」欠算 72 base(Spirit 336 vs base 300)。 + let spirit_total = session.spirit_total(); let mana_total = session.pool_total("MaximumMana"); let life_total = session.pool_total("MaximumLife"); session.set_multiplier("Strength", str_total); @@ -1459,6 +1625,14 @@ fn inject_per_x_multipliers(session: &mut CalculationSession, build: &Build, dat session.set_stat("Spirit", spirit_total); session.set_stat("Mana", mana_total); session.set_stat("Life", life_total); + // 主技能 Life 消耗快照(vendor output.LifeCost):per-life-cost 词条 + // (PerStat stat=LifeCost,如 Atalui's Bloodletting gain-as-physical)的取数源。 + // 消耗先于伤害结算,与 vendor CalcOffence 顺序一致。 + let life_cost = session.life_cost_snapshot(); + if life_cost > 0.0 { + session.set_stat("LifeCost", life_cost); + session.set_multiplier("LifeCost", life_cost); + } // per-槽位防御缩放(`On`):使 `+N to Armour per M Item Energy Shield on // Equipped Boots` 这类按某件装备防御值缩放的词条生效(PoB2 PerStat `On`)。 for (var, value) in per_slot_defence_multipliers(build, data) { @@ -1485,6 +1659,55 @@ fn inject_per_x_multipliers(session: &mut CalculationSession, build: &Build, dat session.set_multiplier("StrengthMoteSkillCount", str_mote); session.set_multiplier("DexterityMoteSkillCount", dex_mote); session.set_multiplier("IntelligenceMoteSkillCount", int_mote); + // Smith of Kitava 身甲连接 notable 计数(vendor CalcSetup.lua:840-841: + // 已分配且 tree.lua `applyToArmour=true` 的 notable 数 → + // `Multiplier:AllocatedConnectedNotable`)。消费方 = Masterwork + // 『+200 to Armour for each Connected Notable Passive Skill Allocated』。 + let connected_notables = build + .tree + .allocated_nodes + .iter() + .filter(|id| { + data.passive_nodes + .get(&id.0) + .is_some_and(|n| n.apply_to_armour) + }) + .count(); + if connected_notables > 0 { + session.set_multiplier("AllocatedConnectedNotable", connected_notables as f64); + } + // 装备属性需求快照(vendor CalcPerform.lua:1848-1857: + // `output[attr.."RequirementsOn"..slot] = floor(itemReq × reqMult)`)—— + // 『Gain Armour equal to N% of total Strength Requirements of Equipped + // Boots, Gloves and Helmet』(PercentStat `StrRequirementsOn`)取数源。 + // ponytail: reqMult(GlobalAttributeRequirements 词条族)恒按 1;出现带 + // 「reduced attribute requirements」的相关 build 时再接乘子。 + for (var, value) in per_slot_attribute_requirements(build, data) { + session.set_stat(var, value); + } +} + +/// 每槽位装备的属性需求(`{Str,Dex,Int}RequirementsOn` → 值)。 +/// 槽位词根与 PercentStat tag 的 stat 名对齐(`StrRequirementsOnboots` 等, +/// 小写槽名 = 引擎解析产物);无需求/空槽不产出。 +fn per_slot_attribute_requirements(build: &Build, data: &BuildData) -> Vec<(String, f64)> { + let mut out = Vec::new(); + for (slot, item) in build.equipped_items() { + let Some(def) = data.base_items.get(&item.base.to_string()) else { + continue; + }; + let slot_key = slot.id(); + for (attr, req) in [ + ("Str", def.req_str), + ("Dex", def.req_dex), + ("Int", def.req_int), + ] { + if req > 0 { + out.push((format!("{attr}RequirementsOn{slot_key}"), f64::from(req))); + } + } + } + out } /// Attribute-Mote 计数(Gemling Virtuous Barrier):base 3/3/3 + 每个启用非辅助 @@ -1717,12 +1940,14 @@ fn inject_character_base( } /// 2 阶段:装备归因路径注入——逐件 filter / Kalandra 镜射 / 局部词条(武器·防御·Spirit) -/// 剔除 / add_item / 槽位加成效果数值副本。`off_weapon_active` = 副手武器源是否被消费。 +/// 剔除 / add_item / 槽位加成效果数值副本。`off_weapon_active` = 副手武器源是否被消费; +/// `main_weapon_active` = 主技能以 Weapon1 为伤害源(持武攻击)。 fn inject_items( session: &mut CalculationSession, build: &Build, data: &BuildData, off_weapon_active: bool, + main_weapon_active: bool, ) -> Result<(), BuildError> { // 槽位加成效果(『N% increased bonuses gained from Equipped Rings and Amulets』, // Ritualist 等):对应槽位物品词条按 scale 追加缩放副本(PoB2 CalcPerform.lua: @@ -1748,6 +1973,39 @@ fn inject_items( filtered.modifier_texts = drop_local(filtered.modifier_texts); filtered.enchant_texts = drop_local(filtered.enchant_texts); } + // 非伤害源武器的裸「Adds N to M Damage」剔除(#10-3,titan/smith + // 高估根因):vendor Item.lua:1923-1928 把武器上全类型裸 adds 折入 + // weaponData(局部,只随该武器攻击生效)。主技能不以该武器为伤害源 + // (非武器攻击如 Shield Wall / 法术 / 未消费副手)时,这些词条不得进 + // 全局加法桶(titan Nebuloch『Adds 30 to 52 Chaos damage』经 added + // effectiveness 放大 → TotalDPS 1.05x)。该武器**是**伤害源时维持现状: + // 裸元素/混沌 adds 走全局注入近似(与 vendor weaponData 折算数值等价, + // deadeye/twister 1.00x 钉住)。 + let weapon_source_inactive = (slot == EquipmentSlot::Weapon1 && !main_weapon_active) + || (slot == EquipmentSlot::Weapon2 && !off_weapon_active); + if weapon_source_inactive && data.weapon_base(&item.base.to_string()).is_some() { + const TYPED_ADDS_SUFFIXES: [&str; 5] = [ + "physical damage", + "fire damage", + "cold damage", + "lightning damage", + "chaos damage", + ]; + let drop_typed_adds = |texts: Vec| -> Vec { + texts + .into_iter() + .filter(|t| { + let clean = clean_item_text(t); + !TYPED_ADDS_SUFFIXES + .iter() + .any(|s| parse_adds_with_suffix(&clean, s).is_some()) + }) + .collect() + }; + filtered.implicit_texts = drop_typed_adds(filtered.implicit_texts); + filtered.modifier_texts = drop_typed_adds(filtered.modifier_texts); + filtered.enchant_texts = drop_typed_adds(filtered.enchant_texts); + } // 护甲件:剔除局部「increased / +flat Armour/Evasion/ES」(已折入 rolled 件级底值 / // 基底兜底乘区,见 defence_base_modifiers);留在全局会重复(且错误地变成全局加法)。 // 判定护甲件:有基底护甲项 **或** 文本给出 rolled 防御行(兜底覆盖无 catalog 的 unique)。 @@ -1796,9 +2054,20 @@ fn inject_items( filtered.modifier_texts = drop_spirit(filtered.modifier_texts); filtered.enchant_texts = drop_spirit(filtered.enchant_texts); } - session - .add_item(slot, &filtered) - .map_err(|e| BuildError::Parse(e.to_string()))?; + // 武器件走 add_weapon_item:无 flag 爆伤词条转按手条件 + // (vendor Item.lua:1954-1961,0.22.0 把 CritMultiplier 加进转换清单; + // 仅武器基底转换——Weapon2 的盾/箭袋/法器等非武器件不转)。 + let is_weapon_item = matches!(slot, EquipmentSlot::Weapon1 | EquipmentSlot::Weapon2) + && data.weapon_base(&item.base.to_string()).is_some(); + if is_weapon_item { + session + .add_weapon_item(slot, &filtered) + .map_err(|e| BuildError::Parse(e.to_string()))?; + } else { + session + .add_item(slot, &filtered) + .map_err(|e| BuildError::Parse(e.to_string()))?; + } // 槽位加成效果副本:该槽位有 `EffectOfBonusesFrom` INC 时,把本件已 // 注入词条的**数值差额副本** 追加注入(vendor CalcPerform.lua:1347-1369 @@ -1891,6 +2160,7 @@ mod ring3_tests { base: ItemBaseId::from("Ring"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec!["+30 to maximum Life".into()], enchant_texts: vec![], @@ -1902,6 +2172,7 @@ mod ring3_tests { fn ring_slot_data() -> BuildData { // 『+1 Ring Slot』词条节点(Ritualist『Unfurled Finger』形态)。 let node = pobr_data::catalog::PassiveNodeDef { + apply_to_armour: false, skill: 34785, id: "ascendancy_ritualist_unfurled_finger".into(), name: Some("Unfurled Finger".into()), @@ -2022,6 +2293,7 @@ mod tests { base: ItemBaseId::from("Iron Ring"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec![format!("+{amount} to maximum Life")], enchant_texts: vec![], @@ -2041,6 +2313,7 @@ mod tests { base: ItemBaseId::from("Solar Amulet"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec![], enchant_texts: vec!["Allocates Paragon".into()], @@ -2196,6 +2469,7 @@ mod tests { fn passive_node_contributes_attributed_life() { // 构造一个携带 +30 maximum Life 的普通节点,分配后应抬升生命。 let node = pobr_data::catalog::PassiveNodeDef { + apply_to_armour: false, skill: 12345, id: "test_life_node".into(), name: Some("Life Node".into()), @@ -2243,6 +2517,7 @@ mod tests { stats: Vec, ) -> pobr_data::catalog::PassiveNodeDef { pobr_data::catalog::PassiveNodeDef { + apply_to_armour: false, skill, id: format!("n{skill}"), name: None, @@ -2709,6 +2984,7 @@ mod tests { vec![QualityStat { stat: "damage_+%".into(), per_quality_rate: 0.55, + alt: false, }], ); // 直接调取数点(不经 calculate_with_data):手动安装 Data 通道上下文 @@ -3059,6 +3335,7 @@ mod tests { fn slot_bonus_effect_scales_covers_equipped_quiver() { use pobr_data::passive_tree::{NodeId, PassiveTreeSpec}; let quiver_node = pobr_data::catalog::PassiveNodeDef { + apply_to_armour: false, skill: 30341, id: "bow_quiver_effect".into(), name: Some("Master Fletching".into()), @@ -3089,6 +3366,7 @@ mod tests { base: ItemBaseId::from("Visceral Quiver"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec!["53% increased Damage with Bow Skills".into()], enchant_texts: vec![], @@ -4239,6 +4517,9 @@ mod tests { /// 测试用武器基底(仅 item_class 参与持握/近战判定)。 fn weapon_base_item(name: &str, item_class: &str) -> pobr_data::catalog::BaseItemDef { pobr_data::catalog::BaseItemDef { + req_str: 0, + req_dex: 0, + req_int: 0, id: format!("Test/{name}"), name: name.to_string(), item_class: item_class.to_string(), @@ -4293,6 +4574,7 @@ mod tests { base: ItemBaseId::from(base_name.as_str()), rarity: ItemRarity::Normal, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec![], enchant_texts: vec![], @@ -4321,6 +4603,7 @@ mod tests { base: ItemBaseId::from(base_name.as_str()), rarity: ItemRarity::Normal, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec![], enchant_texts: vec![], diff --git a/crates/pobr-build/src/calc_orchestrator/skill_resolve.rs b/crates/pobr-build/src/calc_orchestrator/skill_resolve.rs index 8ecd1b4e..c5673308 100644 --- a/crates/pobr-build/src/calc_orchestrator/skill_resolve.rs +++ b/crates/pobr-build/src/calc_orchestrator/skill_resolve.rs @@ -85,6 +85,65 @@ pub(crate) fn spawn_minions( if minion_ids.is_empty() { continue; } + // 召唤物等级取**生效宝石等级**(vendor `data.minionLevelTable[activeEffect + // .level]`,CalcActiveSkill.lua:948——activeEffect.level 含 applyGemMods + // 的 `+N to Level of all Skills` 与 support 授予等级)。wolf-pack + // 「+4 to Level of all Minion Skills」:gem 18 → 22 → 怪物等级 44 + // (oracle 钉值;修正前 36 → 生命 1013 vs 2262)。 + let effective_gem_level = gem_level + .saturating_add(additional_gem_levels(build, data, skill_id)) + .saturating_add(support_granted_gem_levels(build, data, skill_id)); + // (#12 companion)伴侣判定:授予技能 `SkillType.Companion` 且非 + // `MinionsAreUndamagable`(vendor CalcPerform.lua:3365-3367 的 + // includeSkill 谓词)→ 该技能的召唤物计入 `TotalCompanionLife`。 + let is_companion = data.granted_effects.get(skill_id).is_some_and(|e| { + e.skill_types.iter().any(|t| t == "Companion") + && !e.skill_types.iter().any(|t| t == "MinionsAreUndamagable") + }); + // (#12)同组兼容 support 的召唤物侧载荷(vendor:support statmap 的 + // `MinionModifier LIST` 并入被支援技能 skillModList → + // `addMinionModifiers` 注入**该技能的** minion modDB,组内作用域)。 + // 数据通道 = `map_minion_life_stat`(第一批只收内层 Life,如 Loyalty + // 的 −30% more minion life)。 + let mut group_minion_modifiers = minion_modifiers.clone(); + if let Some(catalog) = data.stat_map_catalog.as_deref() { + use pobr_core::calc::minion::MinionModifierEntry; + use pobr_core::rules::stat_map_engine::map_minion_life_stat; + for sup in super::triggers::judge_group_supports(group, data, skill_id).compatible { + let sup_gem = &group.gem_skills[sup.gem_index]; + let set_index = (sup_gem.skill_id == sup.effect_id) + .then_some(sup_gem.stat_set_index) + .flatten(); + // quality 传 0 与 support_modifiers 同口径(support 品质表条目不存在)。 + let stats = data.effect_stats(&sup.effect_id, sup_gem.gem_level, 0, set_index); + let set_key = data.selected_set_key(&sup.effect_id, set_index); + for ds in stats.all() { + if ds.value == 0.0 { + continue; + } + for inner in map_minion_life_stat( + catalog, + &sup.effect_id, + set_key.as_deref(), + &ds.stat, + ds.value, + ) { + let origin = ModifierSource::new(SourceId::new( + SourceKind::SupportGem, + format!("minion.{}.{}", sup.effect_id, ds.stat), + )) + .with_raw_text(format!( + "minion {} {} ({})", + sup.effect_id, ds.stat, ds.value + )); + group_minion_modifiers.push(MinionModifierEntry { + inner: inner.with_origin(origin), + minion_type: None, + }); + } + } + } + } for minion_id in minion_ids { if !seen.insert(minion_id.clone()) { continue; @@ -105,16 +164,17 @@ pub(crate) fn spawn_minions( if summed >= 1.0 { summed as u32 } else { 1 } }; let def = def.clone(); - // `add_minion_from_def` 内部经 `minion_level_from_gem_level` 把 gem_level - // 映射到怪物等级(CalcActiveSkill.lua:896 默认规则),故此处传 gem_level - // 原值,不可预先 resolve(否则二次映射)。 + // `add_minion_from_def` 内部经 `minion_level_from_gem_level` 把宝石等级 + // 映射到怪物等级(CalcActiveSkill.lua:948 默认规则),故此处传生效 + // 宝石等级(含 +N to Level 加成),不可预先 resolve(否则二次映射)。 session.add_minion_from_def( &def, - gem_level, + effective_gem_level, limit, - minion_modifiers.clone(), + group_minion_modifiers.clone(), Vec::new(), AttributeInfusion::default(), + is_companion, ); } } @@ -170,28 +230,10 @@ pub(crate) fn pick_group_main_skill<'b>( build_data: &'b BuildData, group: &'b SocketGroup, ) -> Option<(&'b str, u32, Option)> { - // 非辅助宝石列表(meta 壳算入),与 PoB socketGroupSkillList 一致。`gem_skills` 存的是 - // 授予效果 id,故经 granted_effects.is_support 判定(未知效果按非 support 处理,宁可保留)。 - let actives: Vec<&crate::build::GemSkillRef> = group - .gem_skills - .iter() - .filter(|g| { - !build_data - .granted_effects - .get(&g.skill_id) - .map(|e| e.is_support) - .unwrap_or(false) - }) - .collect(); + let actives = group_active_gems(build_data, group); if !actives.is_empty() { - // mainActiveSkill(1-based)→ 0-based,越界 clamp 到末项。 - let idx = group - .main_active_skill - .unwrap_or(1) - .saturating_sub(1) - .min(actives.len() - 1); - let chosen = actives[idx]; + let chosen = group_chosen_active(group, &actives); // 指定项即伤害技能 → 直接用;否则(meta 壳等)穿透到组内首个伤害技能。 if is_damage_skill(build_data, &chosen.skill_id) { @@ -235,6 +277,71 @@ pub(crate) fn pick_group_main_skill<'b>( .map(|id| (id, group.active_gem_level.unwrap_or(1), None)) } +/// 组内非辅助宝石列表(meta 壳算入),与 PoB `socketGroupSkillList` 一致。`gem_skills` +/// 存的是授予效果 id,故经 granted_effects.is_support 判定(未知效果按非 support 处理, +/// 宁可保留)。 +fn group_active_gems<'b>( + build_data: &BuildData, + group: &'b SocketGroup, +) -> Vec<&'b crate::build::GemSkillRef> { + group + .gem_skills + .iter() + .filter(|g| { + !build_data + .granted_effects + .get(&g.skill_id) + .map(|e| e.is_support) + .unwrap_or(false) + }) + .collect() +} + +/// `mainActiveSkill`(1-based,缺省 1,越界 clamp 到末项)在非辅助宝石列表中的选中项。 +fn group_chosen_active<'b>( + group: &SocketGroup, + actives: &[&'b crate::build::GemSkillRef], +) -> &'b crate::build::GemSkillRef { + let idx = group + .main_active_skill + .unwrap_or(1) + .saturating_sub(1) + .min(actives.len() - 1); + actives[idx] +} + +/// 组内按 `mainActiveSkill` 选中的**任意**主动技能(非 support、非 Meta 壳), +/// 不要求攻击/法术标签。 +/// +/// vendor 语义:`socketGroupSkillList` 收录组内全部非辅助宝石,`mainActiveSkill` +/// 直接选中——**没有**「必须是伤害技能」的过滤(CalcSetup.lua socketGroupSkillList +/// 段)。伙伴/召唤类主技能(如 Wolf Pack:`Minion`+`Companion`,非 Attack 非 +/// Spell)在 vendor 里照常作为 mainActiveSkill 计算(castTime 基底、Speed=1/castTime)。 +/// PoBR 的 [`pick_group_main_skill`] 出于 meta 壳穿透保留伤害技能偏好;本函数作为 +/// **显式指定主组**(`mainSocketGroup`)落空后的兜底,避免回退扫描把主技能劫持到 +/// 其它组(wolf-pack 实测:曾错落到 Blasphemy 组的 Temporal Chains, +/// Speed 1.43 vs vendor 1.00)。仅供指定主组分支消费;回退扫描仍只找伤害技能组。 +pub(crate) fn pick_group_chosen_active<'b>( + build_data: &'b BuildData, + group: &'b SocketGroup, +) -> Option<(&'b str, u32, Option)> { + let actives = group_active_gems(build_data, group); + if actives.is_empty() { + return None; + } + let chosen = group_chosen_active(group, &actives); + // Meta 壳无独立施放参数,仍排除(穿透逻辑归 pick_group_main_skill)。 + let effect = build_data.granted_effects.get(&chosen.skill_id)?; + if effect.skill_types.iter().any(|t| t == "Meta") { + return None; + } + Some(( + chosen.skill_id.as_str(), + chosen.gem_level, + chosen.stat_set_index, + )) +} + /// 解析 build 的主技能分等级参数:优先用 PoB 指定的主技能组(`mainSocketGroup`,1-based)+ /// 组内 `mainActiveSkill` 选中真正的伤害技能(跳过 support 与 meta/触发壳),用其授予效果 /// id + 宝石等级查 [`BuildData::resolve_skill_level`]。 @@ -249,9 +356,12 @@ pub(crate) fn resolve_main_skill<'b>( data: &'b BuildData, ) -> Option<(ResolvedSkillLevel, &'b SocketGroup, &'b str)> { // 优先用 PoB 指定的主技能组(`mainSocketGroup`,1-based)+ 组内 mainActiveSkill。 + // 组内无伤害技能候选时兜底用选中的任意主动技能(vendor 语义无伤害过滤, + // 见 [`pick_group_chosen_active`];避免伙伴/召唤主组被回退扫描劫持到其它组)。 if let Some(n) = build.main_socket_group && let Some(group) = build.socket_groups.get(n.saturating_sub(1)) - && let Some((skill_id, level, set_index)) = pick_group_main_skill(data, group) + && let Some((skill_id, level, set_index)) = + pick_group_main_skill(data, group).or_else(|| pick_group_chosen_active(data, group)) && let Some(resolved) = resolve_skill_level_with_gem_bonus(build, data, skill_id, level, set_index) { @@ -278,7 +388,8 @@ pub(crate) fn resolve_main_skill<'b>( pub fn resolve_main_skill_selection(build: &Build, data: &BuildData) -> Option<(usize, String)> { if let Some(n) = build.main_socket_group && let Some(group) = build.socket_groups.get(n.saturating_sub(1)) - && let Some((skill_id, level, set_index)) = pick_group_main_skill(data, group) + && let Some((skill_id, level, set_index)) = + pick_group_main_skill(data, group).or_else(|| pick_group_chosen_active(data, group)) && resolve_skill_level_with_gem_bonus(build, data, skill_id, level, set_index).is_some() { return Some((n.saturating_sub(1), skill_id.to_string())); @@ -350,13 +461,13 @@ pub(crate) fn support_granted_gem_levels(build: &Build, data: &BuildData, skill_ } let judgement = super::triggers::judge_group_supports(group, data, skill_id); let mut total = 0u32; - for &idx in &judgement.compatible { - let sup = &group.gem_skills[idx]; + for sup in &judgement.compatible { + let host = &group.gem_skills[sup.gem_index]; let stats = data.effect_stats( - &sup.skill_id, - sup.gem_level, - sup.quality, - sup.stat_set_index, + &sup.effect_id, + host.gem_level, + host.quality, + sup.stat_set_index(group), ); for s in &stats.base { let Some(rest) = s.stat.strip_prefix("supported_") else { @@ -442,6 +553,30 @@ pub(crate) fn gem_property_bonuses(build: &Build, data: &BuildData) -> Vec bool { + const FLAG_TEXT: &str = "gem quality grants socketed skills an additional effect"; + let matches = |stat: &str| { + clean_grant_text(stat) + .trim() + .eq_ignore_ascii_case(FLAG_TEXT) + }; + for node_id in &build.tree.allocated_nodes { + if let Some(node) = data.passive_nodes.get(&node_id.0) + && node.stats.iter().any(|s| matches(s)) + { + return true; + } + } + granted_passive_defs(build, data) + .iter() + .any(|def| def.stats.iter().any(|s| matches(s))) +} + /// 某 GemProperty 词条是否适用于指定授予效果的宝石(vendor `applyGemMods` /// keyword/keywordList 逐项 `gemIsType` + `gemRequirements` 检查, /// CalcSetup.lua:410-435)。 @@ -876,6 +1011,7 @@ mod kalandra_tests { base: ItemBaseId::from("Ring"), rarity: ItemRarity::Unique, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: texts.iter().map(|s| s.to_string()).collect(), enchant_texts: vec![], diff --git a/crates/pobr-build/src/calc_orchestrator/stat_map.rs b/crates/pobr-build/src/calc_orchestrator/stat_map.rs index f94a9efd..057fb1d2 100644 --- a/crates/pobr-build/src/calc_orchestrator/stat_map.rs +++ b/crates/pobr-build/src/calc_orchestrator/stat_map.rs @@ -418,7 +418,7 @@ pub(crate) fn exposure_support_modifiers( } // 曝光源宿主:组内主动技能自身产 debuff 曝光载荷,或(M4-m)自身/兼容 // support 含曝光施加能力载荷 → 其兼容 support 名单。 - let mut support_indices: BTreeSet = BTreeSet::new(); + let mut support_entries: BTreeSet<(usize, String)> = BTreeSet::new(); for gem in &group.gem_skills { let Some(effect) = data.granted_effects.get(&gem.skill_id) else { continue; @@ -436,32 +436,35 @@ pub(crate) fn exposure_support_modifiers( let judgement = judge_group_supports(group, data, &gem.skill_id); let is_host = has_debuff_payload(data, &es, &gem.skill_id, set_key.as_deref()) || has_exposure_inflict_stats(data, &es, &gem.skill_id, set_key.as_deref()) - || judgement.compatible.iter().any(|&idx| { - let sup = &group.gem_skills[idx]; + || judgement.compatible.iter().any(|sup| { + let host = &group.gem_skills[sup.gem_index]; // quality 传 0 与 support_modifiers 同口径。 - let sup_stats = - data.effect_stats(&sup.skill_id, sup.gem_level, 0, sup.stat_set_index); - let sup_key = data.selected_set_key(&sup.skill_id, sup.stat_set_index); - has_exposure_inflict_stats(data, &sup_stats, &sup.skill_id, sup_key.as_deref()) + let set_index = sup.stat_set_index(group); + let sup_stats = data.effect_stats(&sup.effect_id, host.gem_level, 0, set_index); + let sup_key = data.selected_set_key(&sup.effect_id, set_index); + has_exposure_inflict_stats(data, &sup_stats, &sup.effect_id, sup_key.as_deref()) }); if !is_host { continue; } - for idx in judgement.compatible { - support_indices.insert(idx); + for sup in judgement.compatible { + support_entries.insert((sup.gem_index, sup.effect_id)); } } - for idx in support_indices { + for (idx, effect_id) in support_entries { let gem = &group.gem_skills[idx]; + let set_index = (gem.skill_id == effect_id) + .then_some(gem.stat_set_index) + .flatten(); // quality 传 0 与 support_modifiers 同口径(support 品质表条目不存在)。 - let stats = data.effect_stats(&gem.skill_id, gem.gem_level, 0, gem.stat_set_index); - let set_key = data.selected_set_key(&gem.skill_id, gem.stat_set_index); + let stats = data.effect_stats(&effect_id, gem.gem_level, 0, set_index); + let set_key = data.selected_set_key(&effect_id, set_index); mods.extend( mapped_stat_modifiers( &stats.base, SourceKind::SupportGem, - &gem.skill_id, - &gem.skill_id, + &effect_id, + &effect_id, set_key.as_deref(), ) .into_iter() diff --git a/crates/pobr-build/src/calc_orchestrator/triggers.rs b/crates/pobr-build/src/calc_orchestrator/triggers.rs index e598b333..2c2d074e 100644 --- a/crates/pobr-build/src/calc_orchestrator/triggers.rs +++ b/crates/pobr-build/src/calc_orchestrator/triggers.rs @@ -550,17 +550,42 @@ pub(crate) fn in_group_trigger_source_stats( /// 组级 support 适用性裁决结果(M1 蓝图契约 C2)。 /// -/// `compatible` 为 `group.gem_skills` 中**通过 PoB2 四段裁决**的 support 下标(保持 -/// 插槽顺序);`final_skill_types` 为 addSkillTypes 不动点收敛后的主动技能类型集合 +/// `compatible` 为**通过 PoB2 四段裁决**的 support 效果引用(保持插槽顺序); +/// `final_skill_types` 为 addSkillTypes 不动点收敛后的主动技能类型集合 /// (种子 = 主动效果 `skill_types`,并入所有兼容 support 的 `add_skill_types`)。 #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct GroupSupportJudgement { - /// 兼容 support 在 `gem_skills` 中的下标(插槽顺序)。 - pub(crate) compatible: Vec, + /// 兼容 support(插槽顺序;含附加授予的 support 半身,见 [`CompatibleSupport`])。 + pub(crate) compatible: Vec, /// 不动点收敛后的技能类型集合(供后续 require 裁决 / T4 SupportManaMultiplier 复用)。 pub(crate) final_skill_types: std::collections::HashSet, } +/// 一个兼容 support 的效果引用:等级/品质/插槽序取宿主宝石实例(`gem_index`), +/// stat 取数用 `effect_id`——普通 support 二者同源(effect_id = 宝石主效果); +/// meta 宝石(Blasphemy)主效果是主动技能,support 半身在附加授予位 +/// (`gem_effects` 外键 `additionalGrantedEffectId1..N`,vendor 对 +/// grantedEffectList 逐效果按 `support` 标志分流,CalcSetup.lua gemList 装配)。 +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) struct CompatibleSupport { + /// 宿主宝石在 `group.gem_skills` 中的下标。 + pub(crate) gem_index: usize, + /// support 授予效果 id(stat / manaMultiplier / set_key 取数键)。 + pub(crate) effect_id: String, +} + +impl CompatibleSupport { + /// 该 support 效果的 statSet 选择:宝石实例的 `statSetIndex` 只对**主效果** + /// 有意义;附加授予的 support 半身用默认 set(vendor 附加效果同 gemInstance + /// 但 set 选择不跨效果沿用)。 + pub(crate) fn stat_set_index(&self, group: &SocketGroup) -> Option { + let gem = &group.gem_skills[self.gem_index]; + (gem.skill_id == self.effect_id) + .then_some(gem.stat_set_index) + .flatten() + } +} + /// 对一个 socket group 做 **support 适用性裁决 + addSkillTypes 不动点** /// (对照 PoB2 `Modules/CalcActiveSkill.lua:179-210`,契约 C2): /// @@ -591,42 +616,49 @@ pub(crate) fn judge_group_supports( .unwrap_or_default(); let cannot_be_supported = active_effect.is_some_and(|e| e.cannot_be_supported); - // 组内 support 下标(保持插槽顺序);active / 未知效果不参与裁决。 - let support_indices: Vec = group + // 组内 support 候选(保持插槽顺序):每个宝石的主授予效果 + 附加授予效果 + // (`gem_effects` 外键)中 `is_support` 者——vendor 对 grantedEffectList 逐 + // 效果按 support 标志分流,meta 宝石(Blasphemy)的 support 半身在附加位 + // (SupportBlasphemyPlayer,携带 `CurseEffect MORE` 等技能局部段)。 + // active / 未知效果不参与裁决。 + let support_candidates: Vec<(usize, &str)> = group .gem_skills .iter() .enumerate() - .filter(|(_, g)| { - data.granted_effects - .get(&g.skill_id) - .is_some_and(|e| e.is_support) + .flat_map(|(i, g)| { + std::iter::once(g.skill_id.as_str()) + .chain( + data.gem_effects + .get(&g.skill_id) + .into_iter() + .flat_map(|l| l.additional_granted_effect_ids.iter().map(String::as_str)), + ) + .filter(|id| data.granted_effects.get(*id).is_some_and(|e| e.is_support)) + .map(move |id| (i, id)) }) - .map(|(i, _)| i) .collect(); // 四段裁决(CalcTools.lua:84-110):cannotBeSupported → supportGemsOnly → // exclude 表达式 → require 表达式(空 = 接受)。socket group 内技能恒由宝石授予 // (from_gem=true);fromItem 特例 M5c、minionTypes 第二集合 M5a(defer)。 - let judge = |idx: usize, types: &HashSet| -> bool { - data.granted_effects - .get(&group.gem_skills[idx].skill_id) - .is_some_and(|effect| { - can_support( - &SupportJudgeInput { - support_gems_only: effect.support_gems_only, - exclude_skill_types: &effect.exclude_skill_types, - require_skill_types: &effect.require_skill_types, - }, - &ActiveSkillJudgeInput { - cannot_be_supported, - from_gem: true, - skill_types: types, - }, - ) - }) + let judge = |effect_id: &str, types: &HashSet| -> bool { + data.granted_effects.get(effect_id).is_some_and(|effect| { + can_support( + &SupportJudgeInput { + support_gems_only: effect.support_gems_only, + exclude_skill_types: &effect.exclude_skill_types, + require_skill_types: &effect.require_skill_types, + }, + &ActiveSkillJudgeInput { + cannot_be_supported, + from_gem: true, + skill_types: types, + }, + ) + }) }; - let merge_add = |idx: usize, types: &mut HashSet| { - if let Some(effect) = data.granted_effects.get(&group.gem_skills[idx].skill_id) { + let merge_add = |effect_id: &str, types: &mut HashSet| { + if let Some(effect) = data.granted_effects.get(effect_id) { for t in &effect.add_skill_types { types.insert(t.clone()); } @@ -634,24 +666,24 @@ pub(crate) fn judge_group_supports( }; // pass1:兼容 support 并入 addSkillTypes;不兼容进被拒名单。 - let mut rejected: Vec = Vec::new(); - for &i in &support_indices { - if judge(i, &skill_types) { - merge_add(i, &mut skill_types); + let mut rejected: Vec<&(usize, &str)> = Vec::new(); + for cand in &support_candidates { + if judge(cand.1, &skill_types) { + merge_add(cand.1, &mut skill_types); } else { - rejected.push(i); + rejected.push(cand); } } // repeat-until 不动点:重扫被拒名单直到一轮无新增。 loop { let mut newly_accepted = false; let mut still_rejected = Vec::with_capacity(rejected.len()); - for &i in &rejected { - if judge(i, &skill_types) { + for cand in rejected { + if judge(cand.1, &skill_types) { newly_accepted = true; - merge_add(i, &mut skill_types); + merge_add(cand.1, &mut skill_types); } else { - still_rejected.push(i); + still_rejected.push(cand); } } rejected = still_rejected; @@ -660,9 +692,13 @@ pub(crate) fn judge_group_supports( } } // pass2:终态集合下全量重裁决。 - let compatible: Vec = support_indices - .into_iter() - .filter(|&i| judge(i, &skill_types)) + let compatible: Vec = support_candidates + .iter() + .filter(|(_, id)| judge(id, &skill_types)) + .map(|&(i, id)| CompatibleSupport { + gem_index: i, + effect_id: id.to_string(), + }) .collect(); GroupSupportJudgement { compatible, @@ -688,20 +724,21 @@ pub(crate) fn support_modifiers( ) -> Vec { let judgement = judge_group_supports(group, data, active_skill_id); let mut mods = Vec::new(); - for &i in &judgement.compatible { - let gem = &group.gem_skills[i]; + for sup in &judgement.compatible { + let gem = &group.gem_skills[sup.gem_index]; + let set_index = sup.stat_set_index(group); // TODO(T1,T3.6 合并后 rebase 追加):quality 传参改为 gem.quality——support 的 // 品质表条目不存在(PoB2 导出即跳过),当前恒空段,传 0 与传 gem.quality 等价。 - let stats = data.effect_stats(&gem.skill_id, gem.gem_level, 0, gem.stat_set_index); + let stats = data.effect_stats(&sup.effect_id, gem.gem_level, 0, set_index); // support 的 set_key 取自身选中 set(per-set 覆盖以 support 效果 id 定位)。 // 注:vendor 对 support 效果不传 statSet(CalcActiveSkill.lua:130 全 set 全量 // merge)——多 set support 的附加 set 全量 merge 当前缺口见 m1 验收报告。 - let set_key = data.selected_set_key(&gem.skill_id, gem.stat_set_index); + let set_key = data.selected_set_key(&sup.effect_id, set_index); mods.extend(mapped_stat_modifiers( &stats.base, SourceKind::SupportGem, - &gem.skill_id, - &gem.skill_id, + &sup.effect_id, + &sup.effect_id, set_key.as_deref(), )); // (M1-T4.4)兼容 support 的分等级 cost 倍率 → `SupportManaMultiplier` MORE @@ -711,7 +748,7 @@ pub(crate) fn support_modifiers( // (倍率连乘截断 4 位小数后,先于 inc/more 链作用于 base cost)。 if let Some(mm) = data .granted_effect_levels - .get(&gem.skill_id) + .get(&sup.effect_id) .and_then(|rows| { rows.iter() .rfind(|r| r.level <= gem.gem_level) @@ -722,9 +759,9 @@ pub(crate) fn support_modifiers( { let origin = ModifierSource::new(SourceId::new( SourceKind::SupportGem, - format!("support.{}.manaMultiplier", gem.skill_id), + format!("support.{}.manaMultiplier", sup.effect_id), )) - .with_raw_text(format!("support {} cost multiplier {mm}%", gem.skill_id)); + .with_raw_text(format!("support {} cost multiplier {mm}%", sup.effect_id)); mods.push( Modifier::number("SupportManaMultiplier", ModType::More, mm).with_origin(origin), ); @@ -795,11 +832,8 @@ mod support_judgement_tests { } /// 兼容名单换算回效果 id(断言可读性)。 - fn compatible_ids(j: &GroupSupportJudgement, gem_order: &[&str]) -> Vec { - j.compatible - .iter() - .map(|&i| gem_order[i].to_string()) - .collect() + fn compatible_ids(j: &GroupSupportJudgement, _gem_order: &[&str]) -> Vec { + j.compatible.iter().map(|c| c.effect_id.clone()).collect() } /// 不动点顺序无关(CalcActiveSkill.lua:193-208):「A 加 Triggered、B require diff --git a/crates/pobr-build/src/snapshot.rs b/crates/pobr-build/src/snapshot.rs index dd5ff078..41602142 100644 --- a/crates/pobr-build/src/snapshot.rs +++ b/crates/pobr-build/src/snapshot.rs @@ -248,6 +248,7 @@ mod tests { base: ItemBaseId::from("Iron Ring"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec!["+10 to maximum Life".into()], enchant_texts: vec![], diff --git a/crates/pobr-build/src/xml_build.rs b/crates/pobr-build/src/xml_build.rs index b2f15fca..21c26bf3 100644 --- a/crates/pobr-build/src/xml_build.rs +++ b/crates/pobr-build/src/xml_build.rs @@ -73,7 +73,6 @@ pub fn parse_build(xml: &str) -> Result { let use_second_weapon_set = parse_active_item_set(xml)?.3; let ParsedPassives { allocated: allocated_nodes, - inactive_weapon_set: inactive_weapon_set_nodes, tree_version, } = parse_passive_nodes(xml, use_second_weapon_set)?; let allocated_set: std::collections::HashSet = @@ -110,9 +109,6 @@ pub fn parse_build(xml: &str) -> Result { if !radius_jewels.is_empty() { build = build.with_radius_jewels(radius_jewels); } - if !inactive_weapon_set_nodes.is_empty() { - build = build.with_inactive_weapon_set_nodes(inactive_weapon_set_nodes); - } if !flask_charms.is_empty() { build = build.with_utility_slots(flask_charms); } @@ -470,25 +466,18 @@ struct SpecNodes { /// `activeSpec` 为 1-based 索引;越界 / 缺失时取首个 ``。无 `` 返回空。 /// /// 武器集语义(PoB2 CalcSetup.lua:209-233 / :791-792):武器集专属点 -/// (`allocMode = 1|2`)的全部**自身** mod 追加 `Condition: WeaponSet`,而该条件 -/// flag 只对当前激活武器集置真(`useSecondWeaponSet` ? 2 : 1)——净效果是非激活集 -/// 专属点的**自身词条**整体不生效。PoBR 在解析层等价实现:从已分配节点中剔除非激活集 -/// 的专属点(其自身 mod 收集随之关闭,与 PoB2 条件门控等价)。 -/// -/// ⚠️ 但 PoB2 **不**把这些节点从 `allocNodes` 移除——它们仍是已分配节点,只是自身 mod -/// 被条件门控(CalcSetup.lua:209-228)。因此**范围珠宝授予**(`... in Radius also -/// grant`,源=jewel 而非节点,按 jewel 的 allocMode 门控而非节点的,:224-228)仍会落到 -/// 这些非激活集 notable 上。PoBR 把剔除掉的节点单独回传(返回值 `.1`),供 -/// [`crate::calc_orchestrator::collect::radius_jewel_expansions`] 在 radius 几何里并回, -/// 以复刻 PoB2「非激活集节点仍计入 radius 授予」的行为(gemling crit jewel 实测)。 +/// (`allocMode = 1|2`)节点上的**每条** mod——含自身词条与范围珠宝授予——都被追加 +/// `Condition: WeaponSet`(节点自身 allocMode 优先,CalcSetup.lua:222-223;珠宝 +/// 来源门控的 :224-227 分支仅对 allocMode=0 节点生效),而该条件 flag 只对当前激活 +/// 武器集置真(`useSecondWeaponSet` ? 2 : 1)——净效果是非激活集专属点上的全部词条 +/// **整体不生效**。PoBR 在解析层等价实现:从已分配节点中剔除非激活集的专属点 +/// (mod 收集 / 范围珠宝授予计数 / per-X 倍率均随之一致;oracle 实证见 +/// `collect::radius_jewel_expansions`)。 /// -/// 返回 `(激活已分配节点, 被剔除的非激活集节点, tree_version)`。 /// [`parse_passive_nodes`] 的解析结果。 struct ParsedPassives { /// 激活已分配节点(自身 mod 参与计算)。 allocated: Vec, - /// 被剔除的非激活武器组专属点(自身 mod 已 masking,但仍计入范围珠宝授予几何)。 - inactive_weapon_set: Vec, tree_version: Option, } @@ -540,7 +529,6 @@ fn parse_passive_nodes(xml: &str, use_second_weapon_set: bool) -> Result Result = spec.weapon_set [if use_second_weapon_set { 0 } else { 1 }] .iter() .copied() .collect(); - let mut nodes = Vec::with_capacity(spec.nodes.len()); - let mut masked = Vec::new(); - for n in spec.nodes { - if inactive.contains(&n) { - masked.push(n); - } else { - nodes.push(n); - } - } + let allocated = spec + .nodes + .into_iter() + .filter(|n| !inactive.contains(n)) + .collect(); Ok(ParsedPassives { - allocated: nodes, - inactive_weapon_set: masked, + allocated, tree_version, }) } @@ -662,11 +644,53 @@ fn parse_items_and_slots( // 树上珠宝在 ``(非 ItemSet),单独收集; // 仅保留 socket 节点已分配的珠宝。 + let socket_items = parse_socket_node_items(xml)?; + // Voices(0.5.4b unique):「Allocates N Sinister Jewel sockets」——已分配 socket + // 内珠宝带此词条时,按 vendor alias 序把前 N 个 sinister socket 视为已分配 + // (vendor PassiveSpec.lua:1067-1090 `voices_jewel_slot1..5` → 0_5 tree 节点 id, + // 钉自 TreeData/0_5/tree.lua `sinister=true` + `aliasPassiveSocket`)。 + // ponytail: 节点 id 钉 0_5 树(sinister socket 仅存在于 0.5.4+;旧树版本无此 + // 词条来源,零行为)。树版本再迭代时 parity 门禁会点名此列,届时改从树数据取。 + const SINISTER_SOCKETS_0_5: [u32; 5] = [62152, 26178, 23960, 39087, 3367]; + let sinister_count: usize = socket_items + .iter() + .filter(|(node, _)| allocated.contains(node)) + .filter_map(|(_, id)| items.get(id)) + .flat_map(|it| it.implicit_texts.iter().chain(&it.modifier_texts)) + .filter_map(|t| sinister_socket_alloc_count(t)) + .sum(); + let mut sinister_allocated: std::collections::HashSet = SINISTER_SOCKETS_0_5 + .iter() + .copied() + .take(sinister_count) + .collect(); + // 具名 jewel socket 的「Allocates <名>」授予(vendor PassiveSpec.lua:1106-1114 + // ResolveGrantedPassiveNodes 的 sockets 名匹配 fallback):amulet anoint + // `{enchant}Allocates Zarokh's Gift` 分配 socket 节点,socket 内珠宝随之入计。 + // ponytail: 0_5 树唯一具名 socket 就是 Zarokh's Gift(其余全叫 Sinister Jewel + // Socket,走上面的 Voices 计数通道);树版本再迭代新增具名 socket 时 parity + // 门禁会点名,届时改从树数据取名表。 + const NAMED_SOCKETS_0_5: [(&str, u32); 1] = [("zarokh's gift", 11184)]; + let equipped_texts = out.iter().flat_map(|(_, item)| { + item.implicit_texts + .iter() + .chain(&item.modifier_texts) + .chain(&item.enchant_texts) + }); + for text in equipped_texts { + if let Some(name) = text.trim().strip_prefix("Allocates ") + && let Some((_, node)) = NAMED_SOCKETS_0_5 + .iter() + .find(|(n, _)| name.trim().eq_ignore_ascii_case(n)) + { + sinister_allocated.insert(*node); + } + } let mut all_jewel_ids = jewel_ids; all_jewel_ids.extend( - parse_socket_node_items(xml)? + socket_items .into_iter() - .filter(|(node, _)| allocated.contains(node)) + .filter(|(node, _)| allocated.contains(node) || sinister_allocated.contains(node)) .map(|(_, item)| item), ); all_jewel_ids.sort_unstable(); @@ -683,6 +707,19 @@ fn parse_items_and_slots( Ok((out, jewels, flask_charms, use_second_weapon_set)) } +/// 解析「Allocates N Sinister Jewel socket(s)」词条 → N(vendor ModParser.lua +/// `allocates (%d+) sinister jewel sockets?` → GrantedPassive SinisterJewelSockets)。 +/// 非此词条返回 None。 +fn sinister_socket_alloc_count(text: &str) -> Option { + let rest = text.trim().strip_prefix("Allocates ")?; + let (num, tail) = rest.split_once(' ')?; + matches!( + tail.trim().to_ascii_lowercase().as_str(), + "sinister jewel sockets" | "sinister jewel socket" + ) + .then(|| num.parse().ok())? +} + /// 解析树插槽 `` → `(socket_node, item_id)`(itemId≠0)。 fn parse_socket_node_items(xml: &str) -> Result, XmlError> { let mut reader = Reader::from_str(xml); @@ -1145,15 +1182,17 @@ fn parse_socket_groups(xml: &str) -> Result, XmlError> { "Gem" if in_target_set => { if let Some(cur) = current.as_mut() && attr_bool_default_true(&e, b"enabled") - && let Some(gem_id) = attr_value(&e, b"gemId") - && !gem_id.is_empty() { + let gem_id = attr_value(&e, b"gemId").filter(|v| !v.is_empty()); + let skill_id = attr_value(&e, b"skillId").filter(|v| !v.is_empty()); + // lineage support(如 Atziri's Communion)序列化时缺 + // skillId/gemId,仅有 nameSpec——保留显示名,交编排层 + // `stage_build_view` 按 granted_effects 反查回填 id。 + let name_spec = attr_value(&e, b"nameSpec").filter(|v| !v.is_empty()); // 捕获每个启用 gem 的 skillId + level + quality(active 与 // support 皆收)。quality 属性缺失/非法按 0(无品质),对齐 // PoB2 SkillsTab.lua 的 `quality` 属性读取(缺省 0)。 - if let Some(skill_id) = attr_value(&e, b"skillId") - && !skill_id.is_empty() - { + if skill_id.is_some() || name_spec.is_some() { let level = attr_value(&e, b"level") .and_then(|v| v.parse::().ok()) .unwrap_or(1); @@ -1166,20 +1205,28 @@ fn parse_socket_groups(xml: &str) -> Result, XmlError> { // (calcs 页独立选择)M1 不做,忽略。 let stat_set_index = attr_value(&e, b"statSetIndex") .and_then(|v| v.parse::().ok()); - // 组内首个启用 gem 视为主动技能(PoB Gem 列表 active 在前)。 - if cur.active_skill_id.is_none() { + // 组内首个带 skillId 的启用 gem 视为主动技能 + // (PoB Gem 列表 active 在前;nameSpec-only 引用 + // 均为 lineage support,不参与主动技能判定)。 + if let Some(skill_id) = &skill_id + && cur.active_skill_id.is_none() + { cur.active_skill_id = Some(skill_id.clone()); cur.active_gem_level = Some(level); cur.active_gem_quality = Some(quality); } + let name_spec_pending = skill_id.is_none(); cur.gem_skills.push(crate::build::GemSkillRef { - skill_id, + skill_id: skill_id.unwrap_or_default(), gem_level: level, quality, stat_set_index, + name_spec: if name_spec_pending { name_spec } else { None }, }); } - cur.gem_ids.push(gem_id); + if let Some(gem_id) = gem_id { + cur.gem_ids.push(gem_id); + } } } "StatSetIndex" if in_target_set => { diff --git a/crates/pobr-build/tests/parity/crossbow_reload_golden.rs b/crates/pobr-build/tests/parity/crossbow_reload_golden.rs index 2b1193b0..988529dd 100644 --- a/crates/pobr-build/tests/parity/crossbow_reload_golden.rs +++ b/crates/pobr-build/tests/parity/crossbow_reload_golden.rs @@ -34,6 +34,7 @@ fn bare_weapon(base_name: &str) -> Item { base: ItemBaseId::from(base_name), rarity: ItemRarity::Normal, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec![], enchant_texts: vec![], diff --git a/crates/pobr-build/tests/parity/defence_panels_golden.rs b/crates/pobr-build/tests/parity/defence_panels_golden.rs index 7b4c3bb3..cd35d3f2 100644 --- a/crates/pobr-build/tests/parity/defence_panels_golden.rs +++ b/crates/pobr-build/tests/parity/defence_panels_golden.rs @@ -97,13 +97,18 @@ fn block_chance_zero_on_non_shield_builds() { /// `DeflectChance`/`DeflectionRating` @5%(13-G10):huntress/monk 系 /// `Gain Deflection Rating equal to N% of Evasion` build 是现成 fixture; /// 无 deflect 来源的 build 双值保持 0(verify 零值不误报)。 +/// +/// 0.5.4b 适配注:Phase 0 曾以「DeflectionRating ~0.60x」ignore 本 canary; +/// 复盘(oracle 复跑 2026-07-17)确认该缺口整体是 Evasion 缺口(Mageblood, +/// 6685c30)的下游——rating 派生自 `Evasion × GainAsDeflection%`,公式本身 +/// (CalcDefence.lua:48-54 / :1516-1522)与 vendor 一致,Evasion 闭合后 +/// monk rating 22267.8 vs golden 22312.08(0.998x),无需公式改动。 #[test] -#[ignore = "0.5.4b DeflectionRating 公式适配缺口(~0.60x);见 docs/adapting-to-0.5.4b.md Phase 1"] fn deflection_matches_golden() { let data = load_data(); for name in [ "huntress-spirit-walker-twister", // rating 5666.7 / chance 37 - "monk-martial-artist-twister", // rating 11229.76 / chance 58 + "monk-martial-artist-twister", // rating 22312.08 / chance 84 "warrior-titan-shield-wall", // rating 0.84 / chance 0 "sorceress-stormweaver-comet", // 0 / 0 ] { diff --git a/crates/pobr-build/tests/parity/golden_canary.rs b/crates/pobr-build/tests/parity/golden_canary.rs index a769ba3a..31861203 100644 --- a/crates/pobr-build/tests/parity/golden_canary.rs +++ b/crates/pobr-build/tests/parity/golden_canary.rs @@ -142,8 +142,11 @@ fn canary_evasion_melee() { } /// 火焰法术 / 护甲层(CI,Life=1 跳过)。 +/// +/// Phase 0 曾以「0.5.4b offence DPS 适配缺口(~0.60x)」`#[ignore]`;#4 重验 +/// ember-fusillade TotalDPS 已 1.00x(548742 vs 549423——gap map 条目在先前 +/// mana-multiplier / Arcane Surge 等修复中顺带闭合,未及回验),un-ignore。 #[test] -#[ignore = "0.5.4b offence DPS 适配缺口(~0.60x);见 docs/adapting-to-0.5.4b.md Phase 1"] fn canary_fire_spell_armour() { let d = load_data(); let n = "druid-oracle-ember-fusillade"; diff --git a/crates/pobr-build/tests/parity/ninja_parity.rs b/crates/pobr-build/tests/parity/ninja_parity.rs index 2394c494..9d709c3f 100644 --- a/crates/pobr-build/tests/parity/ninja_parity.rs +++ b/crates/pobr-build/tests/parity/ninja_parity.rs @@ -37,6 +37,14 @@ fn discover_builds() -> Vec { .filter(|p| p.is_dir() && p.join("code.txt").exists() && p.join("meta.json").exists()) .collect(); dirs.sort(); + // Debug aid: POBR_ONLY_BUILD= narrows the dashboard to matching + // build dirs so POBR_DBG_* channels stay readable. Never set in CI. + if let Ok(filter) = std::env::var("POBR_ONLY_BUILD") { + dirs.retain(|p| { + p.file_name() + .is_some_and(|n| n.to_string_lossy().contains(&filter)) + }); + } dirs } @@ -528,7 +536,16 @@ fn compute_tallies(verbose: bool) -> (Tally, Tally, Tally, Tally, Vec) { // 展示行」改为 PoB2 口径「基底 DB 重算 (esBase+flat)×(1+localInc/100)×(1+quality/100)」 // (Item.lua:1994-1996;展示行跨数据版本会滞后)——titan ES 41→55、stormweaver ES // 986→1120,各连带 ESRecoveryCap。见 calc_orchestrator/defence.rs::item_rolled_defence。 -const BASELINE_DEF_CORE_HIT5: usize = 138; // ItemES 后 138/144(Barrier-Life 136;Mageblood 135;迁移基线 118;0.5.0=139) +// **0.5.4b #4 Communion/LowLife + Voices 重记(+2 @5% core-8 138→140)**: +// huntress-ritualist SpiritUnres −13.00x→1.00x / LifeUnres 12.74x→1.01x—— +// Atziri's Communion 的 Spirit→Life 保留转换(LifeReservePercentPerSpirit, +// vendor CalcDefence.lua:248-254)接入后双列翻正;abyssal-lich(同戴 Communion) +// SpiritUnres inf→1.00x 同根。见 buffs.rs spirit_reservation_modifiers 转换分支。 +// **#14 防御长尾分诊重记(+2 core-8 142→144/144 = 100%)**:abyssal-lich Life +// (LifeConvertToEnergyShield 池扣减,0_5 树 Enhanced Barrier)+ smith Armour +// (connected-notable multiplier + StrRequirements 快照)翻正。详见 #14 各修复 +// commit 与 docs/adapting-to-0.5.4b.md §#14。 +const BASELINE_DEF_CORE_HIT5: usize = 144; // #14 长尾分诊后 144/144(存量 #7-3/4 142;Communion 140(ItemES 138;Barrier-Life 136;Mageblood 135;迁移基线 118;0.5.0=139) // **per-socket-filled 修复重记(+1 @5%/@10%)**:gemling-legionnaire 身甲 Morior Invictus // `+14 to Spirit per Socket filled`(×5 socket)经 `RunesSocketedIn{SlotName}` Multiplier // 接入 → Spirit 180→250(0.72x→1.00x,翻正)。详见 collect.rs::filter_parseable 闸门 + @@ -618,8 +635,63 @@ const BASELINE_DEF_CORE_HIT5: usize = 138; // ItemES 后 138/144(Barrier-Life // BASELINE_DEF_CORE_HIT5 上的说明;gemling 8 列(Life/TotalEHP/5×MaxHit/LifeUnres)翻正。 // **Item ES 重算重记(+4 @5% 401→405 / +3 @10% 425→428)**:titan+stormweaver 各 // ES+ESRecoveryCap 翻正;见 BASELINE_DEF_CORE_HIT5 上说明。 -const BASELINE_DEF_HIT5: usize = 405; // ItemES 后 405/450(Barrier-Life 401;Mageblood 393;迁移基线 343;0.5.0=415) -const BASELINE_DEF_HIT10: usize = 428; // ItemES 后 428/450(Barrier-Life 425;Mageblood 417;迁移基线 361;0.5.0=432) +// **Refraction buff EvasionGainAsDeflection 重记(+2 @5% 405→407 / +1 @10% +// 428→429)**:support Refraction I/II 的 Refractive Plating buff 载荷 +// (`support_tempered_valour_deflection_rating_%_of_evasion_rating` BASE 20) +// 经 player buff 允收名单接入(stat_map_engine),wolf-pack DeflectChance +// 0.80x→1.00x(@5%+@10%)、pathfinder 0.93x→1.00x(@5%)。 +// **Refraction buff ArmourAppliesToDamageTaken 重记(+3 @5% 407→410)**: +// 同 buff 的 `support_tempered_valour_%_armour_to_apply_to_elemental_damage` +// 载荷(三条 BASE 30)经同一 player buff 允收名单接入,消费方 +// `calc::taken::armour_applies_pct`(tree 84 + buff 30 = 114%,oracle 钉值 +// FireEffectiveAppliedArmour 21181.2)。wolf-pack Fire/Cold/LightMaxHit +// 0.94x→0.96x(@5% 翻正)、TotalEHP 0.81x→0.88x(余量 = Armour 0.98x 本体 +// 差 + ChaosMaxHit 0.87x + Life 1.11x,均与本通道无关)。@10% 无变化。 +// **0.5.4b #4 Communion/LowLife + Voices 重记(+3 @5% 410→413 / +5 @10% 429→434)**: +// core-8 的 SpiritUnres/LifeUnres 翻正(见 BASELINE_DEF_CORE_HIT5 上说明)+ +// abyssal-lich EnergyShield 0.93x→0.98x(Voices sinister 珠宝的 ES 词条找回)。 +// **#12 companion allies 层重记(+6 @5% 425→431 / +5 @10% 434→439)**:伴侣先扣层 +// 落地(TakenFromCompanionBeforeYou buff 允收 + TotalCompanionLife 求和注入 + +// pool_setup companion AllyLayer;连带 = 召唤物等级吃 `+N to Level of Minion +// Skills`、召唤物基础生命改走 monsterAllyLifeTable、Loyalty 的 −30% more minion +// life 经 minion 域 statmap 通道注入)。spirit-walker-twister 6 格全翻正 +// (5×MaxHit + TotalEHP 0.89-0.90x→1.00x 精确闭合,Bear Companion + Wild +// Protector 自带 10% taken);wolf-pack MaxHit 族 0.82x→0.90x / ChaosMaxHit +// 0.72x→0.80x / TotalEHP 0.74x→0.83x(池侧 3817 vs oracle 3826.67 = 0.9975 已 +// 闭合,余量 = per-type taken 乘子侧 ~10% 均匀缺口 + Mana 761.2 vs 770,均与 +// companion 层无关)。 +// **#13 防御残差定点修复重记(+6 @5% 431→437 / +6 @10% 439→445)**:三根因—— +// ① wolf-pack per-type taken 乘子 ~10% 均匀缺口 = 敌人 Intimidated 基础条件对 +// (vendor CalcSetup.lua:73-77 `Damage INC -10 / DamageTaken INC 10 if +// Intimidated`)未建:体甲词条「Enemies in your Presence are Intimidated」的 +// 敌侧 `Condition:Intimidated` flag 已入 enemy db 但无消费方。setup_enemy 注入 +// 条件对 + env_finalize 桥接 flag→cfg `EnemyIntimidated` + orchestrator 默认 +// 置真 `EnemyInPresence`(vendor CalcPerform.lua:524)→ `EnemyDamageMult` +// 0.9 生效(max hit 末端除数 :3734-3771 + EHP 进伤),wolf-pack 5×MaxHit +// 0.80-0.90x→1.00x、TotalEHP 0.83x→1.00x、PhysDR 68.03 精确。 +// ② wolf-pack Mana 761.2 vs 770 = The Adorned「97% increased Effect of Jewel +// Socket Passive Skills containing Corrupted Magic Jewels」未建:腐化魔法珠宝 +// (Rallying Ruby ×6,enchant +Int/+Dex/+chaos res)mod 未按 1.97 缩放 +// (vendor CalcSetup.lua:944-948/:1342-1347,ScaleAddList = trunc(round(v×s,2)))。 +// orchestrator stage_inject_jewels 解析后缩放注入 → Int 135→139 → Mana 770 +// 精确(连带 ChaosMaxHit 尾差闭合)。 +// ③ titan Armour 0.985x = 三件 Runeforged 基底(0.5.4b buff 过)护甲展示行滞后: +// item_rolled_defence 的「基底已知恒重算」从 ES-only 扩到三防(vendor +// Item.lua:1994-1996 + round 口径)——手套 96→101 / 盔 192→284 / 靴 58→100, +// Gear:Armour 6100→6239 = vendor,titan Armour/ES/5×MaxHit 精确闭合;连带 +// pathfinder Evasion 0.98x→1.00x、twister DeflectChance 0.97x→1.00x 精确化。 +// **#14 防御长尾分诊重记(+13 @5% 431→444 / +5 @10% 439→444)**:五簇闭合—— +// ① PhysDR 取整(vendor :2402 armourReduction 整数变体)ember/deadeye 2 格; +// ② Life 池 ConvertTo 扣减(CalcDefence.lua:92)abyssal-lich Life/LifeUnres 2 格; +// ③ Blasphemy per-curse 并入 baseFlat 单次 round(:229-239)essence-drain +// SpiritUnres 1 格;④ altQualityStats 通道(GemlingQuality 门控, +// CalcTools.lua:147-152)gemling SpiritUnres 1 格;⑤ Smith connected-notable +// multiplier + StrRequirementsOn 快照(CalcSetup.lua:840/CalcPerform. +// lua:1848-1857)smith Armour+4×MaxHit+TotalEHP 等 5 格;⑥ EHP 平均格挡改 +// 四分型均值(:1067,SpellProjectileBlock=max(spell,proj) 不再漏)smith+titan +// TotalEHP 2 格。剩余 6 格全部 = wolf-pack(#13 领地)。 +const BASELINE_DEF_HIT5: usize = 450; // #13+#14 合并实测 450/450 = 100%(#13 单独 437:wolf-pack 全清;#14 单独 444:长尾 12 格+四分型格挡;迁移基线 343;0.5.0=415) +const BASELINE_DEF_HIT10: usize = 450; // #13+#14 合并实测 450/450 = 100%(迁移基线 361;0.5.0=432) // **附加授予效果展开重记(+3 @10%)**:gem 的 additionalGrantedEffectId1..N // (overlay/gem_effects.json 外键,如三 banner 的 buff 侧效果——主位是预留侧 // ReservationPlayer、buff 侧 BannerPlayer(Aura)在附加位)在 buff_skill_specs @@ -642,14 +714,11 @@ const BASELINE_DEF_HIT10: usize = 428; // ItemES 后 428/450(Barrier-Life 425 // titan-shield-wall 连带。 // 三修复 build 互不重叠、增益叠加;合并后全量实测重记(master 62/70 → 70/73)。 // -// **radius-jewel × weapon-set 交互修复重记(gemling CritChance)**:非激活武器组专属点 -// 在 PoB2 仍留在 allocNodes(CalcSetup.lua:209-228),范围珠宝授予(`... in Radius also -// grant`,源=jewel)照样落到这些 notable 上。PoBR 原先把非激活组节点整个剔除 → gemling -// crit jewel 的 `7% increased Crit Hit Chance for Attacks` 只命中 1/6 个 in-radius -// notable(其余 5 个在 WeaponSet2)→ CritChance 8.55 vs 10.30(0.83x)。修复= -// `parse_passive_nodes` 单独回传被剔除的非激活组节点,`radius_jewel_expansions` 在几何里 -// 并回完整已分配集(节点自身 mod 仍 masking,行为不变)。gemling CritChance→1.00x、 -// AvgDamage/TotalDPS 0.96x→1.03x。其余 build 零回归(off 70/73 → 71/74)。 +// **radius-jewel × weapon-set 交互修复重记(gemling CritChance,⚠️已在 #15 回退)**: +// 曾把非激活武器组节点并回 radius 授予几何(当时 golden 10.30 = 6×+7)。0.5.4b 重采 +// golden 后 vendor 实测(oracle Tabulate)授予受**目标节点**的 `Condition:WeaponSet` +// 门控(CalcSetup.lua:222-223),非激活组授予净效果为零 → 正确值 8.55 = 1×+7, +// 机制整体回退(见 BASELINE_OFF_HIT5 上 #15 ①)。 // **Mageblood Diamond crit 名归一重记(+2 @5% 39→41 / +3 @10% 47→50)**:Mageblood // LegacyOfDiamond 注入 vendor 名 `CritChance` INC,但 calc::crit 读 `CriticalStrikeChance` // (PoBR 规范名)——裸注入不过 parser 的 translate_vendor_name,落死桶(同 Virtuous @@ -665,8 +734,99 @@ const BASELINE_DEF_HIT10: usize = 428; // ItemES 后 428/450(Barrier-Life 425 // mana_pool 并回填 cfg.stats["Mana"],但漏刷 cfg.multipliers["Mana"](per-100-max-Mana // 类词条如 Arcane Intensity 读它)→ 池转换 build 的 mana 缩放用了转换前的旧值。补刷后 // blood-mage SpellDamage INC 39→105、TotalDPS 0.74x→0.87x,其 DoT 基底随之抬升。见 perform.rs。 -const BASELINE_OFF_HIT5: usize = 46; // mana-mult 后 46/80(Silver-speed 45;迁移基线 39;0.5.0=71) -const BASELINE_OFF_HIT10: usize = 55; // mana-mult 后 55/80(Silver-speed 54;迁移基线 47;0.5.0=74) +// **0.5.4b #4 Communion/LowLife + Voices 重记(off +6 @5% 46→52 / +4 @10% 55→59)**: +// 两个 0.5.4b 新机制在真实 build 上叠加成 per-build DPS 簇(gap map「~0.60x」项): +// 1. Atziri's Communion Spirit→Life 保留转换(vendor CalcDefence.lua:248-254)→ +// 重保留 build 自动 Low Life(:335-350 unreserved ≤ 35%)→「while on Low Life」 +// 族增伤解锁(ritualist:tree +60 与 Direstrike buff +70 attack INC,oracle +// damageModList 钉值 = 缺口 130 INC 整)。 +// 2. Voices「Allocates 2 Sinister Jewel sockets」→ sinister socket 珠宝入计 +// (ritualist crit chance/mult 13/37 INC 找回,双列精确闭合)。 +// huntress-ritualist TotalDPS 0.68x→0.99x(AvgDamage/CritChance/CritMultiplier 同翻)、 +// witch-abyssal-lich TotalDPS 0.62x→0.91x(Speed 0.91x→1.00x、CritChance 0.98x、 +// CritMultiplier 0.75x→0.97x,其中 Speed/CritChance @5% 翻正、DPS 未回带)。 +// **0.5.4b #4 grenade 短语解禁重记(off +4 @5% 52→56 / +3 @10% 59→62)**:vendor +// 0.22.0 ModParser gem 名注册循环新增 `not grantedEffect.fromItem` 排除 +// (ModParser.lua:6423)——`MeleeGrenadeLauncherPlayer`(name "Grenade",fromItem) +// 不再抢注 skillNameList,`grenade` / `for grenade skills` 短语恢复为 live +// `SkillType.Grenade` tag(run-parsemod 双证)。PR#53 时代(0.21 语义)的抽取侧 +// 死条目/惰性改写撤销 + mod_parser_rules/parsed_mods 再生成。deadeye 3×15 CDR +// 树词条(oracle extraModList 钉源 Tree:21077/354/48429)生效:deadeye Speed +// 0.65x→1.00x(翻正)、TotalDPS 0.53x→0.83x;gemling Speed/AvgDamage/TotalDPS/ +// CombinedDPS 全部 1.00-1.04x 翻正。 +// **0.5.4b #5 Blazing Critical 全局火焰 buff 重记(off +2 @5% 56→58 / +2 @10% +// 62→64)**:0.22.0 给 `support_blazing_crits_gain_%_fire_damage_with_attacks_ +// on_critical_hit` 补 GlobalEffect/Buff tag(sup_int.lua:959)——15% +// `DamageGainAsFire`(Attack + Condition:CritRecently)从死词条变成全局玩家 +// buff。两处接线:stat_map_engine 玩家 buff 允收名单 + support_buff_specs +// 裁决对象补附加授予效果(Charged Staff 的隐藏 Attack 附加效果 +// ChargedStaffShockwavePlayer 才是 Blazing Critical 的兼容宿主)。 +// monk-twister AverageDamage/TotalDPS 0.60x→0.96x 双列翻正;flicker +// TotalDPS 0.76x→0.84x、spirit-walker 0.78x→0.89x 收敛未入列(残余 = +// 攻击 AvgDamage 族存量缺口的平方传导)。 +// **0.5.4b #6 攻击 AvgDamage 族攻坚重记(off +13 @5% 58→71 / +9 @10% 64→73)**: +// 五个通用消费点修复叠加,整族(smith/titan/flicker/monk-twister/spirit-walker/ +// pathfinder/ritualist/gemling)全部进入 5% 带: +// 1. Bifurcate 爆伤条件概率(vendor :3823-3846 `conditionalBifurcateChance = +// (PreBifurcate²/100)/CritChance`,PoBR 误移植为无条件 pre²/10000——新旧 vendor +// 同式,属存量误差)+ 武器无 flag 爆伤词条转按手条件(Item.lua:1954-1961, +// **0.22.0 新增** CritMultiplier 进转换清单):spirit-walker/pathfinder CritMult +// 0.94x→1.00x/0.99x,titan CritMult 1.20x→1.00x(oracle 钉值 6.02→5.00 golden 精确)。 +// 2. enemyDistance placeholder 喂 skillDist(CalcActiveSkill.lua:671,**0.22.0 新增** +// configPlaceholder 兜底):Close Combat 30% MORE 按 ramp(20)=0.6 生效 → +// flicker 0.838x→0.99x、smith +Close Combat 段。 +// 3. PerStat statList 支持(ModParser.lua:1631 `per 75 armour and evasion on +// equipped shield` → `|` 复合 Multiplier var 求和):smith/titan 盾防御缩放 +// tree notable(Tree:27687,oracle 钉值 88 INC)生效。 +// 4. hybrid mana→life cost + per-LifeCost 词条(Atalui's Bloodletting: +// `base_skill_cost_life_instead_of_mana_%` 100 + PerStat{stat=LifeCost,div=20, +// limit=40,limitTotal},vendor :2067/:2090-2104):smith +30% DamageGainAsPhysical +// (oracle LifeCost 309 → floor(309/20)=15 → 30)。 +// 5. 暴击短路路径分腿减伤 blend(vendor :4395;敌方护甲 DR 依赖单次击中量, +// crit 腿用暴击后击中算 DR):spirit-walker 0.94x→0.98x、blood-mage/abyssal-lich +// 连带收敛(0.87x→0.88x / 0.91x→0.93x,未入列)。 +// 逐 build:smith 0.575x→0.996x、titan 0.874x→0.978x、flicker 0.838x→1.003x、 +// spirit-walker 0.892x→0.980x、monk-twister 0.958x→0.980x、pathfinder 0.904x→ +// 0.963x、ritualist 0.989x→1.000x。剩余脱靶:deadeye 0.832x(pre-0.5.4b per-hit +// 欠条)、blood-mage 0.880x / abyssal-lich 0.926x(Mageblood 词条族缺口,Phase 1 +// 独立项——oracle 钉值 blood-mage 缺 `INC CritChance 107 'Mageblood'`)、 +// frost-bomb 0.661x(golden 两版未动,存量冷却 DPS 缺口)。 +// (存量 #7-1)frost-bomb TotalDPS 0.66x→1.00x 翻正(off @5/@10 各 +1): +// Archmage buff `DamageGainAsLightning`(BASE 4/100 Mana → 80% gain-as, +// act_int.lua:229-231)+ curse 链两缺口(EW 取数等级未吃 +8 spell skill +// levels:-58→-66;技能局部 CurseEffect 段缺失:Heightened Curse +25 + +// EW 品质 +10 → 敌抗 9→-7,oracle enemyMitigation 逐源钉值)。 +// **0.5.4b #8 Zarokh's Gift anoint socket 重记(off +3 @5% 73→76 / +1 @10% 75→76)**: +// #6 留下的「blood-mage 缺 `INC CritChance 107 'Mageblood'`」钉值实为下游症状: +// Mageblood 效果表与 `MagesLegacyEffect` 解析均已在位(逐 mod 对拍与 oracle 一致), +// 真根因 = 两 build 的 amulet anoint `{enchant}Allocates Zarokh's Gift` 未把具名 +// jewel socket 节点 11184 视为已分配(vendor PassiveSpec.lua:1106-1114 sockets 名 +// 匹配 fallback),socket 内珠宝(blood-mage: Pandemonium Ornament——CritChance +// INC 24 + CritMult INC 25/28;abyssal: 同位 ES/防御珠宝)整体被丢弃。修复见 +// xml_build.rs NAMED_SOCKETS_0_5。blood-mage TotalDPS 0.880x→1.00x(CritChance +// 88.5→92.1、CritMult 5.34→5.87 逐值精确)、abyssal-lich TotalDPS 0.926x→1.00x +// (CritChance/CritMult 1.00x;ES 12124→12437 vs golden 12434、MaxHit 五族 + +// TotalEHP 0.97-0.98x→1.00x——def 列先前已在 5% 带内,def 计数不变)。 +// 18 build 逐格 diff 仅此两 build 变动。 +// **#15 最后三格清零(off 78→80、dot 36→37,进攻/dot 满分)**: +// ① gemling CritChance 1.20x→1.00x:范围珠宝授予不再落到非激活武器组节点—— +// vendor 对 allocMode≠0 节点的**每条** mod(含珠宝授予)都加 `Condition:WeaponSet` +// (CalcSetup.lua:222-223,节点自身门控优先于珠宝来源分支 :224-227),非激活组 +// 授予净效果为零;oracle critModList 实证仅 1 条 `7 @ Tree:32763`(旧 75a348e 的 +// 「按 jewel allocMode 门控」判读有误,已整体回退)。同珠宝的 Small 授予 +// (Crossbow 伤害)同步收敛 → AvgDamage/TotalDPS 1.04x→0.97x(带内换向)。 +// ② gemling TotalDotDPS 1.10x→0.95x(转入带内):点燃链吃 crit/珠宝高估传导,修复后 +// 残差 -4.9%(952 vs 1001)分解 = 点燃几率 0.0962 vs 0.098636(0.9754)× 堆叠潜力 +// 0.2603 vs 0.26691(0.9752)——两者均 ∝ 击中火伤,0.9754² ≈ 0.951 与 dot 残差 +// 逐位吻合,即完全是 AvgDamage 0.97x 既有低估的下游(此前被 6× 珠宝授予掩盖)。 +// ③ wolf-pack Speed 1.43x→1.00x:主技能选择兜底——mainSocketGroup 指向的组无 +// 攻击/法术候选(Wolf Pack = Minion+Companion)时不再回退扫描其它组(曾错选 +// Blasphemy 组 Temporal Chains,0.7s 施放 → 1.43),改用组内 mainActiveSkill +// 选中项(vendor socketGroupSkillList 无伤害过滤);并修 speed bucket:非攻非 +// 法术技能不吃 Attack/CastSpeed INC(vendor ModFlag 匹配语义),Wolf Pack 不再 +// 错吃武器 `12% reduced Attack Speed`(0.88→1.00)。18 build 逐格零倒退(全命中)。 +const BASELINE_OFF_HIT5: usize = 80; // #15 满分 80/80(#10 后 78;#8 后 76;#6+#7 合并 73;迁移基线 39) +const BASELINE_OFF_HIT10: usize = 80; // #15 满分 80/80(#10 后 78;#8 后 76;迁移基线 47;0.5.0=74) /// DoT 三列(TotalDotDPS/WithDotDPS/CombinedDPS)独立基线(M4-G 扩列时实测; /// 新列单独常量,不动既有 BASELINE_OFF_*)。命中 3 = wolf-pack 双 0 命中 @@ -727,8 +887,59 @@ const BASELINE_OFF_HIT10: usize = 55; // mana-mult 后 55/80(Silver-speed 54 // 18 build 逐格 diff 仅 blood-mage 三格变动。冻结榜只剩 legacy `split`。 // **bloodmage mana-mult 重记(dot +2 @5% 9→11 / @10% 11→13)**:见 BASELINE_OFF_HIT5 上 // 说明——mana 缩放抬 blood-mage 的 spell DoT 基底,其 TotalDotDPS/CombinedDPS 翻正。 -const BASELINE_DOT_HIT5: usize = 11; // mana-mult 后 11/37(迁移基线 9;0.5.0=26) -const BASELINE_DOT_HIT10: usize = 13; // mana-mult 后 13/37(迁移基线 11;0.5.0=28) +// **0.5.4b #4 Communion/LowLife + Voices 重记(dot +2 @5% 11→13 / +5 @10% 13→18)**: +// ritualist TotalDotDPS 0.60x→1.00x / CombinedDPS 0.63x→0.99x(LowLife 增伤 + +// sinister 珠宝的 damaging-ailment-magnitude 词条同时抬 bleed/poison 基底); +// abyssal-lich dot 列随 hit 侧收敛入 @10% 带。 +// **0.5.4b #4 grenade 短语解禁重记(dot +1 @5% 13→14 / +1 @10% 18→19)**: +// gemling CombinedDPS 0.65x→1.04x 翻正(见 BASELINE_OFF_HIT5 上说明)。 +// **0.5.4b #5 Blazing Critical 重记(dot +2 @5% 14→16 / +2 @10% 19→21)**: +// 点燃火源随全局 15% DamageGainAsFire 平方级放大(chance ∝ fire/threshold × +// magnitude ∝ fire):monk-twister TotalDotDPS 0.44x→0.98x + CombinedDPS +// 0.60x→0.96x 翻正;flicker dot 0.05x→0.72x、spirit-walker 0.23x→0.87x 收敛 +// 未入列(残余同为 hit 侧存量缺口的平方传导,非 dot 侧机制)。其余 dot 脱靶 +// 逐格判定:deadeye 0.69x=hit 0.83x²、blood-mage 0.79x≈hit 0.87x²、titan/ +// abyssal/pathfinder 0.91-0.94x 随 hit 收敛;smith 0.20x 中 dot 特有残差 = +// Infernal Cry uptime-scaled DamageGainAsFire 12% 未建模(新旧 vendor 同值, +// 存量缺口非 0.5.4b 项);frost-bomb 0.87x / essence-drain WithDotDPS 1.36x +// golden 两版未动(存量);gemling dot 1.10x 高估 = fire/crit 小幅 hit 侧 +// 高估的下游传导(oracle 逐分量:fire 1.03x × stacks 1.05x × crit 混叠)。 +// **0.5.4b #6 AvgDamage 族 dot 列跟涨重记(dot +9 @5% 16→25 / +6 @10% 21→27)**: +// 点燃 ∝ 火源²,hit 侧整族闭合后 dot 列自动跟正(flicker 0.72x→0.87✓ 附近、 +// spirit-walker 0.87x→0.98x✓、titan/pathfinder/monk-twister CombinedDPS 随 hit +// 翻正)。剩余脱靶:smith TotalDotDPS 0.40x(= 火源比 0.63² —— Infernal Cry +// uptime-scaled DamageGainAsFire 12.04% 未建模,新旧 vendor 同值的存量 warcry +// uptime 机制,见 BASELINE_OFF_HIT5 注);deadeye 0.69x = hit 0.83x²; +// blood-mage 0.79x(Mageblood);gemling 1.10x 高估(存量)。 +// (存量 #7-1)frost-bomb 修复的 dot 列迁移:CombinedDPS 0.66x→1.00x 入列 +// (@5/@10 各 +1)、TotalDotDPS 0.87x→1.07x 入 @10%;druid-oracle-comet +// TotalDotDPS 1.04x→1.06x 出 @5%(EW 变强的下游——vendor 侧 druid 的 EW +// 根本未入 enemy resistMods(curse 槽位/优先级差异,oracle 钉值),PoBR +// 施加了它,存量高估被放大 2%,另行追)。@5 净 0、@10 净 +2。 +// **0.5.4b #8 Zarokh's Gift anoint socket 重记(dot +4 @5% 27→31 / +2 @10% 31→33)**: +// blood-mage TotalDotDPS 0.79x→1.00x + CombinedDPS 0.88x→1.00x、abyssal-lich +// TotalDotDPS 0.94x→1.00x + CombinedDPS 0.93x→1.00x——hit 侧 crit 闭合后 +// 点燃/DoT 基底跟正(见 BASELINE_OFF_HIT5 上 #8 说明)。 + +// **存量 #9 warcry uptime 机器重记(dot +1 @10% 31→32)**:Infernal Cry 的 +// uptime 缩放 `DamageGainAsFire`(CalcOffence.lua:3229-3256,pobr-core +// `calc::warcry`)落地,smith TotalDotDPS 0.40x→1.06x 入 @10% 带(uptime/ +// castTime/cooldown 对 oracle 逐位:19.4116%/0.544218/6.27;gain 62×uptime +// =12.035 与 vendor "Uptime Scaled Infernal Cry" 条 bit-exact)。残余 +6% = +// smith 命中侧原有 +2% 高估(此前被缺失的 gain 抵消遮蔽,AverageDamage +// 0.996→1.02)经点燃 ∝ 火源² 放大——命中侧存量项,非 warcry 机制。titan 随动: +// TotalDotDPS 0.98→1.01、TotalDPS 0.98→1.05(同为被遮蔽的原有高估暴露, +// 仍在 @5% 带内)。其余 16 build 无 warcry,逐值不变。 +// **存量 #11 Blasphemy support 半身接入(dot +2 @5% 31→33)**:support 裁决 +// 扩到宝石附加授予效果(gem_effects 外键),Blasphemy 的 SupportBlasphemyPlayer +// (`support_blasphemy_curse_effect_+%_final` → `CurseEffect MORE -41`@L19)进入 +// curse 局部乘区——Temporal Chains 施加值 -13→-8(vendor 逐位:mult 0.55→0.3245, +// (1+10%)×0.59×0.5boss),点燃 debuffDurationMult 1/0.87→1/0.92 跟正:druid +// TotalDotDPS 1.06x→1.00x(182.40 vs 182.60)、monk frost-bomb 1.07x→0.99x +// (4.53 vs 4.58);witch-lich 带内微降(21659→21621,仍 1.00x)。curse 槽位 +// 归属逐 build 不变(druid 单槽仍 Temporal Chains 胜出,EW 依旧不入槽)。 +const BASELINE_DOT_HIT5: usize = 37; // #15 满分 37/37(gemling TotalDotDPS 随 crit 修复入带;#10+#11 合并 36;迁移基线 9;0.5.0=26) +const BASELINE_DOT_HIT10: usize = 37; // #15 满分 37/37(#10+#11 合并 36;迁移基线 11;0.5.0=28) /// 面板口径(`mode_effective=false`)守卫基线:防止口径回归无感知(effective 与 /// panel 在防御侧逐值相同,故只守进攻)。M3-W5 切换 commit 实测。 @@ -746,8 +957,8 @@ const BASELINE_DOT_HIT10: usize = 13; // mana-mult 后 13/37(迁移基线 11 /// (template.rs / special_mod.rs)同 commit 全量化——一批 `ModTag::SkillTypes` /// 域词条(Area/Projectile/Grenade 等)在 panel 口径开始正确匹配。effective /// 主口径与防御/进攻/dot 主基线逐值持平(纯 panel 侧收敛)。 -const PANEL_OFF_HIT5: usize = 27; // 4.5.4.3 迁移基线 27/80(0.5.0=44) -const PANEL_OFF_HIT10: usize = 30; // 4.5.4.3 迁移基线 30/80(0.5.0=46) +const PANEL_OFF_HIT5: usize = 45; // #15 实测 45(gemling CritChance + wolf-pack Speed/DPS 面板同收);#6+#7 叠加 42;迁移基线 27;0.5.0=44 +const PANEL_OFF_HIT10: usize = 47; // #15 实测 47(同上);#6+#7 叠加 43;迁移基线 30;0.5.0=46 /// 回归门禁:聚合命中数不得低于已记录基线([`BASELINE_*`])。CI gate,防止改动倒退 parity。 #[test] diff --git a/crates/pobr-build/tests/parity/pob2_parity.rs b/crates/pobr-build/tests/parity/pob2_parity.rs index 708f59a9..ad2657f9 100644 --- a/crates/pobr-build/tests/parity/pob2_parity.rs +++ b/crates/pobr-build/tests/parity/pob2_parity.rs @@ -160,15 +160,34 @@ fn deadeye_parity_report() { // 两层「过算抵消欠算」**叠乘**拆除(0.613x × 0.647/0.817 ≈ 0.485x,实测吻合), // 容差按合并后真实偏差放宽,只防进一步倒退;待 grenade 冷却吞吐 / Mirage 数据 // 补齐后收紧。 - assert_within(&pob2, "AverageDamage", out.total_hit_avg, 0.55); - assert_within(&pob2, "TotalDPS", out.dps, 0.55); + // + // 0.5.4b #4(grenade 短语解禁)后收口:AvgDamage 实测 1.04x——上述「过算抵消 + // 欠算」链中 base 侧缺口已被历次修复闭合,容差 0.55→0.20 收紧。TotalDPS **不再 + // 对本旧样本断言**(与上方 res/evasion 同理):内嵌 PlayerStat 导出早于 0.5.4b + // 的 grenade CDR 再平衡(vendor 0.22.0 ModParser gem 循环加 `fromItem` 排除, + // `for grenade skills` 短语复活 → 3×15 CDR 树词条生效,Speed 0.164→0.254), + // 旧样本 Speed 口径已失效;权威 DPS 门禁走 ninja_parity 的 0.5.4b fixture + // golden(Speed 0.254 精确、TotalDPS 0.83x 且棘轮守护)。 + assert_within(&pob2, "AverageDamage", out.total_hit_avg, 0.20); // Evasion 见上方注释:内嵌样本缺 Mageblood(14301),不硬断言;权威值走 fixture golden。 } #[test] fn martial_parity_report() { let data = load_data(); - let (out, _pob2) = report("MARTIAL", MARTIAL, &data); + let (out, pob2) = report("MARTIAL", MARTIAL, &data); assert!(out.life.is_finite() && out.mana.is_finite()); assert!(out.dps.is_finite()); + // EnergyShield「1.12x 高估」诊断(存量 #11-2):**旧样本 golden 失真,非 PoBR + // 多算**。本 code `targetVersion="0_1"`(PoE2 0.1 时代导出),内嵌 PlayerStat + // EnergyShield=6257;同一 XML 喂当前 vendor(tools/pob2-oracle)得 7008, + // PoBR 7005.5 = 0.9996x 现行 vendor。0.1→0.5.x 间未变的口径(Life/Mana/ + // Evasion/三抗/Crit)内嵌值与现行 oracle 逐位一致,唯 ES(与进攻侧)随数据 + // 版本漂移——与上方 deadeye 的 Mageblood/res 旧样本失效同类。断言按**现行 + // vendor 语义**守护(容差 0.15 覆盖 stale-golden 缺口 1.12x,只防大幅倒退; + // 权威 ES 门禁走 ninja_parity 的 0.5.4b fixture golden)。 + assert_within(&pob2, "EnergyShield", out.energy_shield, 0.15); + assert_within(&pob2, "Evasion", out.evasion, 0.05); + assert_within(&pob2, "Mana", out.mana, 0.05); + assert_within(&pob2, "CritChance", out.crit_chance * 100.0, 0.05); } diff --git a/crates/pobr-build/tests/skills/dual_wield.rs b/crates/pobr-build/tests/skills/dual_wield.rs index 5827b01c..7b44fd59 100644 --- a/crates/pobr-build/tests/skills/dual_wield.rs +++ b/crates/pobr-build/tests/skills/dual_wield.rs @@ -31,6 +31,7 @@ fn weapon(base_name: &str, mods: &[&str]) -> Item { base: ItemBaseId::from(base_name), rarity: ItemRarity::Normal, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: mods.iter().map(|s| s.to_string()).collect(), enchant_texts: vec![], diff --git a/crates/pobr-build/tests/skills/gem_quality.rs b/crates/pobr-build/tests/skills/gem_quality.rs index 664e1c6b..4a69c5df 100644 --- a/crates/pobr-build/tests/skills/gem_quality.rs +++ b/crates/pobr-build/tests/skills/gem_quality.rs @@ -63,10 +63,12 @@ fn quality_segment_truncates_toward_zero() { QualityStat { stat: "synth_pos".into(), per_quality_rate: 0.55, + alt: false, }, QualityStat { stat: "synth_neg".into(), per_quality_rate: -0.55, + alt: false, }, ], ); diff --git a/crates/pobr-build/tests/skills/minions.rs b/crates/pobr-build/tests/skills/minions.rs index 73438571..ee48ddf2 100644 --- a/crates/pobr-build/tests/skills/minions.rs +++ b/crates/pobr-build/tests/skills/minions.rs @@ -56,8 +56,12 @@ fn zombie_build(gem_level: u32) -> Build { fn build_data_minion_def_zombie() { let data = load_data(); let zombie = data.minion_def("RaisedZombie").expect("RaisedZombie 在库"); - assert_eq!(zombie.life, 0.7); // Minions.lua:12 - assert_eq!(zombie.damage, 0.75); // :18 + // 数值系数来自 Minions.lua,随平衡补丁漂移 → blessed 快照(POBR_BLESS_PINS=1 刷新)。 + pobr_gamedata::test_pins::assert_pin( + &repo_data_root().join(version()), + "minions.raised_zombie", + serde_json::json!({ "life": zombie.life, "damage": zombie.damage }), + ); assert!(zombie.base_damage_ignores_attack_speed); } @@ -68,8 +72,12 @@ fn build_data_minion_def_spectre_falls_back() { let c = data .minion_def("Metadata/Monsters/LeagueAbyss/Lightless/Cocoon3Spectre") .expect("Lightless Abomination 在库(落 spectres)"); - assert_eq!(c.life, 2.2); // Spectres.lua(4.5.4.3/0.5.4b:3.0→2.2) - assert_eq!(c.armour, 0.4); + // 数值系数来自 Spectres.lua,随平衡补丁漂移(0.5.4b:life 3.0→2.2)→ blessed 快照。 + pobr_gamedata::test_pins::assert_pin( + &repo_data_root().join(version()), + "minions.spectre_cocoon3", + serde_json::json!({ "life": c.life, "armour": c.armour }), + ); } #[test] @@ -173,6 +181,7 @@ fn minion_increased_damage_raises_minion_dps() { base: ItemBaseId::from("Ring"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec!["Minions deal 50% increased Damage".into()], enchant_texts: vec![], diff --git a/crates/pobr-build/tests/skills/skill_damage_dps.rs b/crates/pobr-build/tests/skills/skill_damage_dps.rs index 02539081..56a8be5a 100644 --- a/crates/pobr-build/tests/skills/skill_damage_dps.rs +++ b/crates/pobr-build/tests/skills/skill_damage_dps.rs @@ -151,6 +151,7 @@ fn bare_weapon(base_name: &str) -> Item { base: ItemBaseId::from(base_name), rarity: ItemRarity::Normal, quality: 0, + corrupted: false, implicit_texts: vec![], modifier_texts: vec![], enchant_texts: vec![], diff --git a/crates/pobr-build/tests/skills/spirit_reservation.rs b/crates/pobr-build/tests/skills/spirit_reservation.rs index f4ee6165..08f3fb67 100644 --- a/crates/pobr-build/tests/skills/spirit_reservation.rs +++ b/crates/pobr-build/tests/skills/spirit_reservation.rs @@ -175,21 +175,22 @@ fn dedupes_across_groups_and_skips_disabled() { assert_eq!(calc(&build, &data), 0.0, "禁用组不预留"); } -/// Blasphemy per-curse 预留(vendor CalcDefence.lua:273-284):`IsBlasphemy` 效果按 +/// Blasphemy per-curse 预留(vendor CalcDefence.lua:229-239):`IsBlasphemy` 效果按 /// 同组 AppliesCurse 主动技能数各加 `blasphemy_base_spirit_reservation_per_socketed_curse` -/// (constant stat 60),口径 = 单份缩放 round 后 ×count。品质效率(:251, -/// q20 Blasphemy = 20×0.5 = 10%)除在每份上:round(60/1.1) = 55。 +/// (constant stat 60)**先并入 baseFlat**,再统一缩放 round 一次(:236-238)。 +/// 品质效率(q20 Blasphemy = 20×0.5 = 10%)除在总量上:round(120/1.1) = 109 +/// (≠ 旧的单份 round(60/1.1)=55×2=110;essence-drain oracle 钉值同口径 164)。 #[test] fn blasphemy_reserves_per_socketed_curse_with_quality_efficiency() { let data = repo_data(); - // q20 Blasphemy + 2 条 curse → 55 × 2 = 110(curse 自身预留 0)。 + // q20 Blasphemy + 2 条 curse → round(120/1.1) = 109(curse 自身预留 0)。 let build = build_with_group( SocketGroup::new() .with_gem_skill_quality("BlasphemyPlayer", 19, 20) .with_gem_skill("TemporalChainsPlayer", 19) .with_gem_skill("EnfeeblePlayer", 19), ); - assert_eq!(calc(&build, &data), 110.0); + assert_eq!(calc(&build, &data), 109.0); // q0 Blasphemy + 1 条 curse → 60(无效率缩放)。 let build = build_with_group( diff --git a/crates/pobr-core/src/calc/actor.rs b/crates/pobr-core/src/calc/actor.rs index 39a71416..88cb4054 100644 --- a/crates/pobr-core/src/calc/actor.rs +++ b/crates/pobr-core/src/calc/actor.rs @@ -44,6 +44,10 @@ pub struct Actor { pub base: ActorBaseStats, pub output: OutputTable, pub breakdown: BreakdownTable, + /// 可受伤伴侣召唤物(授予技能 `SkillType.Companion` 且非 + /// `MinionsAreUndamagable`,spawn 侧判定)。`TotalCompanionLife` 求和 + /// (vendor CalcPerform.lua:3364-3370)只计此类召唤物;玩家 Actor 恒 false。 + pub is_companion: bool, } impl Actor { @@ -54,6 +58,7 @@ impl Actor { base, output: OutputTable::default(), breakdown: BreakdownTable::default(), + is_companion: false, } } } diff --git a/crates/pobr-core/src/calc/buff_pass.rs b/crates/pobr-core/src/calc/buff_pass.rs index 03715bd4..526dee28 100644 --- a/crates/pobr-core/src/calc/buff_pass.rs +++ b/crates/pobr-core/src/calc/buff_pass.rs @@ -384,17 +384,35 @@ pub fn buff_pass(env: &mut Env) { // (:2296-2298)不实现(简化 (g):无 aura 源建模)。 let curse_effect = [ModName::from("CurseEffect")]; let curse_effect_on_self = [ModName::from("CurseEffectOnSelf")]; + // spec.local_effect_inc/more = vendor skillModList 的技能局部 + // CurseEffect 段(宝石品质 / 组内 support,编排层预折)。 let inc = env.player.mod_db.sum(ModType::Inc, &env.cfg, &curse_effect) + + spec.local_effect_inc + env .enemy .mod_db .sum(ModType::Inc, &env.cfg, &curse_effect_on_self); - let mut more = env.player.mod_db.more(&env.cfg, &curse_effect) * spec.magnitude; + let mut more = env.player.mod_db.more(&env.cfg, &curse_effect) + * spec.local_effect_more + * spec.magnitude; if !spec.is_mark { // vendor :2303-2305:非 mark 再乘敌侧 CurseEffectOnSelf MORE。 more *= env.enemy.mod_db.more(&env.cfg, &curse_effect_on_self); } let mult = (1.0 + inc / 100.0) * more; + if std::env::var("POBR_DBG_CURSE").is_ok() { + eprintln!( + "[POBR_CURSE] entry name={} inc={inc:.2} (local_inc={:.2}) more={more:.4} (local_more={:.4} magnitude={:.4}) mult={mult:.4} mods={:?}", + spec.name, + spec.local_effect_inc, + spec.local_effect_more, + spec.magnitude, + spec.mods + .iter() + .map(|m| (&m.name, &m.value)) + .collect::>(), + ); + } let source_id = format!("curse.{}", spec.skill_id); let mods = spec .mods @@ -659,6 +677,8 @@ mod tests { socket_index, is_mark, ignore_curse_limit, + local_effect_inc: 0.0, + local_effect_more: 1.0, skill_types: pobr_data::skill::SkillTypes::NONE, } } @@ -674,6 +694,8 @@ mod tests { socket_index: 1, is_mark: false, ignore_curse_limit: false, + local_effect_inc: 0.0, + local_effect_more: 1.0, skill_types: pobr_data::skill::SkillTypes::NONE, } } @@ -1075,6 +1097,8 @@ mod tests { socket_index: 1, is_mark: false, ignore_curse_limit: false, + local_effect_inc: 0.0, + local_effect_more: 1.0, skill_types: pobr_data::skill::SkillTypes::NONE, }); @@ -1107,6 +1131,8 @@ mod tests { socket_index: 1, is_mark: false, ignore_curse_limit: false, + local_effect_inc: 0.0, + local_effect_more: 1.0, skill_types: pobr_data::skill::SkillTypes::NONE, }); diff --git a/crates/pobr-core/src/calc/crit.rs b/crates/pobr-core/src/calc/crit.rs index ef2713da..f24964d6 100644 --- a/crates/pobr-core/src/calc/crit.rs +++ b/crates/pobr-core/src/calc/crit.rs @@ -207,6 +207,7 @@ fn resolve_crit_impl( cfg, mode_effective, pre_bifurcate_pct, + crit_pct, bifurcate, inevitable, inevitable_less_more, @@ -254,6 +255,7 @@ fn resolve_crit_multiplier( cfg: &CalcConfig, mode_effective: bool, pre_bifurcate_pct: f64, + effective_crit_pct: f64, bifurcate: bool, inevitable: bool, inevitable_less_more: Option, @@ -289,11 +291,18 @@ fn resolve_crit_multiplier( * more }; - // 分岔:"两次都暴击"的概率额外加权一份爆伤(CalcOffence.lua L3796–3811), + // 分岔:条件概率「已知至少一次暴击时两次都暴击」额外加权一份爆伤 + // (CalcOffence.lua:3823-3846 `conditionalBifurcateChance = + // (PreBifurcateCritChance²/100) / CritChance`,vendor 0.21/0.22 同式), // 与必然互斥(必然路径已把 100% 暴击折进 less)。 if mode_effective && bifurcate && !inevitable { let bifurcate_multi_chance = pre_bifurcate_pct.powi(2) / 100.0; - extra += bifurcate_multi_chance * extra / 100.0; + let conditional = if effective_crit_pct > 0.0 { + bifurcate_multi_chance / effective_crit_pct + } else { + 0.0 + }; + extra += conditional * extra; } // 敌方 SelfCritMultiplier(标记等):BASE 加成 × (1 + INC/100)(CalcOffence.lua L3814–3825)。 diff --git a/crates/pobr-core/src/calc/crit_pass.rs b/crates/pobr-core/src/calc/crit_pass.rs index 0740a20e..c9dcd586 100644 --- a/crates/pobr-core/src/calc/crit_pass.rs +++ b/crates/pobr-core/src/calc/crit_pass.rs @@ -157,14 +157,26 @@ where // total = round(Σavg × crit.effect),I5 恒等保证与真 blend 数学相同。 let player_side: f64 = leg_total(&non_crit); let mitigated: f64 = if mode_effective { - leg_total_mitigated(&non_crit, &cfg_hit, &mitigation) + // 减伤侧**不能**走「单腿减伤 × crit.effect」:敌方护甲减伤依赖 + // 单次击中量(vendor pass1 用暴击后的击中量算 DR,暴击更大 → DR + // 更小),raw 依赖使 I5 恒等在减伤维度不成立。短路下暴击腿 = + // 非暴击腿 × crit.multiplier,据此按 vendor `:4395` 分腿减伤后 + // blend;减伤对 raw 无依赖(纯抗性/受伤链)时数学上退化为 + // 旧公式,逐值不变。 + let hit_leg = leg_total_mitigated(&non_crit, &cfg_hit, &mitigation); + let crit_leg_mitigated: f64 = non_crit + .avgs + .iter() + .zip(non_crit.raw_avgs.iter()) + .map(|((ty, avg), raw)| { + avg * crit.multiplier * mitigation(&cfg_crit, *ty, raw * crit.multiplier) + }) + .sum(); + hit_leg * (1.0 - c) + crit_leg_mitigated * c } else { - player_side + player_side * crit.effect }; - ( - round(player_side * crit.effect), - round(mitigated * crit.effect), - ) + (round(player_side * crit.effect), round(mitigated)) } else { // 真双腿 blend(`:4395`):分腿过敌方减伤后按 c 加权。 let blend = |hit: f64, crit_v: f64| hit * (1.0 - c) + crit_v * c; diff --git a/crates/pobr-core/src/calc/damage.rs b/crates/pobr-core/src/calc/damage.rs index 8baae0f5..7cbc0867 100644 --- a/crates/pobr-core/src/calc/damage.rs +++ b/crates/pobr-core/src/calc/damage.rs @@ -405,6 +405,12 @@ pub(crate) fn aggregate_inc_more( c.name, c.value, c.raw_text ); } + for c in db.contributions(ModType::More, cfg, &generic_names) { + eprintln!( + "[POBR_POOL_MORE] {:?} {} src={:?}", + c.name, c.value, c.raw_text + ); + } } // PoB2-PoE2:类型化 inc/more 只按分量**最终伤害类型**聚合,**不**叠加转换源类型 diff --git a/crates/pobr-core/src/calc/defence_panels.rs b/crates/pobr-core/src/calc/defence_panels.rs index 7b3554b4..8a6f310b 100644 --- a/crates/pobr-core/src/calc/defence_panels.rs +++ b/crates/pobr-core/src/calc/defence_panels.rs @@ -8,7 +8,8 @@ //! vendor 参照:`vendor/PathOfBuilding-PoE2/src/Modules/CalcDefence.lua` //! - Block::961-1058(BlockChanceMax 体系 + 三分型 + lucky/unlucky 幂) //! - Ward::1144-1273(per-slot 聚合 + EnergyShieldToWard) -//! - Deflection::48-54(`deflectChance` 公式)+ :1487-1506(rating 合成) +//! - Deflection::48-54(`deflectChance` 公式)+ :1516-1522(rating 合成, +//! 0.22.0 vendor 行号;0.5.4b 复核公式未变) //! - Spirit::73-126(Life/Mana/Spirit 统一池公式) use crate::{CalcConfig, ModDb}; @@ -45,6 +46,10 @@ pub struct BlockResult { pub effective_block_chance: f64, /// 有效法术格挡(%)。 pub effective_spell_block_chance: f64, + /// 有效投射物攻击格挡(%)。EHP 平均格挡 = 四分型均值(vendor :1067)。 + pub effective_projectile_block_chance: f64, + /// 有效法术投射物格挡(%)。 + pub effective_spell_projectile_block_chance: f64, /// 格挡承伤比例(%;被格挡命中仍承受的伤害份额 = Σ BASE BlockEffect, /// vendor `DamageTakenOnBlock`;0 = 完全格挡)。 pub block_effect_taken_pct: f64, @@ -185,6 +190,11 @@ pub fn calc_block(db: &ModDb, cfg: &CalcConfig) -> BlockResult { spell_projectile_block_chance: round(spell_projectile), effective_block_chance: effective(block, "BlockChance"), effective_spell_block_chance: effective(spell, "SpellBlockChance"), + effective_projectile_block_chance: effective(projectile, "ProjectileBlockChance"), + effective_spell_projectile_block_chance: effective( + spell_projectile, + "SpellProjectileBlockChance", + ), // :1054-1058 承伤份额(clamp 到 [0,100],超额防住不为负)。 block_effect_taken_pct: db .sum(ModType::Base, cfg, &[ModName::from("BlockEffect")]) @@ -228,7 +238,7 @@ pub fn calc_ward(db: &ModDb, cfg: &CalcConfig, es_to_ward: bool) -> f64 { } // ───────────────────────────────────────────────────────────────── -// Deflection(CalcDefence.lua:48-54 / :1487-1506) +// Deflection(CalcDefence.lua:48-54 / :1516-1522) // ───────────────────────────────────────────────────────────────── /// Deflection 面板结果。 @@ -255,14 +265,14 @@ fn deflect_chance_pct(deflection: f64, accuracy: f64, cap: f64) -> f64 { (100.0 - chance_to_not_deflect.round()).clamp(0.0, cap) } -/// Deflection 合成(CalcDefence.lua:1490-1497)。 +/// Deflection 合成(CalcDefence.lua:1516-1522)。 /// /// `DeflectionRating = ΣBASE DeflectionRating + (Evasion × ΣBASE /// EvasionGainAsDeflection/100 + Armour × ΣBASE ArmourGainAsDeflection/100) /// × calcLib.mod(DeflectionRating)`——vendor 括号语义:inc/more 乘区**只作用于 /// GainAs 派生部分**(:1490 原文)。`DeflectChance = deflectChance(rating, -/// enemyAccuracy)`;`DeflectIsLucky` → `(1−(1−p)²)`(:1492-1495); -/// `DeflectEffect = clamp(基础 40 + ΣBASE, 0, 100)`(:1496,常量 +/// enemyAccuracy)`;`DeflectIsLucky` → `(1−(1−p)²)`(:1518-1521); +/// `DeflectEffect = clamp(基础 40 + ΣBASE, 0, 100)`(:1522,常量 /// `cfg.constants.game().deflect_effect`)。 pub fn calc_deflection( db: &ModDb, @@ -294,7 +304,7 @@ pub fn calc_deflection( enemy_accuracy, cfg.constants.game().deflection_chance_cap, ); - // :1492-1495 DeflectIsLucky 幂。 + // :1518-1521 DeflectIsLucky 幂。 if db.flag(cfg, ModName::from("DeflectIsLucky")) { chance = luck_transform(chance, true, false); } @@ -369,6 +379,9 @@ pub fn fill_defence_panels(env: &mut Env, keystones: &crate::rules::DefenceKeyst env.player.output.spell_block_chance_max = block.spell_block_chance_max; env.player.output.effective_block_chance = block.effective_block_chance; env.player.output.effective_spell_block_chance = block.effective_spell_block_chance; + env.player.output.effective_projectile_block_chance = block.effective_projectile_block_chance; + env.player.output.effective_spell_projectile_block_chance = + block.effective_spell_projectile_block_chance; env.player.output.block_effect = block.block_effect_taken_pct; // --- Spirit 池本值 + 未预留余量(CalcDefence.lua:73-126 / :330-337)--- @@ -383,7 +396,7 @@ pub fn fill_defence_panels(env: &mut Env, keystones: &crate::rules::DefenceKeyst // --- Ward 池(CalcDefence.lua:1144-1296;EnergyShieldToWard 走 C-1 快照)--- env.player.output.ward = calc_ward(db, cfg, keystones.energy_shield_to_ward); - // --- Deflection(CalcDefence.lua:48-54 / :1487-1506)--- + // --- Deflection(CalcDefence.lua:48-54 / :1516-1522)--- // 敌人命中读数同 Track E evade 路径(env.enemy.base.accuracy)。 let deflect = calc_deflection( db, diff --git a/crates/pobr-core/src/calc/ehp.rs b/crates/pobr-core/src/calc/ehp.rs index 763150cb..11a45020 100644 --- a/crates/pobr-core/src/calc/ehp.rs +++ b/crates/pobr-core/src/calc/ehp.rs @@ -577,9 +577,13 @@ pub fn taken_hit_per_type( let mut dr_pct = [0.0_f64; 5]; for i in 0..5 { let damage = taken[i]; - // :2379 armourReduct = min(drMax, armourReductionF(effArmour, damage))。 - let armour_dr = (armour_reduction(mit.effective_applied_armour[i], damage) * 100.0) - .min(mit.dr_max_pct[i]); + // :2402 armourReduct = min(drMax, armourReduction(effArmour, damage))—— + // 注意这是**取整**变体(Common.lua round=floor(x+0.5);armourReductionF 才是 + // 小数变体,仅 takenHitFromDamage/:437 用)。golden PhysicalDamageReduction + // 恒为整数即由此来。 + let armour_dr = + vendor_round(armour_reduction(mit.effective_applied_armour[i], damage) * 100.0) + .min(mit.dr_max_pct[i]); // :2382 totalReduct = min(drMax, armourReduct + flatDR)。 let total_dr = (armour_dr + mit.flat_dr_pct[i]).min(mit.dr_max_pct[i]); // :2383 reductMult = 1 − clamp(totalReduct − overwhelm, 0, drMax)/100。 @@ -1130,10 +1134,16 @@ pub fn fill_ehp_pob2( let n_hits = number_of_hits_to_die(&taken_hit, &pools, &ctx, ¶ms); // ---- mitigation 概率层(:3155-3247)---- - // 平均格挡:vendor :1052 为四分型均值;Projectile 分型未进 OutputTable - // (无投射物专项词条时与基础分型同值),以 (攻击+法术)/2 等价。 - let avg_block_frac = - (out.effective_block_chance + out.effective_spell_block_chance) / 2.0 / 100.0; + // 平均格挡 = 四分型均值(vendor :1067 EffectiveAverageBlockChance)。旧 + // 二分型均值把 SpellProjectileBlock = max(spellBlock, projBlock)(:1013) + // 漏掉——盾 build(spellBlock 0、projBlock = block)被低估:smith 13.65 + // vs vendor 20.475(TotalEHP 0.92x 根因)。 + let avg_block_frac = (out.effective_block_chance + + out.effective_projectile_block_chance + + out.effective_spell_block_chance + + out.effective_spell_projectile_block_chance) + / 4.0 + / 100.0; // vendor BlockEffect(防住份额%)= 100 − ΣBASE = 100 − out.block_effect(承伤份额)。 let block_effect_mult = 1.0 - avg_block_frac * (100.0 - out.block_effect) / 100.0; // :3195 deflect 乘数(chance<100 口径;=100 时已折入 afterReductionMulti)。 @@ -1209,6 +1219,14 @@ pub fn fill_ehp_pob2( // ---- 新口径 max hit(:3540-3697)---- let pool_by_type = total_hit_pools(&mom, es_recovery_cap, &pools, &ctx); + // 诊断:POBR_DBG_EHPPOOL=1 时 dump 池分解(与 oracle TotalHitPool / + // MoMHitPool / Ward 对照)。 + if std::env::var("POBR_DBG_EHPPOOL").is_ok() { + eprintln!( + "[POBR_EHPPOOL] pools={pool_by_type:?} mom={mom:?} es_cap={es_recovery_cap:.2} ward={:.2} guard=({:.2},{:.2}) aegis_shared={:.2}", + pools.ward, pools.guard_shared, pools.guard_shared_rate, pools.aegis_shared, + ); + } let inputs = MaxHitInputs { mit: &mit, pools_full: &pools, diff --git a/crates/pobr-core/src/calc/env.rs b/crates/pobr-core/src/calc/env.rs index e6bdb68c..b35527f4 100644 --- a/crates/pobr-core/src/calc/env.rs +++ b/crates/pobr-core/src/calc/env.rs @@ -26,6 +26,13 @@ pub struct Env { /// 且 minion buff 未落地,本波收在 `Env` 顶层(语义即玩家侧);T3 消费时如需 /// per-actor 再迁。**本阶段零消费**:空与否输出逐值不变。 pub buff_skills: Vec, + /// 玩家的 warcry 技能规格(存量 #9;`session::add_warcry_skill` 写入, + /// `perform` 在 hand pass 之前经 [`super::warcry::apply_warcry_uptime`] 消费—— + /// uptime 缩放后的 warcry 进攻效果(Infernal `DamageGainAsFire`)注入玩家 db)。 + pub warcry_skills: Vec, + /// warcry uptime 增益已注入(幂等防重,vendor `InfernalActive` flag 同责, + /// CalcPerform.lua:1365)。 + pub warcry_gain_injected: bool, /// keystone 名 → modifier 列表(M3 T0-4;`session::set_keystone_mods` 写入, /// T5 `merge_keystones`(env_finalize 阶段 1/5)消费)。**本阶段零消费**。 pub keystone_mods: BTreeMap>, @@ -73,6 +80,8 @@ impl Env { cfg: CalcConfig::attack().with_damage_type(DamageType::Physical), minions: Vec::new(), buff_skills: Vec::new(), + warcry_skills: Vec::new(), + warcry_gain_injected: false, keystone_mods: BTreeMap::new(), buff_definitions: Vec::new(), buff_handler_registry: Arc::new(HandlerRegistry::new()), @@ -105,6 +114,11 @@ impl Env { /// /// `limit` 通常由玩家技能 `skillModList:Sum(limitName)` 派生(本阶段由调用方给定)。 /// `limit == 0` 时仍写入(multiplier=0,等价无召唤数量贡献,向后兼容)。 + /// + /// `is_companion`:授予技能是 `SkillType.Companion` 且非 + /// `MinionsAreUndamagable`(调用方按 skill_types 判定)——`TotalCompanionLife` + /// 求和(vendor CalcPerform.lua:3364-3370)只计此类召唤物。 + #[allow(clippy::too_many_arguments)] pub fn add_minion_from_def( &mut self, def: &super::MinionDef, @@ -113,6 +127,7 @@ impl Env { minion_modifiers: Vec, ally_buff_mods: Vec, infusion: super::AttributeInfusion, + is_companion: bool, ) -> &mut Self { let ctx = super::build_minion_context_from_def( def, @@ -122,7 +137,9 @@ impl Env { infusion, ); super::write_summoned_minion_multipliers(&mut self.player.mod_db, limit, &def.id); - self.minions.push(minion_actor_from_context(&ctx)); + let mut actor = minion_actor_from_context(&ctx); + actor.is_companion = is_companion; + self.minions.push(actor); self } diff --git a/crates/pobr-core/src/calc/env_finalize.rs b/crates/pobr-core/src/calc/env_finalize.rs index 2d31e169..2155f7c5 100644 --- a/crates/pobr-core/src/calc/env_finalize.rs +++ b/crates/pobr-core/src/calc/env_finalize.rs @@ -45,6 +45,13 @@ pub fn env_finalize(env: &mut Env) { expand_misc_buffs(env); // 阶段 7(T4):非伤害异常施加(Chill/Shock → enemy db)。 apply_nondamaging_ailments(env); + // 阶段 7.5:敌侧条件 flag → cfg 条件桥接(vendor ModStore GetCondition 语义: + // enemyDB 的 `Condition:` FLAG 使敌人条件 为真)。pobr 条件统一放 + // cfg.conditions(敌侧键空间 = `Enemy`),故在全部敌侧注入源(item + // EnemyModifier 转发 / buff_pass / 异常)落库后统一回填。 + // ponytail: 允收名单只有 Intimidated(消费方 = setup_enemy 注入的敌人基础 + // 条件对);其余 Condition:* flag 已各有专用桥(config/异常),需要时逐条扩。 + bridge_enemy_condition_flags(env); // 阶段 8(M4-L):曝光归约(vendor CalcPerform.lua:3214-3247 "Apply // exposures",buff 循环之后 / offence 之前)——enemy db 内全部 // `Exposure BASE`(config 注入 + buff_pass Debuff 路径,如 Frost Bomb) @@ -453,6 +460,25 @@ pub fn apply_nondamaging_ailments(env: &mut Env) { super::ailment_apply::apply_nondamaging_ailments(env); } +/// 阶段 7.5:敌侧 `Condition:` FLAG → `cfg.conditions["Enemy"]` 桥接。 +/// +/// vendor 语义(ModStore.lua `GetCondition`):条件真值 = conditions 表 **或** +/// modDB `Condition:` FLAG 聚合——敌人被词条施加的条件态(如体甲「Enemies in +/// your Presence are Intimidated」→ enemy db `Condition:Intimidated` flag)等价 +/// 于 config 勾选。pobr 的条件消费统一走 `cfg.conditions`,此处把 flag 聚合结果 +/// 回填(`matches(cfg)` 已含 Effective/EnemyInPresence 等 tag 门控)。 +fn bridge_enemy_condition_flags(env: &mut Env) { + // ponytail: 允收名单当前仅 Intimidated(唯一有敌方基础条件对消费方的条件); + // 全量 `Condition:*` 泛化会一次性点亮全部敌况词条,留给 parity 点名逐条扩。 + const BRIDGED: &[&str] = &["Intimidated"]; + for cond in BRIDGED { + let flag = ModName::from(format!("Condition:{cond}")); + if env.enemy.mod_db.flag(&env.cfg, flag) { + env.cfg.conditions.insert(format!("Enemy{cond}"), true); + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/pobr-core/src/calc/hand_pass.rs b/crates/pobr-core/src/calc/hand_pass.rs index 92d06dc2..aed48601 100644 --- a/crates/pobr-core/src/calc/hand_pass.rs +++ b/crates/pobr-core/src/calc/hand_pass.rs @@ -194,6 +194,19 @@ fn run_single_pass( hand: &HandSource, input: &MinimalInput, ) -> MinimalOutput { + let (hand_cfg, hand_input) = hand_scope(hand, cfg, input); + calculate_minimal_vs_enemy(db, enemy_db, &hand_cfg, &hand_input) +} + +/// per-hand 计算域派生(武器基底注入 `MinimalInput` 副本 + per-hand 条件翻转 + +/// 武器位段替换)。`run_single_pass` 与 warcry uptime 预算(`calc::warcry` 需按 +/// 主手域解析 Speed,vendor CalcOffence.lua:3235 读同一 pass 的 +/// `globalOutput.Speed`)共用,保证两处速率逐位一致。 +pub(crate) fn hand_scope( + hand: &HandSource, + cfg: &CalcConfig, + input: &MinimalInput, +) -> (CalcConfig, MinimalInput) { let mut hand_input = *input; hand_input.base_hit_min += hand.weapon.hit_min; hand_input.base_hit_max += hand.weapon.hit_max; @@ -209,7 +222,7 @@ fn run_single_pass( // per-hand 武器位(W-B2):非空时替换 cfg 的武器位段为该手武器位 // (空 = 恒等,legacy 位表 / 非武器攻击 source 零行为)。 hand_cfg.flags = hand_cfg.flags.replace_weapon_flags(hand.weapon.flags); - calculate_minimal_vs_enemy(db, enemy_db, &hand_cfg, &hand_input) + (hand_cfg, hand_input) } /// combineStat:按 [`COMBINE_TABLE`] 合并两腿(vendor `:2451-2545` + 调用面)。 diff --git a/crates/pobr-core/src/calc/minion.rs b/crates/pobr-core/src/calc/minion.rs index 7b77969b..237f35b4 100644 --- a/crates/pobr-core/src/calc/minion.rs +++ b/crates/pobr-core/src/calc/minion.rs @@ -266,7 +266,11 @@ pub fn derive_minion_base_stats(gem_level: u32, data: &MinionData) -> MinionBase let level = minion_level_from_gem_level(gem_level); let row = MonsterScalingRow::at_level(level); - let life = round(row.life as f64 * data.life); + // 生命走**盟友表**(vendor CalcPerform.lua:1046 `m_floor(monsterAllyLifeTable + // [level] × minionData.life)`——PoBR 召唤物全为玩家盟友;敌对召唤物 + // (hostile spectre,用 monsterLifeTable × mapLevelLifeMult)未建模)。 + // wolf-pack 钉值:ally[44]=2938 × 1.1 = 3231(oracle Life BASE 3231)。 + let life = (pobr_data::monster::monster_ally_life(level) as f64 * data.life).floor(); let armour = round(row.armour as f64 * data.armour); let evasion = round(row.evasion as f64 * data.evasion); // 生命转 ES:energy_shield 占比 × 100 = LifeConvertToEnergyShield BASE,这里直接折算 ES 基础。 diff --git a/crates/pobr-core/src/calc/mod.rs b/crates/pobr-core/src/calc/mod.rs index c8297050..509a3bb0 100644 --- a/crates/pobr-core/src/calc/mod.rs +++ b/crates/pobr-core/src/calc/mod.rs @@ -32,6 +32,7 @@ pub mod stun; pub mod survivability; pub mod taken; pub mod trigger; +pub mod warcry; pub use actor::{Actor, ActorBaseStats}; pub use ailment::{ @@ -120,6 +121,8 @@ pub use taken::{ MitigationCtx, MitigationInputs, armour_applies_pct, build_mitigation_ctx, damage_shift_table, effective_applied_armour, taken_hit_from_damage, }; +pub use warcry::WarcrySpec; + pub use trigger::{ CwcTriggerRate, EnergyTriggerRate, RotationResult, RotationSkill, SocketedSpellInfo, TriggerCondition, TriggerRate, TriggerSourceStats, action_cooldown, calc_cwc_trigger_rate, diff --git a/crates/pobr-core/src/calc/offence.rs b/crates/pobr-core/src/calc/offence.rs index 152b2740..c8d838cf 100644 --- a/crates/pobr-core/src/calc/offence.rs +++ b/crates/pobr-core/src/calc/offence.rs @@ -236,6 +236,48 @@ pub fn calculate_minimal(db: &ModDb, cfg: &CalcConfig, input: &MinimalInput) -> calculate_minimal_vs_enemy(db, &ModDb::new(), cfg, input) } +/// 出手速率解析(= vendor `globalOutput.Speed`):速度族(按技能类型取 AttackSpeed 或 +/// CastSpeed,SkillSpeed 始终)作为一个 inc/more 乘区;ActionSpeed 独立乘区单独相乘 +/// (对齐 PoB CalcOffence:`finalRate = base × (1+Σinc/100) × Π(more) × ActionSpeedMod`)。 +/// 攻击吃武器攻速 + AttackSpeed,法术吃技能施法速率 + CastSpeed——不混淆。 +/// 速度 inc/more 缩放后,先按附加施放/攻击时间(TotalCastTime/TotalAttackTime)换算 +/// 有效时间,再乘 ActionSpeed 独立乘区(PoB CalcOffence L2827 的加法分母 + 末端 action +/// speed),最后冷却限速 + 服务器帧 cap。 +/// +/// 独立成函供两处共用:`calculate_minimal_vs_enemy` 主链,以及 warcry uptime 预算 +/// (`calc::warcry`——vendor 的 warcry 段读同一 `globalOutput.Speed`, +/// CalcOffence.lua:3235)。 +pub(crate) fn resolve_action_rate(db: &ModDb, cfg: &CalcConfig, input: &MinimalInput) -> f64 { + let speed_names = super::skill_use_time::speed_names_for(cfg); + let action_speed_names = [ModName::from(super::skill_use_time::ACTION_SPEED)]; + let inc_speed = db.sum(ModType::Inc, cfg, &speed_names); + let more_speed = db.more(cfg, &speed_names); + let action_speed_mod = (1.0 + db.sum(ModType::Inc, cfg, &action_speed_names) / 100.0) + * db.more(cfg, &action_speed_names); + let scaled_rate = apply_total_time( + db, + cfg, + input.base_action_rate * (1.0 + inc_speed / 100.0) * more_speed, + ); + let uncapped_action_rate = scaled_rate * action_speed_mod; + if std::env::var("POBR_DBG_SPEED").is_ok() { + eprintln!( + "[POBR_DBG_SPEED] base={} inc={} more={} action={} scaled={} names={:?}", + input.base_action_rate, + inc_speed, + more_speed, + action_speed_mod, + scaled_rate, + speed_names + ); + } + round(apply_server_tick_cap( + db, + cfg, + apply_cooldown_cap(db, cfg, uncapped_action_rate), + )) +} + /// 完整入口:玩家 modDB + 敌人 modDB。敌人侧减伤/受伤链/格挡仅在 /// `cfg.mode_effective == true` 时生效(面板口径不引入敌人交互,保证与历史输出一致)。 /// @@ -257,29 +299,7 @@ pub fn calculate_minimal_vs_enemy( let cold_resistance = cold.final_value; let lightning_resistance = lightning.final_value; - // 速度族(按技能类型取 AttackSpeed 或 CastSpeed,SkillSpeed 始终)作为一个 inc/more 乘区; - // ActionSpeed 独立乘区单独相乘(对齐 PoB CalcOffence: - // finalRate = base × (1+Σinc/100) × Π(more) × ActionSpeedMod)。攻击吃武器攻速 + AttackSpeed, - // 法术吃技能施法速率 + CastSpeed——不混淆(攻击不吃 CastSpeed、法术不吃 AttackSpeed)。 - let speed_names = super::skill_use_time::speed_names_for(cfg); - let action_speed_names = [ModName::from(super::skill_use_time::ACTION_SPEED)]; - let inc_speed = db.sum(ModType::Inc, cfg, &speed_names); - let more_speed = db.more(cfg, &speed_names); - let action_speed_mod = (1.0 + db.sum(ModType::Inc, cfg, &action_speed_names) / 100.0) - * db.more(cfg, &action_speed_names); - // 速度 inc/more 缩放后,先按附加施放/攻击时间(TotalCastTime/TotalAttackTime)换算有效时间, - // 再乘 ActionSpeed 独立乘区(对齐 PoB CalcOffence L2827 的加法分母 + 末端 action speed)。 - let scaled_rate = apply_total_time( - db, - cfg, - input.base_action_rate * (1.0 + inc_speed / 100.0) * more_speed, - ); - let uncapped_action_rate = scaled_rate * action_speed_mod; - let action_rate = round(apply_server_tick_cap( - db, - cfg, - apply_cooldown_cap(db, cfg, uncapped_action_rate), - )); + let action_rate = resolve_action_rate(db, cfg, input); let accuracy_names = [ModName::from("Accuracy")]; let accuracy = scaled_numeric_stat(db, cfg, input.base_accuracy, &accuracy_names); // PoE2 命中率(agent-docs/accuracy-and-enemy.md §二,§三): @@ -942,6 +962,22 @@ fn enemy_damage_multiplier( } } let effective_resist = apply_penetration(player_db, &type_cfg, damage_type, resist); + // 诊断:POBR_DBG_ENEMYMIT=1 时逐类型 dump 敌方减伤分解(与 oracle + // enemyMitigation 对照:resistBase/pen/takenInc/takenMore)。 + if std::env::var("POBR_DBG_ENEMYMIT").is_ok() { + eprintln!( + "[POBR_ENEMYMIT] {type_prefix}: resist={resist:.2} eff_resist={effective_resist:.2} taken_inc={taken_inc:.2} taken_more={taken_more:.4}" + ); + for m in enemy_db.iter_mods() { + let n = m.name.as_str(); + if n == format!("{type_prefix}Resist") || n == "ElementalResist" { + eprintln!( + "[POBR_ENEMYMIT] {n} {:?} {:?} origin={:?} tags={:?}", + m.mod_type, m.value, m.origin, m.tags + ); + } + } + } 1.0 - effective_resist / 100.0 }; @@ -1320,7 +1356,46 @@ fn apply_server_tick_cap(db: &ModDb, cfg: &CalcConfig, rate: f64) -> f64 { pub(crate) fn scaled_pool(db: &ModDb, cfg: &CalcConfig, base: f64, name: &str) -> f64 { let names = [ModName::from(name)]; - scaled_numeric_stat(db, cfg, base, &names) + let conv = pool_conversion_pct(db, cfg, name); + if conv == 0.0 { + return scaled_numeric_stat(db, cfg, base, &names); + } + // vendor CalcDefence.lua:92-95:`(base × (1 − conv/100) + extra) × (1+inc) × more`。 + // OVERRIDE 仍然胜过一切(ChaosInoculation 等池钳定)。 + for n in &names { + if let Some(value) = db.override_(cfg, n.clone()) { + return round(value); + } + } + let base_value = base + db.sum(ModType::Base, cfg, &names); + let inc = db.sum(ModType::Inc, cfg, &names); + let more = db.more(cfg, &names); + round(base_value * (1.0 - conv / 100.0) * (1.0 + inc / 100.0) * more) +} + +/// Life/Mana 池的「N% of Maximum X Converted to 」扣减率 +/// (vendor CalcDefence.lua:92 `conv = m_min(Sum(BASE, res.."ConvertTo…"), 100)`)。 +/// 只扣池本体;ES/Armour/Evasion 侧的**转入**由 defence 矩阵按未扣减的全局底 +/// 处理(:1364 `ceil(globalBase × rate/100)`,见 calc_defence_resources)。 +// ponytail: vendor 把 conv 只作用于 base 段、Extra 免扣——PoBR 的矩阵转入 +// 现注入为 Maximum BASE,会一并被扣;fixture 集无「双向转换」build,出现时 +// 再把注入名迁到 Extra 通道。 +fn pool_conversion_pct(db: &ModDb, cfg: &CalcConfig, name: &str) -> f64 { + let prefix = match name { + "MaximumLife" => "Life", + "MaximumMana" => "Mana", + _ => return 0.0, + }; + db.sum( + ModType::Base, + cfg, + &[ + ModName::from(format!("{prefix}ConvertToEnergyShield")), + ModName::from(format!("{prefix}ConvertToArmour")), + ModName::from(format!("{prefix}ConvertToEvasion")), + ], + ) + .min(100.0) } fn scaled_numeric_stat(db: &ModDb, cfg: &CalcConfig, base: f64, names: &[ModName]) -> f64 { @@ -1378,7 +1453,9 @@ fn scaled_pool_traced( trace, format!("{stat_name} BASE modifier sum"), ); - let base_total = base + base_mods.value; + // Life/Mana 池转换扣减(vendor :92——与 scaled_pool 非追踪路径同式)。 + let conv_factor = 1.0 - pool_conversion_pct(db, cfg, stat_name) / 100.0; + let base_total = (base + base_mods.value) * conv_factor; let base_total_node = trace.add_node( format!("{stat_name} base total"), base_total, diff --git a/crates/pobr-core/src/calc/output.rs b/crates/pobr-core/src/calc/output.rs index ba1d70d9..48c059bc 100644 --- a/crates/pobr-core/src/calc/output.rs +++ b/crates/pobr-core/src/calc/output.rs @@ -169,6 +169,12 @@ pub struct OutputTable { pub effective_block_chance: f64, /// 有效法术格挡几率(%;PoB2 `EffectiveSpellBlockChance`)。 pub effective_spell_block_chance: f64, + /// 有效投射物攻击格挡几率(%;PoB2 `EffectiveProjectileBlockChance`)。 + /// EHP 平均格挡 = 四分型均值(vendor CalcDefence.lua:1067)。 + pub effective_projectile_block_chance: f64, + /// 有效法术投射物格挡几率(%;PoB2 `EffectiveSpellProjectileBlockChance`, + /// vendor :1013 与 ProjectileBlock 取 max)。 + pub effective_spell_projectile_block_chance: f64, /// 格挡承伤比例(%;被格挡命中仍承受的伤害份额,PoB2 `BlockEffect`, /// ModParser.lua:2479;0 = 完全格挡)。 pub block_effect: f64, @@ -451,6 +457,8 @@ impl Default for OutputTable { spell_block_chance_max: 0.0, effective_block_chance: 0.0, effective_spell_block_chance: 0.0, + effective_projectile_block_chance: 0.0, + effective_spell_projectile_block_chance: 0.0, block_effect: 0.0, deflection_rating: 0.0, deflect_chance: 0.0, diff --git a/crates/pobr-core/src/calc/perform.rs b/crates/pobr-core/src/calc/perform.rs index 79ea2e99..b13a1416 100644 --- a/crates/pobr-core/src/calc/perform.rs +++ b/crates/pobr-core/src/calc/perform.rs @@ -12,8 +12,7 @@ use super::ailment::{ }; use super::output::StoredDamageRange; use super::skill_mechanics::{ - calc_aoe, calc_cooldown, calc_life_cost, calc_mana_cost, calc_projectile_count, - calc_spirit_reservation, + calc_aoe, calc_cooldown, calc_mana_cost, calc_projectile_count, calc_spirit_reservation, }; use super::trigger::{ RotationSkill, TriggerSourceStats, calc_cwc_trigger_rate_traced, calc_multi_spell_rotation, @@ -124,6 +123,13 @@ pub fn perform(env: &mut Env) -> Result<(), CalcError> { env.cfg.multipliers.insert("Life".into(), life_pool); } + // warcry uptime 机器(存量 #9,vendor CalcOffence.lua:3203-3256):在 hand pass + // **之前**把 uptime 缩放后的 warcry 进攻效果(Infernal `DamageGainAsFire`)注入 + // 玩家 db——vendor 同样在伤害段之前写 skillModList,故击中与其派生 DoT(点燃) + // 都吃该增益。主技能 Speed 用与主手 pass 逐位一致的 resolve_action_rate 预解析 + // (速率是 (db,cfg,input) 的确定函数,注入 gain-as 不回馈速度,无自引用)。 + super::warcry::apply_warcry_uptime(env); + let mut input = MinimalInput::from(env.player.base); // 命中率的敌人闪避来源:优先用 enemy.mod_db 的 Evasion BASE(setup_env 注入,含档位倍率), // 回退到 enemy.base.evasion 标量(兼容直接构造 Env 的旧入口)。 @@ -164,6 +170,14 @@ pub fn perform(env: &mut Env) -> Result<(), CalcError> { env.player.breakdown = BreakdownTable::from_steps(output.breakdown); calc_defence(&mut env.player, &env.cfg, env.enemy.base.accuracy); + // 召唤物(Lane4):每个召唤物是独立 Actor,复用玩家同款 offence/defence 管线。 + // 无召唤物时该段空转。位置在 fill_mechanics **之前**(vendor 先例: + // CalcPerform.lua:3323-3370 calcMinionLifePool 在 calcs.defence(env.player) + // 之前算好召唤物生命)——伴侣总生命(inject_companion_life)要先于 EHP/max-hit + // 池整备写入玩家 ModDb。 + perform_minions(env); + inject_companion_life(env); + fill_mechanics(env); // 弩 reload 折算(M4-T4 W-D2):紧跟 fill_mechanics——vendor 顺序先服务器帧 // cap(calc_skill_use_time 内)后 reload(CalcOffence.lua:2864-2867);下游 @@ -178,13 +192,45 @@ pub fn perform(env: &mut Env) -> Result<(), CalcError> { // 只读消费异常侧 bleed/poison/ignite 现值(ailment.rs 不改,T4 一波约定)。 fill_skill_dot_stage(env); - // 召唤物(Lane4):每个召唤物是独立 Actor,复用玩家同款 offence/defence 管线。 - // 无召唤物时该段空转,行为与无此字段时完全一致(向后兼容)。 - perform_minions(env); - Ok(()) } +/// (#12 companion allies 层)伴侣总生命入库(vendor CalcPerform.lua:3364-3370): +/// 玩家有 `TakenFromCompanionBeforeYou`(Loyalty support 的 +/// `companion_takes_%_damage_before_you_from_support` buff 载荷)且无 +/// `TotalCompanionLife` Override(config 覆盖通道)时,把全部**可受伤伴侣**召唤物 +/// (`Actor::is_companion`,spawn 侧按授予技能 SkillType 判定)的生命求和写入玩家 +/// `TotalCompanionLife` BASE。消费方 = `pool_setup::build_pool_state` 的 companion +/// 先扣层(EHP reduce_pools 与 max-hit extend_total_hit_pool 共用)。 +fn inject_companion_life(env: &mut Env) { + let taken_name = [ModName::from("TakenFromCompanionBeforeYou")]; + if env.player.mod_db.sum(ModType::Base, &env.cfg, &taken_name) == 0.0 { + return; + } + if env + .player + .mod_db + .override_(&env.cfg, ModName::from("TotalCompanionLife")) + .is_some() + { + return; + } + let total: f64 = env + .minions + .iter() + .filter(|m| m.is_companion) + .map(|m| m.output.life) + .sum(); + env.player.mod_db.add_mod( + crate::Modifier::number("TotalCompanionLife", ModType::Base, total).with_origin( + ModifierSource::new(SourceId::new( + SourceKind::GameConstant, + "companion.total_life", + )), + ), + ); +} + /// 对每个召唤物跑同一套 offence/defence 管线,并把关键输出快照收集到玩家 /// `OutputTable.minions`。召唤物复用 `calculate_minimal_vs_enemy` + `calc_defence`, /// 不另写公式。召唤物对敌人的命中沿用玩家敌人配置(同一 `env.enemy`)。 @@ -909,13 +955,24 @@ fn fill_skill_mechanics(env: &mut Env) { } // 消耗:各资源需对应基础值 BASE 词条。无则跳过(保持 0)。 + // hybrid mana→life 转换(`HybridManaAndLifeCost_Life`,如 Atalui's Bloodletting / + // Blood-Magic 族):Life 侧吃 mana finalBase × hybrid,Mana 侧链尾 + // `floor((1-hybrid)×ManaCost)`(vendor CalcOffence.lua:2090-2104 + :2160-2162)。 + let hybrid = crate::calc::skill_mechanics::hybrid_life_cost_share(db, cfg); let base_mc = db.sum(ModType::Base, cfg, &[ModName::from("SkillManaCostBase")]); if base_mc > 0.0 { - env.player.output.mana_cost = calc_mana_cost(db, cfg, base_mc).final_cost; + let mana = calc_mana_cost(db, cfg, base_mc).final_cost; + env.player.output.mana_cost = if hybrid > 0.0 { + ((1.0 - hybrid) * mana).floor().max(0.0) + } else { + mana + }; } let base_lc = db.sum(ModType::Base, cfg, &[ModName::from("SkillLifeCostBase")]); - if base_lc > 0.0 { - env.player.output.life_cost = calc_life_cost(db, cfg, base_lc).final_cost; + if base_lc > 0.0 || (hybrid > 0.0 && base_mc > 0.0) { + env.player.output.life_cost = + crate::calc::skill_mechanics::calc_life_cost_hybrid(db, cfg, base_lc, base_mc) + .final_cost; } let base_sr = db.sum( ModType::Base, @@ -1028,12 +1085,29 @@ fn damaging_ailment_for_pass( ctx.speed, ); let sp = stack_potential(&stack); + if std::env::var("POBR_DBG_AILMENT").is_ok() { + eprintln!( + "[POBR_AILMENT] {name}: hit50={hit50:.2} crit50={crit50:.2} probe_chance={:.4} duration={:.4} speed={:.4} hit_chance={:.4} active={:.4} max={} sp={sp:.4}", + probe_out.chance, + ailment_duration(kind, player, cfg) * debuff_duration_mult(enemy, cfg), + ctx.speed, + ctx.hit_chance, + stack.active_stacks, + stack.max_stacks, + ); + } let ailment_crit = ailment_crit_chance(ctx.crit_chance, sp); let roll = roll_average(&stack); // Pass 2:高 roll 来源 + over-stacking 暴击 → 最终 magnitude。 let (hit_rolled, crit_rolled) = stored_source_at_roll(kind, &ctx.ranges, player, cfg, roll); let source = make_source(hit_rolled, crit_rolled, ailment_crit); let (out, _) = run(&source, trace); + if std::env::var("POBR_DBG_AILMENT").is_ok() { + eprintln!( + "[POBR_AILMENT] {name}: roll={roll:.2} hit_rolled={hit_rolled:.2} crit_rolled={crit_rolled:.2} ailment_crit={ailment_crit:.4} chance={:.4} eff_mult={:.4} magnitude_dps={:.4} duration={:.4}", + out.chance, out.eff_mult, out.magnitude_dps, out.duration_secs, + ); + } if stack.active_stacks > 0.0 { // vendor uptime 口径(`:5189-5193`):activeAilments = min(stacks, max)。 diff --git a/crates/pobr-core/src/calc/pool_setup.rs b/crates/pobr-core/src/calc/pool_setup.rs index 2daed384..dfb91580 100644 --- a/crates/pobr-core/src/calc/pool_setup.rs +++ b/crates/pobr-core/src/calc/pool_setup.rs @@ -17,7 +17,8 @@ //! `pool_damage.rs` 状态机只消费固化后的值类型;本文件同样不写 `Env`。 use crate::calc::pool_damage::{ - PoolCtx, PoolState, apply_protected_layer, life_hit_pool_with_loss_prevention, pool_protected, + AllyLayer, PoolCtx, PoolState, apply_protected_layer, life_hit_pool_with_loss_prevention, + pool_protected, }; use crate::rules::DefenceKeystones; use crate::{CalcConfig, ModDb}; @@ -114,8 +115,9 @@ pub fn build_pool_ctx( /// 构造扣池前的池快照(CalcDefence.lua:2821-2881 + reducePoolsByDamage 入口 /// :490-516 的 output 读出口径)。 /// -/// allies 段本阶段为空 Vec(玩家无 frost shield / soul link 来源时 vendor 同样为空, -/// 结构保留给后续 minion/party 接入)。 +/// allies 段目前只接 companion 层(`TakenFromCompanionBeforeYou` + +/// `TotalCompanionLife`,#12);frost shield / spectre / totem / soul link 等 +/// 其余先扣层无来源时 vendor 同样为空,结构保留给后续接入。 pub fn build_pool_state(db: &ModDb, cfg: &CalcConfig, base: &PoolBaseStats) -> PoolState { // Aegis(:2860-2877):modDB:Max 取最强单源(非求和)。 let aegis_shared = db.max_of(ModType::Base, cfg, &[ModName::from("AegisValue")]); @@ -156,8 +158,34 @@ pub fn build_pool_state(db: &ModDb, cfg: &CalcConfig, base: &PoolBaseStats) -> P 0.0 }; } + // 伴侣先扣层(#12;CalcDefence.lua:2961-2965 整备 + :493-495/:3087-3088 EHP + // 表 + :3656-3663 max-hit):`TakenFromCompanionBeforeYou` ≠ 0 时取 + // `TotalCompanionLife`(config Override 优先,否则 perform 注入的 BASE 和)。 + // deflected 项(`TakenFromCompanionBeforeYouFromDeflected × DeflectChance`, + // :2962-2963)未建模——18-build 语料无来源(wolf-pack oracle 钉值 mitigation + // 恰为 10 = 纯 hits 项),接入时需在此叠加。 + let mut allies = Vec::new(); + let companion_rate = db.sum( + ModType::Base, + cfg, + &[ModName::from("TakenFromCompanionBeforeYou")], + ); + if companion_rate != 0.0 { + let companion_life_name = ModName::from("TotalCompanionLife"); + let companion_life = db + .override_(cfg, companion_life_name.clone()) + .unwrap_or_else(|| db.sum(ModType::Base, cfg, &[companion_life_name])); + if companion_life > 0.0 { + allies.push(AllyLayer { + id: "companion", + remaining: companion_life, + mitigation_pct: companion_rate, + damage_type: None, + }); + } + } PoolState { - allies: Vec::new(), + allies, aegis_shared, aegis_shared_elemental, aegis_by_type, @@ -492,6 +520,53 @@ mod tests { assert_eq!(state.energy_shield, 600.0); } + /// (#12)companion 先扣层整备(:2961-2965):mitigation ≠ 0 且生命 > 0 时 + /// 产出 allies 层;Override 优先于 BASE 求和(config `TotalCompanionLife` + /// 覆盖通道);mitigation = 0 或生命 = 0 → allies 空。 + #[test] + fn build_pool_state_companion_ally_layer() { + let cfg = CalcConfig::new(); + // 无 mitigation → 空。 + assert!( + build_pool_state(&ModDb::new(), &cfg, &base_stats()) + .allies + .is_empty() + ); + // wolf-pack 钉值形态:10% + 2262(oracle TotalCompanionLife)。 + let mut db = ModDb::new(); + db.add_list([ + Modifier::number("TakenFromCompanionBeforeYou", ModType::Base, 10.0), + Modifier::number("TotalCompanionLife", ModType::Base, 2262.0), + ]); + let state = build_pool_state(&db, &cfg, &base_stats()); + assert_eq!(state.allies.len(), 1); + assert_eq!(state.allies[0].id, "companion"); + assert_eq!(state.allies[0].remaining, 2262.0); + assert_eq!(state.allies[0].mitigation_pct, 10.0); + assert_eq!(state.allies[0].damage_type, None); + // Override 优先。 + let mut db2 = ModDb::new(); + db2.add_list([ + Modifier::number("TakenFromCompanionBeforeYou", ModType::Base, 10.0), + Modifier::number("TotalCompanionLife", ModType::Base, 2262.0), + Modifier::number("TotalCompanionLife", ModType::Override, 500.0), + ]); + let state2 = build_pool_state(&db2, &cfg, &base_stats()); + assert_eq!(state2.allies[0].remaining, 500.0); + // mitigation 有、生命 0 → 空(vendor :3656 `TotalCompanionLife > 0` 门控)。 + let mut db3 = ModDb::new(); + db3.add_list([Modifier::number( + "TakenFromCompanionBeforeYou", + ModType::Base, + 10.0, + )]); + assert!( + build_pool_state(&db3, &cfg, &base_stats()) + .allies + .is_empty() + ); + } + /// MinimumBypass = 全类型 min(:2709-2721)。 #[test] fn minimum_es_bypass_takes_min() { diff --git a/crates/pobr-core/src/calc/scaled_damage.rs b/crates/pobr-core/src/calc/scaled_damage.rs index 042a3084..4ccab54b 100644 --- a/crates/pobr-core/src/calc/scaled_damage.rs +++ b/crates/pobr-core/src/calc/scaled_damage.rs @@ -193,10 +193,41 @@ pub fn dps_end_factors( let activate_twice = db .sum(ModType::Base, cfg, &[ModName::from("GrenadeActivateTwice")]) .min(100.0); + // Barrage repeats(vendor CalcOffence.lua:962-976):Barrageable 技能被 + // Barrage buff 授予 SequentialProjectiles + BarrageRepeats 时,写入 + // `DPS MORE (1 + Σ BarrageRepeats) × mod(BarrageRepeatDamage)`。vendor 把 + // 该值**原样**当 MORE 百分比(repeats=1 → MORE 2 → ×1.02,oracle 实证 + // spirit-walker-twister DpsMultiplier=1.02)——忠实复刻,不换算为倍数。 + // ponytail: vendor 同块的 else 分支(crossbow barrage 的 additionalProjectiles + // → 攻速惩罚 ReplaceMod)无 fixture 覆盖,暂不实现。 + let barrage_repeats_more = { + let barrageable = cfg.skill_types.intersects(SkillTypes::BARRAGEABLE) + && db.flag(cfg, ModName::from("SequentialProjectiles")) + && !db.flag(cfg, ModName::from("OneShotProj")) + && !db.flag(cfg, ModName::from("NoAdditionalProjectiles")) + && !db.flag(cfg, ModName::from("TriggeredBySnipe")); + let repeats = db.sum(ModType::Base, cfg, &[ModName::from("BarrageRepeats")]); + if barrageable && repeats > 0.0 { + let repeat_damage_names = [ModName::from("BarrageRepeatDamage")]; + let repeat_damage = (1.0 + db.sum(ModType::Inc, cfg, &repeat_damage_names) / 100.0) + * db.more(cfg, &repeat_damage_names); + let dps_multi = (1.0 + repeats) * repeat_damage; + // vendor MoreInternal 逐名桶百分比取整(ModList.lua:143 + // `result * round(modResult, 2)`):Barrage Repeats 的 DPS MORE 桶 + // 折算后取整到 0.01(1.65 → ×1.0165 → ×1.02,oracle 实证 + // spirit-walker DpsMultiplier=1.02)。 + // ponytail: 与 db.more("DPS") 分桶各自取整——vendor 把二者并在同一 + // "DPS" 名桶先乘后取整,语料中无并存场景,出现时再并桶。 + ((1.0 + dps_multi / 100.0) * 100.0).round() / 100.0 + } else { + 1.0 + } + }; let dps_multiplier = skill_dps_multiplier.unwrap_or(1.0) * (1.0 + db.sum(ModType::Inc, cfg, &dps_names) / 100.0) * db.more(cfg, &dps_names) - * (1.0 + activate_twice / 100.0); + * (1.0 + activate_twice / 100.0) + * barrage_repeats_more; let quantity_multiplier = db .sum(ModType::Base, cfg, &[ModName::from("QuantityMultiplier")]) .max(1.0); diff --git a/crates/pobr-core/src/calc/session.rs b/crates/pobr-core/src/calc/session.rs index 4938b570..a1a1fb10 100644 --- a/crates/pobr-core/src/calc/session.rs +++ b/crates/pobr-core/src/calc/session.rs @@ -52,6 +52,14 @@ pub struct BuffSpec { pub socket_index: u32, pub is_mark: bool, pub ignore_curse_limit: bool, + /// (存量 #7-1)技能局部效果乘区 INC 增量(vendor curse 分支 + /// CalcPerform.lua:2423 `skillModList:Sum("INC", skillCfg, "CurseEffect")` + /// 的 PoBR 对位——curse 宝石自身品质 `curse_effect_+%` + 组内兼容 support + /// (Heightened Curse +25)payload;编排层构造,默认 0)。 + pub local_effect_inc: f64, + /// 同上 MORE 因子(:2427 `skillModList:More(skillCfg, "CurseEffect")`, + /// 如 Atziri's Allure -20% final;默认 1)。 + pub local_effect_more: f64, /// 来源效果的技能类型位(vendor per-skill `skillCfg`——buff_pass 乘区对 /// 域限定词条(「Banner Skills have N% increased Aura Magnitudes」的 /// SkillTypes tag)按此匹配;默认 NONE = 旧行为,域词条不命中)。 @@ -164,6 +172,54 @@ impl CalculationSession { .flag(&self.env.cfg, ModName::from(name)) } + /// 低生命自动条件桥(vendor CalcDefence.lua:335-350:`(max − reserved)/max ≤ + /// LowPoolThreshold(0.35)` → `condList["LowLife"] = true`)。0.5.4b 起 + /// Spirit→Life 保留转换(Atziri's Communion)使重保留 build 自动进入 Low Life, + /// 解锁「while on Low Life」族词条(tree + Direstrike 支援 buff)。 + /// + /// 须在全部来源注入后、[`perform_minimal`](Self::perform_minimal) 之前调用 + /// (预留 mod 已注入,条件在 perform 的聚合查询期生效——vendor 同序: + /// doActorLifeManaSpiritReservation 先于 calcs.offence)。预留聚合口径与 + /// perform 预留段逐式相同(ReservationMultiplier floor4 + efficiency 除数)。 + /// 显式 config 条件(`conditionLowLife`)优先,不被覆盖。 + // ponytail: 只桥 Life(唯一有 fixture 佐证的池);LowMana/LowSpirit 同一 + // vendor 循环,出现消费 build 时按本函数样板扩展。LowLifePercentage 覆盖 + // stat(vendor :337)全 fixture 无来源,未建模。 + pub fn bridge_low_pool_conditions(&mut self) { + if self.env.cfg.conditions.contains_key("LowLife") { + return; + } + let life = self.pool_total("MaximumLife"); + if life <= 0.0 { + return; + } + let db = &self.env.player.mod_db; + let cfg = &self.env.cfg; + let mult = + (db.more(cfg, &[ModName::from("ReservationMultiplier")]) * 10_000.0).floor() / 10_000.0; + let eff_names = [ + ModName::from("LifeReservationEfficiency"), + ModName::from("ReservationEfficiency"), + ]; + let eff_inc = db.sum(ModType::Inc, cfg, &eff_names).max(-100.0); + let divisor = ((1.0 + eff_inc / 100.0) * db.more(cfg, &eff_names)).max(1e-12); + let factor = mult / divisor; + let flat = db.sum(ModType::Base, cfg, &[ModName::from("LifeReserved")]) * factor; + let percent = db.sum(ModType::Inc, cfg, &[ModName::from("LifeReservedPercent")]) * factor; + let reserved = super::survivability::reservation(life, flat, percent).reserved; + if (life - reserved) / life + <= self + .env + .cfg + .constants + .game_constants + .game + .low_pool_threshold + { + self.env.cfg.conditions.insert("LowLife".into(), true); + } + } + pub fn add_modifier_texts( &mut self, texts: impl IntoIterator>, @@ -218,6 +274,17 @@ impl CalculationSession { Ok(()) } + /// 接入一件**武器**(调用方判定基底为武器):同 [`Self::add_item`],另按 vendor + /// `Item.lua:1954-1961` 把无 flag 的爆伤词条转为按手条件 + /// (见 [`crate::item::apply_weapon_hand_conditions`])。 + pub fn add_weapon_item(&mut self, slot: EquipmentSlot, item: &Item) -> Result<(), ParseError> { + let mut ingest = ingest_item_with_ctx(slot, item, self.parse_ctx())?; + crate::item::apply_weapon_hand_conditions(&mut ingest.modifiers, slot); + self.env.player.mod_db.add_list(ingest.modifiers); + self.unsupported_modifier_texts.extend(ingest.unsupported); + Ok(()) + } + /// 接入一件**激活态**药剂/护符(M3-T4 通道切换):词条经 /// [`crate::item::ingest_flask_charm`] 打包为 `FlaskBuff`/`CharmBuff` 载荷 /// List mod 注入(List 不参与 sum/more/flag 聚合 → 未合并前零直接影响),由 @@ -274,6 +341,15 @@ impl CalculationSession { self.env.buff_skills.push(spec); } + /// 注入一个 warcry 技能规格(存量 #9 warcry uptime 机器)。消费在 `perform` + /// 的 hand pass 之前([`super::warcry::apply_warcry_uptime`]):按 + /// `min((賦能次数/主技能Speed)/(冷却+喊叫时间), 1)` 折算 uptime 后,把 warcry + /// 的进攻性效果(Infernal Cry `DamageGainAsFire`)缩放注入玩家 db + /// (vendor CalcOffence.lua:3229-3256)。`cfg.mode_buffs` 门控。 + pub fn add_warcry_skill(&mut self, spec: super::warcry::WarcrySpec) { + self.env.warcry_skills.push(spec); + } + /// 接入一个召唤物(M5a-B2):从 [`MinionDef`](super::MinionDef) 真实底材 + 召唤 /// 宝石等级 + 数量上限派生召唤物 `Actor` 接入 `Env.minions`,并把上限写为玩家 /// `Multiplier:SummonedMinion` / `Multiplier:MinionPresenceCount`(供「per Minion」 @@ -291,6 +367,7 @@ impl CalculationSession { minion_modifiers: Vec, ally_buff_mods: Vec, infusion: super::AttributeInfusion, + is_companion: bool, ) { self.env.add_minion_from_def( def, @@ -299,6 +376,7 @@ impl CalculationSession { minion_modifiers, ally_buff_mods, infusion, + is_companion, ); } @@ -434,6 +512,23 @@ impl CalculationSession { .sum(ModType::Base, &self.env.cfg, &[ModName::from(name)]) } + /// 主技能 Life 消耗快照(vendor `output.LifeCost`;含 hybrid mana→life 转换)。 + /// 编排层在全部来源注入后调用,回填 `cfg.stats/multipliers["LifeCost"]` 供 + /// per-life-cost 词条(PerStat stat=LifeCost,如 Atalui's Bloodletting 的 + /// gain-as-physical)在伤害聚合期取数——与 vendor CalcOffence 先算 cost 再算 + /// 伤害的顺序等价。 + pub fn life_cost_snapshot(&self) -> f64 { + let base_mc = self.base_sum("SkillManaCostBase"); + let base_lc = self.base_sum("SkillLifeCostBase"); + super::skill_mechanics::calc_life_cost_hybrid( + &self.env.player.mod_db, + &self.env.cfg, + base_lc, + base_mc, + ) + .final_cost + } + /// 属性最终总量(PoB2 `calculateAttributes`,CalcPerform.lua:381-388: /// `output[stat] = m_max(round(calcLib.val(modDB, stat)), 0)`,calcLib.val = /// `Σbase × (1 + Σinc/100) × Πmore`)。`class_base` = 职业起始属性(PoBR 把它 @@ -455,6 +550,17 @@ impl CalculationSession { /// (CalcOffence pool 段)。供编排层在全部来源注入后回填 PerStat 资源分母 /// (vendor PerStat tag 读 actor **output**,ModStore.lua:440-460 GetStat)—— /// [`base_sum`](Self::base_sum) 只取 BASE 之和,会漏掉 inc/more 缩放后的池值。 + /// Spirit 最终池值(vendor `output.Spirit`,[`calc_spirit_pool`] 同源: + /// OVERRIDE → (base + Extra) × 未转换比例 × (1+Σinc/100) × Πmore,round)。 + /// 供编排层回填 PerStat `Spirit` 分母——vendor PerStat 读 actor output + /// (ModStore.lua:440-460 GetStat),BASE-only 会把「+2 Armour per 1 Spirit」 + /// (wolf-pack Perfidy,Spirit 336 vs base 300)欠算。 + /// + /// [`calc_spirit_pool`]: super::calc_spirit_pool + pub fn spirit_total(&self) -> f64 { + super::calc_spirit_pool(&self.env.player.mod_db, &self.env.cfg) + } + pub fn pool_total(&self, name: &str) -> f64 { let actor_base = match name { "MaximumLife" => self.env.player.base.life, diff --git a/crates/pobr-core/src/calc/setup_env.rs b/crates/pobr-core/src/calc/setup_env.rs index 6dfe89bb..1cab89ae 100644 --- a/crates/pobr-core/src/calc/setup_env.rs +++ b/crates/pobr-core/src/calc/setup_env.rs @@ -150,6 +150,36 @@ pub fn setup_enemy(env: &mut Env, config_level: u32, tier: EnemyTier) { inject_enemy_mods(&mut env.enemy.mod_db, &defaults, tier); inject_ehp_damage_placeholder(&mut env.enemy.mod_db, constants, defaults.level, tier); + // 档位预设的**玩家侧** mod 组(数据驱动:`enemy_presets.json::tiers[].player_mods`; + // vendor ConfigOptions.lua L2007-2008 等 `modList:NewMod("WarcryPower","BASE",20, + // "Boss")` + `Multiplier:EnemyPower`,Boss/Pinnacle/Uber 共通)。首个消费方 = + // warcry uptime 机器(`calc::warcry` 的 WarcryPower 求和,CalcPerform.lua:2120)。 + // effective_only 条目(当前 player_mods 无)按保守跳过,避免面板口径引入敌人交互。 + if let Some(preset) = env.cfg.constants.enemy_presets.tier_for(tier) { + let player_mods: Vec = preset + .player_mods + .iter() + .filter(|m| !m.effective_only) + .filter_map(|m| { + let mod_type = match m.mod_type.as_str() { + "BASE" => ModType::Base, + "INC" => ModType::Inc, + "MORE" => ModType::More, + _ => return None, // 未知类型:保守跳过(数据损坏防御)。 + }; + Some( + crate::Modifier::number(m.name.as_str(), mod_type, m.value) + .with_source(m.source_label.clone()) + .with_origin(ModifierSource::new(SourceId::new( + SourceKind::EnemyConfig, + format!("tier_player.{}.{}", preset.id, m.name), + ))), + ) + }) + .collect(); + env.player.mod_db.add_list(player_mods); + } + // 注意:Boss 自带元素穿透(Pinnacle 3 / Uber 8,vendor `pinnacleBossPen = 15/5` / // `uberBossPen = 40/5`,Modules/Data.lua:231/:233)**只作用在防御侧**—— // `enemy{Fire,Cold,Lightning}Pen` config var 没有 apply 函数(ConfigOptions.lua:2269-2273, @@ -265,6 +295,21 @@ fn inject_enemy_mods(db: &mut ModDb, defaults: &EnemyTierDefaults, tier: EnemyTi if tier.is_pinnacle_or_uber() { push_enemy_condition(db, "PinnacleBoss", "pinnacle_boss"); } + + // 敌人 actor 基础条件态词条(vendor CalcSetup.lua:73-77 initModDB——每个 actor + // 的 modDB 都带的 Intimidated 条件对:受伤 +10% INC / 输出 −10% INC)。条件 var + // 用 cfg 键空间的 `EnemyIntimidated`(config `conditionEnemyIntimidated` 与 + // env_finalize 的敌侧 `Condition:Intimidated` flag 桥接同置此键)。 + // ponytail: 仅落敌方消费的 Intimidated 对;Maimed/Unnerved/Debilitated 等同表 + // 条件在 18-build 语料无来源,parity 点名时再逐条补。 + for (name, value) in [("DamageTaken", 10.0), ("Damage", -10.0)] { + db.add_mod( + Modifier::number(ModName::from(name), ModType::Inc, value) + .with_source("enemy intimidated_base") + .with_origin(enemy_source("intimidated_base")) + .with_tag(ModTag::condition("EnemyIntimidated", false)), + ); + } } /// EHP 进伤 placeholder 注入(M2 F-1):把 vendor ConfigOptions.lua:1982-1996 的 diff --git a/crates/pobr-core/src/calc/skill_mechanics.rs b/crates/pobr-core/src/calc/skill_mechanics.rs index c80ffd85..2a0a667c 100644 --- a/crates/pobr-core/src/calc/skill_mechanics.rs +++ b/crates/pobr-core/src/calc/skill_mechanics.rs @@ -599,13 +599,25 @@ pub fn calc_skill_cost( // 辅助宝石 cost 倍率:连乘截断 4 位小数 → 作用于 base → floor // (PoB2 CalcOffence.lua:2052/:2076-2077,先于 inc/more 链)。 - let support_mult_names = [ModName::from("SupportManaMultiplier")]; - let support_mult = { - let m = db.more(cfg, &support_mult_names); - (m * 10000.0).floor() / 10000.0 - }; - let base_cost_after_support = (base_cost * support_mult).floor(); + let base_cost_after_support = (base_cost * support_cost_multiplier(db, cfg)).floor(); + let final_cost = apply_cost_chain(db, cfg, resource_mod_prefix, base_cost_after_support); + + SkillCostResult { + kind, + base_cost, + final_cost: round(final_cost), + no_cost: false, + } +} +/// 消耗 inc/more/efficiency 链(vendor CalcOffence.lua:2126-2160 第二循环), +/// 入参 `final_base` = 已含 SupportManaMultiplier 的 finalBaseCost。 +fn apply_cost_chain( + db: &ModDb, + cfg: &CalcConfig, + resource_mod_prefix: &str, + final_base: f64, +) -> f64 { let type_cost_name = format!("{resource_mod_prefix}Cost"); let generic_cost_name = "Cost"; let inc_names = [ @@ -623,11 +635,10 @@ pub fn calc_skill_cost( // 1) `floor(finalBaseCost × (1+inc/100))` (inc 正 → floor,inc 负 → ceil) // 2) `floor/ceil(step1 × moreType)` (more < 1 → ceil) // 3) `floor/ceil(step2 × moreGeneric)` - // finalBaseCost = 上方 base_cost_after_support(已含 SupportManaMultiplier)。 let after_inc = if inc >= 0.0 { - (base_cost_after_support * (1.0 + inc / 100.0)).floor() + (final_base * (1.0 + inc / 100.0)).floor() } else { - (base_cost_after_support * (1.0 + inc / 100.0)).ceil() + (final_base * (1.0 + inc / 100.0)).ceil() }; let after_more_type = if more_type < 1.0 { (after_inc * more_type).ceil() @@ -652,17 +663,36 @@ pub fn calc_skill_cost( ModName::from("CostEfficiency"), ], ); - let final_cost = after_more / (1.0 + efficiency / 100.0); + after_more / (1.0 + efficiency / 100.0) +} - SkillCostResult { - kind, - base_cost, - final_cost: round(final_cost), - no_cost: false, - } +/// 辅助宝石 cost 倍率连乘,截断 4 位小数(PoB2 CalcOffence.lua:2062 +/// `mult = floor(More(skillCfg, "SupportManaMultiplier"), 4)`)。 +fn support_cost_multiplier(db: &ModDb, cfg: &CalcConfig) -> f64 { + let m = db.more(cfg, &[ModName::from("SupportManaMultiplier")]); + (m * 10000.0).floor() / 10000.0 +} + +/// Hybrid mana→life 消耗份额(0..=1)。来源 = `HybridManaAndLifeCost_Life` BASE +/// (vendor stat `base_skill_cost_life_instead_of_mana_%`,如 Atalui's Bloodletting +/// constantStat 100;Blood-Magic 族树词条同名),vendor 封顶 100 +/// (CalcOffence.lua:2067 `m_min(Sum(...), 100) / 100`)。 +pub fn hybrid_life_cost_share(db: &ModDb, cfg: &CalcConfig) -> f64 { + (db.sum( + ModType::Base, + cfg, + &[ModName::from("HybridManaAndLifeCost_Life")], + ) + .min(100.0) + / 100.0) + .max(0.0) } /// 方便的 Mana 消耗计算。 +/// +/// 注意:hybrid mana→life 转换([`hybrid_life_cost_share`] > 0)时 vendor 在链尾 +/// 追加 `floor((1 - hybrid) × ManaCost)`(CalcOffence.lua:2160-2162)——由调用方 +/// (perform fill)执行,本函数保持单资源纯链。 pub fn calc_mana_cost(db: &ModDb, cfg: &CalcConfig, base_mana_cost: f64) -> SkillCostResult { calc_skill_cost(db, cfg, SkillCostKind::Mana, "Mana", base_mana_cost) } @@ -672,6 +702,38 @@ pub fn calc_life_cost(db: &ModDb, cfg: &CalcConfig, base_life_cost: f64) -> Skil calc_skill_cost(db, cfg, SkillCostKind::Life, "Life", base_life_cost) } +/// Life 消耗(含 hybrid mana→life 转换,vendor CalcOffence.lua:2090-2104 Life 分支): +/// `life.finalBaseCost = round(base_life×mult + round(floor(base_mana×mult) × hybrid))`, +/// 之后走 Life 消耗 inc/more/efficiency 链。hybrid = 0 时与 [`calc_life_cost`] 等价。 +pub fn calc_life_cost_hybrid( + db: &ModDb, + cfg: &CalcConfig, + base_life_cost: f64, + base_mana_cost: f64, +) -> SkillCostResult { + let hybrid = hybrid_life_cost_share(db, cfg); + if hybrid <= 0.0 { + return calc_life_cost(db, cfg, base_life_cost); + } + if db.flag(cfg, ModName::from("HasNoCost")) { + return SkillCostResult { + kind: SkillCostKind::Life, + base_cost: base_life_cost, + final_cost: 0.0, + no_cost: true, + }; + } + let mult = support_cost_multiplier(db, cfg); + let mana_final_base = (base_mana_cost * mult).floor(); + let life_final_base = (base_life_cost * mult + (mana_final_base * hybrid).round()).round(); + SkillCostResult { + kind: SkillCostKind::Life, + base_cost: base_life_cost, + final_cost: round(apply_cost_chain(db, cfg, "Life", life_final_base)), + no_cost: false, + } +} + /// 方便的 Spirit(保留)消耗计算。 /// /// Spirit 保留量 = `ReservationMultiplier MORE`(宝石等级保留倍率)作用于宝石基础保留值, diff --git a/crates/pobr-core/src/calc/skill_use_time.rs b/crates/pobr-core/src/calc/skill_use_time.rs index ab7ac42b..0f9aab55 100644 --- a/crates/pobr-core/src/calc/skill_use_time.rs +++ b/crates/pobr-core/src/calc/skill_use_time.rs @@ -44,21 +44,23 @@ pub fn speed_names() -> [ModName; 3] { } /// 按技能类型选取速度 bucket:攻击 → `[AttackSpeed, SkillSpeed]`,法术 → `[CastSpeed, SkillSpeed]`, -/// 二者皆非(如纯 DoT/未标记)→ 取全部三个(向后兼容)。 +/// 二者皆非(如伙伴/召唤/预留类主技能)→ 仅 `[SkillSpeed]`。 /// /// 出处:PoB CalcOffence——攻击只吃攻速、法术只吃施法速度,`SkillSpeed` 两者通吃;不混淆 /// (避免攻击错误吃到 `increased Cast Speed`、法术错误吃到 `increased Attack Speed`)。 +/// 未标记技能:vendor 的 `Speed` mod 带 ModFlag.Attack/Cast,flag 匹配要求 cfg 含对应位 +/// ——非攻非法术 cfg 二者皆不吃(wolf-pack 实测:Wolf Pack 主技能曾错吃武器 +/// `12% reduced Attack Speed` → Speed 0.88 vs vendor 1.00)。 pub fn speed_names_for(cfg: &CalcConfig) -> Vec { // 攻击/法术判定同时认 ModFlags(orchestrator 经 `skill_type_flags` 注入)与 SkillTypes // (`CalcConfig::attack()`/`spell()` 预设),二者任一命中即可——兼容两条装配路径。 let is_attack = cfg.flags.intersects(ModFlags::ATTACK) || cfg.is_attack(); let is_spell = cfg.flags.intersects(ModFlags::SPELL) || cfg.is_spell(); - let untyped = !is_attack && !is_spell; let mut names = Vec::with_capacity(3); - if is_attack || untyped { + if is_attack { names.push(ModName::from(SPEED_BUCKET[0])); // AttackSpeed } - if is_spell || untyped { + if is_spell { names.push(ModName::from(SPEED_BUCKET[1])); // CastSpeed } names.push(ModName::from(SPEED_BUCKET[2])); // SkillSpeed(始终) diff --git a/crates/pobr-core/src/calc/warcry.rs b/crates/pobr-core/src/calc/warcry.rs new file mode 100644 index 00000000..dca94689 --- /dev/null +++ b/crates/pobr-core/src/calc/warcry.rs @@ -0,0 +1,403 @@ +//! Warcry uptime 机器(存量 #9):非主技能的 warcry 按「賦能攻擊次數 / 主技能出手 +//! 速率 / (冷却 + 喊叫时间)」折算 uptime,再把 warcry 的进攻性效果按 uptime 缩放 +//! 注入主技能聚合。 +//! +//! 逐段对照 vendor: +//! - **WarcryPower / 賦能次数**:`CalcPerform.lua:2116-2142`(Warcry buff 分支)—— +//! `warcryPower = Override("WarcryPower") or max(Sum(BASE)×(1+Sum(INC)/100), +//! Sum(BASE,"MinimumWarcryPower"))`(:2120);`baseEmpowers = +//! floor(min(power, Sum("WarcryPowerCap")) / Sum("WarcryPowerPer"))`(:2121-2123) +//! `+ Sum("EmpoweredAttacks")`(:2125);`totalEmpowers = +//! (base + Sum("ExtraEmpoweredAttacks")) × More("ExtraEmpoweredAttacks")` +//! (:2127-2129)→ 发布 `NumEmpowers`(:2130)。 +//! - **冷却**:`calcSkillCooldown`(CalcOffence.lua:325-348)——`cooldown = +//! Override("CooldownRecovery") or (skillData.cooldown + Sum(BASE)) / +//! max(0, (1+Sum(INC)/100)×More)`,storedUses ≤ 1 且无 AdditionalCooldownUses +//! 时向上取整到服务器帧(:338-346)。 +//! - **喊叫时间**:`calcWarcryCastTime`(CalcOffence.lua:350-359)—— +//! `1 / min((1/Sum(BASE,"WarcryCastTime")) × mod("WarcrySpeed") × +//! actionSpeedMod, ServerTickRate)`;`InstantWarcry` flag → 0。 +//! - **uptime**:CalcOffence.lua:3229-3237(Infernal 分支,Ancestral/Intimidating/ +//! Rallying 同构)——`baseUptimeRatio = min((NumEmpowers / Speed) / +//! (cooldown + castTime), 1) × 100`;`UptimeRatio = min(100, baseUptimeRatio × +//! storedUses)`。注:vendor `:3236` 的 `storedUses or 0 + Sum(...)` 受 Lua 优先级 +//! 影响实为 `storedUses or (0 + Sum)`,本实现按意图语义 +//! `storedUses + Sum("AdditionalCooldownUses")`(与 scaled_damage.rs `:3845` +//! 笔误处置同一先例;两 fixture 均 storedUses=1、Additional=0,取值相同)。 +//! - **Infernal 消费点**:`CalcPerform.lua:1362-1366` 把 warcry skillModList 的 +//! `InfernalExtraFireDamageMultiplier` 发布为玩家 `InfernalExtraFireDamage`; +//! `CalcOffence.lua:3251-3254` 注入 `DamageGainAsFire BASE gain×uptime/100` +//! (ModFlag.Melee,source "Uptime Scaled Infernal Cry")。本实现把两步折叠: +//! 直接从 spec 的 skill-local mods(+玩家 db)求和后按 uptime 注入。 +//! +//! 门控(vendor CalcOffence.lua:3203-3205/:3229):`env.mode_buffs`;主技能非 +//! NeverExertable/Triggered/OtherThingUsesSkill/Retaliation;Infernal 消费点要求 +//! 主技能带 SkillType.Melee。 +//! +//! ponytail: 本模块当前只接 Infernal 的 DamageGainAsFire 消费点(fixture 中唯一 +//! 消费者);Intimidating/Rallying/Seismic 的 exert 伤害乘区(OffensiveWarcryEffect +//! 族)待有消费 build 时按同一 spec/uptime 底座补。 + +use pobr_data::prelude::*; +use pobr_data::skill::SkillTypes; + +use crate::{CalcConfig, ModDb, Modifier}; + +use super::env::Env; +use super::offence::MinimalInput; + +/// 一个 warcry 主动技能的注入规格(编排层 `warcry_skill_specs` 构造, +/// `session::add_warcry_skill` 写入 `Env::warcry_skills`)。 +#[derive(Debug, Clone)] +pub struct WarcrySpec { + /// warcry 键名(vendor `buff.name:gsub(" Cry",""):gsub("'s",""):gsub(" ","")`, + /// CalcPerform.lua:2124——"Infernal Cry" → `Infernal`;`EmpoweredAttacks` + /// 求和键用)。 + pub name: String, + /// 授予效果 id(去重 + 归因)。 + pub skill_id: String, + /// 技能基础冷却(秒,granted_effect_levels `cooldown_ms`;vendor + /// `skillData.cooldown`)。 + pub cooldown_base_s: f64, + /// `skillData.storedUses`(granted_effect_levels `stored_uses`,缺省 1)。 + pub stored_uses: f64, + /// warcry 技能自身的类型位(skill-local/全局词条按 warcry 域匹配用—— + /// 对位 vendor 的 per-skill `skillCfg`)。 + pub skill_types: SkillTypes, + /// skill-local mod 列表 = 自身 statmap 产物(WarcryPowerPer/Cap、 + /// InfernalExtraFireDamageMultiplier 等)+ 组内兼容 support 载荷 + /// (如 Cooldown Recovery II 的 CooldownRecovery INC 30)+ + /// `WarcryCastTime BASE`(效果 cast_time,对位 vendor skillModList "Base" 条)。 + pub mods: Vec, +} + +/// spec-local 求和(vendor skillModList 的 local 段;global 段由玩家 db 单独求和后相加)。 +fn local_sum(mods: &[Modifier], cfg: &CalcConfig, mod_type: ModType, name: &str) -> f64 { + mods.iter() + .filter(|m| m.mod_type == mod_type && m.name.as_str() == name && m.matches(cfg)) + .filter_map(|m| m.effective_number(cfg)) + .sum() +} + +/// spec-local MORE 连乘(`Π(1+v/100)`)。 +fn local_more(mods: &[Modifier], cfg: &CalcConfig, name: &str) -> f64 { + mods.iter() + .filter(|m| m.mod_type == ModType::More && m.name.as_str() == name && m.matches(cfg)) + .filter_map(|m| m.effective_number(cfg)) + .fold(1.0, |acc, v| acc * (1.0 + v / 100.0)) +} + +/// skill-local + 玩家 db 的合并 BASE/INC 求和(vendor skillModList 链上溯 modDB)。 +fn scoped_sum(db: &ModDb, spec: &WarcrySpec, cfg: &CalcConfig, ty: ModType, name: &str) -> f64 { + db.sum(ty, cfg, &[ModName::from(name)]) + local_sum(&spec.mods, cfg, ty, name) +} + +fn scoped_more(db: &ModDb, spec: &WarcrySpec, cfg: &CalcConfig, name: &str) -> f64 { + db.more(cfg, &[ModName::from(name)]) * local_more(&spec.mods, cfg, name) +} + +/// 賦能攻擊次数(`NumEmpowers`,CalcPerform.lua:2116-2130)。 +fn total_empowers(db: &ModDb, spec: &WarcrySpec, cfg: &CalcConfig) -> f64 { + // :2120 —— WarcryPower:config OVERRIDE(multiplierWarcryPower)优先,否则 + // BASE×(1+INC/100) 与 MinimumWarcryPower 取大(BASE 20 来自敌人档位预设 + // player_mods,Boss/Pinnacle/Uber 共通,ConfigOptions.lua:2007)。 + let warcry_power = db + .override_(cfg, ModName::from("WarcryPower")) + .unwrap_or_else(|| { + let base = db.sum(ModType::Base, cfg, &[ModName::from("WarcryPower")]); + let inc = db.sum(ModType::Inc, cfg, &[ModName::from("WarcryPower")]); + let min = db.sum(ModType::Base, cfg, &[ModName::from("MinimumWarcryPower")]); + (base * (1.0 + inc / 100.0)).max(min) + }); + // :2121-2123 —— per/cap 是 skillModList 侧 stat(Infernal 常量 stat 10/50)。 + let power_cap = scoped_sum(db, spec, cfg, ModType::Base, "WarcryPowerCap"); + let power_per = scoped_sum(db, spec, cfg, ModType::Base, "WarcryPowerPer"); + let mut base_empowers = if power_per > 0.0 { + (warcry_power.min(power_cap) / power_per).floor() + } else { + 0.0 + }; + // :2125 —— `EmpoweredAttacks`(主技能 cfg 求和;fixture 无来源,恒 0)。 + base_empowers += scoped_sum( + db, + spec, + cfg, + ModType::Base, + &format!("{}EmpoweredAttacks", spec.name), + ); + if base_empowers <= 0.0 { + // :2126 —— base 为 0 时 vendor 不发布 NumEmpowers(Sum 取 0)。 + return 0.0; + } + // :2127-2129。 + let extra = scoped_sum(db, spec, cfg, ModType::Base, "ExtraEmpoweredAttacks"); + let mult = scoped_more(db, spec, cfg, "ExtraEmpoweredAttacks"); + (base_empowers + extra) * mult +} + +/// `calcSkillCooldown`(CalcOffence.lua:325-348)的 warcry 取值路径。 +/// 未建模:Temporalis 冷却注入(:328/:332-337)——fixture 无来源。 +fn actual_cooldown(db: &ModDb, spec: &WarcrySpec, cfg: &CalcConfig, tick_s: f64) -> f64 { + let name = "CooldownRecovery"; + let added = scoped_sum(db, spec, cfg, ModType::Base, name); + let base = spec.cooldown_base_s + added; + let recovery = (1.0 + scoped_sum(db, spec, cfg, ModType::Inc, name) / 100.0) + * scoped_more(db, spec, cfg, name); + let cooldown = match db.override_(cfg, ModName::from(name)) { + Some(v) => v, + None => base / recovery.max(0.0), + }; + // :338-346 —— 可存多次使用时不取整到服务器帧。 + let extra_uses = scoped_sum(db, spec, cfg, ModType::Base, "AdditionalCooldownUses"); + if spec.stored_uses > 1.0 || extra_uses > 0.0 { + cooldown + } else { + (cooldown / tick_s).ceil() * tick_s + } +} + +/// `calcWarcryCastTime`(CalcOffence.lua:350-359)。 +/// 未建模:`SupportedByAutoexertion`(:355 后半)——fixture 无来源。 +fn warcry_cast_time(db: &ModDb, spec: &WarcrySpec, cfg: &CalcConfig, tick_s: f64) -> f64 { + if db.flag(cfg, ModName::from("InstantWarcry")) { + return 0.0; + } + let base = scoped_sum(db, spec, cfg, ModType::Base, "WarcryCastTime"); + if base <= 0.0 { + return 0.0; // 无 cast time 数据(防御:除零)。 + } + // 只求和 "WarcrySpeed"(:352)。「N% increased Skill Speed」文本在 parser 侧 + // 扇出成 {SkillSpeed, WarcrySpeed, TotemPlacementSpeed}(vendor ModParser.lua:770 + // 同构;extract_parser_rules 的 curated 覆盖,存量 #9 起对齐),statmap 的 + // `skill_speed_+%` 条目与 mageblood.rs 的手工扇出本就双名——三通道口径一致, + // 此处单名求和无双计。 + let speed_mod = (1.0 + scoped_sum(db, spec, cfg, ModType::Inc, "WarcrySpeed") / 100.0) + * scoped_more(db, spec, cfg, "WarcrySpeed"); + // vendor calcs.actionSpeedMod(actor):与 offence 主链同名 ActionSpeed 乘区。 + let action_names = [ModName::from(super::skill_use_time::ACTION_SPEED)]; + let action_speed = + (1.0 + db.sum(ModType::Inc, cfg, &action_names) / 100.0) * db.more(cfg, &action_names); + let rate = ((1.0 / base) * speed_mod * action_speed).min(1.0 / tick_s); + 1.0 / rate +} + +/// 单个 warcry 的 uptime(百分比 0..=100,CalcOffence.lua:3231-3237)。 +fn uptime_ratio( + db: &ModDb, + spec: &WarcrySpec, + scope_cfg: &CalcConfig, + main_cfg: &CalcConfig, + speed: f64, +) -> f64 { + if speed <= 0.0 { + return 0.0; + } + // 賦能次数按主技能 cfg 求和(vendor :2125/:3234 读 env.player.mainSkill.skillCfg / + // env.modDB);per/cap 等 skill-local 常量不带条件,两 cfg 等价。 + let empowers = total_empowers(db, spec, main_cfg); + let tick_s = main_cfg.constants.game().server_tick_seconds; + let cooldown = actual_cooldown(db, spec, scope_cfg, tick_s); + let cast_time = warcry_cast_time(db, spec, scope_cfg, tick_s); + if cooldown + cast_time <= 0.0 { + return 0.0; + } + let base_ratio = ((empowers / speed) / (cooldown + cast_time)).min(1.0) * 100.0; + // :3236 —— storedUses 意图语义(模块 doc 的 Lua 优先级说明)。 + let stored = + spec.stored_uses + scoped_sum(db, spec, scope_cfg, ModType::Base, "AdditionalCooldownUses"); + (base_ratio * stored).min(100.0) +} + +/// perform 阶段入口:主技能 hand pass 之前调用,把 uptime 缩放后的 warcry 进攻 +/// 效果注入玩家 db(vendor 在 CalcOffence 伤害段之前写 skillModList,注入后 +/// 击中与其派生 DoT(点燃)同吃该增益——smith dot 缺口 = 命中比平方的根源)。 +/// +/// 幂等:`env.warcry_gain_injected` 防重复注入(vendor 以 `InfernalActive` flag +/// 防重,CalcPerform.lua:1365)。 +pub fn apply_warcry_uptime(env: &mut Env) { + if env.warcry_skills.is_empty() || env.warcry_gain_injected { + return; + } + // vendor CalcOffence.lua:3203 `if env.mode_buffs`。 + if !env.cfg.mode_buffs { + return; + } + // :3205 —— 主技能可被赋能(NeverExertable/Triggered/OtherThingUsesSkill/ + // Retaliation 之外)。 + let excluded = [ + "NeverExertable", + "Triggered", + "OtherThingUsesSkill", + "Retaliation", + ] + .iter() + .filter_map(|n| SkillTypes::from_pob2_name(n)) + .fold(SkillTypes::NONE, |acc, t| acc | t); + if env.cfg.skill_types.intersects(excluded) { + return; + } + // 主技能 Speed(vendor globalOutput.Speed,:3235):与 hand pass 主手域逐位 + // 一致地解析(双持时 vendor 逐 pass 计算 uptime——此处取主手,见 hand_scope doc)。 + let input = MinimalInput::from(env.player.base); + let speed = match env + .hand_sources + .iter() + .find(|h| matches!(h.label, crate::HandTag::MainHand | crate::HandTag::Single)) + .or(env.hand_sources.first()) + { + Some(hand) => { + let (cfg, input) = super::hand_pass::hand_scope(hand, &env.cfg, &input); + super::offence::resolve_action_rate(&env.player.mod_db, &cfg, &input) + } + None => super::offence::resolve_action_rate(&env.player.mod_db, &env.cfg, &input), + }; + + let dbg = std::env::var("POBR_DBG_WARCRY").is_ok(); + let mut gain_mods: Vec = Vec::new(); + for spec in &env.warcry_skills { + // per-skill scope cfg(vendor skillCfg):warcry 自身类型位;flags/keyword + // 清空(warcry 非攻击/法术,主技能的武器位不外溢到冷却/喊叫速度求和)。 + let scope_cfg = env + .cfg + .clone() + .with_skill_types(spec.skill_types) + .with_flags(ModFlags::NONE) + .with_keyword_flags(KeywordFlags::NONE); + let uptime = uptime_ratio(&env.player.mod_db, spec, &scope_cfg, &env.cfg, speed); + if dbg { + let tick_s = env.cfg.constants.game().server_tick_seconds; + eprintln!( + "[POBR_DBG_WARCRY] {} empowers={} cooldown={} castTime={} speed={speed} uptime={uptime} localMods={}", + spec.skill_id, + total_empowers(&env.player.mod_db, spec, &env.cfg), + actual_cooldown(&env.player.mod_db, spec, &scope_cfg, tick_s), + warcry_cast_time(&env.player.mod_db, spec, &scope_cfg, tick_s), + spec.mods.len(), + ); + for m in &spec.mods { + eprintln!( + "[POBR_DBG_WARCRY] local {:?} {:?} {:?}", + m.name, m.mod_type, m.value + ); + } + for m in env.player.mod_db.iter_mods() { + if matches!(m.name.as_str(), "WarcrySpeed" | "SkillSpeed") && m.matches(&scope_cfg) + { + eprintln!( + "[POBR_DBG_WARCRY] db {:?} {:?} {:?} src={:?}", + m.name, m.mod_type, m.value, m.source + ); + } + } + } + + // Infernal 消费点(CalcOffence.lua:3229/:3251-3254):主技能须带 Melee。 + let gain = scoped_sum( + &env.player.mod_db, + spec, + &scope_cfg, + ModType::Base, + "InfernalExtraFireDamageMultiplier", + ); + if gain > 0.0 && env.cfg.skill_types.intersects(SkillTypes::MELEE) { + // :3253 —— `Condition:WarcryMaxHit`(config)时按满 uptime。 + let uptime_used = if env + .player + .mod_db + .flag(&env.cfg, ModName::from("Condition:WarcryMaxHit")) + || env.cfg.condition("WarcryMaxHit") + { + 100.0 + } else { + uptime + }; + if uptime_used > 0.0 { + let origin = ModifierSource::new(SourceId::new( + SourceKind::SkillGem, + format!("warcry.{}.uptime_gain_as_fire", spec.skill_id), + )) + .with_raw_text(format!( + "Uptime Scaled Infernal Cry ({gain} x {uptime_used}%)" + )); + gain_mods.push( + Modifier::number( + "DamageGainAsFire", + ModType::Base, + gain * uptime_used / 100.0, + ) + .with_flags(ModFlags::MELEE) + .with_source("Uptime Scaled Infernal Cry") + .with_origin(origin), + ); + } + } + } + env.player.mod_db.add_list(gain_mods); + env.warcry_gain_injected = true; +} + +#[cfg(test)] +mod tests { + //! smith-of-kitava oracle 钉值链(tools/pob2-oracle,2026-07-17 复跑): + //! WarcryPower 20(Boss preset)→ empowers floor(min(20,50)/10)=2; + //! cooldown 8/(1+(30-12+10)/100)=6.25 → 帧取整 6.27;castTime + //! 1/((1/0.8)×1.47×1)=0.544218;Speed 1.512 → + //! uptime (2/1.512)/6.814218=19.4116%;gain 62 → DamageGainAsFire 12.0352。 + + use super::*; + use crate::CalcConfig; + + fn smith_spec() -> WarcrySpec { + WarcrySpec { + name: "Infernal".into(), + skill_id: "InfernalCryPlayer".into(), + cooldown_base_s: 8.0, + stored_uses: 1.0, + skill_types: SkillTypes::WARCRY, + mods: vec![ + Modifier::number("WarcryCastTime", ModType::Base, 0.8), + Modifier::number("WarcryPowerPer", ModType::Base, 10.0), + Modifier::number("WarcryPowerCap", ModType::Base, 50.0), + Modifier::number("InfernalExtraFireDamageMultiplier", ModType::Base, 62.0), + // Cooldown Recovery II support 载荷。 + Modifier::number("CooldownRecovery", ModType::Inc, 30.0), + ], + } + } + + fn smith_db() -> ModDb { + let mut db = ModDb::new(); + db.add_list([ + Modifier::number("WarcryPower", ModType::Base, 20.0).with_source("Boss"), + Modifier::number("CooldownRecovery", ModType::Inc, -12.0).with_source("Quest"), + Modifier::number("CooldownRecovery", ModType::Inc, 10.0).with_source("Rune"), + // Mageblood 30 + 树上「Skill Speed」小点 17(parser 扇出成 WarcrySpeed)。 + Modifier::number("WarcrySpeed", ModType::Inc, 47.0), + ]); + db + } + + #[test] + fn smith_uptime_matches_oracle() { + let db = smith_db(); + let spec = smith_spec(); + let cfg = CalcConfig::attack(); + let tick = cfg.constants.game().server_tick_seconds; + + assert_eq!(total_empowers(&db, &spec, &cfg), 2.0); + + let cd = actual_cooldown(&db, &spec, &cfg, tick); + assert!((cd - 6.27).abs() < 1e-9, "cooldown {cd} != 6.27"); + + let ct = warcry_cast_time(&db, &spec, &cfg, tick); + assert!((ct - 0.5442176870748299).abs() < 1e-12, "castTime {ct}"); + + let uptime = uptime_ratio(&db, &spec, &cfg, &cfg, 1.512); + assert!( + (uptime - 19.41163877).abs() < 1e-6, + "uptime {uptime} != 19.41163877" + ); + let gain = 62.0 * uptime / 100.0; + assert!((gain - 12.03521604).abs() < 1e-6, "gain {gain}"); + } +} diff --git a/crates/pobr-core/src/ingest/item.rs b/crates/pobr-core/src/ingest/item.rs index 3bd8a648..f8e8a55f 100644 --- a/crates/pobr-core/src/ingest/item.rs +++ b/crates/pobr-core/src/ingest/item.rs @@ -162,6 +162,40 @@ fn ingest_section( Ok(()) } +/// 武器件上的「转局部」词条:无 flag 的 `CriticalStrikeMultiplier`(vendor +/// `CritMultiplier`)加 `Condition:{Main,Off}HandAttack` tag,使其只作用于 +/// **用该武器攻击**的 hand pass(非武器攻击如 Shield Wall / 法术不吃)。 +/// +/// 对照 vendor `Item.lua:1954-1961`("Convert accuracy, crit damage bonus, … +/// to local"):0.22.0(0.5.4b)把 `CritMultiplier and mod.flags == 0` 加进 +/// 转换清单。守卫与 vendor 逐条对应:`mod.flags == 0`、 +/// `keywordFlags == 0 or KeywordFlag.Attack`、`not mod[1]`(无既有 tag)。 +/// +/// 仅由编排层对**武器**件调用(Weapon2 的盾/箭袋/法器不转换——vendor 该转换在 +/// `self.base.weapon` 分支内)。 +/// +/// ponytail: vendor 同清单还有 Accuracy/ImpaleChance/OnHit/leech 的转换 +/// (0.22.0 之前就有、PoBR 未建模的存量项);此处只落地 0.5.4b 增量 +/// CritMultiplier,其余待各自 oracle 钉值后按同一入口补。 +pub fn apply_weapon_hand_conditions(modifiers: &mut [Modifier], slot: EquipmentSlot) { + let var = match slot { + EquipmentSlot::Weapon1 => "MainHandAttack", + EquipmentSlot::Weapon2 => "OffHandAttack", + _ => return, + }; + for m in modifiers { + let keyword_ok = + m.keyword_flags == KeywordFlags::NONE || m.keyword_flags == KeywordFlags::ATTACK; + if m.name == ModName::from("CriticalStrikeMultiplier") + && m.flags == ModFlags::NONE + && keyword_ok + && m.tags.is_empty() + { + m.tags.push(ModTag::condition(var, false)); + } + } +} + /// 把物品词条 Multiplier tag 里的 `{SlotName}` 占位符替换为本件槽位 ID。 /// /// PoB2 在合并物品 mod 时按所在槽展开 `{SlotName}`(`calcLib.mod`)。典型来源 diff --git a/crates/pobr-core/src/ingest/item_text.rs b/crates/pobr-core/src/ingest/item_text.rs index b6f66589..d2eed987 100644 --- a/crates/pobr-core/src/ingest/item_text.rs +++ b/crates/pobr-core/src/ingest/item_text.rs @@ -108,6 +108,7 @@ pub fn parse_item_text(raw: &str) -> Result { let mut rolled_defence = RolledDefence::default(); // 后续段:先扫描元数据(Quality / Implicits 头 / 防御底值),再按行归类词条。 + let mut corrupted = false; for section in §ions[1..] { let mut mod_lines: Vec<&str> = Vec::new(); @@ -119,7 +120,10 @@ pub fn parse_item_text(raw: &str) -> Result { } else if accumulate_rolled_defence(line, &mut rolled_defence) { // 已掷出防御底值行:记入 rolled_defence,不计入词条。 } else if is_metadata_line(line) { - // 元数据行不计入词条。 + // 元数据行不计入词条;`Corrupted` 标记行落 corrupted 状态。 + if line.trim() == "Corrupted" { + corrupted = true; + } } else { mod_lines.push(line); } @@ -138,6 +142,7 @@ pub fn parse_item_text(raw: &str) -> Result { base, rarity, quality, + corrupted, implicit_texts, modifier_texts, enchant_texts, @@ -203,6 +208,7 @@ pub fn parse_pob_xml_item(raw: &str) -> Result { let mut quality = 0u8; let mut implicit_count = 0usize; let mut rolled_defence = RolledDefence::default(); + let mut corrupted = false; let mut mod_lines: Vec<&str> = Vec::new(); for &line in &lines[idx..] { if let Some(value) = quality_from_line(line) { @@ -212,7 +218,10 @@ pub fn parse_pob_xml_item(raw: &str) -> Result { } else if accumulate_rolled_defence(line, &mut rolled_defence) { // 已掷出防御底值行:记入 rolled_defence,不计入词条。 } else if is_xml_metadata_line(line) { - // 元数据行不计入词条。 + // 元数据行不计入词条;`Corrupted` 标记行落 corrupted 状态。 + if line == "Corrupted" { + corrupted = true; + } } else { mod_lines.push(line); } @@ -233,6 +242,7 @@ pub fn parse_pob_xml_item(raw: &str) -> Result { base, rarity, quality, + corrupted, implicit_texts, modifier_texts, enchant_texts, diff --git a/crates/pobr-core/src/lib.rs b/crates/pobr-core/src/lib.rs index 1e23204e..922c22ee 100644 --- a/crates/pobr-core/src/lib.rs +++ b/crates/pobr-core/src/lib.rs @@ -56,7 +56,9 @@ pub use attribute::trace::{ pub use display_catalog::{display_catalog, extract_display_values}; pub use ingest::campaign::{CampaignProgress, CampaignReward, CampaignState}; pub use ingest::character::CharacterBase; -pub use ingest::item::{ItemIngest, ItemModSection, ingest_item_with_ctx}; +pub use ingest::item::{ + ItemIngest, ItemModSection, apply_weapon_hand_conditions, ingest_item_with_ctx, +}; pub use ingest::item_text::{ItemTextError, parse_item_text, parse_pob_xml_item}; pub use ingest::passive::{AllocatedNode, PassiveIngest, ingest_passive_nodes_with_ctx}; pub use ingest::skill_source::{ diff --git a/crates/pobr-core/src/model/modifier.rs b/crates/pobr-core/src/model/modifier.rs index 901ce8e9..b0b464bf 100644 --- a/crates/pobr-core/src/model/modifier.rs +++ b/crates/pobr-core/src/model/modifier.rs @@ -213,6 +213,12 @@ pub enum ModTag { }, DamageType(DamageType), SkillTypes(SkillTypes), + /// 反选技能类型限定(vendor `SkillType` tag 的 `neg = true` 形态, + /// ModStore.lua:829-833:`match = skillTypes[tag.skillType]; if tag.neg then + /// match = not match`):任一位命中即**不**生效。独立变体而非在 + /// [`ModTag::SkillTypes`] 上加字段——后者的 Debug 形被预编译缓存 + /// (`parsed_mods.json`)逐字节钉定,改形状会伪失效全部既有条目。 + SkillTypesNeg(SkillTypes), /// 具名技能限定(PoB2 `SkillName` tag,ModStore.lua:752-780):mod 仅在 /// 主技能名命中列表任一项时生效。vendor `skillName` 单名与 `skillNameList` /// 列表统一收编为 `names`;两侧均按小写等值比较(vendor `:lower()` 双向)。 @@ -417,6 +423,9 @@ impl Modifier { ModTag::SkillTypes(skill_types) => { skill_types.is_empty() || skill_types.intersects(cfg.skill_types) } + // 反选:位集命中 cfg 即失配(vendor neg 反转;空位集 → 恒生效, + // 与 vendor `skillTypes[nil]=false → not false` 一致)。 + ModTag::SkillTypesNeg(skill_types) => !skill_types.intersects(cfg.skill_types), // 具名技能限定(vendor ModStore.lua:752-780):主技能名任一命中; // cfg 无主技能名 → 不匹配(保守)。 ModTag::SkillName { names } => cfg @@ -469,9 +478,17 @@ impl Modifier { // 取数源按 actor 维度切换(PoB2 ModStore.lua:347-353 `tag.actor` → // getActor(self, ...).modDB):None=当前 cfg.multiplier;Some= // actor_multipliers 快照(缺键=0,保守等价 PoB2 actor 缺位不生效)。 - let base = match actor { - None => cfg.multiplier(var), - Some(actor) => cfg.actor_multiplier(*actor, var), + // `|` 连接的复合 var(vendor PerStat `statList` 归一产物,见 + // mod_parser template):各分量取数求和后再 ÷div(vendor + // ModStore.lua:445-452 对 statList 逐项 GetStat 累加)。 + let lookup = |v: &str| match actor { + None => cfg.multiplier(v), + Some(actor) => cfg.actor_multiplier(*actor, v), + }; + let base = if var.contains('|') { + var.split('|').map(&lookup).sum() + } else { + lookup(var) }; // PoB2 ModStore.lua EvalMod(Multiplier L365 / PerStat L460): // `mult = m_floor(base / (tag.div or 1) + 0.0001)` —— 资源数除以 div 后向下取整 @@ -556,6 +573,7 @@ impl Modifier { | ModTag::GlobalLimit { .. } | ModTag::DamageType(_) | ModTag::SkillTypes(_) + | ModTag::SkillTypesNeg(_) | ModTag::SkillName { .. } | ModTag::SlotName(_) => {} } diff --git a/crates/pobr-core/src/parse/mod_parser/canonical.rs b/crates/pobr-core/src/parse/mod_parser/canonical.rs index a454b4a9..7e98c357 100644 --- a/crates/pobr-core/src/parse/mod_parser/canonical.rs +++ b/crates/pobr-core/src/parse/mod_parser/canonical.rs @@ -133,6 +133,15 @@ fn canonical_tag(tag: &ModTag) -> String { format!("SkillTypes({})", hex.join(",")) } } + ModTag::SkillTypesNeg(st) => { + let w = st.words(); + if w[1..].iter().all(|&x| x == 0) { + format!("SkillTypesNeg({:#x})", w[0]) + } else { + let hex: Vec = w.iter().map(|x| format!("{x:#x}")).collect(); + format!("SkillTypesNeg({})", hex.join(",")) + } + } ModTag::SkillName { names } => format!("SkillName(names=[{}])", names.join(",")), ModTag::SlotName(s) => format!("SlotName({s})"), ModTag::DistanceRamp { ramp } => { diff --git a/crates/pobr-core/src/parse/mod_parser/template.rs b/crates/pobr-core/src/parse/mod_parser/template.rs index 4c98b56b..56e1ae92 100644 --- a/crates/pobr-core/src/parse/mod_parser/template.rs +++ b/crates/pobr-core/src/parse/mod_parser/template.rs @@ -264,12 +264,32 @@ pub fn compile_tag(tag: &TagTemplate, captures: &[String]) -> Option { // M6.3 归一(C2):vendor `PerStat{stat,div,limit}` ↔ PoBR `Multiplier // {var=stat,div,limit}` 字段一一对应(计算侧 effective_number 只识别 // Multiplier;legacy 也统一产 Multiplier)。归一为 Multiplier。 - let stat = f - .get("stat") - .or_else(|| f.get("var")) - .and_then(|v| field_text(v, captures))?; - let stat = normalize_perstat_slot_suffix(&stat); - let stat = normalize_attribute_var(&stat); + // + // vendor `statList = {A, B, …}`(如 `per 75 armour and evasion on + // equipped shield` → {ArmourOnWeapon 2, EvasionOnWeapon 2}, + // ModParser.lua:1631):mult = floor(Σstats/div)——多 stat 求和后再 + // 除。归一为 `|` 连接的复合 var,取数端(effective_number Multiplier + // 分支)按 `|` 拆分求和,语义与 vendor ModStore.lua:445-452 一致。 + let stat = if let Some(StatMapValue::List(items)) = f.get("statList") { + let parts: Vec = items + .iter() + .map(|v| field_text(v, captures)) + .collect::>()?; + if parts.is_empty() { + return None; + } + parts + .into_iter() + .map(|p| normalize_attribute_var(&normalize_perstat_slot_suffix(&p))) + .collect::>() + .join("|") + } else { + let stat = f + .get("stat") + .or_else(|| f.get("var")) + .and_then(|v| field_text(v, captures))?; + normalize_attribute_var(&normalize_perstat_slot_suffix(&stat)) + }; let div = f .get("div") .and_then(|v| field_number(v, captures)) diff --git a/crates/pobr-core/src/rules/special_mod.rs b/crates/pobr-core/src/rules/special_mod.rs index 82e890a0..45ad2a17 100644 --- a/crates/pobr-core/src/rules/special_mod.rs +++ b/crates/pobr-core/src/rules/special_mod.rs @@ -663,6 +663,25 @@ fn compile_tag(tag: &TemplateTagDef) -> Option { upper, }) } + "DistanceRamp" => { + // 距离插值(vendor ModStore.lua:574-590)。TemplateScalarDef 无嵌套 + // 数组形态,ramp 点列以 `"距离 倍率"` 文本对转录(如 `["35 0.2", + // "70 0"]` = vendor `{ {35,0.2}, {70,0} }`);语义与 statmap 引擎的 + // DistanceRamp 分支一致(求值期按 `cfg.skill_distance` 线性插值)。 + let TemplateScalarDef::TextList(points) = tag.fields.get("ramp")? else { + return None; + }; + let mut ramp = Vec::with_capacity(points.len()); + for point in points { + let mut parts = point.split_whitespace(); + let (Some(dist), Some(mult), None) = (parts.next(), parts.next(), parts.next()) + else { + return None; + }; + ramp.push((dist.parse().ok()?, mult.parse().ok()?)); + } + (!ramp.is_empty()).then_some(ModTag::DistanceRamp { ramp }) + } // 未映射 tag 形态:保守跳过。 _ => None, } @@ -1415,16 +1434,30 @@ mod tests { } /// 真实仓库数据全量编译成功(闸门冒烟,正式断言在 special_mods_gate.rs)。 + /// special_mods 分两层:版本无关策展层 `data/overlay-common/`(P1-3)+ 版本层 + /// `data//overlay/`。这里读同一并集拼接后编译(pobr-core 不依赖 pobr-gamedata, + /// 故直读文件而非走 loader)。 #[test] fn repo_special_mods_compile() { - let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) - .join("../../data") - .join(pobr_data::data_version()) - .join("overlay/special_mods.json"); - let raw = std::fs::read_to_string(path).expect("special_mods.json 可读"); - let doc: SpecialModsDef = serde_json::from_str(&raw).expect("special_mods.json 可解析"); - let rules = SpecialModRules::compile(&doc.entries, &HandlerRegistry::new()) + let data_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../data"); + let mut entries = Vec::new(); + for path in [ + data_root.join("overlay-common/special_mods.json"), + data_root + .join(pobr_data::data_version()) + .join("overlay/special_mods.json"), + ] { + let raw = match std::fs::read_to_string(&path) { + Ok(raw) => raw, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => continue, + Err(e) => panic!("{}: {e}", path.display()), + }; + let doc: SpecialModsDef = serde_json::from_str(&raw).expect("special_mods.json 可解析"); + entries.extend(doc.entries); + } + assert!(!entries.is_empty(), "special_mods 两层皆空?"); + let rules = SpecialModRules::compile(&entries, &HandlerRegistry::new()) .expect("仓库 special_mods 全量编译成功"); - assert_eq!(rules.len(), doc.entries.len()); + assert_eq!(rules.len(), entries.len()); } } diff --git a/crates/pobr-core/src/rules/stat_map_engine.rs b/crates/pobr-core/src/rules/stat_map_engine.rs index 56e53335..e79d7e2c 100644 --- a/crates/pobr-core/src/rules/stat_map_engine.rs +++ b/crates/pobr-core/src/rules/stat_map_engine.rs @@ -430,6 +430,57 @@ pub fn has_curse_payload( .is_some_and(|entry| entry.mods.iter().any(is_curse_effect)) } +/// (存量 #7-1)curse 技能的**技能局部效果乘区**取数:stat 若映射为 +/// **无 GlobalEffect tag** 的 `CurseEffect` INC/MORE(留在 skillModList 的 +/// 技能局部 mod——vendor curse 乘区 CalcPerform.lua:2423/:2427 读 +/// `skillModList:Sum/More(skillCfg, "CurseEffect")`),返回其 +/// `(inc 增量, more 因子)`。典型来源 = curse 宝石自身品质 `curse_effect_+%` +/// (EW 0.5/q)、组内 Heightened Curse support(constantStats +25)、 +/// Atziri's Allure lineage(`support_atziri_curse_effect_+%_final` MORE -20)。 +/// +/// 保守口径:仅 kind=="mod"、无 tag、无 flag 的裸 `CurseEffect` 计入 +/// (Mark 门控变体带 SkillType tag,不计——mark 域另行建模时再放开); +/// 其余 stat / 形态返回 `(0.0, 1.0)`(零贡献,不误算)。 +pub fn curse_local_effect( + catalog: &StatMapCatalog, + effect_id: &str, + set_key: Option<&str>, + stat: &str, + stat_value: f64, +) -> (f64, f64) { + let (mut inc, mut more) = (0.0, 1.0); + let Some(entry) = catalog.lookup(effect_id, set_key, stat) else { + return (inc, more); + }; + if entry.unextractable { + return (inc, more); + } + let params = MergeParams { + div: entry.div, + mult: entry.mult, + base: entry.base, + value: entry.value, + }; + for element in &entry.mods { + if element.kind != "mod" + || element.name.as_deref() != Some("CurseEffect") + || !element.tags.is_empty() + || !element.flags.is_empty() + || !element.keyword_flags.is_empty() + || element.scalar.is_some() + { + continue; + } + let merged = params.merge(stat_value); + match element.mod_type.as_deref() { + Some("INC") => inc += merged, + Some("MORE") => more *= 1.0 + merged / 100.0, + _ => {} + } + } + (inc, more) +} + /// 元素是否为**曝光施加能力**载荷(M4-m,宿主探测用、非取数):vendor /// `flag("InflictExposure", …)`(SkillStatMap.lua:1692-1715 各 on_shock / /// on_cold_crit / on_ignite / on_hit 形)或 `ExposureChance BASE` @@ -731,11 +782,53 @@ fn translate_player_buff_mod_name(name: &str) -> Result, Unsup "FireDamage" => Ok(vec!["FireDamage"]), "ColdDamage" => Ok(vec!["ColdDamage"]), "LightningDamage" => Ok(vec!["LightningDamage"]), + // Refraction I/II support(`sup_str.lua:5984/6023` Refractive Plating buff, + // `support_tempered_valour_deflection_rating_%_of_evasion_rating` → BASE 20): + // 消费方 = `calc::defence_panels::calc_deflection`(CalcDefence.lua:1516 + // `Evasion × ΣBASE EvasionGainAsDeflection / 100`)。 + "EvasionGainAsDeflection" => Ok(vec!["EvasionGainAsDeflection"]), + // 同 buff 的 `support_tempered_valour_%_armour_to_apply_to_elemental_damage` + // → ArmourAppliesToDamageTaken BASE 30(Refraction II)。消费方 = + // `calc::taken::armour_applies_pct`(vendor CalcDefence.lua:2361-2368 + // `percentOfArmourApplies` → `effectiveAppliedArmour`,进 per-type + // DamageReduction / MaximumHit / EHP)。tag 形态与 deflection 载荷同 + // (GlobalEffect + MultiplierThreshold RefractionMinimumValour 静态折 0)。 + "ArmourAppliesToFireDamageTaken" => Ok(vec!["ArmourAppliesToFireDamageTaken"]), + "ArmourAppliesToColdDamageTaken" => Ok(vec!["ArmourAppliesToColdDamageTaken"]), + "ArmourAppliesToLightningDamageTaken" => Ok(vec!["ArmourAppliesToLightningDamageTaken"]), // Sigil of Power `circle_of_power_max_stages` → 玩家 `Multiplier: // SigilOfPowerMaxStages` BASE(vendor 消费点 = GetMultiplier 动态上限 // ModStore.lua:369;PoBR 编排层把 buff 载荷中 `Multiplier:` BASE 桥进 // cfg.multipliers,见 calc_orchestrator buff specs 注入点)。 "Multiplier:SigilOfPowerMaxStages" => Ok(vec!["Multiplier:SigilOfPowerMaxStages"]), + // (0.5.4b #5)Blazing Critical support(sup_int.lua:959):0.22.0 给 + // `support_blazing_crits_gain_%_fire_damage_with_attacks_on_critical_hit` + // 补上 GlobalEffect/Buff tag——15% `DamageGainAsFire` BASE(ModFlag.Attack + // + Condition:CritRecently)从「只挂在被支援技能上的死词条」变成全局玩家 + // buff("imbue all of your Attacks")。消费方 = `calc::damage` gain-as + // 矩阵(buildGainTable,`DamageGainAs` BASE 查询);点燃火源随之 + // 平方级放大(chance ∝ fire/threshold,magnitude ∝ fire)。 + "DamageGainAsFire" => Ok(vec!["DamageGainAsFire"]), + // (存量 #7-1)Archmage(act_int.lua:229-231):`archmage_all_damage_%_to_ + // gain_as_lightning_to_grant_to_non_channelling_spells_per_100_max_mana` + // → `DamageGainAsLightning` BASE 4(GlobalEffect/Buff + SkillType + // Channel neg + SkillType Spell + PerStat Mana div 100)。消费方与 + // DamageGainAsFire 同 = `calc::damage` gain-as 矩阵;Mana 分母由编排层 + // `inject_per_x_multipliers` 预灌(cfg.multipliers["Mana"] = 全管线池值)。 + // monk-invoker-frost-bomb TotalDPS 0.66x 根因(缺 80% 闪电 gain-as)。 + "DamageGainAsLightning" => Ok(vec!["DamageGainAsLightning"]), + // (#10-2)Barrage buff(BarragePlayer `empower_barrage_*`,act_dex.lua: + // 216-224):`BarrageRepeats` BASE / `BarrageRepeatDamage` MORE。消费方 = + // `calc::scaled_damage::dps_end_factors` 的 Barrage repeats DPS 乘区 + // (vendor CalcOffence.lua:962-976,Barrageable + SequentialProjectiles 门控)。 + "BarrageRepeats" => Ok(vec!["BarrageRepeats"]), + "BarrageRepeatDamage" => Ok(vec!["BarrageRepeatDamage"]), + // (#12 companion allies 层)Loyalty support(SupportLoyaltyPlayer)的 + // `companion_takes_%_damage_before_you_from_support` → BASE 10(GlobalEffect + // /Buff/unscalable,SkillStatMap.lua:2559-2561)。消费方 = perform 的 + // `inject_companion_life` 门控 + `pool_setup::build_pool_state` companion + // 先扣层(CalcDefence.lua:2961-2965 / :3656-3663)。 + "TakenFromCompanionBeforeYou" => Ok(vec!["TakenFromCompanionBeforeYou"]), other => Err(UnsupportedReason::UnknownModName(other.to_string())), } } @@ -796,7 +889,9 @@ fn collect_player_buff_flag( items: &mut Vec, ) -> Result<(), UnsupportedReason> { let name = element.name.as_deref().unwrap_or("?"); - if !is_cross_type_ailment_flag(name) { + // `SequentialProjectiles`(Barrage buff,act_dex.lua:219):消费方 = + // `dps_end_factors` 的 Barrage repeats 门控(vendor CalcOffence.lua:962)。 + if !is_cross_type_ailment_flag(name) && name != "SequentialProjectiles" { return Err(UnsupportedReason::UnknownModName(format!("flag:{name}"))); } if !element.flags.is_empty() { @@ -919,6 +1014,92 @@ fn collect_player_buff_mod( Ok(()) } +// ---- #12:minion 域(MinionModifier LIST 载荷 → 召唤物内层 mod) ---- + +/// 把一条 support/skill stat 经 statmap 翻译为**召唤物侧**内层 modifier 列表 +/// (`MinionModifierEntry.inner` 载荷;消费方 = 编排层 spawn_minions → +/// `build_minion_context` 通道 1)。 +/// +/// vendor 语义:statmap 的 `mod("MinionModifier","LIST",{ mod = mod() })` +/// 随 support 并入被支援技能 skillModList(CalcActiveSkill.lua merge 循环), +/// `addMinionModifiers`(CalcPerform.lua:1668-1686)再把内层 mod 注入**该技能的** +/// 召唤物 modDB——作用域是组内被支援技能的 minion,不是全局。典型 = Loyalty +/// support `support_trusty_companion_minion_life_+%_final` → Life MORE −30 +/// (wolf-pack 伴侣生命 3231 × 0.7 = 2262 的 MORE 因子,oracle 钉值)。 +/// +/// 第一批允收内层 = `Life`(BASE/INC/MORE;vendor 名 `Life` 归一到 PoBR 生命池 +/// 聚合名 `MaximumLife`,与 buff 域 [`translate_player_buff_mod_name`] 同口径)。 +/// 其余内层(伤害/速度族)暂不准入——minion DPS 不在 parity 面板,宁可跳过不可 +/// 错算。保守门控:外层带 flags/keyword_flags/tags/scalar、内层含 +/// kind/mod_type/name 之外的键的条目整条跳过(返回空,不上报——窄通道, +/// 未准入形态无消费方)。 +pub fn map_minion_life_stat( + catalog: &StatMapCatalog, + effect_id: &str, + set_key: Option<&str>, + stat: &str, + stat_value: f64, +) -> Vec { + let Some(entry) = catalog.lookup(effect_id, set_key, stat) else { + return Vec::new(); + }; + if entry.unextractable { + return Vec::new(); + } + let params = MergeParams { + div: entry.div, + mult: entry.mult, + base: entry.base, + value: entry.value, + }; + let mut out = Vec::new(); + for element in &entry.mods { + if element.kind != "mod" + || element.name.as_deref() != Some("MinionModifier") + || element.mod_type.as_deref() != Some("LIST") + || !element.flags.is_empty() + || !element.keyword_flags.is_empty() + || !element.tags.is_empty() + || element.scalar.is_some() + { + continue; + } + let Some(StatMapValue::Table(wrapper)) = &element.value else { + continue; + }; + let Some(StatMapValue::Table(inner)) = wrapper.get("mod") else { + continue; + }; + // 内层只接受 `{ kind:"mod", mod_type, name:"Life" }` 的裸形态 + // (带 tags/flags 的内层 = 额外门控语义,跳过)。 + if wrapper.len() != 1 + || inner + .keys() + .any(|k| !matches!(k.as_str(), "kind" | "mod_type" | "name")) + { + continue; + } + if !matches!(inner.get("name"), Some(StatMapValue::Text(n)) if n == "Life") { + continue; + } + let mod_type = match inner.get("mod_type") { + Some(StatMapValue::Text(t)) => match t.as_str() { + "BASE" => ModType::Base, + "INC" => ModType::Inc, + "MORE" => ModType::More, + _ => continue, + }, + _ => continue, + }; + out.push(Modifier::number( + "MaximumLife", + mod_type, + params.merge(stat_value), + )); + } + out +} + // ---- M4-L:debuff 域(GlobalEffect effectType=Debuff)敌侧映射 ---- /// 元素是否为**敌侧 debuff 载荷**(vendor `GlobalEffect` tag 且 @@ -1643,6 +1824,15 @@ pub fn translate_mod_name( // 消费方 = `calc::ailment::ailment_rate_mod`(CalcOffence.lua:5036 rateMod, // calcLib.mod 的 INC+MORE 两腿同名集)。 "BleedFaster" | "PoisonFaster" | "IgniteFaster" => base_name.to_string(), + // 存量 #9:warcry uptime 机器直通族(vendor `warcry_empowers_per_X_monster_power[_mp_cap]` + // → WarcryPowerPer/Cap(SkillStatMap.lua:608-613)、Infernal Cry per-set + // `infernal_cry_exerted_attack_all_damage_%_to_gain_as_fire_%` → + // InfernalExtraFireDamageMultiplier(act_str.lua:7729-7731))。消费方 = + // `calc::warcry`(賦能次数 CalcPerform.lua:2121-2123 + uptime 缩放的 + // DamageGainAsFire 注入 CalcOffence.lua:3251-3254)。 + "WarcryPowerPer" | "WarcryPowerCap" | "InfernalExtraFireDamageMultiplier" => { + base_name.to_string() + } // M4-K:异常持续时间——vendor 施加方词条名带 Enemy 前缀(作用于敌身上的 // debuff 时长,CalcOffence.lua:5037 durationMod 取 // `EnemyDuration`/`EnemyAilmentDuration`/`DamagingAilmentDuration`), @@ -1782,8 +1972,49 @@ pub fn translate_tag(tag: &BTreeMap) -> Result { + if !keys_subset_of(&["type", "var", "threshold", "thresholdVar", "upper"]) { + return Err(UnsupportedReason::UnsupportedTag(format!( + "MultiplierThreshold 含约定外键:{:?}", + tag.keys().collect::>() + ))); + } + let Some(var) = text("var") else { + return Err(UnsupportedReason::UnsupportedTag( + "MultiplierThreshold 缺 var".into(), + )); + }; + let threshold = match (number("threshold"), text("thresholdVar")) { + (Some(t), None) => t, + // Refraction I/II `RefractionMinimumValour`(sup_str.lua:5978-6024): + // 全 vendor 树无任何 setter → 恒 0(ValourStacks ≥ 0 恒过 gate, + // 与 vendor 默认配置行为一致)。 + (None, Some(v)) if v == "RefractionMinimumValour" => 0.0, + (None, Some(v)) => { + return Err(UnsupportedReason::UnsupportedTag(format!( + "MultiplierThreshold thresholdVar 非零 setter 未核实:{v}" + ))); + } + _ => { + return Err(UnsupportedReason::UnsupportedTag( + "MultiplierThreshold 缺 threshold".into(), + )); + } + }; + Ok(ModTag::MultiplierThreshold { + var, + threshold, + upper: matches!(tag.get("upper"), Some(StatMapValue::Bool(true))), + }) + } "PerStat" => { - if !keys_subset_of(&["type", "stat", "div"]) { + if !keys_subset_of(&["type", "stat", "div", "limit", "limitTotal"]) { return Err(UnsupportedReason::UnsupportedTag(format!( "PerStat 含约定外键:{:?}", tag.keys().collect::>() @@ -1800,31 +2031,43 @@ pub fn translate_tag(tag: &BTreeMap) -> Result "Intelligence".to_string(), other => other.to_string(), }; - Ok(ModTag::multiplier(var, number("div").unwrap_or(1.0), None)) + // limit / limitTotal(vendor ModStore.lua:461-468 + :402-404;如 Atalui's + // Bloodletting `PerStat{stat=LifeCost,div=20,limit=40,limitTotal}`—— + // per 20 life cost 至多 +40% 总量封顶)。 + let mut mtag = ModTag::multiplier(var, number("div").unwrap_or(1.0), number("limit")); + if let (ModTag::Multiplier { limit_total, .. }, Some(StatMapValue::Bool(true))) = + (&mut mtag, tag.get("limitTotal")) + { + *limit_total = true; + } + Ok(mtag) } - // 技能类型限定(vendor `{ type = "SkillType", skillType = SkillType.X }`, - // 如 Garukhan `attacks_roll_crits_twice` 的 Attack 限定)→ - // [`ModTag::SkillTypes`](`Modifier::matches` 按 `cfg.skill_types` - // intersects 判定)。第一批仅 Attack/Spell(编排层 `skill_type_bits` - // 当前只填这两个判别位——其余类型位未注入 cfg,盲翻会让 mod 恒不生效, - // 维持 Unsupported 整条跳过)。`neg` 变体同样不支持。 + // 技能类型限定(vendor `{ type = "SkillType", skillType = SkillType.X, + // [neg = true] }`,如 Garukhan `attacks_roll_crits_twice` 的 Attack 限定、 + // Archmage buff 的「non-channelling Spells」= Channel neg + Spell)→ + // [`ModTag::SkillTypes`] / [`ModTag::SkillTypesNeg`](`Modifier::matches` + // 按 `cfg.skill_types` intersects / 反选判定)。类型名走单源 + // `SkillTypes::from_pob2_name`(A1 全量 290 枚举表)——编排层 + // `skill_type_bits` 已全量置位(conditions.rs),限 Attack/Spell 的 + // 旧白名单口径已过时。枚举外名维持 Unsupported。 "SkillType" => { - if !keys_subset_of(&["type", "skillType"]) { + if !keys_subset_of(&["type", "skillType", "neg"]) { return Err(UnsupportedReason::UnsupportedTag(format!( "SkillType 含约定外键:{:?}", tag.keys().collect::>() ))); } - let bits = match text("skillType").as_deref() { - Some("Attack") => SkillTypes::ATTACK, - Some("Spell") => SkillTypes::SPELL, - other => { - return Err(UnsupportedReason::UnsupportedTag(format!( - "SkillType 未支持类型:{other:?}" - ))); - } + let name = text("skillType"); + let Some(bits) = name.as_deref().and_then(SkillTypes::from_pob2_name) else { + return Err(UnsupportedReason::UnsupportedTag(format!( + "SkillType 未支持类型:{name:?}" + ))); }; - Ok(ModTag::SkillTypes(bits)) + if matches!(tag.get("neg"), Some(StatMapValue::Bool(true))) { + Ok(ModTag::SkillTypesNeg(bits)) + } else { + Ok(ModTag::SkillTypes(bits)) + } } // 距离插值(vendor `{ type = "DistanceRamp", ramp = {{d,m},...} }`,如 Close // Combat `support_close_combat_attack_damage_+%_final_from_distance`)→ @@ -2014,7 +2257,8 @@ mod tests { assert_eq!(mods[0].value.as_number(), Some(1.0), "div=100 → 分数"); } - /// 白名单外 flag 维持未知名上报;SkillType 未支持类型整条跳过。 + /// 白名单外 flag 维持未知名上报;SkillType 枚举外类型名整条跳过 + /// (枚举内类型经 `SkillTypes::from_pob2_name` 全量准入——存量 #7-1)。 #[test] fn flag_kind_outside_whitelist_or_unknown_skill_type_unsupported() { let entry = entry_json( @@ -2027,7 +2271,7 @@ mod tests { let entry = entry_json( r#"{ "mods": [ { "kind": "flag", "name": "BifurcateCrit", "mod_type": "FLAG", - "tags": [ { "type": "SkillType", "skillType": "Minion" } ] } ] }"#, + "tags": [ { "type": "SkillType", "skillType": "NotARealSkillType" } ] } ] }"#, ); assert!(matches!( map_entry(&entry, 1.0), @@ -2035,6 +2279,27 @@ mod tests { )); } + /// (存量 #7-1)SkillType tag:枚举内类型名全量准入(单源 + /// `SkillTypes::from_pob2_name`);`neg = true` → [`ModTag::SkillTypesNeg`] + /// (vendor ModStore.lua:829-833 反选,如 Archmage 的 non-channelling 限定)。 + #[test] + fn skill_type_tag_full_enum_and_neg_translate() { + use pobr_data::skill::SkillTypes; + let mut tag = BTreeMap::new(); + tag.insert("type".into(), StatMapValue::Text("SkillType".into())); + tag.insert("skillType".into(), StatMapValue::Text("Minion".into())); + assert_eq!( + translate_tag(&tag).unwrap(), + ModTag::SkillTypes(SkillTypes::MINION) + ); + tag.insert("skillType".into(), StatMapValue::Text("Channel".into())); + tag.insert("neg".into(), StatMapValue::Bool(true)); + assert_eq!( + translate_tag(&tag).unwrap(), + ModTag::SkillTypesNeg(SkillTypes::CHANNEL) + ); + } + /// CritChanceCap 直通(Garukhan constant stat 50 → OVERRIDE)。 #[test] fn crit_chance_cap_override_passthrough() { @@ -2637,6 +2902,47 @@ mod tests { ); } + /// (存量 #7-1)curse 技能局部效果乘区取数:裸 `CurseEffect` INC/MORE 计入, + /// 带 GlobalEffect / 其他 tag 的元素与无关 stat 归零贡献。 + #[test] + fn curse_local_effect_collects_bare_curse_effect_only() { + let catalog = catalog_json( + r#"{ + "global": { + "curse_effect_+%": { "mods": [ { "kind": "mod", "name": "CurseEffect", "mod_type": "INC" } ] }, + "support_atziri_curse_effect_+%_final": { "mods": [ { "kind": "mod", "name": "CurseEffect", "mod_type": "MORE" } ] }, + "mark_effect_+%": { "mods": [ { "kind": "mod", "name": "CurseEffect", "mod_type": "INC", + "tags": [ { "type": "SkillType", "skillType": "Mark" } ] } ] } + }, + "per_stat_set": {} + }"#, + ); + assert_eq!( + curse_local_effect(&catalog, "X", None, "curse_effect_+%", 25.0), + (25.0, 1.0) + ); + assert_eq!( + curse_local_effect( + &catalog, + "X", + None, + "support_atziri_curse_effect_+%_final", + -20.0 + ), + (0.0, 0.8) + ); + // 带 tag(Mark 门控)的变体保守不计。 + assert_eq!( + curse_local_effect(&catalog, "X", None, "mark_effect_+%", 30.0), + (0.0, 1.0) + ); + // 无关 stat / 无条目 → 零贡献。 + assert_eq!( + curse_local_effect(&catalog, "X", None, "nope", 1.0), + (0.0, 1.0) + ); + } + // ---- W-J:isGlobalEffect / global-only merge ---- /// isGlobalEffect 等价(CalcActiveSkill.lua:68-80):单 mod 查自身 tags; @@ -3115,6 +3421,51 @@ mod tests { ); } + /// (#12)Loyalty 形态(per_stat_set["SupportLoyaltyPlayer"]["1"]): + /// `MinionModifier LIST { mod = Life MORE }` → 召唤物内层 `MaximumLife MORE` + /// (名归一,与 buff 域 Life→MaximumLife 同口径)。allow-list 外内层 + /// (Damage)与带 tag 的外层整条跳过(返回空)。 + #[test] + fn minion_life_stat_maps_loyalty_more_life() { + let catalog = catalog_json( + r#"{ "global": {}, "per_stat_set": { "SupportLoyaltyPlayer": { "1": { + "support_trusty_companion_minion_life_+%_final": { + "mods": [ { "kind": "mod", "name": "MinionModifier", "mod_type": "LIST", + "value": { "mod": { "kind": "mod", "mod_type": "MORE", + "name": "Life" } } } ] }, + "minion_damage_+%": { + "mods": [ { "kind": "mod", "name": "MinionModifier", "mod_type": "LIST", + "value": { "mod": { "kind": "mod", "mod_type": "INC", + "name": "Damage" } } } ] } } } } }"#, + ); + let mods = map_minion_life_stat( + &catalog, + "SupportLoyaltyPlayer", + None, + "support_trusty_companion_minion_life_+%_final", + -30.0, + ); + assert_eq!(mods.len(), 1); + assert_eq!(mods[0].name.as_str(), "MaximumLife"); + assert_eq!(mods[0].mod_type, ModType::More); + assert_eq!(mods[0].value.as_number(), Some(-30.0)); + // 内层非 Life(Damage):窄通道未准入 → 空。 + assert!( + map_minion_life_stat( + &catalog, + "SupportLoyaltyPlayer", + None, + "minion_damage_+%", + 20.0 + ) + .is_empty() + ); + // 未知 stat → 空。 + assert!( + map_minion_life_stat(&catalog, "SupportLoyaltyPlayer", None, "no_such", 1.0).is_empty() + ); + } + /// Precision II 形态(sup_dex.lua:4216-4250):`Accuracy INC` + GlobalEffect /// Buff(含 effectName 键,无门控语义)→ 玩家侧 Accuracy INC,tag 剥净。 #[test] @@ -3403,6 +3754,139 @@ mod tests { assert_eq!(m.effective_number(&cfg9), Some(68.0)); } + /// Refraction II 形态(vendor sup_str.lua:6023-6025:`support_tempered_ + /// valour_deflection_rating_%_of_evasion_rating` → `EvasionGainAsDeflection + /// BASE 20` + GlobalEffect Buff "Refractive Plating" + MultiplierThreshold + /// ValourStacks/thresholdVar=RefractionMinimumValour)→ 玩家侧 BASE, + /// threshold 静态折 0(该 var 全 vendor 树零 setter),默认 cfg 下生效。 + /// oracle 钉值(wolf-pack):tree 28 + 本载荷 20 = 48%,rating 11791.52。 + #[test] + fn player_buff_refraction_evasion_gain_as_deflection_maps() { + let catalog = catalog_json( + r#"{ "global": {}, "per_stat_set": { "SupportRefractionPlayerTwo": { "1": { + "support_tempered_valour_deflection_rating_%_of_evasion_rating": { + "mods": [ { "kind": "mod", "name": "EvasionGainAsDeflection", + "mod_type": "BASE", + "tags": [ { "type": "GlobalEffect", "effectType": "Buff", + "effectName": "Refractive Plating" }, + { "type": "MultiplierThreshold", "var": "ValourStacks", + "thresholdVar": "RefractionMinimumValour" } ] } ] } } } } }"#, + ); + let MappedOutcome::Mapped(items) = map_player_buff_stat( + &catalog, + "SupportRefractionPlayerTwo", + None, + "support_tempered_valour_deflection_rating_%_of_evasion_rating", + 20.0, + ) else { + panic!("期望 Mapped"); + }; + let MappedItem::Modifier(m) = &items[0] else { + panic!("期望 Modifier"); + }; + assert_eq!(m.name.as_str(), "EvasionGainAsDeflection"); + assert_eq!(m.mod_type, ModType::Base); + assert_eq!(m.value.as_number(), Some(20.0)); + assert_eq!( + m.tags, + vec![crate::ModTag::MultiplierThreshold { + var: "ValourStacks".into(), + threshold: 0.0, + upper: false, + }], + "thresholdVar 静态折 0,GlobalEffect 剥除" + ); + // 默认 cfg(ValourStacks 未注入 = 0):0 ≥ 0 → 生效,与 vendor 默认一致。 + assert!(m.matches(&crate::CalcConfig::new())); + } + + /// 同 buff 的护甲折算载荷(vendor sup_str.lua:6019-6021:`support_tempered_ + /// valour_%_armour_to_apply_to_elemental_damage` → ArmourAppliesTo{Fire,Cold, + /// Lightning}DamageTaken BASE 30,tag 形态与 deflection 载荷同)→ 三条玩家侧 + /// BASE,消费方 `calc::taken::armour_applies_pct`。oracle 钉值(wolf-pack): + /// tree 84 + 本载荷 30 = 114%,FireEffectiveAppliedArmour 21181.2。 + #[test] + fn player_buff_refraction_armour_applies_to_elements_maps() { + let catalog = catalog_json( + r#"{ "global": {}, "per_stat_set": { "SupportRefractionPlayerTwo": { "1": { + "support_tempered_valour_%_armour_to_apply_to_elemental_damage": { + "mods": [ { "kind": "mod", "name": "ArmourAppliesToFireDamageTaken", + "mod_type": "BASE", + "tags": [ { "type": "GlobalEffect", "effectType": "Buff", + "effectName": "Refractive Plating" }, + { "type": "MultiplierThreshold", "var": "ValourStacks", + "thresholdVar": "RefractionMinimumValour" } ] }, + { "kind": "mod", "name": "ArmourAppliesToColdDamageTaken", + "mod_type": "BASE", + "tags": [ { "type": "GlobalEffect", "effectType": "Buff", + "effectName": "Refractive Plating" }, + { "type": "MultiplierThreshold", "var": "ValourStacks", + "thresholdVar": "RefractionMinimumValour" } ] }, + { "kind": "mod", "name": "ArmourAppliesToLightningDamageTaken", + "mod_type": "BASE", + "tags": [ { "type": "GlobalEffect", "effectType": "Buff", + "effectName": "Refractive Plating" }, + { "type": "MultiplierThreshold", "var": "ValourStacks", + "thresholdVar": "RefractionMinimumValour" } ] } ] } } } } }"#, + ); + let MappedOutcome::Mapped(items) = map_player_buff_stat( + &catalog, + "SupportRefractionPlayerTwo", + None, + "support_tempered_valour_%_armour_to_apply_to_elemental_damage", + 30.0, + ) else { + panic!("期望 Mapped"); + }; + let names: Vec<&str> = items + .iter() + .map(|item| { + let MappedItem::Modifier(m) = item else { + panic!("期望 Modifier"); + }; + assert_eq!(m.mod_type, ModType::Base); + assert_eq!(m.value.as_number(), Some(30.0)); + // 默认 cfg(ValourStacks 未注入 = 0):0 ≥ 0 → 生效。 + assert!(m.matches(&crate::CalcConfig::new())); + m.name.as_str() + }) + .collect(); + assert_eq!( + names, + vec![ + "ArmourAppliesToFireDamageTaken", + "ArmourAppliesToColdDamageTaken", + "ArmourAppliesToLightningDamageTaken", + ] + ); + } + + /// MultiplierThreshold thresholdVar 有 setter(Attrition + /// `AttritionCullSeconds`,act_str.lua:1258 设 Multiplier)→ 静态折 0 会 + /// 错开 gate,维持 Unsupported 整条上报。 + #[test] + fn player_buff_threshold_var_with_setter_reported() { + let catalog = catalog_json( + r#"{ "global": {}, "per_stat_set": { "AttritionPlayer": { "1": { + "attrition_cull_payload": { + "mods": [ { "kind": "mod", "name": "EvasionGainAsDeflection", + "mod_type": "BASE", + "tags": [ { "type": "GlobalEffect", "effectType": "Buff" }, + { "type": "MultiplierThreshold", "var": "EnemyPresenceSeconds", + "thresholdVar": "AttritionCullSeconds" } ] } ] } } } } }"#, + ); + assert!(matches!( + map_player_buff_stat( + &catalog, + "AttritionPlayer", + None, + "attrition_cull_payload", + 1.0, + ), + MappedOutcome::Unsupported(UnsupportedReason::UnsupportedTag(_)) + )); + } + /// Sigil of Power 最大层数载荷(`circle_of_power_max_stages` → /// `Multiplier:SigilOfPowerMaxStages` BASE,GlobalEffect 带 unscalable /// 标记——允收通过;编排层把该 BASE 桥进 cfg.multipliers 作 limitVar 分母)。 diff --git a/crates/pobr-core/tests/defence/ehp_pob2.rs b/crates/pobr-core/tests/defence/ehp_pob2.rs index 6a65f2a1..bd6093c9 100644 --- a/crates/pobr-core/tests/defence/ehp_pob2.rs +++ b/crates/pobr-core/tests/defence/ehp_pob2.rs @@ -296,9 +296,10 @@ fn taken_hit_per_type_neutral_identity() { assert_eq!(dr, [0.0; 5]); } -/// 抗性 + 护甲减伤(:2379-2383/:2442):fire 抗 75%、物理 effArmour 2000 vs 进伤 1000 -/// → 护甲 DR = 2000/(2000+10×1000) = 16.67%(armour_ratio=10,四舍到 9 位)→ -/// 物理承受 = 1000 × (1−0.1667) = 833.33…;fire 承受 = 500 × 0.25 = 125。 +/// 抗性 + 护甲减伤(:2402-2409/:2442):fire 抗 75%、物理 effArmour 2000 vs 进伤 1000 +/// → 护甲 DR = round(2000/(2000+10×1000)×100) = round(16.67) = **17%**(vendor +/// `calcs.armourReduction` 是取整变体,Common.lua round=floor(x+0.5))→ +/// 物理承受 = 1000 × (1−0.17) = 830;fire 承受 = 500 × 0.25 = 125。 #[test] fn taken_hit_per_type_applies_resist_and_armour() { // Arrange @@ -315,9 +316,9 @@ fn taken_hit_per_type_applies_resist_and_armour() { let (taken, dr) = taken_hit_per_type(&damage, &mit); // Assert - let armour_dr = 2000.0 / (2000.0 + 10.0 * 1000.0); // 0.166666… - assert!((dr[0] - armour_dr * 100.0).abs() < 1e-6); - assert!((taken.physical - 1000.0 * (1.0 - armour_dr)).abs() < 1e-3); + let armour_dr_pct = (2000.0_f64 / (2000.0 + 10.0 * 1000.0) * 100.0).round(); // 17 + assert!((dr[0] - armour_dr_pct).abs() < 1e-6); + assert!((taken.physical - 1000.0 * (1.0 - armour_dr_pct / 100.0)).abs() < 1e-3); assert!((taken.fire - 125.0).abs() < 1e-9); } diff --git a/crates/pobr-core/tests/engine/perform_fill.rs b/crates/pobr-core/tests/engine/perform_fill.rs index dcad7e4c..a7427670 100644 --- a/crates/pobr-core/tests/engine/perform_fill.rs +++ b/crates/pobr-core/tests/engine/perform_fill.rs @@ -1287,7 +1287,15 @@ fn perform_minion_from_def_with_limit() { env.cfg = CalcConfig::attack().with_damage_type(DamageType::Physical); let def = minion_def_zombie(); - env.add_minion_from_def(&def, 20, 3, vec![], vec![], AttributeInfusion::default()); + env.add_minion_from_def( + &def, + 20, + 3, + vec![], + vec![], + AttributeInfusion::default(), + false, + ); perform(&mut env).unwrap(); // 数量上限写入玩家 multiplier。 @@ -1334,6 +1342,7 @@ fn perform_minion_damage_per_summoned_minion_uses_limit() { vec![entry], vec![], AttributeInfusion::default(), + false, ); perform(&mut env).unwrap(); env.player.output.minions[0].dps diff --git a/crates/pobr-core/tests/offence/crit.rs b/crates/pobr-core/tests/offence/crit.rs index b68d81af..cf3e4924 100644 --- a/crates/pobr-core/tests/offence/crit.rs +++ b/crates/pobr-core/tests/offence/crit.rs @@ -199,9 +199,11 @@ fn bifurcate_crit_chance_50_to_75() { approx(crit.chance, 0.75); } -/// Bifurcate 额外爆伤:两次都暴击概率 = PreBifurcate²/100,额外加权一份 extra。 +/// Bifurcate 额外爆伤:条件概率「至少一次暴击时两次都暴击」额外加权一份 extra +/// (vendor CalcOffence.lua `conditionalBifurcateChance`)。 /// base_crit=50%,extra 基础 = (100)/100 = 1.0; -/// bifurcateMultiChance = 50²/100 = 25;extra' = 1.0 + 25*1.0/100 = 1.25 → crit_mult = 2.25。 +/// bifurcateMultiChance = 50²/100 = 25;有效暴击 = 75; +/// conditional = 25/75 = 1/3;extra' = 1.0×(1+1/3) → crit_mult = 2.3333。 #[test] fn bifurcate_adds_extra_crit_multiplier() { let mut db = player_with_base_crit(50.0); @@ -210,7 +212,7 @@ fn bifurcate_adds_extra_crit_multiplier() { let cfg = CalcConfig::spell().with_mode_effective(true); let crit = resolve_crit(&db, &enemy, &cfg, 1.0, 0.0, true); - approx(crit.multiplier, 2.25); + approx(crit.multiplier, 1.0 + 1.0 + 25.0 / 75.0); } // ─────────────────────────── Inevitable ─────────────────────────── diff --git a/crates/pobr-core/tests/parser/mod_parser.rs b/crates/pobr-core/tests/parser/mod_parser.rs index b8171818..8e69a39c 100644 --- a/crates/pobr-core/tests/parser/mod_parser.rs +++ b/crates/pobr-core/tests/parser/mod_parser.rs @@ -249,13 +249,14 @@ fn strips_pob_bracket_markup() { assert_eq!(o.mods[0].name, ModName::from("ElementalDamage")); // `any attribute`(属性小点三选一)不展开——玩家选择经 AttributeOverride 在树 - // 收集阶段改写为具体属性后再解析。4.5.4.3 vendor specialModList 起,原文 - // `to any attribute` 被 vendor 规则整行识别为「无贡献」(空 mods),与旧引擎 - // 「留残 → 生产闸门整行丢弃」净效果一致:未选中节点绝不产出任何具体属性 mod。 + // 收集阶段改写为具体属性后再解析。「无净贡献」的具体形态随数据版本变:旧规则 + // 留残(生产闸门整行丢弃),4.5.4.3 vendor 规则整行识别为空 mods。两者净效果 + // 一致,故只断言版本无关不变式:要么零 mod,要么留残,绝不产出具体属性 mod。 let o = parse_mod("+5 to any [Attributes|Attribute]").unwrap(); assert!( - o.mods.is_empty(), - "any attribute 原文不产出任何 mod(选择在树收集阶段改写)" + o.mods.is_empty() || o.unparsed.is_some(), + "any attribute 原文不得产出净贡献(零 mod 或留残丢弃):{:?}", + o.mods ); for attr in ["Strength", "Dexterity", "Intelligence"] { assert!( diff --git a/crates/pobr-core/tests/parser/special_mods_gate.rs b/crates/pobr-core/tests/parser/special_mods_gate.rs index f716ec52..f38224bb 100644 --- a/crates/pobr-core/tests/parser/special_mods_gate.rs +++ b/crates/pobr-core/tests/parser/special_mods_gate.rs @@ -1,7 +1,7 @@ //! special_mods 闸门测试(M5b 蓝图 C-4,§0.3 监控线落成 CI 原生门禁)。 //! -//! 读仓库 `data/4.5.0.3.4/{overlay/special_mods.json, generated/special_derived.json}`, -//! 断言: +//! 读仓库 `data/overlay-common/special_mods.json`(版本无关策展层,P1-3)+ +//! `data//{overlay/special_mods.json, generated/special_derived.json}`,断言: //! 1. [`SpecialModRules::compile`] 全量成功(pattern 合法 / mod_type 已知 / //! enums 引用不越界 / id 唯一); //! 2. 所有 `handler_id` 均已注册(未注册 = 测试失败 + 打印未映射清单, @@ -18,6 +18,11 @@ use std::collections::BTreeMap; use pobr_core::rules::{HandlerRegistry, SpecialModRules}; use pobr_data::catalog::parser_rules::{SpecialModsDef, SpecialTemplateDef}; +fn overlay_common_special_mods_path() -> std::path::PathBuf { + std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../data") + .join("overlay-common/special_mods.json") +} fn special_mods_path() -> std::path::PathBuf { std::path::Path::new(env!("CARGO_MANIFEST_DIR")) .join("../../data") @@ -37,12 +42,24 @@ fn special_vendor_path() -> std::path::PathBuf { .join("generated/special_vendor.json") } -/// 加载仓库 special 条目(overlay + 可选 generated 派生/vendor 批量,拼接——与 -/// pobr-gamedata `load_ruleset` 三源同序)。 +/// 加载仓库 special 条目(overlay-common 版本无关层 + 版本 overlay + 可选 generated +/// 派生/vendor 批量,拼接——与 pobr-gamedata `load_ruleset` 同序)。overlay-common 层 +/// (P1-3)按 id 打底,版本层覆盖 / 追加。 fn load_entries() -> Vec { + let mut entries: Vec = Vec::new(); + if let Ok(raw) = std::fs::read_to_string(overlay_common_special_mods_path()) { + let doc: SpecialModsDef = + serde_json::from_str(&raw).expect("overlay-common/special_mods.json 可解析"); + entries = doc.entries; + } let raw = std::fs::read_to_string(special_mods_path()).expect("special_mods.json 可读"); let doc: SpecialModsDef = serde_json::from_str(&raw).expect("special_mods.json 可解析"); - let mut entries = doc.entries; + for v in doc.entries { + match entries.iter_mut().find(|e| e.id == v.id) { + Some(slot) => *slot = v, + None => entries.push(v), + } + } if let Ok(raw) = std::fs::read_to_string(special_derived_path()) { let derived: SpecialModsDef = serde_json::from_str(&raw).expect("special_derived.json 可解析"); diff --git a/crates/pobr-core/tests/sources/env_finalize_flasks.rs b/crates/pobr-core/tests/sources/env_finalize_flasks.rs index 1fc5098a..2c0e7073 100644 --- a/crates/pobr-core/tests/sources/env_finalize_flasks.rs +++ b/crates/pobr-core/tests/sources/env_finalize_flasks.rs @@ -25,6 +25,7 @@ fn utility_item(base: &str, explicits: &[&str]) -> Item { base: ItemBaseId::from(base), rarity: ItemRarity::Magic, quality: 0, + corrupted: false, implicit_texts: Vec::new(), modifier_texts: explicits.iter().map(|t| (*t).to_string()).collect(), enchant_texts: Vec::new(), diff --git a/crates/pobr-core/tests/sources/item_source.rs b/crates/pobr-core/tests/sources/item_source.rs index 7f1d3202..c480df39 100644 --- a/crates/pobr-core/tests/sources/item_source.rs +++ b/crates/pobr-core/tests/sources/item_source.rs @@ -16,6 +16,7 @@ fn helmet(texts: &[&str]) -> Item { base: ItemBaseId::from("Helmet"), rarity: ItemRarity::Rare, quality: 20, + corrupted: false, implicit_texts: Vec::new(), modifier_texts: texts.iter().map(|t| (*t).to_string()).collect(), enchant_texts: Vec::new(), @@ -114,6 +115,7 @@ fn ingest_item_distinguishes_implicit_explicit_enchant_sections() { base: ItemBaseId::from("Helmet"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec!["+30% to Fire Resistance".to_string()], modifier_texts: vec!["+40 to maximum Life".to_string()], enchant_texts: vec!["+25% to Cold Resistance".to_string()], @@ -157,6 +159,7 @@ fn ingest_item_collects_unsupported_texts_across_sections() { base: ItemBaseId::from("Helmet"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec!["split".to_string()], modifier_texts: vec!["+40 to maximum Life".to_string(), "mirrored".to_string()], enchant_texts: Vec::new(), @@ -179,6 +182,7 @@ fn ingested_item_modifiers_attribute_back_to_slot() { base: ItemBaseId::from("Iron Ring"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: Vec::new(), modifier_texts: vec!["+25 to maximum Life".to_string()], enchant_texts: Vec::new(), @@ -209,6 +213,7 @@ fn ingested_implicit_attributes_to_item_implicit_source() { base: ItemBaseId::from("Amber Amulet"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: vec!["+25 to maximum Life".to_string()], modifier_texts: Vec::new(), enchant_texts: Vec::new(), @@ -242,6 +247,7 @@ fn session_add_item_feeds_minimal_calc() { base: ItemBaseId::from("Plate Vest"), rarity: ItemRarity::Rare, quality: 0, + corrupted: false, implicit_texts: Vec::new(), modifier_texts: vec![ "+40 to maximum Life".to_string(), @@ -294,6 +300,7 @@ fn bare_item(base: &str, slot_quality: u8) -> Item { base: ItemBaseId::from(base), rarity: ItemRarity::Rare, quality: slot_quality, + corrupted: false, implicit_texts: Vec::new(), modifier_texts: Vec::new(), enchant_texts: Vec::new(), @@ -368,6 +375,7 @@ fn utility_item(base: &str, implicits: &[&str], explicits: &[&str]) -> Item { base: ItemBaseId::from(base), rarity: ItemRarity::Magic, quality: 0, + corrupted: false, implicit_texts: implicits.iter().map(|t| (*t).to_string()).collect(), modifier_texts: explicits.iter().map(|t| (*t).to_string()).collect(), enchant_texts: Vec::new(), @@ -433,8 +441,11 @@ fn ingest_charm_wraps_mods_into_list_payload_with_flask_attribution() { /// 同样来自真实 build,静默忽略会让调用方误以为效果已经生效。 #[test] fn ingest_charm_parses_guard_and_possession_effects_via_engine() { - // 引擎 special 通道已建模这两行(GuardAbsorb* / SpiritPossessionOnUse)—— - // legacy 时代它们是 unmodeled unsupported,现应正常产 mod、不进 unsupported。 + // possession 行由引擎 special 通道建模(SpiritPossessionOnUse),正常产 mod。 + // guard 行(`Also grants N Guard`)曾被策展条目 also_grants_guard 建模,但 + // vendor ModParser 根本不解析它——对 PoB2 golden 是幻影 Guard 池(存量 #7 + // 已摘除,ritualist EHP 1.10x→1.00x)。与 PoB2 对齐后它回到「未建模 → + // 必须响亮进 unsupported 报告」的口径,静默忽略才是失败。 let charm = utility_item( "Thawing Charm", &["Used when you become Frozen"], @@ -446,9 +457,10 @@ fn ingest_charm_parses_guard_and_possession_effects_via_engine() { let ingest = ingest_flask_charm("Charm 1", &charm); - assert!( - ingest.unsupported.is_empty(), - "guard/possession 行应由引擎解析,实际 unsupported: {:?}", + assert_eq!( + ingest.unsupported, + vec!["Also grants 435 Guard".to_string()], + "guard 行未建模应上报(与 PoB2 口径一致)、possession 行应解析,实际 unsupported: {:?}", ingest.unsupported ); } diff --git a/crates/pobr-core/tests/sources/minion.rs b/crates/pobr-core/tests/sources/minion.rs index 985aa6cb..53eddb5f 100644 --- a/crates/pobr-core/tests/sources/minion.rs +++ b/crates/pobr-core/tests/sources/minion.rs @@ -33,14 +33,16 @@ fn gem_level_table_maps_per_pob2() { } #[test] -fn base_stats_use_monster_table_times_normalizer() { +fn base_stats_use_ally_life_table_times_normalizer() { + // #12 起召唤物生命走盟友表 + floor(vendor CalcPerform.lua:1046 + // `m_floor(monsterAllyLifeTable[level] × minionData.life)`),不再用敌方 + // monsterLifeTable。armour/evasion 仍走敌方表(vendor 同源)。 let data = MinionData { life: 0.7, ..MinionData::default() }; let base = derive_minion_base_stats(20, &data); - let row = MonsterScalingRow::at_level(40); - let expected = (row.life as f64 * 0.7 * 1_000_000_000.0).round() / 1_000_000_000.0; + let expected = (pobr_data::monster::monster_ally_life(40) as f64 * 0.7).floor(); assert!((base.life - expected).abs() < 1e-6); assert!(base.life > 0.0); } @@ -282,8 +284,8 @@ fn build_context_from_raging_spirit_life_matches_pob2() { // 暴怒魂灵:life=0.25,gem_level=20 → 怪物等级 40。 let def = minion_def_raging_spirit(); let ctx = build_minion_context_from_def(&def, 20, vec![], vec![], AttributeInfusion::default()); - let row = MonsterScalingRow::at_level(40); - let expected = (row.life as f64 * 0.25 * 1e9).round() / 1e9; + // #12:生命走盟友表 + floor(vendor CalcPerform.lua:1046)。 + let expected = (pobr_data::monster::monster_ally_life(40) as f64 * 0.25).floor(); assert!( (ctx.base.life - expected).abs() < 1e-6, "RagingSpirit life: expected {expected}, got {}", diff --git a/crates/pobr-core/tests/support/parse.rs b/crates/pobr-core/tests/support/parse.rs index 7beaf4bd..c52967b1 100644 --- a/crates/pobr-core/tests/support/parse.rs +++ b/crates/pobr-core/tests/support/parse.rs @@ -35,7 +35,16 @@ static RULES: LazyLock> = LazyLock::new(|| { let path = data_root().join("overlay/mod_parser_rules.json"); let json = std::fs::read_to_string(&path).expect("读取 mod_parser_rules.json"); let doc: ModParserRulesDoc = serde_json::from_str(&json).expect("反序列化规则表"); - let mut special = load_special("overlay/special_mods.json"); + // special_mods 两层(与 pobr-gamedata `load_ruleset` 同序):版本无关策展层 + // `data/overlay-common/`(相对版本目录是 `../overlay-common/`)打底,版本层按 id + // 覆盖 / 追加,再拼 derived / vendor。 + let mut special = load_special("../overlay-common/special_mods.json"); + for v in load_special("overlay/special_mods.json") { + match special.iter_mut().find(|e| e.id == v.id) { + Some(slot) => *slot = v, + None => special.push(v), + } + } special.extend(load_special("generated/special_derived.json")); special.extend(load_special("generated/special_vendor.json")); std::sync::Arc::new( diff --git a/crates/pobr-data/src/catalog/base_item_overrides.rs b/crates/pobr-data/src/catalog/base_item_overrides.rs index f0f22aaf..dd540e56 100644 --- a/crates/pobr-data/src/catalog/base_item_overrides.rs +++ b/crates/pobr-data/src/catalog/base_item_overrides.rs @@ -40,6 +40,14 @@ pub struct BaseItemOverrideEntry { /// spawn weight 判定(tier 反查)需要全集。消费侧与 base tags **并集** merge。 #[serde(default, skip_serializing_if = "Option::is_none")] pub tags: Option>, + /// 基底属性需求(vendor `req = { str/dex/int }`;消费侧写入 + /// [`super::BaseItemDef::req_str`] 等,装备需求快照的取数源)。 + #[serde(default, skip_serializing_if = "Option::is_none")] + pub req_str: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub req_dex: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub req_int: Option, } /// `overlay/base_item_overrides.json` 顶层(消费侧视角:`_meta` 头部为生成溯源 diff --git a/crates/pobr-data/src/catalog/items.rs b/crates/pobr-data/src/catalog/items.rs index ed2cdbb6..06979494 100644 --- a/crates/pobr-data/src/catalog/items.rs +++ b/crates/pobr-data/src/catalog/items.rs @@ -51,6 +51,18 @@ pub struct BaseItemDef { /// 非 charm / 无 buff 为空。 #[serde(default, skip_serializing_if = "Vec::is_empty")] pub charm_buff: Vec, + /// 基底属性需求(vendor `Data/Bases/*.lua` 的 `req = { str/dex/int }`;GGG + /// `.dat` 对应表 bundle 不可得,走 `overlay/base_item_overrides.json` 抽取 + /// merge——与 [`Self::spirit`] 同款兜底)。消费方 = 装备需求快照 + /// `RequirementsOn`(vendor CalcPerform.lua:1848-1857, + /// Smith『Gain Armour equal to 150% of total Strength Requirements …』)。 + /// 无需求为 0。 + #[serde(default, skip_serializing_if = "is_zero_u32")] + pub req_str: u32, + #[serde(default, skip_serializing_if = "is_zero_u32")] + pub req_dex: u32, + #[serde(default, skip_serializing_if = "is_zero_u32")] + pub req_int: u32, } /// 武器基底数值(`WeaponTypes.dat` 外键解析;攻击技能伤害的基底,对照 PoB2 diff --git a/crates/pobr-data/src/catalog/monster_scaling.rs b/crates/pobr-data/src/catalog/monster_scaling.rs index 4f749ef2..6a65bf96 100644 --- a/crates/pobr-data/src/catalog/monster_scaling.rs +++ b/crates/pobr-data/src/catalog/monster_scaling.rs @@ -134,10 +134,12 @@ impl MonsterScalingTable { /// fallback(无 GameData 注入时使用):与 `base/monster_scaling.json` **逐值相等** /// (搬迁不变式,W2 测试已锁 JSON == Rust 准源)。 /// -/// - 有 pobr Rust 准源的七张表直接引用 `crate::monster` 既有 const(零字面量复制); -/// - `ally_life` / `ally_damage` 为 vendor-only(pobr 此前未迁、calc 暂无消费方), -/// 字面量抄录自 `vendor/PathOfBuilding-PoE2/src/Data/Misc.lua` L8 / L10 -/// (与 `base/monster_scaling.json` 同源同值;`ally_damage` 为 2 位小数口径)。 +/// - 有 pobr Rust 准源的八张表(含 #12 升格的 `ally_life` = +/// `MONSTER_ALLY_LIFE_TABLE`,消费方 = 召唤物基础生命派生)直接引用 +/// `crate::monster` 既有 const(零字面量复制); +/// - `ally_damage` 为 vendor-only(calc 暂无消费方),字面量抄录自 +/// `vendor/PathOfBuilding-PoE2/src/Data/Misc.lua` L10 +/// (与 `base/monster_scaling.json` 同源同值;2 位小数口径)。 impl Default for MonsterScalingTable { fn default() -> Self { Self { @@ -145,20 +147,7 @@ impl Default for MonsterScalingTable { evasion: MONSTER_EVASION_TABLE.to_vec(), armour: MONSTER_ARMOUR_TABLE.to_vec(), life: MONSTER_LIFE_TABLE.to_vec(), - ally_life: vec![ - 51, 83, 116, 150, 186, 223, 261, 300, 341, 382, // lv1-10 - 426, 471, 517, 565, 614, 665, 718, 772, 828, 886, // lv11-20 - 945, 1007, 1070, 1135, 1203, 1272, 1344, 1417, 1493, 1571, // lv21-30 - 1652, 1734, 1820, 1907, 1998, 2091, 2186, 2285, 2386, 2490, // lv31-40 - 2598, 2708, 2821, 2938, 3058, 3181, 3307, 3438, 3571, 3709, // lv41-50 - 3850, 3995, 4144, 4298, 4455, 4617, 4783, 4953, 5128, 5308, // lv51-60 - 5493, 5682, 5877, 6077, 6282, 6492, 6708, 6930, 7157, 7391, // lv61-70 - 7630, 7876, 8128, 8387, 8652, 8924, 9203, 9489, 9783, 10084, // lv71-80 - 10393, 10710, 11034, 11367, 11708, 12058, 12417, 12785, 13161, - 13548, // lv81-90 - 13944, 14350, 14766, 15192, 15629, 16076, 16535, 17005, 17486, - 17980, // lv91-100 - ], + ally_life: crate::monster::MONSTER_ALLY_LIFE_TABLE.to_vec(), damage: MONSTER_DAMAGE_TABLE.to_vec(), ally_damage: vec![ 3.11, 4.42, 5.82, 7.31, 8.92, 10.63, 12.46, 14.42, // lv1-8 diff --git a/crates/pobr-data/src/catalog/skills.rs b/crates/pobr-data/src/catalog/skills.rs index 689d47fb..15f9d595 100644 --- a/crates/pobr-data/src/catalog/skills.rs +++ b/crates/pobr-data/src/catalog/skills.rs @@ -388,6 +388,16 @@ pub struct QualityStat { /// stat 集——**截断取整**(toward zero),对齐 PoB2 `CalcTools.lua:142` /// `math.modf(stat[2] * skillInstance.quality)`。 pub per_quality_rate: f64, + /// alt 品质 stat(vendor `altQualityStats`):仅当 build 带 GemlingQuality + /// flag(Gemling 升华『Gem Quality grants Socketed Skills an additional + /// effect』)时叠加(PoB2 `CalcTools.lua:147-152` `includeAltQualityStats`)。 + #[serde(default, skip_serializing_if = "is_false")] + pub alt: bool, +} + +/// serde 跳过 false 布尔(diff 友好;旧数据无 `alt` 键 = false)。 +fn is_false(v: &bool) -> bool { + !*v } /// 某授予效果的品质 stat 表(`overlay/gem_quality_stats.json` 的单条)。 diff --git a/crates/pobr-data/src/catalog/tree.rs b/crates/pobr-data/src/catalog/tree.rs index 6f316c15..b315db13 100644 --- a/crates/pobr-data/src/catalog/tree.rs +++ b/crates/pobr-data/src/catalog/tree.rs @@ -101,6 +101,12 @@ pub struct PassiveNodeDef { /// `#[serde(default)]` 兼容;非 switchable 节点恒为空。 #[serde(default, skip_serializing_if = "Vec::is_empty")] pub variants: Vec, + /// Smith of Kitava 身甲连接 notable 标记(vendor `tree.lua` `applyToArmour`, + /// 由 `pobr-data-adapter --tree-coords` 回填):已分配数 → + /// `Multiplier:AllocatedConnectedNotable`(vendor CalcSetup.lua:840-841, + /// 消费方 = Masterwork『+200 to Armour for each Connected Notable …』)。 + #[serde(default, skip_serializing_if = "core::ops::Not::not")] + pub apply_to_armour: bool, } /// 某个职业的飞升摘要。 diff --git a/crates/pobr-data/src/item.rs b/crates/pobr-data/src/item.rs index 0af8ff09..f501fa26 100644 --- a/crates/pobr-data/src/item.rs +++ b/crates/pobr-data/src/item.rs @@ -57,6 +57,9 @@ pub struct Item { pub base: ItemBaseId, pub rarity: ItemRarity, pub quality: u8, + /// 是否已腐化(item 文本的 `Corrupted` 标记行)。消费方:The Adorned 珠宝 + /// 效果缩放(corrupted magic jewel 门控)等 vendor `item.corrupted` 语义。 + pub corrupted: bool, /// implicit 词条文本(基底固有词缀),归因到 `SourceKind::ItemImplicit`。 pub implicit_texts: Vec, /// explicit 词条文本(前后缀),归因到 `SourceKind::ItemAffix`。 diff --git a/crates/pobr-data/src/monster.rs b/crates/pobr-data/src/monster.rs index d3174708..af567cd1 100644 --- a/crates/pobr-data/src/monster.rs +++ b/crates/pobr-data/src/monster.rs @@ -251,6 +251,25 @@ pub const MONSTER_LIFE_TABLE: [u32; MONSTER_TABLE_LEN] = [ 43001, 44291, 45619, 46988, 48398, 49850, 51345, 52885, 54472, 56106, // lv91-100 ]; +/// 盟友(非敌对召唤物)生命值查表(等级 1..=100)。 +/// +/// 来源:PoB2 `src/Data/Misc.lua::data.monsterAllyLifeTable`(L8)。召唤物基础生命 +/// = `floor(monsterAllyLifeTable[level] × minionData.life)`(CalcPerform.lua:1046; +/// 敌对召唤物才用 `monsterLifeTable` × mapLevelLifeMult)。与敌方表不同:无 lv65+ +/// 终局跳升,平滑单调。 +pub const MONSTER_ALLY_LIFE_TABLE: [u32; MONSTER_TABLE_LEN] = [ + 51, 83, 116, 150, 186, 223, 261, 300, 341, 382, // lv1-10 + 426, 471, 517, 565, 614, 665, 718, 772, 828, 886, // lv11-20 + 945, 1007, 1070, 1135, 1203, 1272, 1344, 1417, 1493, 1571, // lv21-30 + 1652, 1734, 1820, 1907, 1998, 2091, 2186, 2285, 2386, 2490, // lv31-40 + 2598, 2708, 2821, 2938, 3058, 3181, 3307, 3438, 3571, 3709, // lv41-50 + 3850, 3995, 4144, 4298, 4455, 4617, 4783, 4953, 5128, 5308, // lv51-60 + 5493, 5682, 5877, 6077, 6282, 6492, 6708, 6930, 7157, 7391, // lv61-70 + 7630, 7876, 8128, 8387, 8652, 8924, 9203, 9489, 9783, 10084, // lv71-80 + 10393, 10710, 11034, 11367, 11708, 12058, 12417, 12785, 13161, 13548, // lv81-90 + 13944, 14350, 14766, 15192, 15629, 16076, 16535, 17005, 17486, 17980, // lv91-100 +]; + /// 怪物基础伤害查表(等级 1..=100,f64)。 /// /// 来源:PoB2 `src/Data/Misc.lua::data.monsterDamageTable`(DefaultMonsterStats.dat)。 @@ -376,6 +395,11 @@ pub fn monster_life(level: u32) -> u32 { MONSTER_LIFE_TABLE[level_to_index(level)] } +/// 查询盟友(非敌对召唤物)生命值(等级 1..=100,超界自动 clamp)。 +pub fn monster_ally_life(level: u32) -> u32 { + MONSTER_ALLY_LIFE_TABLE[level_to_index(level)] +} + /// 查询怪物基础伤害(等级 1..=100,超界自动 clamp)。 pub fn monster_damage(level: u32) -> f64 { MONSTER_DAMAGE_TABLE[level_to_index(level)] diff --git a/crates/pobr-data/src/skill.rs b/crates/pobr-data/src/skill.rs index 6905fa39..219e8e74 100644 --- a/crates/pobr-data/src/skill.rs +++ b/crates/pobr-data/src/skill.rs @@ -76,6 +76,9 @@ impl SkillTypes { /// 「Persistent Buffs have N% less Reservation」(Tactician『A Solid /// Plan』)以 Persistent+Buff 双 tag AND 限定作用域) pub const PERSISTENT: Self = Self::bit(139); + /// PoB2 SkillType.Barrageable = 70(Barrage buff 的 repeats DPS 乘区 + /// 门控,vendor CalcOffence.lua:962-976) + pub const BARRAGEABLE: Self = Self::bit(69); /// 第 `index` 位(0-based)置 1 的掩码(const 构造)。 const fn bit(index: u32) -> Self { diff --git a/crates/pobr-gamedata/src/domains/base_item_overrides.rs b/crates/pobr-gamedata/src/domains/base_item_overrides.rs index f15b9483..592fd0bd 100644 --- a/crates/pobr-gamedata/src/domains/base_item_overrides.rs +++ b/crates/pobr-gamedata/src/domains/base_item_overrides.rs @@ -102,6 +102,16 @@ pub fn apply_base_item_overrides(bases: &mut [BaseItemDef], overrides: &BaseItem merged.dedup(); base.tags = merged; } + // 基底属性需求(vendor `req = { str/dex/int }`,装备需求快照取数源)。 + if let Some(req) = entry.req_str { + base.req_str = req; + } + if let Some(req) = entry.req_dex { + base.req_dex = req; + } + if let Some(req) = entry.req_int { + base.req_int = req; + } } } @@ -125,6 +135,9 @@ mod tests { armour, spirit: None, charm_buff: Vec::new(), + req_str: 0, + req_dex: 0, + req_int: 0, } } @@ -149,6 +162,9 @@ mod tests { let overrides = BaseItemOverridesDef { overrides: vec![ BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Crude Tower Shield".to_string(), block_chance: Some(26.0), spirit: None, @@ -157,6 +173,9 @@ mod tests { tags: None, }, BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Omen Sceptre".to_string(), block_chance: None, spirit: Some(100), @@ -183,6 +202,9 @@ mod tests { let mut bases = vec![base("Phantom Buckler", None)]; let overrides = BaseItemOverridesDef { overrides: vec![BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Phantom Buckler".to_string(), block_chance: Some(20.0), spirit: None, @@ -203,6 +225,9 @@ mod tests { let mut bases = vec![base("Crude Tower Shield", Some(armour_stats(18)))]; let overrides = BaseItemOverridesDef { overrides: vec![BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Removed Legacy Shield".to_string(), block_chance: Some(30.0), spirit: None, @@ -233,6 +258,9 @@ mod tests { let overrides = BaseItemOverridesDef { overrides: vec![ BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Makeshift Crossbow".to_string(), block_chance: None, spirit: None, @@ -241,6 +269,9 @@ mod tests { tags: None, }, BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Weaponless Oddity".to_string(), block_chance: None, spirit: None, @@ -278,6 +309,9 @@ mod tests { let overrides = BaseItemOverridesDef { overrides: vec![ BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Ruby Charm".to_string(), block_chance: None, spirit: None, @@ -286,6 +320,9 @@ mod tests { tags: None, }, BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Topaz Charm".to_string(), block_chance: None, spirit: None, @@ -295,6 +332,9 @@ mod tests { }, // charm_buff None → 不动(保持空),且校验非 charm 基底不受扰动。 BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Crude Tower Shield".to_string(), block_chance: Some(26.0), spirit: None, diff --git a/crates/pobr-gamedata/src/domains/buff_definitions.rs b/crates/pobr-gamedata/src/domains/buff_definitions.rs index b81fc0fa..05c07670 100644 --- a/crates/pobr-gamedata/src/domains/buff_definitions.rs +++ b/crates/pobr-gamedata/src/domains/buff_definitions.rs @@ -10,11 +10,37 @@ use pobr_data::catalog::buffs::BuffDefinitionsDef; use crate::{GameData, LoadError}; impl GameData { - /// 加载内建 buff 定义(恒走 `overlay/` 定位;`_meta` 由 serde 忽略)。 - /// 文件缺失(旧数据包无此 overlay 域)返回 `Ok(None)`——消费侧行为 = - /// 无内建 buff 展开(向后兼容);其余 IO / 解析错误照常上抛,不静默。 + /// 加载内建 buff 定义,**两层合并**:版本无关策展层 + /// `data/overlay-common/buff_definitions.json`(人工归纳,居先打底),叠版本层 + /// `/overlay/buff_definitions.json`(版本特有覆盖)。合并按 `id` 逐条覆盖/ + /// 追加([`crate::paths::merge_by_key`],同 special_mods)——人工归纳的 buff 语义 + /// 随游戏版本不变,放 common 层新版免费继承(`docs/version-bump-architecture.md` + /// P1-3);`_meta` 由 serde 忽略。 + /// + /// 两层皆缺(旧数据包无此 overlay 域)返回 `Ok(None)`——消费侧行为 = 无内建 buff + /// 展开(向后兼容);其余 IO / 解析错误照常上抛,不静默。 pub fn buff_definitions(&self) -> Result, LoadError> { - match self.load_json_at::(self.overlay_path("buff_definitions.json")) { + let common = match self.overlay_common_path("buff_definitions.json") { + Some(path) => self.load_buff_definitions_at(path)?, + None => None, + }; + let version = self.load_buff_definitions_at(self.overlay_path("buff_definitions.json"))?; + Ok(match (common, version) { + (None, None) => None, + (Some(def), None) | (None, Some(def)) => Some(def), + (Some(common), Some(version)) => Some(BuffDefinitionsDef { + buffs: crate::paths::merge_by_key(common.buffs, version.buffs, |b| &b.id), + }), + }) + } + + /// 读一个 `buff_definitions` schema 文件为 `Option`:NotFound → `None`(软降级), + /// 其余错误上抛。`load_json_at` 仍叠加用户 patch 层。 + fn load_buff_definitions_at( + &self, + path: std::path::PathBuf, + ) -> Result, LoadError> { + match self.load_json_at::(path) { Ok(def) => Ok(Some(def)), Err(LoadError::Io { ref source, .. }) if source.kind() == std::io::ErrorKind::NotFound => diff --git a/crates/pobr-gamedata/src/domains/high_precision_mods.rs b/crates/pobr-gamedata/src/domains/high_precision_mods.rs index 0b09a291..e7b1ed68 100644 --- a/crates/pobr-gamedata/src/domains/high_precision_mods.rs +++ b/crates/pobr-gamedata/src/domains/high_precision_mods.rs @@ -10,8 +10,9 @@ use pobr_data::catalog::high_precision_mods::HighPrecisionModsDef; use crate::{GameData, LoadError}; impl GameData { - /// 加载取整精度例外表(单对象域,恒走 `overlay/` 定位,缺文件即报错)。 + /// 加载取整精度例外表(单对象域,版本无关策展):版本 `overlay/` 优先、 + /// `overlay-common/` 兜底([`Self::load_overlay_or_common`]),两层皆缺即报错。 pub fn high_precision_mods(&self) -> Result { - self.load_json_at(self.overlay_path("high_precision_mods.json")) + self.load_overlay_or_common("high_precision_mods.json") } } diff --git a/crates/pobr-gamedata/src/domains/local_mods.rs b/crates/pobr-gamedata/src/domains/local_mods.rs index 1749bcdf..564fd9bd 100644 --- a/crates/pobr-gamedata/src/domains/local_mods.rs +++ b/crates/pobr-gamedata/src/domains/local_mods.rs @@ -11,9 +11,10 @@ use pobr_data::catalog::local_mods::LocalModsDef; use crate::{GameData, LoadError}; impl GameData { - /// 加载局部词条白名单(单对象域,恒走 `overlay/` 定位,缺文件即报错—— - /// 降级语义由消费方裁决,不在 loader 层吞错)。 + /// 加载局部词条白名单(单对象域,版本无关策展):版本 `overlay/` 优先、 + /// `overlay-common/` 兜底([`Self::load_overlay_or_common`]),两层皆缺即报错—— + /// 降级语义由消费方裁决,不在 loader 层吞错。 pub fn local_mods(&self) -> Result { - self.load_json_at(self.overlay_path("local_mods.json")) + self.load_overlay_or_common("local_mods.json") } } diff --git a/crates/pobr-gamedata/src/domains/parser_rules.rs b/crates/pobr-gamedata/src/domains/parser_rules.rs index 089c85dc..6c6a7f0a 100644 --- a/crates/pobr-gamedata/src/domains/parser_rules.rs +++ b/crates/pobr-gamedata/src/domains/parser_rules.rs @@ -36,49 +36,53 @@ mod tests { use crate::GameData; + fn golden_version_dir() -> std::path::PathBuf { + crate::repo_data_root().join(pobr_data::GOLDEN_PARITY_DATA_VERSION) + } + fn real_data() -> GameData { // 本模块测试钉定段计数 / vendor-commit 实测样本(版本特定,随抽取增长),故加载 // golden 校验版本而非活动版本(数据/计算解耦,见 pobr_data::GOLDEN_PARITY_DATA_VERSION)。 - GameData::new(crate::repo_data_root().join(pobr_data::GOLDEN_PARITY_DATA_VERSION)) + GameData::new(golden_version_dir()) } - /// 仓库真实数据:各段条目数与钉定 vendor commit 的实测值一致 - /// (蓝图 §1.9 计数自检的消费侧镜像。golden 4.5.4.3(vendor ce8bffab)实测: - /// forms 91→95、name_map 775→789、flag_phrases 201→205、tag_phrases 687→691、 - /// flag_types 25→26、distinct forms 28→29)。 + /// 仓库真实数据:各段条目数与 blessed 快照一致(蓝图 §1.9 计数自检的消费侧 + /// 镜像)。计数随 vendor 抽取增长——具体数值进 `generated/test_pins.json` + /// (regen 后 `POBR_BLESS_PINS=1` 刷新,见 [`crate::test_pins`]);本函数只 + /// 保留结构性守卫(核心 form id 必须在场)。 #[test] fn real_data_section_counts() { let doc = real_data() .mod_parser_rules() .expect("加载 mod_parser_rules.json 不应失败") .expect("仓库数据包应含 mod_parser_rules 域"); - assert_eq!(doc.forms.len(), 95, "forms"); - assert_eq!(doc.name_map.len(), 789, "name_map"); - assert_eq!(doc.flag_phrases.len(), 205, "flag_phrases"); - assert_eq!(doc.pre_flags.len(), 219, "pre_flags"); - assert_eq!(doc.tag_phrases.len(), 691, "tag_phrases"); - assert_eq!(doc.suffix_types.len(), 40, "suffix_types"); - assert_eq!(doc.damage_types.len(), 5, "damage_types"); - assert_eq!(doc.pen_types.len(), 6, "pen_types"); - assert_eq!(doc.regen_types.len(), 32, "regen_types"); - assert_eq!(doc.degen_types.len(), 32, "degen_types"); - assert_eq!(doc.cost_types_map.len(), 32, "cost_types_map"); - assert_eq!(doc.base_cost_types.len(), 32, "base_cost_types"); - // 26 = vendor 25(4.5.4.3 ce8bffab 新增一条)+ pobr `hindered`→ - // `Condition:Hindered`(M6-conv2:legacy `parse_enemy_inner` 对 `are hindered` - // 的特例搬迁,使 `Enemies in your Presence are Hindered` 走 EnemyModifier - // 包装收敛,见 m6-dualrun-report §2.5)。 - assert_eq!(doc.flag_types.len(), 26, "flag_types"); - assert_eq!(doc.unsupported, vec!["mirrored"], "unsupported"); - assert_eq!( - doc.unsupported_pobr_extra, - vec!["split"], - "unsupported_pobr_extra" - ); - // form id 集 29 种(蓝图 §1.1 记 28;4.5.4.3 vendor 新增 1 种) let forms: std::collections::BTreeSet<&str> = doc.forms.iter().map(|f| f.form.as_str()).collect(); - assert_eq!(forms.len(), 29, "distinct form ids"); + // flag_types 含 pobr 自增条目 `hindered`→`Condition:Hindered`(M6-conv2, + // 见 m6-dualrun-report §2.5),计数恒 = vendor + 1。 + crate::test_pins::assert_pin( + &golden_version_dir(), + "parser_rules.section_counts", + serde_json::json!({ + "forms": doc.forms.len(), + "name_map": doc.name_map.len(), + "flag_phrases": doc.flag_phrases.len(), + "pre_flags": doc.pre_flags.len(), + "tag_phrases": doc.tag_phrases.len(), + "suffix_types": doc.suffix_types.len(), + "damage_types": doc.damage_types.len(), + "pen_types": doc.pen_types.len(), + "regen_types": doc.regen_types.len(), + "degen_types": doc.degen_types.len(), + "cost_types_map": doc.cost_types_map.len(), + "base_cost_types": doc.base_cost_types.len(), + "flag_types": doc.flag_types.len(), + "distinct_forms": forms.len(), + "unsupported": doc.unsupported, + "unsupported_pobr_extra": doc.unsupported_pobr_extra, + }), + ); + // 结构性守卫:核心 form id 缺失 = 抽取通道坏,不随数据漂移。 for id in [ "INC", "RED", "MORE", "LESS", "BASE", "PEN", "DMG", "DOUBLED", ] { @@ -240,7 +244,8 @@ mod tests { assert!(loaded.is_none()); } - /// 探针推断条目的 handler 兜底数量在蓝图预算内(≤15;当前实测 3)。 + /// 探针推断条目的 handler 兜底数量在蓝图预算内(≤15,结构性守卫);具体 + /// 条数随 vendor 漂移,进 blessed 快照。 #[test] fn handler_fallback_within_budget() { let doc = real_data().mod_parser_rules().unwrap().unwrap(); @@ -255,6 +260,10 @@ mod tests { .filter(|e| e.handler_id.is_some()) .count(); assert!(handlers <= 15, "handler 兜底 {handlers} 超出蓝图预算 ≤15"); - assert_eq!(handlers, 3, "钉定 vendor commit 下实测 3 条 handler 兜底"); + crate::test_pins::assert_pin( + &golden_version_dir(), + "parser_rules.handler_fallbacks", + handlers, + ); } } diff --git a/crates/pobr-gamedata/src/domains/special_mods.rs b/crates/pobr-gamedata/src/domains/special_mods.rs index b22e5569..725fee51 100644 --- a/crates/pobr-gamedata/src/domains/special_mods.rs +++ b/crates/pobr-gamedata/src/domains/special_mods.rs @@ -12,11 +12,35 @@ use pobr_data::catalog::parser_rules::SpecialModsDef; use crate::{GameData, LoadError}; impl GameData { - /// 加载 special 词条模板表(恒走 `overlay/` 定位)。文件缺失返回 - /// `Ok(None)`(M5b B-4 约定:缺表 → RuleSet 域 None,解析行为退回 - /// 既有硬编码路径);其余错误照常上抛。 + /// 加载 special 词条模板表,**两层合并**:先读版本无关策展层 + /// `data/overlay-common/special_mods.json`(不存在则跳过),再叠版本层 + /// `/overlay/special_mods.json`。合并语义简单明确:**版本层条目按 `id` + /// 覆盖 common 层同 id 条目,其余按出现序追加**(common 顺序保持,version-only + /// 追加在后)。人工策展的 vendor-语义修正放 common 层,新数据版本目录自动继承, + /// 免去逐版本手迁(`docs/version-bump-architecture.md` P1-3)。 + /// + /// 两层皆缺 → `Ok(None)`(M5b B-4 约定:缺表 → RuleSet 域 None,解析退回硬编码 + /// 路径)。任一层坏 JSON 照常上抛;common 层文件缺失是常态(软降级,非错误)。 pub fn special_mods(&self) -> Result, LoadError> { - match self.load_json_at::(self.overlay_path("special_mods.json")) { + let common = match self.overlay_common_path("special_mods.json") { + Some(path) => self.load_special_mods_at(path)?, + None => None, + }; + let version = self.load_special_mods_at(self.overlay_path("special_mods.json"))?; + Ok(match (common, version) { + (None, None) => None, + (Some(def), None) | (None, Some(def)) => Some(def), + (Some(common), Some(version)) => Some(merge_special_layers(common, version)), + }) + } + + /// 读一个 `special_mods` schema 文件为 `Option`:NotFound → `None`(软降级), + /// 其余错误上抛。`load_json_at` 仍叠加用户 patch 层。 + fn load_special_mods_at( + &self, + path: std::path::PathBuf, + ) -> Result, LoadError> { + match self.load_json_at::(path) { Ok(def) => Ok(Some(def)), Err(LoadError::Io { ref source, .. }) if source.kind() == std::io::ErrorKind::NotFound => @@ -57,3 +81,11 @@ impl GameData { } } } + +/// 合并策展两层:`common`(版本无关基底)叠 `version`(版本特有覆盖),按 `id` +/// 逐条覆盖/追加([`crate::paths::merge_by_key`] 的 special_mods 特化)。 +fn merge_special_layers(common: SpecialModsDef, version: SpecialModsDef) -> SpecialModsDef { + SpecialModsDef { + entries: crate::paths::merge_by_key(common.entries, version.entries, |e| &e.id), + } +} diff --git a/crates/pobr-gamedata/src/lib.rs b/crates/pobr-gamedata/src/lib.rs index ff2345b2..86f0ed77 100644 --- a/crates/pobr-gamedata/src/lib.rs +++ b/crates/pobr-gamedata/src/lib.rs @@ -16,6 +16,7 @@ pub mod manifest; pub mod overlay; pub mod paths; pub mod ruleset; +pub mod test_pins; use std::fmt; use std::fs; diff --git a/crates/pobr-gamedata/src/paths.rs b/crates/pobr-gamedata/src/paths.rs index 537b0f03..6ce95ee4 100644 --- a/crates/pobr-gamedata/src/paths.rs +++ b/crates/pobr-gamedata/src/paths.rs @@ -39,6 +39,59 @@ impl GameData { pub(crate) fn generated_path(&self, rel: &str) -> PathBuf { self.root().join("generated").join(rel) } + + /// 定位 **版本无关策展层** overlay 文件:`data/overlay-common/`——版本目录的 + /// **同级** `overlay-common/` 兄弟目录(`/../overlay-common/`)。 + /// + /// 人工策展、随游戏版本不变的 vendor-语义修正放这里,新数据版本目录自动继承,免去 + /// 逐版本手迁(见 `docs/version-bump-architecture.md` P1-3)。加载侧把它 merge 到 + /// 版本层 `overlay/` **之下**(版本层按条目 key 覆盖,其余追加)。 + /// + /// 返回 `None` 仅当版本根无父目录(如 root 为文件系统根)——正常磁盘/内存后端恒 + /// `Some`:内存后端 root=``,父为空 → 键规约为 `overlay-common/`。 + pub(crate) fn overlay_common_path(&self, rel: &str) -> Option { + self.root() + .parent() + .map(|parent| parent.join("overlay-common").join(rel)) + } + + /// 加载一个**单对象策展 overlay 域**,版本层优先、版本无关层 + /// `overlay-common/` 兜底:版本 `overlay/` 存在则整份用之(版本特有修正 + /// 的逃生舱),否则读 common(版本目录免费继承,见 `docs/version-bump-architecture.md` + /// P1-3)。两层皆缺 → 版本层的 [`LoadError::Io`](NotFound,路径指向 `overlay/`), + /// 是否降级由消费方裁决。列表域(按 id 逐条覆盖/追加)用 [`merge_by_key`] 而非本方法。 + pub(crate) fn load_overlay_or_common(&self, rel: &str) -> Result + where + T: for<'de> serde::Deserialize<'de>, + { + match self.load_json_at::(self.overlay_path(rel)) { + Err(crate::LoadError::Io { ref source, .. }) + if source.kind() == std::io::ErrorKind::NotFound => + { + match self.overlay_common_path(rel) { + Some(common) => self.load_json_at(common), + // root 无父目录(FS 根)——无 common 层可退,复现版本层 NotFound 给消费方。 + None => self.load_json_at(self.overlay_path(rel)), + } + } + other => other, + } + } +} + +/// 合并两个按稳定 key 索引的策展 overlay 层:`version` 每条按 `key` 覆盖 `common` +/// 同 key 条目(整条替换,保持 common 原位),common 无此 key 的 version 条目按出现序 +/// 追加在末尾。同输入恒同输出(确定性)。人工策展基底放 common,版本特有覆盖放版本层 +/// (见 `docs/version-bump-architecture.md` P1-3)。 +pub(crate) fn merge_by_key(common: Vec, version: Vec, key: impl Fn(&T) -> &str) -> Vec { + let mut entries = common; + for v in version { + match entries.iter_mut().find(|e| key(e) == key(&v)) { + Some(slot) => *slot = v, + None => entries.push(v), + } + } + entries } #[cfg(test)] diff --git a/crates/pobr-gamedata/src/test_pins.rs b/crates/pobr-gamedata/src/test_pins.rs new file mode 100644 index 00000000..d0a9ca99 --- /dev/null +++ b/crates/pobr-gamedata/src/test_pins.rs @@ -0,0 +1,123 @@ +//! Test-pin snapshots:数据内容计数钉的 bless 快照(v0.0.3 P0-1)。 +//! +//! 「断言值 = 当前数据文件内容的计数/统计量」这类测试钉(段条数、覆盖率、某条 +//! 数据的具体数值)随每次数据 regen 必然变化,手工重钉是零信息量劳动。此类钉 +//! 统一存进 `data//generated/test_pins.json`(扁平 map:pin 名 → JSON 值), +//! 测试经 [`assert_pin`] 对照;regen 后以 `POBR_BLESS_PINS=1` 重跑同一批测试 +//! 一步刷新(`pipeline/regen-all.sh` 末步已编排)。 +//! +//! 甄别边界:**结构性守卫**(schema 非空、单调棘轮、去重不变式)仍写死在代码 +//! 里,不进快照——快照只承载「会随数据内容漂移、且漂移本身无对错」的值。 +//! +//! 注意:bless 写回在进程内串行(全局锁);跨进程并发 bless 同一文件会整文件 +//! 互相覆盖。请用 `cargo test`(单进程多线程)而非 nextest(进程/测试)执行 +//! bless 命令。 + +use std::collections::BTreeMap; +use std::path::Path; +use std::sync::Mutex; + +use serde_json::Value; + +/// bless 开关环境变量:`POBR_BLESS_PINS=1` 时 [`assert_pin`] 把实际值写回快照。 +pub const BLESS_ENV: &str = "POBR_BLESS_PINS"; + +/// bless 写回锁(同进程内多测试线程对同一快照文件 read-modify-write 串行)。 +static WRITE_LOCK: Mutex<()> = Mutex::new(()); + +/// 对照(或 bless 时写回)`/generated/test_pins.json` 中的一个 pin。 +/// +/// `version_dir` = 该测试实际加载数据的版本目录(golden 测试传 +/// `GOLDEN_PARITY_DATA_VERSION` 对应目录,活动版本测试传 `DATA_VERSION` 对应 +/// 目录)——pin 跟数据同目录,regen 哪个版本就刷新哪个版本的快照。 +/// +/// 正常模式:pin 缺失或值不等 → panic,报错信息给出 bless 刷新命令。 +/// bless 模式(`POBR_BLESS_PINS=1`):写回实际值并通过。 +pub fn assert_pin(version_dir: &Path, name: &str, actual: impl Into) { + let actual = actual.into(); + let path = version_dir.join("generated/test_pins.json"); + + if std::env::var(BLESS_ENV).is_ok_and(|v| v == "1") { + let _guard = WRITE_LOCK.lock().unwrap(); + let mut pins = read_pins(&path); + pins.insert(name.to_string(), actual); + let mut json = serde_json::to_string_pretty(&pins).expect("serialize test pins"); + json.push('\n'); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent).unwrap_or_else(|e| { + panic!("create {} failed: {e}", parent.display()); + }); + } + std::fs::write(&path, json) + .unwrap_or_else(|e| panic!("write {} failed: {e}", path.display())); + return; + } + + let pins = read_pins(&path); + match pins.get(name) { + Some(expected) if *expected == actual => {} + found => { + let expected = found.map_or("".to_string(), Value::to_string); + panic!( + "test pin `{name}` out of date in {}:\n blessed: {expected}\n actual: {actual}\n\ + 数据内容变了(regen 后属预期)。刷新:POBR_BLESS_PINS=1 重跑本测试\ + (pipeline/regen-all.sh 末步会批量刷新并提交快照)。", + path.display() + ); + } + } +} + +/// 读快照(缺文件 → 空 map;损坏文件 → panic,不静默)。 +fn read_pins(path: &Path) -> BTreeMap { + match std::fs::read(path) { + Ok(bytes) => serde_json::from_slice(&bytes) + .unwrap_or_else(|e| panic!("parse {} failed: {e}", path.display())), + Err(e) if e.kind() == std::io::ErrorKind::NotFound => BTreeMap::new(), + Err(e) => panic!("read {} failed: {e}", path.display()), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn temp_version_dir(tag: &str) -> std::path::PathBuf { + let dir = std::env::temp_dir().join(format!("pobr-test-pins-{tag}-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + dir + } + + #[test] + fn bless_then_match_roundtrip() { + let dir = temp_version_dir("roundtrip"); + // ponytail: env var is process-global — this test only exercises the + // non-bless read path directly via a hand-written snapshot file. + std::fs::create_dir_all(dir.join("generated")).unwrap(); + std::fs::write( + dir.join("generated/test_pins.json"), + r#"{"a.count": 3, "b.obj": {"x": 2.5}}"#, + ) + .unwrap(); + assert_pin(&dir, "a.count", 3); + assert_pin(&dir, "b.obj", serde_json::json!({"x": 2.5})); + std::fs::remove_dir_all(&dir).ok(); + } + + #[test] + #[should_panic(expected = "out of date")] + fn mismatch_panics_with_bless_hint() { + let dir = temp_version_dir("mismatch"); + std::fs::create_dir_all(dir.join("generated")).unwrap(); + std::fs::write(dir.join("generated/test_pins.json"), r#"{"a.count": 3}"#).unwrap(); + assert_pin(&dir, "a.count", 4); + } + + #[test] + #[should_panic(expected = "out of date")] + fn missing_pin_panics() { + let dir = temp_version_dir("missing"); + assert_pin(&dir, "no.such.pin", 1); + } +} diff --git a/crates/pobr-gamedata/tests/mods/load_special_mods.rs b/crates/pobr-gamedata/tests/mods/load_special_mods.rs index aedb3de3..843bcef4 100644 --- a/crates/pobr-gamedata/tests/mods/load_special_mods.rs +++ b/crates/pobr-gamedata/tests/mods/load_special_mods.rs @@ -168,3 +168,90 @@ fn no_open_captures_in_patterns() { ); } } + +// ===== 版本无关策展层(data/overlay-common/)两层合并行为(P1-3)===== +// +// 在临时目录里手搭两层,精确验证合并语义(repo 真数据两层 id 互斥,无 override 样本): +// /overlay-common/special_mods.json ← 版本无关基底 +// //overlay/special_mods.json ← 版本特有覆盖 + +/// 建唯一临时 data 根,返回 (根, 版本目录)。 +fn temp_data_root(tag: &str) -> (std::path::PathBuf, std::path::PathBuf) { + let root = std::env::temp_dir().join(format!( + "pobr-gamedata-special-merge-{tag}-{}", + std::process::id() + )); + let _ = std::fs::remove_dir_all(&root); + let ver_dir = root.join("4.5.4.3"); + std::fs::create_dir_all(ver_dir.join("overlay")).unwrap(); + (root, ver_dir) +} + +/// 写一个只含给定 id 条目的 special_mods.json(最小合法形状)。 +fn write_special(path: &std::path::Path, entries: &[(&str, &str)]) { + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + let body: Vec = entries + .iter() + .map(|(id, pattern)| format!(r#"{{"id":"{id}","pattern":"{pattern}","batch":"T"}}"#)) + .collect(); + std::fs::write(path, format!(r#"{{"entries":[{}]}}"#, body.join(","))).unwrap(); +} + +fn ids(def: &SpecialModsDef) -> Vec { + def.entries.iter().map(|e| e.id.clone()).collect() +} + +/// common 层被继承,且 version-only 条目追加在后(common 顺序在前)。 +#[test] +fn overlay_common_is_inherited() { + let (root, ver_dir) = temp_data_root("inherit"); + write_special( + &root.join("overlay-common/special_mods.json"), + &[("common_a", "aaa"), ("common_b", "bbb")], + ); + write_special( + &ver_dir.join("overlay/special_mods.json"), + &[("ver_c", "ccc")], + ); + let def = GameData::new(&ver_dir).special_mods().unwrap().unwrap(); + assert_eq!(ids(&def), ["common_a", "common_b", "ver_c"]); +} + +/// version 层同 id 整条覆盖 common 层(不产生重复 id)。 +#[test] +fn version_layer_overrides_common_by_id() { + let (root, ver_dir) = temp_data_root("override"); + write_special( + &root.join("overlay-common/special_mods.json"), + &[("shared", "old_pattern"), ("common_only", "keep")], + ); + write_special( + &ver_dir.join("overlay/special_mods.json"), + &[("shared", "new_pattern")], + ); + let def = GameData::new(&ver_dir).special_mods().unwrap().unwrap(); + // 覆盖后仍只有一条 shared,取 version 的 pattern;common_only 保留。 + assert_eq!(ids(&def), ["shared", "common_only"]); + let shared = def.entries.iter().find(|e| e.id == "shared").unwrap(); + assert_eq!(shared.pattern, "new_pattern"); +} + +/// 仅 common 存在(版本目录无 overlay/special_mods.json)→ 直接继承 common。 +#[test] +fn common_only_when_version_absent() { + let (root, ver_dir) = temp_data_root("common-only"); + write_special( + &root.join("overlay-common/special_mods.json"), + &[("common_x", "xxx")], + ); + // 版本层文件缺失。 + let def = GameData::new(&ver_dir).special_mods().unwrap().unwrap(); + assert_eq!(ids(&def), ["common_x"]); +} + +/// 两层皆缺 → None(保留 RuleSet 域缺表软降级语义)。 +#[test] +fn both_layers_absent_yields_none() { + let (_root, ver_dir) = temp_data_root("none"); + assert!(GameData::new(&ver_dir).special_mods().unwrap().is_none()); +} diff --git a/crates/pobr-gamedata/tests/skills/load_buff_definitions.rs b/crates/pobr-gamedata/tests/skills/load_buff_definitions.rs index f5e7b994..f0a99e29 100644 --- a/crates/pobr-gamedata/tests/skills/load_buff_definitions.rs +++ b/crates/pobr-gamedata/tests/skills/load_buff_definitions.rs @@ -75,7 +75,7 @@ fn handler_budget() { assert!(handlers.contains(&"buff:onslaught_flask")); } -/// Onslaught 公式参数(vendor :539-570 基本形)。 +/// Onslaught 公式参数(vendor :614-645 基本形)。 #[test] fn onslaught_formula() { let doc = load(); @@ -97,7 +97,7 @@ fn onslaught_formula() { assert_eq!(def.mods[3].value, BuffModValue::PerEffect { coeff: 1.0 }); } -/// Adrenaline 逐 mod floor(vendor :586-593)。 +/// Adrenaline 逐 mod floor(vendor :661-668)。 #[test] fn adrenaline_per_mod_rounding() { let doc = load(); @@ -120,7 +120,7 @@ fn adrenaline_per_mod_rounding() { ); } -/// UnholyMight:Multiplier 字面量 + 0.3 系数 per-multiplier(vendor :577-581)。 +/// UnholyMight:Multiplier 字面量 + 0.3 系数 per-multiplier(vendor :652-656)。 #[test] fn unholy_might_shape() { let doc = load(); @@ -142,12 +142,12 @@ fn unholy_might_shape() { #[test] fn vendor_refs_well_formed() { let doc = load(); - // 允许的 vendor 行段:doActorMisc(CalcPerform :503-765,主体)+ - // Arcane Surge 注入段(CalcDefence :1580-1591,vendor 把该 buff 写在 + // 允许的 vendor 行段:doActorMisc(CalcPerform :578-850,主体)+ + // Arcane Surge 注入段(CalcDefence :1606-1617,vendor 把该 buff 写在 // doActorLifeManaSpirit 之后、recovery 之前——M4-n 条目)。 let allowed: &[(&str, u32, u32)] = &[ - ("Modules/CalcPerform.lua", 503, 765), - ("Modules/CalcDefence.lua", 1580, 1591), + ("Modules/CalcPerform.lua", 578, 850), + ("Modules/CalcDefence.lua", 1606, 1617), ]; for buff in &doc.buffs { assert!( diff --git a/crates/pobr-tree/tests/radius_jewel.rs b/crates/pobr-tree/tests/radius_jewel.rs index b517db6a..535201fd 100644 --- a/crates/pobr-tree/tests/radius_jewel.rs +++ b/crates/pobr-tree/tests/radius_jewel.rs @@ -40,6 +40,7 @@ fn fixture_positions() -> HashMap { fn node(skill: u32, kind: PassiveNodeKind) -> PassiveNodeDef { PassiveNodeDef { + apply_to_armour: false, skill, id: format!("node_{skill}"), name: Some(format!("Node {skill}")), diff --git a/crates/pobr-tree/tests/tree.rs b/crates/pobr-tree/tests/tree.rs index 7d4a3b58..2a85c022 100644 --- a/crates/pobr-tree/tests/tree.rs +++ b/crates/pobr-tree/tests/tree.rs @@ -273,6 +273,7 @@ fn compute_node_mods_splits_multiline_stats_into_separate_texts() { fn from_nodes_round_trips_with_positions() { let nodes = vec![ PassiveNodeDef { + apply_to_armour: false, skill: 1, id: "a".into(), name: None, @@ -288,6 +289,7 @@ fn from_nodes_round_trips_with_positions() { variants: vec![], }, PassiveNodeDef { + apply_to_armour: false, skill: 2, id: "b".into(), name: None, diff --git a/data/4.5.4.3/base/granted_effect_stat_sets.json b/data/4.5.4.3/base/granted_effect_stat_sets.json index 4bb99be0..557c84f3 100644 --- a/data/4.5.4.3/base/granted_effect_stat_sets.json +++ b/data/4.5.4.3/base/granted_effect_stat_sets.json @@ -1996,11 +1996,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 11.0 + "value": 0.0 } ] }, @@ -2010,11 +2010,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 18.0 + "value": 0.0 } ] }, @@ -2024,11 +2024,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 28.0 + "value": 0.0 } ] }, @@ -2038,11 +2038,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 38.0 + "value": 0.0 } ] }, @@ -2052,11 +2052,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 49.0 + "value": 0.0 } ] }, @@ -2066,11 +2066,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 61.0 + "value": 0.0 } ] }, @@ -2080,11 +2080,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 73.0 + "value": 0.0 } ] }, @@ -2094,11 +2094,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 86.0 + "value": 0.0 } ] }, @@ -2108,11 +2108,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 67.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 100.0 + "value": 0.0 } ] }, @@ -2122,11 +2122,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 114.0 + "value": 0.0 } ] }, @@ -2136,11 +2136,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 86.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 129.0 + "value": 0.0 } ] }, @@ -2150,11 +2150,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 97.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 145.0 + "value": 0.0 } ] }, @@ -2164,11 +2164,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 108.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 161.0 + "value": 0.0 } ] }, @@ -2178,11 +2178,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 119.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 178.0 + "value": 0.0 } ] }, @@ -2192,11 +2192,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 131.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 196.0 + "value": 0.0 } ] }, @@ -2206,11 +2206,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 143.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 214.0 + "value": 0.0 } ] }, @@ -2220,11 +2220,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 156.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 233.0 + "value": 0.0 } ] }, @@ -2234,11 +2234,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 169.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 253.0 + "value": 0.0 } ] }, @@ -2248,11 +2248,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 182.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 273.0 + "value": 0.0 } ] }, @@ -2262,11 +2262,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 196.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 294.0 + "value": 0.0 } ] }, @@ -2276,11 +2276,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 211.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 316.0 + "value": 0.0 } ] }, @@ -2290,11 +2290,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 226.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 338.0 + "value": 0.0 } ] }, @@ -2304,11 +2304,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 241.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 361.0 + "value": 0.0 } ] }, @@ -2318,11 +2318,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 257.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 385.0 + "value": 0.0 } ] }, @@ -2332,11 +2332,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 273.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 409.0 + "value": 0.0 } ] }, @@ -2346,11 +2346,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 289.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 434.0 + "value": 0.0 } ] }, @@ -2360,11 +2360,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 307.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 460.0 + "value": 0.0 } ] }, @@ -2374,11 +2374,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 324.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 486.0 + "value": 0.0 } ] }, @@ -2388,11 +2388,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 342.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 513.0 + "value": 0.0 } ] }, @@ -2402,11 +2402,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 360.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 541.0 + "value": 0.0 } ] }, @@ -2416,11 +2416,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 379.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 569.0 + "value": 0.0 } ] }, @@ -2430,11 +2430,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 399.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 598.0 + "value": 0.0 } ] }, @@ -2444,11 +2444,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 418.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 628.0 + "value": 0.0 } ] }, @@ -2458,11 +2458,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 439.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 658.0 + "value": 0.0 } ] }, @@ -2472,11 +2472,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 459.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 689.0 + "value": 0.0 } ] }, @@ -2486,11 +2486,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 480.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 720.0 + "value": 0.0 } ] }, @@ -2500,11 +2500,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 502.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 753.0 + "value": 0.0 } ] }, @@ -2514,11 +2514,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 524.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 785.0 + "value": 0.0 } ] }, @@ -2528,11 +2528,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 546.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 819.0 + "value": 0.0 } ] }, @@ -2542,11 +2542,11 @@ "stats": [ { "stat": "main_hand_weapon_minimum_physical_damage", - "value": 569.0 + "value": 0.0 }, { "stat": "main_hand_weapon_maximum_physical_damage", - "value": 853.0 + "value": 0.0 } ] } @@ -16861,11 +16861,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -16882,11 +16882,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -16903,11 +16903,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -16924,11 +16924,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -16945,11 +16945,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -16966,11 +16966,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -16987,11 +16987,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17008,11 +17008,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17029,11 +17029,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17050,11 +17050,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17071,11 +17071,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17092,11 +17092,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17113,11 +17113,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17134,11 +17134,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17155,11 +17155,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17176,11 +17176,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17197,11 +17197,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17218,11 +17218,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 83.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17239,11 +17239,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 93.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17260,11 +17260,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 105.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17281,11 +17281,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 118.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17302,11 +17302,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 133.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17323,11 +17323,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 150.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17344,11 +17344,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 169.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17365,11 +17365,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 189.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17386,11 +17386,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 213.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17407,11 +17407,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 239.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17428,11 +17428,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 268.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17449,11 +17449,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 301.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17470,11 +17470,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17491,11 +17491,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 380.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17512,11 +17512,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 427.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17533,11 +17533,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 480.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17554,11 +17554,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 539.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17575,11 +17575,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 607.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17596,11 +17596,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 683.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17617,11 +17617,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 769.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17638,11 +17638,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 46.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 866.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17659,11 +17659,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 977.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17680,11 +17680,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 58.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1102.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17749,11 +17749,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17770,11 +17770,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17791,11 +17791,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17812,11 +17812,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17833,11 +17833,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17854,11 +17854,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17875,11 +17875,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17896,11 +17896,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17917,11 +17917,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17938,11 +17938,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17959,11 +17959,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -17980,11 +17980,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18001,11 +18001,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18022,11 +18022,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18043,11 +18043,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18064,11 +18064,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18085,11 +18085,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18106,11 +18106,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 83.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18127,11 +18127,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 93.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18148,11 +18148,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 105.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18169,11 +18169,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 118.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18190,11 +18190,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 133.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18211,11 +18211,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 150.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18232,11 +18232,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 169.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18253,11 +18253,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 189.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18274,11 +18274,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 213.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18295,11 +18295,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 239.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18316,11 +18316,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 268.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18337,11 +18337,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 301.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18358,11 +18358,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18379,11 +18379,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 380.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18400,11 +18400,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 427.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18421,11 +18421,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 480.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18442,11 +18442,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 539.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18463,11 +18463,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 607.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18484,11 +18484,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 683.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18505,11 +18505,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 769.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18526,11 +18526,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 46.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 866.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18547,11 +18547,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 977.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -18568,11 +18568,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 58.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1102.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -19267,11 +19267,11 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 5.0 + "value": 0.0 } ] } @@ -23549,7 +23549,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23566,7 +23566,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23583,7 +23583,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23600,7 +23600,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23617,7 +23617,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23634,7 +23634,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23651,7 +23651,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23668,7 +23668,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23685,7 +23685,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23702,7 +23702,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23719,7 +23719,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23736,7 +23736,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23753,7 +23753,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23770,7 +23770,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23787,7 +23787,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23804,7 +23804,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23821,7 +23821,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23838,7 +23838,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23855,7 +23855,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23872,7 +23872,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23889,7 +23889,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23906,7 +23906,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23923,7 +23923,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23940,7 +23940,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23957,7 +23957,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23974,7 +23974,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -23991,7 +23991,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24008,7 +24008,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24025,7 +24025,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24042,7 +24042,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24059,7 +24059,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24076,7 +24076,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24093,7 +24093,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24110,7 +24110,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24127,7 +24127,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24144,7 +24144,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24161,7 +24161,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24178,7 +24178,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24195,7 +24195,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24212,7 +24212,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24261,7 +24261,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24278,7 +24278,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24295,7 +24295,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24312,7 +24312,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24329,7 +24329,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24346,7 +24346,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24363,7 +24363,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24380,7 +24380,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24397,7 +24397,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24414,7 +24414,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24431,7 +24431,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24448,7 +24448,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24465,7 +24465,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24482,7 +24482,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24499,7 +24499,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24516,7 +24516,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24533,7 +24533,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24550,7 +24550,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24567,7 +24567,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24584,7 +24584,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24601,7 +24601,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24618,7 +24618,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24635,7 +24635,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24652,7 +24652,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24669,7 +24669,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24686,7 +24686,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24703,7 +24703,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24720,7 +24720,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24737,7 +24737,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24754,7 +24754,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24771,7 +24771,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24788,7 +24788,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24805,7 +24805,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24822,7 +24822,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24839,7 +24839,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24856,7 +24856,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24873,7 +24873,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24890,7 +24890,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24907,7 +24907,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24924,7 +24924,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -24981,7 +24981,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -24994,7 +24994,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25007,7 +25007,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 1.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25020,7 +25020,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25033,7 +25033,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25046,7 +25046,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 2.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25059,7 +25059,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25072,7 +25072,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25085,7 +25085,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 3.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25098,7 +25098,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25111,7 +25111,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25124,7 +25124,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 4.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25137,7 +25137,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25150,7 +25150,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25163,7 +25163,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 5.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25176,7 +25176,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25189,7 +25189,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25202,7 +25202,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 6.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25215,7 +25215,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25228,7 +25228,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25241,7 +25241,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 7.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25254,7 +25254,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25267,7 +25267,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25280,7 +25280,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 8.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25293,7 +25293,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25306,7 +25306,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25319,7 +25319,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 9.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25332,7 +25332,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25345,7 +25345,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25358,7 +25358,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 10.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25371,7 +25371,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25384,7 +25384,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25397,7 +25397,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 11.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25410,7 +25410,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25423,7 +25423,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25436,7 +25436,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 12.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25449,7 +25449,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25462,7 +25462,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25475,7 +25475,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 13.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -25488,7 +25488,7 @@ "stats": [ { "stat": "volatile_dead_base_number_of_corpses_to_consume", - "value": 14.0 + "value": 0.0 }, { "stat": "base_cold_damage_to_deal_per_minute", @@ -33755,11 +33755,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33776,11 +33776,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33797,11 +33797,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33818,11 +33818,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33839,11 +33839,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33860,11 +33860,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33881,11 +33881,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33902,11 +33902,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33923,11 +33923,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33944,11 +33944,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33965,11 +33965,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -33986,11 +33986,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34007,11 +34007,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 48.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 72.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34028,11 +34028,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 83.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34049,11 +34049,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 94.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34070,11 +34070,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 107.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34091,11 +34091,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 81.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 121.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34112,11 +34112,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 91.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34133,11 +34133,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 103.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 155.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34154,11 +34154,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 116.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 175.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34175,11 +34175,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 131.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 197.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34196,11 +34196,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 148.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 221.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34217,11 +34217,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 166.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 249.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34238,11 +34238,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 187.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 280.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34259,11 +34259,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 210.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 315.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34280,11 +34280,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 236.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 353.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34301,11 +34301,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 264.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 397.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34322,11 +34322,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 297.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 445.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34343,11 +34343,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 333.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 500.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34364,11 +34364,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 374.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 562.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34385,11 +34385,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 421.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 631.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34406,11 +34406,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 473.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 709.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34427,11 +34427,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 531.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 797.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34448,11 +34448,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 597.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 896.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34469,11 +34469,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 672.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1008.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34490,11 +34490,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 756.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1134.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34511,11 +34511,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 851.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1277.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34532,11 +34532,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 959.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1439.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34553,11 +34553,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1082.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1623.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34574,11 +34574,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1220.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1831.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -34721,11 +34721,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -47001,11 +47001,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47022,11 +47022,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47043,11 +47043,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47064,11 +47064,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47085,11 +47085,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47106,11 +47106,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 52.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47127,11 +47127,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47148,11 +47148,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47169,11 +47169,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 89.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47190,11 +47190,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 104.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47211,11 +47211,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 81.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 122.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47232,11 +47232,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 94.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 141.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47253,11 +47253,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 109.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 163.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47274,11 +47274,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 125.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 188.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47295,11 +47295,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 144.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 216.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47316,11 +47316,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 165.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 247.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47337,11 +47337,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 188.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 283.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47358,11 +47358,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 215.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 322.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47379,11 +47379,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 245.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 367.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47400,11 +47400,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 279.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 418.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47421,11 +47421,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 317.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 476.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47442,11 +47442,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 360.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 540.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47463,11 +47463,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 409.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 614.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47484,11 +47484,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 465.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 697.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47505,11 +47505,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 528.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 792.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47526,11 +47526,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 599.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 899.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47547,11 +47547,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 681.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1021.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47568,11 +47568,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 773.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1160.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47589,11 +47589,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 879.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1318.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47610,11 +47610,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 999.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1498.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47631,11 +47631,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1136.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1704.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47652,11 +47652,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1293.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1939.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47673,11 +47673,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1472.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2208.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47694,11 +47694,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1677.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2516.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47715,11 +47715,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1913.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2869.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47736,11 +47736,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2183.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3274.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47757,11 +47757,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2493.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3740.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47778,11 +47778,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2850.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 4275.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47799,11 +47799,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 3261.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 4892.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -47820,11 +47820,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 3735.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 5603.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -48969,11 +48969,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -48998,11 +48998,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49027,11 +49027,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49056,11 +49056,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 56.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 83.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49085,11 +49085,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 106.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49114,11 +49114,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 87.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 131.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49143,11 +49143,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 106.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 160.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49172,11 +49172,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 128.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 192.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49201,11 +49201,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 153.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 229.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49230,11 +49230,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 180.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 271.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49259,11 +49259,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 212.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 318.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49288,11 +49288,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 248.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 372.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49317,11 +49317,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 289.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 433.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49346,11 +49346,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 335.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 503.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49375,11 +49375,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 388.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 582.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49404,11 +49404,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 448.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 672.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49433,11 +49433,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 517.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 775.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49462,11 +49462,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 595.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 893.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49491,11 +49491,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 685.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1027.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49520,11 +49520,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 787.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1181.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49549,11 +49549,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 905.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1357.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49578,11 +49578,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1039.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1559.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49607,11 +49607,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1193.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1790.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49636,11 +49636,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1371.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2056.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49665,11 +49665,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1574.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2362.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49694,11 +49694,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1809.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2714.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49723,11 +49723,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2080.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3119.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49752,11 +49752,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2392.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3588.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49781,11 +49781,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2753.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 4129.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49810,11 +49810,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3170.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 4756.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49839,11 +49839,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3654.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5481.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49868,11 +49868,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4216.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 6324.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49897,11 +49897,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4868.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 7302.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49926,11 +49926,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 5627.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 8440.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49955,11 +49955,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6511.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 9766.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -49984,11 +49984,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7542.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 11313.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -50013,11 +50013,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 8747.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 13121.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -50042,11 +50042,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 10157.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 15235.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -50071,11 +50071,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 11808.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 17713.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -50100,11 +50100,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 13746.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 20619.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -77238,11 +77238,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77263,11 +77263,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77288,11 +77288,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77313,11 +77313,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77338,11 +77338,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77363,11 +77363,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77388,11 +77388,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77413,11 +77413,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77438,11 +77438,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77463,11 +77463,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77488,11 +77488,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77513,11 +77513,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77538,11 +77538,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77563,11 +77563,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77588,11 +77588,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77613,11 +77613,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77638,11 +77638,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77663,11 +77663,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77688,11 +77688,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77713,11 +77713,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 46.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77738,11 +77738,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77763,11 +77763,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77788,11 +77788,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77813,11 +77813,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 48.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77838,11 +77838,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 80.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77863,11 +77863,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 89.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77888,11 +77888,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 99.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77913,11 +77913,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 74.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 110.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77938,11 +77938,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 123.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77963,11 +77963,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 91.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -77988,11 +77988,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 102.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 153.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78013,11 +78013,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 170.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78038,11 +78038,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 190.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78063,11 +78063,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 141.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 212.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78088,11 +78088,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 157.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 236.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78113,11 +78113,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 176.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 264.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78138,11 +78138,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 196.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 294.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78163,11 +78163,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 219.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 329.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78188,11 +78188,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 245.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 367.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -78213,11 +78213,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 274.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 410.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -79375,7 +79375,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 1.0 + "value": 0.0 } ] }, @@ -79385,7 +79385,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 1.0 + "value": 0.0 } ] }, @@ -79395,7 +79395,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 1.0 + "value": 0.0 } ] }, @@ -79405,7 +79405,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 1.0 + "value": 0.0 } ] }, @@ -79415,7 +79415,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 1.0 + "value": 0.0 } ] }, @@ -79425,7 +79425,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 1.0 + "value": 0.0 } ] }, @@ -79435,7 +79435,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 1.0 + "value": 0.0 } ] }, @@ -79445,7 +79445,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 2.0 + "value": 0.0 } ] }, @@ -79455,7 +79455,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 2.0 + "value": 0.0 } ] }, @@ -79465,7 +79465,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 2.0 + "value": 0.0 } ] }, @@ -79475,7 +79475,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 2.0 + "value": 0.0 } ] }, @@ -79485,7 +79485,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 2.0 + "value": 0.0 } ] }, @@ -79495,7 +79495,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 2.0 + "value": 0.0 } ] }, @@ -79505,7 +79505,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 2.0 + "value": 0.0 } ] }, @@ -79515,7 +79515,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 2.0 + "value": 0.0 } ] }, @@ -79525,7 +79525,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79535,7 +79535,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79545,7 +79545,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79555,7 +79555,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79565,7 +79565,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79575,7 +79575,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79585,7 +79585,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79595,7 +79595,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79605,7 +79605,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79615,7 +79615,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79625,7 +79625,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79635,7 +79635,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79645,7 +79645,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79655,7 +79655,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79665,7 +79665,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79675,7 +79675,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79685,7 +79685,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79695,7 +79695,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79705,7 +79705,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79715,7 +79715,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79725,7 +79725,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79735,7 +79735,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79745,7 +79745,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79755,7 +79755,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] }, @@ -79765,7 +79765,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 3.0 + "value": 0.0 } ] } @@ -79874,7 +79874,7 @@ "stats": [ { "stat": "consume_parry_debuff_on_hit_to_gain_X_frenzy_charges", - "value": 1.0 + "value": 0.0 } ] } @@ -98640,11 +98640,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98665,11 +98665,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98690,11 +98690,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98715,11 +98715,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98740,11 +98740,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98765,11 +98765,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98790,11 +98790,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98815,11 +98815,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 52.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98840,11 +98840,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98865,11 +98865,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98890,11 +98890,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98915,11 +98915,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 99.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98940,11 +98940,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98965,11 +98965,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 88.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 132.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -98990,11 +98990,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 101.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 151.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99015,11 +99015,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 173.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99040,11 +99040,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 132.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 198.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99065,11 +99065,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 150.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 226.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99090,11 +99090,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 171.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 257.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99115,11 +99115,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 195.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 293.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99140,11 +99140,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 222.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 333.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99165,11 +99165,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 252.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 378.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99190,11 +99190,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 287.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 430.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99215,11 +99215,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 325.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 488.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99240,11 +99240,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 370.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 554.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99265,11 +99265,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 420.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 629.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99290,11 +99290,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 477.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 715.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99315,11 +99315,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 541.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 812.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99340,11 +99340,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 615.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 923.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99365,11 +99365,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 699.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1049.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99390,11 +99390,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 795.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1193.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99415,11 +99415,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 905.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1357.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99440,11 +99440,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1030.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1546.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99465,11 +99465,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1174.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1761.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99490,11 +99490,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1339.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2008.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99515,11 +99515,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1528.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2292.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99540,11 +99540,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1745.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2618.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99565,11 +99565,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1995.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2993.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99590,11 +99590,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2283.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3424.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -99615,11 +99615,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2615.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3922.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -103182,11 +103182,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103207,11 +103207,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103232,11 +103232,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103257,11 +103257,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103282,11 +103282,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103307,11 +103307,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103332,11 +103332,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103357,11 +103357,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103382,11 +103382,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103407,11 +103407,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103432,11 +103432,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103457,11 +103457,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103482,11 +103482,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 65.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103507,11 +103507,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103532,11 +103532,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 58.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 86.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103557,11 +103557,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 99.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103582,11 +103582,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 113.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103607,11 +103607,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 86.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103632,11 +103632,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 98.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 147.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103657,11 +103657,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 111.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 167.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103682,11 +103682,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 190.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103707,11 +103707,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 144.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 216.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103732,11 +103732,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 164.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 246.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103757,11 +103757,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 186.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 279.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103782,11 +103782,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 211.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 317.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103807,11 +103807,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 240.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 360.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103832,11 +103832,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 272.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 408.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103857,11 +103857,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 309.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 464.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103882,11 +103882,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 351.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 527.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103907,11 +103907,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 400.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 599.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103932,11 +103932,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 454.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 682.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103957,11 +103957,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 517.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 776.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -103982,11 +103982,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 589.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 883.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -104007,11 +104007,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 671.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1006.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -104032,11 +104032,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 765.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1148.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -104057,11 +104057,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 873.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1310.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -104082,11 +104082,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 997.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1496.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -104107,11 +104107,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1140.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1710.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -104132,11 +104132,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1305.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1957.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -104157,11 +104157,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1494.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2241.0 + "value": 0.0 }, { "stat": "base_number_of_entangle_roots_allowed", @@ -105856,11 +105856,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -105873,11 +105873,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -105890,11 +105890,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -105907,11 +105907,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -105924,11 +105924,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -105941,11 +105941,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -105958,11 +105958,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -105975,11 +105975,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 46.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -105992,11 +105992,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106009,11 +106009,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106026,11 +106026,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106043,11 +106043,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 87.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106060,11 +106060,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 54.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 100.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106077,11 +106077,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106094,11 +106094,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 133.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106111,11 +106111,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 152.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106128,11 +106128,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 93.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 173.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106145,11 +106145,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 107.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 198.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106162,11 +106162,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 121.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 226.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106179,11 +106179,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 138.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 257.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106196,11 +106196,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 157.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 292.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106213,11 +106213,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 179.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 332.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106230,11 +106230,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 203.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 377.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106247,11 +106247,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 230.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 428.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106264,11 +106264,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 262.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 486.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106281,11 +106281,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 297.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 552.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106298,11 +106298,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 627.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106315,11 +106315,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 383.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 712.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106332,11 +106332,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 436.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 809.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106349,11 +106349,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 495.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 920.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106366,11 +106366,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 563.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1046.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106383,11 +106383,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 641.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1190.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106400,11 +106400,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 730.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1355.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106417,11 +106417,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 832.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1545.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106434,11 +106434,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 948.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1761.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106451,11 +106451,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1082.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 2010.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106468,11 +106468,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1236.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 2296.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106485,11 +106485,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1413.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 2624.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106502,11 +106502,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1617.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 3003.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106519,11 +106519,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1852.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 3440.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -106638,11 +106638,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -112256,7 +112256,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 40.0 + "value": 0.0 } ] }, @@ -112270,7 +112270,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 41.0 + "value": 0.0 } ] }, @@ -112284,7 +112284,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 42.0 + "value": 0.0 } ] }, @@ -112298,7 +112298,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 43.0 + "value": 0.0 } ] }, @@ -112312,7 +112312,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 44.0 + "value": 0.0 } ] }, @@ -112326,7 +112326,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 45.0 + "value": 0.0 } ] }, @@ -112340,7 +112340,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 46.0 + "value": 0.0 } ] }, @@ -112354,7 +112354,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 47.0 + "value": 0.0 } ] }, @@ -112368,7 +112368,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 48.0 + "value": 0.0 } ] }, @@ -112382,7 +112382,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 49.0 + "value": 0.0 } ] }, @@ -112396,7 +112396,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 50.0 + "value": 0.0 } ] }, @@ -112410,7 +112410,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 51.0 + "value": 0.0 } ] }, @@ -112424,7 +112424,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 52.0 + "value": 0.0 } ] }, @@ -112438,7 +112438,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 53.0 + "value": 0.0 } ] }, @@ -112452,7 +112452,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 54.0 + "value": 0.0 } ] }, @@ -112466,7 +112466,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 55.0 + "value": 0.0 } ] }, @@ -112480,7 +112480,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 56.0 + "value": 0.0 } ] }, @@ -112494,7 +112494,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 57.0 + "value": 0.0 } ] }, @@ -112508,7 +112508,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 58.0 + "value": 0.0 } ] }, @@ -112522,7 +112522,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 59.0 + "value": 0.0 } ] }, @@ -112536,7 +112536,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 60.0 + "value": 0.0 } ] }, @@ -112550,7 +112550,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 61.0 + "value": 0.0 } ] }, @@ -112564,7 +112564,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 62.0 + "value": 0.0 } ] }, @@ -112578,7 +112578,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 63.0 + "value": 0.0 } ] }, @@ -112592,7 +112592,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 64.0 + "value": 0.0 } ] }, @@ -112606,7 +112606,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 65.0 + "value": 0.0 } ] }, @@ -112620,7 +112620,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 66.0 + "value": 0.0 } ] }, @@ -112634,7 +112634,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 67.0 + "value": 0.0 } ] }, @@ -112648,7 +112648,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 68.0 + "value": 0.0 } ] }, @@ -112662,7 +112662,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 69.0 + "value": 0.0 } ] }, @@ -112676,7 +112676,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 70.0 + "value": 0.0 } ] }, @@ -112690,7 +112690,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 71.0 + "value": 0.0 } ] }, @@ -112704,7 +112704,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 72.0 + "value": 0.0 } ] }, @@ -112718,7 +112718,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 73.0 + "value": 0.0 } ] }, @@ -112732,7 +112732,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 74.0 + "value": 0.0 } ] }, @@ -112746,7 +112746,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 75.0 + "value": 0.0 } ] }, @@ -112760,7 +112760,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 76.0 + "value": 0.0 } ] }, @@ -112774,7 +112774,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 77.0 + "value": 0.0 } ] }, @@ -112788,7 +112788,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 78.0 + "value": 0.0 } ] }, @@ -112802,7 +112802,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 79.0 + "value": 0.0 } ] } @@ -112965,7 +112965,7 @@ }, { "stat": "active_skill_base_area_of_effect_radius", - "value": 40.0 + "value": 0.0 } ] } @@ -117288,11 +117288,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 6.0 + "value": 0.0 } ] } @@ -117337,11 +117337,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -117362,11 +117362,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 4883.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 7324.0 + "value": 0.0 }, { "stat": "fire_djinn_flame_rune_tick_rate_ms", @@ -118602,11 +118602,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118623,11 +118623,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118644,11 +118644,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118665,11 +118665,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118686,11 +118686,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118707,11 +118707,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118728,11 +118728,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118749,11 +118749,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118770,11 +118770,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118791,11 +118791,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 88.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118812,11 +118812,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 68.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 102.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118833,11 +118833,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 79.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 118.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118854,11 +118854,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 91.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 136.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118875,11 +118875,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 104.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 156.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118896,11 +118896,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 119.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 178.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118917,11 +118917,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 135.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 203.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118938,11 +118938,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 154.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 231.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118959,11 +118959,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 174.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 262.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -118980,11 +118980,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 198.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 297.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119001,11 +119001,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 224.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 336.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119022,11 +119022,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 253.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 379.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119043,11 +119043,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 286.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 429.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119064,11 +119064,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 323.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 484.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119085,11 +119085,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 364.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 546.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119106,11 +119106,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 411.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 616.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119127,11 +119127,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 463.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 695.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119148,11 +119148,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 522.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 784.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119169,11 +119169,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 589.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 884.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119190,11 +119190,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 665.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 997.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119211,11 +119211,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 750.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1125.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119232,11 +119232,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 847.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1270.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119253,11 +119253,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 956.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1434.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119274,11 +119274,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1080.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1619.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119295,11 +119295,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1220.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1830.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119316,11 +119316,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1380.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2070.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119337,11 +119337,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1561.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2342.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119358,11 +119358,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1768.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2651.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119379,11 +119379,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2003.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3004.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119400,11 +119400,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2271.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3407.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -119421,11 +119421,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2577.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3866.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -121303,11 +121303,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121324,11 +121324,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121345,11 +121345,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121366,11 +121366,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121387,11 +121387,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121408,11 +121408,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121429,11 +121429,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121450,11 +121450,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121471,11 +121471,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121492,11 +121492,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121513,11 +121513,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121534,11 +121534,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 54.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121555,11 +121555,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121576,11 +121576,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121597,11 +121597,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 56.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 84.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121618,11 +121618,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 65.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 97.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121639,11 +121639,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 74.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 111.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121660,11 +121660,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121681,11 +121681,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 97.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 146.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121702,11 +121702,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 111.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 167.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121723,11 +121723,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 191.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121744,11 +121744,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 145.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 218.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121765,11 +121765,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 166.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 249.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121786,11 +121786,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 190.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 284.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121807,11 +121807,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 217.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 325.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121828,11 +121828,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 247.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 371.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121849,11 +121849,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 283.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 424.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121870,11 +121870,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 323.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 485.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121891,11 +121891,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 369.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 554.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121912,11 +121912,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 423.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 634.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121933,11 +121933,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 484.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 726.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121954,11 +121954,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 555.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 832.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121975,11 +121975,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 636.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 954.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -121996,11 +121996,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 730.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1095.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -122017,11 +122017,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 838.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1257.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -122038,11 +122038,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 964.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1446.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -122059,11 +122059,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1109.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1664.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -122080,11 +122080,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1278.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1917.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -122101,11 +122101,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1474.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2211.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -122122,11 +122122,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1702.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2553.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -122207,11 +122207,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122228,11 +122228,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122249,11 +122249,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122270,11 +122270,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122291,11 +122291,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122312,11 +122312,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122333,11 +122333,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122354,11 +122354,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122375,11 +122375,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122396,11 +122396,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122417,11 +122417,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122438,11 +122438,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 54.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122459,11 +122459,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122480,11 +122480,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122501,11 +122501,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 56.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 84.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122522,11 +122522,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 65.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 97.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122543,11 +122543,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 74.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 111.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122564,11 +122564,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122585,11 +122585,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 97.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 146.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122606,11 +122606,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 111.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 167.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122627,11 +122627,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 191.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122648,11 +122648,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 145.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 218.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122669,11 +122669,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 166.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 249.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122690,11 +122690,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 190.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 284.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122711,11 +122711,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 217.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 325.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122732,11 +122732,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 247.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 371.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122753,11 +122753,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 283.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 424.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122774,11 +122774,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 323.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 485.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122795,11 +122795,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 369.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 554.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122816,11 +122816,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 423.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 634.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122837,11 +122837,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 484.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 726.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122858,11 +122858,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 555.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 832.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122879,11 +122879,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 636.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 954.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122900,11 +122900,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 730.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1095.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122921,11 +122921,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 838.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1257.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122942,11 +122942,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 964.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1446.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122963,11 +122963,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1109.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1664.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -122984,11 +122984,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1278.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1917.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -123005,11 +123005,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1474.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2211.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -123026,11 +123026,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1702.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2553.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -123189,11 +123189,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -123274,11 +123274,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -125023,15 +125023,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 105.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125039,7 +125039,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4500.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125064,15 +125064,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 141.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125080,7 +125080,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4600.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125105,15 +125105,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 193.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125121,7 +125121,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4700.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125146,15 +125146,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 253.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125162,7 +125162,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4800.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125187,15 +125187,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 320.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125203,7 +125203,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4900.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125228,15 +125228,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 396.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125244,7 +125244,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5000.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125269,15 +125269,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 37.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 483.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125285,7 +125285,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5100.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125310,15 +125310,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 581.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125326,7 +125326,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5200.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125351,15 +125351,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 52.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 692.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125367,7 +125367,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5300.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125392,15 +125392,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 819.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125408,7 +125408,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5400.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125433,15 +125433,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 962.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125449,7 +125449,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5500.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125474,15 +125474,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1126.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125490,7 +125490,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5600.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125515,15 +125515,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 99.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1311.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125531,7 +125531,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5700.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125556,15 +125556,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 77.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1522.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125572,7 +125572,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5800.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125597,15 +125597,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 89.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 134.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1762.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125613,7 +125613,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5900.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125638,15 +125638,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 103.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 154.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 2035.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125654,7 +125654,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6000.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125679,15 +125679,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 119.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 178.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 2347.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125695,7 +125695,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6100.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125720,15 +125720,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 205.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 2703.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125736,7 +125736,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6200.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125761,15 +125761,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 157.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 236.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 3110.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125777,7 +125777,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6300.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125802,15 +125802,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 181.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 271.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 3575.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125818,7 +125818,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6400.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125843,15 +125843,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 208.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 311.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 4108.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125859,7 +125859,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6500.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125884,15 +125884,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 238.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 358.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 4718.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125900,7 +125900,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6600.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125925,15 +125925,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 274.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 411.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 5419.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125941,7 +125941,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6700.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -125966,15 +125966,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 314.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 472.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 6223.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -125982,7 +125982,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6800.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126007,15 +126007,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 361.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 542.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 7149.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126023,7 +126023,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6900.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126048,15 +126048,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 415.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 623.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 8214.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126064,7 +126064,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7000.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126089,15 +126089,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 477.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 716.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 9443.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126105,7 +126105,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7100.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126130,15 +126130,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 549.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 823.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 10861.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126146,7 +126146,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7200.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126171,15 +126171,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 632.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 947.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 12499.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126187,7 +126187,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7300.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126212,15 +126212,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 727.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1091.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 14396.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126228,7 +126228,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7400.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126253,15 +126253,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 838.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1258.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 16593.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126269,7 +126269,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7450.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126294,15 +126294,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 967.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1451.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 19142.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126310,7 +126310,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7500.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126335,15 +126335,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1117.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1675.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 22104.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126351,7 +126351,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7550.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126376,15 +126376,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1291.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1936.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 25550.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126392,7 +126392,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7600.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126417,15 +126417,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1494.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2241.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 29564.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126433,7 +126433,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7650.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126458,15 +126458,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1730.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2596.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 34247.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126474,7 +126474,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7700.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126499,15 +126499,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2007.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3010.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 39718.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126515,7 +126515,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7750.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126540,15 +126540,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2330.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3495.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 46118.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126556,7 +126556,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7800.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126581,15 +126581,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2709.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 4064.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 53617.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126597,7 +126597,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7850.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126622,15 +126622,15 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 3154.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 4730.0 + "value": 0.0 }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 62416.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126638,7 +126638,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7900.0 + "value": 0.0 }, { "stat": "flame_wall_minimum_added_fire_damage", @@ -126707,7 +126707,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 105.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126715,7 +126715,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4500.0 + "value": 0.0 } ] }, @@ -126732,7 +126732,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 141.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126740,7 +126740,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4600.0 + "value": 0.0 } ] }, @@ -126757,7 +126757,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 193.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126765,7 +126765,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4700.0 + "value": 0.0 } ] }, @@ -126782,7 +126782,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 253.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126790,7 +126790,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4800.0 + "value": 0.0 } ] }, @@ -126807,7 +126807,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 320.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126815,7 +126815,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 4900.0 + "value": 0.0 } ] }, @@ -126832,7 +126832,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 396.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126840,7 +126840,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5000.0 + "value": 0.0 } ] }, @@ -126857,7 +126857,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 483.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126865,7 +126865,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5100.0 + "value": 0.0 } ] }, @@ -126882,7 +126882,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 581.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126890,7 +126890,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5200.0 + "value": 0.0 } ] }, @@ -126907,7 +126907,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 692.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126915,7 +126915,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5300.0 + "value": 0.0 } ] }, @@ -126932,7 +126932,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 819.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126940,7 +126940,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5400.0 + "value": 0.0 } ] }, @@ -126957,7 +126957,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 962.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126965,7 +126965,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5500.0 + "value": 0.0 } ] }, @@ -126982,7 +126982,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1126.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -126990,7 +126990,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5600.0 + "value": 0.0 } ] }, @@ -127007,7 +127007,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1311.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127015,7 +127015,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5700.0 + "value": 0.0 } ] }, @@ -127032,7 +127032,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1522.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127040,7 +127040,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5800.0 + "value": 0.0 } ] }, @@ -127057,7 +127057,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1762.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127065,7 +127065,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 5900.0 + "value": 0.0 } ] }, @@ -127082,7 +127082,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 2035.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127090,7 +127090,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6000.0 + "value": 0.0 } ] }, @@ -127107,7 +127107,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 2347.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127115,7 +127115,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6100.0 + "value": 0.0 } ] }, @@ -127132,7 +127132,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 2703.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127140,7 +127140,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6200.0 + "value": 0.0 } ] }, @@ -127157,7 +127157,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 3110.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127165,7 +127165,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6300.0 + "value": 0.0 } ] }, @@ -127182,7 +127182,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 3575.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127190,7 +127190,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6400.0 + "value": 0.0 } ] }, @@ -127207,7 +127207,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 4108.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127215,7 +127215,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6500.0 + "value": 0.0 } ] }, @@ -127232,7 +127232,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 4718.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127240,7 +127240,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6600.0 + "value": 0.0 } ] }, @@ -127257,7 +127257,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 5419.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127265,7 +127265,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6700.0 + "value": 0.0 } ] }, @@ -127282,7 +127282,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 6223.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127290,7 +127290,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6800.0 + "value": 0.0 } ] }, @@ -127307,7 +127307,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 7149.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127315,7 +127315,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 6900.0 + "value": 0.0 } ] }, @@ -127332,7 +127332,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 8214.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127340,7 +127340,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7000.0 + "value": 0.0 } ] }, @@ -127357,7 +127357,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 9443.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127365,7 +127365,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7100.0 + "value": 0.0 } ] }, @@ -127382,7 +127382,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 10861.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127390,7 +127390,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7200.0 + "value": 0.0 } ] }, @@ -127407,7 +127407,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 12499.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127415,7 +127415,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7300.0 + "value": 0.0 } ] }, @@ -127432,7 +127432,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 14396.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127440,7 +127440,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7400.0 + "value": 0.0 } ] }, @@ -127457,7 +127457,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 16593.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127465,7 +127465,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7450.0 + "value": 0.0 } ] }, @@ -127482,7 +127482,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 19142.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127490,7 +127490,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7500.0 + "value": 0.0 } ] }, @@ -127507,7 +127507,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 22104.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127515,7 +127515,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7550.0 + "value": 0.0 } ] }, @@ -127532,7 +127532,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 25550.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127540,7 +127540,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7600.0 + "value": 0.0 } ] }, @@ -127557,7 +127557,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 29564.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127565,7 +127565,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7650.0 + "value": 0.0 } ] }, @@ -127582,7 +127582,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 34247.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127590,7 +127590,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7700.0 + "value": 0.0 } ] }, @@ -127607,7 +127607,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 39718.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127615,7 +127615,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7750.0 + "value": 0.0 } ] }, @@ -127632,7 +127632,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 46118.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127640,7 +127640,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7800.0 + "value": 0.0 } ] }, @@ -127657,7 +127657,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 53617.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127665,7 +127665,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7850.0 + "value": 0.0 } ] }, @@ -127682,7 +127682,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 62416.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -127690,7 +127690,7 @@ }, { "stat": "base_skill_effect_duration", - "value": 7900.0 + "value": 0.0 } ] } @@ -132609,7 +132609,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 2.0 + "value": 0.0 } ] }, @@ -132619,7 +132619,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 2.0 + "value": 0.0 } ] }, @@ -132629,7 +132629,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 2.0 + "value": 0.0 } ] }, @@ -132639,7 +132639,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 2.0 + "value": 0.0 } ] }, @@ -132649,7 +132649,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 2.0 + "value": 0.0 } ] }, @@ -132659,7 +132659,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 2.0 + "value": 0.0 } ] }, @@ -132669,7 +132669,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 2.0 + "value": 0.0 } ] }, @@ -132679,7 +132679,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 3.0 + "value": 0.0 } ] }, @@ -132689,7 +132689,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 3.0 + "value": 0.0 } ] }, @@ -132699,7 +132699,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 3.0 + "value": 0.0 } ] }, @@ -132709,7 +132709,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 3.0 + "value": 0.0 } ] }, @@ -132719,7 +132719,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 3.0 + "value": 0.0 } ] }, @@ -132729,7 +132729,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 3.0 + "value": 0.0 } ] }, @@ -132739,7 +132739,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 3.0 + "value": 0.0 } ] }, @@ -132749,7 +132749,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 3.0 + "value": 0.0 } ] }, @@ -132759,7 +132759,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 4.0 + "value": 0.0 } ] }, @@ -132769,7 +132769,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 4.0 + "value": 0.0 } ] }, @@ -132779,7 +132779,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 4.0 + "value": 0.0 } ] }, @@ -132789,7 +132789,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 4.0 + "value": 0.0 } ] }, @@ -132799,7 +132799,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 4.0 + "value": 0.0 } ] }, @@ -132809,7 +132809,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 4.0 + "value": 0.0 } ] }, @@ -132819,7 +132819,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 4.0 + "value": 0.0 } ] }, @@ -132829,7 +132829,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 4.0 + "value": 0.0 } ] }, @@ -132839,7 +132839,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132849,7 +132849,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132859,7 +132859,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132869,7 +132869,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132879,7 +132879,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132889,7 +132889,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132899,7 +132899,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132909,7 +132909,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132919,7 +132919,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132929,7 +132929,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132939,7 +132939,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132949,7 +132949,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132959,7 +132959,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132969,7 +132969,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132979,7 +132979,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132989,7 +132989,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] }, @@ -132999,7 +132999,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 5.0 + "value": 0.0 } ] } @@ -133184,7 +133184,7 @@ "stats": [ { "stat": "projectile_base_number_of_targets_to_pierce", - "value": 2.0 + "value": 0.0 } ] } @@ -137574,11 +137574,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137595,11 +137595,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137616,11 +137616,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137637,11 +137637,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137658,11 +137658,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137679,11 +137679,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137700,11 +137700,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137721,11 +137721,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137742,11 +137742,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137763,11 +137763,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137784,11 +137784,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137805,11 +137805,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137826,11 +137826,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137847,11 +137847,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137868,11 +137868,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137889,11 +137889,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137910,11 +137910,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137931,11 +137931,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137952,11 +137952,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 60.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137973,11 +137973,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 45.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 68.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -137994,11 +137994,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138015,11 +138015,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 86.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138036,11 +138036,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 96.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138057,11 +138057,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 72.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 108.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138078,11 +138078,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 81.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 122.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138099,11 +138099,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 91.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138120,11 +138120,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 102.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 154.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138141,11 +138141,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 173.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138162,11 +138162,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 194.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138183,11 +138183,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 145.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 218.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138204,11 +138204,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 163.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 244.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138225,11 +138225,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 183.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 275.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138246,11 +138246,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 206.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 309.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138267,11 +138267,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 231.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 347.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138288,11 +138288,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 260.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 390.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138309,11 +138309,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 293.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 439.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138330,11 +138330,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 330.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 495.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138351,11 +138351,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 372.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 557.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138372,11 +138372,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 419.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 628.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138393,11 +138393,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 473.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 709.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138454,11 +138454,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138475,11 +138475,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138496,11 +138496,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138517,11 +138517,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138538,11 +138538,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138559,11 +138559,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138580,11 +138580,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138601,11 +138601,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138622,11 +138622,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138643,11 +138643,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138664,11 +138664,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138685,11 +138685,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138706,11 +138706,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138727,11 +138727,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138748,11 +138748,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138769,11 +138769,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138790,11 +138790,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138811,11 +138811,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138832,11 +138832,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 60.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138853,11 +138853,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 45.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 68.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138874,11 +138874,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138895,11 +138895,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 86.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138916,11 +138916,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 96.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138937,11 +138937,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 72.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 108.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138958,11 +138958,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 81.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 122.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -138979,11 +138979,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 91.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139000,11 +139000,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 102.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 154.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139021,11 +139021,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 173.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139042,11 +139042,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 194.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139063,11 +139063,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 145.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 218.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139084,11 +139084,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 163.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 244.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139105,11 +139105,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 183.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 275.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139126,11 +139126,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 206.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 309.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139147,11 +139147,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 231.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 347.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139168,11 +139168,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 260.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 390.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139189,11 +139189,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 293.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 439.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139210,11 +139210,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 330.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 495.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139231,11 +139231,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 372.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 557.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139252,11 +139252,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 419.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 628.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -139273,11 +139273,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 473.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 709.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -140255,11 +140255,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140284,11 +140284,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140313,11 +140313,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140342,11 +140342,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140371,11 +140371,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140400,11 +140400,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140429,11 +140429,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 46.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140458,11 +140458,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 37.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140487,11 +140487,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 65.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140516,11 +140516,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140545,11 +140545,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 88.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140574,11 +140574,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 67.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 101.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140603,11 +140603,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 77.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 116.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140632,11 +140632,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 88.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 133.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140661,11 +140661,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 101.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 151.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140690,11 +140690,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 172.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140719,11 +140719,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 130.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 195.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140748,11 +140748,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 147.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 220.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140777,11 +140777,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 166.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 249.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140806,11 +140806,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 187.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 280.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140835,11 +140835,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 211.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 316.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140864,11 +140864,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 237.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 356.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140893,11 +140893,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 267.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 400.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140922,11 +140922,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 300.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 449.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140951,11 +140951,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 337.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 505.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -140980,11 +140980,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 378.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 567.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141009,11 +141009,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 425.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 637.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141038,11 +141038,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 477.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 715.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141067,11 +141067,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 535.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 803.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141096,11 +141096,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 601.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 902.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141125,11 +141125,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 675.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1013.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141154,11 +141154,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 759.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1138.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141183,11 +141183,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 853.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1279.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141212,11 +141212,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 959.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1438.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141241,11 +141241,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1079.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1618.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141270,11 +141270,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1214.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1821.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141299,11 +141299,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1367.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2051.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141328,11 +141328,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1540.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2311.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141357,11 +141357,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1737.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2605.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -141386,11 +141386,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1960.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2939.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142384,11 +142384,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142405,11 +142405,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142434,11 +142434,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142463,11 +142463,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142492,11 +142492,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142521,11 +142521,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 37.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142550,11 +142550,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142579,11 +142579,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142608,11 +142608,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 37.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142637,11 +142637,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142666,11 +142666,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 46.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 68.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142695,11 +142695,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142724,11 +142724,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142753,11 +142753,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 60.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 90.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142782,11 +142782,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 65.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 98.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142811,11 +142811,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 106.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142840,11 +142840,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142869,11 +142869,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 123.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142898,11 +142898,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 88.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 132.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142927,11 +142927,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 94.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 141.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142956,11 +142956,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 100.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 151.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -142985,11 +142985,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 107.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 161.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143014,11 +143014,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 171.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143043,11 +143043,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 121.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 182.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143072,11 +143072,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 193.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143101,11 +143101,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 136.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 204.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143130,11 +143130,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 144.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 216.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143159,11 +143159,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 152.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 229.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143188,11 +143188,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 161.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 241.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143217,11 +143217,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 170.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 255.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143246,11 +143246,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 179.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 268.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143275,11 +143275,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 188.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 282.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143304,11 +143304,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 198.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 297.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143333,11 +143333,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 208.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 312.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143362,11 +143362,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 218.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 328.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143391,11 +143391,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 229.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 344.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143420,11 +143420,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 240.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 361.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143449,11 +143449,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 252.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 378.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143478,11 +143478,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 264.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 396.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -143507,11 +143507,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 276.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 414.0 + "value": 0.0 }, { "stat": "wall_maximum_length", @@ -144273,11 +144273,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144298,11 +144298,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144323,11 +144323,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144348,11 +144348,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144373,11 +144373,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144398,11 +144398,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144423,11 +144423,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144448,11 +144448,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144473,11 +144473,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 48.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144498,11 +144498,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 56.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144523,11 +144523,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144548,11 +144548,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144573,11 +144573,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 58.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 87.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144598,11 +144598,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 67.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 100.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144623,11 +144623,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144648,11 +144648,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 87.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 130.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144673,11 +144673,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 99.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 148.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144698,11 +144698,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 112.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 168.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144723,11 +144723,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 190.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144748,11 +144748,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 144.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 216.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144773,11 +144773,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 162.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 244.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144798,11 +144798,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 184.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 275.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144823,11 +144823,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 207.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 311.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144848,11 +144848,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 234.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 351.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144873,11 +144873,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 264.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 396.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144898,11 +144898,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 298.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 446.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144923,11 +144923,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 336.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 503.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144948,11 +144948,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 379.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 568.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144973,11 +144973,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 427.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 640.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -144998,11 +144998,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 482.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 723.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145023,11 +145023,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 544.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 816.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145048,11 +145048,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 614.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 921.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145073,11 +145073,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 693.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1040.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145098,11 +145098,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 784.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1176.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145123,11 +145123,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 886.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1329.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145148,11 +145148,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1003.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1504.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145173,11 +145173,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1135.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1703.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145198,11 +145198,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1286.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1930.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145223,11 +145223,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1459.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2188.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145248,11 +145248,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1655.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2483.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -145355,11 +145355,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "active_skill_chill_effect_+%_final", @@ -207588,11 +207588,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207617,11 +207617,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207646,11 +207646,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207675,11 +207675,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207704,11 +207704,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207733,11 +207733,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207762,11 +207762,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207791,11 +207791,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207820,11 +207820,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207849,11 +207849,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207878,11 +207878,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207907,11 +207907,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207936,11 +207936,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 56.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207965,11 +207965,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 65.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -207994,11 +207994,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208023,11 +208023,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 58.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 86.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208052,11 +208052,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 99.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208081,11 +208081,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208110,11 +208110,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 87.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 130.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208139,11 +208139,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 99.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208168,11 +208168,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 170.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208197,11 +208197,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 130.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 195.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208226,11 +208226,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 148.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 222.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208255,11 +208255,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 169.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 254.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208284,11 +208284,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 193.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 290.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208313,11 +208313,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 221.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 331.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208342,11 +208342,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 252.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 379.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208371,11 +208371,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 288.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 433.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208400,11 +208400,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 330.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 495.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208429,11 +208429,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 377.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 566.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208458,11 +208458,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 432.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 648.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208487,11 +208487,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 495.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 743.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208516,11 +208516,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 568.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 852.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208545,11 +208545,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 652.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 977.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208574,11 +208574,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 749.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1123.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208603,11 +208603,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 861.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1291.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208632,11 +208632,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 991.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1486.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208661,11 +208661,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1141.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1712.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208690,11 +208690,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1316.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1974.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -208719,11 +208719,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1520.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2280.0 + "value": 0.0 }, { "stat": "frost_wall_maximum_life", @@ -221050,7 +221050,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 3000.0 + "value": 0.0 } ] }, @@ -221060,7 +221060,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2950.0 + "value": 0.0 } ] }, @@ -221070,7 +221070,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2900.0 + "value": 0.0 } ] }, @@ -221080,7 +221080,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2850.0 + "value": 0.0 } ] }, @@ -221090,7 +221090,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2800.0 + "value": 0.0 } ] }, @@ -221100,7 +221100,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2750.0 + "value": 0.0 } ] }, @@ -221110,7 +221110,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2700.0 + "value": 0.0 } ] }, @@ -221120,7 +221120,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2650.0 + "value": 0.0 } ] }, @@ -221130,7 +221130,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2600.0 + "value": 0.0 } ] }, @@ -221140,7 +221140,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2550.0 + "value": 0.0 } ] }, @@ -221150,7 +221150,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2500.0 + "value": 0.0 } ] }, @@ -221160,7 +221160,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2450.0 + "value": 0.0 } ] }, @@ -221170,7 +221170,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2400.0 + "value": 0.0 } ] }, @@ -221180,7 +221180,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2350.0 + "value": 0.0 } ] }, @@ -221190,7 +221190,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2300.0 + "value": 0.0 } ] }, @@ -221200,7 +221200,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2250.0 + "value": 0.0 } ] }, @@ -221210,7 +221210,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2200.0 + "value": 0.0 } ] }, @@ -221220,7 +221220,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2150.0 + "value": 0.0 } ] }, @@ -221230,7 +221230,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2100.0 + "value": 0.0 } ] }, @@ -221240,7 +221240,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2050.0 + "value": 0.0 } ] }, @@ -221250,7 +221250,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2050.0 + "value": 0.0 } ] }, @@ -221260,7 +221260,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2000.0 + "value": 0.0 } ] }, @@ -221270,7 +221270,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 2000.0 + "value": 0.0 } ] }, @@ -221280,7 +221280,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1950.0 + "value": 0.0 } ] }, @@ -221290,7 +221290,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1950.0 + "value": 0.0 } ] }, @@ -221300,7 +221300,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1900.0 + "value": 0.0 } ] }, @@ -221310,7 +221310,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1900.0 + "value": 0.0 } ] }, @@ -221320,7 +221320,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1850.0 + "value": 0.0 } ] }, @@ -221330,7 +221330,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1850.0 + "value": 0.0 } ] }, @@ -221340,7 +221340,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1800.0 + "value": 0.0 } ] }, @@ -221350,7 +221350,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1800.0 + "value": 0.0 } ] }, @@ -221360,7 +221360,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1750.0 + "value": 0.0 } ] }, @@ -221370,7 +221370,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1750.0 + "value": 0.0 } ] }, @@ -221380,7 +221380,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1700.0 + "value": 0.0 } ] }, @@ -221390,7 +221390,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1700.0 + "value": 0.0 } ] }, @@ -221400,7 +221400,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1700.0 + "value": 0.0 } ] }, @@ -221410,7 +221410,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1650.0 + "value": 0.0 } ] }, @@ -221420,7 +221420,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1650.0 + "value": 0.0 } ] }, @@ -221430,7 +221430,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1600.0 + "value": 0.0 } ] }, @@ -221440,7 +221440,7 @@ "stats": [ { "stat": "base_cooldown_modifiable_repeat_interval_ms", - "value": 1600.0 + "value": 0.0 } ] } @@ -225689,11 +225689,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225718,11 +225718,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225747,11 +225747,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225776,11 +225776,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225805,11 +225805,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225834,11 +225834,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225863,11 +225863,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225892,11 +225892,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 37.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225921,11 +225921,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225950,11 +225950,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -225979,11 +225979,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 60.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226008,11 +226008,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 46.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 69.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226037,11 +226037,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 79.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226066,11 +226066,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 91.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226095,11 +226095,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 69.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 104.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226124,11 +226124,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 79.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 119.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226153,11 +226153,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 90.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 135.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226182,11 +226182,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 102.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 153.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226211,11 +226211,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 116.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 173.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226240,11 +226240,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 131.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 196.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226269,11 +226269,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 148.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 222.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226298,11 +226298,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 167.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 251.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226327,11 +226327,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 189.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 283.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226356,11 +226356,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 213.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 319.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226385,11 +226385,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 240.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 360.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226414,11 +226414,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 271.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 406.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226443,11 +226443,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 305.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 458.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226472,11 +226472,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 345.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 517.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226501,11 +226501,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 389.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 583.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226530,11 +226530,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 438.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 658.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226559,11 +226559,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 495.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 742.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226588,11 +226588,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 559.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 838.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226617,11 +226617,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 631.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 947.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226646,11 +226646,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 713.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1070.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226675,11 +226675,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 807.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1210.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226704,11 +226704,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 913.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1369.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226733,11 +226733,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1033.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1550.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226762,11 +226762,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1171.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1756.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226791,11 +226791,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1328.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1992.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -226820,11 +226820,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1507.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2260.0 + "value": 0.0 }, { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", @@ -229991,11 +229991,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230012,11 +230012,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230033,11 +230033,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230054,11 +230054,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230075,11 +230075,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230096,11 +230096,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230117,11 +230117,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230138,11 +230138,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230159,11 +230159,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230180,11 +230180,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230201,11 +230201,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230222,11 +230222,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230243,11 +230243,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 54.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230264,11 +230264,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230285,11 +230285,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 48.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 72.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230306,11 +230306,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230327,11 +230327,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 94.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230348,11 +230348,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 72.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 107.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230369,11 +230369,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 122.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230390,11 +230390,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 93.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 139.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230411,11 +230411,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 106.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 159.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230432,11 +230432,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 120.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 180.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230453,11 +230453,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 136.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 205.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230474,11 +230474,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 155.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 232.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230495,11 +230495,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 176.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 264.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230516,11 +230516,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 200.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 300.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230537,11 +230537,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 227.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 340.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230558,11 +230558,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 258.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 387.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230579,11 +230579,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 293.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 439.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230600,11 +230600,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 333.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 499.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230621,11 +230621,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 379.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 568.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230642,11 +230642,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 431.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 646.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230663,11 +230663,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 491.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 736.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230684,11 +230684,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 559.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 839.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230705,11 +230705,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 638.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 956.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230726,11 +230726,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 728.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1091.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230747,11 +230747,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 831.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1247.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230768,11 +230768,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 950.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1425.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230789,11 +230789,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1087.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1631.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -230810,11 +230810,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1245.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1868.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -232830,7 +232830,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 101.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -232859,7 +232859,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 136.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -232888,7 +232888,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 187.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -232917,7 +232917,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 244.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -232946,7 +232946,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 309.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -232975,7 +232975,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 383.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233004,7 +233004,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 466.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233033,7 +233033,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 561.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233062,7 +233062,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 669.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233091,7 +233091,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 791.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233120,7 +233120,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 930.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233149,7 +233149,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1087.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233178,7 +233178,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1266.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233207,7 +233207,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1470.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233236,7 +233236,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1702.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233265,7 +233265,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 1966.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233294,7 +233294,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 2267.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233323,7 +233323,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 2611.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233352,7 +233352,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 3004.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233381,7 +233381,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 3453.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233410,7 +233410,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 3968.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233439,7 +233439,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 4557.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233468,7 +233468,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 5234.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233497,7 +233497,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 6011.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233526,7 +233526,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 6905.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233555,7 +233555,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 7934.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233584,7 +233584,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 9121.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233613,7 +233613,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 10491.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233642,7 +233642,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 12074.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233671,7 +233671,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 13905.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233700,7 +233700,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 16028.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233729,7 +233729,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 18490.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233758,7 +233758,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 21351.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233787,7 +233787,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 24680.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233816,7 +233816,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 28557.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233845,7 +233845,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 33080.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233874,7 +233874,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 38365.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233903,7 +233903,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 44547.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233932,7 +233932,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 51791.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -233961,7 +233961,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 60290.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -234152,7 +234152,7 @@ }, { "stat": "base_fire_damage_to_deal_per_minute", - "value": 104.0 + "value": 0.0 }, { "stat": "incinerate_fuel_gain_per_mana_spent", @@ -239221,11 +239221,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", @@ -242587,7 +242587,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242597,7 +242597,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242607,7 +242607,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242617,7 +242617,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242627,7 +242627,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242637,7 +242637,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242647,7 +242647,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242657,7 +242657,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242667,7 +242667,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 2.0 + "value": 0.0 } ] }, @@ -242677,7 +242677,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242687,7 +242687,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242697,7 +242697,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242707,7 +242707,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242717,7 +242717,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242727,7 +242727,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242737,7 +242737,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242747,7 +242747,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242757,7 +242757,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 3.0 + "value": 0.0 } ] }, @@ -242767,7 +242767,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242777,7 +242777,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242787,7 +242787,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242797,7 +242797,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242807,7 +242807,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242817,7 +242817,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242827,7 +242827,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242837,7 +242837,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242847,7 +242847,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 4.0 + "value": 0.0 } ] }, @@ -242857,7 +242857,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242867,7 +242867,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242877,7 +242877,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242887,7 +242887,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242897,7 +242897,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242907,7 +242907,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242917,7 +242917,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242927,7 +242927,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242937,7 +242937,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242947,7 +242947,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242957,7 +242957,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242967,7 +242967,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] }, @@ -242977,7 +242977,7 @@ "stats": [ { "stat": "lightning_arrow_maximum_number_of_extra_targets", - "value": 5.0 + "value": 0.0 } ] } @@ -255190,11 +255190,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 26.0 + "value": 0.0 } ] } @@ -290684,11 +290684,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -333421,7 +333421,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333442,7 +333442,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333463,7 +333463,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333484,7 +333484,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333505,7 +333505,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333526,7 +333526,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333547,7 +333547,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333568,7 +333568,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333589,7 +333589,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333610,7 +333610,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333631,7 +333631,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333652,7 +333652,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333673,7 +333673,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333694,7 +333694,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333715,7 +333715,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333736,7 +333736,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333757,7 +333757,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333778,7 +333778,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333799,7 +333799,7 @@ }, { "stat": "number_of_chains", - "value": 3.0 + "value": 0.0 } ] }, @@ -333820,7 +333820,7 @@ }, { "stat": "number_of_chains", - "value": 4.0 + "value": 0.0 } ] }, @@ -333841,7 +333841,7 @@ }, { "stat": "number_of_chains", - "value": 4.0 + "value": 0.0 } ] }, @@ -333862,7 +333862,7 @@ }, { "stat": "number_of_chains", - "value": 4.0 + "value": 0.0 } ] }, @@ -333883,7 +333883,7 @@ }, { "stat": "number_of_chains", - "value": 4.0 + "value": 0.0 } ] }, @@ -333904,7 +333904,7 @@ }, { "stat": "number_of_chains", - "value": 4.0 + "value": 0.0 } ] }, @@ -333925,7 +333925,7 @@ }, { "stat": "number_of_chains", - "value": 4.0 + "value": 0.0 } ] }, @@ -333946,7 +333946,7 @@ }, { "stat": "number_of_chains", - "value": 4.0 + "value": 0.0 } ] }, @@ -333967,7 +333967,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -333988,7 +333988,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -334009,7 +334009,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -334030,7 +334030,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -334051,7 +334051,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -334072,7 +334072,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -334093,7 +334093,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -334114,7 +334114,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -334135,7 +334135,7 @@ }, { "stat": "number_of_chains", - "value": 5.0 + "value": 0.0 } ] }, @@ -334156,7 +334156,7 @@ }, { "stat": "number_of_chains", - "value": 6.0 + "value": 0.0 } ] }, @@ -334177,7 +334177,7 @@ }, { "stat": "number_of_chains", - "value": 6.0 + "value": 0.0 } ] }, @@ -334198,7 +334198,7 @@ }, { "stat": "number_of_chains", - "value": 6.0 + "value": 0.0 } ] }, @@ -334219,7 +334219,7 @@ }, { "stat": "number_of_chains", - "value": 6.0 + "value": 0.0 } ] }, @@ -334240,7 +334240,7 @@ }, { "stat": "number_of_chains", - "value": 7.0 + "value": 0.0 } ] } @@ -340196,11 +340196,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340230,11 +340230,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340264,11 +340264,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340298,11 +340298,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340332,11 +340332,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340366,11 +340366,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340400,11 +340400,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340434,11 +340434,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340468,11 +340468,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340502,11 +340502,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340536,11 +340536,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340570,11 +340570,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340604,11 +340604,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340638,11 +340638,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340672,11 +340672,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340706,11 +340706,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340740,11 +340740,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340774,11 +340774,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340808,11 +340808,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340842,11 +340842,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340876,11 +340876,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340910,11 +340910,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340944,11 +340944,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -340978,11 +340978,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341012,11 +341012,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341046,11 +341046,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341080,11 +341080,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341114,11 +341114,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341148,11 +341148,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341182,11 +341182,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341216,11 +341216,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341250,11 +341250,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341284,11 +341284,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341318,11 +341318,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341352,11 +341352,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341386,11 +341386,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341420,11 +341420,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341454,11 +341454,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341488,11 +341488,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -341522,11 +341522,11 @@ }, { "stat": "off_hand_minimum_added_physical_damage_per_15_shield_armour", - "value": 3.0 + "value": 0.0 }, { "stat": "off_hand_maximum_added_physical_damage_per_15_shield_armour", - "value": 5.0 + "value": 0.0 }, { "stat": "base_movement_velocity_+%", @@ -350779,19 +350779,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -350820,19 +350820,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -350861,19 +350861,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 45.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 45.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -350902,19 +350902,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 39.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 39.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -350943,19 +350943,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 74.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 74.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -350984,19 +350984,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 92.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 92.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351025,19 +351025,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 112.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 75.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 112.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351066,19 +351066,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 90.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 135.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 90.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 135.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351107,19 +351107,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 107.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 161.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 107.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 161.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351148,19 +351148,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 190.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 190.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351189,19 +351189,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 223.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 223.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351230,19 +351230,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 174.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 261.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 174.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 261.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351271,19 +351271,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 203.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 304.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 203.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 304.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351312,19 +351312,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 235.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 353.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 235.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 353.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351353,19 +351353,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 272.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 408.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 272.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 408.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351394,19 +351394,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 315.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 472.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 315.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 472.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351435,19 +351435,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 363.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 544.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 363.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 544.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351476,19 +351476,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 418.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 627.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 418.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 627.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351517,19 +351517,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 481.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 721.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 481.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 721.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351558,19 +351558,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 553.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 829.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 553.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 829.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351599,19 +351599,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 635.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 952.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 635.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 952.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351640,19 +351640,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 729.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1094.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 729.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1094.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351681,19 +351681,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 837.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1256.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 837.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1256.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351722,19 +351722,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 962.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1443.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 962.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1443.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351763,19 +351763,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1105.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1657.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 1105.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1657.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351804,19 +351804,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1270.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1904.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 1270.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1904.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351845,19 +351845,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1459.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2189.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 1459.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2189.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351886,19 +351886,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1679.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2518.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 1679.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2518.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351927,19 +351927,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1932.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2898.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 1932.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2898.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -351968,19 +351968,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2225.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3337.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 2225.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3337.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352009,19 +352009,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2564.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3847.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 2564.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3847.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352050,19 +352050,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2958.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 4438.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 2958.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 4438.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352091,19 +352091,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3416.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5124.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 3416.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 5124.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352132,19 +352132,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3949.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5923.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 3949.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 5923.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352173,19 +352173,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4569.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 6854.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 4569.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 6854.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352214,19 +352214,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 5293.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 7939.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 5293.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 7939.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352255,19 +352255,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6138.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 9208.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 6138.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 9208.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352296,19 +352296,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7128.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 10691.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 7128.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 10691.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352337,19 +352337,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 8287.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 12430.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 8287.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 12430.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -352378,19 +352378,19 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 9646.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 14470.0 + "value": 0.0 }, { "stat": "spell_minimum_base_physical_damage", - "value": 9646.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 14470.0 + "value": 0.0 }, { "stat": "active_skill_requires_X_glory", @@ -353403,11 +353403,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353424,11 +353424,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353445,11 +353445,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353466,11 +353466,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353487,11 +353487,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353508,11 +353508,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 52.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 79.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353529,11 +353529,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 96.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353550,11 +353550,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 77.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353571,11 +353571,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 92.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353592,11 +353592,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 108.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 162.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353613,11 +353613,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 191.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353634,11 +353634,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 223.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353655,11 +353655,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 173.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 260.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353676,11 +353676,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 201.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 302.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353697,11 +353697,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 233.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 350.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353718,11 +353718,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 269.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 404.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353739,11 +353739,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 310.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 466.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353760,11 +353760,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 358.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 536.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353781,11 +353781,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 411.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 617.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353802,11 +353802,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 473.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 709.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353823,11 +353823,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 543.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 815.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353844,11 +353844,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 624.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 936.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353865,11 +353865,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 717.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1075.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353886,11 +353886,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 823.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1235.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353907,11 +353907,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 945.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1418.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353928,11 +353928,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1086.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1630.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353949,11 +353949,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1249.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1873.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353970,11 +353970,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1436.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2155.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -353991,11 +353991,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1653.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2480.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354012,11 +354012,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1904.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2856.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354033,11 +354033,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2195.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3292.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354054,11 +354054,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2532.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3798.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354075,11 +354075,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2923.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 4385.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354096,11 +354096,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3379.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5069.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354117,11 +354117,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3910.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5865.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354138,11 +354138,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4529.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 6794.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354159,11 +354159,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 5253.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 7880.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354180,11 +354180,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6100.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 9149.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354201,11 +354201,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7091.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 10637.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354222,11 +354222,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 8255.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 12383.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -354287,11 +354287,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354308,11 +354308,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 19.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354329,11 +354329,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354350,11 +354350,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 50.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354371,11 +354371,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 42.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354392,11 +354392,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 52.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 79.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354413,11 +354413,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 64.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 96.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354434,11 +354434,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 77.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354455,11 +354455,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 92.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354476,11 +354476,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 108.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 162.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354497,11 +354497,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 191.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354518,11 +354518,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 223.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354539,11 +354539,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 173.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 260.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354560,11 +354560,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 201.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 302.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354581,11 +354581,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 233.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 350.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354602,11 +354602,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 269.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 404.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354623,11 +354623,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 310.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 466.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354644,11 +354644,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 358.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 536.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354665,11 +354665,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 411.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 617.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354686,11 +354686,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 473.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 709.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354707,11 +354707,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 543.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 815.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354728,11 +354728,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 624.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 936.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354749,11 +354749,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 717.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1075.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354770,11 +354770,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 823.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1235.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354791,11 +354791,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 945.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1418.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354812,11 +354812,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1086.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1630.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354833,11 +354833,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1249.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 1873.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354854,11 +354854,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1436.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2155.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354875,11 +354875,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1653.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2480.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354896,11 +354896,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 1904.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 2856.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354917,11 +354917,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2195.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3292.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354938,11 +354938,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2532.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 3798.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354959,11 +354959,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 2923.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 4385.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -354980,11 +354980,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3379.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5069.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -355001,11 +355001,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 3910.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 5865.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -355022,11 +355022,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 4529.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 6794.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -355043,11 +355043,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 5253.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 7880.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -355064,11 +355064,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 6100.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 9149.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -355085,11 +355085,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 7091.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 10637.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -355106,11 +355106,11 @@ "stats": [ { "stat": "spell_minimum_base_cold_damage", - "value": 8255.0 + "value": 0.0 }, { "stat": "spell_maximum_base_cold_damage", - "value": 12383.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -360030,11 +360030,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360047,11 +360047,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360064,11 +360064,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360081,11 +360081,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360098,11 +360098,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360115,11 +360115,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360132,11 +360132,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 33.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360149,11 +360149,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360166,11 +360166,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360183,11 +360183,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360200,11 +360200,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360217,11 +360217,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360234,11 +360234,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 94.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360251,11 +360251,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 58.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 109.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360268,11 +360268,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 67.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 125.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360285,11 +360285,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 77.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 143.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360302,11 +360302,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 88.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 163.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360319,11 +360319,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 100.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 186.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360336,11 +360336,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 212.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360353,11 +360353,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 130.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 242.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360370,11 +360370,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 148.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 275.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360387,11 +360387,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 168.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 312.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360404,11 +360404,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 191.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 355.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360421,11 +360421,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 217.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 403.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360438,11 +360438,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 246.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 457.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360455,11 +360455,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 280.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 520.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360472,11 +360472,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 318.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 590.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360489,11 +360489,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 361.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 670.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360506,11 +360506,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 410.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 762.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360523,11 +360523,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 466.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 866.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360540,11 +360540,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 530.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 985.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360557,11 +360557,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 603.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1120.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360574,11 +360574,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 687.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1276.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360591,11 +360591,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 783.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1454.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360608,11 +360608,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 893.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1658.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360625,11 +360625,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1019.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 1892.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360642,11 +360642,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1163.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 2161.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360659,11 +360659,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1330.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 2470.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360676,11 +360676,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1522.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 2826.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -360693,11 +360693,11 @@ "stats": [ { "stat": "spell_minimum_base_chaos_damage", - "value": 1743.0 + "value": 0.0 }, { "stat": "spell_maximum_base_chaos_damage", - "value": 3237.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -361513,15 +361513,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361550,15 +361550,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361587,15 +361587,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361624,15 +361624,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361661,15 +361661,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361698,15 +361698,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361735,15 +361735,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361772,15 +361772,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 45.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361809,15 +361809,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361846,15 +361846,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361883,15 +361883,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361920,15 +361920,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 81.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361957,15 +361957,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 93.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -361994,15 +361994,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 106.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362031,15 +362031,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 120.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362068,15 +362068,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 135.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362105,15 +362105,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 153.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362142,15 +362142,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 172.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362179,15 +362179,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 193.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362216,15 +362216,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 216.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362253,15 +362253,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 242.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362290,15 +362290,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 271.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362327,15 +362327,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 303.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362364,15 +362364,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362401,15 +362401,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 378.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362438,15 +362438,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 421.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362475,15 +362475,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 470.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362512,15 +362512,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 524.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362549,15 +362549,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 584.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362586,15 +362586,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 651.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362623,15 +362623,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 726.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362660,15 +362660,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 809.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362697,15 +362697,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 902.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362734,15 +362734,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1006.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362771,15 +362771,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1122.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362808,15 +362808,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1252.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362845,15 +362845,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 74.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1398.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362882,15 +362882,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1561.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362919,15 +362919,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 92.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1744.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -362956,15 +362956,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 103.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1949.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -397079,7 +397079,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 } ] }, @@ -397089,7 +397089,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 } ] }, @@ -397099,7 +397099,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 } ] }, @@ -397109,7 +397109,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 } ] }, @@ -397119,7 +397119,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 } ] }, @@ -397129,7 +397129,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 } ] }, @@ -397139,7 +397139,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 } ] }, @@ -397149,7 +397149,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 } ] }, @@ -397159,7 +397159,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 } ] }, @@ -397169,7 +397169,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 } ] }, @@ -397179,7 +397179,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 } ] }, @@ -397189,7 +397189,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 } ] }, @@ -397199,7 +397199,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 } ] }, @@ -397209,7 +397209,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 } ] }, @@ -397219,7 +397219,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 } ] }, @@ -397229,7 +397229,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 } ] }, @@ -397239,7 +397239,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 } ] }, @@ -397249,7 +397249,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 } ] }, @@ -397259,7 +397259,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 } ] }, @@ -397269,7 +397269,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 } ] }, @@ -397279,7 +397279,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 } ] }, @@ -397289,7 +397289,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 } ] }, @@ -397299,7 +397299,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 } ] }, @@ -397309,7 +397309,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397319,7 +397319,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397329,7 +397329,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397339,7 +397339,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397349,7 +397349,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397359,7 +397359,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397369,7 +397369,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397379,7 +397379,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397389,7 +397389,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397399,7 +397399,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397409,7 +397409,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397419,7 +397419,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397429,7 +397429,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397439,7 +397439,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397449,7 +397449,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397459,7 +397459,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] }, @@ -397469,7 +397469,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 } ] } @@ -397535,7 +397535,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397553,7 +397553,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397571,7 +397571,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397589,7 +397589,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397607,7 +397607,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397625,7 +397625,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397643,7 +397643,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397661,7 +397661,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397679,7 +397679,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397697,7 +397697,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397715,7 +397715,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397733,7 +397733,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397751,7 +397751,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397769,7 +397769,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397786,7 +397786,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397804,7 +397804,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397822,7 +397822,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397840,7 +397840,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397858,7 +397858,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397876,7 +397876,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397894,7 +397894,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397912,7 +397912,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397930,7 +397930,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397948,7 +397948,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397966,7 +397966,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -397984,7 +397984,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398002,7 +398002,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398020,7 +398020,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398038,7 +398038,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398056,7 +398056,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398074,7 +398074,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398092,7 +398092,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398110,7 +398110,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398128,7 +398128,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398146,7 +398146,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398164,7 +398164,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398182,7 +398182,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398200,7 +398200,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398218,7 +398218,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -398236,7 +398236,7 @@ "stats": [ { "stat": "base_number_of_tempest_bells_allowed", - "value": 4.0 + "value": 0.0 }, { "stat": "bell_ailment_threshold", @@ -420463,15 +420463,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420500,15 +420500,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420537,15 +420537,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420574,15 +420574,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420611,15 +420611,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420648,15 +420648,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420685,15 +420685,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420722,15 +420722,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420759,15 +420759,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420796,15 +420796,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420833,15 +420833,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420870,15 +420870,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 54.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420907,15 +420907,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420944,15 +420944,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -420981,15 +420981,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 80.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421018,15 +421018,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 90.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421055,15 +421055,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 102.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421092,15 +421092,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421129,15 +421129,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421166,15 +421166,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 144.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421203,15 +421203,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 162.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421240,15 +421240,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 181.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421277,15 +421277,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 202.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421314,15 +421314,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 226.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421351,15 +421351,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 252.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421388,15 +421388,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 281.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421425,15 +421425,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 313.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421462,15 +421462,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 349.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421499,15 +421499,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 389.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421536,15 +421536,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 434.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421573,15 +421573,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 484.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421610,15 +421610,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 539.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421647,15 +421647,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 601.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421684,15 +421684,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 671.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421721,15 +421721,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 39.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 748.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421758,15 +421758,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 835.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421795,15 +421795,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 932.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421832,15 +421832,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1041.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421869,15 +421869,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1163.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -421906,15 +421906,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 68.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1300.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422676,15 +422676,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422713,15 +422713,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422750,15 +422750,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422787,15 +422787,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422824,15 +422824,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422861,15 +422861,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422898,15 +422898,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422935,15 +422935,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -422972,15 +422972,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423009,15 +423009,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423046,15 +423046,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423083,15 +423083,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 54.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423120,15 +423120,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423157,15 +423157,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423194,15 +423194,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 80.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423231,15 +423231,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 90.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423268,15 +423268,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 102.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423305,15 +423305,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423342,15 +423342,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423379,15 +423379,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 144.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423416,15 +423416,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 162.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423453,15 +423453,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 181.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423490,15 +423490,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 202.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423527,15 +423527,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 226.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423564,15 +423564,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 252.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423601,15 +423601,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 281.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423638,15 +423638,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 313.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423675,15 +423675,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 349.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423712,15 +423712,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 389.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423749,15 +423749,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 434.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423786,15 +423786,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 484.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423823,15 +423823,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 539.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423860,15 +423860,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 601.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423897,15 +423897,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 671.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423934,15 +423934,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 39.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 748.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -423971,15 +423971,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 835.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -424008,15 +424008,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 932.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -424045,15 +424045,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1041.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -424082,15 +424082,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1163.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -424119,15 +424119,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 68.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1300.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -425807,11 +425807,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425828,11 +425828,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425849,11 +425849,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425870,11 +425870,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425891,11 +425891,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425912,11 +425912,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425933,11 +425933,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425954,11 +425954,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425975,11 +425975,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -425996,11 +425996,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426017,11 +426017,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 60.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426038,11 +426038,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426059,11 +426059,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426080,11 +426080,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 95.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426101,11 +426101,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 110.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426122,11 +426122,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426143,11 +426143,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 98.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 146.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426164,11 +426164,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 112.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 169.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426185,11 +426185,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 194.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426206,11 +426206,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 223.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426227,11 +426227,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 171.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 256.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426248,11 +426248,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 196.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 294.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426269,11 +426269,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 225.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426290,11 +426290,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 259.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 388.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426311,11 +426311,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 297.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 446.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426332,11 +426332,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 342.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 513.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426353,11 +426353,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 393.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 589.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426374,11 +426374,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 452.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 678.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426395,11 +426395,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 520.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 780.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426416,11 +426416,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 599.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 898.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426437,11 +426437,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 690.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1036.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426458,11 +426458,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 797.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1195.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426479,11 +426479,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 920.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1380.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426500,11 +426500,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1063.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1595.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426521,11 +426521,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1230.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1845.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426542,11 +426542,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1425.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2138.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426563,11 +426563,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1653.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2479.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426584,11 +426584,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1919.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2878.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426605,11 +426605,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2231.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3347.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426626,11 +426626,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2597.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3896.0 + "value": 0.0 }, { "stat": "spell_minimum_base_cold_damage", @@ -426659,11 +426659,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426680,11 +426680,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426701,11 +426701,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426722,11 +426722,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426743,11 +426743,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426764,11 +426764,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426785,11 +426785,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426806,11 +426806,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426827,11 +426827,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426848,11 +426848,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426869,11 +426869,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 60.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426890,11 +426890,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426911,11 +426911,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426932,11 +426932,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 95.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426953,11 +426953,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 110.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426974,11 +426974,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -426995,11 +426995,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 98.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 146.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427016,11 +427016,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 112.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 169.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427037,11 +427037,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 194.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427058,11 +427058,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 223.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427079,11 +427079,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 171.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 256.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427100,11 +427100,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 196.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 294.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427121,11 +427121,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 225.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427142,11 +427142,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 259.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 388.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427163,11 +427163,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 297.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 446.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427184,11 +427184,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 342.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 513.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427205,11 +427205,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 393.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 589.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427226,11 +427226,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 452.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 678.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427247,11 +427247,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 520.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 780.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427268,11 +427268,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 599.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 898.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427289,11 +427289,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 690.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1036.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427310,11 +427310,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 797.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1195.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427331,11 +427331,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 920.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1380.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427352,11 +427352,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1063.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1595.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427373,11 +427373,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1230.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1845.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427394,11 +427394,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1425.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2138.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427415,11 +427415,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1653.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2479.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427436,11 +427436,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1919.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2878.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427457,11 +427457,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2231.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3347.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427478,11 +427478,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2597.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3896.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -427511,11 +427511,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427532,11 +427532,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427553,11 +427553,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427574,11 +427574,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427595,11 +427595,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427616,11 +427616,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427637,11 +427637,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427658,11 +427658,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427679,11 +427679,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427700,11 +427700,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427721,11 +427721,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 60.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427742,11 +427742,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427763,11 +427763,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427784,11 +427784,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 95.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427805,11 +427805,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 110.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427826,11 +427826,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427847,11 +427847,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 98.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 146.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427868,11 +427868,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 112.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 169.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427889,11 +427889,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 194.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427910,11 +427910,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 223.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427931,11 +427931,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 171.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 256.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427952,11 +427952,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 196.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 294.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427973,11 +427973,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 225.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -427994,11 +427994,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 259.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 388.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428015,11 +428015,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 297.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 446.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428036,11 +428036,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 342.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 513.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428057,11 +428057,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 393.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 589.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428078,11 +428078,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 452.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 678.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428099,11 +428099,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 520.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 780.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428120,11 +428120,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 599.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 898.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428141,11 +428141,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 690.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1036.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428162,11 +428162,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 797.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1195.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428183,11 +428183,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 920.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1380.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428204,11 +428204,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1063.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1595.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428225,11 +428225,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1230.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1845.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428246,11 +428246,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1425.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2138.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428267,11 +428267,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1653.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2479.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428288,11 +428288,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1919.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2878.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428309,11 +428309,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2231.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3347.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428330,11 +428330,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2597.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3896.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -428363,11 +428363,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428384,11 +428384,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428405,11 +428405,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428426,11 +428426,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428447,11 +428447,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428468,11 +428468,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428489,11 +428489,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428510,11 +428510,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428531,11 +428531,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428552,11 +428552,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 51.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428573,11 +428573,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 40.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 60.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428594,11 +428594,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 70.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428615,11 +428615,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 55.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428636,11 +428636,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 95.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428657,11 +428657,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 110.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428678,11 +428678,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 127.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428699,11 +428699,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 98.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 146.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428720,11 +428720,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 112.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 169.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428741,11 +428741,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 129.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 194.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428762,11 +428762,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 149.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 223.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428783,11 +428783,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 171.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 256.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428804,11 +428804,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 196.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 294.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428825,11 +428825,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 225.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428846,11 +428846,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 259.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 388.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428867,11 +428867,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 297.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 446.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428888,11 +428888,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 342.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 513.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428909,11 +428909,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 393.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 589.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428930,11 +428930,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 452.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 678.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428951,11 +428951,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 520.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 780.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428972,11 +428972,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 599.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 898.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -428993,11 +428993,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 690.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1036.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429014,11 +429014,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 797.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1195.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429035,11 +429035,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 920.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1380.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429056,11 +429056,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1063.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1595.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429077,11 +429077,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1230.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 1845.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429098,11 +429098,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1425.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2138.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429119,11 +429119,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1653.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2479.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429140,11 +429140,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 1919.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 2878.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429161,11 +429161,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2231.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3347.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -429182,11 +429182,11 @@ "stats": [ { "stat": "spell_minimum_base_physical_damage", - "value": 2597.0 + "value": 0.0 }, { "stat": "spell_maximum_base_physical_damage", - "value": 3896.0 + "value": 0.0 }, { "stat": "spell_minimum_base_chaos_damage", @@ -443951,11 +443951,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -443976,11 +443976,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444001,11 +444001,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444026,11 +444026,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 23.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444051,11 +444051,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444076,11 +444076,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 24.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 36.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444101,11 +444101,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 29.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 44.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444126,11 +444126,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 52.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444151,11 +444151,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444176,11 +444176,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 73.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444201,11 +444201,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 57.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 85.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444226,11 +444226,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 99.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444251,11 +444251,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 76.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 114.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444276,11 +444276,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 88.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 132.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444301,11 +444301,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 101.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 151.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444326,11 +444326,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 115.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 173.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444351,11 +444351,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 132.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 198.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444376,11 +444376,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 150.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 226.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444401,11 +444401,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 171.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 257.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444426,11 +444426,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 195.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 293.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444451,11 +444451,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 222.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 333.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444476,11 +444476,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 252.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 378.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444501,11 +444501,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 287.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 430.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444526,11 +444526,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 325.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 488.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444551,11 +444551,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 370.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 554.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444576,11 +444576,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 420.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 629.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444601,11 +444601,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 477.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 715.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444626,11 +444626,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 541.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 812.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444651,11 +444651,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 615.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 923.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444676,11 +444676,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 699.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1049.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444701,11 +444701,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 795.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1193.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444726,11 +444726,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 905.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1357.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444751,11 +444751,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1030.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1546.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444776,11 +444776,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1174.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1761.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444801,11 +444801,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1339.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2008.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444826,11 +444826,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1528.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2292.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444851,11 +444851,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1745.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2618.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444876,11 +444876,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1995.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2993.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444901,11 +444901,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2283.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3424.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -444926,11 +444926,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 2615.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 3922.0 + "value": 0.0 }, { "stat": "blazing_cluster_maximum_number_of_projectiles_allowed", @@ -445720,15 +445720,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -445757,15 +445757,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -445794,15 +445794,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 17.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -445831,15 +445831,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 21.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -445868,15 +445868,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 1.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -445905,15 +445905,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -445942,15 +445942,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -445979,15 +445979,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 2.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 45.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446016,15 +446016,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446053,15 +446053,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 3.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446090,15 +446090,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446127,15 +446127,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 81.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446164,15 +446164,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 93.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446201,15 +446201,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 106.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446238,15 +446238,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 120.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446275,15 +446275,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 135.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446312,15 +446312,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 153.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446349,15 +446349,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 172.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446386,15 +446386,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 193.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446423,15 +446423,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 216.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446460,15 +446460,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 242.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 9.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446497,15 +446497,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 271.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446534,15 +446534,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 16.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 303.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446571,15 +446571,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 338.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446608,15 +446608,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 20.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 378.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446645,15 +446645,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 421.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446682,15 +446682,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 25.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 470.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446719,15 +446719,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 28.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 524.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446756,15 +446756,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 31.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 584.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446793,15 +446793,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 34.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 651.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446830,15 +446830,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 726.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446867,15 +446867,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 43.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 809.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446904,15 +446904,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 902.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446941,15 +446941,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1006.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -446978,15 +446978,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 59.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1122.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -447015,15 +447015,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 66.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1252.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -447052,15 +447052,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 74.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1398.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -447089,15 +447089,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1561.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -447126,15 +447126,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 92.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1744.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -447163,15 +447163,15 @@ "stats": [ { "stat": "spell_minimum_base_lightning_damage", - "value": 103.0 + "value": 0.0 }, { "stat": "spell_maximum_base_lightning_damage", - "value": 1949.0 + "value": 0.0 }, { "stat": "base_number_of_projectiles", - "value": 13.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451455,7 +451455,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 17.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451476,7 +451476,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 26.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451497,7 +451497,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 37.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451518,7 +451518,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 49.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451539,7 +451539,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 63.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451560,7 +451560,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 79.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451581,7 +451581,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 97.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451602,7 +451602,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 117.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451623,7 +451623,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 140.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451644,7 +451644,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 166.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451665,7 +451665,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 194.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451686,7 +451686,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 226.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451707,7 +451707,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 262.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451728,7 +451728,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 301.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451749,7 +451749,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 344.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451770,7 +451770,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 392.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451791,7 +451791,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 443.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451812,7 +451812,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 500.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451833,7 +451833,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 561.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451854,7 +451854,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 628.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451875,7 +451875,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 701.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451896,7 +451896,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 777.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451917,7 +451917,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 857.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451938,7 +451938,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 940.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451959,7 +451959,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1027.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -451980,7 +451980,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1118.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452001,7 +452001,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1212.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452022,7 +452022,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1310.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452043,7 +452043,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1411.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452064,7 +452064,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1516.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452085,7 +452085,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1625.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452106,7 +452106,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1737.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452127,7 +452127,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1853.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452148,7 +452148,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 1972.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452169,7 +452169,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 2095.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452190,7 +452190,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 2222.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452211,7 +452211,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 2351.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452232,7 +452232,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 2485.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452253,7 +452253,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 2622.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -452274,7 +452274,7 @@ "stats": [ { "stat": "cast_on_damage_taken_threshold", - "value": 2763.0 + "value": 0.0 }, { "stat": "spell_minimum_base_lightning_damage", @@ -453970,7 +453970,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -453988,7 +453988,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454006,7 +454006,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454024,7 +454024,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454041,7 +454041,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454059,7 +454059,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454077,7 +454077,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454095,7 +454095,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454113,7 +454113,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454131,7 +454131,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454149,7 +454149,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454167,7 +454167,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454185,7 +454185,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454203,7 +454203,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454221,7 +454221,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454239,7 +454239,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454257,7 +454257,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454275,7 +454275,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 2.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454293,7 +454293,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454311,7 +454311,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454329,7 +454329,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454347,7 +454347,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454365,7 +454365,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454383,7 +454383,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454401,7 +454401,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454419,7 +454419,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454437,7 +454437,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454455,7 +454455,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454473,7 +454473,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454491,7 +454491,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454509,7 +454509,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454527,7 +454527,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454545,7 +454545,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454563,7 +454563,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454581,7 +454581,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454599,7 +454599,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454617,7 +454617,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454635,7 +454635,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454653,7 +454653,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454671,7 +454671,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 3.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -454800,7 +454800,7 @@ "stats": [ { "stat": "number_of_vine_arrow_pod_allowed", - "value": 1.0 + "value": 0.0 }, { "stat": "base_chaos_damage_to_deal_per_minute", @@ -457870,11 +457870,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -457895,11 +457895,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -457920,11 +457920,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -457945,11 +457945,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -457970,11 +457970,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -457995,11 +457995,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458020,11 +458020,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458045,11 +458045,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458070,11 +458070,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458095,11 +458095,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 45.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458120,11 +458120,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458145,11 +458145,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458170,11 +458170,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458195,11 +458195,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 54.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 81.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458220,11 +458220,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 94.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458245,11 +458245,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 107.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458270,11 +458270,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 122.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458295,11 +458295,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 93.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 140.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458320,11 +458320,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 106.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 159.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458345,11 +458345,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 121.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 181.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458370,11 +458370,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 206.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458395,11 +458395,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 156.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 234.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458420,11 +458420,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 177.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 266.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458445,11 +458445,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 201.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 302.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458470,11 +458470,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 229.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 343.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458495,11 +458495,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 260.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 390.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458520,11 +458520,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 295.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 443.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458545,11 +458545,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 335.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 503.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458570,11 +458570,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 381.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 571.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458595,11 +458595,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 433.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 649.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458620,11 +458620,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 492.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 738.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458645,11 +458645,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 560.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 840.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458670,11 +458670,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 638.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 957.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458695,11 +458695,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 727.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1090.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458720,11 +458720,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 829.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1243.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458745,11 +458745,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 946.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1419.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458770,11 +458770,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1080.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1620.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458795,11 +458795,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1235.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1853.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458820,11 +458820,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1413.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2120.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458845,11 +458845,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1619.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2428.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458958,11 +458958,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 4.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 6.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -458983,11 +458983,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 5.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 8.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459008,11 +459008,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 7.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 11.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459033,11 +459033,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 10.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 14.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459058,11 +459058,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 12.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459083,11 +459083,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 15.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459108,11 +459108,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 18.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 27.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459133,11 +459133,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 22.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 32.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459158,11 +459158,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 26.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 38.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459183,11 +459183,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 30.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 45.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459208,11 +459208,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 35.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 53.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459233,11 +459233,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 41.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 61.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459258,11 +459258,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 47.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459283,11 +459283,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 54.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 81.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459308,11 +459308,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 62.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 94.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459333,11 +459333,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 71.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 107.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459358,11 +459358,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 82.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 122.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459383,11 +459383,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 93.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 140.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459408,11 +459408,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 106.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 159.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459433,11 +459433,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 121.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 181.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459458,11 +459458,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 137.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 206.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459483,11 +459483,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 156.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 234.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459508,11 +459508,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 177.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 266.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459533,11 +459533,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 201.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 302.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459558,11 +459558,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 229.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 343.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459583,11 +459583,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 260.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 390.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459608,11 +459608,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 295.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 443.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459633,11 +459633,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 335.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 503.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459658,11 +459658,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 381.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 571.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459683,11 +459683,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 433.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 649.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459708,11 +459708,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 492.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 738.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459733,11 +459733,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 560.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 840.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459758,11 +459758,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 638.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 957.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459783,11 +459783,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 727.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1090.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459808,11 +459808,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 829.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1243.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459833,11 +459833,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 946.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1419.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459858,11 +459858,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1080.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1620.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459883,11 +459883,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1235.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 1853.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459908,11 +459908,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1413.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2120.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", @@ -459933,11 +459933,11 @@ "stats": [ { "stat": "spell_minimum_base_fire_damage", - "value": 1619.0 + "value": 0.0 }, { "stat": "spell_maximum_base_fire_damage", - "value": 2428.0 + "value": 0.0 }, { "stat": "spell_minimum_base_fire_damage", diff --git a/data/4.5.4.3/base/passive_tree.json b/data/4.5.4.3/base/passive_tree.json index af706ee7..8d07dc1f 100644 --- a/data/4.5.4.3/base/passive_tree.json +++ b/data/4.5.4.3/base/passive_tree.json @@ -249,7 +249,8 @@ "orbit_index": 0, "x": -15422.891927, "y": 5717.99705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 116, @@ -10526,7 +10527,8 @@ "orbit_index": 0, "x": -15190.211927, "y": 5992.68705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 8531, @@ -12762,7 +12764,8 @@ "orbit_index": 0, "x": -15031.611927, "y": 6079.39705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 10011, @@ -17727,7 +17730,8 @@ "orbit_index": 0, "x": -14861.501927, "y": 6123.01705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 13777, @@ -20686,7 +20690,8 @@ "orbit_index": 0, "x": -14062.601927, "y": 5558.05705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 16311, @@ -25715,7 +25720,8 @@ "orbit_index": 0, "x": -14136.951927, "y": 5717.99705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 20205, @@ -28867,7 +28873,8 @@ "orbit_index": 0, "x": -15325.041927, "y": 5867.83705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 22927, @@ -32032,7 +32039,8 @@ "orbit_index": 0, "x": -14678.231927, "y": 6123.01705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 25446, @@ -63080,7 +63088,8 @@ "orbit_index": 0, "x": -14511.001927, "y": 6079.39705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 49356, @@ -77820,7 +77829,8 @@ "orbit_index": 0, "x": -14353.191927, "y": 5992.68705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 60916, @@ -77914,7 +77924,8 @@ "orbit_index": 0, "x": -14229.211927, "y": 5867.83705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 61042, @@ -83073,7 +83084,8 @@ "orbit_index": 0, "x": -15479.931927, "y": 5558.05705, - "ascendancy_id": "Warrior3" + "ascendancy_id": "Warrior3", + "apply_to_armour": true }, { "skill": 64990, diff --git a/data/4.5.4.3/generated/parse-coverage.json b/data/4.5.4.3/generated/parse-coverage.json index 5409ad9d..e720c29d 100644 --- a/data/4.5.4.3/generated/parse-coverage.json +++ b/data/4.5.4.3/generated/parse-coverage.json @@ -6,22 +6,22 @@ }, "summary": { "total": 4280, - "parsed": 3440, - "unsupported": 840, + "parsed": 3438, + "unsupported": 842, "err": 0, - "coverage_ratio": 0.803738 + "coverage_ratio": 0.803271 }, "by_source": [ { "source": "C1_build", - "parsed": 1195, - "unsupported": 511, + "parsed": 1191, + "unsupported": 515, "err": 0 }, { "source": "C2_tree", - "parsed": 2212, - "unsupported": 329, + "parsed": 2214, + "unsupported": 327, "err": 0 }, { @@ -47,11 +47,6 @@ "status": "unsupported", "source": "C2_tree" }, - { - "text": "2% increased [Attack] Damage per 75 [ItemArmour|Item Armour] and [ItemEvasion|Evasion] on Equipped Shield", - "status": "unsupported", - "source": "C2_tree" - }, { "text": "20% Chance to gain a Charge when you kill an enemy", "status": "unsupported", @@ -92,11 +87,6 @@ "status": "unsupported", "source": "C2_tree" }, - { - "text": "4% increased [Attack] Damage per 75 [ItemArmour|Item Armour] and [ItemEvasion|Evasion] on Equipped Shield", - "status": "unsupported", - "source": "C2_tree" - }, { "text": "40% increased [Spell] Damage with [Spell|Spells] that cost Life", "status": "unsupported", @@ -193,42 +183,52 @@ "source": "C1_build" }, { - "text": "Amber Amulet", + "text": "Also grants 180 Guard", "status": "unsupported", "source": "C1_build" }, { - "text": "Amethyst Ring", + "text": "Also grants 265 Guard", "status": "unsupported", "source": "C1_build" }, { - "text": "Amor Mandragora", + "text": "Also grants 435 Guard", "status": "unsupported", "source": "C1_build" }, { - "text": "Analyst's Stone Charm of the Perpetual", + "text": "Also grants 491 Guard", "status": "unsupported", "source": "C1_build" }, { - "text": "Ancestral Tiara", + "text": "Amber Amulet", "status": "unsupported", "source": "C1_build" }, { - "text": "Apocalypse Desire", + "text": "Amethyst Ring", + "status": "unsupported", + "source": "C1_build" + }, + { + "text": "Amor Mandragora", "status": "unsupported", "source": "C1_build" }, { - "text": "Apocalypse Hope", + "text": "Analyst's Stone Charm of the Perpetual", "status": "unsupported", "source": "C1_build" }, { - "text": "Apocalypse Pelt", + "text": "Ancestral Tiara", + "status": "unsupported", + "source": "C1_build" + }, + { + "text": "Apocalypse Desire", "status": "unsupported", "source": "C1_build" } diff --git a/data/4.5.4.3/generated/parsed_mods.json b/data/4.5.4.3/generated/parsed_mods.json index ace80545..11d18e55 100644 --- a/data/4.5.4.3/generated/parsed_mods.json +++ b/data/4.5.4.3/generated/parsed_mods.json @@ -8325,7 +8325,7 @@ "type": "Inc", "value": 10.0, "tags": [ - "SkillName { names: [\"grenade\"] }" + "SkillTypes(SkillTypes([0, 0, 1073741824, 0, 0]))" ] } ] @@ -8543,6 +8543,16 @@ "name": "SkillSpeed", "type": "Inc", "value": 10.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 10.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 10.0 } ] }, @@ -8557,6 +8567,22 @@ "tags": [ "Multiplier { var: \"RemovableFrenzyCharge\", div: 1.0, limit: Some(1.0), actor: None, limit_var: None, limit_actor: None, invert: false, limit_total: false }" ] + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 10.0, + "tags": [ + "Multiplier { var: \"RemovableFrenzyCharge\", div: 1.0, limit: Some(1.0), actor: None, limit_var: None, limit_actor: None, invert: false, limit_total: false }" + ] + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 10.0, + "tags": [ + "Multiplier { var: \"RemovableFrenzyCharge\", div: 1.0, limit: Some(1.0), actor: None, limit_var: None, limit_actor: None, invert: false, limit_total: false }" + ] } ] }, @@ -8571,6 +8597,22 @@ "tags": [ "Condition { var: \"Shapeshifted\", negated: false, actor: None }" ] + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 10.0, + "tags": [ + "Condition { var: \"Shapeshifted\", negated: false, actor: None }" + ] + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 10.0, + "tags": [ + "Condition { var: \"Shapeshifted\", negated: false, actor: None }" + ] } ] }, @@ -10452,7 +10494,7 @@ "type": "Inc", "value": 12.0, "tags": [ - "SkillName { names: [\"grenade\"] }" + "SkillTypes(SkillTypes([0, 0, 1073741824, 0, 0]))" ] } ] @@ -11404,7 +11446,7 @@ "type": "Inc", "value": 15.0, "tags": [ - "SkillName { names: [\"grenade\"] }" + "SkillTypes(SkillTypes([0, 0, 1073741824, 0, 0]))" ] } ] @@ -13467,6 +13509,16 @@ "name": "SkillSpeed", "type": "Inc", "value": 16.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 16.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 16.0 } ] }, @@ -14489,7 +14541,18 @@ }, { "text": "2% increased [Attack] Damage per 75 [ItemArmour|Item Armour] and [ItemEvasion|Evasion] on Equipped Shield", - "status": "unsupported" + "status": "parsed", + "mods": [ + { + "name": "AttackDamage", + "type": "Inc", + "value": 2.0, + "tags": [ + "Multiplier { var: \"ArmourOnweapon2|EvasionOnweapon2\", div: 75.0, limit: None, actor: None, limit_var: None, limit_actor: None, invert: false, limit_total: false }", + "Condition { var: \"UsingShield\", negated: false, actor: None }" + ] + } + ] }, { "text": "2% increased [Attack] Speed", @@ -14524,6 +14587,16 @@ "name": "SkillSpeed", "type": "Inc", "value": 2.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 2.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 2.0 } ] }, @@ -14538,6 +14611,22 @@ "tags": [ "SkillTypes(SkillTypes(140737488355328))" ] + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 2.0, + "tags": [ + "SkillTypes(SkillTypes(140737488355328))" + ] + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 2.0, + "tags": [ + "SkillTypes(SkillTypes(140737488355328))" + ] } ] }, @@ -20232,6 +20321,22 @@ "tags": [ "Condition { var: \"Shapeshifted\", negated: false, actor: None }" ] + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 3.0, + "tags": [ + "Condition { var: \"Shapeshifted\", negated: false, actor: None }" + ] + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 3.0, + "tags": [ + "Condition { var: \"Shapeshifted\", negated: false, actor: None }" + ] } ] }, @@ -20524,6 +20629,16 @@ "name": "SkillSpeed", "type": "Inc", "value": 3.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 3.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 3.0 } ] }, @@ -20538,6 +20653,22 @@ "tags": [ "Condition { var: \"Shapeshifted\", negated: false, actor: None }" ] + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 3.0, + "tags": [ + "Condition { var: \"Shapeshifted\", negated: false, actor: None }" + ] + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 3.0, + "tags": [ + "Condition { var: \"Shapeshifted\", negated: false, actor: None }" + ] } ] }, @@ -20552,6 +20683,22 @@ "tags": [ "SkillTypes(SkillTypes(140737488355328))" ] + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 3.0, + "tags": [ + "SkillTypes(SkillTypes(140737488355328))" + ] + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 3.0, + "tags": [ + "SkillTypes(SkillTypes(140737488355328))" + ] } ] }, @@ -20728,6 +20875,16 @@ "name": "SkillSpeed", "type": "Inc", "value": -3.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": -3.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": -3.0 } ] }, @@ -23315,7 +23472,18 @@ }, { "text": "4% increased [Attack] Damage per 75 [ItemArmour|Item Armour] and [ItemEvasion|Evasion] on Equipped Shield", - "status": "unsupported" + "status": "parsed", + "mods": [ + { + "name": "AttackDamage", + "type": "Inc", + "value": 4.0, + "tags": [ + "Multiplier { var: \"ArmourOnweapon2|EvasionOnweapon2\", div: 75.0, limit: None, actor: None, limit_var: None, limit_actor: None, invert: false, limit_total: false }", + "Condition { var: \"UsingShield\", negated: false, actor: None }" + ] + } + ] }, { "text": "4% increased [Attack] Speed", @@ -23412,6 +23580,16 @@ "name": "SkillSpeed", "type": "Inc", "value": 4.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 4.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 4.0 } ] }, @@ -23564,7 +23742,7 @@ "type": "Inc", "value": 40.0, "tags": [ - "SkillName { names: [\"grenade\"] }" + "SkillTypes(SkillTypes([0, 0, 1073741824, 0, 0]))" ] } ] @@ -24427,6 +24605,22 @@ "tags": [ "Condition { var: \"OpenWeaknessEnemyPresence\", negated: false, actor: None }" ] + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 40.0, + "tags": [ + "Condition { var: \"OpenWeaknessEnemyPresence\", negated: false, actor: None }" + ] + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 40.0, + "tags": [ + "Condition { var: \"OpenWeaknessEnemyPresence\", negated: false, actor: None }" + ] } ] }, @@ -25335,7 +25529,7 @@ "status": "parsed", "mods": [ { - "name": "Life", + "name": "MaximumLife", "type": "Inc", "value": 5.0, "tags": [ @@ -25349,7 +25543,7 @@ "status": "parsed", "mods": [ { - "name": "Mana", + "name": "MaximumMana", "type": "Inc", "value": 5.0, "tags": [ @@ -25652,6 +25846,16 @@ "name": "SkillSpeed", "type": "Inc", "value": 5.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 5.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 5.0 } ] }, @@ -25973,6 +26177,16 @@ "name": "SkillSpeed", "type": "Inc", "value": -5.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": -5.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": -5.0 } ] }, @@ -27657,6 +27871,16 @@ "name": "SkillSpeed", "type": "Inc", "value": 6.0 + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 6.0 + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 6.0 } ] }, @@ -29743,6 +29967,22 @@ "tags": [ "Condition { var: \"Shapeshifted\", negated: false, actor: None }" ] + }, + { + "name": "WarcrySpeed", + "type": "Inc", + "value": 8.0, + "tags": [ + "Condition { var: \"Shapeshifted\", negated: false, actor: None }" + ] + }, + { + "name": "TotemPlacementSpeed", + "type": "Inc", + "value": 8.0, + "tags": [ + "Condition { var: \"Shapeshifted\", negated: false, actor: None }" + ] } ] }, @@ -30055,7 +30295,7 @@ "type": "Inc", "value": -80.0, "tags": [ - "SkillName { names: [\"grenade\"] }" + "SkillTypes(SkillTypes([0, 0, 1073741824, 0, 0]))" ] } ] @@ -33015,67 +33255,19 @@ }, { "text": "Also grants 180 Guard", - "status": "parsed", - "mods": [ - { - "name": "GuardAbsorbRate", - "type": "Base", - "value": 100.0 - }, - { - "name": "GuardAbsorbLimit", - "type": "Base", - "value": 180.0 - } - ] + "status": "unsupported" }, { "text": "Also grants 265 Guard", - "status": "parsed", - "mods": [ - { - "name": "GuardAbsorbRate", - "type": "Base", - "value": 100.0 - }, - { - "name": "GuardAbsorbLimit", - "type": "Base", - "value": 265.0 - } - ] + "status": "unsupported" }, { "text": "Also grants 435 Guard", - "status": "parsed", - "mods": [ - { - "name": "GuardAbsorbRate", - "type": "Base", - "value": 100.0 - }, - { - "name": "GuardAbsorbLimit", - "type": "Base", - "value": 435.0 - } - ] + "status": "unsupported" }, { "text": "Also grants 491 Guard", - "status": "parsed", - "mods": [ - { - "name": "GuardAbsorbRate", - "type": "Base", - "value": 100.0 - }, - { - "name": "GuardAbsorbLimit", - "type": "Base", - "value": 491.0 - } - ] + "status": "unsupported" }, { "text": "Amber Amulet", @@ -40376,6 +40568,18 @@ "type": "More", "value": 30.0, "kw": 16384 + }, + { + "name": "WarcrySpeed", + "type": "More", + "value": 30.0, + "kw": 16384 + }, + { + "name": "TotemPlacementSpeed", + "type": "More", + "value": 30.0, + "kw": 16384 } ] }, diff --git a/data/4.5.4.3/generated/test_pins.json b/data/4.5.4.3/generated/test_pins.json new file mode 100644 index 00000000..a1ef8be5 --- /dev/null +++ b/data/4.5.4.3/generated/test_pins.json @@ -0,0 +1,33 @@ +{ + "minions.raised_zombie": { + "damage": 0.75, + "life": 0.7 + }, + "minions.spectre_cocoon3": { + "armour": 0.4, + "life": 2.2 + }, + "parser_rules.handler_fallbacks": 3, + "parser_rules.section_counts": { + "base_cost_types": 32, + "cost_types_map": 32, + "damage_types": 5, + "degen_types": 32, + "distinct_forms": 29, + "flag_phrases": 206, + "flag_types": 26, + "forms": 95, + "name_map": 789, + "pen_types": 6, + "pre_flags": 219, + "regen_types": 32, + "suffix_types": 40, + "tag_phrases": 691, + "unsupported": [ + "mirrored" + ], + "unsupported_pobr_extra": [ + "split" + ] + } +} diff --git a/data/4.5.4.3/overlay/base_item_overrides.json b/data/4.5.4.3/overlay/base_item_overrides.json index 70c6b834..3dbf8576 100644 --- a/data/4.5.4.3/overlay/base_item_overrides.json +++ b/data/4.5.4.3/overlay/base_item_overrides.json @@ -3,8 +3,8 @@ "schema": "base_item_overrides/v1", "generator": "sync-pob-catalog extract-bases", "vendor": "PathOfBuilding-PoE2", - "vendor_commit": "29ab8262dd4a867eac56165afb8391a509e34a0e", - "vendor_commit_subject": "29ab826 Add support for Darkness Enthroned and Atziri's Splendour augment mods (#2343)", + "vendor_commit": "ce8bffaba31f8e68cfce70579e1c96465e7c133c", + "vendor_commit_subject": "ce8bffaba31f8e68cfce70579e1c96465e7c133c", "extracted_files": [ "Data/Bases/amulet.lua", "Data/Bases/axe.lua", @@ -46,7 +46,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Absent Amulet", @@ -62,7 +63,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Abyssal Flail", @@ -72,7 +74,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 89, + "req_int": 36 }, { "name": "Abyssal Signet", @@ -89,7 +93,8 @@ "default", "onehand", "wand" - ] + ], + "req_int": 60 }, { "name": "Adherent Bow", @@ -100,7 +105,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 104 }, { "name": "Adherent Cuffs", @@ -110,7 +116,9 @@ "gloves", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 55, + "req_int": 55 }, { "name": "Adherent Leggings", @@ -119,7 +127,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 34, + "req_int": 34 }, { "name": "Adherent's Raiment", @@ -128,7 +138,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 94 }, { "name": "Adorned Gloves", @@ -137,7 +148,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 80 }, { "name": "Adorned Wraps", @@ -146,7 +158,9 @@ "default", "dex_int_armour", "gloves" - ] + ], + "req_dex": 41, + "req_int": 41 }, { "name": "Aegis Buckler", @@ -158,7 +172,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 91 }, { "name": "Aegis Quarterstaff", @@ -168,7 +183,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 127, + "req_int": 50 }, { "name": "Aged Cuffs", @@ -178,7 +195,9 @@ "gloves", "maraketh_basetype", "str_int_armour" - ] + ], + "req_str": 13, + "req_int": 13 }, { "name": "Aged Tower Shield", @@ -189,7 +208,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 64 }, { "name": "Akoyan Club", @@ -200,7 +220,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Akoyan Spear", @@ -211,7 +232,10 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 50, + "req_dex": 127, + "req_int": 90 }, { "name": "Alloy Crossbow", @@ -224,7 +248,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 28, + "req_dex": 28 }, { "name": "Alpha Talisman", @@ -235,7 +261,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 98, + "req_int": 72 }, { "name": "Altar Robe", @@ -245,7 +273,8 @@ "default", "int_armour", "vaal_basetype" - ] + ], + "req_int": 65 }, { "name": "Amber Amulet", @@ -284,7 +313,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 71 }, { "name": "Ancestral Mail", @@ -294,7 +324,9 @@ "default", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 44, + "req_dex": 44 }, { "name": "Ancestral Tiara", @@ -304,7 +336,8 @@ "helmet", "int_armour", "karui_basetype" - ] + ], + "req_int": 115 }, { "name": "Anchorite Garb", @@ -314,7 +347,9 @@ "default", "dex_int_armour", "vaal_basetype" - ] + ], + "req_dex": 31, + "req_int": 31 }, { "name": "Ancient Buckler", @@ -326,7 +361,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 107 }, { "name": "Ancient Cuffs", @@ -335,7 +371,9 @@ "default", "gloves", "str_int_armour" - ] + ], + "req_str": 48, + "req_int": 48 }, { "name": "Ancient Gauntlets", @@ -344,7 +382,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 52, + "req_dex": 52 }, { "name": "Ancient Greatblade", @@ -354,7 +394,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 49, + "req_dex": 49 }, { "name": "Ancient Leggings", @@ -363,7 +405,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 56, + "req_int": 56 }, { "name": "Ancient Mail", @@ -372,7 +416,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Ancient Mitts", @@ -381,7 +427,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 67 }, { "name": "Ancient Visor", @@ -390,7 +437,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 59, + "req_dex": 59 }, { "name": "Anima Quarterstaff", @@ -400,7 +449,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 72, + "req_int": 29 }, { "name": "Antidote Charm", @@ -421,7 +472,8 @@ "ezomyte_basetype", "focus", "int_armour" - ] + ], + "req_int": 17 }, { "name": "Anvil Maul", @@ -431,7 +483,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 134 }, { "name": "Apostle Leggings", @@ -440,7 +493,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 51, + "req_int": 51 }, { "name": "Arcane Dirk", @@ -450,7 +505,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 55, + "req_int": 55 }, { "name": "Arcane Raiment", @@ -459,7 +516,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 121 }, { "name": "Arced Claw", @@ -470,7 +528,8 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_dex": 60 }, { "name": "Arced Longsword", @@ -481,7 +540,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 29, + "req_dex": 29 }, { "name": "Arched Greataxe", @@ -492,7 +553,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 25, + "req_dex": 12 }, { "name": "Archon Crown", @@ -501,7 +564,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Arcing Quarterstaff", @@ -511,7 +576,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 71, + "req_int": 29 }, { "name": "Armoured Cap", @@ -520,7 +587,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 91 }, { "name": "Armoured Claw", @@ -530,7 +598,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 92 }, { "name": "Armoured Vest", @@ -539,7 +608,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 121 }, { "name": "Aromatic Sceptre", @@ -548,7 +618,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 92 }, { "name": "Array Buckler", @@ -560,7 +631,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 78 }, { "name": "Arrayed Focus", @@ -569,7 +641,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 77 }, { "name": "Artillery Bow", @@ -581,7 +654,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 80 }, { "name": "Ascetic Garb", @@ -590,7 +664,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 41, + "req_int": 41 }, { "name": "Ashbark Talisman", @@ -601,7 +677,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 94, + "req_int": 67 }, { "name": "Ashen Staff", @@ -622,7 +700,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Attuned Focus", @@ -631,7 +711,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 81 }, { "name": "Attuned Wand", @@ -651,7 +732,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 45, + "req_dex": 45 }, { "name": "Austere Garb", @@ -661,7 +744,9 @@ "default", "dex_int_armour", "karui_basetype" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Avian Mask", @@ -670,7 +755,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 46, + "req_int": 46 }, { "name": "Avian Robe", @@ -679,7 +766,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 72 }, { "name": "Avian Targe", @@ -690,7 +778,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 48, + "req_dex": 48 }, { "name": "Avian Tiara", @@ -699,7 +789,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 69 }, { "name": "Azure Amulet", @@ -715,7 +806,9 @@ "default", "dex_int_armour", "gloves" - ] + ], + "req_dex": 32, + "req_int": 32 }, { "name": "Bandit Hatchet", @@ -726,7 +819,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 30, + "req_dex": 14 }, { "name": "Bandit Mace", @@ -736,7 +831,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 104 }, { "name": "Bandit Mask", @@ -745,7 +841,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 38, + "req_int": 38 }, { "name": "Bangled Sandals", @@ -754,7 +852,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 68 }, { "name": "Barbarian Plate", @@ -763,7 +862,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 72 }, { "name": "Barbarous Quarterstaff", @@ -773,7 +873,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 67, + "req_int": 27 }, { "name": "Barbed Bracers", @@ -782,7 +884,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 94 }, { "name": "Barbed Spear", @@ -793,7 +896,9 @@ "spear", "vaal_basetype", "weapon" - ] + ], + "req_str": 20, + "req_dex": 47 }, { "name": "Baroque Gloves", @@ -802,7 +907,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 67 }, { "name": "Baroque Targe", @@ -813,7 +919,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 54, + "req_dex": 54 }, { "name": "Barricade Tower Shield", @@ -825,7 +933,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 25 }, { "name": "Barrier Quarterstaff", @@ -836,7 +945,9 @@ "vaal_basetype", "warstaff", "weapon" - ] + ], + "req_dex": 52, + "req_int": 22 }, { "name": "Bastion Sabatons", @@ -845,7 +956,9 @@ "boots", "default", "str_dex_armour" - ] + ], + "req_str": 44, + "req_dex": 44 }, { "name": "Battle Axe", @@ -855,7 +968,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 72, + "req_dex": 29 }, { "name": "Battle Pick", @@ -865,7 +980,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 91 }, { "name": "Beaded Circlet", @@ -875,7 +991,8 @@ "helmet", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 25 }, { "name": "Bearded Axe", @@ -886,7 +1003,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 17, + "req_dex": 9 }, { "name": "Bearskin Mantle", @@ -895,7 +1014,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 43, + "req_int": 43 }, { "name": "Biostatic Ring", @@ -917,7 +1038,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 45, + "req_dex": 45 }, { "name": "Blacksmith Maul", @@ -927,7 +1050,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 86 }, { "name": "Blacksteel Crest Shield", @@ -939,7 +1063,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 63, + "req_int": 63 }, { "name": "Blacksteel Gauntlets", @@ -949,7 +1075,9 @@ "gloves", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 55, + "req_dex": 55 }, { "name": "Blacksteel Sabatons", @@ -959,7 +1087,9 @@ "default", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 59, + "req_dex": 59 }, { "name": "Blacksteel Tower Shield", @@ -970,7 +1100,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 91 }, { "name": "Bladed Quarterstaff", @@ -980,7 +1111,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 81, + "req_int": 33 }, { "name": "Bladed Shoes", @@ -989,7 +1122,9 @@ "boots", "default", "dex_int_armour" - ] + ], + "req_dex": 47, + "req_int": 47 }, { "name": "Bladed Trap", @@ -1009,7 +1144,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 86 }, { "name": "Blazon Crest Shield", @@ -1033,7 +1169,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 60, + "req_dex": 60 }, { "name": "Blessed Claymore", @@ -1044,7 +1182,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 14, + "req_dex": 14 }, { "name": "Bloodletting Dagger", @@ -1055,7 +1195,9 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_dex": 39, + "req_int": 39 }, { "name": "Bloodstone Amulet", @@ -1079,7 +1221,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 63, + "req_dex": 26 }, { "name": "Bold Sabatons", @@ -1088,7 +1232,9 @@ "boots", "default", "str_dex_armour" - ] + ], + "req_str": 47, + "req_dex": 47 }, { "name": "Bolstered Mitts", @@ -1098,7 +1244,8 @@ "gloves", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 35 }, { "name": "Bolting Quarterstaff", @@ -1108,7 +1255,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 127, + "req_int": 50 }, { "name": "Bombard Crossbow", @@ -1121,7 +1270,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 34, + "req_dex": 34 }, { "name": "Bone Raiment", @@ -1131,7 +1282,8 @@ "default", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 28 }, { "name": "Bone Wand", @@ -1152,7 +1304,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 60 }, { "name": "Bound Bracers", @@ -1162,7 +1315,8 @@ "dex_armour", "gloves", "maraketh_basetype" - ] + ], + "req_dex": 22 }, { "name": "Bound Cuffs", @@ -1171,7 +1325,9 @@ "default", "gloves", "str_int_armour" - ] + ], + "req_str": 44, + "req_int": 44 }, { "name": "Bound Leggings", @@ -1180,7 +1336,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 38, + "req_int": 38 }, { "name": "Bound Sandals", @@ -1189,7 +1347,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 86 }, { "name": "Braced Sabatons", @@ -1199,7 +1358,9 @@ "default", "maraketh_basetype", "str_dex_armour" - ] + ], + "req_str": 14, + "req_dex": 14 }, { "name": "Braced Tower Shield", @@ -1211,7 +1372,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 19 }, { "name": "Braided Cuffs", @@ -1220,7 +1382,9 @@ "default", "gloves", "str_int_armour" - ] + ], + "req_str": 32, + "req_int": 32 }, { "name": "Branched Spear", @@ -1230,7 +1394,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 30, + "req_dex": 75 }, { "name": "Breach Ring", @@ -1250,7 +1416,8 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_str": 60 }, { "name": "Brigand Mask", @@ -1259,7 +1426,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 50, + "req_int": 50 }, { "name": "Brimmed Helm", @@ -1269,7 +1438,9 @@ "ezomyte_basetype", "helmet", "str_dex_armour" - ] + ], + "req_str": 7, + "req_dex": 7 }, { "name": "Broad Greatsword", @@ -1280,7 +1451,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 19, + "req_dex": 19 }, { "name": "Broad Spear", @@ -1291,7 +1464,9 @@ "spear", "vaal_basetype", "weapon" - ] + ], + "req_str": 26, + "req_dex": 55 }, { "name": "Broadhead Quiver", @@ -1309,7 +1484,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 9, + "req_dex": 9 }, { "name": "Bronze Greaves", @@ -1319,7 +1496,8 @@ "default", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 23 }, { "name": "Buckled Wraps", @@ -1329,7 +1507,9 @@ "dex_int_armour", "gloves", "karui_basetype" - ] + ], + "req_dex": 32, + "req_int": 32 }, { "name": "Bulwark Greaves", @@ -1338,7 +1518,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 86 }, { "name": "Bulwark Tower Shield", @@ -1349,7 +1530,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 77 }, { "name": "Burnished Gauntlets", @@ -1358,7 +1540,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 36, + "req_dex": 36 }, { "name": "Cabalist Helm", @@ -1367,7 +1551,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 42, + "req_dex": 42 }, { "name": "Calescent Hammer", @@ -1377,7 +1563,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 80 }, { "name": "Calm Leg", @@ -1392,7 +1579,9 @@ "default", "dex_int_armour", "gloves" - ] + ], + "req_dex": 35, + "req_int": 35 }, { "name": "Cannonade Crossbow", @@ -1404,7 +1593,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 58, + "req_dex": 58 }, { "name": "Captain Gauntlets", @@ -1413,7 +1604,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 35, + "req_dex": 35 }, { "name": "Carved Greaves", @@ -1422,7 +1615,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 78 }, { "name": "Carved Targe", @@ -1433,7 +1627,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 40, + "req_dex": 40 }, { "name": "Carving Hatchet", @@ -1444,7 +1640,9 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_str": 47, + "req_dex": 20 }, { "name": "Cassis Helm", @@ -1453,7 +1651,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 46, + "req_dex": 46 }, { "name": "Caster Arm", @@ -1468,7 +1668,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 93 }, { "name": "Cavalry Bow", @@ -1479,7 +1680,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 149 }, { "name": "Ceremonial Halberd", @@ -1489,7 +1691,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 72, + "req_dex": 29 }, { "name": "Ceremonial Robe", @@ -1498,7 +1702,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 98 }, { "name": "Chain Flail", @@ -1509,7 +1714,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 12 }, { "name": "Chain Mail", @@ -1529,7 +1735,8 @@ "helmet", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 38 }, { "name": "Chain Vestments", @@ -1538,7 +1745,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 45, + "req_int": 45 }, { "name": "Champion Cuirass", @@ -1547,7 +1756,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 92 }, { "name": "Champion Helm", @@ -1556,7 +1766,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 59, + "req_dex": 59 }, { "name": "Changeling Talisman", @@ -1576,7 +1788,9 @@ "boots", "default", "dex_int_armour" - ] + ], + "req_dex": 51, + "req_int": 51 }, { "name": "Charred Shortsword", @@ -1587,7 +1801,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 23, + "req_dex": 23 }, { "name": "Chieftain Cuirass", @@ -1597,7 +1813,8 @@ "default", "karui_basetype", "str_armour" - ] + ], + "req_str": 80 }, { "name": "Chiming Staff", @@ -1605,7 +1822,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 46 }, { "name": "Chiseled Targe", @@ -1617,7 +1835,9 @@ "str_dex_armour", "str_dex_shield", "vaal_basetype" - ] + ], + "req_str": 27, + "req_dex": 27 }, { "name": "Cinched Boots", @@ -1626,7 +1846,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 86 }, { "name": "Cinderbark Talisman", @@ -1637,7 +1858,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 15, + "req_int": 11 }, { "name": "Cinquedea", @@ -1647,7 +1870,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 63, + "req_int": 63 }, { "name": "Clamping Trap", @@ -1664,7 +1889,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 46, + "req_int": 46 }, { "name": "Clasped Sceptre", @@ -1673,7 +1900,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 65 }, { "name": "Clay Trap", @@ -1699,7 +1927,9 @@ "default", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Cloaked Mail", @@ -1709,7 +1939,9 @@ "default", "maraketh_basetype", "str_dex_armour" - ] + ], + "req_str": 25, + "req_dex": 25 }, { "name": "Closed Helm", @@ -1719,7 +1951,9 @@ "helmet", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 36, + "req_dex": 36 }, { "name": "Coiled Buckler", @@ -1731,7 +1965,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 73 }, { "name": "Coiled Trap", @@ -1764,7 +1999,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 83 }, { "name": "Combat Arm", @@ -1779,7 +2015,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 48, + "req_dex": 48 }, { "name": "Commander Greathelm", @@ -1789,7 +2027,8 @@ "helmet", "karui_basetype", "str_armour" - ] + ], + "req_str": 64 }, { "name": "Commander Sword", @@ -1799,7 +2038,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 53, + "req_dex": 53 }, { "name": "Commanding Arm", @@ -1817,7 +2058,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 41 }, { "name": "Condemned Talisman", @@ -1827,7 +2069,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 74, + "req_int": 52 }, { "name": "Conjurer Mantle", @@ -1836,7 +2080,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Conqueror Plate", @@ -1845,7 +2091,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Construct Crossbow", @@ -1858,7 +2105,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 39, + "req_dex": 39 }, { "name": "Construct Hammer", @@ -1869,7 +2118,8 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_str": 65 }, { "name": "Corona Amulet", @@ -1885,7 +2135,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 64 }, { "name": "Corroded Longsword", @@ -1906,7 +2157,8 @@ "dex_armour", "helmet", "karui_basetype" - ] + ], + "req_dex": 64 }, { "name": "Corsair Coat", @@ -1916,7 +2168,8 @@ "default", "dex_armour", "karui_basetype" - ] + ], + "req_dex": 121 }, { "name": "Corsair Vest", @@ -1926,7 +2179,8 @@ "default", "dex_armour", "karui_basetype" - ] + ], + "req_dex": 72 }, { "name": "Corvus Mantle", @@ -1935,7 +2189,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Coursing Spear", @@ -1945,7 +2201,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 27, + "req_dex": 67 }, { "name": "Covered Sabatons", @@ -1955,7 +2213,9 @@ "default", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 34, + "req_dex": 34 }, { "name": "Covert Hood", @@ -1964,7 +2224,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 79 }, { "name": "Cowled Helm", @@ -1974,7 +2235,9 @@ "helmet", "maraketh_basetype", "str_dex_armour" - ] + ], + "req_str": 22, + "req_dex": 22 }, { "name": "Crackling Quarterstaff", @@ -1985,7 +2248,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 25, + "req_int": 12 }, { "name": "Crescent Axe", @@ -1996,7 +2261,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 38, + "req_dex": 17 }, { "name": "Crescent Quarterstaff", @@ -2007,7 +2274,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 30, + "req_int": 14 }, { "name": "Crescent Targe", @@ -2019,7 +2288,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 22, + "req_dex": 22 }, { "name": "Crimson Amulet", @@ -2034,7 +2305,8 @@ "default", "onehand", "wand" - ] + ], + "req_int": 92 }, { "name": "Crone Knife", @@ -2045,7 +2317,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 9, + "req_int": 9 }, { "name": "Crossblade Spear", @@ -2056,7 +2330,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 26, + "req_dex": 63 }, { "name": "Crown Mace", @@ -2066,7 +2342,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 149 }, { "name": "Crucible Tower Shield", @@ -2078,7 +2355,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 64 }, { "name": "Crude Bow", @@ -2112,7 +2390,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 72, + "req_int": 51 }, { "name": "Crumbling Maul", @@ -2123,7 +2403,8 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 68 }, { "name": "Cryptic Crown", @@ -2133,7 +2414,9 @@ "helmet", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 63, + "req_int": 63 }, { "name": "Cryptic Helm", @@ -2142,7 +2425,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 54, + "req_dex": 54 }, { "name": "Cryptic Leggings", @@ -2152,7 +2437,9 @@ "default", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 59, + "req_int": 59 }, { "name": "Crystal Focus", @@ -2162,7 +2449,8 @@ "focus", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 38 }, { "name": "Cultist Bow", @@ -2174,7 +2462,8 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_dex": 60 }, { "name": "Cultist Crown", @@ -2184,7 +2473,9 @@ "helmet", "maraketh_basetype", "str_int_armour" - ] + ], + "req_str": 15, + "req_int": 15 }, { "name": "Cultist Focus", @@ -2193,7 +2484,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 83 }, { "name": "Cultist Gauntlets", @@ -2202,7 +2494,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 52, + "req_dex": 52 }, { "name": "Cultist Greathammer", @@ -2213,7 +2507,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 41 }, { "name": "Cultist Tower Shield", @@ -2224,7 +2519,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 73 }, { "name": "Cumbrous Crossbow", @@ -2236,7 +2532,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 51, + "req_dex": 51 }, { "name": "Cursespeaker's Robe", @@ -2245,7 +2543,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 77 }, { "name": "Cutlass", @@ -2255,7 +2554,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 45, + "req_dex": 45 }, { "name": "Daggerfoot Shoes", @@ -2265,7 +2566,9 @@ "default", "dex_int_armour", "karui_basetype" - ] + ], + "req_dex": 59, + "req_int": 59 }, { "name": "Dark Blade", @@ -2275,7 +2578,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 63, + "req_dex": 63 }, { "name": "Dark Staff", @@ -2283,7 +2588,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 114 }, { "name": "Dart Trap", @@ -2300,7 +2606,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Death Mail", @@ -2309,7 +2617,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Death Mantle", @@ -2318,7 +2628,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Death Mask", @@ -2327,7 +2639,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 50, + "req_int": 50 }, { "name": "Decorated Helm", @@ -2336,7 +2650,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Decrepifying Arm", @@ -2354,7 +2670,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 55, + "req_dex": 55 }, { "name": "Deerstalker Hood", @@ -2363,7 +2681,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 83 }, { "name": "Defiant Tower Shield", @@ -2374,7 +2693,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 82 }, { "name": "Deflective Arm", @@ -2391,7 +2711,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Dekharan Crest Shield", @@ -2402,7 +2724,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 42, + "req_int": 42 }, { "name": "Descry Crest Shield", @@ -2413,7 +2737,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 40, + "req_int": 40 }, { "name": "Desert Buckler", @@ -2426,7 +2752,8 @@ "dex_shield", "karui_basetype", "shield" - ] + ], + "req_dex": 115 }, { "name": "Desert Cap", @@ -2435,7 +2762,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 99 }, { "name": "Desert Circlet", @@ -2444,7 +2772,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 73 }, { "name": "Desolate Crossbow", @@ -2456,7 +2785,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 89, + "req_dex": 89 }, { "name": "Detailed Mitts", @@ -2466,7 +2797,8 @@ "gloves", "karui_basetype", "str_armour" - ] + ], + "req_str": 56 }, { "name": "Devotional Sceptre", @@ -2475,7 +2807,9 @@ "default", "onehand", "sceptre" - ] + ], + "req_str": 26, + "req_int": 63 }, { "name": "Devouring Sceptre", @@ -2484,7 +2818,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 60 }, { "name": "Devout Garb", @@ -2493,7 +2828,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Diamond", @@ -2514,7 +2851,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 109 }, { "name": "Distorted Amulet", @@ -2530,7 +2868,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 59, + "req_int": 59 }, { "name": "Domed Helm", @@ -2539,7 +2879,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 36, + "req_dex": 36 }, { "name": "Double Belt", @@ -2559,7 +2901,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 99 }, { "name": "Doubled Gauntlets", @@ -2569,7 +2912,9 @@ "gloves", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 24, + "req_dex": 24 }, { "name": "Dousing Charm", @@ -2589,7 +2934,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 101 }, { "name": "Drakeskin Boots", @@ -2599,7 +2945,8 @@ "default", "dex_armour", "karui_basetype" - ] + ], + "req_dex": 108 }, { "name": "Dread Hatchet", @@ -2609,7 +2956,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 89, + "req_dex": 36 }, { "name": "Dreaming Quarterstaff", @@ -2620,7 +2969,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 127, + "req_int": 50 }, { "name": "Druidic Circlet", @@ -2629,7 +2980,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 64 }, { "name": "Druidic Crown", @@ -2638,7 +2990,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Druidic Focus", @@ -2647,7 +3001,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 91 }, { "name": "Dualstring Bow", @@ -2659,7 +3014,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 52 }, { "name": "Dueling Wand", @@ -2667,7 +3023,8 @@ "default", "onehand", "wand" - ] + ], + "req_int": 114 }, { "name": "Dull Hatchet", @@ -2687,7 +3044,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 78 }, { "name": "Dusk Amulet", @@ -2716,7 +3074,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 22, + "req_dex": 22 }, { "name": "Edged Buckler", @@ -2729,7 +3089,8 @@ "dex_shield", "shield", "vaal_basetype" - ] + ], + "req_dex": 56 }, { "name": "Edged Claw", @@ -2740,7 +3101,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 52 }, { "name": "Effigial Tower Shield", @@ -2752,7 +3114,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 32 }, { "name": "Elaborate Sandals", @@ -2761,7 +3124,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 86 }, { "name": "Elegant Crossbow", @@ -2774,7 +3138,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 89, + "req_dex": 89 }, { "name": "Elegant Focus", @@ -2783,7 +3149,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 74 }, { "name": "Elegant Glaive", @@ -2794,7 +3161,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 30, + "req_dex": 14 }, { "name": "Elegant Greathelm", @@ -2803,7 +3172,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 77 }, { "name": "Elegant Greaves", @@ -2812,7 +3182,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 72 }, { "name": "Elegant Mitts", @@ -2821,7 +3192,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 64 }, { "name": "Elegant Plate", @@ -2830,7 +3202,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 86 }, { "name": "Elegant Slippers", @@ -2839,7 +3212,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 72 }, { "name": "Elegant Wraps", @@ -2848,7 +3222,9 @@ "default", "dex_int_armour", "gloves" - ] + ], + "req_dex": 48, + "req_int": 48 }, { "name": "Elementalist Robe", @@ -2858,7 +3234,8 @@ "default", "int_armour", "karui_basetype" - ] + ], + "req_int": 72 }, { "name": "Elite Greathelm", @@ -2868,7 +3245,8 @@ "helmet", "str_armour", "vaal_basetype" - ] + ], + "req_str": 48 }, { "name": "Embellished Gloves", @@ -2877,7 +3255,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 64 }, { "name": "Ember Greataxe", @@ -2887,7 +3266,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 70, + "req_dex": 28 }, { "name": "Emblem Crest Shield", @@ -2899,7 +3280,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 15, + "req_int": 15 }, { "name": "Embossed Boots", @@ -2909,7 +3292,8 @@ "default", "dex_armour", "maraketh_basetype" - ] + ], + "req_dex": 23 }, { "name": "Embroidered Boots", @@ -2918,7 +3302,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 86 }, { "name": "Embroidered Gloves", @@ -2927,7 +3312,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 64 }, { "name": "Emerald", @@ -2955,7 +3341,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 45, + "req_int": 45 }, { "name": "Energy Blade One Handed", @@ -2986,7 +3374,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 80 }, { "name": "Engraved Crest Shield", @@ -2997,7 +3386,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 38, + "req_int": 38 }, { "name": "Engraved Crossbow", @@ -3009,7 +3400,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 82, + "req_dex": 82 }, { "name": "Engraved Focus", @@ -3019,7 +3412,8 @@ "focus", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 25 }, { "name": "Engraved Helm", @@ -3028,7 +3422,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 38, + "req_dex": 38 }, { "name": "Engraved Knife", @@ -3039,7 +3435,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 29, + "req_int": 29 }, { "name": "Enlightened Robe", @@ -3048,7 +3446,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 121 }, { "name": "Esoteric Crossbow", @@ -3060,7 +3459,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 63, + "req_dex": 63 }, { "name": "Ethereal Blade", @@ -3080,7 +3481,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 45, + "req_int": 45 }, { "name": "Evasive Leg", @@ -3096,7 +3499,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 97 }, { "name": "Executioner Greataxe", @@ -3107,7 +3511,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 17, + "req_dex": 9 }, { "name": "Explorer Armour", @@ -3117,7 +3523,9 @@ "default", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 31, + "req_dex": 31 }, { "name": "Exquisite Vest", @@ -3126,7 +3534,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 121 }, { "name": "Extended Cleaver", @@ -3137,7 +3546,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 25, + "req_dex": 12 }, { "name": "Face Mask", @@ -3147,7 +3558,9 @@ "dex_int_armour", "ezomyte_basetype", "helmet" - ] + ], + "req_dex": 10, + "req_int": 10 }, { "name": "Faithful Leggings", @@ -3156,7 +3569,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 47, + "req_int": 47 }, { "name": "Falchion", @@ -3167,7 +3582,9 @@ "sword", "vaal_basetype", "weapon" - ] + ], + "req_str": 34, + "req_dex": 34 }, { "name": "Falconer's Jacket", @@ -3176,7 +3593,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Familial Talisman", @@ -3187,7 +3606,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 21, + "req_int": 16 }, { "name": "Fanatic Bow", @@ -3198,7 +3619,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 163 }, { "name": "Fanatic Greathammer", @@ -3208,7 +3630,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Fang Talisman", @@ -3219,7 +3642,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 89, + "req_int": 68 }, { "name": "Faridun Mask", @@ -3228,7 +3653,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 54, + "req_int": 54 }, { "name": "Feathered Mitts", @@ -3237,7 +3664,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 73 }, { "name": "Feathered Raiment", @@ -3247,7 +3675,8 @@ "default", "int_armour", "karui_basetype" - ] + ], + "req_int": 121 }, { "name": "Feathered Robe", @@ -3257,7 +3686,8 @@ "default", "ezomyte_basetype", "int_armour" - ] + ], + "req_int": 11 }, { "name": "Feathered Sandals", @@ -3267,7 +3697,8 @@ "default", "int_armour", "vaal_basetype" - ] + ], + "req_int": 45 }, { "name": "Feathered Targe", @@ -3279,7 +3710,9 @@ "str_dex_armour", "str_dex_shield", "vaal_basetype" - ] + ], + "req_str": 30, + "req_dex": 30 }, { "name": "Feathered Tiara", @@ -3289,7 +3722,8 @@ "helmet", "int_armour", "vaal_basetype" - ] + ], + "req_int": 48 }, { "name": "Felled Greatclub", @@ -3310,7 +3744,8 @@ "dex_armour", "ezomyte_basetype", "helmet" - ] + ], + "req_dex": 17 }, { "name": "Fierce Greathelm", @@ -3320,7 +3755,8 @@ "helmet", "karui_basetype", "str_armour" - ] + ], + "req_str": 73 }, { "name": "Fine Belt", @@ -3339,7 +3775,8 @@ "dex_armour", "gloves", "karui_basetype" - ] + ], + "req_dex": 56 }, { "name": "Fire Quiver", @@ -3356,7 +3793,8 @@ "dex_armour", "ezomyte_basetype", "gloves" - ] + ], + "req_dex": 16 }, { "name": "Fishing Rod", @@ -3384,7 +3822,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 51, + "req_dex": 51 }, { "name": "Flanged Mace", @@ -3394,7 +3834,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 134 }, { "name": "Flared Boots", @@ -3404,7 +3845,8 @@ "default", "dex_armour", "karui_basetype" - ] + ], + "req_dex": 60 }, { "name": "Flared Mace", @@ -3414,7 +3856,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 86 }, { "name": "Flax Sandals", @@ -3424,7 +3867,8 @@ "default", "int_armour", "karui_basetype" - ] + ], + "req_int": 60 }, { "name": "Flexed Crossbow", @@ -3436,7 +3880,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 89, + "req_dex": 89 }, { "name": "Flexile Sabatons", @@ -3445,7 +3891,9 @@ "boots", "default", "str_dex_armour" - ] + ], + "req_str": 38, + "req_dex": 38 }, { "name": "Flowing Raiment", @@ -3454,7 +3902,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 121 }, { "name": "Flying Spear", @@ -3464,7 +3913,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 50, + "req_dex": 127 }, { "name": "Forest Crown", @@ -3473,7 +3924,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 38, + "req_int": 38 }, { "name": "Forge Maul", @@ -3484,7 +3937,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 23 }, { "name": "Forked Claw", @@ -3495,7 +3949,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 31 }, { "name": "Forked Spear", @@ -3506,7 +3961,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 17, + "req_dex": 38 }, { "name": "Forking Belt", @@ -3525,7 +3982,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Fortress Sabatons", @@ -3534,7 +3992,9 @@ "boots", "default", "str_dex_armour" - ] + ], + "req_str": 56, + "req_dex": 56 }, { "name": "Fortress Tower Shield", @@ -3545,7 +4005,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 99 }, { "name": "Frayed Shoes", @@ -3555,7 +4016,9 @@ "default", "dex_int_armour", "ezomyte_basetype" - ] + ], + "req_dex": 7, + "req_int": 7 }, { "name": "Freebooter Cap", @@ -3565,7 +4028,8 @@ "dex_armour", "helmet", "karui_basetype" - ] + ], + "req_dex": 115 }, { "name": "Frenzied Talisman", @@ -3576,7 +4040,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 28, + "req_int": 20 }, { "name": "Frigid Wand", @@ -3588,7 +4054,8 @@ "no_physical_spell_mods", "onehand", "wand" - ] + ], + "req_int": 80 }, { "name": "Full Plate", @@ -3598,7 +4065,8 @@ "default", "str_armour", "vaal_basetype" - ] + ], + "req_str": 54 }, { "name": "Fungal Talisman", @@ -3609,7 +4077,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 96, + "req_int": 70 }, { "name": "Fur Plate", @@ -3619,7 +4089,8 @@ "default", "ezomyte_basetype", "str_armour" - ] + ], + "req_str": 10 }, { "name": "Fur-lined Targe", @@ -3630,7 +4101,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 38, + "req_dex": 38 }, { "name": "Furtive Wraps", @@ -3639,7 +4112,9 @@ "default", "dex_int_armour", "gloves" - ] + ], + "req_dex": 36, + "req_int": 36 }, { "name": "Fury Cleaver", @@ -3649,7 +4124,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 67, + "req_dex": 27 }, { "name": "Fury Talisman", @@ -3660,7 +4137,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 67, + "req_int": 48 }, { "name": "Gallant Helm", @@ -3669,7 +4148,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Galvanic Wand", @@ -3681,7 +4162,8 @@ "no_physical_spell_mods", "onehand", "wand" - ] + ], + "req_int": 46 }, { "name": "Gargantuan Life Flask", @@ -3716,7 +4198,9 @@ "dex_int_armour", "ezomyte_basetype", "gloves" - ] + ], + "req_dex": 6, + "req_int": 6 }, { "name": "Gelid Staff", @@ -3739,7 +4223,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 163 }, { "name": "Gemini Crossbow", @@ -3751,7 +4236,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 89, + "req_dex": 89 }, { "name": "Giant Life Flask", @@ -3777,7 +4264,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 114 }, { "name": "Gilded Vestments", @@ -3786,7 +4274,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 46, + "req_int": 46 }, { "name": "Gilt Leggings", @@ -3795,7 +4285,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 38, + "req_int": 38 }, { "name": "Glacial Fortress", @@ -3806,7 +4298,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 99 }, { "name": "Gladiator Armour", @@ -3815,7 +4308,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 51, + "req_dex": 51 }, { "name": "Gladiatorial Helm", @@ -3825,7 +4320,9 @@ "helmet", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 63, + "req_dex": 63 }, { "name": "Glass Shank", @@ -3845,7 +4342,9 @@ "default", "gloves", "str_int_armour" - ] + ], + "req_str": 52, + "req_int": 52 }, { "name": "Gloam Amulet", @@ -3870,7 +4369,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Glowering Crest Shield", @@ -3881,7 +4381,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 48, + "req_int": 48 }, { "name": "Gold Amulet", @@ -3898,7 +4400,8 @@ "helmet", "int_armour", "vaal_basetype" - ] + ], + "req_int": 58 }, { "name": "Gold Gloves", @@ -3907,7 +4410,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 73 }, { "name": "Gold Ring", @@ -3926,7 +4430,9 @@ "gloves", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 24, + "req_int": 24 }, { "name": "Golden Blade", @@ -3989,7 +4495,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 54, + "req_dex": 54 }, { "name": "Golden Mantle", @@ -4000,7 +4508,10 @@ "demigods", "not_for_sale", "str_dex_int_armour" - ] + ], + "req_str": 7, + "req_dex": 7, + "req_int": 7 }, { "name": "Golden Obi", @@ -4023,7 +4534,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 63, + "req_dex": 63 }, { "name": "Golden Visage", @@ -4052,7 +4565,9 @@ "boots", "default", "str_dex_armour" - ] + ], + "req_str": 38, + "req_dex": 38 }, { "name": "Goldworked Tower Shield", @@ -4063,7 +4578,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 86 }, { "name": "Goliath Greathelm", @@ -4072,7 +4588,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 81 }, { "name": "Gothic Quarterstaff", @@ -4083,7 +4600,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 18, + "req_int": 9 }, { "name": "Graceful Quarterstaff", @@ -4093,7 +4612,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 77, + "req_int": 31 }, { "name": "Grand Bracers", @@ -4102,7 +4623,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 87 }, { "name": "Grand Cuisses", @@ -4111,7 +4633,10 @@ "boots", "default", "str_dex_int_armour" - ] + ], + "req_str": 34, + "req_dex": 34, + "req_int": 34 }, { "name": "Grand Life Flask", @@ -4136,7 +4661,10 @@ "default", "gloves", "str_dex_int_armour" - ] + ], + "req_str": 32, + "req_dex": 32, + "req_int": 32 }, { "name": "Grand Mitts", @@ -4145,7 +4673,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 80 }, { "name": "Grand Regalia", @@ -4154,7 +4683,10 @@ "body_armour", "default", "str_dex_int_armour" - ] + ], + "req_str": 41, + "req_dex": 41, + "req_int": 41 }, { "name": "Grand Spear", @@ -4164,7 +4696,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 68, + "req_dex": 109 }, { "name": "Grand Targe", @@ -4175,7 +4709,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Grand Visage", @@ -4184,7 +4720,10 @@ "default", "helmet", "str_dex_int_armour" - ] + ], + "req_str": 36, + "req_dex": 36, + "req_int": 36 }, { "name": "Grasping Mail", @@ -4193,7 +4732,10 @@ "body_armour", "default", "str_dex_int_armour" - ] + ], + "req_str": 41, + "req_dex": 41, + "req_int": 41 }, { "name": "Grasping Ring", @@ -4212,7 +4754,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 80, + "req_int": 32 }, { "name": "Greatbow", @@ -4223,7 +4767,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 92, + "req_dex": 92 }, { "name": "Greater Life Flask", @@ -4249,7 +4795,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 92 }, { "name": "Grim Gloves", @@ -4258,7 +4805,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 80 }, { "name": "Grinning Mask", @@ -4268,7 +4816,9 @@ "dex_int_armour", "helmet", "karui_basetype" - ] + ], + "req_dex": 63, + "req_int": 63 }, { "name": "Grounding Charm", @@ -4289,7 +4839,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 63, + "req_int": 26 }, { "name": "Guarded Helm", @@ -4299,7 +4851,9 @@ "ezomyte_basetype", "helmet", "str_dex_armour" - ] + ], + "req_str": 11, + "req_dex": 11 }, { "name": "Guardian Bow", @@ -4310,7 +4864,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 163 }, { "name": "Guardian Greathelm", @@ -4319,7 +4874,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 91 }, { "name": "Guardian Quarterstaff", @@ -4329,7 +4885,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 85, + "req_int": 34 }, { "name": "Guardian Spear", @@ -4340,7 +4898,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 50, + "req_dex": 127 }, { "name": "Guarding Arm", @@ -4358,7 +4918,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 99 }, { "name": "Hallowed Crown", @@ -4367,7 +4928,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 42, + "req_int": 42 }, { "name": "Hallowed Focus", @@ -4376,7 +4939,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 86 }, { "name": "Hallowed Sceptre", @@ -4385,7 +4949,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 114 }, { "name": "Hardened Bracers", @@ -4394,7 +4959,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 64 }, { "name": "Hardleather Coat", @@ -4403,7 +4969,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 89 }, { "name": "Hardwood Spear", @@ -4435,7 +5002,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 52, + "req_int": 52 }, { "name": "Havoc Raiment", @@ -4444,7 +5013,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 121 }, { "name": "Hawker's Jacket", @@ -4453,7 +5023,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 54, + "req_int": 54 }, { "name": "Heartcarver Mantle", @@ -4462,7 +5034,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 54, + "req_int": 54 }, { "name": "Heartwood Shortbow", @@ -4473,7 +5047,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 134 }, { "name": "Heavy Belt", @@ -4493,7 +5068,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 114 }, { "name": "Heavy Crown", @@ -4503,7 +5079,9 @@ "helmet", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 27, + "req_int": 27 }, { "name": "Heavy Greathammer", @@ -4513,7 +5091,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 104 }, { "name": "Heavy Plate", @@ -4522,7 +5101,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 94 }, { "name": "Hefty Quarterstaff", @@ -4533,7 +5113,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 63, + "req_int": 26 }, { "name": "Heirloom Cuffs", @@ -4542,7 +5124,9 @@ "default", "gloves", "str_int_armour" - ] + ], + "req_str": 35, + "req_int": 35 }, { "name": "Helix Spear", @@ -4552,7 +5136,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 36, + "req_dex": 89 }, { "name": "Heraldric Tower Shield", @@ -4564,7 +5150,8 @@ "str_armour", "str_shield", "vaal_basetype" - ] + ], + "req_str": 48 }, { "name": "Hermit Garb", @@ -4583,7 +5170,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Hewn Mask", @@ -4593,7 +5182,9 @@ "dex_int_armour", "ezomyte_basetype", "helmet" - ] + ], + "req_dex": 7, + "req_int": 7 }, { "name": "Hexer's Robe", @@ -4603,7 +5194,8 @@ "default", "ezomyte_basetype", "int_armour" - ] + ], + "req_int": 21 }, { "name": "Holy Flail", @@ -4614,7 +5206,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 18, + "req_int": 9 }, { "name": "Homeguard Greathelm", @@ -4623,7 +5217,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 73 }, { "name": "Hooded Mask", @@ -4633,7 +5228,9 @@ "dex_int_armour", "helmet", "maraketh_basetype" - ] + ], + "req_dex": 15, + "req_int": 15 }, { "name": "Hook Axe", @@ -4644,7 +5241,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 9 }, { "name": "Hooked Claw", @@ -4655,7 +5253,8 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_dex": 65 }, { "name": "Horned Crown", @@ -4665,7 +5264,9 @@ "ezomyte_basetype", "helmet", "str_int_armour" - ] + ], + "req_str": 10, + "req_int": 10 }, { "name": "Howling Talisman", @@ -4676,7 +5277,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 63, + "req_int": 45 }, { "name": "Hunter Hood", @@ -4686,7 +5289,8 @@ "dex_armour", "helmet", "vaal_basetype" - ] + ], + "req_dex": 48 }, { "name": "Hunting Bracers", @@ -4695,7 +5299,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 56 }, { "name": "Hunting Coat", @@ -4704,7 +5309,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 77 }, { "name": "Hunting Shoes", @@ -4714,7 +5320,9 @@ "default", "dex_int_armour", "vaal_basetype" - ] + ], + "req_dex": 26, + "req_int": 26 }, { "name": "Hunting Spear", @@ -4725,7 +5333,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 9, + "req_dex": 17 }, { "name": "Icicle Flail", @@ -4735,7 +5345,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 66, + "req_int": 27 }, { "name": "Icicle Staff", @@ -4747,7 +5359,8 @@ "no_physical_spell_mods", "staff", "twohand" - ] + ], + "req_int": 80 }, { "name": "Imperial Greathelm", @@ -4757,7 +5370,8 @@ "helmet", "karui_basetype", "str_armour" - ] + ], + "req_str": 115 }, { "name": "Imperial Robe", @@ -4766,7 +5380,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 83 }, { "name": "Incense Trap", @@ -4783,7 +5398,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 46, + "req_int": 46 }, { "name": "Intricate Crest Shield", @@ -4794,7 +5411,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Intricate Gloves", @@ -4804,7 +5423,8 @@ "gloves", "int_armour", "vaal_basetype" - ] + ], + "req_int": 42 }, { "name": "Intricate Trap", @@ -4834,7 +5454,8 @@ "dex_shield", "maraketh_basetype", "shield" - ] + ], + "req_dex": 25 }, { "name": "Iron Crown", @@ -4844,7 +5465,9 @@ "ezomyte_basetype", "helmet", "str_int_armour" - ] + ], + "req_str": 7, + "req_int": 7 }, { "name": "Iron Cuirass", @@ -4854,7 +5477,8 @@ "default", "ezomyte_basetype", "str_armour" - ] + ], + "req_str": 21 }, { "name": "Iron Flail", @@ -4865,7 +5489,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 25, + "req_int": 12 }, { "name": "Iron Greatsword", @@ -4876,7 +5502,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 9, + "req_dex": 9 }, { "name": "Iron Greaves", @@ -4886,7 +5514,8 @@ "default", "ezomyte_basetype", "str_armour" - ] + ], + "req_str": 17 }, { "name": "Iron Ring", @@ -4905,7 +5534,9 @@ "default", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 31, + "req_int": 31 }, { "name": "Ironhead Spear", @@ -4916,7 +5547,8 @@ "onehand", "spear", "weapon" - ] + ], + "req_dex": 10 }, { "name": "Ironmail Gauntlets", @@ -4925,7 +5557,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 32, + "req_dex": 32 }, { "name": "Ironwood Greathammer", @@ -4935,7 +5569,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Ironwood Shortbow", @@ -4946,7 +5581,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 134 }, { "name": "Ironwood Targe", @@ -4957,7 +5593,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 36, + "req_dex": 36 }, { "name": "Itinerant Jacket", @@ -4966,7 +5604,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 48, + "req_int": 48 }, { "name": "Jade Amulet", @@ -4984,7 +5624,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 87 }, { "name": "Jade Talisman", @@ -4995,7 +5636,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 109, + "req_int": 65 }, { "name": "Jade Tiara", @@ -5005,7 +5648,8 @@ "helmet", "int_armour", "karui_basetype" - ] + ], + "req_int": 71 }, { "name": "Jagged Greataxe", @@ -5016,7 +5660,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 56, + "req_dex": 23 }, { "name": "Jagged Spear", @@ -5026,7 +5672,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 33, + "req_dex": 81 }, { "name": "Jewelled Gloves", @@ -5036,7 +5684,8 @@ "gloves", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 34 }, { "name": "Jingling Buckler", @@ -5048,7 +5697,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 83 }, { "name": "Jingling Crest Shield", @@ -5060,7 +5710,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 23, + "req_int": 23 }, { "name": "Jingling Focus", @@ -5069,7 +5721,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 73 }, { "name": "Juggernaut Plate", @@ -5079,7 +5732,8 @@ "default", "karui_basetype", "str_armour" - ] + ], + "req_str": 72 }, { "name": "Jungle Tiara", @@ -5088,7 +5742,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 83 }, { "name": "Kalguuran Cuffs", @@ -5098,7 +5753,9 @@ "gloves", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 32, + "req_int": 32 }, { "name": "Kalguuran Forgehammer", @@ -5117,7 +5774,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 107 }, { "name": "Keen Greatsword", @@ -5127,7 +5785,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 45, + "req_dex": 45 }, { "name": "Keth Raiment", @@ -5137,7 +5797,8 @@ "default", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 47 }, { "name": "Keyblade", @@ -5167,7 +5828,9 @@ "default", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Knightly Mitts", @@ -5176,7 +5839,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 80 }, { "name": "Kris Knife", @@ -5186,7 +5850,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 49, + "req_int": 49 }, { "name": "Lace Hood", @@ -5196,7 +5862,8 @@ "dex_armour", "helmet", "maraketh_basetype" - ] + ], + "req_dex": 25 }, { "name": "Laced Boots", @@ -5206,7 +5873,8 @@ "default", "dex_armour", "ezomyte_basetype" - ] + ], + "req_dex": 17 }, { "name": "Laced Sandals", @@ -5215,7 +5883,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 60 }, { "name": "Lamellar Mail", @@ -5224,7 +5893,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 46, + "req_dex": 46 }, { "name": "Lament Amulet", @@ -5244,7 +5915,8 @@ "dex_shield", "karui_basetype", "shield" - ] + ], + "req_dex": 64 }, { "name": "Lapis Amulet", @@ -5261,7 +5933,8 @@ "default", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 23 }, { "name": "Lavish Crown", @@ -5270,7 +5943,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Layered Gauntlets", @@ -5280,7 +5955,9 @@ "gloves", "maraketh_basetype", "str_dex_armour" - ] + ], + "req_str": 13, + "req_dex": 13 }, { "name": "Layered Vest", @@ -5289,7 +5966,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 86 }, { "name": "Lazuli Ring", @@ -5317,7 +5995,8 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 60 }, { "name": "Leather Buckler", @@ -5350,7 +6029,8 @@ "dex_armour", "helmet", "karui_basetype" - ] + ], + "req_dex": 71 }, { "name": "Leatherplate Boots", @@ -5359,7 +6039,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 69 }, { "name": "Lesser Life Flask", @@ -5384,7 +6065,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 99 }, { "name": "Light Halberd", @@ -5395,7 +6077,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 9 }, { "name": "Linen Belt", @@ -5414,7 +6097,9 @@ "dex_int_armour", "gloves", "maraketh_basetype" - ] + ], + "req_dex": 13, + "req_int": 13 }, { "name": "Lionheart Greaves", @@ -5423,7 +6108,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 68 }, { "name": "Lizardscale Boots", @@ -5433,7 +6119,8 @@ "default", "dex_armour", "vaal_basetype" - ] + ], + "req_dex": 45 }, { "name": "Lizardscale Coat", @@ -5442,7 +6129,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 98 }, { "name": "Long Belt", @@ -5462,7 +6150,8 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 9 }, { "name": "Lumbering Talisman", @@ -5473,7 +6162,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 60, + "req_int": 43 }, { "name": "Lumen Mace", @@ -5483,7 +6174,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 92 }, { "name": "Lunar Amulet", @@ -5500,7 +6192,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 115, + "req_int": 46 }, { "name": "Lupine Sceptre", @@ -5509,7 +6203,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 24 }, { "name": "Luxurious Robe", @@ -5518,7 +6213,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 82 }, { "name": "Luxurious Slippers", @@ -5527,7 +6223,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 93 }, { "name": "Magus Focus", @@ -5536,7 +6233,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 91 }, { "name": "Magus Tiara", @@ -5545,7 +6243,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 91 }, { "name": "Mail Belt", @@ -5564,7 +6263,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 45, + "req_int": 45 }, { "name": "Mail Coat", @@ -5573,7 +6274,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 121 }, { "name": "Mail Sabatons", @@ -5583,7 +6285,9 @@ "default", "ezomyte_basetype", "str_dex_armour" - ] + ], + "req_str": 7, + "req_dex": 7 }, { "name": "Mail Vestments", @@ -5593,7 +6297,9 @@ "default", "maraketh_basetype", "str_int_armour" - ] + ], + "req_str": 17, + "req_int": 17 }, { "name": "Mailed Crown", @@ -5602,7 +6308,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 36, + "req_int": 36 }, { "name": "Maji Talisman", @@ -5613,7 +6321,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 100, + "req_int": 67 }, { "name": "Makeshift Crossbow", @@ -5637,7 +6347,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Mantled Mail", @@ -5646,7 +6358,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 48, + "req_dex": 48 }, { "name": "Marabout Garb", @@ -5656,7 +6370,9 @@ "default", "dex_int_armour", "maraketh_basetype" - ] + ], + "req_dex": 17, + "req_int": 17 }, { "name": "Maraketh Cuirass", @@ -5666,7 +6382,8 @@ "default", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 34 }, { "name": "Marauding Mace", @@ -5676,7 +6393,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Marching Mace", @@ -5686,7 +6404,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 96 }, { "name": "Martyr Crown", @@ -5696,7 +6415,9 @@ "helmet", "maraketh_basetype", "str_int_armour" - ] + ], + "req_str": 23, + "req_int": 23 }, { "name": "Masked Greathelm", @@ -5705,7 +6426,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 99 }, { "name": "Massive Greathammer", @@ -5715,7 +6437,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Massive Mitts", @@ -5725,7 +6448,8 @@ "gloves", "karui_basetype", "str_armour" - ] + ], + "req_str": 101 }, { "name": "Massive Spear", @@ -5735,7 +6459,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 40, + "req_dex": 80 }, { "name": "Medallion Trap", @@ -5768,7 +6494,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 69 }, { "name": "Mercenary Targe", @@ -5779,7 +6506,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 40, + "req_dex": 40 }, { "name": "Messer", @@ -5789,7 +6518,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 51, + "req_dex": 51 }, { "name": "Metalworked Tower Shield", @@ -5800,7 +6531,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 69 }, { "name": "Militant Bow", @@ -5811,7 +6543,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 109 }, { "name": "Mnemonic Ring", @@ -5830,7 +6563,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Monastic Garb", @@ -5839,7 +6573,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 50, + "req_int": 50 }, { "name": "Monument Greataxe", @@ -5849,7 +6585,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 79, + "req_dex": 32 }, { "name": "Monument Greaves", @@ -5858,7 +6596,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 69 }, { "name": "Moon Dagger", @@ -5869,7 +6608,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 22, + "req_int": 22 }, { "name": "Morning Star", @@ -5880,7 +6621,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 80 }, { "name": "Mosaic Targe", @@ -5892,7 +6634,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Moulded Mitts", @@ -5902,7 +6646,8 @@ "gloves", "str_armour", "vaal_basetype" - ] + ], + "req_str": 42 }, { "name": "Mystic Raiment", @@ -5912,7 +6657,8 @@ "default", "int_armour", "karui_basetype" - ] + ], + "req_int": 78 }, { "name": "Narrow Hood", @@ -5921,7 +6667,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 73 }, { "name": "Nettle Talisman", @@ -5932,7 +6679,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 9, + "req_int": 8 }, { "name": "Noble Circlet", @@ -5941,7 +6690,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 74 }, { "name": "Noble Greathelm", @@ -5950,7 +6700,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 83 }, { "name": "Noble Sabatons", @@ -5959,7 +6710,9 @@ "boots", "default", "str_dex_armour" - ] + ], + "req_str": 51, + "req_dex": 51 }, { "name": "Noble Tower Shield", @@ -5970,7 +6723,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 83 }, { "name": "Oak Buckler", @@ -5982,7 +6736,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 64 }, { "name": "Oak Greathammer", @@ -5993,7 +6748,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 11 }, { "name": "Oak Mask", @@ -6002,7 +6758,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 36, + "req_int": 36 }, { "name": "Obliterator Bow", @@ -6014,7 +6772,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 163 }, { "name": "Obsidian Dagger", @@ -6025,7 +6784,9 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_dex": 34, + "req_int": 34 }, { "name": "Obsidian Greatsword", @@ -6036,7 +6797,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 37, + "req_dex": 37 }, { "name": "Occultist Mantle", @@ -6045,7 +6808,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 48, + "req_int": 48 }, { "name": "Ochre Sceptre", @@ -6054,7 +6819,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 40 }, { "name": "Offering Wand", @@ -6066,7 +6832,8 @@ "no_lightning_spell_mods", "onehand", "wand" - ] + ], + "req_int": 68 }, { "name": "Oiled Jacket", @@ -6075,7 +6842,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 43, + "req_int": 43 }, { "name": "Omen Crest Shield", @@ -6087,7 +6856,9 @@ "str_int_armour", "str_int_shield", "vaal_basetype" - ] + ], + "req_str": 30, + "req_int": 30 }, { "name": "Omen Sceptre", @@ -6096,7 +6867,9 @@ "default", "onehand", "sceptre" - ] + ], + "req_str": 12, + "req_int": 25 }, { "name": "Ominous Gloves", @@ -6105,7 +6878,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 56 }, { "name": "Oneiric Ring", @@ -6123,7 +6897,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 87 }, { "name": "Orichalcum Spear", @@ -6133,7 +6908,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 41, + "req_dex": 104 }, { "name": "Ornate Belt", @@ -6154,7 +6931,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 91 }, { "name": "Ornate Cuffs", @@ -6163,7 +6941,9 @@ "default", "gloves", "str_int_armour" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Ornate Gauntlets", @@ -6172,7 +6952,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 44, + "req_dex": 44 }, { "name": "Ornate Greaves", @@ -6181,7 +6963,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 93 }, { "name": "Ornate Mitts", @@ -6190,7 +6973,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 87 }, { "name": "Ornate Plate", @@ -6199,7 +6983,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Ornate Ringmail", @@ -6208,7 +6993,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 45, + "req_int": 45 }, { "name": "Padded Leggings", @@ -6218,7 +7005,9 @@ "default", "ezomyte_basetype", "str_int_armour" - ] + ], + "req_str": 7, + "req_int": 7 }, { "name": "Painted Buckler", @@ -6230,7 +7019,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 69 }, { "name": "Painted Crest Shield", @@ -6241,7 +7031,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 36, + "req_int": 36 }, { "name": "Painted Crossbow", @@ -6253,7 +7045,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Painted Tower Shield", @@ -6265,7 +7059,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 11 }, { "name": "Paragon Greathelm", @@ -6274,7 +7069,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 107 }, { "name": "Paralysing Staff", @@ -6286,7 +7082,8 @@ "no_physical_spell_mods", "staff", "twohand" - ] + ], + "req_int": 92 }, { "name": "Pariah Mask", @@ -6295,7 +7092,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 42, + "req_int": 42 }, { "name": "Parrying Dagger", @@ -6305,7 +7104,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 51, + "req_int": 51 }, { "name": "Patchwork Vest", @@ -6314,7 +7115,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 72 }, { "name": "Pathfinder Coat", @@ -6324,7 +7126,8 @@ "default", "dex_armour", "ezomyte_basetype" - ] + ], + "req_dex": 21 }, { "name": "Pauascale Gloves", @@ -6334,7 +7137,8 @@ "gloves", "int_armour", "karui_basetype" - ] + ], + "req_int": 56 }, { "name": "Pearl Buckler", @@ -6347,7 +7151,8 @@ "dex_shield", "karui_basetype", "shield" - ] + ], + "req_dex": 71 }, { "name": "Pearl Ring", @@ -6375,7 +7180,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 9, + "req_dex": 9 }, { "name": "Pelt Leggings", @@ -6385,7 +7192,9 @@ "default", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 26, + "req_int": 26 }, { "name": "Pelt Mantle", @@ -6395,7 +7204,9 @@ "default", "ezomyte_basetype", "str_int_armour" - ] + ], + "req_str": 12, + "req_int": 12 }, { "name": "Penetrating Quiver", @@ -6426,7 +7237,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 114 }, { "name": "Permafrost Staff", @@ -6434,7 +7246,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 114 }, { "name": "Phalanx Tower Shield", @@ -6445,7 +7258,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 74 }, { "name": "Pict Claw", @@ -6456,7 +7270,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 14 }, { "name": "Piercing Claw", @@ -6466,7 +7281,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 97 }, { "name": "Piercing Crossbow", @@ -6479,7 +7295,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 49, + "req_dex": 49 }, { "name": "Pilgrim Vestments", @@ -6498,7 +7316,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 47, + "req_int": 47 }, { "name": "Pious Sceptre", @@ -6507,7 +7327,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 102 }, { "name": "Plate Belt", @@ -6526,7 +7347,9 @@ "gloves", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 32, + "req_dex": 32 }, { "name": "Plated Buckler", @@ -6539,7 +7362,8 @@ "dex_shield", "ezomyte_basetype", "shield" - ] + ], + "req_dex": 18 }, { "name": "Plated Claw", @@ -6550,7 +7374,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 41 }, { "name": "Plated Greaves", @@ -6559,7 +7384,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 60 }, { "name": "Plated Mace", @@ -6570,7 +7396,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 48 }, { "name": "Plated Mitts", @@ -6579,7 +7406,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 56 }, { "name": "Plated Raiment", @@ -6588,7 +7416,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 92 }, { "name": "Plated Vestments", @@ -6597,7 +7426,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 52, + "req_int": 52 }, { "name": "Plumed Focus", @@ -6607,7 +7438,8 @@ "focus", "int_armour", "vaal_basetype" - ] + ], + "req_int": 52 }, { "name": "Pointed Maul", @@ -6618,7 +7450,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 80 }, { "name": "Polished Bracers", @@ -6628,7 +7461,8 @@ "dex_armour", "gloves", "karui_basetype" - ] + ], + "req_dex": 101 }, { "name": "Polished Targe", @@ -6639,7 +7473,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 42, + "req_dex": 42 }, { "name": "Portent Amulet", @@ -6656,7 +7492,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 96 }, { "name": "Primal Markings", @@ -6665,7 +7502,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Primal Talisman", @@ -6676,7 +7515,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 34, + "req_int": 25 }, { "name": "Primed Quiver", @@ -6695,7 +7536,8 @@ "no_physical_spell_mods", "onehand", "wand" - ] + ], + "req_int": 99 }, { "name": "Prismatic Ring", @@ -6714,7 +7556,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 75, + "req_dex": 30 }, { "name": "Pronged Spear", @@ -6724,7 +7568,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 46, + "req_dex": 115 }, { "name": "Protector Bow", @@ -6735,7 +7581,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 86 }, { "name": "Pyrophyte Staff", @@ -6747,7 +7594,8 @@ "no_physical_spell_mods", "staff", "twohand" - ] + ], + "req_int": 31 }, { "name": "Quartered Crest Shield", @@ -6758,7 +7606,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 46, + "req_int": 46 }, { "name": "Quickslip Shoes", @@ -6767,7 +7617,9 @@ "boots", "default", "dex_int_armour" - ] + ], + "req_dex": 56, + "req_int": 56 }, { "name": "Quilted Vest", @@ -6777,7 +7629,8 @@ "default", "dex_armour", "ezomyte_basetype" - ] + ], + "req_dex": 10 }, { "name": "Rabid Talisman", @@ -6788,7 +7641,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 40, + "req_int": 29 }, { "name": "Raider Plate", @@ -6798,7 +7653,8 @@ "default", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 28 }, { "name": "Rambler Jacket", @@ -6807,7 +7663,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Rampart Tower Shield", @@ -6819,7 +7677,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 42 }, { "name": "Rattling Sceptre", @@ -6836,7 +7695,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 114 }, { "name": "Rawhide Belt", @@ -6865,7 +7725,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 127, + "req_int": 50 }, { "name": "Razorglass Claw", @@ -6875,7 +7737,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 80 }, { "name": "Reaching Quarterstaff", @@ -6885,7 +7748,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 63, + "req_int": 26 }, { "name": "Reaping Staff", @@ -6897,7 +7762,8 @@ "no_lightning_spell_mods", "staff", "twohand" - ] + ], + "req_int": 68 }, { "name": "Reaver Glaive", @@ -6907,7 +7773,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 63, + "req_dex": 26 }, { "name": "Recurve Bow", @@ -6919,7 +7787,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 31 }, { "name": "Reefsteel Greaves", @@ -6929,7 +7798,8 @@ "default", "karui_basetype", "str_armour" - ] + ], + "req_str": 60 }, { "name": "Refined Bracers", @@ -6938,7 +7808,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 67 }, { "name": "Refined Breach Ring", @@ -6963,7 +7834,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 114 }, { "name": "Regalia Longsword", @@ -6973,7 +7845,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 53, + "req_dex": 53 }, { "name": "Rending Halberd", @@ -6984,7 +7858,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 47, + "req_dex": 20 }, { "name": "Rending Staff", @@ -6996,7 +7872,8 @@ "no_physical_spell_mods", "staff", "twohand" - ] + ], + "req_int": 60 }, { "name": "Restorative Leg", @@ -7011,7 +7888,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Rhoahide Coat", @@ -7021,7 +7900,8 @@ "default", "dex_armour", "maraketh_basetype" - ] + ], + "req_dex": 37 }, { "name": "Rider Bow", @@ -7032,7 +7912,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 91 }, { "name": "Ridged Buckler", @@ -7045,7 +7926,8 @@ "dex_shield", "maraketh_basetype", "shield" - ] + ], + "req_dex": 33 }, { "name": "Riding Coat", @@ -7054,7 +7936,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 82 }, { "name": "Righteous Cuffs", @@ -7063,7 +7946,9 @@ "default", "gloves", "str_int_armour" - ] + ], + "req_str": 36, + "req_int": 36 }, { "name": "Ring", @@ -7083,7 +7968,9 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_str": 54, + "req_int": 23 }, { "name": "Ring Mail", @@ -7092,7 +7979,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Ringed Buckler", @@ -7105,7 +7994,8 @@ "dex_shield", "shield", "vaal_basetype" - ] + ], + "req_dex": 48 }, { "name": "Ringmail Gauntlets", @@ -7115,7 +8005,9 @@ "ezomyte_basetype", "gloves", "str_dex_armour" - ] + ], + "req_str": 6, + "req_dex": 6 }, { "name": "Rippled Greatsword", @@ -7126,7 +8018,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 24, + "req_dex": 24 }, { "name": "River Raiment", @@ -7135,7 +8029,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 86 }, { "name": "Riveted Mitts", @@ -7145,7 +8040,8 @@ "ezomyte_basetype", "gloves", "str_armour" - ] + ], + "req_str": 16 }, { "name": "Roaring Staff", @@ -7153,7 +8049,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 87 }, { "name": "Roaring Talisman", @@ -7163,7 +8060,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 66, + "req_int": 47 }, { "name": "Robust Crossbow", @@ -7175,7 +8074,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 48, + "req_dex": 48 }, { "name": "Rogue Armour", @@ -7185,7 +8086,9 @@ "default", "ezomyte_basetype", "str_dex_armour" - ] + ], + "req_str": 13, + "req_dex": 13 }, { "name": "Rope Cuffs", @@ -7195,7 +8098,9 @@ "ezomyte_basetype", "gloves", "str_int_armour" - ] + ], + "req_str": 6, + "req_int": 6 }, { "name": "Rotted Hood", @@ -7204,7 +8109,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 64 }, { "name": "Rough Greaves", @@ -7225,7 +8131,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 91 }, { "name": "Ruby", @@ -7262,7 +8169,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 77 }, { "name": "Ruination Maul", @@ -7272,7 +8180,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Runed Focus", @@ -7282,7 +8191,8 @@ "focus", "int_armour", "karui_basetype" - ] + ], + "req_int": 64 }, { "name": "Runefather's Grasping Mail", @@ -7292,7 +8202,10 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 57, + "req_dex": 57, + "req_int": 57 }, { "name": "Runeforged Abyssal Cuirass", @@ -7302,7 +8215,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Runeforged Adherent Cuffs", @@ -7313,7 +8227,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 55, + "req_int": 55 }, { "name": "Runeforged Adherent's Raiment", @@ -7323,7 +8239,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 94 }, { "name": "Runeforged Adorned Gloves", @@ -7333,7 +8250,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 80 }, { "name": "Runeforged Adorned Wraps", @@ -7343,7 +8261,9 @@ "dex_int_armour", "gloves", "runeforged" - ] + ], + "req_dex": 41, + "req_int": 41 }, { "name": "Runeforged Aegis Buckler", @@ -7356,7 +8276,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 91 }, { "name": "Runeforged Aged Cuffs", @@ -7367,7 +8288,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 13, + "req_int": 13 }, { "name": "Runeforged Altar Robe", @@ -7378,7 +8301,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 65 }, { "name": "Runeforged Ancestor Tower Shield", @@ -7391,7 +8315,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 71 }, { "name": "Runeforged Ancestral Mail", @@ -7402,7 +8327,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 44, + "req_dex": 44 }, { "name": "Runeforged Ancestral Tiara", @@ -7413,7 +8340,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 115 }, { "name": "Runeforged Anchorite Garb", @@ -7424,7 +8352,9 @@ "dex_int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 31, + "req_int": 31 }, { "name": "Runeforged Ancient Buckler", @@ -7437,7 +8367,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 107 }, { "name": "Runeforged Ancient Cuffs", @@ -7447,7 +8378,9 @@ "gloves", "runeforged", "str_int_armour" - ] + ], + "req_str": 48, + "req_int": 48 }, { "name": "Runeforged Ancient Mitts", @@ -7457,7 +8390,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 67 }, { "name": "Runeforged Antler Focus", @@ -7468,7 +8402,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 17 }, { "name": "Runeforged Apostle Leggings", @@ -7478,7 +8413,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 51, + "req_int": 51 }, { "name": "Runeforged Arcane Raiment", @@ -7488,7 +8425,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runeforged Archon Crown", @@ -7498,7 +8436,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Runeforged Armoured Cap", @@ -7508,7 +8448,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 91 }, { "name": "Runeforged Armoured Vest", @@ -7518,7 +8459,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 121 }, { "name": "Runeforged Array Buckler", @@ -7531,7 +8473,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 78 }, { "name": "Runeforged Arrayed Focus", @@ -7541,7 +8484,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 77 }, { "name": "Runeforged Ascetic Garb", @@ -7552,7 +8496,9 @@ "dex_int_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 45, + "req_int": 45 }, { "name": "Runeforged Assassin Garb", @@ -7562,7 +8508,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runeforged Attuned Focus", @@ -7572,7 +8520,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 81 }, { "name": "Runeforged Aureate Targe", @@ -7585,7 +8534,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 45, + "req_dex": 45 }, { "name": "Runeforged Austere Garb", @@ -7596,7 +8547,9 @@ "dex_int_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runeforged Avian Mask", @@ -7606,7 +8559,9 @@ "dex_int_armour", "helmet", "runeforged" - ] + ], + "req_dex": 46, + "req_int": 46 }, { "name": "Runeforged Avian Targe", @@ -7618,7 +8573,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 48, + "req_dex": 48 }, { "name": "Runeforged Barbed Bracers", @@ -7628,7 +8585,8 @@ "dex_armour", "gloves", "runeforged" - ] + ], + "req_dex": 94 }, { "name": "Runeforged Barbed Spear", @@ -7640,7 +8598,9 @@ "spear", "vaal_basetype", "weapon" - ] + ], + "req_str": 31, + "req_dex": 76 }, { "name": "Runeforged Baroque Gloves", @@ -7650,7 +8610,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 67 }, { "name": "Runeforged Baroque Targe", @@ -7662,7 +8623,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 54, + "req_dex": 54 }, { "name": "Runeforged Barricade Tower Shield", @@ -7675,7 +8638,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 25 }, { "name": "Runeforged Bastion Sabatons", @@ -7685,7 +8649,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 44, + "req_dex": 44 }, { "name": "Runeforged Beaded Circlet", @@ -7696,7 +8662,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 25 }, { "name": "Runeforged Blacksteel Crest Shield", @@ -7709,7 +8676,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 63, + "req_int": 63 }, { "name": "Runeforged Blacksteel Gauntlets", @@ -7720,7 +8689,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 55, + "req_dex": 55 }, { "name": "Runeforged Blacksteel Sabatons", @@ -7731,7 +8702,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 59, + "req_dex": 59 }, { "name": "Runeforged Blacksteel Tower Shield", @@ -7743,7 +8716,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 91 }, { "name": "Runeforged Bladed Shoes", @@ -7753,7 +8727,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 47, + "req_int": 47 }, { "name": "Runeforged Bladeguard Buckler", @@ -7766,7 +8742,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 86 }, { "name": "Runeforged Blazon Crest Shield", @@ -7789,7 +8766,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 47, + "req_dex": 47 }, { "name": "Runeforged Bolstered Mitts", @@ -7800,7 +8779,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 35 }, { "name": "Runeforged Bombard Crossbow", @@ -7814,7 +8794,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 54, + "req_dex": 54 }, { "name": "Runeforged Bone Raiment", @@ -7825,7 +8807,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 28 }, { "name": "Runeforged Bound Bracers", @@ -7836,7 +8819,8 @@ "gloves", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 22 }, { "name": "Runeforged Bound Cuffs", @@ -7846,7 +8830,9 @@ "gloves", "runeforged", "str_int_armour" - ] + ], + "req_str": 44, + "req_int": 44 }, { "name": "Runeforged Bound Sandals", @@ -7856,7 +8842,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 86 }, { "name": "Runeforged Braced Sabatons", @@ -7867,7 +8854,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 14, + "req_dex": 14 }, { "name": "Runeforged Braced Tower Shield", @@ -7880,7 +8869,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 19 }, { "name": "Runeforged Brigand Mask", @@ -7890,7 +8880,9 @@ "dex_int_armour", "helmet", "runeforged" - ] + ], + "req_dex": 50, + "req_int": 50 }, { "name": "Runeforged Brimmed Helm", @@ -7901,7 +8893,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 7, + "req_dex": 7 }, { "name": "Runeforged Bronze Greaves", @@ -7912,7 +8906,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 23 }, { "name": "Runeforged Buckled Wraps", @@ -7923,7 +8918,9 @@ "gloves", "karui_basetype", "runeforged" - ] + ], + "req_dex": 32, + "req_int": 32 }, { "name": "Runeforged Bulwark Greaves", @@ -7933,7 +8930,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 86 }, { "name": "Runeforged Bulwark Tower Shield", @@ -7945,7 +8943,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 77 }, { "name": "Runeforged Burnished Gauntlets", @@ -7955,7 +8954,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 36, + "req_dex": 36 }, { "name": "Runeforged Cabalist Helm", @@ -7965,7 +8966,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 42, + "req_dex": 42 }, { "name": "Runeforged Carved Greaves", @@ -7975,7 +8978,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 78 }, { "name": "Runeforged Carved Targe", @@ -7987,7 +8991,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 40, + "req_dex": 40 }, { "name": "Runeforged Cavalry Boots", @@ -7997,7 +9003,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 93 }, { "name": "Runeforged Ceremonial Robe", @@ -8007,7 +9014,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 98 }, { "name": "Runeforged Chain Mail", @@ -8029,7 +9037,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 38 }, { "name": "Runeforged Champion Cuirass", @@ -8039,7 +9048,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 92 }, { "name": "Runeforged Champion Helm", @@ -8049,7 +9059,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 59, + "req_dex": 59 }, { "name": "Runeforged Changeling Talisman", @@ -8061,7 +9073,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 45, + "req_int": 32 }, { "name": "Runeforged Charmed Shoes", @@ -8071,7 +9085,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 51, + "req_int": 51 }, { "name": "Runeforged Chieftain Cuirass", @@ -8082,7 +9098,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 80 }, { "name": "Runeforged Chiseled Targe", @@ -8095,7 +9112,9 @@ "str_dex_armour", "str_dex_shield", "vaal_basetype" - ] + ], + "req_str": 27, + "req_dex": 27 }, { "name": "Runeforged Cinched Boots", @@ -8105,7 +9124,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 86 }, { "name": "Runeforged Clandestine Jacket", @@ -8115,7 +9135,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 46, + "req_int": 46 }, { "name": "Runeforged Cleric Vestments", @@ -8126,7 +9148,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Runeforged Cloaked Mail", @@ -8137,7 +9161,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 25, + "req_dex": 25 }, { "name": "Runeforged Closed Helm", @@ -8148,7 +9174,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 36, + "req_dex": 36 }, { "name": "Runeforged Colosseum Plate", @@ -8158,7 +9186,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 83 }, { "name": "Runeforged Commander Gauntlets", @@ -8168,7 +9197,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 48, + "req_dex": 48 }, { "name": "Runeforged Commander Greathelm", @@ -8179,7 +9210,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 64 }, { "name": "Runeforged Composite Bow", @@ -8192,7 +9224,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 97 }, { "name": "Runeforged Conjurer Mantle", @@ -8202,7 +9235,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runeforged Conqueror Plate", @@ -8212,7 +9247,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Runeforged Corsair Cap", @@ -8223,7 +9259,8 @@ "helmet", "karui_basetype", "runeforged" - ] + ], + "req_dex": 64 }, { "name": "Runeforged Corsair Coat", @@ -8234,7 +9271,8 @@ "dex_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 121 }, { "name": "Runeforged Corsair Vest", @@ -8245,7 +9283,8 @@ "dex_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 72 }, { "name": "Runeforged Corvus Mantle", @@ -8255,7 +9294,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runeforged Covered Sabatons", @@ -8266,7 +9307,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 34, + "req_dex": 34 }, { "name": "Runeforged Covert Hood", @@ -8276,7 +9319,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 79 }, { "name": "Runeforged Cowled Helm", @@ -8287,7 +9331,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 22, + "req_dex": 22 }, { "name": "Runeforged Crescent Targe", @@ -8300,7 +9346,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 22, + "req_dex": 22 }, { "name": "Runeforged Crucible Tower Shield", @@ -8313,7 +9361,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 64 }, { "name": "Runeforged Crude Bow", @@ -8326,7 +9375,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 97 }, { "name": "Runeforged Crumbling Maul", @@ -8338,7 +9388,8 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 97 }, { "name": "Runeforged Cryptic Crown", @@ -8349,7 +9400,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 63, + "req_int": 63 }, { "name": "Runeforged Cryptic Helm", @@ -8359,7 +9412,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 54, + "req_dex": 54 }, { "name": "Runeforged Cryptic Leggings", @@ -8370,7 +9425,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 59, + "req_int": 59 }, { "name": "Runeforged Crystal Focus", @@ -8381,7 +9438,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 38 }, { "name": "Runeforged Cultist Crown", @@ -8392,7 +9450,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 15, + "req_int": 15 }, { "name": "Runeforged Cultist Focus", @@ -8402,7 +9462,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 83 }, { "name": "Runeforged Cultist Gauntlets", @@ -8412,7 +9473,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 52, + "req_dex": 52 }, { "name": "Runeforged Cultist Greathammer", @@ -8424,7 +9487,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 72 }, { "name": "Runeforged Daggerfoot Shoes", @@ -8435,7 +9499,9 @@ "dex_int_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 59, + "req_int": 59 }, { "name": "Runeforged Dastard Armour", @@ -8445,7 +9511,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runeforged Death Mail", @@ -8455,7 +9523,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runeforged Death Mantle", @@ -8465,7 +9535,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runeforged Death Mask", @@ -8475,7 +9547,9 @@ "dex_int_armour", "helmet", "runeforged" - ] + ], + "req_dex": 50, + "req_int": 50 }, { "name": "Runeforged Decorated Helm", @@ -8485,7 +9559,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Runeforged Deerstalker Hood", @@ -8495,7 +9571,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 83 }, { "name": "Runeforged Defiant Tower Shield", @@ -8507,7 +9584,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 82 }, { "name": "Runeforged Deified Crest Shield", @@ -8519,7 +9597,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Runeforged Dekharan Crest Shield", @@ -8531,7 +9611,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 42, + "req_int": 42 }, { "name": "Runeforged Desert Buckler", @@ -8545,7 +9627,8 @@ "karui_basetype", "runeforged", "shield" - ] + ], + "req_dex": 115 }, { "name": "Runeforged Desert Cap", @@ -8555,7 +9638,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 99 }, { "name": "Runeforged Detailed Mitts", @@ -8566,7 +9650,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 56 }, { "name": "Runeforged Devout Garb", @@ -8576,7 +9661,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runeforged Divine Crown", @@ -8586,7 +9673,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 59, + "req_int": 59 }, { "name": "Runeforged Doubled Gauntlets", @@ -8597,7 +9686,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 24, + "req_dex": 24 }, { "name": "Runeforged Dragonscale Boots", @@ -8607,7 +9698,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 101 }, { "name": "Runeforged Drakeskin Boots", @@ -8618,7 +9710,8 @@ "dex_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 108 }, { "name": "Runeforged Druidic Crown", @@ -8628,7 +9721,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Runeforged Druidic Focus", @@ -8638,7 +9733,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 91 }, { "name": "Runeforged Dualstring Bow", @@ -8651,7 +9747,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 97 }, { "name": "Runeforged Dunerunner Sandals", @@ -8661,7 +9758,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 78 }, { "name": "Runeforged Dyad Crossbow", @@ -8675,7 +9773,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 40, + "req_dex": 40 }, { "name": "Runeforged Edged Buckler", @@ -8689,7 +9789,8 @@ "runeforged", "shield", "vaal_basetype" - ] + ], + "req_dex": 56 }, { "name": "Runeforged Effigial Tower Shield", @@ -8702,7 +9803,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 32 }, { "name": "Runeforged Elaborate Sandals", @@ -8712,7 +9814,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 86 }, { "name": "Runeforged Elegant Focus", @@ -8722,7 +9825,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 74 }, { "name": "Runeforged Elegant Greathelm", @@ -8732,7 +9836,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 77 }, { "name": "Runeforged Elegant Greaves", @@ -8742,7 +9847,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 72 }, { "name": "Runeforged Elegant Plate", @@ -8752,7 +9858,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 86 }, { "name": "Runeforged Elegant Slippers", @@ -8762,7 +9869,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 72 }, { "name": "Runeforged Elegant Wraps", @@ -8772,7 +9880,9 @@ "dex_int_armour", "gloves", "runeforged" - ] + ], + "req_dex": 48, + "req_int": 48 }, { "name": "Runeforged Elementalist Robe", @@ -8783,7 +9893,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 72 }, { "name": "Runeforged Elite Greathelm", @@ -8794,7 +9905,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 48 }, { "name": "Runeforged Emblem Crest Shield", @@ -8807,7 +9919,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 15, + "req_int": 15 }, { "name": "Runeforged Embossed Boots", @@ -8818,7 +9932,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 23 }, { "name": "Runeforged Embroidered Boots", @@ -8828,7 +9943,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 86 }, { "name": "Runeforged Embroidered Gloves", @@ -8838,7 +9954,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 64 }, { "name": "Runeforged Empyreal Crest Shield", @@ -8850,7 +9967,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 45, + "req_int": 45 }, { "name": "Runeforged Engraved Bracers", @@ -8860,7 +9979,8 @@ "dex_armour", "gloves", "runeforged" - ] + ], + "req_dex": 80 }, { "name": "Runeforged Engraved Focus", @@ -8871,7 +9991,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 25 }, { "name": "Runeforged Enlightened Robe", @@ -8881,7 +10002,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runeforged Explorer Armour", @@ -8892,7 +10014,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 31, + "req_dex": 31 }, { "name": "Runeforged Exquisite Vest", @@ -8902,7 +10026,9 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 85, + "req_int": 85 }, { "name": "Runeforged Face Mask", @@ -8913,7 +10039,9 @@ "ezomyte_basetype", "helmet", "runeforged" - ] + ], + "req_dex": 10, + "req_int": 10 }, { "name": "Runeforged Faithful Leggings", @@ -8923,7 +10051,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 47, + "req_int": 47 }, { "name": "Runeforged Falconer's Jacket", @@ -8933,7 +10063,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runeforged Familial Talisman", @@ -8945,7 +10077,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 45, + "req_int": 32 }, { "name": "Runeforged Faridun Mask", @@ -8955,7 +10089,9 @@ "dex_int_armour", "helmet", "runeforged" - ] + ], + "req_dex": 54, + "req_int": 54 }, { "name": "Runeforged Feathered Mitts", @@ -8965,7 +10101,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 73 }, { "name": "Runeforged Feathered Raiment", @@ -8976,7 +10113,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runeforged Feathered Robe", @@ -8987,7 +10125,8 @@ "ezomyte_basetype", "int_armour", "runeforged" - ] + ], + "req_int": 11 }, { "name": "Runeforged Feathered Sandals", @@ -8998,7 +10137,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 45 }, { "name": "Runeforged Feathered Targe", @@ -9011,7 +10151,9 @@ "str_dex_armour", "str_dex_shield", "vaal_basetype" - ] + ], + "req_str": 30, + "req_dex": 30 }, { "name": "Runeforged Feathered Tiara", @@ -9022,7 +10164,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 48 }, { "name": "Runeforged Felled Greatclub", @@ -9034,7 +10177,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 68 }, { "name": "Runeforged Felt Cap", @@ -9045,7 +10189,8 @@ "ezomyte_basetype", "helmet", "runeforged" - ] + ], + "req_dex": 17 }, { "name": "Runeforged Fierce Greathelm", @@ -9056,7 +10201,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 73 }, { "name": "Runeforged Fine Bracers", @@ -9067,7 +10213,8 @@ "gloves", "karui_basetype", "runeforged" - ] + ], + "req_dex": 56 }, { "name": "Runeforged Firm Bracers", @@ -9078,7 +10225,8 @@ "ezomyte_basetype", "gloves", "runeforged" - ] + ], + "req_dex": 16 }, { "name": "Runeforged Fists of Stone", @@ -9099,7 +10247,8 @@ "dex_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 60 }, { "name": "Runeforged Flax Sandals", @@ -9110,7 +10259,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 60 }, { "name": "Runeforged Flexile Sabatons", @@ -9120,7 +10270,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 38, + "req_dex": 38 }, { "name": "Runeforged Flowing Raiment", @@ -9130,7 +10282,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runeforged Forge Maul", @@ -9142,7 +10295,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 72 }, { "name": "Runeforged Forked Spear", @@ -9154,7 +10308,9 @@ "runeforged", "spear", "weapon" - ] + ], + "req_str": 31, + "req_dex": 76 }, { "name": "Runeforged Fortress Sabatons", @@ -9164,7 +10320,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 56, + "req_dex": 56 }, { "name": "Runeforged Fortress Tower Shield", @@ -9176,7 +10334,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 99 }, { "name": "Runeforged Frayed Shoes", @@ -9187,7 +10346,9 @@ "dex_int_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 7, + "req_int": 7 }, { "name": "Runeforged Freebooter Cap", @@ -9198,7 +10359,8 @@ "helmet", "karui_basetype", "runeforged" - ] + ], + "req_dex": 115 }, { "name": "Runeforged Full Plate", @@ -9209,7 +10371,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 54 }, { "name": "Runeforged Fur Plate", @@ -9220,7 +10383,8 @@ "ezomyte_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 61 }, { "name": "Runeforged Furtive Wraps", @@ -9230,7 +10394,9 @@ "dex_int_armour", "gloves", "runeforged" - ] + ], + "req_dex": 36, + "req_int": 36 }, { "name": "Runeforged Gallant Helm", @@ -9240,7 +10406,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Runeforged Garment", @@ -9261,7 +10429,9 @@ "ezomyte_basetype", "gloves", "runeforged" - ] + ], + "req_dex": 6, + "req_int": 6 }, { "name": "Runeforged Gilded Vestments", @@ -9271,7 +10441,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 46, + "req_int": 46 }, { "name": "Runeforged Gilt Leggings", @@ -9281,7 +10453,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 38, + "req_int": 38 }, { "name": "Runeforged Gladiator Armour", @@ -9291,7 +10465,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 51, + "req_dex": 51 }, { "name": "Runeforged Gladiatorial Helm", @@ -9302,7 +10478,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 63, + "req_dex": 63 }, { "name": "Runeforged Gleaming Cuffs", @@ -9312,7 +10490,9 @@ "gloves", "runeforged", "str_int_armour" - ] + ], + "req_str": 52, + "req_int": 52 }, { "name": "Runeforged Glorious Plate", @@ -9322,7 +10502,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Runeforged Glowering Crest Shield", @@ -9334,7 +10515,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 48, + "req_int": 48 }, { "name": "Runeforged Gold Circlet", @@ -9345,7 +10528,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 58 }, { "name": "Runeforged Gold Gloves", @@ -9355,7 +10539,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 73 }, { "name": "Runeforged Goldcast Cuffs", @@ -9366,7 +10551,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 24, + "req_int": 24 }, { "name": "Runeforged Golden Mail", @@ -9376,7 +10563,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 54, + "req_dex": 54 }, { "name": "Runeforged Golden Targe", @@ -9389,7 +10578,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 63, + "req_dex": 63 }, { "name": "Runeforged Goldworked Tower Shield", @@ -9401,7 +10592,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 86 }, { "name": "Runeforged Goliath Greathelm", @@ -9411,7 +10603,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 81 }, { "name": "Runeforged Grand Bracers", @@ -9421,7 +10614,8 @@ "dex_armour", "gloves", "runeforged" - ] + ], + "req_dex": 87 }, { "name": "Runeforged Grand Cuisses", @@ -9431,7 +10625,10 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 34, + "req_dex": 34, + "req_int": 34 }, { "name": "Runeforged Grand Manchettes", @@ -9441,7 +10638,10 @@ "gloves", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 32, + "req_dex": 32, + "req_int": 32 }, { "name": "Runeforged Grand Mitts", @@ -9451,7 +10651,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 80 }, { "name": "Runeforged Grand Regalia", @@ -9461,7 +10662,10 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 41, + "req_dex": 41, + "req_int": 41 }, { "name": "Runeforged Grand Targe", @@ -9473,7 +10677,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Runeforged Grand Visage", @@ -9483,7 +10689,10 @@ "helmet", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 36, + "req_dex": 36, + "req_int": 36 }, { "name": "Runeforged Grasping Mail", @@ -9493,7 +10702,10 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 41, + "req_dex": 41, + "req_int": 41 }, { "name": "Runeforged Grim Gloves", @@ -9503,7 +10715,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 80 }, { "name": "Runeforged Grinning Mask", @@ -9514,7 +10727,9 @@ "helmet", "karui_basetype", "runeforged" - ] + ], + "req_dex": 63, + "req_int": 63 }, { "name": "Runeforged Guarded Helm", @@ -9525,7 +10740,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 11, + "req_dex": 11 }, { "name": "Runeforged Guardian Greathelm", @@ -9535,7 +10752,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 91 }, { "name": "Runeforged Gutspike Buckler", @@ -9548,7 +10766,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 99 }, { "name": "Runeforged Hallowed Crown", @@ -9558,7 +10777,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 42, + "req_int": 42 }, { "name": "Runeforged Hallowed Focus", @@ -9568,7 +10789,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 86 }, { "name": "Runeforged Hardened Bracers", @@ -9578,7 +10800,8 @@ "dex_armour", "gloves", "runeforged" - ] + ], + "req_dex": 64 }, { "name": "Runeforged Hardleather Coat", @@ -9588,7 +10811,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 89 }, { "name": "Runeforged Hardwood Spear", @@ -9600,7 +10824,9 @@ "runeforged", "spear", "weapon" - ] + ], + "req_str": 23, + "req_dex": 56 }, { "name": "Runeforged Hardwood Targe", @@ -9623,7 +10849,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 52, + "req_int": 52 }, { "name": "Runeforged Havoc Raiment", @@ -9633,7 +10861,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runeforged Hawker's Jacket", @@ -9643,7 +10872,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 54, + "req_int": 54 }, { "name": "Runeforged Heartcarver Mantle", @@ -9653,7 +10884,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 54, + "req_int": 54 }, { "name": "Runeforged Heavy Crown", @@ -9664,7 +10897,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 27, + "req_int": 27 }, { "name": "Runeforged Heavy Plate", @@ -9674,7 +10909,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 94 }, { "name": "Runeforged Heraldric Tower Shield", @@ -9687,7 +10923,8 @@ "str_armour", "str_shield", "vaal_basetype" - ] + ], + "req_str": 48 }, { "name": "Runeforged Hermit Garb", @@ -9708,7 +10945,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runeforged Hewn Mask", @@ -9719,7 +10958,9 @@ "ezomyte_basetype", "helmet", "runeforged" - ] + ], + "req_dex": 7, + "req_int": 7 }, { "name": "Runeforged Hexer's Robe", @@ -9730,7 +10971,8 @@ "ezomyte_basetype", "int_armour", "runeforged" - ] + ], + "req_int": 21 }, { "name": "Runeforged Hooded Mask", @@ -9741,7 +10983,9 @@ "helmet", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 15, + "req_int": 15 }, { "name": "Runeforged Horned Crown", @@ -9752,7 +10996,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 10, + "req_int": 10 }, { "name": "Runeforged Hunter Hood", @@ -9763,7 +11009,8 @@ "helmet", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 48 }, { "name": "Runeforged Hunting Shoes", @@ -9774,7 +11021,9 @@ "dex_int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 26, + "req_int": 26 }, { "name": "Runeforged Hunting Spear", @@ -9786,7 +11035,9 @@ "runeforged", "spear", "weapon" - ] + ], + "req_str": 23, + "req_dex": 54 }, { "name": "Runeforged Imperial Greathelm", @@ -9797,7 +11048,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 115 }, { "name": "Runeforged Imperial Robe", @@ -9807,7 +11059,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 83 }, { "name": "Runeforged Inquisitor Crown", @@ -9817,7 +11070,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 46, + "req_int": 46 }, { "name": "Runeforged Intricate Crest Shield", @@ -9829,7 +11084,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Runeforged Intricate Gloves", @@ -9840,7 +11097,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 42 }, { "name": "Runeforged Iron Buckler", @@ -9854,7 +11112,8 @@ "maraketh_basetype", "runeforged", "shield" - ] + ], + "req_dex": 25 }, { "name": "Runeforged Iron Crown", @@ -9865,7 +11124,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 7, + "req_int": 7 }, { "name": "Runeforged Iron Cuirass", @@ -9876,7 +11137,8 @@ "ezomyte_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 21 }, { "name": "Runeforged Iron Greaves", @@ -9887,7 +11149,8 @@ "ezomyte_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 17 }, { "name": "Runeforged Ironclad Vestments", @@ -9898,7 +11161,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 31, + "req_int": 31 }, { "name": "Runeforged Ironhead Spear", @@ -9910,7 +11175,9 @@ "runeforged", "spear", "weapon" - ] + ], + "req_str": 23, + "req_dex": 54 }, { "name": "Runeforged Itinerant Jacket", @@ -9920,7 +11187,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 48, + "req_int": 48 }, { "name": "Runeforged Jade Tiara", @@ -9931,7 +11200,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 71 }, { "name": "Runeforged Jewelled Gloves", @@ -9942,7 +11212,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 34 }, { "name": "Runeforged Jingling Buckler", @@ -9955,7 +11226,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 83 }, { "name": "Runeforged Jingling Crest Shield", @@ -9968,7 +11240,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 23, + "req_int": 23 }, { "name": "Runeforged Juggernaut Plate", @@ -9979,7 +11253,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 72 }, { "name": "Runeforged Jungle Tiara", @@ -9989,7 +11264,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 83 }, { "name": "Runeforged Kalguuran Cuffs", @@ -10000,7 +11276,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 32, + "req_int": 32 }, { "name": "Runeforged Kalguuran Forgehammer", @@ -10021,7 +11299,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 107 }, { "name": "Runeforged Keth Raiment", @@ -10032,7 +11311,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 47 }, { "name": "Runeforged Knight Armour", @@ -10043,7 +11323,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Runeforged Knightly Mitts", @@ -10053,7 +11335,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 80 }, { "name": "Runeforged Lace Hood", @@ -10064,7 +11347,8 @@ "helmet", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 54 }, { "name": "Runeforged Laced Boots", @@ -10075,7 +11359,8 @@ "dex_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 17 }, { "name": "Runeforged Lamellar Mail", @@ -10085,7 +11370,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 46, + "req_dex": 46 }, { "name": "Runeforged Laminate Buckler", @@ -10099,7 +11386,8 @@ "karui_basetype", "runeforged", "shield" - ] + ], + "req_dex": 64 }, { "name": "Runeforged Lattice Sandals", @@ -10110,7 +11398,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 23 }, { "name": "Runeforged Lavish Crown", @@ -10120,7 +11409,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Runeforged Layered Gauntlets", @@ -10131,7 +11422,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 13, + "req_dex": 13 }, { "name": "Runeforged Layered Vest", @@ -10141,7 +11434,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 86 }, { "name": "Runeforged Leaden Greathammer", @@ -10153,7 +11447,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 60, + "req_int": 50 }, { "name": "Runeforged Leather Buckler", @@ -10189,7 +11485,8 @@ "helmet", "karui_basetype", "runeforged" - ] + ], + "req_dex": 71 }, { "name": "Runeforged Leatherplate Boots", @@ -10199,7 +11496,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 69 }, { "name": "Runeforged Leyline Focus", @@ -10209,7 +11507,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 99 }, { "name": "Runeforged Linen Wraps", @@ -10220,7 +11519,9 @@ "gloves", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 13, + "req_int": 13 }, { "name": "Runeforged Lizardscale Boots", @@ -10231,7 +11532,8 @@ "dex_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 45 }, { "name": "Runeforged Lizardscale Coat", @@ -10241,7 +11543,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 98 }, { "name": "Runeforged Luxurious Slippers", @@ -10251,7 +11554,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 93 }, { "name": "Runeforged Magus Focus", @@ -10261,7 +11565,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 91 }, { "name": "Runeforged Magus Tiara", @@ -10271,7 +11576,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 91 }, { "name": "Runeforged Mail Coat", @@ -10281,7 +11587,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 121 }, { "name": "Runeforged Mail Sabatons", @@ -10292,7 +11599,9 @@ "ezomyte_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 7, + "req_dex": 7 }, { "name": "Runeforged Mail Vestments", @@ -10303,7 +11612,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 17, + "req_int": 17 }, { "name": "Runeforged Makeshift Crossbow", @@ -10317,7 +11628,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 39, + "req_dex": 39 }, { "name": "Runeforged Mammoth Targe", @@ -10329,7 +11642,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Runeforged Mantled Mail", @@ -10339,7 +11654,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 48, + "req_dex": 48 }, { "name": "Runeforged Marabout Garb", @@ -10350,7 +11667,9 @@ "dex_int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 17, + "req_int": 17 }, { "name": "Runeforged Maraketh Cuirass", @@ -10361,7 +11680,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 34 }, { "name": "Runeforged Marching Mace", @@ -10372,7 +11692,8 @@ "onehand", "runeforged", "weapon" - ] + ], + "req_str": 114 }, { "name": "Runeforged Martyr Crown", @@ -10383,7 +11704,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 23, + "req_int": 23 }, { "name": "Runeforged Masked Greathelm", @@ -10393,7 +11716,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 99 }, { "name": "Runeforged Massive Mitts", @@ -10404,7 +11728,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 101 }, { "name": "Runeforged Monastic Garb", @@ -10414,7 +11739,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 50, + "req_int": 50 }, { "name": "Runeforged Monument Greaves", @@ -10424,7 +11751,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 69 }, { "name": "Runeforged Morning Star", @@ -10435,7 +11763,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 114 }, { "name": "Runeforged Mosaic Targe", @@ -10448,7 +11777,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Runeforged Moulded Mitts", @@ -10459,7 +11790,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 42 }, { "name": "Runeforged Mystic Raiment", @@ -10470,7 +11802,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 78 }, { "name": "Runeforged Nettle Talisman", @@ -10482,7 +11815,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 45, + "req_int": 32 }, { "name": "Runeforged Noble Circlet", @@ -10492,7 +11827,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 74 }, { "name": "Runeforged Noble Greathelm", @@ -10502,7 +11838,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 83 }, { "name": "Runeforged Noble Sabatons", @@ -10512,7 +11849,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 51, + "req_dex": 51 }, { "name": "Runeforged Noble Tower Shield", @@ -10524,7 +11863,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 83 }, { "name": "Runeforged Oak Greathammer", @@ -10536,7 +11876,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 68 }, { "name": "Runeforged Occultist Mantle", @@ -10546,7 +11887,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 48, + "req_int": 48 }, { "name": "Runeforged Omen Crest Shield", @@ -10559,7 +11902,9 @@ "str_int_armour", "str_int_shield", "vaal_basetype" - ] + ], + "req_str": 30, + "req_int": 30 }, { "name": "Runeforged Opulent Gloves", @@ -10569,7 +11914,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 87 }, { "name": "Runeforged Ornate Buckler", @@ -10582,7 +11928,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 91 }, { "name": "Runeforged Ornate Cuffs", @@ -10592,7 +11939,9 @@ "gloves", "runeforged", "str_int_armour" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Runeforged Ornate Gauntlets", @@ -10602,7 +11951,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 44, + "req_dex": 44 }, { "name": "Runeforged Ornate Greaves", @@ -10612,7 +11963,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 93 }, { "name": "Runeforged Ornate Mitts", @@ -10622,7 +11974,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 87 }, { "name": "Runeforged Ornate Plate", @@ -10632,7 +11985,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Runeforged Padded Leggings", @@ -10643,7 +11997,9 @@ "ezomyte_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 7, + "req_int": 7 }, { "name": "Runeforged Painted Tower Shield", @@ -10656,7 +12012,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 11 }, { "name": "Runeforged Paragon Greathelm", @@ -10666,7 +12023,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 107 }, { "name": "Runeforged Pariah Mask", @@ -10676,7 +12034,9 @@ "dex_int_armour", "helmet", "runeforged" - ] + ], + "req_dex": 42, + "req_int": 42 }, { "name": "Runeforged Pathfinder Coat", @@ -10687,7 +12047,8 @@ "dex_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 21 }, { "name": "Runeforged Pauascale Gloves", @@ -10698,7 +12059,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 56 }, { "name": "Runeforged Pearl Buckler", @@ -10712,7 +12074,8 @@ "karui_basetype", "runeforged", "shield" - ] + ], + "req_dex": 71 }, { "name": "Runeforged Pelage Targe", @@ -10725,7 +12088,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 9, + "req_dex": 9 }, { "name": "Runeforged Pelt Leggings", @@ -10736,7 +12101,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 26, + "req_int": 26 }, { "name": "Runeforged Pelt Mantle", @@ -10747,7 +12114,9 @@ "ezomyte_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 12, + "req_int": 12 }, { "name": "Runeforged Phalanx Tower Shield", @@ -10759,7 +12128,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 74 }, { "name": "Runeforged Pilgrim Vestments", @@ -10780,7 +12150,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 47, + "req_int": 47 }, { "name": "Runeforged Plate Gauntlets", @@ -10791,7 +12163,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 32, + "req_dex": 32 }, { "name": "Runeforged Plated Buckler", @@ -10805,7 +12179,8 @@ "ezomyte_basetype", "runeforged", "shield" - ] + ], + "req_dex": 18 }, { "name": "Runeforged Plated Raiment", @@ -10815,7 +12190,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 92 }, { "name": "Runeforged Plated Vestments", @@ -10825,7 +12201,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 52, + "req_int": 52 }, { "name": "Runeforged Plumed Focus", @@ -10836,7 +12214,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 52 }, { "name": "Runeforged Pointed Maul", @@ -10848,7 +12227,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 114 }, { "name": "Runeforged Polished Bracers", @@ -10859,7 +12239,8 @@ "gloves", "karui_basetype", "runeforged" - ] + ], + "req_dex": 101 }, { "name": "Runeforged Polished Targe", @@ -10871,7 +12252,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 42, + "req_dex": 42 }, { "name": "Runeforged Primal Markings", @@ -10881,7 +12264,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runeforged Quartered Crest Shield", @@ -10893,7 +12278,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 46, + "req_int": 46 }, { "name": "Runeforged Quickslip Shoes", @@ -10903,7 +12290,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 56, + "req_int": 56 }, { "name": "Runeforged Quilted Vest", @@ -10914,7 +12303,8 @@ "dex_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 10 }, { "name": "Runeforged Raider Plate", @@ -10925,7 +12315,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 28 }, { "name": "Runeforged Rambler Jacket", @@ -10935,7 +12326,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runeforged Rampart Tower Shield", @@ -10948,7 +12341,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 42 }, { "name": "Runeforged Rawhide Boots", @@ -10972,7 +12366,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 72 }, { "name": "Runeforged Reefsteel Greaves", @@ -10983,7 +12378,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 60 }, { "name": "Runeforged Refined Bracers", @@ -10993,7 +12389,8 @@ "dex_armour", "gloves", "runeforged" - ] + ], + "req_dex": 67 }, { "name": "Runeforged Revered Vestments", @@ -11003,7 +12400,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runeforged Rhoahide Coat", @@ -11014,7 +12413,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 37 }, { "name": "Runeforged Ridged Buckler", @@ -11028,7 +12428,8 @@ "maraketh_basetype", "runeforged", "shield" - ] + ], + "req_dex": 33 }, { "name": "Runeforged Righteous Cuffs", @@ -11038,7 +12439,9 @@ "gloves", "runeforged", "str_int_armour" - ] + ], + "req_str": 36, + "req_int": 36 }, { "name": "Runeforged Ringed Buckler", @@ -11052,7 +12455,8 @@ "runeforged", "shield", "vaal_basetype" - ] + ], + "req_dex": 48 }, { "name": "Runeforged Ringmail Gauntlets", @@ -11063,7 +12467,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 6, + "req_dex": 6 }, { "name": "Runeforged River Raiment", @@ -11073,7 +12479,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 86 }, { "name": "Runeforged Riveted Mitts", @@ -11084,7 +12491,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 16 }, { "name": "Runeforged Rogue Armour", @@ -11095,7 +12503,9 @@ "ezomyte_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 13, + "req_dex": 13 }, { "name": "Runeforged Rope Cuffs", @@ -11106,7 +12516,9 @@ "gloves", "runeforged", "str_int_armour" - ] + ], + "req_str": 6, + "req_int": 6 }, { "name": "Runeforged Rough Greaves", @@ -11129,7 +12541,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 91 }, { "name": "Runeforged Runed Focus", @@ -11140,7 +12553,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 64 }, { "name": "Runeforged Runner Vest", @@ -11150,7 +12564,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 94 }, { "name": "Runeforged Rusted Cuirass", @@ -11182,7 +12597,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runeforged Sacred Focus", @@ -11192,7 +12608,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 107 }, { "name": "Runeforged Sacrificial Mantle", @@ -11203,7 +12620,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 33, + "req_int": 33 }, { "name": "Runeforged Sacrificial Regalia", @@ -11213,7 +12632,9 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 80, + "req_int": 80 }, { "name": "Runeforged Saintly Crown", @@ -11223,7 +12644,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 54, + "req_int": 54 }, { "name": "Runeforged Sandsworn Sandals", @@ -11233,7 +12656,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 101 }, { "name": "Runeforged Sandsworn Tiara", @@ -11243,7 +12667,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 77 }, { "name": "Runeforged Scale Mail", @@ -11254,7 +12679,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 34, + "req_dex": 34 }, { "name": "Runeforged Scalper's Jacket", @@ -11265,7 +12692,9 @@ "dex_int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 35, + "req_int": 35 }, { "name": "Runeforged Scoundrel Jacket", @@ -11276,7 +12705,9 @@ "dex_int_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 41, + "req_int": 41 }, { "name": "Runeforged Scout's Vest", @@ -11287,7 +12718,8 @@ "dex_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 54 }, { "name": "Runeforged Seastorm Mantle", @@ -11298,7 +12730,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runeforged Sectarian Crest Shield", @@ -11311,7 +12745,9 @@ "str_int_armour", "str_int_shield", "vaal_basetype" - ] + ], + "req_str": 27, + "req_int": 27 }, { "name": "Runeforged Sectioned Bracers", @@ -11322,7 +12758,8 @@ "gloves", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 36 }, { "name": "Runeforged Secured Leggings", @@ -11333,7 +12770,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 14, + "req_int": 14 }, { "name": "Runeforged Secured Wraps", @@ -11344,7 +12783,9 @@ "gloves", "karui_basetype", "runeforged" - ] + ], + "req_dex": 55, + "req_int": 55 }, { "name": "Runeforged Seer Crest Shield", @@ -11357,7 +12798,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 39, + "req_int": 39 }, { "name": "Runeforged Sekhema Sandals", @@ -11368,7 +12811,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 108 }, { "name": "Runeforged Sekheman Crest Shield", @@ -11380,7 +12824,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 54, + "req_int": 54 }, { "name": "Runeforged Sentinel Greathelm", @@ -11390,7 +12836,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 74 }, { "name": "Runeforged Serpentscale Boots", @@ -11400,7 +12847,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 78 }, { "name": "Runeforged Serpentscale Coat", @@ -11411,7 +12859,8 @@ "dex_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 59 }, { "name": "Runeforged Shabby Hood", @@ -11432,7 +12881,9 @@ "dex_int_armour", "helmet", "runeforged" - ] + ], + "req_dex": 41, + "req_int": 41 }, { "name": "Runeforged Shaman Mantle", @@ -11443,7 +12894,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 26, + "req_int": 26 }, { "name": "Runeforged Shamanistic Leggings", @@ -11453,7 +12906,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 44, + "req_int": 44 }, { "name": "Runeforged Shielded Helm", @@ -11464,7 +12919,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 27, + "req_dex": 27 }, { "name": "Runeforged Shortbow", @@ -11477,7 +12934,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 97 }, { "name": "Runeforged Shrouded Mail", @@ -11487,7 +12945,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runeforged Shrouded Vest", @@ -11498,7 +12958,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 28 }, { "name": "Runeforged Sigil Crest Shield", @@ -11511,7 +12972,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 8, + "req_int": 8 }, { "name": "Runeforged Signet Cuffs", @@ -11521,7 +12984,9 @@ "gloves", "runeforged", "str_int_armour" - ] + ], + "req_str": 44, + "req_int": 44 }, { "name": "Runeforged Silk Robe", @@ -11532,7 +12997,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 37 }, { "name": "Runeforged Silk Slippers", @@ -11543,7 +13009,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 38 }, { "name": "Runeforged Sirenscale Gloves", @@ -11554,7 +13021,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 101 }, { "name": "Runeforged Skycrown Tiara", @@ -11564,7 +13032,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 91 }, { "name": "Runeforged Slayer Armour", @@ -11574,7 +13043,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runeforged Sleek Jacket", @@ -11584,7 +13055,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runeforged Slim Mace", @@ -11596,7 +13069,8 @@ "onehand", "runeforged", "weapon" - ] + ], + "req_str": 68 }, { "name": "Runeforged Slipstrike Vest", @@ -11606,7 +13080,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 121 }, { "name": "Runeforged Smuggler Coat", @@ -11617,7 +13092,8 @@ "dex_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 82 }, { "name": "Runeforged Soaring Mask", @@ -11627,7 +13103,9 @@ "dex_int_armour", "helmet", "runeforged" - ] + ], + "req_dex": 59, + "req_int": 59 }, { "name": "Runeforged Soaring Targe", @@ -11639,7 +13117,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 59, + "req_dex": 59 }, { "name": "Runeforged Soldier Cuirass", @@ -11649,7 +13129,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Runeforged Soldier Greathelm", @@ -11660,7 +13141,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 19 }, { "name": "Runeforged Solid Mask", @@ -11671,7 +13153,9 @@ "helmet", "karui_basetype", "runeforged" - ] + ], + "req_dex": 36, + "req_int": 36 }, { "name": "Runeforged Sombre Gloves", @@ -11682,7 +13166,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 17 }, { "name": "Runeforged Sorcerous Tiara", @@ -11692,7 +13177,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 99 }, { "name": "Runeforged Spiked Bracers", @@ -11702,7 +13188,8 @@ "dex_armour", "gloves", "runeforged" - ] + ], + "req_dex": 73 }, { "name": "Runeforged Spiked Buckler", @@ -11716,7 +13203,8 @@ "maraketh_basetype", "runeforged", "shield" - ] + ], + "req_dex": 38 }, { "name": "Runeforged Spiked Club", @@ -11728,7 +13216,8 @@ "onehand", "runeforged", "weapon" - ] + ], + "req_str": 72 }, { "name": "Runeforged Spikeward Buckler", @@ -11741,7 +13230,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 77 }, { "name": "Runeforged Spined Bracers", @@ -11752,7 +13242,8 @@ "gloves", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 42 }, { "name": "Runeforged Spiral Wraps", @@ -11763,7 +13254,9 @@ "gloves", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 24, + "req_int": 24 }, { "name": "Runeforged Spired Greathelm", @@ -11774,7 +13267,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 40 }, { "name": "Runeforged Spiritbone Crown", @@ -11785,7 +13279,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 36, + "req_int": 36 }, { "name": "Runeforged Splintered Tower Shield", @@ -11809,7 +13305,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 26, + "req_dex": 26 }, { "name": "Runeforged Stalking Bracers", @@ -11819,7 +13317,8 @@ "dex_armour", "gloves", "runeforged" - ] + ], + "req_dex": 80 }, { "name": "Runeforged Steel Plate", @@ -11830,7 +13329,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 45 }, { "name": "Runeforged Steelmail Gauntlets", @@ -11840,7 +13340,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 44, + "req_dex": 44 }, { "name": "Runeforged Steelpoint Shoes", @@ -11851,7 +13353,9 @@ "dex_int_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 34, + "req_int": 34 }, { "name": "Runeforged Steeltoe Boots", @@ -11862,7 +13366,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 39 }, { "name": "Runeforged Stitched Gloves", @@ -11873,7 +13378,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 22 }, { "name": "Runeforged Stocky Mitts", @@ -11896,7 +13402,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Runeforged Stone Cuirass", @@ -11906,7 +13414,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 98 }, { "name": "Runeforged Stone Greaves", @@ -11917,7 +13426,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 45 }, { "name": "Runeforged Stone Targe", @@ -11929,7 +13439,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 46, + "req_dex": 46 }, { "name": "Runeforged Stone Tower Shield", @@ -11942,7 +13454,8 @@ "str_armour", "str_shield", "vaal_basetype" - ] + ], + "req_str": 52 }, { "name": "Runeforged Stratified Targe", @@ -11954,7 +13467,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 37, + "req_dex": 37 }, { "name": "Runeforged Straw Sandals", @@ -11975,7 +13490,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 83 }, { "name": "Runeforged Studded Boots", @@ -11985,7 +13501,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 72 }, { "name": "Runeforged Studded Greatclub", @@ -11997,7 +13514,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 68 }, { "name": "Runeforged Studded Sandals", @@ -12007,7 +13525,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 69 }, { "name": "Runeforged Studded Targe", @@ -12020,7 +13539,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 15, + "req_dex": 15 }, { "name": "Runeforged Studded Vest", @@ -12031,7 +13552,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 43 }, { "name": "Runeforged Sturdy Crossbow", @@ -12045,7 +13567,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 39, + "req_dex": 39 }, { "name": "Runeforged Suede Bracers", @@ -12067,7 +13591,8 @@ "helmet", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 38 }, { "name": "Runeforged Swiftstalker Coat", @@ -12077,7 +13602,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 121 }, { "name": "Runeforged Tasalian Focus", @@ -12088,7 +13614,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 115 }, { "name": "Runeforged Tasalian Greaves", @@ -12099,7 +13626,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 108 }, { "name": "Runeforged Tattered Robe", @@ -12123,7 +13651,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 115 }, { "name": "Runeforged Tempered Mitts", @@ -12134,7 +13663,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 22 }, { "name": "Runeforged Temple Maul", @@ -12146,7 +13676,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 76, + "req_dex": 40 }, { "name": "Runeforged Tense Crossbow", @@ -12160,7 +13692,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 39, + "req_dex": 39 }, { "name": "Runeforged Thane Mail", @@ -12171,7 +13705,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runeforged Threaded Shoes", @@ -12182,7 +13718,9 @@ "dex_int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 14, + "req_int": 14 }, { "name": "Runeforged Tideseer Mantle", @@ -12193,7 +13731,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 45, + "req_int": 45 }, { "name": "Runeforged Titan Mitts", @@ -12203,7 +13743,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 64 }, { "name": "Runeforged Tonal Focus", @@ -12214,7 +13755,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 33 }, { "name": "Runeforged Torment Jacket", @@ -12224,7 +13766,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runeforged Torn Gloves", @@ -12245,7 +13789,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 86 }, { "name": "Runeforged Tournament Mail", @@ -12255,7 +13800,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runeforged Trailblazer Armour", @@ -12265,7 +13812,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 52, + "req_dex": 52 }, { "name": "Runeforged Trapper Hood", @@ -12275,7 +13824,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 107 }, { "name": "Runeforged Treerunner Shoes", @@ -12285,7 +13835,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 44, + "req_int": 44 }, { "name": "Runeforged Tribal Mask", @@ -12296,7 +13848,9 @@ "helmet", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 27, + "req_int": 27 }, { "name": "Runeforged Trimmed Greaves", @@ -12307,7 +13861,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 38 }, { "name": "Runeforged Twig Circlet", @@ -12339,7 +13894,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 82 }, { "name": "Runeforged Utility Wraps", @@ -12349,7 +13905,9 @@ "dex_int_armour", "gloves", "runeforged" - ] + ], + "req_dex": 44, + "req_int": 44 }, { "name": "Runeforged Utzaal Cuirass", @@ -12359,7 +13917,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Runeforged Vaal Crest Shield", @@ -12371,7 +13930,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 59, + "req_int": 59 }, { "name": "Runeforged Vaal Cuirass", @@ -12382,7 +13943,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 60 }, { "name": "Runeforged Vaal Gloves", @@ -12392,7 +13954,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 94 }, { "name": "Runeforged Vaal Greaves", @@ -12402,7 +13965,8 @@ "default", "runeforged", "str_armour" - ] + ], + "req_str": 101 }, { "name": "Runeforged Vaal Mitts", @@ -12412,7 +13976,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 94 }, { "name": "Runeforged Vaal Tower Shield", @@ -12424,7 +13989,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 107 }, { "name": "Runeforged Vaal Wraps", @@ -12434,7 +14000,9 @@ "dex_int_armour", "gloves", "runeforged" - ] + ], + "req_dex": 52, + "req_int": 52 }, { "name": "Runeforged Vagabond Armour", @@ -12445,7 +14013,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 17, + "req_dex": 17 }, { "name": "Runeforged Veiled Mask", @@ -12456,7 +14026,9 @@ "helmet", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 23, + "req_int": 23 }, { "name": "Runeforged Velour Shoes", @@ -12466,7 +14038,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 38, + "req_int": 38 }, { "name": "Runeforged Velvet Cap", @@ -12476,7 +14050,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 74 }, { "name": "Runeforged Venerated Mantle", @@ -12486,7 +14061,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 48, + "req_int": 48 }, { "name": "Runeforged Vermeil Circlet", @@ -12497,7 +14074,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 64 }, { "name": "Runeforged Veteran Sabatons", @@ -12507,7 +14085,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 47, + "req_dex": 47 }, { "name": "Runeforged Vicious Talisman", @@ -12519,7 +14099,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 74, + "req_int": 52 }, { "name": "Runeforged Vile Robe", @@ -12529,7 +14111,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runeforged Viper Cap", @@ -12540,7 +14123,8 @@ "helmet", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 54 }, { "name": "Runeforged Visored Helm", @@ -12551,7 +14135,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 15, + "req_dex": 15 }, { "name": "Runeforged Voodoo Focus", @@ -12562,7 +14148,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 48 }, { "name": "Runeforged Votive Raiment", @@ -12573,7 +14160,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 54 }, { "name": "Runeforged Wanderer Shoes", @@ -12583,7 +14171,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 47, + "req_int": 47 }, { "name": "Runeforged War Spear", @@ -12595,7 +14185,9 @@ "runeforged", "spear", "weapon" - ] + ], + "req_str": 23, + "req_dex": 56 }, { "name": "Runeforged War Wraps", @@ -12605,7 +14197,9 @@ "dex_int_armour", "gloves", "runeforged" - ] + ], + "req_dex": 44, + "req_int": 44 }, { "name": "Runeforged Warded Helm", @@ -12615,7 +14209,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Runeforged Warlock Leggings", @@ -12625,7 +14221,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 56, + "req_int": 56 }, { "name": "Runeforged Warlord Cuirass", @@ -12636,7 +14234,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Runeforged Warmonger Greathelm", @@ -12646,7 +14245,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 91 }, { "name": "Runeforged Warpick", @@ -12658,7 +14258,8 @@ "onehand", "runeforged", "weapon" - ] + ], + "req_str": 68 }, { "name": "Runeforged Warrior Greathelm", @@ -12669,7 +14270,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 52 }, { "name": "Runeforged Waxed Jacket", @@ -12680,7 +14282,9 @@ "dex_int_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 13, + "req_int": 13 }, { "name": "Runeforged Wayfarer Jacket", @@ -12691,7 +14295,9 @@ "dex_int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 26, + "req_int": 26 }, { "name": "Runeforged Wayward Crest Shield", @@ -12704,7 +14310,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 36, + "req_int": 36 }, { "name": "Runeforged Weaver Leggings", @@ -12715,7 +14323,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 34, + "req_int": 34 }, { "name": "Runeforged Whorl Focus", @@ -12726,7 +14336,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 73 }, { "name": "Runeforged Wicker Tiara", @@ -12737,7 +14348,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 17 }, { "name": "Runeforged Winged Spear", @@ -12749,7 +14361,9 @@ "runeforged", "spear", "weapon" - ] + ], + "req_str": 23, + "req_dex": 56 }, { "name": "Runeforged Wolfskin Mantle", @@ -12759,7 +14373,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runeforged Wooden Buckler", @@ -12773,7 +14389,8 @@ "ezomyte_basetype", "runeforged", "shield" - ] + ], + "req_dex": 10 }, { "name": "Runeforged Wooden Club", @@ -12785,7 +14402,8 @@ "onehand", "runeforged", "weapon" - ] + ], + "req_str": 68 }, { "name": "Runeforged Woven Cap", @@ -12795,7 +14413,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 91 }, { "name": "Runeforged Woven Focus", @@ -12806,7 +14425,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 11 }, { "name": "Runeforged Wrapped Cap", @@ -12816,7 +14436,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 77 }, { "name": "Runeforged Wrapped Greathelm", @@ -12827,7 +14448,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 25 }, { "name": "Runeforged Wrapped Sandals", @@ -12838,7 +14460,8 @@ "ezomyte_basetype", "int_armour", "runeforged" - ] + ], + "req_int": 17 }, { "name": "Runeforged Wyrmscale Coat", @@ -12848,7 +14471,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 121 }, { "name": "Runeforged Zealot Bow", @@ -12861,7 +14485,8 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_dex": 97 }, { "name": "Runeforged Zealot Gauntlets", @@ -12871,7 +14496,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Runeforged Zenith Vestments", @@ -12881,7 +14508,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runemastered Aberrant Sledge", @@ -12892,7 +14521,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Runemastered Aged Cuffs", @@ -12903,7 +14533,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 27, + "req_int": 27 }, { "name": "Runemastered Altar Robe", @@ -12914,7 +14546,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 87 }, { "name": "Runemastered Ancestral Mail", @@ -12925,7 +14558,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 57, + "req_dex": 57 }, { "name": "Runemastered Anchorite Garb", @@ -12936,7 +14571,9 @@ "dex_int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 49, + "req_int": 49 }, { "name": "Runemastered Ancient Leggings", @@ -12946,7 +14583,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 56, + "req_int": 56 }, { "name": "Runemastered Ancient Mail", @@ -12956,7 +14595,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runemastered Ancient Visor", @@ -12966,7 +14607,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 59, + "req_dex": 59 }, { "name": "Runemastered Antler Focus", @@ -12977,7 +14620,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 54 }, { "name": "Runemastered Armoured Cap", @@ -12987,7 +14631,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 91 }, { "name": "Runemastered Armoured Vest", @@ -12997,7 +14642,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 121 }, { "name": "Runemastered Array Buckler", @@ -13010,7 +14656,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 85 }, { "name": "Runemastered Assassin Garb", @@ -13020,7 +14667,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runemastered Barricade Tower Shield", @@ -13033,7 +14682,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 54 }, { "name": "Runemastered Beaded Circlet", @@ -13044,7 +14694,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 54 }, { "name": "Runemastered Blacksteel Tower Shield", @@ -13056,7 +14707,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 91 }, { "name": "Runemastered Blazon Crest Shield", @@ -13069,7 +14721,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 32, + "req_int": 32 }, { "name": "Runemastered Bolstered Mitts", @@ -13080,7 +14734,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 48 }, { "name": "Runemastered Bone Raiment", @@ -13091,7 +14746,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 61 }, { "name": "Runemastered Braced Sabatons", @@ -13102,7 +14758,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 29, + "req_dex": 29 }, { "name": "Runemastered Braced Tower Shield", @@ -13115,7 +14773,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 54 }, { "name": "Runemastered Brimmed Helm", @@ -13126,7 +14785,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 31, + "req_dex": 31 }, { "name": "Runemastered Bronze Greaves", @@ -13137,7 +14798,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 51 }, { "name": "Runemastered Burnished Gauntlets", @@ -13147,7 +14809,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 36, + "req_dex": 36 }, { "name": "Runemastered Chain Mail", @@ -13158,7 +14822,9 @@ "ezomyte_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 35, + "req_dex": 35 }, { "name": "Runemastered Chain Tiara", @@ -13169,7 +14835,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 58 }, { "name": "Runemastered Cinched Boots", @@ -13179,7 +14846,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 86 }, { "name": "Runemastered Cleric Vestments", @@ -13190,7 +14858,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 49, + "req_int": 49 }, { "name": "Runemastered Cloaked Mail", @@ -13201,7 +14871,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 36, + "req_dex": 36 }, { "name": "Runemastered Corsair Cap", @@ -13212,7 +14884,8 @@ "helmet", "karui_basetype", "runeforged" - ] + ], + "req_dex": 78 }, { "name": "Runemastered Corvus Mantle", @@ -13222,7 +14895,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runemastered Covered Sabatons", @@ -13233,7 +14908,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Runemastered Covert Hood", @@ -13243,7 +14920,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 79 }, { "name": "Runemastered Cowled Helm", @@ -13254,7 +14932,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 32, + "req_dex": 32 }, { "name": "Runemastered Crescent Targe", @@ -13267,7 +14947,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 31, + "req_dex": 31 }, { "name": "Runemastered Crucible Tower Shield", @@ -13280,7 +14962,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 91 }, { "name": "Runemastered Crystal Focus", @@ -13291,7 +14974,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 58 }, { "name": "Runemastered Cultist Crown", @@ -13302,7 +14986,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 31, + "req_int": 31 }, { "name": "Runemastered Death Mask", @@ -13312,7 +14998,9 @@ "dex_int_armour", "helmet", "runeforged" - ] + ], + "req_dex": 50, + "req_int": 50 }, { "name": "Runemastered Decorated Helm", @@ -13322,7 +15010,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Runemastered Doubled Gauntlets", @@ -13333,7 +15023,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 38, + "req_dex": 38 }, { "name": "Runemastered Dyad Crossbow", @@ -13347,7 +15039,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 63, + "req_dex": 63 }, { "name": "Runemastered Effigial Tower Shield", @@ -13360,7 +15054,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 54 }, { "name": "Runemastered Elementalist Robe", @@ -13371,7 +15066,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 87 }, { "name": "Runemastered Elite Greathelm", @@ -13382,7 +15078,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 78 }, { "name": "Runemastered Emblem Crest Shield", @@ -13395,7 +15092,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 31, + "req_int": 31 }, { "name": "Runemastered Embossed Boots", @@ -13406,7 +15105,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 51 }, { "name": "Runemastered Embroidered Gloves", @@ -13416,7 +15116,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 64 }, { "name": "Runemastered Engraved Focus", @@ -13427,7 +15128,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 54 }, { "name": "Runemastered Enlightened Robe", @@ -13437,7 +15139,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runemastered Explorer Armour", @@ -13448,7 +15151,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 49, + "req_dex": 49 }, { "name": "Runemastered Exquisite Vest", @@ -13458,7 +15163,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 121 }, { "name": "Runemastered Face Mask", @@ -13469,7 +15175,9 @@ "ezomyte_basetype", "helmet", "runeforged" - ] + ], + "req_dex": 31, + "req_int": 31 }, { "name": "Runemastered Familial Talisman", @@ -13481,7 +15189,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 63, + "req_int": 45 }, { "name": "Runemastered Feathered Robe", @@ -13492,7 +15202,8 @@ "ezomyte_basetype", "int_armour", "runeforged" - ] + ], + "req_int": 61 }, { "name": "Runemastered Feathered Sandals", @@ -13503,7 +15214,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 54 }, { "name": "Runemastered Feathered Tiara", @@ -13514,7 +15226,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 78 }, { "name": "Runemastered Felled Greatclub", @@ -13526,7 +15239,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 97 }, { "name": "Runemastered Felt Cap", @@ -13537,7 +15251,8 @@ "ezomyte_basetype", "helmet", "runeforged" - ] + ], + "req_dex": 54 }, { "name": "Runemastered Fierce Greathelm", @@ -13548,7 +15263,8 @@ "karui_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 78 }, { "name": "Runemastered Fine Bracers", @@ -13559,7 +15275,8 @@ "gloves", "karui_basetype", "runeforged" - ] + ], + "req_dex": 56 }, { "name": "Runemastered Firm Bracers", @@ -13570,7 +15287,8 @@ "ezomyte_basetype", "gloves", "runeforged" - ] + ], + "req_dex": 48 }, { "name": "Runemastered Full Plate", @@ -13581,7 +15299,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 72 }, { "name": "Runemastered Furtive Wraps", @@ -13591,7 +15310,9 @@ "dex_int_armour", "gloves", "runeforged" - ] + ], + "req_dex": 38, + "req_int": 38 }, { "name": "Runemastered Garment", @@ -13612,7 +15333,9 @@ "ezomyte_basetype", "gloves", "runeforged" - ] + ], + "req_dex": 27, + "req_int": 27 }, { "name": "Runemastered Gilded Vestments", @@ -13622,7 +15345,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 57, + "req_int": 57 }, { "name": "Runemastered Glacial Fortress", @@ -13634,7 +15359,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 99 }, { "name": "Runemastered Gold Circlet", @@ -13645,7 +15371,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 78 }, { "name": "Runemastered Goldcast Cuffs", @@ -13656,7 +15383,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 38, + "req_int": 38 }, { "name": "Runemastered Grand Cuisses", @@ -13666,7 +15395,10 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 34, + "req_dex": 34, + "req_int": 34 }, { "name": "Runemastered Grand Manchettes", @@ -13676,7 +15408,10 @@ "gloves", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 32, + "req_dex": 32, + "req_int": 32 }, { "name": "Runemastered Grand Regalia", @@ -13686,7 +15421,10 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 41, + "req_dex": 41, + "req_int": 41 }, { "name": "Runemastered Grand Visage", @@ -13696,7 +15434,10 @@ "helmet", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 36, + "req_dex": 36, + "req_int": 36 }, { "name": "Runemastered Grasping Mail", @@ -13706,7 +15447,10 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 41, + "req_dex": 41, + "req_int": 41 }, { "name": "Runemastered Guarded Helm", @@ -13717,7 +15461,9 @@ "helmet", "runeforged", "str_dex_armour" - ] + ], + "req_str": 31, + "req_dex": 31 }, { "name": "Runemastered Hardwood Targe", @@ -13730,7 +15476,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 31, + "req_dex": 31 }, { "name": "Runemastered Havoc Raiment", @@ -13740,7 +15488,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 121 }, { "name": "Runemastered Heavy Belt", @@ -13761,7 +15510,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 43, + "req_int": 43 }, { "name": "Runemastered Heraldric Tower Shield", @@ -13774,7 +15525,8 @@ "str_armour", "str_shield", "vaal_basetype" - ] + ], + "req_str": 71 }, { "name": "Runemastered Hermit Garb", @@ -13785,7 +15537,9 @@ "dex_int_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 35, + "req_int": 35 }, { "name": "Runemastered Heroic Armour", @@ -13795,7 +15549,9 @@ "default", "runeforged", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runemastered Hewn Mask", @@ -13806,7 +15562,9 @@ "ezomyte_basetype", "helmet", "runeforged" - ] + ], + "req_dex": 31, + "req_int": 31 }, { "name": "Runemastered Hexer's Robe", @@ -13817,7 +15575,8 @@ "ezomyte_basetype", "int_armour", "runeforged" - ] + ], + "req_int": 61 }, { "name": "Runemastered Hooded Mask", @@ -13828,7 +15587,9 @@ "helmet", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 31, + "req_int": 31 }, { "name": "Runemastered Horned Crown", @@ -13839,7 +15600,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 31, + "req_int": 31 }, { "name": "Runemastered Hunter Hood", @@ -13850,7 +15613,8 @@ "helmet", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 58 }, { "name": "Runemastered Hunting Shoes", @@ -13861,7 +15625,9 @@ "dex_int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 30, + "req_int": 30 }, { "name": "Runemastered Intricate Crest Shield", @@ -13873,7 +15639,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Runemastered Intricate Gloves", @@ -13884,7 +15652,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 68 }, { "name": "Runemastered Iron Buckler", @@ -13898,7 +15667,8 @@ "maraketh_basetype", "runeforged", "shield" - ] + ], + "req_dex": 54 }, { "name": "Runemastered Iron Crown", @@ -13909,7 +15679,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 31, + "req_int": 31 }, { "name": "Runemastered Iron Cuirass", @@ -13920,7 +15692,8 @@ "ezomyte_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 61 }, { "name": "Runemastered Iron Greaves", @@ -13931,7 +15704,8 @@ "ezomyte_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 51 }, { "name": "Runemastered Ironclad Vestments", @@ -13942,7 +15716,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 49, + "req_int": 49 }, { "name": "Runemastered Ironhead Spear", @@ -13954,7 +15730,9 @@ "runeforged", "spear", "weapon" - ] + ], + "req_str": 31, + "req_dex": 76 }, { "name": "Runemastered Jade Tiara", @@ -13965,7 +15743,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 91 }, { "name": "Runemastered Jewelled Gloves", @@ -13976,7 +15755,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 48 }, { "name": "Runemastered Jingling Crest Shield", @@ -13989,7 +15769,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 31, + "req_int": 31 }, { "name": "Runemastered Keth Raiment", @@ -14000,7 +15782,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 61 }, { "name": "Runemastered Knight Armour", @@ -14011,7 +15794,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 49, + "req_dex": 49 }, { "name": "Runemastered Laced Boots", @@ -14022,7 +15807,8 @@ "dex_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 51 }, { "name": "Runemastered Lattice Sandals", @@ -14033,7 +15819,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 51 }, { "name": "Runemastered Layered Gauntlets", @@ -14044,7 +15831,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 27, + "req_dex": 27 }, { "name": "Runemastered Leather Buckler", @@ -14058,7 +15847,8 @@ "ezomyte_basetype", "runeforged", "shield" - ] + ], + "req_dex": 54 }, { "name": "Runemastered Leather Vest", @@ -14069,7 +15859,8 @@ "dex_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 61 }, { "name": "Runemastered Leatherbound Hood", @@ -14080,7 +15871,8 @@ "helmet", "karui_basetype", "runeforged" - ] + ], + "req_dex": 91 }, { "name": "Runemastered Linen Wraps", @@ -14091,7 +15883,9 @@ "gloves", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 27, + "req_int": 27 }, { "name": "Runemastered Lizardscale Boots", @@ -14102,7 +15896,8 @@ "dex_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 54 }, { "name": "Runemastered Magus Tiara", @@ -14112,7 +15907,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 91 }, { "name": "Runemastered Mail Sabatons", @@ -14123,7 +15919,9 @@ "ezomyte_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 29, + "req_dex": 29 }, { "name": "Runemastered Mail Vestments", @@ -14134,7 +15932,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 35, + "req_int": 35 }, { "name": "Runemastered Marabout Garb", @@ -14145,7 +15945,9 @@ "dex_int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 35, + "req_int": 35 }, { "name": "Runemastered Maraketh Cuirass", @@ -14156,7 +15958,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 61 }, { "name": "Runemastered Martyr Crown", @@ -14167,7 +15970,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 32, + "req_int": 32 }, { "name": "Runemastered Moulded Mitts", @@ -14178,7 +15983,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 68 }, { "name": "Runemastered Nettle Talisman", @@ -14190,7 +15996,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 63, + "req_int": 45 }, { "name": "Runemastered Oak Greathammer", @@ -14202,7 +16010,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 97 }, { "name": "Runemastered Omen Crest Shield", @@ -14215,7 +16024,9 @@ "str_int_armour", "str_int_shield", "vaal_basetype" - ] + ], + "req_str": 38, + "req_int": 38 }, { "name": "Runemastered Ornate Buckler", @@ -14228,7 +16039,8 @@ "dex_shield", "runeforged", "shield" - ] + ], + "req_dex": 78 }, { "name": "Runemastered Ornate Ringmail", @@ -14238,7 +16050,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 57, + "req_int": 57 }, { "name": "Runemastered Painted Tower Shield", @@ -14251,7 +16065,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 54 }, { "name": "Runemastered Pathfinder Coat", @@ -14262,7 +16077,8 @@ "dex_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 61 }, { "name": "Runemastered Pauascale Gloves", @@ -14273,7 +16089,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 68 }, { "name": "Runemastered Pilgrim Vestments", @@ -14284,7 +16101,9 @@ "ezomyte_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 35, + "req_int": 35 }, { "name": "Runemastered Plate Gauntlets", @@ -14295,7 +16114,9 @@ "karui_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 38, + "req_dex": 38 }, { "name": "Runemastered Plated Buckler", @@ -14309,7 +16130,8 @@ "ezomyte_basetype", "runeforged", "shield" - ] + ], + "req_dex": 54 }, { "name": "Runemastered Plated Raiment", @@ -14319,7 +16141,8 @@ "default", "int_armour", "runeforged" - ] + ], + "req_int": 103 }, { "name": "Runemastered Plumed Focus", @@ -14330,7 +16153,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 91 }, { "name": "Runemastered Primal Markings", @@ -14340,7 +16164,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Runemastered Quilted Vest", @@ -14351,7 +16177,8 @@ "dex_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 61 }, { "name": "Runemastered Raider Plate", @@ -14362,7 +16189,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 61 }, { "name": "Runemastered Rampart Tower Shield", @@ -14375,7 +16203,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 58 }, { "name": "Runemastered Revered Vestments", @@ -14385,7 +16214,9 @@ "default", "runeforged", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Runemastered Rhoahide Coat", @@ -14396,7 +16227,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 61 }, { "name": "Runemastered Ridged Buckler", @@ -14410,7 +16242,8 @@ "maraketh_basetype", "runeforged", "shield" - ] + ], + "req_dex": 58 }, { "name": "Runemastered Ringmail Gauntlets", @@ -14421,7 +16254,9 @@ "gloves", "runeforged", "str_dex_armour" - ] + ], + "req_str": 27, + "req_dex": 27 }, { "name": "Runemastered Riveted Mitts", @@ -14432,7 +16267,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 48 }, { "name": "Runemastered Rogue Armour", @@ -14443,7 +16279,9 @@ "ezomyte_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 35, + "req_dex": 35 }, { "name": "Runemastered Rope Cuffs", @@ -14454,7 +16292,9 @@ "gloves", "runeforged", "str_int_armour" - ] + ], + "req_str": 27, + "req_int": 27 }, { "name": "Runemastered Rough Greaves", @@ -14465,7 +16305,8 @@ "ezomyte_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 51 }, { "name": "Runemastered Runic Fork", @@ -14474,7 +16315,8 @@ "onehand", "runeforged", "wand" - ] + ], + "req_int": 114 }, { "name": "Runemastered Rusted Cuirass", @@ -14485,7 +16327,8 @@ "ezomyte_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 61 }, { "name": "Runemastered Rusted Greathelm", @@ -14496,7 +16339,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 54 }, { "name": "Runemastered Sacrificial Mantle", @@ -14507,7 +16351,9 @@ "runeforged", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 49, + "req_int": 49 }, { "name": "Runemastered Sacrificial Regalia", @@ -14517,7 +16363,10 @@ "default", "runeforged", "str_dex_int_armour" - ] + ], + "req_str": 72, + "req_dex": 72, + "req_int": 72 }, { "name": "Runemastered Scale Mail", @@ -14528,7 +16377,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 49, + "req_dex": 49 }, { "name": "Runemastered Scalper's Jacket", @@ -14539,7 +16390,9 @@ "dex_int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 49, + "req_int": 49 }, { "name": "Runemastered Scout's Vest", @@ -14550,7 +16403,8 @@ "dex_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 87 }, { "name": "Runemastered Sectioned Bracers", @@ -14561,7 +16415,8 @@ "gloves", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 48 }, { "name": "Runemastered Secured Leggings", @@ -14572,7 +16427,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 29, + "req_int": 29 }, { "name": "Runemastered Serpentscale Coat", @@ -14583,7 +16440,8 @@ "dex_armour", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 87 }, { "name": "Runemastered Shabby Hood", @@ -14594,7 +16452,8 @@ "ezomyte_basetype", "helmet", "runeforged" - ] + ], + "req_dex": 54 }, { "name": "Runemastered Shaman Mantle", @@ -14605,7 +16464,9 @@ "maraketh_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 35, + "req_int": 35 }, { "name": "Runemastered Shielded Helm", @@ -14616,7 +16477,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 43, + "req_dex": 43 }, { "name": "Runemastered Shrouded Vest", @@ -14627,7 +16490,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 61 }, { "name": "Runemastered Sigil Crest Shield", @@ -14640,7 +16504,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 32, + "req_int": 32 }, { "name": "Runemastered Silk Robe", @@ -14651,7 +16517,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 61 }, { "name": "Runemastered Silk Slippers", @@ -14662,7 +16529,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 51 }, { "name": "Runemastered Smuggler Coat", @@ -14673,7 +16541,8 @@ "dex_armour", "karui_basetype", "runeforged" - ] + ], + "req_dex": 103 }, { "name": "Runemastered Soldier Greathelm", @@ -14684,7 +16553,8 @@ "helmet", "runeforged", "str_armour" - ] + ], + "req_str": 54 }, { "name": "Runemastered Solid Mask", @@ -14695,7 +16565,9 @@ "helmet", "karui_basetype", "runeforged" - ] + ], + "req_dex": 43, + "req_int": 43 }, { "name": "Runemastered Sombre Gloves", @@ -14706,7 +16578,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 49 }, { "name": "Runemastered Spiked Buckler", @@ -14720,7 +16593,8 @@ "maraketh_basetype", "runeforged", "shield" - ] + ], + "req_dex": 58 }, { "name": "Runemastered Spined Bracers", @@ -14731,7 +16605,8 @@ "gloves", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 48 }, { "name": "Runemastered Spiral Wraps", @@ -14741,7 +16616,9 @@ "dex_int_armour", "gloves", "vaal_basetype" - ] + ], + "req_dex": 38, + "req_int": 38 }, { "name": "Runemastered Spired Greathelm", @@ -14752,7 +16629,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 58 }, { "name": "Runemastered Spiritbone Crown", @@ -14763,7 +16641,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 50, + "req_int": 50 }, { "name": "Runemastered Splintered Tower Shield", @@ -14776,7 +16656,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 54 }, { "name": "Runemastered Stacked Sabatons", @@ -14787,7 +16668,9 @@ "runeforged", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 30, + "req_dex": 30 }, { "name": "Runemastered Steel Plate", @@ -14798,7 +16681,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 65 }, { "name": "Runemastered Steeltoe Boots", @@ -14809,7 +16693,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 54 }, { "name": "Runemastered Stitched Gloves", @@ -14820,7 +16705,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 48 }, { "name": "Runemastered Stocky Mitts", @@ -14831,7 +16717,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 48 }, { "name": "Runemastered Stone Greaves", @@ -14842,7 +16729,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 73 }, { "name": "Runemastered Straw Sandals", @@ -14853,7 +16741,8 @@ "ezomyte_basetype", "int_armour", "runeforged" - ] + ], + "req_int": 51 }, { "name": "Runemastered Strider Vest", @@ -14863,7 +16752,8 @@ "default", "dex_armour", "runeforged" - ] + ], + "req_dex": 103 }, { "name": "Runemastered Studded Greatclub", @@ -14875,7 +16765,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 97 }, { "name": "Runemastered Studded Vest", @@ -14886,7 +16777,8 @@ "dex_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 65 }, { "name": "Runemastered Suede Bracers", @@ -14897,7 +16789,8 @@ "ezomyte_basetype", "gloves", "runeforged" - ] + ], + "req_dex": 48 }, { "name": "Runemastered Tattered Robe", @@ -14908,7 +16801,8 @@ "ezomyte_basetype", "int_armour", "runeforged" - ] + ], + "req_int": 61 }, { "name": "Runemastered Tempered Mitts", @@ -14919,7 +16813,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 48 }, { "name": "Runemastered Tenebrous Crown", @@ -14929,7 +16824,9 @@ "helmet", "runeforged", "str_int_armour" - ] + ], + "req_str": 59, + "req_int": 59 }, { "name": "Runemastered Tense Crossbow", @@ -14943,7 +16840,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 54, + "req_dex": 54 }, { "name": "Runemastered Threaded Shoes", @@ -14954,7 +16853,9 @@ "dex_int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 29, + "req_int": 29 }, { "name": "Runemastered Tideseer Mantle", @@ -14965,7 +16866,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 57, + "req_int": 57 }, { "name": "Runemastered Titan Mitts", @@ -14975,7 +16878,8 @@ "gloves", "runeforged", "str_armour" - ] + ], + "req_str": 80 }, { "name": "Runemastered Tonal Focus", @@ -14986,7 +16890,8 @@ "int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_int": 54 }, { "name": "Runemastered Torment Club", @@ -14997,7 +16902,8 @@ "onehand", "runeforged", "weapon" - ] + ], + "req_str": 124 }, { "name": "Runemastered Torn Gloves", @@ -15008,7 +16914,8 @@ "gloves", "int_armour", "runeforged" - ] + ], + "req_int": 48 }, { "name": "Runemastered Tribal Mask", @@ -15019,7 +16926,9 @@ "helmet", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 41, + "req_int": 41 }, { "name": "Runemastered Trimmed Greaves", @@ -15030,7 +16939,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 54 }, { "name": "Runemastered Twig Circlet", @@ -15041,7 +16951,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 54 }, { "name": "Runemastered Twig Focus", @@ -15052,7 +16963,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 54 }, { "name": "Runemastered Twilight Tiara", @@ -15062,7 +16974,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 91 }, { "name": "Runemastered Utility Wraps", @@ -15072,7 +16985,9 @@ "dex_int_armour", "gloves", "runeforged" - ] + ], + "req_dex": 44, + "req_int": 44 }, { "name": "Runemastered Vaal Cuirass", @@ -15083,7 +16998,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 87 }, { "name": "Runemastered Vaal Tower Shield", @@ -15095,7 +17011,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 107 }, { "name": "Runemastered Vagabond Armour", @@ -15106,7 +17023,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 35, + "req_dex": 35 }, { "name": "Runemastered Veiled Mask", @@ -15117,7 +17036,9 @@ "helmet", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 32, + "req_int": 32 }, { "name": "Runemastered Velour Shoes", @@ -15127,7 +17048,9 @@ "default", "dex_int_armour", "runeforged" - ] + ], + "req_dex": 47, + "req_int": 47 }, { "name": "Runemastered Velvet Cap", @@ -15137,7 +17060,8 @@ "dex_armour", "helmet", "runeforged" - ] + ], + "req_dex": 91 }, { "name": "Runemastered Venerable Defender", @@ -15150,7 +17074,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Runemastered Veridical Chain", @@ -15169,7 +17095,9 @@ "karui_basetype", "runeforged", "str_int_armour" - ] + ], + "req_str": 38, + "req_int": 38 }, { "name": "Runemastered Vermeil Circlet", @@ -15180,7 +17108,8 @@ "int_armour", "karui_basetype", "runeforged" - ] + ], + "req_int": 78 }, { "name": "Runemastered Viper Cap", @@ -15191,7 +17120,8 @@ "helmet", "runeforged", "vaal_basetype" - ] + ], + "req_dex": 78 }, { "name": "Runemastered Visored Helm", @@ -15202,7 +17132,9 @@ "maraketh_basetype", "runeforged", "str_dex_armour" - ] + ], + "req_str": 31, + "req_dex": 31 }, { "name": "Runemastered Voodoo Focus", @@ -15213,7 +17145,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 78 }, { "name": "Runemastered Votive Raiment", @@ -15224,7 +17157,8 @@ "int_armour", "runeforged", "vaal_basetype" - ] + ], + "req_int": 87 }, { "name": "Runemastered Warding Quarterstaff", @@ -15235,7 +17169,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 127, + "req_int": 50 }, { "name": "Runemastered Warrior Greathelm", @@ -15246,7 +17182,8 @@ "runeforged", "str_armour", "vaal_basetype" - ] + ], + "req_str": 78 }, { "name": "Runemastered Waxed Jacket", @@ -15257,7 +17194,9 @@ "dex_int_armour", "ezomyte_basetype", "runeforged" - ] + ], + "req_dex": 35, + "req_int": 35 }, { "name": "Runemastered Wayfarer Jacket", @@ -15268,7 +17207,9 @@ "dex_int_armour", "maraketh_basetype", "runeforged" - ] + ], + "req_dex": 36, + "req_int": 36 }, { "name": "Runemastered Wicker Tiara", @@ -15279,7 +17220,8 @@ "helmet", "int_armour", "runeforged" - ] + ], + "req_int": 54 }, { "name": "Runemastered Wooden Buckler", @@ -15293,7 +17235,8 @@ "ezomyte_basetype", "runeforged", "shield" - ] + ], + "req_dex": 54 }, { "name": "Runemastered Wooden Club", @@ -15305,7 +17248,8 @@ "onehand", "runeforged", "weapon" - ] + ], + "req_str": 97 }, { "name": "Runemastered Woven Focus", @@ -15316,7 +17260,8 @@ "focus", "int_armour", "runeforged" - ] + ], + "req_int": 54 }, { "name": "Runemastered Wrapped Greathelm", @@ -15327,7 +17272,8 @@ "maraketh_basetype", "runeforged", "str_armour" - ] + ], + "req_str": 54 }, { "name": "Runemastered Wrapped Sandals", @@ -15338,7 +17284,8 @@ "ezomyte_basetype", "int_armour", "runeforged" - ] + ], + "req_int": 51 }, { "name": "Runic Fork", @@ -15346,7 +17293,8 @@ "default", "onehand", "wand" - ] + ], + "req_int": 114 }, { "name": "Runic Shortsword", @@ -15356,7 +17304,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 49, + "req_dex": 49 }, { "name": "Runner Vest", @@ -15365,7 +17315,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 94 }, { "name": "Rusted Cuirass", @@ -15401,7 +17352,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 121 }, { "name": "Sacred Focus", @@ -15410,7 +17362,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 107 }, { "name": "Sacred Maul", @@ -15420,7 +17373,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 149 }, { "name": "Sacrificial Axe", @@ -15431,7 +17385,9 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_str": 52, + "req_dex": 22 }, { "name": "Sacrificial Mantle", @@ -15441,7 +17397,9 @@ "default", "str_int_armour", "vaal_basetype" - ] + ], + "req_str": 33, + "req_int": 33 }, { "name": "Sacrificial Regalia", @@ -15450,7 +17408,10 @@ "body_armour", "default", "str_dex_int_armour" - ] + ], + "req_str": 72, + "req_dex": 72, + "req_int": 72 }, { "name": "Saintly Crown", @@ -15459,7 +17420,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 54, + "req_int": 54 }, { "name": "Sanctified Staff", @@ -15467,7 +17430,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 99 }, { "name": "Sandsworn Cuirass", @@ -15476,7 +17440,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 82 }, { "name": "Sandsworn Sandals", @@ -15485,7 +17450,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 101 }, { "name": "Sandsworn Tiara", @@ -15494,7 +17460,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 77 }, { "name": "Sapphire", @@ -15533,7 +17500,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 39, + "req_dex": 17 }, { "name": "Scale Mail", @@ -15543,7 +17512,9 @@ "default", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 34, + "req_dex": 34 }, { "name": "Scalper's Jacket", @@ -15553,7 +17524,9 @@ "default", "dex_int_armour", "vaal_basetype" - ] + ], + "req_dex": 35, + "req_int": 35 }, { "name": "Scimitar", @@ -15564,7 +17537,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 19, + "req_dex": 19 }, { "name": "Scoundrel Armour", @@ -15573,7 +17548,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 43, + "req_dex": 43 }, { "name": "Scoundrel Jacket", @@ -15583,7 +17560,9 @@ "default", "dex_int_armour", "karui_basetype" - ] + ], + "req_dex": 41, + "req_int": 41 }, { "name": "Scout's Vest", @@ -15593,7 +17572,8 @@ "default", "dex_armour", "vaal_basetype" - ] + ], + "req_dex": 54 }, { "name": "Seaglass Spear", @@ -15604,7 +17584,10 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 29, + "req_dex": 71, + "req_int": 50 }, { "name": "Seastorm Mantle", @@ -15614,7 +17597,9 @@ "default", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Sectarian Crest Shield", @@ -15626,7 +17611,9 @@ "str_int_armour", "str_int_shield", "vaal_basetype" - ] + ], + "req_str": 27, + "req_int": 27 }, { "name": "Sectioned Bracers", @@ -15636,7 +17623,8 @@ "dex_armour", "gloves", "maraketh_basetype" - ] + ], + "req_dex": 36 }, { "name": "Secured Leggings", @@ -15646,7 +17634,9 @@ "default", "maraketh_basetype", "str_int_armour" - ] + ], + "req_str": 14, + "req_int": 14 }, { "name": "Secured Wraps", @@ -15656,7 +17646,9 @@ "dex_int_armour", "gloves", "karui_basetype" - ] + ], + "req_dex": 55, + "req_int": 55 }, { "name": "Seer Crest Shield", @@ -15668,7 +17660,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 39, + "req_int": 39 }, { "name": "Sekhema Sandals", @@ -15678,7 +17672,8 @@ "default", "int_armour", "karui_basetype" - ] + ], + "req_int": 108 }, { "name": "Sekheman Crest Shield", @@ -15689,7 +17684,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 54, + "req_int": 54 }, { "name": "Sentinel Greathelm", @@ -15698,7 +17695,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 74 }, { "name": "Serpentscale Boots", @@ -15707,7 +17705,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 78 }, { "name": "Serpentscale Coat", @@ -15717,7 +17716,8 @@ "default", "dex_armour", "vaal_basetype" - ] + ], + "req_dex": 59 }, { "name": "Serrated Quiver", @@ -15743,7 +17743,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 41, + "req_int": 41 }, { "name": "Shaman Mantle", @@ -15753,7 +17755,9 @@ "default", "maraketh_basetype", "str_int_armour" - ] + ], + "req_str": 26, + "req_int": 26 }, { "name": "Shamanistic Leggings", @@ -15762,7 +17766,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 44, + "req_int": 44 }, { "name": "Sharktooth Claw", @@ -15772,7 +17778,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 87 }, { "name": "Shielded Helm", @@ -15782,7 +17789,9 @@ "helmet", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 27, + "req_dex": 27 }, { "name": "Shortbow", @@ -15794,7 +17803,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 12 }, { "name": "Shortsword", @@ -15822,7 +17832,9 @@ "default", "onehand", "sceptre" - ] + ], + "req_str": 17, + "req_int": 38 }, { "name": "Shrine Sceptre (Purity of Cold)", @@ -15831,7 +17843,9 @@ "default", "onehand", "sceptre" - ] + ], + "req_str": 17, + "req_int": 38 }, { "name": "Shrine Sceptre (Purity of Fire)", @@ -15840,7 +17854,9 @@ "default", "onehand", "sceptre" - ] + ], + "req_str": 17, + "req_int": 38 }, { "name": "Shrine Sceptre (Purity of Lighting)", @@ -15849,7 +17865,9 @@ "default", "onehand", "sceptre" - ] + ], + "req_str": 17, + "req_int": 38 }, { "name": "Shrouded Mail", @@ -15858,7 +17876,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Shrouded Vest", @@ -15868,7 +17888,8 @@ "default", "dex_armour", "maraketh_basetype" - ] + ], + "req_dex": 28 }, { "name": "Sickle Sword", @@ -15879,7 +17900,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 29, + "req_dex": 29 }, { "name": "Siege Crossbow", @@ -15891,7 +17914,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 89, + "req_dex": 89 }, { "name": "Sigil Crest Shield", @@ -15903,7 +17928,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 8, + "req_int": 8 }, { "name": "Signet Cuffs", @@ -15912,7 +17939,9 @@ "default", "gloves", "str_int_armour" - ] + ], + "req_str": 44, + "req_int": 44 }, { "name": "Silk Robe", @@ -15922,7 +17951,8 @@ "default", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 37 }, { "name": "Silk Slippers", @@ -15932,7 +17962,8 @@ "default", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 38 }, { "name": "Silver Charm", @@ -15952,7 +17983,9 @@ "boots", "default", "dex_int_armour" - ] + ], + "req_dex": 38, + "req_int": 38 }, { "name": "Simple Dagger", @@ -15963,7 +17996,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 15, + "req_int": 15 }, { "name": "Sinew Belt", @@ -15982,7 +18017,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 104, + "req_int": 41 }, { "name": "Siphoning Wand", @@ -15990,7 +18027,8 @@ "default", "onehand", "wand" - ] + ], + "req_int": 23 }, { "name": "Sirenscale Gloves", @@ -16000,7 +18038,8 @@ "gloves", "int_armour", "karui_basetype" - ] + ], + "req_int": 101 }, { "name": "Skinning Knife", @@ -16011,7 +18050,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 19, + "req_int": 19 }, { "name": "Skulking Mask", @@ -16020,7 +18061,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 40, + "req_int": 40 }, { "name": "Skullcrusher Quarterstaff", @@ -16031,7 +18074,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 127, + "req_int": 50 }, { "name": "Skycrown Tiara", @@ -16040,7 +18085,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 91 }, { "name": "Slayer Armour", @@ -16049,7 +18095,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Sleek Boots", @@ -16058,7 +18106,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 68 }, { "name": "Sleek Jacket", @@ -16067,7 +18116,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Slender Flail", @@ -16078,7 +18129,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 38, + "req_int": 17 }, { "name": "Slicing Quarterstaff", @@ -16089,7 +18142,9 @@ "vaal_basetype", "warstaff", "weapon" - ] + ], + "req_dex": 47, + "req_int": 20 }, { "name": "Slim Mace", @@ -16100,7 +18155,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 21 }, { "name": "Slipstrike Vest", @@ -16109,7 +18165,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 121 }, { "name": "Smithing Hammer", @@ -16120,7 +18177,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 11 }, { "name": "Smooth Quarterstaff", @@ -16131,7 +18189,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 68, + "req_int": 28 }, { "name": "Smuggler Coat", @@ -16141,7 +18201,8 @@ "default", "dex_armour", "karui_basetype" - ] + ], + "req_dex": 82 }, { "name": "Snakewood Greathammer", @@ -16151,7 +18212,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 80 }, { "name": "Snakewood Shortbow", @@ -16162,7 +18224,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 80 }, { "name": "Soaring Mask", @@ -16171,7 +18234,9 @@ "default", "dex_int_armour", "helmet" - ] + ], + "req_dex": 59, + "req_int": 59 }, { "name": "Soaring Spear", @@ -16182,7 +18247,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 41, + "req_dex": 115 }, { "name": "Soaring Targe", @@ -16193,7 +18260,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 59, + "req_dex": 59 }, { "name": "Solar Amulet", @@ -16209,7 +18278,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Soldier Greathelm", @@ -16219,7 +18289,8 @@ "ezomyte_basetype", "helmet", "str_armour" - ] + ], + "req_str": 19 }, { "name": "Soldier Helm", @@ -16228,7 +18299,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 40, + "req_dex": 40 }, { "name": "Soldiering Sabatons", @@ -16237,7 +18310,9 @@ "boots", "default", "str_dex_armour" - ] + ], + "req_str": 34, + "req_dex": 34 }, { "name": "Solemn Maul", @@ -16247,7 +18322,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 96 }, { "name": "Solid Mask", @@ -16257,7 +18333,9 @@ "dex_int_armour", "helmet", "karui_basetype" - ] + ], + "req_dex": 36, + "req_int": 36 }, { "name": "Sombre Gloves", @@ -16267,7 +18345,8 @@ "ezomyte_basetype", "gloves", "int_armour" - ] + ], + "req_int": 17 }, { "name": "Sorcerous Tiara", @@ -16276,7 +18355,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 99 }, { "name": "Spike Trap", @@ -16293,7 +18373,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 73 }, { "name": "Spiked Buckler", @@ -16306,7 +18387,8 @@ "dex_shield", "maraketh_basetype", "shield" - ] + ], + "req_dex": 38 }, { "name": "Spiked Club", @@ -16317,7 +18399,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 31 }, { "name": "Spiked Spear", @@ -16327,7 +18410,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 50, + "req_dex": 127 }, { "name": "Spikeward Buckler", @@ -16339,7 +18424,8 @@ "dex_armour", "dex_shield", "shield" - ] + ], + "req_dex": 77 }, { "name": "Spined Bracers", @@ -16349,7 +18435,8 @@ "dex_armour", "gloves", "vaal_basetype" - ] + ], + "req_dex": 42 }, { "name": "Spiny Talisman", @@ -16360,7 +18447,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 86, + "req_int": 65 }, { "name": "Spiral Wraps", @@ -16370,7 +18459,9 @@ "dex_int_armour", "gloves", "vaal_basetype" - ] + ], + "req_dex": 24, + "req_int": 24 }, { "name": "Spired Greathelm", @@ -16380,7 +18471,8 @@ "helmet", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 40 }, { "name": "Spiritbone Crown", @@ -16390,7 +18482,9 @@ "helmet", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 36, + "req_int": 36 }, { "name": "Splintered Flail", @@ -16432,7 +18526,8 @@ "default", "staff", "twohand" - ] + ], + "req_int": 23 }, { "name": "Sprinters Leg", @@ -16448,7 +18543,9 @@ "default", "str_dex_armour", "vaal_basetype" - ] + ], + "req_str": 26, + "req_dex": 26 }, { "name": "Staghorn Focus", @@ -16457,7 +18554,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 69 }, { "name": "Stalking Belt", @@ -16475,7 +18573,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 80 }, { "name": "Stalking Spear", @@ -16485,7 +18584,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 50, + "req_dex": 127 }, { "name": "Staunching Charm", @@ -16506,7 +18607,8 @@ "default", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 45 }, { "name": "Steelhead Spear", @@ -16516,7 +18618,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 26, + "req_dex": 63 }, { "name": "Steelmail Gauntlets", @@ -16525,7 +18629,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 44, + "req_dex": 44 }, { "name": "Steelpoint Quarterstaff", @@ -16536,7 +18642,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 41, + "req_int": 18 }, { "name": "Steelpoint Shoes", @@ -16546,7 +18654,9 @@ "default", "dex_int_armour", "karui_basetype" - ] + ], + "req_dex": 34, + "req_int": 34 }, { "name": "Steeltoe Boots", @@ -16556,7 +18666,8 @@ "default", "dex_armour", "maraketh_basetype" - ] + ], + "req_dex": 39 }, { "name": "Stellar Amulet", @@ -16573,7 +18684,8 @@ "gloves", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 22 }, { "name": "Stocky Mitts", @@ -16594,7 +18706,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Stoic Sceptre", @@ -16603,7 +18717,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 12 }, { "name": "Stone Charm", @@ -16623,7 +18738,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 98 }, { "name": "Stone Flail", @@ -16634,7 +18750,9 @@ "onehand", "vaal_basetype", "weapon" - ] + ], + "req_str": 47, + "req_int": 20 }, { "name": "Stone Greatsword", @@ -16645,7 +18763,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 34, + "req_dex": 34 }, { "name": "Stone Greaves", @@ -16655,7 +18775,8 @@ "default", "str_armour", "vaal_basetype" - ] + ], + "req_str": 45 }, { "name": "Stone Targe", @@ -16666,7 +18787,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 46, + "req_dex": 46 }, { "name": "Stone Tower Shield", @@ -16678,7 +18801,8 @@ "str_armour", "str_shield", "vaal_basetype" - ] + ], + "req_str": 52 }, { "name": "Stout Crossbow", @@ -16690,7 +18814,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 74, + "req_dex": 74 }, { "name": "Stratified Targe", @@ -16701,7 +18827,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 37, + "req_dex": 37 }, { "name": "Straw Sandals", @@ -16720,7 +18848,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 83 }, { "name": "Strife Pick", @@ -16730,7 +18859,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Striking Quarterstaff", @@ -16740,7 +18870,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 127, + "req_int": 50 }, { "name": "Striking Spear", @@ -16750,7 +18882,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 31, + "req_dex": 76 }, { "name": "Structured Hammer", @@ -16760,7 +18894,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 109 }, { "name": "Studded Boots", @@ -16769,7 +18904,8 @@ "boots", "default", "dex_armour" - ] + ], + "req_dex": 72 }, { "name": "Studded Greatclub", @@ -16780,7 +18916,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 31 }, { "name": "Studded Sandals", @@ -16789,7 +18926,8 @@ "boots", "default", "int_armour" - ] + ], + "req_int": 69 }, { "name": "Studded Targe", @@ -16801,7 +18939,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 15, + "req_dex": 15 }, { "name": "Studded Vest", @@ -16811,7 +18951,8 @@ "default", "dex_armour", "maraketh_basetype" - ] + ], + "req_dex": 43 }, { "name": "Sturdy Crossbow", @@ -16824,7 +18965,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 13, + "req_dex": 13 }, { "name": "Sturdy Leg", @@ -16856,7 +18999,8 @@ "dex_armour", "helmet", "maraketh_basetype" - ] + ], + "req_dex": 38 }, { "name": "Swift Bracers", @@ -16865,7 +19009,8 @@ "default", "dex_armour", "gloves" - ] + ], + "req_dex": 64 }, { "name": "Swift Spear", @@ -16875,7 +19020,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 29, + "req_dex": 71 }, { "name": "Swiftstalker Coat", @@ -16884,7 +19031,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 121 }, { "name": "Sword Spear", @@ -16894,7 +19042,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 29, + "req_dex": 72 }, { "name": "Talon Claw", @@ -16904,7 +19054,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 114 }, { "name": "Tasalian Focus", @@ -16914,7 +19065,8 @@ "focus", "int_armour", "karui_basetype" - ] + ], + "req_int": 115 }, { "name": "Tasalian Greaves", @@ -16924,7 +19076,8 @@ "default", "karui_basetype", "str_armour" - ] + ], + "req_str": 108 }, { "name": "Tattered Robe", @@ -16946,7 +19099,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 45, + "req_dex": 45 }, { "name": "Tawhoan Greatclub", @@ -16957,7 +19112,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 163 }, { "name": "Tawhoan Tower Shield", @@ -16969,7 +19125,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 115 }, { "name": "Tearing Flail", @@ -16979,7 +19136,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 72, + "req_int": 29 }, { "name": "Tempered Mitts", @@ -16989,7 +19148,8 @@ "gloves", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 22 }, { "name": "Templar Vestments", @@ -16998,7 +19158,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 41, + "req_int": 41 }, { "name": "Temple Maul", @@ -17009,7 +19171,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 52 }, { "name": "Tenebrous Amulet", @@ -17025,7 +19188,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 59, + "req_int": 59 }, { "name": "Tenebrous Ring", @@ -17047,7 +19212,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 8, + "req_dex": 8 }, { "name": "Tethering Bands", @@ -17057,7 +19224,9 @@ "gloves", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 55, + "req_int": 55 }, { "name": "Thane Mail", @@ -17067,7 +19236,9 @@ "default", "karui_basetype", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Thawing Charm", @@ -17088,7 +19259,9 @@ "default", "dex_int_armour", "maraketh_basetype" - ] + ], + "req_dex": 14, + "req_int": 14 }, { "name": "Thunder Talisman", @@ -17099,7 +19272,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 102, + "req_int": 72 }, { "name": "Tideseer Mantle", @@ -17109,7 +19284,9 @@ "default", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 45, + "req_int": 45 }, { "name": "Time-Lost Diamond", @@ -17171,7 +19348,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 64 }, { "name": "Tonal Focus", @@ -17181,7 +19359,8 @@ "focus", "int_armour", "maraketh_basetype" - ] + ], + "req_int": 33 }, { "name": "Topaz Charm", @@ -17211,7 +19390,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 114 }, { "name": "Torment Jacket", @@ -17220,7 +19400,9 @@ "body_armour", "default", "dex_int_armour" - ] + ], + "req_dex": 67, + "req_int": 67 }, { "name": "Torn Gloves", @@ -17238,7 +19420,8 @@ "default", "onehand", "wand" - ] + ], + "req_int": 87 }, { "name": "Totemic Greatclub", @@ -17249,7 +19432,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 89 }, { "name": "Totemic Greaves", @@ -17258,7 +19442,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 86 }, { "name": "Tournament Mail", @@ -17267,7 +19452,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 67, + "req_dex": 67 }, { "name": "Toxic Quiver", @@ -17283,7 +19470,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 52, + "req_dex": 52 }, { "name": "Transcendent Life Flask", @@ -17308,7 +19497,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 107 }, { "name": "Trarthan Cannon", @@ -17320,7 +19510,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 114, + "req_dex": 63 }, { "name": "Treasured Blade", @@ -17331,7 +19523,9 @@ "sword", "vaal_basetype", "weapon" - ] + ], + "req_str": 40, + "req_dex": 40 }, { "name": "Treerunner Shoes", @@ -17340,7 +19534,9 @@ "boots", "default", "dex_int_armour" - ] + ], + "req_dex": 44, + "req_int": 44 }, { "name": "Tribal Bow", @@ -17352,7 +19548,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 89 }, { "name": "Tribal Mask", @@ -17362,7 +19559,9 @@ "dex_int_armour", "helmet", "vaal_basetype" - ] + ], + "req_dex": 27, + "req_int": 27 }, { "name": "Trimmed Greaves", @@ -17372,7 +19571,8 @@ "default", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 38 }, { "name": "Twig Circlet", @@ -17401,7 +19601,8 @@ "default", "helmet", "int_armour" - ] + ], + "req_int": 82 }, { "name": "Twin Bow", @@ -17412,7 +19613,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 96 }, { "name": "Twin Crossbow", @@ -17424,7 +19626,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 53, + "req_dex": 53 }, { "name": "Twin Flail", @@ -17435,7 +19639,9 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 30, + "req_int": 14 }, { "name": "Twisted Amulet", @@ -17450,7 +19656,8 @@ "default", "onehand", "wand" - ] + ], + "req_int": 114 }, { "name": "Two-Point Quiver", @@ -17492,7 +19699,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 63, + "req_dex": 63 }, { "name": "Unset Ring", @@ -17527,7 +19736,9 @@ "default", "dex_int_armour", "gloves" - ] + ], + "req_dex": 44, + "req_int": 44 }, { "name": "Utzaal Cuirass", @@ -17536,7 +19747,8 @@ "body_armour", "default", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Vaal Crest Shield", @@ -17547,7 +19759,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 59, + "req_int": 59 }, { "name": "Vaal Cuirass", @@ -17557,7 +19771,8 @@ "default", "str_armour", "vaal_basetype" - ] + ], + "req_str": 60 }, { "name": "Vaal Gloves", @@ -17566,7 +19781,8 @@ "default", "gloves", "int_armour" - ] + ], + "req_int": 94 }, { "name": "Vaal Greaves", @@ -17575,7 +19791,8 @@ "boots", "default", "str_armour" - ] + ], + "req_str": 101 }, { "name": "Vaal Mitts", @@ -17584,7 +19801,8 @@ "default", "gloves", "str_armour" - ] + ], + "req_str": 94 }, { "name": "Vaal Tower Shield", @@ -17595,7 +19813,8 @@ "shield", "str_armour", "str_shield" - ] + ], + "req_str": 107 }, { "name": "Vaal Wraps", @@ -17604,7 +19823,9 @@ "default", "dex_int_armour", "gloves" - ] + ], + "req_dex": 52, + "req_int": 52 }, { "name": "Vagabond Armour", @@ -17614,7 +19835,9 @@ "default", "maraketh_basetype", "str_dex_armour" - ] + ], + "req_str": 17, + "req_dex": 17 }, { "name": "Vampiric Blade", @@ -17625,7 +19848,9 @@ "onehand", "sword", "weapon" - ] + ], + "req_str": 14, + "req_dex": 14 }, { "name": "Varnished Crossbow", @@ -17638,7 +19863,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 19, + "req_dex": 19 }, { "name": "Veiled Mask", @@ -17648,7 +19875,9 @@ "dex_int_armour", "helmet", "maraketh_basetype" - ] + ], + "req_dex": 23, + "req_int": 23 }, { "name": "Velour Shoes", @@ -17657,7 +19886,9 @@ "boots", "default", "dex_int_armour" - ] + ], + "req_dex": 38, + "req_int": 38 }, { "name": "Velvet Cap", @@ -17666,7 +19897,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 74 }, { "name": "Venerable Defender", @@ -17678,7 +19910,9 @@ "shield", "str_dex_armour", "str_dex_shield" - ] + ], + "req_str": 64, + "req_dex": 64 }, { "name": "Venerated Mantle", @@ -17687,7 +19921,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 48, + "req_int": 48 }, { "name": "Veridical Chain", @@ -17704,7 +19940,8 @@ "helmet", "int_armour", "karui_basetype" - ] + ], + "req_int": 64 }, { "name": "Veteran Sabatons", @@ -17713,7 +19950,9 @@ "boots", "default", "str_dex_armour" - ] + ], + "req_str": 47, + "req_dex": 47 }, { "name": "Vicious Talisman", @@ -17724,7 +19963,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 47, + "req_int": 34 }, { "name": "Vile Greataxe", @@ -17734,7 +19975,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 89, + "req_dex": 36 }, { "name": "Vile Robe", @@ -17743,7 +19986,8 @@ "body_armour", "default", "int_armour" - ] + ], + "req_int": 121 }, { "name": "Viper Cap", @@ -17753,7 +19997,8 @@ "dex_armour", "helmet", "vaal_basetype" - ] + ], + "req_dex": 54 }, { "name": "Visceral Quiver", @@ -17770,7 +20015,9 @@ "helmet", "maraketh_basetype", "str_dex_armour" - ] + ], + "req_str": 15, + "req_dex": 15 }, { "name": "Vitalic Ring", @@ -17798,7 +20045,8 @@ "no_physical_spell_mods", "onehand", "wand" - ] + ], + "req_int": 31 }, { "name": "Voltaic Staff", @@ -17821,7 +20069,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 53, + "req_int": 38 }, { "name": "Voodoo Focus", @@ -17831,7 +20081,8 @@ "focus", "int_armour", "vaal_basetype" - ] + ], + "req_int": 48 }, { "name": "Votive Raiment", @@ -17841,7 +20092,8 @@ "default", "int_armour", "vaal_basetype" - ] + ], + "req_int": 54 }, { "name": "Wanderer Armour", @@ -17850,7 +20102,9 @@ "body_armour", "default", "str_dex_armour" - ] + ], + "req_str": 45, + "req_dex": 45 }, { "name": "Wanderer Shoes", @@ -17859,7 +20113,9 @@ "boots", "default", "dex_int_armour" - ] + ], + "req_dex": 47, + "req_int": 47 }, { "name": "War Spear", @@ -17870,7 +20126,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 14, + "req_dex": 31 }, { "name": "War Wraps", @@ -17879,7 +20137,9 @@ "default", "dex_int_armour", "gloves" - ] + ], + "req_dex": 44, + "req_int": 44 }, { "name": "Warded Helm", @@ -17888,7 +20148,9 @@ "default", "helmet", "str_dex_armour" - ] + ], + "req_str": 50, + "req_dex": 50 }, { "name": "Warden Bow", @@ -17900,7 +20162,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 23 }, { "name": "Warding Quarterstaff", @@ -17910,7 +20173,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 127, + "req_int": 50 }, { "name": "Warlock Leggings", @@ -17919,7 +20184,9 @@ "boots", "default", "str_int_armour" - ] + ], + "req_str": 56, + "req_int": 56 }, { "name": "Warlord Cuirass", @@ -17929,7 +20196,8 @@ "default", "karui_basetype", "str_armour" - ] + ], + "req_str": 121 }, { "name": "Warmonger Bow", @@ -17940,7 +20208,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_dex": 163 }, { "name": "Warmonger Greathelm", @@ -17949,7 +20218,8 @@ "default", "helmet", "str_armour" - ] + ], + "req_str": 91 }, { "name": "Warpick", @@ -17960,7 +20230,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_str": 41 }, { "name": "Warrior Greathelm", @@ -17970,7 +20241,8 @@ "helmet", "str_armour", "vaal_basetype" - ] + ], + "req_str": 52 }, { "name": "Waxed Jacket", @@ -17980,7 +20252,9 @@ "default", "dex_int_armour", "ezomyte_basetype" - ] + ], + "req_dex": 13, + "req_int": 13 }, { "name": "Waxing Quarterstaff", @@ -17990,7 +20264,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 75, + "req_int": 30 }, { "name": "Wayfarer Jacket", @@ -18000,7 +20276,9 @@ "default", "dex_int_armour", "maraketh_basetype" - ] + ], + "req_dex": 26, + "req_int": 26 }, { "name": "Wayfarer Shoes", @@ -18009,7 +20287,9 @@ "boots", "default", "dex_int_armour" - ] + ], + "req_dex": 34, + "req_int": 34 }, { "name": "Wayward Crest Shield", @@ -18021,7 +20301,9 @@ "shield", "str_int_armour", "str_int_shield" - ] + ], + "req_str": 36, + "req_int": 36 }, { "name": "Weaver Leggings", @@ -18031,7 +20313,9 @@ "default", "karui_basetype", "str_int_armour" - ] + ], + "req_str": 34, + "req_int": 34 }, { "name": "Whorl Focus", @@ -18041,7 +20325,8 @@ "focus", "int_armour", "karui_basetype" - ] + ], + "req_int": 73 }, { "name": "Wicker Tiara", @@ -18051,7 +20336,8 @@ "ezomyte_basetype", "helmet", "int_armour" - ] + ], + "req_int": 17 }, { "name": "Wide Belt", @@ -18071,7 +20357,9 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_str": 98, + "req_int": 72 }, { "name": "Wingbeat Talisman", @@ -18081,7 +20369,9 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 74, + "req_int": 52 }, { "name": "Winged Spear", @@ -18092,7 +20382,9 @@ "onehand", "spear", "weapon" - ] + ], + "req_str": 12, + "req_dex": 25 }, { "name": "Withered Wand", @@ -18115,7 +20407,8 @@ "one_hand_weapon", "onehand", "weapon" - ] + ], + "req_dex": 24 }, { "name": "Wolfskin Mantle", @@ -18124,7 +20417,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 }, { "name": "Wooden Buckler", @@ -18137,7 +20432,8 @@ "dex_shield", "ezomyte_basetype", "shield" - ] + ], + "req_dex": 10 }, { "name": "Wooden Club", @@ -18157,7 +20453,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 69 }, { "name": "Woven Cap", @@ -18166,7 +20463,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 91 }, { "name": "Woven Focus", @@ -18176,7 +20474,8 @@ "ezomyte_basetype", "focus", "int_armour" - ] + ], + "req_int": 11 }, { "name": "Wrapped Cap", @@ -18185,7 +20484,8 @@ "default", "dex_armour", "helmet" - ] + ], + "req_dex": 77 }, { "name": "Wrapped Greathelm", @@ -18195,7 +20495,8 @@ "helmet", "maraketh_basetype", "str_armour" - ] + ], + "req_str": 25 }, { "name": "Wrapped Quarterstaff", @@ -18216,7 +20517,8 @@ "default", "ezomyte_basetype", "int_armour" - ] + ], + "req_int": 17 }, { "name": "Wrath Sceptre", @@ -18225,7 +20527,8 @@ "default", "onehand", "sceptre" - ] + ], + "req_int": 87 }, { "name": "Wreath Focus", @@ -18234,7 +20537,8 @@ "default", "focus", "int_armour" - ] + ], + "req_int": 64 }, { "name": "Wyrm Quarterstaff", @@ -18244,7 +20548,9 @@ "twohand", "warstaff", "weapon" - ] + ], + "req_dex": 89, + "req_int": 36 }, { "name": "Wyrmscale Coat", @@ -18253,7 +20559,8 @@ "body_armour", "default", "dex_armour" - ] + ], + "req_dex": 121 }, { "name": "Zealot Bow", @@ -18265,7 +20572,8 @@ "twohand", "vaal_basetype", "weapon" - ] + ], + "req_dex": 70 }, { "name": "Zealot Crown", @@ -18274,7 +20582,9 @@ "default", "helmet", "str_int_armour" - ] + ], + "req_str": 40, + "req_int": 40 }, { "name": "Zealot Gauntlets", @@ -18283,7 +20593,9 @@ "default", "gloves", "str_dex_armour" - ] + ], + "req_str": 41, + "req_dex": 41 }, { "name": "Zealot Greathammer", @@ -18293,7 +20605,8 @@ "two_hand_weapon", "twohand", "weapon" - ] + ], + "req_str": 91 }, { "name": "Zenith Vestments", @@ -18302,7 +20615,9 @@ "body_armour", "default", "str_int_armour" - ] + ], + "req_str": 67, + "req_int": 67 } ] } diff --git a/data/4.5.4.3/overlay/buff_definitions.json b/data/4.5.4.3/overlay/buff_definitions.json deleted file mode 100644 index 3f88e557..00000000 --- a/data/4.5.4.3/overlay/buff_definitions.json +++ /dev/null @@ -1,563 +0,0 @@ -{ - "_meta": { - "extracted_files": [ - "Modules/CalcPerform.lua" - ], - "generator": "manual-curation (00-index 裁决 §4.2-4 批准的 overlay 通道例外)", - "regen_command": "人工归纳(doActorMisc :503-765 过程式 if-chain 无法 luajit 序列化);vendor 升级后跑 `cargo run -p sync-pob-catalog -- check-buff-refs --vendor-root vendor/PathOfBuilding-PoE2/src --defs data/4.5.0.3.4/overlay/buff_definitions.json` 对账,人工复核后 --write 刷新行段 hash", - "schema": "buff_definitions/v1", - "vendor": "PathOfBuilding-PoE2", - "vendor_commit": "2df5a7433dd2f1609e2fad8a6c3c917f923fe34f", - "vendor_commit_subject": "2df5a74 Fix crash when importing a character that uses Facebreaker gloves (#2098)" - }, - "buffs": [ - { - "id": "Adrenaline", - "trigger_flag": "Adrenaline", - "mode_gate": "combat", - "effect": { - "base": 1.0, - "inc_stats": [ - "BuffEffectOnSelf" - ], - "rounding": "none" - }, - "mods": [ - { - "name": "Damage", - "mod_type": "INC", - "value": { - "kind": "scaled_rounded", - "coeff": 100.0, - "rounding": "floor" - } - }, - { - "name": "Speed", - "mod_type": "INC", - "value": { - "kind": "scaled_rounded", - "coeff": 25.0, - "rounding": "floor" - }, - "flags": [ - "Attack" - ] - }, - { - "name": "Speed", - "mod_type": "INC", - "value": { - "kind": "scaled_rounded", - "coeff": 25.0, - "rounding": "floor" - }, - "flags": [ - "Cast" - ] - }, - { - "name": "MovementSpeed", - "mod_type": "INC", - "value": { - "kind": "scaled_rounded", - "coeff": 25.0, - "rounding": "floor" - } - }, - { - "name": "PhysicalDamageReduction", - "mod_type": "BASE", - "value": { - "kind": "scaled_rounded", - "coeff": 10.0, - "rounding": "floor" - } - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 586, - "line_end": 593, - "segment_hash": "fnv1a64:e3f46c64c93e2f77" - }, - "notes": "vendor 逐 mod m_floor(coeff × effectMod),effect 级不取整" - }, - { - "id": "ArcaneSurge", - "trigger_flag": "Condition:ArcaneSurge", - "mode_gate": "combat", - "effect": { - "base": 1.0, - "inc_stats": [ - "ArcaneSurgeEffect", - "BuffEffectOnSelf" - ], - "rounding": "none" - }, - "mods": [ - { - "name": "Speed", - "mod_type": "INC", - "value": { - "kind": "scaled_rounded", - "coeff": 15.0, - "rounding": "none" - }, - "flags": [ - "Cast" - ] - }, - { - "name": "ManaRegen", - "mod_type": "MORE", - "value": { - "kind": "scaled_rounded", - "coeff": 20.0, - "rounding": "none" - } - } - ], - "conditions_set": [ - "AffectedByArcaneSurge" - ], - "verified": true, - "vendor_ref": { - "file": "Modules/CalcDefence.lua", - "line_start": 1580, - "line_end": 1591, - "segment_hash": "fnv1a64:144064cc425efef2" - }, - "notes": "基本形(默认 15% Cast Speed / 20% more ManaRegen × effect,effect=1+Σinc/100 不取整,vendor 无 floor)。未覆盖分支:Max(ArcaneSurgeCastSpeed/ManaRegen) 覆写、ArcaneSurgeLifeRegen flag(LifeRegen 改道)、ArcaneSurgeDamage(Spell Damage MORE)——均无树/装备样本,出现时升级 handler。" - }, - { - "id": "ChaoticMight", - "trigger_flag": "ChaoticMight", - "mode_gate": "combat", - "effect": { - "base": 1.0, - "inc_stats": [ - "BuffEffectOnSelf" - ], - "rounding": "none" - }, - "mods": [ - { - "name": "PhysicalDamageGainAsChaos", - "mod_type": "BASE", - "value": { - "kind": "scaled_rounded", - "coeff": 30.0, - "rounding": "floor" - } - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 582, - "line_end": 585, - "segment_hash": "fnv1a64:dbd8f9c8a44c9452" - } - }, - { - "id": "Convergence", - "trigger_flag": "Convergence", - "mode_gate": "combat", - "effect": { - "base": 30.0, - "inc_stats": [ - "BuffEffectOnSelf" - ], - "rounding": "floor" - }, - "mods": [ - { - "name": "ElementalDamage", - "mod_type": "MORE", - "value": { - "kind": "per_effect", - "coeff": 1.0 - } - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 594, - "line_end": 597, - "segment_hash": "fnv1a64:4abf1b725bc2c12b" - } - }, - { - "id": "Elusive", - "trigger_flag": "Elusive", - "mode_gate": "combat", - "handler_id": "buff:elusive", - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 612, - "line_end": 631, - "segment_hash": "fnv1a64:36b76d63b4ee74c6" - }, - "notes": "真逻辑:Max({source=Skill}) 查询 + Override 上限 + Nightblade 交互 + 输出字段 ElusiveEffectMod" - }, - { - "id": "Fanaticism", - "trigger_flag": "Fanaticism", - "mode_gate": "combat", - "handler_id": "buff:fanaticism", - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 571, - "line_end": 576, - "segment_hash": "fnv1a64:7d71030ed94f4da6" - }, - "notes": "真逻辑:selfCast 门控需 mainSkill.activeEffect.srcInstance 状态;公式 = floor(75×(1+BuffEffectOnSelf/100)) → Speed MORE / Cost INC -e / AoE INC(全 Cast flag)" - }, - { - "id": "Fortify", - "trigger_flag": "Fortified", - "mode_gate": "combat", - "handler_id": "buff:fortify", - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 524, - "line_end": 538, - "segment_hash": "fnv1a64:9e63cf1ecf4d6c25" - }, - "notes": "真逻辑:stacks 模型(Maximum/Minimum/Override Fortification + alliedFortify)→ DamageTakenWhenHit MORE -floor((1+BuffEffectOnSelf/100)×stacks);触发还含 Multiplier:Fortification > 0 分支" - }, - { - "id": "Freeze", - "trigger_flag": "Freeze", - "mode_gate": "combat", - "effect": { - "base": 70.0, - "inc_stats": [ - "SelfChillEffect" - ], - "more_stats": [ - "SelfChillEffect" - ], - "rounding": "floor", - "min": 0.0 - }, - "mods": [ - { - "name": "ActionSpeed", - "mod_type": "INC", - "value": { - "kind": "per_effect", - "coeff": -1.0 - } - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 684, - "line_end": 687, - "segment_hash": "fnv1a64:b64bb12d1a1a4549" - }, - "notes": "calcLib.mod = (1+ΣINC/100)×ΠMORE;vendor m_max(m_floor(70×mod),0)——floor 在 clamp 前,与 effect 公式序一致" - }, - { - "id": "HerEmbrace", - "trigger_flag": "HerEmbrace", - "mode_gate": "combat", - "mods": [ - { - "name": "AvoidStun", - "mod_type": "BASE", - "value": { - "kind": "literal", - "value": 100.0 - } - }, - { - "name": "PhysicalDamageGainAsFire", - "mod_type": "BASE", - "value": { - "kind": "literal", - "value": 123.0 - }, - "flags": [ - "Sword" - ] - }, - { - "name": "AvoidFreeze", - "mod_type": "BASE", - "value": { - "kind": "literal", - "value": 100.0 - } - }, - { - "name": "AvoidChill", - "mod_type": "BASE", - "value": { - "kind": "literal", - "value": 100.0 - } - }, - { - "name": "AvoidIgnite", - "mod_type": "BASE", - "value": { - "kind": "literal", - "value": 100.0 - } - }, - { - "name": "Speed", - "mod_type": "INC", - "value": { - "kind": "literal", - "value": 20.0 - }, - "flags": [ - "Attack" - ] - }, - { - "name": "Speed", - "mod_type": "INC", - "value": { - "kind": "literal", - "value": 20.0 - }, - "flags": [ - "Cast" - ] - }, - { - "name": "MovementSpeed", - "mod_type": "INC", - "value": { - "kind": "literal", - "value": 20.0 - } - } - ], - "conditions_set": [ - "HerEmbrace" - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 598, - "line_end": 608, - "segment_hash": "fnv1a64:7ccc1cb631cff09f" - }, - "notes": "全字面量(不吃 BuffEffectOnSelf 缩放)" - }, - { - "id": "MaddeningPresence", - "trigger_flag": "HasMaddeningPresence", - "mode_gate": "combat", - "mods": [ - { - "name": "ActionSpeed", - "mod_type": "INC", - "value": { - "kind": "literal", - "value": -10.0 - } - }, - { - "name": "Damage", - "mod_type": "INC", - "value": { - "kind": "literal", - "value": -10.0 - } - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 748, - "line_end": 751, - "segment_hash": "fnv1a64:679897be912337f4" - } - }, - { - "id": "Malediction", - "trigger_flag": "HasMalediction", - "mode_gate": "combat", - "mods": [ - { - "name": "DamageTaken", - "mod_type": "INC", - "value": { - "kind": "literal", - "value": 10.0 - } - }, - { - "name": "Damage", - "mod_type": "INC", - "value": { - "kind": "literal", - "value": -10.0 - } - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 744, - "line_end": 747, - "segment_hash": "fnv1a64:56f9043453784061" - } - }, - { - "id": "Onslaught", - "trigger_flag": "Onslaught", - "mode_gate": "combat", - "effect": { - "base": 10.0, - "inc_stats": [ - "OnslaughtEffect", - "BuffEffectOnSelf" - ], - "rounding": "floor" - }, - "mods": [ - { - "name": "Speed", - "mod_type": "INC", - "value": { - "kind": "per_effect", - "coeff": 2.0 - }, - "flags": [ - "Attack" - ] - }, - { - "name": "Speed", - "mod_type": "INC", - "value": { - "kind": "per_effect", - "coeff": 2.0 - }, - "flags": [ - "Cast" - ] - }, - { - "name": "WarcrySpeed", - "mod_type": "INC", - "value": { - "kind": "per_effect", - "coeff": 2.0 - } - }, - { - "name": "MovementSpeed", - "mod_type": "INC", - "value": { - "kind": "per_effect", - "coeff": 1.0 - } - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 539, - "line_end": 570, - "segment_hash": "fnv1a64:e6f99ba533f1ffe3" - }, - "notes": "基本形(不含 Silver Flask 分支——见 OnslaughtFlask handler 条目);effect = floor(10×(1+Σinc/100))" - }, - { - "id": "OnslaughtFlask", - "trigger_flag": "Onslaught", - "mode_gate": "combat", - "handler_id": "buff:onslaught_flask", - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 539, - "line_end": 570, - "segment_hash": "fnv1a64:e6f99ba533f1ffe3" - }, - "notes": "真逻辑:Silver Flask 来源时 effect 计入 flaskData.effectInc + FlaskEffect/MagicUtilityFlaskEffect INC(依赖 M3-T4 flask merge,M3 末接通)" - }, - { - "id": "ShapersPresence", - "trigger_flag": "HasShapersPresence", - "mode_gate": "combat", - "mods": [ - { - "name": "BuffExpireFaster", - "mod_type": "MORE", - "value": { - "kind": "literal", - "value": -20.0 - } - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 752, - "line_end": 754, - "segment_hash": "fnv1a64:7b53c45448fcec95" - } - }, - { - "id": "UnholyMight", - "trigger_flag": "UnholyMight", - "mode_gate": "combat", - "effect": { - "base": 1.0, - "inc_stats": [ - "BuffEffectOnSelf" - ], - "rounding": "none" - }, - "mods": [ - { - "name": "Multiplier:UnholyMightMagnitude", - "mod_type": "BASE", - "value": { - "kind": "literal", - "value": 100.0 - } - }, - { - "name": "DamageGainAsChaos", - "mod_type": "BASE", - "value": { - "kind": "scaled_rounded", - "coeff": 0.3, - "rounding": "none" - }, - "tags": [ - { - "type": "multiplier", - "var": "UnholyMightMagnitude" - } - ] - } - ], - "verified": false, - "vendor_ref": { - "file": "Modules/CalcPerform.lua", - "line_start": 577, - "line_end": 581, - "segment_hash": "fnv1a64:6ffdd69243656a03" - }, - "notes": "vendor 注释:Magnitude 经 Multiplier 实现(perStat 数据该阶段不可用);DamageGainAsChaos = 0.3×(1+BuffEffectOnSelf/100) per Multiplier" - } - ] -} diff --git a/data/4.5.4.3/overlay/gem_quality_stats.json b/data/4.5.4.3/overlay/gem_quality_stats.json index 05e8b7fb..d3149aa4 100644 --- a/data/4.5.4.3/overlay/gem_quality_stats.json +++ b/data/4.5.4.3/overlay/gem_quality_stats.json @@ -3,8 +3,8 @@ "schema": "gem_quality_stats/v1", "generator": "sync-pob-catalog extract-lua", "vendor": "PathOfBuilding-PoE2", - "vendor_commit": "29ab8262dd4a867eac56165afb8391a509e34a0e", - "vendor_commit_subject": "29ab826 Add support for Darkness Enthroned and Atziri's Splendour augment mods (#2343)", + "vendor_commit": "ce8bffaba31f8e68cfce70579e1c96465e7c133c", + "vendor_commit_subject": "ce8bffaba31f8e68cfce70579e1c96465e7c133c", "extracted_files": [ "Data/Skills/act_dex.lua", "Data/Skills/act_int.lua", @@ -34,6 +34,16 @@ { "stat": "skill_alchemists_boon_generate_x_charges_for_any_flask_per_minute", "per_quality_rate": 0.1 + }, + { + "stat": "alchemists_boon_attack_speed_granted_+%_during_life_flask", + "per_quality_rate": 1.0, + "alt": true + }, + { + "stat": "alchemists_boon_cast_speed_granted_+%_during_mana_flask", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -61,6 +71,11 @@ { "stat": "ancestral_cry_duration_+%_final_per_removable_endurance_charge", "per_quality_rate": 1.0 + }, + { + "stat": "gem_quality_ancestral_cry_global_fire_damage_granted_+%_final", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -79,6 +94,11 @@ { "stat": "base_totem_duration", "per_quality_rate": 100.0 + }, + { + "stat": "totem_life_+%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -97,6 +117,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "animus_exchange_gain_%_maximum_life_spent_as_ward", + "per_quality_rate": 0.25, + "alt": true } ] }, @@ -115,6 +140,11 @@ { "stat": "number_of_chains", "per_quality_rate": 0.1 + }, + { + "stat": "active_skill_projectile_damage_+%_final_for_each_remaining_chain", + "per_quality_rate": 0.15, + "alt": true } ] }, @@ -124,6 +154,16 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 0.5 + }, + { + "stat": "archmage_all_damage_%_to_gain_as_lightning_to_grant_to_non_channelling_spells_per_100_max_mana", + "per_quality_rate": 0.05, + "alt": true + }, + { + "stat": "archmage_max_mana_permyriad_to_add_to_non_channelled_spell_mana_cost", + "per_quality_rate": 10.0, + "alt": true } ] }, @@ -142,6 +182,11 @@ { "stat": "maximum_number_of_arctic_armour_stationary_stacks", "per_quality_rate": 0.05 + }, + { + "stat": "arctic_armour_armour_granted_+%_per_stage", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -151,6 +196,11 @@ { "stat": "armour_break_amount_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_physical_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -160,6 +210,11 @@ { "stat": "armour_break_amount_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -169,6 +224,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.0 + }, + { + "stat": "base_number_of_totems_allowed", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -187,6 +247,11 @@ { "stat": "skill_attrition_culling_strike_at_x_or_more_stacks", "per_quality_rate": -0.25 + }, + { + "stat": "presence_area_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -205,6 +270,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "active_skill_projectile_speed_+%_final", + "per_quality_rate": -1.5, + "alt": true } ] }, @@ -214,6 +284,11 @@ { "stat": "barkskin_armour_to_gain_as_%_of_energy_shield_lost_to_enemy_hits", "per_quality_rate": 0.25 + }, + { + "stat": "active_skill_quality_duration_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -223,6 +298,11 @@ { "stat": "empower_barrage_damage_-%_final_with_repeated_projectiles", "per_quality_rate": -0.25 + }, + { + "stat": "charge_skip_consume_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -232,6 +312,11 @@ { "stat": "gain_x_rage_on_attack_hit", "per_quality_rate": 0.1 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -250,6 +335,11 @@ { "stat": "channelled_skill_suppress_ongoing_rage_cost_for_first_X_ms", "per_quality_rate": 50.0 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -259,6 +349,11 @@ { "stat": "skill_base_rage_effect_+%_to_apply", "per_quality_rate": 0.5 + }, + { + "stat": "berserk_maximum_rage_granted_+", + "per_quality_rate": 0.4, + "alt": true } ] }, @@ -268,6 +363,11 @@ { "stat": "volatile_dead_base_number_of_corpses_to_consume", "per_quality_rate": 0.05 + }, + { + "stat": "base_chance_to_not_consume_corpse_%", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -304,6 +404,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 0.5 + }, + { + "stat": "blink_travel_distance", + "per_quality_rate": 1.25, + "alt": true } ] }, @@ -322,6 +427,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "blood_hunt_explosion_%_blood_loss_to_deal_as_life_loss", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -331,6 +441,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "active_skill_physical_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -358,6 +473,11 @@ { "stat": "active_skill_pins_as_though_dealt_damage_+%_final", "per_quality_rate": 2.5 + }, + { + "stat": "active_skill_bleeding_effect_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -367,6 +487,11 @@ { "stat": "bone_offering_damage_taken_+%_final_after_shield_loss", "per_quality_rate": -1.5 + }, + { + "stat": "active_skill_quality_duration_+%_final", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -376,6 +501,11 @@ { "stat": "attack_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_base_area_of_effect_radius", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -385,6 +515,11 @@ { "stat": "active_skill_cast_speed_+%_final", "per_quality_rate": 0.5 + }, + { + "stat": "charge_skip_consume_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -394,6 +529,11 @@ { "stat": "spells_chance_to_hinder_on_hit_%", "per_quality_rate": 0.25 + }, + { + "stat": "active_skill_base_area_of_effect_radius", + "per_quality_rate": 0.3, + "alt": true } ] }, @@ -403,6 +543,11 @@ { "stat": "consume_frenzy_power_and_endurance_charge_every_x_ms", "per_quality_rate": 120.0 + }, + { + "stat": "charge_regulation_damage_per_charge_granted_+%", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -412,6 +557,11 @@ { "stat": "skill_effect_duration_+%", "per_quality_rate": 1.0 + }, + { + "stat": "charge_skip_consume_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -443,6 +593,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "skill_detonation_time_+%", + "per_quality_rate": -2.0, + "alt": true } ] }, @@ -461,6 +616,11 @@ { "stat": "chance_to_gain_1_more_charge_%", "per_quality_rate": 0.5 + }, + { + "stat": "skill_combat_frenzy_x_ms_cooldown", + "per_quality_rate": -50.0, + "alt": true } ] }, @@ -470,6 +630,11 @@ { "stat": "base_spell_%_chance_to_echo", "per_quality_rate": 0.5 + }, + { + "stat": "damage_+%_vs_frozen_enemies", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -483,6 +648,11 @@ { "stat": "rune_hazard_detonate_time_ms", "per_quality_rate": -5.0 + }, + { + "stat": "active_skill_base_area_of_effect_radius", + "per_quality_rate": 0.3, + "alt": true } ] }, @@ -492,6 +662,11 @@ { "stat": "contagion_number_of_additional_targets", "per_quality_rate": 0.1 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -501,6 +676,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 25.0 + }, + { + "stat": "base_cooldown_speed_+%", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -559,6 +739,11 @@ { "stat": "chance_to_gain_1_more_charge_%", "per_quality_rate": 1.0 + }, + { + "stat": "chance_to_gain_1_more_random_charge_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -568,6 +753,11 @@ { "stat": "active_skill_hit_damage_stun_multiplier_+%_final", "per_quality_rate": 2.0 + }, + { + "stat": "active_skill_damage_+%_final_vs_immobilised_enemies", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -577,6 +767,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.0 + }, + { + "stat": "base_number_of_totems_allowed", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -595,6 +790,11 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -613,6 +813,11 @@ { "stat": "curse_effect_+%", "per_quality_rate": 0.5 + }, + { + "stat": "base_mana_cost_-%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -631,6 +836,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "active_skill_base_physical_damage_%_to_convert_to_fire", + "per_quality_rate": 3.0, + "alt": true } ] }, @@ -640,6 +850,11 @@ { "stat": "corpse_explosion_monster_life_permillage_physical", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_base_area_of_effect_radius", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -649,6 +864,11 @@ { "stat": "detonating_arrow_max_number_of_stages", "per_quality_rate": 0.05 + }, + { + "stat": "active_skill_ignite_effect_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -667,6 +887,11 @@ { "stat": "disengage_%_chance_for_additional_shockwave", "per_quality_rate": 1.0 + }, + { + "stat": "melee_range_+", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -676,6 +901,11 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -694,6 +924,11 @@ { "stat": "base_number_of_earthquakes_allowed", "per_quality_rate": 0.1 + }, + { + "stat": "gem_quality_earthquake_damaging_ailment_effect_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -703,6 +938,11 @@ { "stat": "earthshatter_damage_+%_final_per_spike", "per_quality_rate": 0.3 + }, + { + "stat": "slam_aftershock_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -712,6 +952,11 @@ { "stat": "electrocuting_arrow_%_damage_gained_as_extra_lightning_on_debuffed_target", "per_quality_rate": 0.5 + }, + { + "stat": "electrocuting_arrow_damage_taken_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -721,6 +966,11 @@ { "stat": "skill_elemental_conflux_active_element_damage_+%_final", "per_quality_rate": 0.5 + }, + { + "stat": "base_skill_effect_duration", + "per_quality_rate": 200.0, + "alt": true } ] }, @@ -748,6 +998,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.1 + }, + { + "stat": "active_skill_critical_strike_chance_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -757,6 +1012,11 @@ { "stat": "curse_effect_+%", "per_quality_rate": 0.5 + }, + { + "stat": "curse_delay_+%", + "per_quality_rate": -2.5, + "alt": true } ] }, @@ -766,6 +1026,16 @@ { "stat": "ember_fusillade_damage_+%_final_per_ember_fired", "per_quality_rate": 0.1 + }, + { + "stat": "skill_effect_duration_+%", + "per_quality_rate": -2.0, + "alt": true + }, + { + "stat": "active_skill_cast_speed_+%_final", + "per_quality_rate": -1.0, + "alt": true } ] }, @@ -775,6 +1045,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 0.5 + }, + { + "stat": "emergency_reload_damage_+%_final", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -802,6 +1077,11 @@ { "stat": "curse_effect_+%", "per_quality_rate": 0.5 + }, + { + "stat": "base_mana_cost_-%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -811,6 +1091,11 @@ { "stat": "skill_additional_fissure_chance_%", "per_quality_rate": 1.0 + }, + { + "stat": "base_number_of_entangle_roots_allowed", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -820,6 +1105,11 @@ { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", "per_quality_rate": 6.0 + }, + { + "stat": "damage_+%_vs_frozen_enemies", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -829,6 +1119,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 50.0 + }, + { + "stat": "number_of_chains", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -838,6 +1133,11 @@ { "stat": "skill_eternal_march_maximum_ward_cost", "per_quality_rate": 10.0 + }, + { + "stat": "base_cooldown_speed_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -847,6 +1147,11 @@ { "stat": "ceaseless_rage_base_rage_regeneration_per_minute", "per_quality_rate": 1.5 + }, + { + "stat": "base_spirit_reservation_efficiency_+%", + "per_quality_rate": 0.75, + "alt": true } ] }, @@ -874,6 +1179,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -883,6 +1193,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "base_number_of_crossbow_bolts", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -901,6 +1216,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "charge_skip_consume_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -928,6 +1248,11 @@ { "stat": "base_projectile_speed_+%", "per_quality_rate": 1.5 + }, + { + "stat": "projectile_return_%_chance", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -937,6 +1262,11 @@ { "stat": "lightning_strike_damage_+%_final_per_power_charge", "per_quality_rate": 1.0 + }, + { + "stat": "charge_skip_consume_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -946,6 +1276,11 @@ { "stat": "chance_to_not_consume_parried_%", "per_quality_rate": 0.75 + }, + { + "stat": "melee_range_+", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -982,6 +1317,11 @@ { "stat": "spell_skills_fire_2_additional_projectiles_final_chance_%", "per_quality_rate": 0.5 + }, + { + "stat": "spell_skill_%_chance_to_fire_8_additional_projectiles_in_nova", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -1000,6 +1340,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.1 + }, + { + "stat": "chance_to_not_consume_infusion_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1018,6 +1363,11 @@ { "stat": "active_skill_ignite_chance_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_fire_damage_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1027,6 +1377,11 @@ { "stat": "active_skill_cast_speed_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "gem_quality_flameblast_damaging_ailment_effect_per_stage_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1036,6 +1391,16 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_base_all_damage_%_to_gain_as_lightning", + "per_quality_rate": 0.5, + "alt": true + }, + { + "stat": "active_skill_base_all_damage_%_to_gain_as_cold", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -1045,6 +1410,11 @@ { "stat": "active_skill_critical_strike_chance_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "charge_skip_consume_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1054,6 +1424,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_base_all_damage_%_to_gain_as_fire", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1063,6 +1438,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "fortifying_cry_guard_gained_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1072,6 +1452,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "base_secondary_skill_effect_duration", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1081,6 +1466,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.0 + }, + { + "stat": "active_skill_reload_speed_+%_final", + "per_quality_rate": 5.0, + "alt": true } ] }, @@ -1108,6 +1498,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "base_skill_effect_duration", + "per_quality_rate": 50.0, + "alt": true } ] }, @@ -1117,6 +1512,11 @@ { "stat": "freezing_mark_hit_damage_freeze_multiplier_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "base_mana_cost_-%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -1126,6 +1526,11 @@ { "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", "per_quality_rate": 2.0 + }, + { + "stat": "base_maximum_seals_for_skill", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -1144,6 +1549,11 @@ { "stat": "active_skill_all_elemental_exposure_compounding_magnitude_cap", "per_quality_rate": 0.5 + }, + { + "stat": "base_maximum_number_of_frost_bombs", + "per_quality_rate": 0.15, + "alt": true } ] }, @@ -1153,6 +1563,11 @@ { "stat": "spell_skills_fire_2_additional_projectiles_final_chance_%", "per_quality_rate": 0.5 + }, + { + "stat": "number_of_additional_forks_base", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -1162,6 +1577,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "ice_crystal_maximum_life_+%", + "per_quality_rate": 20.0, + "alt": true } ] }, @@ -1171,6 +1591,11 @@ { "stat": "active_skill_projectile_damage_+%_final_if_pierced_enemy", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_projectile_speed_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1180,6 +1605,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.5 + }, + { + "stat": "damage_+%_vs_frozen_enemies", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1189,6 +1619,11 @@ { "stat": "active_skill_chill_effect_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "base_number_of_frozen_locus_allowed", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -1216,6 +1651,11 @@ { "stat": "active_skill_stun_threshold_+%_while_performing_action", "per_quality_rate": 2.0 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1234,6 +1674,11 @@ { "stat": "wind_blast_damage_+%_final_from_distance", "per_quality_rate": 1.0 + }, + { + "stat": "armour_break_physical_damage_%_dealt_as_armour_break", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1252,6 +1697,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "base_number_of_crossbow_bolts", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -1270,6 +1720,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "active_skill_fire_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1279,6 +1734,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "active_skill_fire_damage_+%_final", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -1288,6 +1748,11 @@ { "stat": "perfect_timing_window_ms_+%", "per_quality_rate": 1.0 + }, + { + "stat": "chance_for_extra_damage_roll_with_lightning_damage_%", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -1306,6 +1771,11 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 1.0 + }, + { + "stat": "ghost_dance_max_stacks", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -1324,6 +1794,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "active_skill_base_area_of_effect_radius", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -1333,6 +1808,11 @@ { "stat": "active_skill_base_physical_damage_%_to_gain_as_cold", "per_quality_rate": 0.75 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1342,6 +1822,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "charge_skip_consume_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1351,6 +1836,11 @@ { "stat": "grim_remnant_health_stored_in_globe_%", "per_quality_rate": 0.25 + }, + { + "stat": "remnant_pickup_range_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1360,6 +1850,11 @@ { "stat": "grim_pillars_number_of_pillars_to_create", "per_quality_rate": 0.1 + }, + { + "stat": "active_skill_base_secondary_area_of_effect_radius", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -1378,6 +1873,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "base_reduce_enemy_cold_resistance_%", + "per_quality_rate": 3.0, + "alt": true } ] }, @@ -1387,6 +1887,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "chance_to_not_consume_glory_%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -1414,6 +1919,11 @@ { "stat": "herald_of_ash_burning_%_overkill_damage_per_minute", "per_quality_rate": 15.0 + }, + { + "stat": "herald_of_ash_fire_damage_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1423,6 +1933,11 @@ { "stat": "skill_herald_bleeding_enemies_explode_for_%_blood_loss_as_unscalable_physical_damage", "per_quality_rate": 0.2 + }, + { + "stat": "herald_of_blood_global_physical_damage_granted_+%", + "per_quality_rate": 0.75, + "alt": true } ] }, @@ -1432,6 +1947,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "herald_of_ice_cold_damage_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1441,6 +1961,11 @@ { "stat": "hinder_chance_%_on_spreading_poioson", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -1450,6 +1975,11 @@ { "stat": "herald_of_thunder_storm_max_hits", "per_quality_rate": 0.1 + }, + { + "stat": "herald_of_thunder_lightning_damage_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1459,6 +1989,11 @@ { "stat": "hexblast_damage_+%_final_per_second_remaining_curse_duration", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_critical_strike_chance_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1468,6 +2003,11 @@ { "stat": "active_skill_projectile_damage_+%_final_if_pierced_enemy", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_physical_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1513,6 +2053,11 @@ { "stat": "skill_hollow_shell_spent_ward_%_to_grant_as_guard", "per_quality_rate": 0.25 + }, + { + "stat": "base_skill_effect_duration", + "per_quality_rate": 100.0, + "alt": true } ] }, @@ -1531,6 +2076,11 @@ { "stat": "active_skill_damage_+%_final_vs_chilled_enemies", "per_quality_rate": 1.0 + }, + { + "stat": "chance_to_not_consume_infusion_%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1540,6 +2090,11 @@ { "stat": "active_skill_chill_as_though_damage_+%_final", "per_quality_rate": 5.0 + }, + { + "stat": "active_skill_hit_damage_freeze_multiplier_+%_final", + "per_quality_rate": 10.0, + "alt": true } ] }, @@ -1549,6 +2104,11 @@ { "stat": "active_skill_chill_effect_+%_final", "per_quality_rate": 1.5 + }, + { + "stat": "movement_speed_penalty_+%_while_performing_action", + "per_quality_rate": -2.0, + "alt": true } ] }, @@ -1558,6 +2118,11 @@ { "stat": "attack_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_critical_strike_chance_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1567,6 +2132,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 0.5 + }, + { + "stat": "shearing_bolts_number_of_empowered_attacks", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -1594,6 +2164,11 @@ { "stat": "ignite_duration_+%_per_shotgun_pellet_hit", "per_quality_rate": 0.75 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -1603,6 +2178,11 @@ { "stat": "active_skill_ignite_duration_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "incinerate_maximum_fuel", + "per_quality_rate": 100.0, + "alt": true } ] }, @@ -1621,6 +2201,11 @@ { "stat": "infernal_cry_exerted_attack_all_damage_%_to_gain_as_fire_%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_base_area_of_effect_radius", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -1639,6 +2224,11 @@ { "stat": "active_skill_hit_damage_stun_multiplier_+%_final", "per_quality_rate": 2.5 + }, + { + "stat": "active_skill_physical_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1648,6 +2238,11 @@ { "stat": "recover_%_maximum_mana_on_cull", "per_quality_rate": 0.2 + }, + { + "stat": "recover_%_maximum_life_on_cull", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -1666,6 +2261,11 @@ { "stat": "active_skill_damage_+%_final_vs_fully_broken_armour", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1675,6 +2275,11 @@ { "stat": "skill_leylines_spell_damage_+%_final", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_base_area_of_effect_radius", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -1693,6 +2298,11 @@ { "stat": "active_skill_shock_chance_+%_final", "per_quality_rate": 2.0 + }, + { + "stat": "chance_for_extra_damage_roll_with_lightning_damage_%", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -1711,6 +2321,11 @@ { "stat": "active_skill_lightning_damage_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "lightning_conduit_x_additional_strikes_if_consumed_a_shock", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -1720,6 +2335,11 @@ { "stat": "lightning_rod_%_chance_for_additional_burst_on_landing", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1729,6 +2349,11 @@ { "stat": "base_number_of_projectiles", "per_quality_rate": 0.1 + }, + { + "stat": "chance_%_to_double_effect_of_removing_charges", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1738,6 +2363,11 @@ { "stat": "shock_effect_+%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_cast_speed_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1747,6 +2377,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "base_spirit_reservation_efficiency_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1774,6 +2409,16 @@ { "stat": "active_skill_ignite_chance_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_fire_damage_+%_final", + "per_quality_rate": 2.5, + "alt": true + }, + { + "stat": "living_bomb_damage_threshold_%_of_ailment_threshold", + "per_quality_rate": 10.0, + "alt": true } ] }, @@ -1783,6 +2428,11 @@ { "stat": "active_skill_base_physical_damage_%_to_gain_as_cold", "per_quality_rate": 0.5 + }, + { + "stat": "base_reduce_enemy_cold_resistance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1792,6 +2442,11 @@ { "stat": "skill_igneous_shield_grants_block_chance_+%", "per_quality_rate": 0.25 + }, + { + "stat": "magma_barrier_maximum_block_chance_granted_%", + "per_quality_rate": 0.25, + "alt": true } ] }, @@ -1801,6 +2456,11 @@ { "stat": "base_number_of_projectiles", "per_quality_rate": 0.2 + }, + { + "stat": "active_skill_lightning_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1828,6 +2488,11 @@ { "stat": "mana_remnants_mana_gain_per_globe", "per_quality_rate": 2.0 + }, + { + "stat": "mana_remnants_global_mana_regeneration_rate_granted_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1837,6 +2502,11 @@ { "stat": "mana_tempest_effects_linger_X_ms", "per_quality_rate": 100.0 + }, + { + "stat": "mana_tempest_mana_cost_%_to_add_to_cost_per_second", + "per_quality_rate": -0.4, + "alt": true } ] }, @@ -1855,6 +2525,11 @@ { "stat": "active_skill_required_number_of_combo_stacks", "per_quality_rate": -0.05 + }, + { + "stat": "base_secondary_skill_effect_duration", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -1882,6 +2557,11 @@ { "stat": "base_skill_cost_efficiency_+%", "per_quality_rate": 1.0 + }, + { + "stat": "skill_effect_duration_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1891,6 +2571,11 @@ { "stat": "energy_generated_+%", "per_quality_rate": 0.75 + }, + { + "stat": "triggered_skill_damage_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1936,6 +2621,11 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 0.5 + }, + { + "stat": "cast_on_crit_global_critical_hit_chance_granted_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1945,6 +2635,11 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 0.5 + }, + { + "stat": "cast_on_dodge_dodge_roll_distance_granted_+", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -1954,6 +2649,11 @@ { "stat": "energy_generated_+%", "per_quality_rate": 0.75 + }, + { + "stat": "base_reservation_efficiency_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -1963,6 +2663,11 @@ { "stat": "energy_generated_+%", "per_quality_rate": 1.0 + }, + { + "stat": "triggered_skill_damage_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1981,6 +2686,11 @@ { "stat": "generic_ongoing_trigger_maximum_energy", "per_quality_rate": 5.0 + }, + { + "stat": "triggered_skill_damage_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -1990,6 +2700,11 @@ { "stat": "energy_generated_+%", "per_quality_rate": 1.0 + }, + { + "stat": "base_reservation_efficiency_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -2008,6 +2723,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.0 + }, + { + "stat": "base_reservation_efficiency_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -2017,6 +2737,11 @@ { "stat": "totem_skill_area_of_effect_+%", "per_quality_rate": 1.0 + }, + { + "stat": "base_number_of_totems_allowed", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -2026,6 +2751,11 @@ { "stat": "energy_generated_+%", "per_quality_rate": 1.0 + }, + { + "stat": "triggered_skill_damage_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2039,6 +2769,11 @@ { "stat": "ward_remnants_chance_to_spawn_remnant_on_stun_%", "per_quality_rate": 0.25 + }, + { + "stat": "ward_remnants_spawn_remnant_on_stun_cooldown_ms", + "per_quality_rate": -2.5, + "alt": true } ] }, @@ -2075,6 +2810,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 50.0 + }, + { + "stat": "base_reservation_efficiency_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -2102,6 +2842,11 @@ { "stat": "inflict_exposure_on_hit_%_chance", "per_quality_rate": 1.5 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -2138,6 +2883,11 @@ { "stat": "skill_base_oil_exposure_-_to_total_elemental_resistance", "per_quality_rate": 0.25 + }, + { + "stat": "charge_skip_consume_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2147,6 +2897,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "skill_base_oil_exposure_-_to_total_elemental_resistance", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -2156,6 +2911,11 @@ { "stat": "number_of_chains", "per_quality_rate": 0.15 + }, + { + "stat": "orb_of_storms_maximum_number_of_hits", + "per_quality_rate": 0.3, + "alt": true } ] }, @@ -2174,6 +2934,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 1.2 + }, + { + "stat": "pain_offering_attack_and_cast_speed_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2192,6 +2957,11 @@ { "stat": "active_skill_ignite_chance_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -2201,6 +2971,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.0 + }, + { + "stat": "active_skill_reload_speed_+%_final", + "per_quality_rate": 5.0, + "alt": true } ] }, @@ -2237,6 +3012,11 @@ { "stat": "plague_bearer_gains_%_of_damage_from_inflicted_poisons", "per_quality_rate": 0.1 + }, + { + "stat": "poison_effect_+%_vs_non_poisoned_enemies", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -2246,6 +3026,11 @@ { "stat": "active_skill_shock_duration_+%_final", "per_quality_rate": 1.5 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -2255,6 +3040,11 @@ { "stat": "active_skill_poison_effect_+%_final", "per_quality_rate": 0.5 + }, + { + "stat": "armour_break_for_%_of_poison_damage_over_poison_duration", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2273,6 +3063,11 @@ { "stat": "verisium_infusion_duration_+%", "per_quality_rate": 2.5 + }, + { + "stat": "additional_infusion_gain_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2291,6 +3086,11 @@ { "stat": "attack_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_critical_strike_chance_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2300,6 +3100,11 @@ { "stat": "base_chance_to_not_consume_corpse_%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_quality_duration_+%_final", + "per_quality_rate": 5.0, + "alt": true } ] }, @@ -2336,6 +3141,11 @@ { "stat": "base_number_of_raging_spirits_allowed", "per_quality_rate": 0.1 + }, + { + "stat": "active_skill_minion_damage_+%_final", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -2345,6 +3155,11 @@ { "stat": "rain_of_arrows_arrow_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2363,6 +3178,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "hit_damage_immobilisation_multiplier_+%", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -2372,6 +3192,11 @@ { "stat": "raise_zombie_empowerment_effect_+%", "per_quality_rate": 1.25 + }, + { + "stat": "base_number_of_zombies_allowed", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -2381,6 +3206,11 @@ { "stat": "base_additional_damage_from_distance_+%_final", "per_quality_rate": 1.5 + }, + { + "stat": "base_aggravate_bleeding_on_attack_hit_chance_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2390,6 +3220,11 @@ { "stat": "rapid_assault_%_chance_to_attach_additional_spear", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_bleeding_effect_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -2399,6 +3234,11 @@ { "stat": "maximum_number_of_crossbow_heat_stacks", "per_quality_rate": 0.75 + }, + { + "stat": "maximum_number_of_crossbow_heat_stacks", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -2408,6 +3248,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.5 + }, + { + "stat": "base_cooldown_modifiable_repeat_interval_ms", + "per_quality_rate": -100.0, + "alt": true } ] }, @@ -2426,6 +3271,11 @@ { "stat": "runic_fortress_stun_threshold_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "base_skill_effect_duration", + "per_quality_rate": 50.0, + "alt": true } ] }, @@ -2435,6 +3285,11 @@ { "stat": "armour_break_amount_+%", "per_quality_rate": 1.0 + }, + { + "stat": "stun_threshold_+%_while_channelling", + "per_quality_rate": 5.0, + "alt": true } ] }, @@ -2444,6 +3299,11 @@ { "stat": "active_skill_minion_life_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "base_reservation_efficiency_+%", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -2471,6 +3331,11 @@ { "stat": "active_skill_damage_+%_final_per_time_chained", "per_quality_rate": 0.5 + }, + { + "stat": "number_of_chains", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -2480,6 +3345,11 @@ { "stat": "active_skill_stun_threshold_+%_while_performing_action", "per_quality_rate": 5.0 + }, + { + "stat": "armour_break_physical_damage_%_dealt_as_armour_break", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -2489,6 +3359,11 @@ { "stat": "active_skill_stun_threshold_+%_while_performing_action", "per_quality_rate": 2.0 + }, + { + "stat": "rune_ward_block_%_damage_taken", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -2507,6 +3382,11 @@ { "stat": "harvester_minion_resummon_speed_+%_final", "per_quality_rate": 0.25 + }, + { + "stat": "sacrifice_minion_life_granted_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -2525,6 +3405,11 @@ { "stat": "wild_beast_damage_+%_final", "per_quality_rate": 0.25 + }, + { + "stat": "wild_beast_energy_per_hit", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -2543,6 +3428,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 100.0 + }, + { + "stat": "scavenged_plating_armour_+%_final_per_stack", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -2552,6 +3442,11 @@ { "stat": "seismic_cry_slam_skill_aftershock_damage_+%_final", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_base_physical_damage_%_to_gain_as_fire", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2561,6 +3456,11 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_quality_duration_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2579,6 +3479,11 @@ { "stat": "active_skill_critical_strike_chance_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2588,6 +3493,11 @@ { "stat": "active_skill_critical_strike_chance_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2606,6 +3516,11 @@ { "stat": "base_additional_damage_from_distance_+%_final", "per_quality_rate": 2.0 + }, + { + "stat": "shield_charge_extra_distance", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -2615,6 +3530,11 @@ { "stat": "shield_wall_damage_+%_final_when_slammed", "per_quality_rate": 2.0 + }, + { + "stat": "active_skill_base_physical_damage_%_to_gain_as_fire", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2624,6 +3544,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_lightning_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2642,6 +3567,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -2651,6 +3581,11 @@ { "stat": "active_skill_lightning_damage_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2660,6 +3595,11 @@ { "stat": "base_totem_duration", "per_quality_rate": 200.0 + }, + { + "stat": "base_number_of_totems_allowed", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -2669,6 +3609,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "base_number_of_totems_allowed", + "per_quality_rate": 0.05, + "alt": true } ] }, @@ -2687,6 +3632,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "base_number_of_crossbow_bolts", + "per_quality_rate": 0.15, + "alt": true } ] }, @@ -2696,6 +3646,11 @@ { "stat": "active_skill_damage_+%_final_vs_immobilised_enemies", "per_quality_rate": 2.0 + }, + { + "stat": "base_number_of_crossbow_bolts", + "per_quality_rate": 0.005, + "alt": true } ] }, @@ -2722,6 +3677,11 @@ { "stat": "infusion_remnants_%_chance_to_spawn_lightning_infusion_on_shocking_an_enemy", "per_quality_rate": 0.1 + }, + { + "stat": "remnant_pickup_range_+%", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -2731,6 +3691,11 @@ { "stat": "base_chance_to_daze_%", "per_quality_rate": 2.5 + }, + { + "stat": "chance_to_gain_1_more_charge_%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -2740,6 +3705,11 @@ { "stat": "base_spell_%_chance_to_echo", "per_quality_rate": 0.5 + }, + { + "stat": "damage_+%_vs_frozen_enemies", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2749,6 +3719,11 @@ { "stat": "chance_%_to_spawn_another_infusion_remnant", "per_quality_rate": 0.5 + }, + { + "stat": "base_cooldown_speed_+%", + "per_quality_rate": 5.0, + "alt": true } ] }, @@ -2758,6 +3733,16 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true + }, + { + "stat": "perfect_timing_window_ms_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2767,6 +3752,11 @@ { "stat": "enemy_additional_critical_strike_multiplier_against_self", "per_quality_rate": 0.75 + }, + { + "stat": "gem_quality_marked_enemy_damage_dealt_+%_final", + "per_quality_rate": -0.5, + "alt": true } ] }, @@ -2794,6 +3784,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 50.0 + }, + { + "stat": "power_offering_buff_spell_damage_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2812,6 +3807,11 @@ { "stat": "base_projectile_speed_+%", "per_quality_rate": 1.5 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -2821,6 +3821,11 @@ { "stat": "chance_to_retain_40%_of_glory_on_use_%", "per_quality_rate": 1.25 + }, + { + "stat": "active_skill_fire_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2830,6 +3835,11 @@ { "stat": "hazard_rearm_%_chance", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2839,6 +3849,11 @@ { "stat": "base_number_of_projectiles", "per_quality_rate": 0.2 + }, + { + "stat": "chance_%_to_double_effect_of_removing_charges", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -2866,6 +3881,11 @@ { "stat": "attacks_chance_to_blind_on_hit_%", "per_quality_rate": 2.0 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -2875,6 +3895,11 @@ { "stat": "slam_aftershock_chance_%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2893,6 +3918,11 @@ { "stat": "base_number_of_overcharged_spears_allowed", "per_quality_rate": 0.05 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -2902,6 +3932,11 @@ { "stat": "active_skill_base_secondary_area_of_effect_radius", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_base_area_of_effect_radius", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -2911,6 +3946,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "base_number_of_crossbow_bolts", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -2929,6 +3969,11 @@ { "stat": "shock_duration_+%", "per_quality_rate": 1.5 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -2947,6 +3992,11 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_minion_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -2983,6 +4033,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "base_number_of_projectiles", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -2992,6 +4047,11 @@ { "stat": "active_skill_minion_hit_damage_stun_multiplier_+%_final", "per_quality_rate": 2.0 + }, + { + "stat": "active_skill_minion_life_+%_final", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -3001,6 +4061,11 @@ { "stat": "skeletal_cleric_revived_skeletons_immune_for_X_ms", "per_quality_rate": 150.0 + }, + { + "stat": "minion_damage_taken_+%", + "per_quality_rate": -2.0, + "alt": true } ] }, @@ -3010,6 +4075,11 @@ { "stat": "active_skill_minion_damage_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "base_spirit_reservation_efficiency_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3019,6 +4089,11 @@ { "stat": "minion_rage_effect_+%", "per_quality_rate": 1.0 + }, + { + "stat": "armour_break_physical_damage_%_dealt_as_armour_break", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -3037,6 +4112,11 @@ { "stat": "minion_maximum_life_%_to_gain_as_maximum_energy_shield", "per_quality_rate": 1.0 + }, + { + "stat": "minion_cast_speed_+%", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -3055,6 +4135,11 @@ { "stat": "active_skill_minion_damage_+%_final", "per_quality_rate": 1.0 + }, + { + "stat": "base_reservation_efficiency_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3073,6 +4158,11 @@ { "stat": "accuracy_range_penalty_+%", "per_quality_rate": -2.5 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3082,6 +4172,11 @@ { "stat": "channelled_slam_max_stages", "per_quality_rate": 0.05 + }, + { + "stat": "active_skill_hit_damage_stun_multiplier_+%_final", + "per_quality_rate": 15.0, + "alt": true } ] }, @@ -3091,6 +4186,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "curse_effect_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3100,6 +4200,11 @@ { "stat": "warcry_grant_damage_+%_to_exerted_attacks", "per_quality_rate": 1.5 + }, + { + "stat": "base_cooldown_speed_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -3113,6 +4218,11 @@ { "stat": "mark_effect_+%", "per_quality_rate": 0.5 + }, + { + "stat": "base_mana_cost_-%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3122,6 +4232,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.0 + }, + { + "stat": "totems_spells_cast_speed_+%_per_active_totem", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -3140,6 +4255,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 80.0 + }, + { + "stat": "base_mana_cost_-%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3158,6 +4278,11 @@ { "stat": "tempest_bell_damage_+%_final_per_time_hit", "per_quality_rate": 0.15 + }, + { + "stat": "bell_hit_limit", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -3167,6 +4292,11 @@ { "stat": "melee_range_+", "per_quality_rate": 0.2 + }, + { + "stat": "final_strike_number_of_spirit_strikes", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -3176,6 +4306,11 @@ { "stat": "curse_effect_+%", "per_quality_rate": 0.5 + }, + { + "stat": "curse_delay_+%", + "per_quality_rate": -2.5, + "alt": true } ] }, @@ -3203,6 +4338,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.25 + }, + { + "stat": "impale_on_hit_%_chance", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -3212,6 +4352,11 @@ { "stat": "thunderous_leap_%_chance_for_shocked_ground_when_detonating", "per_quality_rate": 1.5 + }, + { + "stat": "slam_aftershock_chance_%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -3225,6 +4370,11 @@ { "stat": "thunderstorm_wet_debuff_hit_damage_freeze_multiplier_+%_final", "per_quality_rate": 0.25 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3243,6 +4393,11 @@ { "stat": "skill_time_of_need_gain_x_life", "per_quality_rate": 2.0 + }, + { + "stat": "time_of_need_global_life_regeneration_rate_granted_+%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3261,6 +4416,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 100.0 + }, + { + "stat": "number_of_tornados_allowed", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -3270,6 +4430,11 @@ { "stat": "tornado_shot_projectile_damage_+%_final", "per_quality_rate": 0.75 + }, + { + "stat": "base_number_of_tornado_shots_allowed", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -3279,6 +4444,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.15 + }, + { + "stat": "toxic_domain_buff_linger_duration_ms", + "per_quality_rate": 100.0, + "alt": true } ] }, @@ -3288,6 +4458,11 @@ { "stat": "base_cooldown_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_fire_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3301,6 +4476,11 @@ { "stat": "number_of_poisonbloom_arrow_bloom_allowed", "per_quality_rate": 0.05 + }, + { + "stat": "base_poison_duration_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -3310,6 +4490,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.1 + }, + { + "stat": "base_ward_cost_efficiency_+%", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -3319,6 +4504,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 100.0 + }, + { + "stat": "base_number_of_verisium_runes_allowed", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -3337,6 +4527,11 @@ { "stat": "maximum_caltrops_allowed", "per_quality_rate": 0.25 + }, + { + "stat": "active_skill_physical_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3346,6 +4541,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "wind_dancer_damage_+%_final_per_stage", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3355,6 +4555,11 @@ { "stat": "trinity_skill_speed_+%_while_all_resonance_is_at_least_250_to_grant", "per_quality_rate": 0.75 + }, + { + "stat": "trinity_%_physical_damage_to_convert_to_random_element_granted", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3364,6 +4569,11 @@ { "stat": "triskelion_cascade_next_skill_damage_+%_final", "per_quality_rate": 0.5 + }, + { + "stat": "triskelion_cascade_next_skill_area_of_effect_+%_final", + "per_quality_rate": 0.25, + "alt": true } ] }, @@ -3373,6 +4583,11 @@ { "stat": "twister_%_chance_for_additional_twister", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_projectile_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3395,6 +4610,11 @@ { "stat": "minion_movement_speed_+%", "per_quality_rate": 2.5 + }, + { + "stat": "active_skill_minion_attack_speed_+%_final", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3431,6 +4651,11 @@ { "stat": "broken_stance_hit_limit", "per_quality_rate": 0.1 + }, + { + "stat": "active_skill_damage_+%_final_against_heavy_stunned_enemies", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3449,6 +4674,11 @@ { "stat": "poison_vine_arrow_vine_stored_poison_damage_+%_final", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_quality_duration_+%_final", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -3498,6 +4728,11 @@ { "stat": "slam_aftershock_chance_%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_fire_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3507,6 +4742,11 @@ { "stat": "active_skill_base_area_of_effect_radius", "per_quality_rate": 0.1 + }, + { + "stat": "active_skill_quality_duration_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3525,6 +4765,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.0 + }, + { + "stat": "number_of_chains", + "per_quality_rate": 0.1, + "alt": true } ] }, @@ -3534,6 +4779,11 @@ { "stat": "thaumaturgist_mark_hit_damage_electrocute_multiplier_+%", "per_quality_rate": 1.0 + }, + { + "stat": "base_mana_cost_-%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3543,6 +4793,11 @@ { "stat": "curse_effect_+%", "per_quality_rate": 0.5 + }, + { + "stat": "base_mana_cost_-%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3552,6 +4807,11 @@ { "stat": "walking_calamity_non_skill_base_all_damage_%_to_gain_as_fire", "per_quality_rate": 0.5 + }, + { + "stat": "chance_to_not_consume_glory_%", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3561,6 +4821,11 @@ { "stat": "base_reservation_efficiency_+%", "per_quality_rate": 0.5 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.5, + "alt": true } ] }, @@ -3570,6 +4835,11 @@ { "stat": "wardbound_minion_maximum_number_of_casts", "per_quality_rate": 0.1 + }, + { + "stat": "base_skill_effect_duration", + "per_quality_rate": 250.0, + "alt": true } ] }, @@ -3588,6 +4858,11 @@ { "stat": "base_reduce_enemy_cold_resistance_%", "per_quality_rate": 1.0 + }, + { + "stat": "frozen_monsters_take_increased_damage", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -3606,6 +4881,11 @@ { "stat": "attack_speed_+%", "per_quality_rate": 1.0 + }, + { + "stat": "active_skill_physical_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3615,6 +4895,11 @@ { "stat": "sandstorm_swipe_storm_damage_+%_final_per_stage", "per_quality_rate": 2.0 + }, + { + "stat": "active_skill_attack_speed_+%_final", + "per_quality_rate": 0.5, + "alt": true } ] }, @@ -3624,6 +4909,11 @@ { "stat": "sandstorm_swipe_storm_damage_+%_final_per_stage", "per_quality_rate": 2.0 + }, + { + "stat": "windstorm_gain_all_damage_%_as_corresponding_element_if_empowered", + "per_quality_rate": 2.5, + "alt": true } ] }, @@ -3646,6 +4936,11 @@ { "stat": "active_skill_knockback_distance_+%_final", "per_quality_rate": 1.5 + }, + { + "stat": "active_skill_base_all_damage_%_to_gain_as_chaos", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3655,6 +4950,11 @@ { "stat": "wing_blast_chance_to_gain_power_charge_on_stun_%", "per_quality_rate": 0.25 + }, + { + "stat": "active_skill_physical_damage_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3664,6 +4964,11 @@ { "stat": "base_skill_effect_duration", "per_quality_rate": 50.0 + }, + { + "stat": "skill_withering_presence_frequency_ms", + "per_quality_rate": -25.0, + "alt": true } ] }, @@ -3673,6 +4978,11 @@ { "stat": "wolf_warcry_buff_freeze_buildup_+%", "per_quality_rate": 1.0 + }, + { + "stat": "chance_for_exerted_attacks_to_not_reduce_count_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3682,6 +4992,11 @@ { "stat": "active_skill_base_secondary_area_of_effect_radius", "per_quality_rate": 0.2 + }, + { + "stat": "active_skill_base_physical_damage_%_to_convert_to_cold", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -3691,6 +5006,11 @@ { "stat": "wolf_lunar_blessing_all_damage_%_to_gain_as_cold_damage", "per_quality_rate": 0.5 + }, + { + "stat": "base_cooldown_speed_+%", + "per_quality_rate": 2.0, + "alt": true } ] }, @@ -3700,6 +5020,11 @@ { "stat": "skill_wolf_pack_size", "per_quality_rate": 0.05 + }, + { + "stat": "active_skill_minion_attack_speed_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3722,6 +5047,11 @@ { "stat": "dummy_stat_display_nothing", "per_quality_rate": 0.001 + }, + { + "stat": "number_of_wolves_allowed", + "per_quality_rate": 0.2, + "alt": true } ] }, @@ -3740,6 +5070,11 @@ { "stat": "wyvern_devour_flask_charm_charge_gain_chance_%", "per_quality_rate": 2.5 + }, + { + "stat": "chance_to_gain_1_more_charge_%", + "per_quality_rate": 1.0, + "alt": true } ] }, @@ -3749,6 +5084,11 @@ { "stat": "channelled_skill_suppress_ongoing_rage_cost_for_first_X_ms", "per_quality_rate": 50.0 + }, + { + "stat": "active_skill_area_of_effect_+%_final", + "per_quality_rate": 1.0, + "alt": true } ] }, diff --git a/data/4.5.4.3/overlay/high_precision_mods.json b/data/4.5.4.3/overlay/high_precision_mods.json deleted file mode 100644 index e4e9aa78..00000000 --- a/data/4.5.4.3/overlay/high_precision_mods.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "_meta": { - "schema": "high_precision_mods/v1", - "generator": "manual transcription (M0-W4d)", - "vendor": "PathOfBuilding-PoE2", - "vendor_commit": "2df5a7433dd2f1609e2fad8a6c3c917f923fe34f", - "source": [ - "src/Modules/Data.lua:413 (defaultHighPrecision)", - "src/Modules/Data.lua:415-530 (highPrecisionMods, 38 entries)", - "src/Classes/ModList.lua:144 (MoreInternal default round(modResult, 2))" - ], - "notes": "pobr 现状无 ScaleAddMod/MORE 精度例外消费方(audits/rearchitecture-2026-06-10/10-mod-system.md Gap 6),本表先落库零接线、零 parity 影响;more_default_round_decimals 的 pobr 准源为 pobr-core::mod_db::round_more 固定 2 位", - "audit": "版本 bump 对账(F4,drill 无自动重放通道):人工转录域——对照 vendor src/Modules/Data.lua 的 defaultHighPrecision / highPrecisionMods(38 条)与 src/Classes/ModList.lua MoreInternal 默认取整逐条复核,复核后更新 vendor_commit 与 source 行号并在 commit message 注明逐条核对结论;待 ScaleAddMod / MORE 精度例外分支落地后改走自动对账命令" - }, - "default_high_precision": 1, - "more_default_round_decimals": 2, - "mods": { - "ChaosDamageEnergyShieldLeech": { "BASE": 2 }, - "ChaosDamageLifeLeech": { "BASE": 2 }, - "ChaosDamageManaLeech": { "BASE": 2 }, - "ColdDamageEnergyShieldLeech": { "BASE": 2 }, - "ColdDamageLifeLeech": { "BASE": 2 }, - "ColdDamageManaLeech": { "BASE": 2 }, - "CritChance": { "BASE": 2 }, - "DamageEnergyShieldLeech": { "BASE": 2 }, - "DamageLifeLeech": { "BASE": 2 }, - "DamageManaLeech": { "BASE": 2 }, - "ElementalDamageEnergyShieldLeech": { "BASE": 2 }, - "ElementalDamageLifeLeech": { "BASE": 2 }, - "ElementalDamageManaLeech": { "BASE": 2 }, - "EnergyShieldDegen": { "BASE": 1 }, - "EnergyShieldDegenPercent": { "BASE": 2 }, - "EnergyShieldRegen": { "BASE": 1 }, - "EnergyShieldRegenPercent": { "BASE": 2 }, - "FireDamageEnergyShieldLeech": { "BASE": 2 }, - "FireDamageLifeLeech": { "BASE": 2 }, - "FireDamageManaLeech": { "BASE": 2 }, - "LifeDegen": { "BASE": 1 }, - "LifeDegenPercent": { "BASE": 2 }, - "LifeRegen": { "BASE": 1 }, - "LifeRegenPercent": { "BASE": 2 }, - "LightningDamageEnergyShieldLeech": { "BASE": 2 }, - "LightningDamageLifeLeech": { "BASE": 2 }, - "LightningDamageManaLeech": { "BASE": 2 }, - "ManaDegen": { "BASE": 1 }, - "ManaDegenPercent": { "BASE": 2 }, - "ManaRegen": { "BASE": 1 }, - "ManaRegenPercent": { "BASE": 2 }, - "PhysicalDamageEnergyShieldLeech": { "BASE": 2 }, - "PhysicalDamageLifeLeech": { "BASE": 2 }, - "PhysicalDamageManaLeech": { "BASE": 2 }, - "RageRegen": { "BASE": 1 }, - "ReservationMultiplier": { "MORE": 4 }, - "SelfCritChance": { "BASE": 2 }, - "SupportManaMultiplier": { "MORE": 4 } - } -} diff --git a/data/4.5.4.3/overlay/local_mods.json b/data/4.5.4.3/overlay/local_mods.json deleted file mode 100644 index a3dd14ac..00000000 --- a/data/4.5.4.3/overlay/local_mods.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "_meta": { - "schema": "local_mods/v1", - "generator": "manual transcription (M0-W4d)", - "vendor": "PathOfBuilding-PoE2", - "vendor_commit": "2df5a7433dd2f1609e2fad8a6c3c917f923fe34f", - "source": [ - "pobr 准源:crates/pobr-build/src/calc_orchestrator.rs::is_weapon_local_mod(搬迁不变式,逐值一致)", - "vendor 对照:src/Classes/Item.lua:1655-1682 calcLocal(结构化规则非文本枚举,差异仅记录不改值,见 audits/rearchitecture-2026-06-10/16-items.md)" - ], - "notes": "条目为 clean_item_text 产物口径(剥 {...} 标记 + trim + 小写);增删条目=行为变更,须独立 commit 并附 PoB2 依据", - "audit": "版本 bump 对账(F4,drill 无自动重放通道):人工转录域——条目须与 pobr 准源 crates/pobr-build/src/calc_orchestrator.rs::is_weapon_local_mod 逐值一致(搬迁不变式);vendor 升级时对照 src/Classes/Item.lua calcLocal 规则,差异仅记录不改值,复核后更新 vendor_commit 与 source 行号" - }, - "weapon": { - "increased_suffixes": [ - "% increased physical damage", - "% increased attack speed" - ], - "adds_damage_suffixes": [ - "physical damage" - ] - } -} diff --git a/data/4.5.4.3/overlay/mod_parser_rules.json b/data/4.5.4.3/overlay/mod_parser_rules.json index 85897fc2..02f8700a 100644 --- a/data/4.5.4.3/overlay/mod_parser_rules.json +++ b/data/4.5.4.3/overlay/mod_parser_rules.json @@ -3,8 +3,8 @@ "schema": "mod_parser_rules/v1", "generator": "sync-pob-catalog extract-lua", "vendor": "PathOfBuilding-PoE2", - "vendor_commit": "29ab8262dd4a867eac56165afb8391a509e34a0e", - "vendor_commit_subject": "29ab826 Add support for Darkness Enthroned and Atziri's Splendour augment mods (#2343)", + "vendor_commit": "ce8bffaba31f8e68cfce70579e1c96465e7c133c", + "vendor_commit_subject": "ce8bffaba31f8e68cfce70579e1c96465e7c133c", "extracted_files": [ "Modules/ModParser.lua" ], @@ -5069,7 +5069,9 @@ { "phrase": "skill speed", "names": [ - "SkillSpeed" + "SkillSpeed", + "WarcrySpeed", + "TotemPlacementSpeed" ] }, { @@ -6212,6 +6214,15 @@ "Curse" ] }, + { + "phrase": "for grenade skills", + "tags": [ + { + "type": "SkillType", + "skill_type": "Grenade" + } + ] + }, { "phrase": "for hexes", "tags": [ @@ -6429,8 +6440,8 @@ "phrase": "grenade", "tags": [ { - "type": "SkillName", - "skillName": "Grenade" + "type": "SkillType", + "skill_type": "Grenade" } ] }, diff --git a/data/4.5.4.3/overlay/special_mods.json b/data/4.5.4.3/overlay/special_mods.json index 09d9f6fc..69cc931d 100644 --- a/data/4.5.4.3/overlay/special_mods.json +++ b/data/4.5.4.3/overlay/special_mods.json @@ -12,2944 +12,291 @@ }, "entries": [ { - "id": "all_damage_is_taken_from_mana_before_life", - "pattern": "all damage is taken from mana before life", - "vendor_pattern": "all damage is taken from mana before life", - "mods": [ - { - "name": "DamageTakenFromManaBeforeLife", - "type": "BASE", - "value": 100 - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2389(探针求值自动转写;样本:All Damage is taken from Mana before Life)" - }, - { - "id": "allocates_passive", - "pattern": "allocates (.+)", - "vendor_pattern": "allocates (.+)", + "id": "mageblood_legacy", + "pattern": "legacy of (\\w+)", + "vendor_pattern": "legacy of (%w+)", "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5809(油涂/anoint 附魔 → GrantedPassive LIST 名;pobr 准源 legacy.rs:1067。开放捕获 (.+) 走模板直引——条件形『if you have the matching modifier on forbidden Y』未建模,本表保守不排除,corpus 无该形)", - "handler_id": "special:granted_passive", + "batch": "S3", + "source_note": "ModParser.lua:5554-5557(Mageblood 腰带变体行 → LegacyOf BASE 1 + MagebloodEquipped FLAG;捕获驱动的动态 mod 名走 handler,聚合应用见 calc/mageblood.rs)", + "handler_id": "special:mageblood_legacy", "handler_args": [ "$1" ] }, { - "id": "base_critical_hit_chance_for_spells_is", - "pattern": "base critical hit chance for spells is (\\d+)%", - "vendor_pattern": "base critical hit chance for spells is (%d+)%%", + "id": "immune_to_ignite", + "pattern": "immun[ei]t?y? to ignite", + "vendor_pattern": "immun[ei]t?y? to ignite", "mods": [ { - "name": "CritChanceBase", - "type": "OVERRIDE", - "value": "$1", - "tags": [ - { - "type": "SkillType", - "skillType": "SkillType:Spell" - } - ] + "name": "IgniteImmune", + "type": "FLAG", + "value": true } ], "verified": false, "batch": "S2", - "source_note": "ModParser.lua:5801(探针求值自动转写;样本:Base Critical Hit Chance for Spells is 15%)" + "source_note": "ModParser.lua:5172 flag(IgniteImmune);charm『Immune to Ignite』词条走此行" }, { - "id": "bow_attacks_fire_an_additional_arrow", - "pattern": "bow attacks fire an additional arrow", - "vendor_pattern": "bow attacks fire an additional arrow", + "id": "immune_to_freeze", + "pattern": "immun[ei]t?y? to freeze", + "vendor_pattern": "immun[ei]t?y? to freeze", "mods": [ { - "name": "ProjectileCount", - "type": "BASE", - "value": 1, - "keyword_flags": [ - "Arrow" - ] + "name": "FreezeImmune", + "type": "FLAG", + "value": true } ], "verified": false, "batch": "S2", - "source_note": "ModParser.lua:4795(探针求值自动转写;样本:Bow Attacks fire an additional Arrow)" + "source_note": "ModParser.lua:5168 flag(FreezeImmune);Thawing Charm『Immune to Freeze』词条走此行" }, { - "id": "break_increased_armour", - "pattern": "break (\\d+)% increased armour", - "vendor_pattern": "break (%d+)%% increased armour", + "id": "recover_mana_when_used", + "pattern": "recovers? (\\d+) mana when used", + "vendor_pattern": null, "mods": [ { - "name": "ArmourBreakPerHit", - "type": "INC", + "name": "ManaOnFlaskUse", + "type": "BASE", "value": "$1" } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4258(探针求值自动转写;样本:Break 10% increased Armour)" - }, - { - "id": "buffs_on_you_expire_slower", - "pattern": "buffs on you expire (\\d+)% slower", - "vendor_pattern": "buffs on you expire (%d+)%% slower", - "mods": [ - { - "name": "Duration", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "SkillType", - "skillType": "SkillType:Buff" - } - ] - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4532(探针求值自动转写;样本:Buffs on you expire 10% slower)" - }, - { - "id": "cannot_be_blinded_while_on_full_life", - "pattern": "cannot be blinded while on full life", - "vendor_pattern": "cannot be blinded while on full life", - "mods": [ - { - "name": "Condition:CannotBeBlinded", - "type": "FLAG", - "value": true, - "tags": [ - { - "type": "Condition", - "var": "FullLife" - } - ] - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5123(探针求值自动转写;样本:Cannot be Blinded while on Full Life)" + "batch": "S0", + "source_note": "药剂/护符使用时瞬时回魔:解析为 ManaOnFlaskUse BASE(归因/Calcs 可见;稳态面板无消费——瞬时恢复不属于稳态模型,flask 恢复面板落地时接线)。vendor 走 flaskData 本地系统不产 mod" }, { - "id": "cannot_be_heavy_stunned_while_sprinting", - "pattern": "cannot be heavy stunned while sprinting", - "vendor_pattern": "cannot be heavy stunned while sprinting", + "id": "flask_mana_recovery_overflow", + "pattern": "mana recovery from flasks can overflow maximum mana( during effect)?", + "vendor_pattern": null, "mods": [ { - "name": "StunImmune", + "name": "FlaskManaRecoveryOverflow", "type": "FLAG", - "value": true, - "tags": [ - { - "type": "Condition", - "var": "Sprinting" - } - ] + "value": true } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3205(探针求值自动转写;样本:Cannot be Heavy Stunned while Sprinting)" + "batch": "S0", + "source_note": "Melting Maelstrom:效果期间药剂魔力恢复可溢出上限 → FLAG 进 ModDb(归因可见;溢出魔力稳态无消费者,vendor 亦未建模)" }, { - "id": "cannot_be_ignited", - "pattern": "cannot be ignited", - "vendor_pattern": "cannot be ignited", + "id": "possessed_by_spirit_on_use", + "pattern": "possessed by [a-z' ]+ for (\\d+) seconds on use", + "vendor_pattern": null, "mods": [ { - "name": "IgniteImmune", + "name": "SpiritPossessionOnUse", "type": "FLAG", "value": true } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5131(探针求值自动转写;样本:Cannot be Ignited)" + "batch": "S0", + "source_note": "金护符阿兹莫里之灵附身(Stag/Wolf/Bear…):玩家侧 buff 数值无可验证一手来源(poe2db/wiki 仅载敌方附身效果,BuffDefinitions 未入库)→ 暂解析为 FLAG 登记,数据可得后升级 handler 接具体 buff" }, { - "id": "cannot_immobilise_enemies", - "pattern": "cannot immobilise enemies", - "vendor_pattern": "cannot immobilise enemies", + "id": "armour_applies_to_fcl_instead_of_physical", + "pattern": "armour applies to fire, cold and lightning damage taken from hits instead of physical damage", + "vendor_pattern": "armour applies to fire, cold and lightning damage taken from hits instead of physical damage", "mods": [ { - "name": "CannotElectrocute", - "type": "FLAG", - "value": true + "name": "ArmourAppliesToFireDamageTaken", + "type": "BASE", + "value": 100 }, { - "name": "CannotFreeze", - "type": "FLAG", - "value": true + "name": "ArmourAppliesToColdDamageTaken", + "type": "BASE", + "value": 100 }, { - "name": "CannotHeavyStun", - "type": "FLAG", - "value": true + "name": "ArmourAppliesToLightningDamageTaken", + "type": "BASE", + "value": 100 }, { - "name": "CannotPin", + "name": "ArmourDoesNotApplyToPhysicalDamageTaken", "type": "FLAG", "value": true } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5735(探针求值自动转写;样本:Cannot Immobilise enemies)" + "batch": "wave2-defence", + "source_note": "ModParser.lua:2545-2550(三元素 ArmourAppliesToDamageTaken BASE 100 + instead 变体专属 flag)。消费端 taken.rs armour_applies_pct(flag 时物理份额归 0)。legacy-only 测试掩盖的 engine 缺口(原 mod_parser_m2_defence.rs:182)" }, { - "id": "cannot_regenerate_mana_if_you_haven_t_dealt_a_critical_hit_recently", - "pattern": "cannot regenerate mana if you haven't dealt a critical hit recently", - "vendor_pattern": "cannot regenerate mana if you haven't dealt a critical hit recently", + "id": "pct_of_armour_applies_to_fcl", + "pattern": "(\\d+)% of armour applies to fire, cold and lightning damage taken from hits", + "vendor_pattern": "(%d+)%% of armour applies to fire, cold and lightning damage taken from hits", "mods": [ { - "name": "NoManaRegen", - "type": "FLAG", - "value": true, - "tags": [ - { - "type": "Condition", - "neg": true, - "var": "CritRecently" - } - ] - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5028(探针求值自动转写;样本:Cannot Regenerate Mana if you haven't dealt a Critical Hit Recently)" - }, - { - "id": "chance_for_damage_with_hits_to_be_lucky", - "pattern": "(\\d+)% chance for () ?damage with hits to be lucky", - "vendor_pattern": "(%d+)%% chance for (%w*) ?damage with hits to be lucky", - "mods": [ + "name": "ArmourAppliesToFireDamageTaken", + "type": "BASE", + "value": "$1" + }, { - "name": "LuckyHitsChance", + "name": "ArmourAppliesToColdDamageTaken", "type": "BASE", "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4255(探针求值自动转写;样本:20% chance for Damage with Hits to be Lucky)" - }, - { - "id": "charm_slots_colon", - "pattern": "charm slots: (\\d+)", - "vendor_pattern": "h?a?s? ?+?(%d+) charm slots?", - "mods": [ + }, { - "name": "CharmLimit", + "name": "ArmourAppliesToLightningDamageTaken", "type": "BASE", "value": "$1" } ], "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:5453(CharmLimit;冒号格式 'Charm Slots: N',与 has_charm_slots 互补,命中 18 build 首位缺口)" + "batch": "wave2-defence", + "source_note": "ModParser.lua:2551-2555(function(num)→三元素 BASE num)。消费端 taken.rs armour_applies_pct。原 mod_parser_m2_defence.rs:192" }, { - "id": "ci_maximum_life_is_1", - "pattern": "maximum life is 1", + "id": "armour_applies_to_elemental_damage", + "pattern": "armour applies to elemental damage", + "vendor_pattern": "armour applies to elemental damage", "mods": [ { - "name": "MaximumLife", - "type": "OVERRIDE", - "value": 1.0 + "name": "ArmourAppliesToFireDamageTaken", + "type": "BASE", + "value": 100 + }, + { + "name": "ArmourAppliesToColdDamageTaken", + "type": "BASE", + "value": 100 }, { - "name": "ChaosInoculation", - "type": "FLAG", - "value": true + "name": "ArmourAppliesToLightningDamageTaken", + "type": "BASE", + "value": 100 } ], "verified": false, - "batch": "S0", - "source_note": "Chaos Inoculation(PoE2 树文本);pobr 准源 mod_parser.rs:524-528;vendor 近似 key = 'maximum life becomes 1, immune to chaos damage'(:2354,另含 ChaosDamageTaken MORE -100——pobr 暂未消费,B-3 升级时对齐)" + "batch": "wave2-defence", + "source_note": "ModParser.lua:2556-2560(三元素 BASE 100,无 instead flag)。原 mod_parser_m2_defence.rs:201" }, { - "id": "convert_pct_max_es_to_mana", - "pattern": "convert (\\d+(?:\\.\\d+)?)% of maximum energy shield to maximum mana", - "vendor_pattern": "convert (%d+)%% of maximum energy shield to maximum mana", + "id": "pct_of_armour_applies_to_elemental_damage", + "pattern": "\\+?(\\d+)% of armour (?:also )?applies to elemental damage", + "vendor_pattern": "%+?(%d+)%% of armour (a?l?s?o? ?)applies to elemental damage", "mods": [ { - "name": "EnergyShieldConvertToMana", + "name": "ArmourAppliesToFireDamageTaken", "type": "BASE", "value": "$1" - } - ], - "verified": false, - "batch": "S0", - "source_note": "pobr 准源 mod_parser.rs:508-522;vendor ModParser.lua:2396 同形" - }, - { - "id": "converts_all_energy_shield_to_mana", - "pattern": "converts all energy shield to mana", - "vendor_pattern": "converts all energy shield to mana", - "mods": [ + }, { - "name": "EnergyShieldConvertToMana", + "name": "ArmourAppliesToColdDamageTaken", "type": "BASE", - "value": 100.0 - } - ], - "verified": false, - "batch": "S0", - "source_note": "Eldritch Battery 型;pobr 准源 mod_parser.rs:533-538;vendor ModParser.lua:2395" - }, - { - "id": "critical_hits_ignore_non_negative_enemy_monster_elemental_resistances", - "pattern": "critical hits ignore non-negative enemy monster elemental resistances", - "vendor_pattern": "critical hits ignore non%-negative enemy monster elemental resistances", - "mods": [ + "value": "$1" + }, { - "name": "IgnoreNonNegativeEleRes", - "type": "FLAG", - "value": true, - "tags": [ - { - "type": "Condition", - "var": "CriticalStrike" - } - ] + "name": "ArmourAppliesToLightningDamageTaken", + "type": "BASE", + "value": "$1" } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3372(探针求值自动转写;样本:Critical Hits ignore non-negative Enemy Monster Elemental Resistances)" + "batch": "wave2-defence", + "source_note": "ModParser.lua:2561-2565(function(num)→三元素 BASE num;vendor 第二捕获 also 为可选填充词,此处转非捕获组保持 $1 语义)" }, { - "id": "cursed_enemies_killed_by_you_or_by_allies_in_your_presence_have_a_chan", - "pattern": "cursed enemies killed by you, or by allies in your presence, have a (\\d+)% chance to explode, dealing a (quarter) of their maximum life as (chaos) damage", - "vendor_pattern": "cursed enemies killed by you, or by allies in your presence, have a (%d+)%% chance to explode, dealing a (.+) of their maximum life as (.+) damage", + "id": "energy_shield_protects_mana_instead_of_life", + "pattern": "energy shield protects mana instead of life", + "vendor_pattern": "energy shield protects mana instead of life", "mods": [ { - "name": "ExplodeMod", - "type": "LIST", - "value": { - "amount": 25, - "keyOfScaledMod": "value", - "type": "Chaos", - "value": "$1" - }, - "tags": [ - { - "type": "ActorCondition", - "actor": "enemy", - "var": "Cursed" - } - ] - }, - { - "name": "CanExplode", + "name": "EnergyShieldProtectsMana", "type": "FLAG", "value": true } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2260(探针求值自动转写;样本:Cursed Enemies killed by you, or by Allies in your Presence, have a 33% chance to explode, dealing a quarter of their maximum Life as Chaos damage)" + "batch": "wave2-defence", + "source_note": "ModParser.lua:2465(Eldritch Battery 类)。消费端 keystone_registry.rs DefenceKeystones.energy_shield_protects_mana → pool_damage.rs/ehp.rs/defence.rs。原 mod_parser_m2_defence.rs:99" }, { - "id": "curses_you_inflict_ignore_curse_limit", - "pattern": "curses you inflict ignore curse limit", - "vendor_pattern": "curses you inflict ignore curse limit", + "id": "converts_all_evasion_rating_to_armour", + "pattern": "converts all evasion rating to armour", + "vendor_pattern": "converts all evasion rating to armour", "mods": [ { - "name": "EnemyCurseLimit", - "type": "BASE", - "value": 99 - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4275(探针求值自动转写;样本:Curses you inflict ignore Curse limit)" - }, - { - "id": "defend_with_pct_of_armour", - "pattern": "defend with (\\d+(?:\\.\\d+)?)% of armour(?: during effect)?", - "vendor_pattern": "defend with (%d+)%% of armour", - "mods": [ + "name": "IronReflexes", + "type": "FLAG", + "value": true + }, { - "name": "ArmourDefense", + "name": "EvasionConvertToArmour", "type": "BASE", - "value": { - "ref": "$1", - "ops": [ - { - "base": -100.0 - } - ] - } + "value": 100 } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2616/:2619(Defend with N% of Armour [during effect] → ArmourDefense BASE N-100;pobr 准源 legacy.rs:1715。during effect 变体同无条件,消费侧 max_of)" + "batch": "wave2-defence", + "source_note": "ModParser.lua:2369(Iron Reflexes 类:flag + EvasionConvertToArmour BASE 100)。消费端 defence.rs calc_defence_resources 五元 ConvertTo 矩阵 + keystone_registry.rs iron_reflexes(Unbreakable 联动)。原 mod_parser_m2_defence.rs:265" }, { - "id": "double_activation_delay_of_curses", - "pattern": "double activation delay of curses", - "vendor_pattern": "double activation delay of curses", + "id": "chance_to_deflect_is_lucky", + "pattern": "chance to deflect is lucky", + "vendor_pattern": "chance to deflect is lucky", "mods": [ { - "name": "CurseDelay", - "type": "MORE", - "value": 100 + "name": "DeflectIsLucky", + "type": "FLAG", + "value": true } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4278(探针求值自动转写;样本:Double Activation Delay of Curses)" + "batch": "wave2-defence", + "source_note": "ModParser.lua:4202。消费端 defence_panels.rs:298 偏斜几率 lucky 幂(1−(1−p)²)。原 mod_parser_m2_defence.rs:397" }, { - "id": "empowered_attacks_deal_increased_damage", - "pattern": "empowered attacks deal (\\d+)% increased damage", - "vendor_pattern": "empowered attacks deal (%d+)%% increased damage", + "id": "chance_to_block_damage_is_lucky", + "pattern": "chance to block damage is lucky", + "vendor_pattern": "chance to block damage is lucky", "mods": [ { - "name": "Damage", - "type": "INC", - "value": "$1", - "flags": [ - "Attack" - ], - "tags": [ - { - "type": "Condition", - "var": "Empowered" - } - ] + "name": "BlockChanceIsLucky", + "type": "FLAG", + "value": true } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2647(Empowered Attacks deal N% increased Damage;vendor 产 EmpoweredIncrease INC,pobr legacy.rs:367 产 Damage INC flags=Attack + Condition:Empowered——双跑收敛以 legacy 为基准。Empowered 默认不激活)" + "batch": "wave2-defence", + "source_note": "ModParser.lua:4371。消费端 defence_panels.rs:174 effective(BlockChance) luck_transform" }, { - "id": "enemies_you_kill_with_empowered_attacks_have_a_chance_to_explode_deali", - "pattern": "enemies you kill with empowered attacks have a (\\d+)% chance to explode, dealing a (tenth) of their maximum life as (fire) damage", - "vendor_pattern": "enemies you kill with empowered attacks have a (%d+)%% chance to explode, dealing a (.+) of their maximum life as (.+) damage", + "id": "chance_to_block_is_lucky", + "pattern": "(?:your )?chance to block is lucky", + "vendor_pattern": "y?o?u?r? ?chance to block is lucky", "mods": [ { - "name": "ExplodeMod", - "type": "LIST", - "value": { - "amount": 10, - "keyOfScaledMod": "value", - "type": "Fire", - "value": "$1" - } + "name": "BlockChanceIsLucky", + "type": "FLAG", + "value": true }, { - "name": "CanExplode", + "name": "ProjectileBlockChanceIsLucky", "type": "FLAG", "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2242(探针求值自动转写;样本:Enemies you kill with Empowered Attacks have a 10% chance to Explode, dealing a tenth of their maximum Life as Fire Damage)" - }, - { - "id": "enemy_critical_hit_chance_against_you_is_unlucky", - "pattern": "enemy critical hit chance against you is unlucky", - "vendor_pattern": "enemy critical hit chance against you is unlucky", - "mods": [ + }, { - "name": "EnemyUnluckyCrit", + "name": "SpellBlockChanceIsLucky", "type": "FLAG", "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3740(探针求值自动转写;样本:Enemy Critical Hit Chance against you is Unlucky)" - }, - { - "id": "energy_shield_does_not_recharge", - "pattern": "energy shield does not recharge", - "vendor_pattern": "energy shield does not recharge", - "mods": [ + }, { - "name": "NoEnergyShieldRecharge", + "name": "SpellProjectileBlockChanceIsLucky", "type": "FLAG", "value": true } ], "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5030(探针求值自动转写;样本:Energy Shield does not Recharge)" - }, - { - "id": "equipment_and_skill_gems_have_reduced_attribute_requirements", - "pattern": "equipment and skill gems have (\\d+)% reduced attribute requirements", - "vendor_pattern": "equipment and skill gems have (%d+)%% reduced attribute requirements", - "mods": [ - { - "name": "GlobalAttributeRequirements", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5610(探针求值自动转写;样本:Equipment and Skill Gems have 4% reduced Attribute Requirements)" - }, - { - "id": "exposure_you_inflict_lowers_resistances_by_an_additional", - "pattern": "exposure you inflict lowers resistances by an additional (5)%", - "vendor_pattern": "exposure you inflict lowers resistances by an additional (%-?%d+)%%", - "mods": [ - { - "name": "ExtraExposure", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2917(探针求值自动转写;样本:Exposure you inflict lowers Resistances by an additional 5%)" - }, - { - "id": "flasks_gain_charges_per_second", - "pattern": "flasks gain (0\\.17) charges? per second", - "vendor_pattern": "flasks gain (%d*%.?%d+) charges? per second", - "mods": [ - { - "name": "FlaskChargesGenerated", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5441(探针求值自动转写;样本:Flasks gain 0.17 charges per Second)" - }, - { - "id": "gain_deflection_rating_equal_to_of_armour", - "pattern": "gain deflection rating equal to (\\d+)% of armour", - "vendor_pattern": "gain deflection rating equal to (%d+)%% of armour", - "mods": [ - { - "name": "ArmourGainAsDeflection", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4159(探针求值自动转写;样本:Gain Deflection Rating equal to 20% of Armour)" - }, - { - "id": "gain_deflection_rating_equal_to_of_evasion_rating", - "pattern": "gain deflection rating equal to (\\d+)% of evasion rating", - "vendor_pattern": "gain deflection rating equal to (%d+)%% of evasion rating", - "mods": [ - { - "name": "EvasionGainAsDeflection", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:4158(探针求值自动转写;样本:Gain Deflection Rating equal to 21% of Evasion Rating)" - }, - { - "id": "gain_mana_per_enemy_killed", - "pattern": "gain (\\d+) mana per enemy killed", - "vendor_pattern": "(%d+) mana per enemy killed", - "mods": [ - { - "name": "ManaOnKill", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:543(mana per enemy killed→ManaOnKill BASE)" - }, - { - "id": "gain_pct_damage_as_extra_all_elements", - "pattern": "gain (\\d+(?:\\.\\d+)?)% of damage as extra damage of all elements", - "vendor_pattern": "gain (%d+)%% of damage as extra damage of all elements", - "mods": [ - { - "name": "DamageGainAsFire", - "type": "BASE", - "value": "$1" - }, - { - "name": "DamageGainAsCold", - "type": "BASE", - "value": "$1" - }, - { - "name": "DamageGainAsLightning", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2244 等(Gain N% of Damage as Extra Damage of all Elements → DamageGainAs{Fire,Cold,Lightning} BASE N,三系展开;pobr 准源 legacy gain-as 通道)" - }, - { - "id": "gain_rage_on_melee_hit", - "pattern": "gain \\d+ rage on melee hit", - "vendor_pattern": "gain %d+ rage on melee hit", - "mods": [ - { - "name": "Condition:CanGainRage", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:2761(探针求值自动转写;样本:Gain 1 Rage on Melee Hit)" - }, - { - "id": "grants_passive_skill_point", - "pattern": "grants (\\d+) passive skill points?", - "vendor_pattern": "grants (%d+) passive skill points?", - "mods": [ - { - "name": "ExtraPoints", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:2727(探针求值自动转写;样本:Grants 1 Passive Skill Point)" - }, - { - "id": "grenade_skills_fire_an_additional_projectile", - "pattern": "grenade skills fire an additional projectile", - "vendor_pattern": "grenade skills fire an additional projectile", - "mods": [ - { - "name": "ProjectileCount", - "type": "BASE", - "value": 1, - "flags": [ - "Projectile" - ], - "tags": [ - { - "type": "SkillType", - "skillType": "SkillType:Grenade" - } - ] - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:4803(探针求值自动转写;样本:Grenade Skills Fire an additional Projectile)" - }, - { - "id": "grenades_have_chance_to_activate_a_second_time", - "pattern": "grenades have (\\d+)% chance to activate a second time", - "vendor_pattern": "grenades have (%d+)%% chance to activate a second time", - "mods": [ - { - "name": "GrenadeActivateTwice", - "type": "BASE", - "value": "$1", - "tags": [ - { - "type": "SkillType", - "skillType": "SkillType:Grenade" - } - ] - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4804(探针求值自动转写;样本:Grenades have 15% chance to activate a second time)" - }, - { - "id": "has_charm_slots", - "pattern": "h?a?s? ?\\+?(\\d+) charm slots?", - "vendor_pattern": "h?a?s? ?+?(%d+) charm slots?", - "mods": [ - { - "name": "CharmLimit", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:5453(探针求值自动转写;样本:Has 3 Charm Slots)" - }, - { - "id": "has_no_attribute_requirements", - "pattern": "has no attribute requirements", - "vendor_pattern": "has no attribute requirements", - "mods": [ - { - "name": "NoAttributeRequirements", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3464(探针求值自动转写;样本:Has no Attribute Requirements)" - }, - { - "id": "has_to_defence_per_player_level", - "pattern": "has \\+(\\d+) to (armour|evasion|evasion rating|energy shield|maximum energy shield) per player level", - "vendor_pattern": "has %+(%d+) to (.+) per player level", - "mods": [ - { - "name": { - "enum": 2 - }, - "type": "BASE", - "value": "$1" - } - ], - "enums": { - "2": { - "armour": "ArmourPerLevel", - "evasion": "EvasionPerLevel", - "evasion rating": "EvasionPerLevel", - "energy shield": "EnergyShieldPerLevel", - "maximum energy shield": "EnergyShieldPerLevel" - } - }, - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3400-3402(Has +N to per player level → PerLevel BASE,件级局部底值;pobr 准源 legacy.rs:640)" - }, - { - "id": "has_to_maximum_runic_ward_per_player_level", - "pattern": "has ([+-]\\d+) to maximum runic ward per player level", - "vendor_pattern": "has ([%+%-]%d+) to maximum runic ward per player level", - "mods": [ - { - "name": "WardPerLevel", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3402(探针求值自动转写;样本:Has +1 to maximum Runic Ward per player level)" - }, - { - "id": "hits_have_reduced_critical_hit_chance_against_you", - "pattern": "hits have (\\d+)% reduced critical hit chance against you", - "vendor_pattern": "hits have (%d+)%% reduced critical hit chance against you", - "mods": [ - { - "name": "EnemyCritChance", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3771(探针求值自动转写;样本:Hits have 25% reduced Critical Hit Chance against you)" - }, - { - "id": "hits_ignore_non_negative_elemental_resistances_of_frozen_enemies", - "pattern": "hits ignore non-negative elemental resistances of frozen enemies", - "vendor_pattern": "hits ignore non%-negative elemental resistances of frozen enemies", - "mods": [ - { - "name": "IgnoreNonNegativeEleRes", - "type": "FLAG", - "value": true, - "tags": [ - { - "type": "ActorCondition", - "actor": "enemy", - "var": "Frozen" - } - ] - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5994(探针求值自动转写;样本:Hits ignore non-negative Elemental Resistances of Frozen Enemies)" - }, - { - "id": "ignore_all_movement_penalties_from_armour", - "pattern": "ignore all movement penalties from armour", - "vendor_pattern": "ignore all movement penalties from armour", - "mods": [ - { - "name": "Condition:IgnoreMovementPenalties", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5112(探针求值自动转写;样本:Ignore all Movement Penalties from Armour)" - }, - { - "id": "immune_to_chaos_damage", - "pattern": "immune to chaos damage", - "vendor_pattern": "immune to chaos damage", - "mods": [], - "verified": false, - "batch": "S0", - "source_note": "纯识别条目(pobr 现状 = Unsupported 不产 mod,mod_parser.rs:539-548);vendor :2358 产 ChaosInoculation flag + ChaosDamageTaken MORE -100——B-3 行为升级时改 mods 并对拍" - }, - { - "id": "immune_to_chaos_damage_and_bleeding", - "pattern": "immune to chaos damage and bleeding", - "vendor_pattern": "immune to chaos damage and bleeding", - "mods": [], - "verified": false, - "batch": "S0", - "source_note": "纯识别条目(pobr 现状 = Unsupported,mod_parser.rs:539-548);vendor :2362 另含 BleedImmune flag" - }, - { - "id": "immune_to_poison", - "pattern": "immun[ei]t?y? to poison", - "vendor_pattern": "immun[ei]t?y? to poison", - "mods": [ - { - "name": "PoisonImmune", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5162(探针求值自动转写;样本:Immune to Poison)" - }, - { - "id": "increased_bonuses_gained_from_equipped_quiver", - "pattern": "(\\d+)% increased bonuses gained from equipped quiver", - "vendor_pattern": "(%d+)%% increased bonuses gained from equipped quiver", - "mods": [ - { - "name": "EffectOfBonusesFromQuiver", - "type": "INC", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4866(探针求值自动转写;样本:6% increased bonuses gained from Equipped Quiver)" - }, - { - "id": "increased_bonuses_gained_from_equipped_rings_and_amulets", - "pattern": "(\\d+)% increased bonuses gained from equipped rings and amulets", - "vendor_pattern": "(%d+)%% increased bonuses gained from equipped rings and amulets", - "mods": [ - { - "name": "EffectOfBonusesFromRing 1", - "type": "INC", - "value": "$1" - }, - { - "name": "EffectOfBonusesFromRing 2", - "type": "INC", - "value": "$1" - }, - { - "name": "EffectOfBonusesFromRing 3", - "type": "INC", - "value": "$1" - }, - { - "name": "EffectOfBonusesFromAmulet", - "type": "INC", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4873(探针求值自动转写;样本:25% increased bonuses gained from Equipped Rings and Amulets)" - }, - { - "id": "increased_damage_for_each_type_of_elemental_ailment_on_enemy", - "pattern": "(\\d+)% increased damage for each type of elemental ailment on enemy", - "vendor_pattern": "(%d+)%% increased damage for each type of elemental ailment on enemy", - "mods": [ - { - "name": "Damage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "ActorCondition", - "actor": "enemy", - "var": "Electrocuted" - } - ] - }, - { - "name": "Damage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "ActorCondition", - "actor": "enemy", - "var": "Frozen" - } - ] - }, - { - "name": "Damage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "ActorCondition", - "actor": "enemy", - "var": "Chilled" - } - ] - }, - { - "name": "Damage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "ActorCondition", - "actor": "enemy", - "var": "Ignited" - } - ] - }, - { - "name": "Damage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "ActorCondition", - "actor": "enemy", - "var": "Shocked" - } - ] - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:3798(探针求值自动转写;样本:21% increased Damage for each type of Elemental Ailment on Enemy)" - }, - { - "id": "increased_effect_of_small_passive_skills", - "pattern": "(\\d+)% increased effect of small passive skills", - "vendor_pattern": "(%d+)%% increased effect of small passive skills", - "mods": [ - { - "name": "SmallPassiveSkillEffect", - "type": "INC", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3281(探针求值自动转写;样本:50% increased effect of Small Passive Skills)" - }, - { - "id": "increased_energy_shield_recharge_rate", - "pattern": "(\\d+)% increased energy shield recharge rate", - "vendor_pattern": "(%d+)%% increased energy shield recharge rate", - "mods": [ - { - "name": "EnergyShieldRecharge", - "type": "INC", - "value": "$1" - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:234(energy shield recharge rate→EnergyShieldRecharge;form parser modNameList 未含,M6 名表缺口)" - }, - { - "id": "increased_skill_effect_duration", - "pattern": "(\\d+)% increased skill effect duration", - "vendor_pattern": "(%d+)%% increased skill effect duration", - "mods": [ - { - "name": "Duration", - "type": "INC", - "value": "$1" - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:651(skill effect duration→Duration;form parser modNameList 未含,M6 名表缺口)" - }, - { - "id": "increased_total_power_counted_by_warcries", - "pattern": "(\\d+)% increased total power counted by warcries", - "vendor_pattern": "(%d+)%% increased total power counted by warcries", - "mods": [ - { - "name": "WarcryPower", - "type": "INC", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5774(探针求值自动转写;样本:5% increased total Power counted by Warcries)" - }, - { - "id": "increases_and_reductions_to_projectile_speed_also_apply_to_damage_with", - "pattern": "increases and reductions to projectile speed also apply to damage with bows", - "vendor_pattern": "increases and reductions to projectile speed also apply to damage with bows", - "mods": [ - { - "name": "ProjectileSpeedAppliesToBowDamage", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3648(探针求值自动转写;样本:Increases and Reductions to Projectile Speed also apply to Damage with Bows)" - }, - { - "id": "inevitable_critical_hits", - "pattern": "inevitable critical hits", - "vendor_pattern": "inevitable critical hits", - "mods": [ - { - "name": "InevitableCriticalHits", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3393(探针求值自动转写;样本:Inevitable Critical Hits)" - }, - { - "id": "inherent_life_granted_by_strength_is_halved", - "pattern": "inherent life granted by strength is halved", - "vendor_pattern": "inherent life granted by strength is halved", - "mods": [ - { - "name": "HalvesLifeFromStrength", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2329(探针求值自动转写;样本:Inherent Life granted by Strength is halved)" - }, - { - "id": "leech_of_physical_attack_damage_as_life", - "pattern": "leeche?s? (\\d+(?:\\.\\d+)?)% of (physical) attack damage as life", - "vendor_pattern": "leeche?s? ([%d%.]+)%% of (%a+) attack damage as life", - "mods": [ - { - "name": "PhysicalDamageLifeLeech", - "type": "BASE", - "value": "$1", - "flags": [ - "Attack" - ] - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:2671(探针求值自动转写;样本:Leech 7.88% of Physical Attack Damage as Life)" - }, - { - "id": "leech_of_physical_attack_damage_as_mana", - "pattern": "leeche?s? (\\d+(?:\\.\\d+)?)% of (physical) attack damage as mana", - "vendor_pattern": "leeche?s? ([%d%.]+)%% of (%a+) attack damage as mana", - "mods": [ - { - "name": "PhysicalDamageManaLeech", - "type": "BASE", - "value": "$1", - "flags": [ - "Attack" - ] - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:2668(探针求值自动转写;样本:Leech 8.74% of Physical Attack Damage as Mana)" - }, - { - "id": "less_movement_speed_penalty_from_using_skills_while_moving", - "pattern": "(\\d+)% less movement speed penalty from using skills while moving", - "vendor_pattern": "(%d+)%% less movement speed penalty from using skills while moving", - "mods": [ - { - "name": "MovementSpeedPenalty", - "type": "MORE", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:6018(探针求值自动转写;样本:30% less Movement Speed Penalty from using Skills while moving)" - }, - { - "id": "life_leech_recovers_based_on_your_lightning_damage_as_well_as_physical", - "pattern": "(life) leech recovers based on y?o?u?r? ?(lightning) damage as well as physical damage", - "vendor_pattern": "(%a+%s?%a*) leech recovers based on y?o?u?r? ?(%a+) damage as well as physical damage", - "mods": [ - { - "name": "LifeLeechBasedOnLightningDamage", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:2677(探针求值自动转写;样本:Life Leech recovers based on your Lightning damage as well as Physical damage)" - }, - { - "id": "life_regeneration_per_second", - "pattern": "(\\d+(?:\\.\\d+)?) life regeneration per second", - "vendor_pattern": "(%d+%.?%d*) life regeneration per second", - "mods": [ - { - "name": "LifeRegen", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:175(life regeneration→LifeRegen BASE 平直每秒回复)" - }, - { - "id": "mageblood_legacy", - "pattern": "legacy of (\\w+)", - "vendor_pattern": "legacy of (%w+)", - "verified": false, - "batch": "S3", - "source_note": "ModParser.lua:5554-5557(Mageblood 腰带变体行 → LegacyOf BASE 1 + MagebloodEquipped FLAG;捕获驱动的动态 mod 名走 handler,聚合应用见 calc/mageblood.rs)", - "handler_id": "special:mageblood_legacy", - "handler_args": [ - "$1" - ] - }, - { - "id": "magnitudes_of_curses_you_inflict_are_zero", - "pattern": "magnitudes of curses you inflict are zero", - "vendor_pattern": "magnitudes of curses you inflict are zero", - "mods": [ - { - "name": "CurseEffect", - "type": "MORE", - "value": -100 - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:4276(探针求值自动转写;样本:Magnitudes of Curses you inflict are zero)" - }, - { - "id": "mana_costs_are_doubled", - "pattern": "d?o?u?b?l?e?s? ?mana costs ?a?r?e? ?d?o?u?b?l?e?d?", - "vendor_pattern": "d?o?u?b?l?e?s? ?mana costs ?a?r?e? ?d?o?u?b?l?e?d?", - "mods": [ - { - "name": "ManaCost", - "type": "MORE", - "value": 100 - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:2393(探针求值自动转写;样本:Mana Costs are Doubled)" - }, - { - "id": "no_inherent_mana_regeneration", - "pattern": "no inherent mana regeneration", - "vendor_pattern": "no inherent mana regeneration", - "mods": [ - { - "name": "Condition:NoInherentManaRegen", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3127(探针求值自动转写;样本:No inherent Mana Regeneration)" - }, - { - "id": "no_rage_effect", - "pattern": "no rage effect", - "vendor_pattern": "no rage effect", - "mods": [ - { - "name": "RageEffect", - "type": "OVERRIDE", - "value": 0 - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2788(探针求值自动转写;样本:No Rage effect)" - }, - { - "id": "of_armour_also_applies_to_cold_damage", - "pattern": "\\+?(\\d+)% of armour also applies to (cold) damage", - "vendor_pattern": "%+?(%d+)%% of armour also applies to (%a+) damage", - "mods": [ - { - "name": "ArmourAppliesToColdDamageTaken", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2543(探针求值自动转写;样本:+15% of Armour also applies to Cold Damage)" - }, - { - "id": "of_armour_also_applies_to_elemental_damage", - "pattern": "\\+?(\\d+)% of armour (also )applies to elemental damage", - "vendor_pattern": "%+?(%d+)%% of armour (a?l?s?o? ?)applies to elemental damage", - "mods": [ - { - "name": "ArmourAppliesToFireDamageTaken", - "type": "BASE", - "value": "$1" - }, - { - "name": "ArmourAppliesToColdDamageTaken", - "type": "BASE", - "value": "$1" - }, - { - "name": "ArmourAppliesToLightningDamageTaken", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2535(探针求值自动转写;样本:+5% of Armour also applies to Elemental Damage)" - }, - { - "id": "of_armour_also_applies_to_fire_damage", - "pattern": "\\+?(\\d+)% of armour also applies to (fire) damage", - "vendor_pattern": "%+?(%d+)%% of armour also applies to (%a+) damage", - "mods": [ - { - "name": "ArmourAppliesToFireDamageTaken", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2543(探针求值自动转写;样本:+15% of Armour also applies to Fire Damage)" - }, - { - "id": "of_armour_also_applies_to_lightning_damage", - "pattern": "\\+?(\\d+)% of armour also applies to (lightning) damage", - "vendor_pattern": "%+?(%d+)%% of armour also applies to (%a+) damage", - "mods": [ - { - "name": "ArmourAppliesToLightningDamageTaken", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2543(探针求值自动转写;样本:+15% of Armour also applies to Lightning Damage)" - }, - { - "id": "of_damage_taken_bypasses_energy_shield", - "pattern": "(\\d+)% of damage taken bypasses energy shield", - "vendor_pattern": "(%d+)%% of damage taken bypasses energy shield", - "mods": [ - { - "name": "PhysicalEnergyShieldBypass", - "type": "BASE", - "value": "$1" - }, - { - "name": "LightningEnergyShieldBypass", - "type": "BASE", - "value": "$1" - }, - { - "name": "ColdEnergyShieldBypass", - "type": "BASE", - "value": "$1" - }, - { - "name": "FireEnergyShieldBypass", - "type": "BASE", - "value": "$1" - }, - { - "name": "ChaosEnergyShieldBypass", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:2495(探针求值自动转写;样本:12% of Damage taken bypasses Energy Shield)" - }, - { - "id": "of_flask_recovery_applied_instantly", - "pattern": "(\\d+)% of flask recovery applied instantly", - "vendor_pattern": "(%d+)%% of flask recovery applied instantly", - "mods": [ - { - "name": "FlaskInstantRecovery", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:3463(探针求值自动转写;样本:20% of Flask Recovery applied Instantly)" - }, - { - "id": "passives_in_radius_can_be_allocated_without_being_connected_to_your_tr", - "pattern": "passives in radius can be allocated without being connected to your tree", - "vendor_pattern": "passives in radius can be allocated without being connected to your tree", - "mods": [ - { - "name": "JewelData", - "type": "LIST", - "value": { - "key": "intuitiveLeapLike", - "value": true - } - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:5467(探针求值自动转写;样本:Passives in Radius can be Allocated without being connected to your tree)" - }, - { - "id": "reduced_movement_speed_penalty_from_using_skills_while_moving", - "pattern": "(\\d+)% reduced movement speed penalty from using skills while moving", - "vendor_pattern": "(%d+)%% reduced movement speed penalty from using skills while moving", - "mods": [ - { - "name": "MovementSpeedPenalty", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } - } - ], - "verified": false, - "batch": "S1", - "source_note": "ModParser.lua:6017(探针求值自动转写;样本:5% reduced Movement Speed Penalty from using Skills while moving)" - }, - { - "id": "take_no_extra_damage_from_critical_hits", - "pattern": "take no extra damage from critical hits", - "vendor_pattern": "take no extra damage from critical hits", - "mods": [ - { - "name": "ReduceCritExtraDamage", - "type": "BASE", - "value": 100.0 - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:6129(暴击不造成额外伤害 → ReduceCritExtraDamage BASE 100;pobr 准源 legacy.rs:1445)" - }, - { - "id": "targets_can_be_affected_by_poisons", - "pattern": "targets can be affected by \\+(\\d+) of your poisons at the same time", - "vendor_pattern": "targets can be affected by %+(%d+) of your poisons at the same time", - "mods": [ - { - "name": "PoisonCanStack", - "type": "FLAG", - "value": true - }, - { - "name": "PoisonStacks", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:3895(+N poison stacks → PoisonCanStack FLAG + PoisonStacks BASE N;pobr 准源 legacy.rs:1974)" - }, - { - "id": "you_have_no_mana", - "pattern": "you have no mana", - "vendor_pattern": "you have no mana", - "mods": [ - { - "name": "MaximumMana", - "type": "OVERRIDE", - "value": 0.0 - } - ], - "verified": false, - "batch": "S0", - "source_note": "pobr 准源 mod_parser.rs:529-531;vendor ModParser.lua:2392(ModName 为 Mana,pobr 现行稳定名 MaximumMana)" - }, - { - "id": "your_critical_damage_bonus_override", - "pattern": "your critical damage bonus is (\\d+(?:\\.\\d+)?)%", - "vendor_pattern": "your critical damage bonus is (%d+)%%", - "mods": [ - { - "name": "CriticalStrikeMultiplier", - "type": "OVERRIDE", - "value": "$1" - } - ], - "verified": false, - "batch": "S0", - "source_note": "pobr 准源 mod_parser.rs:490-506(dynamic_overrides);vendor ModParser.lua:5798 同语义但 ModName 为 CritMultiplier(pobr 现行稳定名 CriticalStrikeMultiplier,B-3 双跑以 pobr 现状为基准)" - }, - { - "id": "your_critical_hit_chance_override", - "pattern": "your critical hit chance is (\\d+(?:\\.\\d+)?)%", - "mods": [ - { - "name": "CriticalStrikeChance", - "type": "OVERRIDE", - "value": "$1" - } - ], - "verified": false, - "batch": "S0", - "source_note": "pobr 准源 mod_parser.rs:490-506;vendor 无数值形同 key(仅 lucky 系 :3730-3732)" - }, - { - "id": "stun_threshold_from_es_8", - "pattern": "gain additional stun threshold equal to 8% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "StunThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 8 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "stun_threshold_from_es_12", - "pattern": "gain additional stun threshold equal to 12% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "StunThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 12 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "stun_threshold_from_es_15", - "pattern": "gain additional stun threshold equal to 15% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "StunThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 15 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "stun_threshold_from_es_20", - "pattern": "gain additional stun threshold equal to 20% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "StunThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 20 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "stun_threshold_from_es_30", - "pattern": "gain additional stun threshold equal to 30% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "StunThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 30 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "ailment_threshold_from_es_8", - "pattern": "gain additional ailment threshold equal to 8% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "AilmentThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 8 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "ailment_threshold_from_es_12", - "pattern": "gain additional ailment threshold equal to 12% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "AilmentThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 12 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "ailment_threshold_from_es_15", - "pattern": "gain additional ailment threshold equal to 15% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "AilmentThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 15 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "ailment_threshold_from_es_20", - "pattern": "gain additional ailment threshold equal to 20% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "AilmentThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 20 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "ailment_threshold_from_es_30", - "pattern": "gain additional ailment threshold equal to 30% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ - { - "name": "AilmentThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 30 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "mana_regen_from_life_6", - "pattern": "regenerate mana equal to 6% of maximum life per second", - "vendor_pattern": "regenerate mana equal to (%d+)%% of maximum life per second", - "mods": [ - { - "name": "ManaRegen", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "Life", - "percent": 6 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #28(oracle:ManaRegen BASE 1 + PercentStat{Life,6});DSL PercentStat 字面值——按语料数值钉 6" - }, - { - "id": "ailment_threshold_from_evasion_100", - "pattern": "gain 100% of evasion rating as extra ailment threshold", - "vendor_pattern": "gain (%d+)%% of evasion rating as extra ailment threshold", - "mods": [ - { - "name": "AilmentThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "Evasion", - "percent": 100 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #24(oracle:AilmentThreshold BASE 1 + PercentStat{Evasion,100});玩家侧 AilmentThreshold 暂无 calc 消费——解析对齐 vendor,接线即生效" - }, - { - "id": "threshold_10_red_support_gems_5pct", - "pattern": "5% increased maximum life if you have at least 10 red support gems socketed", - "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", - "mods": [ - { - "name": "Life", - "type": "INC", - "value": 5, - "tags": [ - { - "type": "MultiplierThreshold", - "var": "RedSupportGems", - "threshold": 10 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值" - }, - { - "id": "threshold_10_blue_support_gems_5pct", - "pattern": "5% increased maximum mana if you have at least 10 blue support gems socketed", - "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", - "mods": [ - { - "name": "Mana", - "type": "INC", - "value": 5, - "tags": [ - { - "type": "MultiplierThreshold", - "var": "BlueSupportGems", - "threshold": 10 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值" - }, - { - "id": "threshold_10_green_support_gems_5pct", - "pattern": "5% increased movement speed if you have at least 10 green support gems socketed", - "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", - "mods": [ - { - "name": "MovementSpeed", - "type": "INC", - "value": 5, - "tags": [ - { - "type": "MultiplierThreshold", - "var": "GreenSupportGems", - "threshold": 10 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值" - }, - { - "id": "body_armour_grants_reduced_crit_damage_bonus_100", - "pattern": "body armour grants hits against you have 100% reduced critical damage bonus", - "vendor_pattern": "body armour grants hits against you have (%d+)%% reduced critical damage bonus", - "mods": [ - { - "name": "ReduceCritExtraDamage", - "type": "BASE", - "value": 100 - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:3284(mod(ReduceCritExtraDamage, BASE, num, ItemCondition{Body Armour, rarityCond=NORMAL});ItemCondition 无 PoBR 落点按 body-armour-grants pre_flag 族同口径丢弃(dropped-tag 报表 7 行同款欠条)——Smith of Kitava 机制要求白装胸甲,语料 build 满足故不 over-apply。语料数值集 {100} 钉值。消费方 defence.rs CritExtraDamageReduction 已存在" - }, - { - "id": "body_armour_grants_unaffected_by_damaging_ailments", - "pattern": "body armour grants unaffected by damaging ailments", - "vendor_pattern": "body armour grants unaffected by damaging ailments", - "mods": [ - { - "name": "SelfBleedEffect", - "type": "MORE", - "value": -100 - }, - { - "name": "SelfIgniteEffect", - "type": "MORE", - "value": -100 - }, - { - "name": "SelfPoisonEffect", - "type": "MORE", - "value": -100 - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:3288(Self{Bleed,Ignite,Poison}Effect MORE -100 ×3,ItemCondition 同上丢弃)。Self*Effect 玩家侧 calc 暂无消费(解析对齐 vendor,自异常效果消费端接线时词条已就位;AilmentThreshold 先例)" - }, - { - "id": "break_armour_on_crit_with_spells", - "pattern": "break armour on critical hit with spells equal to (\\d+)% of physical damage dealt", - "vendor_pattern": "break armour on critical hit with spells equal to (%d+)%% of physical damage dealt", - "mods": [ - { - "name": "Condition:CanArmourBreak", - "type": "FLAG", - "value": true, - "tags": [ - { - "type": "Condition", - "neg": true, - "var": "NeverCrit" - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:3803(flag(Condition:CanArmourBreak, GlobalEffect{Buff, ArmourBreak}, Condition{neg NeverCrit});数值不进 mods——vendor 同样忽略捕获,正则一条覆盖语料 {5,10}。GlobalEffect 无 PoBR 落点丢弃(已有评估:不值窄做);CanArmourBreak 玩家侧 calc 暂无消费(armour break 机制未建模,解析对齐 vendor)" - }, - { - "id": "limit_for_elemental_skills", - "pattern": "\\+(\\d+) to limit for elemental skills", - "vendor_pattern": "%+(%d+) to limit for elemental skills", - "mods": [ - { - "name": "AdditionalCooldownUses", - "type": "BASE", - "value": "$1", - "tags": [ - { - "type": "SkillType", - "skillTypeList": [ - "Cold", - "Fire", - "Lightning" - ] - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:3374(mod(AdditionalCooldownUses, BASE, num, SkillType{skillTypeList={Cold,Fire,Lightning}});skillTypeList → SkillTypes 位集并集(intersects 即 OR,与 vendor ModStore SkillType 任一命中同语义)。消费方 skill_mechanics.rs stored uses 已存在)" - }, - { - "id": "immune_to_ignite", - "pattern": "immun[ei]t?y? to ignite", - "vendor_pattern": "immun[ei]t?y? to ignite", - "mods": [ - { - "name": "IgniteImmune", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5172 flag(IgniteImmune);charm『Immune to Ignite』词条走此行" - }, - { - "id": "immune_to_freeze", - "pattern": "immun[ei]t?y? to freeze", - "vendor_pattern": "immun[ei]t?y? to freeze", - "mods": [ - { - "name": "FreezeImmune", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S2", - "source_note": "ModParser.lua:5168 flag(FreezeImmune);Thawing Charm『Immune to Freeze』词条走此行" - }, - { - "id": "recover_mana_when_used", - "pattern": "recovers? (\\d+) mana when used", - "vendor_pattern": null, - "mods": [ - { - "name": "ManaOnFlaskUse", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S0", - "source_note": "药剂/护符使用时瞬时回魔:解析为 ManaOnFlaskUse BASE(归因/Calcs 可见;稳态面板无消费——瞬时恢复不属于稳态模型,flask 恢复面板落地时接线)。vendor 走 flaskData 本地系统不产 mod" - }, - { - "id": "flask_mana_recovery_overflow", - "pattern": "mana recovery from flasks can overflow maximum mana( during effect)?", - "vendor_pattern": null, - "mods": [ - { - "name": "FlaskManaRecoveryOverflow", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S0", - "source_note": "Melting Maelstrom:效果期间药剂魔力恢复可溢出上限 → FLAG 进 ModDb(归因可见;溢出魔力稳态无消费者,vendor 亦未建模)" - }, - { - "id": "possessed_by_spirit_on_use", - "pattern": "possessed by [a-z' ]+ for (\\d+) seconds on use", - "vendor_pattern": null, - "mods": [ - { - "name": "SpiritPossessionOnUse", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "S0", - "source_note": "金护符阿兹莫里之灵附身(Stag/Wolf/Bear…):玩家侧 buff 数值无可验证一手来源(poe2db/wiki 仅载敌方附身效果,BuffDefinitions 未入库)→ 暂解析为 FLAG 登记,数据可得后升级 handler 接具体 buff" - }, - { - "id": "also_grants_guard", - "pattern": "also grants (\\d+) guard", - "vendor_pattern": null, - "mods": [ - { - "name": "GuardAbsorbRate", - "type": "BASE", - "value": 100 - }, - { - "name": "GuardAbsorbLimit", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "S0", - "source_note": "药剂/护符使用效果:PoE2 Guard buff=生命/ES 前全额吸收击中的缓冲池(agent-docs/active-defences.md §2;poe2db Guard 定义)→ rate 100 + limit $1,消费端 pool_setup.rs:132 现成(EHP/MaxHit 承受层)。vendor ModParser 未接此词条(比 PoB2 多建模一层)" - }, - { - "id": "armour_applies_to_fcl_instead_of_physical", - "pattern": "armour applies to fire, cold and lightning damage taken from hits instead of physical damage", - "vendor_pattern": "armour applies to fire, cold and lightning damage taken from hits instead of physical damage", - "mods": [ - { - "name": "ArmourAppliesToFireDamageTaken", - "type": "BASE", - "value": 100 - }, - { - "name": "ArmourAppliesToColdDamageTaken", - "type": "BASE", - "value": 100 - }, - { - "name": "ArmourAppliesToLightningDamageTaken", - "type": "BASE", - "value": 100 - }, - { - "name": "ArmourDoesNotApplyToPhysicalDamageTaken", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:2545-2550(三元素 ArmourAppliesToDamageTaken BASE 100 + instead 变体专属 flag)。消费端 taken.rs armour_applies_pct(flag 时物理份额归 0)。legacy-only 测试掩盖的 engine 缺口(原 mod_parser_m2_defence.rs:182)" - }, - { - "id": "pct_of_armour_applies_to_fcl", - "pattern": "(\\d+)% of armour applies to fire, cold and lightning damage taken from hits", - "vendor_pattern": "(%d+)%% of armour applies to fire, cold and lightning damage taken from hits", - "mods": [ - { - "name": "ArmourAppliesToFireDamageTaken", - "type": "BASE", - "value": "$1" - }, - { - "name": "ArmourAppliesToColdDamageTaken", - "type": "BASE", - "value": "$1" - }, - { - "name": "ArmourAppliesToLightningDamageTaken", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:2551-2555(function(num)→三元素 BASE num)。消费端 taken.rs armour_applies_pct。原 mod_parser_m2_defence.rs:192" - }, - { - "id": "armour_applies_to_elemental_damage", - "pattern": "armour applies to elemental damage", - "vendor_pattern": "armour applies to elemental damage", - "mods": [ - { - "name": "ArmourAppliesToFireDamageTaken", - "type": "BASE", - "value": 100 - }, - { - "name": "ArmourAppliesToColdDamageTaken", - "type": "BASE", - "value": 100 - }, - { - "name": "ArmourAppliesToLightningDamageTaken", - "type": "BASE", - "value": 100 - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:2556-2560(三元素 BASE 100,无 instead flag)。原 mod_parser_m2_defence.rs:201" - }, - { - "id": "pct_of_armour_applies_to_elemental_damage", - "pattern": "\\+?(\\d+)% of armour (?:also )?applies to elemental damage", - "vendor_pattern": "%+?(%d+)%% of armour (a?l?s?o? ?)applies to elemental damage", - "mods": [ - { - "name": "ArmourAppliesToFireDamageTaken", - "type": "BASE", - "value": "$1" - }, - { - "name": "ArmourAppliesToColdDamageTaken", - "type": "BASE", - "value": "$1" - }, - { - "name": "ArmourAppliesToLightningDamageTaken", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:2561-2565(function(num)→三元素 BASE num;vendor 第二捕获 also 为可选填充词,此处转非捕获组保持 $1 语义)" - }, - { - "id": "energy_shield_protects_mana_instead_of_life", - "pattern": "energy shield protects mana instead of life", - "vendor_pattern": "energy shield protects mana instead of life", - "mods": [ - { - "name": "EnergyShieldProtectsMana", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:2465(Eldritch Battery 类)。消费端 keystone_registry.rs DefenceKeystones.energy_shield_protects_mana → pool_damage.rs/ehp.rs/defence.rs。原 mod_parser_m2_defence.rs:99" - }, - { - "id": "converts_all_evasion_rating_to_armour", - "pattern": "converts all evasion rating to armour", - "vendor_pattern": "converts all evasion rating to armour", - "mods": [ - { - "name": "IronReflexes", - "type": "FLAG", - "value": true - }, - { - "name": "EvasionConvertToArmour", - "type": "BASE", - "value": 100 - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:2369(Iron Reflexes 类:flag + EvasionConvertToArmour BASE 100)。消费端 defence.rs calc_defence_resources 五元 ConvertTo 矩阵 + keystone_registry.rs iron_reflexes(Unbreakable 联动)。原 mod_parser_m2_defence.rs:265" - }, - { - "id": "chance_to_deflect_is_lucky", - "pattern": "chance to deflect is lucky", - "vendor_pattern": "chance to deflect is lucky", - "mods": [ - { - "name": "DeflectIsLucky", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:4202。消费端 defence_panels.rs:298 偏斜几率 lucky 幂(1−(1−p)²)。原 mod_parser_m2_defence.rs:397" - }, - { - "id": "chance_to_block_damage_is_lucky", - "pattern": "chance to block damage is lucky", - "vendor_pattern": "chance to block damage is lucky", - "mods": [ - { - "name": "BlockChanceIsLucky", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:4371。消费端 defence_panels.rs:174 effective(BlockChance) luck_transform" - }, - { - "id": "chance_to_block_is_lucky", - "pattern": "(?:your )?chance to block is lucky", - "vendor_pattern": "y?o?u?r? ?chance to block is lucky", - "mods": [ - { - "name": "BlockChanceIsLucky", - "type": "FLAG", - "value": true - }, - { - "name": "ProjectileBlockChanceIsLucky", - "type": "FLAG", - "value": true - }, - { - "name": "SpellBlockChanceIsLucky", - "type": "FLAG", - "value": true - }, - { - "name": "SpellProjectileBlockChanceIsLucky", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "wave2-defence", - "source_note": "ModParser.lua:4372(四 flag 全套)。消费端 defence_panels.rs:174 消费 BlockChance/SpellBlockChance 两口径;Projectile/SpellProjectile 两 flag 目前无消费端(pobr 未算 projectile block 有效值),形态先对齐 vendor" - }, - { - "id": "bonded_modifiers_enabler", - "pattern": "gain the benefits of bonded modifiers on runes and idols", - "vendor_pattern": "gain the benefits of bonded modifiers on runes and idols", - "mods": [ - { - "name": "Condition:CanUseBondedModifiers", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "M6-3b", - "source_note": "ModParser.lua:3418-3419(Druid Oracle specialModList 整行;flag(Condition:CanUseBondedModifiers) 解锁 'Bonded:' 前缀词条,vendor :1437)" - }, - { - "id": "bonded_meta_res_eff_inc", - "pattern": "bonded: meta skills have (\\d+)% increased reservation efficiency", - "vendor_pattern": "(Bonded 前缀 + 域限定效率;见 source_note 口径说明)", - "mods": [ - { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - }, - "tags": [ - { - "type": "Condition", - "var": "CanUseBondedModifiers" - }, - { - "type": "SkillType", - "skillType": "Meta" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "Bonded rune 变体(语料 C1 双跑对齐:legacy 的 bonded 递归会命中 parse_reservation_efficiency,引擎须同产出;Condition:CanUseBondedModifiers 默认不激活)。vendor 对前缀域形 Bonded 变体 unsupported(special 表不在前缀剥离后重查)——此处取 legacy 超集方向(条件门控恒 false 时零行为)" - }, - { - "id": "bonded_herald_res_eff_inc", - "pattern": "bonded: (\\d+)% increased reservation efficiency of herald skills", - "vendor_pattern": "(Bonded 前缀 + 域限定效率;见 source_note 口径说明)", - "mods": [ - { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - }, - "tags": [ - { - "type": "Condition", - "var": "CanUseBondedModifiers" - }, - { - "type": "SkillType", - "skillType": "Herald" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "Bonded rune 变体(语料 C1 双跑对齐:legacy 的 bonded 递归会命中 parse_reservation_efficiency,引擎须同产出;Condition:CanUseBondedModifiers 默认不激活)。vendor 对前缀域形 Bonded 变体 unsupported(special 表不在前缀剥离后重查)——此处取 legacy 超集方向(条件门控恒 false 时零行为)" - }, - { - "id": "all_elemental_damage_converted_to_chaos", - "pattern": "all elemental damage converted to chaos damage", - "vendor_pattern": "all elemental damage converted to chaos damage", - "mods": [ - { - "name": "ColdDamageConvertToChaos", - "type": "BASE", - "value": 100.0 - }, - { - "name": "FireDamageConvertToChaos", - "type": "BASE", - "value": 100.0 - }, - { - "name": "LightningDamageConvertToChaos", - "type": "BASE", - "value": 100.0 - } - ], - "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:2410-2414(all elemental → chaos 100,整行特例;通用后缀路径整行不识别)" - }, - { - "id": "cold_damage_taken_as_lightning", - "pattern": "(\\d+(?:\\.\\d+)?)% of cold damage taken as lightning", - "vendor_pattern": "(%d+)%% of cold damage taken as lightning", - "mods": [ - { - "name": "ColdDamageTakenAsLightning", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:5655(裸目标 taken-as:suffixTypes 无 bare `as lightning`,通用路径残留 `as lightning` 并误产 ColdDamageTaken BASE)" - }, - { - "id": "fire_and_lightning_from_hits_taken_as_cold_during_effect", - "pattern": "(\\d+(?:\\.\\d+)?)% of fire and lightning damage from hits taken as cold damage during effect", - "vendor_pattern": "(%d+)%% of fire and lightning damage from hits taken as cold damage during effect", - "mods": [ - { - "name": "FireDamageFromHitsTakenAsCold", - "type": "BASE", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "UsingFlask" - } - ] - }, - { - "name": "LightningDamageFromHitsTakenAsCold", - "type": "BASE", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "UsingFlask" - } - ] - } - ], - "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:5657-5660(flask 词条;通用路径只吃 lightning 分支、残留 `Fire and`)" - }, - { - "id": "fire_damage_taken_as_lightning", - "pattern": "(\\d+(?:\\.\\d+)?)% of fire damage taken as lightning", - "vendor_pattern": "(%d+)%% of fire damage taken as lightning", - "mods": [ - { - "name": "FireDamageTakenAsLightning", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:5656(同 cold_damage_taken_as_lightning,裸目标 taken-as)" - }, - { - "id": "phys_cold_lightning_converted_to_fire", - "pattern": "(\\d+(?:\\.\\d+)?)% of physical, cold and lightning damage converted to fire damage", - "vendor_pattern": "(%d+)%% of physical, cold and lightning damage converted to fire damage", - "mods": [ - { - "name": "PhysicalDamageConvertToFire", - "type": "BASE", - "value": "$1" - }, - { - "name": "LightningDamageConvertToFire", - "type": "BASE", - "value": "$1" - }, - { - "name": "ColdDamageConvertToFire", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:2405-2409(多源合写 converted to:通用路径只吃 lightning 分支、残留 `Physical, Cold and`)" - }, - { - "id": "phys_from_hits_taken_as_random_element", - "pattern": "(\\d+(?:\\.\\d+)?)% of physical damage from hits taken as damage of a random element", - "vendor_pattern": "(%d+)%% of physical damage from hits taken as damage of a random element", - "mods": [ - { - "name": "PhysicalDamageFromHitsTakenAsFire", - "type": "BASE", - "value": { - "ref": "$1", - "ops": [ - { - "div": 3.0 - } - ] - } - }, - { - "name": "PhysicalDamageFromHitsTakenAsCold", - "type": "BASE", - "value": { - "ref": "$1", - "ops": [ - { - "div": 3.0 - } - ] - } - }, - { - "name": "PhysicalDamageFromHitsTakenAsLightning", - "type": "BASE", - "value": { - "ref": "$1", - "ops": [ - { - "div": 3.0 - } - ] - } - } - ], - "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:5661-5665(AVERAGE 三分口径 num/3;真实语料词条,legacy 删除后回归恢复)" - }, - { - "id": "eternal_life_while_energy_shield", - "pattern": "your life cannot change while you have energy shield", - "vendor_pattern": "your life cannot change while you have energy shield", - "mods": [ - { - "name": "EternalLife", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:3144(-- Lich specialModList,flag(EternalLife));legacy 经 max-hit ES bypass 消费(pool_damage.rs)。fork-a 迁入补 engine 数据驱动 special 通道缺口(detonate-dead MaxHit/EHP 偏低)" - }, - { - "id": "blood_mage_additional_life_from_body_es", - "pattern": "gain additional maximum life equal to 100% of the (?:item )?energy shield on equipped body armour", - "vendor_pattern": "gain additional maximum life equal to (%d+)%% of the (i?t?e?m? ?)energy shield on equipped body armour", - "mods": [ - { - "name": "MaximumLife", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "Multiplier", - "var": "EnergyShieldOnbodyarmour", - "div": 1 - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:2834(-- Blood Mage specialModList,mod(Life,BASE,1,PerStat{stat=EnergyShieldOnBody Armour,div=100/N});legacy.rs:1796-1810 同形(MaximumLife BASE 1 × Multiplier:EnergyShieldOnbodyarmour,div=100/N,slot 倍率经 orchestrator per_slot_defence_multipliers 填充 = Body Armour 件级最终 ES)。本条钉 N=100(升华恒 100%,corpus 唯一形)→ div=1;special 整行命中在 pre_flag 剥 `gain` 前。需 special_mod.rs 字面 Multiplier tag 支持。fork-a 补 engine special 通道(blood-mage Life→EHP/MaxHit 级联)" - }, - { - "id": "life_loss_from_hits_prevented_over_4s", - "pattern": "(\\d+(?:\\.\\d+)?)% of life loss from hits is prevented, then that much life is lost over 4 seconds instead", - "vendor_pattern": "(%d+)%% of life loss from hits is prevented, then that much life is lost over 4 seconds instead", - "mods": [ - { - "name": "LifeLossPrevented", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:2839 function(num)→mod(LifeLossPrevented,BASE,num);legacy.rs:1824-1827 同。pool_setup.rs:104 `min(ΣLifeLossPrevented,100)` 减伤(max-hit 机制)。vendor 函数形,extract 抽不出静态模板 → 引擎误解析为 MaximumLife BASE 25。fork-a 补 engine special(blood-mage EHP/五类 MaxHit 0.88x)" - }, - { - "id": "fire_damage_while_affected_by_herald_of_ash", - "pattern": "(\\d+(?:\\.\\d+)?)% increased fire damage while affected by herald of ash", - "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2536 硬编码]", - "mods": [ - { - "name": "FireDamage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "AffectedByHeraldofAsh" - }, - { - "type": "DamageType", - "damageType": "Fire" - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "vendor `while affected by (%a+)` modTagList 单词捕获抽不出多词「Herald of Ash」+ 多元素 varList 引擎丢弃 → engine 无条件应用、泄漏进 dot(grenade/ice-shot dot over-count)。legacy.rs:2536 硬编码 `AffectedByHeraldofAsh`。整行 data 化对齐 legacy(FireDamage INC + Condition + DamageType)" - }, - { - "id": "cold_damage_while_affected_by_herald_of_ice", - "pattern": "(\\d+(?:\\.\\d+)?)% increased cold damage while affected by herald of ice", - "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2532 硬编码]", - "mods": [ - { - "name": "ColdDamage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "AffectedByHeraldofIce" - }, - { - "type": "DamageType", - "damageType": "Cold" - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "同 fire_damage_while_affected_by_herald_of_ash;legacy.rs:2532 `AffectedByHeraldofIce`" - }, - { - "id": "lightning_damage_while_affected_by_herald_of_thunder", - "pattern": "(\\d+(?:\\.\\d+)?)% increased lightning damage while affected by herald of thunder", - "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2540 硬编码]", - "mods": [ - { - "name": "LightningDamage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "AffectedByHeraldofThunder" - }, - { - "type": "DamageType", - "damageType": "Lightning" - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "同 fire_damage_while_affected_by_herald_of_ash;legacy.rs:2540 `AffectedByHeraldofThunder`" - }, - { - "id": "body_armour_grants_of_armour_also_applies_to_chaos_damage", - "pattern": "body armour grants \\+?(\\d+)% of armour also applies to (chaos) damage", - "vendor_pattern": "body armour grants %+(%d+)%% of armour also applies to (%a+) damage", - "mods": [ - { - "name": "ArmourAppliesToChaosDamageTaken", - "type": "BASE", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "NormalBodyArmourEquipped" - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:3281 -- Warrior - Smith of Kitava,function(num,_,dmgType)→mod(ArmourAppliesToDamageTaken,BASE,num,{type=ItemCondition,itemSlot=Body Armour,rarityCond=NORMAL})。vendor 函数形带 (%a+) 伤害类型捕获 + ItemCondition,extract_parser_rules 抽不出(S2 批仅手转非 body-armour 的 fire/cold/lightning 三元素,漏 chaos + 漏 body-armour-grants 变体)。legacy 经 body-armour-grants 前缀剥离 + parse_armour_applies_pct(legacy.rs:393/1621)通用处理任意类型,chaos 正常,故 engine 落后 legacy。本条把 vendor ItemCondition{Body Armour,NORMAL} 映射为 pobr `Condition:NormalBodyArmourEquipped`(orchestrator calc_orchestrator.rs:373 按体甲槽 Normal 稀有度置真,与 legacy.rs:397 同口径),消费侧 taken.rs ArmourAppliesToChaosDamageTaken。修 warrior-smith-of-kitava-shield-wall ChaosMaxHit 0.84x→1.00x" - }, - { - "id": "prevent_pct_of_damage_from_deflected_hits", - "pattern": "prevent \\+(\\d+(?:\\.\\d+)?)% of damage from deflected hits", - "vendor_pattern": "prevent %+(%d+)%% of damage from deflected hits", - "mods": [ - { - "name": "DeflectEffect", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:4191 function(num)→mod(DeflectEffect,BASE,num);legacy.rs:1721 parse_deflection_special 同。defence_panels.rs:241 偏斜减伤=基础40+ΣBASE DeflectEffect,clamp[0,100](DeflectChance 58% 时生效,非仅≥100)。vendor 函数形 extract 抽不出 → 引擎丢弃(twister 缺 DeflectEffect 3+6=9 → 偏斜减伤 40 而非 49 → EHP 0.89x)。捕获形一条匹配全部 N。fork-a 补 engine special(monk-martial-artist-twister TotalEHP)" - }, - { - "id": "you_can_apply_an_additional_curse", - "pattern": "you can apply an additional curse", - "vendor_pattern": "you can apply an additional curse", - "mods": [ - { - "name": "EnemyCurseLimit", - "type": "BASE", - "value": 1 - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:4303(Whispers of Doom keystone tree 47759 第一行『You can apply an additional Curse』;第二行 Double Activation Delay 已在 double_activation_delay_of_curses 条目)。缺它时 frost-bomb 第二诅咒 Elemental Weakness 被挤出唯一槽,敌侧 -45 元素抗丢失(CritChance 路径外的 hit 伤害缺口)" - }, - { - "id": "enemies_can_have_1_additional_curse", - "pattern": "enemies can have 1 additional curse", - "vendor_pattern": "enemies can have 1 additional curse", - "mods": [ - { - "name": "EnemyCurseLimit", - "type": "BASE", - "value": 1 - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:4302(curse limit 平表同族)" - }, - { - "id": "you_can_apply_one_fewer_curse", - "pattern": "you can apply one fewer curse", - "vendor_pattern": "you can apply one fewer curse", - "mods": [ - { - "name": "EnemyCurseLimit", - "type": "BASE", - "value": -1 - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:4306(curse limit 平表同族)" - }, - { - "id": "you_can_apply_an_additional_mark", - "pattern": "you can apply an additional mark", - "vendor_pattern": "you can apply an additional mark", - "mods": [ - { - "name": "EnemyMarkLimit", - "type": "BASE", - "value": 1 - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:4309(mark limit 平表同族)" - }, - { - "id": "es_added_to_armour_for_pdr", - "pattern": "(\\d+(?:\\.\\d+)?)% of your current energy shield is added to your armour for determining your physical damage reduction from armour", - "vendor_pattern": "(%d+)%% of your current energy shield is added to your armour for determining your physical damage reduction from armour", - "mods": [ - { - "name": "EnergyShieldAppliesToPhysicalDamageTaken", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:2917-2919(Disciple of Varashta 升华 Sacred Rituals,tree node 56857 —— N% of your current Energy Shield is added to your Armour for determining your Physical Damage Reduction from Armour → EnergyShieldAppliesToPhysicalDamageTaken BASE N)。消费 taken.rs effective_applied_armour 的 from_es 借入项(CalcDefence.lua:2358-2367)。pobr 准源 legacy.rs parse_defence_numeric_sentence(须走 legacy 以过 collect.rs::combine_wrapped_then_filter 树 stat 闸门)。" - }, - { - "id": "take_pct_less_damage", - "pattern": "take (\\d+)% less damage", - "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% less Damage)", - "mods": [ - { - "name": "DamageTaken", - "type": "MORE", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" - }, - { - "id": "take_pct_more_damage", - "pattern": "take (\\d+)% more damage", - "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% more Damage)", - "mods": [ - { - "name": "DamageTaken", - "type": "MORE", - "value": { - "ref": "$1" - } - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" - }, - { - "id": "take_pct_reduced_damage", - "pattern": "take (\\d+)% reduced damage", - "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% reduced Damage)", - "mods": [ - { - "name": "DamageTaken", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" - }, - { - "id": "take_pct_increased_damage", - "pattern": "take (\\d+)% increased damage", - "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% increased Damage)", - "mods": [ - { - "name": "DamageTaken", - "type": "INC", - "value": { - "ref": "$1" - } - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" - }, - { - "id": "meta_skills_res_eff_inc", - "pattern": "meta skills have (\\d+)% increased reservation efficiency", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", - "mods": [ - { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - }, - "tags": [ - { - "type": "SkillType", - "skillType": "Meta" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" - }, - { - "id": "meta_skills_res_eff_red", - "pattern": "meta skills have (\\d+)% reduced reservation efficiency", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", - "mods": [ - { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - }, - "tags": [ - { - "type": "SkillType", - "skillType": "Meta" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" - }, - { - "id": "herald_res_eff_inc", - "pattern": "(\\d+)% increased reservation efficiency of herald skills", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", - "mods": [ - { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - }, - "tags": [ - { - "type": "SkillType", - "skillType": "Herald" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" - }, - { - "id": "herald_res_eff_red", - "pattern": "(\\d+)% reduced reservation efficiency of herald skills", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", - "mods": [ - { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - }, - "tags": [ - { - "type": "SkillType", - "skillType": "Herald" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" - }, - { - "id": "spirit_res_eff_inc", - "pattern": "(\\d+)% increased spirit reservation efficiency of skills", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", - "mods": [ - { - "name": "SpiritReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - } - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" - }, - { - "id": "spirit_res_eff_red", - "pattern": "(\\d+)% reduced spirit reservation efficiency of skills", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", - "mods": [ - { - "name": "SpiritReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" - }, - { - "id": "totems_reserve_spirit_each", - "pattern": "totems reserve (\\d+) spirit each", - "vendor_pattern": "(ModParser.lua:4644 Ancestral Bond;run-parsemod 实证双 mod)", - "mods": [ - { - "name": "AncestralBond", - "type": "FLAG", - "value": true - }, - { - "name": "ExtraSpirit", - "type": "BASE", - "value": { - "ref": "$1" - }, - "tags": [ - { - "type": "SkillType", - "skillType": "SummonsTotem" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 45202「Ancestral Bond」Totems reserve 75 Spirit each;消费=spirit_reservation_modifiers totem 入选分支(SummonsTotem×AncestralBond flag,CalcDefence.lua:197)+ ExtraSpirit per-gem Sum;legacy parse_totem_spirit_reservation 同形过树闸门" - }, - { - "id": "banner_aura_magnitudes_inc", - "pattern": "banner skills have (\\d+)% increased aura magnitudes", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", - "mods": [ - { - "name": "AuraEffect", - "type": "INC", - "value": { - "ref": "$1" - }, - "tags": [ - { - "type": "SkillType", - "skillType": "Banner" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" - }, - { - "id": "aura_skills_magnitudes_inc", - "pattern": "aura skills have (\\d+)% increased magnitudes", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", - "mods": [ - { - "name": "Magnitude", - "type": "INC", - "value": { - "ref": "$1" - }, - "tags": [ - { - "type": "SkillType", - "skillType": "Aura" - } - ] - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" - }, - { - "id": "aura_magnitudes_bare_inc", - "pattern": "(\\d+)% increased aura magnitudes", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", - "mods": [ - { - "name": "AuraEffect", - "type": "INC", - "value": { - "ref": "$1" - } - } - ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" + "batch": "wave2-defence", + "source_note": "ModParser.lua:4372(四 flag 全套)。消费端 defence_panels.rs:174 消费 BlockChance/SpellBlockChance 两口径;Projectile/SpellProjectile 两 flag 目前无消费端(pobr 未算 projectile block 有效值),形态先对齐 vendor" } ] } diff --git a/data/4.5.4.3/overlay/vendor_name_aliases.json b/data/4.5.4.3/overlay/vendor_name_aliases.json deleted file mode 100644 index 2dcae192..00000000 --- a/data/4.5.4.3/overlay/vendor_name_aliases.json +++ /dev/null @@ -1,510 +0,0 @@ -{ - "_meta": { - "schema": "vendor_name_aliases/v1", - "purpose": "vendor PoB2 ModName -> PoBR canonical StatId 别名表(M6.3 切换前置数据资产)。", - "consumed_by": "NONE(纯数据资产;A 路线=引擎产物运行期翻译表 / B 路线=extract-lua 抽取期归一。owner 定夺后 D-T8 接线)。", - "generated_from": [ - "crates/pobr-core/src/mod_parser/legacy.rs::parse_name (PoBR 短语->StatId)", - "data/4.5.0.3.4/overlay/mod_parser_rules.json::name_map (vendor 短语->vendor名)" - ], - "bootstrap_method": "对齐同一触发短语:legacy 与 engine 都把短语 P 解析出单一 ModName 时,engine 名(vendor)->legacy 名(PoBR) 即一条别名。多名(聚合)短语与 damage-flag dispatch 短语不入纯别名表,登记于 structural_deferrals。", - "vendor_commit": "2df5a7433dd2f1609e2fad8a6c3c917f923fe34f", - "dualrun_report": "audits/rearchitecture-2026-06-10/blueprints/m6-dualrun-report.md", - "report": "audits/rearchitecture-2026-06-10/blueprints/m6-alias-table.md", - "coverage_note": "覆盖全部 358 name-only DIFF 涉及的 distinct stat 名(dual-run 样例 8/8 命中)。real-rename=20, identity=56, 共 76 vendor 名。" - }, - "aliases": [ - { - "vendor_name": "Accuracy", - "pobr_stat_id": "Accuracy", - "identity": true, - "via_phrase": "accuracy" - }, - { - "vendor_name": "AilmentChance", - "pobr_stat_id": "AilmentChance", - "identity": true, - "via_phrase": "chance to inflict ailments" - }, - { - "vendor_name": "AilmentThreshold", - "pobr_stat_id": "AilmentThreshold", - "identity": true, - "via_phrase": "ailment threshold" - }, - { - "vendor_name": "ArcaneSurgeEffect", - "pobr_stat_id": "ArcaneSurgeEffect", - "identity": true, - "via_phrase": "effect of arcane surge on you" - }, - { - "vendor_name": "Armour", - "pobr_stat_id": "Armour", - "identity": true, - "via_phrase": "armour" - }, - { - "vendor_name": "AvoidStun", - "pobr_stat_id": "AvoidStun", - "identity": true, - "via_phrase": "to avoid being stunned" - }, - { - "vendor_name": "BlockChance", - "pobr_stat_id": "BlockChance", - "identity": true, - "via_phrase": "to block" - }, - { - "vendor_name": "BlockChanceMax", - "pobr_stat_id": "BlockChanceMax", - "identity": true, - "via_phrase": "maximum block chance" - }, - { - "vendor_name": "ChaosDamage", - "pobr_stat_id": "ChaosDamage", - "identity": true, - "via_phrase": "chaos damage" - }, - { - "vendor_name": "ChaosDamageTaken", - "pobr_stat_id": "ChaosDamageTaken", - "identity": true, - "via_phrase": "chaos damage taken" - }, - { - "vendor_name": "ChaosResist", - "pobr_stat_id": "ChaosResistance", - "identity": false, - "via_phrase": "chaos resistance" - }, - { - "vendor_name": "ChaosResistMax", - "pobr_stat_id": "MaximumChaosResistance", - "identity": false, - "via_phrase": "maximum chaos resistance" - }, - { - "vendor_name": "ColdDamage", - "pobr_stat_id": "ColdDamage", - "identity": true, - "via_phrase": "cold damage" - }, - { - "vendor_name": "ColdDamageTaken", - "pobr_stat_id": "ColdDamageTaken", - "identity": true, - "via_phrase": "cold damage taken" - }, - { - "vendor_name": "ColdExposureEffect", - "pobr_stat_id": "ColdExposureEffect", - "identity": true, - "via_phrase": "cold exposure effect" - }, - { - "vendor_name": "ColdResist", - "pobr_stat_id": "ColdResistance", - "identity": false, - "via_phrase": "cold resistance" - }, - { - "vendor_name": "ColdResistMax", - "pobr_stat_id": "MaximumColdResistance", - "identity": false, - "via_phrase": "maximum cold resistance" - }, - { - "vendor_name": "CooldownRecovery", - "pobr_stat_id": "CooldownRecovery", - "identity": true, - "via_phrase": "cooldown recovery" - }, - { - "vendor_name": "CostEfficiency", - "pobr_stat_id": "CostEfficiency", - "identity": true, - "via_phrase": "cost efficiency" - }, - { - "vendor_name": "CritChance", - "pobr_stat_id": "CriticalStrikeChance", - "identity": false, - "via_phrase": "critical hit chance" - }, - { - "vendor_name": "CritMultiplier", - "pobr_stat_id": "CriticalStrikeMultiplier", - "identity": false, - "via_phrase": "critical damage bonus" - }, - { - "vendor_name": "DamageTaken", - "pobr_stat_id": "DamageTaken", - "identity": true, - "via_phrase": "damage taken" - }, - { - "vendor_name": "DeflectEffect", - "pobr_stat_id": "DeflectEffect", - "identity": true, - "via_phrase": "amount of damage prevented by deflection" - }, - { - "vendor_name": "DeflectionRating", - "pobr_stat_id": "DeflectionRating", - "identity": true, - "via_phrase": "deflection rating" - }, - { - "vendor_name": "Dex", - "pobr_stat_id": "Dexterity", - "identity": false, - "via_phrase": "dexterity" - }, - { - "vendor_name": "ElementalDamage", - "pobr_stat_id": "ElementalDamage", - "identity": true, - "via_phrase": "elemental damage" - }, - { - "vendor_name": "ElementalDamageTaken", - "pobr_stat_id": "ElementalDamageTaken", - "identity": true, - "via_phrase": "elemental damage taken" - }, - { - "vendor_name": "ElementalResistMax", - "pobr_stat_id": "MaximumAllElementalResistances", - "identity": false, - "via_phrase": "all maximum elemental resistances" - }, - { - "vendor_name": "EnemyBleedDuration", - "pobr_stat_id": "BleedDuration", - "identity": false, - "via_phrase": "bleed duration" - }, - { - "vendor_name": "EnemyFreezeBuildup", - "pobr_stat_id": "FreezeBuildup", - "identity": false, - "via_phrase": "freeze buildup" - }, - { - "vendor_name": "EnemyIgniteChance", - "pobr_stat_id": "EnemyIgniteChance", - "identity": true, - "via_phrase": "to ignite" - }, - { - "vendor_name": "EnemyIgniteDuration", - "pobr_stat_id": "IgniteDuration", - "identity": false, - "via_phrase": "ignite duration" - }, - { - "vendor_name": "EnemyPoisonDuration", - "pobr_stat_id": "PoisonDuration", - "identity": false, - "via_phrase": "poison duration" - }, - { - "vendor_name": "EnergyShield", - "pobr_stat_id": "EnergyShield", - "identity": true, - "via_phrase": "maximum energy shield" - }, - { - "vendor_name": "EvadeChance", - "pobr_stat_id": "EvadeChance", - "identity": true, - "via_phrase": "to evade" - }, - { - "vendor_name": "Evasion", - "pobr_stat_id": "Evasion", - "identity": true, - "via_phrase": "evasion" - }, - { - "vendor_name": "FireDamage", - "pobr_stat_id": "FireDamage", - "identity": true, - "via_phrase": "fire damage" - }, - { - "vendor_name": "FireDamageTaken", - "pobr_stat_id": "FireDamageTaken", - "identity": true, - "via_phrase": "fire damage taken" - }, - { - "vendor_name": "FireExposureEffect", - "pobr_stat_id": "FireExposureEffect", - "identity": true, - "via_phrase": "fire exposure effect" - }, - { - "vendor_name": "FireResist", - "pobr_stat_id": "FireResistance", - "identity": false, - "via_phrase": "fire resistance" - }, - { - "vendor_name": "FireResistMax", - "pobr_stat_id": "MaximumFireResistance", - "identity": false, - "via_phrase": "maximum fire resistance" - }, - { - "vendor_name": "Int", - "pobr_stat_id": "Intelligence", - "identity": false, - "via_phrase": "intelligence" - }, - { - "vendor_name": "Life", - "pobr_stat_id": "MaximumLife", - "identity": false, - "via_phrase": "maximum life" - }, - { - "vendor_name": "LifeCost", - "pobr_stat_id": "LifeCost", - "identity": true, - "via_phrase": "life cost" - }, - { - "vendor_name": "LifeCostEfficiency", - "pobr_stat_id": "LifeCostEfficiency", - "identity": true, - "via_phrase": "life cost efficiency" - }, - { - "vendor_name": "LifeRegen", - "pobr_stat_id": "LifeRegen", - "identity": true, - "via_phrase": "life regeneration rate" - }, - { - "vendor_name": "LifeReservationEfficiency", - "pobr_stat_id": "LifeReservationEfficiency", - "identity": true, - "via_phrase": "life reservation efficiency" - }, - { - "vendor_name": "LightningDamage", - "pobr_stat_id": "LightningDamage", - "identity": true, - "via_phrase": "lightning damage" - }, - { - "vendor_name": "LightningDamageTaken", - "pobr_stat_id": "LightningDamageTaken", - "identity": true, - "via_phrase": "lightning damage taken" - }, - { - "vendor_name": "LightningExposureEffect", - "pobr_stat_id": "LightningExposureEffect", - "identity": true, - "via_phrase": "lightning exposure effect" - }, - { - "vendor_name": "LightningResist", - "pobr_stat_id": "LightningResistance", - "identity": false, - "via_phrase": "lightning resistance" - }, - { - "vendor_name": "LightningResistMax", - "pobr_stat_id": "MaximumLightningResistance", - "identity": false, - "via_phrase": "maximum lightning resistance" - }, - { - "vendor_name": "LootRarity", - "pobr_stat_id": "LootRarity", - "identity": true, - "via_phrase": "rarity of items found" - }, - { - "vendor_name": "Mana", - "pobr_stat_id": "MaximumMana", - "identity": false, - "via_phrase": "maximum mana" - }, - { - "vendor_name": "ManaCost", - "pobr_stat_id": "ManaCost", - "identity": true, - "via_phrase": "mana cost" - }, - { - "vendor_name": "ManaCostEfficiency", - "pobr_stat_id": "ManaCostEfficiency", - "identity": true, - "via_phrase": "mana cost efficiency" - }, - { - "vendor_name": "ManaRegen", - "pobr_stat_id": "ManaRegen", - "identity": true, - "via_phrase": "mana regeneration rate" - }, - { - "vendor_name": "ManaReservationEfficiency", - "pobr_stat_id": "ManaReservationEfficiency", - "identity": true, - "via_phrase": "mana reservation efficiency" - }, - { - "vendor_name": "MaxLightningDamage", - "pobr_stat_id": "MaxLightningDamage", - "identity": true, - "via_phrase": "maximum lightning damage" - }, - { - "vendor_name": "MaxPhysicalDamage", - "pobr_stat_id": "MaxPhysicalDamage", - "identity": true, - "via_phrase": "maximum physical attack damage" - }, - { - "vendor_name": "MeleeEvadeChance", - "pobr_stat_id": "MeleeEvadeChance", - "identity": true, - "via_phrase": "chance to evade melee attacks" - }, - { - "vendor_name": "MinPhysicalDamage", - "pobr_stat_id": "MinPhysicalDamage", - "identity": true, - "via_phrase": "minimum physical attack damage" - }, - { - "vendor_name": "MovementSpeed", - "pobr_stat_id": "MovementSpeed", - "identity": true, - "via_phrase": "movement speed" - }, - { - "vendor_name": "PhysicalDamage", - "pobr_stat_id": "PhysicalDamage", - "identity": true, - "via_phrase": "physical damage" - }, - { - "vendor_name": "PhysicalDamageTaken", - "pobr_stat_id": "PhysicalDamageTaken", - "identity": true, - "via_phrase": "physical damage taken" - }, - { - "vendor_name": "ProjectileEvadeChance", - "pobr_stat_id": "ProjectileEvadeChance", - "identity": true, - "via_phrase": "chance to evade projectile attacks" - }, - { - "vendor_name": "ProjectileSpeed", - "pobr_stat_id": "ProjectileSpeed", - "identity": true, - "via_phrase": "projectile speed" - }, - { - "vendor_name": "ReservationEfficiency", - "pobr_stat_id": "ReservationEfficiency", - "identity": true, - "via_phrase": "reservation efficiency" - }, - { - "vendor_name": "SpellBlockChance", - "pobr_stat_id": "SpellBlockChance", - "identity": true, - "via_phrase": "spell block chance" - }, - { - "vendor_name": "SpellBlockChanceMax", - "pobr_stat_id": "SpellBlockChanceMax", - "identity": true, - "via_phrase": "maximum chance to block spell damage" - }, - { - "vendor_name": "SpellEvadeChance", - "pobr_stat_id": "SpellEvadeChance", - "identity": true, - "via_phrase": "chance to evade spells" - }, - { - "vendor_name": "Spirit", - "pobr_stat_id": "Spirit", - "identity": true, - "via_phrase": "spirit" - }, - { - "vendor_name": "SpiritReservationEfficiency", - "pobr_stat_id": "SpiritReservationEfficiency", - "identity": true, - "via_phrase": "spirit reservation efficiency" - }, - { - "vendor_name": "Str", - "pobr_stat_id": "Strength", - "identity": false, - "via_phrase": "strength" - }, - { - "vendor_name": "StunThreshold", - "pobr_stat_id": "StunThreshold", - "identity": true, - "via_phrase": "stun threshold" - }, - { - "vendor_name": "Ward", - "pobr_stat_id": "Ward", - "identity": true, - "via_phrase": "ward" - } - ], - "structural_deferrals": { - "note": "以下不入纯 name 别名表——需语义归一规则(见 m6-alias-table.md 结构四类),非单纯改名。", - "aggregate_expansion_or_flag_dispatch_phrases": [ - { - "phrase": "skill speed", - "legacy": "SkillSpeed", - "engine_names": [ - "Speed", - "WarcrySpeed", - "TotemPlacementSpeed" - ], - "class": "aggregate" - } - ], - "damage_flag_dispatch_phrases": [ - "spell damage", - "area damage", - "grenade damage", - "damage with bow", - "damage with bows", - "damage with bow skills", - "damage with crossbows", - "damage with crossbow skills", - "damage with maces", - "damage with mace", - "damage with mace skills", - "damage with spears", - "damage with spear", - "damage with spear skills", - "damage with quarterstaves", - "damage with quarterstaff", - "damage with quarterstaff skills", - "elemental damage with attacks", - "elemental damage with attack skills" - ] - } -} \ No newline at end of file diff --git a/data/4.5.0.3.4/overlay/buff_definitions.json b/data/overlay-common/buff_definitions.json similarity index 91% rename from data/4.5.0.3.4/overlay/buff_definitions.json rename to data/overlay-common/buff_definitions.json index 3f88e557..649caa25 100644 --- a/data/4.5.0.3.4/overlay/buff_definitions.json +++ b/data/overlay-common/buff_definitions.json @@ -4,11 +4,11 @@ "Modules/CalcPerform.lua" ], "generator": "manual-curation (00-index 裁决 §4.2-4 批准的 overlay 通道例外)", - "regen_command": "人工归纳(doActorMisc :503-765 过程式 if-chain 无法 luajit 序列化);vendor 升级后跑 `cargo run -p sync-pob-catalog -- check-buff-refs --vendor-root vendor/PathOfBuilding-PoE2/src --defs data/4.5.0.3.4/overlay/buff_definitions.json` 对账,人工复核后 --write 刷新行段 hash", + "regen_command": "人工归纳(doActorMisc :578-850 过程式 if-chain 无法 luajit 序列化);vendor 升级后跑 `cargo run -p sync-pob-catalog -- check-buff-refs --vendor-root vendor/PathOfBuilding-PoE2/src --defs data/overlay-common/buff_definitions.json` 对账,人工复核后 --write 刷新行段 hash", "schema": "buff_definitions/v1", "vendor": "PathOfBuilding-PoE2", - "vendor_commit": "2df5a7433dd2f1609e2fad8a6c3c917f923fe34f", - "vendor_commit_subject": "2df5a74 Fix crash when importing a character that uses Facebreaker gloves (#2098)" + "vendor_commit": "ce8bffaba31f8e68cfce70579e1c96465e7c133c", + "vendor_commit_subject": "ce8bffa Fix Liminal Coil counting Marks as Curses (#2365)" }, "buffs": [ { @@ -78,8 +78,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 586, - "line_end": 593, + "line_start": 661, + "line_end": 668, "segment_hash": "fnv1a64:e3f46c64c93e2f77" }, "notes": "vendor 逐 mod m_floor(coeff × effectMod),effect 级不取整" @@ -125,8 +125,8 @@ "verified": true, "vendor_ref": { "file": "Modules/CalcDefence.lua", - "line_start": 1580, - "line_end": 1591, + "line_start": 1606, + "line_end": 1617, "segment_hash": "fnv1a64:144064cc425efef2" }, "notes": "基本形(默认 15% Cast Speed / 20% more ManaRegen × effect,effect=1+Σinc/100 不取整,vendor 无 floor)。未覆盖分支:Max(ArcaneSurgeCastSpeed/ManaRegen) 覆写、ArcaneSurgeLifeRegen flag(LifeRegen 改道)、ArcaneSurgeDamage(Spell Damage MORE)——均无树/装备样本,出现时升级 handler。" @@ -156,8 +156,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 582, - "line_end": 585, + "line_start": 657, + "line_end": 660, "segment_hash": "fnv1a64:dbd8f9c8a44c9452" } }, @@ -185,8 +185,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 594, - "line_end": 597, + "line_start": 669, + "line_end": 672, "segment_hash": "fnv1a64:4abf1b725bc2c12b" } }, @@ -198,8 +198,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 612, - "line_end": 631, + "line_start": 687, + "line_end": 706, "segment_hash": "fnv1a64:36b76d63b4ee74c6" }, "notes": "真逻辑:Max({source=Skill}) 查询 + Override 上限 + Nightblade 交互 + 输出字段 ElusiveEffectMod" @@ -212,8 +212,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 571, - "line_end": 576, + "line_start": 646, + "line_end": 651, "segment_hash": "fnv1a64:7d71030ed94f4da6" }, "notes": "真逻辑:selfCast 门控需 mainSkill.activeEffect.srcInstance 状态;公式 = floor(75×(1+BuffEffectOnSelf/100)) → Speed MORE / Cost INC -e / AoE INC(全 Cast flag)" @@ -226,8 +226,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 524, - "line_end": 538, + "line_start": 599, + "line_end": 613, "segment_hash": "fnv1a64:9e63cf1ecf4d6c25" }, "notes": "真逻辑:stacks 模型(Maximum/Minimum/Override Fortification + alliedFortify)→ DamageTakenWhenHit MORE -floor((1+BuffEffectOnSelf/100)×stacks);触发还含 Multiplier:Fortification > 0 分支" @@ -260,8 +260,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 684, - "line_end": 687, + "line_start": 760, + "line_end": 763, "segment_hash": "fnv1a64:b64bb12d1a1a4549" }, "notes": "calcLib.mod = (1+ΣINC/100)×ΠMORE;vendor m_max(m_floor(70×mod),0)——floor 在 clamp 前,与 effect 公式序一致" @@ -351,8 +351,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 598, - "line_end": 608, + "line_start": 673, + "line_end": 683, "segment_hash": "fnv1a64:7ccc1cb631cff09f" }, "notes": "全字面量(不吃 BuffEffectOnSelf 缩放)" @@ -382,8 +382,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 748, - "line_end": 751, + "line_start": 824, + "line_end": 827, "segment_hash": "fnv1a64:679897be912337f4" } }, @@ -412,8 +412,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 744, - "line_end": 747, + "line_start": 820, + "line_end": 823, "segment_hash": "fnv1a64:56f9043453784061" } }, @@ -472,8 +472,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 539, - "line_end": 570, + "line_start": 614, + "line_end": 645, "segment_hash": "fnv1a64:e6f99ba533f1ffe3" }, "notes": "基本形(不含 Silver Flask 分支——见 OnslaughtFlask handler 条目);effect = floor(10×(1+Σinc/100))" @@ -486,8 +486,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 539, - "line_end": 570, + "line_start": 614, + "line_end": 645, "segment_hash": "fnv1a64:e6f99ba533f1ffe3" }, "notes": "真逻辑:Silver Flask 来源时 effect 计入 flaskData.effectInc + FlaskEffect/MagicUtilityFlaskEffect INC(依赖 M3-T4 flask merge,M3 末接通)" @@ -509,8 +509,8 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 752, - "line_end": 754, + "line_start": 828, + "line_end": 830, "segment_hash": "fnv1a64:7b53c45448fcec95" } }, @@ -553,9 +553,9 @@ "verified": false, "vendor_ref": { "file": "Modules/CalcPerform.lua", - "line_start": 577, - "line_end": 581, - "segment_hash": "fnv1a64:6ffdd69243656a03" + "line_start": 652, + "line_end": 656, + "segment_hash": "fnv1a64:91e4f9947ce02683" }, "notes": "vendor 注释:Magnitude 经 Multiplier 实现(perStat 数据该阶段不可用);DamageGainAsChaos = 0.3×(1+BuffEffectOnSelf/100) per Multiplier" } diff --git a/data/4.5.0.3.4/overlay/high_precision_mods.json b/data/overlay-common/high_precision_mods.json similarity index 100% rename from data/4.5.0.3.4/overlay/high_precision_mods.json rename to data/overlay-common/high_precision_mods.json diff --git a/data/4.5.0.3.4/overlay/local_mods.json b/data/overlay-common/local_mods.json similarity index 100% rename from data/4.5.0.3.4/overlay/local_mods.json rename to data/overlay-common/local_mods.json diff --git a/data/4.5.0.3.4/overlay/special_mods.json b/data/overlay-common/special_mods.json similarity index 97% rename from data/4.5.0.3.4/overlay/special_mods.json rename to data/overlay-common/special_mods.json index 9f257610..887a60cd 100644 --- a/data/4.5.0.3.4/overlay/special_mods.json +++ b/data/overlay-common/special_mods.json @@ -11,169 +11,6 @@ "regen_command": "(手工策展域:本字段记录对账命令而非再生命令)sync-pob-catalog check --special-coverage(M5b A-3 落地后启用)" }, "entries": [ - { - "id": "eternal_life_while_energy_shield", - "pattern": "your life cannot change while you have energy shield", - "vendor_pattern": "your life cannot change while you have energy shield", - "mods": [ - { - "name": "EternalLife", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:3144(-- Lich specialModList,flag(EternalLife));legacy 经 max-hit ES bypass 消费(pool_damage.rs)。fork-a 迁入补 engine 数据驱动 special 通道缺口(detonate-dead MaxHit/EHP 偏低)" - }, - { - "id": "blood_mage_additional_life_from_body_es", - "pattern": "gain additional maximum life equal to 100% of the (?:item )?energy shield on equipped body armour", - "vendor_pattern": "gain additional maximum life equal to (%d+)%% of the (i?t?e?m? ?)energy shield on equipped body armour", - "mods": [ - { - "name": "MaximumLife", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "Multiplier", - "var": "EnergyShieldOnbodyarmour", - "div": 1 - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:2834(-- Blood Mage specialModList,mod(Life,BASE,1,PerStat{stat=EnergyShieldOnBody Armour,div=100/N});legacy.rs:1796-1810 同形(MaximumLife BASE 1 × Multiplier:EnergyShieldOnbodyarmour,div=100/N,slot 倍率经 orchestrator per_slot_defence_multipliers 填充 = Body Armour 件级最终 ES)。本条钉 N=100(升华恒 100%,corpus 唯一形)→ div=1;special 整行命中在 pre_flag 剥 `gain` 前。需 special_mod.rs 字面 Multiplier tag 支持。fork-a 补 engine special 通道(blood-mage Life→EHP/MaxHit 级联)" - }, - { - "id": "life_loss_from_hits_prevented_over_4s", - "pattern": "(\\d+(?:\\.\\d+)?)% of life loss from hits is prevented, then that much life is lost over 4 seconds instead", - "vendor_pattern": "(%d+)%% of life loss from hits is prevented, then that much life is lost over 4 seconds instead", - "mods": [ - { - "name": "LifeLossPrevented", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:2839 function(num)→mod(LifeLossPrevented,BASE,num);legacy.rs:1824-1827 同。pool_setup.rs:104 `min(ΣLifeLossPrevented,100)` 减伤(max-hit 机制)。vendor 函数形,extract 抽不出静态模板 → 引擎误解析为 MaximumLife BASE 25。fork-a 补 engine special(blood-mage EHP/五类 MaxHit 0.88x)" - }, - { - "id": "fire_damage_while_affected_by_herald_of_ash", - "pattern": "(\\d+(?:\\.\\d+)?)% increased fire damage while affected by herald of ash", - "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2536 硬编码]", - "mods": [ - { - "name": "FireDamage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "AffectedByHeraldofAsh" - }, - { - "type": "DamageType", - "damageType": "Fire" - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "vendor `while affected by (%a+)` modTagList 单词捕获抽不出多词「Herald of Ash」+ 多元素 varList 引擎丢弃 → engine 无条件应用、泄漏进 dot(grenade/ice-shot dot over-count)。legacy.rs:2536 硬编码 `AffectedByHeraldofAsh`。整行 data 化对齐 legacy(FireDamage INC + Condition + DamageType)" - }, - { - "id": "cold_damage_while_affected_by_herald_of_ice", - "pattern": "(\\d+(?:\\.\\d+)?)% increased cold damage while affected by herald of ice", - "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2532 硬编码]", - "mods": [ - { - "name": "ColdDamage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "AffectedByHeraldofIce" - }, - { - "type": "DamageType", - "damageType": "Cold" - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "同 fire_damage_while_affected_by_herald_of_ash;legacy.rs:2532 `AffectedByHeraldofIce`" - }, - { - "id": "lightning_damage_while_affected_by_herald_of_thunder", - "pattern": "(\\d+(?:\\.\\d+)?)% increased lightning damage while affected by herald of thunder", - "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2540 硬编码]", - "mods": [ - { - "name": "LightningDamage", - "type": "INC", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "AffectedByHeraldofThunder" - }, - { - "type": "DamageType", - "damageType": "Lightning" - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "同 fire_damage_while_affected_by_herald_of_ash;legacy.rs:2540 `AffectedByHeraldofThunder`" - }, - { - "id": "body_armour_grants_of_armour_also_applies_to_chaos_damage", - "pattern": "body armour grants \\+?(\\d+)% of armour also applies to (chaos) damage", - "vendor_pattern": "body armour grants %+(%d+)%% of armour also applies to (%a+) damage", - "mods": [ - { - "name": "ArmourAppliesToChaosDamageTaken", - "type": "BASE", - "value": "$1", - "tags": [ - { - "type": "Condition", - "var": "NormalBodyArmourEquipped" - } - ] - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:3281 -- Warrior - Smith of Kitava,function(num,_,dmgType)→mod(ArmourAppliesToDamageTaken,BASE,num,{type=ItemCondition,itemSlot=Body Armour,rarityCond=NORMAL})。vendor 函数形带 (%a+) 伤害类型捕获 + ItemCondition,extract_parser_rules 抽不出(S2 批仅手转非 body-armour 的 fire/cold/lightning 三元素,漏 chaos + 漏 body-armour-grants 变体)。legacy 经 body-armour-grants 前缀剥离 + parse_armour_applies_pct(legacy.rs:393/1621)通用处理任意类型,chaos 正常,故 engine 落后 legacy。本条把 vendor ItemCondition{Body Armour,NORMAL} 映射为 pobr `Condition:NormalBodyArmourEquipped`(orchestrator calc_orchestrator.rs:373 按体甲槽 Normal 稀有度置真,与 legacy.rs:397 同口径),消费侧 taken.rs ArmourAppliesToChaosDamageTaken。修 warrior-smith-of-kitava-shield-wall ChaosMaxHit 0.84x→1.00x" - }, - { - "id": "prevent_pct_of_damage_from_deflected_hits", - "pattern": "prevent \\+(\\d+(?:\\.\\d+)?)% of damage from deflected hits", - "vendor_pattern": "prevent %+(%d+)%% of damage from deflected hits", - "mods": [ - { - "name": "DeflectEffect", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "fork-a", - "source_note": "ModParser.lua:4191 function(num)→mod(DeflectEffect,BASE,num);legacy.rs:1721 parse_deflection_special 同。defence_panels.rs:241 偏斜减伤=基础40+ΣBASE DeflectEffect,clamp[0,100](DeflectChance 58% 时生效,非仅≥100)。vendor 函数形 extract 抽不出 → 引擎丢弃(twister 缺 DeflectEffect 3+6=9 → 偏斜减伤 40 而非 49 → EHP 0.89x)。捕获形一条匹配全部 N。fork-a 补 engine special(monk-martial-artist-twister TotalEHP)" - }, { "id": "all_damage_is_taken_from_mana_before_life", "pattern": "all damage is taken from mana before life", @@ -532,66 +369,6 @@ "batch": "S2", "source_note": "ModParser.lua:4275(探针求值自动转写;样本:Curses you inflict ignore Curse limit)" }, - { - "id": "you_can_apply_an_additional_curse", - "pattern": "you can apply an additional curse", - "vendor_pattern": "you can apply an additional curse", - "mods": [ - { - "name": "EnemyCurseLimit", - "type": "BASE", - "value": 1 - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:4303(Whispers of Doom keystone tree 47759 第一行『You can apply an additional Curse』;第二行 Double Activation Delay 已在 double_activation_delay_of_curses 条目)。缺它时 frost-bomb 第二诅咒 Elemental Weakness 被挤出唯一槽,敌侧 -45 元素抗丢失(CritChance 路径外的 hit 伤害缺口)" - }, - { - "id": "enemies_can_have_1_additional_curse", - "pattern": "enemies can have 1 additional curse", - "vendor_pattern": "enemies can have 1 additional curse", - "mods": [ - { - "name": "EnemyCurseLimit", - "type": "BASE", - "value": 1 - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:4302(curse limit 平表同族)" - }, - { - "id": "you_can_apply_one_fewer_curse", - "pattern": "you can apply one fewer curse", - "vendor_pattern": "you can apply one fewer curse", - "mods": [ - { - "name": "EnemyCurseLimit", - "type": "BASE", - "value": -1 - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:4306(curse limit 平表同族)" - }, - { - "id": "you_can_apply_an_additional_mark", - "pattern": "you can apply an additional mark", - "vendor_pattern": "you can apply an additional mark", - "mods": [ - { - "name": "EnemyMarkLimit", - "type": "BASE", - "value": 1 - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:4309(mark limit 平表同族)" - }, { "id": "defend_with_pct_of_armour", "pattern": "defend with (\\d+(?:\\.\\d+)?)% of armour(?: during effect)?", @@ -614,21 +391,6 @@ "batch": "S2", "source_note": "ModParser.lua:2616/:2619(Defend with N% of Armour [during effect] → ArmourDefense BASE N-100;pobr 准源 legacy.rs:1715。during effect 变体同无条件,消费侧 max_of)" }, - { - "id": "es_added_to_armour_for_pdr", - "pattern": "(\\d+(?:\\.\\d+)?)% of your current energy shield is added to your armour for determining your physical damage reduction from armour", - "vendor_pattern": "(%d+)%% of your current energy shield is added to your armour for determining your physical damage reduction from armour", - "mods": [ - { - "name": "EnergyShieldAppliesToPhysicalDamageTaken", - "type": "BASE", - "value": "$1" - } - ], - "verified": false, - "batch": "hand-curated", - "source_note": "ModParser.lua:2917-2919(Disciple of Varashta 升华 Sacred Rituals,tree node 56857 —— N% of your current Energy Shield is added to your Armour for determining your Physical Damage Reduction from Armour → EnergyShieldAppliesToPhysicalDamageTaken BASE N)。消费 taken.rs effective_applied_armour 的 from_es 借入项(CalcDefence.lua:2358-2367)。pobr 准源 legacy.rs parse_defence_numeric_sentence(须走 legacy 以过 collect.rs::combine_wrapped_then_filter 树 stat 闸门)。" - }, { "id": "double_activation_delay_of_curses", "pattern": "double activation delay of curses", @@ -1691,958 +1453,1252 @@ "source_note": "pobr 准源 mod_parser.rs:490-506;vendor 无数值形同 key(仅 lucky 系 :3730-3732)" }, { - "id": "bonded_modifiers_enabler", - "pattern": "gain the benefits of bonded modifiers on runes and idols", - "vendor_pattern": "gain the benefits of bonded modifiers on runes and idols", + "id": "stun_threshold_from_es_8", + "pattern": "gain additional stun threshold equal to 8% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "Condition:CanUseBondedModifiers", - "type": "FLAG", - "value": true - } - ], - "verified": false, - "batch": "M6-3b", - "source_note": "ModParser.lua:3418-3419(Druid Oracle specialModList 整行;flag(Condition:CanUseBondedModifiers) 解锁 'Bonded:' 前缀词条,vendor :1437)" - }, - { - "id": "take_pct_less_damage", - "pattern": "take (\\d+)% less damage", - "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% less Damage)", - "mods": [ - { - "name": "DamageTaken", - "type": "MORE", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } + "name": "StunThreshold", + "type": "BASE", + "value": 1, + "tags": [ + { + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 8 + } + ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "take_pct_more_damage", - "pattern": "take (\\d+)% more damage", - "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% more Damage)", + "id": "stun_threshold_from_es_12", + "pattern": "gain additional stun threshold equal to 12% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "DamageTaken", - "type": "MORE", - "value": { - "ref": "$1" - } + "name": "StunThreshold", + "type": "BASE", + "value": 1, + "tags": [ + { + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 12 + } + ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "take_pct_reduced_damage", - "pattern": "take (\\d+)% reduced damage", - "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% reduced Damage)", + "id": "stun_threshold_from_es_15", + "pattern": "gain additional stun threshold equal to 15% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "DamageTaken", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } + "name": "StunThreshold", + "type": "BASE", + "value": 1, + "tags": [ + { + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 15 + } + ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "take_pct_increased_damage", - "pattern": "take (\\d+)% increased damage", - "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% increased Damage)", + "id": "stun_threshold_from_es_20", + "pattern": "gain additional stun threshold equal to 20% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "DamageTaken", - "type": "INC", - "value": { - "ref": "$1" - } + "name": "StunThreshold", + "type": "BASE", + "value": 1, + "tags": [ + { + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 20 + } + ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "meta_skills_res_eff_inc", - "pattern": "meta skills have (\\d+)% increased reservation efficiency", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "id": "stun_threshold_from_es_30", + "pattern": "gain additional stun threshold equal to 30% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - }, + "name": "StunThreshold", + "type": "BASE", + "value": 1, "tags": [ { - "type": "SkillType", - "skillType": "Meta" + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 30 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "meta_skills_res_eff_red", - "pattern": "meta skills have (\\d+)% reduced reservation efficiency", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "id": "ailment_threshold_from_es_8", + "pattern": "gain additional ailment threshold equal to 8% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - }, + "name": "AilmentThreshold", + "type": "BASE", + "value": 1, "tags": [ { - "type": "SkillType", - "skillType": "Meta" + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 8 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "herald_res_eff_inc", - "pattern": "(\\d+)% increased reservation efficiency of herald skills", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "id": "ailment_threshold_from_es_12", + "pattern": "gain additional ailment threshold equal to 12% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - }, + "name": "AilmentThreshold", + "type": "BASE", + "value": 1, "tags": [ { - "type": "SkillType", - "skillType": "Herald" + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 12 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "herald_res_eff_red", - "pattern": "(\\d+)% reduced reservation efficiency of herald skills", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "id": "ailment_threshold_from_es_15", + "pattern": "gain additional ailment threshold equal to 15% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - }, + "name": "AilmentThreshold", + "type": "BASE", + "value": 1, "tags": [ { - "type": "SkillType", - "skillType": "Herald" + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 15 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "spirit_res_eff_inc", - "pattern": "(\\d+)% increased spirit reservation efficiency of skills", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "id": "ailment_threshold_from_es_20", + "pattern": "gain additional ailment threshold equal to 20% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", "mods": [ { - "name": "SpiritReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - } + "name": "AilmentThreshold", + "type": "BASE", + "value": 1, + "tags": [ + { + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 20 + } + ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "spirit_res_eff_red", - "pattern": "(\\d+)% reduced spirit reservation efficiency of skills", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", - "mods": [ + "id": "ailment_threshold_from_es_30", + "pattern": "gain additional ailment threshold equal to 30% of maximum energy shield", + "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "mods": [ { - "name": "SpiritReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1", - "ops": [ - { - "negate": {} - } - ] - } + "name": "AilmentThreshold", + "type": "BASE", + "value": 1, + "tags": [ + { + "type": "PercentStat", + "stat": "EnergyShield", + "percent": 30 + } + ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" }, { - "id": "totems_reserve_spirit_each", - "pattern": "totems reserve (\\d+) spirit each", - "vendor_pattern": "(ModParser.lua:4644 Ancestral Bond;run-parsemod 实证双 mod)", + "id": "mana_regen_from_life_6", + "pattern": "regenerate mana equal to 6% of maximum life per second", + "vendor_pattern": "regenerate mana equal to (%d+)%% of maximum life per second", "mods": [ { - "name": "AncestralBond", - "type": "FLAG", - "value": true - }, - { - "name": "ExtraSpirit", + "name": "ManaRegen", "type": "BASE", - "value": { - "ref": "$1" - }, + "value": 1, "tags": [ { - "type": "SkillType", - "skillType": "SummonsTotem" + "type": "PercentStat", + "stat": "Life", + "percent": 6 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "tree node 45202「Ancestral Bond」Totems reserve 75 Spirit each;消费=spirit_reservation_modifiers totem 入选分支(SummonsTotem×AncestralBond flag,CalcDefence.lua:197)+ ExtraSpirit per-gem Sum;legacy parse_totem_spirit_reservation 同形过树闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "A2 真缺口 #28(oracle:ManaRegen BASE 1 + PercentStat{Life,6});DSL PercentStat 字面值——按语料数值钉 6" }, { - "id": "bonded_meta_res_eff_inc", - "pattern": "bonded: meta skills have (\\d+)% increased reservation efficiency", - "vendor_pattern": "(Bonded 前缀 + 域限定效率;见 source_note 口径说明)", + "id": "ailment_threshold_from_evasion_100", + "pattern": "gain 100% of evasion rating as extra ailment threshold", + "vendor_pattern": "gain (%d+)%% of evasion rating as extra ailment threshold", "mods": [ { - "name": "ReservationEfficiency", - "type": "INC", - "value": { - "ref": "$1" - }, + "name": "AilmentThreshold", + "type": "BASE", + "value": 1, "tags": [ { - "type": "Condition", - "var": "CanUseBondedModifiers" - }, - { - "type": "SkillType", - "skillType": "Meta" + "type": "PercentStat", + "stat": "Evasion", + "percent": 100 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "Bonded rune 变体(语料 C1 双跑对齐:legacy 的 bonded 递归会命中 parse_reservation_efficiency,引擎须同产出;Condition:CanUseBondedModifiers 默认不激活)。vendor 对前缀域形 Bonded 变体 unsupported(special 表不在前缀剥离后重查)——此处取 legacy 超集方向(条件门控恒 false 时零行为)" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "A2 真缺口 #24(oracle:AilmentThreshold BASE 1 + PercentStat{Evasion,100});玩家侧 AilmentThreshold 暂无 calc 消费——解析对齐 vendor,接线即生效" }, { - "id": "bonded_herald_res_eff_inc", - "pattern": "bonded: (\\d+)% increased reservation efficiency of herald skills", - "vendor_pattern": "(Bonded 前缀 + 域限定效率;见 source_note 口径说明)", + "id": "threshold_10_red_support_gems_5pct", + "pattern": "5% increased maximum life if you have at least 10 red support gems socketed", + "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", "mods": [ { - "name": "ReservationEfficiency", + "name": "MaximumLife", "type": "INC", - "value": { - "ref": "$1" - }, + "value": 5, "tags": [ { - "type": "Condition", - "var": "CanUseBondedModifiers" - }, - { - "type": "SkillType", - "skillType": "Herald" + "type": "MultiplierThreshold", + "var": "RedSupportGems", + "threshold": 10 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "Bonded rune 变体(语料 C1 双跑对齐:legacy 的 bonded 递归会命中 parse_reservation_efficiency,引擎须同产出;Condition:CanUseBondedModifiers 默认不激活)。vendor 对前缀域形 Bonded 变体 unsupported(special 表不在前缀剥离后重查)——此处取 legacy 超集方向(条件门控恒 false 时零行为)" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值;名归一 MaximumLife(parser name_map 口径,裸 Life 是死桶——wolf-pack 5% INC 漏计根因)" }, { - "id": "banner_aura_magnitudes_inc", - "pattern": "banner skills have (\\d+)% increased aura magnitudes", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", + "id": "threshold_10_blue_support_gems_5pct", + "pattern": "5% increased maximum mana if you have at least 10 blue support gems socketed", + "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", "mods": [ { - "name": "AuraEffect", + "name": "MaximumMana", "type": "INC", - "value": { - "ref": "$1" - }, + "value": 5, "tags": [ { - "type": "SkillType", - "skillType": "Banner" + "type": "MultiplierThreshold", + "var": "BlueSupportGems", + "threshold": 10 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值;名归一 MaximumMana(同 red 条目)" }, { - "id": "aura_skills_magnitudes_inc", - "pattern": "aura skills have (\\d+)% increased magnitudes", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", + "id": "threshold_10_green_support_gems_5pct", + "pattern": "5% increased movement speed if you have at least 10 green support gems socketed", + "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", "mods": [ { - "name": "Magnitude", + "name": "MovementSpeed", "type": "INC", - "value": { - "ref": "$1" - }, + "value": 5, "tags": [ { - "type": "SkillType", - "skillType": "Aura" + "type": "MultiplierThreshold", + "var": "GreenSupportGems", + "threshold": 10 } ] } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值" }, { - "id": "aura_magnitudes_bare_inc", - "pattern": "(\\d+)% increased aura magnitudes", - "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", + "id": "body_armour_grants_reduced_crit_damage_bonus_100", + "pattern": "body armour grants hits against you have 100% reduced critical damage bonus", + "vendor_pattern": "body armour grants hits against you have (%d+)%% reduced critical damage bonus", "mods": [ { - "name": "AuraEffect", - "type": "INC", - "value": { - "ref": "$1" - } + "name": "ReduceCritExtraDamage", + "type": "BASE", + "value": 100 } ], - "verified": true, - "batch": "hand-curated", - "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" + "verified": false, + "batch": "a2-real-gaps", + "source_note": "ModParser.lua:3284(mod(ReduceCritExtraDamage, BASE, num, ItemCondition{Body Armour, rarityCond=NORMAL});ItemCondition 无 PoBR 落点按 body-armour-grants pre_flag 族同口径丢弃(dropped-tag 报表 7 行同款欠条)——Smith of Kitava 机制要求白装胸甲,语料 build 满足故不 over-apply。语料数值集 {100} 钉值。消费方 defence.rs CritExtraDamageReduction 已存在" }, { - "id": "stun_threshold_from_es_8", - "pattern": "gain additional stun threshold equal to 8% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "body_armour_grants_unaffected_by_damaging_ailments", + "pattern": "body armour grants unaffected by damaging ailments", + "vendor_pattern": "body armour grants unaffected by damaging ailments", "mods": [ { - "name": "StunThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 8 - } - ] + "name": "SelfBleedEffect", + "type": "MORE", + "value": -100 + }, + { + "name": "SelfIgniteEffect", + "type": "MORE", + "value": -100 + }, + { + "name": "SelfPoisonEffect", + "type": "MORE", + "value": -100 } ], "verified": false, "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" + "source_note": "ModParser.lua:3288(Self{Bleed,Ignite,Poison}Effect MORE -100 ×3,ItemCondition 同上丢弃)。Self*Effect 玩家侧 calc 暂无消费(解析对齐 vendor,自异常效果消费端接线时词条已就位;AilmentThreshold 先例)" }, { - "id": "stun_threshold_from_es_12", - "pattern": "gain additional stun threshold equal to 12% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "break_armour_on_crit_with_spells", + "pattern": "break armour on critical hit with spells equal to (\\d+)% of physical damage dealt", + "vendor_pattern": "break armour on critical hit with spells equal to (%d+)%% of physical damage dealt", "mods": [ { - "name": "StunThreshold", - "type": "BASE", - "value": 1, + "name": "Condition:CanArmourBreak", + "type": "FLAG", + "value": true, "tags": [ { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 12 + "type": "Condition", + "neg": true, + "var": "NeverCrit" } ] } ], "verified": false, "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" + "source_note": "ModParser.lua:3803(flag(Condition:CanArmourBreak, GlobalEffect{Buff, ArmourBreak}, Condition{neg NeverCrit});数值不进 mods——vendor 同样忽略捕获,正则一条覆盖语料 {5,10}。GlobalEffect 无 PoBR 落点丢弃(已有评估:不值窄做);CanArmourBreak 玩家侧 calc 暂无消费(armour break 机制未建模,解析对齐 vendor)" }, { - "id": "stun_threshold_from_es_15", - "pattern": "gain additional stun threshold equal to 15% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "limit_for_elemental_skills", + "pattern": "\\+(\\d+) to limit for elemental skills", + "vendor_pattern": "%+(%d+) to limit for elemental skills", "mods": [ { - "name": "StunThreshold", + "name": "AdditionalCooldownUses", "type": "BASE", - "value": 1, + "value": "$1", "tags": [ { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 15 + "type": "SkillType", + "skillTypeList": [ + "Cold", + "Fire", + "Lightning" + ] } ] } ], "verified": false, "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" + "source_note": "ModParser.lua:3374(mod(AdditionalCooldownUses, BASE, num, SkillType{skillTypeList={Cold,Fire,Lightning}});skillTypeList → SkillTypes 位集并集(intersects 即 OR,与 vendor ModStore SkillType 任一命中同语义)。消费方 skill_mechanics.rs stored uses 已存在)" }, { - "id": "stun_threshold_from_es_20", - "pattern": "gain additional stun threshold equal to 20% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "bonded_modifiers_enabler", + "pattern": "gain the benefits of bonded modifiers on runes and idols", + "vendor_pattern": "gain the benefits of bonded modifiers on runes and idols", "mods": [ { - "name": "StunThreshold", - "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 20 - } - ] + "name": "Condition:CanUseBondedModifiers", + "type": "FLAG", + "value": true } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" + "batch": "M6-3b", + "source_note": "ModParser.lua:3418-3419(Druid Oracle specialModList 整行;flag(Condition:CanUseBondedModifiers) 解锁 'Bonded:' 前缀词条,vendor :1437)" }, { - "id": "stun_threshold_from_es_30", - "pattern": "gain additional stun threshold equal to 30% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "bonded_meta_res_eff_inc", + "pattern": "bonded: meta skills have (\\d+)% increased reservation efficiency", + "vendor_pattern": "(Bonded 前缀 + 域限定效率;见 source_note 口径说明)", "mods": [ { - "name": "StunThreshold", - "type": "BASE", - "value": 1, + "name": "ReservationEfficiency", + "type": "INC", + "value": { + "ref": "$1" + }, "tags": [ { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 30 + "type": "Condition", + "var": "CanUseBondedModifiers" + }, + { + "type": "SkillType", + "skillType": "Meta" } ] } ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" + "verified": true, + "batch": "hand-curated", + "source_note": "Bonded rune 变体(语料 C1 双跑对齐:legacy 的 bonded 递归会命中 parse_reservation_efficiency,引擎须同产出;Condition:CanUseBondedModifiers 默认不激活)。vendor 对前缀域形 Bonded 变体 unsupported(special 表不在前缀剥离后重查)——此处取 legacy 超集方向(条件门控恒 false 时零行为)" }, { - "id": "ailment_threshold_from_es_8", - "pattern": "gain additional ailment threshold equal to 8% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "bonded_herald_res_eff_inc", + "pattern": "bonded: (\\d+)% increased reservation efficiency of herald skills", + "vendor_pattern": "(Bonded 前缀 + 域限定效率;见 source_note 口径说明)", "mods": [ { - "name": "AilmentThreshold", - "type": "BASE", - "value": 1, + "name": "ReservationEfficiency", + "type": "INC", + "value": { + "ref": "$1" + }, "tags": [ { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 8 + "type": "Condition", + "var": "CanUseBondedModifiers" + }, + { + "type": "SkillType", + "skillType": "Herald" } ] } ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" + "verified": true, + "batch": "hand-curated", + "source_note": "Bonded rune 变体(语料 C1 双跑对齐:legacy 的 bonded 递归会命中 parse_reservation_efficiency,引擎须同产出;Condition:CanUseBondedModifiers 默认不激活)。vendor 对前缀域形 Bonded 变体 unsupported(special 表不在前缀剥离后重查)——此处取 legacy 超集方向(条件门控恒 false 时零行为)" }, { - "id": "ailment_threshold_from_es_12", - "pattern": "gain additional ailment threshold equal to 12% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "all_elemental_damage_converted_to_chaos", + "pattern": "all elemental damage converted to chaos damage", + "vendor_pattern": "all elemental damage converted to chaos damage", "mods": [ { - "name": "AilmentThreshold", + "name": "ColdDamageConvertToChaos", "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 12 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "ailment_threshold_from_es_15", - "pattern": "gain additional ailment threshold equal to 15% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", - "mods": [ + "value": 100.0 + }, { - "name": "AilmentThreshold", + "name": "FireDamageConvertToChaos", "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 15 - } - ] + "value": 100.0 + }, + { + "name": "LightningDamageConvertToChaos", + "type": "BASE", + "value": 100.0 } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" + "batch": "conv-taken-as", + "source_note": "ModParser.lua:2410-2414(all elemental → chaos 100,整行特例;通用后缀路径整行不识别)" }, { - "id": "ailment_threshold_from_es_20", - "pattern": "gain additional ailment threshold equal to 20% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "cold_damage_taken_as_lightning", + "pattern": "(\\d+(?:\\.\\d+)?)% of cold damage taken as lightning", + "vendor_pattern": "(%d+)%% of cold damage taken as lightning", "mods": [ { - "name": "AilmentThreshold", + "name": "ColdDamageTakenAsLightning", "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 20 - } - ] + "value": "$1" } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" + "batch": "conv-taken-as", + "source_note": "ModParser.lua:5655(裸目标 taken-as:suffixTypes 无 bare `as lightning`,通用路径残留 `as lightning` 并误产 ColdDamageTaken BASE)" }, { - "id": "ailment_threshold_from_es_30", - "pattern": "gain additional ailment threshold equal to 30% of maximum energy shield", - "vendor_pattern": "gain additional (%a+) threshold equal to (%d+)%% of maximum energy shield", + "id": "fire_and_lightning_from_hits_taken_as_cold_during_effect", + "pattern": "(\\d+(?:\\.\\d+)?)% of fire and lightning damage from hits taken as cold damage during effect", + "vendor_pattern": "(%d+)%% of fire and lightning damage from hits taken as cold damage during effect", "mods": [ { - "name": "AilmentThreshold", + "name": "FireDamageFromHitsTakenAsCold", "type": "BASE", - "value": 1, + "value": "$1", "tags": [ { - "type": "PercentStat", - "stat": "EnergyShield", - "percent": 30 + "type": "Condition", + "var": "UsingFlask" } ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:5234(mod(firstToUpper(statType)..\"Threshold\", BASE, 1, PercentStat{EnergyShield, num});DSL PercentStat 为字面值不吃捕获——按语料数值集 {8,12,15,20,30} 钉值展开(blood_mage_additional_life_from_body_es 同款先例)。A2 真缺口榜 #2/#3(hit=6,cnt=20/16)。AilmentThreshold 玩家侧 calc 暂无消费(解析对齐 vendor,消费端接线时词条已就位)" - }, - { - "id": "mana_regen_from_life_6", - "pattern": "regenerate mana equal to 6% of maximum life per second", - "vendor_pattern": "regenerate mana equal to (%d+)%% of maximum life per second", - "mods": [ + }, { - "name": "ManaRegen", + "name": "LightningDamageFromHitsTakenAsCold", "type": "BASE", - "value": 1, + "value": "$1", "tags": [ { - "type": "PercentStat", - "stat": "Life", - "percent": 6 + "type": "Condition", + "var": "UsingFlask" } ] } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #28(oracle:ManaRegen BASE 1 + PercentStat{Life,6});DSL PercentStat 字面值——按语料数值钉 6" + "batch": "conv-taken-as", + "source_note": "ModParser.lua:5657-5660(flask 词条;通用路径只吃 lightning 分支、残留 `Fire and`)" }, { - "id": "ailment_threshold_from_evasion_100", - "pattern": "gain 100% of evasion rating as extra ailment threshold", - "vendor_pattern": "gain (%d+)%% of evasion rating as extra ailment threshold", + "id": "fire_damage_taken_as_lightning", + "pattern": "(\\d+(?:\\.\\d+)?)% of fire damage taken as lightning", + "vendor_pattern": "(%d+)%% of fire damage taken as lightning", "mods": [ { - "name": "AilmentThreshold", + "name": "FireDamageTakenAsLightning", "type": "BASE", - "value": 1, - "tags": [ - { - "type": "PercentStat", - "stat": "Evasion", - "percent": 100 - } - ] + "value": "$1" } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #24(oracle:AilmentThreshold BASE 1 + PercentStat{Evasion,100});玩家侧 AilmentThreshold 暂无 calc 消费——解析对齐 vendor,接线即生效" + "batch": "conv-taken-as", + "source_note": "ModParser.lua:5656(同 cold_damage_taken_as_lightning,裸目标 taken-as)" }, { - "id": "threshold_10_red_support_gems_5pct", - "pattern": "5% increased maximum life if you have at least 10 red support gems socketed", - "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", + "id": "phys_cold_lightning_converted_to_fire", + "pattern": "(\\d+(?:\\.\\d+)?)% of physical, cold and lightning damage converted to fire damage", + "vendor_pattern": "(%d+)%% of physical, cold and lightning damage converted to fire damage", "mods": [ { - "name": "Life", - "type": "INC", - "value": 5, - "tags": [ - { - "type": "MultiplierThreshold", - "var": "RedSupportGems", - "threshold": 10 - } - ] + "name": "PhysicalDamageConvertToFire", + "type": "BASE", + "value": "$1" + }, + { + "name": "LightningDamageConvertToFire", + "type": "BASE", + "value": "$1" + }, + { + "name": "ColdDamageConvertToFire", + "type": "BASE", + "value": "$1" } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值" + "batch": "conv-taken-as", + "source_note": "ModParser.lua:2405-2409(多源合写 converted to:通用路径只吃 lightning 分支、残留 `Physical, Cold and`)" }, { - "id": "threshold_10_blue_support_gems_5pct", - "pattern": "5% increased maximum mana if you have at least 10 blue support gems socketed", - "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", + "id": "phys_from_hits_taken_as_random_element", + "pattern": "(\\d+(?:\\.\\d+)?)% of physical damage from hits taken as damage of a random element", + "vendor_pattern": "(%d+)%% of physical damage from hits taken as damage of a random element", "mods": [ { - "name": "Mana", - "type": "INC", - "value": 5, - "tags": [ - { - "type": "MultiplierThreshold", - "var": "BlueSupportGems", - "threshold": 10 - } - ] - } - ], - "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值" + "name": "PhysicalDamageFromHitsTakenAsFire", + "type": "BASE", + "value": { + "ref": "$1", + "ops": [ + { + "div": 3.0 + } + ] + } + }, + { + "name": "PhysicalDamageFromHitsTakenAsCold", + "type": "BASE", + "value": { + "ref": "$1", + "ops": [ + { + "div": 3.0 + } + ] + } + }, + { + "name": "PhysicalDamageFromHitsTakenAsLightning", + "type": "BASE", + "value": { + "ref": "$1", + "ops": [ + { + "div": 3.0 + } + ] + } + } + ], + "verified": false, + "batch": "conv-taken-as", + "source_note": "ModParser.lua:5661-5665(AVERAGE 三分口径 num/3;真实语料词条,legacy 删除后回归恢复)" }, { - "id": "threshold_10_green_support_gems_5pct", - "pattern": "5% increased movement speed if you have at least 10 green support gems socketed", - "vendor_pattern": "if you have at least (%d+) (%a+) support gems socketed", + "id": "eternal_life_while_energy_shield", + "pattern": "your life cannot change while you have energy shield", + "vendor_pattern": "your life cannot change while you have energy shield", "mods": [ { - "name": "MovementSpeed", - "type": "INC", - "value": 5, - "tags": [ - { - "type": "MultiplierThreshold", - "var": "GreenSupportGems", - "threshold": 10 - } - ] + "name": "EternalLife", + "type": "FLAG", + "value": true } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "A2 真缺口 #4/#5/#6(oracle: INC 5 + MultiplierThreshold{SupportGems,10},vendor ModParser.lua:1697 函数 tag);下界阈值盲产欠算安全(cfg.multiplier 未灌 SupportGems 时不生效,编排层计数接线后自动生效);DSL 不吃捕获——按语料钉值" + "batch": "fork-a", + "source_note": "ModParser.lua:3144(-- Lich specialModList,flag(EternalLife));legacy 经 max-hit ES bypass 消费(pool_damage.rs)。fork-a 迁入补 engine 数据驱动 special 通道缺口(detonate-dead MaxHit/EHP 偏低)" }, { - "id": "body_armour_grants_reduced_crit_damage_bonus_100", - "pattern": "body armour grants hits against you have 100% reduced critical damage bonus", - "vendor_pattern": "body armour grants hits against you have (%d+)%% reduced critical damage bonus", + "id": "blood_mage_additional_life_from_body_es", + "pattern": "gain additional maximum life equal to 100% of the (?:item )?energy shield on equipped body armour", + "vendor_pattern": "gain additional maximum life equal to (%d+)%% of the (i?t?e?m? ?)energy shield on equipped body armour", "mods": [ { - "name": "ReduceCritExtraDamage", + "name": "MaximumLife", "type": "BASE", - "value": 100 + "value": 1, + "tags": [ + { + "type": "Multiplier", + "var": "EnergyShieldOnbodyarmour", + "div": 1 + } + ] } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:3284(mod(ReduceCritExtraDamage, BASE, num, ItemCondition{Body Armour, rarityCond=NORMAL});ItemCondition 无 PoBR 落点按 body-armour-grants pre_flag 族同口径丢弃(dropped-tag 报表 7 行同款欠条)——Smith of Kitava 机制要求白装胸甲,语料 build 满足故不 over-apply。语料数值集 {100} 钉值。消费方 defence.rs CritExtraDamageReduction 已存在" + "batch": "fork-a", + "source_note": "ModParser.lua:2834(-- Blood Mage specialModList,mod(Life,BASE,1,PerStat{stat=EnergyShieldOnBody Armour,div=100/N});legacy.rs:1796-1810 同形(MaximumLife BASE 1 × Multiplier:EnergyShieldOnbodyarmour,div=100/N,slot 倍率经 orchestrator per_slot_defence_multipliers 填充 = Body Armour 件级最终 ES)。本条钉 N=100(升华恒 100%,corpus 唯一形)→ div=1;special 整行命中在 pre_flag 剥 `gain` 前。需 special_mod.rs 字面 Multiplier tag 支持。fork-a 补 engine special 通道(blood-mage Life→EHP/MaxHit 级联)" }, { - "id": "body_armour_grants_unaffected_by_damaging_ailments", - "pattern": "body armour grants unaffected by damaging ailments", - "vendor_pattern": "body armour grants unaffected by damaging ailments", + "id": "life_loss_from_hits_prevented_over_4s", + "pattern": "(\\d+(?:\\.\\d+)?)% of life loss from hits is prevented, then that much life is lost over 4 seconds instead", + "vendor_pattern": "(%d+)%% of life loss from hits is prevented, then that much life is lost over 4 seconds instead", "mods": [ { - "name": "SelfBleedEffect", - "type": "MORE", - "value": -100 - }, - { - "name": "SelfIgniteEffect", - "type": "MORE", - "value": -100 - }, - { - "name": "SelfPoisonEffect", - "type": "MORE", - "value": -100 + "name": "LifeLossPrevented", + "type": "BASE", + "value": "$1" } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:3288(Self{Bleed,Ignite,Poison}Effect MORE -100 ×3,ItemCondition 同上丢弃)。Self*Effect 玩家侧 calc 暂无消费(解析对齐 vendor,自异常效果消费端接线时词条已就位;AilmentThreshold 先例)" + "batch": "fork-a", + "source_note": "ModParser.lua:2839 function(num)→mod(LifeLossPrevented,BASE,num);legacy.rs:1824-1827 同。pool_setup.rs:104 `min(ΣLifeLossPrevented,100)` 减伤(max-hit 机制)。vendor 函数形,extract 抽不出静态模板 → 引擎误解析为 MaximumLife BASE 25。fork-a 补 engine special(blood-mage EHP/五类 MaxHit 0.88x)" }, { - "id": "break_armour_on_crit_with_spells", - "pattern": "break armour on critical hit with spells equal to (\\d+)% of physical damage dealt", - "vendor_pattern": "break armour on critical hit with spells equal to (%d+)%% of physical damage dealt", + "id": "fire_damage_while_affected_by_herald_of_ash", + "pattern": "(\\d+(?:\\.\\d+)?)% increased fire damage while affected by herald of ash", + "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2536 硬编码]", "mods": [ { - "name": "Condition:CanArmourBreak", - "type": "FLAG", - "value": true, + "name": "FireDamage", + "type": "INC", + "value": "$1", "tags": [ { "type": "Condition", - "neg": true, - "var": "NeverCrit" + "var": "AffectedByHeraldofAsh" + }, + { + "type": "DamageType", + "damageType": "Fire" } ] } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:3803(flag(Condition:CanArmourBreak, GlobalEffect{Buff, ArmourBreak}, Condition{neg NeverCrit});数值不进 mods——vendor 同样忽略捕获,正则一条覆盖语料 {5,10}。GlobalEffect 无 PoBR 落点丢弃(已有评估:不值窄做);CanArmourBreak 玩家侧 calc 暂无消费(armour break 机制未建模,解析对齐 vendor)" + "batch": "fork-a", + "source_note": "vendor `while affected by (%a+)` modTagList 单词捕获抽不出多词「Herald of Ash」+ 多元素 varList 引擎丢弃 → engine 无条件应用、泄漏进 dot(grenade/ice-shot dot over-count)。legacy.rs:2536 硬编码 `AffectedByHeraldofAsh`。整行 data 化对齐 legacy(FireDamage INC + Condition + DamageType)" }, { - "id": "limit_for_elemental_skills", - "pattern": "\\+(\\d+) to limit for elemental skills", - "vendor_pattern": "%+(%d+) to limit for elemental skills", + "id": "cold_damage_while_affected_by_herald_of_ice", + "pattern": "(\\d+(?:\\.\\d+)?)% increased cold damage while affected by herald of ice", + "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2532 硬编码]", "mods": [ { - "name": "AdditionalCooldownUses", - "type": "BASE", + "name": "ColdDamage", + "type": "INC", "value": "$1", "tags": [ { - "type": "SkillType", - "skillTypeList": [ - "Cold", - "Fire", - "Lightning" - ] + "type": "Condition", + "var": "AffectedByHeraldofIce" + }, + { + "type": "DamageType", + "damageType": "Cold" } ] } ], "verified": false, - "batch": "a2-real-gaps", - "source_note": "ModParser.lua:3374(mod(AdditionalCooldownUses, BASE, num, SkillType{skillTypeList={Cold,Fire,Lightning}});skillTypeList → SkillTypes 位集并集(intersects 即 OR,与 vendor ModStore SkillType 任一命中同语义)。消费方 skill_mechanics.rs stored uses 已存在)" + "batch": "fork-a", + "source_note": "同 fire_damage_while_affected_by_herald_of_ash;legacy.rs:2532 `AffectedByHeraldofIce`" }, { - "id": "all_elemental_damage_converted_to_chaos", - "pattern": "all elemental damage converted to chaos damage", - "vendor_pattern": "all elemental damage converted to chaos damage", + "id": "lightning_damage_while_affected_by_herald_of_thunder", + "pattern": "(\\d+(?:\\.\\d+)?)% increased lightning damage while affected by herald of thunder", + "vendor_pattern": "while affected by (%a+) [via modTagList; legacy.rs:2540 硬编码]", "mods": [ { - "name": "ColdDamageConvertToChaos", - "type": "BASE", - "value": 100.0 - }, - { - "name": "FireDamageConvertToChaos", - "type": "BASE", - "value": 100.0 - }, - { - "name": "LightningDamageConvertToChaos", - "type": "BASE", - "value": 100.0 + "name": "LightningDamage", + "type": "INC", + "value": "$1", + "tags": [ + { + "type": "Condition", + "var": "AffectedByHeraldofThunder" + }, + { + "type": "DamageType", + "damageType": "Lightning" + } + ] } ], "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:2410-2414(all elemental → chaos 100,整行特例;通用后缀路径整行不识别)" + "batch": "fork-a", + "source_note": "同 fire_damage_while_affected_by_herald_of_ash;legacy.rs:2540 `AffectedByHeraldofThunder`" }, { - "id": "cold_damage_taken_as_lightning", - "pattern": "(\\d+(?:\\.\\d+)?)% of cold damage taken as lightning", - "vendor_pattern": "(%d+)%% of cold damage taken as lightning", + "id": "body_armour_grants_of_armour_also_applies_to_chaos_damage", + "pattern": "body armour grants \\+?(\\d+)% of armour also applies to (chaos) damage", + "vendor_pattern": "body armour grants %+(%d+)%% of armour also applies to (%a+) damage", "mods": [ { - "name": "ColdDamageTakenAsLightning", + "name": "ArmourAppliesToChaosDamageTaken", "type": "BASE", - "value": "$1" + "value": "$1", + "tags": [ + { + "type": "Condition", + "var": "NormalBodyArmourEquipped" + } + ] } ], "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:5655(裸目标 taken-as:suffixTypes 无 bare `as lightning`,通用路径残留 `as lightning` 并误产 ColdDamageTaken BASE)" + "batch": "fork-a", + "source_note": "ModParser.lua:3281 -- Warrior - Smith of Kitava,function(num,_,dmgType)→mod(ArmourAppliesToDamageTaken,BASE,num,{type=ItemCondition,itemSlot=Body Armour,rarityCond=NORMAL})。vendor 函数形带 (%a+) 伤害类型捕获 + ItemCondition,extract_parser_rules 抽不出(S2 批仅手转非 body-armour 的 fire/cold/lightning 三元素,漏 chaos + 漏 body-armour-grants 变体)。legacy 经 body-armour-grants 前缀剥离 + parse_armour_applies_pct(legacy.rs:393/1621)通用处理任意类型,chaos 正常,故 engine 落后 legacy。本条把 vendor ItemCondition{Body Armour,NORMAL} 映射为 pobr `Condition:NormalBodyArmourEquipped`(orchestrator calc_orchestrator.rs:373 按体甲槽 Normal 稀有度置真,与 legacy.rs:397 同口径),消费侧 taken.rs ArmourAppliesToChaosDamageTaken。修 warrior-smith-of-kitava-shield-wall ChaosMaxHit 0.84x→1.00x" }, { - "id": "fire_and_lightning_from_hits_taken_as_cold_during_effect", - "pattern": "(\\d+(?:\\.\\d+)?)% of fire and lightning damage from hits taken as cold damage during effect", - "vendor_pattern": "(%d+)%% of fire and lightning damage from hits taken as cold damage during effect", + "id": "point_blank_projectiles_more_hit_damage_scaling_down", + "pattern": "projectiles deal 20% more hit damage to targets in the first 3\\.5 metres of their movement, scaling down with distance travelled to reach 0% after 7 metres", + "vendor_pattern": "projectiles deal (%d+)%% more hit damage to targets in the first ([%d%.]+) metres of their movement, scaling [du][op]w?n? with distance travelled to reach (%d+)%% after ([%d%.]+) metres", "mods": [ { - "name": "FireDamageFromHitsTakenAsCold", - "type": "BASE", - "value": "$1", + "name": "Damage", + "type": "MORE", + "value": 100, + "flags": [ + "Hit", + "Projectile" + ], "tags": [ { - "type": "Condition", - "var": "UsingFlask" + "type": "DistanceRamp", + "ramp": [ + "35 0.2", + "70 0" + ] } ] - }, + } + ], + "verified": false, + "batch": "fork-a", + "source_note": "ModParser.lua:2911-2913(vendor 产 Damage MORE 100 + DistanceRamp {10*首距, num/100},{10*末距, low/100};本条为 Point Blank 升华固定文本 20%/3.5m→0%/7m 的字面转写,ramp={35,0.2},{70,0}。数值/距离不同的未来变体保守不匹配。此前引擎误产平坦 ProjectileDamage MORE 20(丢距离插值)——special 通道整行优先修正)" + }, + { + "id": "point_blank_projectiles_more_hit_damage_scaling_up", + "pattern": "projectiles deal 0% more hit damage to targets in the first 3\\.5 metres of their movement, scaling up with distance travelled to reach 20% after 7 metres", + "vendor_pattern": "projectiles deal (%d+)%% more hit damage to targets in the first ([%d%.]+) metres of their movement, scaling [du][op]w?n? with distance travelled to reach (%d+)%% after ([%d%.]+) metres", + "mods": [ { - "name": "LightningDamageFromHitsTakenAsCold", - "type": "BASE", - "value": "$1", + "name": "Damage", + "type": "MORE", + "value": 100, + "flags": [ + "Hit", + "Projectile" + ], "tags": [ { - "type": "Condition", - "var": "UsingFlask" + "type": "DistanceRamp", + "ramp": [ + "35 0", + "70 0.2" + ] } ] } ], "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:5657-5660(flask 词条;通用路径只吃 lightning 分支、残留 `Fire and`)" + "batch": "fork-a", + "source_note": "ModParser.lua:2911-2913(同上规则的 scaling-up 变体固定文本 0%/3.5m→20%/7m,ramp={35,0},{70,0.2})" }, { - "id": "fire_damage_taken_as_lightning", - "pattern": "(\\d+(?:\\.\\d+)?)% of fire damage taken as lightning", - "vendor_pattern": "(%d+)%% of fire damage taken as lightning", - "mods": [ + "id": "prevent_pct_of_damage_from_deflected_hits", + "pattern": "prevent \\+(\\d+(?:\\.\\d+)?)% of damage from deflected hits", + "vendor_pattern": "prevent %+(%d+)%% of damage from deflected hits", + "mods": [ { - "name": "FireDamageTakenAsLightning", + "name": "DeflectEffect", "type": "BASE", "value": "$1" } ], "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:5656(同 cold_damage_taken_as_lightning,裸目标 taken-as)" + "batch": "fork-a", + "source_note": "ModParser.lua:4191 function(num)→mod(DeflectEffect,BASE,num);legacy.rs:1721 parse_deflection_special 同。defence_panels.rs:241 偏斜减伤=基础40+ΣBASE DeflectEffect,clamp[0,100](DeflectChance 58% 时生效,非仅≥100)。vendor 函数形 extract 抽不出 → 引擎丢弃(twister 缺 DeflectEffect 3+6=9 → 偏斜减伤 40 而非 49 → EHP 0.89x)。捕获形一条匹配全部 N。fork-a 补 engine special(monk-martial-artist-twister TotalEHP)" }, { - "id": "phys_cold_lightning_converted_to_fire", - "pattern": "(\\d+(?:\\.\\d+)?)% of physical, cold and lightning damage converted to fire damage", - "vendor_pattern": "(%d+)%% of physical, cold and lightning damage converted to fire damage", + "id": "you_can_apply_an_additional_curse", + "pattern": "you can apply an additional curse", + "vendor_pattern": "you can apply an additional curse", "mods": [ { - "name": "PhysicalDamageConvertToFire", + "name": "EnemyCurseLimit", "type": "BASE", - "value": "$1" - }, + "value": 1 + } + ], + "verified": false, + "batch": "hand-curated", + "source_note": "ModParser.lua:4303(Whispers of Doom keystone tree 47759 第一行『You can apply an additional Curse』;第二行 Double Activation Delay 已在 double_activation_delay_of_curses 条目)。缺它时 frost-bomb 第二诅咒 Elemental Weakness 被挤出唯一槽,敌侧 -45 元素抗丢失(CritChance 路径外的 hit 伤害缺口)" + }, + { + "id": "enemies_can_have_1_additional_curse", + "pattern": "enemies can have 1 additional curse", + "vendor_pattern": "enemies can have 1 additional curse", + "mods": [ { - "name": "LightningDamageConvertToFire", + "name": "EnemyCurseLimit", "type": "BASE", - "value": "$1" - }, + "value": 1 + } + ], + "verified": false, + "batch": "hand-curated", + "source_note": "ModParser.lua:4302(curse limit 平表同族)" + }, + { + "id": "you_can_apply_one_fewer_curse", + "pattern": "you can apply one fewer curse", + "vendor_pattern": "you can apply one fewer curse", + "mods": [ { - "name": "ColdDamageConvertToFire", + "name": "EnemyCurseLimit", "type": "BASE", - "value": "$1" + "value": -1 } ], "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:2405-2409(多源合写 converted to:通用路径只吃 lightning 分支、残留 `Physical, Cold and`)" + "batch": "hand-curated", + "source_note": "ModParser.lua:4306(curse limit 平表同族)" }, { - "id": "phys_from_hits_taken_as_random_element", - "pattern": "(\\d+(?:\\.\\d+)?)% of physical damage from hits taken as damage of a random element", - "vendor_pattern": "(%d+)%% of physical damage from hits taken as damage of a random element", + "id": "you_can_apply_an_additional_mark", + "pattern": "you can apply an additional mark", + "vendor_pattern": "you can apply an additional mark", "mods": [ { - "name": "PhysicalDamageFromHitsTakenAsFire", + "name": "EnemyMarkLimit", + "type": "BASE", + "value": 1 + } + ], + "verified": false, + "batch": "hand-curated", + "source_note": "ModParser.lua:4309(mark limit 平表同族)" + }, + { + "id": "es_added_to_armour_for_pdr", + "pattern": "(\\d+(?:\\.\\d+)?)% of your current energy shield is added to your armour for determining your physical damage reduction from armour", + "vendor_pattern": "(%d+)%% of your current energy shield is added to your armour for determining your physical damage reduction from armour", + "mods": [ + { + "name": "EnergyShieldAppliesToPhysicalDamageTaken", "type": "BASE", + "value": "$1" + } + ], + "verified": false, + "batch": "hand-curated", + "source_note": "ModParser.lua:2917-2919(Disciple of Varashta 升华 Sacred Rituals,tree node 56857 —— N% of your current Energy Shield is added to your Armour for determining your Physical Damage Reduction from Armour → EnergyShieldAppliesToPhysicalDamageTaken BASE N)。消费 taken.rs effective_applied_armour 的 from_es 借入项(CalcDefence.lua:2358-2367)。pobr 准源 legacy.rs parse_defence_numeric_sentence(须走 legacy 以过 collect.rs::combine_wrapped_then_filter 树 stat 闸门)。" + }, + { + "id": "take_pct_less_damage", + "pattern": "take (\\d+)% less damage", + "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% less Damage)", + "mods": [ + { + "name": "DamageTaken", + "type": "MORE", "value": { "ref": "$1", "ops": [ { - "div": 3.0 + "negate": {} } ] } - }, + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" + }, + { + "id": "take_pct_more_damage", + "pattern": "take (\\d+)% more damage", + "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% more Damage)", + "mods": [ { - "name": "PhysicalDamageFromHitsTakenAsCold", - "type": "BASE", + "name": "DamageTaken", + "type": "MORE", + "value": { + "ref": "$1" + } + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" + }, + { + "id": "take_pct_reduced_damage", + "pattern": "take (\\d+)% reduced damage", + "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% reduced Damage)", + "mods": [ + { + "name": "DamageTaken", + "type": "INC", "value": { "ref": "$1", "ops": [ { - "div": 3.0 + "negate": {} } ] } - }, + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" + }, + { + "id": "take_pct_increased_damage", + "pattern": "take (\\d+)% increased damage", + "vendor_pattern": "(vendor 通用改写链解析动词前置形;oracle: Take 30% increased Damage)", + "mods": [ { - "name": "PhysicalDamageFromHitsTakenAsLightning", - "type": "BASE", + "name": "DamageTaken", + "type": "INC", + "value": { + "ref": "$1" + } + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "tree node 28153「Phased Form」等动词前置形受伤词条;oracle run-parsemod 实证四方向(less/more→MORE±N、reduced/increased→INC±N);消费 defence.rs taken_mult_for_type_*;legacy parse_defence_numeric_sentence 同形分支过 collect.rs 树闸门" + }, + { + "id": "meta_skills_res_eff_inc", + "pattern": "meta skills have (\\d+)% increased reservation efficiency", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "mods": [ + { + "name": "ReservationEfficiency", + "type": "INC", + "value": { + "ref": "$1" + }, + "tags": [ + { + "type": "SkillType", + "skillType": "Meta" + } + ] + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + }, + { + "id": "meta_skills_res_eff_red", + "pattern": "meta skills have (\\d+)% reduced reservation efficiency", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "mods": [ + { + "name": "ReservationEfficiency", + "type": "INC", "value": { "ref": "$1", "ops": [ { - "div": 3.0 + "negate": {} + } + ] + }, + "tags": [ + { + "type": "SkillType", + "skillType": "Meta" + } + ] + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + }, + { + "id": "herald_res_eff_inc", + "pattern": "(\\d+)% increased reservation efficiency of herald skills", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "mods": [ + { + "name": "ReservationEfficiency", + "type": "INC", + "value": { + "ref": "$1" + }, + "tags": [ + { + "type": "SkillType", + "skillType": "Herald" + } + ] + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + }, + { + "id": "herald_res_eff_red", + "pattern": "(\\d+)% reduced reservation efficiency of herald skills", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "mods": [ + { + "name": "ReservationEfficiency", + "type": "INC", + "value": { + "ref": "$1", + "ops": [ + { + "negate": {} } ] + }, + "tags": [ + { + "type": "SkillType", + "skillType": "Herald" + } + ] + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + }, + { + "id": "spirit_res_eff_inc", + "pattern": "(\\d+)% increased spirit reservation efficiency of skills", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "mods": [ + { + "name": "SpiritReservationEfficiency", + "type": "INC", + "value": { + "ref": "$1" } } ], - "verified": false, - "batch": "conv-taken-as", - "source_note": "ModParser.lua:5661-5665(AVERAGE 三分口径 num/3;真实语料词条,legacy 删除后回归恢复)" + "verified": true, + "batch": "hand-curated", + "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + }, + { + "id": "spirit_res_eff_red", + "pattern": "(\\d+)% reduced spirit reservation efficiency of skills", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证 tag 口径)", + "mods": [ + { + "name": "SpiritReservationEfficiency", + "type": "INC", + "value": { + "ref": "$1", + "ops": [ + { + "negate": {} + } + ] + } + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "域限定预留效率(tree 42245/63236「Meta Skills have N% increased Reservation Efficiency」等);vendor→ReservationEfficiency INC±N+SkillType tag(run-parsemod 实证);消费=spirit_reservation_modifiers 预留公式 /(1+eff/100)(CalcDefence.lua:240-243/:251);legacy parse_reservation_efficiency 同形过树闸门" + }, + { + "id": "totems_reserve_spirit_each", + "pattern": "totems reserve (\\d+) spirit each", + "vendor_pattern": "(ModParser.lua:4644 Ancestral Bond;run-parsemod 实证双 mod)", + "mods": [ + { + "name": "AncestralBond", + "type": "FLAG", + "value": true + }, + { + "name": "ExtraSpirit", + "type": "BASE", + "value": { + "ref": "$1" + }, + "tags": [ + { + "type": "SkillType", + "skillType": "SummonsTotem" + } + ] + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "tree node 45202「Ancestral Bond」Totems reserve 75 Spirit each;消费=spirit_reservation_modifiers totem 入选分支(SummonsTotem×AncestralBond flag,CalcDefence.lua:197)+ ExtraSpirit per-gem Sum;legacy parse_totem_spirit_reservation 同形过树闸门" + }, + { + "id": "banner_aura_magnitudes_inc", + "pattern": "banner skills have (\\d+)% increased aura magnitudes", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", + "mods": [ + { + "name": "AuraEffect", + "type": "INC", + "value": { + "ref": "$1" + }, + "tags": [ + { + "type": "SkillType", + "skillType": "Banner" + } + ] + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" + }, + { + "id": "aura_skills_magnitudes_inc", + "pattern": "aura skills have (\\d+)% increased magnitudes", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", + "mods": [ + { + "name": "Magnitude", + "type": "INC", + "value": { + "ref": "$1" + }, + "tags": [ + { + "type": "SkillType", + "skillType": "Aura" + } + ] + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" + }, + { + "id": "aura_magnitudes_bare_inc", + "pattern": "(\\d+)% increased aura magnitudes", + "vendor_pattern": "(vendor 通用改写链;oracle run-parsemod 实证)", + "mods": [ + { + "name": "AuraEffect", + "type": "INC", + "value": { + "ref": "$1" + } + } + ], + "verified": true, + "batch": "hand-curated", + "source_note": "域限定 buff magnitude(wolf-pack banner/aura 词条族;run-parsemod 实证 tag 口径);消费=buff_pass aura 乘区(AuraEffect 桶×Magnitude 桶分乘,CalcPerform.lua:2204-2205);legacy parse_scoped_buff_magnitude 同形过树/装备闸门" } ] } diff --git a/data/4.5.0.3.4/overlay/vendor_name_aliases.json b/data/overlay-common/vendor_name_aliases.json similarity index 100% rename from data/4.5.0.3.4/overlay/vendor_name_aliases.json rename to data/overlay-common/vendor_name_aliases.json diff --git a/devs/ci/parse-coverage-baseline.json b/devs/ci/parse-coverage-baseline.json index 76410785..b0fce27f 100644 --- a/devs/ci/parse-coverage-baseline.json +++ b/devs/ci/parse-coverage-baseline.json @@ -4,12 +4,12 @@ "purpose": "M6-T7 解析覆盖率棘轮基线(蓝图 §6.3)。PR 不得降低 coverage_ratio;升高时同 PR 更新本文件。", "regen": "cargo run -p precompile-mods -- --data data/4.5.4.3 --report,取 generated/parse-coverage.json::summary", "parser_engine": "scan_engine+special", - "note": "golden 4.5.4.3(vendor ce8bffab):special_vendor 全量抽取 + 策展移植后覆盖率 0.794962→0.801168;Mageblood `Legacy of X` handler 接入后 0.801168→0.803738(+11 行)。" + "note": "golden 4.5.4.3(vendor ce8bffab):special_vendor 全量抽取 + 策展移植后覆盖率 0.794962→0.801168;Mageblood `Legacy of X` handler 接入后 0.801168→0.803738(+11 行)。;存量 #7 摘除 also_grants_guard 幻影建模(vendor 不解析,2 行如实回到 unsupported)0.803738→0.803271" }, "patch": "4.5.4.3", "total": 4280, - "parsed": 3440, - "unsupported": 840, + "parsed": 3438, + "unsupported": 842, "err": 0, - "coverage_ratio": 0.803738 + "coverage_ratio": 0.803271 } diff --git a/devs/docs/audits/vendor-delta-ce8bffab.md b/devs/docs/audits/vendor-delta-ce8bffab.md new file mode 100644 index 00000000..28c3cdb1 --- /dev/null +++ b/devs/docs/audits/vendor-delta-ce8bffab.md @@ -0,0 +1,2380 @@ +# Vendor calc-delta — a82a33b4 → ce8bffab + +| | old | new | +|---|---|---| +| commit | `a82a33b4fbdb7306ed93159664f7abe2c6819413` | `ce8bffaba31f8e68cfce70579e1c96465e7c133c` | +| PoB2 version | 0.21.0 | 0.22.0 | + +Generated by `pipeline/diff-vendor-calcs.sh a82a33b4fbdb7306ed93159664f7abe2c6819413 ce8bffaba31f8e68cfce70579e1c96465e7c133c`. +This is a Phase-1 engine work list: the calc-file hunks and overlay entry +deltas below are what a hand-port must chase before flipping the parity golden. + +## Calc module diff + +Files PoBR mirrors: `Modules/Calc*.lua` + `Modules/ModParser.lua`. +Full hunks are in the collapsed blocks; a file whose diff exceeds +`MAX_HUNK_LINES=800` shows only its stat line. + +| file | +added | -removed | +|---|---:|---:| +| `Modules/CalcActiveSkill.lua` | 53 | 6 | +| `Modules/CalcDefence.lua` | 75 | 17 | +| `Modules/CalcOffence.lua` | 62 | 40 | +| `Modules/CalcPerform.lua` | 193 | 118 | +| `Modules/Calcs.lua` | 236 | 125 | +| `Modules/CalcSections.lua` | 9 | 3 | +| `Modules/CalcSetup.lua` | 115 | 24 | +| `Modules/CalcTools.lua` | 12 | 4 | +| `Modules/CalcTriggers.lua` | 3 | 3 | +| `Modules/ModParser.lua` | 62 | 34 | + +
Modules/CalcActiveSkill.lua (115 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcActiveSkill.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcActiveSkill.lua +index 90af8a6..49d8ca6 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcActiveSkill.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcActiveSkill.lua +@@ -88,7 +88,7 @@ function calcs.mergeSkillInstanceMods(env, modList, skillEffect, statSet, extraS + local grantedEffect = skillEffect.grantedEffect + local selectedGlobalStats = { } + local function mergeStatSet(set, onlyGlobals) +- local stats = calcLib.buildSkillInstanceStats(skillEffect, grantedEffect, set) ++ local stats = calcLib.buildSkillInstanceStats(skillEffect, grantedEffect, set, env.useAltGemQualityStats) + if extraStats and extraStats[1] then + for _, stat in pairs(extraStats) do + stats[stat.key] = (stats[stat.key] or 0) + stat.value +@@ -230,6 +230,35 @@ function calcs.createActiveSkill(activeEffect, supportList, env, actor, socketGr + return activeSkill + end + ++local function getSourceGemPropertyInfo(env, activeSkill) ++ local activeEffect = activeSkill.activeEffect ++ local sourceGem = activeEffect.srcInstance ++ if not sourceGem or not activeEffect.gemData or activeEffect.gemData.tags.support then ++ return { } ++ end ++ ++ env.sourceGemPropertyInfo = env.sourceGemPropertyInfo or { } ++ if not env.sourceGemPropertyInfo[sourceGem] then ++ local modList = new("ModList", activeSkill.actor.modDB) ++ local supportCount = 0 ++ for _, supportEffect in ipairs(activeSkill.supportList) do ++ if supportEffect.isSupporting and supportEffect.isSupporting[sourceGem] then ++ calcs.mergeSkillInstanceMods(env, modList, supportEffect) ++ if not supportEffect.grantedEffect.hidden then ++ supportCount = supportCount + 1 ++ end ++ end ++ end ++ modList:NewMod("Multiplier:SupportCount", "BASE", supportCount, "Support Count") ++ env.sourceGemPropertyInfo[sourceGem] = modList:Tabulate("LIST", { ++ skillName = activeEffect.gemData.name, ++ skillGem = activeEffect.gemData, ++ slotName = activeSkill.slotName, ++ }, "SupportedGemProperty") ++ end ++ return env.sourceGemPropertyInfo[sourceGem] ++end ++ + function calcs.getActiveSkillDisplayName(activeSkill) + local skillName = activeSkill.activeEffect.grantedEffect.name + local skillMinion = activeSkill.minion +@@ -525,7 +554,7 @@ function calcs.buildActiveSkillModList(env, activeSkill) + end + + -- Apply stat-map flagged skill flags. +- for stat, statValue in pairs(calcLib.buildSkillInstanceStats(activeEffect, activeGrantedEffect, activeStatSet)) do ++ for stat, statValue in pairs(calcLib.buildSkillInstanceStats(activeEffect, activeGrantedEffect, activeStatSet, env.useAltGemQualityStats)) do + local map = activeGrantedEffect.statMap[stat] + if statValue ~= 0 and map and map.skillFlag then + skillFlags[map.skillFlag] = true +@@ -639,7 +668,7 @@ function calcs.buildActiveSkillModList(env, activeSkill) + end + + -- Calculate distance from enemy +- effectiveRange = env.configInput.enemyDistance ++ effectiveRange = env.configInput.enemyDistance or env.configPlaceholder.enemyDistance + + -- Build config structure for modifier searches + activeSkill.skillCfg = { +@@ -740,12 +769,15 @@ function calcs.buildActiveSkillModList(env, activeSkill) + skillModList:NewMod("GemLevel", "BASE", activeSkill.activeEffect.srcInstance and activeSkill.activeEffect.srcInstance.level or activeSkill.activeEffect.level, "Max Level") + if activeSkill.activeEffect.srcInstance and activeSkill.activeEffect.srcInstance.corrupted and not (activeSkill.activeEffect.srcInstance.fromItem or activeSkill.activeEffect.srcInstance.fromTree or activeSkill.activeEffect.grantedEffect.fromItem or activeSkill.activeEffect.grantedEffect.fromTree) then + skillModList:NewMod("GemCorruptionLevel", "BASE", activeSkill.activeEffect.srcInstance.corruptLevel, "Corruption") ++ activeSkill.skillCfg.skillCond["GemCorrupted"] = true + end +- for _, supportProperty in ipairs(skillModList:Tabulate("LIST", activeSkill.skillCfg, "SupportedGemProperty")) do ++ for _, supportProperty in ipairs(getSourceGemPropertyInfo(env, activeSkill)) do + local value = supportProperty.value +- if value.keyword == "grants_active_skill" and activeSkill.activeEffect.gemData and not activeSkill.activeEffect.gemData.tags.support then ++ if value.keyword == "grants_active_skill" then + activeEffect[value.key] = activeEffect[value.key] + value.value +- skillModList:NewMod("GemSupport".. value.key:gsub("^%l", string.upper), "BASE", value.value, supportProperty.mod.source, #supportProperty.mod > 0 and supportProperty.mod[1] or nil) ++ local gemTag = supportProperty.mod[1] ++ gemTag = gemTag and gemTag.type == "GemTag" and gemTag or nil ++ skillModList:NewMod("GemSupport".. value.key:gsub("^%l", string.upper), "BASE", value.value, supportProperty.mod.source, gemTag) + end + end + +@@ -763,6 +795,12 @@ function calcs.buildActiveSkillModList(env, activeSkill) + grantedEffectLevel[k] = v + end + end ++ if activeEffect.srcInstance and activeEffect.srcInstance.noReservation then ++ for _, resource in ipairs({ "mana", "life", "spirit" }) do ++ grantedEffectLevel[resource.."ReservationFlat"] = 0 ++ grantedEffectLevel[resource.."ReservationPercent"] = 0 ++ end ++ end + activeEffect.grantedEffectLevel = grantedEffectLevel + + -- Add extra modifiers from granted effect level +@@ -996,6 +1034,15 @@ function calcs.buildActiveSkillModList(env, activeSkill) + if tag.type == "GlobalEffect" then + effectType = tag.effectType + effectName = tag.effectName or activeGrantedEffect.name ++ if activeSkill.minion and activeSkill.minion.minionData then ++ if effectName:find("{0}", 1, true) then ++ effectName = effectName:gsub("{0}", activeSkill.minion.minionData.name) ++ elseif activeGrantedEffect.minionList and effectName:match("^Companion") then ++ effectName = "Companion: "..activeSkill.minion.minionData.name ++ elseif activeGrantedEffect.minionList and effectName:match("^Spectre") then ++ effectName = "Spectre: "..activeSkill.minion.minionData.name ++ end ++ end + effectTag = tag + break + end +``` + +
+ +
Modules/CalcDefence.lua (170 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcDefence.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcDefence.lua +index a96b386..e155293 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcDefence.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcDefence.lua +@@ -225,6 +225,16 @@ function calcs.doActorLifeManaSpiritReservation(actor) + pool.Life.baseFlat = skillModList:Sum("BASE", skillCfg, "LifeCostBase") + (activeSkill.activeEffect.grantedEffectLevel.cost.Life or 0) + end + pool.Life.basePercent = activeSkill.skillData.lifeReservationPercent or activeSkill.activeEffect.grantedEffectLevel.lifeReservationPercent or 0 ++ if activeSkill.skillTypes[SkillType.IsBlasphemy] and activeSkill.activeEffect.srcInstance.supportEffect and activeSkill.activeEffect.srcInstance.supportEffect.isSupporting then ++ -- Sadly no better way to get key/val table element count in lua. ++ local instances = 0 ++ for _ in pairs(activeSkill.activeEffect.srcInstance.supportEffect.isSupporting) do ++ instances = instances + 1 ++ end ++ for name, values in pairs(pool) do ++ values.baseFlat = values.baseFlat + (activeSkill.skillData["blasphemyReservationFlat" .. name] or 0) * instances ++ end ++ end + if skillModList:Flag(skillCfg, "BloodMagicReserved") then + pool.Life.baseFlat = pool.Life.baseFlat + pool.Mana.baseFlat + pool.Mana.baseFlat = 0 +@@ -235,6 +245,13 @@ function calcs.doActorLifeManaSpiritReservation(actor) + activeSkill.skillData["LifeReservationPercentForced"] = activeSkill.skillData["ManaReservationPercentForced"] + activeSkill.skillData["ManaReservationPercentForced"] = nil + end ++ local spiritToLifeReservation = skillModList:Sum("BASE", skillCfg, "LifeReservePercentPerSpirit") ++ if spiritToLifeReservation > 0 then ++ pool.Life.basePercent = pool.Life.basePercent + pool.Spirit.baseFlat * spiritToLifeReservation ++ pool.Spirit.baseFlat = 0 ++ pool.Life.basePercent = pool.Life.basePercent + pool.Spirit.basePercent * spiritToLifeReservation ++ pool.Spirit.basePercent = 0 ++ end + for name, values in pairs(pool) do + values.more = skillModList:More(skillCfg, name.."Reserved", "Reserved") + values.inc = skillModList:Sum("INC", skillCfg, name.."Reserved", "Reserved") +@@ -269,18 +286,6 @@ function calcs.doActorLifeManaSpiritReservation(actor) + values.count = activeSkillCount + local minionFreeSpiritCount = skillModList:Sum("BASE", skillCfg, "MinionFreeSpiritCount") + values.reservedFlat = values.reservedFlat * m_max(activeSkillCount - minionFreeSpiritCount, 0) +- end +- if activeSkill.skillTypes[SkillType.IsBlasphemy] and activeSkill.activeEffect.srcInstance.supportEffect and activeSkill.activeEffect.srcInstance.supportEffect.isSupporting and activeSkill.skillData["blasphemyReservationFlat" .. name] then +- -- Sadly no better way to get key/val table element count in lua. +- local instances = 0 +- for _ in pairs(activeSkill.activeEffect.srcInstance.supportEffect.isSupporting) do +- instances = instances + 1 +- end +- +- -- Extra reservation of blasphemy needs to be separated from the reservation caused by curses +- local blasphemyFlat = activeSkill.skillData["blasphemyReservationFlat" .. name] +- local blasphemyEffectiveFlat = m_max(round(blasphemyFlat * mult * (100 + values.inc) / 100 * values.more / (1 + values.efficiency / 100) / values.efficiencyMore, 0), 0) +- values.reservedFlat = values.reservedFlat + blasphemyEffectiveFlat * instances + end + -- Blood Sacrament increases reservation per stage channelled + if activeSkill.skillCfg.skillName == "Blood Sacrament" and activeSkill.activeStageCount then +@@ -485,6 +490,9 @@ function calcs.reducePoolsByDamage(poolTable, damageTable, actor) + if output.TotalRadianceSentinelLife then + alliesTakenBeforeYou["radianceSentinel"] = { remaining = output.TotalRadianceSentinelLife, percent = output.RadianceSentinelAllyDamageMitigation / 100 } + end ++ if output.TotalCompanionLife then ++ alliesTakenBeforeYou["companion"] = { remaining = output.TotalCompanionLife, percent = output.CompanionAllyDamageMitigation / 100 } ++ end + if output.AlliedEnergyShield then + alliesTakenBeforeYou["soulLink"] = { remaining = output.AlliedEnergyShield, percent = output.SoulLinkMitigation / 100 } + end +@@ -702,6 +710,9 @@ local function incomingDamageBreakdown(breakdownTable, poolsRemaining, output) + if output.TotalRadianceSentinelLife and output.TotalRadianceSentinelLife > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Sentinel of Radiance Life ^7(%d remaining)", output.TotalRadianceSentinelLife - poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining, poolsRemaining.AlliesTakenBeforeYou["radianceSentinel"].remaining)) + end ++ if output.TotalCompanionLife and output.TotalCompanionLife > 0 then ++ t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Companion Life ^7(%d remaining)", output.TotalCompanionLife - poolsRemaining.AlliesTakenBeforeYou["companion"].remaining, poolsRemaining.AlliesTakenBeforeYou["companion"].remaining)) ++ end + if output.AlliedEnergyShield and output.AlliedEnergyShield > 0 then + t_insert(breakdownTable, s_format("\t%d "..colorCodes.GEM.."Total Allied Energy shield ^7(%d remaining)", output.AlliedEnergyShield - poolsRemaining.AlliesTakenBeforeYou["soulLink"].remaining, poolsRemaining.AlliesTakenBeforeYou["soulLink"].remaining)) + end +@@ -1369,8 +1380,8 @@ function calcs.defence(env, actor) + local gainRate = modDB:Sum("BASE", nil, source.name .. "GainAs" .. target.name) + local rate = source.conversionRate[target.name] + gainRate + if rate > 0 then +- local targetBase = math.ceil(globalBase * rate / 100) +- local targetTotalBase = math.ceil(totalBase * rate / 100) ++ local targetBase = round(globalBase * rate / 100) ++ local targetTotalBase = round(totalBase * rate / 100) + target.globalBase = target.globalBase + targetBase + target.totalBase = target.totalBase + targetTotalBase + if breakdown then +@@ -2913,13 +2924,23 @@ function calcs.buildDefenceEstimations(env, actor) + end + + -- from spectres +- output["SpectreAllyDamageMitigation"] = modDB:Sum("BASE", nil, "takenFromSpectresBeforeYou") ++ output["SpectreAllyDamageMitigation"] = modDB:Sum("BASE", nil, "TakenFromSpectresBeforeYou") + if output["SpectreAllyDamageMitigation"] ~= 0 then +- output["TotalSpectreLife"] = modDB:Sum("BASE", nil, "TotalSpectreLife") ++ output["TotalSpectreLife"] = modDB:Override(nil, "TotalSpectreLife") or modDB:Sum("BASE", nil, "TotalSpectreLife") ++ if breakdown then ++ breakdown["TotalSpectreLife"] = { } ++ if modDB:Override(nil, "TotalSpectreLife") then ++ t_insert(breakdown["TotalSpectreLife"], s_format("%d ^8(from config)", output["TotalSpectreLife"])) ++ else ++ for _, spectre in ipairs(actor.spectreLifeList or { }) do ++ t_insert(breakdown["TotalSpectreLife"], s_format("%d ^8(%s)", spectre.life, spectre.name)) ++ end ++ end ++ end + end + + -- from totems +- output["TotemAllyDamageMitigation"] = modDB:Sum("BASE", nil, "takenFromTotemsBeforeYou") ++ output["TotemAllyDamageMitigation"] = modDB:Sum("BASE", nil, "TakenFromTotemsBeforeYou") + if output["TotemAllyDamageMitigation"] ~= 0 then + output["TotalTotemLife"] = modDB:Sum("BASE", nil, "TotalTotemLife") + end +@@ -2936,6 +2957,31 @@ function calcs.buildDefenceEstimations(env, actor) + output["TotalRadianceSentinelLife"] = modDB:Sum("BASE", nil, "TotalRadianceSentinelLife") + end + ++ -- from companions ++ local companionMitigation = modDB:Sum("BASE", nil, "TakenFromCompanionBeforeYou") ++ local companionMitigationFromDeflected = modDB:Sum("BASE", nil, "TakenFromCompanionBeforeYouFromDeflected") ++ output["CompanionAllyDamageMitigation"] = companionMitigation + companionMitigationFromDeflected * (output.DeflectChance or 0) / 100 ++ if output["CompanionAllyDamageMitigation"] ~= 0 then ++ output["TotalCompanionLife"] = modDB:Override(nil, "TotalCompanionLife") or modDB:Sum("BASE", nil, "TotalCompanionLife") ++ if breakdown then ++ breakdown["TotalCompanionLife"] = { } ++ if modDB:Override(nil, "TotalCompanionLife") then ++ t_insert(breakdown["TotalCompanionLife"], s_format("%d ^8(from config)", output["TotalCompanionLife"])) ++ else ++ for _, companion in ipairs(actor.companionLifeList or { }) do ++ t_insert(breakdown["TotalCompanionLife"], s_format("%d ^8(%s)", companion.life, companion.name)) ++ end ++ end ++ if companionMitigationFromDeflected ~= 0 then ++ breakdown["CompanionAllyDamageMitigation"] = { ++ s_format("%d%% ^8(taken from hits)", companionMitigation), ++ s_format("+ %d%% x %.2f ^8(taken from deflected hits, scaled by deflect chance)", companionMitigationFromDeflected, (output.DeflectChance or 0) / 100), ++ s_format("= %.1f%%", output["CompanionAllyDamageMitigation"]), ++ } ++ end ++ end ++ end ++ + -- from Allied Energy Shield + output["SoulLinkMitigation"] = modDB:Sum("BASE", nil, "TakenFromParentESBeforeYou") + if output["SoulLinkMitigation"] ~= 0 then +@@ -3038,6 +3084,9 @@ function calcs.buildDefenceEstimations(env, actor) + if output.TotalRadianceSentinelLife then + alliesTakenBeforeYou["radianceSentinel"] = { remaining = output.TotalRadianceSentinelLife, percent = output.RadianceSentinelAllyDamageMitigation / 100 } + end ++ if output.TotalCompanionLife then ++ alliesTakenBeforeYou["companion"] = { remaining = output.TotalCompanionLife, percent = output.CompanionAllyDamageMitigation / 100 } ++ end + if output.AlliedEnergyShield then + alliesTakenBeforeYou["soulLink"] = { remaining = output.AlliedEnergyShield, percent = output.SoulLinkMitigation / 100 } + end +@@ -3603,6 +3652,15 @@ function calcs.buildDefenceEstimations(env, actor) + local poolProtected = output["TotalRadianceSentinelLife"] / (output["RadianceSentinelAllyDamageMitigation"] / 100) * (1 - output["RadianceSentinelAllyDamageMitigation"] / 100) + output[damageType.."TotalHitPool"] = m_max(output[damageType.."TotalHitPool"] - poolProtected, 0) + m_min(output[damageType.."TotalHitPool"], poolProtected) / (1 - output["RadianceSentinelAllyDamageMitigation"] / 100) + end ++ -- companions ++ if output["TotalCompanionLife"] and output["TotalCompanionLife"] > 0 then ++ if output["CompanionAllyDamageMitigation"] >= 100 then ++ output[damageType.."TotalHitPool"] = output[damageType.."TotalHitPool"] + output["TotalCompanionLife"] ++ else ++ local poolProtected = output["TotalCompanionLife"] / (output["CompanionAllyDamageMitigation"] / 100) * (1 - output["CompanionAllyDamageMitigation"] / 100) ++ output[damageType.."TotalHitPool"] = m_max(output[damageType.."TotalHitPool"] - poolProtected, 0) + m_min(output[damageType.."TotalHitPool"], poolProtected) / (1 - output["CompanionAllyDamageMitigation"] / 100) ++ end ++ end + -- soul link + if output["AlliedEnergyShield"] and output["AlliedEnergyShield"] > 0 then + local poolProtected = output["AlliedEnergyShield"] / (output["SoulLinkMitigation"] / 100) * (1 - output["SoulLinkMitigation"] / 100) +``` + +
+ +
Modules/CalcOffence.lua (293 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcOffence.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcOffence.lua +index a750c61..b6de2bf 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcOffence.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcOffence.lua +@@ -1131,6 +1131,11 @@ function calcs.offence(env, actor, activeSkill) + modDB:NewMod("DPS", "MORE", detonateTwice, "Grenade Activate Twice") + end + ++ -- Dual wield DPS multiplier ++ if skillFlags.bothWeaponAttack and skillData.doubleHitsWhenDualWielding then ++ skillModList:NewMod("DPS", "MORE", 100, "Hits with both weapons") ++ end ++ + if skillModList:Flag(nil, "HasSeals") and not skillModList:Flag(nil, "NoRepeatBonuses") then + -- Applies seal bonuses based on seal count + local totalCastSpeed = 1 / activeSkill.activeEffect.grantedEffect.castTime * calcLib.mod(skillModList, skillCfg, "Speed") +@@ -2386,9 +2391,6 @@ function calcs.offence(env, actor, activeSkill) + -- Unarmed override for Concoction skills + if skillFlags.unarmed then + source = copyTable(data.unarmedWeaponData[env.classId]) +- if skillData.CritChance then +- source.CritChance = skillData.CritChance +- end + end + if source.FacebreakerItemDamage and activeSkill.activeEffect.grantedEffect.weaponTypes and activeSkill.activeEffect.grantedEffect.weaponTypes["One Hand Mace"] then + for _, damageType in ipairs(dmgTypeList) do +@@ -2399,6 +2401,9 @@ function calcs.offence(env, actor, activeSkill) + if critOverride and source.type and source.type ~= "None" then + source.CritChance = critOverride + end ++ if skillData.CritChance then ++ source.CritChance = skillData.CritChance ++ end + t_insert(passList, { + label = "Main Hand", + source = source, +@@ -2416,9 +2421,6 @@ function calcs.offence(env, actor, activeSkill) + -- Unarmed override for Concoction skills + if skillFlags.unarmed then + source = copyTable(data.unarmedWeaponData[env.classId]) +- if skillData.CritChance then +- source.CritChance = skillData.CritChance +- end + end + if critOverride and source.type and source.type ~= "None" then + source.CritChance = critOverride +@@ -2468,7 +2470,7 @@ function calcs.offence(env, actor, activeSkill) + elseif mode == "AVERAGE" then + output[stat] = ((output.MainHand[stat] or 0) + (output.OffHand[stat] or 0)) / 2 + elseif mode == "CRIT" then +- if skillFlags.bothWeaponAttack and skillData.doubleHitsWhenDualWielding then ++ if skillFlags.bothWeaponAttack and skillData.combinesHitsWhenDualWielding then + output[stat] = (output.MainHand[stat] or 0) + (output.OffHand[stat] or 0) - ((output.MainHand[stat] or 0) * (output.OffHand[stat] or 0) / 100) + else + output[stat] = ((output.MainHand[stat] or 0) + (output.OffHand[stat] or 0)) / 2 +@@ -2542,7 +2544,7 @@ function calcs.offence(env, actor, activeSkill) + end + elseif mode == "DPS" then + output[stat] = (output.MainHand[stat] or 0) + (output.OffHand[stat] or 0) +- if not skillData.doubleHitsWhenDualWielding then ++ if not skillData.combinesHitsWhenDualWielding then + output[stat] = output[stat] / 2 + end + end +@@ -2741,7 +2743,7 @@ function calcs.offence(env, actor, activeSkill) + baseTime = 1 / ( source.AttackRate or 1 ) + skillModList:Sum("BASE", cfg, "Speed") + end + else +- baseTime = skillData.castTimeOverride or activeSkill.activeEffect.grantedEffect.castTime or 1 ++ baseTime = (skillData.castTimeOverride or activeSkill.activeEffect.grantedEffect.castTime or 1) + skillModList:Sum("BASE", cfg, "Speed") + end + local more = skillModList:More(cfg, "Speed") + output.Repeats = globalOutput.Repeats or 1 +@@ -3057,11 +3059,26 @@ function calcs.offence(env, actor, activeSkill) + end + elseif skillFlags.bothWeaponAttack then + if breakdown then +- breakdown.Speed = { +- "Both weapons:", +- s_format("2 / (1 / %.2f + 1 / %.2f)", output.MainHand.Speed, output.OffHand.Speed), +- s_format("= %.2f", output.Speed), +- } ++ if skillData.combinesHitsWhenDualWielding then ++ breakdown.Speed = { ++ "Combined hit from both weapons:", ++ s_format("1 / (1 / %.2f + 1 / %.2f)", output.MainHand.Speed, output.OffHand.Speed), ++ s_format("= %.2f", output.Speed), ++ } ++ elseif skillData.doubleHitsWhenDualWielding then ++ breakdown.Speed = { ++ "Simultaneous hits from each weapon:", ++ s_format("2 / (1 / %.2f + 1 / %.2f)", output.MainHand.Speed, output.OffHand.Speed), ++ s_format("%.2f ^8(hits twice per attack)", output.Speed), ++ s_format("= %.2f", output.Speed), ++ } ++ else ++ breakdown.Speed = { ++ "Alternating both weapons:", ++ s_format("2 / (1 / %.2f + 1 / %.2f)", output.MainHand.Speed, output.OffHand.Speed), ++ s_format("= %.2f", output.Speed), ++ } ++ end + end + end + if skillData.channelTimeMultiplier then +@@ -3185,7 +3202,7 @@ function calcs.offence(env, actor, activeSkill) + + if env.mode_buffs then + -- Iterative over all the active skills to account for exerted attacks provided by warcries +- if not activeSkill.skillTypes[SkillType.NeverExertable] and not activeSkill.skillTypes[SkillType.Triggered] and not activeSkill.skillTypes[SkillType.Channel] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] and not activeSkill.skillTypes[SkillType.Retaliation] then ++ if not activeSkill.skillTypes[SkillType.NeverExertable] and not activeSkill.skillTypes[SkillType.Triggered] and not activeSkill.skillTypes[SkillType.OtherThingUsesSkill] and not activeSkill.skillTypes[SkillType.Retaliation] then + for index, value in ipairs(actor.activeSkillList) do + if value.activeEffect.grantedEffect.name == "Ancestral Cry" and activeSkill.skillTypes[SkillType.MeleeSingleTarget] and not globalOutput.AncestralCryCalculated then + globalOutput.AncestralCryDuration = calcSkillDuration(value.skillModList, value.skillCfg, value.skillData, env, enemyDB) +@@ -3875,9 +3892,11 @@ function calcs.offence(env, actor, activeSkill) + output.DoubleDamageEffect = output.DoubleDamageChance / 100 + output.ScaledDamageEffect = output.ScaledDamageEffect * (1 + output.DoubleDamageEffect + output.TripleDamageEffect) + +- skillData.dpsMultiplier = ( skillData.dpsMultiplier or 1 ) * calcLib.mod(skillModList, skillCfg, "DPS") + +- local hitRate = output.HitChance / 100 * (globalOutput.HitSpeed or globalOutput.Speed) * skillData.dpsMultiplier ++ ++ output.DpsMultiplier = ( skillData.dpsMultiplier or 1 ) * calcLib.mod(skillModList, skillCfg, "DPS") ++ ++ local hitRate = output.HitChance / 100 * (globalOutput.HitSpeed or globalOutput.Speed) * output.DpsMultiplier + + local enemyRarity = (enemyDB:Flag(nil, "Condition:Unique") and "Unique" or (enemyDB:Flag(nil, "Condition:RareOrUnique") and "Rare" or "Normal")) + -- Calculate culling DPS +@@ -4425,7 +4444,7 @@ function calcs.offence(env, actor, activeSkill) + local repeatPenalty = skillModList:Flag(nil, "HasSeals") and skillModList:Flag(nil, "DamageSeal") and not skillModList:Flag(nil, "NoRepeatBonuses") and calcLib.mod(skillModList, skillCfg, "SealRepeatPenalty") or 1 + globalOutput.AverageBurstDamage = output.AverageDamage + output.AverageDamage * (globalOutput.AverageBurstHits - 1) * repeatPenalty or 0 + globalOutput.ShowBurst = globalOutput.AverageBurstHits > 1 +- output.TotalDPS = output.AverageDamage * (globalOutput.HitSpeed or globalOutput.Speed) * skillData.dpsMultiplier * quantityMultiplier ++ output.TotalDPS = output.AverageDamage * (globalOutput.HitSpeed or globalOutput.Speed) * output.DpsMultiplier * quantityMultiplier + if breakdown then + if output.CritEffect ~= 1 then + breakdown.AverageHit = { } +@@ -4517,7 +4536,7 @@ function calcs.offence(env, actor, activeSkill) + local portionElemental = (output.AverageHit / PvpTvalue / PvpElemental2 ) ^ PvpElemental1 * PvpTvalue * PvpElemental2 * percentageElemental + output.PvpAverageHit = (portionNonElemental + portionElemental) * PvpMultiplier + output.PvpAverageDamage = output.PvpAverageHit * output.HitChance / 100 +- output.PvpTotalDPS = output.PvpAverageDamage * (globalOutput.HitSpeed or globalOutput.Speed) * skillData.dpsMultiplier ++ output.PvpTotalDPS = output.PvpAverageDamage * (globalOutput.HitSpeed or globalOutput.Speed) * output.DpsMultiplier + + -- fix for these being nan + if output.PvpAverageHit ~= output.PvpAverageHit then +@@ -4579,6 +4598,7 @@ function calcs.offence(env, actor, activeSkill) + combineStat("CritBifurcates", "AVERAGE") + combineStat("AverageDamage", "DPS") + combineStat("PvpAverageDamage", "DPS") ++ combineStat("DpsMultiplier", "DPS") + combineStat("TotalDPS", "DPS") + combineStat("PvpTotalDPS", "DPS") + combineStat("LifeLeechDuration", "DPS") +@@ -4648,8 +4668,10 @@ function calcs.offence(env, actor, activeSkill) + if breakdown then + breakdown.AverageDamage = { } + t_insert(breakdown.AverageDamage, "Both weapons:") +- if skillData.doubleHitsWhenDualWielding then ++ if skillData.combinesHitsWhenDualWielding then + t_insert(breakdown.AverageDamage, s_format("%.1f + %.1f ^8(skill hits with both weapons at once)", output.MainHand.AverageDamage, output.OffHand.AverageDamage)) ++ elseif skillData.doubleHitsWhenDualWielding then ++ t_insert(breakdown.AverageDamage, s_format("(%.1f + %.1f) / 2 ^8(skill hits once with each weapon)", output.MainHand.AverageDamage, output.OffHand.AverageDamage)) + else + t_insert(breakdown.AverageDamage, s_format("(%.1f + %.1f) / 2 ^8(skill alternates weapons)", output.MainHand.AverageDamage, output.OffHand.AverageDamage)) + end +@@ -4657,7 +4679,7 @@ function calcs.offence(env, actor, activeSkill) + if skillFlags.isPvP then + breakdown.PvpAverageDamage = { } + t_insert(breakdown.PvpAverageDamage, "Both weapons:") +- if skillData.doubleHitsWhenDualWielding then ++ if skillData.combinesHitsWhenDualWielding then + t_insert(breakdown.PvpAverageDamage, s_format("%.1f + %.1f ^8(skill hits with both weapons at once)", output.MainHand.PvpAverageDamage, output.OffHand.PvpAverageDamage)) + else + t_insert(breakdown.PvpAverageDamage, s_format("(%.1f + %.1f) / 2 ^8(skill alternates weapons)", output.MainHand.PvpAverageDamage, output.OffHand.PvpAverageDamage)) +@@ -4691,8 +4713,8 @@ function calcs.offence(env, actor, activeSkill) + output.HitSpeed and s_format("x %.2f ^8(hit rate)", output.HitSpeed) or s_format("x %.2f ^8(cast rate)", output.Speed), + } + end +- if skillData.dpsMultiplier ~= 1 then +- t_insert(breakdown.TotalDPS, s_format("x %g ^8(DPS multiplier for this skill)", skillData.dpsMultiplier)) ++ if output.DpsMultiplier ~= 1 then ++ t_insert(breakdown.TotalDPS, s_format("x %g ^8(DPS multiplier for this skill)", output.DpsMultiplier)) + end + if quantityMultiplier > 1 then + t_insert(breakdown.TotalDPS, s_format("x %g ^8(quantity multiplier for this skill)", quantityMultiplier)) +@@ -4709,8 +4731,8 @@ function calcs.offence(env, actor, activeSkill) + s_format("%.1f ^8(average pvp hit)", output.PvpAverageDamage), + output.HitSpeed and s_format("x %.2f ^8(hit rate)", output.HitSpeed) or s_format("x %.2f ^8(%s rate)", output.Speed, rateType), + } +- if skillData.dpsMultiplier ~= 1 then +- t_insert(breakdown.PvpTotalDPS, s_format("x %g ^8(DPS multiplier for this skill)", skillData.dpsMultiplier)) ++ if output.DpsMultiplier ~= 1 then ++ t_insert(breakdown.PvpTotalDPS, s_format("x %g ^8(DPS multiplier for this skill)", output.DpsMultiplier)) + end + if quantityMultiplier > 1 then + t_insert(breakdown.PvpTotalDPS, s_format("x %g ^8(quantity multiplier for this skill)", quantityMultiplier)) +@@ -4720,7 +4742,7 @@ function calcs.offence(env, actor, activeSkill) + end + + if skillFlags.minion then +- skillData.summonSpeed = output.SummonedMinionsPerCast * (output.HitSpeed or output.Speed) * skillData.dpsMultiplier ++ skillData.summonSpeed = output.SummonedMinionsPerCast * (output.HitSpeed or output.Speed) * output.DpsMultiplier + end + + -- Calculate leech rates +@@ -4766,7 +4788,7 @@ function calcs.offence(env, actor, activeSkill) + output.ManaLeechGainRate = output.ManaLeechRate + output.ManaOnHitRate + end + if breakdown then +- local hitRate = output.HitChance / 100 * (globalOutput.HitSpeed or globalOutput.Speed) * skillData.dpsMultiplier ++ local hitRate = output.HitChance / 100 * (globalOutput.HitSpeed or globalOutput.Speed) * output.DpsMultiplier + if skillFlags.leechLife then + breakdown.LifeLeech = breakdown.leech(output.LifeLeechInstant, output.LifeLeechInstantRate, output.LifeLeechInstances, output.Life, "LifeLeechRate", output.MaxLifeLeechRate, output.LifeLeechDuration, output.LifeLeechInstantProportion, hitRate) + end +@@ -5064,7 +5086,7 @@ function calcs.offence(env, actor, activeSkill) + local ailmentChance = output[ailment .. "ChanceOnHit"] / 100 * (1 - output.CritChance / 100) + output[ailment .. "ChanceOnCrit"] / 100 * output.CritChance / 100 + + -- The average number of ailment that will be active on the enemy at once +- local ailmentStacks = output.HitChance / 100 * ailmentChance * skillData.dpsMultiplier ++ local ailmentStacks = output.HitChance / 100 * ailmentChance * output.DpsMultiplier + local configStacks = enemyDB:Sum("BASE", nil, "Multiplier:" .. ailment .. "Stacks") + if not skillData.triggeredOnDeath then + if output.Cooldown then +@@ -5106,8 +5128,8 @@ function calcs.offence(env, actor, activeSkill) + elseif (globalOutput.HitSpeed or globalOutput.Speed) > 0 then + t_insert(globalBreakdown[ailment .. "StackPotential"], s_format("* (%.2f / %.2f) ^8(Duration / Attack Time)", globalOutput[ailment .. "Duration"], (globalOutput.HitTime or output.Time))) + end +- if skillData.dpsMultiplier ~= 1 then +- t_insert(globalBreakdown[ailment .. "StackPotential"], s_format("* %g ^8(DPS multiplier for this skill)", skillData.dpsMultiplier)) ++ if output.DpsMultiplier ~= 1 then ++ t_insert(globalBreakdown[ailment .. "StackPotential"], s_format("* %g ^8(DPS multiplier for this skill)", output.DpsMultiplier)) + end + end + t_insert(globalBreakdown[ailment .. "StackPotential"], s_format("/ %d ^8(max number of stacks)", maxStacks)) +@@ -5949,7 +5971,7 @@ function calcs.offence(env, actor, activeSkill) + elseif band(dotCfg.keywordFlags, KeywordFlag.Trap) ~= 0 then + speed = output.TrapThrowingSpeed + end +- output.TotalDot = m_min(output.TotalDotInstance * speed * output.Duration * skillData.dpsMultiplier * quantityMultiplier, data.misc.DotDpsCap) ++ output.TotalDot = m_min(output.TotalDotInstance * speed * output.Duration * output.DpsMultiplier * quantityMultiplier, data.misc.DotDpsCap) + output.TotalDotCalcSection = output.TotalDot + if breakdown then + breakdown.TotalDot = { +@@ -5957,8 +5979,8 @@ function calcs.offence(env, actor, activeSkill) + s_format("x %.2f ^8(hits per second)", speed), + s_format("x %.2f ^8(skill duration)", output.Duration), + } +- if skillData.dpsMultiplier ~= 1 then +- t_insert(breakdown.TotalDot, s_format("x %g ^8(DPS multiplier for this skill)", skillData.dpsMultiplier)) ++ if output.DpsMultiplier ~= 1 then ++ t_insert(breakdown.TotalDot, s_format("x %g ^8(DPS multiplier for this skill)", output.DpsMultiplier)) + end + if quantityMultiplier > 1 then + t_insert(breakdown.TotalDot, s_format("x %g ^8(quantity multiplier for this skill)", quantityMultiplier)) +@@ -6206,13 +6228,13 @@ function calcs.offence(env, actor, activeSkill) + end + if skillFlags.impale then + local mainHandImpaleDPS, offHandImpaleDPS +- if skillFlags.attack and skillData.doubleHitsWhenDualWielding and skillFlags.bothWeaponAttack then ++ if skillFlags.attack and skillData.combinesHitsWhenDualWielding and skillFlags.bothWeaponAttack then + -- separately combine +- mainHandImpaleDPS = output.MainHand.impaleStoredHitAvg * ((output.MainHand.ImpaleModifier or 1) - 1) * output.MainHand.HitChance / 100 * skillData.dpsMultiplier +- offHandImpaleDPS = output.OffHand.impaleStoredHitAvg * ((output.OffHand.ImpaleModifier or 1) - 1) * output.OffHand.HitChance / 100 * skillData.dpsMultiplier ++ mainHandImpaleDPS = output.MainHand.impaleStoredHitAvg * ((output.MainHand.ImpaleModifier or 1) - 1) * output.MainHand.HitChance / 100 * output.DpsMultiplier ++ offHandImpaleDPS = output.OffHand.impaleStoredHitAvg * ((output.OffHand.ImpaleModifier or 1) - 1) * output.OffHand.HitChance / 100 * output.DpsMultiplier + output.ImpaleDPS = mainHandImpaleDPS + offHandImpaleDPS + else +- output.ImpaleDPS = output.PhysicalStoredCombinedAvg * ((output.ImpaleModifier or 1) - 1) * output.HitChance / 100 * skillData.dpsMultiplier ++ output.ImpaleDPS = output.PhysicalStoredCombinedAvg * ((output.ImpaleModifier or 1) - 1) * output.HitChance / 100 * output.DpsMultiplier + end + if skillData.showAverage then + output.WithImpaleDPS = output.AverageDamage + output.ImpaleDPS +@@ -6228,7 +6250,7 @@ function calcs.offence(env, actor, activeSkill) + output.CombinedDPS = output.CombinedDPS + output.ImpaleDPS + if breakdown then + breakdown.ImpaleDPS = {} +- if skillFlags.attack and skillData.doubleHitsWhenDualWielding and skillFlags.bothWeaponAttack then ++ if skillFlags.attack and skillData.combinesHitsWhenDualWielding and skillFlags.bothWeaponAttack then + t_insert(breakdown.ImpaleDPS, s_format("Main Hand:")) + t_insert(breakdown.ImpaleDPS, s_format("%.2f ^8(MH average physical hit before mitigation)", output.MainHand.impaleStoredHitAvg)) + t_insert(breakdown.ImpaleDPS, s_format("x %.2f ^8(MH chance to hit)", output.MainHand.HitChance / 100)) +@@ -6249,8 +6271,8 @@ function calcs.offence(env, actor, activeSkill) + if skillFlags.notAverage then + t_insert(breakdown.ImpaleDPS, output.HitSpeed and s_format("x %.2f ^8(hit rate)", output.HitSpeed) or s_format("x %.2f ^8(%s rate)", output.Speed, skillFlags.attack and "attack" or "cast")) + end +- if skillData.dpsMultiplier ~= 1 then +- t_insert(breakdown.ImpaleDPS, s_format("x %g ^8(dps multiplier for this skill)", skillData.dpsMultiplier)) ++ if output.DpsMultiplier ~= 1 then ++ t_insert(breakdown.ImpaleDPS, s_format("x %g ^8(dps multiplier for this skill)", output.DpsMultiplier)) + end + if quantityMultiplier > 1 then + t_insert(breakdown.ImpaleDPS, s_format("x %g ^8(quantity multiplier for this skill)", quantityMultiplier)) +``` + +
+ +
Modules/CalcPerform.lua (441 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcPerform.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcPerform.lua +index c903d6b..dbc4bb9 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcPerform.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcPerform.lua +@@ -86,7 +86,7 @@ local legacies = { + }, + LegacyOfGold = { + effects = { +- { stat = "ItemRarity", type = "INC", value = 45 }, ++ { stat = "LootRarity", type = "INC", value = 45 }, + } + }, + LegacyOfGranite = { +@@ -345,10 +345,6 @@ local function doActorAttribsConditions(env, actor) + end + end + +- if env.configInput.conditionShapeshifted then +- condList["Shapeshifted"] = true +- end +- + if actor.mainSkill.skillTypes[SkillType.Bear] then + condList["Shapeshifted"] = true + condList["BearForm"] = true +@@ -779,7 +775,7 @@ local function doActorMisc(env, actor) + condList["LeechingEnergyShield"] = true + end + if modDB:Flag(nil, "Condition:CanGainRage") or modDB:Sum("BASE", nil, "RageRegen") > 0 then +- local maxStacks = modDB:Sum("BASE", skillCfg, "MaximumRage") ++ local maxStacks = modDB:Sum("BASE", skillCfg, "MaximumRage") * calcLib.mod(modDB, nil, "MaximumRage") + local minStacks = m_min(modDB:Sum("BASE", nil, "MinimumRage"), maxStacks) + local rageConfig = modDB:Sum("BASE", nil, "Multiplier:RageStack") + local stacks = m_max(m_min(rageConfig, maxStacks), (minStacks > 0 and minStacks) or 0) +@@ -1034,6 +1030,125 @@ function calcs.actionSpeedMod(actor) + return actionSpeedMod + end + ++-- Initialises a minion's modifier database with its base stats (life, defences, resists), ++-- monster type mods, tamed beast mods and player-granted mods, for the given owning skill ++local function initMinionModDB(env, activeSkill) ++ local skillFlags ++ if env.mode == "CALCS" then ++ skillFlags = activeSkill.activeEffect.statSetCalcs.skillFlags ++ else ++ skillFlags = activeSkill.activeEffect.statSet.skillFlags ++ end ++ local modDB = env.modDB ++ local minion = activeSkill.minion ++ minion.modDB.multipliers["Level"] = minion.level ++ calcs.initModDB(env, minion.modDB) ++ local baseLife = minion.lifeTable[minion.level] * minion.minionData.life ++ if minion.hostile then ++ baseLife = baseLife * (env.data.mapLevelLifeMult[env.enemyLevel] or 1) ++ end ++ minion.modDB:NewMod("Life", "BASE", m_floor(baseLife), "Base") ++ if minion.minionData.energyShield then ++ minion.modDB:NewMod("LifeConvertToEnergyShield", "BASE", minion.minionData.energyShield * 100, "Base") ++ end ++ --Armour formula is math.floor((10 + 2 * level) * 1.067 ^ level) ++ minion.modDB:NewMod("Armour", "BASE", round(env.data.monsterArmourTable[minion.level] * (minion.minionData.armour or 1)), "Base") ++ --Evasion formula is math.floor((50 + 16 * level + 16 * level * (MonsterType.Evasion / 100)) * (1.0212 ^ level) ++ minion.modDB:NewMod("Evasion", "BASE", round(env.data.monsterEvasionTable[minion.level] * (minion.minionData.evasion or 1)), "Base") ++ if modDB:Flag(nil, "MinionAccuracyEqualsAccuracy") then ++ minion.modDB:NewMod("Accuracy", "BASE", calcLib.val(modDB, "Accuracy") + calcLib.val(modDB, "Dex") * (modDB:Override(nil, "DexAccBonusOverride") or data.misc.AccuracyPerDexBase), "Player") ++ else ++ -- Minions no longer need Accuracy as of patch 0.3.0 ++ minion.modDB:NewMod("CannotBeEvaded", "FLAG", 1, "Minion Attacks always hit") ++ end ++ minion.modDB:NewMod("CritMultiplier", "BASE", env.data.monsterConstants["base_critical_hit_damage_bonus"] + env.data.playerMinionIntrinsicStats["base_critical_hit_damage_bonus"], "Base") ++ if skillFlags.summonBeast then ++ minion.modDB:NewMod("FireResist", "BASE", minion.minionData.companionFireResist, "Base") ++ minion.modDB:NewMod("ColdResist", "BASE", minion.minionData.companionColdResist, "Base") ++ minion.modDB:NewMod("LightningResist", "BASE", minion.minionData.companionLightningResist, "Base") ++ minion.modDB:NewMod("ChaosResist", "BASE", minion.minionData.companionChaosResist, "Base") ++ else ++ minion.modDB:NewMod("FireResist", "BASE", minion.minionData.fireResist, "Base") ++ minion.modDB:NewMod("ColdResist", "BASE", minion.minionData.coldResist, "Base") ++ minion.modDB:NewMod("LightningResist", "BASE", minion.minionData.lightningResist, "Base") ++ minion.modDB:NewMod("ChaosResist", "BASE", minion.minionData.chaosResist, "Base") ++ end ++ minion.modDB:NewMod("ProjectileCount", "BASE", 1, "Base") ++ minion.modDB:NewMod("PhysicalHeavyStunBuildup", "MORE", data.monsterConstants["physical_hit_damage_stun_multiplier_+%_final_from_ot"], "Physical Damage") ++ minion.modDB:NewMod("EnemyHeavyStunBuildup", "MORE", data.monsterConstants["melee_hit_damage_stun_multiplier_+%_final_from_ot"], "Melee Damage", ModFlag.Melee) ++ minion.modDB:NewMod("Damage", "MORE", minion.hiddenDamageFixup * 100, "Hidden Level Scaling") ++ for _, mod in ipairs(minion.minionData.modList) do ++ minion.modDB:AddMod(mod) ++ end ++ for _, mod in ipairs(activeSkill.extraSkillModList) do ++ minion.modDB:AddMod(mod) ++ end ++ if env.talismanModList then ++ -- Adding mods provided by "Necromantic Talisman" ++ minion.modDB:AddList(env.talismanModList) ++ end ++ if env.theIronMass and minion.type == "RaisedSkeleton" then ++ minion.modDB:AddList(env.theIronMass) ++ end ++ if activeSkill.skillData.minionUseBowAndQuiver then ++ if env.player.weaponData1.type == "Bow" then ++ minion.modDB:AddList(env.player.itemList["Weapon 1"].slotModList[1]) ++ end ++ if env.player.itemList["Weapon 2"] and env.player.itemList["Weapon 2"].type == "Quiver" then ++ local quiverEffectMod = env.player.modDB:Sum("INC", nil, "EffectOfBonusesFromQuiver") / 100 ++ if quiverEffectMod > 0 then ++ for _, mod in ipairs(env.player.itemList["Weapon 2"].modList) do ++ local modCopy = copyTable(mod) ++ modCopy.source = "Many Sources:" .. tostring(quiverEffectMod * 100) .. "% Quiver Bonus Effect" ++ minion.modDB:ScaleAddMod(modCopy, quiverEffectMod) ++ end ++ end ++ end ++ end ++ if minion.itemSet or minion.uses then ++ for slotName, slot in pairs(env.build.itemsTab.slots) do ++ if minion.uses[slotName] then ++ local item ++ if minion.itemSet then ++ if slot.weaponSet == 1 and minion.itemSet.useSecondWeaponSet then ++ slotName = slotName .. " Swap" ++ end ++ item = env.build.itemsTab.items[minion.itemSet[slotName].selItemId] ++ else ++ item = env.player.itemList[slotName] ++ end ++ if item then ++ minion.itemList[slotName] = item ++ minion.modDB:AddList(item.modList or item.slotModList[slot.slotNum]) ++ end ++ end ++ end ++ end ++ if modDB:Flag(nil, "StrengthAddedToMinions") then ++ minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str")), "Player") ++ end ++ if modDB:Flag(nil, "StrengthAddedToCompanions") and activeSkill.skillTypes[SkillType.Companion] then ++ minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str")), "Sturdy Ally") ++ end ++ if modDB:Flag(nil, "HalfStrengthAddedToMinions") then ++ minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str") * 0.5), "Player") ++ end ++ if modDB:Flag(nil, "DexterityAddedToMinions") then ++ minion.modDB:NewMod("Dex", "BASE", round(calcLib.val(modDB, "Dex")), "Dead can Dance") ++ end ++ if modDB:Flag(nil, "DexterityAddedToCompanions") and activeSkill.skillTypes[SkillType.Companion] then ++ minion.modDB:NewMod("Dex", "BASE", round(calcLib.val(modDB, "Dex")), "Tandem Assault") ++ end ++end ++ ++local function addMinionModifiers(modList, skillCfg, minion) ++ for _, value in ipairs(modList:List(skillCfg, "MinionModifier")) do ++ if not value.type or minion.type == value.type then ++ minion.modDB:AddMod(value.mod) ++ end ++ end ++end ++ + -- Finalises the environment and performs the stat calculations: + -- 1. Merges keystone modifiers + -- 2. Initialises minion skills +@@ -1075,97 +1190,7 @@ function calcs.perform(env, skipEHP) + -- Initialise minion modifier database + output.Minion = { } + env.minion.output = output.Minion +- env.minion.modDB.multipliers["Level"] = env.minion.level +- calcs.initModDB(env, env.minion.modDB) +- local baseLife = env.minion.lifeTable[env.minion.level] * env.minion.minionData.life +- if env.minion.hostile then +- baseLife = baseLife * (env.data.mapLevelLifeMult[env.enemyLevel] or 1) +- end +- env.minion.modDB:NewMod("Life", "BASE", m_floor(baseLife), "Base") +- if env.minion.minionData.energyShield then +- env.minion.modDB:NewMod("LifeConvertToEnergyShield", "BASE", env.minion.minionData.energyShield * 100, "Base") +- end +- --Armour formula is math.floor((10 + 2 * level) * 1.067 ^ level) +- env.minion.modDB:NewMod("Armour", "BASE", round(env.data.monsterArmourTable[env.minion.level] * (env.minion.minionData.armour or 1)), "Base") +- --Evasion formula is math.floor((50 + 16 * level + 16 * level * (MonsterType.Evasion / 100)) * (1.0212 ^ level) +- env.minion.modDB:NewMod("Evasion", "BASE", round(env.data.monsterEvasionTable[env.minion.level] * (env.minion.minionData.evasion or 1)), "Base") +- if modDB:Flag(nil, "MinionAccuracyEqualsAccuracy") then +- env.minion.modDB:NewMod("Accuracy", "BASE", calcLib.val(modDB, "Accuracy") + calcLib.val(modDB, "Dex") * (modDB:Override(nil, "DexAccBonusOverride") or data.misc.AccuracyPerDexBase), "Player") +- else +- -- Minions no longer need Accuracy as of patch 0.3.0 +- env.minion.modDB:NewMod("CannotBeEvaded", "FLAG", 1, "Minion Attacks always hit") +- end +- env.minion.modDB:NewMod("CritMultiplier", "BASE", env.data.monsterConstants["base_critical_hit_damage_bonus"] + env.data.playerMinionIntrinsicStats["base_critical_hit_damage_bonus"], "Base") +- env.minion.modDB:NewMod("FireResist", "BASE", env.minion.minionData.fireResist, "Base") +- env.minion.modDB:NewMod("ColdResist", "BASE", env.minion.minionData.coldResist, "Base") +- env.minion.modDB:NewMod("LightningResist", "BASE", env.minion.minionData.lightningResist, "Base") +- env.minion.modDB:NewMod("ChaosResist", "BASE", env.minion.minionData.chaosResist, "Base") +- env.minion.modDB:NewMod("ProjectileCount", "BASE", 1, "Base") +- env.minion.modDB:NewMod("PhysicalHeavyStunBuildup", "MORE", data.monsterConstants["physical_hit_damage_stun_multiplier_+%_final_from_ot"], "Physical Damage") +- env.minion.modDB:NewMod("EnemyHeavyStunBuildup", "MORE", data.monsterConstants["melee_hit_damage_stun_multiplier_+%_final_from_ot"], "Melee Damage", ModFlag.Melee) +- env.minion.modDB:NewMod("Damage", "MORE", env.minion.hiddenDamageFixup * 100, "Hidden Level Scaling") +- for _, mod in ipairs(env.minion.minionData.modList) do +- env.minion.modDB:AddMod(mod) +- end +- for _, mod in ipairs(env.player.mainSkill.extraSkillModList) do +- env.minion.modDB:AddMod(mod) +- end +- if env.talismanModList then +- -- Adding mods provided by "Necromantic Talisman" +- env.minion.modDB:AddList(env.talismanModList) +- end +- if env.theIronMass and env.minion.type == "RaisedSkeleton" then +- env.minion.modDB:AddList(env.theIronMass) +- end +- if env.player.mainSkill.skillData.minionUseBowAndQuiver then +- if env.player.weaponData1.type == "Bow" then +- env.minion.modDB:AddList(env.player.itemList["Weapon 1"].slotModList[1]) +- end +- if env.player.itemList["Weapon 2"] and env.player.itemList["Weapon 2"].type == "Quiver" then +- local quiverEffectMod = env.player.modDB:Sum("INC", nil, "EffectOfBonusesFromQuiver") / 100 +- if quiverEffectMod > 0 then +- for _, mod in ipairs(env.player.itemList["Weapon 2"].modList) do +- local modCopy = copyTable(mod) +- modCopy.source = "Many Sources:" .. tostring(quiverEffectMod * 100) .. "% Quiver Bonus Effect" +- env.minion.modDB:ScaleAddMod(modCopy, quiverEffectMod) +- end +- end +- end +- end +- if env.minion.itemSet or env.minion.uses then +- for slotName, slot in pairs(env.build.itemsTab.slots) do +- if env.minion.uses[slotName] then +- local item +- if env.minion.itemSet then +- if slot.weaponSet == 1 and env.minion.itemSet.useSecondWeaponSet then +- slotName = slotName .. " Swap" +- end +- item = env.build.itemsTab.items[env.minion.itemSet[slotName].selItemId] +- else +- item = env.player.itemList[slotName] +- end +- if item then +- env.minion.itemList[slotName] = item +- env.minion.modDB:AddList(item.modList or item.slotModList[slot.slotNum]) +- end +- end +- end +- end +- if modDB:Flag(nil, "StrengthAddedToMinions") then +- env.minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str")), "Player") +- end +- if modDB:Flag(nil, "StrengthAddedToCompanions") and env.player.mainSkill.skillTypes[SkillType.Companion] then +- env.minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str")), "Sturdy Ally") +- end +- if modDB:Flag(nil, "HalfStrengthAddedToMinions") then +- env.minion.modDB:NewMod("Str", "BASE", round(calcLib.val(modDB, "Str") * 0.5), "Player") +- end +- if modDB:Flag(nil, "DexterityAddedToMinions") then +- env.minion.modDB:NewMod("Dex", "BASE", round(calcLib.val(modDB, "Dex")), "Dead can Dance") +- end +- if modDB:Flag(nil, "DexterityAddedToCompanions") and env.player.mainSkill.skillTypes[SkillType.Companion] then +- env.minion.modDB:NewMod("Dex", "BASE", round(calcLib.val(modDB, "Dex")), "Tandem Assault") +- end ++ initMinionModDB(env, env.player.mainSkill) + end + if env.talismanModList then + -- Accounting for "Necromantic Talisman" +@@ -1415,7 +1440,7 @@ function calcs.perform(env, skipEHP) + + for slot, item in pairs(env.player.itemList) do + local slotEffectMod = modDB:Sum("INC", nil, "EffectOfBonusesFrom" .. slot) / 100 +- if slotEffectMod > 0 then ++ if slotEffectMod > 0 and slot ~= "Amulet" then + if item.name:match("Kalandra's Touch") then + if slot == "Ring 2" then + item = env.player.itemList["Ring 1"] +@@ -1774,11 +1799,7 @@ function calcs.perform(env, skipEHP) + end + end + else +- for _, value in ipairs(env.player.mainSkill.skillModList:List(env.player.mainSkill.skillCfg, "MinionModifier")) do +- if not value.type or env.minion.type == value.type then +- env.minion.modDB:AddMod(value.mod) +- end +- end ++ addMinionModifiers(env.player.mainSkill.skillModList, env.player.mainSkill.skillCfg, env.minion) + for _, name in ipairs(env.minion.modDB:List(nil, "Keystone")) do + if env.spec.tree.keystoneMap[name] then + env.minion.modDB:AddList(env.spec.tree.keystoneMap[name].modList) +@@ -2414,23 +2435,23 @@ function calcs.perform(env, skipEHP) + end + if buff.type == "Curse" then + curse.modList = new("ModList") +- curse.modList:ScaleAddList(buff.modList, mult) ++ curse.modList:ScaleAddList(buff.modList, mult, true) + if partyTabEnableExportBuffs then + buffExports["Curse"][buff.name] = { isMark = curse.isMark, effectMult = curse.isMark and mult or (1 + inc / 100) * moreMark, modList = buff.modList } + end + else + -- Curse applies a buff; scale by curse effect, then buff effect + local temp = new("ModList") +- temp:ScaleAddList(buff.modList, mult) ++ temp:ScaleAddList(buff.modList, mult, true) + curse.buffModList = new("ModList") + local buffInc = modDB:Sum("INC", skillCfg, "BuffEffectOnSelf") + local buffMore = modDB:More(skillCfg, "BuffEffectOnSelf") +- curse.buffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore) ++ curse.buffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore, true) + if env.minion then + curse.minionBuffModList = new("ModList") + local buffInc = env.minion.modDB:Sum("INC", nil, "BuffEffectOnSelf") + local buffMore = env.minion.modDB:More(nil, "BuffEffectOnSelf") +- curse.minionBuffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore) ++ curse.minionBuffModList:ScaleAddList(temp, (1 + buffInc / 100) * buffMore, true) + end + end + t_insert(curses, curse) +@@ -2894,7 +2915,7 @@ function calcs.perform(env, skipEHP) + local cfg = { skillName = grantedEffect.name } + local inc = modDB:Sum("INC", cfg, "CurseEffectOnSelf") + gemModList:Sum("INC", nil, "CurseEffectAgainstPlayer") + local more = modDB:More(cfg, "CurseEffectOnSelf") * gemModList:More(nil, "CurseEffectAgainstPlayer") +- modDB:ScaleAddList(curseModList, m_max((1 + inc / 100) * more, 0)) ++ modDB:ScaleAddList(curseModList, m_max((1 + inc / 100) * more, 0), true) + end + elseif not enemyDB:Flag(nil, "Hexproof") or modDB:Flag(nil, "CursesIgnoreHexproof") then + local curse = { +@@ -2903,7 +2924,7 @@ function calcs.perform(env, skipEHP) + priority = determineCursePriority(grantedEffect.name), + } + curse.modList = new("ModList") +- curse.modList:ScaleAddList(curseModList, (1 + enemyDB:Sum("INC", nil, "CurseEffectOnSelf") / 100) * enemyDB:More(nil, "CurseEffectOnSelf")) ++ curse.modList:ScaleAddList(curseModList, (1 + enemyDB:Sum("INC", nil, "CurseEffectOnSelf") / 100) * enemyDB:More(nil, "CurseEffectOnSelf"), true) + t_insert(dest, curse) + end + end +@@ -2928,7 +2949,7 @@ function calcs.perform(env, skipEHP) + else + mult = mult * enemyDB:More(nil, "CurseEffectOnSelf") + end +- newCurse.modList:ScaleAddList(curse.modList, mult) ++ newCurse.modList:ScaleAddList(curse.modList, mult, true) + t_insert(allyCurses, newCurse) + end + +@@ -3057,11 +3078,7 @@ function calcs.perform(env, skipEHP) + modDB.multipliers["BuffOnSelf"] = (modDB.multipliers["BuffOnSelf"] or 0) + 1 + end + if env.minion then +- for _, value in ipairs(modList:List(env.player.mainSkill.skillCfg, "MinionModifier")) do +- if not value.type or env.minion.type == value.type then +- env.minion.modDB:AddMod(value.mod) +- end +- end ++ addMinionModifiers(modList, env.player.mainSkill.skillCfg, env.minion) + end + end + if env.minion then +@@ -3072,7 +3089,13 @@ function calcs.perform(env, skipEHP) + for _, modList in pairs(debuffs) do + enemyDB:AddList(modList) + end +- modDB.multipliers["CurseOnEnemy"] = #curseSlots ++ local cursesInCurseSlots = {} ++ for _, slot in ipairs(curseSlots) do ++ if not slot.isMark then ++ table.insert(cursesInCurseSlots, slot) ++ end ++ end ++ modDB.multipliers["CurseOnEnemy"] = #cursesInCurseSlots + for _, slot in ipairs(curseSlots) do + enemyDB.conditions["Cursed"] = true + if slot.isMark then +@@ -3224,6 +3247,9 @@ function calcs.perform(env, skipEHP) + }, + } + ++ -- precalculate life for rathpith Spells have 3% increased Magnitude of Ailments per 100 maximum ++ -- Life cultivated mod ++ calcs.doActorLifeManaSpirit(env.player, true) + local hitFlag + if env.mode == "CALCS" then + hitFlag = env.player.mainSkill.activeEffect.statSetCalcs.skillFlags.hit +@@ -3248,9 +3274,9 @@ function calcs.perform(env, skipEHP) + -- if not, use the generic modifiers + -- Scorch/Sap/Brittle do not have guaranteed sources from hits, and therefore will only end up in this bit of code if it's not supposed to apply the skillModList, which is bad + if ailment ~= "Scorch" and ailment ~= "Sap" and ailment ~= "Brittle" and not env.player.mainSkill.skillModList:Flag(nil, "Cannot"..ailment) and hitFlag and modDB:Flag(nil, "ChecksHighestDamage") then +- effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillModList.skillCfg, "Enemy"..ailment.."Magnitude", "AilmentMagnitude") * calcLib.mod(enemyDB, nil, "Self"..ailment.."Magnitude", "AilmentMagnitude") ++ effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillCfg, "Enemy" .. ailment .. "Magnitude", "AilmentMagnitude") * calcLib.mod(enemyDB, nil, "Self" .. ailment .. "Magnitude", "AilmentMagnitude") + else +- effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillModList.skillCfg, "Enemy"..ailment.."Magnitude", "AilmentMagnitude") * calcLib.mod(enemyDB, nil, "Self"..ailment.."Magnitude", "AilmentMagnitude") ++ effect = effect * calcLib.mod(env.player.mainSkill.skillModList, env.player.mainSkill.skillCfg, "Enemy" .. ailment .. "Magnitude", "AilmentMagnitude") * calcLib.mod(enemyDB, nil, "Self" .. ailment .. "Magnitude", "AilmentMagnitude") + end + modDB:NewMod(ailment.."Override", "BASE", effect, mod.source, mod.flags, mod.keywordFlags, unpack(mod)) + if mod.name == ailment.."Minimum" then +@@ -3294,6 +3320,55 @@ function calcs.perform(env, skipEHP) + enemyDB:NewMod("DamageTaken", "INC", enemyDB:Sum("INC", nil, "DamageTakenConsecratedGround") * effect, "Consecrated Ground") + end + ++ local function calcMinionLifePool(env, buffs, includeSkill) ++ local totalLife = 0 ++ local lifeList = { } ++ local seenMinions = { } ++ for _, activeSkill in ipairs(env.player.activeSkillList) do ++ local skillFlags = env.mode == "CALCS" and activeSkill.activeEffect.statSetCalcs.skillFlags or activeSkill.activeEffect.statSet.skillFlags ++ local minion = activeSkill.minion ++ if minion and not seenMinions[minion] and not skillFlags.disable and includeSkill(activeSkill, skillFlags) then ++ seenMinions[minion] = true ++ if minion ~= env.minion then ++ minion.output = minion.output or { } ++ initMinionModDB(env, activeSkill) ++ addMinionModifiers(activeSkill.skillModList, activeSkill.skillCfg, minion) ++ for _, name in ipairs(minion.modDB:List(nil, "Keystone")) do ++ if env.spec.tree.keystoneMap[name] then ++ minion.modDB:AddList(env.spec.tree.keystoneMap[name].modList) ++ end ++ end ++ for _, modList in pairs(buffs) do ++ addMinionModifiers(modList, activeSkill.skillCfg, minion) ++ end ++ doActorAttribsConditions(env, minion) ++ end ++ calcs.doActorLifeManaSpirit(minion, true) ++ totalLife = totalLife + minion.output.Life ++ t_insert(lifeList, { name = minion.minionData and minion.minionData.name or activeSkill.activeEffect.grantedEffect.name, life = minion.output.Life }) ++ end ++ end ++ return totalLife, lifeList ++ end ++ ++ -- Total life of spectres, for "% of Damage from Hits is taken from your Spectres' Life before you" ++ if modDB:HasMod("BASE", nil, "TakenFromSpectresBeforeYou") and not modDB:Override(nil, "TotalSpectreLife") then ++ local totalSpectreLife, spectreLifeList = calcMinionLifePool(env, buffs, function(activeSkill, skillFlags) ++ return skillFlags.spectre and not activeSkill.skillTypes[SkillType.MinionsAreUndamagable] ++ end) ++ modDB:NewMod("TotalSpectreLife", "BASE", totalSpectreLife, "Spectres") ++ env.player.spectreLifeList = spectreLifeList ++ end ++ ++ -- Total life of damageable companions, for "% of Damage from Hits is taken from your Companion's Life before you" ++ if modDB:HasMod("BASE", nil, "TakenFromCompanionBeforeYou", "TakenFromCompanionBeforeYouFromDeflected") and not modDB:Override(nil, "TotalCompanionLife") then ++ local totalCompanionLife, companionLifeList = calcMinionLifePool(env, buffs, function(activeSkill) ++ return activeSkill.skillTypes[SkillType.Companion] and not activeSkill.skillTypes[SkillType.MinionsAreUndamagable] ++ end) ++ modDB:NewMod("TotalCompanionLife", "BASE", totalCompanionLife, "Companions") ++ env.player.companionLifeList = companionLifeList ++ end ++ + -- Defence/offence calculations + calcs.defence(env, env.player) + local function getSkillExposureEffect(source, element) +``` + +
+ +
Modules/Calcs.lua (450 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/Calcs.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/Calcs.lua +index 12f8169..f8cf2e8 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/Calcs.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/Calcs.lua +@@ -124,14 +124,42 @@ function calcs.getMiscCalculator(build) + -- Run base calculation pass + local env, cachedPlayerDB, cachedEnemyDB, cachedMinionDB = calcs.initEnv(build, "CALCULATOR") + calcs.perform(env) +- local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", {}, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = nil}) ++ -- Capture per-skill Full DPS results and their input references during the base pass, ++ -- so accelerated calls can reuse results for skills whose inputs are unchanged ++ local fullDPSStore = { } ++ local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", {}, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = nil, fullDPSCache = { store = fullDPSStore, capture = true }}) + local usedFullDPS = #fullDPS.skills > 0 + if usedFullDPS then + env.player.output.SkillDPS = fullDPS.skills + env.player.output.FullDPS = fullDPS.combinedDPS + env.player.output.FullDotDPS = fullDPS.TotalDotDPS + end +- return function(override, useFullDPS) ++ local fastEnv ++ return function(override, useFullDPS, fastCalcOptions) ++ if fastCalcOptions then ++ if fastCalcOptions.fullDPSOnly and usedFullDPS and useFullDPS then ++ -- The caller only reads the FullDPS roll-up (e.g. sorting gems by Full DPS), and ++ -- calcFullDPS builds its own environments, so the main-skill pass can be skipped entirely. ++ -- The base-pass cache store lets skills with unchanged inputs reuse their captured results ++ local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", override, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = nil, fullDPSCache = { store = fullDPSStore } }) ++ return { SkillDPS = fullDPS.skills, FullDPS = fullDPS.combinedDPS, FullDotDPS = fullDPS.TotalDotDPS } ++ end ++ -- Accelerated pass for hot loops (e.g. gem dropdown DPS sorting): reuse the cached ++ -- DBs and environment so unchanged state (tree, items, requirements - per the ++ -- accelerate flags) is carried over instead of being rebuilt for every call. ++ -- The first call builds the reusable environment from scratch, like calcFullDPS does. ++ local accelerate = fastEnv and fastCalcOptions or nil ++ fastEnv = calcs.initEnv(build, "CALCULATOR", override, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = fastEnv, accelerate = accelerate }) ++ fastEnv.override = override ++ calcs.perform(fastEnv, fastCalcOptions.skipEHP) ++ if (useFullDPS ~= false or build.viewMode == "TREE") and usedFullDPS then ++ local fullDPS = calcs.calcFullDPS(build, "CALCULATOR", override, { cachedPlayerDB = cachedPlayerDB, cachedEnemyDB = cachedEnemyDB, cachedMinionDB = cachedMinionDB, env = nil}) ++ fastEnv.player.output.SkillDPS = fullDPS.skills ++ fastEnv.player.output.FullDPS = fullDPS.combinedDPS ++ fastEnv.player.output.FullDotDPS = fullDPS.TotalDotDPS ++ end ++ return fastEnv.player.output ++ end + local env, cachedPlayerDB, cachedEnemyDB, cachedMinionDB = calcs.initEnv(build, "CALCULATOR", override) + -- we need to preserve the override somewhere for use by possible trigger-based build-outs with overrides + env.override = override +@@ -149,9 +177,100 @@ function calcs.getMiscCalculator(build) + end, env.player.output + end + ++-- Output fields harvested from each Full DPS calc pass; captured into plain snapshot ++-- tables so that cached passes can be merged identically to freshly computed ones ++local harvestFields = { "TotalDPS", "BleedDPS", "CorruptingBloodDPS", "IgniteDPS", "BurningGroundDPS", "PoisonDPS", "CausticGroundDPS", "ImpaleDPS", "DecayDPS", "TotalDot", "CullMultiplier" } ++local function captureFields(output) ++ local captured = { } ++ for _, field in ipairs(harvestFields) do ++ captured[field] = output[field] ++ end ++ return captured ++end ++ ++local mergeStatsSpec = { ++ { key = "BleedDPS", target = "bleedDPS", mode = "max" }, ++ { key = "CorruptingBloodDPS", target = "corruptingBloodDPS", mode = "max" }, ++ { key = "IgniteDPS", target = "igniteDPS", mode = "max" }, ++ { key = "BurningGroundDPS", target = "burningGroundDPS", mode = "max" }, ++ { key = "PoisonDPS", target = "poisonDPS", mode = "max" }, ++ { key = "CausticGroundDPS", target = "causticGroundDPS", mode = "max" }, ++ { key = "ImpaleDPS", target = "impaleDPS", mode = "add", scaled = true }, ++ { key = "DecayDPS", target = "decayDPS", mode = "add" }, ++ { key = "CullMultiplier", target = "cullingMulti", mode = "cull" }, ++} ++ ++-- Tolerant modifier equality for the Full DPS input diff: mod tables are pointer-stable ++-- across initEnv calls within one build revision, except for a few mods constructed per ++-- pass (e.g. GemLevel, level-scaled support mods), which are compared structurally instead. ++local function modsEqual(a, b) ++ return a == b or (type(a) == "table" and type(b) == "table" and tableDeepEquals(a, b) and tableDeepEquals(b, a)) ++end ++local function modListsEqual(refList, curList) ++ if #refList ~= #curList then ++ return false ++ end ++ for i = 1, #refList do ++ if not modsEqual(refList[i], curList[i]) then ++ return false ++ end ++ end ++ return true ++end ++ ++-- Capture the coupling surface of an environment: the state through which one skill's gems ++-- can influence other skills' results - buffs/auras/curses each skill provides (buffList) ++-- and exposure it can inflict. While this surface is unchanged, a skill whose own mod list ++-- is unchanged must produce unchanged results. ++local exposureElements = { "Fire", "Cold", "Lightning", "Chaos" } ++local function captureCouplingSurface(env) ++ local surface = { mods = { }, meta = { } } ++ for _, skill in ipairs(env.player.activeSkillList) do ++ for _, buff in ipairs(skill.buffList or { }) do ++ surface.meta[#surface.meta + 1] = tostring(buff.type) .. "/" .. tostring(buff.name) ++ for _, mod in ipairs(buff.modList or { }) do ++ surface.mods[#surface.mods + 1] = mod ++ end ++ end ++ local modList = skill.baseSkillModList ++ if modList then ++ if modList:HasMod("FLAG", nil, "InflictExposure") then ++ surface.meta[#surface.meta + 1] = "expoFlag" ++ end ++ for _, element in ipairs(exposureElements) do ++ if modList:HasMod("BASE", nil, element .. "ExposureChance") then ++ surface.meta[#surface.meta + 1] = "expo" .. element ++ end ++ end ++ end ++ end ++ surface.metaStr = table.concat(surface.meta, ";") ++ return surface ++end ++local function surfacesEqual(refSurface, curSurface) ++ return refSurface.metaStr == curSurface.metaStr and modListsEqual(refSurface.mods, curSurface.mods) ++end ++ + function calcs.calcFullDPS(build, mode, override, specEnv) + local fullEnv, cachedPlayerDB, cachedEnemyDB, cachedMinionDB = calcs.initEnv(build, mode, override, specEnv) + local usedEnv = nil ++ -- Optional per-skill result cache driven by input diffing (specEnv.fullDPSCache): ++ -- with capture set, each skill's harvested results are stored in the cache store along ++ -- with its input references (own mod list + the env's coupling surface); on later calls, ++ -- a skill whose references are unchanged merges its cached results instead of recalculating ++ local fullDPSCache = specEnv and specEnv.fullDPSCache ++ local cacheStore = fullDPSCache and fullDPSCache.store ++ local surfaceSame = false ++ if cacheStore then ++ local curSurface = captureCouplingSurface(fullEnv) ++ if fullDPSCache.capture then ++ cacheStore.snapshots = { } ++ cacheStore.refs = { } ++ cacheStore.surface = curSurface ++ else ++ surfaceSame = cacheStore.surface ~= nil and surfacesEqual(cacheStore.surface, curSurface) ++ end ++ end + + local fullDPS = { + combinedDPS = 0, +@@ -169,52 +288,97 @@ function calcs.calcFullDPS(build, mode, override, specEnv) + cullingMulti = 0 + } + +- local poisonSource = "" +- local bleedSource = "" +- local corruptingBloodSource = "" +- local igniteSource = "" +- local burningGroundSource = "" +- local causticGroundSource = "" ++ ++ local sources = { } ++ ++ local function mergeStats(out, count, sourceName) ++ for _, stat in ipairs(mergeStatsSpec) do ++ local value = out[stat.key] ++ if value then ++ if stat.mode == "max" then ++ if value > fullDPS[stat.target] then ++ fullDPS[stat.target] = value ++ sources[stat.target] = sourceName ++ end ++ elseif stat.mode == "add" then ++ if value > 0 then ++ fullDPS[stat.target] = fullDPS[stat.target] + value * (stat.scaled and count or 1) ++ end ++ elseif stat.mode == "cull" then ++ if value > 1 and value > fullDPS[stat.target] then ++ fullDPS[stat.target] = value ++ end ++ end ++ end ++ end ++ end ++ ++ -- Merge one captured calc pass into the Full DPS totals ++ local function mergePass(pass) ++ for _, actor in ipairs(pass.actors) do ++ local out = actor.out ++ if out.TotalDPS and out.TotalDPS > 0 then ++ t_insert(fullDPS.skills, { name = actor.name, dps = out.TotalDPS, count = actor.count, trigger = actor.trigger, skillPart = actor.skillPart }) ++ fullDPS.combinedDPS = fullDPS.combinedDPS + out.TotalDPS * actor.count ++ end ++ mergeStats(out, actor.count, actor.sourceName) ++ if out.TotalDot and out.TotalDot > 0 and actor.dotScale then ++ fullDPS.dotDPS = fullDPS.dotDPS + out.TotalDot * actor.dotScale ++ end ++ end ++ end + + for _, activeSkill in ipairs(fullEnv.player.activeSkillList) do + if activeSkill.socketGroup and activeSkill.socketGroup.includeInFullDPS then +- local activeSkillCount, enabled = calcs.getActiveSkillCount(activeSkill) +- if enabled then ++ local uuid = cacheStore and cacheSkillUUID(activeSkill, fullEnv) ++ local canCacheSkill = not (activeSkill.triggeredBy or activeSkill.skillData.triggered) ++ local cachedPasses ++ if canCacheSkill and surfaceSame and activeSkill.baseSkillModList then ++ local ref = cacheStore.refs[uuid] ++ if ref and cacheStore.snapshots[uuid] and modListsEqual(ref, activeSkill.baseSkillModList) then ++ cachedPasses = cacheStore.snapshots[uuid] ++ end ++ end ++ local activeSkillCount, enabled ++ if not cachedPasses then ++ activeSkillCount, enabled = calcs.getActiveSkillCount(activeSkill) ++ end ++ if cachedPasses then ++ -- This skill's own mod list and the coupling surface are unchanged since the ++ -- capture pass, so its results cannot have changed: merge the cached passes ++ for _, pass in ipairs(cachedPasses) do ++ mergePass(pass) ++ end ++ elseif enabled then ++ local ownRef ++ if canCacheSkill and cacheStore and fullDPSCache.capture and activeSkill.baseSkillModList then ++ -- Reference the skill's pre-perform mod list for later input diffing ++ ownRef = { } ++ for i, mod in ipairs(activeSkill.baseSkillModList) do ++ ownRef[i] = mod ++ end ++ end + fullEnv.player.mainSkill = activeSkill + calcs.perform(fullEnv, true) + usedEnv = fullEnv ++ -- Capture this pass's results into a plain snapshot, then merge it into the totals; ++ -- the snapshot lets later calls reuse the results when this skill's inputs are unchanged + local skillName = calcs.getActiveSkillDisplayName(activeSkill) +- local minionName = nil ++ local dotCanStack = activeSkill.activeEffect.statSet.skillFlags.DotCanStack ++ local pass = { actors = { } } ++ local minionOut + if activeSkill.minion or usedEnv.minion then +- if usedEnv.minion.output.TotalDPS and usedEnv.minion.output.TotalDPS > 0 then +- minionName = (activeSkill.minion and activeSkill.minion.minionData.name..": ") or (usedEnv.minion and usedEnv.minion.minionData.name..": ") or "" +- t_insert(fullDPS.skills, { name = skillName, dps = usedEnv.minion.output.TotalDPS, count = activeSkillCount, trigger = activeSkill.infoTrigger, skillPart = minionName..activeSkill.skillPartName }) +- fullDPS.combinedDPS = fullDPS.combinedDPS + usedEnv.minion.output.TotalDPS * activeSkillCount +- end +- if usedEnv.minion.output.BleedDPS and usedEnv.minion.output.BleedDPS > fullDPS.bleedDPS then +- fullDPS.bleedDPS = usedEnv.minion.output.BleedDPS +- bleedSource = skillName +- end +- if usedEnv.minion.output.IgniteDPS and usedEnv.minion.output.IgniteDPS > fullDPS.igniteDPS then +- fullDPS.igniteDPS = usedEnv.minion.output.IgniteDPS +- igniteSource = skillName +- end +- if usedEnv.minion.output.PoisonDPS and usedEnv.minion.output.PoisonDPS > fullDPS.poisonDPS then +- fullDPS.poisonDPS = usedEnv.minion.output.PoisonDPS +- poisonSource = skillName +- end +- if usedEnv.minion.output.ImpaleDPS and usedEnv.minion.output.ImpaleDPS > 0 then +- fullDPS.impaleDPS = fullDPS.impaleDPS + usedEnv.minion.output.ImpaleDPS * activeSkillCount +- end +- if usedEnv.minion.output.DecayDPS and usedEnv.minion.output.DecayDPS > 0 then +- fullDPS.decayDPS = fullDPS.decayDPS + usedEnv.minion.output.DecayDPS +- end +- if usedEnv.minion.output.TotalDot and usedEnv.minion.output.TotalDot > 0 then +- fullDPS.dotDPS = fullDPS.dotDPS + usedEnv.minion.output.TotalDot +- end +- if usedEnv.minion.output.CullMultiplier and usedEnv.minion.output.CullMultiplier > 1 and usedEnv.minion.output.CullMultiplier > fullDPS.cullingMulti then +- fullDPS.cullingMulti = usedEnv.minion.output.CullMultiplier +- end ++ minionOut = captureFields(usedEnv.minion.output) ++ local minionNamePrefix = (activeSkill.minion and activeSkill.minion.minionData.name..": ") or (usedEnv.minion and usedEnv.minion.minionData.name..": ") or "" ++ t_insert(pass.actors, { ++ out = minionOut, ++ name = skillName, ++ count = activeSkillCount, ++ trigger = activeSkill.infoTrigger, ++ skillPart = minionNamePrefix .. activeSkill.skillPartName, ++ sourceName = skillName, ++ dotScale = 1, ++ }) + -- This is a fix to prevent Absolution spell hit from being counted multiple times when increasing minions count + if activeSkill.activeEffect.grantedEffect.name == "Absolution" and fullEnv.modDB:Flag(false, "Condition:AbsolutionSkillDamageCountedOnce") then + activeSkillCount = 1 +@@ -222,87 +386,34 @@ function calcs.calcFullDPS(build, mode, override, specEnv) + end + end + ++ local playerOut = captureFields(usedEnv.player.output) + if activeSkill.mirage then + local mirageCount = (activeSkill.mirage.count or 1) * activeSkillCount +- if activeSkill.mirage.output.TotalDPS and activeSkill.mirage.output.TotalDPS > 0 then +- t_insert(fullDPS.skills, { name = activeSkill.mirage.name .. " (Mirage)", dps = activeSkill.mirage.output.TotalDPS, count = mirageCount, trigger = activeSkill.mirage.infoTrigger, skillPart = activeSkill.mirage.skillPartName }) +- fullDPS.combinedDPS = fullDPS.combinedDPS + activeSkill.mirage.output.TotalDPS * mirageCount +- end +- if activeSkill.mirage.output.BleedDPS and activeSkill.mirage.output.BleedDPS > fullDPS.bleedDPS then +- fullDPS.bleedDPS = activeSkill.mirage.output.BleedDPS +- bleedSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" +- end +- if activeSkill.mirage.output.IgniteDPS and activeSkill.mirage.output.IgniteDPS > fullDPS.igniteDPS then +- fullDPS.igniteDPS = activeSkill.mirage.output.IgniteDPS +- igniteSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" +- end +- if activeSkill.mirage.output.PoisonDPS and activeSkill.mirage.output.PoisonDPS > fullDPS.poisonDPS then +- fullDPS.poisonDPS = activeSkill.mirage.output.PoisonDPS +- poisonSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" +- end +- if activeSkill.mirage.output.ImpaleDPS and activeSkill.mirage.output.ImpaleDPS > 0 then +- fullDPS.impaleDPS = fullDPS.impaleDPS + activeSkill.mirage.output.ImpaleDPS * mirageCount +- end +- if activeSkill.mirage.output.DecayDPS and activeSkill.mirage.output.DecayDPS > 0 then +- fullDPS.decayDPS = fullDPS.decayDPS + activeSkill.mirage.output.DecayDPS +- end +- -- This will only take skillFlags from main env. Needs rework if trigger section is to be kept. +- if activeSkill.mirage.output.TotalDot and activeSkill.mirage.output.TotalDot > 0 and (activeSkill.activeEffect.statSet.skillFlags.DotCanStack or (usedEnv.player.output.TotalDot and usedEnv.player.output.TotalDot == 0)) then +- fullDPS.dotDPS = fullDPS.dotDPS + activeSkill.mirage.output.TotalDot * (activeSkill.activeEffect.statSet.skillFlags.DotCanStack and mirageCount or 1) +- end +- if activeSkill.mirage.output.CullMultiplier and activeSkill.mirage.output.CullMultiplier > 1 and activeSkill.mirage.output.CullMultiplier > fullDPS.cullingMulti then +- fullDPS.cullingMulti = activeSkill.mirage.output.CullMultiplier +- end +- if activeSkill.mirage.output.BurningGroundDPS and activeSkill.mirage.output.BurningGroundDPS > fullDPS.burningGroundDPS then +- fullDPS.burningGroundDPS = activeSkill.mirage.output.BurningGroundDPS +- burningGroundSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" +- end +- if activeSkill.mirage.output.CausticGroundDPS and activeSkill.mirage.output.CausticGroundDPS > fullDPS.causticGroundDPS then +- fullDPS.causticGroundDPS = activeSkill.mirage.output.CausticGroundDPS +- causticGroundSource = activeSkill.activeEffect.grantedEffect.name .. " (Mirage)" +- end ++ t_insert(pass.actors, { ++ out = captureFields(activeSkill.mirage.output), ++ name = activeSkill.mirage.name .. " (Mirage)", ++ count = mirageCount, ++ trigger = activeSkill.mirage.infoTrigger, ++ skillPart = activeSkill.mirage.skillPartName, ++ sourceName = skillName .. " (Mirage)", ++ dotScale = (dotCanStack or (playerOut.TotalDot and playerOut.TotalDot == 0)) and (dotCanStack and mirageCount or 1) or nil, ++ }) + end + +- if usedEnv.player.output.TotalDPS and usedEnv.player.output.TotalDPS > 0 then +- t_insert(fullDPS.skills, { name = skillName, dps = usedEnv.player.output.TotalDPS, count = activeSkillCount, trigger = activeSkill.infoTrigger, skillPart = minionName and activeSkill.infoMessage2 or activeSkill.skillPartName }) +- fullDPS.combinedDPS = fullDPS.combinedDPS + usedEnv.player.output.TotalDPS * activeSkillCount +- end +- if usedEnv.player.output.BleedDPS and usedEnv.player.output.BleedDPS > fullDPS.bleedDPS then +- fullDPS.bleedDPS = usedEnv.player.output.BleedDPS +- bleedSource = skillName +- end +- if usedEnv.player.output.CorruptingBloodDPS and usedEnv.player.output.CorruptingBloodDPS > fullDPS.corruptingBloodDPS then +- fullDPS.corruptingBloodDPS = usedEnv.player.output.CorruptingBloodDPS +- corruptingBloodSource = skillName +- end +- if usedEnv.player.output.IgniteDPS and usedEnv.player.output.IgniteDPS > fullDPS.igniteDPS then +- fullDPS.igniteDPS = usedEnv.player.output.IgniteDPS +- igniteSource = skillName +- end +- if usedEnv.player.output.BurningGroundDPS and usedEnv.player.output.BurningGroundDPS > fullDPS.burningGroundDPS then +- fullDPS.burningGroundDPS = usedEnv.player.output.BurningGroundDPS +- burningGroundSource = skillName +- end +- if usedEnv.player.output.PoisonDPS and usedEnv.player.output.PoisonDPS > fullDPS.poisonDPS then +- fullDPS.poisonDPS = usedEnv.player.output.PoisonDPS +- poisonSource = skillName +- end +- if usedEnv.player.output.CausticGroundDPS and usedEnv.player.output.CausticGroundDPS > fullDPS.causticGroundDPS then +- fullDPS.causticGroundDPS = usedEnv.player.output.CausticGroundDPS +- causticGroundSource = skillName +- end +- if usedEnv.player.output.ImpaleDPS and usedEnv.player.output.ImpaleDPS > 0 then +- fullDPS.impaleDPS = fullDPS.impaleDPS + usedEnv.player.output.ImpaleDPS * activeSkillCount +- end +- if usedEnv.player.output.DecayDPS and usedEnv.player.output.DecayDPS > 0 then +- fullDPS.decayDPS = fullDPS.decayDPS + usedEnv.player.output.DecayDPS +- end +- -- This will only take skillFlags from main env. Needs rework. +- if usedEnv.player.output.TotalDot and usedEnv.player.output.TotalDot > 0 then +- fullDPS.dotDPS = fullDPS.dotDPS + usedEnv.player.output.TotalDot * (activeSkill.activeEffect.statSet.skillFlags.DotCanStack and activeSkillCount or 1) +- end +- if usedEnv.player.output.CullMultiplier and usedEnv.player.output.CullMultiplier > 1 and usedEnv.player.output.CullMultiplier > fullDPS.cullingMulti then +- fullDPS.cullingMulti = usedEnv.player.output.CullMultiplier ++ local minionContributed = minionOut and minionOut.TotalDPS and minionOut.TotalDPS > 0 ++ t_insert(pass.actors, { ++ out = playerOut, ++ name = skillName, ++ count = activeSkillCount, ++ trigger = activeSkill.infoTrigger, ++ skillPart = minionContributed and activeSkill.infoMessage2 or activeSkill.skillPartName, ++ sourceName = skillName, ++ dotScale = dotCanStack and activeSkillCount or 1, ++ }) ++ mergePass(pass) ++ if cacheStore and fullDPSCache.capture and ownRef then ++ cacheStore.snapshots[uuid] = { pass } ++ cacheStore.refs[uuid] = ownRef + end + + -- Re-Build env calculator for new run +@@ -321,27 +432,27 @@ function calcs.calcFullDPS(build, mode, override, specEnv) + -- Re-Add ailment DPS components + fullDPS.TotalDotDPS = 0 + if fullDPS.bleedDPS > 0 then +- t_insert(fullDPS.skills, { name = "Best Bleed DPS", dps = fullDPS.bleedDPS, count = 1, source = bleedSource }) ++ t_insert(fullDPS.skills, { name = "Best Bleed DPS", dps = fullDPS.bleedDPS, count = 1, source = sources.bleedDPS or "" }) + fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.bleedDPS + end + if fullDPS.corruptingBloodDPS > 0 then +- t_insert(fullDPS.skills, { name = "Best Corr. Blood DPS", dps = fullDPS.corruptingBloodDPS, count = 1, source = corruptingBloodSource }) ++ t_insert(fullDPS.skills, { name = "Best Corr. Blood DPS", dps = fullDPS.corruptingBloodDPS, count = 1, source = sources.corruptingBloodDPS or "" }) + fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.corruptingBloodDPS + end + if fullDPS.igniteDPS > 0 then +- t_insert(fullDPS.skills, { name = "Best Ignite DPS", dps = fullDPS.igniteDPS, count = 1, source = igniteSource }) ++ t_insert(fullDPS.skills, { name = "Best Ignite DPS", dps = fullDPS.igniteDPS, count = 1, source = sources.igniteDPS or "" }) + fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.igniteDPS + end + if fullDPS.burningGroundDPS > 0 then +- t_insert(fullDPS.skills, { name = "Best Burning Ground DPS", dps = fullDPS.burningGroundDPS, count = 1, source = burningGroundSource }) ++ t_insert(fullDPS.skills, { name = "Best Burning Ground DPS", dps = fullDPS.burningGroundDPS, count = 1, source = sources.burningGroundDPS or "" }) + fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.burningGroundDPS + end + if fullDPS.poisonDPS > 0 then +- t_insert(fullDPS.skills, { name = "Best Poison DPS", dps = fullDPS.poisonDPS, count = 1, source = poisonSource }) ++ t_insert(fullDPS.skills, { name = "Best Poison DPS", dps = fullDPS.poisonDPS, count = 1, source = sources.poisonDPS or "" }) + fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.poisonDPS + end + if fullDPS.causticGroundDPS > 0 then +- t_insert(fullDPS.skills, { name = "Best Caustic Ground DPS", dps = fullDPS.causticGroundDPS, count = 1, source = causticGroundSource }) ++ t_insert(fullDPS.skills, { name = "Best Caustic Ground DPS", dps = fullDPS.causticGroundDPS, count = 1, source = sources.causticGroundDPS or "" }) + fullDPS.TotalDotDPS = fullDPS.TotalDotDPS + fullDPS.causticGroundDPS + end + if fullDPS.impaleDPS > 0 then +@@ -466,7 +577,7 @@ function calcs.buildOutput(build, mode) + for _, skillEffect in ipairs(activeSkill.effectList) do + env.skillsUsed[skillEffect.grantedEffect.name] = true + end +- if activeSkill.minion then ++ if activeSkill.minion and activeSkill.minion.activeSkillList then + for _, activeSkill in ipairs(activeSkill.minion.activeSkillList) do + env.skillsUsed[activeSkill.activeEffect.grantedEffect.id] = true + end +@@ -575,7 +686,7 @@ function calcs.buildOutput(build, mode) + addTo(env.tagTypesUsed, tag.type, mod) + end + end +- if activeSkill.minion then ++ if activeSkill.minion and activeSkill.minion.activeSkillList then + for _, activeSkill in pairs(activeSkill.minion.activeSkillList) do + for _, mod in ipairs(activeSkill.baseSkillModList) do + addModTags(env.minion, mod) +``` + +
+ +
Modules/CalcSections.lua (33 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcSections.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcSections.lua +index 4872f63..d885ad0 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcSections.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcSections.lua +@@ -2355,19 +2355,25 @@ return { + { label = "Spectre Ally", haveOutput = "TotalSpectreLife", + { format = "{0:output:TotalSpectreLife}", + { breakdown = "TotalSpectreLife" }, +- { modName = { "TotalSpectreLife", "takenFromSpectresBeforeYou" } }, ++ { modName = { "TotalSpectreLife", "TakenFromSpectresBeforeYou" } }, + }, + }, + { label = "Totem Ally", haveOutput = "TotalTotemLife", + { format = "{0:output:TotalTotemLife}", + { breakdown = "TotalTotemLife" }, +- { modName = { "TotalTotemLife", "takenFromTotemsBeforeYou" } }, ++ { modName = { "TotalTotemLife", "TakenFromTotemsBeforeYou" } }, + }, + }, + { label = "Vaal Rejuv. Totem", haveOutput = "TotalVaalRejuvenationTotemLife", + { format = "{0:output:TotalVaalRejuvenationTotemLife}", + { breakdown = "TotalVaalRejuvenationTotemLife" }, +- { modName = { "TotalVaalRejuvenationTotemLife", "takenFromVaalRejuvenationTotemsBeforeYou", "takenFromTotemsBeforeYou" } }, ++ { modName = { "TotalVaalRejuvenationTotemLife", "takenFromVaalRejuvenationTotemsBeforeYou", "TakenFromTotemsBeforeYou" } }, ++ }, ++ }, ++ { label = "Companion Ally", haveOutput = "TotalCompanionLife", ++ { format = "{0:output:TotalCompanionLife}", ++ { breakdown = "TotalCompanionLife" }, ++ { modName = { "TotalCompanionLife", "TakenFromCompanionBeforeYou", "TakenFromCompanionBeforeYouFromDeflected" } }, + }, + }, + { label = "Soul Link", haveOutput = "AlliedEnergyShield", +``` + +
+ +
Modules/CalcSetup.lua (336 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcSetup.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcSetup.lua +index 62d1f81..5ba7277 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcSetup.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcSetup.lua +@@ -15,6 +15,12 @@ local band = AND64 + + local tempTable1 = { } + ++local function addGrantedPassiveNode(env, node) ++ env.allocNodes[node.id] = env.spec.nodes[node.id] or node -- use the conquered node data, if available ++ env.grantedPassives[node.id] = true ++ env.extraRadiusNodeList[node.id] = nil ++end ++ + -- Initialise modifier database with stats and conditions common to all actors + function calcs.initModDB(env, modDB) + modDB:NewMod("FireResistMax", "BASE", data.characterConstants["base_maximum_all_resistances_%"], "Base") +@@ -92,6 +98,7 @@ function calcs.initModDB(env, modDB) + modDB:NewMod("MassiveShrine", "FLAG", true, "Base", { type = "Condition", var = "MassiveShrine" }) + modDB:NewMod("AlchemistsGenius", "FLAG", true, "Base", { type = "Condition", var = "AlchemistsGenius" }) + modDB:NewMod("LuckyHits", "FLAG", true, "Base", { type = "Condition", var = "LuckyHits" }) ++ modDB:NewMod("HeavyStunBuildup", "MORE", 50, "Base", { type = "Condition", var = "Dazed"}) + modDB:NewMod("ColdCannotHeavyStun", "FLAG", true) + modDB:NewMod("Convergence", "FLAG", true, "Base", { type = "Condition", var = "Convergence" }) + modDB:NewMod("PhysicalDamageReduction", "BASE", -15, "Base", { type = "Condition", var = "Crushed" }) +@@ -104,6 +111,53 @@ function calcs.initModDB(env, modDB) + modDB.conditions["Effective"] = env.mode_effective + end + ++local function getCorruptedJewelEffect(env, item, node) ++ if not item or item.type ~= "Jewel" or not item.corrupted or not node or node.containJewelSocket or node.sinister or item.base.subType == "Charm" then ++ return 0 ++ end ++ local rarity = item.rarity:gsub("(%a)(%u*)", function(a, b) return a..string.lower(b) end) ++ return env.modDB.multipliers["Corrupted" .. rarity .. "JewelEffect"] or 0 ++end ++ ++local function runRadiusJewelFunc(rad, node, out, data) ++ local scale = rad.effectScale ++ if not scale or scale == 1 then ++ rad.func(node, out, data) ++ return ++ end ++ ++ local start = #out ++ rad.func(node, out, data) ++ if #out == start then ++ return ++ end ++ ++ local scaledList = new("ModList") ++ for i = start + 1, #out do ++ scaledList:AddMod(out[i]) ++ end ++ for i = #out, start + 1, -1 do ++ t_remove(out, i) ++ end ++ out:ScaleAddList(scaledList, scale) ++ ++ for i = start + 1, #out do ++ local mod = out[i] ++ if mod.parsedLine then ++ local value = mod.value ++ while type(value) == "table" and value.mod do ++ value = value.mod.value ++ end ++ if type(value) == "table" then ++ value = value.value ++ end ++ if type(value) == "number" then ++ mod.parsedLine = mod.parsedLine:gsub("%d*%.?%d+", math.abs(value), 1) ++ end ++ end ++ end ++end ++ + local function refreshJewelStatCache(env) + local normalNode = { type = "Normal" } + local attributeNode = { type = "Normal", isAttribute = true } +@@ -118,9 +172,9 @@ local function refreshJewelStatCache(env) + GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId].attributeModList = new("ModList") + GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId].notableModList = new("ModList") + end +- rad.func(normalNode, GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId].smallModList, rad.data) +- rad.func(attributeNode, GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId].attributeModList, rad.data) +- rad.func(notableNode, GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId].notableModList, rad.data) ++ runRadiusJewelFunc(rad, normalNode, GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId].smallModList, rad.data) ++ runRadiusJewelFunc(rad, attributeNode, GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId].attributeModList, rad.data) ++ runRadiusJewelFunc(rad, notableNode, GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId].notableModList, rad.data) + end + end + +@@ -146,18 +200,18 @@ function calcs.buildModListForNode(env, node, incSmallPassiveSkill, includeKeyst + for _, rad in pairs(env.radiusJewelList) do + if rad.type == "Other" and rad.nodes[node.id] and rad.nodes[node.id].type ~= "Mastery" then + if rad.item.baseName:find("Time%-Lost") == nil and rad.item.baseName:find("Timeless Jewel") == nil then +- rad.func(node, modList, rad.data) ++ runRadiusJewelFunc(rad, node, modList, rad.data) + elseif node.type == "Normal" or node.type == "Notable" then + local cache = GlobalCache.cachedData[env.mode].radiusJewelData[rad.nodeId] + if not cache or (cache.hash ~= rad.jewelHash) then + refreshJewelStatCache(env) + end + if node.type == "Normal" and node.isAttribute and cache and #cache.attributeModList > 0 then +- modList:AddList(cache.attributeModList) ++ modList:CopyList(cache.attributeModList) + elseif node.type == "Normal" and not node.isAttribute and cache and #cache.smallModList > 0 then +- modList:AddList(cache.smallModList) ++ modList:CopyList(cache.smallModList) + elseif node.type == "Notable" and cache and #cache.notableModList > 0 then +- modList:AddList(cache.notableModList) ++ modList:CopyList(cache.notableModList) + end + break + end +@@ -179,7 +233,7 @@ function calcs.buildModListForNode(env, node, incSmallPassiveSkill, includeKeyst + -- Run second pass radius jewels + for _, rad in pairs(env.radiusJewelList) do + if rad.nodes[node.id] and rad.nodes[node.id].type ~= "Mastery" and (rad.type == "Threshold" or (rad.type == "Self" and env.allocNodes[node.id]) or (rad.type == "SelfUnalloc" and not env.allocNodes[node.id])) then +- rad.func(node, modList, rad.data) ++ runRadiusJewelFunc(rad, node, modList, rad.data) + end + end + +@@ -312,7 +366,7 @@ function calcs.buildModListForNodeList(env, nodeList, finishJewels, includeKeyst + + -- Finalise radius jewels + for _, rad in pairs(env.radiusJewelList) do +- rad.func(nil, modList, rad.data) ++ runRadiusJewelFunc(rad, nil, modList, rad.data) + if env.mode == "MAIN" then + if not rad.item.jewelRadiusData then + rad.item.jewelRadiusData = { } +@@ -394,6 +448,7 @@ function wipeEnv(env, accelerate) + if not accelerate.skills then + -- Player Active Skills generation + wipeTable(env.player.activeSkillList) ++ env.sourceGemPropertyInfo = { } + + -- Enhances Active Skills with skill ModFlags, KeywordFlags + -- and modifiers that affect skill scaling (e.g., global buffs/effects) +@@ -769,9 +824,15 @@ function calcs.initEnv(build, mode, override, specEnv) + nodes = copyTable(env.spec.allocNodes, true) + end + env.allocNodes = nodes ++ for nodeId, node in pairs(env.allocNodes) do ++ if node.isGrantedPassive and node.isFreeAllocate then ++ env.allocNodes[nodeId] = nil ++ end ++ end + end + + local nodesModsList = calcs.buildModListForNodeList(env, env.allocNodes, true, true) ++ env.useAltGemQualityStats = nodesModsList:Flag(nil, "GemlingQuality") + + if allocatedNotableCount and allocatedNotableCount > 0 then + modDB:NewMod("Multiplier:AllocatedNotable", "BASE", allocatedNotableCount) +@@ -811,6 +872,16 @@ function calcs.initEnv(build, mode, override, specEnv) + + -- Build and merge item modifiers, and create list of radius jewels + if not accelerate.requirementsItems then ++ local grantedNodes = env.spec:CollectGrantedPassiveNodesFromItems(build.itemsTab, env.allocNodes, env.configInput.ignoreJewelLimits, override, nodesModsList) ++ if mode == "MAIN" then ++ if build.spec:SetGrantedPassiveNodes(grantedNodes) then ++ build.itemsTab:UpdateSockets() ++ end ++ end ++ for _, node in pairs(grantedNodes) do ++ addGrantedPassiveNode(env, node) ++ end ++ + local items = {} + local jewelLimits = {} + local giantsBlood = weaponFlagState.giantsBlood +@@ -859,10 +930,13 @@ function calcs.initEnv(build, mode, override, specEnv) + if slot.weaponSet == 2 and build.itemsTab.activeItemSet.useSecondWeaponSet then + slotName = slotName:gsub(" Swap","") + end ++ local node = slot.nodeId and env.spec.nodes[slot.nodeId] + if slot.nodeId then + -- Slot is a jewel socket, check if socket is allocated + if not env.allocNodes[slot.nodeId] then + goto continue ++ elseif item and not build.itemsTab:IsItemValidForSlot(item, slot.slotName) then ++ goto continue + elseif item then + if item.jewelData then + item.jewelData.limitDisabled = nil +@@ -888,7 +962,7 @@ function calcs.initEnv(build, mode, override, specEnv) + jewelLimits[limitKey] = (jewelLimits[limitKey] or 0) + 1 + end + end +- if item and ( item.jewelRadiusIndex or (override and override.extraJewelFuncs and #override.extraJewelFuncs > 0) ) then ++ if item and not (node and node.sinister) and ( item.jewelRadiusIndex or (override and override.extraJewelFuncs and #override.extraJewelFuncs > 0) ) then + -- Jewel has a radius, add it to the list + local funcList = (item.jewelData and item.jewelData.funcList) or { { type = "Self", func = function(node, out, data) + -- Default function just tallies all stats in radius +@@ -899,7 +973,6 @@ function calcs.initEnv(build, mode, override, specEnv) + end + end } } + for _, func in ipairs(funcList) do +- local node = env.spec.nodes[slot.nodeId] + t_insert(env.radiusJewelList, { + nodes = node.nodesInRadius and node.nodesInRadius[item.jewelRadiusIndex] or { }, + func = func.func, +@@ -921,7 +994,6 @@ function calcs.initEnv(build, mode, override, specEnv) + end + end + for _, funcData in ipairs(override and override.extraJewelFuncs and override.extraJewelFuncs:List({item = item}, "ExtraJewelFunc") or {}) do +- local node = env.spec.nodes[slot.nodeId] + local radius + for index, data in pairs(data.jewelRadius) do + if funcData.radius == data.label then +@@ -954,6 +1026,14 @@ function calcs.initEnv(build, mode, override, specEnv) + ::continue:: + end + ++ for _, rad in ipairs(env.radiusJewelList) do ++ local effect = getCorruptedJewelEffect(env, rad.item, env.spec.nodes[rad.nodeId]) ++ if effect ~= 0 then ++ rad.effectScale = 1 + effect ++ rad.jewelHash = tostring(rad.jewelHash or getHashFromString(rad.item.modSource..rad.item.raw)) .. ":" .. rad.effectScale ++ end ++ end ++ + if not env.configInput.ignoreItemDisablers then + local itemDisabled = {} + local itemDisablers = {} +@@ -963,7 +1043,7 @@ function calcs.initEnv(build, mode, override, specEnv) + for _, slot in pairs(build.itemsTab.orderedSlots) do + local slotName = slot.slotName + if items[slotName] then +- local srcList = items[slotName].modList or items[slotName].slotModList[slot.slotNum] ++ local srcList = items[slotName].modList or items[slotName].slotModList[slot.slotNum] or {} + for _, mod in ipairs(srcList) do + -- checks if it disables another slot + for _, tag in ipairs(mod) do +@@ -1011,6 +1091,7 @@ function calcs.initEnv(build, mode, override, specEnv) + for _, slot in pairs(build.itemsTab.orderedSlots) do + local slotName = slot.slotName + local item = items[slotName] ++ local node = slot.nodeId and env.spec.nodes[slot.nodeId] + if item and item.type == "Flask" then + if slot.active then + env.flasks[item] = true +@@ -1041,8 +1122,7 @@ function calcs.initEnv(build, mode, override, specEnv) + scale = parentItem.socketedJewelEffectModifier + end + end +- if slot.nodeId and item and item.type == "Jewel" and item.jewelData and item.jewelData.jewelIncEffectFromClassStart then +- local node = env.spec.nodes[slot.nodeId] ++ if slot.nodeId and item and item.type == "Jewel" and item.jewelData and item.jewelData.jewelIncEffectFromClassStart and not (node and node.sinister) then + if node and node.distanceToClassStart then + scale = scale + node.distanceToClassStart * (item.jewelData.jewelIncEffectFromClassStart / 100) + end +@@ -1050,7 +1130,6 @@ function calcs.initEnv(build, mode, override, specEnv) + + local addSourceSlotNum = false + if slot.nodeId and item and item.type == "Jewel" then +- local node = env.spec.nodes[slot.nodeId] + if node and node.containJewelSocket then + addSourceSlotNum = true + local inc = node.modList:Sum("INC", nil, "SocketedJewelEffect") +@@ -1062,6 +1141,7 @@ function calcs.initEnv(build, mode, override, specEnv) + env.player.itemList[slotName] = item + -- Merge mods for this item + local srcList = item.modList or (item.slotModList and item.slotModList[slot.slotNum]) or {} ++ local corruptedJewelEffect = slot.nodeId and getCorruptedJewelEffect(env, item, node) or 0 + + -- Remove Spirit Base if CannotGainSpiritFromEquipment flag is true + if nodesModsList:Flag(nil, "CannotGainSpiritFromEquipment") then +@@ -1259,8 +1339,8 @@ function calcs.initEnv(build, mode, override, specEnv) + env.itemModDB:ScaleAddMod(mod, scale) + end + end +- elseif env.modDB.multipliers["Corrupted" .. item.rarity:gsub("(%a)(%u*)", function(a, b) return a..string.lower(b) end) .. "JewelEffect"] and item.type == "Jewel" and item.corrupted and slot.nodeId and item.base.subType ~= "Charm" and not env.spec.nodes[slot.nodeId].containJewelSocket then +- scale = scale + env.modDB.multipliers["Corrupted" .. item.rarity:gsub("(%a)(%u*)", function(a, b) return a..string.lower(b) end) .. "JewelEffect"] ++ elseif corruptedJewelEffect ~= 0 then ++ scale = scale + corruptedJewelEffect + local combinedList = new("ModList") + for _, mod in ipairs(srcList) do + combinedList:MergeMod(mod) +@@ -1325,11 +1405,10 @@ function calcs.initEnv(build, mode, override, specEnv) + -- Add granted passives (e.g., amulet anoints) + if not accelerate.nodeAlloc then + for _, passive in pairs(env.modDB:List(nil, "GrantedPassive")) do +- local node = env.spec.tree.notableMap[passive] +- if node and (not override.removeNodes or not override.removeNodes[node.id]) then +- env.allocNodes[node.id] = env.spec.nodes[node.id] or node -- use the conquered node data, if available +- env.grantedPassives[node.id] = true +- env.extraRadiusNodeList[node.id] = nil ++ for _, node in ipairs(env.spec:ResolveGrantedPassiveNodes(passive)) do ++ if node and (not override.removeNodes or not override.removeNodes[node.id]) then ++ addGrantedPassiveNode(env, node) ++ end + end + end + end +@@ -1372,10 +1451,20 @@ function calcs.initEnv(build, mode, override, specEnv) + local modList = env.player.itemList["Weapon 2"].modList + for _, mod in ipairs(modList) do + local modCopy = copyTable(mod) +- modCopy.source = "Many Sources:" .. tostring(quiverEffectMod * 100) .. "% Quiver Bonus Effect" ++ modCopy.source = "Many Sources:".. colorCodes.SOURCE .. tostring(quiverEffectMod * 100) .. "% Quiver Bonus Effect" + modDB:ScaleAddMod(modCopy, quiverEffectMod) + end + end ++ ++ if env.player.itemList["Amulet"] and env.player.itemList["Amulet"].type == "Amulet" then ++ local amuletEffectMod = env.modDB:Sum("INC", nil, "EffectOfBonusesFromAmulet") / 100 ++ local modList = env.player.itemList["Amulet"].modList ++ for _, mod in ipairs(modList) do ++ local modCopy = copyTable(mod) ++ modCopy.source = "Many Sources:".. colorCodes.SOURCE .. tostring(amuletEffectMod * 100) .. "% Amulet Bonus Effect" ++ modDB:ScaleAddMod(modCopy, amuletEffectMod) ++ end ++ end + + -- Find skills granted by tree nodes + if not accelerate.nodeAlloc then +@@ -1445,6 +1534,7 @@ function calcs.initEnv(build, mode, override, specEnv) + activeGemInstance.enableGlobal1 = true + activeGemInstance.noSupports = grantedSkill.noSupports + group.noSupports = grantedSkill.noSupports ++ activeGemInstance.noReservation = grantedSkill.noReservation + activeGemInstance.triggered = grantedSkill.triggered + activeGemInstance.triggerChance = grantedSkill.triggerChance + wipeTable(group.gemList) +@@ -1677,6 +1767,7 @@ function calcs.initEnv(build, mode, override, specEnv) + level = value.level, + quality = 0, + enabled = true, ++ isSupporting = { }, + }) + end + end +``` + +
+ +
Modules/CalcTools.lua (29 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcTools.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcTools.lua +index cda906b..a44b7b6 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcTools.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcTools.lua +@@ -135,12 +135,20 @@ function calcLib.getGemStatRequirement(level, multi, isSupport) + end + + -- Build table of stats for the given skill instance statset +-function calcLib.buildSkillInstanceStats(skillInstance, grantedEffect, statSet) ++function calcLib.buildSkillInstanceStats(skillInstance, grantedEffect, statSet, includeAltQualityStats) + local stats = { } +- if skillInstance.quality > 0 and grantedEffect.qualityStats then ++ if skillInstance.quality > 0 then + local qualityStats = grantedEffect.qualityStats +- for _, stat in ipairs(qualityStats) do +- stats[stat[1]] = (stats[stat[1]] or 0) + math.modf(stat[2] * skillInstance.quality) ++ if qualityStats then ++ for _, stat in ipairs(qualityStats) do ++ stats[stat[1]] = (stats[stat[1]] or 0) + math.modf(stat[2] * skillInstance.quality) ++ end ++ end ++ qualityStats = grantedEffect.altQualityStats ++ if includeAltQualityStats and qualityStats then ++ for _, stat in ipairs(qualityStats) do ++ stats[stat[1]] = (stats[stat[1]] or 0) + math.modf(stat[2] * skillInstance.quality) ++ end + end + end + local grantedEffectLevel = grantedEffect.levels[skillInstance.level] or { } +``` + +
+ +
Modules/CalcTriggers.lua (31 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcTriggers.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcTriggers.lua +index 975ad5d..5dafee8 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/CalcTriggers.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/CalcTriggers.lua +@@ -429,7 +429,7 @@ local function defaultTriggerHandler(env, config) + end + + -- Dual wield triggers +- if trigRate and source and env.player.weaponData1.type and env.player.weaponData2.type and not source.skillData.doubleHitsWhenDualWielding and (source.skillTypes[SkillType.Melee] or source.skillTypes[SkillType.Attack]) and actor.mainSkill.triggeredBy and actor.mainSkill.triggeredBy.grantedEffect.support and actor.mainSkill.triggeredBy.grantedEffect.fromItem then ++ if trigRate and source and env.player.weaponData1.type and env.player.weaponData2.type and not source.skillData.combinesHitsWhenDualWielding and (source.skillTypes[SkillType.Melee] or source.skillTypes[SkillType.Attack]) and actor.mainSkill.triggeredBy and actor.mainSkill.triggeredBy.grantedEffect.support and actor.mainSkill.triggeredBy.grantedEffect.fromItem then + trigRate = trigRate / 2 + if breakdown then + t_insert(breakdown.EffectiveSourceRate, 2, s_format("/ 2 ^8(due to dual wielding)")) +@@ -722,7 +722,7 @@ local function defaultTriggerHandler(env, config) + local sourceHitChance = GlobalCache.cachedData[env.mode][uuid].HitChance or 0 + if sourceHitChance ~= 100 then + -- Some skills hit with both weapons at the same time. Each weapon rolls accuracy and crit independently +- if source and env.player.weaponData1.type and env.player.weaponData2.type and source.skillData.doubleHitsWhenDualWielding then ++ if source and env.player.weaponData1.type and env.player.weaponData2.type and source.skillData.combinesHitsWhenDualWielding then + local mainHandHit = GlobalCache.cachedData[env.mode][uuid].Env.player.output.MainHand.HitChance + local offHandHit = GlobalCache.cachedData[env.mode][uuid].Env.player.output.OffHand.HitChance + local bothHit = mainHandHit * offHandHit / 100 +@@ -747,7 +747,7 @@ local function defaultTriggerHandler(env, config) + local sourceCritChance = GlobalCache.cachedData[env.mode][uuid].CritChance or 0 + if sourceCritChance ~= 100 then + -- Some skills hit with both weapons at the same time. Each weapon rolls accuracy and crit independently +- if source and env.player.weaponData1.type and env.player.weaponData2.type and source.skillData.doubleHitsWhenDualWielding then ++ if source and env.player.weaponData1.type and env.player.weaponData2.type and source.skillData.combinesHitsWhenDualWielding then + local mainHandCrit = GlobalCache.cachedData[env.mode][uuid].Env.player.output.MainHand.CritChance + local offHandCrit = GlobalCache.cachedData[env.mode][uuid].Env.player.output.OffHand.CritChance + local bothHit = mainHandCrit * offHandCrit / 100 +``` + +
+ +
Modules/ModParser.lua (292 diff lines) + +```diff +diff --git a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/ModParser.lua b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/ModParser.lua +index 3dd2c16..52fa3b4 100644 +--- a/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/a82a33b4fbdb7306ed93159664f7abe2c6819413/src/Modules/ModParser.lua ++++ b/Users/wuyong/codes/game/pobr/.claude/worktrees/agent-af7756e8e082bac60/.cache/vendor-delta/ce8bffaba31f8e68cfce70579e1c96465e7c133c/src/Modules/ModParser.lua +@@ -897,6 +897,7 @@ local modNameList = { + ["effect of socketed abyss jewels"] = "SocketedJewelEffect", + ["effect of socketed soul cores"] = "SocketedSoulCoreEffect", + ["effect of socketed runes"] = "SocketedRuneEffect", ++ ["effect of socketed augment items"] = "SocketedAugmentItemEffect", + ["to inflict fire exposure on hit"] = "FireExposureChance", + ["to apply fire exposure on hit"] = "FireExposureChance", + ["to inflict cold exposure on hit"] = "ColdExposureChance", +@@ -1037,6 +1038,10 @@ local modFlagList = { + ["with ranged weapons"] = { flags = bor(ModFlag.WeaponRanged, ModFlag.Hit) }, + -- Skill types + ["spell"] = { flags = ModFlag.Spell }, ++ ["fire spell"] = { flags = ModFlag.Spell, keywordFlags = KeywordFlag.Fire }, ++ ["cold spell"] = { flags = ModFlag.Spell, keywordFlags = KeywordFlag.Cold }, ++ ["lightning spell"] = { flags = ModFlag.Spell, keywordFlags = KeywordFlag.Lightning }, ++ ["chaos spell"] = { flags = ModFlag.Spell, keywordFlags = KeywordFlag.Chaos }, + ["for spells"] = { flags = ModFlag.Spell }, + ["for spell skills"] = { flags = ModFlag.Spell }, + ["for spell damage"] = { flags = ModFlag.Spell }, +@@ -1285,7 +1290,7 @@ local preFlagList = { + ["^attacks used by ballistas [hd][ae][va][el] "] = { flags = ModFlag.Attack, keywordFlags = KeywordFlag.Totem, tag = { type = "Condition", var = "BallistaSkill" } }, + ["^attack skills [hd][ae][va][el] "] = { keywordFlags = KeywordFlag.Attack }, + ["^spells [hgdf][aei][ivar][nel] a? ?"] = { flags = ModFlag.Spell }, +- ["^spells which cost life gain "] = { keywordFlags = KeywordFlag.Spell, tag = { type = "StatThreshold", stat = "LifeCost", threshold = 1 } }, ++ ["^spells which cost life gain "] = { keywordFlags = KeywordFlag.Spell, tag = { type = "StatThreshold", statList = { "LifeCost", "LifePerSecondCost" }, threshold = 1 } }, + ["^spell skills [hd][ae][va][el] "] = { keywordFlags = KeywordFlag.Spell }, + ["^spell hits [ghd][ae][iva][eln] "] = { flags = ModFlag.Hit, keywordFlags = KeywordFlag.Spell }, + ["^offering skills [hd][ae][va][el] "] = { tag = { type = "SkillType", skillType = SkillType.Offering } }, +@@ -1472,6 +1477,7 @@ local modTagList = { + ["per level"] = { tag = { type = "Multiplier", var = "Level" } }, + ["per player level"] = { tag = { type = "Multiplier", var = "Level" } }, + ["per (%d+) player levels"] = function(num) return { tag = { type = "Multiplier", var = "Level", div = num } } end, ++ ["per (%d+) levels"] = function(num) return { tag = { type = "Multiplier", var = "Level", div = num } } end, + ["per defiance"] = { tag = { type = "Multiplier", var = "Defiance" } }, + ["per (%d+)%% (%a+) effect on enemy"] = function(num, _, effectName) return { tag = { type = "Multiplier", var = firstToUpper(effectName) .. "Effect", div = num, actor = "enemy" } } end, + ["per socketed rune or soul core"] = { tag = { type = "Multiplier", var = "RunesSocketedIn{SlotName}" } }, +@@ -1562,8 +1568,6 @@ local modTagList = { + ["per animated weapon"] = { tag = { type = "Multiplier", var = "AnimatedWeapon", actor = "parent" } }, + ["per grasping vine"] = { tag = { type = "Multiplier", var = "GraspingVinesCount" } }, + ["per fragile regrowth"] = { tag = { type = "Multiplier", var = "FragileRegrowthCount" } }, +- ["per bark"] = { tag = { type = "Multiplier", var = "BarkskinStacks" } }, +- ["per bark below maximum"] = { tag = { type = "Multiplier", var = "MissingBarkskinStacks" } }, + ["per allocated mastery passive skill"] = { tag = { type = "Multiplier", var = "AllocatedMastery" } }, + ["per allocated notable passive skill"] = { tag = { type = "Multiplier", var = "AllocatedNotable" } }, + ["for each connected notable passive skill allocated"] = { tag = { type = "Multiplier", var = "AllocatedConnectedNotable" } }, +@@ -1691,8 +1695,8 @@ local modTagList = { + ["while affected by a normal abyss jewel"] = { tag = { type = "MultiplierThreshold", var = "NormalAbyssJewels", threshold = 1 } }, + ["while an enemy with an open weakness is in your presence"] = { tag = { type = "Condition", var = "OpenWeaknessEnemyPresence" } }, -- This one means there's an enemy that has open weakness "nearby" + ["against enemies with an open weakness"] = { tag = { type = "Condition", var = "EnemyHasOpenWeakness" } }, -- This one means the enemy you're targeting has open weakness +- ["with skills that cost life"] = { tag = { type = "StatThreshold", stat = "LifeCost", threshold = 1 } }, +- ["with spells that cost life"] = { keywordFlags = KeywordFlag.Spell, tag = { type = "StatThreshold", stat = "LifeCost", threshold = 1 } }, ++ ["with skills that cost life"] = { tag = { type = "StatThreshold", statList = { "LifeCost", "LifePerSecondCost" }, threshold = 1 } }, ++ ["with spells that cost life"] = { keywordFlags = KeywordFlag.Spell, tag = { type = "StatThreshold", statList = { "LifeCost", "LifePerSecondCost" }, threshold = 1 } }, + -- Gem conditions + ["if you have at least (%d+) (%a+) support gems socketed"] = function(count, _, color) return { tag = { type = "MultiplierThreshold", var = firstToUpper(color) .. "SupportGems", threshold = count } } end, + ["if you have at least (%d+) red, green and blue support gems socketed"] = function(count) +@@ -1866,6 +1870,7 @@ local modTagList = { + ["during any life flask effect"] = { tag = { type = "Condition", var = "UsingLifeFlask" } }, + ["if you've used a life flask in the past 10 seconds"] = { tag = { type = "Condition", var = "UsingLifeFlask" } }, + ["if you've used a mana flask in the past 10 seconds"] = { tag = { type = "Condition", var = "UsingManaFlask" } }, ++ ["if you've used a mana flask recently"] = { tag = { type = "Condition", var = "UsingManaFlask" } }, + ["while you have no life flask uses left"] = { tag = { type = "Condition", var = "NoLifeFlaskUsesLeft" } }, + ["during effect of any life or mana flask"] = { tag = { type = "Condition", varList = { "UsingManaFlask", "UsingLifeFlask" } } }, + ["while on consecrated ground"] = { tag = { type = "Condition", var = "OnConsecratedGround" } }, +@@ -3326,9 +3331,6 @@ local specialModList = { + mod("DamageTakenOverTime", "MORE", -num * tonumber(duration) / 10, { type = "Condition", var = "HeartstopperAVERAGE" }) + } end, + -- Warden +- ["prevent %+(%d+)%% of suppressed spell damage per bark below maximum"] = function(num) return { +- mod("SpellSuppressionEffect", "BASE", num, { type = "Multiplier", var = "MissingBarkskinStacks" }) +- } end, + ["hits that would ignite instead scorch"] = { flag("IgniteCanScorch"), flag("CannotIgnite") }, + ["you can inflict an additional scorch on each enemy"] = { flag("ScorchCanStack"), mod("ScorchStacksMax", "BASE", 1) }, + ["maximum effect of shock is (%d+)%% increased damage taken"] = function (num) return { mod("ShockMax", "OVERRIDE", num) } end, +@@ -3348,6 +3350,7 @@ local specialModList = { + ["gain maximum life instead of maximum energy shield from equipped armour items"] = { flag("ConvertArmourESToLife") }, + -- Mercenary - Gemling + ["attribute requirements of gems can be satisi?fied by your highest attribute"] = { flag("GemAttributeRequirementsSatisfiedByHighestAttribute") }, ++ ["gem quality grants socketed skills an additional effect"] = { flag("GemlingQuality") }, + ["you can use two copies of the same support gem in different skills"] = { mod("MaxSupportGemCopies", "OVERRIDE", 2) }, + ["you can use each type of support gem an additional time in different skills"] = { mod("MaxSupportGemCopies", "OVERRIDE", 2) }, + ["skills have (%d+)%% increased critical hit chance per connected blue support gem"] = function(num) return { +@@ -3366,7 +3369,9 @@ local specialModList = { + ["blue: skills have (%d+)%% less cost"] = function(count) return { + mod("ManaCost", "MORE", -count, { type = "Condition", var = "MostNumerousBlueSocketedSupports" }) + } end, +- ++ ["green: (%d+)%% less movement speed penalty from using skills while moving"] = function(num) return { ++ mod("MovementSpeedPenalty", "MORE", -num, { type = "Condition", var = "MostNumerousGreenSocketedSupports" }) ++ } end, + -- Monk - Stormweaver + ["targets can be affected by two of your shocks at the same time"] = { flag("ShockCanStack"), mod("ShockStacksMax", "OVERRIDE", 2) }, + ["targets can be affected by two of your chills at the same time"] = { flag("ChillCanStack"), mod("ChillStacksMax", "OVERRIDE", 2) }, +@@ -3440,6 +3445,8 @@ local specialModList = { + } end, + ["only soul cores can be socketed in this item"] = { flag("SocketedSoulCoresOnly") }, + ["only runes can be socketed in this item"] = { flag("SocketedRunesOnly") }, ++ ["this item gains bonuses from socketed items as though it was a? ?(.+)"] = { }, -- Handled in Item.lua ++ ["this item gains bonuses from socketed soul cores as though it was also a? ?(.+)"] = { }, -- Handled in Item.lua + ["has (%d+) sockets?"] = function(num) return { mod("SocketCount", "BASE", num) } end, + ["no physical damage"] = { mod("WeaponData", "LIST", { key = "PhysicalMin" }), mod("WeaponData", "LIST", { key = "PhysicalMax" }), mod("WeaponData", "LIST", { key = "PhysicalDPS" }) }, + ["cannot load or fire ammunition"] = { mod("WeaponData", "LIST", { key = "cannotUseGemTag", value = "ammunition" }) }, +@@ -3814,6 +3821,8 @@ local specialModList = { + mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Poisoned" }), + mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Electrocuted" }), + } end, ++ ["non%-channelling spells have (%d+)%% increased magnitude of ailments per (%d+) maximum life"] = function(num, _, div) return { mod("AilmentMagnitude", "INC", num, nil, 0, KeywordFlag.Spell, { type = "SkillType", skillType = SkillType.Channel, neg = true }, { type = "PerStat", stat = "Life", div = tonumber(div) }) } end, ++ ["non%-channelling spells have (%d+)%% reduced magnitude of ailments per (%d+) maximum life"] = function(num, _, div) return { mod("AilmentMagnitude", "INC", -num, nil, 0, KeywordFlag.Spell, { type = "SkillType", skillType = SkillType.Channel, neg = true }, { type = "PerStat", stat = "Life", div = tonumber(div) }) } end, + -- Elemental Ailments + ["enemies take (%d+)%% increased damage for each elemental ailment type among your ailments on them"] = function(num) return { + mod("EnemyModifier", "LIST", { mod = mod("DamageTaken", "INC", num) }, { type = "ActorCondition", actor = "enemy", var = "Frozen" }), +@@ -3896,6 +3905,7 @@ local specialModList = { + ["your chaos damage can ignite"] = { flag("ChaosCanIgnite") }, + ["chaos damage can ignite, chill and shock"] = { flag("ChaosCanIgnite"), flag("ChaosCanChill"), flag("ChaosCanShock") }, + ["your physical damage can chill"] = { flag("PhysicalCanChill") }, ++ ["physical damage from hits contributes to chill magnitude and freeze buildup"] = { flag("PhysicalCanChill"), flag("PhysicalCanFreeze") }, + ["your physical damage can shock"] = { flag("PhysicalCanShock") }, + ["your physical damage can freeze"] = { flag("PhysicalCanFreeze") }, + ["your lightning damage can freeze"] = { flag("LightningCanFreeze") }, +@@ -5335,8 +5345,10 @@ local specialModList = { + ["(%d+)%% increased armour per second you've been stationary, up to a maximum of (%d+)%%"] = function(num, _, limit) return { + mod("Armour", "INC", num, { type = "Multiplier", var = "StationarySeconds", limit = tonumber(limit / num) }, { type = "Condition", var = "Stationary" }), + } end, +- ["(%d+)%% of damage from hits is taken from your spectres' life before you"] = function(num) return { mod("takenFromSpectresBeforeYou", "BASE", num) } end, +- ["(%d+)%% of damage from hits is taken from your nearest totem's life before you"] = function(num) return { mod("takenFromTotemsBeforeYou", "BASE", num, { type = "Condition", var = "HaveTotem" }) } end, ++ ["(%d+)%% of damage from hits is taken from your spectres' life before you"] = function(num) return { mod("TakenFromSpectresBeforeYou", "BASE", num) } end, ++ ["(%d+)%% of damage from hits is taken from your nearest totem's life before you"] = function(num) return { mod("TakenFromTotemsBeforeYou", "BASE", num, { type = "Condition", var = "HaveTotem" }) } end, ++ ["(%d+)%% of damage from hits is taken from your damageable companion's life before you"] = function(num) return { mod("TakenFromCompanionBeforeYou", "BASE", num) } end, ++ ["(%d+)%% of damage from deflected hits is taken from damageable companion's life before you"] = function(num) return { mod("TakenFromCompanionBeforeYouFromDeflected", "BASE", num) } end, + ["(%a+) resistance cannot be penetrated"] = function(_, res) return { flag("EnemyCannotPen"..(res:gsub("^%l", string.upper)).."Resistance") } end, + ["your base energy shield recharge delay is (%d+) seconds"] = function(num) return { mod("EnergyShieldRechargeBase", "OVERRIDE", num), } end, + -- Knockback +@@ -5547,6 +5559,10 @@ local specialModList = { + -- Misc + ["fully broken armour effects also apply to fire damage taken from hits"] = { flag("ArmourBreakFireDamageTaken"), }, + ["fully broken armour you inflict also increases fire damage taken from hits"] = { flag("ArmourBreakFireDamageTaken"), }, ++ ["fully broken armour you inflict also increases cold and lightning damage taken from hits"] = { ++ flag("ArmourBreakColdDamageTaken"), ++ flag("ArmourBreakLightningDamageTaken"), ++ }, + ["can't use c?h?e?s?t? ?b?o?d?y? ?armour"] = { mod("CanNotUseBody", "Flag", 1, { type = "DisablesItem", slotName = "Body Armour" }) }, + --["can't use helmets"] = { mod("CanNotUseHelmet", "Flag", 1, { type = "DisablesItem", slotName = "Helmet" }) }, -- this one does not work due to being on a passive? + ["can't use helmet"] = { mod("CanNotUseHelmet", "Flag", 1, { type = "DisablesItem", slotName = "Helmet" }) }, -- this is to allow for custom mod without saying the other is parsed +@@ -5579,7 +5595,7 @@ local specialModList = { + ["(%d+)%% increased accuracy rating against enemies you mark"] = function(num) return { mod("AccuracyVsEnemy", "INC", num, { type = "ActorCondition", actor = "enemy", var = "Marked" } ) } end, + ["(%d+)%% more accuracy rating against enemies you mark"] = function(num) return { mod("AccuracyVsEnemy", "MORE", num, { type = "ActorCondition", actor = "enemy", var = "Marked" } ) } end, + ["%+(%d+) to accuracy against bleeding enemies"] = function(num) return { mod("AccuracyVsEnemy", "BASE", num, { type = "ActorCondition", actor = "enemy", var = "Bleeding" } ) } end, +- ["cannot recover energy shield to above armour"] = { flag("ArmourESRecoveryCap") }, ++ ["y?o?u? ?cannot recover energy shield to above armour"] = { flag("ArmourESRecoveryCap") }, + ["cannot recover energy shield to above evasion rating"] = { flag("EvasionESRecoveryCap") }, + ["warcries empower (%d+) additional attacks?"] = function(num) return { mod("ExtraEmpoweredAttacks", "BASE", num) } end, + ["warcries empower an additional attack"] = function(num) return { mod("ExtraEmpoweredAttacks", "BASE", 1) } end, +@@ -5781,8 +5797,8 @@ local specialModList = { + flag("CannotHeavyStun"), + flag("CannotPin"), + }, +- ["immobilise enemies at (%d+)%% buildup instead of (%d+)%%"] = function(num, _, base) return { +- mod("EnemyModifier", "LIST", { mod = mod("PoiseThreshold", "MORE",-num) }), ++ ["immobilise enemies at (%d+)%% buildup instead of (%d+)%%"] = function(num) return { ++ mod("EnemyModifier", "LIST", { mod = mod("PoiseThreshold", "MORE",(num - 100)) }), + } end, + ["the effect of blind on you is reversed"] = { flag("BlindEffectReversed") }, + ["blind does not affect your chance to hit"] = { flag("IgnoreBlindHitChance") }, +@@ -5838,6 +5854,7 @@ local specialModList = { + ["rage grants spell damage instead of attack damage"] = { flag("Condition:RageSpellDamage") }, + ["inherent loss of rage is (%d+)%% slower"] = function(num) return { mod("InherentRageLoss", "INC", -num) } end, + ["inherent loss of rage is (%d+)%% faster"] = function(num) return { mod("InherentRageLoss", "INC", num) } end, ++ ["no inherent loss of rage"] = { flag("InherentRageLossIsPrevented") }, + ["inherent rage loss starts (%d+) seconds? later"] = function(num) return { mod("InherentRageLossDelay", "BASE", num) } end, + ["your critical damage bonus is (%d+)%%"] = function(num) return { mod("CritMultiplier", "OVERRIDE", num) } end, + ["base critical hit chance for attacks with weapons is ([%d%.]+)%%"] = function(num) return { mod("WeaponBaseCritChance", "OVERRIDE", num) } end, +@@ -5850,6 +5867,7 @@ local specialModList = { + mod("CritChanceCap", "OVERRIDE", num), + } end, + ["allocates (.+) if you have the matching modifiers? on forbidden (.+)"] = function(_, ascendancy, side) return { mod("GrantedAscendancyNode", "LIST", { side = side, name = ascendancy }) } end, ++ ["allocates (%d+) sinister jewel sockets?"] = function(num) return { mod("GrantedPassive", "LIST", { type = "SinisterJewelSockets", count = num }) } end, + ["allocates (.+)"] = function(_, passive) return { mod("GrantedPassive", "LIST", passive) } end, + ["battlemage"] = { flag("Battlemage"), mod("MainHandWeaponDamageAppliesToSpells", "MAX", 100) }, + ["transfiguration of body"] = { flag("TransfigurationOfBody") }, +@@ -6008,6 +6026,9 @@ local specialModList = { + ["attack skills cost life instead of (%d+)%% of mana cost"] = function(num) return { + mod("HybridManaAndLifeCost_Life", "BASE", num, nil, ModFlag.Attack) + } end, ++ ["skills from corrupted gems have (%d+)%% of mana costs converted to life costs"] = function(num) return { ++ mod("HybridManaAndLifeCost_Life", "BASE", num, { type = "Condition", var = "GemCorrupted" }), ++ } end, + ["non%-channelling spells cost an additional (%d+)%% of your maximum life"] = function(num) return { + mod("LifeCostBase", "BASE", 1, nil, 0, KeywordFlag.Spell, { type = "PercentStat", percent = num, stat = "Life", floor = true }, { type = "SkillType", skillType = SkillType.Channel, neg = true }) + } end, +@@ -6076,11 +6097,12 @@ local specialModList = { + mod("LightningMax", "BASE", 1, { type = "PercentStat", stat = "Mana" , percent = num }, { type = "SkillType", skillType = SkillType.Attack }), + } end, + ["(%d+)%% reduced movement speed penalty from using skills while moving"] = function(num) return { mod("MovementSpeedPenalty", "INC", -num) } end, ++ ["(%d+)%% reduced movement speed penalty while actively blocking"] = function(num) return { mod("MovementSpeedPenalty", "INC", -num, { type = "SkillType", skillType = SkillType.ActiveBlock }) } end, + ["(%d+)%% less movement speed penalty from using skills while moving"] = function(num) return { mod("MovementSpeedPenalty", "MORE", -num) } end, + ["no movement speed penalty while shield is raised"] = function(num) return { +- mod("MovementSpeedPenalty", "MORE", -100, { type = "SkillName", skillName = "Raise Shield"}) ++ mod("MovementSpeedPenalty", "MORE", -100, { type = "SkillType", skillType = SkillType.ActiveBlock }) + } end, +- -- Conditional Player Quantity / Rarity ++ -- Conditional Player Quantity / Rarity + ["(%d+)%% increased quantity of items dropped by slain normal enemies"] = function(num) return { mod("LootQuantityNormalEnemies", "INC", num) } end, + ["(%d+)%% increased rarity of items dropped by slain magic enemies"] = function(num) return { mod("LootRarityMagicEnemies", "INC", num) } end, + -- Skill-specific enchantment modifiers +@@ -6216,13 +6238,13 @@ end + -- NOTE: conditional mods with "Immune to ..." cannot be handled for PoE2 as they no longer start with "You are..." or similar prefixes that trigger a "FLAG" mod + specialModList["immune to (.-) w?h?i[lf]e? (.*)"] = = function(_, debuff, cond) + -- NOTE: this only handles cases for which unconditional immunity mods exist to avoid false positives that don't actually get calculated +- ++ + -- look for static or dynamically phrased base immunity mod + local searchPrefix1 = "immun[ei]t?y? to " .. ailment and string.lower(debuff) + local searchPrefix2 = "immune to " .. ailment and string.lower(debuff) + local lowerAilment = ailment and string.lower(ailment) or "" + local validDebuff = (specialModList[searchPrefix1 .. lowerAilment] or specialModList[searchPrefix2 .. lowerAilment]) and true or false +- ++ + -- look if condition exists + -- todo make more dynamic + local tagKey = (validDebuff and cond) and "while " .. string.lower(cond) +@@ -6412,7 +6434,7 @@ local deprecatedSkillNames = { ["Flammability"] = true } + for gemId, gemData in pairs(data.gems) do + local grantedEffect = gemData.grantedEffect + local skillName = grantedEffect.baseTypeName or grantedEffect.name +- if not grantedEffect.hidden and not grantedEffect.support and not deprecatedSkillNames[skillName] then ++ if not grantedEffect.hidden and not grantedEffect.support and not grantedEffect.fromItem and not deprecatedSkillNames[skillName] then + skillNameList[" "..skillName:lower().." "] = { tag = { type = "SkillName", skillName = skillName, includeTransfigured = true } } + preSkillNameList["^"..skillName:lower().." "] = { tag = { type = "SkillName", skillName = skillName, includeTransfigured = true } } + preSkillNameList["^"..skillName:lower().." has ?a? "] = { tag = { type = "SkillName", skillName = skillName, includeTransfigured = true } } +@@ -6764,7 +6786,7 @@ local function parseMod(line, order) + effect = getEffectFromStatus(effectLine) + effect = combineToUpper(effect) + end +- ++ + if type(effect) == "table" then + modName = { effect[1] .. "Immune", effect[2] .. "Immune" } + modType = { type(modValue) == "table" and modValue.type or "FLAG", type(modValue) == "table" and modValue.type or "FLAG" } +@@ -7019,14 +7041,17 @@ local jewelOtherFuncs = { + ["^(%w+) Passive Skills in Radius also grant (.*)$"] = function(passiveType, mod) + return function(node, out, data) + if node and (node.type == firstToUpper(passiveType) or (node.type == "Normal" and not node.isAttribute and firstToUpper(passiveType) == "Small")) then +- local modList, line = parseMod(mod) +- if not line and modList[1] then -- something failed to parse, do not add to list +- modList[1].parsedLine = capitalizeWordsInString(mod) +- modList[1].source = data.modSource +- if type(modList[1].value) == "table" and modList[1].value.mod then +- modList[1].value.mod.source = data.modSource ++ local modList, extra = parseMod(mod) ++ -- avoid adding mods if mod line wasn't parsed correctly ++ if not extra and modList[1] then ++ for _, modListMod in ipairs(modList) do ++ modListMod.parsedLine = capitalizeWordsInString(mod) ++ modListMod.source = data.modSource ++ if type(modListMod.value) == "table" and modListMod.value.mod then ++ modListMod.value.mod.source = data.modSource ++ end ++ out:AddMod(modListMod) + end +- out:AddMod(modList[1]) + end + end + end +@@ -7034,14 +7059,17 @@ local jewelOtherFuncs = { + ["conquered (%w+) Passive Skills also grant (.*)$"] = function(passiveType, mod) + return function(node, out, data) + if node and (node.type == firstToUpper(passiveType) or (node.type == "Normal" and not node.isAttribute and firstToUpper(passiveType) == "Small") or (node.type == "Normal" and node.isAttribute and firstToUpper(passiveType) == "Attribute")) then +- local modList, line = parseMod(mod) +- if not line and modList[1] then -- something failed to parse, do not add to list +- modList[1].parsedLine = capitalizeWordsInString(mod) +- modList[1].source = data.modSource +- if type(modList[1].value) == "table" and modList[1].value.mod then +- modList[1].value.mod.source = data.modSource ++ local modList, extra = parseMod(mod) ++ -- avoid adding mods if mod line wasn't parsed correctly ++ if not extra and modList[1] then ++ for _, modListMod in ipairs(modList) do ++ modListMod.parsedLine = capitalizeWordsInString(mod) ++ modListMod.source = data.modSource ++ if type(modListMod.value) == "table" and modListMod.value.mod then ++ modListMod.value.mod.source = data.modSource ++ end ++ out:AddMod(modListMod) + end +- out:AddMod(modList[1]) + end + end + end +``` + +
+ +## Data module diff + +`src/Data/` + `src/Modules/Data*.lua` — data tables; ranked by churn, no hunks. + +| file | +added | -removed | churn | +|---|---:|---:|---:| +| `Data/StatDescriptions/stat_descriptions.lua` | 13822 | 13341 | 27163 | +| `Data/TimelessJewelData/LegionPassives.lua` | 11131 | 11129 | 22260 | +| `Data/FlavourText.lua` | 1893 | 1891 | 3784 | +| `Data/Spectres.lua` | 3507 | 6 | 3513 | +| `Data/ModItemExclusive.lua` | 1551 | 1518 | 3069 | +| `Data/Skills/spectre.lua` | 2798 | 3 | 2801 | +| `Data/ModRunes.lua` | 934 | 360 | 1294 | +| `Data/Skills/SkillAssets.lua` | 618 | 615 | 1233 | +| `Data/ModItem.lua` | 571 | 570 | 1141 | +| `Data/Skills/act_int.lua` | 788 | 350 | 1138 | +| `Data/TradeSiteStats.lua` | 882 | 176 | 1058 | +| `Data/Skills/other.lua` | 610 | 298 | 908 | +| `Data/Skills/act_str.lua` | 603 | 196 | 799 | +| `Data/StatDescriptions/passive_skill_stat_descriptions.lua` | 277 | 307 | 584 | +| `Data/Skills/act_dex.lua` | 356 | 143 | 499 | +| `Data/ModVeiled.lua` | 250 | 248 | 498 | +| `Data/Bases/shield.lua` | 228 | 228 | 456 | +| `Data/QueryMods.lua` | 313 | 94 | 407 | +| `Data/ModJewel.lua` | 173 | 173 | 346 | +| `Data/ModCache.lua` | 99 | 84 | 183 | +| `Data/StatDescriptions/Specific_Skill_Stat_Descriptions/queens_procession_reservation.lua` | 178 | 0 | 178 | +| `Data/Minions.lua` | 128 | 15 | 143 | +| `Data/StatDescriptions/Specific_Skill_Stat_Descriptions/abyssal_living_bomb.lua` | 141 | 0 | 141 | +| `Data/Skills/minion.lua` | 121 | 16 | 137 | +| `Data/Bases/belt.lua` | 59 | 59 | 118 | +| `Modules/Data.lua` | 84 | 11 | 95 | +| `Modules/Data.lua` | 84 | 11 | 95 | +| `Data/Skills/sup_int.lua` | 82 | 4 | 86 | +| `Data/Bases/body.lua` | 43 | 43 | 86 | +| `Data/SkillStatMap.lua` | 61 | 16 | 77 | +| `Data/Bases/helmet.lua` | 38 | 38 | 76 | +| `Data/Bases/gloves.lua` | 43 | 32 | 75 | +| `Data/Bases/boots.lua` | 33 | 33 | 66 | +| `Data/StatDescriptions/Specific_Skill_Stat_Descriptions/abyssal_pact.lua` | 65 | 0 | 65 | +| `Data/Bases/ring.lua` | 29 | 29 | 58 | +| `Data/ModCorrupted.lua` | 27 | 27 | 54 | +| `Data/Bases/sceptre.lua` | 20 | 20 | 40 | +| `Data/Skills/sup_str.lua` | 39 | 0 | 39 | +| `Data/ModScalability.lua` | 32 | 5 | 37 | +| `Data/Rares.lua` | 17 | 17 | 34 | + +## Extracted overlay diff + +`extract-lua` run against both pins; entry-level add/remove/change per collection. +A section missing below means extraction failed on the *old* pin (incompatible +Lua structure) — see the soft-step summary at the end. + +### `--what special-mods` + +**`entries`** — +13 added, -86 removed, ~4 changed +- added: `vnd_allocates_d_sinister_jewel_sockets_054c1300`, `vnd_d_of_damage_from_deflected_hits_is_taken_dcecf2f5`, `vnd_d_of_damage_from_hits_is_taken_from_your_2f80a1e8`, `vnd_d_reduced_movement_speed_penalty_while_a_bf805056`, `vnd_fully_broken_armour_you_inflict_also_inc_4ed5b5e2`, `vnd_gem_quality_grants_socketed_skills_an_ad_5fbefb66`, `vnd_green_d_less_movement_speed_penalty_from_81bf43df`, `vnd_no_inherent_loss_of_rage_7e3c829b`, `vnd_physical_damage_from_hits_contributes_to_c39e2da0`, `vnd_skills_from_corrupted_gems_have_d_of_man_883f84e0`, `vnd_this_item_gains_bonuses_from_socketed_it_a3f2b519`, `vnd_this_item_gains_bonuses_from_socketed_so_8371786d`, `vnd_y_o_u_cannot_recover_energy_shield_to_ab_d449ee1c` +- removed: `vnd_bow_shot_fires_an_additional_projectile_ccb5e788`, `vnd_bow_shot_fires_d_additional_projectiles_d25e690b`, `vnd_bow_shot_fires_d_additional_shard_projec_b2369979`, `vnd_bow_shot_pierces_an_additional_target_5faa16a9`, `vnd_bow_shot_pierces_d_additional_targets_bf9ac4c1`, `vnd_cannot_recover_energy_shield_to_above_ar_58066d9b`, `vnd_chaos_bolt_fires_an_additional_projectil_be9f3572`, `vnd_chaos_bolt_fires_d_additional_projectile_01874b52`, `vnd_chaos_bolt_fires_d_additional_shard_proj_8c5943e9`, `vnd_chaos_bolt_pierces_an_additional_target_b3ef083f`, `vnd_chaos_bolt_pierces_d_additional_targets_a7607329`, `vnd_compose_requiem_fires_an_additional_proj_38de640c`, `vnd_compose_requiem_fires_d_additional_proje_6026db87`, `vnd_compose_requiem_fires_d_additional_shard_a2d29b23`, `vnd_compose_requiem_pierces_an_additional_ta_e980f59a`, `vnd_compose_requiem_pierces_d_additional_tar_9c6c0f1c`, `vnd_crossbow_shot_fires_an_additional_projec_68cd9458`, `vnd_crossbow_shot_fires_d_additional_project_e5a3b9a0`, `vnd_crossbow_shot_fires_d_additional_shard_p_f559f599`, `vnd_crossbow_shot_pierces_an_additional_targ_db22df9c`, `vnd_crossbow_shot_pierces_d_additional_targe_7abffbad`, `vnd_exsanguinate_chains_an_additional_d_time_45448c87`, `vnd_exsanguinate_chains_an_additional_time_02d87466`, `vnd_exsanguinate_chains_d_additional_times_02dee454`, `vnd_firebolt_fires_an_additional_projectile_6a145ddb`, `vnd_firebolt_fires_d_additional_projectiles_4c8d345b`, `vnd_firebolt_fires_d_additional_shard_projec_967b7c2b`, `vnd_firebolt_pierces_an_additional_target_ae776eac`, `vnd_firebolt_pierces_d_additional_targets_f5efa616`, `vnd_freezing_shards_fires_an_additional_proj_cf8b85c5`, `vnd_freezing_shards_fires_d_additional_proje_c5448c6a`, `vnd_freezing_shards_fires_d_additional_shard_16c6dcac`, `vnd_freezing_shards_pierces_an_additional_ta_aef0f52f`, `vnd_freezing_shards_pierces_d_additional_tar_524bbfb6`, `vnd_galvanic_field_chains_an_additional_d_ti_b7051595`, `vnd_galvanic_field_chains_an_additional_time_1cee14d3`, `vnd_galvanic_field_chains_d_additional_times_e3b243eb`, `vnd_grenade_fires_an_additional_projectile_a7877efa`, `vnd_grenade_fires_d_additional_projectiles_2b3d94aa`, `vnd_grenade_fires_d_additional_shard_project_b8c9fa9e` … (+46 more) +- changed: `vnd_d_of_damage_from_hits_is_taken_from_your_0487689a`, `vnd_d_of_damage_from_hits_is_taken_from_your_628fb916`, `vnd_immobilise_enemies_at_d_buildup_instead_609cc61d`, `vnd_no_movement_speed_penalty_while_shield_i_c7772d82` + + +### `--what parser-rules` + +**`flag_phrases`** — +4 added, -0 removed, ~0 changed +- added: `chaos spell`, `cold spell`, `fire spell`, `lightning spell` + +**`name_map`** — +1 added, -0 removed, ~0 changed +- added: `effect of socketed augment items` + +**`pre_flags`** — +0 added, -0 removed, ~1 changed +- changed: `^spells which cost life gain ` + +**`tag_phrases`** — +2 added, -2 removed, ~2 changed +- added: `if you've used a mana flask recently`, `per (%d+) levels` +- removed: `per bark`, `per bark below maximum` +- changed: `with skills that cost life`, `with spells that cost life` + + +### `--what uniques` + +**`uniques`** — +1 added, -1 removed, ~46 changed +- added: `Waistgate` +- removed: `Waistgate Heavy Belt` +- changed: `Adonia's Ego`, `Bijouborne`, `Blessed Bonds`, `Cadiro's Gambit`, `Choir of the Storm`, `Controlled Metamorphosis`, `Cursecarver`, `Darkness Enthroned`, `Eventide Petals`, `Glimpse of Chaos`, `Goregirdle`, `Guiding Palm`, `Guiding Palm of the Eye`, `Guiding Palm of the Heart`, `Guiding Palm of the Mind`, `Heartbound Loop`, `Hinekora's Sight`, `Infernoclasp`, `Keeper of the Arc`, `Lavianga's Spirits`, `Mageblood`, `Mahuxotl's Machination`, `Marohi Erqi`, `Palm of the Dreamer`, `Pragmatism`, `Prism Guardian`, `Rearguard`, `Reverie`, `Rite of Passage`, `Sacred Flame`, `Saffell's Frame`, `Saitha's Spear`, `Sandstorm Visage`, `Sculpted Suffering`, `Strugglescream`, `Svalinn`, `Sylvan's Effigy`, `Temporalis`, `The Burden of Shadows`, `The Covenant` … (+6 more) + + +## Soft-step summary + +All steps succeeded. + diff --git a/devs/scripts/version-bump-drill.sh b/devs/scripts/version-bump-drill.sh index 449ba33e..bd041651 100755 --- a/devs/scripts/version-bump-drill.sh +++ b/devs/scripts/version-bump-drill.sh @@ -178,7 +178,10 @@ fi # ---- [3b] 策展域对账:buff_definitions(F4,机跑通道)---- step 3b "策展域对账:check-buff-refs(buff_definitions.json)" +# buff_definitions 已迁至版本无关的 data/overlay-common/(P1-3);版本特有覆盖若存在 +# 则优先对账,否则对账 common 层基底。 DEFS="$OVERLAY_DIR/buff_definitions.json" +[[ -f "$DEFS" ]] || DEFS="$ROOT/data/overlay-common/buff_definitions.json" if [[ ! -d "$VENDOR" ]]; then echo "SKIP: vendor 检出不存在(${VENDOR})" SKIPPED+=("vendor 缺失 → buff_definitions 对账跳过") diff --git a/docs/adapting-to-0.5.4b.md b/docs/adapting-to-0.5.4b.md index 3577182b..23259760 100644 --- a/docs/adapting-to-0.5.4b.md +++ b/docs/adapting-to-0.5.4b.md @@ -81,10 +81,567 @@ un-ignored; `ranger-deadeye` Evasion 0.99x vs 0.5.4b golden 29774. The stale `ninja-bd-deadeye.txt` embedded PlayerStats predate PoB2's Mageblood modeling (res/evasion assertions on that old sample relaxed accordingly). -Remaining after Mageblood, re-triage against fresh `defenceModList` dumps: -DeflectionRating scaling, offence per-build DPS clusters, ailment magnitude. -Each is its own oracle-guided investigation; not all are single formula -constants (several are unmodeled unique/flask interactions). +**#2 target — DeflectionRating. ✅ DONE (re-triage + Refraction buff).** +Re-triage after Mageblood showed the gap-map entry (`monk-martial-artist` +13476 vs 22312) was **downstream of the Evasion gap**: rating derives from +`Evasion × EvasionGainAsDeflection%` (CalcDefence.lua:1516-1522, formula +unchanged in 0.5.4b) and closed to 0.998x once Mageblood landed — the +deflection canary (`defence_panels_golden::deflection_matches_golden`) +re-verified against a fresh oracle run and un-ignored, no formula change. +One genuine deflection-side source remained: the **Refraction I/II support** +Refractive Plating buff (`sup_str.lua:5984/6023`, +`support_tempered_valour_deflection_rating_%_of_evasion_rating` BASE 20, +gated by `MultiplierThreshold ValourStacks/thresholdVar= +RefractionMinimumValour` — zero setters vendor-wide, so threshold is +statically 0). Admitted via the player-buff stat-map allowlist plus a +`MultiplierThreshold` arm in `translate_tag` (thresholdVar accepted only for +verified zero-setter vars). wolf-pack DeflectChance 0.80x→1.00x, pathfinder +0.93x→1.00x; def 25-col baseline 405→407 @5% / 428→429 @10%. The same buff's +`ArmourAppliesToDamageTaken` payloads stay reported (EHP-side lead: +wolf-pack TotalEHP 0.76x→0.81x, remainder likely there). + +**#3 target — `ArmourAppliesToDamageTaken` (Refraction buff payload). +✅ DONE.** The consumption chain already existed end-to-end +(`calc::taken::armour_applies_pct` → `build_mitigation_ctx` → per-type +DamageReduction / MaximumHit / EHP, mirroring CalcDefence.lua:2361-2368 +`percentOfArmourApplies` → `effectiveAppliedArmour`); tree-sourced percentages +flow through `mod_parser` ("X% of Armour also applies to Y damage taken"). +The only gap was the player-buff stat-map allowlist: the Refractive Plating +buff's second stat key +(`support_tempered_valour_%_armour_to_apply_to_elemental_damage`, +`sup_str.lua:6019-6021`, three `ArmourAppliesTo{Fire,Cold,Lightning} +DamageTaken` BASE 30 mods with the same GlobalEffect + MultiplierThreshold +tags as the deflection payload) hit `UnknownModName`. Oracle attribution +(extended `defenceModList` name set) pins wolf-pack at tree 84 + buff 30 = +114% per element, `EffectiveAppliedArmour` = 18580 × 1.14 = 21181.2. +Admitting the three names closes wolf-pack Fire/Cold/LightMaxHit +0.94x→0.96x (@5% hits) and TotalEHP 0.81x→0.88x; def 25-col baseline +407→410 @5% (429 @10% unchanged). The EHP remainder is **not** this channel: +Armour itself 0.98x (18169.78 vs 18580), ChaosMaxHit 0.87x (oracle +`ChaosEffectiveAppliedArmour` = 0 — chaos gap is elsewhere), and Life 1.11x +(PoBR overestimate 2973.6 vs 2674). + +**#4 target — offence per-build DPS clusters. ✅ DONE (three sub-fixes).** +Re-triage first: the gap-map poster child `druid-oracle-ember-fusillade` was +already at TotalDPS 1.00x (closed as a side effect of earlier fixes; its +`canary_fire_spell_armour` re-verified and un-ignored). The real 0.5.4b +clusters (cells where PoBR ≈ old 0.5.0 golden while the 0.5.4b golden moved): + +- **#4a Atziri's Communion → auto Low Life** (`huntress-ritualist-bow-shot`, + `witch-abyssal-lich-detonate-dead`): 0.5.4b added + `LifeReservePercentPerSpirit` (CalcDefence.lua:248-254) — the Communion + support converts a persistent skill's Spirit reservation into Life percent + reservation (0.66%/spirit), pushing heavy-reservation builds under the + auto Low Life threshold (:335-350, unreserved ≤ 35%), which unlocks the + "while on Low Life" mod family. Oracle `damageModList` pinned ritualist's + missing 130 Damage INC to exactly the two LowLife-gated entries (tree + +60, Direstrike buff +70 — the buff's stat-map entry already carried + `Condition:LowLife`; only the condition was never true). Three generic + consumption points: nameSpec-only gem resolution (lineage supports + serialize without skillId/gemId), the spirit→life conversion branch in + `spirit_reservation_modifiers`, and + `CalculationSession::bridge_low_pool_conditions` (orchestrator 6e). + Ritualist TotalDPS 0.68x→0.99x, TotalDotDPS 0.60x→1.00x, + SpiritUnres/LifeUnres exact. +- **#4b Voices sinister jewel sockets** (ritualist, titan, abyssal-lich): + the 0.5.4b Voices unique "Allocates 2 Sinister Jewel sockets" + (ModParser 0.22.0 `GrantedPassive SinisterJewelSockets`, + PassiveSpec.lua:1067-1090 alias order `voices_jewel_slot1..5` → 0_5 tree + nodes 62152/26178/23960/39087/3367). PoBR's tree-jewel gate dropped + jewels in never-allocated sinister sockets; `parse_items_and_slots` now + admits the first N pinned sockets. Ritualist CritChance 27.84→29.10 and + CritMultiplier 4.37→4.74, both exact (missing 13/37 INC matched the two + sinister jewels line-for-line). +- **#4c grenade phrases un-preempted** (`ranger-deadeye-` / + `mercenary-gemling-explosive-grenade`): vendor 0.22.0 added + `not grantedEffect.fromItem` to the gem-name registration loop + (ModParser.lua:6423) — "Grenade" (fromItem) no longer shadows the + modFlagList phrases, so `grenade` / `for grenade skills` are live + `SkillType.Grenade` tags again (run-parsemod verified). The PR#53-era + extractor overrides (dead-entry / inert-SkillName rewrite, correct for + 0.21) were retired and `mod_parser_rules.json` + `parsed_mods.json` + regenerated. Deadeye's 3×15% grenade-CDR tree nodes (oracle + `extraModList` — new `ORACLE_EXTRA_STATS` tooling — Tree:21077/354/48429) + now apply: Speed 0.164→0.254 (1.00x), TotalDPS 0.53x→0.83x; gemling + Speed/AvgDamage/TotalDPS all 1.00-1.04x. + +Aggregate: off @5% 46→56 (@10% 55→62), dot 11→14 (@10% 13→19), def 25-col +410→413 (@10% 429→434), core-8 138→140, panel off 27→40 / 30→41. + +Remaining offence clusters after #4 (TotalDPS @5%, decomposed): the attack +AverageDamage family — smith-of-kitava 0.57x, monk-flicker 0.76x, +spirit-walker 0.78x (dot 0.23x), monk-twister 0.88x, titan 0.87x (its +CritMultiplier is a separate 0.5.4b "Bifurcated Crit Damage Bonus" MORE +mechanic, golden 5.00 vs PoBR 6.0) — plus blood-mage 0.87x, abyssal-lich +0.91x, pathfinder 0.90x, deadeye per-hit 0.83x (pre-0.5.4b shortfall, +documented in pob2_parity.rs), and frost-bomb 0.66x (golden unchanged +0.5.0→0.5.4b — a pre-existing cooldown-DPS gap, not a 0.5.4b regression). +These moved 6-46% in the 0.5.4b golden with per-build factors — no shared +constant; each needs its own oracle decomposition. +✅ (2026-07-17, 存量清扫 #7) frost-bomb TotalDPS 0.66x→1.00x:双根因 = +Archmage buff `DamageGainAsLightning`(80% per 100 Mana)未入玩家 buff +允收名单 + SkillType neg tag 不支持;以及 curse 链两缺口(EW 取数等级未吃 ++spell-skill levels、技能局部 CurseEffect 段缺失)。见 commit 9075077。 + +**#5 target — ailment (ignite) magnitude. ✅ DONE (one root cause: Blazing +Critical global fire buff).** Re-triage first: the ailment *formula* did not +change in 0.5.4b — `IgniteChanceMultiplier`/`monsterAilmentThresholdTable`/ +`defaultAilmentDamageTypes`/the `ailmentDPSUncapped` assembly are byte-identical +between vendors (only `skillData.dpsMultiplier` → `output.DpsMultiplier`, a +refactor PoBR already mirrors via `dps_end_factors`). Yet 16 of 18 dot goldens +moved (1.07×–22.4×). Oracle decomposition on the extreme mover +(`monk-martial-artist-flicker-strike`, dot 0.05x, golden 47→1054) pinned a +single fire-specific ×4 on the hit: PoBR's stored-Fire range was 0.21x oracle +while every other damage type sat at the uniform 0.85x hit gap. Per-source +tabulation (`ORACLE_EXTRA_STATS=DamageGainAsFire`) showed the missing 15%: +the **Blazing Critical** support (`sup_int.lua:959`) — 0.22.0 added a +`GlobalEffect effectType=Buff` tag to its +`support_blazing_crits_gain_%_fire_damage_with_attacks_on_critical_hit` stat, +turning the 15% `DamageGainAsFire` (Attack + Condition:CritRecently) from a +dead skill-local mod (old-vendor oracle: absent from the skill modList, +IgniteDPS 47.54 = PoBR's 47.55 exactly) into a global player buff ("imbue all +of your Attacks with Fire"). Since ignite chance ∝ fireAvg/threshold and +magnitude ∝ fireAvg, the buff amplifies IgniteDPS quadratically (×16 on +flicker). Exactly the three worst dot movers carry the gem (flicker, +spirit-walker, monk-twister). + +Two generic consumption points (no per-gem code): +- `translate_player_buff_mod_name` allowlist admits `DamageGainAsFire` + (consumer = the existing gain-as matrix in `calc::damage::buildGainTable` + mirror; flags/Condition tags already translate). +- `support_buff_specs` now judges support compatibility against **additional + granted effects** too (mirroring `buff_skill_specs`): Blazing Critical's + host in these builds is Charged Staff, whose gem is Spell-typed — the + compatible skill is its hidden Attack additional effect + `ChargedStaffShockwavePlayer` (act_int.lua:3387). + +Result: monk-twister TotalDotDPS 0.44x→0.98x, CombinedDPS 0.60x→0.96x, +AverageDamage/TotalDPS 0.60x→0.96x (all into the 5% band); flicker dot +0.05x→0.72x, spirit-walker 0.23x→0.87x (remainder = the attack AvgDamage +family's hit gap squared, not a dot-side mechanic). Baselines: off 56→58 @5% +(62→64 @10%), dot 14→16 @5% (19→21 @10%); def/panel unchanged (CritRecently +is combat-gated, panel mode unaffected). No ailment canary was left ignored +(the suite's only `#[ignore]` is the vendor-dependent oracle differential). + +Dot-side leftovers, each triaged **not** a 0.5.4b ailment item: +- `smith-of-kitava` dot 0.20x: hit gap 0.57x squared explains 0.32; the extra + residual is the un-modeled *uptime-scaled* Infernal Cry `DamageGainAsFire` + 12.04% — present and identical in both vendors (old-vendor oracle proves it + predates 0.5.4b), i.e. a pre-existing warcry-uptime gap. +- `deadeye` 0.69x = hit 0.83x², `blood-mage` 0.79x ≈ hit 0.87x² (its ~16% + per-hit shortfall is the long-registered pre-0.5.4b item), `titan` 0.91x / + `abyssal-lich` 0.94x / `pathfinder` 0.92x track their hit gaps. +- `frost-bomb` dot 0.87x and `essence-drain` WithDotDPS 1.36x: goldens + byte-identical across the flip — pre-existing gaps. + ✅ (2026-07-17, #7) essence-drain 1.36x→1.00x:数据管线漏下 + `GrantedEffectStatSets.RemoveStats`(社区 schema 名 `IgnoredStats`)—— + ED 的 DoT set 本应移除主 set 的击中伤害 stat,PoBR 幻影击中 120.87 DPS。 + 管线补列 + adapter 置零语义 + 55 效果重生成(commit 5edb741)。 + frost-bomb dot 随 #7-1 修复 0.87x→1.07x(@10% 带内)。 +- `gemling` dot 1.10x over: oracle per-component shows fire stored 1.03x × + stacks 1.05x × slight crit-chance overshoot — downstream of its small + hit-side overestimates, no dot-side mechanism. + +**#6 target — the attack AverageDamage family. ✅ DONE (five generic-consumption-point +fixes; the whole family is inside the 5% band).** Per-build oracle decomposition +confirmed the #4 verdict (per-build factors, no shared constant) but found two +*shared* root causes hitting multiple builds plus per-build items: + +- **#6a Bifurcate crit pipeline (Garukhan's Resolve builds: spirit-walker / + pathfinder / titan).** Two halves: + (i) the bifurcated extra-crit-damage weight is the *conditional* probability + `(PreBifurcateCritChance²/100) / CritChance` (CalcOffence.lua:3823-3846 — + identical in 0.21/0.22, i.e. a PoBR mis-port, not a 0.5.4b change; PoBR had + the unconditional `pre²/10000`), and + (ii) **0.22.0 added `CritMultiplier` to the weapon convert-to-local list** + (Item.lua:1954-1961): an unflagged crit-damage-bonus mod on a weapon now + gains `Condition:{Main,Off}HandAttack`, so Nebuloch's +29% no longer leaks + into titan's Shield Wall (a non-weapon attack running the off-hand pass). + Consumption points: `resolve_crit_multiplier` + new + `CalculationSession::add_weapon_item` (orchestrator routes items whose base + resolves as a weapon). Titan CritMultiplier 6.02→5.00 (golden exact, + oracle PreEffectiveCritMultiplier 4.88 reproduced); spirit-walker / + pathfinder CritMult 0.94x→1.00x/0.99x. +- **#6b enemyDistance placeholder feeds skillDist (0.22.0, + CalcActiveSkill.lua:671 `configInput or configPlaceholder`).** The old vendor + read only the explicit `` (what PoBR mirrored), so every DistanceRamp + mod was dropped whole. Close Combat II's 30% MORE (ramp {10:1, 35:0}, + evaluated at the placeholder distance 20 → ×0.6 = 18%) now lands. Fallback + chain mirrors ConfigTab: Input → XML Placeholder → catalog + `defaultPlaceholderState`. flicker 0.838x→0.99x; smith one of three stacked + segments. (Oracle probes added: `intermediates.SkillDist` + + `MoreDamage_at{5,20,30,40}` — this is how the 30-vs-18 ramp base was pinned.) +- **#6c PerStat `statList` (smith/titan shield notable Tree:27687, "4% + increased Attack Damage per 75 Item Armour and Evasion on Equipped + Shield", ModParser.lua:1631).** The rule-driven parser rejected statList + tag phrases whole. Normalized to a `|`-joined compound Multiplier var, + summed at eval (ModStore.lua:445-452 semantics: Σstats then one + floor(sum/div)). Oracle-pinned 88 INC; smith Physical pool scale lands at + 9.5899 = oracle exactly. +- **#6d hybrid mana→life cost + per-LifeCost mods (smith's Atalui's + Bloodletting).** `base_skill_cost_life_instead_of_mana_%` → + `HybridManaAndLifeCost_Life` turns `floor(manaBase × supportMult) × hybrid` + into the Life cost base (CalcOffence.lua:2067/:2090-2104; mana chain tail + `floor((1-hybrid)×ManaCost)`); statmap PerStat now admits + `limit`/`limitTotal` so the support's `PerStat{stat=LifeCost, div=20, + limit=40, limitTotal}` gain-as-physical maps; the orchestrator prefills + `cfg.stats/multipliers[LifeCost]` from the new + `CalculationSession::life_cost_snapshot` (vendor's cost-before-damage + ordering). Oracle LifeCost 309 → floor(309/20)=15 → +30% + DamageGainAsPhysical. +- **#6e per-leg enemy mitigation in the crit short-circuit path.** The + short-circuit (identical legs) mitigated the non-crit leg and scaled by + crit.effect — valid only for raw-independent mitigation; enemy armour DR + depends on hit size (vendor pass 1 computes DR against the post-crit-mult + hit, CalcOffence.lua:4395 blend). Reconstruct the crit leg as + `non_crit × crit.multiplier` and blend per-leg; bit-identical when + mitigation has no raw dependency. spirit-walker mitigated hit 42291 vs + vendor AverageDamage 42318 (0.9994). + +Aggregate: off @5% 58→71 (@10% 64→73), dot 16→25 (@10% 21→27), panel off +40→41/41→42; def unchanged. Per-build TotalDPS (effective): smith 0.575x→0.996x, +titan 0.874x→0.978x, flicker 0.838x→1.003x, spirit-walker 0.892x→0.980x, +monk-twister 0.958x→0.980x, pathfinder 0.904x→0.963x, ritualist →1.000x. + +Remaining offence after #6, each triaged: +- `deadeye` 0.832x — the long-registered pre-0.5.4b per-hit shortfall + (pob2_parity.rs); golden did move in the flip but the residual matches the + old ledger. + ✅ (2026-07-17, #10) 根因钉死:Deadeye 升华 Point Blank(Tree:41875)的 + 「first 3.5m 20% more → 7m 后 0%」被引擎误析为平坦 ProjectileDamage MORE 20 + 且带 leftover 被产线丢弃——所有分量统一少 ×1.20(oracle:MORE Damage 100 + + DistanceRamp {35:0.2,70:0},SkillDist=20 求值 +20%,ModParser.lua:2911-2913)。 + 修复 = special 通道字面条目 ×2 + special 编译器 DistanceRamp tag 支持。 + AverageDamage/TotalDPS 0.83x→1.00x,连带 ignite 链 TotalDotDPS 0.69x→1.00x。 +- `blood-mage` 0.880x / `abyssal-lich` 0.926x — Mageblood mod family + (oracle pins blood-mage's missing `INC CritChance 107 'Mageblood'`; golden + CritChance 72.45→92.1 and CritMult 5.34→5.87 moved with 0.5.4b while PoBR + sits at the old CritMult 5.34 exactly). This is the Phase-1 standalone item. +- `frost-bomb` 0.661x — golden unchanged across the flip; pre-existing + cooldown-DPS gap. +- `smith` TotalDotDPS 0.40x — hit is 0.996x now, so the dot residual is purely + the un-modeled *uptime-scaled* Infernal Cry `DamageGainAsFire` + (fire-source ratio 0.63² ≈ 0.40). Mechanism fully decomposed: uptime = + `min((NumInfernalEmpowers/Speed)/(cooldown + warcryCastTime), 1) × + storedUses` (CalcOffence.lua:3229-3257), `NumInfernalEmpowers = + floor(min(WarcryPower 20, cap 50)/per 10)` (CalcPerform.lua:2117-2131), + gain-as = gem's `infernal_cry_exerted_attack_all_damage_%_to_gain_as_fire_%` + (62 at smith's level) × uptime 19.41% = 12.04. Identical in both vendors — + a pre-existing warcry-uptime gap; needs the warcry buff machinery + (duration/cooldown/cast-time of a non-main skill + WarcryPower config), + registered for its own slice. + ✅ (2026-07-17, #9) warcry uptime 机器落地(pobr-core `calc::warcry` + + 编排层 `warcry_skill_specs`,全数据驱动零技能硬编码):smith TotalDotDPS + 0.40x→1.06x(@10% 带内)。uptime/castTime/cooldown 对 oracle 逐位 + (19.4116% / 0.544218 / 6.27),注入 gain 12.035 = vendor "Uptime Scaled + Infernal Cry" 条 bit-exact。连带修三处通道:敌人档位预设 player_mods + (WarcryPower BASE 20)此前未注入 player db;statmap 直通族补 + WarcryPowerPer/Cap + InfernalExtraFireDamageMultiplier;parser 「skill + speed」短语恢复 vendor 三名扇出(ModParser.lua:770 {Speed, WarcrySpeed, + TotemPlacementSpeed},此前 curated 收窄为单名致树上 17 INC WarcrySpeed + 丢失)。残余 +6% = smith 命中侧原有 +2% 高估(此前被缺失 gain 抵消遮蔽) + 经点燃平方放大;titan 同理暴露(TotalDPS 0.98→1.05,带内)。dot 基线 + @10% 31→32。 +- `spirit-walker`/`monk-twister` last ~2%: "Barrage Repeats" MORE DPS + (vendor `output.DpsMultiplier` via `calcLib.mod(..., "DPS")`) — repeat + DPS bonus channel unwired. + ✅ (2026-07-17, #10) 通道接通:Barrage buff 载荷(BarrageRepeats BASE 2 / + BarrageRepeatDamage MORE -45 / SequentialProjectiles flag)经 buff 域允收 + 名单入 player db,`dps_end_factors` 复刻 vendor 门控(CalcOffence.lua:962-976) + 与 MoreInternal 逐名桶百分比取整(ModList.lua:143:MORE 1.65 → ×1.02, + oracle DpsMultiplier=1.02 逐位)。两 build TotalDPS 0.98x→1.00x。 + vendor else 分支(crossbow barrage 攻时惩罚)无语料覆盖,未实现(代码内登记)。 + 同批(#10-3)smith/titan 命中高估根因 = 非伤害源武器上的裸「Adds N to M + Damage」泄漏进全局加法桶(vendor Item.lua:1923-1928 全类型折入 + weaponData 局部;titan Nebuloch 混沌 30-52 × added-effectiveness 3.47 = + 幻影 104-180 混沌 base,oracle ChaosMinBase=0)。剔除后 titan TotalDPS + 1.05x→1.01x、smith AverageDamage 1.02x→1.00x;titan 残余 ~0.9% 与 + Armour 面板 0.99x 同根(盾 rolled 1736 vs vendor 重算 1725 喂 + per-15-shield-armour phys base)+ 暴击率尾差,属防御侧通道。 + +Remaining elsewhere, re-triage against fresh `defenceModList` dumps: +the wolf-pack EHP remainder decomposed above +(Armour 0.98x / ChaosMaxHit 0.87x / Life 1.11x). Also ritualist TotalEHP +moved 1.04x→1.10x with #4a (低血 EHP 口径——vendor 只在显式 +`conditionLowLife` config 下 cap `LifeRecoverable`,PoBR 的 EHP 消费端 +尚未对齐该分支). Each is its own oracle-guided investigation; not all are +single formula constants (several are unmodeled unique/flask interactions). +✅ (2026-07-17, #7) 两项收口(commit 6bb0685): +- ritualist TotalEHP 1.10x→1.00x:LifeRecoverable 口径是误诊(两侧本就一致, + vendor 只在显式 config 下 cap);真根因 = 策展条目 `also_grants_guard` + (护符 "Also grants N Guard")vendor 根本不解析(oracle AnyGuard=False), + 幻影 +491 共享 Guard 池已摘除。twister maxhit 族随之 1.06x→0.97x。 +- wolf-pack:Life 1.11x→1.00x(Giant's Blood `HalvesLifeFromStrength` + 接消费端)、Armour 0.98x→1.00x(PerStat Spirit 分母改读最终池值 336 而非 + BASE 300)、Mana→0.99x + gemling Life/Mana/MaxHit 族→1.00x(overlay-common + 三色宝石阈值条目池名归一 MaximumLife/MaximumMana)。**未闭合余量** = + companion ally-mitigation 层:vendor 把每个 hit pool 扩到 + `pool/(1−CompanionAllyDamageMitigation 10%)`(上限 TotalCompanionLife + 2262,CalcDefence.lua:3567-3595 allies 层)——PoBR 无 companion actor, + maxhit 族诚实落在 ~0.82x(此前被幻影 Guard 掩蔽到 ~0.96x)。归 companion + 本体项目。 +✅ (2026-07-17) `check-buff-refs` 15-drift re-review done: the recorded hashes +were pinned at vendor `2df5a743` (pre-0.21.0; never refreshed at a82a33b either), +so every buff "drifted" purely because `doActorMisc` shifted ~+75 lines +(:503-765 → :578-850) and the Arcane Surge block moved :1580-1591 → :1606-1617. +All 15 blocks were diffed against the pinned baseline: 14 byte-identical, +UnholyMight differs by one removed trailing space — zero semantic changes, so +no `buff_definitions` entry content changed and parity is untouched. Line +ranges re-pointed to the 0.22.0 (`ce8bffab`) locations, hashes refreshed via +`--write`, `_meta.vendor_commit` updated; check now reports 0 drift. + +**#8 target — the blood-mage/abyssal "Mageblood crit family" residual. ✅ DONE +(one root cause, and it was not Mageblood).** The #6 ledger entry ("PoBR missing +`INC CritChance 107 'Mageblood'`") turned out to be a stale symptom: line-by-line +diff of `calc/mageblood.rs` against vendor `CalcPerform.lua:66-142` shows the +effects table complete (all 14 legacies, Diamond included), and the +per-duplicate implicit (`all mage's legacies have (%d+)% increased effect...`, +ModParser.lua:5558 → `MagesLegacyEffect` INC) is already covered by +`generated/special_vendor.json` (`vnd_all_mage_s_legacies_have_d_...`). A +per-mod dump of the live build confirmed `CriticalStrikeChance INC 107 +src=Mageblood` present and oracle-exact. The *actual* gap, pinned by diffing +oracle `critModList`/`ORACLE_EXTRA_STATS` per-source against the PoBR ModDb: +both builds anoint their amulet with `{enchant}Allocates Zarokh's Gift` — a +*named jewel socket* node (0_5 tree 11184, `isJewelSocket` + `sinister`, alias +`DeliriumAnoint_ZarokhsGift_`). Vendor allocates it through the +`ResolveGrantedPassiveNodes` sockets-by-name fallback +(PassiveSpec.lua:1106-1114); PoBR's granted-passive path only matches Notables, +and the jewel gate in `xml_build.rs` only knew the Voices sinister-count +channel, so the socketed jewel was dropped whole (blood-mage: Pandemonium +Ornament — CritChance INC 24 + CritMult INC 25/28, exactly the CritMult +5.34-vs-5.87 delta; abyssal: an ES/defence jewel). Fix: +`NAMED_SOCKETS_0_5` in `xml_build.rs` — scan equipped items' three text +sections for `Allocates `, match named sockets (0_5 tree has exactly +one: Zarokh's Gift), and treat the node as allocated for jewel inclusion, +same pinned-id pattern (and same tree-version ceiling) as +`SINISTER_SOCKETS_0_5`. Results: blood-mage TotalDPS 0.880x→1.00x (CritChance +88.5→92.1, CritMult 5.34→5.87, both golden-exact), abyssal-lich TotalDPS +0.926x→1.00x (CritChance/CritMult 1.00x; ES 12124→12437 vs golden 12434, +MaxHit family + TotalEHP 0.97-0.98x→1.00x). 18-build per-cell diff: only these +two builds moved. Baselines: off 73→76 @5% / 75→76 @10%, dot 27→31 @5% / +31→33 @10%; def counts unchanged (the abyssal def cells were already inside +the 5% band). The other 7 Mageblood wearers: no movement — their legacy +modelling was already complete. + +**#11 — two legacy leftovers. ✅ DONE (one real root cause, one stale golden).** + +- *druid EW "curse-slot over-application" (TotalDotDPS 1.06x)*: the #7 hypothesis + (PoBR applying Elemental Weakness that vendor keeps out of the slot) was + **wrong** — `POBR_DBG_CURSE` + `POBR_DBG_ENEMYMIT` show PoBR's single curse + slot already resolves to Temporal Chains (EW excluded, IgniteEffMult 0.6 == + vendor). The real residual was the **Temporal Chains magnitude**: support + judgement only enumerated gems whose *primary* granted effect is a support, + so Blasphemy's support half (`SupportBlasphemyPlayer`, additional granted + effect carrying `support_blasphemy_curse_effect_+%_final` → `CurseEffect + MORE -41` @L19, act_int.lua:1126-1163) never entered the curse local-effect + multiplier. TC applied at floor(-25×0.55)=-13% expire-slower vs vendor + floor(-25×(1.1×0.59×0.5))=-8 (CalcPerform.lua:2422-2430 inc/more chain + + Pinnacle `CurseEffectOnSelf MORE -50`), inflating ignite + `debuffDurationMult` (CalcOffence.lua:1845) 1/0.87 vs 1/0.92. Fix: expand + `judge_group_supports` candidates to each gem's granted-effect list + (`gem_effects` overlay) routed by `is_support` — vendor CalcSetup gemList + semantics — and carry the support *effect id* to all consumers. After: + ignite duration 4.3478 == oracle, druid TotalDotDPS 1.06x→1.00x, monk + frost-bomb 1.07x→0.99x, dot baseline 31→33 @5%; per-build curse slot + occupancy unchanged across all 18 builds. +- *MARTIAL embedded-sample ES 1.12x (pob2_parity.rs)*: **stale golden, not a + PoBR over-count.** The code is a `targetVersion="0_1"` (PoE2 0.1-era) export; + feeding the same decoded XML to the current vendor oracle yields + EnergyShield 7008 vs PoBR 7005.5 (0.9996x), while every era-stable stat + (Life/Mana/Evasion/resists/crit) matches the embedded values exactly — only + ES (and offence) drifted with 0.5.x data. Same class as the deadeye + Mageblood/res stale-sample notes in that file; documented inline and + guarded with a wide (0.15) tolerance against the embedded value plus tight + guards on the era-stable stats. Authoritative ES gate remains ninja_parity's + 0.5.4b fixture goldens. + +**#12 — companion allies defence layer. ✅ DONE (exact on twister; wolf-pack +residual is mitigation-side, not companion).** Vendor semantics (all pinned by +oracle on `mercenary-tactician-wolf-pack`): + +- *Mitigation* (`CalcDefence.lua:2961-2965`): `CompanionAllyDamageMitigation = + Σ BASE TakenFromCompanionBeforeYou + Σ BASE + TakenFromCompanionBeforeYouFromDeflected × DeflectChance/100`. The 10% comes + from Loyalty support's constant stat + `companion_takes_%_damage_before_you_from_support` (SkillStatMap.lua:2559 → + `TakenFromCompanionBeforeYou` BASE, GlobalEffect/Buff/unscalable); Wild + Protector (twister's bear) carries the same stat on its own stat set. +- *Pool* (`CalcPerform.lua:3323-3370` `calcMinionLifePool`): when the player + has the mitigation mod and no config Override, `TotalCompanionLife` = Σ life + of minions whose granting skill has `SkillType.Companion` and not + `MinionsAreUndamagable`. Oracle decomposition for the wolf: minion level 44 + (= `minionLevelTable[18+4]` — gem 18 + item "+4 to Level of all Minion + Skills"), base life `floor(monsterAllyLifeTable[44]=2938 × minionData.life + 1.1) = 3231`, × Loyalty `support_trusty_companion_minion_life_+%_final` + MORE −30 → **2262** (`TotalCompanionLife` golden). +- *Consumption*: max hit (`:3656-3663`) folds the layer with the shared + poolProtected formula (`protected = L/(r)×(1−r)`; pool < protected ⇒ + pool/(1−r), i.e. ×1/0.9); EHP (`:493-495` + `reducePoolsByDamage:525-531`) + drains `damage × r` capped by remaining companion life, not recoupable. + +PoBR implementation (minimal slice — no companion actor abstraction; reuses +the existing minion actor + the existing generic `AllyLayer` machinery that +EHP/max-hit already shared): + +- `TakenFromCompanionBeforeYou` admitted through the player-buff statmap + allow-list (`stat_map_engine::translate_player_buff_mod_name`) — reaches the + player ModDb via the existing support/active buff channels (Loyalty via + `support_buff_specs`, Wild Protector via the active-skill Buff branch). +- Minion fixes feeding the life sum (all vendor-faithful, benefit every + summoner): spawn level now includes `+N to Level` gem bonuses + (`spawn_minions` → `additional_gem_levels` + `support_granted_gem_levels`); + minion base life switched from the enemy `monsterLifeTable` to + `monsterAllyLifeTable` (new `MONSTER_ALLY_LIFE_TABLE` const, vendor + CalcPerform.lua:1046 floor semantics); Loyalty's −30% more minion life flows + through a new narrow minion-domain statmap mapper + (`map_minion_life_stat`, inner allow-list = Life → `MaximumLife`) into the + group's `MinionModifierEntry` channel. +- `Actor::is_companion` marks companion minions at spawn (skill_types + judgement); `perform` now runs `perform_minions` *before* `fill_mechanics` + (vendor precedent: minion life pools are computed before player defence) and + `inject_companion_life` writes `TotalCompanionLife` BASE into the player + ModDb (Override-aware); `pool_setup::build_pool_state` emits the + `companion` AllyLayer consumed by both EHP and max-hit paths. +- Not modelled: the `...FromDeflected × DeflectChance` term (no source in the + 18-build corpus; wolf-pack oracle mitigation is exactly 10 = pure hits + term) and multi-companion stacking (no corpus; the sum loop is already + general over `env.minions`). + +Results: PoBR wolf pool 3817.0 vs oracle `TotalHitPool` 3826.67 +(0.9975 — remaining 0.25% is the pre-existing Mana 761.2 vs 770 gap); +`huntress-spirit-walker-twister` closes exactly (5×MaxHit + TotalEHP +0.89-0.90x → 1.00x); wolf-pack moves MaxHit 0.82→0.90x, ChaosMaxHit +0.72→0.80x, TotalEHP 0.74→0.83x — the residual is a uniform ~10% per-type +taken-multiplier gap (armour-applies/mitigation side, tracked separately), +not the companion layer. Baselines: def 425→431 @5%, 434→439 @10%; off/dot/ +core-8 unchanged; 18-build per-cell diff shows only twister and wolf-pack +moving. + +**#13 — defensive residuals pinpoint fixes. ✅ DONE (wolf-pack + titan defensive +columns all exact).** Three independent root causes, each pinned by oracle: + +- *wolf-pack per-type taken ~10% uniform gap = enemy Intimidated base pair.* + Oracle `EnemyDamageMult = 0.9` for all five types; enemyDB tabulate shows + a single `Damage INC -10, source "Base"` — the actor-init conditional mod + `Damage INC -10 { Condition: Intimidated }` (CalcSetup.lua:73-77, paired with + `DamageTaken INC 10`), lit by the body-armour corrupted implicit "Enemies in + your Presence are Intimidated" (flag reaches PoBR's enemy db but had no + consumer). Note the Enfeeble curse payload is *not* the source — its MORE is + gated `!Unique` and the Pinnacle enemy is Unique on both sides. Fix (all + generic consumers): `setup_enemy` injects the Intimidated base pair (tag + `EnemyIntimidated`); `env_finalize::bridge_enemy_condition_flags` bridges the + enemy-db `Condition:Intimidated` FLAG into cfg `EnemyIntimidated` (vendor + ModStore GetCondition semantics; allow-list = Intimidated only); orchestrator + seeds `EnemyInPresence` true (CalcPerform.lua:524 default — PoBR does not + model PresenceRadius vs enemyDistance). `EnemyDamageMult` was already wired + as the max-hit end divisor (:3734-3771) and EHP damage-in multiplier — only + the mod was missing. wolf-pack Phys/Fire/Cold/Light MaxHit 0.90x→1.00x, + PhysDR 65.69→68.03 (oracle 68), TotalEHP 0.83x→(with the Mana fix) 1.00x. +- *wolf-pack Mana 761.2 vs 770 = The Adorned corrupted-magic-jewel scaling.* + Oracle Int=139 vs PoBR 135: the six tree-socketed "Rallying Ruby of Valour" + magic jewels (corrupted, enchant implicits +Int/+Dex/+chaos res) are scaled + ×1.97 by The Adorned's "97% increased Effect of Jewel Socket Passive Skills + containing Corrupted Magic Jewels" (CalcSetup.lua:944-948 sets the + multiplier, :1342-1347 `ScaleAddList`, value = `trunc(round(v×scale, 2))`, + ModStore.lua:70-79): +5 Int→9, +4 Dex→7. Fix: `Item.corrupted` field (item + text `Corrupted` marker line, both parse paths) + + `stage_inject_jewels` parses corrupted-magic-jewel texts and injects + value-scaled modifiers (`adorned_corrupted_magic_jewel_inc` matches the + two-physical-line wrapped text). Int 135→139 → Mana 770 exact; chaos resist + uncapped 72→81 (capped 75) closes the ChaosMaxHit tail (17008 vs 17007). + Not modelled: sinister/containJewelSocket socket exemptions, `unscalable` + payloads (no corpus source). +- *titan Armour 0.985x = Runeforged base-armour display-line lag* (the #10-era + "shield 1736 vs recomputed 1725" hypothesis was wrong — oracle + `item.armourData.Armour = 1736` exactly, the shield was never the gap). + Per-slot dump vs oracle `ArmourOn`: gloves 96 vs 101, helmet 192 vs + 284, boots 58 vs 100 — three 0.5.4b-buffed Runeforged bases whose item-text + `Armour:` lines lag the base DB (same family as the c705fe4 ES fix; helmet + recompute 169×1.40×1.20=283.9→284 matches oracle exactly). Fix: + `item_rolled_defence` now recomputes **all three** defences from the base DB + when the base is known (vendor Item.lua:1994-1996, incl. `round()`), not + just ES. titan Armour 38960→39546 exact, ES 54.67→55 exact, 5×MaxHit exact; + fleet-wide the per-item `round()` also lands pathfinder Evasion + 0.98x→1.00x and twister DeflectChance 0.97x→1.00x exact. + +Baselines: def 431→437 @5%, 439→445 @10% (the six wolf-pack cells); +off/dot/core-8 unchanged; 18-build per-cell diff shows no cell regressing. +titan TotalEHP 0.92x remains (separate residual, outside #13 scope). + +**#14 — defensive 25-col long-tail triage. ✅ DONE (six clusters closed; +def 25-col 431→444 @5% / 439→444 @10%, core-8 142→144/144 = 100%).** + +First full per-cell triage of the 19 cells outside the 5% band (never done +before). Full table at triage time (`~` = inside 10%, outside 5%; excluded = +wolf-pack ×6 + titan ×1, task #13's lane): + +| build × col | ratio | root cause | vintage | status | +|---|---|---|---|---| +| druid-ember-fusillade PhysDR | 1.06x ~ | armour-DR **integer rounding**: vendor `TakenHit` chain uses `calcs.armourReduction` = `round(armourReductionF)` (CalcDefence.lua:2402, Common.lua round = floor(x+0.5)); PoBR used the fractional variant everywhere. Golden PhysDR is always integer for this reason. | pre-existing (only visible at small DR) | ✅ fixed (699e9e3) | +| ranger-deadeye PhysDR | 1.20x | same | same | ✅ fixed (699e9e3) | +| abyssal-lich Life | 1.05x ~ | **Life→ES pool conversion** never deducted: 0_5-tree "Enhanced Barrier" (node 44299) gained `5% of Maximum Life Converted to Energy Shield` in 0.5.4b tree data; parser produced `LifeConvertToEnergyShield` BASE 5, defence matrix credited the ES side, but the pool-side `(1−conv/100)` (CalcDefence.lua:92) was explicitly deferred and never landed. Oracle: 1511×0.95×1.18 = 1693.83 vs golden 1694 exact. | 0.5.4b (node stats changed on 0_5 tree) | ✅ fixed (8b742d8) | +| abyssal-lich LifeUnres | 1.05x ~ | dependent (reservation is %-based) | — | ✅ same commit | +| essence-drain SpiritUnres | 0.86x (6 vs 7) | **Blasphemy per-curse rounding** drifted in 0.5.4b vendor: per-curse flat now folds into `baseFlat` *before* one efficiency-scaled round (`round(180/1.1)=164`, CalcDefence.lua:229-239); PoBR kept the old per-instance `round(60/1.1)=55×3=165`. Oracle `spiritReservedBreakdown` pins 164. | 0.5.4b (vendor code change) | ✅ fixed (fff5b2e) | +| gemling SpiritUnres | 3.33x (−60 vs −18) | **altQualityStats channel missing**: Gemling's "Advanced Thaumaturgy" (GemlingQuality flag) makes gems apply their alt quality stats (CalcTools.lua:147-152). Mirage Archer (alt `base_reservation_efficiency_+%` ×2 → 62% @q31) and Eternal Rage (alt `base_spirit_reservation_efficiency_+%` ×0.75 → 23%) reservation efficiencies were lost: 60→37, 100→81 (Δ42 = the whole gap). extract-lua gem-quality never transcribed `altQualityStats`. | pre-existing (data channel gap) | ✅ fixed (2896807) | +| smith Armour | 0.76x | **two dead provisioning inputs** (both mods parsed): ① `Multiplier:AllocatedConnectedNotable` — count of allocated tree.lua `applyToArmour=true` notables (12 exist, smith allocates 8 → +200×8 flat; CalcSetup.lua:840-841); the flag was absent from PoBR tree data. ② `StrRequirementsOn` PercentStat stats (CalcPerform.lua:1848-1857) — base-item attribute requirements absent from PoBR data (.dat bundle unavailable) → extended extract-bases vendor channel with `req = {str/dex/int}`. Oracle: Tree:9988 BASE 1600 + Tree:59589 152/120/161. Result 49096.16 vs 49096 exact. **Note**: the old "vendor↔PoBR tree skill mapping deadlock" memory was stale — `applyToArmour` is plain per-node vendor tree data, no mapping needed. | pre-existing | ✅ fixed (22e1b79) | +| smith PhysMaxHit / FireMaxHit / ColdMaxHit / LightMaxHit | 0.91-0.93x ~ | dependent on Armour | — | ✅ same commit (all 1.00x exact) | +| smith TotalEHP | 0.85→0.92x ~ | after Armour fix, residual = **EHP average block used 2 categories instead of 4**: vendor `EffectiveAverageBlockChance = (attack+projectile+spell+spellProjectile)/4` (CalcDefence.lua:1067) with `SpellProjectileBlock = max(spellBlock…, ProjectileBlock)` (:1013). Shield builds with 0 spell block: PoBR 13.65% vs vendor 20.475%. | pre-existing | ✅ fixed (3ab51dc), 99177 vs 99167.69 | +| titan TotalEHP | 0.92x ~ | same block-average root (shared consumption point; cell itself is #13's lane but the generic fix closes it) | pre-existing | ✅ same commit, 58898 vs 58904.30 | + +Remaining after #14: the 6 wolf-pack cells (TotalEHP 0.83x, 4×ele/phys +MaxHit 0.90x, ChaosMaxHit 0.80x) — task #13's territory (per-type taken-mult +~10% uniform gap, see #12 notes). + +Deliberate ceilings (marked in code): pool-conv applies to the whole +Maximum BASE sum (vendor exempts `Extra`; no dual-conversion build +in corpus); `reqMult` for attribute requirements held at 1 (no +reduced-requirements + armour-from-str build in corpus); alt quality stats +consumed only by the reservation-efficiency path so far (accessor is +general; offence-side alt stats wire up when a fixture demands). + +**#15 — last three panel cells. ✅ DONE (off 78→80/80, dot 36→37/37 — +offensive and dot panels now full score alongside def 450/450).** + +1. **gemling CritChance 1.20x → 1.00x (10.30 → 8.55 exact).** Root cause: the + old 75a348e "keep inactive weapon-set nodes allocated for radius-jewel + grants" mechanism was based on a misreading — in vendor, *every* mod on an + `allocMode ≠ 0` node (the node's own stats **and** radius-jewel grants + alike) gets `Condition: WeaponSet` appended (CalcSetup.lua:222-223; the + jewel-source branch :224-227 only fires for allocMode-0 nodes), so grants + landing on inactive-set notables are dead. Oracle `critModList` Tabulate + pins exactly one `7 @ Tree:32763` (INC total 71 = 14+10+7+10+20+10 → + 5 × 1.71 = 8.55). The 75a348e-era claim of 6×+7 matched the *old* golden + (10.30); the 0.5.4b golden re-snap flipped it. Mechanism fully reverted + (build.rs field + xml_build plumbing + collect.rs geometry merge). The same + jewel's Small-node grants (crossbow damage) shrink too → gemling + AvgDamage/TotalDPS 1.04x → 0.97x (still in band, sign flipped). +2. **gemling TotalDotDPS 1.10x → 0.95x (in band).** After the crit fix the + residual decomposes exactly: ignite chance 0.0962 vs oracle 0.098636 + (0.9754) × stack potential 0.2603 vs 0.26691 (0.9752); both scale with the + hit's fire damage, and 0.9754² ≈ 0.951 matches the dot ratio bit-for-bit. + I.e. the dot residual is purely downstream of the pre-existing AvgDamage + 0.97x under-estimate (previously masked by the wrong 6× jewel grant); no + independent dot-side gap. +3. **wolf-pack Speed 1.43x → 1.00x.** Two stacked causes: ① main-skill + selection — Wolf Pack (`Minion`+`Companion`, neither Attack nor Spell) + failed PoBR's is-damage-skill filter, so the designated `mainSocketGroup=4` + yielded nothing and the fallback scan hijacked the main skill to the + Blasphemy group's Temporal Chains (0.7 s cast → Speed 1.43). Vendor's + `socketGroupSkillList` has **no** damage filter — fix: after + `pick_group_main_skill` misses on the *designated* group, fall back to the + `mainActiveSkill`-chosen active gem (`pick_group_chosen_active`; + cross-group scan still damage-only). ② speed bucket — with Wolf Pack as + main (castTime 1 s), PoBR's "untyped skill eats all three speed buckets" + fallback consumed the weapon's `12% reduced Attack Speed` → 0.88. Vendor + mod-matching requires the cfg to carry ModFlag.Attack/Cast for those mods + to apply; untyped skills eat neither → `speed_names_for` now returns only + `SkillSpeed` for non-attack/non-spell skills. Oracle mainOutput pins + Speed = 1, Time = 1, CastRate = 1 (statSetLabel "Minion Info", player + TotalDPS 0). + +18-build per-cell diff after #15: every offensive/dot/defensive cell is a +hit (450/450, 144/144, 80/80, 37/37) — zero regressions by construction. +Panel-mode offensive ratchet re-measured 42/43 → 45/47 (@5%/@10%). ## Tooling @@ -92,3 +649,7 @@ constants (several are unmodeled unique/flask interactions). against the currently vendored PoB2 (run after any vendor bump). - `tools/pob2-oracle/run.sh out.json` — per-build 0.5.4b breakdown (`mainOutput` scalars + `intermediates` / `components` / `conversionTable`). + `enemyMitigation.dealtMods` lists enemy outgoing-Damage scalers (Enfeeble / + Intimidated-style feeds of `EnemyDamageMult`); `ORACLE_DUMP_ITEMS="2,17"` + dumps listed build items' parsed modLines + evaluated modList + armourData + (provenance diffs for jewel-effect scaling / item defence recompute). diff --git a/docs/contributing-mods.md b/docs/contributing-mods.md index a499c6fb..fc5d660e 100644 --- a/docs/contributing-mods.md +++ b/docs/contributing-mods.md @@ -46,8 +46,34 @@ top of the machine-generated `.dat` import. The two files this guide is about: | `special_mods.json` | **hand** | Rust regex + value DSL | add/fix a whole-line special modifier (uniques, keystones, unusual phrasings) | | `mod_parser_rules.json` | **extracted from vendor Lua** | Lua pattern | (rarely) extend the generic grammar — but see the warning in §3 | +> **Where to add a curated `special_mods` entry — use `data/overlay-common/`.** +> `special_mods.json` is loaded in **two layers** and merged by `pobr-gamedata`: +> +> 1. `data/overlay-common/special_mods.json` — **version-independent** curated +> layer. Vendor-semantics fixes that do not change with the game patch live +> here; a new data version directory inherits them for free (no manual copy). +> **This is where new curated entries almost always go.** +> 2. `data//overlay/special_mods.json` — **version-specific** layer, +> merged on top. Only entries that genuinely differ for one game version +> belong here; a same-`id` entry here overrides the common layer, and new ids +> are appended. +> +> Practically: add your entry to `data/overlay-common/special_mods.json` unless +> it is a correction that only applies to a single game version. `regen-all.sh` +> no longer carries `special_mods.json` forward between versions — the common +> layer replaces that manual step (see `docs/version-bump-architecture.md` P1-3). +> +> The same version-independent common layer now also holds the other four +> hand-curated overlay domains — `buff_definitions.json`, `high_precision_mods.json`, +> `local_mods.json`, `vendor_name_aliases.json` (all in `data/overlay-common/`). +> The list domain (`buff_definitions`) merges by `id` like `special_mods`; the +> single-object domains (`high_precision_mods`, `local_mods`) are version-first +> with common fallback — a `data//overlay/.json`, if present, +> overrides the common copy entirely. Add curated edits to the common copy unless +> they are version-specific. + The remaining overlay files are separate domains (base-item overrides, uniques, -gem effects, buff/curse definitions, stat descriptions, …). They follow their +gem effects, curse definitions, stat descriptions, …). They follow their own schemas in `crates/pobr-data` and are out of scope here; the same "add JSON, no Rust" philosophy applies, and `--check` will grow to cover them if they become a common contribution surface. @@ -102,7 +128,9 @@ write them by hand — the extractor fills them. ## 4. `special_mods.json` — where you add a modifier -Each entry is a `SpecialTemplateDef` (schema in `parser_rules.rs`). The parser +Add the entry to `data/overlay-common/special_mods.json` (the version-independent +layer — see §2) unless it is a correction specific to one game version. Each entry +is a `SpecialTemplateDef` (schema in `parser_rules.rs`). The parser matches the **whole line** (case-insensitive, auto-anchored `^…$`) against `pattern` (**Rust regex** — `(\d+)`, alternation, *no* look-around/back-refs), and instantiates the `mods` template using the captures. diff --git a/docs/version-bump-architecture.md b/docs/version-bump-architecture.md new file mode 100644 index 00000000..a2c2fbbe --- /dev/null +++ b/docs/version-bump-architecture.md @@ -0,0 +1,157 @@ +# Why version bumps look like 100k-line changes, and the v0.0.3 plan to fix it + +Status: **all five items delivered on v0.0.3-dev** (2026-07-17). Companion to +`adapting-to-0.5.4b.md` (which tracks the remaining 0.5.4b engine gaps). +Delivery map: P0-1 → `pobr_gamedata::test_pins` + `data//generated/test_pins.json` +(bless: `POBR_BLESS_PINS=1`, wired as regen-all's final step); P0-2 → +`pipeline/diff-vendor-calcs.sh` (sample report: `devs/docs/audits/vendor-delta-ce8bffab.md`, +which retro-identifies Mageblood without parity archaeology); P1-3 → +`data/overlay-common/special_mods.json` (133 entries) with id-override merge in +`GameData::special_mods`; P1-4 → `pipeline/bump-version.sh`; P2-5 → `.gitattributes`. +The acceptance test remains the next real GGG patch (§5). + +## 1. Anatomy of the v0.0.1 → v0.0.2 diff (the evidence) + +The release diff is `672 files, +101,068 / -25,386`. Broken down by what the +lines actually are: + +| Category | Lines | Human-written? | Version-bump related? | +|---|---|---|---| +| `data/*/generated/` (parsed_mods, special_vendor, coverage) | +91.8k / -14.5k | No — `regen-all.sh` output | Yes | +| Golden fixture recapture (18 × `meta.json`) | ±1.8k | No — `recapture_golden.py` output | Yes | +| Web/WASM `build_api` + web frontend | ~+5k | Yes | **No** — unrelated feature work | +| Legacy mod-parser deletion | -5k | Deletion | **No** — unrelated cleanup | +| Overlay curation (`special_mods.json` port, 27 entries + new) | +1.2k | **Yes, manual** | Yes | +| Count-pin / mirror-test repairs (parser_rules counts, coverage baseline float, spectre life, tier tests, precompile PATCH…) | ~dozens of edits scattered across ~10 files | **Yes, manual** | Yes | +| Engine formula adaptation (Mageblood model ~300 lines + 6 parity-fix commits) | ~1–2k | **Yes, manual** | Yes | + +So the honest number is: **the bump itself cost ~2–3k lines of human work, not +10k+**. The 10k+ perception comes from (a) generated artifacts committed to +git inflating every diff, and (b) unrelated feature/cleanup work riding the +same release branch. But the ~2–3k of human work is still real recurring cost, +and it splits into two very different kinds. + +## 2. Root causes + +### 2a. Intrinsic cost — engine formula drift (cannot be architected away) + +PoBR is a Rust port of PoB2's calc engine. When GGG rebalances mechanics +(0.5.4b reworked evasion/armour scaling, ailment magnitude, and PoB2 added +Mageblood legacy modeling), PoB2's community hand-edits its Lua, and PoBR must +hand-port the delta. No architecture eliminates this: **porting cost is +proportional to how much the game patch changes formulas**, and a data-only +patch costs zero here. + +What *is* fixable: today this cost is discovered by **archaeology** — flip the +golden, watch parity drop 96%→82%, then oracle-debug build by build until each +missing mechanic is found (that is how Mageblood was found). The discovery cost +dwarfs the porting cost. It should instead start from a **generated work list**. + +### 2b. Self-inflicted cost — everything else + +1. **Count-pins break mechanically every regen.** Tests pin exact counts and + floats (`real_data_section_counts` 202/682→201/687, coverage baseline + `0.801168`, spectre life 3.0→2.2, precompile PATCH, tier-degradation + version literals). Each data regen breaks them; each repair is a hand edit + with zero information content. +2. **Curated overlay entries are keyed per version-directory.** The 27 + hand-curated `special_mods.json` entries had to be copied + 4.5.0.3.4 → 4.5.4.3 by hand. They are vendor-semantics fixes, not + version-specific data — they should carry forward automatically. +3. **The bump drill is half-scripted.** `regen-all.sh` covers extraction, but + `gen-zh-cn.mjs`, `web pnpm sync-data`, vendor tarball swap + + `.pob2-version.txt`, golden recapture, and pin repairs are manual steps + living in a memory note. +4. **Generated JSON pollutes review.** 91.8k generated lines render in every + PR diff as if they were code. + +## 3. Target cost model (the contract v0.0.3 ships) + +| Patch type | Target human cost | +|---|---| +| Data-only patch (no formula changes) | One command + green CI + one small review. Hours, not days. | +| Balance patch (formula/constant changes) | One command + a generated vendor-delta work list; engine fixes sized by the list, each with its parity ratchet. | +| Major version (new mechanics) | Feature development — out of scope for "bump cost". | + +## 4. v0.0.3 work plan (ranked by leverage) + +### P0-1: Kill the count-pins — snapshot-bless instead of hand-pinned literals + +Replace every exact-count/float assertion tied to data content with a single +blessed snapshot per data version (e.g. +`data//generated/test_pins.json`), regenerated by a `--bless` path that +`regen-all.sh` runs as its last step. Tests compare against the snapshot; +a data regen updates the snapshot in the same commit, and review sees one +generated file change instead of ten hand edits. Assertions that guard +*structure* (schema, non-empty, monotonic ratchets) stay as code; assertions +that guard *counts of current data* move to the snapshot. + +Inventory to migrate (from the 4.5.4.3 drill): `parser_rules +real_data_section_counts`, precompile coverage baseline, precompile PATCH pin, +spectre life expectation, `mod_parser.rs` any-attribute expectation, +tier-degradation version literals, `contract_golden` where data-derived. + +### P0-2: Vendor calc-delta report — turn engine adaptation into a checklist + +`pipeline/diff-vendor-calcs.sh `: clones/checkouts both +vendor pins and emits a triage report: + +- `git diff --stat` + hunks for `Modules/Calc{Offence,Defence,Perform,Setup}.lua`, + `ModParser.lua`, `Modules/Data/` — the files PoBR mirrors. +- Diff of the *extracted* overlays (run `extract-lua` against both pins, diff + the JSON) — new/changed specialModList entries, parser rules, uniques. +- Output lands in `devs/docs/audits/vendor-delta-.md` as the Phase-1 work + list, replacing parity-drop archaeology. + +This is a wrapper around git-diff + existing extract-lua tooling — no new +parsing. The report is read by a human (or agent) to size and order the +engine work *before* flipping the golden. + +### P1-3: Version-independent curated overlay (`data/overlay-common/`) + +Split overlays into two layers merged by `pobr-gamedata` at load: +`data/overlay-common/` (hand-curated, vendor-semantics fixes — the 27 ported +special_mods entries and future ones) applied first, then +`data//overlay/` (version-specific, mostly extractor output) on top. +A new version inherits the curated layer for free; only genuinely +version-specific corrections live in the version dir. Loader change is one +merge step in `pobr-gamedata`; entries that stop matching new data degrade to +warnings (existing soft-degrade convention). + +### P1-4: One-command bump — `pipeline/bump-version.sh` + +Fold the whole drill (memory-note steps → script): +`query-patch-version` → config patch → `download-index` → `pathofexile-dat` → +vendor tarball swap + `.pob2-version.txt` → `regen-all.sh` (already includes +tree-snapshot carry-forward, special-mods, precompile, and after P0-1 the pin +bless) → `gen-zh-cn.mjs` → `web pnpm sync-data` → `recapture_golden.py` → +targeted test gate (`driver.sh versions` + parity + gamedata). Idempotent, +resumable per step (reuse `soft_step`), prints a manual-decision summary at +the end (golden flip is a *decision*, not automated — see +`adapting-to-0.5.4b.md` for why). + +### P2-5: Mark generated files in `.gitattributes` + +`data/**/generated/** linguist-generated -diff merge=ours` (and fixture +`meta.json` recaptures similarly). PRs stop rendering 90k generated lines; +review attention goes to the human-written residue. Three lines. + +### Explicitly NOT doing (YAGNI, revisit only with evidence) + +- **Data-driving formulas/constants out of Rust.** 0.5.4b's changes were + structural (evasion rework, Mageblood modeling), not constant tweaks — a + constants file would not have saved the work, and PoB2 itself hardcodes + these in Lua. Revisit only for a constant that has demonstrably changed + across ≥2 patches. +- **Auto-porting Lua formula code.** Transpiling vendor calc Lua is a research + project; the delta report (P0-2) captures 90% of the value. +- **Not committing generated data.** Runtime/deploy needs it; `-diff` + attributes solve the review noise at zero risk. + +## 5. Sequencing + +P0-1 and P0-2 are independent — do first, in either order or parallel. +P1-3 and P1-4 build on P0-1 (bless step slots into the script). P2-5 anytime. +The next real GGG patch is the acceptance test: run `bump-version.sh`, and the +human diff should be ~zero for the data layer plus a delta-report-sized +engine work list. diff --git a/pipeline/README.md b/pipeline/README.md index 45681a7c..52678517 100644 --- a/pipeline/README.md +++ b/pipeline/README.md @@ -42,9 +42,34 @@ cargo run -p pobr-data-adapter -- --raw ./tables --out ../data --patch `./.cache/`(~113MB bundle 索引)、`./tables/`、`./files/` 均为中间物,**已 gitignore,不入库**。 仓库只保存 `config.json`、脚本、本 README,以及第 3 步产出的 `data//*.json`(最小适配数据)。 +## Vendor calc-delta 报告(`diff-vendor-calcs.sh`) + +版本升级后,用它把「这次补丁改了哪些计算公式 / 数据」变成一份 triage 清单, +取代「翻黄金 → 看 parity 暴跌 → 逐 build 考古」的发现流程。 + +```bash +pipeline/diff-vendor-calcs.sh [--out ] +# 默认输出:devs/docs/audits/vendor-delta-.md +``` + +- 两个 vendor pin 各做一次 shallow git checkout 到 `.cache/vendor-delta//` + (gitignore,命中缓存即跳过;用 git checkout 而非 codeload tarball——headless + 抽取的 `HeadlessWrapper.lua` 引导需要完整工作树,tarball 缺文件会导致 + `modLib.parseMod missing`)。 +- 报告三节:**Calc 模块 diff**(`Modules/Calc*.lua` + `ModParser.lua` 的 diffstat + + 折叠 hunks)、**数据模块 diff**(`Data/` + `Modules/Data*.lua` 只给按改动量排名的 + diffstat)、**抽取产物 diff**(对两个 pin 跑 `extract-lua --what + special-mods|parser-rules|uniques`,对生成 JSON 做条目级 add/remove/change 汇总)。 +- 软降级(沿用 `regen-all.sh` 的 `soft_step` 精神):某个 `--what` 在旧 pin 上因 + 结构不兼容跑失败时,报告注明缺失原因,脚本不中止。 +- 旋钮:`MAX_HUNK_LINES`(单文件 hunk 超此行数只留 diffstat,默认 800)、 + `DATA_TOP`(数据文件排名条数,默认 40)。 + ## 扩展 / 升版 -- 新 PoE2 版本:更新 `config.json` 的 `patch`,重跑三步,`data/` 下生成新版本目录,`diff` 审查。 +- 新 PoE2 版本:**`pipeline/bump-version.sh` 一条命令**(查补丁号 → 下载 → 树/vendor 对齐 → + regen-all(含 test-pin bless)→ 推进 CURRENT/DATA_VERSION → zh-CN/web 同步 → 定向验证), + 末尾打印剩余人工决策(golden 翻转、引擎 delta triage)。分步等价操作见脚本头注释。 - 新数据域:在 `config.json` 的 `tables` 增表/列,并在 `pobr-data-adapter` 增对应适配器。 - **CDN 只保留当前补丁**:GGG patch CDN 会下线旧版本(M1-W0 时 4.5.0.3.4 已 404)。`.cache/` 里已缓存的 bundle 可继续离线导出**既有表的全部列**(整张 `.datc64` 在同一 bundle 里); diff --git a/pipeline/bump-version.sh b/pipeline/bump-version.sh new file mode 100755 index 00000000..7a8fafbb --- /dev/null +++ b/pipeline/bump-version.sh @@ -0,0 +1,176 @@ +#!/usr/bin/env bash +# bump-version.sh —— 游戏数据版本升级一条命令编排(v0.0.3 P1-4,docs/version-bump-architecture.md)。 +# +# 把此前散在 memory/README 里的升级 drill 串成单入口: +# [1] 查询最新补丁号(query-patch-version.mjs),改 pipeline/config.json "patch" +# [2] 下载 .dat 表(download-index.mjs 预热索引 + npx pathofexile-dat) +# [3] 刷新被动树导出(GGG poe2-skilltree-export;官方停更时沿用现有,软失败) +# [4] vendor 对齐(--vendor-sha 时 fetch-by-sha 换检出 + 更新 .pob2-version.txt) +# [5] OLD_PATCH=<旧> regen-all.sh(含末步 test-pin bless) +# [6] 推进版本标记:data/CURRENT + pobr-data DATA_VERSION 常量 +# [7] gen-zh-cn.mjs(读 data/CURRENT)+ web pnpm sync-data +# [8] 定向验证(多版本 smoke + gamedata 套件;parity 仅报告不判失败) +# [9] 摘要 + 剩余人工决策清单 +# +# 刻意保留为人工决策(不自动化): +# - golden 翻转(GOLDEN_PARITY_DATA_VERSION + recapture_golden.py)——是否把 +# parity 基准挪到新版本取决于引擎适配进度,见 docs/adapting-to-0.5.4b.md 的教训; +# - vendor 新 pin 的选取(PoB2 社区哪个 commit 对应新补丁); +# - 引擎公式适配本身(先跑 pipeline/diff-vendor-calcs.sh 拿 delta 清单)。 +# +# 用法: +# pipeline/bump-version.sh # 补丁号自动查询,vendor 不动 +# pipeline/bump-version.sh --patch 4.5.5.1 # 显式补丁号 +# pipeline/bump-version.sh --vendor-sha <全长sha> # 同时换 vendor 检出 +# pipeline/bump-version.sh --skip-download # 表已下好,从 regen 开始 +# +# 各步幂等(下载有缓存、regen 整目录覆写),失败后修好直接重跑即可。 + +set -uo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "${ROOT}" || exit 1 + +NEW_PATCH="" +VENDOR_SHA="" +SKIP_DOWNLOAD=0 +while [[ $# -gt 0 ]]; do + case "$1" in + --patch) NEW_PATCH="$2"; shift 2 ;; + --vendor-sha) VENDOR_SHA="$2"; shift 2 ;; + --skip-download) SKIP_DOWNLOAD=1; shift ;; + *) echo "bump-version: 未知参数 $1" >&2; exit 2 ;; + esac +done + +FAILURES=() +soft_step() { + local label="$1"; shift + echo "---- ${label}" + if ! "$@"; then + FAILURES+=("${label}") + echo " ⚠ 软步骤失败(续跑其余):${label}" >&2 + fi +} +die_on_fail() { "$@" || { echo "bump-version: 关键步骤失败,中止:$*" >&2; exit 1; }; } + +OLD_PATCH="$(sed -n 's/.*"patch"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' pipeline/config.json | head -1)" +[[ -n "${OLD_PATCH}" ]] || { echo "bump-version: 无法从 config.json 读取当前 patch" >&2; exit 1; } + +# ---- [1] 目标补丁号 ---- +echo "== [1/9] 目标补丁号" +if [[ -z "${NEW_PATCH}" ]]; then + NEW_PATCH="$(node pipeline/query-patch-version.mjs | sed -n 's/.*"version": "\([^"]*\)".*/\1/p')" + [[ -n "${NEW_PATCH}" ]] || { echo "bump-version: patch 服务器查询失败,用 --patch 显式指定" >&2; exit 1; } +fi +echo " ${OLD_PATCH} → ${NEW_PATCH}" +if [[ "${NEW_PATCH}" == "${OLD_PATCH}" ]]; then + echo " 已是最新(同版本重放请用 devs/scripts/version-bump-drill.sh)——继续执行属刷新语义" +fi +# 只改 "patch" 一行;config.json 其余(表清单)人工维护。sed -i 的 in-place 语法 +# BSD/GNU 不兼容,统一走 tmp+mv。 +sed_replace() { + local pattern="$1" file="$2" tmp + tmp="$(mktemp)" + sed "${pattern}" "${file}" > "${tmp}" && mv "${tmp}" "${file}" +} +die_on_fail sed_replace "s/\"patch\": \"${OLD_PATCH}\"/\"patch\": \"${NEW_PATCH}\"/" pipeline/config.json + +# ---- [2] .dat 表下载 ---- +echo "== [2/9] GGG .dat 表下载(pipeline/tables/)" +if [[ "${SKIP_DOWNLOAD}" -eq 1 ]]; then + echo " --skip-download:跳过" +else + # CDN 只保留当前补丁(pipeline/README.md)——下载失败通常意味着补丁号过期,重查步骤 1。 + die_on_fail bash -c "cd pipeline && node download-index.mjs" + die_on_fail bash -c "cd pipeline && npx -y pathofexile-dat@15" +fi + +# ---- [3] 被动树导出 ---- +echo "== [3/9] 被动树导出(GGG poe2-skilltree-export)" +# 官方树导出常滞后于补丁(0.5.4b 时仍停在 0.5.2)——拿不到就沿用现有 data.json。 +TREE_URL="https://raw.githubusercontent.com/grindinggear/poe2-skilltree-export/HEAD/data.json" +fetch_tree() { + local tmp; tmp="$(mktemp)" + if curl -fsSL --retry 3 -o "${tmp}" "${TREE_URL}" && [[ -s "${tmp}" ]]; then + if cmp -s "${tmp}" pipeline/tree/data.json; then + echo " 树导出无变化" + else + mv "${tmp}" pipeline/tree/data.json + echo " 树导出已更新" + fi + else + rm -f "${tmp}" + echo " 下载失败——沿用现有 pipeline/tree/data.json(官方导出滞后属常态)" + fi +} +soft_step tree_export fetch_tree + +# ---- [4] vendor 对齐 ---- +echo "== [4/9] PoB2 vendor 对齐" +VENDOR_DIR="vendor/PathOfBuilding-PoE2" +OLD_VENDOR_SHA="$(cat vendor/.pob2-version.txt 2>/dev/null || echo '')" +if [[ -n "${VENDOR_SHA}" ]]; then + [[ "${#VENDOR_SHA}" -eq 40 ]] || { echo "bump-version: --vendor-sha 需全长 40 位(gh api 查,别猜短 sha)" >&2; exit 1; } + swap_vendor() { + mkdir -p "${VENDOR_DIR}" + git -C "${VENDOR_DIR}" rev-parse --git-dir >/dev/null 2>&1 || git -C "${VENDOR_DIR}" init -q + git -C "${VENDOR_DIR}" remote get-url origin >/dev/null 2>&1 \ + || git -C "${VENDOR_DIR}" remote add origin https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2 + git -C "${VENDOR_DIR}" fetch -q --depth 1 origin "${VENDOR_SHA}" \ + && git -C "${VENDOR_DIR}" checkout -q FETCH_HEAD \ + && printf '%s\n' "${VENDOR_SHA}" > vendor/.pob2-version.txt + } + die_on_fail swap_vendor + echo " vendor → ${VENDOR_SHA}" +else + echo " 未指定 --vendor-sha:vendor 保持 ${OLD_VENDOR_SHA:-<未检出>}(overlay 抽取将基于旧 vendor)" +fi + +# ---- [5] 全量重生成(含 test-pin bless 末步)---- +echo "== [5/9] regen-all(OLD_PATCH=${OLD_PATCH})" +die_on_fail env OLD_PATCH="${OLD_PATCH}" pipeline/regen-all.sh + +# ---- [6] 推进活动版本标记 ---- +echo "== [6/9] data/CURRENT + pobr_data::DATA_VERSION" +printf '%s\n' "${NEW_PATCH}" > data/CURRENT +# 只动 DATA_VERSION 一行;GOLDEN_PARITY_DATA_VERSION 是人工决策,绝不自动推进。 +die_on_fail sed_replace \ + "s/^pub const DATA_VERSION: &str = \"${OLD_PATCH}\";/pub const DATA_VERSION: \&str = \"${NEW_PATCH}\";/" \ + crates/pobr-data/src/lib.rs +grep -q "pub const DATA_VERSION: &str = \"${NEW_PATCH}\";" crates/pobr-data/src/lib.rs \ + || { echo "bump-version: DATA_VERSION 常量替换失败(crates/pobr-data/src/lib.rs 格式变了?)" >&2; exit 1; } + +# ---- [7] 衍生数据 ---- +echo "== [7/9] 简中语言包 + web 数据同步" +soft_step gen_zh_cn node pipeline/gen-zh-cn.mjs +if [[ -d web/node_modules ]]; then + soft_step web_sync_data bash -c "cd web && pnpm run sync-data" +else + echo " web/node_modules 缺失——跳过 sync-data(web 下次 pnpm install 后手动跑)" + FAILURES+=("web sync-data 未跑(无 node_modules)") +fi + +# ---- [8] 定向验证(禁全量,见 CLAUDE.md 验证分层)---- +echo "== [8/9] 定向验证" +soft_step smoke_versions bash .claude/skills/run-pobr/driver.sh versions +soft_step gamedata_tests env CARGO_BUILD_RUSTC_WRAPPER="" cargo test --quiet -p pobr-gamedata +# parity 只报告不判失败:golden 仍钉旧版本时本就不应红;红/绿都由人读。 +echo "---- parity(信息性,不计失败)" +env CARGO_BUILD_RUSTC_WRAPPER="" cargo test --quiet -p pobr-build --test parity 2>&1 | tail -5 || true + +# ---- [9] 摘要 ---- +echo "== [9/9] 摘要" +echo "补丁:${OLD_PATCH} → ${NEW_PATCH} vendor:${OLD_VENDOR_SHA:-?} → $(cat vendor/.pob2-version.txt 2>/dev/null || echo '?')" +if [[ ${#FAILURES[@]} -gt 0 ]]; then + echo "软失败步骤(须处理后重跑对应步):" + printf ' - %s\n' "${FAILURES[@]}" +fi +cat <} <新sha> 拿公式 delta 清单; + 3. golden 是否翻到 ${NEW_PATCH}:引擎补齐后跑 examples/demo-bd-test/tools/recapture_golden.py + 并推进 pobr_data::GOLDEN_PARITY_DATA_VERSION(教训见 docs/adapting-to-0.5.4b.md)。 +EOF +[[ ${#FAILURES[@]} -eq 0 ]] diff --git a/pipeline/config.json b/pipeline/config.json index a106617b..36d28cc4 100644 --- a/pipeline/config.json +++ b/pipeline/config.json @@ -11,7 +11,7 @@ { "name": "SkillGems", "columns": ["BaseItemType","GemType","GemColour","MinLevelReq","StrengthRequirementPercent","DexterityRequirementPercent","IntelligenceRequirementPercent","GemEffects","ItemExperienceType"] }, { "name": "GrantedEffects", "columns": ["Id","IsSupport","ActiveSkill","StatSet","CastTime","CostTypes","AllowedActiveSkillTypes","AddedActiveSkillTypes","ExcludedActiveSkillTypes","SupportsGemsOnly","CannotBeSupported","AdditionalStatSets"] }, { "name": "GrantedEffectsPerLevel", "columns": ["GrantedEffect","Level","Cooldown","CostAmounts","AttackTime","CostMultiplier","StoredUses","Reservation","EffectOnPlayer","AttackSpeedMultiplier"] }, - { "name": "GrantedEffectStatSets", "columns": ["Id","BaseEffectiveness","IncrementalEffectiveness","DamageIncrementalEffectiveness","ImplicitStats","ConstantStats","ConstantStatsValues","Label"] }, + { "name": "GrantedEffectStatSets", "columns": ["Id","BaseEffectiveness","IncrementalEffectiveness","DamageIncrementalEffectiveness","ImplicitStats","ConstantStats","ConstantStatsValues","Label","IgnoredStats"] }, { "name": "GrantedEffectStatSetsPerLevel", "columns": ["StatSet","GemLevel","BaseMultiplier","BaseResolvedValues","FloatStats","FloatStatsValues","AdditionalStats","AdditionalStatsValues","SpellCritChance","AttackCritChance"] }, { "name": "ActiveSkills", "columns": ["Id","DisplayedName","Description","ActiveSkillTypes","GrantedEffect"] }, { "name": "ActiveSkillType", "columns": ["Id"] }, diff --git a/pipeline/diff-vendor-calcs.sh b/pipeline/diff-vendor-calcs.sh new file mode 100755 index 00000000..0ac4944f --- /dev/null +++ b/pipeline/diff-vendor-calcs.sh @@ -0,0 +1,287 @@ +#!/usr/bin/env bash +# diff-vendor-calcs.sh — P0-2: vendor calc-delta report. +# +# Compares two PoB2 vendor pins (PathOfBuilding-PoE2 commits) and emits a +# markdown triage list of what a game patch changed in the calc engine and in +# the extracted overlays. Engine adaptation then starts from a checklist, +# instead of "flip the golden, watch parity drop, oracle-debug build by build". +# +# Usage: +# pipeline/diff-vendor-calcs.sh [--out ] +# +# Default output: devs/docs/audits/vendor-delta-.md +# +# Env knobs: +# MAX_HUNK_LINES=800 per-file calc hunk cap; larger diffs collapse to +# numstat only (keeps the report readable). +# DATA_TOP=40 how many data files to rank by churn. +# +# Deps: git, python3, cargo (+ luajit for extract-lua). Each vendor pin is a +# shallow git checkout in .cache/vendor-delta// (gitignored, cache-hit +# skips re-fetch). Soft-steps (regen-all.sh convention): an extract that fails +# on the *old* pin (incompatible Lua structure) is noted and skipped, the report +# still generates. +set -euo pipefail + +VENDOR_REPO="https://github.com/PathOfBuildingCommunity/PathOfBuilding-PoE2.git" +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +CACHE="${ROOT}/.cache/vendor-delta" +HELPER="${ROOT}/pipeline/json_entry_diff.py" +SHIM="${ROOT}/pipeline/lua-shims/lua-utf8.lua" +MAX_HUNK_LINES="${MAX_HUNK_LINES:-800}" +DATA_TOP="${DATA_TOP:-40}" + +# Calc engine files PoBR mirrors: everything Calc* plus the two big non-Calc +# calc files. Data*.lua go in the data section, so exclude them here. +CALC_GLOBS=("Modules/Calc"*.lua "Modules/ModParser.lua") + +SYNC=(cargo run --quiet -p sync-pob-catalog --) +SOFT_FAILURES=() + +usage() { grep -E '^# ' "$0" | sed -E 's/^# ?//'; } + +die() { echo "diff-vendor-calcs: $*" >&2; exit 1; } + +# soft: run cmd; on failure record label and keep going (always returns 0 so +# `set -e` never fires on an expected soft-step failure). +soft() { + local label="$1"; shift + if ! "$@"; then + SOFT_FAILURES+=("${label}") + echo " ⚠ soft-step failed (continuing): ${label}" >&2 + fi + return 0 +} + +# Fetch a pin as a shallow git checkout (driver.sh style). NOT a codeload +# tarball: the headless extractor's HeadlessWrapper.lua bootstrap needs the full +# working tree (e.g. TreeData/*/tree.lua) that codeload strips, so a tarball pin +# yields "modLib.parseMod missing" and the overlay diff can't run. +fetch() { + local sha="$1" + local dir="${CACHE}/${sha}" + if [ -d "${dir}/.git" ] && [ -f "${dir}/src/Modules/ModParser.lua" ]; then + echo " cache hit: ${sha}" >&2 + else + echo " fetching ${sha} (shallow git) ..." >&2 + rm -rf "${dir}"; mkdir -p "${dir}" + git -C "${dir}" init -q + git -C "${dir}" remote add origin "${VENDOR_REPO}" + # The vendor tree carries heavy binary art, so the shallow pack is large and + # flaky over a slow link — retry the transient "early EOF" failures. + local ok=0 attempt + for attempt in 1 2 3; do + if git -C "${dir}" fetch -q --depth 1 origin "${sha}"; then ok=1; break; fi + echo " fetch attempt ${attempt} failed; retrying ..." >&2 + sleep 5 + done + [ "${ok}" -eq 1 ] || die "git fetch failed for ${sha} after 3 attempts (bad sha? network?)" + git -C "${dir}" checkout -q FETCH_HEAD \ + || die "git checkout failed for ${sha}" + fi + # extract-lua's headless bootstrap requires lua-utf8 (C module in vendor); + # drop the tracked pure-Lua shim where PoB expects it (regen-all.sh does this). + local rt="${dir}/runtime/lua" + if [ -d "${rt}" ] && [ ! -f "${rt}/lua-utf8.lua" ] && [ -f "${SHIM}" ]; then + cp "${SHIM}" "${rt}/lua-utf8.lua" + fi +} + +pob_version() { + local mf="${CACHE}/$1/manifest.xml" v="" + [ -f "${mf}" ] && v="$(grep -oE 'Version number="[^"]+"' "${mf}" | head -1 | sed -E 's/.*"([^"]+)".*/\1/')" + echo "${v:-unknown}" +} + +# ---- args ---------------------------------------------------------------- +OLD=""; NEW=""; OUT="" +while [ $# -gt 0 ]; do + case "$1" in + --out) OUT="${2:-}"; shift 2 ;; + -h|--help) usage; exit 0 ;; + -*) die "unknown flag: $1" ;; + *) if [ -z "${OLD}" ]; then OLD="$1"; elif [ -z "${NEW}" ]; then NEW="$1"; else die "unexpected arg: $1"; fi; shift ;; + esac +done +[ -n "${OLD}" ] && [ -n "${NEW}" ] || { usage; exit 2; } +[ -f "${HELPER}" ] || die "missing helper: ${HELPER}" +OUT="${OUT:-${ROOT}/devs/docs/audits/vendor-delta-${NEW:0:8}.md}" + +# ---- fetch both pins ----------------------------------------------------- +echo "== [1/4] fetch vendor pins" +fetch "${OLD}" +fetch "${NEW}" +OLD_SRC="${CACHE}/${OLD}/src" +NEW_SRC="${CACHE}/${NEW}/src" +# extract-lua reads a `.pob2-version.txt` next to the vendor tree for _meta; +# the cache layout has none, so write a per-pin file and pass --version-file. +OLD_VF="${CACHE}/${OLD}/.pob2-version.txt"; printf '%s\n' "${OLD}" > "${OLD_VF}" +NEW_VF="${CACHE}/${NEW}/.pob2-version.txt"; printf '%s\n' "${NEW}" > "${NEW_VF}" +OLD_VER="$(pob_version "${OLD}")" +NEW_VER="$(pob_version "${NEW}")" + +# ---- ensure sync-pob-catalog builds (sccache-safe) ----------------------- +echo "== [2/4] build sync-pob-catalog" +if ! cargo build --quiet -p sync-pob-catalog 2>/dev/null; then + echo " build failed; retrying with rustc wrapper disabled (sccache bypass)" >&2 + export CARGO_BUILD_RUSTC_WRAPPER="" + cargo build --quiet -p sync-pob-catalog || die "sync-pob-catalog build failed" +fi + +# ---- report scaffolding -------------------------------------------------- +mkdir -p "$(dirname "${OUT}")" +: > "${OUT}" +w() { printf '%s\n' "$*" >> "${OUT}"; } + +w "# Vendor calc-delta — ${OLD:0:8} → ${NEW:0:8}" +w "" +w "| | old | new |" +w "|---|---|---|" +w "| commit | \`${OLD}\` | \`${NEW}\` |" +w "| PoB2 version | ${OLD_VER} | ${NEW_VER} |" +w "" +w "Generated by \`pipeline/diff-vendor-calcs.sh ${OLD} ${NEW}\`." +w "This is a Phase-1 engine work list: the calc-file hunks and overlay entry" +w "deltas below are what a hand-port must chase before flipping the parity golden." +w "" + +# ---- 3a. calc module diff ------------------------------------------------ +echo "== [3/4] diff calc modules + data" +w "## Calc module diff" +w "" +w "Files PoBR mirrors: \`Modules/Calc*.lua\` + \`Modules/ModParser.lua\`." +w "Full hunks are in the collapsed blocks; a file whose diff exceeds" +w "\`MAX_HUNK_LINES=${MAX_HUNK_LINES}\` shows only its stat line." +w "" + +# collect the union of calc files across both pins +declare -a CALC_FILES=() +for base in "${OLD_SRC}" "${NEW_SRC}"; do + for g in "${CALC_GLOBS[@]}"; do + for f in "${base}/"${g}; do + [ -e "${f}" ] || continue + CALC_FILES+=("${f#"${base}/"}") + done + done +done +# unique, sorted +mapfile -t CALC_FILES < <(printf '%s\n' "${CALC_FILES[@]}" | sort -u) + +w "| file | +added | -removed |" +w "|---|---:|---:|" +declare -a CALC_CHANGED=() +for rel in "${CALC_FILES[@]}"; do + a="${OLD_SRC}/${rel}"; b="${NEW_SRC}/${rel}" + [ -f "${a}" ] || a=/dev/null + [ -f "${b}" ] || b=/dev/null + ns="$(git diff --no-index --numstat "${a}" "${b}" 2>/dev/null || true)" + [ -n "${ns}" ] || continue + add="$(printf '%s' "${ns}" | awk '{print $1}')" + del="$(printf '%s' "${ns}" | awk '{print $2}')" + w "| \`${rel}\` | ${add} | ${del} |" + CALC_CHANGED+=("${rel}") +done +[ ${#CALC_CHANGED[@]} -gt 0 ] || w "| _(no calc files changed)_ | | |" +w "" + +for rel in "${CALC_CHANGED[@]}"; do + a="${OLD_SRC}/${rel}"; b="${NEW_SRC}/${rel}" + [ -f "${a}" ] || a=/dev/null + [ -f "${b}" ] || b=/dev/null + patch="$(git diff --no-index -- "${a}" "${b}" 2>/dev/null || true)" + n="$(printf '%s\n' "${patch}" | wc -l | tr -d ' ')" + w "
${rel} (${n} diff lines)" + w "" + if [ "${n}" -gt "${MAX_HUNK_LINES}" ]; then + w "_Hunks omitted (${n} lines > MAX_HUNK_LINES=${MAX_HUNK_LINES}). Re-run with a higher MAX_HUNK_LINES to inline._" + else + w '```diff' + printf '%s\n' "${patch}" >> "${OUT}" + w '```' + fi + w "" + w "
" + w "" +done + +# ---- 3b. data module diff (stat + churn ranking only) -------------------- +w "## Data module diff" +w "" +w "\`src/Data/\` + \`src/Modules/Data*.lua\` — data tables; ranked by churn, no hunks." +w "" +# numstat over the two Data trees; Modules/Data* handled by a second pass. +data_numstat() { + git diff --no-index --numstat "${OLD_SRC}/Data" "${NEW_SRC}/Data" 2>/dev/null || true + for base in "${OLD_SRC}" "${NEW_SRC}"; do + for f in "${base}/Modules/Data"*.lua; do + [ -e "${f}" ] || continue + rel="${f#"${base}/"}" + a="${OLD_SRC}/${rel}"; b="${NEW_SRC}/${rel}" + [ -f "${a}" ] || a=/dev/null + [ -f "${b}" ] || b=/dev/null + git diff --no-index --numstat "${a}" "${b}" 2>/dev/null || true + done + done +} +w "| file | +added | -removed | churn |" +w "|---|---:|---:|---:|" +rows="$(data_numstat | awk 'NF>=3 && ($1+0>0 || $2+0>0){ch=$1+$2; path=$3; for(i=4;i<=NF;i++)path=path" "$i; print ch"\t"$1"\t"$2"\t"path}' | sort -rn | head -n "${DATA_TOP}")" +if [ -n "${rows}" ]; then + # strip the codeload cache prefix from paths for readability + printf '%s\n' "${rows}" | while IFS=$'\t' read -r ch add del path; do + # collapse git's `{old => new}` rename braces first, then strip the cache + # prefix so only the vendor-relative path (Data/...) remains. + rel="$(printf '%s' "${path}" | sed -E "s#\{[^}]*=> ([^}]*)\}#\1#g; s#.*/${NEW}/src/##; s#.*/${OLD}/src/##")" + w "| \`${rel}\` | ${add} | ${del} | ${ch} |" + done +else + w "| _(no data files changed)_ | | | |" +fi +w "" + +# ---- 4. extracted overlay diff ------------------------------------------- +echo "== [4/4] diff extracted overlays" +w "## Extracted overlay diff" +w "" +w "\`extract-lua\` run against both pins; entry-level add/remove/change per collection." +w "A section missing below means extraction failed on the *old* pin (incompatible" +w "Lua structure) — see the soft-step summary at the end." +w "" +TMP="$(mktemp -d)" +trap 'rm -rf "${TMP}"' EXIT + +extract_diff() { + local what="$1" + local o="${TMP}/${what}-old.json" n="${TMP}/${what}-new.json" + w "### \`--what ${what}\`" + w "" + local ok_old=1 ok_new=1 + "${SYNC[@]}" extract-lua --what "${what}" --vendor-root "${OLD_SRC}" --version-file "${OLD_VF}" --out "${o}" >/dev/null 2>&1 || ok_old=0 + "${SYNC[@]}" extract-lua --what "${what}" --vendor-root "${NEW_SRC}" --version-file "${NEW_VF}" --out "${n}" >/dev/null 2>&1 || ok_new=0 + if [ "${ok_old}" -eq 0 ] || [ "${ok_new}" -eq 0 ]; then + local which="old=${ok_old} new=${ok_new}" + SOFT_FAILURES+=("extract ${what} (${which})") + w "_Skipped — extraction failed (${which}, 1=ok 0=fail). Old-pin failures are" + w "expected when the vendor Lua structure changed across the bump._" + w "" + return 0 + fi + python3 "${HELPER}" "${o}" "${n}" >> "${OUT}" || SOFT_FAILURES+=("diff ${what}") + w "" +} + +for what in special-mods parser-rules uniques; do + extract_diff "${what}" +done + +# ---- soft-step summary --------------------------------------------------- +w "## Soft-step summary" +w "" +if [ ${#SOFT_FAILURES[@]} -eq 0 ]; then + w "All steps succeeded." +else + for f in "${SOFT_FAILURES[@]}"; do w "- ⚠ ${f}"; done +fi +w "" + +echo "report written: ${OUT}" diff --git a/pipeline/json_entry_diff.py b/pipeline/json_entry_diff.py new file mode 100755 index 00000000..e0ca97bc --- /dev/null +++ b/pipeline/json_entry_diff.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 +"""Entity-level diff of two extract-lua JSON outputs, for the vendor-delta report. + +Every top-level list (except `_meta`) is treated as an entry collection; the +diff reports added / removed / changed entries *by identity*, so a game patch's +overlay churn reads as "these rules/uniques/special-mods moved", not a wall of +JSON line hunks. Emits markdown to stdout. + +Usage: json_entry_diff.py + json_entry_diff.py --selftest +""" +import hashlib +import json +import sys + +# Identity key priority — first present string/int field names the entry. +# Covers the shapes we diff: special_vendor(`id`), uniques(`name`), +# parser-rules forms(`pattern`)/name_map(`phrase`)/... +ID_KEYS = ["id", "name", "phrase", "pattern", "key", "text", "stat", "line", "raw"] +NAME_CAP = 40 # ponytail: cap listed names; raise if a section needs the full set + + +def identity(entry): + if isinstance(entry, dict): + for k in ID_KEYS: + v = entry.get(k) + if isinstance(v, (str, int)): + return str(v) + return "hash:" + hashlib.sha1(json.dumps(entry, sort_keys=True).encode()).hexdigest()[:12] + return str(entry) + + +def canon(entry): + return json.dumps(entry, sort_keys=True) + + +def collections(doc): + """Top-level lists keyed by name; a bare list doc becomes `(root)`.""" + if isinstance(doc, list): + return {"(root)": doc} + if isinstance(doc, dict): + return {k: v for k, v in doc.items() if k != "_meta" and isinstance(v, list)} + return {} + + +def diff_list(old, new): + om, nm = {}, {} + for e in old: + om.setdefault(identity(e), e) + for e in new: + nm.setdefault(identity(e), e) + added = sorted(k for k in nm if k not in om) + removed = sorted(k for k in om if k not in nm) + changed = sorted(k for k in nm if k in om and canon(nm[k]) != canon(om[k])) + return added, removed, changed + + +def fmt(names): + shown = names[:NAME_CAP] + more = len(names) - len(shown) + s = ", ".join("`%s`" % n for n in shown) + if more > 0: + s += f" … (+{more} more)" + return s + + +def render(old, new): + oc, nc = collections(old), collections(new) + lines = [] + for k in sorted(set(oc) | set(nc)): + a, r, c = diff_list(oc.get(k, []), nc.get(k, [])) + if not (a or r or c): + continue + lines.append(f"**`{k}`** — +{len(a)} added, -{len(r)} removed, ~{len(c)} changed") + if a: + lines.append(f"- added: {fmt(a)}") + if r: + lines.append(f"- removed: {fmt(r)}") + if c: + lines.append(f"- changed: {fmt(c)}") + lines.append("") + return "\n".join(lines) if lines else "_No entry-level changes._" + + +def selftest(): + old = {"_meta": {"vendor_commit": "aaa"}, "forms": [ + {"pattern": "keep", "form": "BASE"}, + {"pattern": "gone", "form": "INC"}, + {"pattern": "edit", "form": "BASE"}, + ]} + new = {"_meta": {"vendor_commit": "bbb"}, "forms": [ + {"pattern": "keep", "form": "BASE"}, + {"pattern": "edit", "form": "MORE"}, # changed + {"pattern": "fresh", "form": "BASE"}, # added + ]} + a, r, c = diff_list(old["forms"], new["forms"]) + assert a == ["fresh"], a + assert r == ["gone"], r + assert c == ["edit"], c + # _meta churn must not register as a change. + assert "No entry-level changes" not in render(old, new) + assert render({"_meta": {"x": 1}}, {"_meta": {"x": 2}}) == "_No entry-level changes._" + print("selftest OK") + + +def main(): + if len(sys.argv) >= 2 and sys.argv[1] == "--selftest": + return selftest() + if len(sys.argv) != 3: + sys.exit("usage: json_entry_diff.py | --selftest") + with open(sys.argv[1]) as f: + old = json.load(f) + with open(sys.argv[2]) as f: + new = json.load(f) + print(render(old, new)) + + +if __name__ == "__main__": + main() diff --git a/pipeline/regen-all.sh b/pipeline/regen-all.sh index f2775396..72ceb2b7 100755 --- a/pipeline/regen-all.sh +++ b/pipeline/regen-all.sh @@ -15,9 +15,11 @@ # pipeline/regen-all.sh # patch 读 config.json;手工域从同 patch 旧产物沿用 # OLD_PATCH=4.5.0.3.4 pipeline/regen-all.sh # 手工域从指定旧版本沿用(跨版本升级) # -# 手工策展 overlay(无 vendor/官方自动通道):buff_definitions / high_precision_mods / -# local_mods / special_mods / vendor_name_aliases —— 跨版本升级时从 OLD_PATCH 沿用, -# 并需人工复核(游戏平衡变更可能使其过时)。 +# 手工策展 overlay(无 vendor/官方自动通道)全部已迁到版本无关的 +# data/overlay-common/(special_mods / buff_definitions / high_precision_mods / +# local_mods / vendor_name_aliases):新版本目录由 gamedata 加载期自动合并/兜底 +# 继承,无需逐版本沿用(P1-3)。真正版本特有的修正才放 data//overlay/<域>.json +# (加载期按 id 覆盖 common,或对单对象域整份覆盖)。 # 韧性化:不用 -e 全局中止。前置步骤(adapter base/tree)失败仍立即退出(无 base # 数据则后续无意义);overlay 单步失败只记录、续跑其余,末尾汇总。 @@ -122,17 +124,10 @@ soft_step trigger_configs "${SYNC[@]}" gen-trigger-configs --vendor-root "$VENDO # stat_id_map(M6 E/F 段 B)须在 stat_descriptions + mod_parser_rules 之后——消费两者跑引擎派生。 soft_step stat_id_map "${SYNC[@]}" gen-stat-id-map --overlay-dir "$OVL" --out "$OVL/stat_id_map.json" -# ---- 6) 手工策展 overlay:从 OLD_PATCH 沿用(需人工复核)---- -echo "== [6/8] 手工策展 overlay 从 $OLD_PATCH 沿用" -for f in buff_definitions high_precision_mods local_mods special_mods vendor_name_aliases; do - src="data/$OLD_PATCH/overlay/$f.json" - if [[ -f "$src" ]]; then - cp "$src" "$OVL/$f.json" - echo " carried over: $f.json(人工域,复核游戏平衡变更)" - else - echo " WARN: 缺 ${src},跳过 $f.json" >&2 - fi -done +# ---- 6) 手工策展 overlay:全部迁至 data/overlay-common/,无逐版本沿用 ---- +# special_mods / buff_definitions / high_precision_mods / local_mods / +# vendor_name_aliases 均在 data/overlay-common/,gamedata 加载期合并/兜底继承(P1-3)。 +# 版本特有修正才落 data//overlay/<域>.json。此步已无沿用动作。 # ---- 6b) 手工策展 base 文件:管线不产出,从 OLD_PATCH 沿用(需人工复核版本变更)---- # 这些是 git 跟踪、无生成器的游戏常量/定义(武器类型、game/character constants、 @@ -169,9 +164,10 @@ if [[ ${#OVERLAY_FAILURES[@]} -gt 0 ]]; then fi # ---- 6c) vendor specialModList 批量抽取 (generated/special_vendor.json) ---- -# 必须在 special_derived (步骤 4) 与 special_mods 沿用 (步骤 6) 之后:抽取器对这 -# 两个文件做 key 去重。注意去重读的是 pobr_data::data_version() 指向的数据目录, -# 不是 $PATCH——升级 drill 中先把 DATA_VERSION 常量推进到 $PATCH 再跑本脚本。 +# 必须在 special_derived (步骤 4) 之后:抽取器对 special_mods(overlay-common + +# 版本 overlay 两层)/ special_derived 做 key 去重。注意去重读的是 +# pobr_data::data_version() 指向的数据目录(含其同级 overlay-common),不是 $PATCH—— +# 升级 drill 中先把 DATA_VERSION 常量推进到 $PATCH 再跑本脚本。 # 4.5.4.3 升级曾漏掉这一步 (special_vendor 为 0 条);precompile-mods --check 现在 # 会对缺失报错。 echo "== [6c] extract-lua --what special-mods (generated/special_vendor.json)" @@ -179,15 +175,28 @@ mkdir -p "$OUT_DIR/generated" soft_step special_vendor "${SYNC[@]}" extract-lua --what special-mods --vendor-root "$VENDOR" --out "$OUT_DIR/generated/special_vendor.json" # ---- 7) generated/(precompile-mods)---- -echo "== [7/8] precompile-mods(generated/)" +echo "== [7/9] precompile-mods(generated/)" soft_step precompile_mods cargo run --quiet -p precompile-mods -- --data "$OUT_DIR" --report # ---- 8) manifest.json:以 OLD_PATCH 结构为模板,仅换版本号 ---- -echo "== [8/8] manifest.json" +echo "== [8/9] manifest.json" if [[ -f "data/$OLD_PATCH/manifest.json" ]]; then - sed "s/\"$OLD_PATCH\"/\"$PATCH\"/g" "data/$OLD_PATCH/manifest.json" > "$OUT_DIR/manifest.json" + sed "s/\"${OLD_PATCH}\"/\"${PATCH}\"/g" "data/${OLD_PATCH}/manifest.json" > "${OUT_DIR}/manifest.json" fi +# ---- 9) test-pin 快照 bless(generated/test_pins.json,v0.0.3 P0-1)---- +# 数据内容计数钉(parser 规则段计数 / minion 系数等)不再手写在测试里,而是存 +# 每版本一份的 generated/test_pins.json;这里以 POBR_BLESS_PINS=1 重跑对应定向 +# 测试把实际值写回快照(与 regen 同一提交)。注意: +# - 快照落在各测试**实际加载**的版本目录(golden 测试 = +# pobr_data::GOLDEN_PARITY_DATA_VERSION)——升级 drill 中 golden 尚未切换时, +# 刷新的是旧 golden 目录,属预期; +# - 必须用 cargo test(单进程多线程,写回有进程内锁),勿换 nextest +# (进程/测试并发写同一快照会互相覆盖)。 +echo "== [9/9] test-pin bless(generated/test_pins.json)" +soft_step pin_parser_rules env POBR_BLESS_PINS=1 cargo test --quiet -p pobr-gamedata --lib parser_rules +soft_step pin_minions env POBR_BLESS_PINS=1 cargo test --quiet -p pobr-build --test skills minions::build_data_minion_def + # ---- 汇总 ---- echo "regen-all: 完成 → $OUT_DIR" if [[ ${#OVERLAY_FAILURES[@]} -gt 0 ]]; then diff --git a/tools/pob2-oracle/oracle.lua b/tools/pob2-oracle/oracle.lua index f670769a..3cc5e345 100644 --- a/tools/pob2-oracle/oracle.lua +++ b/tools/pob2-oracle/oracle.lua @@ -426,6 +426,16 @@ local intermediates = {} -- Global increased/more damage intermediates.IncDamage = smlSum("INC", skillCfg, "Damage") intermediates.MoreDamage = smlMore(skillCfg, "Damage") +-- DistanceRamp probe: the cfg distance the engine evaluated ramp tags against. +intermediates.SkillDist = skillCfg and skillCfg.skillDist or nil +if skillCfg then + local copyTable = copyTable + for _, dist in ipairs({ 5, 20, 30, 40 }) do + local probe = copyTable(skillCfg, true) + probe.skillDist = dist + intermediates["MoreDamage_at" .. dist] = smlMore(probe, "Damage") + end +end -- Damaging-ailment magnitude breakdown (the `MagnitudeEffect` factor = -- calcLib.mod(skillModList, dotCfg, "AilmentMagnitude"), CalcOffence.lua:5145). @@ -569,6 +579,26 @@ if enemyDB then end end enemyMitigation.resistMods = resistMods + -- Per-mod source dump of enemy outgoing-Damage scalers (Enfeeble-style + -- "enemies deal less damage" curses feeding EnemyDamageMult). + local dealtMods = {} + for _, mt in ipairs({ "INC", "MORE" }) do + local okDmg, dmgTable = pcall(function() + return enemyDB:Tabulate(mt, nil, "Damage", "PhysicalDamage", "FireDamage", + "ColdDamage", "LightningDamage", "ChaosDamage", "ElementalDamage") + end) + if okDmg and dmgTable then + for _, entry in ipairs(dmgTable) do + dealtMods[#dealtMods + 1] = { + modType = mt, + name = entry.mod.name, + value = entry.value, + source = entry.mod.source, + } + end + end + end + enemyMitigation.dealtMods = dealtMods -- Exposure effect composition (vendor CalcPerform.lua:3222-3227): global modDB -- INC + per-active-skill skill-scoped INC, plus extra exposure BASE. local pdb = mainEnv.player.modDB @@ -709,6 +739,23 @@ for _, name in ipairs({ "CritMultiplier", "CritChance" }) do end end +-- Ad-hoc stat tabulation: ORACLE_EXTRA_STATS="CooldownRecovery,Speed" dumps the +-- per-source mod list for any vendor stat names (same shape as critModList), +-- keyed under extraModList. Zero cost when the env var is unset. +local extraModList +do + local names = os.getenv("ORACLE_EXTRA_STATS") + if names and #names > 0 then + extraModList = { INC = {}, MORE = {}, BASE = {}, OVERRIDE = {} } + for name in names:gmatch("[^,%s]+") do + for _, mt in ipairs({ "BASE", "INC", "MORE", "OVERRIDE" }) do + local list = tabulateModList(mt, name) + if #list > 0 then extraModList[mt][name] = list end + end + end + end +end + -- Aggregate cross-check: Sum/More over the same names PoBR uses, so the JSON -- carries the authoritative PoB2 totals alongside the per-mod breakdown. local damageAgg = { @@ -754,6 +801,19 @@ if mainSkill then if vv then skillInfo.skillFlags[k] = true end end end + -- Selected statSet (multi-set gems like Essence Drain: [1]=Projectile, + -- [2]=Damage over Time) — which set drives the main output. + if ae and ae.statSet then + skillInfo.statSetIndex = ae.statSet.index + if ae.statSet.statSet then + skillInfo.statSetLabel = ae.statSet.statSet.label + end + end + if mainSkill.skillData then + skillInfo.chaosMin = mainSkill.skillData.ChaosMin + skillInfo.chaosMax = mainSkill.skillData.ChaosMax + skillInfo.chaosDot = mainSkill.skillData.ChaosDot + end -- skillData.dpsMultiplier (post calcLib.mod "DPS" fold, CalcOffence.lua:3863) for -- the W-C4 dps end-factor parity checks. if mainSkill.skillData then @@ -932,7 +992,7 @@ end local defenceModList = {} do local pdb = mainEnv.player.modDB - for _, name in ipairs({ "Armour", "Evasion", "ArmourAndEvasion", "Defences", "EnergyShield" }) do + for _, name in ipairs({ "Armour", "Evasion", "ArmourAndEvasion", "Defences", "EnergyShield", "DeflectionRating", "EvasionGainAsDeflection", "ArmourGainAsDeflection", "DeflectEffect", "ArmourAppliesToFireDamageTaken", "ArmourAppliesToColdDamageTaken", "ArmourAppliesToLightningDamageTaken", "ArmourAppliesToChaosDamageTaken", "ArmourAppliesToElementalDamageTaken", "EvasionAppliesToFireDamageTaken", "EvasionAppliesToColdDamageTaken", "EvasionAppliesToLightningDamageTaken", "EnergyShieldAppliesToFireDamageTaken", "EnergyShieldAppliesToColdDamageTaken", "EnergyShieldAppliesToLightningDamageTaken" }) do for _, mtype in ipairs({ "BASE", "INC", "MORE" }) do pcall(function() for _, m in ipairs(pdb:Tabulate(mtype, nil, name)) do @@ -968,10 +1028,46 @@ do end end +-- Ad-hoc item mod dump: ORACLE_DUMP_ITEMS="18,19,21" dumps each listed build +-- item's parsed modLines + evaluated modList (post-range) for provenance diffs. +local itemDump +do + local ids = os.getenv("ORACLE_DUMP_ITEMS") + if ids and #ids > 0 then + itemDump = {} + for idStr in ids:gmatch("[^,%s]+") do + local id = tonumber(idStr) + local item = build.itemsTab.items[id] + if item then + local lines = {} + for _, ml in ipairs(item.explicitModLines or {}) do + lines[#lines + 1] = { line = ml.line, range = ml.range } + end + for _, ml in ipairs(item.enchantModLines or {}) do + lines[#lines + 1] = { line = ml.line, range = ml.range, enchant = true } + end + for _, ml in ipairs(item.implicitModLines or {}) do + lines[#lines + 1] = { line = ml.line, range = ml.range, implicit = true } + end + local mods = {} + if item.modList then + for _, m in ipairs(item.modList) do + mods[#mods + 1] = { name = m.name, type = m.type, value = type(m.value) ~= "table" and m.value or nil } + end + end + itemDump[tostring(id)] = { title = item.title, baseName = item.baseName, lines = lines, mods = mods, + armourData = item.armourData, quality = item.quality, + baseArmour = item.base and item.base.armour or nil } + end + end + end +end + ---------------------------------------------------------------------- -- Assemble report ---------------------------------------------------------------------- local report = { + itemDump = itemDump, spiritReservations = spiritReservations, spiritReservedBreakdown = spiritReservedBreakdown, defenceModList = defenceModList, @@ -990,6 +1086,7 @@ local report = { intermediates = intermediates, damageModList = damageModList, critModList = critModList, + extraModList = extraModList, damageAgg = damageAgg, components = components, summedBase = summedBase, diff --git a/tools/pobr-data-adapter/src/main.rs b/tools/pobr-data-adapter/src/main.rs index e2673494..ed579def 100644 --- a/tools/pobr-data-adapter/src/main.rs +++ b/tools/pobr-data-adapter/src/main.rs @@ -432,6 +432,9 @@ fn run(args: Args) -> Result { } bases.push(BaseItemDef { + req_str: 0, + req_dex: 0, + req_int: 0, id: raw.id, name: raw.name, item_class, diff --git a/tools/pobr-data-adapter/src/required_columns.rs b/tools/pobr-data-adapter/src/required_columns.rs index 1d3870bc..886a9435 100644 --- a/tools/pobr-data-adapter/src/required_columns.rs +++ b/tools/pobr-data-adapter/src/required_columns.rs @@ -141,6 +141,9 @@ const REQUIRED_EN: &[(&str, &[&str])] = &[ "BaseEffectiveness", "ConstantStats", "ConstantStatsValues", + // (存量 #7-2)社区 schema 名 IgnoredStats = vendor RemoveStats: + // DoT 变体 set 移除主 set 击中伤害 stat(缺列 → 不移除,幻影击中回归)。 + "IgnoredStats", ], ), ( diff --git a/tools/pobr-data-adapter/src/skills/stat_sets.rs b/tools/pobr-data-adapter/src/skills/stat_sets.rs index fbb2f5fc..fe0ca805 100644 --- a/tools/pobr-data-adapter/src/skills/stat_sets.rs +++ b/tools/pobr-data-adapter/src/skills/stat_sets.rs @@ -41,6 +41,14 @@ struct RawStatSet { constant_stats: Vec, #[serde(rename = "ConstantStatsValues", default)] constant_stats_values: Vec, + /// (存量 #7-2)本 set 要**移除**的 stat(`Stats` 行索引)——社区 schema 列名 + /// `IgnoredStats` = vendor `Export/spec.lua` 的 `RemoveStats`。vendor 导出 + /// (`Export/Scripts/skills.lua:572-597`)把合并行里这些 stat 的值置 0(只置 + /// **首次出现**,即 base-merge 拼入的主 set 副本)。典型 = Essence Drain 的 + /// DoT set 移除主 set 的 `spell_min/max_base_chaos_damage`(纯 DoT 无击中)。 + /// 列缺失(旧表下载)→ 空 = 不移除(韧性降级,与既有缺列口径一致)。 + #[serde(rename = "IgnoredStats", default)] + ignored_stats: Vec, } #[derive(Deserialize)] @@ -250,6 +258,21 @@ pub fn adapt_stat_sets(en: &Path) -> Result { let raw_multiplier = |row: &RawStatSetPerLevel| { 1.0 + f64::from(row.base_multiplier.unwrap_or(0) as i32) / 10000.0 }; + // (存量 #7-2)RemoveStats/IgnoredStats 置零(vendor skills.lua:589-596): + // 对 set 声明移除的每个 stat,把行内**首次出现**的值置 0(合并行中先出现的 + // 是 base-merge 拼入的主 set 副本),其余出现保留。 + // ponytail: 同一 stat 在 IgnoredStats 重复出现时 vendor 会置零多个占位—— + // 当前数据无此形态,重复项按单次处理。 + let apply_ignored = |stats: &mut Vec, ignored: &[usize]| { + for &idx in ignored { + let Some(sid) = stat_id.get(idx).filter(|s| !s.is_empty()) else { + continue; + }; + if let Some(slot) = stats.iter_mut().find(|s| &s.stat == sid) { + slot.value = 0.0; + } + } + }; let mut out = Vec::new(); let mut damage_levels_total = 0usize; @@ -273,7 +296,8 @@ pub fn adapt_stat_sets(en: &Path) -> Result { let Some(gem_level) = row.gem_level.filter(|&l| l > 0).map(|l| l as u32) else { continue; }; - let stats = resolve_row_stats(row); + let mut stats = resolve_row_stats(row); + apply_ignored(&mut stats, &main_set.ignored_stats); let damage_multiplier = raw_multiplier(row); // 收录有 stat 或有非平凡倍率的等级行。 if !stats.is_empty() || (damage_multiplier - 1.0).abs() > f64::EPSILON { @@ -333,6 +357,9 @@ pub fn adapt_stat_sets(en: &Path) -> Result { let paired = main_rows.get(indx); let mut stats = paired.map(|p| resolve_row_stats(p)).unwrap_or_default(); stats.extend(resolve_row_stats(row)); + // 本 set 的 RemoveStats 作用于**合并后**的行(vendor 先 tableConcat + // 再置零):Essence Drain DoT set 置零主 set 拼入的 62/115 击中段。 + apply_ignored(&mut stats, &add_set.ignored_stats); // 倍率:本行 BaseMultiplier ≠ 0 取本行(:533-541 两分支终值同为本行 // `/10000+1`;UseSetAttackMulti 列未下载),否则回退主配对行。 let damage_multiplier = if row.base_multiplier.unwrap_or(0) != 0 { diff --git a/tools/pobr-data-adapter/src/tree.rs b/tools/pobr-data-adapter/src/tree.rs index a264ee49..005d939e 100644 --- a/tools/pobr-data-adapter/src/tree.rs +++ b/tools/pobr-data-adapter/src/tree.rs @@ -152,6 +152,7 @@ pub fn run(args: TreeArgs) -> Result { // isSwitchable 变体由独立的 `--tree-variants ` 步骤回填 // (GGG data.json 不携带 options 变体)。 variants: Vec::new(), + apply_to_armour: false, }); } nodes.sort_by_key(|n| n.skill); diff --git a/tools/pobr-data-adapter/src/tree_anoints.rs b/tools/pobr-data-adapter/src/tree_anoints.rs index 59b9d098..9a896653 100644 --- a/tools/pobr-data-adapter/src/tree_anoints.rs +++ b/tools/pobr-data-adapter/src/tree_anoints.rs @@ -106,6 +106,7 @@ fn parse_missing_notables( connections: Vec::new(), ascendancy_id: None, variants: Vec::new(), + apply_to_armour: false, }); } if out.is_empty() { diff --git a/tools/pobr-data-adapter/src/tree_coords.rs b/tools/pobr-data-adapter/src/tree_coords.rs index bf093d46..861da27a 100644 --- a/tools/pobr-data-adapter/src/tree_coords.rs +++ b/tools/pobr-data-adapter/src/tree_coords.rs @@ -37,6 +37,9 @@ struct NodeOrbit { group: u32, orbit: u32, orbit_index: u32, + /// vendor `applyToArmour=true`(Smith of Kitava 身甲连接 notable 标记, + /// 同一 nodes 块顶层字段,顺路抽取回填 `PassiveNodeDef::apply_to_armour`)。 + apply_to_armour: bool, } /// 从 vendor `tree.lua` 解析出的布局常量、group 坐标与节点 orbit 槽位。 @@ -98,6 +101,11 @@ pub fn run(args: TreeCoordsArgs) -> Result { let mut missing = 0usize; let mut off_graph = 0usize; for node in &mut nodes { + // applyToArmour(Smith 身甲连接 notable)与坐标同源顺路回填(图外与否无关)。 + node.apply_to_armour = layout + .node_orbits + .get(&node.skill) + .is_some_and(|no| no.apply_to_armour); if !on_graph(node) { node.x = None; node.y = None; @@ -347,6 +355,7 @@ fn parse_node_orbits(block: &str) -> BTreeMap { group, orbit, orbit_index, + apply_to_armour: top.contains("applyToArmour=true"), }, ); } @@ -491,6 +500,7 @@ mod tests { group: 813, orbit: 0, orbit_index: 0, + apply_to_armour: false, }, ); let layout = TreeLayout { diff --git a/tools/pobr-data-adapter/src/tree_versions.rs b/tools/pobr-data-adapter/src/tree_versions.rs index a932bcf2..1bab70ce 100644 --- a/tools/pobr-data-adapter/src/tree_versions.rs +++ b/tools/pobr-data-adapter/src/tree_versions.rs @@ -103,6 +103,7 @@ fn parse_all_nodes(lua: &str) -> Result, String> { // `is_some()` 判「属于飞升」,语义等价。 ascendancy_id: string_field(node_block, "ascendancyName="), variants: Vec::new(), + apply_to_armour: false, }); } if out.is_empty() { diff --git a/tools/precompile-mods/src/check.rs b/tools/precompile-mods/src/check.rs index 5f5e0ede..58c10f6d 100644 --- a/tools/precompile-mods/src/check.rs +++ b/tools/precompile-mods/src/check.rs @@ -46,13 +46,21 @@ pub fn check(data_dir: &Path) -> Result<(), String> { None }; - // 2) special_mods.json (hand-curated) + generated/special_derived.json — - // both optional; generated/special_vendor.json — required (the 4.5.4.3 - // upgrade shipped without it because regen-all.sh lacked the step and - // nothing failed; a missing file must be loud, not a silent skip). - // All three are concatenated for the compile step below. + // 2) special_mods entries come from three sources, all concatenated for the + // compile step below (matches the runtime `GameData::load_ruleset` set): + // - overlay-common/special_mods.json (version-independent curated, P1-3) + + // overlay/special_mods.json (version-specific) — both optional; + // - generated/special_derived.json — optional; + // - generated/special_vendor.json — required (the 4.5.4.3 upgrade shipped + // without it because regen-all.sh lacked the step and nothing failed; + // a missing file must be loud, not a silent skip). + let overlay_common = data_dir + .parent() + .map(|p| p.join("overlay-common")) + .unwrap_or_else(|| data_dir.join("overlay-common")); let mut special_entries = Vec::new(); for (path, required) in [ + (overlay_common.join("special_mods.json"), false), (overlay.join("special_mods.json"), false), (generated.join("special_derived.json"), false), (generated.join("special_vendor.json"), true), @@ -128,11 +136,18 @@ fn load_strict(path: &Path, errors: &mut Vec) -> Op mod tests { use super::*; - /// The committed repo data passes `--check` (deserialize + compile clean), - /// for both the parity-golden version and CURRENT. + /// The committed repo data passes `--check` (deserialize + compile clean) + /// for the active and parity-golden versions. Versions come from the + /// `pobr_data` constants (auto-advance on data bumps, no literal to + /// re-pin); stale/experimental dirs under `data/` are out of contract. #[test] fn repo_overlay_passes_check() { - for version in ["4.5.0.3.4", "4.5.4.3"] { + let mut versions = vec![ + pobr_data::DATA_VERSION, + pobr_data::GOLDEN_PARITY_DATA_VERSION, + ]; + versions.dedup(); + for version in versions { let data_dir = Path::new(env!("CARGO_MANIFEST_DIR")) .join("../../data") .join(version); diff --git a/tools/precompile-mods/tests/precompile.rs b/tools/precompile-mods/tests/precompile.rs index 76427852..e9c9b505 100644 --- a/tools/precompile-mods/tests/precompile.rs +++ b/tools/precompile-mods/tests/precompile.rs @@ -125,14 +125,22 @@ fn committed_coverage_matches_fresh_run() { 请重跑 cargo run -p precompile-mods -- --data data/{PATCH} --report 并提交" ); - // 棘轮基线应与已提交产物的 coverage_ratio 一致。 + // 覆盖率棘轮:已提交产物不得低于基线(与 devs/scripts/regen-check.sh 同语义)。 + // 基线是人工决策闸门(同 parity_no_regression),不随 regen 自动刷新;覆盖率 + // 提升后抬高基线是可选的 deliberate 动作,故这里断言方向而非相等——数据 regen + // 抬升覆盖率不再机械打碎本测试。 let baseline_path = repo_root().join("devs/ci/parse-coverage-baseline.json"); if baseline_path.is_file() { let baseline: serde_json::Value = serde_json::from_slice(&std::fs::read(&baseline_path).unwrap()).unwrap(); - assert_eq!( - baseline["coverage_ratio"], committed_summary["coverage_ratio"], - "baseline coverage_ratio 与已提交报表不一致——更新 devs/ci/parse-coverage-baseline.json" + let base = baseline["coverage_ratio"].as_f64().expect("baseline ratio"); + let cur = committed_summary["coverage_ratio"] + .as_f64() + .expect("committed ratio"); + assert!( + cur + 5e-7 >= base, + "覆盖率棘轮失败:已提交 {cur} < 基线 {base}——解析覆盖率不得降低;\ + 若属预期(语料扩面)请同 PR 更新 devs/ci/parse-coverage-baseline.json" ); } @@ -178,11 +186,24 @@ fn mirror_data_dir(src_data: &Path) -> PathBuf { std::fs::copy(&src, tmp_data.join("generated").join(name)).unwrap(); } } - // overlay/special_mods.json(parser 引擎 special 通道输入)。存在即拷。 + // overlay/special_mods.json(parser 引擎 special 通道输入,版本特有条目)。存在即拷。 let special_mods = src_data.join("overlay/special_mods.json"); if special_mods.is_file() { std::fs::copy(&special_mods, tmp_data.join("overlay/special_mods.json")).unwrap(); } + // overlay-common/special_mods.json(版本无关策展层,P1-3):gamedata 加载期把它 + // merge 到版本 overlay 之下,是引擎 special 规则的大头(133 条)。它是版本目录的 + // **同级**兄弟,隔离镜像里也必须复刻到 /data/overlay-common/,否则 fresh 重跑 + // 只见版本层零头、覆盖率跌破已提交产物。存在即拷。 + if let Some(src_common) = src_data + .parent() + .map(|p| p.join("overlay-common/special_mods.json")) + && src_common.is_file() + { + let dst_common = tmp.join("data/overlay-common"); + std::fs::create_dir_all(&dst_common).unwrap(); + std::fs::copy(&src_common, dst_common.join("special_mods.json")).unwrap(); + } // overlay/mod_parser_rules.json(引擎解析规则六表——删 legacy 后是唯一 // 解析器,缺它 precompile 直接报错)。存在即拷。 let parser_rules = src_data.join("overlay/mod_parser_rules.json"); diff --git a/tools/sync-pob-catalog/src/extract_base_overrides.lua b/tools/sync-pob-catalog/src/extract_base_overrides.lua index d3e11b05..e030996d 100644 --- a/tools/sync-pob-catalog/src/extract_base_overrides.lua +++ b/tools/sync-pob-catalog/src/extract_base_overrides.lua @@ -113,7 +113,15 @@ for name, base in pairs(itemBases) do tagsJson = "[" .. table.concat(keys, ",") .. "]" end end - if blockChance or spirit or reloadMs or charmBuff or tagsJson then + -- 基底属性需求(vendor `req = { str/dex/int/level }`;level 不入库—— + -- 消费方是装备需求快照 `RequirementsOn`,只吃三属性)。 + local reqStr, reqDex, reqInt = nil, nil, nil + if type(base.req) == "table" then + if type(base.req.str) == "number" and base.req.str > 0 then reqStr = base.req.str end + if type(base.req.dex) == "number" and base.req.dex > 0 then reqDex = base.req.dex end + if type(base.req.int) == "number" and base.req.int > 0 then reqInt = base.req.int end + end + if blockChance or spirit or reloadMs or charmBuff or tagsJson or reqStr or reqDex or reqInt then local parts = { '"name":"' .. jsonEscape(name) .. '"' } if blockChance then parts[#parts + 1] = '"block_chance":' .. jsonNum(blockChance) @@ -130,6 +138,15 @@ for name, base in pairs(itemBases) do if tagsJson then parts[#parts + 1] = '"tags":' .. tagsJson end + if reqStr then + parts[#parts + 1] = '"req_str":' .. string.format("%d", reqStr) + end + if reqDex then + parts[#parts + 1] = '"req_dex":' .. string.format("%d", reqDex) + end + if reqInt then + parts[#parts + 1] = '"req_int":' .. string.format("%d", reqInt) + end print("{" .. table.concat(parts, ",") .. "}") end end diff --git a/tools/sync-pob-catalog/src/extract_bases.rs b/tools/sync-pob-catalog/src/extract_bases.rs index 35bcf224..583a0056 100644 --- a/tools/sync-pob-catalog/src/extract_bases.rs +++ b/tools/sync-pob-catalog/src/extract_bases.rs @@ -189,6 +189,9 @@ mod tests { }; let entries = vec![ BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Omen Sceptre".to_string(), block_chance: None, spirit: Some(100), @@ -197,6 +200,9 @@ mod tests { tags: None, }, BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Crude Tower Shield".to_string(), block_chance: Some(26.0), spirit: None, @@ -205,6 +211,9 @@ mod tests { tags: None, }, BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Makeshift Crossbow".to_string(), block_chance: None, spirit: None, @@ -213,6 +222,9 @@ mod tests { tags: None, }, BaseItemOverrideEntry { + req_str: None, + req_dex: None, + req_int: None, name: "Ruby Charm".to_string(), block_chance: None, spirit: None, diff --git a/tools/sync-pob-catalog/src/extract_gem_quality.lua b/tools/sync-pob-catalog/src/extract_gem_quality.lua index f97ceb8f..7918ba66 100644 --- a/tools/sync-pob-catalog/src/extract_gem_quality.lua +++ b/tools/sync-pob-catalog/src/extract_gem_quality.lua @@ -105,19 +105,28 @@ end -- 抽取并输出 JSONL(pairs 顺序不确定没关系:Rust 侧按 effect_id 排序, -- 单个效果内的行经 ipairs 保持 vendor 顺序且在输出中天然连续成组) ---------------------------------------------------------------------- +-- altQualityStats(vendor CalcTools.lua:147-152):仅 GemlingQuality flag build +-- 生效的附加品质 stat,带 "alt":true 标记转录(消费侧按 flag 门控)。 for skillId, skill in pairs(skills) do - if type(skill) == "table" and type(skill.qualityStats) == "table" then - for _, qs in ipairs(skill.qualityStats) do - if type(qs) == "table" and type(qs[1]) == "string" and type(qs[2]) == "number" then - print( - '{"effect":"' - .. jsonEscape(skillId) - .. '","stat":"' - .. jsonEscape(qs[1]) - .. '","rate":' - .. jsonNum(qs[2]) - .. "}" - ) + if type(skill) == "table" then + for _, field in ipairs({ "qualityStats", "altQualityStats" }) do + local list = skill[field] + if type(list) == "table" then + local altSuffix = field == "altQualityStats" and ',"alt":true' or "" + for _, qs in ipairs(list) do + if type(qs) == "table" and type(qs[1]) == "string" and type(qs[2]) == "number" then + print( + '{"effect":"' + .. jsonEscape(skillId) + .. '","stat":"' + .. jsonEscape(qs[1]) + .. '","rate":' + .. jsonNum(qs[2]) + .. altSuffix + .. "}" + ) + end + end end end end diff --git a/tools/sync-pob-catalog/src/extract_parser_rules.rs b/tools/sync-pob-catalog/src/extract_parser_rules.rs index 76f88769..ec7a8682 100644 --- a/tools/sync-pob-catalog/src/extract_parser_rules.rs +++ b/tools/sync-pob-catalog/src/extract_parser_rules.rs @@ -126,23 +126,23 @@ const POBR_EXTRA_TAG_PHRASES: &[(&str, &str)] = &[ /// vendor 死条目(B3 裁决):modFlagList 里存在、但 vendor `parseMod` 运行时**永不 /// 命中**的 flag 短语——skillNameList 的 SkillName 剥离(order=1,在 flag scan -/// 之前)抢先吃掉短语中的技能名(`for grenade skills` 中 `grenade` 被剥成 -/// SkillName tag,残留 `forSkills` → 整行 extra 非空 → PoB2 树加载丢弃该行)。 -/// 抽取表保留这些条目会让 engine 比 vendor「多生效」词条(deadeye/gemling 实测 -/// +45% CDR over-apply)。裁决方法:`tools/pob2-oracle/run-parsemod.sh` 实喂词条 -/// 看 leftover;版本升级后若 parity 出现同型 over-apply,用同一方法审计新条目。 -const VENDOR_DEAD_FLAG_PHRASES: &[&str] = &["for grenade skills"]; - -/// vendor skillNameList 抢先条目(B3 死条目机制的**改写**变体):modFlagList 的裸 -/// `grenade` 短语在 vendor 运行时永不产 SkillType tag——skillNameList(order=1) -/// 先把词剥成 `SkillName{"Grenade"}`(技能名单里存在字面名 "Grenade" 的条目), -/// 残留恰好可解析 → 整行保留但 tag 恒不匹配(无真实技能叫 "grenade")= 零效果。 -/// ModCache golden 逐字对齐:`12% increased Grenade Damage` → `Damage INC 12 + -/// SkillName{"Grenade"}`;oracle 探针(塞词条到 gemling 戒指)实测 ratio=1.0000。 -/// 抽取表保留 SkillType payload 会让 engine 比 vendor 多生效(gemling/deadeye -/// 全类型 inc +60 over-apply,AvgDmg 1.13x 根因)。与死条目的区别:这里 vendor -/// 行为是「保留行 + 惰性 tag」而非丢行,故改写 payload 而非剔除条目。 -const VENDOR_SKILLNAME_PREEMPTED_FLAG_PHRASES: &[(&str, &str)] = &[("grenade", "Grenade")]; +/// 之前)抢先吃掉短语中的技能名,残留非空 → 整行不生效。裁决方法: +/// `tools/pob2-oracle/run-parsemod.sh` 实喂词条看 leftover;版本升级后 parity +/// 出现同型 over/under-apply 时用同一方法重审。 +/// +/// **0.5.4b(vendor 0.22.0)清空 grenade 项**:vendor gem 名注册循环新增 +/// `not grantedEffect.fromItem` 排除(ModParser.lua:6423,0.21→0.22 delta), +/// `MeleeGrenadeLauncherPlayer`(name "Grenade",fromItem)不再注册 +/// skillNameList → `grenade` / `for grenade skills` 恢复为 modFlagList 的 +/// **live** `SkillType.Grenade` tag(run-parsemod 实证:`15% increased +/// Cooldown Recovery Rate for Grenade Skills` → CooldownRecovery INC 15 + +/// SkillType 159,leftover 空)。0.21 时代的死条目/抢先改写(PR#53)随之撤销; +/// deadeye 3×15 CDR 树词条 under-apply(Speed 0.164 vs oracle 0.254)即此根因。 +const VENDOR_DEAD_FLAG_PHRASES: &[&str] = &[]; + +/// vendor skillNameList 抢先条目(机制说明见 [`VENDOR_DEAD_FLAG_PHRASES`]—— +/// 「保留行 + 惰性 SkillName tag」改写变体)。0.5.4b 起清空(同上 fromItem 排除)。 +const VENDOR_SKILLNAME_PREEMPTED_FLAG_PHRASES: &[(&str, &str)] = &[]; /// 完整 overlay 文档(生成侧;消费侧 schema = /// [`pobr_data::catalog::parser_rules::ModParserRulesDoc`],serde 形状一致)。 @@ -384,7 +384,7 @@ fn finalize_rules(doc: &mut ModParserRulesDoc) { /// M6.3 路线 B 抽取期归一:把 `name_map` 的 vendor ModName 归一为 PoBR canonical /// StatId(别名表 [`VENDOR_NAME_ALIASES`])+ 按短语展开聚合名 /// ([`AGGREGATE_EXPANSION`])。**源真理 = -/// `data/4.5.0.3.4/overlay/vendor_name_aliases.json`**(本表的 real-rename 子集 +/// `data/overlay-common/vendor_name_aliases.json`**(本表的 real-rename 子集 /// 与之一致);结构归一规格见 `blueprints/m6-alias-table.md` §3。 /// /// 设计:仅改 `names`,不增删条目(保 [`PINNED_SECTION_COUNTS`] 计数)。 @@ -578,7 +578,16 @@ const AGGREGATE_EXPANSION: &[(&str, &[&str])] = &[ ("strength and intelligence", &["Strength", "Intelligence"]), ("strength and dexterity", &["Strength", "Dexterity"]), ("dexterity and intelligence", &["Dexterity", "Intelligence"]), - ("skill speed", &["SkillSpeed"]), + // vendor `["skill speed"] = { "Speed", "WarcrySpeed", "TotemPlacementSpeed" }` + // (ModParser.lua:770)。裸 `Speed` → PoBR 速度桶名 `SkillSpeed`;WarcrySpeed / + // TotemPlacementSpeed 保留原名扇出(存量 #9 起 WarcrySpeed 有真消费方 = + // `pobr-core::calc::warcry` 的喊叫时间,CalcOffence.lua:350-359; + // TotemPlacementSpeed 仍为惰性作用域名)。此前只落 `SkillSpeed` 单名, + // 「N% increased Skill Speed」文本对 warcry 喊叫速度静默丢失。 + ( + "skill speed", + &["SkillSpeed", "WarcrySpeed", "TotemPlacementSpeed"], + ), ]; /// 抽取自检(蓝图 §1.9):钉定 commit 下计数 / form id 集容差 0(Err); diff --git a/tools/sync-pob-catalog/src/extract_quality.rs b/tools/sync-pob-catalog/src/extract_quality.rs index 5f03da09..2f8e6efb 100644 --- a/tools/sync-pob-catalog/src/extract_quality.rs +++ b/tools/sync-pob-catalog/src/extract_quality.rs @@ -43,6 +43,9 @@ pub struct QualityRow { pub stat: String, /// 每 1 点品质的斜率(vendor 数据已 `/1000`,原样转录)。 pub rate: f64, + /// vendor `altQualityStats` 条目(仅 GemlingQuality flag build 生效)。 + #[serde(default)] + pub alt: bool, } /// 完整 overlay 文档(生成侧;消费侧 schema 见 @@ -73,6 +76,7 @@ pub fn assemble_quality_document(meta: OverlayMeta, rows: Vec) -> St by_effect.entry(row.effect).or_default().push(QualityStat { stat: row.stat, per_quality_rate: row.rate, + alt: row.alt, }); } let effects = by_effect diff --git a/tools/sync-pob-catalog/src/extract_special_mods.rs b/tools/sync-pob-catalog/src/extract_special_mods.rs index 95801b29..a3bd9a2b 100644 --- a/tools/sync-pob-catalog/src/extract_special_mods.rs +++ b/tools/sync-pob-catalog/src/extract_special_mods.rs @@ -349,21 +349,27 @@ fn repo_data_dir() -> PathBuf { /// 返回(raw key 集 = vendor_pattern ∪ pattern;regex pattern 集)。缺文件容忍 /// (version-bump 演练时可能只有部分文件)。 +/// +/// 去重源含**三处** special_mods:版本无关策展层 `data/overlay-common/special_mods.json` +/// (P1-3)、版本层 `overlay/special_mods.json`、派生表 `generated/special_derived.json`。 +/// 漏读 overlay-common 会让抽取器把已策展的 133 条当作新 vendor 条目重复产出, +/// 下游 precompile-mods --check 报重复 id。 fn load_existing_keys() -> io::Result<(BTreeSet, BTreeSet)> { let mut raw_keys = BTreeSet::new(); let mut patterns = BTreeSet::new(); - for rel in [ - "overlay/special_mods.json", - "generated/special_derived.json", - ] { - let path = repo_data_dir().join(rel); + let paths = [ + repo_data_dir().join("../overlay-common/special_mods.json"), + repo_data_dir().join("overlay/special_mods.json"), + repo_data_dir().join("generated/special_derived.json"), + ]; + for path in paths { let text = match std::fs::read_to_string(&path) { Ok(t) => t, Err(e) if e.kind() == io::ErrorKind::NotFound => continue, Err(e) => return Err(e), }; let doc: SpecialModsDef = serde_json::from_str(&text) - .map_err(|error| io::Error::other(format!("{rel} 解析失败:{error}")))?; + .map_err(|error| io::Error::other(format!("{} 解析失败:{error}", path.display())))?; for entry in doc.entries { if let Some(vp) = entry.vendor_pattern { raw_keys.insert(vp); diff --git a/tools/sync-pob-catalog/tests/extract/extract_quality.rs b/tools/sync-pob-catalog/tests/extract/extract_quality.rs index 8020acf5..5aaa226a 100644 --- a/tools/sync-pob-catalog/tests/extract/extract_quality.rs +++ b/tools/sync-pob-catalog/tests/extract/extract_quality.rs @@ -106,6 +106,7 @@ fn assemble_document_is_deterministic_and_sorted_by_effect() { effect: effect.to_string(), stat: stat.to_string(), rate, + alt: false, }; // 两种到达顺序(effect 层乱序,单效果内顺序一致——对齐 Lua 侧 pairs 外层 // 不确定 / ipairs 内层连续的输出形态)。 diff --git a/tools/sync-pob-catalog/tests/extract/special_mods_patterns.rs b/tools/sync-pob-catalog/tests/extract/special_mods_patterns.rs index 42be61bd..75431529 100644 --- a/tools/sync-pob-catalog/tests/extract/special_mods_patterns.rs +++ b/tools/sync-pob-catalog/tests/extract/special_mods_patterns.rs @@ -8,20 +8,46 @@ use std::path::Path; use regex::Regex; -/// 仓库 data 根(tools/sync-pob-catalog/ → 上两级)。 -fn special_mods_path() -> std::path::PathBuf { - Path::new(env!("CARGO_MANIFEST_DIR")).join("../../data/4.5.0.3.4/overlay/special_mods.json") +/// special_mods 两层文件(tools/sync-pob-catalog/ → 上两级到仓库根):版本无关策展层 +/// `data/overlay-common/`(P1-3,133 条大头)+ 版本层 `data//overlay/`。两者并集 +/// 覆盖全部策展 pattern。 +fn special_mods_paths() -> Vec { + let data = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../data"); + vec![ + data.join("overlay-common/special_mods.json"), + data.join(pobr_data::data_version()) + .join("overlay/special_mods.json"), + ] +} + +/// 两层 entries 并集(缺文件跳过;至少一层须存在)。 +fn load_entries() -> Vec { + let mut entries = Vec::new(); + for path in special_mods_paths() { + let text = match std::fs::read_to_string(&path) { + Ok(t) => t, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => continue, + Err(e) => panic!("{}: {e}", path.display()), + }; + let doc: serde_json::Value = serde_json::from_str(&text).unwrap(); + entries.extend( + doc["entries"] + .as_array() + .expect("entries 数组") + .iter() + .cloned(), + ); + } + entries } /// 全部 pattern 可被 regex crate 编译(整行锚定由引擎统一加 `^...$`, /// 此处按同口径编译);捕获组数 ≥ mods 内引用的最大 `$n`。 #[test] fn all_patterns_compile_and_captures_cover_refs() { - let text = std::fs::read_to_string(special_mods_path()).expect("special_mods.json 在库"); - let doc: serde_json::Value = serde_json::from_str(&text).unwrap(); - let entries = doc["entries"].as_array().expect("entries 数组"); + let entries = load_entries(); assert!(!entries.is_empty()); - for entry in entries { + for entry in &entries { let id = entry["id"].as_str().unwrap(); let pattern = entry["pattern"].as_str().unwrap(); let re = Regex::new(&format!("^{pattern}$")) @@ -46,10 +72,8 @@ fn all_patterns_compile_and_captures_cover_refs() { /// 之外的捕获必须是显式闭集(不含 `\d`)——DSL 硬边界的「禁开放捕获」。 #[test] fn captures_are_numeric_or_closed_sets() { - let text = std::fs::read_to_string(special_mods_path()).unwrap(); - let doc: serde_json::Value = serde_json::from_str(&text).unwrap(); const NUMERIC_FORMS: [&str; 4] = [r"(\d+)", r"(\d+(?:\.\d+)?)", r"([+-]\d+)", r"(\+?\d+)"]; - for entry in doc["entries"].as_array().unwrap() { + for entry in &load_entries() { let id = entry["id"].as_str().unwrap(); let pattern = entry["pattern"].as_str().unwrap(); // 逐捕获组扫描(顶层括号,忽略 (?: 非捕获组) diff --git a/web/scripts/sync-data.mjs b/web/scripts/sync-data.mjs index f05273a6..a87e4491 100644 --- a/web/scripts/sync-data.mjs +++ b/web/scripts/sync-data.mjs @@ -39,6 +39,19 @@ for (const path of walkJson(src)) { cpSync(path, join(dest, rel)); files.push(rel); } + +// 版本无关策展层 data/overlay-common/(P1-3):版本目录的同级兄弟,gamedata 加载期 +// merge 到版本 overlay 之下。放到 dest/overlay-common/ 并以 `overlay-common/` +// 相对键登记——wasm 内存后端按该键注入,GameData 恰好从此键读取(root 父目录 + +// overlay-common)。缺目录(旧数据包)则跳过。 +const commonSrc = join(dataRoot, 'overlay-common'); +if (statSync(commonSrc, { throwIfNoEntry: false })?.isDirectory()) { + for (const path of walkJson(commonSrc)) { + const rel = join('overlay-common', relative(commonSrc, path)).split('\\').join('/'); + cpSync(path, join(dest, rel)); + files.push(rel); + } +} files.sort(); writeFileSync(join(destRoot, 'manifest.json'), JSON.stringify({ version, files }, null, 2));