a collection of tools for fly for fun universe
skillulator.lol
1import type { Jobs, Skills } from "../types";
2import { SKILL_BRACKETS, type JOB_SKILLPOINTS } from "./constants";
3
4export function getJobById(jobId: number, jobs: Jobs) {
5 return jobs.filter((job) => job.id === jobId).at(0);
6}
7
8export function getSkillById(skillId: number, skills: Skills) {
9 return skills.filter((skill) => skill.id === skillId).at(0);
10}
11
12export interface SkillRequirement {
13 skill: number;
14 level: number;
15 hasMinLevel: boolean;
16}
17
18export function updateSkillRequirements(
19 job: Jobs[0],
20 skillId: number,
21 newSkillLevel: number,
22): void {
23 if (!job) return;
24
25 for (const skill of job.skills) {
26 const requirement = skill.requirements.find((req) => req.skill === skillId);
27
28 if (skill?.masterVariations) {
29 for (const variation of skill.masterVariations) {
30 const masterSkillRequirement = variation.requirements.find(
31 (requirement) => requirement.skill === skillId,
32 );
33
34 if (!masterSkillRequirement) continue;
35 const requirementIndex = variation.requirements.findIndex(
36 (req) => req.skill === skillId,
37 );
38
39 console.log({ requirementIndex });
40
41 const meetsRequirement = newSkillLevel >= masterSkillRequirement.level;
42 variation.requirements[requirementIndex].hasMinLevel = meetsRequirement;
43 }
44 }
45 if (!requirement) continue;
46
47 const requirementIndex = skill.requirements.findIndex(
48 (req) => req.skill === skillId,
49 );
50
51 const meetsRequirement = newSkillLevel >= requirement.level;
52 skill.requirements[requirementIndex].hasMinLevel = meetsRequirement;
53 }
54}
55
56export function checkSkillRequirements(skill: Skills[0]): boolean {
57 return skill.requirements.every((req) => req.hasMinLevel);
58}
59
60export function isSkillMaxed(skill: Skills[0]): boolean {
61 return skill.skillLevel === skill.levels;
62}
63
64export function isMasterSkillSelected(skill: Skills[0]) {
65 return skill.skillLevel >= 1;
66}
67
68export function getJobByName(jobName: string, jobs: Jobs) {
69 return jobs.find(
70 (job) => job.name.en.toLowerCase() === jobName.toLowerCase(),
71 );
72}
73
74export function encodeTree(skills: Skills, characterLevel: number) {
75 const masterVariationSkills = skills
76 .map((skill) =>
77 skill?.masterVariations?.map(
78 (variation) => `${variation.id}:${variation.skillLevel}`,
79 ),
80 )
81 .filter(Boolean)
82 .flat()
83 .join(",");
84
85 const topLevelSkills = skills
86 .map((skill) => `${skill.id}:${skill.skillLevel}`)
87 .join(",");
88
89 return `${topLevelSkills},${masterVariationSkills}#${characterLevel}`;
90}
91
92export function decodeTree(encodedSkills: string) {
93 const characterLevel = encodedSkills.split("#").at(1);
94 const decodedTree = encodedSkills.split("#").at(0);
95 if (characterLevel && decodedTree) {
96 return {
97 normalizedSkillMap: decodedTree
98 .split(",")
99 .map((skill) => skill.split(":"))
100 .map((s) => ({ skill: Number(s[0]), level: Number(s[1]) })),
101 characterLevel,
102 };
103 }
104 throw new Error("Could not decode skill tree");
105}
106
107export function getSkillPointsForLevel(characterLevel: number): number {
108 if (characterLevel < 15) {
109 return 0;
110 }
111
112 let totalPoints = 0;
113 // this is because characters start at level one, not zero
114 // needed to calculate the correct amount of skillpoints for the first bracket
115 let previousMaxLevel = 1;
116
117 for (const bracket of SKILL_BRACKETS) {
118 const effectiveLevel = Math.min(characterLevel, bracket.maxLevel);
119 const levelsInBracket = Math.max(0, effectiveLevel - previousMaxLevel);
120 console.log(bracket, levelsInBracket, levelsInBracket * bracket.pointsPerLevel)
121
122 totalPoints += levelsInBracket * bracket.pointsPerLevel;
123 previousMaxLevel = bracket.maxLevel;
124
125 if (characterLevel <= bracket.maxLevel) {
126 break;
127 }
128 }
129
130 return totalPoints;
131}
132
133export function getJobTotalSkillPoints(
134 jobMap: typeof JOB_SKILLPOINTS,
135 jobId: number,
136 characterLevel: number,
137) {
138 if (characterLevel >= 60) {
139 return (
140 getSkillPointsForLevel(characterLevel) +
141 jobMap[jobId].firstJobSP +
142 jobMap[jobId].secondJobSP +
143 jobMap[jobId].thirdJobSP
144 );
145 }
146
147 return getSkillPointsForLevel(characterLevel) + jobMap[jobId].firstJobSP;
148}