Files
necromants-tome-7d2d-3-2/Config/entityclasses.xml
T
Alex CubeandClaude Opus 5 e8f064f5ec Книга некроманта 1.0 — первая публичная версия
Мод для 7 Days to Die 3.2: навык «Некромантия», растущий от счётчика убитых
зомби, тёмное оружие с шестью собственными модами, призывная нежить, пирамида
духов и сюжетный финал через Чёрный портал. Локализация на 13 языках.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MaNro5hAGTzcQ7rJNN2tCX
2026-09-09 21:13:03 +03:00

285 lines
19 KiB
XML

<config>
<!-- Step 1: lifetime zombie kill counter.
zombieTemplateMale is the root template every zombie entity_class extends
(directly, or indirectly via zombieTemplateShort), so patching it here covers
every zombie variant in the game without listing them individually. -->
<append xpath="/entity_classes/entity_class[@name='zombieTemplateMale']">
<effect_group>
<requirement name="EntityTagCompare" target="other" tags="player"/>
<triggered_effect trigger="onOtherKilledSelf" action="ModifyCVar" target="other" cvar="necroZombieKillsCVar" operation="add" value="1"/>
<!-- "Некромантия" skill: +1 level per zombie kill, capped by its own max_level.
See progression.xml for why this drives the skill instead of reading books. -->
<triggered_effect trigger="onOtherKilledSelf" action="AddProgressionLevel" target="other" progression_name="craftingNecroNecromancy" level="1"/>
</effect_group>
</append>
<!-- "Зомбособака" (Zombie Dog pet): BACKLOG.md item 3. Extends the vanilla hostile
animalZombieDog (same prefab/physics/sounds - a real zombie dog model, not a reskinned
wolf) but flips it to fight FOR the player instead of against them:
- EntityFlags drops "zombie": EntityAlive.DamageEntity has a hardcoded rule that two
entities BOTH flagged EntityFlags.Zombie can never damage each other (see
HarmonySrc/DamagePatch.cs for the same rule affecting charmed zombies) - keeping our
pet flagged "zombie" would make it literally unable to hurt real zombies. Dropping the
flag sidesteps that block entirely; no Harmony damage patch needed here, unlike the
charmed-zombie case (which can't drop the flag without breaking its own zombie-side
kill-counter/quest logic - our pet has none of that to worry about).
- Tags drops "zombie"/"hostile" (kept "entity,animal,dog"), IsEnemyEntity="false" - same
shape vanilla's own player-owned entityJunkDrone uses for "friendly to the player".
- AITask-3/AITarget-1/AITarget-4 retarget from EntityPlayer/EntityBandit to EntityZombie -
purely data-driven, same AI task types animalZombieDog already used, just pointed at a
different class. This is also exactly how HarmonySrc/CharmPatch.cs flips a charmed
zombie's allegiance at runtime - confirmed here that the underlying AI system doesn't
care whether the retarget happens via live Harmony rewrite or via XML at spawn time.
Spawned by HarmonySrc/SummonPatch.cs via item bookSummonZombieDog (items.xml) - see that
file for the ownership/one-pet-limit logic (mirrors vanilla's own drone: EntityDrone.
isValidForPlayer() blocks summoning a second one while you already own one, rather than
replacing the old one - SummonPatch.cs does the same check via ownedEntities). -->
<append xpath="/entity_classes">
<entity_class name="necroZombieDog" extends="animalZombieDog">
<property name="EntityFlags" value="animal"/>
<property name="Tags" value="entity,animal,dog"/>
<property name="IsEnemyEntity" value="false"/>
<property name="Faction" value="none"/>
<!-- User request 2026-08-28: bite applies buffInjurySlow, same debuff the Insect Swarm
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"/>
</entity_class>
</append>
<!-- "Жуки Властелина" (insect swarm pet): user request 2026-08-28, alongside the Zombie Dog
bugfix (see items.xml). Extends vanilla's own animalInsectSwarm (same prefab/sounds/
tanky-vs-melee stats - PhysicalDamageResist 75% vs non-ranged inherits unchanged, a nice
free defensive fit for something meant to be swarmed by zombie melee).
BUG FIXED 2026-08-28 (swarm attacked the PLAYER, not zombies): the original version here
overrode AITask-1/AITarget-1, mirroring animalInsectSwarm's own choice to blank those two
indices - but animalInsectSwarm extends animalTemplateHostile, and re-reading THAT
template (Data/Config/entityclasses.xml) shows the actual player-attacking task/target
live at DIFFERENT indices: AITask-2 ("ApproachAndAttackTarget" class=EntityPlayer,...) and
AITarget-4 ("SetNearestEntityAsTarget" class=EntityPlayer,...). animalInsectSwarm's
AITask-1/AITarget-1 blanking only wipes animalTemplateHostile's harmless AITask-1
(BreakBlock) and AITarget-1 (SetAsTargetIfHurt, generic) - the real player-hunting
behavior at index 2/4 was never touched by that blanking, and my override at index 1
just sat next to it as a no-op extra task while the REAL one kept targeting players.
Fixed by overriding the actual indices (2 and 4) instead. AITask-1/AITarget-1 are left
alone now - they inherit animalInsectSwarm's own blank override, same as vanilla.
BEHAVIOR CHANGE 2026-08-28 (user request): no longer deals real damage + slows zombies -
it stings a zombie once and that zombie becomes a Deviator-charmed ally, same buff as the
Spirit Stone/Grimoire (buffNecroDeviatorCharm - see necroMeleeHandInsectSwarm in
items.xml). Search range widened (22/20 -> 40/30) per "ищут всех зомби в радиусе", though
that number turned out not to matter much either - see below.
TARGETING IS NOT ACTUALLY DRIVEN BY THESE AITask/AITarget PROPERTIES AT ALL, despite the
fix above (found out the hard way 2026-08-28, after that fix didn't stop the swarm from
attacking the player): animalInsectSwarm's own Class="EntitySwarm" extends EntityVulture,
which has entirely hardcoded C# target-finding (World.GetClosestPlayerSeen/GetClosestPlayer,
literally typed to EntityPlayer) - it never consults the declarative AITask/AITarget system
ground creatures like the Dog use. The AITask-2/AITarget-4 overrides above are harmless but
functionally dead for this entity_class. The real fix is HarmonySrc/SwarmTargetPatch.cs,
patching EntityAlive.SetAttackTarget to redirect player-targeting to the nearest zombie -
see that file. It also skips zombies that already carry buffNecroDeviatorCharm (added after
a second user report that the swarm would fly off in wide loops instead of moving straight
to an uncharmed zombie standing right next to the one it had just charmed - re-targeting
the same just-charmed zombie over and over, because it was still the nearest one, was
exactly what caused that).
EntityFlags/EntityType: parent sets EntityFlags="animal,zombie" and EntityType="Zombie" -
same DamageEntity zombie-vs-zombie block as the dog (see that entry above and
HarmonySrc/DamagePatch.cs) would otherwise stop it stinging real zombies at all, so both
get dropped to plain "animal". -->
<append xpath="/entity_classes">
<entity_class name="necroInsectSwarm" extends="animalInsectSwarm">
<property name="EntityFlags" value="animal"/>
<property name="EntityType" value="Animal"/>
<property name="Tags" value="entity,noHead"/>
<property name="IsEnemyEntity" value="false"/>
<property name="Faction" value="none"/>
<property name="HandItem" value="necroMeleeHandInsectSwarm"/>
<property name="AITask-2" value="ApproachAndAttackTarget" data="class=EntityZombie,20"/>
<property name="AITarget-4" value="SetNearestEntityAsTarget" data="class=EntityZombie,40,30"/>
</entity_class>
</append>
<!-- Three more summon-pet zombies, BACKLOG.md item 4a. REPLACED AGAIN 2026-08-29, THIRD
APPROACH, per the user's own direct suggestion after the second approach's Bear/Wolf
fixes still didn't work ("почему нельзя взять зомбособаку, но добавить её ХП и силы
атаки, и заменить ей модельку на медведя?"). Correct call - stop re-deriving AI/targeting
data from each different vanilla template's own quirky format (full pipe-string vs
indexed properties, different index numbering, etc.) and instead extend the Dog's OWN
entity_class (necroZombieDog, defined above) directly. necroZombieDog already has
EntityFlags/Tags/IsEnemyEntity/Faction AND the AITask-3/AITarget-1/AITarget-4 zombie-
targeting overrides all confirmed working correctly in-game across multiple test rounds -
none of that has to be re-verified or re-derived per creature any more, it's inherited
unchanged. Bear/Wolf below only override what's actually cosmetic/stat-related: Prefab
(swap the visible model), PhysicsBody/Mass (match the new model's real size so
collision/knockback look right), HandItem (reuse the REAL vanilla hand-item for that
creature - meleeHandAnimalZombieBear/meleeHandAnimalDireWolf, both real items with their
own already-tuned damage - 60 each, vs. the Dog's own 8), and HealthMax (bumped up to
match, see each entity's own comment for the exact vanilla reference number used).
Griffin NOT converted this way (left on the previous animalZombieVulture-based approach,
unchanged) - flagged as a real, separate risk, not just left out by oversight: Bear/Wolf
share the Dog's own quadruped body plan/animation rig, so swapping just the Prefab is
low-risk (same skeleton shape, same generic AvatarAnimalController). A vulture is a
bird - almost certainly a structurally different skeleton/rig - forcing that Prefab onto
necroZombieDog's own ground-quadruped C# class (EntityZombieDog, no flight code at all)
risks either a broken/distorted-looking model (mismatched bone names) or, best case, a
"walking bird" that never actually flies. Worth a real decision, not a silent guess -
see BACKLOG.md for the open question. -->
<append xpath="/entity_classes">
<entity_class name="necroZombieBear" extends="necroZombieDog">
<!-- Real vanilla animalZombieBear's own Prefab/PhysicsBody/Mass (the same asset a
genuine zombie bear uses) - not re-deriving AI from it any more, just borrowing
its look and physical size so collision/knockback scale correctly for a
bear-sized model sitting on the Dog's skeleton/rig. -->
<property name="Prefab" value="@:Entities/Animals/Bear/animalBearZombiePrefab.prefab"/>
<property name="PrefabCombined" value="true"/>
<property name="PhysicsBody" value="bear"/>
<property name="Mass" value="600"/>
<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
properties and stayed inherited from necroZombieDog/animalZombieDog (dog barks)
the whole time - same oversight needed fixing on Wolf/Griffin below too, not
just this one. Real animalBear's own sound set (animalZombieBear itself doesn't
override any of these, confirmed by reading it directly - it inherits animalBear's). -->
<property name="SoundRandom" value="bearroam"/>
<property name="SoundAlert" value="bearalert"/>
<property name="SoundHurt" value="bearpain"/>
<property name="SoundDeath" value="beardeath"/>
<property name="SoundAttack" value="bearattack"/>
<property name="SoundSense" value="bearsense"/>
<property name="SoundGiveUp" value="beargiveup"/>
<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"/>
<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. -->
<passive_effect name="HealthMax" operation="base_set" value="1500"/>
</effect_group>
</entity_class>
</append>
<append xpath="/entity_classes">
<entity_class name="necroZombieWolf" extends="necroZombieDog">
<!-- Real vanilla animalDireWolf's own Prefab/PhysicsBody/Mass/SizeScale. -->
<property name="Prefab" value="@:Entities/Animals/DireWolf/animalDireWolfPrefab.prefab"/>
<property name="PrefabCombined" value="true"/>
<property name="PhysicsBody" value="AWolf"/>
<property name="Mass" value="180"/>
<property name="SizeScale" value="1.4"/>
<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. -->
<property name="SoundRandom" value="wolfdireroam"/>
<property name="SoundAlert" value="wolfdirealert"/>
<property name="SoundHurt" value="wolfdirepain"/>
<property name="SoundDeath" value="wolfdiredeath"/>
<property name="SoundAttack" value="wolfdireattack"/>
<property name="SoundSense" value="wolfdiresense"/>
<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"/>
<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. -->
<passive_effect name="HealthMax" operation="base_set" value="1200"/>
</effect_group>
</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).
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. -->
<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"/>
<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. -->
<passive_effect name="HealthMax" operation="base_set" value="750"/>
</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.
BUG FIXED 2026-08-28 ("зомби погиб с бафом, гарантированный дроп запустился, но лута
нет"): Mesh was a guess, zpackGreenPrefab.prefab - confirmed by the in-game test itself
that it doesn't exist as a real asset. VictimPatch.cs's own warning fired: "created entity
for 'EntityLootContainerVictim' wasn't an EntityLootContainer" - EntityFactory.CreateEntity
didn't produce a usable entity at all once its mesh failed to resolve, so nothing ever
got spawned, guaranteed roll or not. Reverted to zpackPrefab.prefab (the default/yellow
mesh, confirmed to exist - every other loot container variant in vanilla config either
uses this one directly or one of the three OTHER confirmed variants, blue/red/gold) per
the fallback plan agreed on before this was ever guessed at - not visually distinct from a
normal zombie drop, but a real, working bag with the right guaranteed contents.
Force-spawned by HarmonySrc/VictimPatch.cs when a zombie with buffNecroVictim dies -
never rolled by the normal LootDropProb/LootDropEntityClass system (not referenced from
any zombie's own entity_class), so its own IsEnemyEntity/Faction/etc. just mirror the
other loot containers for consistency, not because anything reads them via that path. -->
<append xpath="/entity_classes">
<entity_class name="EntityLootContainerVictim">
<property name="Class" value="EntityLootContainer"/>
<property name="UserSpawnType" value="Console"/>
<property name="Mesh" value="@:Entities/LootContainers/zpackPrefab.prefab"/>
<property name="ModelType" value="Custom"/>
<property name="Prefab" value="Backpack"/>
<property name="Parent" value="Backpack"/>
<property name="IsEnemyEntity" value="false"/>
<property name="TimeStayAfterDeath" value="3600"/>
<property name="LootList" value="zPackVictim"/>
<property name="Faction" value="none"/>
</entity_class>
</append>
</config>