diff --git a/internal/services/assets/weapons_gen.go b/internal/services/assets/weapons_gen.go
index 910e72a3a..703c6fb3d 100644
--- a/internal/services/assets/weapons_gen.go
+++ b/internal/services/assets/weapons_gen.go
@@ -68,6 +68,7 @@ var weaponMap = map[string]string{
"mappamare": "UI_EquipIcon_Catalyst_Exotic",
"memoryofdust": "UI_EquipIcon_Catalyst_Kunwu",
"everlastingmoonglow": "UI_EquipIcon_Catalyst_Kaleido",
+ "nocturnescourtaincall": "UI_EquipIcon_Catalyst_Brisingamen",
"oathsworneye": "UI_EquipIcon_Catalyst_Jyanome",
"otherworldlystory": "UI_EquipIcon_Catalyst_Lightnov",
"eyeofperception": "UI_EquipIcon_Catalyst_Truelens",
diff --git a/internal/weapons/catalyst/nocturnes/config.yml b/internal/weapons/catalyst/nocturnes/config.yml
new file mode 100644
index 000000000..0fc066d52
--- /dev/null
+++ b/internal/weapons/catalyst/nocturnes/config.yml
@@ -0,0 +1,3 @@
+package_name: nocturnes
+genshin_id: 14522
+key: nocturnescourtaincall
diff --git a/internal/weapons/catalyst/nocturnes/data_gen.textproto b/internal/weapons/catalyst/nocturnes/data_gen.textproto
new file mode 100644
index 000000000..c6d387965
--- /dev/null
+++ b/internal/weapons/catalyst/nocturnes/data_gen.textproto
@@ -0,0 +1,63 @@
+id: 14522
+key: "nocturnescourtaincall"
+rarity: 5
+weapon_class: WEAPON_CATALYST
+image_name: "UI_EquipIcon_Catalyst_Brisingamen"
+base_stats: {
+ base_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ initial_value: 44.3358
+ curve: GROW_CURVE_ATTACK_304
+ }
+ base_props: {
+ prop_type: FIGHT_PROP_CRITICAL_HURT
+ initial_value: 0.192
+ curve: GROW_CURVE_CRITICAL_301
+ }
+ promo_data: {
+ max_level: 20
+ }
+ promo_data: {
+ max_level: 40
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 31.1
+ }
+ }
+ promo_data: {
+ max_level: 50
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 62.2
+ }
+ }
+ promo_data: {
+ max_level: 60
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 93.4
+ }
+ }
+ promo_data: {
+ max_level: 70
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 124.5
+ }
+ }
+ promo_data: {
+ max_level: 80
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 155.6
+ }
+ }
+ promo_data: {
+ max_level: 90
+ add_props: {
+ prop_type: FIGHT_PROP_BASE_ATTACK
+ value: 186.7
+ }
+ }
+}
+name_text_hash_map: 1441327747
diff --git a/internal/weapons/catalyst/nocturnes/nocturnes.go b/internal/weapons/catalyst/nocturnes/nocturnes.go
new file mode 100644
index 000000000..aa147daa6
--- /dev/null
+++ b/internal/weapons/catalyst/nocturnes/nocturnes.go
@@ -0,0 +1,92 @@
+package nocturnes
+
+import (
+ "github.com/genshinsim/gcsim/pkg/core"
+ "github.com/genshinsim/gcsim/pkg/core/attacks"
+ "github.com/genshinsim/gcsim/pkg/core/attributes"
+ "github.com/genshinsim/gcsim/pkg/core/event"
+ "github.com/genshinsim/gcsim/pkg/core/info"
+ "github.com/genshinsim/gcsim/pkg/core/keys"
+ "github.com/genshinsim/gcsim/pkg/core/player/character"
+ "github.com/genshinsim/gcsim/pkg/modifier"
+)
+
+func init() {
+ core.RegisterWeaponFunc(keys.NocturnesCourtainCall, NewWeapon)
+}
+
+const ICDKey = "nocturnes-courtain-call-icd"
+
+type Weapon struct {
+ Index int
+}
+
+func (w *Weapon) SetIndex(idx int) { w.Index = idx }
+func (w *Weapon) Init() error { return nil }
+
+func NewWeapon(c *core.Core, char *character.CharWrapper, p info.WeaponProfile) (info.Weapon, error) {
+ w := &Weapon{}
+ r := p.Refine
+
+ m := make([]float64, attributes.EndStatType)
+ m[attributes.HPP] = 0.075 + float64(r)*0.025
+ char.AddStatMod(character.StatMod{
+ Base: modifier.NewBase("nocturnes-courtain-call-hp", -1),
+ Amount: func() []float64 {
+ return m
+ },
+ })
+
+ onHitF := func(args ...any) {
+ atk := args[1].(*info.AttackEvent)
+ if atk.Info.ActorIndex != char.Index() {
+ return
+ }
+ if atk.Info.AttackTag < attacks.LunarReactionStartDelim || atk.Info.AttackTag > attacks.DirectLunarReactionEndDelim {
+ return
+ }
+ w.nocturneBuff(c, char, r)
+ }
+
+ onReactF := func(args ...any) {
+ atk := args[1].(*info.AttackEvent)
+ if atk.Info.ActorIndex != char.Index() {
+ return
+ }
+
+ w.nocturneBuff(c, char, r)
+ }
+
+ c.Events.Subscribe(event.OnEnemyHit, onHitF, "nocturnes-courtain-call-buff")
+ c.Events.Subscribe(event.OnLunarCharged, onReactF, "nocturnes-courtain-call-buff")
+ c.Events.Subscribe(event.OnLunarBloom, onReactF, "nocturnes-courtain-call-buff")
+ // c.Events.Subscribe(event.OnLunarCrystallize, onReactF, "nocturnes-courtain-call-buff")
+
+ return w, nil
+}
+
+func (w *Weapon) nocturneBuff(c *core.Core, char *character.CharWrapper, r int) {
+ if !char.StatusIsActive(ICDKey) {
+ char.AddEnergy("nocturnes-courtain-call", 15)
+ char.AddStatus(ICDKey, 18*60, true)
+ }
+
+ m := make([]float64, attributes.EndStatType)
+ m[attributes.HPP] = 0.09 + float64(r)*0.03
+ char.AddStatMod(character.StatMod{
+ Base: modifier.NewBaseWithHitlag("nocturnes-courtain-call-hp", 12*60),
+ AffectedStat: attributes.HPP,
+ Amount: func() []float64 {
+ return m
+ },
+ })
+
+ c.Events.Subscribe(event.OnEnemyHit, func(args ...any) {
+ atk := args[1].(*info.AttackEvent)
+
+ if atk.Info.AttackTag < attacks.LunarReactionStartDelim || atk.Info.AttackTag > attacks.DirectLunarReactionEndDelim {
+ return
+ }
+ atk.Snapshot.Stats[attributes.CD] += 0.6
+ }, "nocturnes-courtain-call-buff")
+}
diff --git a/internal/weapons/catalyst/nocturnes/nocturnes_gen.go b/internal/weapons/catalyst/nocturnes/nocturnes_gen.go
new file mode 100644
index 000000000..0a8b133f4
--- /dev/null
+++ b/internal/weapons/catalyst/nocturnes/nocturnes_gen.go
@@ -0,0 +1,25 @@
+// Code generated by "pipeline"; DO NOT EDIT.
+package nocturnes
+
+import (
+ _ "embed"
+
+ "github.com/genshinsim/gcsim/pkg/model"
+ "google.golang.org/protobuf/encoding/prototext"
+)
+
+//go:embed data_gen.textproto
+var pbData []byte
+var base *model.WeaponData
+
+func init() {
+ base = &model.WeaponData{}
+ err := prototext.Unmarshal(pbData, base)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (x *Weapon) Data() *model.WeaponData {
+ return base
+}
diff --git a/pkg/core/keys/weapon.go b/pkg/core/keys/weapon.go
index b5b8b3708..dfeaa9284 100644
--- a/pkg/core/keys/weapon.go
+++ b/pkg/core/keys/weapon.go
@@ -145,6 +145,7 @@ var weaponNames = []string{
"moonweaversdawn",
"mountainbracingbolt",
"mouunsmoon",
+ "nocturnescourtaincall",
"oathsworneye",
"oldmercspal",
"otherworldlystory",
@@ -365,6 +366,7 @@ const (
MoonweaversDawn
MountainBracingBolt
MouunsMoon
+ NocturnesCourtainCall
OathswornEye
OldMercsPal
OtherworldlyStory
diff --git a/pkg/shortcut/weapons.go b/pkg/shortcut/weapons.go
index 4c8ccf956..c2522c9b6 100644
--- a/pkg/shortcut/weapons.go
+++ b/pkg/shortcut/weapons.go
@@ -200,6 +200,8 @@ var WeaponNameToKey = map[string]keys.Weapon{
"mouunsmoon": keys.MouunsMoon,
"mouun": keys.MouunsMoon,
"mouuns": keys.MouunsMoon,
+ "nocturnescourtaincall": keys.NocturnesCourtainCall,
+ "nocturnes": keys.NocturnesCourtainCall,
"oathsworneye": keys.OathswornEye,
"oathsworn": keys.OathswornEye,
"oldmercspal": keys.OldMercsPal,
diff --git a/pkg/simulation/imports.go b/pkg/simulation/imports.go
index 93fffc8b5..2c29678b5 100644
--- a/pkg/simulation/imports.go
+++ b/pkg/simulation/imports.go
@@ -131,6 +131,7 @@ import (
_ "github.com/genshinsim/gcsim/internal/weapons/catalyst/mappa"
_ "github.com/genshinsim/gcsim/internal/weapons/catalyst/memory"
_ "github.com/genshinsim/gcsim/internal/weapons/catalyst/moonglow"
+ _ "github.com/genshinsim/gcsim/internal/weapons/catalyst/nocturnes"
_ "github.com/genshinsim/gcsim/internal/weapons/catalyst/oathsworneye"
_ "github.com/genshinsim/gcsim/internal/weapons/catalyst/otherworldly"
_ "github.com/genshinsim/gcsim/internal/weapons/catalyst/perception"
diff --git a/ui/packages/docs/docs/reference/weapons/nocturnescourtaincall.md b/ui/packages/docs/docs/reference/weapons/nocturnescourtaincall.md
new file mode 100644
index 000000000..610f5d492
--- /dev/null
+++ b/ui/packages/docs/docs/reference/weapons/nocturnescourtaincall.md
@@ -0,0 +1,30 @@
+---
+title: >
+ Nocturne's Curtain Call
+---
+
+import AoETable from "@site/src/components/AoE/AoETable";
+import IssuesTable from "@site/src/components/Issues/IssuesTable";
+import NamesList from "@site/src/components/Names/NamesList";
+import ParamsTable from "@site/src/components/Params/ParamsTable";
+import FieldsTable from "@site/src/components/Fields/FieldsTable";
+
+## AoE Data
+
+
+
+## Known issues
+
+
+
+## Names
+
+
+
+## Params
+
+
+
+## Fields
+
+
diff --git a/ui/packages/docs/src/components/Names/weapon_data.json b/ui/packages/docs/src/components/Names/weapon_data.json
index f7f9a4f23..5e2f28101 100644
--- a/ui/packages/docs/src/components/Names/weapon_data.json
+++ b/ui/packages/docs/src/components/Names/weapon_data.json
@@ -254,6 +254,9 @@
"mouun",
"mouuns"
],
+ "nocturnescourtaincall": [
+ "nocturnes"
+ ],
"oathsworneye": [
"oathsworn"
],
diff --git a/ui/packages/localization/src/locales/names.generated.json b/ui/packages/localization/src/locales/names.generated.json
index 78c0d23da..bef2c12f3 100644
--- a/ui/packages/localization/src/locales/names.generated.json
+++ b/ui/packages/localization/src/locales/names.generated.json
@@ -227,6 +227,7 @@
"moonweaversdawn": "织月者的曙色",
"mountainbracingbolt": "镇山之钉",
"mouunsmoon": "曚云之月",
+ "nocturnescourtaincall": "帷间夜曲",
"oathsworneye": "证誓之明瞳",
"oldmercspal": "佣兵重剑",
"otherworldlystory": "异世界行记",
@@ -1023,6 +1024,7 @@
"moonweaversdawn": "Moonweaver's Dawn",
"mountainbracingbolt": "Mountain-Bracing Bolt",
"mouunsmoon": "Mouun's Moon",
+ "nocturnescourtaincall": "Nocturne's Curtain Call",
"oathsworneye": "Oathsworn Eye",
"oldmercspal": "Old Merc's Pal",
"otherworldlystory": "Otherworldly Story",
@@ -1819,6 +1821,7 @@
"moonweaversdawn": "Dämmerlicht des Mondwebers",
"mountainbracingbolt": "Bergschützer-Bolzen",
"mouunsmoon": "Mouun-Mond",
+ "nocturnescourtaincall": "Nachtmusik im Schleier",
"oathsworneye": "Auge des Gelöbnisses",
"oldmercspal": "Söldnerzweihänder",
"otherworldlystory": "Geschichten einer anderen Welt",
@@ -2615,6 +2618,7 @@
"moonweaversdawn": "月紡ぎの曙光",
"mountainbracingbolt": "鎮山の釘",
"mouunsmoon": "曚雲の月",
+ "nocturnescourtaincall": "帳の夜曲",
"oathsworneye": "誓いの明瞳",
"oldmercspal": "傭兵の重剣",
"otherworldlystory": "異世界旅行記",
@@ -3411,6 +3415,7 @@
"moonweaversdawn": "달을 엮는 자의 새벽빛",
"mountainbracingbolt": "산을 고정하는 못",
"mouunsmoon": "모운의 달",
+ "nocturnescourtaincall": "막간의 야상곡",
"oathsworneye": "맹세의 눈동자",
"oldmercspal": "용병 중검",
"otherworldlystory": "이세계 여행기",
@@ -4207,6 +4212,7 @@
"moonweaversdawn": "Рассвет прядильщицы луны",
"mountainbracingbolt": "Крепящий горы шип",
"mouunsmoon": "Луна Моун",
+ "nocturnescourtaincall": "Вызов ноктюрна",
"oathsworneye": "Око клятвы",
"oldmercspal": "Лучший друг наёмника",
"otherworldlystory": "Потусторонняя история",
@@ -5003,6 +5009,7 @@
"moonweaversdawn": "Alba de la Tejelunas",
"mountainbracingbolt": "Púa Sustentamontañas",
"mouunsmoon": "Luna de Mouun",
+ "nocturnescourtaincall": "Nocturno tras el Velo",
"oathsworneye": "Ojo del Juramento",
"oldmercspal": "Espada del Mercenario",
"otherworldlystory": "Historias de Otros Mundos",
diff --git a/ui/packages/ui/src/Data/weapon_data.generated.json b/ui/packages/ui/src/Data/weapon_data.generated.json
index 42fed788c..e4ed7230c 100644
--- a/ui/packages/ui/src/Data/weapon_data.generated.json
+++ b/ui/packages/ui/src/Data/weapon_data.generated.json
@@ -896,6 +896,14 @@
"image_name": "UI_EquipIcon_Bow_Maria",
"name_text_hash_map ": "1860795787"
},
+ "nocturnescourtaincall": {
+ "id": 14522,
+ "key": "nocturnescourtaincall",
+ "rarity": 5,
+ "weapon_class": "WEAPON_CATALYST",
+ "image_name": "UI_EquipIcon_Catalyst_Brisingamen",
+ "name_text_hash_map ": "1441327747"
+ },
"oathsworneye": {
"id": 14415,
"key": "oathsworneye",