Merge in atree_active_box
This commit is contained in:
parent
b256213f09
commit
c05eb82e60
2 changed files with 92 additions and 74 deletions
160
js/atree.js
160
js/atree.js
|
@ -318,77 +318,88 @@ const atree_validate = new (class extends ComputeNode {
|
|||
|
||||
if (atree_order.length == 0) { return [0, ['no atree data']]; }
|
||||
|
||||
let errors = [];
|
||||
let reachable = new Map();
|
||||
atree_dfs_mark(atree_order[0], atree_state, reachable);
|
||||
console.log(atree_state);
|
||||
|
||||
let atree_to_add = [];
|
||||
for (const node of atree_order) {
|
||||
const abil = node.ability;
|
||||
if (atree_state.get(abil.id).active) { atree_to_add.push([node, 'not reachable', false]); }
|
||||
}
|
||||
|
||||
let reachable = new Set();
|
||||
let abil_points_total = 0;
|
||||
let archetype_count = new Map();
|
||||
while (true) {
|
||||
let _add = [];
|
||||
for (const [node, fail_reason, fail_hardness] of atree_to_add) {
|
||||
const {parents, ability} = node;
|
||||
if (parents.length === 0) {
|
||||
reachable.add(ability.id);
|
||||
// root abil has no archetype.
|
||||
abil_points_total += ability.cost;
|
||||
continue;
|
||||
}
|
||||
let failed_deps = [];
|
||||
for (const dep_id of ability.dependencies) {
|
||||
if (!atree_state.get(dep_id).active) { failed_deps.push(dep_id) }
|
||||
}
|
||||
if (failed_deps.length > 0) {
|
||||
const dep_strings = failed_deps.map(i => '"' + atree_state.get(i).ability.display_name + '"');
|
||||
_add.push([node, 'missing dep: ' + dep_strings.join(", "), true]);
|
||||
continue;
|
||||
}
|
||||
let blocking_ids = [];
|
||||
for (const blocker_id of ability.blockers) {
|
||||
if (atree_state.get(blocker_id).active) { blocking_ids.push(blocker_id); }
|
||||
}
|
||||
if (blocking_ids.length > 0) {
|
||||
const blockers_strings = blocking_ids.map(i => '"' + atree_state.get(i).ability.display_name + '"');
|
||||
_add.push([node, 'blocked by: '+blockers_strings.join(", "), true]);
|
||||
continue;
|
||||
}
|
||||
let node_reachable = false;
|
||||
for (const parent of parents) {
|
||||
if (reachable.has(parent.ability.id)) {
|
||||
node_reachable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!node_reachable) {
|
||||
_add.push([node, 'not reachable', false])
|
||||
continue;
|
||||
}
|
||||
if ('archetype' in ability && ability.archetype !== "") {
|
||||
if ('archetype_req' in ability && ability.archetype_req !== 0) {
|
||||
const others = archetype_count.get(ability.archetype);
|
||||
if (others < ability.archetype_req) {
|
||||
_add.push([node, abil.archetype+': '+others+' < '+abil.archetype_req, false])
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let val = 1;
|
||||
if (archetype_count.has(ability.archetype)) {
|
||||
val = archetype_count.get(ability.archetype) + 1;
|
||||
}
|
||||
archetype_count.set(ability.archetype, val);
|
||||
}
|
||||
abil_points_total += ability.cost;
|
||||
reachable.add(ability.id);
|
||||
}
|
||||
if (atree_to_add.length == _add.length) {
|
||||
break;
|
||||
}
|
||||
atree_to_add = _add;
|
||||
}
|
||||
let hard_error = false;
|
||||
for (const node of atree_order) {
|
||||
const abil = node.ability;
|
||||
if (!atree_state.get(abil.id).active) { continue; }
|
||||
abil_points_total += abil.cost;
|
||||
if (!reachable.get(abil.id)) { errors.push(abil.display_name + ' is not reachable!'); }
|
||||
|
||||
let failed_deps = [];
|
||||
for (const dep_id of abil.dependencies) {
|
||||
if (!atree_state.get(dep_id).active) { failed_deps.push(dep_id) }
|
||||
}
|
||||
if (failed_deps.length > 0) {
|
||||
const dep_string = failed_deps.map(i => '"' + atree_state.get(i).ability.display_name + '"');
|
||||
errors.push(abil.display_name + ' dependencies not satisfied: ' + dep_string.join(", "));
|
||||
hard_error = true;
|
||||
}
|
||||
|
||||
let blocking_ids = [];
|
||||
for (const blocker_id of abil.blockers) {
|
||||
if (atree_state.get(blocker_id).active) { blocking_ids.push(blocker_id); }
|
||||
}
|
||||
if (blocking_ids.length > 0) {
|
||||
const blockers_string = blocking_ids.map(i => '"' + atree_state.get(i).ability.display_name + '"');
|
||||
errors.push(abil.display_name+' is blocked by: '+blockers_string.join(", "));
|
||||
hard_error = true;
|
||||
}
|
||||
|
||||
if ('archetype' in abil && abil.archetype !== "") {
|
||||
let val = 1;
|
||||
if (archetype_count.has(abil.archetype)) {
|
||||
val = archetype_count.get(abil.archetype) + 1;
|
||||
}
|
||||
archetype_count.set(abil.archetype, val);
|
||||
}
|
||||
let errors = [];
|
||||
for (const [node, fail_reason, fail_hardness] of atree_to_add) {
|
||||
if (fail_hardness) { hard_error = true; }
|
||||
errors.push(node.ability.display_name + ": " + fail_reason);
|
||||
}
|
||||
// TODO: FIX THIS! ARCHETYPE REQ IS A PAIN IN THE ASS
|
||||
// it doesn't follow topological order and theres some cases where "equip order" matters.
|
||||
for (const node of atree_order) {
|
||||
const abil = node.ability;
|
||||
if (!atree_state.get(abil.id).active) { continue; }
|
||||
if ('archetype_req' in abil && abil.archetype_req !== 0) {
|
||||
const others = archetype_count.get(abil.archetype) - 1;
|
||||
if (others < abil.archetype_req) {
|
||||
errors.push(abil.display_name+' fails archetype: '+abil.archetype+': '+others+' < '+abil.archetype_req)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (abil_points_total > 45) {
|
||||
errors.push('too many ability points assigned! ('+abil_points_total+' > 45)');
|
||||
}
|
||||
|
||||
return [abil_points_total, hard_error, errors];
|
||||
}
|
||||
})().link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state');
|
||||
|
||||
function atree_dfs_mark(start, atree_state, mark) {
|
||||
if (mark.get(start.ability.id)) { return; }
|
||||
mark.set(start.ability.id, true);
|
||||
for (const child of start.children) {
|
||||
if (atree_state.get(child.ability.id).active) {
|
||||
atree_dfs_mark(child, atree_state, mark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render ability tree.
|
||||
* Return map of id -> corresponding html element.
|
||||
|
@ -420,10 +431,19 @@ const atree_render_active = new (class extends ComputeNode {
|
|||
error_title.innerHTML = "ATree Error!";
|
||||
errorbox.appendChild(error_title);
|
||||
|
||||
for (const error of errors) {
|
||||
let atree_warning = document.createElement("p");
|
||||
atree_warning.classList.add("warning", "small-text");
|
||||
atree_warning.textContent = error;
|
||||
for (let i = 0; i < 5 && i < errors.length; ++i) {
|
||||
const error = errors[i];
|
||||
const atree_warning = make_elem("p", ["warning", "small-text"], {textContent: error});
|
||||
errorbox.appendChild(atree_warning);
|
||||
}
|
||||
if (errors.length > 5) {
|
||||
const error = '... ' + errors.length-5 + ' errors not shown';
|
||||
const atree_warning = make_elem("p", ["warning", "small-text"], {textContent: error});
|
||||
errorbox.appendChild(atree_warning);
|
||||
}
|
||||
if (abil_points_total > 45) {
|
||||
const error = 'too many ability points assigned! ('+abil_points_total+' > 45)';
|
||||
const atree_warning = make_elem("p", ["warning", "small-text"], {textContent: error});
|
||||
errorbox.appendChild(atree_warning);
|
||||
}
|
||||
}
|
||||
|
@ -652,7 +672,8 @@ const atree_stats = new (class extends ComputeNode {
|
|||
if (effect.slider) {
|
||||
// TODO: handle
|
||||
const slider_val = interactive_map.get(effect.slider_name).slider.value;
|
||||
const total = parseInt(slider_val) * effect.scaling[0];
|
||||
let total = parseInt(slider_val) * effect.scaling[0];
|
||||
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') {
|
||||
|
@ -667,13 +688,12 @@ const atree_stats = new (class extends ComputeNode {
|
|||
}
|
||||
}
|
||||
else {
|
||||
const cap = effect.max;
|
||||
// TODO: type: prop?
|
||||
let total = 0;
|
||||
for (const [scaling, input] of zip2(effect.scaling, effect.inputs)) {
|
||||
total += scaling * item_stats.get(input.name);
|
||||
}
|
||||
if (total > cap) { total = cap; }
|
||||
if ('max' in effect && total > effect.max) { total = effect.max; }
|
||||
// TODO: output (list...)
|
||||
if (Array.isArray(effect.output)) {
|
||||
for (const output of effect.output) {
|
||||
|
|
|
@ -2888,14 +2888,12 @@ const atrees = {
|
|||
|
||||
{
|
||||
"display_name": "Provoke",
|
||||
"desc": "Mobs damaged by War Scream will target only you for at least 5s \n\nReduce the Mana cost of War Scream",
|
||||
"archetype": "Paladin",
|
||||
"archetype_req": 0,
|
||||
"desc": "Mobs damaged by War Scream will target only you for at least 5s. Reduce the Mana cost of War Scream",
|
||||
"base_abil": "War Scream",
|
||||
"parents": ["Aerodynamics", "Mantle of the Bovemists"],
|
||||
"dependencies": [],
|
||||
"blockers": [],
|
||||
"cost": 1,
|
||||
"cost": 2,
|
||||
"display": {
|
||||
"row": 17,
|
||||
"col": 7,
|
||||
|
|
Loading…
Reference in a new issue