From 414d5533453ff0296127cc1ca0a31ba4749e8f4d Mon Sep 17 00:00:00 2001 From: kdovtdc Date: Mon, 29 Jul 2024 18:47:33 +0200 Subject: [PATCH 1/9] Implement 10 Relics *initial relic setup *implement effects complete: *Cavern: Band, Eagle, Firesmith, Guard, Messenger, Thief, Wastelander *Planar: Celestial incomplete: *Cavern: Disciple *Planar: Keel To-Do: *Disciple: in onHPChange, it is assumed e.Target means source and compares to mod owner (= wearer; similar to #195) need to check whether this is correct *Keel: how to handle `applied` and pointer logic (idea from conversation on #124; once finished, can be used for Fleet impl since they are functionally almost identical) --- internal/relic/cavern/band/band.go | 66 ++++++++++++++ internal/relic/cavern/disciple/disciple.go | 80 ++++++++++++++++ internal/relic/cavern/eagle/eagle.go | 53 +++++++++++ internal/relic/cavern/firesmith/firesmith.go | 78 ++++++++++++++++ internal/relic/cavern/guard/guard.go | 66 ++++++++++++++ internal/relic/cavern/messenger/messenger.go | 69 ++++++++++++++ internal/relic/cavern/thief/thief.go | 51 +++++++++++ .../relic/cavern/wastelander/wastelander.go | 57 ++++++++++++ internal/relic/planar/celestial/celestial.go | 49 ++++++++++ internal/relic/planar/keel/keel.go | 91 +++++++++++++++++++ pkg/key/relic.go | 36 +++++--- pkg/simulation/imports.go | 10 ++ 12 files changed, 693 insertions(+), 13 deletions(-) create mode 100644 internal/relic/cavern/band/band.go create mode 100644 internal/relic/cavern/disciple/disciple.go create mode 100644 internal/relic/cavern/eagle/eagle.go create mode 100644 internal/relic/cavern/firesmith/firesmith.go create mode 100644 internal/relic/cavern/guard/guard.go create mode 100644 internal/relic/cavern/messenger/messenger.go create mode 100644 internal/relic/cavern/thief/thief.go create mode 100644 internal/relic/cavern/wastelander/wastelander.go create mode 100644 internal/relic/planar/celestial/celestial.go create mode 100644 internal/relic/planar/keel/keel.go diff --git a/internal/relic/cavern/band/band.go b/internal/relic/cavern/band/band.go new file mode 100644 index 00000000..0b448d10 --- /dev/null +++ b/internal/relic/cavern/band/band.go @@ -0,0 +1,66 @@ +package band + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/event" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" + "github.com/simimpact/srsim/pkg/model" +) + +const ( + check = "band-of-sizzling-thunder" + buff = "band-of-sizzling-thunder-buff" +) + +// 2pc: Increases Lightning DMG by 10%. +// 4pc: When the wearer uses their Skill, increases the wearer's ATK by 20% for 1 turn(s). + +func init() { + relic.Register(key.BandOfSizzlingThunder, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.ThunderDamagePercent: 0.1}, + }, + { + MinCount: 4, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: check, + Source: owner, + }) + }, + }, + }, + }) + modifier.Register(check, modifier.Config{ + Listeners: modifier.Listeners{ + OnBeforeAction: onBeforeSkill, + }, + }) + modifier.Register(buff, modifier.Config{ + Stacking: modifier.ReplaceBySource, + StatusType: model.StatusType_STATUS_BUFF, + Duration: 1, + Listeners: modifier.Listeners{ + OnAdd: onAdd, + }, + }) +} + +func onBeforeSkill(mod *modifier.Instance, e event.ActionStart) { + if e.AttackType == model.AttackType_SKILL { + mod.Engine().AddModifier(mod.Owner(), info.Modifier{ + Name: buff, + Source: mod.Owner(), + }) + } +} + +func onAdd(mod *modifier.Instance) { + mod.AddProperty(prop.ATKPercent, 0.2) +} diff --git a/internal/relic/cavern/disciple/disciple.go b/internal/relic/cavern/disciple/disciple.go new file mode 100644 index 00000000..b5ba3bdf --- /dev/null +++ b/internal/relic/cavern/disciple/disciple.go @@ -0,0 +1,80 @@ +package disciple + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/event" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" + "github.com/simimpact/srsim/pkg/model" +) + +const ( + check = "longevous-disciple" + crbuff = "longevous-disciple-cr-buff" +) + +// 2pc: Increases Max HP by 12%. +// 4pc: When the wearer is hit or has their HP consumed by an ally or themselves, +// their CRIT Rate increases by 8% for 2 turn(s) and up to 2 stacks. + +// TO-DO: in onHPChange, assumes e.Target means source; check whether this is correct + +func init() { + relic.Register(key.BandOfSizzlingThunder, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.HPPercent: 0.12}, + }, + { + MinCount: 4, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: check, + Source: owner, + }) + }, + }, + }, + }) + modifier.Register(check, modifier.Config{ + Listeners: modifier.Listeners{ + OnHPChange: onHPChange, + OnAfterBeingAttacked: onAfterBeingAttacked, + }, + }) + modifier.Register(crbuff, modifier.Config{ + Stacking: modifier.ReplaceBySource, + StatusType: model.StatusType_STATUS_BUFF, + MaxCount: 2, + CountAddWhenStack: 1, + Duration: 2, + Listeners: modifier.Listeners{ + OnAdd: onAdd, + }, + }) +} + +func onHPChange(mod *modifier.Instance, e event.HPChange) { + // source is friendly, not HP change by damage, hp change is negative + if mod.Engine().IsCharacter(e.Target) && !e.IsHPChangeByDamage && e.NewHP < e.OldHP { + mod.Engine().AddModifier(mod.Owner(), info.Modifier{ + Name: crbuff, + Source: mod.Owner(), + }) + } +} + +func onAfterBeingAttacked(mod *modifier.Instance, e event.AttackEnd) { + mod.Engine().AddModifier(mod.Owner(), info.Modifier{ + Name: crbuff, + Source: mod.Owner(), + }) +} + +func onAdd(mod *modifier.Instance) { + mod.AddProperty(prop.ATKPercent, 0.08*mod.Count()) +} diff --git a/internal/relic/cavern/eagle/eagle.go b/internal/relic/cavern/eagle/eagle.go new file mode 100644 index 00000000..9703eb56 --- /dev/null +++ b/internal/relic/cavern/eagle/eagle.go @@ -0,0 +1,53 @@ +package eagle + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/event" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" + "github.com/simimpact/srsim/pkg/model" +) + +const eagle = "eagle-of-twilight-thunder" + +// 2pc: Increases Wind DMG by 10%. +// 4pc: After the wearer uses their Ultimate, their action is Advanced Forward by 25%. + +func init() { + relic.Register(key.EagleOfTwilightLine, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.WindDamagePercent: 0.1}, + }, + { + MinCount: 4, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: eagle, + Source: owner, + }) + }, + }, + }, + }) + modifier.Register(eagle, modifier.Config{ + Listeners: modifier.Listeners{ + OnAfterAction: onAfterUltimate, + }, + }) +} + +func onAfterUltimate(mod *modifier.Instance, e event.ActionEnd) { + if e.AttackType == model.AttackType_ULT { + mod.Engine().ModifyGaugeNormalized(info.ModifyAttribute{ + Key: eagle, + Target: mod.Owner(), + Source: mod.Owner(), + Amount: -0.25, + }) + } +} diff --git a/internal/relic/cavern/firesmith/firesmith.go b/internal/relic/cavern/firesmith/firesmith.go new file mode 100644 index 00000000..8ca7865d --- /dev/null +++ b/internal/relic/cavern/firesmith/firesmith.go @@ -0,0 +1,78 @@ +package firesmith + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/event" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" + "github.com/simimpact/srsim/pkg/model" +) + +const ( + check = "firesmith-of-lava-forging" + buff = "firesmith-of-lava-forging-buff" +) + +// 2pc: Increases Fire DMG by 10%. +// 4pc: Increases the wearer's Skill DMG by 12%. +// After unleashing Ultimate, increases the wearer's Fire DMG by 12% for the next attack. + +func init() { + relic.Register(key.FiresmithOfLavaForging, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.FireDamagePercent: 0.1}, + }, + { + MinCount: 4, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: check, + Source: owner, + }) + }, + }, + }, + }) + modifier.Register(check, modifier.Config{ + Listeners: modifier.Listeners{ + OnBeforeHitAll: onBeforeHitAll, + OnAfterAction: onAfterUltimate, + }, + }) + modifier.Register(buff, modifier.Config{ + Stacking: modifier.ReplaceBySource, + StatusType: model.StatusType_STATUS_BUFF, + Listeners: modifier.Listeners{ + OnAdd: onAdd, + OnAfterAttack: onAfterAttack, + }, + }) +} + +func onBeforeHitAll(mod *modifier.Instance, e event.HitStart) { + if e.Hit.AttackType == model.AttackType_SKILL { + e.Hit.Attacker.AddProperty(check, prop.AllDamagePercent, 0.12) + } +} + +func onAfterUltimate(mod *modifier.Instance, e event.ActionEnd) { + if e.AttackType == model.AttackType_ULT { + mod.Engine().AddModifier(mod.Owner(), info.Modifier{ + Name: buff, + Source: mod.Owner(), + }) + } +} + +func onAdd(mod *modifier.Instance) { + mod.AddProperty(prop.FireDamagePercent, 0.12) +} + +func onAfterAttack(mod *modifier.Instance, e event.AttackEnd) { + mod.RemoveSelf() +} diff --git a/internal/relic/cavern/guard/guard.go b/internal/relic/cavern/guard/guard.go new file mode 100644 index 00000000..8e1f7f3c --- /dev/null +++ b/internal/relic/cavern/guard/guard.go @@ -0,0 +1,66 @@ +package guard + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" + "github.com/simimpact/srsim/pkg/model" +) + +const ( + guard = "guard-of-wuthering-snow" + heal = "guard-of-wuthering-snow-heal" + energy = "guard-of-wuthering-snow-energy" +) + +// 2pc: Reduces DMG taken by 8%. +// 4pc: At the beginning of the turn, if the wearer's HP is equal to or less than 50%, +// restores HP equal to 8% of their Max HP and regenerates 5 Energy. + +func init() { + relic.Register(key.GuardOfWutheringSnow, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.AllDamageReduce: 0.08}, + }, + { + MinCount: 4, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: guard, + Source: owner, + }) + }, + }, + }, + }) + modifier.Register(guard, modifier.Config{ + Listeners: modifier.Listeners{ + OnPhase1: onPhase1, + }, + CanModifySnapshot: true, + }) +} + +func onPhase1(mod *modifier.Instance) { + // if above 50% HP, bypass + if mod.Engine().HPRatio(mod.Owner()) > 0.5 { + return + } + mod.Engine().Heal(info.Heal{ + Key: heal, + Targets: []key.TargetID{mod.Owner()}, + Source: mod.Owner(), + BaseHeal: info.HealMap{model.HealFormula_BY_TARGET_MAX_HP: 0.08}, + }) + mod.Engine().ModifyEnergy(info.ModifyAttribute{ + Key: energy, + Target: mod.Owner(), + Source: mod.Owner(), + Amount: 5.0, + }) +} diff --git a/internal/relic/cavern/messenger/messenger.go b/internal/relic/cavern/messenger/messenger.go new file mode 100644 index 00000000..aaae1bf1 --- /dev/null +++ b/internal/relic/cavern/messenger/messenger.go @@ -0,0 +1,69 @@ +package messenger + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/event" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" + "github.com/simimpact/srsim/pkg/model" +) + +const ( + check = "messenger-traversing-hackerspace" + buff = "messenger-traversing-hackerspace-buff" +) + +// 2pc: Increases SPD by 6%. +// 4pc: When the wearer uses their Ultimate on an ally, +// SPD for all allies increases by 12% for 1 turn(s). This effect cannot be stacked. + +func init() { + relic.Register(key.MessengerTraversingHackerspace, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.SPDPercent: 0.06}, + }, + { + MinCount: 4, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: check, + Source: owner, + }) + }, + }, + }, + }) + modifier.Register(check, modifier.Config{ + Listeners: modifier.Listeners{ + OnBeforeAction: onBeforeUlt, + }, + }) + modifier.Register(buff, modifier.Config{ + Stacking: modifier.Replace, + StatusType: model.StatusType_STATUS_BUFF, + Listeners: modifier.Listeners{ + OnAdd: onAdd, + }, + }) +} + +func onBeforeUlt(mod *modifier.Instance, e event.ActionStart) { + if e.AttackType == model.AttackType_ULT { + for _, char := range mod.Engine().Characters() { + mod.Engine().AddModifier(char, info.Modifier{ + Name: buff, + Source: mod.Owner(), + Duration: 1, + }) + } + } +} + +func onAdd(mod *modifier.Instance) { + mod.AddProperty(prop.SPDPercent, 0.12) +} diff --git a/internal/relic/cavern/thief/thief.go b/internal/relic/cavern/thief/thief.go new file mode 100644 index 00000000..797a35f3 --- /dev/null +++ b/internal/relic/cavern/thief/thief.go @@ -0,0 +1,51 @@ +package thief + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" +) + +const thief = "thief-of-shooting-meteor" + +// 2pc: Increases Break Effect by 16%. +// 4pc: Increases the wearer's Break Effect by 16%. +// After the wearer inflicts Weakness Break on an enemy, regenerates 3 Energy. + +func init() { + relic.Register(key.ThiefOfShootingMeteor, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.BreakEffect: 0.16}, + }, + { + MinCount: 4, + Stats: info.PropMap{prop.BreakEffect: 0.16}, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: thief, + Source: owner, + }) + }, + }, + }, + }) + modifier.Register(thief, modifier.Config{ + Listeners: modifier.Listeners{ + OnTriggerBreak: onTriggerBreak, + }, + }) +} + +func onTriggerBreak(mod *modifier.Instance, target key.TargetID) { + mod.Engine().ModifyEnergy(info.ModifyAttribute{ + Key: thief, + Target: mod.Owner(), + Source: mod.Owner(), + Amount: 3.0, + }) +} diff --git a/internal/relic/cavern/wastelander/wastelander.go b/internal/relic/cavern/wastelander/wastelander.go new file mode 100644 index 00000000..c1a3208c --- /dev/null +++ b/internal/relic/cavern/wastelander/wastelander.go @@ -0,0 +1,57 @@ +package wastelander + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/event" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" + "github.com/simimpact/srsim/pkg/model" +) + +const ( + wastelander = "wastelander-of-banditry-desert" + wastelandercr = "wastelander-of-banditry-desert-cr" + wastelandercdmg = "wastelander-of-banditry-desert-cdmg" +) + +// 2pc: Increases Imaginary DMG by 10%. +// 4pc: When attacking debuffed enemies, the wearer's CRIT Rate increases by 10%, +// and their CRIT DMG increases by 20% against Imprisoned enemies. + +func init() { + relic.Register(key.WastelanderOfBanditryDesert, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.ImaginaryDamagePercent: 0.1}, + }, + { + MinCount: 4, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: wastelander, + Source: owner, + }) + }, + }, + }, + }) + modifier.Register(wastelander, modifier.Config{ + Listeners: modifier.Listeners{ + OnBeforeHitAll: onBeforeHitAll, + }, + }) +} + +func onBeforeHitAll(mod *modifier.Instance, e event.HitStart) { + debuffCount := float64(e.Hit.Defender.StatusCount(model.StatusType_STATUS_DEBUFF)) + if debuffCount >= 1 { + e.Hit.Attacker.AddProperty(wastelandercr, prop.CritChance, 0.1) + if mod.Engine().HasBehaviorFlag(e.Defender, model.BehaviorFlag_STAT_CONFINE) { + e.Hit.Attacker.AddProperty(wastelandercdmg, prop.CritDMG, 0.2) + } + } +} diff --git a/internal/relic/planar/celestial/celestial.go b/internal/relic/planar/celestial/celestial.go new file mode 100644 index 00000000..a6e71211 --- /dev/null +++ b/internal/relic/planar/celestial/celestial.go @@ -0,0 +1,49 @@ +package celestial + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/event" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" +) + +// 2pc: Increases the wearer's CRIT DMG by 16%. +// When the wearer's current CRIT DMG reaches 120% or higher, after entering battle, +// the wearer's CRIT Rate increases by 60% until the end of their first attack. + +// Multi Wave Support not implemented + +const celestial = "celestial-differentiator" + +func init() { + relic.Register(key.CelestialDifferentiator, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.CritDMG: 0.16}, + }, + { + MinCount: 2, + CreateEffect: func(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: celestial, + Source: owner, + Stats: info.PropMap{prop.CritChance: 0.6}, + }) + }, + }, + }, + }) + modifier.Register(celestial, modifier.Config{ + Listeners: modifier.Listeners{ + OnAfterAttack: onAfterAttack, + }, + }) +} + +func onAfterAttack(mod *modifier.Instance, e event.AttackEnd) { + mod.RemoveSelf() +} diff --git a/internal/relic/planar/keel/keel.go b/internal/relic/planar/keel/keel.go new file mode 100644 index 00000000..a15977b6 --- /dev/null +++ b/internal/relic/planar/keel/keel.go @@ -0,0 +1,91 @@ +package keel + +import ( + "github.com/simimpact/srsim/pkg/engine" + "github.com/simimpact/srsim/pkg/engine/equip/relic" + "github.com/simimpact/srsim/pkg/engine/event" + "github.com/simimpact/srsim/pkg/engine/info" + "github.com/simimpact/srsim/pkg/engine/modifier" + "github.com/simimpact/srsim/pkg/engine/prop" + "github.com/simimpact/srsim/pkg/key" +) + +// 2pc: Increases the wearer's Effect RES by 10%. +// When the wearer's Effect RES is at 30% or higher, all allies' CRIT DMG increases by 10%. + +// TO-DO: how to handle `applied` and pointer logic, where to put the stats + +const ( + check = "broken-keel" + keelcdmg = "broken-keel-cdmg" +) + +type state struct { + applied *bool +} + +func init() { + relic.Register(key.BrokenKeel, relic.Config{ + Effects: []relic.SetEffect{ + { + MinCount: 2, + Stats: info.PropMap{prop.EffectRES: 0.1}, + }, + { + MinCount: 2, + CreateEffect: Create, + }, + }, + }) + modifier.Register(check, modifier.Config{ + Listeners: modifier.Listeners{ + OnAdd: onCheck, + OnPropertyChange: onCheck, + }, + }) + modifier.Register(keelcdmg, modifier.Config{ + Stacking: modifier.ReplaceBySource, + }) +} + +func Create(engine engine.Engine, owner key.TargetID) { + engine.AddModifier(owner, info.Modifier{ + Name: check, + Source: owner, + }) + engine.Events().BattleStart.Subscribe(func(event event.BattleStart) { + appliedInit := false + for char := range event.CharInfo { + engine.AddModifier(char, info.Modifier{ + Name: keelcdmg, + Source: owner, + State: state{ + applied: &appliedInit, + }, + }) + } + }) +} + +func onCheck(mod *modifier.Instance) { + stats := mod.OwnerStats() + applied := mod.State().(*bool) + + if stats.EffectRES() >= 0.3 && !*applied { + for _, c := range mod.Engine().Characters() { + mod.Engine().AddModifier(c, info.Modifier{ + Name: keelcdmg, + Source: mod.Owner(), + Stats: info.PropMap{prop.CritDMG: 0.1}, + }) + } + *mod.State().(*bool) = true + } + + if stats.EffectRES() < 0.3 && *applied { + for _, c := range mod.Engine().Characters() { + mod.Engine().RemoveModifierFromSource(c, mod.Owner(), keelcdmg) + } + *mod.State().(*bool) = false + } +} diff --git a/pkg/key/relic.go b/pkg/key/relic.go index 904eb2ed..fd9844d5 100644 --- a/pkg/key/relic.go +++ b/pkg/key/relic.go @@ -4,23 +4,33 @@ type Relic string // Cavern const ( - MusketeerOfWildWheat Relic = "musketeer_of_wild_wheat" - HunterOfGlacialForest Relic = "hunter_of_glacial_forest" - PasserbyOfWanderingCloud Relic = "passerby_of_wandering_cloud" - KnightOfPurityPalace Relic = "knight_of_purity_palace" - GeniusOfBrilliantStars Relic = "genius_of_brilliant_stars" - ChampionOfStreetwiseBoxing Relic = "champion_of_streetwise_boxing" + MusketeerOfWildWheat Relic = "musketeer_of_wild_wheat" + HunterOfGlacialForest Relic = "hunter_of_glacial_forest" + PasserbyOfWanderingCloud Relic = "passerby_of_wandering_cloud" + KnightOfPurityPalace Relic = "knight_of_purity_palace" + GeniusOfBrilliantStars Relic = "genius_of_brilliant_stars" + ChampionOfStreetwiseBoxing Relic = "champion_of_streetwise_boxing" + GuardOfWutheringSnow Relic = "guard_of_wuthering_snow" + FiresmithOfLavaForging Relic = "firesmith_of_lava-forging" + BandOfSizzlingThunder Relic = "band_of_sizzling_thunder" + EagleOfTwilightLine Relic = "eagle_of_twilight_line" + ThiefOfShootingMeteor Relic = "thief_of_shooting_meteor" + WastelanderOfBanditryDesert Relic = "wastelander_of_banditry_desert" + LongevousDisciple Relic = "longevous_disciple" + MessengerTraversingHackerspace Relic = "messenger_traversing_hackerspace" ) // Planar const ( - BelobogOfTheArchitects Relic = "belobog_of_the_architects" - SpaceSealingStation Relic = "space_sealing_station" - InertSalsotto Relic = "inert_salsotto" - TaliaKingdomOfBanditry Relic = "talia_kingdom_of_banditry" - SprightlyVonwacq Relic = "sprightly_vonwacq" - PanGalactic Relic = "pan_galactic" - RutilantArena Relic = "rutilant_arena" + BelobogOfTheArchitects Relic = "belobog_of_the_architects" + SpaceSealingStation Relic = "space_sealing_station" + InertSalsotto Relic = "inert_salsotto" + TaliaKingdomOfBanditry Relic = "talia_kingdom_of_banditry" + SprightlyVonwacq Relic = "sprightly_vonwacq" + PanGalactic Relic = "pan_galactic" + RutilantArena Relic = "rutilant_arena" + CelestialDifferentiator Relic = "celestial_differentiator" + BrokenKeel Relic = "broken_keel" ) func (r Relic) String() string { diff --git a/pkg/simulation/imports.go b/pkg/simulation/imports.go index 9fb1c9f0..d146de92 100644 --- a/pkg/simulation/imports.go +++ b/pkg/simulation/imports.go @@ -93,13 +93,23 @@ import ( _ "github.com/simimpact/srsim/internal/lightcone/preservation/thisisme" _ "github.com/simimpact/srsim/internal/lightcone/preservation/trendoftheuniversalmarket" _ "github.com/simimpact/srsim/internal/lightcone/preservation/wearewildfire" + _ "github.com/simimpact/srsim/internal/relic/cavern/band" _ "github.com/simimpact/srsim/internal/relic/cavern/championboxing" + _ "github.com/simimpact/srsim/internal/relic/cavern/disciple" + _ "github.com/simimpact/srsim/internal/relic/cavern/eagle" + _ "github.com/simimpact/srsim/internal/relic/cavern/firesmith" _ "github.com/simimpact/srsim/internal/relic/cavern/genius" + _ "github.com/simimpact/srsim/internal/relic/cavern/guard" _ "github.com/simimpact/srsim/internal/relic/cavern/hunterofglacialforest" + _ "github.com/simimpact/srsim/internal/relic/cavern/messenger" _ "github.com/simimpact/srsim/internal/relic/cavern/musketeer" _ "github.com/simimpact/srsim/internal/relic/cavern/puritypalace" + _ "github.com/simimpact/srsim/internal/relic/cavern/thief" _ "github.com/simimpact/srsim/internal/relic/cavern/wanderingcloud" + _ "github.com/simimpact/srsim/internal/relic/cavern/wastelander" _ "github.com/simimpact/srsim/internal/relic/planar/belobog" + _ "github.com/simimpact/srsim/internal/relic/planar/celestial" + _ "github.com/simimpact/srsim/internal/relic/planar/keel" _ "github.com/simimpact/srsim/internal/relic/planar/pangalactic" _ "github.com/simimpact/srsim/internal/relic/planar/rutilant" _ "github.com/simimpact/srsim/internal/relic/planar/salsotto" From 485e37f33e053c889f3e1d7046b162dd529685a5 Mon Sep 17 00:00:00 2001 From: kdovtdc Date: Mon, 29 Jul 2024 19:04:20 +0200 Subject: [PATCH 2/9] Fix Disciple Relic registration using wrong key --- internal/relic/cavern/disciple/disciple.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/relic/cavern/disciple/disciple.go b/internal/relic/cavern/disciple/disciple.go index b5ba3bdf..d175d0c6 100644 --- a/internal/relic/cavern/disciple/disciple.go +++ b/internal/relic/cavern/disciple/disciple.go @@ -23,7 +23,7 @@ const ( // TO-DO: in onHPChange, assumes e.Target means source; check whether this is correct func init() { - relic.Register(key.BandOfSizzlingThunder, relic.Config{ + relic.Register(key.LongevousDisciple, relic.Config{ Effects: []relic.SetEffect{ { MinCount: 2, From c7bd0d067c140040b21d4e8e4291711d4e9dc3d9 Mon Sep 17 00:00:00 2001 From: kdovtdc Date: Tue, 30 Jul 2024 23:36:35 +0200 Subject: [PATCH 3/9] Fix: Some minor formatting/general changes addressed review https://github.com/simimpact/srsim/pull/267#pullrequestreview-2208508356 * Band, Firesmith, Messenger: refactored singular `onAdd` function calls * Guard: removed `CanModifySnapshot` initialization * Firesmith, Celestial: renamed `onAfterAttack` function to clarify what it does * Wastelander: remove `float64` cast --- internal/relic/cavern/band/band.go | 8 +------- internal/relic/cavern/firesmith/firesmith.go | 10 +++------- internal/relic/cavern/guard/guard.go | 1 - internal/relic/cavern/messenger/messenger.go | 8 +------- internal/relic/cavern/wastelander/wastelander.go | 2 +- internal/relic/planar/celestial/celestial.go | 4 ++-- 6 files changed, 8 insertions(+), 25 deletions(-) diff --git a/internal/relic/cavern/band/band.go b/internal/relic/cavern/band/band.go index 0b448d10..e53de501 100644 --- a/internal/relic/cavern/band/band.go +++ b/internal/relic/cavern/band/band.go @@ -46,9 +46,6 @@ func init() { Stacking: modifier.ReplaceBySource, StatusType: model.StatusType_STATUS_BUFF, Duration: 1, - Listeners: modifier.Listeners{ - OnAdd: onAdd, - }, }) } @@ -57,10 +54,7 @@ func onBeforeSkill(mod *modifier.Instance, e event.ActionStart) { mod.Engine().AddModifier(mod.Owner(), info.Modifier{ Name: buff, Source: mod.Owner(), + Stats: info.PropMap{prop.ATKPercent: 0.2}, }) } } - -func onAdd(mod *modifier.Instance) { - mod.AddProperty(prop.ATKPercent, 0.2) -} diff --git a/internal/relic/cavern/firesmith/firesmith.go b/internal/relic/cavern/firesmith/firesmith.go index 8ca7865d..cb1d1333 100644 --- a/internal/relic/cavern/firesmith/firesmith.go +++ b/internal/relic/cavern/firesmith/firesmith.go @@ -48,8 +48,7 @@ func init() { Stacking: modifier.ReplaceBySource, StatusType: model.StatusType_STATUS_BUFF, Listeners: modifier.Listeners{ - OnAdd: onAdd, - OnAfterAttack: onAfterAttack, + OnAfterAttack: removeBuff, }, }) } @@ -65,14 +64,11 @@ func onAfterUltimate(mod *modifier.Instance, e event.ActionEnd) { mod.Engine().AddModifier(mod.Owner(), info.Modifier{ Name: buff, Source: mod.Owner(), + Stats: info.PropMap{prop.FireDamagePercent: 0.12}, }) } } -func onAdd(mod *modifier.Instance) { - mod.AddProperty(prop.FireDamagePercent, 0.12) -} - -func onAfterAttack(mod *modifier.Instance, e event.AttackEnd) { +func removeBuff(mod *modifier.Instance, e event.AttackEnd) { mod.RemoveSelf() } diff --git a/internal/relic/cavern/guard/guard.go b/internal/relic/cavern/guard/guard.go index 8e1f7f3c..02de4d36 100644 --- a/internal/relic/cavern/guard/guard.go +++ b/internal/relic/cavern/guard/guard.go @@ -42,7 +42,6 @@ func init() { Listeners: modifier.Listeners{ OnPhase1: onPhase1, }, - CanModifySnapshot: true, }) } diff --git a/internal/relic/cavern/messenger/messenger.go b/internal/relic/cavern/messenger/messenger.go index aaae1bf1..82eb6837 100644 --- a/internal/relic/cavern/messenger/messenger.go +++ b/internal/relic/cavern/messenger/messenger.go @@ -46,9 +46,6 @@ func init() { modifier.Register(buff, modifier.Config{ Stacking: modifier.Replace, StatusType: model.StatusType_STATUS_BUFF, - Listeners: modifier.Listeners{ - OnAdd: onAdd, - }, }) } @@ -59,11 +56,8 @@ func onBeforeUlt(mod *modifier.Instance, e event.ActionStart) { Name: buff, Source: mod.Owner(), Duration: 1, + Stats: info.PropMap{prop.SPDPercent: 0.12}, }) } } } - -func onAdd(mod *modifier.Instance) { - mod.AddProperty(prop.SPDPercent, 0.12) -} diff --git a/internal/relic/cavern/wastelander/wastelander.go b/internal/relic/cavern/wastelander/wastelander.go index c1a3208c..feed2938 100644 --- a/internal/relic/cavern/wastelander/wastelander.go +++ b/internal/relic/cavern/wastelander/wastelander.go @@ -47,7 +47,7 @@ func init() { } func onBeforeHitAll(mod *modifier.Instance, e event.HitStart) { - debuffCount := float64(e.Hit.Defender.StatusCount(model.StatusType_STATUS_DEBUFF)) + debuffCount := e.Hit.Defender.StatusCount(model.StatusType_STATUS_DEBUFF) if debuffCount >= 1 { e.Hit.Attacker.AddProperty(wastelandercr, prop.CritChance, 0.1) if mod.Engine().HasBehaviorFlag(e.Defender, model.BehaviorFlag_STAT_CONFINE) { diff --git a/internal/relic/planar/celestial/celestial.go b/internal/relic/planar/celestial/celestial.go index a6e71211..f8a77eca 100644 --- a/internal/relic/planar/celestial/celestial.go +++ b/internal/relic/planar/celestial/celestial.go @@ -39,11 +39,11 @@ func init() { }) modifier.Register(celestial, modifier.Config{ Listeners: modifier.Listeners{ - OnAfterAttack: onAfterAttack, + OnAfterAttack: removeSelf, }, }) } -func onAfterAttack(mod *modifier.Instance, e event.AttackEnd) { +func removeSelf(mod *modifier.Instance, e event.AttackEnd) { mod.RemoveSelf() } From 35763c4947373f8fdac209db636f14c1dce1d492 Mon Sep 17 00:00:00 2001 From: kdovtdc Date: Fri, 2 Aug 2024 19:56:12 +0200 Subject: [PATCH 4/9] Finish Keel implementation * fixed and improved logic for `applied` and related pointers * removed unnecessary initialization of `applied` inside `keelcdmg` modifier --- internal/relic/planar/keel/keel.go | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/internal/relic/planar/keel/keel.go b/internal/relic/planar/keel/keel.go index a15977b6..12cd4eac 100644 --- a/internal/relic/planar/keel/keel.go +++ b/internal/relic/planar/keel/keel.go @@ -13,15 +13,14 @@ import ( // 2pc: Increases the wearer's Effect RES by 10%. // When the wearer's Effect RES is at 30% or higher, all allies' CRIT DMG increases by 10%. -// TO-DO: how to handle `applied` and pointer logic, where to put the stats - const ( check = "broken-keel" keelcdmg = "broken-keel-cdmg" ) type state struct { - applied *bool + // "flag" to reduce redundancy when adding and removing buff + applied bool } func init() { @@ -52,16 +51,13 @@ func Create(engine engine.Engine, owner key.TargetID) { engine.AddModifier(owner, info.Modifier{ Name: check, Source: owner, + State: &state{applied: false}, }) engine.Events().BattleStart.Subscribe(func(event event.BattleStart) { - appliedInit := false for char := range event.CharInfo { engine.AddModifier(char, info.Modifier{ Name: keelcdmg, Source: owner, - State: state{ - applied: &appliedInit, - }, }) } }) @@ -69,9 +65,9 @@ func Create(engine engine.Engine, owner key.TargetID) { func onCheck(mod *modifier.Instance) { stats := mod.OwnerStats() - applied := mod.State().(*bool) + st := mod.State().(*state) - if stats.EffectRES() >= 0.3 && !*applied { + if stats.EffectRES() >= 0.3 && !st.applied { for _, c := range mod.Engine().Characters() { mod.Engine().AddModifier(c, info.Modifier{ Name: keelcdmg, @@ -79,13 +75,13 @@ func onCheck(mod *modifier.Instance) { Stats: info.PropMap{prop.CritDMG: 0.1}, }) } - *mod.State().(*bool) = true + st.applied = true } - if stats.EffectRES() < 0.3 && *applied { + if stats.EffectRES() < 0.3 && st.applied { for _, c := range mod.Engine().Characters() { mod.Engine().RemoveModifierFromSource(c, mod.Owner(), keelcdmg) } - *mod.State().(*bool) = false + st.applied = false } } From dd0695f82047042c9e89d292e9523e974ec5939f Mon Sep 17 00:00:00 2001 From: kdovtdc Date: Sun, 25 Aug 2024 19:14:45 +0200 Subject: [PATCH 5/9] Fix Messenger with comments * KNOWN BUG: this will also buff owners equipping this 4p set even if they do not target allies with an Ult * INACCURACY: this should apply instead when OnBeforeAction is triggered --- internal/relic/cavern/messenger/messenger.go | 31 ++++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/internal/relic/cavern/messenger/messenger.go b/internal/relic/cavern/messenger/messenger.go index 82eb6837..4b21481e 100644 --- a/internal/relic/cavern/messenger/messenger.go +++ b/internal/relic/cavern/messenger/messenger.go @@ -40,23 +40,42 @@ func init() { }) modifier.Register(check, modifier.Config{ Listeners: modifier.Listeners{ - OnBeforeAction: onBeforeUlt, + OnBeforeAction: BuffSelf, + OnAfterAction: BuffAllies, }, }) modifier.Register(buff, modifier.Config{ Stacking: modifier.Replace, StatusType: model.StatusType_STATUS_BUFF, + Duration: 1, }) } -func onBeforeUlt(mod *modifier.Instance, e event.ActionStart) { +// workaround for missing "eligible" target list in ActionStart: +// apply buff to owner when OnBeforeAction is triggered +// KNOWN BUG: this will also buff owners equipping this 4p set even if they do not target allies with an Ult +func BuffSelf(mod *modifier.Instance, e event.ActionStart) { + if e.AttackType == model.AttackType_ULT { + mod.Engine().AddModifier(mod.Owner(), info.Modifier{ + Name: buff, + Source: mod.Owner(), + Stats: info.PropMap{prop.SPDPercent: 0.12}, + }) + } +} + +// apply buff to other allies when OnAfterAction is triggered +// INACCURACY: this should apply instead when OnBeforeAction is triggered +func BuffAllies(mod *modifier.Instance, e event.ActionEnd) { if e.AttackType == model.AttackType_ULT { for _, char := range mod.Engine().Characters() { + if char == mod.Owner() { + continue + } mod.Engine().AddModifier(char, info.Modifier{ - Name: buff, - Source: mod.Owner(), - Duration: 1, - Stats: info.PropMap{prop.SPDPercent: 0.12}, + Name: buff, + Source: mod.Owner(), + Stats: info.PropMap{prop.SPDPercent: 0.12}, }) } } From 9a5b22627b150dbf3e44a47c7fa01ed8267a8971 Mon Sep 17 00:00:00 2001 From: kdovtdc Date: Thu, 5 Sep 2024 19:33:53 +0200 Subject: [PATCH 6/9] add removal on death for Keel --- internal/relic/planar/keel/keel.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/relic/planar/keel/keel.go b/internal/relic/planar/keel/keel.go index 12cd4eac..710849ab 100644 --- a/internal/relic/planar/keel/keel.go +++ b/internal/relic/planar/keel/keel.go @@ -61,6 +61,14 @@ func Create(engine engine.Engine, owner key.TargetID) { }) } }) + // remove buff from all chars on planar holder's death + engine.Events().TargetDeath.Subscribe(func(e event.TargetDeath) { + if e.Target == owner { + for _, char := range engine.Characters() { + engine.RemoveModifierFromSource(char, owner, keelcdmg) + } + } + }) } func onCheck(mod *modifier.Instance) { From 346b5b2d309c4ea88215cf079c27fa7af5b67144 Mon Sep 17 00:00:00 2001 From: Veggie Date: Sat, 21 Sep 2024 01:50:30 +0200 Subject: [PATCH 7/9] fix typo --- pkg/simulation/imports.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/simulation/imports.go b/pkg/simulation/imports.go index 013e7b2a..30b7713b 100644 --- a/pkg/simulation/imports.go +++ b/pkg/simulation/imports.go @@ -115,7 +115,7 @@ import ( _ "github.com/simimpact/srsim/internal/relic/planar/celestial" _ "github.com/simimpact/srsim/internal/relic/planar/keel" _ "github.com/simimpact/srsim/internal/relic/planar/glamoth" - _ "github.com/simimpact/srsim/internal/relic/planar/izumo + _ "github.com/simimpact/srsim/internal/relic/planar/izumo" _ "github.com/simimpact/srsim/internal/relic/planar/pangalactic" _ "github.com/simimpact/srsim/internal/relic/planar/penacony" _ "github.com/simimpact/srsim/internal/relic/planar/rutilant" From 061861b0db24d9256900dd9aebf25f5325484f50 Mon Sep 17 00:00:00 2001 From: kdovtdc Date: Sat, 21 Sep 2024 01:56:06 +0200 Subject: [PATCH 8/9] gofmt --- pkg/simulation/imports.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/simulation/imports.go b/pkg/simulation/imports.go index 30b7713b..78566d4c 100644 --- a/pkg/simulation/imports.go +++ b/pkg/simulation/imports.go @@ -113,9 +113,9 @@ import ( _ "github.com/simimpact/srsim/internal/relic/cavern/wastelander" _ "github.com/simimpact/srsim/internal/relic/planar/belobog" _ "github.com/simimpact/srsim/internal/relic/planar/celestial" - _ "github.com/simimpact/srsim/internal/relic/planar/keel" _ "github.com/simimpact/srsim/internal/relic/planar/glamoth" _ "github.com/simimpact/srsim/internal/relic/planar/izumo" + _ "github.com/simimpact/srsim/internal/relic/planar/keel" _ "github.com/simimpact/srsim/internal/relic/planar/pangalactic" _ "github.com/simimpact/srsim/internal/relic/planar/penacony" _ "github.com/simimpact/srsim/internal/relic/planar/rutilant" From 86f1d92adf34dc33281e733cafb805feb95562aa Mon Sep 17 00:00:00 2001 From: kdovtdc Date: Sun, 24 Nov 2024 18:16:05 +0100 Subject: [PATCH 9/9] Update relics with new logic + bugfixes * update with new RWSD flag + `CanDispel` field * fix Celestial to correctly for CDmg and apply during `BattleStart` --- internal/relic/cavern/band/band.go | 7 +++-- internal/relic/cavern/disciple/disciple.go | 7 +++-- internal/relic/cavern/eagle/eagle.go | 6 ++-- internal/relic/cavern/firesmith/firesmith.go | 8 +++-- internal/relic/cavern/guard/guard.go | 8 +++-- internal/relic/cavern/messenger/messenger.go | 20 ++++++++----- internal/relic/cavern/thief/thief.go | 5 ++-- .../relic/cavern/wastelander/wastelander.go | 6 ++-- internal/relic/planar/celestial/celestial.go | 30 ++++++++++++------- internal/relic/planar/keel/keel.go | 10 +++++-- 10 files changed, 70 insertions(+), 37 deletions(-) diff --git a/internal/relic/cavern/band/band.go b/internal/relic/cavern/band/band.go index e53de501..f7b76d91 100644 --- a/internal/relic/cavern/band/band.go +++ b/internal/relic/cavern/band/band.go @@ -23,11 +23,13 @@ func init() { relic.Register(key.BandOfSizzlingThunder, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.ThunderDamagePercent: 0.1}, + MinCount: 2, + Stats: info.PropMap{prop.ThunderDamagePercent: 0.1}, + CreateEffect: nil, }, { MinCount: 4, + Stats: nil, CreateEffect: func(engine engine.Engine, owner key.TargetID) { engine.AddModifier(owner, info.Modifier{ Name: check, @@ -45,6 +47,7 @@ func init() { modifier.Register(buff, modifier.Config{ Stacking: modifier.ReplaceBySource, StatusType: model.StatusType_STATUS_BUFF, + CanDispel: true, Duration: 1, }) } diff --git a/internal/relic/cavern/disciple/disciple.go b/internal/relic/cavern/disciple/disciple.go index d175d0c6..d747494e 100644 --- a/internal/relic/cavern/disciple/disciple.go +++ b/internal/relic/cavern/disciple/disciple.go @@ -26,11 +26,13 @@ func init() { relic.Register(key.LongevousDisciple, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.HPPercent: 0.12}, + MinCount: 2, + Stats: info.PropMap{prop.HPPercent: 0.12}, + CreateEffect: nil, }, { MinCount: 4, + Stats: nil, CreateEffect: func(engine engine.Engine, owner key.TargetID) { engine.AddModifier(owner, info.Modifier{ Name: check, @@ -49,6 +51,7 @@ func init() { modifier.Register(crbuff, modifier.Config{ Stacking: modifier.ReplaceBySource, StatusType: model.StatusType_STATUS_BUFF, + CanDispel: true, MaxCount: 2, CountAddWhenStack: 1, Duration: 2, diff --git a/internal/relic/cavern/eagle/eagle.go b/internal/relic/cavern/eagle/eagle.go index 9703eb56..fb85d929 100644 --- a/internal/relic/cavern/eagle/eagle.go +++ b/internal/relic/cavern/eagle/eagle.go @@ -20,11 +20,13 @@ func init() { relic.Register(key.EagleOfTwilightLine, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.WindDamagePercent: 0.1}, + MinCount: 2, + Stats: info.PropMap{prop.WindDamagePercent: 0.1}, + CreateEffect: nil, }, { MinCount: 4, + Stats: nil, CreateEffect: func(engine engine.Engine, owner key.TargetID) { engine.AddModifier(owner, info.Modifier{ Name: eagle, diff --git a/internal/relic/cavern/firesmith/firesmith.go b/internal/relic/cavern/firesmith/firesmith.go index cb1d1333..5ae13a3b 100644 --- a/internal/relic/cavern/firesmith/firesmith.go +++ b/internal/relic/cavern/firesmith/firesmith.go @@ -24,11 +24,13 @@ func init() { relic.Register(key.FiresmithOfLavaForging, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.FireDamagePercent: 0.1}, + MinCount: 2, + Stats: info.PropMap{prop.FireDamagePercent: 0.1}, + CreateEffect: nil, }, { MinCount: 4, + Stats: nil, CreateEffect: func(engine engine.Engine, owner key.TargetID) { engine.AddModifier(owner, info.Modifier{ Name: check, @@ -45,8 +47,8 @@ func init() { }, }) modifier.Register(buff, modifier.Config{ - Stacking: modifier.ReplaceBySource, StatusType: model.StatusType_STATUS_BUFF, + CanDispel: true, Listeners: modifier.Listeners{ OnAfterAttack: removeBuff, }, diff --git a/internal/relic/cavern/guard/guard.go b/internal/relic/cavern/guard/guard.go index 02de4d36..2675703a 100644 --- a/internal/relic/cavern/guard/guard.go +++ b/internal/relic/cavern/guard/guard.go @@ -24,11 +24,13 @@ func init() { relic.Register(key.GuardOfWutheringSnow, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.AllDamageReduce: 0.08}, + MinCount: 2, + Stats: info.PropMap{prop.AllDamageReduce: 0.08}, + CreateEffect: nil, }, { MinCount: 4, + Stats: nil, CreateEffect: func(engine engine.Engine, owner key.TargetID) { engine.AddModifier(owner, info.Modifier{ Name: guard, @@ -46,7 +48,7 @@ func init() { } func onPhase1(mod *modifier.Instance) { - // if above 50% HP, bypass + // If above 50% HP, bypass if mod.Engine().HPRatio(mod.Owner()) > 0.5 { return } diff --git a/internal/relic/cavern/messenger/messenger.go b/internal/relic/cavern/messenger/messenger.go index 4b21481e..996e560d 100644 --- a/internal/relic/cavern/messenger/messenger.go +++ b/internal/relic/cavern/messenger/messenger.go @@ -24,11 +24,13 @@ func init() { relic.Register(key.MessengerTraversingHackerspace, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.SPDPercent: 0.06}, + MinCount: 2, + Stats: info.PropMap{prop.SPDPercent: 0.06}, + CreateEffect: nil, }, { MinCount: 4, + Stats: nil, CreateEffect: func(engine engine.Engine, owner key.TargetID) { engine.AddModifier(owner, info.Modifier{ Name: check, @@ -45,14 +47,16 @@ func init() { }, }) modifier.Register(buff, modifier.Config{ - Stacking: modifier.Replace, - StatusType: model.StatusType_STATUS_BUFF, - Duration: 1, + Stacking: modifier.Replace, + StatusType: model.StatusType_STATUS_BUFF, + CanDispel: true, + BehaviorFlags: []model.BehaviorFlag{model.BehaviorFlag_STAT_SPEED_UP}, + Duration: 1, }) } -// workaround for missing "eligible" target list in ActionStart: -// apply buff to owner when OnBeforeAction is triggered +// Workaround for missing "eligible" target list in ActionStart: +// Apply buff to owner when OnBeforeAction is triggered // KNOWN BUG: this will also buff owners equipping this 4p set even if they do not target allies with an Ult func BuffSelf(mod *modifier.Instance, e event.ActionStart) { if e.AttackType == model.AttackType_ULT { @@ -64,7 +68,7 @@ func BuffSelf(mod *modifier.Instance, e event.ActionStart) { } } -// apply buff to other allies when OnAfterAction is triggered +// Apply buff to other allies when OnAfterAction is triggered // INACCURACY: this should apply instead when OnBeforeAction is triggered func BuffAllies(mod *modifier.Instance, e event.ActionEnd) { if e.AttackType == model.AttackType_ULT { diff --git a/internal/relic/cavern/thief/thief.go b/internal/relic/cavern/thief/thief.go index 797a35f3..a29b585c 100644 --- a/internal/relic/cavern/thief/thief.go +++ b/internal/relic/cavern/thief/thief.go @@ -19,8 +19,9 @@ func init() { relic.Register(key.ThiefOfShootingMeteor, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.BreakEffect: 0.16}, + MinCount: 2, + Stats: info.PropMap{prop.BreakEffect: 0.16}, + CreateEffect: nil, }, { MinCount: 4, diff --git a/internal/relic/cavern/wastelander/wastelander.go b/internal/relic/cavern/wastelander/wastelander.go index feed2938..bf911c19 100644 --- a/internal/relic/cavern/wastelander/wastelander.go +++ b/internal/relic/cavern/wastelander/wastelander.go @@ -25,11 +25,13 @@ func init() { relic.Register(key.WastelanderOfBanditryDesert, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.ImaginaryDamagePercent: 0.1}, + MinCount: 2, + Stats: info.PropMap{prop.ImaginaryDamagePercent: 0.1}, + CreateEffect: nil, }, { MinCount: 4, + Stats: nil, CreateEffect: func(engine engine.Engine, owner key.TargetID) { engine.AddModifier(owner, info.Modifier{ Name: wastelander, diff --git a/internal/relic/planar/celestial/celestial.go b/internal/relic/planar/celestial/celestial.go index f8a77eca..93040261 100644 --- a/internal/relic/planar/celestial/celestial.go +++ b/internal/relic/planar/celestial/celestial.go @@ -22,18 +22,14 @@ func init() { relic.Register(key.CelestialDifferentiator, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.CritDMG: 0.16}, + MinCount: 2, + Stats: info.PropMap{prop.CritDMG: 0.16}, + CreateEffect: nil, }, { - MinCount: 2, - CreateEffect: func(engine engine.Engine, owner key.TargetID) { - engine.AddModifier(owner, info.Modifier{ - Name: celestial, - Source: owner, - Stats: info.PropMap{prop.CritChance: 0.6}, - }) - }, + MinCount: 2, + Stats: nil, + CreateEffect: Create, }, }, }) @@ -44,6 +40,20 @@ func init() { }) } +func Create(engine engine.Engine, owner key.TargetID) { + engine.Events().BattleStart.Subscribe(func(e event.BattleStart) { + for _, char := range e.CharStats { + if char.ID() == owner && char.CritDamage() >= 1.2 { + engine.AddModifier(owner, info.Modifier{ + Name: celestial, + Source: owner, + Stats: info.PropMap{prop.CritChance: 0.6}, + }) + } + } + }) +} + func removeSelf(mod *modifier.Instance, e event.AttackEnd) { mod.RemoveSelf() } diff --git a/internal/relic/planar/keel/keel.go b/internal/relic/planar/keel/keel.go index 710849ab..83a4870b 100644 --- a/internal/relic/planar/keel/keel.go +++ b/internal/relic/planar/keel/keel.go @@ -8,6 +8,7 @@ import ( "github.com/simimpact/srsim/pkg/engine/modifier" "github.com/simimpact/srsim/pkg/engine/prop" "github.com/simimpact/srsim/pkg/key" + "github.com/simimpact/srsim/pkg/model" ) // 2pc: Increases the wearer's Effect RES by 10%. @@ -27,11 +28,13 @@ func init() { relic.Register(key.BrokenKeel, relic.Config{ Effects: []relic.SetEffect{ { - MinCount: 2, - Stats: info.PropMap{prop.EffectRES: 0.1}, + MinCount: 2, + Stats: info.PropMap{prop.EffectRES: 0.1}, + CreateEffect: nil, }, { MinCount: 2, + Stats: nil, CreateEffect: Create, }, }, @@ -43,7 +46,8 @@ func init() { }, }) modifier.Register(keelcdmg, modifier.Config{ - Stacking: modifier.ReplaceBySource, + Stacking: modifier.ReplaceBySource, + BehaviorFlags: []model.BehaviorFlag{model.BehaviorFlag_REMOVE_WHEN_SOURCE_DEAD}, }) }