osrs-tools
Version:
A comprehensive TypeScript library for Old School RuneScape (OSRS) data and utilities, including quest data, skill requirements, and game item information
347 lines (346 loc) • 11.9 kB
JavaScript
import { LevelRequirement, QuestRequirement } from "../Requirement";
import { Skill } from "../account/Skill";
import { GuildHunterName, HuntingMethod, RumourTier, createHunterLevelRequirement } from "./HunterRumour";
// ========== Rumour Definitions ==========
// Each rumour represents a hunter creature that can be assigned.
// Reference: https://oldschool.runescape.wiki/w/Hunters%27_Rumours#List_of_rumours
const hunterLevel = (level) => createHunterLevelRequirement(level);
const tropicalWagtail = {
creature: "Tropical wagtail",
hunterRequirement: hunterLevel(19),
method: HuntingMethod.BirdSnare,
locations: ["Feldip Hunter area", "The Great Conch", "Tlati Rainforest"],
requirements: [],
};
const wildKebbit = {
creature: "Wild kebbit",
hunterRequirement: hunterLevel(23),
method: HuntingMethod.Deadfall,
locations: ["Piscatoris Hunter area", "Auburnvale"],
requirements: [],
};
const sapphireGlacialis = {
creature: "Sapphire glacialis",
hunterRequirement: hunterLevel(25),
method: HuntingMethod.ButterflyNet,
locations: ["Rellekka Hunter area", "Farming Guild", "Mons Gratia"],
requirements: [],
};
const swampLizard = {
creature: "Swamp lizard",
hunterRequirement: hunterLevel(29),
method: HuntingMethod.NetTrap,
locations: ["Canifis Hunter area", "North-west of Slepe"],
requirements: [new QuestRequirement("Priest in Peril")],
};
const spinedLarupia = {
creature: "Spined larupia",
hunterRequirement: hunterLevel(31),
method: HuntingMethod.SpikedPit,
locations: ["Feldip Hunter area"],
requirements: [],
};
const barbTailedKebbit = {
creature: "Barb-tailed kebbit",
hunterRequirement: hunterLevel(33),
method: HuntingMethod.Deadfall,
locations: ["Feldip Hunter area"],
requirements: [],
};
const snowyKnight = {
creature: "Snowy knight",
hunterRequirement: hunterLevel(35),
method: HuntingMethod.ButterflyNet,
locations: ["Rellekka Hunter area", "Weiss", "Farming Guild", "Mons Gratia"],
requirements: [],
};
const pricklyKebbit = {
creature: "Prickly kebbit",
hunterRequirement: hunterLevel(37),
method: HuntingMethod.Deadfall,
locations: ["Piscatoris Hunter area"],
requirements: [],
};
const embertailedJerboa = {
creature: "Embertailed jerboa",
hunterRequirement: hunterLevel(39),
method: HuntingMethod.BoxTrap,
locations: ["West of Hunter Guild", "North-west of the Locus Oasis"],
requirements: [new QuestRequirement("Eagles' Peak")],
};
const hornedGraahk = {
creature: "Horned graahk",
hunterRequirement: hunterLevel(41),
method: HuntingMethod.SpikedPit,
locations: ["Karamja Hunter area"],
requirements: [],
};
const spottedKebbit = {
creature: "Spotted kebbit",
hunterRequirement: hunterLevel(43),
method: HuntingMethod.Falconry,
locations: ["Piscatoris falconry area"],
requirements: [],
};
const blackWarlock = {
creature: "Black warlock",
hunterRequirement: hunterLevel(45),
method: HuntingMethod.ButterflyNet,
locations: ["Feldip Hunter area", "Farming Guild", "Crypt of Tonali hunter area", "Tlati Rainforest", "Shimmering Atoll"],
requirements: [],
};
const orangeSalamander = {
creature: "Orange salamander",
hunterRequirement: hunterLevel(47),
method: HuntingMethod.NetTrap,
locations: ["The Great Conch", "Uzer Hunter area", "Necropolis Hunter area"],
requirements: [],
};
const razorBackedKebbit = {
creature: "Razor-backed kebbit",
hunterRequirement: hunterLevel(49),
method: HuntingMethod.TrackingKebbit,
locations: ["Piscatoris Hunter area"],
requirements: [],
};
const sabreToothKebbit = {
creature: "Sabre-toothed kebbit",
hunterRequirement: hunterLevel(51),
method: HuntingMethod.Deadfall,
locations: ["Rellekka Hunter area"],
requirements: [],
};
const greyChinchompa = {
creature: "Grey chinchompa",
hunterRequirement: hunterLevel(53),
method: HuntingMethod.BoxTrap,
locations: ["Piscatoris Hunter area", "Kourend Woodland", "Isle of Souls"],
requirements: [new QuestRequirement("Eagles' Peak")],
};
const sabreToothKyatt = {
creature: "Sabre-toothed kyatt",
hunterRequirement: hunterLevel(55),
method: HuntingMethod.SpikedPit,
locations: ["Rellekka Hunter area"],
requirements: [],
};
const darkKebbit = {
creature: "Dark kebbit",
hunterRequirement: hunterLevel(57),
method: HuntingMethod.Falconry,
locations: ["Piscatoris falconry area"],
requirements: [],
};
const pyreFox = {
creature: "Pyre fox",
hunterRequirement: hunterLevel(57),
method: HuntingMethod.Deadfall,
locations: ["Avium Savannah"],
requirements: [],
};
const redSalamander = {
creature: "Red salamander",
hunterRequirement: hunterLevel(59),
method: HuntingMethod.NetTrap,
locations: ["Ourania Hunter area", "Charred Island"],
requirements: [],
};
const redChinchompa = {
creature: "Red chinchompa",
hunterRequirement: hunterLevel(63),
method: HuntingMethod.BoxTrap,
locations: ["Chinchompa Island", "Feldip Hunter area", "The Great Conch", "Gwenith Hunter area", "Red chinchompa hunting ground", "Tlati Rainforest"],
requirements: [new QuestRequirement("Eagles' Peak")],
};
const dashingKebbit = {
creature: "Dashing kebbit",
hunterRequirement: hunterLevel(69),
method: HuntingMethod.Falconry,
locations: ["Piscatoris falconry area"],
requirements: [],
};
const sunlightAntelope = {
creature: "Sunlight antelope",
hunterRequirement: hunterLevel(72),
method: HuntingMethod.SpikedPit,
locations: ["Avium Savannah"],
requirements: [],
};
const sunlightMoth = {
creature: "Sunlight moth",
hunterRequirement: hunterLevel(75),
method: HuntingMethod.ButterflyNet,
locations: ["Avium Savannah", "Neypotzli"],
requirements: [],
};
const tecuSalamander = {
creature: "Tecu salamander",
hunterRequirement: hunterLevel(79),
method: HuntingMethod.NetTrap,
locations: ["Ralos' Rise"],
requirements: [],
};
const herbiboar = {
creature: "Herbiboar",
hunterRequirement: hunterLevel(80),
method: HuntingMethod.TrackingHerbiboar,
locations: ["Mushroom Forest on Fossil Island"],
requirements: [new QuestRequirement("Bone Voyage"), new LevelRequirement(Skill.Herblore, 31, false)],
};
const moonlightMoth = {
creature: "Moonlight moth",
hunterRequirement: hunterLevel(85),
method: HuntingMethod.ButterflyNet,
locations: ["The Burrow", "Neypotzli", "Ruins of Tapoyauik", "Tonali Cavern"],
requirements: [],
};
const moonlightAntelope = {
creature: "Moonlight antelope",
hunterRequirement: hunterLevel(91),
method: HuntingMethod.SpikedPit,
locations: ["The Burrow"],
requirements: [],
};
// ========== All Rumours ==========
/** All hunter rumours sorted by Hunter level */
export const ALL_RUMOURS = [
tropicalWagtail,
wildKebbit,
sapphireGlacialis,
swampLizard,
spinedLarupia,
barbTailedKebbit,
snowyKnight,
pricklyKebbit,
embertailedJerboa,
hornedGraahk,
spottedKebbit,
blackWarlock,
orangeSalamander,
razorBackedKebbit,
sabreToothKebbit,
greyChinchompa,
sabreToothKyatt,
darkKebbit,
pyreFox,
redSalamander,
redChinchompa,
dashingKebbit,
sunlightAntelope,
sunlightMoth,
tecuSalamander,
herbiboar,
moonlightMoth,
moonlightAntelope,
];
// ========== Guild Hunter Definitions ==========
/**
* Huntmaster Gilman (Novice) - Can assign all rumours.
*/
export const Gilman = {
name: GuildHunterName.Gilman,
tier: RumourTier.Novice,
levelRequired: hunterLevel(46),
rumours: [...ALL_RUMOURS],
};
/**
* Guild Hunter Cervus (Adept) - Has a distinct adept rumour list.
*/
export const Cervus = {
name: GuildHunterName.Cervus,
tier: RumourTier.Adept,
levelRequired: hunterLevel(57),
rumours: [swampLizard, hornedGraahk, spottedKebbit, blackWarlock, orangeSalamander, razorBackedKebbit, sabreToothKebbit, greyChinchompa, darkKebbit, pyreFox, redChinchompa, sunlightMoth],
};
/**
* Guild Hunter Ornus (Adept) - Has a distinct adept rumour list.
*/
export const Ornus = {
name: GuildHunterName.Ornus,
tier: RumourTier.Adept,
levelRequired: hunterLevel(57),
rumours: [spinedLarupia, snowyKnight, embertailedJerboa, spottedKebbit, orangeSalamander, sabreToothKebbit, sabreToothKyatt, pyreFox, redSalamander, redChinchompa],
};
/**
* Guild Hunter Aco (Expert) - Has a distinct expert rumour list.
*/
export const Aco = {
name: GuildHunterName.Aco,
tier: RumourTier.Expert,
levelRequired: hunterLevel(72),
rumours: [orangeSalamander, sabreToothKebbit, greyChinchompa, sabreToothKyatt, darkKebbit, redSalamander, redChinchompa, dashingKebbit, sunlightAntelope, tecuSalamander, moonlightMoth],
};
/**
* Guild Hunter Teco (Expert) - Has a distinct expert rumour list.
*/
export const Teco = {
name: GuildHunterName.Teco,
tier: RumourTier.Expert,
levelRequired: hunterLevel(72),
rumours: [sabreToothKebbit, greyChinchompa, sabreToothKyatt, darkKebbit, redSalamander, redChinchompa, dashingKebbit, sunlightAntelope, sunlightMoth, herbiboar],
};
/**
* Guild Hunter Wolf (Master) - Requires completion of At First Light.
*/
export const Wolf = {
name: GuildHunterName.Wolf,
tier: RumourTier.Master,
levelRequired: hunterLevel(91),
questRequired: "At First Light",
rumours: [redSalamander, redChinchompa, dashingKebbit, sunlightAntelope, tecuSalamander, herbiboar, moonlightMoth, moonlightAntelope],
};
/** All guild hunters */
export const ALL_GUILD_HUNTERS = [Gilman, Cervus, Ornus, Aco, Teco, Wolf];
// ========== Utility Functions ==========
/**
* Get a guild hunter by name.
* @param name - The guild hunter's name (enum or string)
* @returns The guild hunter, or undefined if not found
*/
export function getGuildHunterByName(name) {
return ALL_GUILD_HUNTERS.find((h) => h.name === name);
}
/**
* Get all guild hunters for a specific tier.
* @param tier - The rumour tier
* @returns Array of guild hunters for that tier
*/
export function getGuildHuntersByTier(tier) {
return ALL_GUILD_HUNTERS.filter((h) => h.tier === tier);
}
/**
* Get the available rumours for a guild hunter, excluding any creatures
* already assigned as active rumours from other hunters.
*
* This implements the "blocking" mechanic: players cannot receive the same
* task from multiple guild hunters at once. By obtaining a task from one
* hunter first, it is blocked from appearing with another.
*
* Example: If Gilman assigns "Swamp lizard", Cervus cannot assign "Swamp lizard"
* until the Gilman assignment is completed or reset.
*
* @param hunter - The guild hunter to get available rumours for
* @param activeRumours - Rumours currently assigned from other guild hunters
* @returns Rumours the hunter can assign, excluding blocked ones
*/
export function getAvailableRumours(hunter, activeRumours = []) {
const blockedCreatures = new Set(activeRumours.map((r) => r.creature));
return hunter.rumours.filter((r) => !blockedCreatures.has(r.creature));
}
/**
* Find a rumour by creature name.
* @param creature - The creature name to search for (case-insensitive)
* @returns The matching rumour, or undefined if not found
*/
export function getRumourByCreature(creature) {
const lower = creature.toLowerCase();
return ALL_RUMOURS.find((r) => r.creature.toLowerCase() === lower);
}
/**
* Get all guild hunters that can assign a specific rumour.
* @param rumour - The rumour to check
* @returns Array of guild hunters who include this rumour in their list
*/
export function getHuntersForRumour(rumour) {
return ALL_GUILD_HUNTERS.filter((h) => h.rumours.some((r) => r.creature === rumour.creature));
}