ИИ питомцев переписан, добавлен Дух крысы, пороги разнесены по шкале

Работа по указаниям 2026-09-18. В релиз пока не выходит.

НОВЫЙ ПИТОМЕЦ "Дух крысы" (necroRatSpirit), Некромантия 3 (60 убийств):
модель зомбоволка в масштабе 0.28, урон 5, кроличьи звуки. Сам не нападает
никогда, держится справа-сзади в двух блоках, упёршись в препятствие проходит
СКВОЗЬ него и блоков не ломает. Укус замедляет, оставляет метку духа (видна на
компасе, +25% получаемого урона) и рвёт жилу. Обгрызая труп, лечится.

СВОЯ ЗАДАЧА ИИ. Задачи "иди за сущностью" в игре нет вовсе - проверены все 32
типа EAI*. Написана NecroFollowOwnerTask по образцу EAIApproachSpot: сектор
"3-6 часов" от хозяина, FindPath с canBreak:false, проход сквозь препятствие
через Entity.IsStuck. Вешается в рантайме, минуя Type.GetType.

ПРИКАЗ АТАКОВАТЬ. Повторное применение свитка при живом питомце натравливает
его на цель под прицелом: EntityPlayerLocal.HitInfo + ItemActionAttack.
GetEntityFromHit. Торговцы и игроки отсеяны. Нет цели - "Нет цели для атаки".

ЗОМБОЖИВОТНЫЕ ПРИВЕДЕНЫ К ТОМУ ЖЕ ОБРАЗЦУ. Сняты BreakBlock, Territorial,
ApproachSpot, Wander, BlockingTargetTask и поедание трупов; цель они больше не
выбирают сами. Лестница урона 20/35/45/60 плюс расчленение у Пса, Медведя и
Волка. Кровотечение всем, метка и ослабление - только у крысы.

УБИЙСТВА ПИТОМЦЕМ ЗАСЧИТЫВАЮТСЯ ВЛАДЕЛЬЦУ, включая добивание кровотечением.
Префикс на AwardKillXPServer подменяет убийцу владельцем; для смерти от баффа
заведена память укусов, потому что в DamageSource от баффа нет того, кто его
наложил. Зомби под Камнем духов это не задело - решение от 17.09 в силе.

ГРИФ откачен на летающую ветку EntityVulture и переименован в Могильного
стервятника: модель наконец соответствует имени. Держится у игрока сам, через
собственный механизм "дома" (setHomeArea), на время погони дом отвязывается.
Попытка натянуть птичий префаб на наземный класс провалилась и записана - так
делать нельзя.

ПРОЧЕЕ: призрачный вид распространён с торговцев на питомцев (у Пса, Медведя и
Волка выключен по указанию), у Пса светятся фиолетовые глаза, белая иконка
книги снята со всех свитков призыва, "Жуки Властелина" переименованы в "Рой
фараона" на всех 13 языках.

ПОРОГИ: крыса 60, стервятник 500, пёс 1300, медведь 2000, волк 4000.

ИСПРАВЛЕНО ПО ХОДУ ИГРОВЫХ ПРОВЕРОК: питомцы не призывались обычным кликом
(AnimWait требовал удержания), отзыв срабатывал не с первого раза (автомат
состояний ItemActionSpawnEntity), крыса проваливалась сквозь мир (IsStuck
отключает и пол), питомец подбрасывал хозяина (коллайдеры разводились до
появления модели).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-09-18 20:51:42 +03:00
co-authored by Claude Opus 5
parent 15c59dd37a
commit d97f83e972
21 changed files with 2501 additions and 179 deletions
+161 -48
View File
@@ -58,9 +58,41 @@
originally had before its own rework - see necroMeleeHandZombieDog in items.xml. -->
<property name="HandItem" value="necroMeleeHandZombieDog"/>
<property name="AITask-3" value="ApproachAndAttackTarget" data="class=EntityZombie,20"/>
<property name="AITarget-1" value="SetAsTargetIfHurt" data="class=EntityZombie"/>
<property name="AITarget-4" value="SetNearestEntityAsTarget" data="class=EntityZombie,22,20"/>
<!-- ИИ ПЕРЕПИСАН 2026-09-18 ПОД ОБРАЗЕЦ ДУХА КРЫСЫ, прямое указание: "поведение
других призванных животных зомби тоже подгони под крысу. По сути это те же
крысы, но размер модели оригинальный, урон нарастает от зомбособаки до
зомбоволка". Правка стоит здесь, у necroZombieDog, и этого достаточно:
Зомбомедведь, Зомбоволк и Зомбогриф расширяют именно его и унаследуют всё.
БЫЛО (и разобрано в BACKLOG.md 18.09 как "питомцы унаследовали ИИ враждебной
твари"): AITask-3 переопределял только погоню, а от animalZombieDog оставались
BreakBlock (грыз базу игрока), Territorial (держался точки призыва, а не
хозяина), ApproachSpot и Wander (бродил сам по себе), BlockingTargetTask и
SetNearestCorpseAsTarget (бросал хозяина ради ближайшего трупа), а
SetNearestEntityAsTarget заставлял его самому лезть в драку в 22 метрах.
СТАЛО, ровно как у крысы:
- AITask-3 пустой обрывает перебор, поэтому BreakBlock/Territorial/ApproachSpot/
Wander не грузятся вовсе (CopyPropertiesFromEntityClass идёт по индексам и
встаёт на первом пустом);
- AITarget-2 пустой так же убирает BlockingTargetTask и поедание трупов;
- цель НЕ ВЫБИРАЕТСЯ самостоятельно никогда: SetNearestEntityAsTarget больше
нет. Цель приходит только приказом игрока (PetCommandPatch.cs);
- AITarget-1 остаётся только как ответ на удар, и список классов без
EntityPlayer: питомец огрызается на зомби и враждебных зверей, но никогда на
хозяина;
- class=EntityAlive в AITask-1 - это разрешение задаче подхватить ту цель,
которую ей ДАЛИ, а не "бей всё живое" (EAIApproachAndAttackTarget.CanExecute
сверяет тип цели со списком и без совпадения не запускается). Кого можно
назначать, решает PetCommandPatch.cs, и торговец там отсеян.
Задача следования (NecroFollowOwnerTask) вешается в рантайме из SummonPatch.cs -
всем, у кого UsesFollowTask, то есть теперь и этим четверым. -->
<property name="AITask-1" value="ApproachAndAttackTarget" data="class=EntityAlive,0"/>
<property name="AITask-2" value="Look"/>
<property name="AITask-3" value=""/>
<property name="AITarget-1" value="SetAsTargetIfHurt" data="class=EntityZombie,EntityEnemyAnimal"/>
<property name="AITarget-2" value=""/>
</entity_class>
</append>
@@ -156,6 +188,9 @@
<property name="PrefabCombined" value="true"/>
<property name="PhysicsBody" value="bear"/>
<property name="Mass" value="600"/>
<!-- 80% от ванильного, указание 2026-09-18. У animalZombieBear своего SizeScale нет,
то есть ванильный размер - единица, отсюда 0.8. -->
<property name="SizeScale" value="0.8"/>
<property name="Tags" value="entity,animal,bear"/>
<!-- FIXED 2026-08-30 (user report: "зомбомедведь лает" - swapping the Prefab only
changes the visible model, sound properties are a totally separate set of
@@ -173,7 +208,7 @@
<property name="SoundStepType" value="animalhvystep"/>
<!-- Real vanilla hand item (claw damage 60, vs. the Dog's own bite at 8) - reused
as-is, not customized further (no slow debuff etc. - not asked for). -->
<property name="HandItem" value="meleeHandAnimalZombieBear"/>
<property name="HandItem" value="necroMeleeHandZombieBear"/>
<effect_group name="Base Effects">
<!-- 1500 is a guess between the Dog's 200 and real animalZombieBear's own 4000 -
a tough pet, not necessarily boss-tier tanky. Say if it should be higher/lower. -->
@@ -189,7 +224,8 @@
<property name="PrefabCombined" value="true"/>
<property name="PhysicsBody" value="AWolf"/>
<property name="Mass" value="180"/>
<property name="SizeScale" value="1.4"/>
<!-- 1.12 = 80% от ванильных 1.4 у animalDireWolf, указание 2026-09-18. -->
<property name="SizeScale" value="1.12"/>
<property name="Tags" value="entity,animal,wolf"/>
<!-- FIXED 2026-08-30, same oversight as the Bear above (see its comment) - real
animalDireWolf's own sound set. -->
@@ -202,7 +238,7 @@
<property name="SoundGiveUp" value="wolfdiregiveup"/>
<property name="SoundStepType" value="animalpawstep"/>
<!-- Real vanilla hand item (bite damage 60, vs. the Dog's own 8). -->
<property name="HandItem" value="meleeHandAnimalDireWolf"/>
<property name="HandItem" value="necroMeleeHandZombieWolf"/>
<effect_group name="Base Effects">
<!-- 1200 is a guess between the Dog's 200 and real animalDireWolf's own 3000 -
slightly below the Bear, faster/leaner theme. Say if it should be different. -->
@@ -211,56 +247,133 @@
</entity_class>
</append>
<!-- Griffin CONVERTED 2026-08-29 to the same Dog-reskin trick as Bear/Wolf, after the user
confirmed live in-game that the animalZombieVulture+Harmony-redirect approach genuinely
doesn't work ("летает где-то в небе, и зомби его вообще не интересуют" - flies around
doing EntityVulture's own default Wander behavior, never engaging anything). Not worth
debugging the Harmony redirect further without another live test cycle - switched
straight to the proven-reliable pattern instead, same as Wolf (confirmed working) and
Bear (not yet confirmed, same trick).
<!-- "Зомбогриф" ОТКАЧЕН 2026-09-18 К ЛЕТАЮЩЕЙ ВЕТКЕ.
No real griffin exists in this game and a bird's skeleton/rig was flagged as a real risk
for reusing necroZombieDog's own quadruped rig (see the removed comment this replaces) -
picked animalMountainLion as the substitute model instead of a bird: it EXTENDS
animalWolf (Data/Config/entityclasses.xml, confirmed by reading it directly) - the SAME
immediate parent animalZombieDog itself extends - almost certainly sharing the exact same
quadruped skeleton/rig family the Dog's own model already uses, the lowest-risk pick
available (lower risk than the Bear, which comes from a totally different
animalBear->animalTemplateHostile lineage). Not a literal griffin visually any more (a
mountain lion, not a bird/lion-eagle hybrid) - say if a different substitute or the name
itself should change; kept "Зомбогриф"/"Summon Zombie Griffin" as-is for now since
renaming would touch items.xml/recipes.xml/Localization.csv too and wasn't asked for. -->
История у него длинная, и важно не потерять её конец. До 29.08 он расширял
animalZombieVulture и просто бестолково летал ("летает где-то в небе, и зомби его вообще
не интересуют") - тогда его перевели на necroZombieDog, то есть сделали наземным со
сменённой моделью. 18.09 пользователь заметил результат прямо: "зомбогриф у тебя это серая
пума". Попробовали натянуть на тот же наземный класс префаб стервятника - вышло хуже
всего: "выглядит жутко, прозрачное только туловище и голова, по земле он ползёт на
крыльях". Это и был ответ на висевший с 29.08 вопрос, можно ли подменить ОДИН префаб:
нельзя, птичья модель на аниматоре наземного квадрупа не работает.
Указание: "зомбогрифа откати, пусть ведёт себя как раньше и не делай его прозрачным.
Пусть пока бестолково летает как раньше, но с возможностью нацелить его на противника...
Потом сделаем грифа как надо. Но потом."
Поэтому здесь снова ванильная ЛЕТАЮЩАЯ ветка со всем, что к ней прилагается, и это
сознательный шаг назад до отдельной работы над ним (замысел разведдрона - BACKLOG.md).
ЧТО ПРИШЛОСЬ СНЯТЬ И ПОЧЕМУ:
- EntityFlags и EntityType уходят с "animal,zombie"/"Zombie" на чистое "animal"/"Animal".
Иначе EntityAlive.DamageEntity не даст ему бить зомби вовсе: там жёсткое правило, что
две сущности с флагом Zombie не могут повредить друг другу. Тот же приём и по той же
причине применён к Рою жуков выше.
- Tags теряют zombie/hostile, IsEnemyEntity=false, Faction=none - форма "свой игроку",
как у всех остальных питомцев.
- AITask/AITarget НЕ ЗАДАЮТСЯ ВОВСЕ, и это не упущение: Class="EntityVulture" не
использует систему AITask ни в каком виде, у него собственный захардкоженный поиск
целей на C# (см. HarmonySrc/SwarmTargetPatch.cs, там это разобрано целиком). Писать
сюда задачи - ровно та ошибка, которую уже совершали 28.08 с Роем.
ЧТОБЫ НЕ АТАКОВАЛ ХОЗЯИНА, он добавлен в SwarmTargetPatch.SpeciesByName: префикс на
EntityAlive.SetAttackTarget подменяет игрока ближайшим зомби. Это единственная точка, через
которую проходят все цели EntityVulture.
ПРИКАЗ АТАКОВАТЬ у него остаётся (CommandsAttack в SummonPatch.cs), но с оговоркой:
EntityVulture перебирает цели сам, своим циклом, и может сбросить наш приказ. Задачу
следования ему НЕ вешаем - она наземная и с полётом только подерётся. -->
<append xpath="/entity_classes">
<entity_class name="necroZombieGriffin" extends="necroZombieDog">
<!-- Real vanilla animalMountainLion's own Prefab/PhysicsBody/Mass/SizeScale. -->
<property name="Prefab" value="@:Entities/Animals/Cat/animalMountainLion.prefab"/>
<property name="PrefabCombined" value="true"/>
<property name="PhysicsBody" value="MountainLion"/>
<property name="Mass" value="125"/>
<property name="SizeScale" value="1"/>
<property name="Tags" value="entity,animal,cat"/>
<!-- FIXED 2026-08-30, same oversight as the Bear above (see its comment) - real
animalMountainLion's own sound set. -->
<property name="SoundRandom" value="mlionroam"/>
<property name="SoundAlert" value="mlionalert"/>
<property name="SoundHurt" value="mlionpain"/>
<property name="SoundDeath" value="mliondeath"/>
<property name="SoundAttack" value="mlionattack"/>
<property name="SoundSense" value="mlionsense"/>
<property name="SoundGiveUp" value="mliongiveup"/>
<property name="SoundStepType" value="animalpawstep"/>
<!-- Real vanilla hand item (claw damage 22 - lighter than the Bear/Wolf's 60, a
faster/leaner theme fitting a big cat rather than a heavyweight brawler). -->
<property name="HandItem" value="meleeHandAnimalMountainLion"/>
<entity_class name="necroZombieGriffin" extends="animalZombieVulture">
<property name="EntityFlags" value="animal"/>
<property name="EntityType" value="Animal"/>
<property name="Tags" value="entity,animal,vulture"/>
<property name="IsEnemyEntity" value="false"/>
<property name="Faction" value="none"/>
<property name="HandItem" value="necroMeleeHandZombieGriffin"/>
<effect_group name="Base Effects">
<!-- Real vanilla animalMountainLion's own HealthMax (750) - used as-is, not
scaled further, since this pet is meant to be the "fast/agile" one, not the
tankiest of the three. -->
<!-- У ванильного зомбостервятника 30 HP - для питомца, которого не отозвать до
следующего призыва, это ничто. 750 оставлено с прежней, наземной версии. -->
<passive_effect name="HealthMax" operation="base_set" value="750"/>
</effect_group>
</entity_class>
</append>
<!-- "Дух крысы" (Rat Spirit) - питомец начального уровня, указание 2026-09-18. Первый
питомец, у которого поведение задано НАМЕРЕННО, а не унаследовано: на нём и отлаживается
ИИ питомцев вообще (см. разбор в BACKLOG.md от 2026-09-18).
МОДЕЛЬ. Extends necroZombieWolf, то есть тот же самый ванильный префаб лютоволка, только
SizeScale с 1.4 на 0.28 - "уменьшить в 5 раз". Хитбокс отдельно задавать НЕ НАДО и брать
кроличий НЕЛЬЗЯ: коллайдеры в physicsbodies.xml привязаны к костям по имени пути, а риг
кролика с волчьим не совпадает (у кролика корпус Hips/LowerBack/Spine1 и голова под
Spine2/Neck/Head, у волка Hips/LowerBack/Spine/Spine1/Spine2 и голова под Neck/Neck1/Head)
- кроличье тело нашло бы на волчьей модели только таз и ноги, а корпус и голова остались
бы вообще без хитбокса. Унаследованный PhysicsBody="AWolf" при этом ужимается сам:
Entity.SetScale ставит ModelTransform.localScale, а костяные коллайдеры лежат внутри него.
ЗВУКИ - кроличьи ("он тоже грызун"). На АТАКУ поставлен rabbitpain: это буквально вопль
кролика от боли, и он же остаётся на SoundHurt - крыса вопит и когда кусает, и когда бьют
её. Остальные звуки ГЛУШАТСЯ ПУСТЫМИ НАМЕРЕННО: у animalRabbit нет ни roam, ни alert, ни
sense, ни giveup, и если их не погасить, крыса унаследует волчьи от necroZombieWolf -
ровно те грабли, что дали "зомбомедведь лает" (см. necroZombieBear выше). Дух рыщет молча.
ИИ. Здесь снято ВСЁ, что питомцы до сих пор тащили от враждебного зомбопса:
- нет BreakBlock и BlockingTargetTask - крыса физически не может грызть блоки, и это же
продублировано в коде (EAINecroFollowOwner зовёт FindPath с canBreak:false). Упёршись
в препятствие, дух проходит СКВОЗЬ него - см. Entity.IsStuck в PetFollowTask.cs;
- нет Territorial, ApproachSpot и Wander - крыса не бродит сама, она ходит за хозяином
(задача следования добавляется в рантайме из SummonPatch.cs, отдельным классом, потому
что задачи "иди за сущностью" в игре нет вовсе - все 32 типа EAI* проверены);
- нет SetNearestCorpseAsTarget - она не бросает хозяина ради ближайшего трупа;
- AITarget-1 оставлен ТОЛЬКО как ответ на удар, и список классов без EntityPlayer:
крыса огрызается на зомби и враждебных зверей, но никогда на хозяина, даже если он
заденет её в свалке (прямое указание 2026-09-18).
Сама она цель не ВЫБИРАЕТ никогда: SetNearestEntityAsTarget здесь нет, а AITarget-2
пустой обрывает перебор (CopyPropertiesFromEntityClass идёт по индексам и встаёт на первом
пустом - тем же приёмом ваниль глушит задачи у animalInsectSwarm). Цель приходит снаружи:
по команде игрока из PetCommandPatch.cs.
class=EntityAlive в AITask-1 - это НЕ "бей всё живое" само по себе, а разрешение задаче
подхватить ту цель, которую ей дали (EAIApproachAndAttackTarget.CanExecute сверяет тип
цели с этим списком и без совпадения просто не запускается). Кого можно назначить целью,
решает PetCommandPatch.cs, и торговец там отсеян. -->
<append xpath="/entity_classes">
<entity_class name="necroRatSpirit" extends="necroZombieWolf">
<property name="SizeScale" value="0.28"/>
<property name="Mass" value="33"/>
<property name="Weight" value="11"/>
<property name="Tags" value="entity,animal,rat"/>
<property name="HandItem" value="necroMeleeHandRatSpirit"/>
<property name="SoundRandom" value=""/>
<property name="SoundAlert" value=""/>
<property name="SoundSense" value=""/>
<property name="SoundGiveUp" value=""/>
<property name="SoundHurt" value="rabbitpain"/>
<property name="SoundDeath" value="rabbitdeath"/>
<property name="SoundAttack" value="rabbitpain"/>
<property name="SoundStepType" value="animallightstep"/>
<!-- Жёлтая метка на карте и компасе - указание 2026-09-18. Класс метки наш,
Config/nav_objects.xml; ванильные animaltracking_* не подошли, они завязаны
на перк следопыта, а не на прямое назначение. -->
<property name="NavObject" value="necroRatSpiritPet"/>
<property name="AITask-1" value="ApproachAndAttackTarget" data="class=EntityAlive,0"/>
<property name="AITask-2" value="Look"/>
<property name="AITask-3" value=""/>
<property name="AITarget-1" value="SetAsTargetIfHurt" data="class=EntityZombie,EntityEnemyAnimal"/>
<property name="AITarget-2" value=""/>
<effect_group name="Base Effects">
<!-- Дух-разведчик, а не танк: меньше собаки (200). Урон у неё и так 5. -->
<passive_effect name="HealthMax" operation="base_set" value="120"/>
</effect_group>
</entity_class>
</append>
<!-- "Жертва" loot bag - BACKLOG.md item 5, Necromancer's Knife. Same shape as vanilla's own
EntityLootContainerStrong ("BLUE")/EntityLootContainerBoss ("RED") right above these in
Data/Config/entityclasses.xml - only the Mesh and LootList differ.