feat(mosstank): the button is Force Buff — always recast everything
Virindi Tank's own term: Force Buff recasts the lot rather than only what has lapsed. The button now does that, and says so. BuffPlan gained a force flag that skips the already-in-force check. Forcing means "ignore what is already up", NOT "ignore the settings" -- the trained- skill filter, the attribute toggle and the difficulty margin all still apply, and there is a test pinning that. The loop had to change shape for this. It used to re-derive the plan every tick and treat "plan is empty" as done, which works only because the ordinary plan shrinks as buffs land. A forced plan never shrinks -- that is the point -- so the same loop would have cast forever. A pass now captures a queue at the start and works through it by index, which is also cheaper: no rebuilding 80-odd buff lines every frame. A spell that will not go now advances the queue rather than blocking it. One missing component used to mean everything behind it waited for the stall timeout; now the status line names the refusal and the pass carries on. Solution builds clean; 14,440 tests pass on the standard hermetic lane filter, 0 failures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
54005a864c
commit
5ca4a63272
3 changed files with 77 additions and 33 deletions
|
|
@ -202,6 +202,40 @@ public class BuffPlanTests
|
|||
Assert.Equal(new uint[] { 2, 3, 1 }, plan.Select(s => s.SpellId).ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ForceQueuesBuffsThatAreAlreadyInForce()
|
||||
{
|
||||
// Virindi Tank's Force Buff recasts everything rather than only what
|
||||
// has lapsed, which is what the Buff button does.
|
||||
var lines = Lines(
|
||||
Spell(1, 47, 4, "Increases the caster's Life Magic skill by 10 points.",
|
||||
difficulty: 100, school: LifeMagicSkill));
|
||||
var skills = new[] { Skill(LifeMagicSkill, "Life Magic", PluginSkillTraining.Trained) };
|
||||
var active = new[] { new PluginActiveEnchantment(1, 47, 4, 1800) };
|
||||
|
||||
Assert.Empty(BuffPlan.Build(lines, skills, Array.Empty<PluginAttributeInfo>(),
|
||||
active, Default));
|
||||
Assert.Single(BuffPlan.Build(lines, skills, Array.Empty<PluginAttributeInfo>(),
|
||||
active, Default, force: true));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ForceStillRespectsSkillAndTrainingFilters()
|
||||
{
|
||||
// Forcing means "ignore what is already up", not "ignore the settings".
|
||||
var lines = Lines(
|
||||
Spell(1, 71, 1, "Increases the caster's Leadership skill by 10 points."));
|
||||
|
||||
var plan = BuffPlan.Build(
|
||||
lines,
|
||||
new[] { Skill(35, "Leadership", PluginSkillTraining.Untrained) },
|
||||
Array.Empty<PluginAttributeInfo>(),
|
||||
Array.Empty<PluginActiveEnchantment>(),
|
||||
Default, force: true);
|
||||
|
||||
Assert.Empty(plan);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EmptySpellbookProducesNoPlan()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue