Кровавый прилив: нож-меч (статы, хват мачете), бег, восстановление, пульс, сердце

В прилив: урон, скорость ударов и вампиризм ножа вдвое, плата за силовую
вдвое меньше, выносливость вчетверо меньше, дальность 2.8, хват мачете
(модели меча пока нет). С ножом в руке: бег +50%, восстановление здоровья
и выносливости вдвое, полоски пульсируют фиолетовым, сердце 120 уд/мин.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-10 13:21:46 +03:00
co-authored by Claude Opus 5.5
parent 8d1fe16cf2
commit b13759908e
10 changed files with 342 additions and 0 deletions
+2
View File
@@ -203,6 +203,8 @@ necroPossessHintLeap,items,Item,,,,Space - long leap,,Leertaste - weiter Sprung,
necroPetRecallHint,items,Item,,,,Recall pet - E,,Diener zurückrufen - E,Devolver al sirviente - E,Rappeler le serviteur - E,Richiama il servitore - E,僕を呼び戻す - E,종복 불러들이기 - E,Odwołaj sługę - E,Chamar o servo de volta - E,Отозвать питомца - E,Hizmetkârı geri çağır - E,召回仆从 - E,召回僕從 - E
necroPetNothingToPossess,items,Item,,,,No servant summoned to possess,,"Kein beschworener Diener, in den du fahren kannst",No hay ningún sirviente invocado que poseer,Aucun serviteur invoqué à posséder,Nessun servitore evocato da possedere,憑依できる僕が呼ばれていません,빙의할 종복이 소환되어 있지 않습니다,Brak przywołanego sługi do opętania,Nenhum servo invocado para possuir,Нет призванного слуги для вселения,Ele geçirilecek çağrılmış hizmetkâr yok,没有可附身的已召唤仆从,沒有可附身的已召喚僕從
necroBloodTide,items,Item,,,,Blood tide: the spirit cannot leave the body,,Blutflut: Der Geist kann den Körper nicht verlassen,Marea de sangre: el espíritu no puede abandonar el cuerpo,Marée de sang : l'esprit ne peut pas quitter le corps,Marea di sangue: lo spirito non può lasciare il corpo,血の潮:霊は肉体を離れられない,피의 조수: 영이 몸을 떠날 수 없다,Krwawy przypływ: duch nie może opuścić ciała,Maré de sangue: o espírito não pode deixar o corpo,Кровавый прилив: дух не может покинуть тело,Kan gelgiti: ruh bedeni terk edemiyor,血潮:灵体无法离开身体,血潮:靈體無法離開身體
buffNecroBloodTideName,buffs,Buff,,,,Blood Tide,,Blutflut,Marea de sangre,Marée de sang,Marea di sangue,血の潮,피의 조수,Krwawy przypływ,Maré de sangue,Кровавый прилив,Kan gelgiti,血潮,血潮
buffNecroBloodTideDesc,buffs,Buff,,,,"Necroenergy floods the air until dawn: the spirit cannot leave the body. The necromancer's knife becomes a sword - double damage, attack speed and lifesteal, half the power attack cost, a quarter of the stamina. With the knife in hand you run 50% faster, and health and stamina recover twice as fast.",,"Bis zum Morgengrauen ist die Luft voller Nekroenergie: Der Geist kann den Körper nicht verlassen. Das Messer des Nekromanten wird zum Schwert - doppelter Schaden, doppelte Angriffsgeschwindigkeit und Lebensraub, halbe Kosten für den Kraftangriff, ein Viertel der Ausdauer. Mit dem Messer in der Hand läufst du 50 % schneller, Gesundheit und Ausdauer regenerieren doppelt so schnell.","Hasta el amanecer el aire está saturado de necroenergía: el espíritu no puede abandonar el cuerpo. El cuchillo del nigromante se vuelve espada: daño, velocidad de ataque y robo de vida dobles, la mitad del coste del ataque potente, una cuarta parte de la resistencia. Con el cuchillo en la mano corres un 50 % más rápido, y la salud y la resistencia se recuperan el doble de rápido.","Jusqu'à l'aube, l'air est saturé de nécroénergie : l'esprit ne peut pas quitter le corps. Le couteau du nécromancien devient une épée - dégâts, vitesse d'attaque et vol de vie doublés, coût de l'attaque puissante divisé par deux, endurance divisée par quatre. Couteau en main, tu cours 50 % plus vite, et la santé et l'endurance se régénèrent deux fois plus vite.","Fino all'alba l'aria è satura di necroenergia: lo spirito non può lasciare il corpo. Il coltello del negromante diventa una spada: danno, velocità d'attacco e furto di vita doppi, metà del costo dell'attacco potente, un quarto della resistenza. Con il coltello in mano corri il 50% più veloce, e salute e resistenza si rigenerano il doppio più in fretta.",夜明けまで空気はネクロエネルギーで満ちる:霊は肉体を離れられない。死霊術師のナイフは剣となる - ダメージ、攻撃速度、吸収が2倍、強攻撃のコストは半分、スタミナ消費は4分の1。ナイフを手にしていれば50%速く走り、体力とスタミナの回復は2倍になる。,"새벽까지 공기가 네크로 에너지로 가득 찬다: 영이 몸을 떠날 수 없다. 강령술사의 칼은 검이 된다 - 피해, 공격 속도, 흡혈 2배, 강공격 비용 절반, 스태미나 소모 4분의 1. 칼을 들고 있으면 50% 더 빨리 달리고, 체력과 스태미나가 두 배로 빨리 회복된다.","Do świtu powietrze jest pełne nekroenergii: duch nie może opuścić ciała. Nóż nekromanty staje się mieczem - podwójne obrażenia, szybkość ataku i wampiryzm, połowa kosztu ataku silnego, ćwierć wytrzymałości. Z nożem w ręce biegasz o 50% szybciej, a zdrowie i wytrzymałość odnawiają się dwa razy szybciej.","Até o amanhecer o ar está saturado de necroenergia: o espírito não pode deixar o corpo. A faca do necromante vira espada - dano, velocidade de ataque e roubo de vida dobrados, metade do custo do ataque poderoso, um quarto da vigor. Com a faca na mão você corre 50% mais rápido, e a saúde e o vigor se recuperam duas vezes mais rápido.","До рассвета воздух полон некроэнергии: дух не может покинуть тело. Нож некроманта становится мечом - урон, скорость ударов и вампиризм вдвое, плата за силовую атаку вдвое меньше, выносливость - вчетверо. С ножом в руке бег на 50% быстрее, здоровье и выносливость восстанавливаются вдвое быстрее.","Şafağa kadar hava nekroenerjiyle dolu: ruh bedeni terk edemez. Nekromansörün bıçağı kılıca dönüşür - hasar, saldırı hızı ve can çalma iki kat, güçlü saldırı bedeli yarı, dayanıklılık harcaması dörtte bir. Bıçak elindeyken %50 daha hızlı koşarsın, sağlık ve dayanıklılık iki kat hızlı yenilenir.",直到黎明,空气中充满死灵能量:灵体无法离开身体。死灵法师之刀化为剑——伤害、攻速和吸血翻倍,重击代价减半,耐力消耗仅为四分之一。手持此刀时奔跑速度提高50%,生命和耐力恢复速度翻倍。,直到黎明,空氣中充滿死靈能量:靈體無法離開身體。死靈法師之刀化為劍——傷害、攻速和吸血翻倍,重擊代價減半,耐力消耗僅為四分之一。手持此刀時奔跑速度提高50%,生命和耐力恢復速度翻倍。
necroPossessHintFly,items,Item,,,,"Space - up, C - down, Shift - dive",,"Leertaste - hoch, C - runter, Umschalt - Sturzflug","Espacio: subir, C: bajar, Mayús: picado","Espace : monter, C : descendre, Maj : piqué","Spazio - su, C - giù, Maiusc - picchiata",スペース: 上昇、C: 下降、Shift: 急降下,"스페이스 - 상승, C - 하강, Shift - 급강하","Spacja - w górę, C - w dół, Shift - nurkowanie","Espaço - subir, C - descer, Shift - mergulho","Пробел - вверх, C - вниз, Shift - пике","Boşluk - yukarı, C - aşağı, Shift - dalış",空格 - 上升,C - 下降,Shift - 俯冲,空白鍵 - 上升,C - 下降,Shift - 俯衝
necroPossessHintEatF,items,Item,,,,"F - feed on carrion (sitting by a corpse, heals)",,"F - Aas fressen (neben einer Leiche sitzend, heilt)","F: comer carroña (posado junto a un cadáver, cura)","F : se nourrir de charogne (posé près d'un cadavre, soigne)","F - nutrirsi di carogne (posato accanto a un cadavere, cura)",F: 死肉を食べる(死体のそばに止まって・回復),"F - 썩은 고기 먹기 (시체 옆에 앉아서, 회복)","F - żerowanie na padlinie (siedząc przy zwłokach, leczy)","F - comer carniça (pousado junto a um cadáver, cura)","F - питаться падалью (сидя у трупа, лечит)","F - leş ye (bir cesedin yanına konup, iyileştirir)",F - 食腐(落在尸体旁,治疗),F - 食腐(停在屍體旁,治療)
necroPossessHintEatGroundF,items,Item,,,,"F - feed on carrion (standing still by a corpse, heals)",,"F - Aas fressen (still neben einer Leiche stehend, heilt)","F: comer carroña (quieto junto a un cadáver, cura)","F : se nourrir de charogne (immobile près d'un cadavre, soigne)","F - nutrirsi di carogne (fermo accanto a un cadavere, cura)",F: 死肉を食べる(死体のそばで止まって・回復),"F - 썩은 고기 먹기 (시체 옆에 멈춰 서서, 회복)","F - żerowanie na padlinie (stojąc przy zwłokach, leczy)","F - comer carniça (parado junto a um cadáver, cura)","F - питаться падалью (стоя у трупа, лечит)","F - leş ye (bir cesedin yanında durup, iyileştirir)",F - 食腐(停在尸体旁,治疗),F - 食腐(停在屍體旁,治療)
1 Key File Type UsedInMainMenu NoTranslate KeepLoaded english Context / Alternate Text german spanish french italian japanese koreana polish brazilian russian turkish schinese tchinese
203 necroPetRecallHint items Item Recall pet - E Diener zurückrufen - E Devolver al sirviente - E Rappeler le serviteur - E Richiama il servitore - E 僕を呼び戻す - E 종복 불러들이기 - E Odwołaj sługę - E Chamar o servo de volta - E Отозвать питомца - E Hizmetkârı geri çağır - E 召回仆从 - E 召回僕從 - E
204 necroPetNothingToPossess items Item No servant summoned to possess Kein beschworener Diener, in den du fahren kannst No hay ningún sirviente invocado que poseer Aucun serviteur invoqué à posséder Nessun servitore evocato da possedere 憑依できる僕が呼ばれていません 빙의할 종복이 소환되어 있지 않습니다 Brak przywołanego sługi do opętania Nenhum servo invocado para possuir Нет призванного слуги для вселения Ele geçirilecek çağrılmış hizmetkâr yok 没有可附身的已召唤仆从 沒有可附身的已召喚僕從
205 necroBloodTide items Item Blood tide: the spirit cannot leave the body Blutflut: Der Geist kann den Körper nicht verlassen Marea de sangre: el espíritu no puede abandonar el cuerpo Marée de sang : l'esprit ne peut pas quitter le corps Marea di sangue: lo spirito non può lasciare il corpo 血の潮:霊は肉体を離れられない 피의 조수: 영이 몸을 떠날 수 없다 Krwawy przypływ: duch nie może opuścić ciała Maré de sangue: o espírito não pode deixar o corpo Кровавый прилив: дух не может покинуть тело Kan gelgiti: ruh bedeni terk edemiyor 血潮:灵体无法离开身体 血潮:靈體無法離開身體
206 buffNecroBloodTideName buffs Buff Blood Tide Blutflut Marea de sangre Marée de sang Marea di sangue 血の潮 피의 조수 Krwawy przypływ Maré de sangue Кровавый прилив Kan gelgiti 血潮 血潮
207 buffNecroBloodTideDesc buffs Buff Necroenergy floods the air until dawn: the spirit cannot leave the body. The necromancer's knife becomes a sword - double damage, attack speed and lifesteal, half the power attack cost, a quarter of the stamina. With the knife in hand you run 50% faster, and health and stamina recover twice as fast. Bis zum Morgengrauen ist die Luft voller Nekroenergie: Der Geist kann den Körper nicht verlassen. Das Messer des Nekromanten wird zum Schwert - doppelter Schaden, doppelte Angriffsgeschwindigkeit und Lebensraub, halbe Kosten für den Kraftangriff, ein Viertel der Ausdauer. Mit dem Messer in der Hand läufst du 50 % schneller, Gesundheit und Ausdauer regenerieren doppelt so schnell. Hasta el amanecer el aire está saturado de necroenergía: el espíritu no puede abandonar el cuerpo. El cuchillo del nigromante se vuelve espada: daño, velocidad de ataque y robo de vida dobles, la mitad del coste del ataque potente, una cuarta parte de la resistencia. Con el cuchillo en la mano corres un 50 % más rápido, y la salud y la resistencia se recuperan el doble de rápido. Jusqu'à l'aube, l'air est saturé de nécroénergie : l'esprit ne peut pas quitter le corps. Le couteau du nécromancien devient une épée - dégâts, vitesse d'attaque et vol de vie doublés, coût de l'attaque puissante divisé par deux, endurance divisée par quatre. Couteau en main, tu cours 50 % plus vite, et la santé et l'endurance se régénèrent deux fois plus vite. Fino all'alba l'aria è satura di necroenergia: lo spirito non può lasciare il corpo. Il coltello del negromante diventa una spada: danno, velocità d'attacco e furto di vita doppi, metà del costo dell'attacco potente, un quarto della resistenza. Con il coltello in mano corri il 50% più veloce, e salute e resistenza si rigenerano il doppio più in fretta. 夜明けまで空気はネクロエネルギーで満ちる:霊は肉体を離れられない。死霊術師のナイフは剣となる - ダメージ、攻撃速度、吸収が2倍、強攻撃のコストは半分、スタミナ消費は4分の1。ナイフを手にしていれば50%速く走り、体力とスタミナの回復は2倍になる。 새벽까지 공기가 네크로 에너지로 가득 찬다: 영이 몸을 떠날 수 없다. 강령술사의 칼은 검이 된다 - 피해, 공격 속도, 흡혈 2배, 강공격 비용 절반, 스태미나 소모 4분의 1. 칼을 들고 있으면 50% 더 빨리 달리고, 체력과 스태미나가 두 배로 빨리 회복된다. Do świtu powietrze jest pełne nekroenergii: duch nie może opuścić ciała. Nóż nekromanty staje się mieczem - podwójne obrażenia, szybkość ataku i wampiryzm, połowa kosztu ataku silnego, ćwierć wytrzymałości. Z nożem w ręce biegasz o 50% szybciej, a zdrowie i wytrzymałość odnawiają się dwa razy szybciej. Até o amanhecer o ar está saturado de necroenergia: o espírito não pode deixar o corpo. A faca do necromante vira espada - dano, velocidade de ataque e roubo de vida dobrados, metade do custo do ataque poderoso, um quarto da vigor. Com a faca na mão você corre 50% mais rápido, e a saúde e o vigor se recuperam duas vezes mais rápido. До рассвета воздух полон некроэнергии: дух не может покинуть тело. Нож некроманта становится мечом - урон, скорость ударов и вампиризм вдвое, плата за силовую атаку вдвое меньше, выносливость - вчетверо. С ножом в руке бег на 50% быстрее, здоровье и выносливость восстанавливаются вдвое быстрее. Şafağa kadar hava nekroenerjiyle dolu: ruh bedeni terk edemez. Nekromansörün bıçağı kılıca dönüşür - hasar, saldırı hızı ve can çalma iki kat, güçlü saldırı bedeli yarı, dayanıklılık harcaması dörtte bir. Bıçak elindeyken %50 daha hızlı koşarsın, sağlık ve dayanıklılık iki kat hızlı yenilenir. 直到黎明,空气中充满死灵能量:灵体无法离开身体。死灵法师之刀化为剑——伤害、攻速和吸血翻倍,重击代价减半,耐力消耗仅为四分之一。手持此刀时奔跑速度提高50%,生命和耐力恢复速度翻倍。 直到黎明,空氣中充滿死靈能量:靈體無法離開身體。死靈法師之刀化為劍——傷害、攻速和吸血翻倍,重擊代價減半,耐力消耗僅為四分之一。手持此刀時奔跑速度提高50%,生命和耐力恢復速度翻倍。
208 necroPossessHintFly items Item Space - up, C - down, Shift - dive Leertaste - hoch, C - runter, Umschalt - Sturzflug Espacio: subir, C: bajar, Mayús: picado Espace : monter, C : descendre, Maj : piqué Spazio - su, C - giù, Maiusc - picchiata スペース: 上昇、C: 下降、Shift: 急降下 스페이스 - 상승, C - 하강, Shift - 급강하 Spacja - w górę, C - w dół, Shift - nurkowanie Espaço - subir, C - descer, Shift - mergulho Пробел - вверх, C - вниз, Shift - пике Boşluk - yukarı, C - aşağı, Shift - dalış 空格 - 上升,C - 下降,Shift - 俯冲 空白鍵 - 上升,C - 下降,Shift - 俯衝
209 necroPossessHintEatF items Item F - feed on carrion (sitting by a corpse, heals) F - Aas fressen (neben einer Leiche sitzend, heilt) F: comer carroña (posado junto a un cadáver, cura) F : se nourrir de charogne (posé près d'un cadavre, soigne) F - nutrirsi di carogne (posato accanto a un cadavere, cura) F: 死肉を食べる(死体のそばに止まって・回復) F - 썩은 고기 먹기 (시체 옆에 앉아서, 회복) F - żerowanie na padlinie (siedząc przy zwłokach, leczy) F - comer carniça (pousado junto a um cadáver, cura) F - питаться падалью (сидя у трупа, лечит) F - leş ye (bir cesedin yanına konup, iyileştirir) F - 食腐(落在尸体旁,治疗) F - 食腐(停在屍體旁,治療)
210 necroPossessHintEatGroundF items Item F - feed on carrion (standing still by a corpse, heals) F - Aas fressen (still neben einer Leiche stehend, heilt) F: comer carroña (quieto junto a un cadáver, cura) F : se nourrir de charogne (immobile près d'un cadavre, soigne) F - nutrirsi di carogne (fermo accanto a un cadavere, cura) F: 死肉を食べる(死体のそばで止まって・回復) F - 썩은 고기 먹기 (시체 옆에 멈춰 서서, 회복) F - żerowanie na padlinie (stojąc przy zwłokach, leczy) F - comer carniça (parado junto a um cadáver, cura) F - питаться падалью (стоя у трупа, лечит) F - leş ye (bir cesedin yanında durup, iyileştirir) F - 食腐(停在尸体旁,治疗) F - 食腐(停在屍體旁,治療)
+15
View File
@@ -96,6 +96,21 @@
death too (onSelfDied) even though the buff FLAG itself survives death on purpose
(remove_on_death="false" above) - the glow is cosmetic and shouldn't linger on a
corpse; VictimPatch.cs's own HasBuff check doesn't care whether the particle is gone. -->
<!-- Кровавый прилив (указание 10.10): ставит и снимает BloodTide.cs - на игроке, пока идёт ночь кровавой
луны (SnakeMode.IsBloodTide). Сам по себе ничего не меняет; нож читает его в effect_group
necroKnifeBloodTide (items.xml). Здесь - только то, что зависит от ножа в руке: бег на 50% быстрее.
Восстановление здоровья и выносливости вдвое (только положительное, кровотечение не трогаем),
пульс полосок и сердцебиение - BloodTide.cs. -->
<buff name="buffNecroBloodTide" icon="ui_game_symbol_skull" icon_color="170,60,255" name_key="buffNecroBloodTideName" description_key="buffNecroBloodTideDesc" remove_on_death="false">
<stack_type value="ignore"/>
<effect_group>
<requirement name="HoldingItemHasTags" tags="necroKnife"/>
<passive_effect name="WalkSpeed" operation="perc_add" value=".5"/>
<passive_effect name="RunSpeed" operation="perc_add" value=".5"/>
<passive_effect name="CrouchSpeed" operation="perc_add" value=".5"/>
</effect_group>
</buff>
<buff name="buffNecroVictim" hidden="true" remove_on_death="false">
<stack_type value="ignore"/>
<duration value="0"/>
+8
View File
@@ -284,6 +284,14 @@
отсеивает мёртвых. -->
<requirement name="StatCompareCurrent" target="other" stat="Health" operation="GT" value="0"/>
<requirement name="StatCompareCurrent" stat="Health" operation="GT" value="5"/>
<requirement name="!HasBuff" buff="buffNecroBloodTide"/>
</triggered_effect>
<!-- Кровавый прилив (10.10): плата вдвое меньше - 10 + 10 = 20. -->
<triggered_effect trigger="onSelfSecondaryActionRayHit" action="ModifyStats" stat="Health" operation="subtract" value="10">
<requirement name="EntityTagCompare" target="other" tags="zombie"/>
<requirement name="StatCompareCurrent" target="other" stat="Health" operation="GT" value="0"/>
<requirement name="StatCompareCurrent" stat="Health" operation="GT" value="5"/>
<requirement name="HasBuff" buff="buffNecroBloodTide"/>
</triggered_effect>
<!-- AOE вокруг задетой цели. Базовое сбивание с ног у ножа одиночное, это его
+24
View File
@@ -1549,6 +1549,30 @@
<requirement name="EntityTagCompare" target="other" tags="zombie"/>
<requirement name="StatCompareCurrent" target="other" stat="Health" operation="GT" value="0"/>
<requirement name="StatCompareCurrent" stat="Health" operation="GT" value="20"/>
<requirement name="!HasBuff" buff="buffNecroBloodTide"/>
</triggered_effect>
</effect_group>
<!-- КРОВАВЫЙ ПРИЛИВ (указание 10.10). Некроэнергии в воздухе столько, что нож пьёт её сам: пока на
игроке buffNecroBloodTide (ставит BloodTide.cs на ночь кровавой луны) - урон и скорость ударов
вдвое, вампиризм вдвое (второе такое же лечение), плата за силовую вдвое меньше (10 вместо 20;
обычная плата выше выключена !HasBuff), выносливость на удар вчетверо меньше, дальность -
как у меча (у мачете 2.3, у ножа 2.0). Хват и модель меча, скорость бега и восстановление -
BloodTide.cs и сам бафф. -->
<effect_group name="necroKnifeBloodTide">
<requirement name="HasBuff" buff="buffNecroBloodTide"/>
<passive_effect name="EntityDamage" operation="perc_add" value="1"/>
<passive_effect name="AttacksPerMinute" operation="perc_add" value="1"/>
<passive_effect name="StaminaLoss" operation="perc_add" value="-.75"/>
<passive_effect name="MaxRange" operation="base_set" value="2.8"/>
<triggered_effect trigger="onSelfPrimaryActionRayHit" action="ModifyStats" stat="Health" operation="add" value="@$necroKnifeHealCVar">
<requirement name="EntityTagCompare" target="other" tags="zombie"/>
<requirement name="StatCompareCurrent" target="other" stat="Health" operation="GT" value="0"/>
</triggered_effect>
<triggered_effect trigger="onSelfSecondaryActionRayHit" action="ModifyStats" stat="Health" operation="subtract" value="10">
<requirement name="EntityTagCompare" target="other" tags="zombie"/>
<requirement name="StatCompareCurrent" target="other" stat="Health" operation="GT" value="0"/>
<requirement name="StatCompareCurrent" stat="Health" operation="GT" value="10"/>
</triggered_effect>
</effect_group>
</item>
+283
View File
@@ -0,0 +1,283 @@
using System.Collections.Generic;
using HarmonyLib;
using UnityEngine;
namespace NecromancerTome
{
/// <summary>
/// Кровавый прилив и нож (указание 10.10): «раз некроэнергии становится много, она должна воздействовать не
/// только на зомби и некроманта». Пока идёт прилив (SnakeMode.IsBloodTide - ночь кровавой луны):
/// - на игроке бафф buffNecroBloodTide (buffs.xml): по нему нож (effect_group necroKnifeBloodTide, items.xml) бьёт
/// вдвое сильнее и вдвое чаще, лечит вдвое, плата за силовую вдвое меньше, выносливость на удар вчетверо
/// меньше, дальность - как у меча; с ножом в руке бег на 50% быстрее (сам бафф);
/// - хват ножа - как у мачете, модель - нож в фиолетовом мече (ItemClass ножа подменяется на всю ночь,
/// нож в руке пересоздаётся);
/// и, только если нож в руке:
/// - восстановление здоровья и выносливости вдвое (лишь положительное - кровотечение и прочий урон не трогаем);
/// - полоски здоровья и выносливости пульсируют фиолетовым в такт сердцу;
/// - фоном бьётся сердце, 120 ударов в минуту (синтез в коде: два низких удара синусом, «лаб» и «даб»,
/// с затуханием и спадом тона - по образцу, одобренному пользователем 10.10).
/// Всё - у локального игрока (одиночная игра и хост).
/// </summary>
public static class BloodTide
{
public const string BuffName = "buffNecroBloodTide";
/// <summary>Хват мачете (items.xml игры, meleeWpnBladeT3Machete HoldType=47); у ножа - 36.</summary>
public const int TideHoldType = 47;
/// <summary>Модель меча на прилив. Пока не собрана - null, остаётся модель ножа (меняется только хват).</summary>
public static string TideMeshFile = null;
public const float HeartBpm = 120f;
public const float HeartVolume = 0.55f;
/// <summary>Цвет пульса полосок - фиолетовый меча.</summary>
public static readonly Color PulseColor = new Color(0.67f, 0.24f, 1f);
/// <summary>Идёт прилив (кэш на кадр).</summary>
public static bool Active;
/// <summary>Прилив и нож в руке.</summary>
public static bool Armed;
static bool _swapped;
static int _origHoldType = -1;
static string _origMesh;
static float _nextBuffCheck;
static GameObject _heartGo;
static AudioSource _heart;
static AudioClip _heartClip;
public static void Init()
{
ModEvents.UnityUpdate.RegisterHandler(OnUnityUpdate);
}
static void OnUnityUpdate(ref ModEvents.SUnityUpdateData _data)
{
World world = GameManager.Instance?.World;
EntityPlayerLocal player = world?.GetPrimaryPlayer();
if (world == null || player == null)
{
Active = Armed = false;
_swapped = false; // классы предметов игра грузит заново с миром
_origHoldType = -1;
Heart(false);
Patch_XUiC_HUDStatBar_Update_BloodTide.Forget();
return;
}
bool tide = SnakeMode.IsBloodTide();
if (tide != Active)
{
Active = tide;
Debug.Log("[NecromancerTome] BloodTide: " + (tide ? "прилив начался" : "прилив схлынул"));
}
SwapKnife(player, Active);
if (Time.time >= _nextBuffCheck && !player.IsDead())
{
_nextBuffCheck = Time.time + 0.5f;
bool has = player.Buffs.HasBuff(BuffName);
if (Active && !has)
{
player.Buffs.AddBuff(BuffName);
}
else if (!Active && has)
{
player.Buffs.RemoveBuff(BuffName);
}
}
Armed = Active && !player.IsDead() && SnakeMode.IsKnife(player.inventory?.holdingItem);
Heart(Armed && !GameManager.Instance.IsPaused());
}
/// <summary>Хват и модель ножа на прилив и обратно. Подмена - в общем ItemClass, поэтому видна у любого
/// ножа; нож в руке пересоздаём (снять и достать тот же слот), иначе он до смены оружия остался бы прежним.</summary>
static void SwapKnife(EntityPlayerLocal _player, bool _tide)
{
if (_tide == _swapped)
{
return;
}
ItemClass knife = ItemClass.GetItemClass(SnakeMode.KnifeName);
if (knife == null)
{
return;
}
if (_origHoldType < 0)
{
_origHoldType = knife.HoldType.Value;
_origMesh = knife.MeshFile;
}
knife.HoldType.Value = _tide ? TideHoldType : _origHoldType;
knife.MeshFile = _tide && !string.IsNullOrEmpty(TideMeshFile) ? TideMeshFile : _origMesh;
_swapped = _tide;
Inventory inv = _player.inventory;
ItemInventoryData held = inv?.holdingItemData;
if (held != null && held.item == knife)
{
// NeedsRebuild - «собранный» предмет не совпадает с тем, что в слоте: сбрасываем собранный, и
// повторный выбор того же слота снимает нож и собирает его заново (Hand.SelectHoldingMode).
held.physicalItemValue = ItemValue.None.Clone();
inv.SetHoldingItemIdx(inv.holdingItemIdx);
}
Debug.Log("[NecromancerTome] BloodTide: нож - хват " + knife.HoldType.Value + (held != null && held.item == knife ? ", в руке пересоздан" : ""));
}
// ---------------------------------------------------------------- сердце
static void Heart(bool _on)
{
if (!_on)
{
if (_heart != null && _heart.isPlaying)
{
_heart.Stop();
}
return;
}
if (_heart == null)
{
_heartGo = new GameObject("NecroBloodTideHeart");
Object.DontDestroyOnLoad(_heartGo);
_heart = _heartGo.AddComponent<AudioSource>();
_heart.clip = _heartClip ?? (_heartClip = MakeHeartClip());
_heart.loop = true;
_heart.spatialBlend = 0f;
_heart.playOnAwake = false;
}
_heart.volume = HeartVolume * GamePrefs.GetFloat(EnumGamePrefs.OptionsOverallAudioVolumeLevel);
if (!_heart.isPlaying)
{
_heart.Play();
}
}
/// <summary>Доля удара сердца для пульса полосок: 1 в момент «лаба», дальше спад; без звука - 0.</summary>
public static float Beat()
{
if (_heart == null || !_heart.isPlaying)
{
return 0f;
}
float t = _heart.time;
float dub = 0.17f;
return Mathf.Max(Mathf.Exp(-9f * t), t >= dub ? 0.6f * Mathf.Exp(-12f * (t - dub)) : 0f);
}
/// <summary>Один цикл сердца (60/HeartBpm с): «лаб» 62 Гц и «даб» 52 Гц через 0.17 с, каждый - синус с
/// второй гармоникой, атака 4 мс, экспоненциальное затухание, тон к концу падает на треть.</summary>
static AudioClip MakeHeartClip()
{
const int sr = 44100;
int n = Mathf.RoundToInt(sr * 60f / HeartBpm);
float[] buf = new float[n];
Thump(buf, 0, 62f, 0.16f, 1f, 22f, sr);
Thump(buf, Mathf.RoundToInt(sr * 0.17f), 52f, 0.12f, 0.6f, 28f, sr);
float max = 0f;
foreach (float v in buf)
{
max = Mathf.Max(max, Mathf.Abs(v));
}
for (int i = 0; i < n; i++)
{
buf[i] = buf[i] / max * 0.9f;
}
AudioClip clip = AudioClip.Create("necroHeartbeat", n, 1, sr, false);
clip.SetData(buf, 0);
return clip;
}
static void Thump(float[] _buf, int _start, float _freq, float _dur, float _amp, float _decay, int _sr)
{
int n = Mathf.Min(Mathf.RoundToInt(_sr * _dur), _buf.Length - _start);
double ph = 0;
for (int i = 0; i < n; i++)
{
float t = (float)i / _sr;
float env = Mathf.Min(t / 0.004f, 1f) * Mathf.Exp(-_decay * t);
ph += 2 * Mathf.PI * _freq * (1f - 0.35f * t / _dur) / _sr;
_buf[_start + i] += _amp * env * (float)(System.Math.Sin(ph) + 0.25 * System.Math.Sin(2 * ph));
}
}
}
/// <summary>Восстановление вдвое (прилив и нож в руке). Игра сама задаёт RegenerationAmount и вызывает Stat.Tick в
/// PlayerEntityStats.UpdatePlayerHealthOT/StaminaOT; удваиваем только свежее положительное восстановление этого
/// вызова (у здоровья оно считается, лишь когда здоровье не полное и HealthChangeOT больше нуля - иначе в поле
/// остаётся прошлая разница, её трогать нельзя).</summary>
[HarmonyPatch(typeof(PlayerEntityStats), nameof(PlayerEntityStats.UpdatePlayerHealthOT))]
public static class Patch_PlayerEntityStats_UpdatePlayerHealthOT_BloodTide
{
public static void Prefix(PlayerEntityStats __instance)
{
Patch_Stat_Tick_BloodTide.Next = null;
if (BloodTide.Armed && __instance.m_entity is EntityPlayerLocal p && __instance.Health.ValuePercent < 1f &&
EffectManager.GetValue(PassiveEffects.HealthChangeOT, null, 0f, p) > 0f)
{
Patch_Stat_Tick_BloodTide.Next = __instance.Health;
}
}
}
[HarmonyPatch(typeof(PlayerEntityStats), nameof(PlayerEntityStats.UpdatePlayerStaminaOT))]
public static class Patch_PlayerEntityStats_UpdatePlayerStaminaOT_BloodTide
{
public static void Prefix(PlayerEntityStats __instance)
{
Patch_Stat_Tick_BloodTide.Next = BloodTide.Armed && __instance.m_entity is EntityPlayerLocal ? __instance.Stamina : null;
}
}
[HarmonyPatch(typeof(Stat), nameof(Stat.Tick))]
public static class Patch_Stat_Tick_BloodTide
{
/// <summary>Стат, чей следующий Tick удвоить (ставят префиксы выше).</summary>
public static Stat Next;
public static void Prefix(Stat __instance)
{
if (Next == null || Next != __instance)
{
return;
}
Next = null;
if (__instance.regenAmount > 0f)
{
__instance.regenAmount *= 2f;
}
}
}
/// <summary>Пульс полосок здоровья и выносливости (прилив и нож в руке): цвет полосы (BarContent в HUDLeftStatBars
/// игры, у здоровья 255,0,0,160, у выносливости 0,54,255,160) уходит в фиолетовый на каждом ударе сердца.</summary>
[HarmonyPatch(typeof(XUiC_HUDStatBar), nameof(XUiC_HUDStatBar.Update))]
public static class Patch_XUiC_HUDStatBar_Update_BloodTide
{
static readonly Dictionary<XUiC_HUDStatBar, (XUiV_Sprite bar, Color orig)> _bars = new Dictionary<XUiC_HUDStatBar, (XUiV_Sprite, Color)>();
public static void Forget()
{
_bars.Clear();
}
public static void Postfix(XUiC_HUDStatBar __instance)
{
if (__instance.statType != HUDStatTypes.Health && __instance.statType != HUDStatTypes.Stamina)
{
return;
}
if (!_bars.TryGetValue(__instance, out var e))
{
if (!BloodTide.Armed || !(__instance.GetChildById("BarContent")?.ViewComponent is XUiV_Sprite s))
{
return;
}
e = (s, s.Color);
_bars[__instance] = e;
}
Color c = BloodTide.Armed
? Color.Lerp(e.orig, new Color(BloodTide.PulseColor.r, BloodTide.PulseColor.g, BloodTide.PulseColor.b, Mathf.Max(e.orig.a, 0.8f)), BloodTide.Beat())
: e.orig;
if (e.bar.Color != c)
{
e.bar.Color = c;
}
}
}
}
+4
View File
@@ -28,6 +28,10 @@ namespace NecromancerTome
return;
}
int cost = HasStorm(_data.itemValue) ? StormCost : Cost;
if (BloodTide.Active)
{
cost /= 2; // кровавый прилив (10.10): плата вдвое меньше - как в items.xml/item_modifiers.xml
}
if (player.Health > cost)
{
return;
+1
View File
@@ -65,6 +65,7 @@ namespace NecromancerTome
HandPose.Init();
NecroMailbox.Init();
Possession.Init();
BloodTide.Init();
// PyramidWardPatch.cs's TEFeaturePyramidWard needs no Init() call - it's discovered
// automatically by the engine's own TileEntityCompositeData reflection scan (see that
// file's class doc comment), not registered here like PetFollowPatch's UnityUpdate hook.
+5
View File
@@ -46,6 +46,11 @@
<HintPath>..\..\..\7DaysToDie_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
<Private>false</Private>
</Reference>
<!-- AudioSource/AudioClip.Create - сердцебиение кровавого прилива (BloodTide.cs, 10.10). -->
<Reference Include="UnityEngine.AudioModule">
<HintPath>..\..\..\7DaysToDie_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
<Private>false</Private>
</Reference>
<!-- EntityAlive.PlayOneShot(string)'s own overload set touches AnimationEvent (2026-08-29,
BansheePatch.cs) - needed even though this mod never uses AnimationEvent directly, just
to satisfy the compiler's reference-resolution for that overload. -->
Binary file not shown.
Binary file not shown.