First commit of os-league-tools-master
This commit is contained in:
26
os-league-tools-master/src/util/calculateCombatLevel.js
Normal file
26
os-league-tools-master/src/util/calculateCombatLevel.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @see https://oldschool.runescape.wiki/w/Combat_level
|
||||
* @param {{}} skills Pass in Redux stored hiscores object
|
||||
*/
|
||||
export default function calculateCombatLevel({
|
||||
attack = {},
|
||||
strength = {},
|
||||
defence = {},
|
||||
prayer = {},
|
||||
hitpoints = {},
|
||||
magic = {},
|
||||
ranged = {},
|
||||
} = {}) {
|
||||
const base = 0.25 * (defence.level + hitpoints.level + Math.floor(prayer.level / 2));
|
||||
|
||||
const meeleCombat = 0.325 * (attack.level + strength.level);
|
||||
const rangedCombat = 0.325 * (ranged.level * 1.5);
|
||||
const magicCombat = 0.325 * (magic.level * 1.5);
|
||||
|
||||
const combatLevel = base + Math.max(...[meeleCombat, rangedCombat, magicCombat]);
|
||||
|
||||
return {
|
||||
exact: combatLevel,
|
||||
rounded: Math.floor(combatLevel),
|
||||
};
|
||||
}
|
||||
19
os-league-tools-master/src/util/calculateQuestStats.js
Normal file
19
os-league-tools-master/src/util/calculateQuestStats.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import QUESTS, { QUEST_STATUS } from '../data/quests';
|
||||
|
||||
export default function calculateQuestStats(questState) {
|
||||
const completedQuests = Object.entries(questState).filter(([, status]) => status === QUEST_STATUS.FINISHED);
|
||||
const inProgressQuests = Object.entries(questState).filter(([, status]) => status === QUEST_STATUS.IN_PROGRESS);
|
||||
const totalQuests = QUESTS.length;
|
||||
|
||||
let questPoints = 0;
|
||||
const finished = completedQuests.length;
|
||||
const inProgress = inProgressQuests.length;
|
||||
const notStarted = totalQuests - finished - inProgress;
|
||||
|
||||
for (const [id] of completedQuests) {
|
||||
const questDetails = QUESTS.find(quest => quest.id === id);
|
||||
questPoints += questDetails?.points || 0;
|
||||
}
|
||||
|
||||
return { points: questPoints, finished, inProgress, notStarted };
|
||||
}
|
||||
213
os-league-tools-master/src/util/calculateTaskStats.js
Normal file
213
os-league-tools-master/src/util/calculateTaskStats.js
Normal file
@@ -0,0 +1,213 @@
|
||||
import { forEach } from 'lodash';
|
||||
import { DIFFICULTY } from '../data/constants';
|
||||
import { NONE_REGION_ID, regionsById } from '../data/regions';
|
||||
import tasks from '../data/tasks';
|
||||
|
||||
const ALL_TASKS = {
|
||||
total: {
|
||||
Easy: 224,
|
||||
Medium: 536,
|
||||
Hard: 437,
|
||||
Elite: 345,
|
||||
Master: 47,
|
||||
total: 1589,
|
||||
},
|
||||
General: {
|
||||
Easy: 76,
|
||||
Medium: 177,
|
||||
Hard: 101,
|
||||
Elite: 127,
|
||||
Master: 7,
|
||||
total: 488,
|
||||
},
|
||||
Misthalin: {
|
||||
Easy: 42,
|
||||
Medium: 44,
|
||||
Hard: 16,
|
||||
Elite: 12,
|
||||
Master: 0,
|
||||
total: 114,
|
||||
},
|
||||
Karamja: {
|
||||
Easy: 5,
|
||||
Medium: 17,
|
||||
Hard: 13,
|
||||
Elite: 12,
|
||||
Master: 7,
|
||||
total: 54,
|
||||
},
|
||||
Asgarnia: {
|
||||
Easy: 8,
|
||||
Medium: 32,
|
||||
Hard: 30,
|
||||
Elite: 22,
|
||||
Master: 3,
|
||||
total: 95,
|
||||
},
|
||||
Desert: {
|
||||
Easy: 15,
|
||||
Medium: 39,
|
||||
Hard: 34,
|
||||
Elite: 19,
|
||||
Master: 5,
|
||||
total: 112,
|
||||
},
|
||||
Fremennik: {
|
||||
Easy: 14,
|
||||
Medium: 32,
|
||||
Hard: 41,
|
||||
Elite: 23,
|
||||
Master: 2,
|
||||
total: 112,
|
||||
},
|
||||
Kandarin: {
|
||||
Easy: 13,
|
||||
Medium: 37,
|
||||
Hard: 30,
|
||||
Elite: 20,
|
||||
Master: 3,
|
||||
total: 103,
|
||||
},
|
||||
Kourend: {
|
||||
Easy: 15,
|
||||
Medium: 41,
|
||||
Hard: 38,
|
||||
Elite: 22,
|
||||
Master: 3,
|
||||
total: 119,
|
||||
},
|
||||
Morytania: {
|
||||
Easy: 7,
|
||||
Medium: 35,
|
||||
Hard: 31,
|
||||
Elite: 23,
|
||||
Master: 5,
|
||||
total: 101,
|
||||
},
|
||||
Tirannwn: {
|
||||
Easy: 8,
|
||||
Medium: 16,
|
||||
Hard: 33,
|
||||
Elite: 24,
|
||||
Master: 4,
|
||||
total: 85,
|
||||
},
|
||||
Varlamore: {
|
||||
Easy: 12,
|
||||
Medium: 40,
|
||||
Hard: 39,
|
||||
Elite: 15,
|
||||
Master: 5,
|
||||
total: 111,
|
||||
},
|
||||
Wilderness: {
|
||||
Easy: 9,
|
||||
Medium: 26,
|
||||
Hard: 31,
|
||||
Elite: 26,
|
||||
Master: 3,
|
||||
total: 95,
|
||||
},
|
||||
};
|
||||
|
||||
export default function calculateTaskStats(taskState, unlockedRegions) {
|
||||
const tasksCount = {
|
||||
complete: {
|
||||
Easy: 0,
|
||||
Medium: 0,
|
||||
Hard: 0,
|
||||
Elite: 0,
|
||||
Master: 0,
|
||||
},
|
||||
todo: {
|
||||
Easy: 0,
|
||||
Medium: 0,
|
||||
Hard: 0,
|
||||
Elite: 0,
|
||||
Master: 0,
|
||||
},
|
||||
ignored: {
|
||||
Easy: 0,
|
||||
Medium: 0,
|
||||
Hard: 0,
|
||||
Elite: 0,
|
||||
Master: 0,
|
||||
},
|
||||
};
|
||||
Object.keys(taskState).forEach(taskId => {
|
||||
if (!tasks[taskId]) {
|
||||
return;
|
||||
}
|
||||
const { difficulty } = tasks[taskId];
|
||||
const { completed, todo, ignored } = taskState[taskId];
|
||||
tasksCount.complete[difficulty.label] += completed ? 1 : 0;
|
||||
tasksCount.todo[difficulty.label] += todo ? 1 : 0;
|
||||
tasksCount.ignored[difficulty.label] += ignored ? 1 : 0;
|
||||
});
|
||||
|
||||
const allTasks = { ...ALL_TASKS.General };
|
||||
forEach(unlockedRegions, regionId => {
|
||||
if (regionId === NONE_REGION_ID) {
|
||||
return;
|
||||
}
|
||||
const regionName = regionsById[regionId].label;
|
||||
allTasks.Easy += ALL_TASKS[regionName].Easy;
|
||||
allTasks.Medium += ALL_TASKS[regionName].Medium;
|
||||
allTasks.Hard += ALL_TASKS[regionName].Hard;
|
||||
allTasks.Elite += ALL_TASKS[regionName].Elite;
|
||||
allTasks.Master += ALL_TASKS[regionName].Master;
|
||||
});
|
||||
|
||||
tasksCount.available = {
|
||||
Easy: allTasks.Easy - tasksCount.ignored.Easy,
|
||||
Medium: allTasks.Medium - tasksCount.ignored.Medium,
|
||||
Hard: allTasks.Hard - tasksCount.ignored.Hard,
|
||||
Elite: allTasks.Elite - tasksCount.ignored.Elite,
|
||||
Master: allTasks.Master - tasksCount.ignored.Master,
|
||||
};
|
||||
|
||||
const pointsCount = {
|
||||
points: {
|
||||
complete: {},
|
||||
todo: {},
|
||||
available: {},
|
||||
},
|
||||
};
|
||||
Object.keys(DIFFICULTY).forEach(difficultyKey => {
|
||||
const { label: difficulty, value } = DIFFICULTY[difficultyKey];
|
||||
pointsCount.points.complete[difficulty] = tasksCount.complete[difficulty] * value;
|
||||
pointsCount.points.todo[difficulty] = tasksCount.todo[difficulty] * value;
|
||||
pointsCount.points.available[difficulty] = tasksCount.available[difficulty] * value;
|
||||
});
|
||||
|
||||
return {
|
||||
tasks: {
|
||||
complete: {
|
||||
...tasksCount.complete,
|
||||
total: Object.values(tasksCount.complete).reduce((a, b) => a + b),
|
||||
},
|
||||
todo: {
|
||||
...tasksCount.todo,
|
||||
total: Object.values(tasksCount.todo).reduce((a, b) => a + b),
|
||||
},
|
||||
available: {
|
||||
...tasksCount.available,
|
||||
total: Object.values(tasksCount.available).reduce((a, b) => a + b),
|
||||
},
|
||||
},
|
||||
points: {
|
||||
complete: {
|
||||
...pointsCount.points.complete,
|
||||
total: Object.values(pointsCount.points.complete).reduce((a, b) => a + b),
|
||||
},
|
||||
todo: {
|
||||
...pointsCount.points.todo,
|
||||
total: Object.values(pointsCount.points.todo).reduce((a, b) => a + b),
|
||||
},
|
||||
available: {
|
||||
...pointsCount.points.available,
|
||||
total: Object.values(pointsCount.points.available).reduce((a, b) => a + b),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
30
os-league-tools-master/src/util/colors.js
Normal file
30
os-league-tools-master/src/util/colors.js
Normal file
@@ -0,0 +1,30 @@
|
||||
export default function getAccentColorForTheme(theme) {
|
||||
switch (theme) {
|
||||
case 'tl-dark':
|
||||
return 'rgb(164 206 39)';
|
||||
case 'tb-dark':
|
||||
return 'rgb(229 217 147)';
|
||||
case 'sl-dark':
|
||||
return 'rgb(19 213 145)';
|
||||
case 'mono-dark':
|
||||
return 'rgb(249 250 251)s';
|
||||
case 'tl-light':
|
||||
return 'rgb(100 144 68)';
|
||||
case 'tb-light':
|
||||
return 'rgb(99 66 40)';
|
||||
case 'sl-light':
|
||||
return 'rgb(0 128 118)';
|
||||
case 'tr-light':
|
||||
return 'rgb(180 74 30)';
|
||||
case 'tr-dark':
|
||||
return 'rgb(220 139 54)';
|
||||
case 're-dark':
|
||||
return 'rgb(198 121 160)';
|
||||
case 're-light':
|
||||
return 'rgb(76 33 54)';
|
||||
case 'mono-light':
|
||||
return 'rgb(55 65 81)';
|
||||
default:
|
||||
return 'rgb(19 213 145)';
|
||||
}
|
||||
}
|
||||
18
os-league-tools-master/src/util/getAllQuestPrereqs.js
Normal file
18
os-league-tools-master/src/util/getAllQuestPrereqs.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { questsById } from '../data/quests';
|
||||
|
||||
function traverseQuestsRecursive(questId, callback) {
|
||||
const { prereqs } = questsById[questId];
|
||||
prereqs.forEach(id => {
|
||||
callback(id);
|
||||
traverseQuestsRecursive(id, callback);
|
||||
});
|
||||
}
|
||||
|
||||
export default function getAllQuestPrereqs(questIds) {
|
||||
const allPrereqs = new Set();
|
||||
questIds.forEach(questId => {
|
||||
allPrereqs.add(questId);
|
||||
traverseQuestsRecursive(questId, id => allPrereqs.add(id));
|
||||
});
|
||||
return Array.from(allPrereqs);
|
||||
}
|
||||
16
os-league-tools-master/src/util/getSkillsPanelData.js
Normal file
16
os-league-tools-master/src/util/getSkillsPanelData.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { STATS } from '../data/constants';
|
||||
|
||||
export default function getSkillsPanelData({ customExclusions = [] } = {}) {
|
||||
const skillsArr = [];
|
||||
const excludedItems = ['QP', 'Combat', ...customExclusions];
|
||||
|
||||
Object.keys(STATS).forEach(skillName => {
|
||||
if (excludedItems.includes(skillName)) {
|
||||
return;
|
||||
}
|
||||
const skillData = STATS[skillName];
|
||||
skillsArr[skillData.panelOrder] = skillData;
|
||||
});
|
||||
|
||||
return skillsArr;
|
||||
}
|
||||
41
os-league-tools-master/src/util/getTier.js
Normal file
41
os-league-tools-master/src/util/getTier.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { PASSIVE_RELICS, RELIC_UNLOCK_THRESHOLDS } from '../data/relics';
|
||||
import { REGION_UNLOCK_THRESHOLDS } from '../data/regions';
|
||||
import { TROPHY_THRESHOLDS } from '../data/trophies';
|
||||
|
||||
export function getTier(points) {
|
||||
let tier = 0;
|
||||
for (let i = 0; i < RELIC_UNLOCK_THRESHOLDS.length; i++) {
|
||||
if (points < RELIC_UNLOCK_THRESHOLDS[i]) {
|
||||
break;
|
||||
}
|
||||
tier++;
|
||||
}
|
||||
return tier;
|
||||
}
|
||||
|
||||
export function getExpMultiplier(tier) {
|
||||
const EXP_MULTIPLIERS = PASSIVE_RELICS.map(tierDetails => tierDetails.exp.multiplier);
|
||||
return EXP_MULTIPLIERS[tier];
|
||||
}
|
||||
|
||||
export function getRegionTier(tasksCompleted) {
|
||||
let tier = -1;
|
||||
for (let i = 0; i < REGION_UNLOCK_THRESHOLDS.length; i++) {
|
||||
if (tasksCompleted < REGION_UNLOCK_THRESHOLDS[i]) {
|
||||
break;
|
||||
}
|
||||
tier++;
|
||||
}
|
||||
return tier;
|
||||
}
|
||||
|
||||
export function getTrophyTier(points) {
|
||||
let tier = -1;
|
||||
for (let i = 0; i < TROPHY_THRESHOLDS.length; i++) {
|
||||
if (points < TROPHY_THRESHOLDS[i]) {
|
||||
break;
|
||||
}
|
||||
tier++;
|
||||
}
|
||||
return tier;
|
||||
}
|
||||
53
os-league-tools-master/src/util/numberFormatters.js
Normal file
53
os-league-tools-master/src/util/numberFormatters.js
Normal file
@@ -0,0 +1,53 @@
|
||||
const SECOND = 1000;
|
||||
const MINUTE = SECOND * 60;
|
||||
const HOUR = MINUTE * 60;
|
||||
const DAY = HOUR * 24;
|
||||
|
||||
function getTimeUnits(timestamp) {
|
||||
return {
|
||||
days: Math.floor(timestamp / DAY),
|
||||
hours: Math.floor((timestamp % DAY) / HOUR),
|
||||
minutes: Math.floor((timestamp % HOUR) / MINUTE),
|
||||
seconds: Math.floor((timestamp % MINUTE) / SECOND),
|
||||
};
|
||||
}
|
||||
|
||||
export function durationAsCountdown(endDate, startDate = Date.now()) {
|
||||
const remainingTime = endDate - startDate;
|
||||
if (remainingTime < 0) {
|
||||
return null;
|
||||
}
|
||||
const { days, hours, minutes, seconds } = getTimeUnits(remainingTime);
|
||||
return `${days}d:${hours}h:${minutes}m:${seconds}s`;
|
||||
}
|
||||
|
||||
export function durationAsRelativeTime(endDate, startDate = Date.now()) {
|
||||
if (!endDate) {
|
||||
return 'Never';
|
||||
}
|
||||
|
||||
const timeDiff = Math.abs(endDate - startDate);
|
||||
const outputPrefix = endDate > startDate ? 'in ' : '';
|
||||
const outputSuffix = endDate > startDate ? '' : ' ago';
|
||||
const { days, hours, minutes, seconds } = getTimeUnits(timeDiff);
|
||||
if (days > 0) {
|
||||
return `${outputPrefix} ${days} day(s) ${outputSuffix}`;
|
||||
} else if (hours > 0) {
|
||||
return `${outputPrefix} ${hours} hour(s) ${outputSuffix}`;
|
||||
} else if (minutes > 0) {
|
||||
return `${outputPrefix} ${minutes} minute(s) ${outputSuffix}`;
|
||||
} else if (seconds > 0) {
|
||||
return `${outputPrefix} ${seconds} second(s) ${outputSuffix}`;
|
||||
}
|
||||
return 'Just now';
|
||||
}
|
||||
/**
|
||||
* Formats a number into a locale string
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
|
||||
* @param {*} number
|
||||
* @param {*} options
|
||||
* @returns
|
||||
*/
|
||||
export function numberWithCommas(number, options) {
|
||||
return number.toLocaleString(undefined, { ...options });
|
||||
}
|
||||
99
os-league-tools-master/src/util/taskFilters.js
Normal file
99
os-league-tools-master/src/util/taskFilters.js
Normal file
@@ -0,0 +1,99 @@
|
||||
import { difference } from 'lodash';
|
||||
import { UNLOCKED_REGION_FILTER_VALUE } from '../components/CalculatorFilters';
|
||||
import { STATS } from '../data/constants';
|
||||
import { regionsById } from '../data/regions';
|
||||
import tasks, { REGION_ANY } from '../data/tasks';
|
||||
|
||||
function difficultyFilter(record, filterState) {
|
||||
if (filterState.difficulty === null) {
|
||||
return true;
|
||||
}
|
||||
return filterState.difficulty.includes(record.difficulty.label);
|
||||
}
|
||||
|
||||
function categoryFilter(record, filterState) {
|
||||
if (filterState.categories === null) {
|
||||
return true;
|
||||
}
|
||||
const recordCategory = `${record.category.label}-${record.subcategory.label}`;
|
||||
|
||||
return filterState.categories.includes(recordCategory);
|
||||
}
|
||||
|
||||
function skillFilter(record, filterState, { hiscoresState }) {
|
||||
const taskSkills = record.skillReqs.map(req => req.skill);
|
||||
|
||||
// Check if required skills are included in filter
|
||||
const includeNoReq = filterState.showNoRequirements;
|
||||
const hasValidSkills = difference(taskSkills, filterState.skills).length === 0;
|
||||
if (!hasValidSkills || (!includeNoReq && taskSkills.length === 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if level requirements should be ignored
|
||||
if (!hiscoresState || hiscoresState.loading || hiscoresState.error || filterState.showUnmetRequirements) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if level requirements are met
|
||||
let meetsRequirements = true;
|
||||
record.skillReqs.forEach(skillReq => {
|
||||
const hiscores = hiscoresState.skills[skillReq.skill.toLowerCase()];
|
||||
const levelBoost = filterState.isProductionProdigy && STATS[skillReq.skill]?.productionProdigyEligible ? 12 : 0;
|
||||
const level = (hiscores?.level || 1) + levelBoost;
|
||||
meetsRequirements = meetsRequirements && level >= skillReq.level;
|
||||
});
|
||||
return meetsRequirements;
|
||||
}
|
||||
|
||||
function prereqFilter(record, filterState, { taskState }) {
|
||||
if (filterState.showIncompletePrereqs || !record.prerequisite) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const prereq = tasks[record.prerequisite];
|
||||
return !!taskState[prereq.id]?.completed;
|
||||
}
|
||||
|
||||
function completedFilter(record, filterState, { taskState }) {
|
||||
if (filterState.status === 'all') {
|
||||
return true;
|
||||
}
|
||||
const status = !!taskState[record.id]?.completed;
|
||||
return (filterState.status === 'cmpl') === !!status;
|
||||
}
|
||||
|
||||
function todoFilter(record, filterState, { taskState }) {
|
||||
if (filterState.todo === 'all') {
|
||||
return true;
|
||||
}
|
||||
const todo = !!taskState[record.id]?.todo;
|
||||
return (filterState.todo === 'only') === !!todo;
|
||||
}
|
||||
|
||||
function ignoredFilter(record, filterState, { taskState }) {
|
||||
if (filterState.ignored === 'all') {
|
||||
return true;
|
||||
}
|
||||
const ignored = !!taskState[record.id]?.ignored;
|
||||
return (filterState.ignored === 'only') === !!ignored;
|
||||
}
|
||||
|
||||
function regionsFilter(record, filterState, { regionsState }) {
|
||||
const unlockedRegionNames = regionsState.filter(id => id >= 0).map(id => regionsById[id].label);
|
||||
if (filterState.regions[0] === UNLOCKED_REGION_FILTER_VALUE) {
|
||||
return record.regions[0] === REGION_ANY || record.regions.some(area => unlockedRegionNames.includes(area));
|
||||
}
|
||||
return record.regions.some(area => filterState.regions.includes(area));
|
||||
}
|
||||
|
||||
export default [
|
||||
difficultyFilter,
|
||||
categoryFilter,
|
||||
skillFilter,
|
||||
completedFilter,
|
||||
todoFilter,
|
||||
ignoredFilter,
|
||||
prereqFilter,
|
||||
regionsFilter,
|
||||
];
|
||||
14
os-league-tools-master/src/util/titleSort.js
Normal file
14
os-league-tools-master/src/util/titleSort.js
Normal file
@@ -0,0 +1,14 @@
|
||||
// from https://stackoverflow.com/questions/34347008/how-can-i-sort-a-javascript-array-while-ignoring-articles-a-an-the
|
||||
function stripArticles(title) {
|
||||
const articles = ['a', 'an', 'the'];
|
||||
const re = new RegExp(`^(?:(${articles.join('|')}) )(.*)$`);
|
||||
const replacor = ($0, $1, $2) => `${$2}, ${$1}`;
|
||||
|
||||
return title.toLowerCase().replace(re, replacor);
|
||||
}
|
||||
|
||||
export default function titleSort(a, b) {
|
||||
const cleanA = stripArticles(a);
|
||||
const cleanB = stripArticles(b);
|
||||
return cleanA === cleanB ? 0 : cleanA < cleanB ? -1 : 1;
|
||||
}
|
||||
21
os-league-tools-master/src/util/xpAndLevelConversions.js
Normal file
21
os-league-tools-master/src/util/xpAndLevelConversions.js
Normal file
@@ -0,0 +1,21 @@
|
||||
export const LEVEL_99_XP = 13034431;
|
||||
|
||||
export function levelToExperience(level) {
|
||||
let sum = 0;
|
||||
for (let i = 1; i < level; i++) {
|
||||
sum += Math.floor(i + 300 * 2 ** (i / 7));
|
||||
}
|
||||
return Math.floor(0.25 * sum);
|
||||
}
|
||||
|
||||
export function experienceToLevel(experience) {
|
||||
let level = 0;
|
||||
for (let i = 1; i <= 126; i++) {
|
||||
if (levelToExperience(i + 1) > experience) {
|
||||
level = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
Reference in New Issue
Block a user