Patch Water Mastery fluid healing interaction
according to zeer, all stat scaling is applied after total stats
This commit is contained in:
parent
f9e783e56e
commit
7919647372
2 changed files with 58 additions and 62 deletions
101
js/atree.js
101
js/atree.js
|
@ -696,7 +696,7 @@ const atree_make_interactives = new (class extends ComputeNode {
|
||||||
let slider_container = gen_slider_labeled(slider_info);
|
let slider_container = gen_slider_labeled(slider_info);
|
||||||
document.getElementById("boost-sliders").appendChild(slider_container);
|
document.getElementById("boost-sliders").appendChild(slider_container);
|
||||||
slider_info.slider = document.getElementById(slider_info.id);
|
slider_info.slider = document.getElementById(slider_info.id);
|
||||||
slider_info.slider.addEventListener("change", (e) => atree_stats.mark_dirty().update());
|
slider_info.slider.addEventListener("change", (e) => atree_scaling.mark_dirty().update());
|
||||||
}
|
}
|
||||||
for (const [button_name, button_info] of button_map.entries()) {
|
for (const [button_name, button_info] of button_map.entries()) {
|
||||||
let button = make_elem('button', ["button-boost", "border-0", "text-white", "dark-8u", "dark-shadow-sm", "m-1"], {
|
let button = make_elem('button', ["button-boost", "border-0", "text-white", "dark-8u", "dark-shadow-sm", "m-1"], {
|
||||||
|
@ -709,7 +709,7 @@ const atree_make_interactives = new (class extends ComputeNode {
|
||||||
} else {
|
} else {
|
||||||
button.classList.add("toggleOn");
|
button.classList.add("toggleOn");
|
||||||
}
|
}
|
||||||
atree_stats.mark_dirty().update()
|
atree_scaling.mark_dirty().update()
|
||||||
});
|
});
|
||||||
button_info.button = button;
|
button_info.button = button;
|
||||||
document.getElementById("boost-toggles").appendChild(button);
|
document.getElementById("boost-toggles").appendChild(button);
|
||||||
|
@ -718,20 +718,19 @@ const atree_make_interactives = new (class extends ComputeNode {
|
||||||
}
|
}
|
||||||
})().link_to(atree_node, 'atree-order').link_to(atree_merge, 'atree-merged').link_to(atree_render_active, 'atree-elements');
|
})().link_to(atree_node, 'atree-order').link_to(atree_merge, 'atree-merged').link_to(atree_render_active, 'atree-elements');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect stats from ability tree.
|
* Scaling stats from ability tree.
|
||||||
* Return StatMap of added stats (incl. cost modifications as raw cost)
|
* Return StatMap of added stats,
|
||||||
*
|
*
|
||||||
* Signature: AbilityTreeStatsNode(atree-merged: MergedATree, build: Build,
|
* Signature: AbilityTreeScalingNode(atree-merged: MergedATree, scale-scats: StatMap,
|
||||||
* atree-interactive: [Map<str, slider_info>, Map<str, button_info>]) => StatMap
|
* atree-interactive: [Map<str, slider_info>, Map<str, button_info>]) => StatMap
|
||||||
*/
|
*/
|
||||||
const atree_stats = new (class extends ComputeNode {
|
const atree_scaling = new (class extends ComputeNode {
|
||||||
constructor() { super('atree-stats-collector'); }
|
constructor() { super('atree-scaling-collector'); }
|
||||||
|
|
||||||
compute_func(input_map) {
|
compute_func(input_map) {
|
||||||
const atree_merged = input_map.get('atree-merged');
|
const atree_merged = input_map.get('atree-merged');
|
||||||
const item_stats = input_map.get('build').statMap;
|
const pre_scale_stats = input_map.get('scale-stats');
|
||||||
const [slider_map, button_map] = input_map.get('atree-interactive');
|
const [slider_map, button_map] = input_map.get('atree-interactive');
|
||||||
|
|
||||||
let ret_effects = new Map();
|
let ret_effects = new Map();
|
||||||
|
@ -741,41 +740,26 @@ const atree_stats = new (class extends ComputeNode {
|
||||||
for (const effect of abil.effects) {
|
for (const effect of abil.effects) {
|
||||||
switch (effect.type) {
|
switch (effect.type) {
|
||||||
case 'stat_scaling':
|
case 'stat_scaling':
|
||||||
if (effect.slider) {
|
let total = 0;
|
||||||
if ('output' in effect) { // sometimes nodes will modify slider without having effect.
|
const {round = true, slider = false, scaling = [0]} = effect;
|
||||||
const slider_val = slider_map.get(effect.slider_name).slider.value;
|
if (slider) {
|
||||||
const {round = true} = effect;
|
const slider_val = slider_map.get(effect.slider_name).slider.value;
|
||||||
let total = parseInt(slider_val) * effect.scaling[0];
|
total = parseInt(slider_val) * scaling[0];
|
||||||
if (round) { total = Math.floor(round_near(total)); }
|
|
||||||
if ('max' in effect && total > effect.max) { total = effect.max; }
|
|
||||||
if (Array.isArray(effect.output)) {
|
|
||||||
for (const output of effect.output) {
|
|
||||||
if (output.type === 'stat') { // TODO: prop
|
|
||||||
merge_stat(ret_effects, output.name, total);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (effect.output.type === 'stat') {
|
|
||||||
merge_stat(ret_effects, effect.output.name, total);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: type: prop?
|
// TODO: type: prop?
|
||||||
let total = 0;
|
for (const [_scaling, input] of zip2(scaling, effect.inputs)) {
|
||||||
const {round = true} = effect;
|
total += _scaling * pre_scale_stats.get(input.name);
|
||||||
for (const [scaling, input] of zip2(effect.scaling, effect.inputs)) {
|
|
||||||
total += scaling * item_stats.get(input.name);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('output' in effect) { // sometimes nodes will modify slider without having effect.
|
||||||
if (round) { total = Math.floor(round_near(total)); }
|
if (round) { total = Math.floor(round_near(total)); }
|
||||||
if (total < 0) { total = 0; } // Normal stat scaling will not go negative.
|
if (total < 0) { total = 0; } // Normal stat scaling will not go negative.
|
||||||
if ('max' in effect && total > effect.max) { total = effect.max; }
|
if ('max' in effect && total > effect.max) { total = effect.max; }
|
||||||
// TODO: output (list...)
|
|
||||||
if (Array.isArray(effect.output)) {
|
if (Array.isArray(effect.output)) {
|
||||||
for (const output of effect.output) {
|
for (const output of effect.output) {
|
||||||
if (output.type === 'stat') {
|
if (output.type === 'stat') { // TODO: prop
|
||||||
merge_stat(ret_effects, output.name, total);
|
merge_stat(ret_effects, output.name, total);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -787,6 +771,31 @@ const atree_stats = new (class extends ComputeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret_effects;
|
||||||
|
}
|
||||||
|
})().link_to(atree_merge, 'atree-merged').link_to(atree_make_interactives, 'atree-interactive');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect stats from ability tree.
|
||||||
|
* Return StatMap of added stats.
|
||||||
|
*
|
||||||
|
* Signature: AbilityTreeStatsNode(atree-merged: MergedATree) => StatMap
|
||||||
|
*/
|
||||||
|
const atree_stats = new (class extends ComputeNode {
|
||||||
|
constructor() { super('atree-stats-collector'); }
|
||||||
|
|
||||||
|
compute_func(input_map) {
|
||||||
|
const atree_merged = input_map.get('atree-merged');
|
||||||
|
|
||||||
|
let ret_effects = new Map();
|
||||||
|
for (const [abil_id, abil] of atree_merged.entries()) {
|
||||||
|
if (abil.effects.length == 0) { continue; }
|
||||||
|
|
||||||
|
for (const effect of abil.effects) {
|
||||||
|
switch (effect.type) {
|
||||||
case 'raw_stat':
|
case 'raw_stat':
|
||||||
// TODO: toggles...
|
// TODO: toggles...
|
||||||
if (effect.toggle) {
|
if (effect.toggle) {
|
||||||
|
@ -801,27 +810,12 @@ const atree_stats = new (class extends ComputeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
case 'add_spell_prop':
|
|
||||||
continue;
|
|
||||||
// TODO unjankify....
|
|
||||||
// costs are converted to raw cost ID
|
|
||||||
// const { base_spell, cost = 0} = effect;
|
|
||||||
// if (cost) {
|
|
||||||
// const key = "spRaw"+base_spell;
|
|
||||||
// if (ret_effects.has(key)) { ret_effects.set(key, ret_effects.get(key) + cost); }
|
|
||||||
// else { ret_effects.set(key, cost); }
|
|
||||||
// }
|
|
||||||
// continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ret_effects.has('baseResist')) {
|
|
||||||
merge_stat(ret_effects, "defMult", 1 - (ret_effects.get('baseResist') / 100));
|
|
||||||
}
|
|
||||||
return ret_effects;
|
return ret_effects;
|
||||||
}
|
}
|
||||||
})().link_to(atree_merge, 'atree-merged').link_to(atree_make_interactives, 'atree-interactive');
|
})().link_to(atree_merge, 'atree-merged');
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct compute nodes to link builder items and edit IDs to the appropriate display outputs.
|
* Construct compute nodes to link builder items and edit IDs to the appropriate display outputs.
|
||||||
|
@ -844,16 +838,15 @@ class AbilityTreeEnsureNodesNode extends ComputeNode {
|
||||||
this.build_node = build_node;
|
this.build_node = build_node;
|
||||||
this.stat_agg_node = stat_agg_node;
|
this.stat_agg_node = stat_agg_node;
|
||||||
// Slight amount of wasted compute to keep internal state non-changing.
|
// Slight amount of wasted compute to keep internal state non-changing.
|
||||||
this.passthrough = new PassThroughNode('atree-make-nodes_internal').link_to(this.build_node, 'build').link_to(this.stat_agg_node, 'stats');
|
this.passthrough = new PassThroughNode('spell-calc-buffer').link_to(this.build_node, 'build').link_to(this.stat_agg_node, 'stats');
|
||||||
this.spelldmg_nodes = []; // debugging use
|
this.spelldmg_nodes = []; // debugging use
|
||||||
this.spell_display_elem = document.getElementById("all-spells-display");
|
this.spell_display_elem = document.getElementById("all-spells-display");
|
||||||
}
|
}
|
||||||
|
|
||||||
compute_func(input_map) {
|
compute_func(input_map) {
|
||||||
console.log('atree make nodes');
|
|
||||||
this.passthrough.remove_link(this.build_node);
|
this.passthrough.remove_link(this.build_node);
|
||||||
this.passthrough.remove_link(this.stat_agg_node);
|
this.passthrough.remove_link(this.stat_agg_node);
|
||||||
this.passthrough = new PassThroughNode('atree-make-nodes_internal').link_to(this.build_node, 'build').link_to(this.stat_agg_node, 'stats');
|
this.passthrough = new PassThroughNode('spell-calc-buffer').link_to(this.build_node, 'build').link_to(this.stat_agg_node, 'stats');
|
||||||
this.spell_display_elem.textContent = "";
|
this.spell_display_elem.textContent = "";
|
||||||
const build_node = this.passthrough.get_node('build'); // aaaaaaaaa performance... savings... help....
|
const build_node = this.passthrough.get_node('build'); // aaaaaaaaa performance... savings... help....
|
||||||
const stat_agg_node = this.passthrough.get_node('stats');
|
const stat_agg_node = this.passthrough.get_node('stats');
|
||||||
|
|
|
@ -794,7 +794,7 @@ class DisplayBuildWarningsNode extends ComputeNode {
|
||||||
* Signature: AggregateStatsNode(*args) => StatMap
|
* Signature: AggregateStatsNode(*args) => StatMap
|
||||||
*/
|
*/
|
||||||
class AggregateStatsNode extends ComputeNode {
|
class AggregateStatsNode extends ComputeNode {
|
||||||
constructor() { super("builder-aggregate-stats"); }
|
constructor(name) { super(name); }
|
||||||
|
|
||||||
compute_func(input_map) {
|
compute_func(input_map) {
|
||||||
const output_stats = new Map();
|
const output_stats = new Map();
|
||||||
|
@ -997,7 +997,8 @@ function builder_graph_init() {
|
||||||
// Phase 2/3: Set up editable IDs, skill points; use decodeBuild() skill points, calculate damage
|
// Phase 2/3: Set up editable IDs, skill points; use decodeBuild() skill points, calculate damage
|
||||||
|
|
||||||
// Create one node that will be the "aggregator node" (listen to all the editable id nodes, as well as the build_node (for non editable stats) and collect them into one statmap)
|
// Create one node that will be the "aggregator node" (listen to all the editable id nodes, as well as the build_node (for non editable stats) and collect them into one statmap)
|
||||||
stat_agg_node = new AggregateStatsNode();
|
pre_scale_agg_node = new AggregateStatsNode('pre-scale-stats');
|
||||||
|
stat_agg_node = new AggregateStatsNode('final-stats');
|
||||||
edit_agg_node = new AggregateEditableIDNode();
|
edit_agg_node = new AggregateEditableIDNode();
|
||||||
edit_agg_node.link_to(build_node, 'build');
|
edit_agg_node.link_to(build_node, 'build');
|
||||||
for (const field of editable_item_fields) {
|
for (const field of editable_item_fields) {
|
||||||
|
@ -1021,7 +1022,7 @@ function builder_graph_init() {
|
||||||
edit_input_nodes.push(node);
|
edit_input_nodes.push(node);
|
||||||
skp_inputs.push(node);
|
skp_inputs.push(node);
|
||||||
}
|
}
|
||||||
stat_agg_node.link_to(edit_agg_node);
|
pre_scale_agg_node.link_to(edit_agg_node);
|
||||||
|
|
||||||
// Phase 3/3: Set up atree stuff.
|
// Phase 3/3: Set up atree stuff.
|
||||||
|
|
||||||
|
@ -1029,8 +1030,10 @@ function builder_graph_init() {
|
||||||
// These two are defined in `atree.js`
|
// These two are defined in `atree.js`
|
||||||
atree_node.link_to(class_node, 'player-class');
|
atree_node.link_to(class_node, 'player-class');
|
||||||
atree_merge.link_to(class_node, 'player-class');
|
atree_merge.link_to(class_node, 'player-class');
|
||||||
atree_stats.link_to(build_node, 'build');
|
pre_scale_agg_node.link_to(atree_stats, 'atree-raw-stats');
|
||||||
stat_agg_node.link_to(atree_stats, 'atree-stats');
|
atree_scaling.link_to(pre_scale_agg_node, 'scale-stats');
|
||||||
|
stat_agg_node.link_to(pre_scale_agg_node, 'pre-scaling');
|
||||||
|
stat_agg_node.link_to(atree_scaling, 'atree-scaling');
|
||||||
|
|
||||||
build_encode_node.link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state');
|
build_encode_node.link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state');
|
||||||
|
|
||||||
|
@ -1062,12 +1065,12 @@ function builder_graph_init() {
|
||||||
let powder_special_calc = new PowderSpecialCalcNode().link_to(powder_special_input, 'powder-specials');
|
let powder_special_calc = new PowderSpecialCalcNode().link_to(powder_special_input, 'powder-specials');
|
||||||
new PowderSpecialDisplayNode().link_to(powder_special_input, 'powder-specials')
|
new PowderSpecialDisplayNode().link_to(powder_special_input, 'powder-specials')
|
||||||
.link_to(stat_agg_node, 'stats').link_to(build_node, 'build');
|
.link_to(stat_agg_node, 'stats').link_to(build_node, 'build');
|
||||||
stat_agg_node.link_to(powder_special_calc, 'powder-boost');
|
pre_scale_agg_node.link_to(powder_special_calc, 'powder-boost');
|
||||||
stat_agg_node.link_to(armor_powder_node, 'armor-powder');
|
pre_scale_agg_node.link_to(armor_powder_node, 'armor-powder');
|
||||||
powder_special_input.update();
|
powder_special_input.update();
|
||||||
|
|
||||||
// Potion boost.
|
// Potion boost.
|
||||||
stat_agg_node.link_to(boosts_node, 'potion-boost');
|
pre_scale_agg_node.link_to(boosts_node, 'potion-boost');
|
||||||
|
|
||||||
// Also do something similar for skill points
|
// Also do something similar for skill points
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue