Урна-логист - отдельный блок: без зоны (ставится вплотную), нити только к ней, зелёные руны и глазницы, своя иконка; рецепт с набором для шитья, лимит общий
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
adc9371a09
commit
f4ae9cbcb8
File diff suppressed because one or more lines are too long
@@ -560,5 +560,21 @@
|
|||||||
<property name="CreativeMode" value="None"/>
|
<property name="CreativeMode" value="None"/>
|
||||||
<property name="DescriptionKey" value="necroCinerariumDesc"/>
|
<property name="DescriptionKey" value="necroCinerariumDesc"/>
|
||||||
</block>
|
</block>
|
||||||
|
<!-- Урна-логист (16.10.2026): «Я не могу ставить урны рядом. Может нам для логиста вообще сделать отдельные урны?»
|
||||||
|
Без зоны (ставится вплотную к любым урнам), только нити и перевозка (CinerariumThreads.cs), лимит урн общий.
|
||||||
|
Модель - та же; отличие - код (TEFeatureCinerarium.SyncGlow): зелёные руны и глазницы
|
||||||
|
(Resources/necroCinerarium_e_logist.png), зеленоватая глазурь. Иконка - своя (зелёные руны, нити из горлышка).
|
||||||
|
Своя модель логиста - позже, в Blender. -->
|
||||||
|
<block name="necroCinerariumLogist">
|
||||||
|
<property name="Extends" value="necroCinerarium"/>
|
||||||
|
<property name="CreativeMode" value="Player"/>
|
||||||
|
<property name="DescriptionKey" value="necroCinerariumLogistDesc"/>
|
||||||
|
<property name="CustomIcon" value="necroCinerariumLogist"/>
|
||||||
|
</block>
|
||||||
|
<block name="necroCinerariumLogistSkull">
|
||||||
|
<property name="Extends" value="necroCinerariumLogist"/>
|
||||||
|
<property name="CreativeMode" value="None"/>
|
||||||
|
<property name="DescriptionKey" value="necroCinerariumLogistDesc"/>
|
||||||
|
</block>
|
||||||
</append>
|
</append>
|
||||||
</config>
|
</config>
|
||||||
|
|||||||
@@ -181,7 +181,7 @@
|
|||||||
пользуется, вода сидит на necroNecromancyLvl20. -->
|
пользуется, вода сидит на necroNecromancyLvl20. -->
|
||||||
<unlock_entry item="necroModKnifeScavengersFeast,bookSummonRatSpirit" unlock_tier="3"/>
|
<unlock_entry item="necroModKnifeScavengersFeast,bookSummonRatSpirit" unlock_tier="3"/>
|
||||||
<unlock_entry item="necroModKnifeGravesRepose" unlock_tier="4"/>
|
<unlock_entry item="necroModKnifeGravesRepose" unlock_tier="4"/>
|
||||||
<unlock_entry item="necroModKnifeDarkSense,necroCinerarium" unlock_tier="5"/>
|
<unlock_entry item="necroModKnifeDarkSense,necroCinerarium,necroCinerariumLogist" unlock_tier="5"/>
|
||||||
</display_entry>
|
</display_entry>
|
||||||
<!-- Ступенчатая разблокировка внутри группы. ПЕРЕРАСПРЕДЕЛЕНО 2026-09-09: четыре из
|
<!-- Ступенчатая разблокировка внутри группы. ПЕРЕРАСПРЕДЕЛЕНО 2026-09-09: четыре из
|
||||||
шести модов ножа (вода/еда/покой/чутьё) уехали отсюда в группу 1 - см. большой
|
шести модов ножа (вода/еда/покой/чутьё) уехали отсюда в группу 1 - см. большой
|
||||||
|
|||||||
@@ -621,5 +621,20 @@
|
|||||||
<ingredient name="resourceBone" count="10"/>
|
<ingredient name="resourceBone" count="10"/>
|
||||||
<ingredient name="resourceNecroBlackRoseJuice" count="1"/>
|
<ingredient name="resourceNecroBlackRoseJuice" count="1"/>
|
||||||
</recipe>
|
</recipe>
|
||||||
|
<!-- Урна-логист (16.10: «Рецепт с набором для шитья») - рецепт урны и набор для шитья; копия на соке чёрной розы. -->
|
||||||
|
<recipe name="necroCinerariumLogist" 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"/>
|
||||||
|
<ingredient name="resourceSewingKit" count="1"/>
|
||||||
|
</recipe>
|
||||||
|
<recipe name="necroCinerariumLogist" 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"/>
|
||||||
|
<ingredient name="resourceSewingKit" count="1"/>
|
||||||
|
</recipe>
|
||||||
</append>
|
</append>
|
||||||
</config>
|
</config>
|
||||||
|
|||||||
+67
-21
@@ -31,6 +31,16 @@ namespace NecromancerTome
|
|||||||
{
|
{
|
||||||
public const string BlockName = "necroCinerarium";
|
public const string BlockName = "necroCinerarium";
|
||||||
public const string SkullBlockName = "necroCinerariumSkull";
|
public const string SkullBlockName = "necroCinerariumSkull";
|
||||||
|
/// <summary>Урна-логист (16.10: «Я не могу ставить урны рядом. Может нам для логиста вообще сделать отдельные урны?»):
|
||||||
|
/// без зоны - ставится вплотную к любым урнам, только нити и перевозка, глазницы всегда зелёные. Лимит - общий.</summary>
|
||||||
|
public const string LogistBlockName = "necroCinerariumLogist";
|
||||||
|
public const string LogistSkullBlockName = "necroCinerariumLogistSkull";
|
||||||
|
|
||||||
|
public static bool IsLogistBlock(Block _b)
|
||||||
|
{
|
||||||
|
string n = _b?.GetBlockName();
|
||||||
|
return n == LogistBlockName || n == LogistSkullBlockName;
|
||||||
|
}
|
||||||
public const string SkullItemName = "necroSkull";
|
public const string SkullItemName = "necroSkull";
|
||||||
public const int HalfWidth = 2;
|
public const int HalfWidth = 2;
|
||||||
public const int Below = 1;
|
public const int Below = 1;
|
||||||
@@ -44,7 +54,26 @@ namespace NecromancerTome
|
|||||||
public readonly List<Vector3i> ThreadFrom = new List<Vector3i>();
|
public readonly List<Vector3i> ThreadFrom = new List<Vector3i>();
|
||||||
public bool HasThreadTo;
|
public bool HasThreadTo;
|
||||||
public Vector3i ThreadTo;
|
public Vector3i ThreadTo;
|
||||||
public bool IsLogist => HasThreadTo || ThreadFrom.Count > 0;
|
public bool HasThreads => HasThreadTo || ThreadFrom.Count > 0;
|
||||||
|
/// <summary>Урна-логист - по блоку (necroCinerariumLogist / ...Skull); узнаётся при постановке или по миру.</summary>
|
||||||
|
public bool IsLogist
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!_logistKnown)
|
||||||
|
{
|
||||||
|
World w = GameManager.Instance?.World;
|
||||||
|
BlockValue bv = w != null ? w.GetBlock(ToWorldPos()) : BlockValue.Air;
|
||||||
|
if (IsUrn(bv.Block))
|
||||||
|
{
|
||||||
|
_logist = IsLogistBlock(bv.Block);
|
||||||
|
_logistKnown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _logist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool _logist, _logistKnown;
|
||||||
/// <summary>Фильтр логиста: бит на группу CinerariumGroups; по умолчанию все включены.</summary>
|
/// <summary>Фильтр логиста: бит на группу CinerariumGroups; по умолчанию все включены.</summary>
|
||||||
public uint GroupMask = CinerariumGroups.All;
|
public uint GroupMask = CinerariumGroups.All;
|
||||||
|
|
||||||
@@ -76,7 +105,10 @@ namespace NecromancerTome
|
|||||||
public override void OnAdded(Vector3i _blockPos, BlockValue _blockValue)
|
public override void OnAdded(Vector3i _blockPos, BlockValue _blockValue)
|
||||||
{
|
{
|
||||||
base.OnAdded(_blockPos, _blockValue);
|
base.OnAdded(_blockPos, _blockValue);
|
||||||
if (_blockValue.Block?.GetBlockName() == SkullBlockName)
|
_logist = IsLogistBlock(_blockValue.Block);
|
||||||
|
_logistKnown = true;
|
||||||
|
string placed = _blockValue.Block?.GetBlockName();
|
||||||
|
if (placed == SkullBlockName || placed == LogistSkullBlockName)
|
||||||
{
|
{
|
||||||
HasSkull = true; // поставили урну, поднятую с черепом
|
HasSkull = true; // поставили урну, поднятую с черепом
|
||||||
}
|
}
|
||||||
@@ -290,7 +322,14 @@ namespace NecromancerTome
|
|||||||
/// <summary>Нити к убранным ящикам снимаются (раз в 2 с); вид перестраивается после изменений.</summary>
|
/// <summary>Нити к убранным ящикам снимаются (раз в 2 с); вид перестраивается после изменений.</summary>
|
||||||
void SyncThreads(World _world)
|
void SyncThreads(World _world)
|
||||||
{
|
{
|
||||||
if (_world != null && ConnectionManager.Instance.IsServer && IsLogist && Time.time >= _nextThreadCheck)
|
if (_world != null && ConnectionManager.Instance.IsServer && HasThreads && !IsLogist && _logistKnown)
|
||||||
|
{
|
||||||
|
Debug.Log("[NecromancerTome] Cinerarium: нити у обычной урны " + ToWorldPos() + " сняты - нити только у урны-логиста");
|
||||||
|
ThreadFrom.Clear();
|
||||||
|
HasThreadTo = false;
|
||||||
|
ThreadsChanged();
|
||||||
|
}
|
||||||
|
if (_world != null && ConnectionManager.Instance.IsServer && HasThreads && Time.time >= _nextThreadCheck)
|
||||||
{
|
{
|
||||||
_nextThreadCheck = Time.time + 2f;
|
_nextThreadCheck = Time.time + 2f;
|
||||||
bool gone = false;
|
bool gone = false;
|
||||||
@@ -316,7 +355,7 @@ namespace NecromancerTome
|
|||||||
ThreadsChanged();
|
ThreadsChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!_threadsDirty && (_threadView != null || !IsLogist))
|
if (!_threadsDirty && (_threadView != null || !HasThreads))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -327,7 +366,7 @@ namespace NecromancerTome
|
|||||||
}
|
}
|
||||||
_threadsDirty = false;
|
_threadsDirty = false;
|
||||||
SyncGlow();
|
SyncGlow();
|
||||||
if (!IsLogist)
|
if (!HasThreads)
|
||||||
{
|
{
|
||||||
RemoveThreadView();
|
RemoveThreadView();
|
||||||
return;
|
return;
|
||||||
@@ -545,8 +584,10 @@ namespace NecromancerTome
|
|||||||
void SyncGlow()
|
void SyncGlow()
|
||||||
{
|
{
|
||||||
Transform t = ModelTransform();
|
Transform t = ModelTransform();
|
||||||
int want = HasSkull ? (IsLogist ? 2 : 1) : 0;
|
// Логист (16.10: «Так сразу будет видно что логистика, а что технолог») - всегда своя текстура свечения (руны и
|
||||||
Texture logist = want == 2 ? LogistEmission() : null;
|
// глазницы зелёные) и зеленоватая глазурь; светится, как и обычная урна, только с черепом.
|
||||||
|
int want = (HasSkull ? 1 : 0) + (IsLogist ? 2 : 0);
|
||||||
|
Texture logist = IsLogist ? LogistEmission() : null;
|
||||||
if (t == null || (_glowState == want && _glowModel == t))
|
if (t == null || (_glowState == want && _glowModel == t))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -563,20 +604,17 @@ namespace NecromancerTome
|
|||||||
if (logist != null)
|
if (logist != null)
|
||||||
{
|
{
|
||||||
_glowBlock.SetTexture(EmissionMapId, logist);
|
_glowBlock.SetTexture(EmissionMapId, logist);
|
||||||
}
|
_glowBlock.SetColor(AlbedoColorId, LogistTint);
|
||||||
else if (_hadLogistTex)
|
|
||||||
{
|
|
||||||
_glowBlock.Clear(); // вернуть текстуру материала
|
|
||||||
_glowBlock.SetColor(EmissionColorId, HasSkull ? GlowColor : Color.black);
|
|
||||||
}
|
}
|
||||||
r.SetPropertyBlock(_glowBlock);
|
r.SetPropertyBlock(_glowBlock);
|
||||||
}
|
}
|
||||||
_glowState = want;
|
_glowState = want;
|
||||||
_glowModel = t;
|
_glowModel = t;
|
||||||
_hadLogistTex = logist != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _hadLogistTex;
|
/// <summary>Глазурь урны-логиста - множитель цвета материала (чёрная глазурь с зелёным отливом).</summary>
|
||||||
|
public static Color LogistTint = new Color(0.55f, 1f, 0.75f, 1f);
|
||||||
|
static readonly int AlbedoColorId = Shader.PropertyToID("_Color");
|
||||||
static readonly int EmissionMapId = Shader.PropertyToID("_EmissionMap");
|
static readonly int EmissionMapId = Shader.PropertyToID("_EmissionMap");
|
||||||
static Texture2D _logistTex;
|
static Texture2D _logistTex;
|
||||||
static bool _logistTried;
|
static bool _logistTried;
|
||||||
@@ -704,7 +742,7 @@ namespace NecromancerTome
|
|||||||
public static bool IsUrn(Block _b)
|
public static bool IsUrn(Block _b)
|
||||||
{
|
{
|
||||||
string n = _b?.GetBlockName();
|
string n = _b?.GetBlockName();
|
||||||
return n == BlockName || n == SkullBlockName;
|
return n == BlockName || n == SkullBlockName || n == LogistBlockName || n == LogistSkullBlockName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int UrnLimit(EntityPlayer _player)
|
public static int UrnLimit(EntityPlayer _player)
|
||||||
@@ -714,9 +752,9 @@ namespace NecromancerTome
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Ключ подсказки, почему урну сюда нельзя, или null.</summary>
|
/// <summary>Ключ подсказки, почему урну сюда нельзя, или null.</summary>
|
||||||
public static string PlacementRefusal(Vector3i _pos)
|
public static string PlacementRefusal(Vector3i _pos, Block _placing)
|
||||||
{
|
{
|
||||||
if (CinerariumRegistry.Overlaps(_pos))
|
if (!IsLogistBlock(_placing) && CinerariumRegistry.Overlaps(_pos))
|
||||||
{
|
{
|
||||||
return "necroCinerariumOverlap";
|
return "necroCinerariumOverlap";
|
||||||
}
|
}
|
||||||
@@ -833,8 +871,13 @@ namespace NecromancerTome
|
|||||||
{
|
{
|
||||||
int w = TEFeatureCinerarium.HalfWidth * 2;
|
int w = TEFeatureCinerarium.HalfWidth * 2;
|
||||||
int h = TEFeatureCinerarium.Below + TEFeatureCinerarium.Above;
|
int h = TEFeatureCinerarium.Below + TEFeatureCinerarium.Above;
|
||||||
|
World world = GameManager.Instance?.World;
|
||||||
foreach (Vector3i p in Urns().Keys)
|
foreach (Vector3i p in Urns().Keys)
|
||||||
{
|
{
|
||||||
|
if (world != null && TEFeatureCinerarium.IsLogistBlock(world.GetBlock(p).Block))
|
||||||
|
{
|
||||||
|
continue; // у логиста зоны нет
|
||||||
|
}
|
||||||
if (p != _pos && Math.Abs(p.x - _pos.x) <= w && Math.Abs(p.z - _pos.z) <= w && Math.Abs(p.y - _pos.y) <= h)
|
if (p != _pos && Math.Abs(p.x - _pos.x) <= w && Math.Abs(p.z - _pos.z) <= w && Math.Abs(p.y - _pos.y) <= h)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -886,11 +929,11 @@ namespace NecromancerTome
|
|||||||
}
|
}
|
||||||
else if (text.EndsWith("bounds_show"))
|
else if (text.EndsWith("bounds_show"))
|
||||||
{
|
{
|
||||||
_commands[i].enabled = !urn.ZoneShown;
|
_commands[i].enabled = !urn.ZoneShown && !urn.IsLogist;
|
||||||
}
|
}
|
||||||
else if (text.EndsWith("bounds_hide"))
|
else if (text.EndsWith("bounds_hide"))
|
||||||
{
|
{
|
||||||
_commands[i].enabled = urn.ZoneShown;
|
_commands[i].enabled = urn.ZoneShown && !urn.IsLogist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -968,7 +1011,7 @@ namespace NecromancerTome
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
string why = TEFeatureCinerarium.PlacementRefusal(_blockPos);
|
string why = TEFeatureCinerarium.PlacementRefusal(_blockPos, __instance);
|
||||||
if (why != null)
|
if (why != null)
|
||||||
{
|
{
|
||||||
__result = false;
|
__result = false;
|
||||||
@@ -1029,7 +1072,10 @@ namespace NecromancerTome
|
|||||||
GameManager.ShowTooltip(player, Localization.Get("necroCinerariumBagNotEmpty"), string.Empty, "ui_denied");
|
GameManager.ShowTooltip(player, Localization.Get("necroCinerariumBagNotEmpty"), string.Empty, "ui_denied");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ItemValue iv = ItemClass.GetItem(urn.HasSkull ? TEFeatureCinerarium.SkullBlockName : TEFeatureCinerarium.BlockName);
|
bool logist = TEFeatureCinerarium.IsLogistBlock(bv.Block);
|
||||||
|
ItemValue iv = ItemClass.GetItem(logist
|
||||||
|
? (urn.HasSkull ? TEFeatureCinerarium.LogistSkullBlockName : TEFeatureCinerarium.LogistBlockName)
|
||||||
|
: (urn.HasSkull ? TEFeatureCinerarium.SkullBlockName : TEFeatureCinerarium.BlockName));
|
||||||
if (iv == null || iv.type <= 0)
|
if (iv == null || iv.type <= 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ namespace NecromancerTome
|
|||||||
/// ящика. Дух в цинерарии будет забирать всё что лежит в ящике из которого в него тянется провод, и тащить в ящик, в
|
/// ящика. Дух в цинерарии будет забирать всё что лежит в ящике из которого в него тянется провод, и тащить в ящик, в
|
||||||
/// который тянется провод.» Решения: у урны несколько нитей «откуда» и одна «куда»; везётся по образцу (только то, что уже
|
/// который тянется провод.» Решения: у урны несколько нитей «откуда» и одна «куда»; везётся по образцу (только то, что уже
|
||||||
/// лежит в ящике «куда»; пустой - всё подряд); «куда» полон - дух ждёт; нить призрачная; длина - как у провода (15 м);
|
/// лежит в ящике «куда»; пустой - всё подряд); «куда» полон - дух ждёт; нить призрачная; длина - как у провода (15 м);
|
||||||
/// ящики - любые. Урна с нитями - «логист»: её дух только перевозит, глазницы черепов светятся зелёным.
|
/// ящики - любые. Нити - только у отдельного блока «урна-логист» (necroCinerariumLogist, 16.10): без зоны, дух только перевозит,
|
||||||
|
/// глазницы всегда зелёные.
|
||||||
///
|
///
|
||||||
/// Инструмент - нож некроманта «хватом для нитей»: отдельный предмет necroWpnBladeNecroKnifeThread (класс ножа в сейве
|
/// Инструмент - нож некроманта «хватом для нитей»: отдельный предмет necroWpnBladeNecroKnifeThread (класс ножа в сейве
|
||||||
/// менять нельзя), переключение - пункт в меню ножа по R (то же меню, что «человек/змея/чертоги», SnakeMode.cs; 16.10:
|
/// менять нельзя), переключение - пункт в меню ножа по R (то же меню, что «человек/змея/чертоги», SnakeMode.cs; 16.10:
|
||||||
@@ -134,6 +135,11 @@ namespace NecromancerTome
|
|||||||
}
|
}
|
||||||
if (!_start.HasValue)
|
if (!_start.HasValue)
|
||||||
{
|
{
|
||||||
|
if (urn != null && !urn.IsLogist)
|
||||||
|
{
|
||||||
|
GameManager.ShowTooltip(_pl, Localization.Get("necroThreadNeedLogist"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
_start = owner;
|
_start = owner;
|
||||||
_startUrn = urn != null;
|
_startUrn = urn != null;
|
||||||
_preview = new GameObject("NecroThreadPreview");
|
_preview = new GameObject("NecroThreadPreview");
|
||||||
@@ -155,6 +161,12 @@ namespace NecromancerTome
|
|||||||
GameManager.ShowTooltip(_pl, Localization.Get("necroThreadNeedPair"));
|
GameManager.ShowTooltip(_pl, Localization.Get("necroThreadNeedPair"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
TEFeatureCinerarium end = sUrn ? UrnAt(w, s) : urn;
|
||||||
|
if (end == null || !end.IsLogist)
|
||||||
|
{
|
||||||
|
GameManager.ShowTooltip(_pl, Localization.Get("necroThreadNeedLogist"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (Vector3.Distance(s.ToVector3(), owner.ToVector3()) > MaxLength)
|
if (Vector3.Distance(s.ToVector3(), owner.ToVector3()) > MaxLength)
|
||||||
{
|
{
|
||||||
GameManager.ShowTooltip(_pl, Localization.Get("necroThreadTooFar"));
|
GameManager.ShowTooltip(_pl, Localization.Get("necroThreadTooFar"));
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
Reference in New Issue
Block a user