diff --git a/src/constants/common-weapon-attack-buffs.ts b/src/constants/common-attack-buffs.ts similarity index 71% rename from src/constants/common-weapon-attack-buffs.ts rename to src/constants/common-attack-buffs.ts index a42868b6..544d6a85 100644 --- a/src/constants/common-weapon-attack-buffs.ts +++ b/src/constants/common-attack-buffs.ts @@ -1,12 +1,7 @@ -import type { CommonWeaponAttackBuffDefinition } from '../models/v4/attack-buff/common-weapon-attack-buff-definition'; +import type { AttackBuffDefinition } from '../models/v4/attack-buff/attack-buff-definition'; -export type CommonWeaponAttackBuffId = 'volt-resonance' | 'frost-resonance'; - -export const commonWeaponAttackBuffs: Record< - CommonWeaponAttackBuffId, - CommonWeaponAttackBuffDefinition -> = { - 'volt-resonance': { +export const commonAttackBuffs: AttackBuffDefinition[] = [ + { id: 'volt-resonance', displayName: 'Volt Resonance', description: '+15% volt ATK when equipping 2 or more volt weapons', @@ -21,13 +16,14 @@ export const commonWeaponAttackBuffs: Record< }, cooldown: 0, requirements: { + anyWeaponInTeam: ['Brevey', 'Huang (Mimi)', 'Yanuo'], elementalTypeWeaponsInTeam: { elementalType: 'Volt', numOfWeapons: 2, }, }, }, - 'frost-resonance': { + { id: 'frost-resonance', displayName: 'Frost Resonance', description: '+15% frost ATK when equipping 2 or more frost weapons', @@ -42,10 +38,11 @@ export const commonWeaponAttackBuffs: Record< }, cooldown: 0, requirements: { + anyWeaponInTeam: ['Brevey', 'Yanuo'], elementalTypeWeaponsInTeam: { elementalType: 'Frost', numOfWeapons: 2, }, }, }, -}; +]; diff --git a/src/constants/common-damage-buffs.ts b/src/constants/common-damage-buffs.ts new file mode 100644 index 00000000..a86461db --- /dev/null +++ b/src/constants/common-damage-buffs.ts @@ -0,0 +1,61 @@ +import type { DamageBuffDefinition } from '../models/v4/damage-buff/damage-buff-definition'; + +export const commonDamageBuffs: DamageBuffDefinition[] = [ + { + id: 'attack-weapon-resonance', + displayName: 'Attack Resonance', + description: + 'Equip at least 2 DPS-type weapons to activate. Increase final damage by 10%, which in team play is further increased to 40%.', + value: 0.1, + damageCategory: 'Weapon resonance', + elementalTypes: ['Altered', 'Flame', 'Frost', 'Physical', 'Volt'], + maxStacks: 1, + triggeredBy: { + combatStart: true, + }, + duration: { + untilCombatEnd: true, + }, + cooldown: 0, + requirements: { weaponResonance: 'Attack' }, + }, + { + id: 'balance-weapon-resonance', + displayName: 'Balance Resonance', + description: + 'Equip at least 1 weapon of any type. Increase final damage and damage reduction by 5%, shatter and healing effect by 20%. In team play, increase final damage by an additional 35% and damage reduction by an additional 10%.', + value: 0.05, + damageCategory: 'Weapon resonance', + elementalTypes: ['Altered', 'Flame', 'Frost', 'Physical', 'Volt'], + maxStacks: 1, + triggeredBy: { + combatStart: true, + }, + duration: { + untilCombatEnd: true, + }, + cooldown: 0, + requirements: { weaponResonance: 'Balance' }, + }, + { + id: 'force-impact', + displayName: 'Force Impact', + description: + 'When the weapon is fully charged, the next attack applies Force Impact on the enemy for 45 seconds, increasing their frost and volt damage taken by 10%', + value: 0.1, + elementalTypes: ['Frost', 'Volt'], + damageCategory: '[TEMP_UNKNOWN]', + maxStacks: 1, + triggeredBy: { + fullChargeOfWeapons: ['Brevey'], + weaponAttacks: ['brevey-skill-million-metz-shockwave'], + }, + duration: { + value: 45000, + }, + cooldown: 15000, + requirements: { + anyWeaponInTeam: ['Brevey'], + }, + }, +]; diff --git a/src/constants/common-weapon-damage-buffs.ts b/src/constants/common-weapon-damage-buffs.ts deleted file mode 100644 index 20b84590..00000000 --- a/src/constants/common-weapon-damage-buffs.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { CommonWeaponDamageBuffDefinition } from '../models/v4/damage-buff/common-weapon-damage-buff-definition'; - -export type CommonWeaponDamageBuffId = 'force-impact'; - -export const commonWeaponDamageBuffs: Record< - CommonWeaponDamageBuffId, - CommonWeaponDamageBuffDefinition -> = { - 'force-impact': { - id: 'force-impact', - displayName: 'Force Impact', - description: - 'When the weapon is fully charged, the next attack applies Force Impact on the enemy for 45 seconds, increasing their frost and volt damage taken by 10%', - value: 0.1, - elementalTypes: ['Frost', 'Volt'], - damageCategory: '[TEMP_UNKNOWN]', - maxStacks: 1, - triggeredBy: { - fullChargeOfWeapons: ['Brevey'], - weaponAttacks: ['brevey-skill-million-metz-shockwave'], - }, - duration: { - value: 45000, - }, - cooldown: 15000, - }, -}; diff --git a/src/constants/simulacrum-traits.ts b/src/constants/simulacrum-traits.ts index a77f882f..973508d4 100644 --- a/src/constants/simulacrum-traits.ts +++ b/src/constants/simulacrum-traits.ts @@ -143,7 +143,7 @@ export const simulacrumTraits: Data = { }, cooldown: 0, requirements: { - weaponInTeam: 'Brevey', + anyWeaponInTeam: ['Brevey'], }, }, ], @@ -492,7 +492,7 @@ export const simulacrumTraits: Data = { }, cooldown: 0, requirements: { - weaponInTeam: 'Icarus', + anyWeaponInTeam: ['Icarus'], }, }, ], @@ -1281,7 +1281,7 @@ export const simulacrumTraits: Data = { }, cooldown: 0, requirements: { - weaponInTeam: 'Yanuo', + anyWeaponInTeam: ['Yanuo'], }, }, ], diff --git a/src/constants/weapon-definitions.ts b/src/constants/weapon-definitions.ts index f2b75858..d3601f5d 100644 --- a/src/constants/weapon-definitions.ts +++ b/src/constants/weapon-definitions.ts @@ -124,9 +124,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Alyss', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -192,9 +190,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Annabella', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -250,9 +246,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Asuka', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -375,8 +369,6 @@ export const weaponDefinitions: Data = { cooldown: 10000, }, ], - commonAttackBuffs: ['volt-resonance', 'frost-resonance'], - commonDamageBuffs: ['force-impact'], attackBuffs: [], damageBuffs: [ { @@ -461,9 +453,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Claudia', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -506,9 +496,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Cobalt-B', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -564,9 +552,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Cocoritter', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -596,9 +582,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Crow', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -653,9 +637,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Fei Se', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -722,9 +704,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Fenrir', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -779,9 +759,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Fiona', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -846,9 +824,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Frigg', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -892,9 +868,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Gnonno', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -950,9 +924,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Huang (Mimi)', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: ['volt-resonance'], attackBuffs: [], damageBuffs: [], }, @@ -982,9 +954,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Huma', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1027,9 +997,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Icarus', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1059,9 +1027,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'King', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1104,9 +1070,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Lan', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1184,9 +1148,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Lin', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1240,9 +1202,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Ling Han', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1285,9 +1245,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Liu Huo', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1344,9 +1302,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Lyra', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1376,9 +1332,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Meryl', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1446,9 +1400,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Ming Jing', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1513,8 +1465,6 @@ export const weaponDefinitions: Data = { }, }, effects: [], - commonAttackBuffs: [], - commonDamageBuffs: [], attackBuffs: [ { id: 'nanyin-atk-buff-the-final-tune', @@ -1614,9 +1564,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Nemesis', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1672,9 +1620,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Plotti', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1717,9 +1663,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Rubilia', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1785,9 +1729,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Ruby', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1830,9 +1772,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Saki Fuwa', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1862,9 +1802,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Samir', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1894,9 +1832,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Shiro', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1952,9 +1888,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Tian Lang', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -1984,9 +1918,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Tsubasa', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -2042,9 +1974,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Umi', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -2112,9 +2042,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Yan Miao', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -2195,8 +2123,6 @@ export const weaponDefinitions: Data = { }, }, effects: [], - commonAttackBuffs: ['frost-resonance', 'volt-resonance'], - commonDamageBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -2239,9 +2165,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Yu Lan', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, @@ -2297,9 +2221,7 @@ export const weaponDefinitions: Data = { notActiveWeapon: 'Zero', }, }, - commonDamageBuffs: [], effects: [], - commonAttackBuffs: [], attackBuffs: [], damageBuffs: [], }, diff --git a/src/constants/weapon-resonance.ts b/src/constants/weapon-resonance.ts index 1552aef6..cb4476ba 100644 --- a/src/constants/weapon-resonance.ts +++ b/src/constants/weapon-resonance.ts @@ -1,19 +1,6 @@ -import type { DataById } from '../models/data'; - export type WeaponResonance = | 'None' | 'Attack' | 'Balance' | 'Benediction' | 'Fortitude'; - -export const weaponResonanceDamageBuffsLookup: DataById< - WeaponResonance, - number -> = { - None: 0, - Attack: 0.1, - Balance: 0.05, - Benediction: 0, - Fortitude: 0, -}; diff --git a/src/features/combat-simulator/CombatSimulatorTimeline.tsx b/src/features/combat-simulator/CombatSimulatorTimeline.tsx index 856e0a40..d5a41e87 100644 --- a/src/features/combat-simulator/CombatSimulatorTimeline.tsx +++ b/src/features/combat-simulator/CombatSimulatorTimeline.tsx @@ -120,7 +120,7 @@ export function CombatSimulatorTimeline() { }); } - for (const effectController of combatSimulatorSnap.effectControllerContext + for (const effectController of combatSimulatorSnap.effectRegistry .allEffectControllers) { const { id, displayName, timeline } = effectController; editorData.push({ diff --git a/src/models/v4/__tests__/__snapshots__/combat-simulator.test.ts.snap b/src/models/v4/__tests__/__snapshots__/combat-simulator.test.ts.snap index 37389f62..cfd4f19e 100644 --- a/src/models/v4/__tests__/__snapshots__/combat-simulator.test.ts.snap +++ b/src/models/v4/__tests__/__snapshots__/combat-simulator.test.ts.snap @@ -51,13 +51,6 @@ exports[`CombatSimulator next available attacks includes attacks from all weapon "value": 0.15, }, ], - "commonAttackBuffs": [ - "volt-resonance", - "frost-resonance", - ], - "commonDamageBuffs": [ - "force-impact", - ], "critRateBuffs": [], "damageBuffs": [ { @@ -254,13 +247,6 @@ exports[`CombatSimulator next available attacks includes attacks from all weapon "value": 0.15, }, ], - "commonAttackBuffs": [ - "volt-resonance", - "frost-resonance", - ], - "commonDamageBuffs": [ - "force-impact", - ], "critRateBuffs": [], "damageBuffs": [ { @@ -457,13 +443,6 @@ exports[`CombatSimulator next available attacks includes attacks from all weapon "value": 0.15, }, ], - "commonAttackBuffs": [ - "volt-resonance", - "frost-resonance", - ], - "commonDamageBuffs": [ - "force-impact", - ], "critRateBuffs": [], "damageBuffs": [ { @@ -660,11 +639,6 @@ exports[`CombatSimulator next available attacks includes attacks from all weapon "value": 0.15, }, ], - "commonAttackBuffs": [ - "frost-resonance", - "volt-resonance", - ], - "commonDamageBuffs": [], "critRateBuffs": [], "damageBuffs": [], "damageElement": "Frost", @@ -772,11 +746,6 @@ exports[`CombatSimulator next available attacks includes attacks from all weapon "value": 0.15, }, ], - "commonAttackBuffs": [ - "frost-resonance", - "volt-resonance", - ], - "commonDamageBuffs": [], "critRateBuffs": [], "damageBuffs": [], "damageElement": "Frost", @@ -904,8 +873,6 @@ exports[`CombatSimulator next available attacks includes attacks from all weapon "value": 0.3, }, ], - "commonAttackBuffs": [], - "commonDamageBuffs": [], "critRateBuffs": [], "damageBuffs": [], "damageElement": "Altered", diff --git a/src/models/v4/__tests__/combat-simulator.test.ts b/src/models/v4/__tests__/combat-simulator.test.ts index c1929803..3e8226d9 100644 --- a/src/models/v4/__tests__/combat-simulator.test.ts +++ b/src/models/v4/__tests__/combat-simulator.test.ts @@ -118,8 +118,8 @@ describe('CombatSimulator', () => { expect(hasEffectEvent(sut, 'volt-resonance')).toBe(true); const frostResonanceBuff = - sut.effectControllerContext.getEffectController('frost-resonance') - ?.timeline.effects[0]; + sut.effectRegistry.getEffectController('frost-resonance')?.timeline + .effects[0]; expect(frostResonanceBuff).toBeDefined(); if (frostResonanceBuff) { expect(frostResonanceBuff.startTime).toBe(0); @@ -138,8 +138,8 @@ describe('CombatSimulator', () => { }); const voltResonanceBuffEvent = - sut.effectControllerContext.getEffectController('volt-resonance') - ?.timeline.effects[0]; + sut.effectRegistry.getEffectController('volt-resonance')?.timeline + .effects[0]; expect(voltResonanceBuffEvent).toBeDefined(); if (voltResonanceBuffEvent) { expect(voltResonanceBuffEvent.stacks).toBe(1); @@ -156,7 +156,7 @@ describe('CombatSimulator', () => { }); expect( - sut.effectControllerContext.allEffectControllers.filter( + sut.effectRegistry.allEffectControllers.filter( (effectController) => effectController.id === 'volt-resonance' ).length ).toBe(1); @@ -174,7 +174,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon3.definition.normalAttacks[0], }); - const effect = sut.effectControllerContext.getEffectController( + const effect = sut.effectRegistry.getEffectController( weaponDefinitions.byId['Nan Yin'].attackBuffs[0].id ); expect(effect).toBeDefined(); @@ -235,7 +235,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon2.definition.normalAttacks[0], }); - const voltBuffEvent = sut.effectControllerContext.getEffectController( + const voltBuffEvent = sut.effectRegistry.getEffectController( 'brevey-damage-buff-pact-amplification-volt' )?.timeline.lastEffect; expect(voltBuffEvent).toBeDefined(); @@ -250,7 +250,7 @@ describe('CombatSimulator', () => { ); } - const frostBuffEvent = sut.effectControllerContext.getEffectController( + const frostBuffEvent = sut.effectRegistry.getEffectController( 'brevey-damage-buff-pact-amplification-frost' )?.timeline.lastEffect; expect(frostBuffEvent).toBeDefined(); @@ -282,7 +282,7 @@ describe('CombatSimulator', () => { expect( Array.from( - sut.effectControllerContext.damageBuffControllers.controllers.values() + sut.effectRegistry.damageBuffControllers.controllers.values() ) .filter( (damageBuffController) => @@ -308,8 +308,8 @@ describe('CombatSimulator', () => { }); const damageBuffEvent = - sut.effectControllerContext.getEffectController('brevey-trait') - ?.timeline.effects[0]; + sut.effectRegistry.getEffectController('brevey-trait')?.timeline + .effects[0]; if (damageBuffEvent) { expect(damageBuffEvent.startTime).toBe(0); expect(damageBuffEvent.duration).toBe(combatDuration); @@ -327,7 +327,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon1.definition.normalAttacks[0], }); - const damageBuffEvent = sut.effectControllerContext.getEffectController( + const damageBuffEvent = sut.effectRegistry.getEffectController( 'brevey-trait-additional' )?.timeline.effects[0]; expect(damageBuffEvent).toBeDefined(); @@ -449,7 +449,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon1.definition.normalAttacks[0], }); - const buffEvent = sut.effectControllerContext.getEffectController( + const buffEvent = sut.effectRegistry.getEffectController( 'yanmiao-trait-weapon-buff' )?.timeline.effects[0]; expect(buffEvent).toBeDefined(); @@ -473,7 +473,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon1.definition.skills[0], }); - const damageBuffEvent = sut.effectControllerContext.getEffectController( + const damageBuffEvent = sut.effectRegistry.getEffectController( alyssTrait.damageBuffs[0].id )?.timeline.effects[0]; if (damageBuffEvent) { @@ -497,7 +497,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon1.definition.normalAttacks[0], }); - const damageBuffEvent = sut.effectControllerContext.getEffectController( + const damageBuffEvent = sut.effectRegistry.getEffectController( crowTrait.damageBuffs[1].id )?.timeline.effects[0]; expect(damageBuffEvent).toBeDefined(); @@ -522,8 +522,8 @@ describe('CombatSimulator', () => { expect( feiseTrait.damageBuffs.some( (buff) => - !!sut.effectControllerContext.getEffectController(buff.id) - ?.timeline.lastEffect + !!sut.effectRegistry.getEffectController(buff.id)?.timeline + .lastEffect ) ).toBe(false); @@ -538,8 +538,8 @@ describe('CombatSimulator', () => { expect( feiseTrait.damageBuffs.some( (buff) => - !!sut2.effectControllerContext.getEffectController(buff.id) - ?.timeline.lastEffect + !!sut2.effectRegistry.getEffectController(buff.id)?.timeline + .lastEffect ) ).toBe(true); }); @@ -624,7 +624,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon3.definition.normalAttacks[0], }); - const buffController = sut.effectControllerContext.getEffectController( + const buffController = sut.effectRegistry.getEffectController( 'nanyin-trait-active-weapon-2-non-altered' ); expect(buffController).toBeDefined(); @@ -729,7 +729,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon1.definition.skills[0], }); - const attackBuffEvent = sut.effectControllerContext.getEffectController( + const attackBuffEvent = sut.effectRegistry.getEffectController( cocoTrait.attackBuffs[0].id )?.timeline.effects[0]; expect(attackBuffEvent).toBeDefined(); @@ -768,7 +768,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon1.definition.discharge, }); - const attackBuffEvent = sut.effectControllerContext.getEffectController( + const attackBuffEvent = sut.effectRegistry.getEffectController( cocoTrait.attackBuffs[0].id )?.timeline.effects[0]; expect(attackBuffEvent).toBeDefined(); @@ -882,7 +882,7 @@ describe('CombatSimulator', () => { attackDefinition: mingJingWeapon.definition.normalAttacks[0], }); - const buffController = sut.effectControllerContext.getEffectController( + const buffController = sut.effectRegistry.getEffectController( 'mingjing-trait-normal-attack' ); expect(buffController).toBeDefined(); @@ -993,7 +993,7 @@ describe('CombatSimulator', () => { attackDefinition: weapon1.definition.skills[0], }); - const effectEvent = sut.effectControllerContext.getEffectController( + const effectEvent = sut.effectRegistry.getEffectController( 'brevey-effect-pact-amplification' )?.timeline.lastEffect; expect(effectEvent).toBeDefined(); @@ -1009,6 +1009,6 @@ describe('CombatSimulator', () => { }); function hasEffectEvent(combatSimulator: CombatSimulator, effectId: string) { - return !!combatSimulator.effectControllerContext.getEffectController(effectId) + return !!combatSimulator.effectRegistry.getEffectController(effectId) ?.timeline.lastEffect; } diff --git a/src/models/v4/attack-buff/common-weapon-attack-buff-definition.ts b/src/models/v4/attack-buff/common-weapon-attack-buff-definition.ts deleted file mode 100644 index c38392a1..00000000 --- a/src/models/v4/attack-buff/common-weapon-attack-buff-definition.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { CommonWeaponAttackBuffId } from '../../../constants/common-weapon-attack-buffs'; -import type { AttackBuffDefinition } from './attack-buff-definition'; - -export interface CommonWeaponAttackBuffDefinition extends AttackBuffDefinition { - id: CommonWeaponAttackBuffId; -} diff --git a/src/models/v4/attack/team-attack-controller.ts b/src/models/v4/attack/team-attack-controller.ts index 638ec22e..b464725f 100644 --- a/src/models/v4/attack/team-attack-controller.ts +++ b/src/models/v4/attack/team-attack-controller.ts @@ -15,7 +15,7 @@ export class TeamAttackController { private previousWeapon: Weapon | undefined; public constructor( - public readonly team: Team, + team: Team, combatDuration: number, private readonly chargeTimeline: ChargeTimeline ) { diff --git a/src/models/v4/combat-simulator.ts b/src/models/v4/combat-simulator.ts index 730f40e8..219048bb 100644 --- a/src/models/v4/combat-simulator.ts +++ b/src/models/v4/combat-simulator.ts @@ -1,28 +1,26 @@ -import { commonWeaponAttackBuffs } from '../../constants/common-weapon-attack-buffs'; -import { commonWeaponDamageBuffs } from '../../constants/common-weapon-damage-buffs'; +import { commonAttackBuffs } from '../../constants/common-attack-buffs'; +import { commonDamageBuffs } from '../../constants/common-damage-buffs'; import type { Loadout } from '../loadout'; import type { AttackCommand } from './attack/attack-command'; import type { AttackResult } from './attack/attack-result'; import { TeamAttackController } from './attack/team-attack-controller'; -import type { AttackBuffDefinition } from './attack-buff/attack-buff-definition'; import { ChargeTimeline } from './charge/charge-timeline'; -import type { DamageBuffDefinition } from './damage-buff/damage-buff-definition'; import { EffectController } from './effect/effect-controller'; -import { EffectControllerContext } from './effect/effect-controller-context'; import { EffectControllerSet } from './effect/effect-controller-set'; import { EffectEvaluator } from './effect/effect-evaluator'; +import { EffectRegistry } from './effect/effect-registry'; import { EffectTimeline } from './effect/effect-timeline'; import type { Relics } from './relics'; export class CombatSimulator { public readonly teamAttackController: TeamAttackController; public readonly chargeTimeline: ChargeTimeline; - public readonly effectControllerContext: EffectControllerContext; + public readonly effectRegistry: EffectRegistry; public constructor( public readonly combatDuration: number, private readonly loadout: Loadout, - private readonly relics: Relics + relics: Relics ) { const { team: { weapons }, @@ -39,12 +37,8 @@ export class CombatSimulator { const attackBuffControllers = new Map( weapons - .flatMap((weapon) => - weapon.definition.commonAttackBuffs.map( - (buffId) => commonWeaponAttackBuffs[buffId] - ) - ) - .concat(weapons.flatMap((weapon) => weapon.definition.attackBuffs)) + .flatMap((weapon) => weapon.definition.attackBuffs) + .concat(commonAttackBuffs) .concat(simulacrumTrait?.attackBuffs ?? []) .map((attackBuffDefinition) => { const timeline = new EffectTimeline(combatDuration); @@ -57,12 +51,8 @@ export class CombatSimulator { const damageBuffControllers = new Map( weapons - .flatMap((weapon) => - weapon.definition.commonDamageBuffs.map( - (buffId) => commonWeaponDamageBuffs[buffId] - ) - ) - .concat(weapons.flatMap((weapon) => weapon.definition.damageBuffs)) + .flatMap((weapon) => weapon.definition.damageBuffs) + .concat(commonDamageBuffs) .concat(simulacrumTrait?.damageBuffs ?? []) .concat(relics.passiveRelicBuffs) .map((damageBuffDefinition) => { @@ -96,7 +86,7 @@ export class CombatSimulator { }) ); - this.effectControllerContext = new EffectControllerContext( + this.effectRegistry = new EffectRegistry( new EffectControllerSet('Attack buffs', attackBuffControllers), new EffectControllerSet('Damage buffs', damageBuffControllers), new EffectControllerSet('Miscellaneous buffs', miscBuffControllers), @@ -127,13 +117,12 @@ export class CombatSimulator { } private triggerEffects(attackResult: AttackResult) { - for (const effectController of this.effectControllerContext - .allEffectControllers) { + for (const effectController of this.effectRegistry.allEffectControllers) { const effectEvaluator = new EffectEvaluator( attackResult, effectController.definition, effectController.timeline, - this.effectControllerContext, + this.effectRegistry, this.loadout.team ); effectController.triggerEffect(effectEvaluator); diff --git a/src/models/v4/damage-buff/common-weapon-damage-buff-definition.ts b/src/models/v4/damage-buff/common-weapon-damage-buff-definition.ts deleted file mode 100644 index cc537416..00000000 --- a/src/models/v4/damage-buff/common-weapon-damage-buff-definition.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { CommonWeaponDamageBuffId } from '../../../constants/common-weapon-damage-buffs'; -import type { DamageBuffDefinition } from './damage-buff-definition'; - -export interface CommonWeaponDamageBuffDefinition extends DamageBuffDefinition { - id: CommonWeaponDamageBuffId; -} diff --git a/src/models/v4/damage-buff/damage-buff-definition.ts b/src/models/v4/damage-buff/damage-buff-definition.ts index 416551fc..45b5b305 100644 --- a/src/models/v4/damage-buff/damage-buff-definition.ts +++ b/src/models/v4/damage-buff/damage-buff-definition.ts @@ -7,6 +7,7 @@ export interface DamageBuffDefinition extends EffectDefinition { elementalTypes: WeaponElementalType[]; /** Damage buffs in the same category are additive. If they are not, they are multiplicative */ damageCategory: + | 'Weapon resonance' | 'Relic passive' | 'Enemy debuff' | 'DMG buff category 1' diff --git a/src/models/v4/effect/effect-definition.ts b/src/models/v4/effect/effect-definition.ts index 22050e0c..7069d1c3 100644 --- a/src/models/v4/effect/effect-definition.ts +++ b/src/models/v4/effect/effect-definition.ts @@ -18,8 +18,10 @@ export interface EffectDefinition { }; }; - // Order triggers from least specific to most specific. Check in this order for efficiency + /** Triggers are treated as an "OR" check i.e. the effect is triggered when any defined trigger passes check */ triggeredBy: { + // Order triggers from least specific to most specific. Check in this order for efficiency + combatStart?: boolean; skillOfAnyWeapon?: boolean; dischargeOfAnyWeapon?: boolean; @@ -46,10 +48,12 @@ export interface EffectDefinition { /** Effect goes into cooldown when triggered and cannot be triggered again until cooldown ends */ cooldown: number; - // Order requirements from most specific to least specific. Check in this order for efficiency + /** Requirements are treated as a "AND" check i.e. the effect is triggered when all defined requirements pass check */ requirements?: { + // Order requirements from most specific to least specific. Check in this order for efficiency + activeEffect?: string; - weaponInTeam?: WeaponName; + anyWeaponInTeam?: WeaponName[]; weaponResonance?: WeaponResonance; elementalTypeWeaponsInTeam?: { elementalType: WeaponElementalType; diff --git a/src/models/v4/effect/effect-evaluator.ts b/src/models/v4/effect/effect-evaluator.ts index 7c8354b7..28ef20f8 100644 --- a/src/models/v4/effect/effect-evaluator.ts +++ b/src/models/v4/effect/effect-evaluator.ts @@ -3,8 +3,8 @@ import groupBy from 'lodash.groupby'; import type { Team } from '../../team'; import type { AttackResult } from '../attack/attack-result'; -import type { EffectControllerContext } from './effect-controller-context'; import type { EffectDefinition } from './effect-definition'; +import type { EffectRegistry } from './effect-registry'; import type { EffectTimeline } from './effect-timeline'; export class EffectEvaluator { @@ -12,7 +12,7 @@ export class EffectEvaluator { private readonly attackResult: AttackResult, private readonly effectDefinition: EffectDefinition, private readonly effectTimeline: EffectTimeline, - private readonly effectControllerContext: EffectControllerContext, + private readonly effectRegistry: EffectRegistry, private readonly team: Team ) {} @@ -100,7 +100,7 @@ export class EffectEvaluator { // Check requirements from most specific to least specific for efficiency if (requirements.activeEffect) { - const effectController = this.effectControllerContext.getEffectController( + const effectController = this.effectRegistry.getEffectController( requirements.activeEffect ); return ( @@ -109,8 +109,10 @@ export class EffectEvaluator { } if ( - requirements.weaponInTeam && - !weaponNames.includes(requirements.weaponInTeam) + requirements.anyWeaponInTeam && + requirements.anyWeaponInTeam.every( + (weaponName) => !weaponNames.includes(weaponName) + ) ) return false; diff --git a/src/models/v4/effect/effect-controller-context.ts b/src/models/v4/effect/effect-registry.ts similarity index 97% rename from src/models/v4/effect/effect-controller-context.ts rename to src/models/v4/effect/effect-registry.ts index e29ad181..9e44d1ef 100644 --- a/src/models/v4/effect/effect-controller-context.ts +++ b/src/models/v4/effect/effect-registry.ts @@ -4,7 +4,7 @@ import type { MiscellaneousBuffDefinition } from '../miscellaneous-buff/miscella import type { EffectControllerSet } from './effect-controller-set'; import type { EffectDefinition } from './effect-definition'; -export class EffectControllerContext { +export class EffectRegistry { public constructor( public readonly attackBuffControllers: EffectControllerSet, public readonly damageBuffControllers: EffectControllerSet, diff --git a/src/models/v4/timeline/timeline.ts b/src/models/v4/timeline/timeline.ts index 4ffc3698..db254424 100644 --- a/src/models/v4/timeline/timeline.ts +++ b/src/models/v4/timeline/timeline.ts @@ -41,11 +41,15 @@ export class Timeline { ); } - /** Returns events that have any sort of overlap with the period of start time to end time */ + /** Returns events that have any sort of overlap with the period of start time to end time. */ public getEventsOverlappingPeriod( startTime: number, endTime: number ): TEvent[] { + if (startTime === endTime) { + return this.getEventsOverlappingTime(startTime); + } + return this._events.filter( (event) => event.startTime < endTime && event.endTime >= startTime ); diff --git a/src/models/weapon-definition.ts b/src/models/weapon-definition.ts index 9142a761..f0b623db 100644 --- a/src/models/weapon-definition.ts +++ b/src/models/weapon-definition.ts @@ -1,5 +1,3 @@ -import type { CommonWeaponAttackBuffId } from '../constants/common-weapon-attack-buffs'; -import type { CommonWeaponDamageBuffId } from '../constants/common-weapon-damage-buffs'; import type { WeaponElementalType } from '../constants/elemental-type'; import type { WeaponName, WeaponType } from '../constants/weapon-definitions'; import { weaponDefinitions } from '../constants/weapon-definitions'; @@ -39,9 +37,6 @@ export interface WeaponDefinition { effects: EffectDefinition[]; - commonAttackBuffs: CommonWeaponAttackBuffId[]; - commonDamageBuffs: CommonWeaponDamageBuffId[]; - attackBuffs: AttackBuffDefinition[]; damageBuffs: DamageBuffDefinition[]; }