- Топливо скакуна - кровавые сферы в 4 ячейках модификаций, тратятся по очереди (одна сфера = 120 ед., бак 480); уровень бака считается по прочности сфер, выработанная сфера исчезает. Заправка канистрой убрана. В ячейки - только сферы. - Причина «не едет» и «-2147483648%»: Extends не наследует effect_group, у предмета скакуна не было ни ячеек, ни прочности. Своя группа: ModSlots 4, DegradationMax 4000; здоровье закреплено кодом (DegradationMax сфер в ячейках его перебивал бы). - Ремонт - 50 костей за ход вместо ремкомплекта; подсказка при нехватке, 13 языков. - Модель скакуна: сиденье и рама прогнуты по ванили, рога по оси руля, череп меньше и короче, свет фары в глазнице, крыло над передним колесом, зубы под черепом убраны. - Книга крысы: повёрнута как ванильная (палец на корешке), без металлических уголков. В игре не проверено. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
124 lines
4.9 KiB
C#
124 lines
4.9 KiB
C#
using System.Collections.Generic;
|
|
using HarmonyLib;
|
|
using UnityEngine;
|
|
|
|
namespace NecromancerTome
|
|
{
|
|
/// <summary>
|
|
/// Костяной скакун (1.7.0, 01.10.2026): мотоцикл из костей, призывается книгой, ездит на
|
|
/// кровавых сферах. Сущность necroBoneSteed в entityclasses.xml - наследник vehicleMotorcycle
|
|
/// со своей моделью (бандл necrobonesteed, собран из копии ванильного VMotorcycleP.prefab).
|
|
///
|
|
/// Топливо - кровавые сферы в четырёх ячейках модификаций, ремонт - костями: всё это в
|
|
/// BoneSteedFuelPatch. Здесь только запрет заправки канистрой (GetFuelItem).
|
|
///
|
|
/// Модель выросла из рипнутого префаба, и у неё те же две беды, что у оссуария: игровые теги
|
|
/// коллайдеров потеряны (без них на скакуна не сесть и по нему не попасть) и шейдер-заглушка.
|
|
/// Оба лечатся с ванильного мотоцикла - теги по путям объектов, шейдер у его материала.
|
|
/// </summary>
|
|
public static class BoneSteed
|
|
{
|
|
public const string EntityClassName = "necroBoneSteed";
|
|
public const string FuelItem = "resourceBloodSphere";
|
|
public const string ItemName = "necroBoneSteedPlaceable";
|
|
const string VanillaPrefab = "@:Entities/Vehicles/VMotorcycle/VMotorcycleP.prefab";
|
|
|
|
public static bool Is(Entity e)
|
|
{
|
|
return e != null && EntityClass.list.TryGetValue(e.entityClass, out EntityClass cls) &&
|
|
cls != null && cls.entityClassName == EntityClassName;
|
|
}
|
|
|
|
static Transform vanilla;
|
|
static Shader vanillaShader;
|
|
|
|
public static void FixModel(EntityVehicle ev)
|
|
{
|
|
if (vanilla == null)
|
|
{
|
|
vanilla = DataLoader.LoadAsset<Transform>(VanillaPrefab);
|
|
if (vanilla == null)
|
|
{
|
|
Debug.LogWarning("[NecromancerTome] BoneSteed: ванильный мотоцикл не найден - теги и шейдер не поправлены");
|
|
return;
|
|
}
|
|
foreach (Renderer r in vanilla.GetComponentsInChildren<Renderer>(true))
|
|
{
|
|
if (r.sharedMaterial != null && r.sharedMaterial.HasProperty("_RMOM"))
|
|
{
|
|
vanillaShader = r.sharedMaterial.shader;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
var byPath = new Dictionary<string, Transform>();
|
|
foreach (Transform t in vanilla.GetComponentsInChildren<Transform>(true))
|
|
byPath[PathOf(t, vanilla)] = t;
|
|
int tags = 0, mats = 0;
|
|
foreach (Transform t in ev.transform.GetComponentsInChildren<Transform>(true))
|
|
{
|
|
if (!byPath.TryGetValue(PathOf(t, ev.transform), out Transform src))
|
|
continue;
|
|
if (t.tag != src.tag || t.gameObject.layer != src.gameObject.layer)
|
|
{
|
|
t.tag = src.tag;
|
|
t.gameObject.layer = src.gameObject.layer;
|
|
tags++;
|
|
}
|
|
}
|
|
if (vanillaShader != null)
|
|
{
|
|
foreach (Renderer r in ev.transform.GetComponentsInChildren<Renderer>(true))
|
|
{
|
|
foreach (Material m in r.sharedMaterials)
|
|
{
|
|
if (m != null && m.HasProperty("_RMOM") && m.shader != vanillaShader)
|
|
{
|
|
m.shader = vanillaShader;
|
|
m.enableInstancing = true;
|
|
mats++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Debug.Log("[NecromancerTome] BoneSteed: теги поправлены у " + tags + " объектов, шейдер '" +
|
|
(vanillaShader != null ? vanillaShader.name : "-") + "' поставлен " + mats + " материалам");
|
|
}
|
|
|
|
/// <summary>Путь объекта от корня префаба. Корень - пустая строка: у экземпляра корень
|
|
/// называется иначе (necroBoneSteedP(Clone)), чем у ванильного префаба.</summary>
|
|
static string PathOf(Transform t, Transform root)
|
|
{
|
|
if (t == root)
|
|
return "";
|
|
string p = t.name;
|
|
for (Transform x = t.parent; x != null && x != root; x = x.parent)
|
|
p = x.name + "/" + p;
|
|
return p;
|
|
}
|
|
}
|
|
|
|
[HarmonyPatch(typeof(EntityVehicle), nameof(EntityVehicle.PostInit))]
|
|
public static class Patch_EntityVehicle_PostInit_BoneSteed
|
|
{
|
|
public static void Postfix(EntityVehicle __instance)
|
|
{
|
|
if (BoneSteed.Is(__instance))
|
|
BoneSteed.FixModel(__instance);
|
|
}
|
|
}
|
|
|
|
/// <summary>Канистрой и вообще из рюкзака скакуна не заправить (указание 01.10): кровь
|
|
/// вставляется только в ячейки. Пустой предмет топлива прячет пункт «Заправить» в меню.</summary>
|
|
[HarmonyPatch(typeof(Vehicle), nameof(Vehicle.GetFuelItem))]
|
|
public static class Patch_Vehicle_GetFuelItem_BoneSteed
|
|
{
|
|
public static void Postfix(Vehicle __instance, ref string __result)
|
|
{
|
|
if (BoneSteed.Is(__instance.entity))
|
|
__result = "";
|
|
}
|
|
}
|
|
}
|