using System.Collections.Generic; using HarmonyLib; namespace NecromancerTome { /// /// Двигатель костяного скакуна (тест 01.10.2026): /// /// - «ДАЖЕ БЕЗ СФЕР ЕДЕТ БЫСТРО». Ванильный VPEngine.startEngine ставит isRunning без /// проверки топлива, а глохнет только по событию FuelEmpty - то есть когда бак пустеет на /// ходу. Заведённый с пустым баком мотор так и работал на полной тяге. Здесь: без крови мотор /// не заводится, кончилась на ходу - глохнет; вставили сферу, сидя в седле, - заводится сам. /// Без мотора у ванили остаётся тяга x50 - еле ползёт, как пустой мотоцикл. /// - «ЗВУК МОТОЦИКЛА УБРАТЬ, ПУСТЬ БУДЕТ ВЕЛОСИПЕД». Все звуки мотора (заводка, глушение, /// обороты) у скакуна молчат; вместо них на ходу под тягой - стук педалей bicycle_pedal с /// ритмом ванильного велосипеда (VPPedals: 0.75 с, на турбо 0.55 с). Деталь Pedals ванили /// не годится - ей нужны шатун и педали в модели. /// Дым и огонь (розовые кубы - частицы без материалов) убраны в vehicles.xml и префабе. /// public static class BoneSteedEngine { public const string PedalSound = "bicycle_pedal"; static readonly Dictionary pedalTimers = new Dictionary(); public static bool Is(VehiclePart part) => part?.vehicle != null && BoneSteed.Is(part.vehicle.entity); public static bool HasBlood(Vehicle v) => BoneSteedFuel.FuelOf(v) > 0f; public static void Pedal(VPEngine engine, float dt) { Vehicle v = engine.vehicle; EntityVehicle e = v.entity; if (e == null || e.isEntityRemote || !e.HasDriver || !engine.isRunning || v.CurrentMotorTorquePercent <= 0f || v.CurrentForwardVelocity <= 0.3f) { pedalTimers.Remove(e != null ? e.entityId : 0); return; } pedalTimers.TryGetValue(e.entityId, out float t); t += dt; if (t > (v.IsTurbo ? 0.55f : 0.75f)) { e.PlayOneShot(PedalSound); t = 0f; } pedalTimers[e.entityId] = t; } } [HarmonyPatch(typeof(VPEngine), nameof(VPEngine.startEngine))] public static class Patch_VPEngine_startEngine_BoneSteed { public static bool Prefix(VPEngine __instance) => !BoneSteedEngine.Is(__instance) || BoneSteedEngine.HasBlood(__instance.vehicle); } [HarmonyPatch(typeof(VPEngine), nameof(VPEngine.Update))] public static class Patch_VPEngine_Update_BoneSteed { public static void Postfix(VPEngine __instance, float _dt) { if (!BoneSteedEngine.Is(__instance)) return; Vehicle v = __instance.vehicle; bool blood = BoneSteedEngine.HasBlood(v); if (__instance.isRunning && !blood) __instance.stopEngine(true); else if (!__instance.isRunning && blood && v.entity.HasDriver && !__instance.IsBroken()) __instance.startEngine(); BoneSteedEngine.Pedal(__instance, _dt); } } [HarmonyPatch(typeof(VPEngine), nameof(VPEngine.playSound))] public static class Patch_VPEngine_playSound_BoneSteed { public static bool Prefix(VPEngine __instance) => !BoneSteedEngine.Is(__instance); } [HarmonyPatch(typeof(VPEngine), nameof(VPEngine.updateEngineSounds))] public static class Patch_VPEngine_updateEngineSounds_BoneSteed { public static bool Prefix(VPEngine __instance) => !BoneSteedEngine.Is(__instance); } }