osrs-tools
Version:
A comprehensive TypeScript library for Old School RuneScape (OSRS) data and utilities, including quest data, skill requirements, and game item information
184 lines (183 loc) • 6.9 kB
JavaScript
import { LevelRequirement } from "../Requirement";
import { Skill } from "../account/Skill";
/**
* Hunting methods used for Hunters' Rumours.
* Each method has its own drop rate for rare creature parts.
* Reference: https://oldschool.runescape.wiki/w/Hunters%27_Rumours
*/
export var HuntingMethod;
(function (HuntingMethod) {
HuntingMethod["BirdSnare"] = "Bird snare";
HuntingMethod["BoxTrap"] = "Box trap";
HuntingMethod["ButterflyNet"] = "Butterfly net";
HuntingMethod["Deadfall"] = "Deadfall";
HuntingMethod["Falconry"] = "Falconry";
HuntingMethod["NetTrap"] = "Net trap";
HuntingMethod["SpikedPit"] = "Spiked pit";
HuntingMethod["TrackingKebbit"] = "Tracking (kebbit)";
HuntingMethod["TrackingHerbiboar"] = "Tracking (herbiboar)";
})(HuntingMethod || (HuntingMethod = {}));
/**
* Tier of a Hunter's Rumour.
* Each tier has its own Hunter level requirement and reward quality.
*/
export var RumourTier;
(function (RumourTier) {
RumourTier["Novice"] = "Novice";
RumourTier["Adept"] = "Adept";
RumourTier["Expert"] = "Expert";
RumourTier["Master"] = "Master";
})(RumourTier || (RumourTier = {}));
/**
* Hunters' loot sack variants by rumour tier.
*/
export var HunterLootSackType;
(function (HunterLootSackType) {
HunterLootSackType["Basic"] = "Hunters' loot sack (basic)";
HunterLootSackType["Adept"] = "Hunters' loot sack (adept)";
HunterLootSackType["Expert"] = "Hunters' loot sack (expert)";
HunterLootSackType["Master"] = "Hunters' loot sack (master)";
})(HunterLootSackType || (HunterLootSackType = {}));
/**
* Guild hunters who assign Hunters' Rumours.
* Each hunter has a distinct list of rumours they can assign.
*/
export var GuildHunterName;
(function (GuildHunterName) {
GuildHunterName["Gilman"] = "Huntmaster Gilman";
GuildHunterName["Cervus"] = "Guild Hunter Cervus";
GuildHunterName["Ornus"] = "Guild Hunter Ornus";
GuildHunterName["Aco"] = "Guild Hunter Aco";
GuildHunterName["Teco"] = "Guild Hunter Teco";
GuildHunterName["Wolf"] = "Guild Hunter Wolf";
})(GuildHunterName || (GuildHunterName = {}));
/**
* Drop rates for rare creature parts by hunting method.
* Reference: https://oldschool.runescape.wiki/w/Hunters%27_Rumours#Drop_rates
*/
export const DROP_RATES = {
[]: { baseRate: 20, pityThreshold: 40, pityThresholdWithOutfit: 38 },
[]: { baseRate: 50, pityThreshold: 100, pityThresholdWithOutfit: 94 },
[]: { baseRate: 75, pityThreshold: 150, pityThresholdWithOutfit: 142 },
[]: { baseRate: 15, pityThreshold: 30, pityThresholdWithOutfit: 28 },
[]: { baseRate: 10, pityThreshold: 20, pityThresholdWithOutfit: 18 },
[]: { baseRate: 25, pityThreshold: 50, pityThresholdWithOutfit: 46 },
[]: { baseRate: 15, pityThreshold: 30, pityThresholdWithOutfit: 28 },
[]: { baseRate: 15, pityThreshold: 30, pityThresholdWithOutfit: 28 },
[]: { baseRate: 7, pityThreshold: 14, pityThresholdWithOutfit: 12 },
};
/**
* Experience modifier per rumour tier, used in the reward formula:
* Experience = (HunterLevel + 5) * Modifier
*/
export const TIER_XP_MODIFIER = {
[]: 50,
[]: 50,
[]: 55,
[]: 60,
};
/**
* Loot sack metadata from the wiki's rewards table.
*/
export const HUNTER_LOOT_SACK_INFO = {
[]: {
sackType: HunterLootSackType.Basic,
estimatedGpValue: 7705.71,
minimumHunterLevel: 46,
minimumHunterXp: 2550,
maximumHunterXp: 5200,
},
[]: {
sackType: HunterLootSackType.Adept,
estimatedGpValue: 21802.42,
minimumHunterLevel: 57,
minimumHunterXp: 3100,
maximumHunterXp: 5200,
},
[]: {
sackType: HunterLootSackType.Expert,
estimatedGpValue: 28609.94,
minimumHunterLevel: 72,
minimumHunterXp: 4235,
maximumHunterXp: 5720,
},
[]: {
sackType: HunterLootSackType.Master,
estimatedGpValue: 34604.61,
minimumHunterLevel: 91,
minimumHunterXp: 5760,
maximumHunterXp: 6240,
},
};
/**
* Rumour completion milestone unlocks.
*/
export const RUMOUR_MILESTONE_UNLOCKS = [
{
rumoursCompleted: 10,
unlock: "A basic quetzal whistle blueprint from Soar Leader Pitri, to craft a basic quetzal whistle.",
},
{
rumoursCompleted: 25,
unlock: "The ability to cook raw graahk, raw kyatt, and raw pyre foxes.",
},
{
rumoursCompleted: 50,
unlock: "The ability to cook raw dashing kebbit, raw sunlight antelope, and raw moonlight antelope.",
},
{
rumoursCompleted: 50,
unlock: "A tattered request note from Guildmaster Apatura.",
},
{
rumoursCompleted: 100,
unlock: "A torn enhanced quetzal whistle blueprint from any hunters' loot sack, to craft an enhanced quetzal whistle.",
},
{
rumoursCompleted: 100,
unlock: "A guild history excerpt from Guildmaster Apatura.",
},
{
rumoursCompleted: 150,
unlock: "A special chest key from Guildmaster Apatura.",
},
{
rumoursCompleted: 250,
unlock: "A torn perfected quetzal whistle blueprint from any expert or master hunters' loot sack, to craft a perfected quetzal whistle.",
},
];
/**
* Calculate the Hunter experience rewarded for completing a rumour.
* @param hunterLevel - The player's current Hunter level
* @param tier - The tier of the completed rumour
* @returns The experience awarded
*/
export function calculateRumourExperience(hunterLevel, tier) {
return (hunterLevel + 5) * TIER_XP_MODIFIER[tier];
}
/**
* Create an unboostable Hunter level requirement helper.
*/
export function createHunterLevelRequirement(level) {
return new LevelRequirement(Skill.Hunter, level, false);
}
/**
* Get milestones unlocked at a total rumour completion count.
*/
export function getMilestoneUnlocks(rumoursCompleted) {
return RUMOUR_MILESTONE_UNLOCKS.filter((milestone) => milestone.rumoursCompleted === rumoursCompleted);
}
/**
* Open a hunters' loot sack for a completed rumour.
* Returns deterministic reward metadata and XP calculation from official formula.
*/
export function openHuntersLootSack(tier, hunterLevel, rumoursCompleted = 0) {
const info = HUNTER_LOOT_SACK_INFO[tier];
return {
sackType: info.sackType,
tier,
estimatedGpValue: info.estimatedGpValue,
hunterExperience: calculateRumourExperience(hunterLevel, tier),
milestonesUnlocked: getMilestoneUnlocks(rumoursCompleted),
};
}