osrs-tools 2.12.0 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/runescape/model/slayer/core/MortimerSlayerMaster.d.ts +7 -3
- package/dist/runescape/model/slayer/core/MortimerSlayerMaster.js +7 -3
- package/dist/runescape/model/slayer/core/SlayerMaster.d.ts +32 -4
- package/dist/runescape/model/slayer/core/SlayerMaster.js +59 -7
- package/dist/runescape/model/slayer/core/eligibility.d.ts +7 -0
- package/dist/runescape/model/slayer/core/eligibility.js +41 -0
- package/dist/runescape/model/slayer/core/index.d.ts +1 -1
- package/dist/runescape/model/slayer/core/types.d.ts +18 -0
- package/dist/runescape/model/slayer/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Mortifier } from './Mortifier';
|
|
2
2
|
import { SlayerMaster } from './SlayerMaster';
|
|
3
3
|
import { Task } from './Task';
|
|
4
|
-
import { SlayerMasterConfig } from './types';
|
|
4
|
+
import { SlayerAssignmentContext, SlayerMasterConfig } from './types';
|
|
5
5
|
/**
|
|
6
6
|
* Configuration for Mortimer, extending the standard SlayerMaster config with the
|
|
7
7
|
* quirks that make him behave differently to every other Slayer Master.
|
|
@@ -64,8 +64,12 @@ declare class MortimerSlayerMaster extends SlayerMaster {
|
|
|
64
64
|
* Get a set of distinct, weighted-random task choices for a Mortimer visit.
|
|
65
65
|
* The number of choices scales with completedTasks (see getTaskChoiceCount()).
|
|
66
66
|
* Mortimer never offers the same task twice in a single set of choices.
|
|
67
|
-
* @
|
|
67
|
+
* @param {number} [completedTasks] - Number of tasks completed with Mortimer so far.
|
|
68
|
+
* @param {SlayerAssignmentContext} [context] - The requesting player's Slayer level, completed
|
|
69
|
+
* quests, and unlocked rewards; tasks the player doesn't qualify for are excluded (see
|
|
70
|
+
* {@link SlayerMaster.getAvailableTasks}).
|
|
71
|
+
* @returns {Task[]} The offered tasks. May be shorter than requested if there aren't enough distinct eligible tasks.
|
|
68
72
|
*/
|
|
69
|
-
getTaskChoices(completedTasks?: number): Task[];
|
|
73
|
+
getTaskChoices(completedTasks?: number, context?: SlayerAssignmentContext): Task[];
|
|
70
74
|
}
|
|
71
75
|
export { MortimerSlayerMaster };
|
|
@@ -67,11 +67,15 @@ class MortimerSlayerMaster extends SlayerMaster {
|
|
|
67
67
|
* Get a set of distinct, weighted-random task choices for a Mortimer visit.
|
|
68
68
|
* The number of choices scales with completedTasks (see getTaskChoiceCount()).
|
|
69
69
|
* Mortimer never offers the same task twice in a single set of choices.
|
|
70
|
-
* @
|
|
70
|
+
* @param {number} [completedTasks] - Number of tasks completed with Mortimer so far.
|
|
71
|
+
* @param {SlayerAssignmentContext} [context] - The requesting player's Slayer level, completed
|
|
72
|
+
* quests, and unlocked rewards; tasks the player doesn't qualify for are excluded (see
|
|
73
|
+
* {@link SlayerMaster.getAvailableTasks}).
|
|
74
|
+
* @returns {Task[]} The offered tasks. May be shorter than requested if there aren't enough distinct eligible tasks.
|
|
71
75
|
*/
|
|
72
|
-
getTaskChoices(completedTasks = 0) {
|
|
76
|
+
getTaskChoices(completedTasks = 0, context) {
|
|
73
77
|
const choiceCount = this.getTaskChoiceCount(completedTasks);
|
|
74
|
-
const remainingTasks = this.getAvailableTasks().slice();
|
|
78
|
+
const remainingTasks = this.getAvailableTasks(context).slice();
|
|
75
79
|
const choices = [];
|
|
76
80
|
while (choices.length < choiceCount && remainingTasks.length > 0) {
|
|
77
81
|
const totalWeight = remainingTasks.reduce((total, task) => total + (task.weight || 0), 0);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Task } from './Task';
|
|
2
|
-
import { SlayerMasterConfig } from './types';
|
|
2
|
+
import { SlayerAssignmentContext, SlayerMasterConfig } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* SlayerMaster class represents a Slayer Master in the game.
|
|
5
5
|
* It encapsulates the properties and methods related to a Slayer Master,
|
|
@@ -51,9 +51,32 @@ declare class SlayerMaster {
|
|
|
51
51
|
/**
|
|
52
52
|
* Get a random task based on the weighting system of the tasks.
|
|
53
53
|
* Tasks with higher weights have a higher chance of being selected.
|
|
54
|
+
* @param {SlayerAssignmentContext} [context] - The requesting player's Slayer level, completed
|
|
55
|
+
* quests, and unlocked rewards. When provided, tasks the player doesn't qualify for are
|
|
56
|
+
* excluded from both the candidate pool and the weight sum, per the task weighting formula
|
|
57
|
+
* (see https://oldschool.runescape.wiki/w/Slayer#Task_weighting). When omitted, only blocked
|
|
58
|
+
* tasks are excluded.
|
|
54
59
|
* @returns {Task | null} A randomly selected task or null if no tasks are available.
|
|
55
60
|
*/
|
|
56
|
-
getRandomTask(): Task | null;
|
|
61
|
+
getRandomTask(context?: SlayerAssignmentContext): Task | null;
|
|
62
|
+
/**
|
|
63
|
+
* Get the percentage chance of being assigned each currently available task:
|
|
64
|
+
* (w / S) * 100, where w is a task's weight and S is the sum of weights of every task
|
|
65
|
+
* the player currently qualifies for (blocked, toggled-off, and requirement-locked tasks
|
|
66
|
+
* excluded from S). Reference: https://oldschool.runescape.wiki/w/Slayer#Task_weighting
|
|
67
|
+
* @param {SlayerAssignmentContext} [context] - The requesting player's Slayer level, completed
|
|
68
|
+
* quests, and unlocked rewards. When omitted, only blocked tasks are excluded from S.
|
|
69
|
+
* @returns {Map<string, number>} Task name to percentage chance (0-100), for eligible tasks only.
|
|
70
|
+
*/
|
|
71
|
+
getTaskChances(context?: SlayerAssignmentContext): Map<string, number>;
|
|
72
|
+
/**
|
|
73
|
+
* Get the percentage chance of being assigned a specific task, by name (case insensitive).
|
|
74
|
+
* @param {string} taskName - Name of the task to check.
|
|
75
|
+
* @param {SlayerAssignmentContext} [context] - See {@link getTaskChances}.
|
|
76
|
+
* @returns {number} The percentage chance (0-100) of being assigned this task, or 0 if the
|
|
77
|
+
* task doesn't exist or isn't currently available to the player.
|
|
78
|
+
*/
|
|
79
|
+
getTaskChance(taskName: string, context?: SlayerAssignmentContext): number;
|
|
57
80
|
/**
|
|
58
81
|
* Block a task so it will no longer be returned by getRandomTask().
|
|
59
82
|
* Mirrors the in-game block list: only tasks this master actually assigns can be blocked.
|
|
@@ -76,9 +99,14 @@ declare class SlayerMaster {
|
|
|
76
99
|
*/
|
|
77
100
|
getBlockedTasks(): string[];
|
|
78
101
|
/**
|
|
79
|
-
* Get the tasks this master can currently assign
|
|
102
|
+
* Get the tasks this master can currently assign: excludes blocked tasks, and - when a
|
|
103
|
+
* player context is given - also excludes tasks whose Slayer level, combat level, skill,
|
|
104
|
+
* quest, or unlock requirements the player doesn't yet meet. A boosted Slayer level never
|
|
105
|
+
* unlocks a task; pass the player's base level.
|
|
106
|
+
* @param {SlayerAssignmentContext} [context] - The requesting player's stats/unlocks. When
|
|
107
|
+
* omitted, requirement eligibility isn't checked (only the block list is applied).
|
|
80
108
|
*/
|
|
81
|
-
getAvailableTasks(): Task[];
|
|
109
|
+
getAvailableTasks(context?: SlayerAssignmentContext): Task[];
|
|
82
110
|
/**
|
|
83
111
|
* Get the total weight of tasks
|
|
84
112
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { meetsRequirements } from './eligibility';
|
|
1
2
|
/**
|
|
2
3
|
* SlayerMaster class represents a Slayer Master in the game.
|
|
3
4
|
* It encapsulates the properties and methods related to a Slayer Master,
|
|
@@ -95,12 +96,17 @@ class SlayerMaster {
|
|
|
95
96
|
/**
|
|
96
97
|
* Get a random task based on the weighting system of the tasks.
|
|
97
98
|
* Tasks with higher weights have a higher chance of being selected.
|
|
99
|
+
* @param {SlayerAssignmentContext} [context] - The requesting player's Slayer level, completed
|
|
100
|
+
* quests, and unlocked rewards. When provided, tasks the player doesn't qualify for are
|
|
101
|
+
* excluded from both the candidate pool and the weight sum, per the task weighting formula
|
|
102
|
+
* (see https://oldschool.runescape.wiki/w/Slayer#Task_weighting). When omitted, only blocked
|
|
103
|
+
* tasks are excluded.
|
|
98
104
|
* @returns {Task | null} A randomly selected task or null if no tasks are available.
|
|
99
105
|
*/
|
|
100
|
-
getRandomTask() {
|
|
101
|
-
const availableTasks = this.getAvailableTasks();
|
|
106
|
+
getRandomTask(context) {
|
|
107
|
+
const availableTasks = this.getAvailableTasks(context);
|
|
102
108
|
if (availableTasks.length === 0)
|
|
103
|
-
return null; // Return null if there are no
|
|
109
|
+
return null; // Return null if there are no eligible tasks
|
|
104
110
|
const availableWeight = availableTasks.reduce((total, task) => total + (task.weight || 0), 0);
|
|
105
111
|
if (availableWeight <= 0)
|
|
106
112
|
return null;
|
|
@@ -114,6 +120,41 @@ class SlayerMaster {
|
|
|
114
120
|
}
|
|
115
121
|
return null; // Fallback in case no task is selected (shouldn't happen if weights are correct)
|
|
116
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Get the percentage chance of being assigned each currently available task:
|
|
125
|
+
* (w / S) * 100, where w is a task's weight and S is the sum of weights of every task
|
|
126
|
+
* the player currently qualifies for (blocked, toggled-off, and requirement-locked tasks
|
|
127
|
+
* excluded from S). Reference: https://oldschool.runescape.wiki/w/Slayer#Task_weighting
|
|
128
|
+
* @param {SlayerAssignmentContext} [context] - The requesting player's Slayer level, completed
|
|
129
|
+
* quests, and unlocked rewards. When omitted, only blocked tasks are excluded from S.
|
|
130
|
+
* @returns {Map<string, number>} Task name to percentage chance (0-100), for eligible tasks only.
|
|
131
|
+
*/
|
|
132
|
+
getTaskChances(context) {
|
|
133
|
+
const availableTasks = this.getAvailableTasks(context);
|
|
134
|
+
const availableWeight = availableTasks.reduce((total, task) => total + (task.weight || 0), 0);
|
|
135
|
+
const chances = new Map();
|
|
136
|
+
if (availableWeight <= 0)
|
|
137
|
+
return chances;
|
|
138
|
+
for (const task of availableTasks) {
|
|
139
|
+
chances.set(task.getName(), ((task.weight || 0) / availableWeight) * 100);
|
|
140
|
+
}
|
|
141
|
+
return chances;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get the percentage chance of being assigned a specific task, by name (case insensitive).
|
|
145
|
+
* @param {string} taskName - Name of the task to check.
|
|
146
|
+
* @param {SlayerAssignmentContext} [context] - See {@link getTaskChances}.
|
|
147
|
+
* @returns {number} The percentage chance (0-100) of being assigned this task, or 0 if the
|
|
148
|
+
* task doesn't exist or isn't currently available to the player.
|
|
149
|
+
*/
|
|
150
|
+
getTaskChance(taskName, context) {
|
|
151
|
+
const normalized = taskName.toLowerCase();
|
|
152
|
+
for (const [name, chance] of this.getTaskChances(context)) {
|
|
153
|
+
if (name.toLowerCase() === normalized)
|
|
154
|
+
return chance;
|
|
155
|
+
}
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
117
158
|
/**
|
|
118
159
|
* Block a task so it will no longer be returned by getRandomTask().
|
|
119
160
|
* Mirrors the in-game block list: only tasks this master actually assigns can be blocked.
|
|
@@ -149,10 +190,21 @@ class SlayerMaster {
|
|
|
149
190
|
return Array.from(this.blockedTasks);
|
|
150
191
|
}
|
|
151
192
|
/**
|
|
152
|
-
* Get the tasks this master can currently assign
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
193
|
+
* Get the tasks this master can currently assign: excludes blocked tasks, and - when a
|
|
194
|
+
* player context is given - also excludes tasks whose Slayer level, combat level, skill,
|
|
195
|
+
* quest, or unlock requirements the player doesn't yet meet. A boosted Slayer level never
|
|
196
|
+
* unlocks a task; pass the player's base level.
|
|
197
|
+
* @param {SlayerAssignmentContext} [context] - The requesting player's stats/unlocks. When
|
|
198
|
+
* omitted, requirement eligibility isn't checked (only the block list is applied).
|
|
199
|
+
*/
|
|
200
|
+
getAvailableTasks(context) {
|
|
201
|
+
return this.tasks.filter(task => {
|
|
202
|
+
if (this.isTaskBlocked(task.getName()))
|
|
203
|
+
return false;
|
|
204
|
+
if (!context)
|
|
205
|
+
return true;
|
|
206
|
+
return meetsRequirements(task.getRequirements(), context);
|
|
207
|
+
});
|
|
156
208
|
}
|
|
157
209
|
/**
|
|
158
210
|
* Get the total weight of tasks
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Requirement } from '../../Requirement';
|
|
2
|
+
import { SlayerAssignmentContext } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Checks whether every requirement in the list is satisfied by the given player context.
|
|
5
|
+
* A task with no requirements is always eligible.
|
|
6
|
+
*/
|
|
7
|
+
export declare function meetsRequirements(requirements: Requirement[], context: SlayerAssignmentContext): boolean;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { RequirementType, } from '../../Requirement';
|
|
2
|
+
function toLowerCaseSet(values) {
|
|
3
|
+
const result = new Set();
|
|
4
|
+
if (!values)
|
|
5
|
+
return result;
|
|
6
|
+
for (const value of values)
|
|
7
|
+
result.add(value.toLowerCase());
|
|
8
|
+
return result;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Checks whether a single requirement is satisfied by the given player context.
|
|
12
|
+
* Requirement types that don't gate task assignment (e.g. items to bring) are
|
|
13
|
+
* always treated as satisfied - only Slayer level, combat level, skill level,
|
|
14
|
+
* quest, and Slayer unlock requirements can block an assignment.
|
|
15
|
+
*/
|
|
16
|
+
function meetsRequirement(requirement, context) {
|
|
17
|
+
switch (requirement.type) {
|
|
18
|
+
case RequirementType.SlayerLevel:
|
|
19
|
+
return (context.slayerLevel ?? 0) >= requirement.level;
|
|
20
|
+
case RequirementType.CombatLevel:
|
|
21
|
+
return (context.combatLevel ?? 0) >= requirement.level;
|
|
22
|
+
case RequirementType.Level: {
|
|
23
|
+
const levelRequirement = requirement;
|
|
24
|
+
const playerLevel = context.skillLevels?.[levelRequirement.skillName] ?? 0;
|
|
25
|
+
return playerLevel >= levelRequirement.level;
|
|
26
|
+
}
|
|
27
|
+
case RequirementType.Quest:
|
|
28
|
+
return toLowerCaseSet(context.completedQuests).has(requirement.questName.toLowerCase());
|
|
29
|
+
case RequirementType.SlayerUnlock:
|
|
30
|
+
return toLowerCaseSet(context.unlockedRewards).has(requirement.name.toLowerCase());
|
|
31
|
+
default:
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Checks whether every requirement in the list is satisfied by the given player context.
|
|
37
|
+
* A task with no requirements is always eligible.
|
|
38
|
+
*/
|
|
39
|
+
export function meetsRequirements(requirements, context) {
|
|
40
|
+
return requirements.every(requirement => meetsRequirement(requirement, context));
|
|
41
|
+
}
|
|
@@ -10,5 +10,5 @@ export { MortimerSlayerMaster } from './MortimerSlayerMaster';
|
|
|
10
10
|
export { SlayerMaster } from './SlayerMaster';
|
|
11
11
|
export type { TaskJson } from './Task';
|
|
12
12
|
export { Task } from './Task';
|
|
13
|
-
export type { SlayerMasterConfig, TaskDefinition, TaskOptions, TaskQuantity } from './types';
|
|
13
|
+
export type { SlayerAssignmentContext, SlayerMasterConfig, TaskDefinition, TaskOptions, TaskQuantity, } from './types';
|
|
14
14
|
export { POINTS_TABLE, SlayerBoss, SlayerLocation, TASK_DEFAULTS } from './types';
|
|
@@ -94,6 +94,24 @@ export interface TaskDefinition {
|
|
|
94
94
|
* Builder options for creating tasks (alias for TaskDefinition)
|
|
95
95
|
*/
|
|
96
96
|
export type TaskOptions = TaskDefinition;
|
|
97
|
+
/**
|
|
98
|
+
* Describes what a specific player currently has access to, for the purposes of
|
|
99
|
+
* filtering which Slayer tasks a master is allowed to assign them.
|
|
100
|
+
* All fields are optional; an omitted field is treated as "player has none of these"
|
|
101
|
+
* (e.g. no completed quests), which is the conservative/safe default for eligibility checks.
|
|
102
|
+
*/
|
|
103
|
+
export interface SlayerAssignmentContext {
|
|
104
|
+
/** The player's base (unboosted) Slayer level. Boosts never unlock higher-tier tasks. */
|
|
105
|
+
slayerLevel?: number;
|
|
106
|
+
/** The player's combat level. */
|
|
107
|
+
combatLevel?: number;
|
|
108
|
+
/** Names of quests the player has completed (case-insensitive). */
|
|
109
|
+
completedQuests?: Iterable<string>;
|
|
110
|
+
/** Names of Slayer unlocks the player has purchased with reward points (case-insensitive). */
|
|
111
|
+
unlockedRewards?: Iterable<string>;
|
|
112
|
+
/** Base skill levels keyed by skill name, for tasks with non-Slayer skill requirements. */
|
|
113
|
+
skillLevels?: Partial<Record<string, number>>;
|
|
114
|
+
}
|
|
97
115
|
/**
|
|
98
116
|
* Slayer Master configuration interface
|
|
99
117
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Complete slayer system including masters, tasks, rewards, and utilities
|
|
4
4
|
* Reference: https://oldschool.runescape.wiki/w/Slayer
|
|
5
5
|
*/
|
|
6
|
-
export type { MortifierConfig, MortimerSlayerMasterConfig, SlayerMasterConfig, TaskDefinition, TaskOptions, TaskQuantity, } from './core';
|
|
6
|
+
export type { MortifierConfig, MortimerSlayerMasterConfig, SlayerAssignmentContext, SlayerMasterConfig, TaskDefinition, TaskOptions, TaskQuantity, } from './core';
|
|
7
7
|
export { Assignment, getAvailableMortifiers, getMortifierByName, Mortifier, MORTIFIERS, MortimerSlayerMaster, SlayerMaster, Task, } from './core';
|
|
8
8
|
export { POINTS_TABLE, SlayerBoss, SlayerLocation, TASK_DEFAULTS } from './core';
|
|
9
9
|
export type { SlayerMasterProgression } from './masters';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "osrs-tools",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "A comprehensive TypeScript library for Old School RuneScape (OSRS) data and utilities, including quest data, skill requirements, and general game information",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"sideEffects": false,
|