Conversation
Reviewer's GuideRefactors the Ultra Nulgath and Champion Drakath ultra scripts to use a shared gear optimization utility, add multi‑page configuration with class composition presets and overrides, and introduce life‑steal scroll support, while preserving the core fight logic and taunt behavior. Also adds a reusable CoreGearUtils helper and a life‑steal helper to CoreUltra. Sequence diagram for UltraNulgath ScriptMain with gear snapshot, presets, and life stealsequenceDiagram
participant Bot as IScriptInterface
participant Ultra as UltraNulgath
participant Core as CoreEngine
participant Bots as CoreBots
participant Gear as CoreGearUtils
participant UltraCore as CoreUltra
Bot->>Ultra: ScriptMain(bot)
Ultra->>Bots: OneTimeMessage(...)
Ultra->>Bot: Config.Configure() [if not SkipOption]
Ultra->>Bot: Read Main.DoEquipClasses
Ultra->>Bot: Read ClassOverrides (a,b,c,d)
Ultra->>Bot: Read CoreSettings.UseLifeSteal
Ultra->>Gear: CaptureEquipment(Bot)
Gear-->>Ultra: EquipmentSnapshot
Ultra->>Core: Boot()
Ultra->>Ultra: Prep()
activate Ultra
Ultra->>Bot: Get Main.DoEquipClasses
alt comp selected
Ultra->>Ultra: ApplyCompAndEquip(comp, overrides)
Ultra->>UltraCore: EquipClassSync(classes, 4, nulgath_class.sync, true)
end
Ultra->>Bot: Get CoreSettings.EquipBestGear
alt EquipBestGear true
Ultra->>Gear: EquipBestGear(Bot, Bots, GearProfilePreset.Damage)
end
Ultra->>Bot: Get CoreSettings.DoEnh
alt DoEnh true
Ultra->>Ultra: DoEnhs() [apply enhancements]
end
Ultra->>UltraCore: UseAlchemyPotions(bestTonic, bestElixir)
alt IsTaunter()
Ultra->>UltraCore: GetScrollOfEnrage()
else not taunter and UseLifeSteal
Ultra->>UltraCore: GetScrollOfLifeSteal()
end
deactivate Ultra
Ultra->>Ultra: Fight()
loop fight loop
Ultra->>Bot: Check Alive, quest progress
alt IsTaunter()
Ultra->>Bot: Attack(2) [Nulgath]
Ultra->>Bot: UseSkill(5) [Scroll of Enrage until Focus]
else non-taunter
Ultra->>Bot: Attack(1 or 2)
alt UseLifeSteal
Ultra->>Bot: UseSkill(5) [Scroll of Life Steal]
end
end
end
Ultra-->>Bot: Fight exits
Ultra->>Gear: RestoreEquipment(Bot, Bots, EquipmentSnapshot, true)
Ultra->>Bots: SetOptions(false)
Ultra-->>Bot: ScriptMain returns
Class diagram for new CoreGearUtils gear optimization utilityclassDiagram
direction LR
class CoreGearUtils {
<<static>>
+EquipBestGear(preset GearProfilePreset)
+EquipBestGear(bot IScriptInterface, core CoreBots, preset GearProfilePreset)
+EquipBestGear(profileOrMetaOrder string)
+EquipBestGear(bot IScriptInterface, core CoreBots, profileOrMetaOrder string)
+CaptureEquipment() EquipmentSnapshot
+CaptureEquipment(bot IScriptInterface) EquipmentSnapshot
+RestoreEquipment(snapshot EquipmentSnapshot, loadBank bool)
+RestoreEquipment(bot IScriptInterface, core CoreBots, snapshot EquipmentSnapshot, loadBank bool)
}
class GearProfilePreset {
<<enum>>
Damage
Gold
Exp
ClassPoints
Reputation
Chaos
Undead
Elemental
Dragonkin
Human
Orc
}
class EquipmentSnapshot {
+EquipmentSnapshot(bySlot Dictionary~string,string~, orderedItems string[])
+BySlot Dictionary~string,string~
+OrderedItems string[]
}
class GearPlan {
<<internal>>
-GearPlan(primaryMeta string, secondaryMeta string, metaPriority string[])
-PrimaryMeta string
-SecondaryMeta string
-MetaPriority string[]
}
class BoostCandidate {
<<internal>>
-BoostCandidate(item InventoryItem, slot string, primary double, secondary double)
-Item InventoryItem
-Slot string
-Primary double
-Secondary double
}
class CoreBots {
+Unbank(itemName string) void
+EquipBestItemsForMeta(metaBySlot Dictionary~string,string[]~) void
+GetBoostFloat(item InventoryItem, meta string) double
+Instance CoreBots
}
class IScriptInterface {
+Instance IScriptInterface
+Inventory Inventory
+Bank Bank
+Player Player
+Log(message string) void
}
class InventoryItem {
}
CoreGearUtils ..> GearProfilePreset : uses
CoreGearUtils ..> EquipmentSnapshot : creates
CoreGearUtils ..> CoreBots : uses
CoreGearUtils ..> IScriptInterface : uses
CoreGearUtils ..> GearPlan : builds
CoreGearUtils ..> BoostCandidate : evaluates
BoostCandidate --> InventoryItem : wraps
EquipmentSnapshot o--> "1" Dictionary~string,string~ : BySlot
EquipmentSnapshot o--> "*" string : OrderedItems
CoreBots ..> InventoryItem : boosts
IScriptInterface ..> InventoryItem : owns
Class diagram for updated UltraNulgath and ChampionDrakath scripts with presets and life stealclassDiagram
direction LR
class UltraNulgath {
+DontPreconfigure bool
+OptionsStorage string
+MultiOptions string[]
-a string
-b string
-c string
-d string
-overrideA string
-overrideB string
-overrideC string
-overrideD string
-UseLifeSteal bool
+Main List~IOption~
+CoreSettings List~IOption~
+ClassOverrides List~IOption~
+ScriptMain(bot IScriptInterface) void
-IsTaunter() bool
-Prep() void
-ApplyCompAndEquip(comp NulgathComp, aOverride string, bOverride string, cOverride string, dOverride string) void
-Fight() void
-DoEnhs() void
}
class NulgathComp {
<<enum>>
Unselected
Fast
F2PFast
Common
Balanced
}
class ChampionDrakath {
+DontPreconfigure bool
+OptionsStorage string
+MultiOptions string[]
-a string
-b string
-c string
-d string
-overrideA string
-overrideB string
-overrideC string
-overrideD string
-UseLifeSteal bool
-previousHP int
-hpThresholds int[]
+Main List~IOption~
+CoreSettings List~IOption~
+ClassOverrides List~IOption~
+ScriptMain(bot IScriptInterface) void
-IsTaunter() bool
-Prep() void
-ApplyCompAndEquip(comp DrakathComp, aOverride string, bOverride string, cOverride string, dOverride string) void
-Fight() void
-DoEnhs() void
}
class DrakathComp {
<<enum>>
Unselected
Safe
Fast
Cheapest
}
class HowManyTaunts {
<<enum>>
One
Two
Three
Four
}
class CoreUltra {
+GetScrollOfEnrage() void
+GetScrollOfLifeSteal(minStock int, restockTo int) void
+UseAlchemyPotions(tonic string, elixir string) void
+EquipClassSync(classes string[][], slots int, syncFile string, allowDuplicates bool) void
+WaitForArmy(minCount int, syncFile string) void
+ResolveSyncPath(fileName string) string
+ClearSyncFile(path string) void
+CheckArmyProgressBool(checkFunc Func~bool~, syncPath string) bool
}
class CoreGearUtils {
+EquipBestGear(bot IScriptInterface, core CoreBots, preset GearProfilePreset) void
+CaptureEquipment(bot IScriptInterface) EquipmentSnapshot
+RestoreEquipment(bot IScriptInterface, core CoreBots, snapshot EquipmentSnapshot, loadBank bool) void
}
class GearProfilePreset {
<<enum>>
}
class CoreBots {
+Logger(tag string, message string) void
+EnsureAccept(id int) void
+EnsureComplete(id int) void
+AddDrop(name string) void
+Jump(cell string, pad string) void
+Join(map string) void
+SetOptions(isActive bool) void
}
class CoreEngine {
+Boot() void
+Join(map string) void
+ChooseBestCell(target string) void
+EnableSkills() void
+DisableSkills() void
+EquipEnrage() void
}
UltraNulgath ..> NulgathComp : uses
UltraNulgath ..> CoreUltra : collaborates
UltraNulgath ..> CoreGearUtils : snapshot_and_best_gear
UltraNulgath ..> GearProfilePreset : selects
UltraNulgath ..> CoreBots : uses
UltraNulgath ..> CoreEngine : uses
ChampionDrakath ..> DrakathComp : uses
ChampionDrakath ..> HowManyTaunts : uses
ChampionDrakath ..> CoreUltra : collaborates
ChampionDrakath ..> CoreGearUtils : snapshot_and_best_gear
ChampionDrakath ..> GearProfilePreset : selects
ChampionDrakath ..> CoreBots : uses
ChampionDrakath ..> CoreEngine : uses
CoreUltra ..> CoreBots : uses
CoreGearUtils ..> EquipmentSnapshot : returns
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- The taunter/composition handling patterns in UltraNulgath and ChampionDrakath (MultiOptions, overrides, ApplyCompAndEquip, IsTaunter, life-steal vs enrage behavior) are very similar; consider extracting shared helpers (e.g., a small
CoreUltraRolesutility) to reduce duplication and keep the logic consistent across ultras. - In ChampionDrakath.IsTaunter you are using
currentClass.Contains(a/b/c/d)with default overrides that can be substrings (e.g., "Chrono Shadow"), and the comparison is case‑sensitive; consider switching to an ordinal case-insensitive equality or well-defined prefix pattern to avoid accidental matches or misses when class names differ only by case or contain overlapping substrings. - CoreGearUtils.RestoreEquipment always restores in a fixed slot order and then additional items; if a user had multiple cosmetics of the same slot equipped, you may want to document or adjust the ordering logic (e.g., preserve original equip order or prioritize class/weapon) to better match player expectations for what "equipment snapshot" means.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The taunter/composition handling patterns in UltraNulgath and ChampionDrakath (MultiOptions, overrides, ApplyCompAndEquip, IsTaunter, life-steal vs enrage behavior) are very similar; consider extracting shared helpers (e.g., a small `CoreUltraRoles` utility) to reduce duplication and keep the logic consistent across ultras.
- In ChampionDrakath.IsTaunter you are using `currentClass.Contains(a/b/c/d)` with default overrides that can be substrings (e.g., "Chrono Shadow"), and the comparison is case‑sensitive; consider switching to an ordinal case-insensitive equality or well-defined prefix pattern to avoid accidental matches or misses when class names differ only by case or contain overlapping substrings.
- CoreGearUtils.RestoreEquipment always restores in a fixed slot order and then additional items; if a user had multiple cosmetics of the same slot equipped, you may want to document or adjust the ordering logic (e.g., preserve original equip order or prioritize class/weapon) to better match player expectations for what "equipment snapshot" means.
## Individual Comments
### Comment 1
<location path="Ultras/UltraNulgath.cs" line_range="141-149" />
<code_context>
+ if (bot == null || core == null)
+ return;
+
+ try
+ {
+ TryLoadBank(bot);
</code_context>
<issue_to_address>
**issue (bug_risk):** Equipment snapshot restore does not revert enhancements, so DoEnhs permanently alters the player’s gear
Previously this used `Adv.GearStore(false, true)` before enhancing and `Adv.GearStore(true, true)` after, which reverted both items and their enhancements. The new snapshot restore only re-equips items and does not revert enhancements, so `DoEnhs()` now leaves permanent enhancement changes. If the goal is to fully restore the user’s gear, either keep the `GearStore` calls around `DoEnhs` or extend the snapshot/restore logic to capture and reapply enhancements too.
</issue_to_address>
### Comment 2
<location path="Ultras/ChampionDrakath.cs" line_range="252-253" />
<code_context>
+ if (Bot.Config!.Get<bool>("CoreSettings", "EquipBestGear"))
+ CoreGearUtils.EquipBestGear(Bot, C, GearProfilePreset.Chaos);
+
+ if (Bot.Config!.Get<bool>("CoreSettings", "DoEnh"))
DoEnhs();
Ultra.UseAlchemyPotions(
</code_context>
<issue_to_address>
**issue (bug_risk):** Enhancement changes are no longer reverted at the end of the run, unlike the previous GearStore-based behavior
Previously this logic wrapped enhancements with `Adv.GearStore(false, true)` / `Adv.GearStore(true, true)`, so any changes were reverted after the run. Now `DoEnhs()` is called directly and `CoreGearUtils.RestoreEquipment` only restores items, not their enhancements, so players keep the new enhancements permanently. If that’s unintended, we should either reintroduce the GearStore pattern around `DoEnhs()` or extend the snapshot/restore logic to include enhancement data.
</issue_to_address>
### Comment 3
<location path="CoreGearUtils.cs" line_range="137-146" />
<code_context>
+ if (bot == null || core == null)
+ return;
+
+ try
+ {
+ TryLoadBank(bot);
+
+ core.EquipBestItemsForMeta(
+ new Dictionary<string, string[]>
+ {
+ { "Weapon", plan.MetaPriority },
+ { "Armor", plan.MetaPriority },
+ { "Helm", plan.MetaPriority },
+ { "Cape", plan.MetaPriority },
+ { "Pet", plan.MetaPriority },
+ }
+ );
+
+ EquipBestStackingPair(bot, core, plan.PrimaryMeta, plan.SecondaryMeta);
+ }
+ catch
+ {
+ bot.Log("Best gear equip failed. Continuing with current setup.");
+ }
+ }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Swallowing all exceptions in EquipBestGearInternal can hide real issues and make debugging harder
The blanket try/catch hides all errors and only logs a generic message, which will make regressions in calls like `EquipBestItemsForMeta` or `GetBoostFloat` very hard to diagnose. Please either log the actual exception details (at least `ex.Message` and some relevant context such as preset/meta info) or narrow the catch to the specific, expected failures (e.g., bank load issues) and let unexpected exceptions propagate.
Suggested implementation:
```csharp
private static void EquipBestGearInternal(IScriptInterface bot, CoreBots core, GearPlan plan)
{
if (bot == null || core == null)
return;
try
{
TryLoadBank(bot);
core.EquipBestItemsForMeta(
new Dictionary<string, string[]>
{
{ "Weapon", plan.MetaPriority },
{ "Armor", plan.MetaPriority },
{ "Helm", plan.MetaPriority },
{ "Cape", plan.MetaPriority },
{ "Pet", plan.MetaPriority },
}
);
EquipBestStackingPair(bot, core, plan.PrimaryMeta, plan.SecondaryMeta);
}
catch (System.Exception ex)
{
bot.Log(
$"Best gear equip failed for plan '{plan?.Name ?? "unknown"}'. " +
$"Primary meta: '{plan?.PrimaryMeta ?? "null"}', Secondary meta: '{plan?.SecondaryMeta ?? "null"}'."
);
bot.Log($"Exception while equipping best gear: {ex}");
}
```
If `GearPlan` does not currently expose a `Name` property, either add one or adjust the log message to use whatever identifying information is available for the plan (e.g., preset enum, ID, or omit the plan name segment of the log).
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| try | ||
| { | ||
| Core.Boot(); | ||
| Prep(); | ||
| Fight(); | ||
| } | ||
| finally | ||
| { | ||
| CoreGearUtils.RestoreEquipment(Bot, C, equippedBefore); |
There was a problem hiding this comment.
issue (bug_risk): Equipment snapshot restore does not revert enhancements, so DoEnhs permanently alters the player’s gear
Previously this used Adv.GearStore(false, true) before enhancing and Adv.GearStore(true, true) after, which reverted both items and their enhancements. The new snapshot restore only re-equips items and does not revert enhancements, so DoEnhs() now leaves permanent enhancement changes. If the goal is to fully restore the user’s gear, either keep the GearStore calls around DoEnhs or extend the snapshot/restore logic to capture and reapply enhancements too.
| if (Bot.Config!.Get<bool>("CoreSettings", "DoEnh")) | ||
| DoEnhs(); |
There was a problem hiding this comment.
issue (bug_risk): Enhancement changes are no longer reverted at the end of the run, unlike the previous GearStore-based behavior
Previously this logic wrapped enhancements with Adv.GearStore(false, true) / Adv.GearStore(true, true), so any changes were reverted after the run. Now DoEnhs() is called directly and CoreGearUtils.RestoreEquipment only restores items, not their enhancements, so players keep the new enhancements permanently. If that’s unintended, we should either reintroduce the GearStore pattern around DoEnhs() or extend the snapshot/restore logic to include enhancement data.
| try | ||
| { | ||
| TryLoadBank(bot); | ||
|
|
||
| core.EquipBestItemsForMeta( | ||
| new Dictionary<string, string[]> | ||
| { | ||
| { "Weapon", plan.MetaPriority }, | ||
| { "Armor", plan.MetaPriority }, | ||
| { "Helm", plan.MetaPriority }, |
There was a problem hiding this comment.
suggestion (bug_risk): Swallowing all exceptions in EquipBestGearInternal can hide real issues and make debugging harder
The blanket try/catch hides all errors and only logs a generic message, which will make regressions in calls like EquipBestItemsForMeta or GetBoostFloat very hard to diagnose. Please either log the actual exception details (at least ex.Message and some relevant context such as preset/meta info) or narrow the catch to the specific, expected failures (e.g., bank load issues) and let unexpected exceptions propagate.
Suggested implementation:
private static void EquipBestGearInternal(IScriptInterface bot, CoreBots core, GearPlan plan)
{
if (bot == null || core == null)
return;
try
{
TryLoadBank(bot);
core.EquipBestItemsForMeta(
new Dictionary<string, string[]>
{
{ "Weapon", plan.MetaPriority },
{ "Armor", plan.MetaPriority },
{ "Helm", plan.MetaPriority },
{ "Cape", plan.MetaPriority },
{ "Pet", plan.MetaPriority },
}
);
EquipBestStackingPair(bot, core, plan.PrimaryMeta, plan.SecondaryMeta);
}
catch (System.Exception ex)
{
bot.Log(
$"Best gear equip failed for plan '{plan?.Name ?? "unknown"}'. " +
$"Primary meta: '{plan?.PrimaryMeta ?? "null"}', Secondary meta: '{plan?.SecondaryMeta ?? "null"}'."
);
bot.Log($"Exception while equipping best gear: {ex}");
}If GearPlan does not currently expose a Name property, either add one or adjust the log message to use whatever identifying information is available for the plan (e.g., preset enum, ID, or omit the plan name segment of the log).
Doing a pass on Ultras to try and make them as simple stupid as possible. Mostly they are already good!
Summary by Sourcery
Simplify and generalize ultra boss helper scripts by introducing shared gear utilities, configurable multi-tab options, and clearer role handling for taunter and DPS slots.
New Features:
Enhancements: