ИИ питомцев переписан, добавлен Дух крысы, пороги разнесены по шкале
Работа по указаниям 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:
co-authored by
Claude Opus 5
parent
15c59dd37a
commit
d97f83e972
@@ -0,0 +1,235 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NecromancerTome
|
||||
{
|
||||
/// <summary>
|
||||
/// СВЕТЯЩИЕСЯ ГЛАЗА у призванных зомбоживотных - указание 2026-09-18: "псу и волку сделай,
|
||||
/// глаза светлофиолетовые светящиеся".
|
||||
///
|
||||
/// ПОЧЕМУ ТОЛЬКО ДВОЕ, И ЭТО НЕ ВЫБОР, А ОГРАНИЧЕНИЕ МОДЕЛЕЙ. Покрасить глаза отдельно можно
|
||||
/// ровно тогда, когда они лежат ОТДЕЛЬНЫМ материалом. Проба шейдеров, которую печатает
|
||||
/// GhostTraderPatch, показала по питомцам такую картину:
|
||||
///
|
||||
/// necroZombieDog - 5 рендереров: FeralEye, NormalEye, LOD0..LOD2 - ГОДИТСЯ
|
||||
/// necroZombieWolf - 2 рендерера: DireWolf + DireWolfHair - НЕ ГОДИТСЯ
|
||||
/// necroZombieBear - 1 рендерер - НЕ ГОДИТСЯ
|
||||
/// necroZombieGriffin - 1 рендерер - НЕ ГОДИТСЯ
|
||||
///
|
||||
/// ПО ВОЛКУ ОТВЕТ ОКОНЧАТЕЛЬНЫЙ И ОТРИЦАТЕЛЬНЫЙ, по дампу 18.09:
|
||||
///
|
||||
/// DireWolf[0] shader='Game/Animal/Fur' texture=dire_wolf_df _Color=False
|
||||
/// DireWolfHair[0] shader='Game/SDCS/Hair' texture=Afro_normal _Color=False
|
||||
///
|
||||
/// Глазного рендерера у него НЕТ ВООБЩЕ - только шкура и шерсть, глаза запечены прямо в
|
||||
/// dire_wolf_df. Ни отдельного материала, ни даже _Color, чтобы хоть что-то подкрасить.
|
||||
/// Единственный оставшийся путь - править саму текстуру по пикселям, зная координаты глаз на
|
||||
/// развёртке. Поэтому LitEyes у Волка снят: пусть флаг не обещает того, чего нет.
|
||||
///
|
||||
/// У Медведя и Грифа материал один на всю модель, и отдельно глаза там не достать ничем,
|
||||
/// кроме правки самой текстуры по пикселям. Поэтому их в списке нет - см. PetInfo.LitEyes.
|
||||
///
|
||||
/// КРАСИТСЯ СВЕЧЕНИЕ, А НЕ ЦВЕТ. У зомби глаза светятся сами (_EmissionMap у этого материала
|
||||
/// уже назначена), и именно свечение читается как "горящие глаза". Поэтому ставится
|
||||
/// _EmissionColor, а _Color правится следом только чтобы радужка не спорила с ним при ярком
|
||||
/// дневном свете. Ключевое слово _EMISSION включается явно: материал, собранный без эмиссии,
|
||||
/// игнорирует _EmissionColor, пока оно выключено, - ровно тот же класс ловушки, что с
|
||||
/// _SrcBlend/_Mode у прозрачности (см. ApplyTransparency в GhostTraderPatch.cs).
|
||||
///
|
||||
/// ПОЧЕМУ ЭТО ТИК, А НЕ ХУК НА ПРИЗЫВ. Материалы появляются вместе с моделью, а она
|
||||
/// собирается ПОЗЖЕ создания сущности - это уже дважды стоило нам ошибок: сначала
|
||||
/// GhostTraderPatch пришлось перевести на опрос из-за трейдеров, потом
|
||||
/// TryIgnoreCollisionWithOwner из-за того, что коллайдеров в момент CreateEntity ещё нет.
|
||||
/// Здесь та же природа, поэтому сразу попытка с повтором: раз в секунду, до первого успеха,
|
||||
/// из общего тика в PetFollowPatch.
|
||||
/// </summary>
|
||||
public static class PetEyeGlow
|
||||
{
|
||||
/// <summary>Фиолетовый, НАСЫЩЕННЫЙ. Первая версия была светлой (0.72, 0.55, 1.0) и в игре
|
||||
/// дала ровно то, о чём сказал пользователь: "у собаки глаза просто белые".
|
||||
///
|
||||
/// Причина арифметическая: _EmissionColor читается как HDR, цвет умножается на яркость.
|
||||
/// При множителе 6 светлый фиолетовый превращался в (4.3, 3.3, 6.0) - все три канала
|
||||
/// далеко за единицей, и тонемаппинг сводил их в белое пятно. Оттенок выживает только
|
||||
/// когда каналы РАСХОДЯТСЯ: отсюда низкий зелёный и умеренная яркость ниже.</summary>
|
||||
public static readonly Color EyeColour = new Color(0.55f, 0.18f, 1f);
|
||||
|
||||
/// <summary>ПОДНЯТО С 2.4 ДО 6 после первой проверки: "у собаки они вообще никак не
|
||||
/// светятся". Цвет сменился (это видно), а свечения нет - значит либо _EmissionColor у
|
||||
/// этого шейдера читается как HDR и 2.4 для него ничто, либо свечение вообще идёт не
|
||||
/// отсюда. Шесть - это попытка проверить первое предположение, а чтобы проверить второе,
|
||||
/// рядом добавлен разовый дамп всех материалов питомца (DumpMaterialsOnce).</summary>
|
||||
/// <summary>1.6, а не 6: см. комментарий к EyeColour - на шести глаза выгорали в белый.
|
||||
/// Итоговое свечение (0.88, 0.29, 1.6): синий вдвое выше красного и вшестеро выше
|
||||
/// зелёного, так что фиолетовый читается, а не тонет в пересвете.</summary>
|
||||
public const float EmissionIntensity = 1.6f;
|
||||
|
||||
/// <summary>Классы, по которым дамп уже печатался: он нужен один раз на вид, а не на
|
||||
/// каждого призванного.</summary>
|
||||
public static readonly System.Collections.Generic.HashSet<string> Dumped =
|
||||
new System.Collections.Generic.HashSet<string>();
|
||||
|
||||
/// <summary>ДИАГНОСТИКА, добавлена 2026-09-18. Первая попытка зажечь глаза дала половину
|
||||
/// результата: у Пса цвет сменился, но свечения нет, а у Волка не изменилось ничего -
|
||||
/// значит материала с "eye" в имени текстуры у него просто не нашлось. Гадать дальше
|
||||
/// дороже, чем один раз посмотреть: этот дамп печатает по каждому виду все рендереры, их
|
||||
/// материалы, шейдеры, имена текстур и наличие свойств свечения. По нему и будет видно,
|
||||
/// за что хвататься - и надо ли вообще.</summary>
|
||||
public static void DumpMaterialsOnce(Entity _pet, string _className)
|
||||
{
|
||||
if (_className == null || !Dumped.Add(_className))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Renderer[] renderers = _pet.GetComponentsInChildren<Renderer>(true);
|
||||
Debug.Log("[NecromancerTome] PetEyeGlow: ДАМП материалов " + _className + " - " +
|
||||
(renderers != null ? renderers.Length : 0) + " рендерер(ов)");
|
||||
if (renderers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (Renderer renderer in renderers)
|
||||
{
|
||||
if (renderer == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Material[] mats = renderer.sharedMaterials;
|
||||
for (int i = 0; mats != null && i < mats.Length; i++)
|
||||
{
|
||||
Material m = mats[i];
|
||||
if (m == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string albedo = GhostTraderPatch.FindAlbedoProperty(m);
|
||||
Texture tex = albedo != null ? m.GetTexture(albedo) : null;
|
||||
Debug.Log("[NecromancerTome] PetEyeGlow: " + renderer.name + "[" + i + "] shader='" +
|
||||
(m.shader != null ? m.shader.name : "null") + "' albedo=" + (albedo ?? "-") +
|
||||
" texture=" + (tex != null ? tex.name : "-") +
|
||||
" _EmissionColor=" + m.HasProperty("_EmissionColor") +
|
||||
" _EmissionMap=" + (m.HasProperty("_EmissionMap") && m.GetTexture("_EmissionMap") != null) +
|
||||
" _EmissionIntensity=" + m.HasProperty("_EmissionIntensity") +
|
||||
" _Color=" + m.HasProperty("_Color"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>ПЕРЕПИСАНО 2026-09-18 ПО ДАМПУ. Первая версия искала материал по имени
|
||||
/// ТЕКСТУРЫ ("eye"), нашла у собаки ровно один и зажгла его - а глаза всё равно не
|
||||
/// светились. Дамп показал, почему:
|
||||
///
|
||||
/// FeralEye[0] shader='Game/Autodesk' texture=feral_eye _EmissionMap=True
|
||||
/// NormalEye[0] shader='Standard' texture=HD_ZombieDog _EmissionMap=False
|
||||
/// LOD0..LOD2 shader='Standard' texture=HD_ZombieDog
|
||||
///
|
||||
/// Глаз у собаки ДВА РАЗНЫХ, отдельными рендерерами. Светящийся feral - тот, что горит у
|
||||
/// разъярённой собаки, и в обычном состоянии он не показывается; именно его мы и зажгли,
|
||||
/// не увидев ничего. А обычный глаз - NormalEye - берёт текстуру ТУШКИ (HD_ZombieDog),
|
||||
/// поэтому поиск по имени текстуры его пропускал.
|
||||
///
|
||||
/// Поэтому теперь глаз опознаётся по имени РЕНДЕРЕРА, а имя текстуры оставлено как
|
||||
/// запасной признак. Материал у NormalEye свой собственный, так что правка цвета и
|
||||
/// свечения на нём затрагивает только глаз, хотя текстура и общая с телом.</summary>
|
||||
public static bool IsEyeRenderer(Renderer _renderer)
|
||||
{
|
||||
if (_renderer == null || _renderer is ParticleSystemRenderer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (_renderer.name != null && _renderer.name.ToLower().Contains("eye"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
Material[] shared = _renderer.sharedMaterials;
|
||||
if (shared == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (Material m in shared)
|
||||
{
|
||||
if (IsEyeMaterial(m))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Запасной признак: текстура с "eye" в имени (у собаки это feral_eye).</summary>
|
||||
public static bool IsEyeMaterial(Material _material)
|
||||
{
|
||||
if (_material == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string albedo = GhostTraderPatch.FindAlbedoProperty(_material);
|
||||
if (albedo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Texture texture = _material.GetTexture(albedo);
|
||||
return texture != null && texture.name != null &&
|
||||
texture.name.ToLower().Contains("eye");
|
||||
}
|
||||
|
||||
/// <summary>true, только если глаза действительно нашлись и были подожжены. Пока false,
|
||||
/// тик повторяет попытку - модель может быть ещё не собрана.</summary>
|
||||
public static bool TryLightEyes(Entity _pet)
|
||||
{
|
||||
if (_pet == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Renderer[] renderers = _pet.GetComponentsInChildren<Renderer>(true);
|
||||
if (renderers == null || renderers.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int lit = 0;
|
||||
foreach (Renderer renderer in renderers)
|
||||
{
|
||||
if (!IsEyeRenderer(renderer))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Рендерер целиком глазной, поэтому красим ВСЕ его материалы: мешу глаза больше
|
||||
// ничего не принадлежит, а вот у собаки их два (обычный и feral), и попасть надо
|
||||
// в оба - какой из них покажется, решает сама игра.
|
||||
Material[] instances = renderer.materials;
|
||||
foreach (Material eye in instances)
|
||||
{
|
||||
if (eye == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (eye.HasProperty("_EmissionColor"))
|
||||
{
|
||||
eye.EnableKeyword("_EMISSION");
|
||||
eye.globalIlluminationFlags = MaterialGlobalIlluminationFlags.RealtimeEmissive;
|
||||
eye.SetColor("_EmissionColor", EyeColour * EmissionIntensity);
|
||||
if (eye.HasProperty("_EmissionIntensity"))
|
||||
{
|
||||
eye.SetFloat("_EmissionIntensity", EmissionIntensity);
|
||||
}
|
||||
lit++;
|
||||
}
|
||||
if (eye.HasProperty("_Color"))
|
||||
{
|
||||
Color tint = eye.GetColor("_Color");
|
||||
eye.SetColor("_Color", new Color(EyeColour.r, EyeColour.g, EyeColour.b, tint.a));
|
||||
}
|
||||
}
|
||||
Debug.Log("[NecromancerTome] PetEyeGlow: рендерер глаз '" + renderer.name + "', материалов " +
|
||||
instances.Length);
|
||||
}
|
||||
|
||||
if (lit > 0)
|
||||
{
|
||||
Debug.Log("[NecromancerTome] PetEyeGlow: pet " + _pet.entityId + " - " + lit +
|
||||
" eye material(s) lit");
|
||||
}
|
||||
return lit > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user