diff --git a/Config/Localization.csv b/Config/Localization.csv index 15efe49..990b886 100644 --- a/Config/Localization.csv +++ b/Config/Localization.csv @@ -375,79 +375,79 @@ necroPossessNoCarrionGround,items,Item,,,,"No carrion nearby - stop next to a co necroSnakeSpirit,entityclasses,Entity,,,,Snake Spirit,,Schlangengeist,Espíritu de serpiente,Esprit du serpent,Spirito del serpente,蛇の霊,뱀의 영혼,Duch węża,Espírito da serpente,Дух змеи,Yılan Ruhu,蛇灵,蛇靈 necroGeoOssuary,blocks,Block,,,,Geo-Ossuary,,Geo-Ossarium,Geo-osario,Géo-ossuaire,Geo-ossario,ジオ納骨堂,지오 납골당,Geo-ossuarium,Geo-ossário,Гео-оссуарий,Jeo-Kemiklik,地脉骨堂,地脈骨堂 necroGeoOssuaryDesc,blocks,Block,,,,"A riveted iron cauldron full of bones, standing on a bone tripod. Wild spirits dig here - not out of obedience, but for a price: a Blood Sphere in the hollow of the lid. -Put one resource into the sample slot: stone, coal, nitrate, iron or oil shale. The spirits bring it up from the depths into six storage cells. +Put up to three resources into the sample slots: stone, coal, nitrate, iron or oil shale. The spirits bring each one up from the depths into the two storage cells below its slot. Every 10-16 hours each storage cell yields a full stack and drains a tenth of the sphere's durability: one sphere lasts ten stacks. While the spirits are at work, the cauldron glows from within. Works anywhere, even underground. Repair with bones. A Blood Stone instead of the sphere pays them forever.",,"Ein genieteter Eisenkessel voller Knochen auf einem Knochendreibein. Hier graben wilde Geister - nicht aus Gehorsam, sondern gegen Bezahlung: eine Blutsphäre in der Mulde des Deckels. -Lege eine Ressource in den Musterplatz: Stein, Kohle, Salpeter, Eisen oder Ölschiefer. Die Geister holen sie aus der Tiefe in sechs Lagerzellen. +Lege bis zu drei Ressourcen in die Musterplätze: Stein, Kohle, Salpeter, Eisen oder Ölschiefer. Die Geister holen jede aus der Tiefe in die zwei Lagerzellen unter ihrem Platz. Alle 10-16 Stunden liefert jede Lagerzelle einen vollen Stapel und verbraucht ein Zehntel der Haltbarkeit der Sphäre: eine Sphäre reicht für zehn Stapel. Solange die Geister arbeiten, glüht der Kessel von innen. Funktioniert überall, auch unter der Erde. Mit Knochen reparieren. Ein Blutstein statt der Sphäre bezahlt sie für immer.","Un caldero de hierro remachado lleno de huesos sobre un trípode de hueso. Aquí excavan espíritus salvajes, no por obediencia, sino a cambio de un precio: una esfera de sangre en el hueco de la tapa. -Pon un recurso en la ranura de muestra: piedra, carbón, nitrato, hierro o pizarra bituminosa. Los espíritus lo sacan de las profundidades a seis celdas de almacén. +Pon hasta tres recursos en las ranuras de muestra: piedra, carbón, nitrato, hierro o pizarra bituminosa. Los espíritus sacan cada uno de las profundidades a las dos celdas de almacén bajo su ranura. Cada 10-16 horas cada celda de almacén da una pila completa y gasta una décima parte de la durabilidad de la esfera: una esfera dura diez pilas. Mientras los espíritus trabajan, el caldero brilla por dentro. Funciona en cualquier lugar, incluso bajo tierra. Se repara con huesos. Una piedra de sangre en lugar de la esfera les paga para siempre.","Un chaudron de fer riveté rempli d'os, posé sur un trépied d'os. Des esprits sauvages y creusent - non par obéissance, mais contre paiement : une sphère de sang dans le creux du couvercle. -Placez une ressource dans l'emplacement d'échantillon : pierre, charbon, salpêtre, fer ou schiste bitumineux. Les esprits la remontent des profondeurs dans six cases de stockage. +Placez jusqu'à trois ressources dans les emplacements d'échantillon : pierre, charbon, salpêtre, fer ou schiste bitumineux. Les esprits remontent chacune des profondeurs dans les deux cases de stockage sous son emplacement. Toutes les 10-16 heures, chaque case de stockage donne une pile complète et consomme un dixième de la durabilité de la sphère : une sphère dure dix piles. Tant que les esprits travaillent, le chaudron luit de l'intérieur. Fonctionne partout, même sous terre. Se répare avec des os. Une pierre de sang à la place de la sphère les paie pour toujours.","Un calderone di ferro rivettato pieno di ossa, su un treppiede d'osso. Qui scavano spiriti selvaggi - non per obbedienza, ma a pagamento: una sfera di sangue nell'incavo del coperchio. -Metti una risorsa nello slot campione: pietra, carbone, nitrato, ferro o scisto bituminoso. Gli spiriti la portano su dalle profondità in sei celle di deposito. +Metti fino a tre risorse negli slot campione: pietra, carbone, nitrato, ferro o scisto bituminoso. Gli spiriti portano ciascuna su dalle profondità nelle due celle di deposito sotto il suo slot. Ogni 10-16 ore ogni cella di deposito produce una pila completa e consuma un decimo della durabilità della sfera: una sfera basta per dieci pile. Mentre gli spiriti lavorano, il calderone brilla dall'interno. Funziona ovunque, anche sottoterra. Si ripara con le ossa. Una pietra di sangue al posto della sfera li paga per sempre.","骨の三脚に載った、骨でいっぱいのリベット留めの鉄の大釜。ここで掘るのは野生の霊――服従ではなく報酬のために。報酬は蓋のくぼみに置く血の球だ。 -見本スロットに資源を1つ入れる:石、石炭、硝石、鉄、オイルシェール。霊たちは地の底からそれを6つの保管セルへ運び上げる。 +見本スロットに資源を3つまで入れる:石、石炭、硝石、鉄、オイルシェール。霊たちはそれぞれを地の底から、そのスロットの下にある2つの保管セルへ運び上げる。 10~16時間ごとに各保管セルが1スタックを生み、血の球の耐久値を10分の1消費する。球1つで10スタック分。 霊たちが働いている間、大釜は内側から光る。 どこでも動く。地下でも。 骨で修理できる。 球の代わりに血の石を置けば、永遠に報酬を払える。","뼈 삼각대 위에 놓인, 뼈로 가득한 리벳 박은 철 가마솥. 이곳에서는 야생 영혼들이 땅을 판다 - 복종이 아니라 대가를 받고. 대가는 뚜껑 홈에 놓인 피의 구슬이다. -견본 칸에 자원 하나를 넣으세요: 돌, 석탄, 초석, 철 또는 오일 셰일. 영혼들이 깊은 곳에서 그것을 여섯 개의 보관 칸으로 끌어올린다. +견본 칸에 자원을 세 개까지 넣으세요: 돌, 석탄, 초석, 철 또는 오일 셰일. 영혼들이 각각을 깊은 곳에서 그 칸 아래의 보관 칸 두 개로 끌어올린다. 10-16시간마다 각 보관 칸이 한 묶음을 내고 구슬 내구도의 10분의 1을 소모한다: 구슬 하나로 열 묶음. 영혼들이 일하는 동안 가마솥은 안에서부터 빛난다. 어디서든 작동한다. 지하에서도. 뼈로 수리한다. 구슬 대신 피의 돌을 두면 영원히 대가를 치른다.","Nitowany żelazny kocioł pełen kości na kościanym trójnogu. Kopią tu dzikie duchy - nie z posłuszeństwa, lecz za zapłatę: krwawą sferę we wgłębieniu pokrywy. -Włóż jeden surowiec do slotu próbki: kamień, węgiel, saletrę, żelazo lub łupek bitumiczny. Duchy wynoszą go z głębin do sześciu komórek magazynu. +Włóż do trzech surowców do slotów próbek: kamień, węgiel, saletrę, żelazo lub łupek bitumiczny. Duchy wynoszą każdy z głębin do dwóch komórek magazynu pod jego slotem. Co 10-16 godzin każda komórka magazynu daje pełny stos i zużywa jedną dziesiątą wytrzymałości sfery: jedna sfera starcza na dziesięć stosów. Póki duchy pracują, kocioł świeci od środka. Działa wszędzie, nawet pod ziemią. Naprawiany kośćmi. Krwawy kamień zamiast sfery płaci im na zawsze.","Um caldeirão de ferro rebitado cheio de ossos, sobre um tripé de osso. Aqui cavam espíritos selvagens - não por obediência, mas por um preço: uma esfera de sangue na cavidade da tampa. -Coloque um recurso no espaço de amostra: pedra, carvão, nitrato, ferro ou xisto betuminoso. Os espíritos o trazem das profundezas para seis células de armazenamento. +Coloque até três recursos nos espaços de amostra: pedra, carvão, nitrato, ferro ou xisto betuminoso. Os espíritos trazem cada um das profundezas para as duas células de armazenamento abaixo do seu espaço. A cada 10-16 horas, cada célula de armazenamento rende uma pilha cheia e gasta um décimo da durabilidade da esfera: uma esfera dura dez pilhas. Enquanto os espíritos trabalham, o caldeirão brilha por dentro. Funciona em qualquer lugar, até no subsolo. Repara-se com ossos. Uma pedra de sangue no lugar da esfera os paga para sempre.","Клёпаный железный котёл, полный костей, на костяной треноге. Здесь копают дикие духи - не из подчинения, а за плату: кровавую сферу в углублении крышки. -Положите в ячейку образца один ресурс: камень, уголь, селитру, железо или сланец. Духи поднимают его из недр в шесть ячеек хранилища. +Положите в ячейки образцов до трёх ресурсов: камень, уголь, селитру, железо или сланец. Духи поднимают каждый из недр в две ячейки хранилища под его ячейкой. Раз в 10-16 часов каждая ячейка хранилища выдаёт полный стак и тратит десятую часть прочности сферы: одной сферы хватает на десять стаков. Пока духи работают, котёл светится изнутри. Работает где угодно, даже под землёй. Чинится костями. Кровавый камень вместо сферы платит им вечно.","Kemik bir üçayak üzerinde duran, kemiklerle dolu perçinli demir bir kazan. Burada vahşi ruhlar kazar - itaatten değil, bir bedel karşılığında: kapağın oyuğundaki bir Kan Küresi. -Numune yuvasına bir kaynak koy: taş, kömür, güherçile, demir veya bitümlü şist. Ruhlar onu derinliklerden altı depo hücresine çıkarır. +Numune yuvalarına en fazla üç kaynak koy: taş, kömür, güherçile, demir veya bitümlü şist. Ruhlar her birini derinliklerden yuvasının altındaki iki depo hücresine çıkarır. Her 10-16 saatte bir her depo hücresi tam bir yığın verir ve kürenin dayanıklılığının onda birini harcar: bir küre on yığına yeter. Ruhlar çalışırken kazan içten parlar. Her yerde çalışır, yer altında bile. Kemikle onarılır. Küre yerine bir Kan Taşı onlara sonsuza dek öder.","一口铆接铁锅,装满骨头,立在骨制三脚架上。在这里挖掘的是野生灵魂——不是出于服从,而是为了报酬:锅盖凹槽里的一颗血之球。 -在样本槽中放入一种资源:石头、煤、硝石、铁或油页岩。灵魂们会把它从地底运到六个储存格中。 +在样本槽中放入最多三种资源:石头、煤、硝石、铁或油页岩。灵魂们会把每一种从地底运到其样本槽下方的两个储存格中。 每10-16小时,每个储存格产出一整组,并消耗血之球十分之一的耐久:一颗球可用十组。 灵魂们工作时,铁锅会从内部发光。 在任何地方都能运作,即使在地下。 用骨头修理。 用血之石代替血之球,便能永远支付报酬。","一口鉚接鐵鍋,裝滿骨頭,立在骨製三腳架上。在這裡挖掘的是野生靈魂——不是出於服從,而是為了報酬:鍋蓋凹槽裡的一顆血之球。 -在樣本槽中放入一種資源:石頭、煤、硝石、鐵或油頁岩。靈魂們會把它從地底運到六個儲存格中。 +在樣本槽中放入最多三種資源:石頭、煤、硝石、鐵或油頁岩。靈魂們會把每一種從地底運到其樣本槽下方的兩個儲存格中。 每10-16小時,每個儲存格產出一整組,並消耗血之球十分之一的耐久:一顆球可用十組。 靈魂們工作時,鐵鍋會從內部發光。 在任何地方都能運作,即使在地下。 diff --git a/Config/blocks.xml b/Config/blocks.xml index f322637..2aff4d0 100644 --- a/Config/blocks.xml +++ b/Config/blocks.xml @@ -209,9 +209,10 @@ - + diff --git a/HarmonySrc/GeoOssuaryPatch.cs b/HarmonySrc/GeoOssuaryPatch.cs index 9e54ef9..4b81e42 100644 --- a/HarmonySrc/GeoOssuaryPatch.cs +++ b/HarmonySrc/GeoOssuaryPatch.cs @@ -53,21 +53,23 @@ namespace NecromancerTome public static bool Is(TileEntityCollector te) => te != null && Is(te.blockValue.Block); - /// Ячейка образца для выхода: у котла (#66, 22.10) образец один - все выходы os1..os6 берут ресурс из - /// ячейки 0 («Ячейка под образец - одна»). Не наш выход - -1. + /// Ячейка образца для выхода: хранилище 2 ряда по 3, столбец - образец над ним (os1 и os4 - образец 1, os2 и + /// os5 - 2, os3 и os6 - 3). 22.10 сначала решили «ячейка под образец - одна», но спрятать две лишние не вышло с первого + /// раза, и пользователь: «Пусть можно будет положить 3 разных образца, и тогда в ячейки под ними пойдут такие же ресурсы. + /// Примерно так оссуарий и работал». Не наш выход - -1. public static int ModSlotOf(BlockCollector.OutputType outputType) { string name = outputType?.Name; if (name == null || name.Length != 3 || !name.StartsWith("os")) return -1; - return 0; + return (name[2] - '1') % 3; } /// Видимых в окне ячеек образца и топлива (#66, 22.10: «Ячейка под образец - одна; ячейка под кровавую /// сферу (или камень) - одна»). В данных их по-прежнему 3 и 6: длины пишутся в сейв, а при загрузке игра обрезает /// лишнее по конфигу - уменьшение молча выбросило бы содержимое. Лишние прячутся в окне, их старое содержимое /// переносит в хранилище Patch_TileEntityCollector_UpdateTick_GeoOssuaryMigrate. - public const int VisibleModSlots = 1; + public const int VisibleModSlots = 3; // все три (см. ModSlotOf); прятать нечего, перенос образцов не нужен public const int VisibleFuelSlots = 1; /// Ресурс в ячейке модификации, если он из списка; иначе null. @@ -107,6 +109,41 @@ namespace NecromancerTome } } + /// Лишние ячейки держать скрытыми каждый кадр, пока окно открыто (22.10: «почему-то ячеек под образец 3, а мы + /// планировали сделать 1»): сетка топлива сама выставляет видимость по высоте в своём Update (updateGridHeight), ячейки + /// образца тоже показывались снова после SetTileEntity. Сеттер IsVisible при том же значении ничего не делает. + [HarmonyPatch(typeof(XUiC_ItemStackGrid), nameof(XUiC_ItemStackGrid.Update))] + public static class Patch_XUiC_ItemStackGrid_Update_GeoOssuary + { + public static void Postfix(XUiC_ItemStackGrid __instance) + { + if (__instance is XUiC_DewCollectorModGrid mods) + { + if (!GeoOssuary.Is(mods.tileEntity)) + return; + for (int i = GeoOssuary.VisibleModSlots; i < mods.itemControllers.Length; i++) + mods.itemControllers[i].ViewComponent.IsVisible = false; + } + else if (__instance is XUiC_CollectorFuelGrid fuel && fuel.fuelBehavior == XUiC_CollectorFuelGrid.FuelBehavior.Fuel && + GeoOssuary.Is(fuel.tileEntity)) + { + GeoOssuaryFuelGrid.Apply(fuel); + } + } + } + + /// Сетка топлива меняет видимость после базового Update (updateGridHeight) - прятать и после него. + [HarmonyPatch(typeof(XUiC_VariableHeightGrid), nameof(XUiC_VariableHeightGrid.Update))] + public static class Patch_XUiC_VariableHeightGrid_Update_GeoOssuary + { + public static void Postfix(XUiC_VariableHeightGrid __instance) + { + if (__instance is XUiC_CollectorFuelGrid fuel && fuel.fuelBehavior == XUiC_CollectorFuelGrid.FuelBehavior.Fuel && + GeoOssuary.Is(fuel.tileEntity)) + GeoOssuaryFuelGrid.Apply(fuel); + } + } + [HarmonyPatch(typeof(TileEntityCollector), nameof(TileEntityCollector.isDisabled))] public static class Patch_TileEntityCollector_isDisabled_GeoOssuary { diff --git a/HarmonySrc/OssuaryGlow.cs b/HarmonySrc/OssuaryGlow.cs index 38607be..eadc197 100644 --- a/HarmonySrc/OssuaryGlow.cs +++ b/HarmonySrc/OssuaryGlow.cs @@ -19,6 +19,9 @@ namespace NecromancerTome public static bool WispEnabled = true; /// necroossuary wisp log - писать в лог вылет и влёт (чтобы успеть снять). public static bool WispLog; + /// necroossuary wisp trace - трассер: линии обоих путей огонька (вылет и влёт) у каждого котла (22.10: «А не проще + /// для отладки нарисовать трассер, по которому будет лететь огонёк?»). + public static bool WispTrace; public const string WispPath = "#@modfolder(NecromancerTome):Resources/necrowisp?necroWispPrefab.prefab"; static GameObject _wispPrefab; static bool _wispTried; @@ -195,9 +198,12 @@ namespace NecromancerTome public class OssuaryWisp { public const float WispViewRange = 60f; - /// Окошки крышки (модель #67): шесть, между швами, через 60°; по высоте - на WindowUp от низа крышки, - /// от оси - на WindowR (доли полуширины крышки; в модели 0.14 м и 0.37 м при полуширине 0.418). - const float WindowUp = 0.14f / 0.836f, WindowR = 0.37f / 0.418f; + /// Окошки крышки (модель #67): шесть, через 60°, со сдвигом WindowAngle от оси X модели (рамки окошек в сетке - + /// на 30°, 90°...; на 0°, 60°... - металлические полосы: 22.10 «Светлячок заходит в полосы металла, и игнорирует окошки»). + /// По высоте - на WindowUp от низа крышки, от оси - на WindowR (доли размеров крышки; в модели окошко 0.46-0.56 м + /// при низе крышки 0.382, радиус 0.37 при полуширине 0.418). + const float WindowAngle = 30f; + const float WindowUp = 0.13f / 0.836f, WindowR = 0.37f / 0.418f; /// Подъём и спуск - вертикально снаружи, на Clear дальше самого широкого места котла (22.10: «Огонёк летит сквозь /// котёл. А надо чтобы поднимался почти на уровень окошка, и по дуге летел прямо через его центр»). const float Clear = 0.25f; @@ -213,6 +219,7 @@ namespace NecromancerTome TrailRenderer _trail; int _phase = -1; // -1 дома, 0 вылет и уход в землю, 1 под землёй, 2 подъём и влёт float _t0, _until; + LineRenderer _traceOut, _traceIn; Vector3[] _pathOut, _pathIn; // вылет: нутро -> окошко -> дуга -> вниз в землю; влёт - обратный порядок с другой стороны static float Ease(float _k) => _k * _k * (3f - 2f * _k); @@ -236,6 +243,14 @@ namespace NecromancerTome { return; } + if (!OssuaryGlow.WispTrace && _traceOut != null && _traceOut.enabled) + { + _traceOut.enabled = _traceIn.enabled = false; + } + else if (OssuaryGlow.WispTrace && _pathOut == null) + { + Places(_model); + } float k = Mathf.Clamp01((now - _t0) / Mathf.Max(0.01f, _until - _t0)); switch (_phase) { @@ -294,13 +309,21 @@ namespace NecromancerTome /// Гладкая кривая (Catmull-Rom) точно через точки пути; скорость по пути ровная (время - по длинам отрезков). void Fly(Vector3[] _path, float _k) + { + Vector3 p = At(_path, Ease(_k)); + p.y += 0.015f * Mathf.Sin(Time.time * 7f); // лёгкое дрожание огонька + _go.transform.position = p; + } + + /// Точка пути на доле длины _s (0..1). + static Vector3 At(Vector3[] _path, float _s01) { float total = 0f; for (int i = 1; i < _path.Length; i++) { total += Vector3.Distance(_path[i - 1], _path[i]); } - float s = Ease(_k) * total; + float s = _s01 * total; int seg = 0; float len = 0f; for (; seg < _path.Length - 2; seg++) @@ -315,9 +338,7 @@ namespace NecromancerTome len = Vector3.Distance(_path[seg], _path[seg + 1]); float u = len > 0.0001f ? Mathf.Clamp01(s / len) : 1f; Vector3 p0 = _path[Mathf.Max(0, seg - 1)], p1 = _path[seg], p2 = _path[seg + 1], p3 = _path[Mathf.Min(_path.Length - 1, seg + 2)]; - Vector3 p = 0.5f * (2f * p1 + (p2 - p0) * u + (2f * p0 - 5f * p1 + 4f * p2 - p3) * u * u + (3f * p1 - p0 - 3f * p2 + p3) * u * u * u); - p.y += 0.015f * Mathf.Sin(Time.time * 7f); // лёгкое дрожание огонька - _go.transform.position = p; + return 0.5f * (2f * p1 + (p2 - p0) * u + (2f * p0 - 5f * p1 + 4f * p2 - p3) * u * u + (3f * p1 - p0 - 3f * p2 + p3) * u * u * u); } /// Окошко вылета - случайное из шести, влёта - напротив. Путь: нутро, центр окошка, точка дуги снаружи на высоте @@ -338,12 +359,13 @@ namespace NecromancerTome float winY = b.min.y + WindowUp * half * 2f; Vector3 axis = new Vector3(b.center.x, winY, b.center.z); int w = Random.Range(0, 6); - Vector3 dOut = lid.rotation * Quaternion.Euler(0f, w * 60f, 0f) * Vector3.right; + Vector3 dOut = lid.rotation * Quaternion.Euler(0f, WindowAngle + w * 60f, 0f) * Vector3.right; dOut.y = 0f; dOut.Normalize(); _pathOut = Path(axis, dOut, half, Mathf.Max(bodyHalf, half) + Clear); _pathIn = Path(axis, -dOut, half, Mathf.Max(bodyHalf, half) + Clear); System.Array.Reverse(_pathIn); + Trace(_model); return true; } @@ -363,6 +385,49 @@ namespace NecromancerTome }; } + /// Трассер: путь вылета и путь влёта линиями, точками той же кривой, по которой летит огонёк. + void Trace(Transform _model) + { + if (!OssuaryGlow.WispTrace || _trail == null) + { + return; + } + if (_traceOut == null) + { + _traceOut = Line(_model, "NecroWispTraceOut", new Color(1f, 0.6f, 0.1f)); + _traceIn = Line(_model, "NecroWispTraceIn", new Color(0.2f, 0.8f, 1f)); + } + Fill(_traceOut, _pathOut); + Fill(_traceIn, _pathIn); + } + + LineRenderer Line(Transform _model, string _name, Color _c) + { + var g = new GameObject(_name); + g.transform.SetParent(_model, false); + LineRenderer l = g.AddComponent(); + l.sharedMaterial = _trail.sharedMaterial; + l.useWorldSpace = true; + l.widthMultiplier = 0.015f; + l.startColor = l.endColor = _c; + l.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + l.receiveShadows = false; + return l; + } + + void Fill(LineRenderer _l, Vector3[] _path) + { + const int n = 60; + var pts = new Vector3[n + 1]; + for (int i = 0; i <= n; i++) + { + pts[i] = At(_path, (float)i / n); + } + _l.positionCount = pts.Length; + _l.SetPositions(pts); + _l.enabled = true; + } + Vector3 Ground(Vector3 _p) { if (Physics.Raycast(_p + Vector3.up * 1.5f, Vector3.down, out RaycastHit hit, 8f, SnakeControl.WallMask, QueryTriggerInteraction.Ignore)) @@ -451,6 +516,14 @@ namespace NecromancerTome Object.Destroy(_go); _go = null; } + foreach (LineRenderer l in new[] { _traceOut, _traceIn }) + { + if (l != null) + { + Object.Destroy(l.gameObject); + } + } + _traceOut = _traceIn = null; } } @@ -491,6 +564,8 @@ namespace NecromancerTome "necroossuary remove x y z - remove the ossuary at x y z (only if it is an ossuary)\n" + "necroossuary on|off - off: sphere and glow no longer follow the ossuary state\n" + "necroossuary wisp on|off - wild spirit wisp flying while the ossuary works\n" + + "necroossuary wisp trace|log - dev: draw the wisp paths / log take-off and return\n" + + "necroossuary open x y z - dev: open the ossuary window as with E\n" + "necroossuary info x y z - slots of the ossuary (samples, fuel, storage) and whether it works\n" + "necroossuary put x y z mod|fuel [count] - dev: put an item into a slot (none - empty it)\n" + "necroossuary color r g b - glow color (HDR, e.g. 6 1.4 0.35)\n" + @@ -534,6 +609,18 @@ namespace NecromancerTome con.Output("necroossuary: убран оссуарий в " + p); break; } + case "open": + { + var p = new Vector3i(int.Parse(_params[1]), int.Parse(_params[2]), int.Parse(_params[3])); + BlockValue bv = w.GetBlock(p); + if (bv.ischild) + { + p = p + bv.parent; + bv = w.GetBlock(p); + } + con.Output("necroossuary: открыть " + p + " - " + (GeoOssuary.Is(bv.Block) && bv.Block.OnBlockActivated(w, p, bv, pl))); + break; + } case "info": case "put": { @@ -596,6 +683,12 @@ namespace NecromancerTome con.Output("necroossuary: пульсация " + OssuaryGlow.GlowPulse + ", скорость " + OssuaryGlow.GlowPulseSpeed); break; case "wisp": + if (_params.Count > 1 && _params[1] == "trace") + { + OssuaryGlow.WispTrace = !OssuaryGlow.WispTrace; + con.Output("necroossuary: трассер огонька " + (OssuaryGlow.WispTrace ? "включён (оранжевый - вылет, голубой - влёт)" : "выключен")); + break; + } if (_params.Count > 1 && _params[1] == "log") { OssuaryGlow.WispLog = !OssuaryGlow.WispLog; diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index 26cb5cc..a6931b2 100644 Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ diff --git a/NecromancerHarmony.pdb b/NecromancerHarmony.pdb index dbdee98..883cbb5 100644 Binary files a/NecromancerHarmony.pdb and b/NecromancerHarmony.pdb differ