@@ -65,19 +65,21 @@ local function packageSkillDataForSimulation(skill, env)
65
65
return { uuid = cacheSkillUUID (skill , env ), cd = skill .skillData .cooldown , cdOverride = skill .skillModList :Override (skill .skillCfg , " CooldownRecovery" ), addsCastTime = processAddedCastTime (skill ), icdr = calcLib .mod (skill .skillModList , skill .skillCfg , " CooldownRecovery" ), addedCooldown = skill .skillModList :Sum (" BASE" , skill .skillCfg , " CooldownRecovery" )}
66
66
end
67
67
68
+ local function defaultComparer (env , uuid , source , triggerRate )
69
+ local cachedSpeed = GlobalCache .cachedData [env .mode ][uuid ].HitSpeed or GlobalCache .cachedData [env .mode ][uuid ].Speed
70
+ return (not source and cachedSpeed ) or (cachedSpeed and cachedSpeed > (triggerRate or 0 ))
71
+ end
72
+
68
73
-- Identify the trigger action skill for trigger conditions, take highest Attack Per Second
69
74
local function findTriggerSkill (env , skill , source , triggerRate , comparer )
70
- local comparer = comparer or function (uuid , source , triggerRate )
71
- local cachedSpeed = GlobalCache .cachedData [env .mode ][uuid ].HitSpeed or GlobalCache .cachedData [env .mode ][uuid ].Speed
72
- return (not source and cachedSpeed ) or (cachedSpeed and cachedSpeed > (triggerRate or 0 ))
73
- end
75
+ local comparer = comparer or defaultComparer
74
76
75
77
local uuid = cacheSkillUUID (skill , env )
76
78
if not GlobalCache .cachedData [env .mode ][uuid ] or env .mode == " CALCULATOR" then
77
79
calcs .buildActiveSkill (env , env .mode , skill , uuid )
78
80
end
79
81
80
- if GlobalCache .cachedData [env .mode ][uuid ] and comparer (uuid , source , triggerRate ) and (skill .skillFlags and not skill .skillFlags .disable ) and (skill .skillCfg and not skill .skillCfg .skillCond [" usedByMirage" ]) and not skill .skillTypes [SkillType .OtherThingUsesSkill ] then
82
+ if GlobalCache .cachedData [env .mode ][uuid ] and comparer (env , uuid , source , triggerRate ) and (skill .skillFlags and not skill .skillFlags .disable ) and (skill .skillCfg and not skill .skillCfg .skillCond [" usedByMirage" ]) and not skill .skillTypes [SkillType .OtherThingUsesSkill ] then
81
83
return skill , GlobalCache .cachedData [env .mode ][uuid ].HitSpeed or GlobalCache .cachedData [env .mode ][uuid ].Speed , uuid
82
84
end
83
85
return source , triggerRate , source and cacheSkillUUID (source , env )
@@ -106,7 +108,7 @@ function calcMultiSpellRotationImpact(env, skillRotation, sourceRate, triggerCD,
106
108
if skillRotation [currentIndex ].next_trig <= next_trigger then -- Skill at current index off cooldown, Trigger it.
107
109
skillRotation [currentIndex ].count = skillRotation [currentIndex ].count + 1
108
110
-- Cooldown starts at the beginning of current tick and ends at the next tick after cooldown expiration
109
- skillRotation [currentIndex ].next_trig = ceil_b (floor_b (next_trigger , 0.033 ) + skillRotation [currentIndex ].cd , 0.033 )
111
+ skillRotation [currentIndex ].next_trig = ceil_b (floor_b (next_trigger , data . misc . ServerTickTime ) + skillRotation [currentIndex ].cd , data . misc . ServerTickTime )
110
112
break
111
113
end
112
114
currentIndex = (currentIndex % skillCount ) + 1 -- Current skill on cooldown, try the next one.
@@ -425,7 +427,7 @@ local function defaultTriggerHandler(env, config)
425
427
t_insert (breakdown .EffectiveSourceRate , s_format (" %.2f ^8(%s %s)" , trigRate , config .sourceName or source .activeEffect .grantedEffect .name , config .useCastRate and " cast rate" or " attack rate" ))
426
428
end
427
429
end
428
-
430
+
429
431
-- Dual wield triggers
430
432
if trigRate and source and env .player .weaponData1 .type and env .player .weaponData2 .type and not source .skillData .doubleHitsWhenDualWielding and (source .skillTypes [SkillType .Melee ] or source .skillTypes [SkillType .Attack ]) and actor .mainSkill .triggeredBy and actor .mainSkill .triggeredBy .grantedEffect .support and actor .mainSkill .triggeredBy .grantedEffect .fromItem then
431
433
trigRate = trigRate / 2
@@ -447,24 +449,6 @@ local function defaultTriggerHandler(env, config)
447
449
end
448
450
end
449
451
450
- -- Battlemage's Cry uptime
451
- if actor .mainSkill .skillData .triggeredByBattleMageCry and GlobalCache .cachedData [env .mode ][uuid ] and source and source .skillTypes [SkillType .Melee ] then
452
- local battleMageUptime = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .BattlemageUpTimeRatio or 100
453
- trigRate = trigRate * battleMageUptime / 100
454
- if breakdown then
455
- t_insert (breakdown .EffectiveSourceRate , s_format (" x %d%% ^8(Battlemage's Cry uptime)" , battleMageUptime ))
456
- end
457
- end
458
-
459
- -- Infernal Cry uptime
460
- if actor .mainSkill .activeEffect .grantedEffect .name == " Combust" and GlobalCache .cachedData [env .mode ][uuid ] and source and source .skillTypes [SkillType .Melee ] then
461
- local InfernalUpTime = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .InfernalUpTimeRatio or 100
462
- trigRate = trigRate * InfernalUpTime / 100
463
- if breakdown then
464
- t_insert (breakdown .EffectiveSourceRate , s_format (" x %d%% ^8(Infernal Cry uptime)" , InfernalUpTime ))
465
- end
466
- end
467
-
468
452
-- Account for skills that can hit multiple times per use
469
453
if source and GlobalCache .cachedData [env .mode ][uuid ] and source .skillPartName and source .skillPartName :match (" (.*)All(.*)Projectiles(.*)" ) and source .skillFlags .projectile then
470
454
local multiHitDpsMult = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .ProjectileCount or 1
@@ -484,6 +468,44 @@ local function defaultTriggerHandler(env, config)
484
468
end
485
469
end
486
470
471
+ -- Battlemage's Cry uptime
472
+ if actor .mainSkill .skillData .triggeredByBattleMageCry and GlobalCache .cachedData [env .mode ][uuid ] and source and source .skillTypes [SkillType .Melee ] then
473
+ local battleMageExertsCount = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .BattleCryExertsCount
474
+ local battleMageDuration = ceil_b (GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .BattleMageCryDuration , data .misc .ServerTickTime )
475
+ local battleMageCastTime = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .BattleMageCryCastTime
476
+ local battleMageCooldown = ceil_b (GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .BattleMageCryCooldown , data .misc .ServerTickTime )
477
+
478
+ -- Cap the number of hits that happen during the duration
479
+ local battleMageHits = m_max (m_min (trigRate * battleMageDuration , battleMageExertsCount ), 0 )
480
+
481
+ if breakdown then
482
+ t_insert (breakdown .EffectiveSourceRate , s_format (" ^8(min(%.2f * %.2f, %d) = %.2f average number of exerted attacks capped by exerted count)" , trigRate , battleMageDuration , battleMageExertsCount , battleMageHits ))
483
+ t_insert (breakdown .EffectiveSourceRate , s_format (" = %.2f / (%.2f + %.2f) ^8(the calculated number of exerted attacks happens every cooldown + duration)" , battleMageHits , battleMageCastTime , battleMageCooldown ))
484
+ end
485
+
486
+ -- The hits happen every battlemage cooldown + duration
487
+ trigRate = battleMageHits / (battleMageCastTime + battleMageCooldown )
488
+ end
489
+
490
+ -- Infernal Cry uptime
491
+ if actor .mainSkill .activeEffect .grantedEffect .name == " Combust" and GlobalCache .cachedData [env .mode ][uuid ] and source and source .skillTypes [SkillType .Melee ] then
492
+ local infernalCryExertsCount = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .InfernalExertsCount
493
+ local infernalCryDuration = ceil_b (GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .InfernalCryDuration , data .misc .ServerTickTime )
494
+ local infernalCryCastTime = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .InfernalCryCastTime
495
+ local infernalCryCooldown = ceil_b (GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .InfernalCryCooldown , data .misc .ServerTickTime )
496
+
497
+ -- Cap the number of hits that happen during the duration
498
+ local infernalCryHits = m_max (m_min (trigRate * infernalCryDuration , infernalCryExertsCount ), 0 )
499
+
500
+ if breakdown then
501
+ t_insert (breakdown .EffectiveSourceRate , s_format (" ^8(min(%.2f * %.2f, %d) = %.2f average number of exerted attacks capped by exerted count)" , trigRate , infernalCryDuration , infernalCryExertsCount , infernalCryHits ))
502
+ t_insert (breakdown .EffectiveSourceRate , s_format (" = %.2f / (%.2f + %.2f) ^8(the calculated number of exerted attacks happens every cooldown + duration)" , infernalCryHits , infernalCryCastTime , infernalCryCooldown ))
503
+ end
504
+
505
+ -- The hits happen every Infernal Cry cooldown + duration
506
+ trigRate = infernalCryHits / (infernalCryCastTime + infernalCryCooldown )
507
+ end
508
+
487
509
-- Handling for mana spending rate for Manaforged Arrows Support
488
510
if actor .mainSkill .skillData .triggeredByManaforged and trigRate > 0 then
489
511
local triggeredUUID = cacheSkillUUID (actor .mainSkill , env )
@@ -525,7 +547,7 @@ local function defaultTriggerHandler(env, config)
525
547
local triggerCD = actor .mainSkill .triggeredBy and env .player .mainSkill .triggeredBy .grantedEffect .levels [env .player .mainSkill .triggeredBy .level ].cooldown
526
548
triggerCD = triggerCD or source .triggeredBy and source .triggeredBy .grantedEffect .levels [source .triggeredBy .level ].cooldown
527
549
local triggeredCD = actor .mainSkill .skillData .cooldown
528
-
550
+
529
551
if actor .mainSkill .skillData .triggeredByBrand then
530
552
triggerCD = actor .mainSkill .triggeredBy .mainSkill .skillData .repeatFrequency / actor .mainSkill .triggeredBy .activationFreqMore / actor .mainSkill .triggeredBy .activationFreqInc
531
553
triggerCD = triggerCD * icdr -- cancels out division by icdr lower, brand activation rate is not affected by icdr
@@ -1037,7 +1059,7 @@ local configTable = {
1037
1059
local requiredManaCost = env .player .modDB :Sum (" BASE" , nil , " KitavaRequiredManaCost" )
1038
1060
return {triggerChance = env .player .modDB :Sum (" BASE" , nil , " KitavaTriggerChance" ),
1039
1061
triggerName = " Kitava's Thirst" ,
1040
- comparer = function (uuid , source , triggerRate )
1062
+ comparer = function (env , uuid , source , triggerRate )
1041
1063
local cachedSpeed = GlobalCache .cachedData [env .mode ][uuid ].HitSpeed or GlobalCache .cachedData [env .mode ][uuid ].Speed
1042
1064
local cachedManaCost = GlobalCache .cachedData [env .mode ][uuid ].ManaCost
1043
1065
return ( (not source and cachedSpeed ) or (cachedSpeed and cachedSpeed > (triggerRate or 0 )) ) and ( (cachedManaCost or 0 ) > requiredManaCost )
@@ -1190,6 +1212,11 @@ local configTable = {
1190
1212
[" battlemage's cry" ] = function (env )
1191
1213
if env .player .mainSkill .activeEffect .grantedEffect .name ~= " Battlemage's Cry" then
1192
1214
return {triggerSkillCond = function (env , skill ) return skill .skillTypes [SkillType .Melee ] end ,
1215
+ comparer = function (env , uuid , source , triggerRate )
1216
+ -- Skills with no uptime ratio are not exerted by battlemage so should not be considered.
1217
+ local uptimeRatio = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .BattlemageUpTimeRatio
1218
+ return defaultComparer (env , uuid , source , triggerRate ) and uptimeRatio
1219
+ end ,
1193
1220
triggeredSkillCond = function (env , skill ) return skill .skillData .triggeredByBattleMageCry and slotMatch (env , skill ) end }
1194
1221
end
1195
1222
end ,
@@ -1219,7 +1246,12 @@ local configTable = {
1219
1246
env .player .mainSkill .infoMessage = env .player .mainSkill .activeEffect .grantedEffect .name .. " Triggered on Death"
1220
1247
end ,
1221
1248
[" combust" ] = function (env )
1222
- return {triggerSkillCond = function (env , skill ) return skill .skillTypes [SkillType .Melee ] end }
1249
+ return {triggerSkillCond = function (env , skill ) return skill .skillTypes [SkillType .Melee ] end ,
1250
+ comparer = function (env , uuid , source , triggerRate )
1251
+ -- Skills with no uptime ratio are not exerted by infernal cry so should not be considered.
1252
+ local uptimeRatio = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .InfernalUpTimeRatio
1253
+ return defaultComparer (env , uuid , source , triggerRate ) and uptimeRatio
1254
+ end ,}
1223
1255
end ,
1224
1256
[" prismatic burst" ] = function (env )
1225
1257
return {triggerSkillCond = function (env , skill ) return skill .skillTypes [SkillType .Attack ] and slotMatch (env , skill ) end }
@@ -1324,7 +1356,7 @@ local configTable = {
1324
1356
end ,
1325
1357
[" avenging flame" ] = function (env )
1326
1358
return {triggerSkillCond = function (env , skill ) return skill .skillFlags .totem and slotMatch (env , skill ) end ,
1327
- comparer = function (uuid , source , currentTotemLife )
1359
+ comparer = function (env , uuid , source , currentTotemLife )
1328
1360
local totemLife = GlobalCache .cachedData [env .mode ][uuid ].Env .player .output .TotemLife
1329
1361
return (not source and totemLife ) or (totemLife and totemLife > (currentTotemLife or 0 ))
1330
1362
end ,
@@ -1395,4 +1427,4 @@ function calcs.triggers(env, actor)
1395
1427
actor .mainSkill .skillData .triggered = nil
1396
1428
end
1397
1429
end
1398
- end
1430
+ end
0 commit comments