using System.Collections.Generic; using System.Globalization; using HutongGames.PlayMaker; using UnityEngine; namespace MSCO { /// /// Konsole "oilcheck": woher läuft Öl aus? Das Spiel kennt fünf Quellen - die Motor-FSM rechnet LeakOilpan, /// LeakOilfilter, LeakHeadgasket und LeakRockerCover aus den Teilen aus, dazu die Ablassschraube der Ölwanne /// (Stufe 0-5 = offen, Objekt "Oil" aktiv). Der Ölfilter ist ein gekauftes Teil und steht in items.txt /// (Installed/Tightness) - fehlt die Datei im Spielstand eines Servers, fehlt auch der Filter. /// public static class OilCheck { static readonly string[] PartWords = { "oilpan", "oilfilter", "oil filter", "headgasket", "rocker", "valvecover", "drain" }; public static List Report() { var lines = new List(); if (!MenuHelper.InGame) { lines.Add("Only in the game."); return lines; } var fsms = Object.FindObjectsOfType(); // 1. Leck-Werte der Motor-FSM bool leakFsm = false; foreach (PlayMakerFSM f in fsms) { if (f == null || f.FsmVariables.FindFsmFloat("LeakOilfilter") == null) continue; leakFsm = true; var parts = new List(); foreach (FsmFloat v in f.FsmVariables.FloatVariables) if (v != null && v.Name.StartsWith("Leak")) parts.Add(v.Name + "=" + Num(v.Value)); lines.Add("Engine leaks (" + f.gameObject.name + "/" + f.FsmName + ", state " + f.ActiveStateName + "): " + string.Join(" ", parts.ToArray())); } if (!leakFsm) lines.Add("Engine leak values: not found (engine not assembled?)"); // 2. Teile in der Database (eingebaut, festgeschraubt, kaputt, Ölstand) foreach (PlayMakerFSM f in Resources.FindObjectsOfTypeAll()) { if (f == null || f.FsmName != "Data" || f.gameObject.hideFlags != HideFlags.None) continue; if (f.transform.root.name != "Database" || !Matches(f.gameObject.name)) continue; lines.Add(" " + f.gameObject.name + ": " + Values(f.FsmVariables, "Installed", "Bolted", "Damaged", "Tightness", "Oil", "Wear")); } // 3. Schrauben der Ölwanne (die Ablassschraube schaltet das Leck "Oil") foreach (PlayMakerFSM f in fsms) { if (f == null || f.FsmName != "Screw") continue; string path = FsmSync.PathOf(f.transform); if (path.ToLower().IndexOf("oilpan", System.StringComparison.Ordinal) < 0) continue; FsmInt stage = f.FsmVariables.FindFsmInt("Stage"); lines.Add(" bolt " + Short(path) + ": stage " + (stage != null ? stage.Value.ToString() : "?") + (Switches(f) ? " (drain plug - 0-5 = open)" : "")); } foreach (GameObject go in Object.FindObjectsOfType()) if (go.name == "Oil" && go.transform.parent != null && FsmSync.PathOf(go.transform).ToLower().Contains("oilpan")) lines.Add(" drain leak object " + Short(FsmSync.PathOf(go.transform)) + " is ACTIVE (oil runs out of the drain plug)"); // 4. Ölfilter als Gegenstand (items.txt) int filters = 0; foreach (PlayMakerFSM f in fsms) { if (f == null || !f.gameObject.name.StartsWith("oil filter")) continue; if (f.FsmVariables.FindFsmBool("Installed") == null && f.FsmVariables.FindFsmFloat("Tightness") == null) continue; filters++; lines.Add(" item " + f.gameObject.name + " (" + f.FsmName + ", under " + f.transform.root.name + "): " + Values(f.FsmVariables, "Installed", "Tightness", "Consumed", "Dirt")); } if (filters == 0) lines.Add(" no oil filter item in the world - if the server's save has no items.txt, bought parts are missing"); return lines; } static bool Matches(string name) { string n = name.ToLower(); foreach (string w in PartWords) if (n.Contains(w)) return true; return false; } static bool Switches(PlayMakerFSM f) { try { foreach (FsmState s in f.FsmStates) { if (!s.ActionsLoaded) s.LoadActions(); if (s.Actions == null) continue; foreach (FsmStateAction a in s.Actions) if (a != null && a.GetType().Name == "ActivateGameObject") return true; } } catch { } return false; } static string Values(FsmVariables vars, params string[] names) { var parts = new List(); foreach (string n in names) { FsmBool b = vars.FindFsmBool(n); if (b != null) { parts.Add(n + "=" + b.Value); continue; } FsmFloat f = vars.FindFsmFloat(n); if (f != null) { parts.Add(n + "=" + Num(f.Value)); continue; } FsmInt i = vars.FindFsmInt(n); if (i != null) parts.Add(n + "=" + i.Value); } return parts.Count == 0 ? "-" : string.Join(" ", parts.ToArray()); } static string Num(float v) { return v.ToString("0.###", CultureInfo.InvariantCulture); } static string Short(string path) { string[] s = path.Split('|'); return s.Length <= 3 ? path : "…|" + string.Join("|", s, s.Length - 3, 3); } } }