Big changes 2

- Split into several projects
- All dalamud/lumina deps are in the plugin
- Crafty/craftingway sim implemented!
- optimizations to follow
This commit is contained in:
Asriel Camora
2023-06-17 08:50:46 -07:00
parent 15d416ef2a
commit e190368d62
76 changed files with 1284 additions and 435 deletions
+119
View File
@@ -0,0 +1,119 @@
namespace Craftimizer.Simulator.Actions;
public enum ActionType
{
AdvancedTouch,
BasicSynthesis,
BasicTouch,
ByregotsBlessing,
CarefulObservation,
CarefulSynthesis,
DelicateSynthesis,
FinalAppraisal,
FocusedSynthesis,
FocusedTouch,
GreatStrides,
Groundwork,
HastyTouch,
HeartAndSoul,
Innovation,
IntensiveSynthesis,
Manipulation,
MastersMend,
MuscleMemory,
Observe,
PreciseTouch,
PreparatoryTouch,
PrudentSynthesis,
PrudentTouch,
RapidSynthesis,
Reflect,
StandardTouch,
TrainedEye,
TrainedFinesse,
TricksOfTheTrade,
Veneration,
WasteNot,
WasteNot2,
}
public static class ActionUtils
{
private static readonly BaseAction[] Actions;
static ActionUtils()
{
var types = typeof(BaseAction).Assembly.GetTypes()
.Where(t => t.IsAssignableTo(typeof(BaseAction)) && !t.IsAbstract);
Actions = Enum.GetNames<ActionType>()
.Select(a => types.First(t => t.Name == a))
.Select(t => (Activator.CreateInstance(t) as BaseAction)!)
.ToArray();
}
public static void SetSimulation(Simulator simulation) =>
BaseAction.TLSSimulation.Value = simulation;
public static BaseAction WithUnsafe(this ActionType me) => Actions[(int)me];
public static BaseAction With(this ActionType me, Simulator simulation)
{
SetSimulation(simulation);
return WithUnsafe(me);
}
public static IEnumerable<ActionType> AvailableActions(Simulator simulation)
{
if (simulation.IsComplete)
return Enumerable.Empty<ActionType>();
SetSimulation(simulation);
return Enum.GetValues<ActionType>()
.Where(a => WithUnsafe(a).CanUse);
}
public static int Level(this ActionType me) =>
WithUnsafe(me).Level;
public static ActionCategory Category(this ActionType me) =>
WithUnsafe(me).Category;
public static string IntName(this ActionType me) =>
me switch
{
ActionType.AdvancedTouch => "Advanced Touch",
ActionType.BasicSynthesis => "Basic Synthesis",
ActionType.BasicTouch => "Basic Touch",
ActionType.ByregotsBlessing => "Byregot's Blessing",
ActionType.CarefulObservation => "Careful Observation",
ActionType.CarefulSynthesis => "Careful Synthesis",
ActionType.DelicateSynthesis => "Delicate Synthesis",
ActionType.FinalAppraisal => "Final Appraisal",
ActionType.FocusedSynthesis => "Focused Synthesis",
ActionType.FocusedTouch => "Focused Touch",
ActionType.GreatStrides => "Great Strides",
ActionType.Groundwork => "Groundwork",
ActionType.HastyTouch => "Hasty Touch",
ActionType.HeartAndSoul => "Heart And Soul",
ActionType.Innovation => "Innovation",
ActionType.IntensiveSynthesis => "Intensive Synthesis",
ActionType.Manipulation => "Manipulation",
ActionType.MastersMend => "Master's Mend",
ActionType.MuscleMemory => "Muscle Memory",
ActionType.Observe => "Observe",
ActionType.PreciseTouch => "Precise Touch",
ActionType.PreparatoryTouch => "Preparatory Touch",
ActionType.PrudentSynthesis => "Prudent Synthesis",
ActionType.PrudentTouch => "Prudent Touch",
ActionType.RapidSynthesis => "Rapid Synthesis",
ActionType.Reflect => "Reflect",
ActionType.StandardTouch => "Standard Touch",
ActionType.TrainedEye => "Trained Eye",
ActionType.TrainedFinesse => "Trained Finesse",
ActionType.TricksOfTheTrade => "Tricks Of The Trade",
ActionType.Veneration => "Veneration",
ActionType.WasteNot => "Waste Not",
ActionType.WasteNot2 => "Waste Not II",
_ => me.ToString(),
};
}
+12
View File
@@ -0,0 +1,12 @@
namespace Craftimizer.Simulator.Actions;
internal class AdvancedTouch : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 84;
public override uint ActionId => 100411;
public override int CPCost => Simulation.IsPreviousAction(ActionType.StandardTouch) && Simulation.IsPreviousAction(ActionType.BasicTouch, 2) ? 18 : 46;
public override float Efficiency => 1.50f;
public override bool IncreasesQuality => true;
}
+82
View File
@@ -0,0 +1,82 @@
using System;
using System.Text;
using System.Threading;
namespace Craftimizer.Simulator.Actions;
public abstract class BaseAction
{
internal static readonly ThreadLocal<Simulator?> TLSSimulation = new(false);
protected static Simulator Simulation => TLSSimulation.Value ?? throw new NullReferenceException();
public BaseAction() { }
// Non-instanced properties
public abstract ActionCategory Category { get; }
public abstract int Level { get; }
// Doesn't matter from which class, we'll use the sheet to extrapolate the rest
public abstract uint ActionId { get; }
// Instanced properties
public abstract int CPCost { get; }
public virtual float Efficiency => 0f;
public virtual bool IncreasesProgress => false;
public virtual bool IncreasesQuality => false;
public virtual float SuccessRate => 1f;
public virtual int DurabilityCost => 10;
public virtual bool IncreasesStepCount => true;
public virtual bool IsGuaranteedAction => SuccessRate == 1f;
public virtual bool CanUse =>
Simulation.Input.Stats.Level >= Level && Simulation.CP >= CPCost;
public virtual void Use()
{
Simulation.ReduceCP(CPCost);
Simulation.ReduceDurability(DurabilityCost);
if (Simulation.HasEffect(EffectType.Manipulation))
Simulation.RestoreDurability(5);
if (Simulation.RollSuccess(SuccessRate))
UseSuccess();
if (IncreasesStepCount)
Simulation.IncreaseStepCount();
}
public virtual void UseSuccess()
{
if (Efficiency != 0f)
{
if (IncreasesProgress)
Simulation.IncreaseProgress(Efficiency);
if (IncreasesQuality)
Simulation.IncreaseQuality(Efficiency);
}
}
public virtual string GetTooltip(bool addUsability)
{
var builder = new StringBuilder();
if (addUsability && !CanUse)
builder.AppendLine($"Cannot Use");
builder.AppendLine($"Level {Level}");
if (CPCost != 0)
builder.AppendLine($"-{Simulation.CalculateCPCost(CPCost)} CP");
if (DurabilityCost != 0)
builder.AppendLine($"-{Simulation.CalculateDurabilityCost(DurabilityCost)} Durability");
if (Efficiency != 0)
{
if (IncreasesProgress)
builder.AppendLine($"+{Simulation.CalculateProgressGain(Efficiency)} Progress");
if (IncreasesQuality)
builder.AppendLine($"+{Simulation.CalculateQualityGain(Efficiency)} Quality");
}
if (!IncreasesStepCount)
builder.AppendLine($"Does Not Increase Step Count");
if (SuccessRate != 1f)
builder.AppendLine($"{Simulation.CalculateSuccessRate(SuccessRate) * 100}%% Success Rate");
return builder.ToString();
}
}
+26
View File
@@ -0,0 +1,26 @@
using System.Text;
namespace Craftimizer.Simulator.Actions;
internal abstract class BaseBuffAction : BaseAction
{
public abstract Effect Effect { get; }
public virtual EffectType[] ConflictingEffects => Array.Empty<EffectType>();
public override int DurabilityCost => 0;
public override void UseSuccess()
{
if (ConflictingEffects.Length != 0)
foreach(var effect in ConflictingEffects)
Simulation.RemoveEffect(effect);
Simulation.AddEffect(Effect.Type, Effect.Duration, Effect.Strength);
}
public override string GetTooltip(bool addUsability)
{
var builder = new StringBuilder(base.GetTooltip(addUsability));
builder.AppendLine($"{Effect.Duration} Steps");
return builder.ToString();
}
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class BasicSynthesis : BaseAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 1;
public override uint ActionId => 100001;
public override int CPCost => 0;
// Basic Synthesis Mastery Trait
public override float Efficiency => Simulation.Input.Stats.Level >= 31 ? 1.20f : 1.00f;
public override bool IncreasesProgress => true;
}
+12
View File
@@ -0,0 +1,12 @@
namespace Craftimizer.Simulator.Actions;
internal class BasicTouch : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 5;
public override uint ActionId => 100002;
public override int CPCost => 18;
public override float Efficiency => 1.00f;
public override bool IncreasesQuality => true;
}
+20
View File
@@ -0,0 +1,20 @@
namespace Craftimizer.Simulator.Actions;
internal class ByregotsBlessing : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 50;
public override uint ActionId => 100339;
public override int CPCost => 24;
public override float Efficiency => 1.00f + (0.20f * (Simulation.GetEffect(EffectType.InnerQuiet)?.Strength ?? 0));
public override bool IncreasesQuality => true;
public override bool CanUse => Simulation.HasEffect(EffectType.InnerQuiet) && base.CanUse;
public override void UseSuccess()
{
base.UseSuccess();
Simulation.RemoveEffect(EffectType.InnerQuiet);
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace Craftimizer.Simulator.Actions;
internal class CarefulObservation : BaseAction
{
public override ActionCategory Category => ActionCategory.Other;
public override int Level => 55;
public override uint ActionId => 100395;
public override int CPCost => 0;
public override int DurabilityCost => 0;
public override bool IncreasesStepCount => false;
public override bool CanUse => Simulation.Input.Stats.IsSpecialist && Simulation.CountPreviousAction(ActionType.CarefulObservation) < 3;
public override void UseSuccess() =>
Simulation.StepCondition();
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class CarefulSynthesis : BaseAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 62;
public override uint ActionId => 100203;
public override int CPCost => 7;
// Careful Synthesis Mastery Trait
public override float Efficiency => Simulation.Input.Stats.Level >= 82 ? 1.80f : 1.50f;
public override bool IncreasesProgress => true;
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class DelicateSynthesis : BaseAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 76;
public override uint ActionId => 100323;
public override int CPCost => 32;
public override float Efficiency => 1.00f;
public override bool IncreasesProgress => true;
public override bool IncreasesQuality => true;
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class FinalAppraisal : BaseBuffAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 42;
public override uint ActionId => 19012;
public override int CPCost => 1;
public override bool IncreasesStepCount => false;
public override Effect Effect => new() { Type = EffectType.FinalAppraisal, Duration = 5 };
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class FocusedSynthesis : BaseAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 67;
public override uint ActionId => 100235;
public override int CPCost => 5;
public override float Efficiency => 2.00f;
public override bool IncreasesProgress => true;
public override float SuccessRate => Simulation.IsPreviousAction(ActionType.Observe) ? 1.00f : 0.50f;
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class FocusedTouch : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 68;
public override uint ActionId => 100243;
public override int CPCost => 18;
public override float Efficiency => 1.50f;
public override bool IncreasesQuality => true;
public override float SuccessRate => Simulation.IsPreviousAction(ActionType.Observe) ? 1.00f : 0.50f;
}
+12
View File
@@ -0,0 +1,12 @@
namespace Craftimizer.Simulator.Actions;
internal class GreatStrides : BaseBuffAction
{
public override ActionCategory Category => ActionCategory.Buffs;
public override int Level => 21;
public override uint ActionId => 260;
public override int CPCost => 32;
public override Effect Effect => new() { Type = EffectType.GreatStrides, Duration = 3 };
}
+22
View File
@@ -0,0 +1,22 @@
namespace Craftimizer.Simulator.Actions;
internal class Groundwork : BaseAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 72;
public override uint ActionId => 100403;
public override int CPCost => 18;
// Groundwork Mastery Trait
public override float Efficiency
{
get
{
var ret = Simulation.Input.Stats.Level >= 86 ? 3.60f : 3.00f;
// TODO: does not account for waste not
return Simulation.Durability < DurabilityCost ? ret / 2 : ret;
}
}
public override bool IncreasesProgress => true;
public override int DurabilityCost => 20;
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class HastyTouch : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 9;
public override uint ActionId => 100355;
public override int CPCost => 0;
public override float Efficiency => 1.00f;
public override bool IncreasesQuality => true;
public override float SuccessRate => 0.60f;
}
+15
View File
@@ -0,0 +1,15 @@
namespace Craftimizer.Simulator.Actions;
internal class HeartAndSoul : BaseBuffAction
{
public override ActionCategory Category => ActionCategory.Other;
public override int Level => 86;
public override uint ActionId => 100419;
public override int CPCost => 0;
public override bool IncreasesStepCount => false;
public override Effect Effect => new() { Type = EffectType.HeartAndSoul };
public override bool CanUse => Simulation.Input.Stats.IsSpecialist && Simulation.CountPreviousAction(ActionType.HeartAndSoul) == 0;
}
+12
View File
@@ -0,0 +1,12 @@
namespace Craftimizer.Simulator.Actions;
internal class Innovation : BaseBuffAction
{
public override ActionCategory Category => ActionCategory.Buffs;
public override int Level => 26;
public override uint ActionId => 19004;
public override int CPCost => 18;
public override Effect Effect => new() { Type = EffectType.Innovation, Duration = 4 };
}
+24
View File
@@ -0,0 +1,24 @@
namespace Craftimizer.Simulator.Actions;
internal class IntensiveSynthesis : BaseAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 78;
public override uint ActionId => 100315;
public override int CPCost => 6;
public override float Efficiency => 4.00f;
public override bool IncreasesProgress => true;
public override bool IsGuaranteedAction => false;
public override bool CanUse =>
(Simulation.Condition == Condition.Good || Simulation.Condition == Condition.Excellent || Simulation.HasEffect(EffectType.HeartAndSoul))
&& base.CanUse;
public override void UseSuccess()
{
base.UseSuccess();
if (Simulation.Condition != Condition.Good && Simulation.Condition != Condition.Excellent)
Simulation.RemoveEffect(EffectType.HeartAndSoul);
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace Craftimizer.Simulator.Actions;
internal class Manipulation : BaseBuffAction
{
public override ActionCategory Category => ActionCategory.Durability;
public override int Level => 65;
public override uint ActionId => 4574;
public override int CPCost => 96;
public override Effect Effect => new() { Type = EffectType.Manipulation, Duration = 8 };
}
+14
View File
@@ -0,0 +1,14 @@
namespace Craftimizer.Simulator.Actions;
internal class MastersMend : BaseAction
{
public override ActionCategory Category => ActionCategory.Durability;
public override int Level => 7;
public override uint ActionId => 100003;
public override int CPCost => 88;
public override int DurabilityCost => 0;
public override void UseSuccess() =>
Simulation.RestoreDurability(30);
}
+20
View File
@@ -0,0 +1,20 @@
namespace Craftimizer.Simulator.Actions;
internal class MuscleMemory : BaseAction
{
public override ActionCategory Category => ActionCategory.FirstTurn;
public override int Level => 54;
public override uint ActionId => 100379;
public override int CPCost => 6;
public override float Efficiency => 3.00f;
public override bool IncreasesProgress => true;
public override bool CanUse => Simulation.IsFirstStep && base.CanUse;
public override void UseSuccess()
{
base.UseSuccess();
Simulation.AddEffect(EffectType.MuscleMemory, 5);
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace Craftimizer.Simulator.Actions;
internal class Observe : BaseAction
{
public override ActionCategory Category => ActionCategory.Other;
public override int Level => 13;
public override uint ActionId => 100010;
public override int CPCost => 7;
public override int DurabilityCost => 0;
}
+25
View File
@@ -0,0 +1,25 @@
namespace Craftimizer.Simulator.Actions;
internal class PreciseTouch : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 53;
public override uint ActionId => 100128;
public override int CPCost => 18;
public override float Efficiency => 1.50f;
public override bool IncreasesQuality => true;
public override bool IsGuaranteedAction => false;
public override bool CanUse =>
(Simulation.Condition == Condition.Good || Simulation.Condition == Condition.Excellent || Simulation.HasEffect(EffectType.HeartAndSoul))
&& base.CanUse;
public override void UseSuccess()
{
base.UseSuccess();
Simulation.StrengthenEffect(EffectType.InnerQuiet);
if (Simulation.Condition != Condition.Good && Simulation.Condition != Condition.Excellent)
Simulation.RemoveEffect(EffectType.HeartAndSoul);
}
}
+19
View File
@@ -0,0 +1,19 @@
namespace Craftimizer.Simulator.Actions;
internal class PreparatoryTouch : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 71;
public override uint ActionId => 100299;
public override int CPCost => 40;
public override float Efficiency => 2.00f;
public override bool IncreasesQuality => true;
public override int DurabilityCost => 20;
public override void UseSuccess()
{
base.UseSuccess();
Simulation.StrengthenEffect(EffectType.InnerQuiet);
}
}
+17
View File
@@ -0,0 +1,17 @@
namespace Craftimizer.Simulator.Actions;
internal class PrudentSynthesis : BaseAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 88;
public override uint ActionId => 100427;
public override int CPCost => 18;
public override float Efficiency => 1.80f;
public override bool IncreasesProgress => true;
public override int DurabilityCost => base.DurabilityCost / 2;
public override bool CanUse =>
!(Simulation.HasEffect(EffectType.WasteNot) || Simulation.HasEffect(EffectType.WasteNot2))
&& base.CanUse;
}
+17
View File
@@ -0,0 +1,17 @@
namespace Craftimizer.Simulator.Actions;
internal class PrudentTouch : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 66;
public override uint ActionId => 100227;
public override int CPCost => 25;
public override float Efficiency => 1.00f;
public override bool IncreasesQuality => true;
public override int DurabilityCost => base.DurabilityCost / 2;
public override bool CanUse =>
!(Simulation.HasEffect(EffectType.WasteNot) || Simulation.HasEffect(EffectType.WasteNot2))
&& base.CanUse;
}
+14
View File
@@ -0,0 +1,14 @@
namespace Craftimizer.Simulator.Actions;
internal class RapidSynthesis : BaseAction
{
public override ActionCategory Category => ActionCategory.Synthesis;
public override int Level => 9;
public override uint ActionId => 100363;
public override int CPCost => 0;
// Rapid Synthesis Mastery Trait
public override float Efficiency => Simulation.Input.Stats.Level >= 63 ? 5.00f : 2.50f;
public override bool IncreasesProgress => true;
public override float SuccessRate => 0.50f;
}
+20
View File
@@ -0,0 +1,20 @@
namespace Craftimizer.Simulator.Actions;
internal class Reflect : BaseAction
{
public override ActionCategory Category => ActionCategory.FirstTurn;
public override int Level => 69;
public override uint ActionId => 100387;
public override int CPCost => 6;
public override float Efficiency => 1.00f;
public override bool IncreasesQuality => true;
public override bool CanUse => Simulation.IsFirstStep && base.CanUse;
public override void UseSuccess()
{
base.UseSuccess();
Simulation.StrengthenEffect(EffectType.InnerQuiet);
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace Craftimizer.Simulator.Actions;
internal class StandardTouch : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 18;
public override uint ActionId => 100004;
public override int CPCost => Simulation.IsPreviousAction(ActionType.BasicTouch) ? 18 : 32;
public override float Efficiency => 1.25f;
public override bool IncreasesQuality => true;
}
+20
View File
@@ -0,0 +1,20 @@
namespace Craftimizer.Simulator.Actions;
internal class TrainedEye : BaseAction
{
public override ActionCategory Category => ActionCategory.FirstTurn;
public override int Level => 80;
public override uint ActionId => 100283;
public override int CPCost => 250;
public override bool IncreasesQuality => true;
public override bool CanUse =>
Simulation.IsFirstStep &&
!Simulation.Input.Recipe.IsExpert &&
Simulation.Input.Stats.Level >= (Simulation.Input.Recipe.ClassJobLevel + 10) &&
base.CanUse;
public override void UseSuccess() =>
Simulation.IncreaseQualityRaw(Simulation.Input.Recipe.MaxQuality - Simulation.Quality);
}
+17
View File
@@ -0,0 +1,17 @@
namespace Craftimizer.Simulator.Actions;
internal class TrainedFinesse : BaseAction
{
public override ActionCategory Category => ActionCategory.Quality;
public override int Level => 90;
public override uint ActionId => 100435;
public override int CPCost => 32;
public override float Efficiency => 1.00f;
public override bool IncreasesQuality => true;
public override int DurabilityCost => 0;
public override bool CanUse =>
(Simulation.GetEffect(EffectType.InnerQuiet)?.Strength ?? 0) == 10
&& base.CanUse;
}
+23
View File
@@ -0,0 +1,23 @@
namespace Craftimizer.Simulator.Actions;
internal class TricksOfTheTrade : BaseAction
{
public override ActionCategory Category => ActionCategory.Other;
public override int Level => 13;
public override uint ActionId => 100371;
public override int CPCost => 0;
public override int DurabilityCost => 0;
public override bool IsGuaranteedAction => false;
public override bool CanUse =>
(Simulation.Condition == Condition.Good || Simulation.Condition == Condition.Excellent || Simulation.HasEffect(EffectType.HeartAndSoul))
&& base.CanUse;
public override void UseSuccess()
{
Simulation.RestoreCP(20);
if (Simulation.Condition != Condition.Good && Simulation.Condition != Condition.Excellent)
Simulation.RemoveEffect(EffectType.HeartAndSoul);
}
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class Veneration : BaseBuffAction
{
public override ActionCategory Category => ActionCategory.Buffs;
public override int Level => 15;
public override uint ActionId => 19297;
public override int CPCost => 18;
public override int DurabilityCost => 0;
public override Effect Effect => new() { Type = EffectType.Veneration, Duration = 4 };
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class WasteNot : BaseBuffAction
{
public override ActionCategory Category => ActionCategory.Durability;
public override int Level => 15;
public override uint ActionId => 4631;
public override int CPCost => 56;
public override Effect Effect => new() { Type = EffectType.WasteNot, Duration = 4 };
public override EffectType[] ConflictingEffects => new[] { EffectType.WasteNot2 };
}
+13
View File
@@ -0,0 +1,13 @@
namespace Craftimizer.Simulator.Actions;
internal class WasteNot2 : BaseBuffAction
{
public override ActionCategory Category => ActionCategory.Durability;
public override int Level => 47;
public override uint ActionId => 4639;
public override int CPCost => 98;
public override Effect Effect => new() { Type = EffectType.WasteNot2, Duration = 8 };
public override EffectType[] ConflictingEffects => new[] { EffectType.WasteNot };
}