const preact = require('preact'); const get = require('lodash/get'); const shapes = require('./components/shapes'); const stringSort = (k, desc) => { if (desc) { return (a, b) => { if (!get(a, k)) return 1; if (!get(b, k)) return -1; return get(b, k).localeCompare(get(a, k)); }; } return (a, b) => { if (!get(a, k)) return 1; if (!get(b, k)) return -1; return get(a, k).localeCompare(get(b, k)); }; }; const numSort = (k, desc) => { if (desc) { return (a, b) => { if (!get(a, k)) return 1; if (!get(b, k)) return -1; return get(b, k) - get(a, k); }; } return (a, b) => { if (!get(a, k)) return 1; if (!get(b, k)) return -1; return get(a, k) - get(b, k); }; }; const NULL_UUID = '00000000-0000-0000-0000-000000000000'; const STATS = { RedPower: { stat: 'red_power', colour: 'red', svg: shapes.circle, }, GreenPower: { stat: 'green_power', colour: 'green', svg: shapes.circle, }, BluePower: { stat: 'blue_power', colour: 'blue', svg: shapes.circle, }, Speed: { stat: 'speed', colour: 'white', svg: shapes.triangle, }, RedLife: { stat: 'red_life', colour: 'red', svg: shapes.square, }, GreenLife: { stat: 'green_life', colour: 'green', svg: shapes.square, }, BlueLife: { stat: 'blue_life', colour: 'blue', svg: shapes.square, }, }; function eventClasses(resolution, construct) { if (!resolution) return ''; const postSkill = resolution.stages.includes('POST_SKILL'); const source = construct.id === resolution.source.id; const target = construct.id === resolution.target.id; // not involved at all. blur them if (!(source || target)) return 'unfocus'; // not the target. just ignore for now // if (construct.id !== resolution.target.id) return ''; const [type, event] = resolution.event; if (type === 'Ko') { if (target) return 'ko'; } if (type === 'Disable') { const { skill, disable } = event; } if (type === 'Immunity') { const { skill, immunity } = event; } if (type === 'TargetKo') { const { skill } = event; } if (type === 'Damage') { const { skill, amount, mitigation, colour } = event; // Highlight the flow of damage from source -> target // Deal damage to construct and return effect if (target && postSkill) { construct.green_life.value = resolution.target.green; if (colour === 'Red') { construct.red_life.value = resolution.target.red; return 'red-damage'; } if (colour === 'Blue') { construct.blue_life.value = resolution.target.blue; return 'blue-damage'; } if (colour === 'Green') { construct.green_life.value = resolution.target.green; return 'green-damage'; } } } if (type === 'Healing') { const { skill, amount, overhealing } = event; if (target && postSkill) { construct.green_life.value = resolution.target.green; return 'green-damage'; } } if (type === 'Inversion') { const { skill } = event; } if (type === 'Reflection') { const { skill } = event; } if (type === 'Effect') { const { skill, effect, duration, construct_effects: constructEffects } = event; if (target && postSkill) construct.effects = constructEffects; } if (type === 'Skill') { const { skill } = event; // Highlight the flow of damage from source -> target } if (type === 'Removal') { const { effect, construct_effects: constructEffects } = event; if (target && postSkill) construct.effects = constructEffects; } if (type === 'Recharge') { const { skill, red, blue } = event; if (target && postSkill) { if (red > 0 && blue > 0) { construct.red_life.value = resolution.target.red; construct.blue_life.value = resolution.target.blue; return 'purple-damage'; } if (red > 0) { construct.red_life.value = resolution.target.red; return 'red-damage'; } if (blue > 0) { construct.blue_life.value = resolution.target.blue; return 'blue-damage'; } } } if (type === 'Evasion') { const { skill, evasion_rating } = event; } return ''; } function getCombatSequence(resolution) { if (!resolution.event) return false; if (resolution.event[0] === 'Inversion') return false; if (resolution.event[0] === 'Skill') return [['START_SKILL', 'END_SKILL']]; if (resolution.event[0] === 'Ko') return [['POST_SKILL']]; switch (resolution.stages) { case 1: return [['START_SKILL', 'END_SKILL']]; case 2: return [['START_SKILL'], ['POST_SKILL']]; case 3: return [['START_SKILL']]; case 4: return [['END_SKILL'], ['POST_SKILL']]; case 5: return [['END_SKILL']]; case 6: return [['POST_SKILL']]; case 7: return false; default: return [['START_SKILL', 'END_SKILL'], ['POST_SKILL']]; } } function getCombatText(resolution, construct) { if (!resolution) return false; if (!resolution.stages.includes('POST_SKILL')) return false; if (construct.id !== resolution.target.id) return false; const [type, event] = resolution.event; if (type === 'Ko') { return 'KO!'; } if (type === 'Disable') { const { disable } = event; return `${disable}`; } if (type === 'Immunity') { return 'IMMUNE'; } if (type === 'Damage') { const { mitigation, colour } = event; let { amount } = event; if (colour === 'Green') amount *= -1; const mitigationText = mitigation ? `(${mitigation})` : ''; return `${amount} ${mitigationText}`; } if (type === 'Healing') { const { amount, overhealing } = event; return `${amount} (${overhealing} OH)`; } if (type === 'Inversion') { return 'INVERT'; } if (type === 'Reflection') { return 'REFLECT'; } if (type === 'Effect') { const { effect, duration } = event; return `+ ${effect} ${duration}T`; } if (type === 'Recharge') { const { red, blue } = event; return [`+${red}R ${blue}B`, '']; } if (type === 'Removal') { const { effect } = event; return `-${effect}`; } return false; } function convertItem(v) { if (['Red', 'Green', 'Blue'].includes(v)) { return ( shapes.vboxColour(v.toLowerCase()) ); } return v ||  ; // uncomment for double borders in vbox; // if (v) { // return
{v}
; // } // return; } const COLOURS = [ '#a52a2a', '#1FF01F', '#3498db', ]; const TARGET_COLOURS = { BLUE: '#004bfe', CYAN: '#27e7c0', PURPLE: '#61008c', YELLOW: '#fdfe02', ORANGE: '#ff9215', PINK: '#e766b6', GRAY: '#9d9ea0', LBLUE: '#87c6f2', GREEN: '#166c4f', BROWN: '#583108', }; function randomPoints(numPoints, radius, dimensions) { const { x, y, width, height, } = dimensions; const points = []; let infCheck = 0; while (points.length < numPoints) { const c = [ Math.floor(Math.random() * (x + width - 2 * radius) + x + radius), Math.floor(Math.random() * (y + height - 2 * radius) + y + radius), ]; let overlapping = false; for (let j = 0; j < points.length; j += 1) { const o = points[j]; const dx = c[0] - o[0]; const dy = c[1] - o[1]; const d = Math.floor(Math.sqrt(dx * dx + dy * dy)); if (d < radius) { overlapping = true; } } if (!overlapping) { points.push(c); infCheck = 0; } else { infCheck += 1; if (infCheck > 100) { break; } } } return points; } const removeTier = skill => { if (skill.includes('SiphonTick')) return 'SiphonTick'; if (skill.includes('Strike')) return 'Strike'; if (skill.includes('Heal')) return 'Heal'; if (skill.includes('Blast')) return 'Blast'; if (skill.includes('Chaos')) return 'Chaos'; if (skill.includes('Slay')) return 'Slay'; if (skill.includes('Siphon')) return 'Siphon'; if (skill.includes('Snare')) return 'Snare'; if (skill.includes('Purge')) return 'Purge'; if (skill.includes('Silence')) return 'Silence'; if (skill.includes('Curse')) return 'Curse'; if (skill.includes('Decay')) return 'Decay'; if (skill.includes('Invert')) return 'Invert'; if (skill.includes('Taunt')) return 'Taunt'; if (skill.includes('Triage')) return 'Triage'; if (skill.includes('Scatter')) return 'Scatter'; if (skill.includes('Haste')) return 'Haste'; if (skill.includes('Hybrid')) return 'Hybrid'; if (skill.includes('Amplify')) return 'Amplify'; if (skill.includes('Parry')) return 'Parry'; if (skill.includes('Purify')) return 'Purify'; if (skill.includes('Electrify')) return 'Electrify'; if (skill.includes('Clutch')) return 'Clutch'; if (skill.includes('Reflect')) return 'Reflect'; if (skill.includes('Recharge')) return 'Recharge'; if (skill.includes('Bash')) return 'Bash'; if (skill.includes('Sleep')) return 'Sleep'; if (skill.includes('Ruin')) return 'Ruin'; if (skill.includes('Throw')) return 'Throw'; if (skill.includes('Hex')) return 'Hex'; if (skill.includes('Banish')) return 'Banish'; return skill; }; const SERVER = process.env.NODE_ENV === 'production' ? '/api/' : 'http://localhost:40000/api'; function postData(url = '/', data = {}) { // Default options are marked with * return fetch(`${SERVER}${url}`, { method: "POST", // *GET, POST, PUT, DELETE, etc. // mode: "no-cors", // no-cors, cors, *same-origin cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached credentials: "include", // include, same-origin, *omit headers: { 'Accept': 'application/json', 'content-type': 'application/json' }, redirect: "error", // manual, *follow, error // referrer: "", // no-referrer, *client body: JSON.stringify(data), // body data type must match "Content-Type" header }) } module.exports = { stringSort, convertItem, numSort, eventClasses, getCombatSequence, getCombatText, postData, SERVER, NULL_UUID, STATS, COLOURS, TARGET_COLOURS, randomPoints, removeTier, };