Урна-цинерарий: своя модель, свечение по черепу, кровь в рецепте

Модель (бандл necrocinerarium, BlenderWork/necroCinerarium/make_urn.py):
тело вращения в чёрной глазури, по четырём сторонам - вдавленные лицевые
части черепа, наклонённые вниз; руны старшего футарка кровью «SERVU ĜIS
LA LASTA CINDRO» («Служи до последнего пепла»), меандр на ножке, бусины на
шейке, пояс черепов в двух линиях. Руны тлеют красным, глазницы светятся
фиолетовым, только когда в урне череп (_EmissionColor через
MaterialPropertyBlock). Своя иконка. Коллайдер-тег - DecorColliderTagPatch.
Дух: выше на 10 см и на 7 см вперёд в своей системе (хвост не вылезает
сзади), necrogenie fwd. Рецепт: + кровь некроманта, копия на соке розы.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-16 17:37:13 +03:00
co-authored by Claude Opus 5.5
parent 94bf0a5f5c
commit 9f813bb699
8 changed files with 63 additions and 11 deletions
+6 -3
View File
@@ -518,7 +518,9 @@
Составной блок, как земельный камень: TEFeatureStorage - сумка духа (окно хранилища 6x2, «Открыть»),
TEFeatureCinerarium (HarmonySrc/Cinerarium.cs) - череп (положить/забрать), показ зоны 5x5, -1..+4,
лимит ceil(убийств / 500) и запрет пересечения зон при постановке. Всё - в радиальном меню на E (решение 16.10).
Модель и иконка ВРЕМЕННЫЕ - кастрюля игры; своя урна будет из Blender. -->
Модель (16.10) - своя: бандл necrocinerarium (BlenderWork/necroCinerarium, make_urn.py): чёрная глазурь, черепа по
четырём сторонам, руны футарка кровью «SERVU ĜIS LA LASTA CINDRO», меандр, бусины; свечение рун и глазниц
включает TEFeatureCinerarium по черепу. Иконка - рендер той же модели (make_icon.py). -->
<append xpath="/blocks">
<block name="necroCinerarium">
<property name="CreativeMode" value="Player"/>
@@ -536,8 +538,9 @@
</property>
<property name="Material" value="Mstone"/>
<property name="Shape" value="ModelEntity"/>
<property name="Model" value="@:Other/Items/Crafting/cookingPot_01Prefab.prefab"/>
<property name="CustomIcon" value="toolCookingPot"/>
<property name="Model" value="#@modfolder(NecromancerTome):Resources/necrocinerarium?necroCinerariumPrefab.prefab"/>
<property name="ModelOffset" value="0,0,0"/> <!-- меш стоит основанием на y=0; без этого ModelEntity поднимает на полклетки -->
<property name="CustomIcon" value="necroCinerarium"/>
<property name="WaterFlow" value="permitted"/>
<property name="OnlySimpleRotations" value="true"/>
<property name="Collide" value="movement,melee,bullet,arrow,rocket"/>
+9 -1
View File
@@ -606,12 +606,20 @@
</recipe>
</append>
<!-- Урна-цинерарий (1.7.0, 16.10): конец Адепта - уровень 15, 300 убийств (решение 06.10). Состав - черновой. -->
<!-- Урна-цинерарий (1.7.0, 16.10): конец Адепта - уровень 15, 300 убийств (решение 06.10). Кровь - 16.10: «Да, кровью» (руны на урне расписаны кровью некроманта). -->
<append xpath="/recipes">
<recipe name="necroCinerarium" count="1" tags="learnable,packMuleCrafting,necroNecromancyLvl300">
<ingredient name="resourceClayLump" count="30"/>
<ingredient name="resourceZombieAsh" count="100"/>
<ingredient name="resourceBone" count="10"/>
<ingredient name="resourceNecromancerBlood" count="1"/>
</recipe>
<!-- Копия на соке чёрной розы (правило 05.10: у каждого рецепта на крови - копия; одна банка крови = одна банка сока). -->
<recipe name="necroCinerarium" count="1" tags="learnable,packMuleCrafting,necroNecromancyLvl300">
<ingredient name="resourceClayLump" count="30"/>
<ingredient name="resourceZombieAsh" count="100"/>
<ingredient name="resourceBone" count="10"/>
<ingredient name="resourceNecroBlackRoseJuice" count="1"/>
</recipe>
</append>
</config>
+32
View File
@@ -245,6 +245,7 @@ namespace NecromancerTome
/// <summary>_sound - череп только что положили или вынули (порыв); при загрузке чанка дух появляется молча.</summary>
public void SyncGenie(bool _sound)
{
SyncGlow();
if (HasSkull && _genie == null)
{
_genie = CinerariumGenie.Spawn(ModelTransform());
@@ -259,6 +260,37 @@ namespace NecromancerTome
}
}
/// <summary>Руны кровью и глазницы черепов светятся, только когда в урне череп (16.10): _EmissionColor через
/// MaterialPropertyBlock на рендерерах модели урны (материал общий не трогается), духа не задевает.</summary>
public static Color GlowColor = new Color(2.2f, 2.2f, 2.2f, 1f);
static readonly MaterialPropertyBlock _glowBlock = new MaterialPropertyBlock();
static readonly int EmissionColorId = Shader.PropertyToID("_EmissionColor");
int _glowState = -1; // -1 - не ставили на эту модель
void SyncGlow()
{
Transform t = ModelTransform();
int want = HasSkull ? 1 : 0;
if (t == null || (_glowState == want && _glowModel == t))
{
return;
}
foreach (Renderer r in t.GetComponentsInChildren<Renderer>(true))
{
if (_genie != null && r.transform.IsChildOf(_genie.transform) || _bounds != null && r.transform.IsChildOf(_bounds.transform))
{
continue;
}
r.GetPropertyBlock(_glowBlock);
_glowBlock.SetColor(EmissionColorId, HasSkull ? GlowColor : Color.black);
r.SetPropertyBlock(_glowBlock);
}
_glowState = want;
_glowModel = t;
}
Transform _glowModel;
void RemoveGenie(bool _sound)
{
if (_genie == null)
+15 -6
View File
@@ -22,8 +22,13 @@ namespace NecromancerTome
{
public const string ModelPath = "#@modfolder(NecromancerTome):Resources/necrotechnologist?necroTechnologistPrefab.prefab";
/// <summary>Высота корня модели над низом блока урны, м (кончик хвоста в модели - на 0.45 м). Подгоняется командой necrogenie.</summary>
public static float OffsetY = -0.25f;
/// <summary>Высота корня модели над низом блока урны, м. 16.10 в Blender по модели урны: -0.15 («духа чуть приподними»).
/// Подгоняется командой necrogenie.</summary>
public static float OffsetY = -0.15f;
/// <summary>Сдвиг вперёд в системе самого духа, м (16.10: «чуть вперёд, чтобы хвост не просвечивал сквозь урну сзади»
/// - загнутый назад кончик хвоста; в Blender 0.06 - ни одной вершины за стенкой, взято 0.07). Поворачивается вместе
/// с духом, поэтому хвост всегда в горлышке. Знак проверить в игре: necrogenie fwd.</summary>
public static float Forward = 0.07f;
/// <summary>Поворот без работы, градусов в секунду.</summary>
public static float TurnSpeed = 6f;
/// <summary>Покачивание: размах (м) и период (с).</summary>
@@ -203,14 +208,14 @@ namespace NecromancerTome
{
return; // замер как был
}
Vector3 home = new Vector3(0f, CinerariumGenie.OffsetY, 0f);
float yawTarget = _yaw + CinerariumGenie.TurnSpeed * Time.deltaTime;
Vector3 home = new Vector3(0f, CinerariumGenie.OffsetY, 0f) + Quaternion.Euler(0f, _yaw, 0f) * new Vector3(0f, 0f, CinerariumGenie.Forward);
if (_visitLeft > 0f)
{
// Туда и обратно по синусу: на полпути - над местом работы, лицом к нему.
_visitLeft -= Time.deltaTime;
float k = Mathf.Sin(Mathf.Clamp01(1f - _visitLeft / VisitSeconds) * Mathf.PI);
Vector3 over = _visit + new Vector3(0f, CinerariumGenie.OffsetY + 0.6f, 0f);
Vector3 over = _visit + new Vector3(0f, CinerariumGenie.OffsetY + 0.6f, 0f) + Quaternion.Euler(0f, _yaw, 0f) * new Vector3(0f, 0f, CinerariumGenie.Forward);
transform.localPosition = Vector3.Lerp(home, over, k);
Vector3 d = _visit - home;
if (d.x * d.x + d.z * d.z > 0.01f)
@@ -252,7 +257,8 @@ namespace NecromancerTome
public override string getHelp()
{
return "necrogenie - show the current values and how many spirits are on screen\n" +
"necrogenie y <m> - model root height above the urn block's bottom (tail tip is 0.45 m above the root)\n" +
"necrogenie y <m> - model root height above the urn block's bottom (tail tip is 0.47 m above the root)\n" +
"necrogenie fwd <m> - shift along the spirit's own forward (keeps the curled tail inside the neck)\n" +
"necrogenie turn <deg/s> - idle turning speed\n" +
"necrogenie bob <m> <s> - bobbing height and period\n" +
"necrogenie alpha <0-1> - body opacity";
@@ -268,6 +274,9 @@ namespace NecromancerTome
case "y":
CinerariumGenie.OffsetY = v;
break;
case "fwd":
CinerariumGenie.Forward = v;
break;
case "turn":
CinerariumGenie.TurnSpeed = v;
break;
@@ -287,7 +296,7 @@ namespace NecromancerTome
return;
}
}
con.Output("necrogenie: y " + CinerariumGenie.OffsetY.ToString("F2") + ", turn " + CinerariumGenie.TurnSpeed.ToString("F1") +
con.Output("necrogenie: y " + CinerariumGenie.OffsetY.ToString("F2") + ", fwd " + CinerariumGenie.Forward.ToString("F2") + ", turn " + CinerariumGenie.TurnSpeed.ToString("F1") +
", bob " + CinerariumGenie.BobHeight.ToString("F2") + " / " + CinerariumGenie.BobPeriod.ToString("F1") + " s, alpha " +
CinerariumGenie.Alpha.ToString("F2") + "; spirits on screen: " + CinerariumGenie.Live.Count);
}
+1 -1
View File
@@ -20,7 +20,7 @@ namespace NecromancerTome
static bool Ours(string _name)
{
return _name == "necroBookMindPrefab" || _name == "necroKnifeDecorPrefab" || _name == "necroMortarPrefab" || _name.StartsWith("necroBloodRose") || _name.StartsWith("necroPoster") || _name == "necroBookDoorPrefab" || _name.StartsWith("necroSkullDecor");
return _name == "necroBookMindPrefab" || _name == "necroKnifeDecorPrefab" || _name == "necroMortarPrefab" || _name.StartsWith("necroBloodRose") || _name.StartsWith("necroPoster") || _name == "necroBookDoorPrefab" || _name.StartsWith("necroSkullDecor") || _name == "necroCinerariumPrefab";
}
public static void Postfix(Transform __result)
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB