diff --git a/assets/database/db.bin b/assets/database/db.bin index 0766e1fbd5..fe8c6e6558 100644 Binary files a/assets/database/db.bin and b/assets/database/db.bin differ diff --git a/assets/database/db.json b/assets/database/db.json index ba276e7b5e..32dd634c33 100644 --- a/assets/database/db.json +++ b/assets/database/db.json @@ -10128,7 +10128,7 @@ ], "encounters":[ {"path":"Default/Raid Target","targets":[{"path":"Default/Raid Target","target":{"id":31146,"name":"Raid Target","level":88,"mobType":7,"stats":[0,0,0,0,0,0,0,0,0,0,0,650,0,0,0,0,0,0,11977,0,0,0,0,0,0,120016403,0,0,0,0,0,0,0],"minBaseDamage":210000,"damageSpread":0.4,"swingSpeed":2.5}}]}, -{"path":"Movement/Light","targets":[{"path":"Movement/Light","target":{"id":31147,"name":"Light","level":88,"mobType":7,"stats":[0,0,0,0,0,0,0,0,0,0,0,650,0,0,0,0,0,0,11977,0,0,0,0,0,0,120016403,0,0,0,0,0,0,0],"minBaseDamage":210000,"damageSpread":0.4,"swingSpeed":2.5}}]}, +{"path":"Default/Movement","targets":[{"path":"Default/Movement","target":{"id":31147,"name":"Movement","level":88,"mobType":7,"stats":[0,0,0,0,0,0,0,0,0,0,0,650,0,0,0,0,0,0,11977,0,0,0,0,0,0,120016403,0,0,0,0,0,0,0],"minBaseDamage":210000,"damageSpread":0.4,"swingSpeed":2.5,"targetInputs":[{"inputType":1,"label":"Movement Interval","tooltip":"How often the player will move in seconds","numberValue":10},{"inputType":1,"label":"Reaction Time","tooltip":"How long the player can wait for casts to finish before moving in seconds","numberValue":1.5},{"inputType":1,"label":"Yards","tooltip":"How many yards the player moves","numberValue":5}]}}]}, {"path":"Blackwing Descent/Magmaw 10","targets":[{"path":"Blackwing Descent/Magmaw 10","target":{"id":41570,"name":"Magmaw 10","level":88,"mobType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,650,0,0,0,0,0,0,11977,0,0,0,0,0,0,26798304,0,0,0,0,0,0,0],"minBaseDamage":110000,"damageSpread":0.4,"swingSpeed":2.5,"targetInputs":[{"inputType":1,"label":"Impale Reaction Time","tooltip":"How long will the Raid take to Impale Head in Seconds. (After the initial 10s)","numberValue":5}]}}]}, {"path":"Blackwing Descent/Magmaw 25","targets":[{"path":"Blackwing Descent/Magmaw 25","target":{"id":41571,"name":"Magmaw 25","level":88,"mobType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,650,0,0,0,0,0,0,11977,0,0,0,0,0,0,81082048,0,0,0,0,0,0,0],"minBaseDamage":150000,"damageSpread":0.4,"swingSpeed":2.5,"targetInputs":[{"inputType":1,"label":"Impale Reaction Time","tooltip":"How long will the Raid take to Impale Head in Seconds. (After the initial 10s)","numberValue":5}]}}]}, {"path":"Blackwing Descent/Magmaw 10 H","targets":[{"path":"Blackwing Descent/Magmaw 10 H","target":{"id":41572,"name":"Magmaw 10 H","level":88,"mobType":1,"stats":[0,0,0,0,0,0,0,0,0,0,0,650,0,0,0,0,0,0,11977,0,0,0,0,0,0,39200000,0,0,0,0,0,0,0],"minBaseDamage":150000,"damageSpread":0.4,"swingSpeed":2.5,"targetInputs":[{"inputType":1,"label":"Impale Reaction Time","tooltip":"How long will the Raid take to Impale Head in Seconds. (After the initial 10s)","numberValue":5}]}}]}, @@ -10482,4 +10482,4 @@ {"itemId":43380,"spellId":58038}, {"itemId":43379,"spellId":58039} ] -} +} \ No newline at end of file diff --git a/sim/encounters/light_movement.go b/sim/encounters/light_movement.go deleted file mode 100644 index 2d58074700..0000000000 --- a/sim/encounters/light_movement.go +++ /dev/null @@ -1,83 +0,0 @@ -package encounters - -import ( - "time" - - "github.com/wowsims/cata/sim/core" - "github.com/wowsims/cata/sim/core/proto" - "github.com/wowsims/cata/sim/core/stats" -) - -func addLightMovementAI() { - core.AddPresetTarget(&core.PresetTarget{ - PathPrefix: "Movement", - Config: &proto.Target{ - Id: 31147, - Name: "Light", - Level: 88, - MobType: proto.MobType_MobTypeMechanical, - TankIndex: 0, - - Stats: stats.Stats{ - stats.Health: 120_016_403, - stats.Armor: 11977, - stats.AttackPower: 650, - }.ToFloatArray(), - - SpellSchool: proto.SpellSchool_SpellSchoolPhysical, - SwingSpeed: 2.5, - MinBaseDamage: 210000, - DamageSpread: 0.4, - SuppressDodge: false, - ParryHaste: false, - DualWield: false, - DualWieldPenalty: false, - TargetInputs: []*proto.TargetInput{}, - }, - AI: NewLightMovementAI(), - }) - core.AddPresetEncounter("Light", []string{ - "Movement/Light", - }) -} - -type LightMovementAI struct { - Target *core.Target - LastMoveTime time.Duration -} - -func NewLightMovementAI() core.AIFactory { - return func() core.TargetAI { - return &LightMovementAI{} - } -} - -func (ai *LightMovementAI) Initialize(target *core.Target, config *proto.Target) { - ai.Target = target -} - -func (ai *LightMovementAI) Reset(sim *core.Simulation) { - ai.LastMoveTime = 0 -} - -func (ai *LightMovementAI) ExecuteCustomRotation(sim *core.Simulation) { - players := sim.Raid.AllPlayerUnits - - if !ai.ShouldMove(sim) { - return - } - - for i := 0; i < len(players); i++ { - player := players[i] - - player.MoveDuration(time.Second*2, sim) - } -} - -func (ai *LightMovementAI) ShouldMove(sim *core.Simulation) bool { - if sim.CurrentTime-ai.LastMoveTime >= 10*time.Second { - ai.LastMoveTime = sim.CurrentTime - return true - } - return false -} diff --git a/sim/encounters/movement_ai.go b/sim/encounters/movement_ai.go new file mode 100644 index 0000000000..fbbe8d5d34 --- /dev/null +++ b/sim/encounters/movement_ai.go @@ -0,0 +1,141 @@ +package encounters + +import ( + "time" + + "github.com/wowsims/cata/sim/core" + "github.com/wowsims/cata/sim/core/proto" + "github.com/wowsims/cata/sim/core/stats" +) + +func addMovementAI() { + core.AddPresetTarget(&core.PresetTarget{ + PathPrefix: "Default", + Config: &proto.Target{ + Id: 31147, + Name: "Movement", + Level: 88, + MobType: proto.MobType_MobTypeMechanical, + TankIndex: 0, + + Stats: stats.Stats{ + stats.Health: 120_016_403, + stats.Armor: 11977, + stats.AttackPower: 650, + }.ToFloatArray(), + + SpellSchool: proto.SpellSchool_SpellSchoolPhysical, + SwingSpeed: 2.5, + MinBaseDamage: 210000, + DamageSpread: 0.4, + SuppressDodge: false, + ParryHaste: false, + DualWield: false, + DualWieldPenalty: false, + TargetInputs: []*proto.TargetInput{ + { + Label: "Movement Interval", + Tooltip: "How often the player will move in seconds", + InputType: proto.InputType_Number, + NumberValue: 10.0, + }, + { + Label: "Reaction Time", + Tooltip: "How long the player can wait for casts to finish before moving in seconds", + InputType: proto.InputType_Number, + NumberValue: 1.5, + }, + { + Label: "Yards", + Tooltip: "How many yards the player moves", + InputType: proto.InputType_Number, + NumberValue: 5, + }, + }, + }, + AI: NewMovementAI(), + }) + core.AddPresetEncounter("Movement", []string{ + "Default/Movement", + }) +} + +type MovementAI struct { + Target *core.Target + LastMoveTime time.Duration + MoveInterval time.Duration // How often moves happen + ReactionTime time.Duration // Time available to react before area should be cleared + MoveYards float64 // Duration of the move +} + +func NewMovementAI() core.AIFactory { + return func() core.TargetAI { + return &MovementAI{} + } +} + +func (ai *MovementAI) Initialize(target *core.Target, config *proto.Target) { + ai.Target = target + + if len(config.TargetInputs) > 0 { + ai.MoveInterval = core.DurationFromSeconds(config.TargetInputs[0].NumberValue) + } else { + ai.MoveInterval = core.DurationFromSeconds(10) + } + + if len(config.TargetInputs) > 1 { + ai.ReactionTime = core.DurationFromSeconds(config.TargetInputs[1].NumberValue) + } else { + ai.ReactionTime = core.DurationFromSeconds(1.5) + } + + if len(config.TargetInputs) > 2 { + ai.MoveYards = config.TargetInputs[2].NumberValue + } else { + ai.MoveYards = 5.0 + } +} + +func (ai *MovementAI) Reset(sim *core.Simulation) { + ai.LastMoveTime = 0 +} + +func (ai *MovementAI) ExecuteCustomRotation(sim *core.Simulation) { + players := sim.Raid.AllPlayerUnits + + if !ai.ShouldMove(sim) { + return + } + for i := 0; i < len(players); i++ { + player := players[i] + duration := ai.TimeToMove(ai.MoveYards, player) + if player.Hardcast.Expires > sim.CurrentTime && !player.Hardcast.CanMove { + castEndsAt := player.Hardcast.Expires - sim.CurrentTime + // if castEndsAt < ai.ReactionTime { + core.StartDelayedAction(sim, core.DelayedActionOptions{ + DoAt: sim.CurrentTime + castEndsAt, + Priority: core.ActionPriorityPrePull + 1, + OnAction: func(s *core.Simulation) { + player.MoveDuration(duration, sim) + }, + }) + // } else { + // // Cancel casted spell and move immediately + // // For now we do nothing in this scenario + // return + // } + } else { + player.MoveDuration(duration, sim) + } + } +} +func (ai *MovementAI) TimeToMove(distance float64, unit *core.Unit) time.Duration { + return core.DurationFromSeconds(distance / unit.GetMovementSpeed()) +} +func (ai *MovementAI) ShouldMove(sim *core.Simulation) bool { + if sim.CurrentTime-ai.LastMoveTime >= ai.MoveInterval { + ai.LastMoveTime = sim.CurrentTime + return true + } + return false +} diff --git a/sim/encounters/register_all.go b/sim/encounters/register_all.go index 9add0e4d67..de336bc9c3 100644 --- a/sim/encounters/register_all.go +++ b/sim/encounters/register_all.go @@ -9,7 +9,7 @@ import ( func init() { AddDefaultPresetEncounter() - addLightMovementAI() + addMovementAI() bwd.Register() }