Skip to content

Commit dadcee0

Browse files
committed
Improve config
- Game mode - Dungeon infos
1 parent cb9f63a commit dadcee0

1 file changed

Lines changed: 97 additions & 10 deletions

File tree

lab/melvor_discovered_missing_items.js

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
// Configuration object
88
const CONFIG = {
99
filterDiscovered: true, // Set to false to show all items regardless of discovery status
10+
gameMode: [], // Possible values: 'base', 'td', 'aod', 'cr' (for base game, Throne of the Herald, Astrology of Dragons, Crimson Reborn)
1011
showDropSources: true, // Set to false to hide drop source information
12+
showDungeonInfo: true, // Set to false to hide dungeon information
1113
showItemIds: true, // Set to false to hide item IDs
1214
showSlayerInfo: true, // Set to false to hide slayer task information
1315
sortByCombatLevel: true, // Set to false to keep default sort
@@ -25,6 +27,21 @@
2527

2628
// Loop through all game items
2729
game.items.allObjects.forEach((item) => {
30+
// Check item game mode
31+
if (CONFIG.gameMode && CONFIG.gameMode.length > 0) {
32+
const itemGameMode = item.gamemode;
33+
const isValidGameMode = CONFIG.gameMode.some(
34+
(mode) =>
35+
(mode === 'base' && itemGameMode === 'melvorBase') ||
36+
(mode === 'td' && itemGameMode === 'melvorTotH') ||
37+
(mode === 'aod' && itemGameMode === 'melvorAoD') ||
38+
(mode === 'cr' && itemGameMode === 'melvorCR')
39+
);
40+
if (!isValidGameMode) {
41+
return; // Skip items not from selected game modes
42+
}
43+
}
44+
2845
// Check if item has been discovered
2946
const isDiscovered = game.stats.itemFindCount(item) > 0;
3047
// Check if it's not in inventory
@@ -57,6 +74,7 @@
5774
if ((!CONFIG.filterDiscovered || isDiscovered) && !isInInventory && !isEquipped) {
5875
// Get drop sources for this item
5976
const dropSources = [];
77+
const dungeonSources = []; // Array for dungeon sources
6078

6179
game.monsters.allObjects.forEach((monster) => {
6280
const drops = monster.lootTable.drops;
@@ -86,12 +104,49 @@
86104
});
87105
});
88106

107+
// Function to get dungeon combat level
108+
const getDungeonLevel = (dungeon) => {
109+
// Use the highest level monster in the dungeon as reference
110+
return dungeon.monsters
111+
? Math.max(...dungeon.monsters.map((monster) => monster.combatLevel))
112+
: dungeon.combinedModifiers?.decreasedMinimumCombatLevel || dungeon.recommendedBaseCombatLevel || 0;
113+
};
114+
115+
// Modify dungeon sources collection to include max monster level
116+
game.dungeons.allObjects.forEach((dungeon) => {
117+
if (dungeon._rewards) {
118+
const dungeonLevel = getDungeonLevel(dungeon);
119+
dungeon._rewards.forEach((reward) => {
120+
if (reward.type === 'Item' && reward.name === item.name) {
121+
dungeonSources.push({
122+
dungeon: dungeon.name,
123+
chance: 100,
124+
type: 'completion',
125+
level: dungeonLevel,
126+
});
127+
} else if (reward.type === 'Chest' && reward.dropTable && reward.dropTable.drops) {
128+
reward.dropTable.drops.forEach((drop) => {
129+
if (drop.item === item) {
130+
dungeonSources.push({
131+
dungeon: dungeon.name,
132+
chance: (drop.weight / reward.dropTable.totalWeight) * 100,
133+
type: 'chest',
134+
level: dungeonLevel,
135+
});
136+
}
137+
});
138+
}
139+
});
140+
}
141+
});
142+
89143
// Sort drop sources by chance (highest to lowest)
90144
dropSources.sort((a, b) => b.chance - a.chance);
91145

92146
missingItems.push({
93147
item: item,
94148
dropSources: dropSources,
149+
dungeonSources: dungeonSources, // Add dungeon sources
95150
});
96151
}
97152
}
@@ -115,27 +170,47 @@
115170

116171
const aHasSlayer = hasSlayerDrops(a);
117172
const bHasSlayer = hasSlayerDrops(b);
173+
const aHasDrops = a.dropSources.length > 0;
174+
const bHasDrops = b.dropSources.length > 0;
175+
const aHasDungeon = a.dungeonSources.length > 0;
176+
const bHasDungeon = b.dungeonSources.length > 0;
118177

119-
// First sort by whether the item has slayer drops
178+
// Slayer first
120179
if (aHasSlayer !== bHasSlayer) {
121-
return bHasSlayer - aHasSlayer; // Slayer items first
180+
return bHasSlayer - aHasSlayer;
122181
}
123182

124183
// If both have slayer drops, sort by slayer combat level
125184
if (aHasSlayer && bHasSlayer) {
126185
return getMinSlayerCombatLevel(a) - getMinSlayerCombatLevel(b);
127186
}
128187

129-
// If neither have slayer drops, sort by non-slayer combat level
130-
const aHasDrops = a.dropSources.length > 0;
131-
const bHasDrops = b.dropSources.length > 0;
188+
if (aHasDrops !== bHasDrops) {
189+
return bHasDrops - aHasDrops;
190+
}
132191

133192
if (aHasDrops && bHasDrops) {
134193
return getMinNonSlayerCombatLevel(a) - getMinNonSlayerCombatLevel(b);
135194
}
136195

137-
// Put items without drops at the end
138-
return aHasDrops ? -1 : bHasDrops ? 1 : 0;
196+
// Add check for dungeon sources
197+
if (aHasDungeon !== bHasDungeon) {
198+
return bHasDungeon - aHasDungeon;
199+
}
200+
201+
// Then dungeons
202+
if (aHasDungeon && bHasDungeon) {
203+
// First sort by dungeon level
204+
const aMinLevel = Math.min(...a.dungeonSources.map((source) => source.level));
205+
const bMinLevel = Math.min(...b.dungeonSources.map((source) => source.level));
206+
if (aMinLevel !== bMinLevel) {
207+
return aMinLevel - bMinLevel;
208+
}
209+
// If same level, sort by name
210+
return a.dungeonSources[0].dungeon.localeCompare(b.dungeonSources[0].dungeon);
211+
}
212+
213+
return 0;
139214
});
140215
}
141216

@@ -146,18 +221,30 @@
146221
itemsToShow.length > 0
147222
? '\n' +
148223
itemsToShow
149-
.map(({ item, dropSources }) => {
224+
.map(({ item, dropSources, dungeonSources }) => {
150225
const itemInfo = `- ${item.name}${CONFIG.showItemIds ? ` [ID: ${item.id}]` : ''}`;
151226

152-
if (!CONFIG.showDropSources || dropSources.length === 0) return itemInfo;
227+
if (!CONFIG.showDropSources || (dropSources.length === 0 && dungeonSources.length === 0)) return itemInfo;
153228

154229
const dropInfo = dropSources
155230
.map((source) => {
156231
const slayerInfo = CONFIG.showSlayerInfo && source.canSlayer ? ` [${source.taskDifficulty} Task]` : '';
157232
return `\n-- Drops from ${source.monster} (${source.combatLevel})${slayerInfo} (${source.chance.toFixed(2)}%)`;
158233
})
159234
.join('');
160-
return `${itemInfo}${dropInfo}`;
235+
236+
const dungeonInfo =
237+
CONFIG.showDungeonInfo && dungeonSources.length > 0
238+
? dungeonSources
239+
.map((source) => {
240+
const levelInfo = source.level > 0 ? ` (Level ${source.level})` : '';
241+
const sourceType = source.type === 'chest' ? 'Chest' : 'Completion';
242+
return `\n-- Found in ${source.dungeon}${levelInfo} (${sourceType}) (${source.chance.toFixed(2)}%)`;
243+
})
244+
.join('')
245+
: '';
246+
247+
return `${itemInfo}${dropInfo}${dungeonInfo}`;
161248
})
162249
.filter(Boolean)
163250
.join('\n')

0 commit comments

Comments
 (0)