From 8b1cfe012f5b766fd401135dcec7040b038d394c Mon Sep 17 00:00:00 2001 From: Brandon Fowler Date: Fri, 3 Feb 2023 21:04:56 -0500 Subject: [PATCH 1/7] feat: add Power & Stat Turning stats --- public/resources/scss/stats.scss | 20 +- public/resources/ts/calculate-player-stats.ts | 20 ++ public/resources/ts/development-defer.ts | 6 + public/resources/ts/globals.d.ts | 24 ++ public/resources/ts/stats-defer.ts | 6 + src/constants.js | 1 + src/constants/powers.js | 326 ++++++++++++++++++ src/lib.js | 152 ++++++++ views/stats.ejs | 105 ++++-- 9 files changed, 623 insertions(+), 37 deletions(-) create mode 100644 src/constants/powers.js diff --git a/public/resources/scss/stats.scss b/public/resources/scss/stats.scss index 488761444f..017d2f7ab1 100644 --- a/public/resources/scss/stats.scss +++ b/public/resources/scss/stats.scss @@ -1524,7 +1524,8 @@ a.additional-player-stat:hover { } .missing-pet, -.missing-accessory { +.missing-accessory, +.missing-power { filter: grayscale(0.8); transition: filter 0.2s; @@ -2563,6 +2564,23 @@ bonus-stats { } } +.stats-tuning { + bonus-stats p { + margin: 0; + } +} + +.selected-power { + display: flex; + align-items: center; + gap: 4px; + font-size: 20px; + + .piece { + margin-top: 0; + } +} + #techno-support { text-align: center; padding: 20px; diff --git a/public/resources/ts/calculate-player-stats.ts b/public/resources/ts/calculate-player-stats.ts index c397047dc5..6aa31032e7 100644 --- a/public/resources/ts/calculate-player-stats.ts +++ b/public/resources/ts/calculate-player-stats.ts @@ -84,6 +84,26 @@ export function getPlayerStats() { } } + // Thaumaturgist power + if (calculated.selected_power) { + for (const [name, value] of Object.entries(calculated.selected_power.stats)) { + if (!allowedStats.includes(name)) { + continue; + } + + stats[name].thaumaturgist_power = value; + } + } + + // Tuning points + for (const [name, value] of Object.entries(calculated.tuning_points.distribution)) { + if (!allowedStats.includes(name)) { + continue; + } + + stats[name].tuning_points = value; + } + // Skill bonus stats for (const [skill, data] of Object.entries(calculated.levels)) { const bonusStats: ItemStats = getBonusStat(data.level, `skill_${skill}` as BonusType, data.maxLevel); diff --git a/public/resources/ts/development-defer.ts b/public/resources/ts/development-defer.ts index a41ef35884..37755853ee 100644 --- a/public/resources/ts/development-defer.ts +++ b/public/resources/ts/development-defer.ts @@ -37,6 +37,12 @@ document.addEventListener("click", (e) => { } else if (element.hasAttribute("data-upgrade-accessory-index")) { item = calculated.missingAccessories.upgrades[parseInt(element.getAttribute("data-upgrade-accessory-index") as string)]; + } else if (element.hasAttribute("data-power-selected")) { + item = calculated.selected_power; + } else if (element.hasAttribute("data-power-index")) { + item = calculated.unlocked_powers[parseInt(element.getAttribute("data-power-index") as string)]; + } else if (element.hasAttribute("data-locked-power-index")) { + item = calculated.locked_powers[parseInt(element.getAttribute("data-locked-power-index") as string)]; } console.log(item); diff --git a/public/resources/ts/globals.d.ts b/public/resources/ts/globals.d.ts index 56e682e852..af43b8e4fd 100644 --- a/public/resources/ts/globals.d.ts +++ b/public/resources/ts/globals.d.ts @@ -569,6 +569,30 @@ declare const calculated: SkyCryptPlayer & { amount: number; }[]; reaper_peppers_eaten: number; + selected_power: Item & { + stats: { + [key in StatName]: number; + }; + }; + unlocked_powers: (Item & { + power_name: string; + stats: { + [key in StatName]: number; + }; + })[]; + locked_powers: (Item & { + power_name: string; + stats: { + [key in StatName]: number; + }; + })[]; + tuning_points: { + distribution: { + [key in StatName]: number; + }; + total: number; + used: number; + }; }; interface SkyCryptRelativeTime { diff --git a/public/resources/ts/stats-defer.ts b/public/resources/ts/stats-defer.ts index 3bdec3138c..8ef169064f 100644 --- a/public/resources/ts/stats-defer.ts +++ b/public/resources/ts/stats-defer.ts @@ -263,6 +263,12 @@ function fillLore(element: HTMLElement) { } else if (element.hasAttribute("data-upgrade-accessory-index")) { item = calculated.missingAccessories.upgrades[parseInt(element.getAttribute("data-upgrade-accessory-index") as string)]; + } else if (element.hasAttribute("data-power-selected")) { + item = calculated.selected_power; + } else if (element.hasAttribute("data-power-index")) { + item = calculated.unlocked_powers[parseInt(element.getAttribute("data-power-index") as string)]; + } else if (element.hasAttribute("data-locked-power-index")) { + item = calculated.locked_powers[parseInt(element.getAttribute("data-locked-power-index") as string)]; } if (item == undefined) { diff --git a/src/constants.js b/src/constants.js index 33f20d9dcf..2d1803ef65 100644 --- a/src/constants.js +++ b/src/constants.js @@ -19,3 +19,4 @@ export * from "./constants/skills.js"; export * from "./constants/skins-animations.js"; export * from "./constants/tags.js"; export * from "./constants/accessories.js"; +export * from "./constants/powers.js"; diff --git a/src/constants/powers.js b/src/constants/powers.js new file mode 100644 index 0000000000..ac24533f85 --- /dev/null +++ b/src/constants/powers.js @@ -0,0 +1,326 @@ +export const POWERS = { + fortuitous: { + type: "Starter", + id: 266, + stats: { + health: 3.35, + defense: 1.2, + strength: 4.8, + crit_chance: 4.35, + crit_damage: 4.8, + }, + }, + pretty: { + type: "Starter", + id: 38, + Damage: 8, + stats: { + health: 1.65, + defense: 1.2, + speed: 0.65, + strength: 4.8, + intelligence: 10.8, + crit_chance: 0.475, + crit_damage: 1.2, + }, + }, + protected: { + type: "Starter", + id: 307, + stats: { + health: 11.75, + defense: 10.8, + strength: 2.4, + crit_chance: 0.475, + crit_damage: 1.2, + }, + }, + simple: { + type: "Starter", + id: 1, + stats: { + health: 5.02, + defense: 3.6, + speed: 1.2, + strength: 3.6, + intelligence: 5.4, + crit_chance: 1.45, + crit_damage: 3.6, + }, + }, + warrior: { + type: "Starter", + id: 264, + stats: { + health: 3.35, + defense: 1.2, + strength: 8.4, + crit_chance: 2.4, + crit_damage: 6, + }, + }, + commando: { + type: "Intermediate", + id: 280, + stats: { + health: 5.02, + defense: 2.4, + strength: 8.4, + crit_chance: 0.475, + crit_damage: 8.4, + }, + }, + disciplined: { + type: "Intermediate", + id: 267, + stats: { + health: 5.02, + defense: 2.4, + strength: 7.2, + crit_chance: 1.45, + crit_damage: 7.2, + }, + }, + inspired: { + type: "Intermediate", + id: 351, + Damage: 4, + stats: { + health: 1.65, + defense: 1.2, + strength: 4.8, + intelligence: 16.2, + crit_chance: 0.95, + crit_damage: 3.6, + }, + }, + ominous: { + type: "Intermediate", + id: 410, + stats: { + health: 5.02, + speed: 0.95, + strength: 3.6, + intelligence: 6.1, + crit_chance: 1.45, + crit_damage: 3.6, + bonus_attack_speed: 0.9, + }, + }, + prepared: { + type: "Intermediate", + id: 297, + stats: { + health: 12.4, + speed: 11.3, + strength: 1.95, + crit_chance: 0.4, + crit_damage: 0.95, + }, + }, + scorching: { + type: "Advanced Stone", + id: 400, + stats: { + strength: 8.4, + crit_damage: 9.6, + bonus_attack_speed: 1.8, + }, + unique: { + ferocity: 7, + }, + }, + healthy: { + type: "Advanced Stone", + texture_path: "/item/SCORCHED_BOOKS", + stats: { + health: 33.6, + }, + unique: { + health: 200, + }, + }, + slender: { + type: "Advanced Stone", + texture_path: "/item/HAZMAT_ENDERMAN", + stats: { + health: 8.4, + defense: 6, + speed: 0.6, + strength: 6, + intelligence: 7.2, + crit_damage: 6, + bonus_attack_speed: 1.1, + }, + unique: { + defense: 100, + strength: 50, + }, + }, + strong: { + type: "Advanced Stone", + texture_path: "/item/MANDRAA", + stats: { + strength: 12, + crit_damage: 12, + }, + unique: { + strength: 25, + crit_damage: 25, + }, + }, + bizarre: { + type: "Advanced Stone", + texture_path: "/item/ECCENTRIC_PAINTING", + stats: { + strength: -2.4, + intelligence: 43.2, + crit_damage: -2.4, + }, + unique: { + ability_damage: 5, + }, + }, + demonic: { + type: "Advanced Stone", + texture_path: "/item/HORNS_OF_TORMENT", + stats: { + strength: 5.5, + intelligence: 27.725, + }, + unique: { + crit_damage: 50, + }, + }, + hurtful: { + type: "Advanced Stone", + texture_path: "/item/MAGMA_URCHIN", + stats: { + strength: 4.8, + crit_damage: 19.2, + }, + unique: { + bonus_attack_speed: 15, + }, + }, + pleasant: { + type: "Advanced Stone", + texture_path: "/item/PRECIOUS_PEARL", + stats: { + health: 13.45, + defense: 14.4, + }, + }, + adept: { + type: "Advanced Stone", + texture_path: "/item/END_STONE_SHULKER", + stats: { + health: 16.8, + defense: 9.6, + intelligence: 3.6, + }, + unique: { + health: 100, + defense: 40, + }, + }, + bloody: { + type: "Advanced Stone", + texture_path: "/item/BEATING_HEART", + stats: { + strength: 10.8, + intelligence: 3.6, + crit_damage: 10.8, + }, + unique: { + bonus_attack_speed: 10, + }, + }, + forceful: { + type: "Advanced Stone", + texture_path: "/item/ACACIA_BIRDHOUSE", + stats: { + health: 1.7, + strength: 18, + crit_damage: 4.8, + }, + unique: { + ferocity: 4, + }, + }, + itchy: { + type: "Advanced Stone", + texture_path: "/item/FURBALL", + stats: { + speed: 0.6, + strength: 7.2, + crit_damage: 8.4, + bonus_attack_speed: 2.15, + }, + unique: { + strength: 15, + crit_damage: 15, + }, + }, + mythical: { + type: "Advanced Stone", + texture_path: "/item/OBSIDIAN_TABLET", + stats: { + health: 5.7, + defense: 4.05, + speed: 0.95, + strength: 4.05, + intelligence: 6.1, + crit_chance: 1.65, + crit_damage: 4.05, + }, + unique: { + health: 150, + strength: 40, + }, + }, + shaded: { + type: "Advanced Stone", + texture_path: "/item/ENDER_MONOCLE", + stats: { + intelligence: 36, + }, + unique: { + ability_damage: 3, + }, + }, + silky: { + type: "Advanced Stone", + texture_path: "/item/LUXURIOUS_SPOOL", + stats: { + speed: 0.6, + crit_damage: 22.8, + }, + unique: { + bonus_attack_speed: 5, + }, + }, + sweet: { + type: "Advanced Stone", + texture_path: "/item/ROCK_CANDY", + stats: { + health: 15.1, + defense: 10.8, + speed: 1.2, + }, + unique: { + speed: 5, + }, + }, +}; + +export const POWER_TUNING_MULTIPLIERS = { + health: 5, + defense: 1, + speed: 1.5, + strength: 1, + crit_chance: 0.2, + crit_damage: 1, + bonus_attack_speed: 0.3, + intelligence: 2, +}; diff --git a/src/lib.js b/src/lib.js index 38e4a71ee2..bd36616986 100644 --- a/src/lib.js +++ b/src/lib.js @@ -824,6 +824,73 @@ function getMinionSlots(minions) { return output; } +function addPowerLoreStat(lore, stat, value) { + const statData = constants.STATS_DATA[stat]; + + lore.push( + `§${statData.color}${value >= 0 ? "+" : ""}${Math.round(value).toLocaleString()}${statData.symbol} ${ + statData.nameLore + }` + ); +} + +function getPower(name, magicalPower) { + const powerMultiplier = 29.97 * Math.pow(Math.log(0.0019 * magicalPower + 1), 1.2); + const displayName = helper.titleCase(name); + + const itemData = { + power_name: name, + display_name: displayName, + tag: { + display: { + name: displayName, + }, + }, + stats: {}, + }; + + if (name in constants.POWERS) { + const info = constants.POWERS[name]; + + const stats = {}; + const lore = [`§8${info.type} Power`, "", "§7Stats:"]; + + for (const [name, value] of Object.entries(info.stats)) { + stats[name] = value * powerMultiplier; + + addPowerLoreStat(lore, name, stats[name]); + } + + const combined = { ...stats }; + + if (info.unique) { + lore.push(""); + lore.push("§7Unique Power Bonus:"); + + for (const [name, value] of Object.entries(info.unique)) { + if (!combined[name]) { + combined[name] = value; + } else { + combined[name] += value; + } + + addPowerLoreStat(lore, name, value); + } + } + + lore.push("", `You Have: §6${magicalPower} Magical Power`); + + itemData.id = info.id; + itemData.rarity = "uncommon"; + itemData.Damage = info.Damage; + itemData.texture_path = info.texture_path; + itemData.tag.display.Lore = lore; + itemData.stats = combined; + } + + return helper.generateItem(itemData); +} + export const getItems = async ( profile, customTextures = false, @@ -2087,6 +2154,91 @@ export async function getStats( active: userProfile.nether_island_player_data?.abiphone?.active_contacts?.length || 0, }; + output.magical_power = { + total: 0, + }; + + for (const [rarity, value] of Object.entries(constants.MAGICAL_POWER)) { + output.magical_power[rarity] = items.accessory_rarities[rarity] * value || 0; + } + + output.magical_power.hegemony = items.accessory_rarities.hegemony + ? constants.MAGICAL_POWER[items.accessory_rarities.hegemony.rarity] + : 0; + + if (items.accessory_rarities.abicase) { + output.magical_power.abicase = Math.floor(output.abiphone.active / 2); + } + + for (const value of Object.values(output.magical_power)) { + output.magical_power.total += value; + } + + output.selected_power = null; + output.unlocked_powers = []; + output.locked_powers = []; + + output.tuning_points = { + distribution: {}, + total: Math.floor(output.magical_power.total / 10), + used: 0, + }; + + if ("accessory_bag_storage" in userProfile) { + const selectedPower = userProfile.accessory_bag_storage.selected_power; + + if (selectedPower) { + output.selected_power = getPower(selectedPower, output.magical_power.total); + } + + const unlockedPowers = Object.entries(constants.POWERS) + .filter( + ([_, power]) => power.type === "Starter" || (output.levels.combat.level >= 15 && power.type === "Intermediate") + ) + .map(([name, _]) => name); + + if ("unlocked_powers" in userProfile.accessory_bag_storage) { + unlockedPowers.push(...userProfile.accessory_bag_storage.unlocked_powers); + } + + for (const [power] of Object.entries(constants.POWERS)) { + if (unlockedPowers.includes(power)) { + continue; + } + + output.locked_powers.push(getPower(power, output.magical_power.total)); + } + + const selectedIndex = unlockedPowers.indexOf(selectedPower); + + if (selectedIndex !== -1) { + unlockedPowers.splice(selectedIndex, 1); + } + + for (const power of unlockedPowers) { + output.unlocked_powers.push(getPower(power, output.magical_power.total)); + } + + const tuning = userProfile.accessory_bag_storage.tuning.slot_0; + + for (const [hypixelStat, stat] of Object.entries({ + walk_speed: "speed", + critical_chance: "crit_chance", + critical_damage: "crit_damage", + })) { + tuning[stat] = tuning[hypixelStat]; + + delete tuning[hypixelStat]; + } + + for (const [name, value] of Object.entries(tuning)) { + if (!value) continue; + + output.tuning_points.used += value; + output.tuning_points.distribution[name] = value * constants.POWER_TUNING_MULTIPLIERS[name]; + } + } + // MISC const misc = {}; diff --git a/views/stats.ejs b/views/stats.ejs index daa1f86ac9..472ad20bb2 100644 --- a/views/stats.ejs +++ b/views/stats.ejs @@ -918,6 +918,7 @@ const metaDescription = getMetaDescription() Armor <% if(!items.no_inventory){ %>Weapons<% } %> <% if(!items.no_inventory){ %>Accessories<% } %> + <% if(!items.no_inventory){ %>Power<% } %> <% if(calculated.pets.length > 0){ %>Pets<% } %> <% if(!items.no_inventory){ %>Inventory<% } %> Skills @@ -935,7 +936,7 @@ const metaDescription = getMetaDescription() const notAvailable = []; if(items.no_inventory) - notAvailable.push('Weapons', 'Accessories', 'Inventory', 'Storage'); + notAvailable.push('Weapons', 'Accessories', 'Power', 'Inventory', 'Storage'); if(items.no_personal_vault) notAvailable.push('Personal Vault'); @@ -1095,41 +1096,6 @@ const metaDescription = getMetaDescription() Recombobulated: <%= items.accessories.filter(a => a.isUnique && a.extra?.recombobulated).length %> / <%= constants.RECOMBABLE_ACCESSORIES_COUNT %>
- <% - const rarities = items.accessory_rarities; - const player_magical_power = {} - - for (const rarity in constants.MAGICAL_POWER) { - player_magical_power[rarity] = 0 - player_magical_power[rarity] += rarities[rarity] * constants.MAGICAL_POWER[rarity]; - } - - const mp_hegemony = rarities.hegemony ? constants.MAGICAL_POWER[rarities.hegemony.rarity] : 0 - const mp_total = Object.values(player_magical_power).reduce((a, b) => a + b) + mp_hegemony + Math.floor(calculated.abiphone.active / 2); - %> - );' class='grey-text'>Abicase = +<%= Math.floor(calculated.abiphone.active / 2).toLocaleString() %> MP
- <% } %> -
- Total: <%= mp_total.toLocaleString() %> Magical Power - "> - Magical Power: <%= mp_total.toLocaleString() %> -

<% if(items.accessories.find(a => !a.isInactive) != undefined){ %>
@@ -1193,6 +1159,73 @@ const metaDescription = getMetaDescription() <% } %>
+
+ +

Power

+ Magical Power: <%= calculated.magical_power.total.toLocaleString() %> +

Selected Power

+ <% if (calculated.selected_power) { %> +
+
+ <% itemIcon(calculated.selected_power, ['piece-icon']); %> +
+
+ <%= calculated.selected_power.display_name %> +
+
+
+ <% } else { %> +

+ <%= calculated.display_name %> hasn't selected a power. +

+ <% } %> +

Other Powers

+
+ <% for (const [i, power] of calculated.unlocked_powers.entries()) { %> +
+ <% itemIcon(power, ['piece-icon']); %> +
+ <% } %> +
+ <% if (calculated.locked_powers.length) { %> + +
+ <% for (const [i, power] of calculated.locked_powers.entries()) { %> +
+ <% itemIcon(power, ['piece-icon']); %> +
+ <% } %> +
+ <% } %> +
+

Stats Tuning

+ Used Points: + <%= calculated.tuning_points.used %> / <%= calculated.tuning_points.total %> +
+
+
<% } %> <% if(calculated.pets.length > 0){ %>
From f3c87f3f4e4ead1b40211747e3ae5dec82b94ee6 Mon Sep 17 00:00:00 2001 From: Brandon Fowler Date: Sat, 4 Feb 2023 15:47:53 -0500 Subject: [PATCH 2/7] add spaces to power lore stats --- src/lib.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.js b/src/lib.js index bd36616986..58116d5e16 100644 --- a/src/lib.js +++ b/src/lib.js @@ -828,7 +828,7 @@ function addPowerLoreStat(lore, stat, value) { const statData = constants.STATS_DATA[stat]; lore.push( - `§${statData.color}${value >= 0 ? "+" : ""}${Math.round(value).toLocaleString()}${statData.symbol} ${ + `§${statData.color}${value >= 0 ? "+" : ""}${Math.round(value).toLocaleString()} ${statData.symbol} ${ statData.nameLore }` ); @@ -864,8 +864,7 @@ function getPower(name, magicalPower) { const combined = { ...stats }; if (info.unique) { - lore.push(""); - lore.push("§7Unique Power Bonus:"); + lore.push("", "§7Unique Power Bonus:"); for (const [name, value] of Object.entries(info.unique)) { if (!combined[name]) { From 6ddb8b69253614b809d26597ab52364913c41448 Mon Sep 17 00:00:00 2001 From: Brandon Fowler Date: Sun, 5 Feb 2023 02:42:21 -0500 Subject: [PATCH 3/7] correct power order and types --- public/resources/ts/globals.d.ts | 4 +- src/constants/powers.js | 275 ++++++++++++++++--------------- src/helper.js | 24 +++ src/lib.js | 46 ++---- views/stats.ejs | 21 +-- 5 files changed, 184 insertions(+), 186 deletions(-) diff --git a/public/resources/ts/globals.d.ts b/public/resources/ts/globals.d.ts index af43b8e4fd..2c0f63a9e7 100644 --- a/public/resources/ts/globals.d.ts +++ b/public/resources/ts/globals.d.ts @@ -575,13 +575,13 @@ declare const calculated: SkyCryptPlayer & { }; }; unlocked_powers: (Item & { - power_name: string; + power_type: string; stats: { [key in StatName]: number; }; })[]; locked_powers: (Item & { - power_name: string; + power_type: string; stats: { [key in StatName]: number; }; diff --git a/src/constants/powers.js b/src/constants/powers.js index ac24533f85..c63cb4ef2c 100644 --- a/src/constants/powers.js +++ b/src/constants/powers.js @@ -1,126 +1,7 @@ export const POWERS = { - fortuitous: { - type: "Starter", - id: 266, - stats: { - health: 3.35, - defense: 1.2, - strength: 4.8, - crit_chance: 4.35, - crit_damage: 4.8, - }, - }, - pretty: { - type: "Starter", - id: 38, - Damage: 8, - stats: { - health: 1.65, - defense: 1.2, - speed: 0.65, - strength: 4.8, - intelligence: 10.8, - crit_chance: 0.475, - crit_damage: 1.2, - }, - }, - protected: { - type: "Starter", - id: 307, - stats: { - health: 11.75, - defense: 10.8, - strength: 2.4, - crit_chance: 0.475, - crit_damage: 1.2, - }, - }, - simple: { - type: "Starter", - id: 1, - stats: { - health: 5.02, - defense: 3.6, - speed: 1.2, - strength: 3.6, - intelligence: 5.4, - crit_chance: 1.45, - crit_damage: 3.6, - }, - }, - warrior: { - type: "Starter", - id: 264, - stats: { - health: 3.35, - defense: 1.2, - strength: 8.4, - crit_chance: 2.4, - crit_damage: 6, - }, - }, - commando: { - type: "Intermediate", - id: 280, - stats: { - health: 5.02, - defense: 2.4, - strength: 8.4, - crit_chance: 0.475, - crit_damage: 8.4, - }, - }, - disciplined: { - type: "Intermediate", - id: 267, - stats: { - health: 5.02, - defense: 2.4, - strength: 7.2, - crit_chance: 1.45, - crit_damage: 7.2, - }, - }, - inspired: { - type: "Intermediate", - id: 351, - Damage: 4, - stats: { - health: 1.65, - defense: 1.2, - strength: 4.8, - intelligence: 16.2, - crit_chance: 0.95, - crit_damage: 3.6, - }, - }, - ominous: { - type: "Intermediate", - id: 410, - stats: { - health: 5.02, - speed: 0.95, - strength: 3.6, - intelligence: 6.1, - crit_chance: 1.45, - crit_damage: 3.6, - bonus_attack_speed: 0.9, - }, - }, - prepared: { - type: "Intermediate", - id: 297, - stats: { - health: 12.4, - speed: 11.3, - strength: 1.95, - crit_chance: 0.4, - crit_damage: 0.95, - }, - }, scorching: { - type: "Advanced Stone", - id: 400, + type: "Marvelous Stone", + texture_path: "/item/SCORCHED_BOOKS", stats: { strength: 8.4, crit_damage: 9.6, @@ -131,8 +12,8 @@ export const POWERS = { }, }, healthy: { - type: "Advanced Stone", - texture_path: "/item/SCORCHED_BOOKS", + type: "Grandiose Stone", + texture_path: "/item/VITAMIN_DEATH", stats: { health: 33.6, }, @@ -141,7 +22,7 @@ export const POWERS = { }, }, slender: { - type: "Advanced Stone", + type: "Grandiose Stone", texture_path: "/item/HAZMAT_ENDERMAN", stats: { health: 8.4, @@ -158,7 +39,7 @@ export const POWERS = { }, }, strong: { - type: "Advanced Stone", + type: "Grandiose Stone", texture_path: "/item/MANDRAA", stats: { strength: 12, @@ -170,7 +51,7 @@ export const POWERS = { }, }, bizarre: { - type: "Advanced Stone", + type: "Master Stone", texture_path: "/item/ECCENTRIC_PAINTING", stats: { strength: -2.4, @@ -182,7 +63,7 @@ export const POWERS = { }, }, demonic: { - type: "Advanced Stone", + type: "Master Stone", texture_path: "/item/HORNS_OF_TORMENT", stats: { strength: 5.5, @@ -193,7 +74,7 @@ export const POWERS = { }, }, hurtful: { - type: "Advanced Stone", + type: "Master Stone", texture_path: "/item/MAGMA_URCHIN", stats: { strength: 4.8, @@ -204,7 +85,7 @@ export const POWERS = { }, }, pleasant: { - type: "Advanced Stone", + type: "Master Stone", texture_path: "/item/PRECIOUS_PEARL", stats: { health: 13.45, @@ -280,6 +161,19 @@ export const POWERS = { }, }, shaded: { + type: "Advanced Stone", + texture_path: "/item/DARK_ORB", + stats: { + speed: 0.6, + strength: 4.8, + crit_damage: 18, + }, + unique: { + bonus_attack_speed: 3, + ferocity: 3, + }, + }, + sighted: { type: "Advanced Stone", texture_path: "/item/ENDER_MONOCLE", stats: { @@ -290,7 +184,7 @@ export const POWERS = { }, }, silky: { - type: "Advanced Stone", + type: "Intermediate Stone", texture_path: "/item/LUXURIOUS_SPOOL", stats: { speed: 0.6, @@ -301,7 +195,7 @@ export const POWERS = { }, }, sweet: { - type: "Advanced Stone", + type: "Intermediate Stone", texture_path: "/item/ROCK_CANDY", stats: { health: 15.1, @@ -312,6 +206,125 @@ export const POWERS = { speed: 5, }, }, + commando: { + type: "Intermediate", + id: 280, + stats: { + health: 5.02, + defense: 2.4, + strength: 8.4, + crit_chance: 0.475, + crit_damage: 8.4, + }, + }, + disciplined: { + type: "Intermediate", + id: 267, + stats: { + health: 5.02, + defense: 2.4, + strength: 7.2, + crit_chance: 1.45, + crit_damage: 7.2, + }, + }, + inspired: { + type: "Intermediate", + id: 351, + Damage: 4, + stats: { + health: 1.65, + defense: 1.2, + strength: 4.8, + intelligence: 16.2, + crit_chance: 0.95, + crit_damage: 3.6, + }, + }, + ominous: { + type: "Intermediate", + id: 410, + stats: { + health: 5.02, + speed: 0.95, + strength: 3.6, + intelligence: 6.1, + crit_chance: 1.45, + crit_damage: 3.6, + bonus_attack_speed: 0.9, + }, + }, + prepared: { + type: "Intermediate", + id: 297, + stats: { + health: 12.4, + speed: 11.3, + strength: 1.95, + crit_chance: 0.4, + crit_damage: 0.95, + }, + }, + fortuitous: { + type: "Starter", + id: 266, + stats: { + health: 3.35, + defense: 1.2, + strength: 4.8, + crit_chance: 4.35, + crit_damage: 4.8, + }, + }, + pretty: { + type: "Starter", + id: 38, + Damage: 8, + stats: { + health: 1.65, + defense: 1.2, + speed: 0.65, + strength: 4.8, + intelligence: 10.8, + crit_chance: 0.475, + crit_damage: 1.2, + }, + }, + protected: { + type: "Starter", + id: 307, + stats: { + health: 11.75, + defense: 10.8, + strength: 2.4, + crit_chance: 0.475, + crit_damage: 1.2, + }, + }, + simple: { + type: "Starter", + id: 1, + stats: { + health: 5.02, + defense: 3.6, + speed: 1.2, + strength: 3.6, + intelligence: 5.4, + crit_chance: 1.45, + crit_damage: 3.6, + }, + }, + warrior: { + type: "Starter", + id: 264, + stats: { + health: 3.35, + defense: 1.2, + strength: 8.4, + crit_chance: 2.4, + crit_damage: 6, + }, + }, }; export const POWER_TUNING_MULTIPLIERS = { diff --git a/src/helper.js b/src/helper.js index 0ca19c7b98..0ed0e91d4e 100644 --- a/src/helper.js +++ b/src/helper.js @@ -1080,3 +1080,27 @@ export function getAnimatedTexture(item) { return deepResults[0] ?? false; } + +/** + * @param {string} enrichment + * @returns string + * @description takes an enrichment name and returns the corresponding stat name + */ +export function enrichmentToStatName(enrichment) { + switch (enrichment) { + case "walk_speed": + return "speed"; + + case "critical_chance": + return "crit_chance"; + + case "critical_damage": + return "crit_damage"; + + case "attack_speed": + return "bonus_attack_speed"; + + default: + return enrichment; + } +} diff --git a/src/lib.js b/src/lib.js index 58116d5e16..a31b20d917 100644 --- a/src/lib.js +++ b/src/lib.js @@ -839,7 +839,6 @@ function getPower(name, magicalPower) { const displayName = helper.titleCase(name); const itemData = { - power_name: name, display_name: displayName, tag: { display: { @@ -884,6 +883,7 @@ function getPower(name, magicalPower) { itemData.Damage = info.Damage; itemData.texture_path = info.texture_path; itemData.tag.display.Lore = lore; + itemData.power_type = info.type; itemData.stats = combined; } @@ -2190,51 +2190,31 @@ export async function getStats( output.selected_power = getPower(selectedPower, output.magical_power.total); } - const unlockedPowers = Object.entries(constants.POWERS) - .filter( - ([_, power]) => power.type === "Starter" || (output.levels.combat.level >= 15 && power.type === "Intermediate") - ) - .map(([name, _]) => name); + const unlockedPowers = new Set(userProfile.accessory_bag_storage.unlocked_powers); - if ("unlocked_powers" in userProfile.accessory_bag_storage) { - unlockedPowers.push(...userProfile.accessory_bag_storage.unlocked_powers); - } - - for (const [power] of Object.entries(constants.POWERS)) { - if (unlockedPowers.includes(power)) { + for (const name of Object.keys(constants.POWERS)) { + if (name === selectedPower) { continue; } - output.locked_powers.push(getPower(power, output.magical_power.total)); - } - - const selectedIndex = unlockedPowers.indexOf(selectedPower); - - if (selectedIndex !== -1) { - unlockedPowers.splice(selectedIndex, 1); - } + const power = getPower(name, output.magical_power.total); + const unlocked = + power.power_type === "Starter" || + (power.power_type === "Intermediate" && output.levels.combat.level >= 15) || + unlockedPowers.has(name); - for (const power of unlockedPowers) { - output.unlocked_powers.push(getPower(power, output.magical_power.total)); + output[unlocked ? "unlocked_powers" : "locked_powers"].push(power); } const tuning = userProfile.accessory_bag_storage.tuning.slot_0; - for (const [hypixelStat, stat] of Object.entries({ - walk_speed: "speed", - critical_chance: "crit_chance", - critical_damage: "crit_damage", - })) { - tuning[stat] = tuning[hypixelStat]; - - delete tuning[hypixelStat]; - } - for (const [name, value] of Object.entries(tuning)) { if (!value) continue; + const stat = helper.enrichmentToStatName(name); + output.tuning_points.used += value; - output.tuning_points.distribution[name] = value * constants.POWER_TUNING_MULTIPLIERS[name]; + output.tuning_points.distribution[stat] = value * constants.POWER_TUNING_MULTIPLIERS[stat]; } } diff --git a/views/stats.ejs b/views/stats.ejs index 472ad20bb2..ab607cf930 100644 --- a/views/stats.ejs +++ b/views/stats.ejs @@ -234,25 +234,6 @@ function formatEnrichment(string) { return enrichment } -function enrichmentToStatName(enrichment) { - switch (enrichment) { - case 'walk_speed': - return 'speed' - - case 'critical_chance': - return 'crit_chance' - - case 'critical_damage': - return 'crit_damage' - - case 'attack_speed': - return 'bonus_attack_speed' - - default: - return enrichment - } -} - function getEnrichments(accessories) { const enrichmentCounts = {} const filteredAccessories = accessories @@ -272,7 +253,7 @@ function getEnrichments(accessories) { Enrichments: <% for (const [enrichment, amount] of Object.entries(enrichmentCounts)) { - const stat = enrichmentToStatName(enrichment) + const stat = helper.enrichmentToStatName(enrichment) %> "> <%= amount %>× <%= formatEnrichment(enrichment) %> From d871b3a87415b1fc12ed2b4a922e162a8e38c010 Mon Sep 17 00:00:00 2001 From: Brandon Fowler Date: Sun, 19 Feb 2023 13:17:10 -0500 Subject: [PATCH 4/7] fix: slot_0 might be undefined --- src/lib.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib.js b/src/lib.js index ba7d5594ed..db4d64b31b 100644 --- a/src/lib.js +++ b/src/lib.js @@ -2257,15 +2257,17 @@ export async function getStats( output[unlocked ? "unlocked_powers" : "locked_powers"].push(power); } - const tuning = userProfile.accessory_bag_storage.tuning.slot_0; + const tuning = userProfile.accessory_bag_storage.tuning?.slot_0; - for (const [name, value] of Object.entries(tuning)) { - if (!value) continue; + if (tuning) { + for (const [name, value] of Object.entries(tuning)) { + if (!value) continue; - const stat = helper.enrichmentToStatName(name); + const stat = helper.enrichmentToStatName(name); - output.tuning_points.used += value; - output.tuning_points.distribution[stat] = value * constants.POWER_TUNING_MULTIPLIERS[stat]; + output.tuning_points.used += value; + output.tuning_points.distribution[stat] = value * constants.POWER_TUNING_MULTIPLIERS[stat]; + } } } From 815ef7b885c34e561bb9ca9eb016ac78d57ec1c4 Mon Sep 17 00:00:00 2001 From: Brandon Fowler Date: Sun, 19 Feb 2023 13:17:46 -0500 Subject: [PATCH 5/7] fix: accessories were counted twice for MP --- src/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.js b/src/lib.js index db4d64b31b..f79f47c05e 100644 --- a/src/lib.js +++ b/src/lib.js @@ -1158,7 +1158,7 @@ export const getItems = async ( accessories.push(insertAccessory); accessoryIds.push(id); - accessoryRarities[insertAccessory.rarity]++; + if (insertAccessory.isInactive === false) { accessoryRarities[insertAccessory.rarity]++; if (id == "HEGEMONY_ARTIFACT") { From 7fb8293a7a68e56c8e82093771c06dd0e5cc4743 Mon Sep 17 00:00:00 2001 From: Brandon Fowler Date: Tue, 11 Jul 2023 01:47:57 -0400 Subject: [PATCH 6/7] add new powers --- common/constants/stats.js | 9 +++++++ src/constants/powers.js | 53 +++++++++++++++++++++++++++++++++++++++ src/lib.js | 1 + 3 files changed, 63 insertions(+) diff --git a/common/constants/stats.js b/common/constants/stats.js index 1c94bd4eb0..a2ef2fad27 100644 --- a/common/constants/stats.js +++ b/common/constants/stats.js @@ -237,6 +237,15 @@ export const STATS_DATA = { suffix: "", color: "3", }, + combat_wisdom: { + name: "Combat Wisdom", + nameLore: "Combat Wisdom", + nameShort: "Combat Wisdom", + nameTiny: "CW", + symbol: "☯", + suffix: "", + color: "3", + }, mana_regen: { name: "Mana Regen", nameLore: "Mana Regen", diff --git a/src/constants/powers.js b/src/constants/powers.js index c63cb4ef2c..b2fcf7b083 100644 --- a/src/constants/powers.js +++ b/src/constants/powers.js @@ -62,6 +62,22 @@ export const POWERS = { ability_damage: 5, }, }, + bubba: { + type: "Master Stone", + texture_path: "/item/BUBBA_BLISTER", + stats: { + strength: 6, + crit_damage: 10.8, + defense: -9.6, + true_defense: 1.2, + bonus_attack_speed: 1.8, + health: 5.1, + crit_chance: 0.9, + }, + unique: { + combat_wisdom: 2, + }, + }, demonic: { type: "Master Stone", texture_path: "/item/HORNS_OF_TORMENT", @@ -117,6 +133,20 @@ export const POWERS = { bonus_attack_speed: 10, }, }, + crumbly: { + type: "Advanced Stone", + texture_path: "/item/CHOCOLATE_CHIP", + stats: { + mending: 1.8, + intelligence: 5.4, + true_defense: 0.6, + vitality: 2.4, + health: 10.1, + }, + unique: { + speed: 25, + }, + }, forceful: { type: "Advanced Stone", texture_path: "/item/ACACIA_BIRDHOUSE", @@ -206,6 +236,19 @@ export const POWERS = { speed: 5, }, }, + sanguisuge: { + type: "Starter", + texture_path: "/item/DISPLACED_LEECH", + stats: { + strength: 12, + vitality: 1.2, + crit_damage: 4.8, + health: 5.1, + }, + unique: { + intelligence: 100, + }, + }, commando: { type: "Intermediate", id: 280, @@ -216,6 +259,7 @@ export const POWERS = { crit_chance: 0.475, crit_damage: 8.4, }, + unlocked_at: 15, }, disciplined: { type: "Intermediate", @@ -227,6 +271,7 @@ export const POWERS = { crit_chance: 1.45, crit_damage: 7.2, }, + unlocked_at: 15, }, inspired: { type: "Intermediate", @@ -240,6 +285,7 @@ export const POWERS = { crit_chance: 0.95, crit_damage: 3.6, }, + unlocked_at: 15, }, ominous: { type: "Intermediate", @@ -253,6 +299,7 @@ export const POWERS = { crit_damage: 3.6, bonus_attack_speed: 0.9, }, + unlocked_at: 15, }, prepared: { type: "Intermediate", @@ -264,6 +311,7 @@ export const POWERS = { crit_chance: 0.4, crit_damage: 0.95, }, + unlocked_at: 15, }, fortuitous: { type: "Starter", @@ -275,6 +323,7 @@ export const POWERS = { crit_chance: 4.35, crit_damage: 4.8, }, + unlocked_at: 0, }, pretty: { type: "Starter", @@ -289,6 +338,7 @@ export const POWERS = { crit_chance: 0.475, crit_damage: 1.2, }, + unlocked_at: 0, }, protected: { type: "Starter", @@ -300,6 +350,7 @@ export const POWERS = { crit_chance: 0.475, crit_damage: 1.2, }, + unlocked_at: 0, }, simple: { type: "Starter", @@ -313,6 +364,7 @@ export const POWERS = { crit_chance: 1.45, crit_damage: 3.6, }, + unlocked_at: 0, }, warrior: { type: "Starter", @@ -324,6 +376,7 @@ export const POWERS = { crit_chance: 2.4, crit_damage: 6, }, + unlocked_at: 0, }, }; diff --git a/src/lib.js b/src/lib.js index 402ef3fcd2..8f12a50694 100644 --- a/src/lib.js +++ b/src/lib.js @@ -943,6 +943,7 @@ function getPower(name, magicalPower) { itemData.tag.display.Lore = lore; itemData.power_type = info.type; itemData.stats = combined; + itemData.unlocked_at = info.unlocked_at; } return helper.generateItem(itemData); From 8d33a2ba465d5fb635f4e7be418610a9aa3664b9 Mon Sep 17 00:00:00 2001 From: Brandon Fowler Date: Sun, 16 Jul 2023 23:36:19 -0400 Subject: [PATCH 7/7] use unlocked_at to determine if power is unlocked --- src/lib.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.js b/src/lib.js index 8f12a50694..c6f6dd41f3 100644 --- a/src/lib.js +++ b/src/lib.js @@ -2320,9 +2320,7 @@ export async function getStats( const power = getPower(name, output.magical_power.total); const unlocked = - power.power_type === "Starter" || - (power.power_type === "Intermediate" && output.levels.combat.level >= 15) || - unlockedPowers.has(name); + ("unlocked_at" in power && output.levels.combat.level >= power.unlocked_at) || unlockedPowers.has(name); output[unlocked ? "unlocked_powers" : "locked_powers"].push(power); }