How to use elapsedMs method in stryker-parent

Best JavaScript code snippet using stryker-parent

champions.ts

Source:champions.ts Github

copy

Full Screen

1import { BonusKey, ChampionKey, DamageType } from '@tacticians-academy/academy-library'2import type { SpellCalculation } from '@tacticians-academy/academy-library'3import { state } from '#/store/store'4import { delayUntil } from '#/sim/loop'5import { isVIPActiveFor } from '#/sim/data/set6/utils'6import type { ChampionEffects } from '#/sim/data/types'7import { ShapeEffectCircle, ShapeEffectCone } from '#/sim/effects/ShapeEffect'8import { toRadians } from '#/sim/helpers/angles'9import { getBestDensityHexes, getHexRing, getHexRow, getOccupiedHexes, getHexesSurroundingWithin, getEdgeHexes } from '#/sim/helpers/board'10import type { SurroundingHexRange } from '#/sim/helpers/board'11import { createDamageCalculation } from '#/sim/helpers/calculate'12import { DEFAULT_CAST_SECONDS, DEFAULT_MANA_LOCK_MS, HEX_MOVE_LEAGUEUNITS, MAX_HEX_COUNT } from '#/sim/helpers/constants'13import { getDistanceUnitOfTeam, getRowOfMostAttackable, getInteractableUnitsOfTeam, modifyMissile, getDistanceUnitFromUnits, getUnitsOfTeam, getAttackableUnitsOfTeam, getProjectileSpread } from '#/sim/helpers/effectUtils'14import { containsHex } from '#/sim/helpers/hexes'15import { SpellKey, StatusEffectType } from '#/sim/helpers/types'16import type { BleedData, BonusLabelKey, DamageModifier } from '#/sim/helpers/types'17import { getBestRandomAsMax, getBestSortedAsMax, randomItem, randomItems, shuffle } from '#/sim/helpers/utils'18export const baseChampionEffects = {19 [ChampionKey.Blitzcrank]: {20 cast: (elapsedMS, spell, champion) => {21 const stunSeconds = champion.getSpellVariable(spell, SpellKey.StunDuration)22 const durationMS = stunSeconds * 100023 const target = getDistanceUnitOfTeam(true, champion, champion.opposingTeam()) //TODO Blitz pulls Blitz should swap hexes24 champion.setTarget(target)25 champion.queueProjectileEffect(elapsedMS, spell, {26 target,27 returnMissile: spell.missile,28 statusEffects: [29 [StatusEffectType.stunned, { durationMS }],30 ],31 onCollided: (elapsedMS, effect, withUnit) => {32 if (withUnit === champion) { return }33 champion.performActionUntilMS = 034 const adjacentHex = withUnit.projectHexFrom(champion, false, 1)35 if (adjacentHex) {36 withUnit.customMoveTo(adjacentHex, false, spell.missile?.speedInitial, undefined, false, (elapsedMS, withUnit) => {37 withUnit.applyStatusEffect(elapsedMS, StatusEffectType.stunned, durationMS)38 })39 if (!champion.checkInRangeOfTarget()) {40 champion.setTarget(null)41 }42 champion.alliedUnits(false).forEach(unit => unit.setTarget(withUnit)) //TODO target if in range43 champion.empoweredAutos.add({44 amount: 1,45 statusEffects: [46 [StatusEffectType.stunned, { durationMS: 1 * 1000 }], //NOTE investigate in data47 ],48 })49 }50 },51 })52 champion.performActionUntilMS = elapsedMS + durationMS53 return true54 },55 },56 [ChampionKey.Braum]: {57 cast: (elapsedMS, spell, champion) => {58 const stunSeconds = champion.getSpellVariable(spell, SpellKey.StunDuration)59 return champion.queueProjectileEffect(elapsedMS, spell, {60 destroysOnCollision: false,61 fixedHexRange: MAX_HEX_COUNT,62 hasBackingVisual: true,63 statusEffects: [64 [StatusEffectType.stunned, { durationMS: stunSeconds * 1000 }],65 ],66 })67 },68 },69 [ChampionKey.Caitlyn]: {70 cast: (elapsedMS, spell, champion) => {71 const target = getDistanceUnitOfTeam(true, champion, champion.opposingTeam())72 if (!target) { return false }73 return champion.queueProjectileEffect(elapsedMS, spell, {74 target,75 destroysOnCollision: true,76 targetDeathAction: 'farthestFromSource',77 })78 },79 },80 [ChampionKey.Camille]: {81 cast: (elapsedMS, spell, champion) => {82 const target = champion.target83 if (!target) { return false }84 return champion.queueShapeEffect(elapsedMS, spell, {85 shape: new ShapeEffectCone(champion, true, target, HEX_MOVE_LEAGUEUNITS * 2, toRadians(66)),86 })87 },88 },89 [ChampionKey.ChoGath]: {90 innate: (spell, champion) => {91 const maxStacks = champion.getSpellVariable(spell, 'MaxFeastStacks')92 const hpOnKillProportion = champion.getSpellVariable(spell, 'BonusHealthOnKill')93 const stackCount = champion.initStack(ChampionKey.ChoGath, { max: maxStacks })94 return [95 ['HPMultiplier' as BonusKey, hpOnKillProportion * stackCount],96 ]97 },98 cast: (elapsedMS, spell, champion) => {99 const hpOnKillProportion = champion.getSpellVariable(spell, 'BonusHealthOnKill')100 return champion.queueTargetEffect(elapsedMS, spell, {101 onCollided: (elapsedMS, effect, withUnit) => {102 if (withUnit.dead) {103 champion.increaseMaxHealthByProportion(spell.name as BonusLabelKey, hpOnKillProportion)104 }105 },106 })107 },108 },109 [ChampionKey.Darius]: {110 cast: (elapsedMS, spell, champion) => {111 if (!champion.wasInRangeOfTarget) { return false }112 return champion.queueShapeEffect(elapsedMS, spell, {113 shape: new ShapeEffectCircle(champion, HEX_MOVE_LEAGUEUNITS * 1.125),114 onCollided: (elapsedMS, effect, withUnit) => {115 const healCalculation = champion.getSpellCalculationResult(spell, SpellKey.Heal)116 if (healCalculation) champion.gainHealth(elapsedMS, champion, healCalculation, true)117 },118 })119 },120 },121 [ChampionKey.Ekko]: {122 cast: (elapsedMS, spell, champion) => {123 const hexRadius = champion.getSpellVariable(spell, 'HexRadius')124 const hotspotHex = randomItem(getBestDensityHexes(true, getInteractableUnitsOfTeam(null), true, hexRadius as SurroundingHexRange))125 if (!hotspotHex) { return false }126 const delaySeconds = champion.getSpellVariable(spell, 'FieldDelay')127 const fieldSeconds = champion.getSpellVariable(spell, 'FieldDuration')128 const allyASProportion = champion.getSpellCalculationResult(spell, 'BonusAS')129 const enemyASProportion = champion.getSpellVariable(spell, 'ASSlow')130 const allySeconds = champion.getSpellVariable(spell, 'BuffDuration')131 const enemySeconds = champion.getSpellVariable(spell, 'SlowDuration')132 const startsAfterMS = delaySeconds * 1000133 const expiresAfterMS = fieldSeconds * 1000134 const shape = new ShapeEffectCircle(hotspotHex, HEX_MOVE_LEAGUEUNITS * (hexRadius + 0.2))135 const bonusLabelKey = spell.name as BonusLabelKey136 champion.queueShapeEffect(elapsedMS, spell, { //TODO projectile to shape effect137 targetTeam: champion.team,138 shape,139 startsAfterMS,140 expiresAfterMS,141 opacity: 0.5,142 onCollided: (elapsedMS, effect, withUnit) => {143 withUnit.setBonusesFor(bonusLabelKey, [BonusKey.AttackSpeed, allyASProportion * 100, elapsedMS + allySeconds * 1000])144 },145 })146 return champion.queueShapeEffect(elapsedMS, spell, {147 shape,148 startsAfterMS,149 expiresAfterMS,150 opacity: 0.5,151 onCollided: (elapsedMS, effect, withUnit) => {152 withUnit.setBonusesFor(bonusLabelKey, [BonusKey.AttackSpeed, -enemyASProportion * 100, elapsedMS + enemySeconds * 1000])153 },154 })155 },156 },157 [ChampionKey.Ezreal]: {158 cast: (elapsedMS, spell, champion) => {159 return champion.queueProjectileEffect(elapsedMS, spell, {160 destroysOnCollision: true,161 onCollided: (elapsedMS, effect, withUnit) => {162 const allASBoosts = champion.getBonusesFrom(SpellKey.ASBoost)163 const maxStacks = champion.getSpellVariable(spell, SpellKey.MaxStacks)164 if (allASBoosts.length < maxStacks) {165 const boostAS = champion.getSpellCalculationResult(spell, SpellKey.ASBoost)! / maxStacks166 champion.bonuses.push([SpellKey.ASBoost, [[BonusKey.AttackSpeed, boostAS]]])167 }168 },169 })170 },171 },172 [ChampionKey.Galio]: {173 passive: (elapsedMS, spell, target, champion, damage) => {174 if (damage && damage.didCrit) {175 champion.queueHexEffect(elapsedMS, undefined, {176 hexes: getHexRing(target.activeHex),177 damageCalculation: champion.getSpellCalculation(spell, 'BonusDamage'),178 opacity: 0.5,179 })180 }181 },182 cast: (elapsedMS, spell, champion) => {183 const hexRadius = champion.getSpellVariable(spell, 'HexRadius')184 const stunSeconds = champion.getSpellVariable(spell, 'StunDuration')185 return champion.queueMoveUnitEffect(elapsedMS, spell, {186 target: champion,187 idealDestination: (champion) => randomItem(getBestDensityHexes(true, getAttackableUnitsOfTeam(champion.opposingTeam()), true, Math.min(4, hexRadius) as SurroundingHexRange)),188 hexEffect: {189 hexDistanceFromSource: Math.min(4, hexRadius) as SurroundingHexRange,190 statusEffects: [191 [StatusEffectType.stunned, { durationMS: stunSeconds * 1000 }],192 ],193 },194 moveDurationMS: 600, //TODO experimentally determine195 onActivate: (elapsedMS, champion) => {196 champion.applyStatusEffect(elapsedMS, StatusEffectType.invulnerable, 5000) //TODO time197 },198 onDestination: (elapsedMS, champion) => {199 champion.applyStatusEffect(elapsedMS, StatusEffectType.invulnerable, 0)200 },201 })202 },203 },204 [ChampionKey.Gangplank]: {205 cast: (elapsedMS, spell, champion) => {206 return champion.queueProjectileEffect(elapsedMS, spell, {})207 },208 },209 [ChampionKey.Illaoi]: {210 cast: (elapsedMS, spell, champion) => {211 const target = champion.target212 if (!target) { return false }213 const durationSeconds = champion.getSpellVariable(spell, SpellKey.Duration)214 const healingProportion = champion.getSpellVariable(spell, 'PercentHealing')215 return champion.queueTargetEffect(elapsedMS, spell, {216 sourceTargets: [[champion, target]],217 onActivate: (elapsedMS, champion) => {218 const id = champion.instanceID219 target.damageCallbacks.forEach(damageCallback => {220 if (damageCallback.id !== id) {221 target.damageCallbacks.delete(damageCallback)222 }223 })224 target.damageCallbacks.add({225 id,226 expiresAtMS: elapsedMS + durationSeconds * 1000,227 onDamage: (elapsedMS, target, damage) => {228 champion.gainHealth(elapsedMS, champion, damage.takingDamage * healingProportion, true)229 },230 })231 },232 })233 },234 },235 [ChampionKey.Jayce]: {236 innate: (spell, champion) => {237 champion.attackMissile = champion.transformIndex === 0 ? undefined : champion.getMissileWithSuffix('RangedAttack')238 },239 cast: (elapsedMS, spell, champion) => {240 const damageCalculation = champion.getSpellCalculation(spell, SpellKey.Damage)241 if (spell.variables['RangedASBoost'] != null) {242 const attackSpeedDuration = champion.getSpellVariable(spell, 'RangedASDuration')243 const attackSpeedProportion = champion.getSpellCalculationResult(spell, 'RangedASBoost')244 const durationMS = attackSpeedDuration * 1000245 champion.queueHexEffect(elapsedMS, spell, {246 targetTeam: champion.team,247 hexes: getHexRow(champion.activeHex[1]),248 expiresAfterMS: durationMS, //TODO verify249 onCollided: (elapsedMS, effect, withUnit) => {250 withUnit.setBonusesFor(spell.name as BonusLabelKey, [BonusKey.AttackSpeed, attackSpeedProportion, elapsedMS + durationMS])251 },252 })253 champion.manaLockUntilMS = Number.MAX_SAFE_INTEGER254 const missile = champion.getMissileWithSuffix('ShockBlastMis')255 champion.empoweredAutos.add({ //TODO verify these are attacks and not custom spell casts256 amount: 2,257 missile,258 hexEffect: {259 hexDistanceFromSource: 1,260 damageCalculation,261 },262 })263 champion.empoweredAutos.add({264 activatesAfterAmount: 2,265 amount: 1,266 missile,267 hexEffect: {268 hexDistanceFromSource: 2,269 damageCalculation,270 },271 onActivate: (elapsedMS, champion) => {272 champion.manaLockUntilMS = elapsedMS + DEFAULT_MANA_LOCK_MS273 },274 })275 } else {276 const target = champion.target277 if (!target || !champion.wasInRangeOfTarget) { return false } //TODO verify278 const hexes = getBestSortedAsMax(false, getHexRing(champion.activeHex, 1), (hex) => target.coordDistanceSquaredTo(hex))279 .slice(0, 3)280 champion.queueHexEffect(elapsedMS, spell, {281 hexes,282 onActivate: (elapsedMS, champion) => {283 const shieldSeconds = champion.getSpellVariable(spell, 'ShieldDuration')284 const shieldAmount = champion.getSpellCalculationResult(spell, 'ShieldAmount')285 const expiresAfterMS = shieldSeconds * 1000286 champion.applyStatusEffect(elapsedMS, StatusEffectType.unstoppable, expiresAfterMS)287 champion.queueShield(elapsedMS, champion, {288 id: champion.instanceID,289 amount: shieldAmount,290 expiresAfterMS,291 })292 champion.queueHexEffect(elapsedMS, spell, {293 hexes,294 onActivate: (elapsedMS, champion) => {295 const shredProportion = champion.getSpellVariable(spell, 'MeleeShred')296 const shredSeconds = champion.getSpellVariable(spell, 'MeleeShredDuration')297 const shredExpiresAtMS = elapsedMS + shredSeconds * 1000298 champion.queueMoveUnitEffect(elapsedMS, undefined, {299 target: champion,300 idealDestination: () => target.activeHex,301 ignoresDestinationCollision: true,302 moveSpeed: 1000, //TODO experimentally determine303 hexEffect: {304 damageCalculation,305 hexSource: target,306 hexDistanceFromSource: 2,307 bonuses: [spell.name as BonusLabelKey, [BonusKey.ArmorShred, shredProportion, shredExpiresAtMS], [BonusKey.MagicResistShred, shredProportion, shredExpiresAtMS]],308 },309 onDestination: (elapsedMS, champion) => {310 if (!target.dead) { //TODO check if target hex is open311 champion.customMoveTo(champion.activeHex, true, undefined, undefined, true) //TODO experimentally determine312 }313 },314 })315 },316 })317 },318 })319 }320 return true321 },322 },323 [ChampionKey.Jhin]: {324 cast: (elapsedMS, spell, champion) => {325 const falloffProportion = champion.getSpellVariable(spell, 'DamageFalloff')326 const stackingDamageModifier: DamageModifier = {327 multiplier: -falloffProportion,328 }329 const damageCalculation = champion.getSpellCalculation(spell, SpellKey.Damage)330 const missile = champion.getMissileWithSuffix('RShotMis')331 champion.empoweredAutos.add({332 amount: 3,333 damageCalculation,334 destroysOnCollision: false,335 missile,336 stackingDamageModifier,337 })338 const fourShotCalculation: SpellCalculation | undefined = JSON.parse(JSON.stringify(damageCalculation))339 fourShotCalculation?.parts.push({ //NOTE hardcoded340 operator: 'product',341 subparts: [342 {343 stat: BonusKey.MissingHealthPercent,344 statFromTarget: true,345 ratio: 1,346 },347 {348 stat: BonusKey.AbilityPower,349 ratio: 1,350 },351 ],352 })353 champion.empoweredAutos.add({354 activatesAfterAmount: 3,355 amount: 1,356 damageCalculation: fourShotCalculation,357 destroysOnCollision: false,358 damageModifier: {359 alwaysCrits: true,360 },361 missile: champion.getMissileWithSuffix('RShotMis4') ?? missile,362 stackingDamageModifier,363 onActivate: (elapsedMS, champion) => {364 champion.manaLockUntilMS = elapsedMS + DEFAULT_MANA_LOCK_MS365 },366 })367 if (spell.castTime != null) {368 champion.performActionUntilMS = elapsedMS + spell.castTime //TODO lock in place, infinite range?369 }370 champion.manaLockUntilMS = Number.MAX_SAFE_INTEGER371 return true372 },373 },374 [ChampionKey.Jinx]: {375 passive: (elapsedMS, spell, target, source, damage) => {376 if (state.setNumber >= 6.5 && source.castCount > 0) {377 const otherEnemies = getAttackableUnitsOfTeam(source.opposingTeam()).filter(unit => unit !== target)378 source.setTarget(randomItem(otherEnemies))379 }380 },381 cast: (elapsedMS, spell, champion) => {382 return champion.queueMoveUnitEffect(elapsedMS, spell, {383 target: champion,384 idealDestination: (champion) => randomItem(getBestDensityHexes(true, getInteractableUnitsOfTeam(champion.opposingTeam()), true, 4)),385 moveDurationMS: 1000, //TODO experimentally determine386 onDestination: (elapsedMS, champion) => {387 champion.manaLockUntilMS = Number.MAX_SAFE_INTEGER388 champion.addBonuses(spell.name as BonusLabelKey, [BonusKey.HexRangeIncrease, MAX_HEX_COUNT])389 const centerHex = champion.activeHex390 const innerRadius = champion.getSpellVariable(spell, 'InnerRadius')391 const outerRadius = champion.getSpellVariable(spell, 'OuterRadius')392 const damageFalloffProportion = champion.getSpellVariable(spell, 'FalloffPercent')393 const innerHexes = getHexesSurroundingWithin(centerHex, innerRadius as SurroundingHexRange, false)394 const outerHexes = getHexesSurroundingWithin(centerHex, Math.min(4, outerRadius) as SurroundingHexRange, false) //TODO support 5 range395 const magicDamage = champion.getSpellVariable(spell, SpellKey.Damage, true)396 const damageCalculation = createDamageCalculation(spell.name, magicDamage, DamageType.magic, BonusKey.AbilityPower, false, 0.01)397 champion.queueHexEffect(elapsedMS, undefined, {398 hexes: innerHexes,399 damageCalculation,400 damageModifier: {401 multiplier: -damageFalloffProportion,402 },403 opacity: damageFalloffProportion,404 })405 champion.queueHexEffect(elapsedMS, undefined, {406 hexes: outerHexes,407 damageCalculation,408 damageModifier: {409 multiplier: -damageFalloffProportion,410 },411 opacity: damageFalloffProportion,412 })413 const burnHexes = getHexesSurroundingWithin(centerHex, 2, true) //NOTE Hardcoded414 const burnPercent = champion.getSpellVariable(spell, 'PercentBurn')415 const burnHexSeconds = champion.getSpellVariable(spell, 'HexDuration')416 const burnTickMS = 1000 //NOTE hardcoded417 champion.queueHexEffect(elapsedMS, undefined, {418 targetTeam: null,419 hexes: burnHexes,420 expiresAfterMS: burnHexSeconds * 1000,421 ticksEveryMS: burnTickMS,422 damageCalculation: createDamageCalculation(spell.name, burnPercent, DamageType.true, BonusKey.Health, true, 0.01),423 })424 champion.empoweredAutos.add({425 amount: 9001,426 hexEffect: {427 hexDistanceFromSource: 1, //NOTE hardcoded428 targetTeam: champion.opposingTeam(),429 damageCalculation: champion.getSpellCalculation(spell, SpellKey.Damage), //TODO This adds to the base attack damage for the target. Should it replace it instead?430 },431 })432 },433 })434 },435 },436 [ChampionKey.KaiSa]: {437 cast: (elapsedMS, spell, champion) => {438 return champion.queueMoveUnitEffect(elapsedMS, spell, {439 target: champion,440 moveSpeed: 4000, //TODO experimentally determine441 idealDestination: (champion) => {442 const enemies = getInteractableUnitsOfTeam(champion.opposingTeam())443 const enemyColdMap = getBestDensityHexes(false, enemies, true, Math.min(4, champion.range()) as SurroundingHexRange)444 return getBestRandomAsMax(true, enemyColdMap.filter(hex => !champion.isAt(hex)), (hex) => enemies.reduce((acc, unit) => acc + unit.coordDistanceSquaredTo(hex), 0))445 },446 onDestination: (elapsedMS, champion) => {447 const attackableEnemies = getAttackableUnitsOfTeam(champion.opposingTeam())448 const missileCount = champion.getSpellVariable(spell, 'NumMissiles') + champion.basicAttackCount449 const castSeconds = champion.getSpellVariable(spell, 'FakeCastTime')450 getProjectileSpread(missileCount, toRadians(5)).forEach((changeRadians, index) => {451 champion.queueProjectileEffect(elapsedMS, spell, {452 startsAfterMS: (castSeconds + castSeconds * index / missileCount) * 1000,453 target: attackableEnemies[index % attackableEnemies.length],454 changeRadians, //TODO from sides with turn speed455 targetDeathAction: 'closestFromTarget',456 // missile: //TODO shoulder missile fixed travel time457 })458 })459 },460 })461 },462 },463 [ChampionKey.Kassadin]: {464 cast: (elapsedMS, spell, champion) => {465 return champion.queueProjectileEffect(elapsedMS, spell, {466 onCollided: (elapsedMS, effect, withUnit) => {467 const manaReave = champion.getSpellVariable(spell, SpellKey.ManaReave)468 const durationSeconds = champion.getSpellVariable(spell, SpellKey.Duration)469 const damageReduction = champion.getSpellVariable(spell, SpellKey.DamageReduction)470 withUnit.setBonusesFor(SpellKey.ManaReave, [BonusKey.ManaReductionPercent, manaReave * -100])471 champion.setBonusesFor(SpellKey.DamageReduction, [BonusKey.DamageReduction, damageReduction / 100, elapsedMS + durationSeconds * 1000])472 },473 })474 },475 },476 [ChampionKey.Leona]: {477 innate: (spell, champion) => {478 if (isVIPActiveFor(champion)) {479 const maxHPPerSecondPercent = champion.getSpellVariable(spell, 'T1DebutantBonus')480 champion.scalings.add({481 source: champion,482 sourceID: ChampionKey.Leona,483 activatedAtMS: 0,484 stats: [BonusKey.Health],485 intervalSeconds: 1, //NOTE hardcoded486 calculateAmount: (elapsedMS) => {487 const targetedByCount = getUnitsOfTeam(champion.opposingTeam()).filter(unit => unit.target === champion).length488 console.log(targetedByCount)489 return targetedByCount * maxHPPerSecondPercent / 100 * champion.healthMax490 },491 })492 }493 },494 cast: (elapsedMS, spell, champion) => {495 const shieldAmount = champion.getSpellCalculationResult(spell, 'Shielding')496 const durationSeconds = champion.getSpellVariable(spell, SpellKey.Duration)497 const bonusStats = champion.getSpellVariable(spell, 'BonusStats')498 const expiresAfterMS = durationSeconds * 1000499 champion.queueHexEffect(elapsedMS, spell, {500 targetTeam: champion.team,501 hexDistanceFromSource: 2, //NOTE hardcoded502 opacity: 0.5,503 onActivate: (elapsedMS, champion) => {504 champion.queueShield(elapsedMS, champion, {505 amount: shieldAmount,506 expiresAfterMS,507 })508 champion.manaLockUntilMS = elapsedMS + expiresAfterMS509 },510 onCollided: (elapsedMS, effect, withUnit) => {511 withUnit.setBonusesFor(spell.name as BonusLabelKey, [BonusKey.Armor, bonusStats, elapsedMS + expiresAfterMS], [BonusKey.MagicResist, bonusStats, elapsedMS + expiresAfterMS])512 },513 })514 return true515 },516 },517 [ChampionKey.Lulu]: {518 cast: (elapsedMS, spell, champion) => {519 const alliesByLowestHP = getBestSortedAsMax(false, champion.alliedUnits(true), (unit) => unit.health)520 const allyCount = champion.getSpellVariable(spell, 'NumAllies')521 const stunSeconds = champion.getSpellVariable(spell, 'CCDuration')522 const healAmount = champion.getSpellCalculationResult(spell, 'BonusHealth')523 alliesByLowestHP524 .slice(0, allyCount)525 .forEach(unit => {526 const bonusLabelKey = spell.name as BonusLabelKey527 if (!unit.getBonusesFrom(bonusLabelKey).length) {528 champion.queueHexEffect(elapsedMS, spell, {529 hexSource: unit,530 hexDistanceFromSource: 1,531 statusEffects: [532 [StatusEffectType.stunned, { durationMS: stunSeconds * 1000 }],533 ],534 })535 }536 unit.addBonuses(bonusLabelKey)537 unit.gainHealth(elapsedMS, champion, healAmount, true)538 })539 return true540 },541 },542 [ChampionKey.Malzahar]: {543 cast: (elapsedMS, spell, champion) => {544 let target = champion.target545 if (!target) { return false }546 const sourceID = ChampionKey.Malzahar547 if (target.getBleed(sourceID)) {548 const unafflictedEnemies = getAttackableUnitsOfTeam(target.team).filter(unit => !unit.getBleed(sourceID))549 const newTarget = getDistanceUnitFromUnits(false, target, unafflictedEnemies)550 if (newTarget) {551 target = newTarget552 }553 }554 const mrShredProportion = champion.getSpellVariable(spell, 'MRShred')555 const damageCalculation = champion.getSpellCalculation(spell, SpellKey.Damage)!556 const durationMS = champion.getSpellVariable(spell, SpellKey.Duration) * 1000557 const repeatsEveryMS = champion.getSpellVariable(spell, 'TickRate') * 1000558 const iterationCount = durationMS / repeatsEveryMS559 const bleed: BleedData = {560 sourceID,561 source: champion,562 activatesAtMS: elapsedMS,563 damageCalculation,564 damageModifier: {565 multiplier: -(1 - 1 / iterationCount),566 },567 repeatsEveryMS,568 remainingIterations: iterationCount,569 onDeath: (elapsedMS, oldTarget) => {570 const spreadCount = champion.getSpellVariable(spell, 'SpreadTargets')571 getBestSortedAsMax(false, getInteractableUnitsOfTeam(oldTarget.team), (unit) => unit.coordDistanceSquaredTo(oldTarget) + (unit.getBleed(sourceID) ? 1 : 0)) //TODO attackable only?572 .slice(0, spreadCount)573 .forEach(newTarget => {574 newTarget.addBleedIfStrongerThan(sourceID, bleed)575 })576 },577 }578 target.addBleedIfStrongerThan(sourceID, bleed)579 target.setBonusesFor(spell.name as BonusLabelKey, [BonusKey.MagicResistShred, mrShredProportion, elapsedMS + durationMS])580 return true581 },582 },583 [ChampionKey.MalzaharVoidling]: {584 cast: (elapsedMS, spell, champion) => {585 delayUntil(elapsedMS, spell.castTime ?? DEFAULT_CAST_SECONDS).then(elapsedMS => {586 const shieldSeconds = champion.getSpellVariable(spell, 'DamageReducedDuration')587 const damageReductionProportion = champion.getSpellVariable(spell, 'DamageReducedPercent')588 const shieldDamageCalculation = champion.getSpellCalculation(spell, 'DamageAmount')589 const shielding = [champion]590 const enemies = getUnitsOfTeam(champion.opposingTeam())591 const mostTargetedAlly = getBestRandomAsMax(true, champion.alliedUnits(false), (unit) => enemies.filter(enemy => enemy.target === unit).length)592 if (mostTargetedAlly) { shielding.push(mostTargetedAlly) }593 shielding.forEach(unit => {594 unit.queueShield(elapsedMS, champion, {595 id: champion.name,596 type: 'barrier',597 damageReduction: damageReductionProportion,598 expiresAfterMS: shieldSeconds * 1000,599 bonusDamage: shieldDamageCalculation,600 })601 })602 })603 return true604 },605 },606 [ChampionKey.Tibbers]: {607 passiveCasts: true,608 passive: (elapsedMS, spell, target, champion, damage) => {609 delayUntil(elapsedMS, spell.castTime ?? DEFAULT_CAST_SECONDS).then(elapsedMS => {610 const buffSeconds = champion.getSpellCalculationResult(spell, 'BuffDuration')611 const bonusADProportion = champion.getSpellVariable(spell, 'PercentAD')612 const allyADAP = champion.getSpellVariable(spell, 'AllyADAPBuff')613 const expiresAtMS = elapsedMS + buffSeconds * 1000614 const bonusKey = spell.name as BonusLabelKey615 champion.setBonusesFor(bonusKey, [BonusKey.AttackDamage, champion.attackDamage() * bonusADProportion, expiresAtMS])616 champion617 .alliedUnits(false)618 .forEach(unit => unit.setBonusesFor(bonusKey, [BonusKey.AttackDamage, allyADAP, expiresAtMS], [BonusKey.AbilityPower, allyADAP, expiresAtMS]))619 })620 },621 },622 [ChampionKey.HexTechDragon]: {623 innate: (spell, champion) => {624 const damageCalculation = champion.getSpellCalculation(spell, 'BonusLightningDamage')625 const chainCount = champion.getSpellVariable(spell, 'NumEnemies')626 champion.statusEffects.ccImmune.active = true627 champion.statusEffects.ccImmune.expiresAtMS = Number.MAX_SAFE_INTEGER628 champion.empoweredAutos.add({629 amount: 9001,630 nthAuto: 3, //NOTE hardcoded631 bounce: {632 bouncesRemaining: chainCount, //TODO applies to first target as bonus633 damageCalculation,634 },635 missile: champion.data.spells[1]?.missile,636 })637 },638 cast: (elapsedMS, spell, champion) => {639 const fearHexRange = champion.getSpellVariable(spell, 'FearHexRange')640 const fearSeconds = champion.getSpellVariable(spell, 'FearDuration')641 return champion.queueHexEffect(elapsedMS, spell, {642 targetTeam: champion.opposingTeam(),643 hexDistanceFromSource: Math.min(4, fearHexRange) as SurroundingHexRange, //TODO support 5 hex range644 onCollided: (elapsedMS, effect, withUnit) => {645 const occupiedHexes = getOccupiedHexes(state.units.filter(unit => unit !== withUnit))646 champion.queueMoveUnitEffect(elapsedMS, undefined, {647 target: withUnit,648 idealDestination: (target) => getBestRandomAsMax(true, getHexesSurroundingWithin(target.activeHex, 1, true), (hex) => (containsHex(hex, occupiedHexes) ? undefined : champion.coordDistanceSquaredTo(hex))),649 ignoresDestinationCollision: true,650 moveDurationMS: fearSeconds / 1000,651 })652 withUnit.applyStatusEffect(elapsedMS, StatusEffectType.stunned, fearSeconds * 1000)653 },654 onActivate: (elapsedMS, champion) => {655 const energizedSeconds = champion.getSpellVariable(spell, 'EnergizedDuration')656 const expiresAtMS = elapsedMS + energizedSeconds * 1000657 champion.alliedUnits(true).forEach(alliedUnit => {658 alliedUnit.empoweredAutos.add({659 amount: 9001,660 expiresAtMS,661 damageModifier: {662 alwaysCrits: true,663 },664 })665 })666 },667 })668 },669 },670 [ChampionKey.MissFortune]: {671 cast: (elapsedMS, spell, champion) => {672 if (!champion.target) { return false }673 const damageCalculation = champion.getSpellCalculation(spell, 'MagicDamage')674 const grievousWoundsSeconds = champion.getSpellVariable(spell, 'HealingReductionDuration')675 const grievousWoundsPercent = champion.getSpellVariable(spell, 'HealingReduction')676 const wavesCount = 4 //NOTE hardcoded677 const hexRadius = 2 //TODO experimentally determine678 const castMS = 1000679 const msBetweenAttacks = castMS / wavesCount680 for (let waveIndex = 0; waveIndex < wavesCount; waveIndex += 1) {681 champion.queueShapeEffect(elapsedMS, spell, {682 startsAfterMS: waveIndex * msBetweenAttacks,683 shape: new ShapeEffectCircle(champion.target.activeHex, HEX_MOVE_LEAGUEUNITS * hexRadius),684 damageCalculation,685 damageModifier: {686 multiplier: -(1 - 1 / wavesCount),687 },688 statusEffects: [689 [StatusEffectType.grievousWounds, { amount: grievousWoundsPercent / 100, durationMS: grievousWoundsSeconds * 1000 }],690 ],691 })692 }693 return true694 },695 },696 [ChampionKey.Orianna]: {697 cast: (elapsedMS, spell, champion) => {698 const hexRange = 2 //NOTE hardcoded699 const hotspotHex = randomItem(getBestDensityHexes(true, getInteractableUnitsOfTeam(null), true, hexRange))700 if (!hotspotHex) { return false }701 const stunSeconds = champion.getSpellVariable(spell, SpellKey.StunDuration)702 const shieldAmount = champion.getSpellCalculationResult(spell, 'ShieldAmount')703 const shieldSeconds = champion.getSpellVariable(spell, 'Duration')704 const hexes = getHexesSurroundingWithin(hotspotHex, hexRange, true)705 champion.queueHexEffect(elapsedMS, spell, {706 hexes,707 statusEffects: [708 [StatusEffectType.stunned, { durationMS: stunSeconds * 1000 }],709 ],710 })711 champion.queueHexEffect(elapsedMS, spell, {712 targetTeam: champion.team,713 hexes,714 onCollided: (elapsedMS, effect, withUnit) => {715 withUnit.queueShield(elapsedMS, champion, {716 amount: shieldAmount,717 expiresAfterMS: shieldSeconds * 1000,718 })719 },720 })721 return true722 },723 },724 [ChampionKey.Poppy]: {725 passiveCasts: true,726 passive: (elapsedMS, spell, target, champion, damage) => {727 const mostDistantEnemy = getDistanceUnitOfTeam(true, champion, champion.opposingTeam())728 if (!mostDistantEnemy) { return false }729 return champion.queueProjectileEffect(elapsedMS, spell, {730 target: mostDistantEnemy,731 returnMissile: champion.getMissileWithSuffix('PBounce'),732 onCollided: (elapsedMS, effect, withUnit) => {733 if (withUnit !== champion) { return }734 const shieldAmount = champion.getSpellCalculationResult(spell, 'Shield')735 champion.queueShield(elapsedMS, champion, {736 id: ChampionKey.Poppy,737 amount: shieldAmount,738 })739 },740 })741 },742 },743 [ChampionKey.Quinn]: {744 cast: (elapsedMS, spell, champion) => {745 const highestASEnemy = getBestRandomAsMax(true, getAttackableUnitsOfTeam(champion.opposingTeam()), (unit) => unit.attackSpeed())746 const disarmSeconds = champion.getSpellVariable(spell, 'DisarmDuration')747 return champion.queueProjectileEffect(elapsedMS, spell, {748 target: highestASEnemy,749 hexEffect: {750 hexDistanceFromSource: 1,751 statusEffects: [752 [StatusEffectType.disarm, { durationMS: disarmSeconds * 1000 }],753 ],754 },755 })756 },757 },758 [ChampionKey.Seraphine]: {759 cast: (elapsedMS, spell, champion) => {760 const densestEnemyHex = randomItem(getBestDensityHexes(true, getInteractableUnitsOfTeam(null), true, 1)) //TODO experimentally determine761 if (!densestEnemyHex) { return false }762 const bonusASProportion = champion.getSpellVariable(spell, 'ASBonus')763 const bonusSeconds = champion.getSpellVariable(spell, 'ASBonusDuration')764 champion.queueProjectileEffect(elapsedMS, spell, {765 target: densestEnemyHex,766 targetTeam: champion.team,767 fixedHexRange: MAX_HEX_COUNT,768 destroysOnCollision: false,769 opacity: 0.5,770 onCollided: (elapsedMS, effect, withUnit) => {771 const healAmount = champion.getSpellCalculationResult(spell, SpellKey.Heal)772 withUnit.gainHealth(elapsedMS, champion, healAmount, true)773 withUnit.setBonusesFor(spell.name as BonusLabelKey, [BonusKey.AttackSpeed, bonusASProportion * 100, elapsedMS + bonusSeconds * 1000])774 },775 })776 champion.queueProjectileEffect(elapsedMS, spell, {777 target: densestEnemyHex,778 fixedHexRange: MAX_HEX_COUNT,779 destroysOnCollision: false,780 opacity: 0.5,781 })782 return true783 },784 },785 [ChampionKey.Singed]: {786 cast: (elapsedMS, spell, champion) => {787 const targetStunSeconds = champion.getSpellVariable(spell, SpellKey.StunDuration)788 const aoeStunSeconds = champion.getSpellVariable(spell, 'AoEStunDuration')789 return champion.queueMoveUnitEffect(elapsedMS, spell, {790 moveSpeed: 1000, //TODO experimentally determine791 idealDestination: (target) => randomItem(getBestDensityHexes(true, getInteractableUnitsOfTeam(target.team).filter(unit => unit !== target), false, 2)),792 statusEffects: [793 [StatusEffectType.stunned, { durationMS: targetStunSeconds * 1000 }],794 ],795 hexEffect: {796 hexDistanceFromSource: 1,797 statusEffects: [798 [StatusEffectType.stunned, { durationMS: aoeStunSeconds * 1000 }],799 ],800 },801 })802 },803 },804 [ChampionKey.Swain]: {805 cast: (elapsedMS, spell, champion) => {806 const target = champion.target807 if (!target) { return false } //TODO detaches from caster to reach?808 const arcRadians = toRadians(45) //TODO experimentally determine809 return champion.queueShapeEffect(elapsedMS, spell, {810 shape: new ShapeEffectCone(champion, false, target, HEX_MOVE_LEAGUEUNITS * 2, arcRadians),811 onCollided: (elapsedMS, effect, withUnit) => {812 const heal = champion.getSpellCalculationResult(spell, 'Healing')813 champion.gainHealth(elapsedMS, champion, heal, true)814 },815 })816 },817 },818 [ChampionKey.Talon]: {819 passive: (elapsedMS, spell, target, source, damage) => {820 const bleedSeconds = source.getSpellVariable(spell, 'BleedDuration')821 const bonusBleedTimePercent = source.getSpellVariable(spell, 'VIPBleedDurationBonus')822 const repeatsEveryMS = 1000 //TODO experimentally determine823 const iterationsCount = bleedSeconds * 1000 / repeatsEveryMS824 const sourceID = source.instanceID825 const basicAttacksOnTarget = target.basicAttackSourceIDs.filter(basicAttackSourceID => basicAttackSourceID === sourceID).length826 const isVIP = isVIPActiveFor(source)827 const remainingIterations = isVIP828 ? iterationsCount * Math.ceil(1 + bonusBleedTimePercent / 100)829 : iterationsCount830 if (basicAttacksOnTarget % 3 === 0) { //NOTE hardcoded831 target.bleeds.add({832 sourceID,833 source,834 damageCalculation: source.getSpellCalculation(spell, SpellKey.Damage)!,835 damageModifier: {836 damageType: isVIP ? DamageType.true : undefined,837 multiplier: -(1 - 1 / iterationsCount),838 },839 activatesAtMS: elapsedMS,840 repeatsEveryMS,841 remainingIterations,842 })843 }844 return true845 },846 },847 [ChampionKey.TahmKench]: {848 cast: (elapsedMS, spell, champion) => {849 const target = champion.target850 if (!target) { return false }851 delayUntil(elapsedMS, spell.castTime ?? DEFAULT_CAST_SECONDS).then(elapsedMS => {852 const spellShield = target.consumeSpellShield()853 const ignoresCC = spellShield != null || target.isUnstoppable()854 const bellySeconds = champion.getSpellVariable(spell, 'BellyDuration')855 const damageCalculation = ignoresCC ? champion.getSpellCalculation(spell, 'ReducedDamageToCC') : champion.getSpellCalculation(spell, SpellKey.Damage)856 if (damageCalculation) {857 if (!ignoresCC) {858 target.applyStatusEffect(elapsedMS, StatusEffectType.invulnerable, bellySeconds * 1000)859 target.collides = false860 }861 const sourceID = ChampionKey.TahmKench862 const tickSeconds = champion.getSpellVariable(spell, 'TickRate')863 const tickCount = bellySeconds / tickSeconds864 target.addBleedIfStrongerThan(sourceID, {865 sourceID,866 source: champion,867 damageCalculation,868 damageModifier: {869 multiplier: -(1 - 1 / tickCount),870 increase: spellShield?.amount != null ? -spellShield.amount : undefined,871 ignoresInvulnerability: true,872 },873 activatesAtMS: elapsedMS,874 repeatsEveryMS: tickSeconds * 1000,875 remainingIterations: tickCount,876 })877 delayUntil(elapsedMS, bellySeconds).then(elapsedMS => {878 target.collides = true879 if (!target.dead) {880 const farthestEnemy = getDistanceUnitOfTeam(true, champion, champion.opposingTeam())881 const impactStunSeconds = champion.getSpellVariable(spell, 'StunDuration')882 champion.queueMoveUnitEffect(elapsedMS, undefined, {883 target,884 targetTeam: target.team,885 idealDestination: () => (farthestEnemy ? champion.projectHexFrom(farthestEnemy, false, 1) : champion.activeHex),886 moveSpeed: 2000, //TODO experimentally determine887 collisionSizeMultiplier: 2,888 onCollided: (elapsedMS, effect, withUnit) => {889 withUnit.applyStatusEffect(elapsedMS, StatusEffectType.stunned, impactStunSeconds * 1000)890 },891 })892 }893 })894 }895 })896 return true897 },898 },899 [ChampionKey.Twitch]: {900 cast: (elapsedMS, spell, champion) => {901 const grievousWoundsProportion = champion.getSpellVariable(spell, 'GWStrength')902 const grievousWoundsSeconds = champion.getSpellVariable(spell, 'GWDuration')903 const durationMS = grievousWoundsSeconds * 1000904 return champion.queueProjectileEffect(elapsedMS, spell, {905 destroysOnCollision: false,906 fixedHexRange: MAX_HEX_COUNT,907 statusEffects: [908 [StatusEffectType.grievousWounds, { durationMS, amount: grievousWoundsProportion }],909 ],910 })911 },912 },913 [ChampionKey.Veigar]: {914 cast: (elapsedMS, spell, champion) => {915 const strikeCount = champion.getSpellVariable(spell, 'NumStrikes')916 const enemies = getAttackableUnitsOfTeam(champion.opposingTeam())917 shuffle(enemies)918 const castSeconds = 3 //TODO experimentally determine919 const secondsBetweenCasts = castSeconds / strikeCount920 for (let strikeIndex = 0; strikeIndex < strikeCount; strikeIndex += 1) {921 const enemy = enemies[strikeIndex % enemies.length]922 delayUntil(elapsedMS, strikeIndex * secondsBetweenCasts).then(elapsedMS => {923 champion.queueHexEffect(elapsedMS, spell, {924 startsAfterMS: secondsBetweenCasts,925 hexes: [[...enemy.activeHex]],926 })927 })928 }929 return true930 },931 },932 [ChampionKey.Viktor]: {933 passive: (elapsedMS, spell, target, source, damage) => {934 const armorShredProportion = source.getSpellVariable(spell, 'ArmorReduction')935 const armorShredSeconds = source.getSpellVariable(spell, 'ShredDuration')936 target.applyStatusEffect(elapsedMS, StatusEffectType.armorReduction, armorShredSeconds * 1000, armorShredProportion)937 },938 cast: (elapsedMS, spell, champion) => {939 delayUntil(elapsedMS, spell.castTime!).then(elapsedMS => {940 const laserCount = champion.getSpellVariable(spell, 'NumLasers')941 const droneMissile = champion.getMissileWithSuffix('EDroneMis')942 const laserMissile = champion.getMissileWithSuffix('EDamageMis')943 const droneHexes = randomItems(laserCount, getEdgeHexes()) //TODO distributed random944 champion.queueHexEffect(elapsedMS, undefined, {945 startsAfterMS: droneMissile?.travelTime,946 hexes: droneHexes,947 onActivate: (elapsedMS) => {948 const validTargets = shuffle(getAttackableUnitsOfTeam(champion.opposingTeam()))949 if (!validTargets.length) { return }950 droneHexes.forEach((droneHex, laserIndex) => {951 champion.queueProjectileEffect(elapsedMS, spell, {952 projectileStartsFrom: droneHex,953 target: validTargets[laserIndex % validTargets.length], //TODO handle same projectileStartsFrom/target hex954 missile: laserMissile,955 destroysOnCollision: false,956 fixedHexRange: MAX_HEX_COUNT,957 onModifyDamage: (elapsedMS, withUnit, damage) => {958 const shieldDestructionProportion = champion.getSpellVariable(spell, 'ShieldDestructionPercent')959 withUnit.shields.forEach(shield => {960 if (shield.amount != null) {961 shield.amount *= (1 - shieldDestructionProportion)962 }963 })964 },965 })966 })967 },968 })969 })970 return true971 },972 },973 [ChampionKey.Vex]: {974 cast: (elapsedMS, spell, champion) => {975 const shieldKey = 'VexShieldMultiplier' as BonusKey976 const shieldAmount = champion.getSpellVariable(spell, 'ShieldAmount')977 const shieldSeconds = champion.getSpellVariable(spell, 'ShieldDuration')978 const shieldAmp = champion.getSpellVariable(spell, 'ShieldAmp')979 const shieldTotalAmp = champion.getBonuses(shieldKey)980 const expiresAfterMS = shieldSeconds * 1000981 champion.queueShield(elapsedMS, champion, {982 amount: shieldAmount * (1 + shieldTotalAmp),983 expiresAfterMS,984 onRemoved: (elapsedMS, shield) => {985 champion.manaLockUntilMS = 0986 const hexDistanceFromSource = champion.data.stats.range as SurroundingHexRange987 champion.queueHexEffect(elapsedMS, spell, {988 hexDistanceFromSource,989 })990 if (shield.amount != null && shield.amount > 0) {991 champion.queueHexEffect(elapsedMS, undefined, {992 hexDistanceFromSource,993 damageCalculation: champion.getSpellCalculation(spell, 'BonusDamage'),994 })995 } else {996 champion.addBonuses(spell.name as BonusLabelKey, [shieldKey, shieldAmp])997 }998 },999 })1000 champion.manaLockUntilMS = 60 * 10001001 return true1002 },1003 },1004 [ChampionKey.Warwick]: {1005 passive: (elapsedMS, spell, target, source, damage) => {1006 const heal = source.getSpellCalculationResult(spell, SpellKey.HealAmount)1007 const percentHealthDamage = source.getSpellCalculationResult(spell, SpellKey.PercentHealth) / 1001008 const damageCalculation = createDamageCalculation(SpellKey.PercentHealth, percentHealthDamage, DamageType.magic, BonusKey.CurrentHealth, true, 1)1009 target.takeBonusDamage(elapsedMS, source, damageCalculation, false)1010 source.gainHealth(elapsedMS, source, heal, true)1011 return true1012 },1013 },1014 [ChampionKey.Zac]: {1015 cast: (elapsedMS, spell, champion) => {1016 const validUnits = getAttackableUnitsOfTeam(champion.opposingTeam())1017 .filter(unit => unit.hexDistanceTo(champion) <= 3) //NOTE hardcoded1018 const targets = getBestSortedAsMax(true, validUnits, (unit) => unit.coordDistanceSquaredTo(champion))1019 .slice(0, 2)1020 if (!targets.length) { return false }1021 champion.queueProjectileEffect(elapsedMS, spell, { //TODO line visual style1022 target: targets[0],1023 onCollided: (elapsedMS, effect, withUnit) => {1024 champion.queueProjectileEffect(elapsedMS, spell, {1025 target: targets[1] ?? targets[0],1026 onCollided: (elapsedMS, effect, withUnit) => {1027 targets.forEach(target => {1028 champion.queueMoveUnitEffect(elapsedMS, undefined, {1029 target,1030 idealDestination: (target) => champion.projectHexFrom(target, false, 2),1031 moveDurationMS: 600,1032 onDestination: (elapsedMS, unit) => {1033 champion.performActionUntilMS = 01034 },1035 })1036 })1037 },1038 })1039 champion.performActionUntilMS = elapsedMS + 10001040 },1041 })1042 champion.performActionUntilMS = elapsedMS + 10001043 return true1044 },1045 },1046 [ChampionKey.Ziggs]: {1047 cast: (elapsedMS, spell, champion) => {1048 const targetHex = champion.target?.activeHex1049 if (!targetHex) { return false }1050 const centerHexes = [targetHex]1051 const outerHexes = getHexesSurroundingWithin(targetHex, 1, false)1052 champion.queueProjectileEffect(elapsedMS, spell, {1053 width: 40,1054 hexEffect: {1055 hexes: centerHexes,1056 },1057 })1058 champion.queueProjectileEffect(elapsedMS, spell, {1059 hexEffect: {1060 hexes: outerHexes,1061 damageModifier: {1062 multiplier: -0.5,1063 },1064 opacity: 0.5,1065 },1066 })1067 return true1068 },1069 },1070 [ChampionKey.Zilean]: {1071 cast: (elapsedMS, spell, champion) => {1072 const stunSeconds = champion.getSpellVariable(spell, SpellKey.StunDuration)1073 const slowProportion = champion.getSpellVariable(spell, 'Slow')1074 const slowSeconds = champion.getSpellVariable(spell, 'SlowDuration')1075 const missile = modifyMissile(spell, { width: 30 })1076 const durationMS = stunSeconds * 10001077 return champion.queueProjectileEffect(elapsedMS, spell, {1078 missile,1079 statusEffects: [1080 [StatusEffectType.stunned, { durationMS }],1081 ],1082 delayAfterReachingTargetMS: durationMS,1083 onCollided: (elapsedMS, effect, withUnit, damage) => {1084 if (damage == null) {1085 champion.queueHexEffect(elapsedMS, undefined, {1086 damageCalculation: champion.getSpellCalculation(spell, SpellKey.Damage),1087 hexSource: withUnit,1088 hexDistanceFromSource: 1,1089 statusEffects: [1090 [StatusEffectType.attackSpeedSlow, { amount: slowProportion * 100, durationMS: slowSeconds * 1000 }],1091 ],1092 })1093 }1094 },1095 })1096 },1097 },1098 [ChampionKey.Zyra]: {1099 cast: (elapsedMS, spell, champion) => {1100 const stunSeconds = champion.getSpellVariable(spell, SpellKey.StunDuration)1101 return champion.queueHexEffect(elapsedMS, spell, {1102 hexes: getRowOfMostAttackable(champion.opposingTeam()),1103 statusEffects: [1104 [StatusEffectType.stunned, { durationMS: stunSeconds * 1000 }],1105 ],1106 })1107 },1108 },...

Full Screen

Full Screen

Stopwatch.spec.ts

Source:Stopwatch.spec.ts Github

copy

Full Screen

1import { expect } from 'chai';2import { Stopwatch } from '../src/Util/Stopwatch';3import { sleep } from './util';4describe('Stopwatch', function () {5 it('should keep track of time', async function () {6 let min = 10;7 let max = 25;8 let sw = new Stopwatch();9 await sleep(10);10 expect(sw.elapsedMs).to.be.greaterThan(min).and.lessThan(max);11 expect(sw.elapsedS).to.be.greaterThan(min / 1000).and.lessThan(max / 1000);12 expect(sw.running).to.be.true;13 });14 it('should start automatically start', function () {15 let sw = new Stopwatch();16 expect(sw.running).to.be.true;17 expect(sw.elapsedMs).to.be.greaterThan(0);18 });19 it('should not start automatically if false is passed to the constructor', function () {20 let sw = new Stopwatch(false);21 expect(sw.running).to.be.false;22 expect(sw.elapsedMs).to.equal(0);23 });24 it('should track time in seconds and milliseconds', async function () {25 let sw = new Stopwatch();26 await sleep(10);27 sw.stop();28 expect(sw.elapsedMs).to.be.greaterThan(0);29 expect(sw.running).to.be.false;30 expect(sw.elapsedMs).to.equal(1000 * sw.elapsedS);31 });32 it('should be pausable/resumable', async function () {33 let sw = new Stopwatch();34 await sleep(1);35 sw.stop();36 expect(sw.elapsedMs).to.be.greaterThan(0);37 expect(sw.paused).to.be.true;38 expect(sw.running).to.be.false;39 let elapsedMs = sw.elapsedMs;40 await sleep(1);41 expect(sw.elapsedMs).to.equal(elapsedMs);42 sw.start();43 await sleep(1);44 expect(sw.elapsedMs).to.be.greaterThan(elapsedMs);45 });46 it('should be restartable', async function () {47 let sw = new Stopwatch();48 await sleep(1);49 expect(sw.elapsedMs).to.be.greaterThan(0);50 let oldElapsedMs = sw.elapsedMs;51 sw.restart();52 expect(sw.running).to.be.true;53 expect(sw.elapsedMs).to.be.greaterThan(0);54 expect(sw.elapsedMs).to.be.lessThan(oldElapsedMs);55 });56 it('should be restartable (while paused)', async function () {57 let sw = new Stopwatch();58 await sleep(1);59 expect(sw.elapsedMs).to.be.greaterThan(0);60 let oldElapsedMs = sw.elapsedMs;61 sw.stop();62 sw.restart();63 expect(sw.running).to.be.true;64 expect(sw.elapsedMs).to.be.greaterThan(0);65 expect(sw.elapsedMs).to.be.lessThan(oldElapsedMs);66 });67 it('should be resettable (start=true)', async function () {68 let sw = new Stopwatch();69 await sleep(1);70 expect(sw.elapsedMs).to.be.greaterThan(0);71 let oldElapsedMs = sw.elapsedMs;72 sw.reset(true);73 expect(sw.running).to.be.true;74 expect(sw.elapsedMs).to.be.greaterThan(0);75 expect(sw.elapsedMs).to.be.lessThan(oldElapsedMs);76 });77 it('should be resettable (start=false)', async function () {78 let sw = new Stopwatch();79 await sleep(1);80 expect(sw.elapsedMs).to.be.greaterThan(0);81 sw.reset(false);82 expect(sw.running).to.be.false;83 expect(sw.elapsedMs).to.equal(0);84 });85 it('should be resettable (while paused) (start=true)', async function () {86 let sw = new Stopwatch();87 await sleep(1);88 expect(sw.elapsedMs).to.be.greaterThan(0);89 let oldElapsedMs = sw.elapsedMs;90 sw.stop();91 sw.reset(true);92 expect(sw.running).to.be.true;93 expect(sw.elapsedMs).to.be.greaterThan(0);94 expect(sw.elapsedMs).to.be.lessThan(oldElapsedMs);95 });96 it('should be resettable (while paused) (start=false)', async function () {97 let sw = new Stopwatch();98 await sleep(1);99 expect(sw.elapsedMs).to.be.greaterThan(0);100 sw.stop();101 sw.reset(false);102 expect(sw.running).to.be.false;103 expect(sw.elapsedMs).to.equal(0);104 });105 it('should be adjustable', async function () {106 let sw = new Stopwatch();107 await sleep(1);108 expect(sw.elapsedMs).to.be.greaterThan(0);109 sw.elapsedMs += 5000;110 expect(sw.running).to.be.true;111 expect(sw.elapsedMs).to.be.greaterThan(5000);112 sw.elapsedMs -= 10000;113 expect(sw.running).to.be.true;114 expect(sw.elapsedMs).to.be.lessThan(0);115 });116 it('should be adjustable (while paused)', async function () {117 let sw = new Stopwatch();118 await sleep(1);119 expect(sw.elapsedMs).to.be.greaterThan(0);120 sw.stop();121 let elapsedMs = sw.elapsedMs;122 sw.elapsedMs += 5000;123 expect(sw.running).to.be.false;124 expect(sw.elapsedMs).to.equal(5000 + elapsedMs);125 sw.elapsedMs -= 10000;126 expect(sw.running).to.be.false;127 expect(sw.elapsedMs).to.equal(5000 - 10000 + elapsedMs);128 });129 it('should be ok to call stop() while paused', async function () {130 let sw = new Stopwatch();131 await sleep(1);132 expect(sw.elapsedMs).to.be.greaterThan(0);133 sw.stop();134 let elapsedMs = sw.elapsedMs;135 expect(sw.running).to.be.false;136 sw.stop();137 expect(sw.elapsedMs).to.equal(elapsedMs);138 expect(sw.running).to.be.false;139 });140 it('should be ok to call start() while running', async function () {141 let sw = new Stopwatch();142 await sleep(1);143 let elapsedMs = sw.elapsedMs;144 expect(elapsedMs).to.be.greaterThan(0);145 expect(sw.running).to.be.true;146 sw.start();147 await sleep(1);148 expect(sw.running).to.be.true;149 expect(sw.elapsedMs).to.be.greaterThan(elapsedMs);150 });...

Full Screen

Full Screen

speedTest.js

Source:speedTest.js Github

copy

Full Screen

1/* eslint-disable no-console */2'use strict';3var AvlTree = require('../index.js');4var count = Math.pow(10, 7); // I run oom at 10^85var tree = new AvlTree();6console.warn('---in order insert---');7var startMs = Date.now();8for (var i = 0; i < count; i += 1) {9 tree.insert(i);10}11var elapsedMs = Date.now() - startMs;12var avgMs = elapsedMs / count;13console.warn('elapsedMs:', elapsedMs, 'averageMs', avgMs);14console.warn('---in order delete---');15startMs = Date.now();16for (var j = 0; j < count; j += 1) {17 tree.delete(j);18}19elapsedMs = Date.now() - startMs;20avgMs = elapsedMs / count;21console.warn('elapsedMs:', elapsedMs, 'averageMs', avgMs);22console.warn('---in order search---');23startMs = Date.now();24for (var k = 0; k < count; k += 1) {25 tree.search(k);26}27elapsedMs = Date.now() - startMs;28avgMs = elapsedMs / count;29console.warn('elapsedMs:', elapsedMs, 'averageMs', avgMs);...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const { elapsedMs } = require('stryker-parent');2const { elapsedMs } = require('stryker-parent');3const { elapsedMs } = require('stryker-parent');4const { elapsedMs } = require('stryker-parent');5const { elapsedMs } = require('stryker-parent');6const { elapsedMs } = require('stryker-parent');7const { elapsedMs } = require('stryker-parent');8const { elapsedMs } = require('stryker-parent');9const { elapsedMs } = require('stryker-parent');10const { elapsedMs } = require('stryker-parent');11const { elapsedMs } = require('stryker-parent');12const { elapsedMs } = require('stryker-parent');13const { elapsedMs } = require('stryker-parent');14const { elapsedMs } = require('stryker-parent');15const { elapsedMs } = require('stryker-parent');16const { elapsedMs } = require('stryker-parent');17const { elapsedMs } = require('stryker-parent');18const { elapsedMs } = require('stryker-parent');19const { elapsedMs } = require('stryker-parent');

Full Screen

Using AI Code Generation

copy

Full Screen

1const elapsedMs = require('stryker-parent').elapsedMs;2const child = require('stryker-child');3const elapsedMs = child.elapsedMs;4const child2 = require('stryker-child-2');5const elapsedMs = child2.elapsedMs;6const child3 = require('stryker-child-3');7const elapsedMs = child3.elapsedMs;8const child4 = require('stryker-child-4');9const elapsedMs = child4.elapsedMs;10const child5 = require('stryker-child-5');11const elapsedMs = child5.elapsedMs;12const child6 = require('stryker-child-6');13const elapsedMs = child6.elapsedMs;14const child7 = require('stryker-child-7');15const elapsedMs = child7.elapsedMs;16const child8 = require('stryker-child-8');17const elapsedMs = child8.elapsedMs;18const child9 = require('stryker-child-9');19const elapsedMs = child9.elapsedMs;20const child10 = require('stryker-child-10');21const elapsedMs = child10.elapsedMs;22const child11 = require('stryker-child-11');23const elapsedMs = child11.elapsedMs;24const child12 = require('stryker-child-12');25const elapsedMs = child12.elapsedMs;26const child13 = require('stryker-child-13');27const elapsedMs = child13.elapsedMs;28const child14 = require('stryker-child

Full Screen

Using AI Code Generation

copy

Full Screen

1const strykerParent = require('stryker-parent');2const elapsedMs = strykerParent.elapsedMs;3const start = new Date();4setTimeout(() => {5 const end = new Date();6 console.log(elapsedMs(start, end));7}, 1000);8const strykerParent = require('stryker-parent');9const elapsedMs = strykerParent.elapsedMs;10describe('elapsedMs', () => {11 it('should return the elapsed milliseconds', () => {12 const start = new Date();13 const end = new Date();14 end.setMilliseconds(start.getMilliseconds() + 1000);15 expect(elapsedMs(start, end)).toBe(1000);16 });17});

Full Screen

Using AI Code Generation

copy

Full Screen

1var elapsedMs = require('stryker-parent').elapsedMs;2module.exports = function (config) {3 config.set({4 });5};6var elapsedMs = require('stryker-parent').elapsedMs;7module.exports = function (config) {8 config.set({9 });10};11var elapsedMs = require('stryker-parent').elapsedMs;12module.exports = function (config) {13 config.set({14 });15};

Full Screen

Using AI Code Generation

copy

Full Screen

1const { elapsedMs } = require('stryker-parent');2const { performance } = require('perf_hooks');3const start = performance.now();4const end = performance.now();5console.log(elapsedMs(start, end));6const { elapsedMs } = require('stryker-parent');7const { performance } = require('perf_hooks');8const start = performance.now();9const end = performance.now();10console.log(elapsedMs(start, end));

Full Screen

Using AI Code Generation

copy

Full Screen

1module.exports = {2 elapsedMs: function () {3 return 1000;4 }5};6{7}8module.exports = {9 elapsedMs: function () {10 return 500;11 }12};13{14}15module.exports = {16 elapsedMs: function () {17 return 250;18 }19};20{21}22module.exports = {23 elapsedMs: function () {24 return 125;25 }26};27{28}29module.exports = {30 elapsedMs: function () {31 return 62.5;32 }33};34{35}36module.exports = {37 elapsedMs: function () {38 return 31.25;39 }40};41{42}43module.exports = {

Full Screen

Using AI Code Generation

copy

Full Screen

1var elapsedMs = require('stryker-parent').elapsedMs;2var start = elapsedMs();3var end = elapsedMs();4console.log('elapsed time = ' + end - start);5{6 "dependencies": {7 }8}9{10 "scripts": {11 },12 "devDependencies": {13 }14}15var elapsedMs = require('./elapsedMs');16module.exports = {17};18module.exports = function elapsedMs() {19 var hrtime = process.hrtime();20 return hrtime[0] * 1000 + hrtime[1] / 1000000;21};22{23 "scripts": {24 },25 "repository": {26 },

Full Screen

Using AI Code Generation

copy

Full Screen

1const start = Date.now();2const start = Date.now();3const start = Date.now();4const start = Date.now();5const start = Date.now();6const start = Date.now();7const start = Date.now();

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run stryker-parent automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful