using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using RepoAmigos.Patches; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Utilities; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RepoAmigos")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.5.0.0")] [assembly: AssemblyInformationalVersion("1.5.0+e3104b6eec231ad272c5f572b8d3df08ee8dbf9b")] [assembly: AssemblyProduct("RepoAmigos")] [assembly: AssemblyTitle("RepoAmigos")] [assembly: AssemblyVersion("1.5.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace RepoAmigos { [BepInPlugin("com.usuario.repoamigos", "RepoAmigos", "1.5.0")] [BepInProcess("REPO.exe")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.usuario.repoamigos"; public const string PluginName = "RepoAmigos"; public const string PluginVersion = "1.5.0"; private Harmony _harmony; internal static ConfigEntry VerboseLogging; internal static ManualLogSource Log { get; private set; } internal static Plugin Instance { get; private set; } private void Awake() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; BindConfig(); ExtractionOnDemand.BindConfig(((BaseUnityPlugin)this).Config); ReviveEnExtractor.BindConfig(((BaseUnityPlugin)this).Config); GeneradorDePruebas.BindConfig(((BaseUnityPlugin)this).Config); CarritoEncoge.BindConfig(((BaseUnityPlugin)this).Config); ComprobacionDeVersion.BindConfig(((BaseUnityPlugin)this).Config); Roles.BindConfig(((BaseUnityPlugin)this).Config); RolMedico.BindConfig(((BaseUnityPlugin)this).Config); RolIngeniero.BindConfig(((BaseUnityPlugin)this).Config); RolSaboteador.BindConfig(((BaseUnityPlugin)this).Config); RolRastreador.BindConfig(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.usuario.repoamigos"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)("RepoAmigos v1.5.0 cargado. " + $"Metodos parcheados: {_harmony.GetPatchedMethods().Count()}")); Log.LogInfo((object)("Extraccion manual: " + (ExtractionOnDemand.Enabled.Value ? "ACTIVADA" : "desactivada"))); Log.LogInfo((object)("Revivir en extractor: " + (ReviveEnExtractor.Enabled.Value ? $"ACTIVADO ({ReviveEnExtractor.Segundos.Value}s)" : "desactivado"))); Log.LogInfo((object)($"Pruebas: Activado={GeneradorDePruebas.Enabled.Value}, " + $"Tecla={GeneradorDePruebas.Tecla.Value}, " + $"Cantidad={GeneradorDePruebas.Cantidad.Value}")); Log.LogInfo((object)(Roles.Enabled.Value ? ($"Roles: ACTIVADOS (minimo {Roles.MinJugadores.Value} jugadores) " + $"medico[{RolMedico.Tecla.Value}]={RolMedico.Enabled.Value} " + $"ingeniero={RolIngeniero.Enabled.Value} " + $"saboteador[{RolSaboteador.Tecla.Value}]={RolSaboteador.Enabled.Value} " + $"rastreador={RolRastreador.Enabled.Value}") : "Roles: desactivados")); } private void Update() { GeneradorDePruebas.Tick("Plugin"); } private void OnDestroy() { Log.LogWarning((object)"OnDestroy: el componente del plugin se ha destruido. Los parches Harmony se mantienen a proposito."); ExtractionOnDemand.DesconectarRed(); Roles.DesconectarRed(); } private void BindConfig() { VerboseLogging = ((BaseUnityPlugin)this).Config.Bind("General", "LogDetallado", false, "Escribe informacion extra en la consola de BepInEx. Util para depurar, ruidoso para jugar."); } internal static void Debug(string mensaje) { if (VerboseLogging != null && VerboseLogging.Value) { Log.LogInfo((object)("[debug] " + mensaje)); } } } } namespace RepoAmigos.Patches { internal static class CarritoEncoge { private sealed class Encogido { public Vector3 TamanoOriginal; public float VistoPorUltimaVez; } [HarmonyPatch(typeof(PhysGrabCart), "ObjectsInCart")] private static class ReconciliarContenido { private static void Prefix(out float __state, float ___objectInCartCheckTimer) { __state = ___objectInCartCheckTimer; } private static void Postfix(float __state, float ___objectInCartCheckTimer, List ___itemsInCart) { if (Enabled == null || !Enabled.Value || ___objectInCartCheckTimer <= __state) { return; } if (___itemsInCart != null) { foreach (PhysGrabObject item in ___itemsInCart) { Marcar(item); } } DevolverALosQueSalieron(); } } [HarmonyPatch(typeof(RunManager), "ChangeLevel")] private static class SoltarTodoAlCambiarDeNivel { private static void Prefix() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (_dentro.Count == 0) { return; } int num = 0; foreach (KeyValuePair item in _dentro) { if (!((Object)(object)item.Key == (Object)null)) { ((Component)item.Key).transform.localScale = item.Value.TamanoOriginal; num++; } } Plugin.Debug($"Carrito: cambio de nivel, {num} objetos devueltos a su tamano."); _dentro.Clear(); } } internal static ConfigEntry Enabled; internal static ConfigEntry Escala; internal static ConfigEntry SoloValiosos; private static readonly Dictionary _dentro = new Dictionary(); private const float MargenSalida = 1.6f; private static readonly FieldInfo _campoValioso = AccessTools.Field(typeof(PhysGrabObject), "isValuable"); private static readonly FieldInfo _campoEnemigo = AccessTools.Field(typeof(PhysGrabObject), "isEnemy"); private static readonly FieldInfo _campoJugador = AccessTools.Field(typeof(PhysGrabObject), "isPlayer"); internal static void BindConfig(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown Enabled = config.Bind("Carrito", "Activado", true, "Encoge los objetos mientras estan dentro del C.A.R.T. y les devuelve su tamano al sacarlos."); Escala = config.Bind("Carrito", "EscalaDentro", 0.75f, new ConfigDescription("Tamano dentro del carrito respecto al original. 0.75 los deja al 75%; 0.25 seria encogerlos un 75%.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 1f), Array.Empty())); SoloValiosos = config.Bind("Carrito", "SoloValiosos", true, "true: solo se encoge el botin, que es lo que de verdad ocupa sitio. false: tambien objetos normales. Aun en false hay cosas que NUNCA se tocan (armas equipables, jugadores, enemigos, puertas y bisagras), porque encogerlas rompia el nivel o el propio objeto."); } private static bool LaBanderaDice(FieldInfo campo, PhysGrabObject objeto, bool siNoSePuede) { if (campo == null) { return siNoSePuede; } object value = campo.GetValue(objeto); if (!(value is bool)) { return siNoSePuede; } return (bool)value; } private static bool SePuedeEncoger(PhysGrabObject objeto) { if ((Object)(object)objeto == (Object)null) { return false; } if ((Object)(object)((Component)objeto).GetComponent() != (Object)null) { return false; } if (LaBanderaDice(_campoEnemigo, objeto, siNoSePuede: true)) { return false; } if (LaBanderaDice(_campoJugador, objeto, siNoSePuede: true)) { return false; } if ((Object)(object)((Component)objeto).GetComponentInChildren(true) != (Object)null) { return false; } if ((Object)(object)((Component)objeto).GetComponentInChildren(true) != (Object)null) { return false; } if ((Object)(object)((Component)objeto).GetComponentInChildren(true) != (Object)null) { return false; } if (SoloValiosos.Value && !LaBanderaDice(_campoValioso, objeto, siNoSePuede: false)) { return false; } return true; } private static void Marcar(PhysGrabObject objeto) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)objeto == (Object)null) { return; } if (_dentro.TryGetValue(objeto, out var value)) { value.VistoPorUltimaVez = Time.time; } else if (SePuedeEncoger(objeto)) { Vector3 localScale = ((Component)objeto).transform.localScale; if (!(((Vector3)(ref localScale)).sqrMagnitude < 0.01f)) { _dentro[objeto] = new Encogido { TamanoOriginal = localScale, VistoPorUltimaVez = Time.time }; ((Component)objeto).transform.localScale = localScale * Escala.Value; Plugin.Debug($"Carrito: '{((Object)objeto).name}' encogido al {Escala.Value:P0}."); } } } private static void DevolverALosQueSalieron() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (_dentro.Count == 0) { return; } List list = null; foreach (KeyValuePair item in _dentro) { if ((Object)(object)item.Key == (Object)null) { (list ?? (list = new List())).Add(item.Key); } else if (!(Time.time - item.Value.VistoPorUltimaVez < 1.6f)) { ((Component)item.Key).transform.localScale = item.Value.TamanoOriginal; (list ?? (list = new List())).Add(item.Key); Plugin.Debug("Carrito: '" + ((Object)item.Key).name + "' recupera su tamano."); } } if (list == null) { return; } foreach (PhysGrabObject item2 in list) { _dentro.Remove(item2); } } } internal static class ComprobacionDeVersion { internal static ConfigEntry Enabled; private static readonly Dictionary _versiones = new Dictionary(); private static readonly Dictionary _vistoDesde = new Dictionary(); private static float _proximoAnuncio; private static float _proximaRevision; private static string _ultimoProblema = ""; private const float MargenDeGracia = 25f; private const float CadaCuantoAnuncio = 15f; private const float CadaCuantoRevision = 5f; private static readonly FieldInfo _campoNombre = AccessTools.Field(typeof(PlayerAvatar), "playerName"); internal static void BindConfig(ConfigFile config) { Enabled = config.Bind("Version", "AvisarDesajuste", true, "Avisa en pantalla si algun jugador de la sala lleva otra version del mod o no lo lleva. Muy recomendable dejarlo activado: un desajuste de version no da ningun error, simplemente hace que los roles no funcionen."); } internal static void AlCambiarNivel() { _versiones.Clear(); _vistoDesde.Clear(); _proximoAnuncio = 2f; _proximaRevision = 25f; _ultimoProblema = ""; } internal static void Tick() { if (Enabled != null && Enabled.Value && Roles.EnPartida()) { _proximoAnuncio -= Time.deltaTime; if (_proximoAnuncio <= 0f) { _proximoAnuncio = 15f; Anunciar(); } _proximaRevision -= Time.deltaTime; if (_proximaRevision <= 0f) { _proximaRevision = 5f; Revisar(); } } } private static void Anunciar() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown PlayerAvatar instance = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null) { return; } string text = SemiFunc.PlayerGetSteamID(instance); if (!string.IsNullOrEmpty(text)) { _versiones[text] = "1.5.0"; if (SemiFunc.IsMultiplayer() && PhotonNetwork.NetworkingClient != null && PhotonNetwork.InRoom) { PhotonNetwork.RaiseEvent((byte)178, (object)(text + "|1.5.0"), new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); } } } internal static void Recibir(object datos) { if (datos is string text) { int num = text.IndexOf('|'); if (num > 0 && num != text.Length - 1) { _versiones[text.Substring(0, num)] = text.Substring(num + 1); } } } private static string Nombre(PlayerAvatar avatar) { if (_campoNombre == null) { return "Alguien"; } string text = _campoNombre.GetValue(avatar) as string; if (!string.IsNullOrEmpty(text)) { return text; } return "Alguien"; } private static void Revisar() { if (!SemiFunc.IsMultiplayer()) { return; } List list = SemiFunc.PlayerGetAll(); if (list == null || list.Count <= 1) { return; } List list2 = new List(); List list3 = new List(); foreach (PlayerAvatar item in list) { if ((Object)(object)item == (Object)null) { continue; } string text = SemiFunc.PlayerGetSteamID(item); if (string.IsNullOrEmpty(text)) { continue; } if (!_vistoDesde.ContainsKey(text)) { _vistoDesde[text] = Time.time; } if (_versiones.TryGetValue(text, out var value)) { if (value != "1.5.0") { list2.Add(Nombre(item) + " lleva la " + value); } } else if (Time.time - _vistoDesde[text] >= 25f) { list3.Add(Nombre(item)); } } if (list2.Count == 0 && list3.Count == 0) { _ultimoProblema = ""; return; } string text2 = string.Join(",", list2.ToArray()) + "//" + string.Join(",", list3.ToArray()); if (!(text2 == _ultimoProblema)) { _ultimoProblema = text2; Avisar(list2, list3); } } private static void Avisar(List distintos, List ausentes) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) SemiFunc.UIBigMessage("MOD DESINCRONIZADO", "!", 35f, new Color(1f, 0.4f, 0.2f), Color.white); string text = ((distintos.Count > 0 && ausentes.Count > 0) ? (string.Join(", ", distintos.ToArray()) + " - sin el mod: " + string.Join(", ", ausentes.ToArray())) : ((distintos.Count <= 0) ? ("Sin el mod (o version anterior a la 1.3.0): " + string.Join(", ", ausentes.ToArray())) : (string.Join(", ", distintos.ToArray()) + " - tu la 1.5.0"))); SemiFunc.UIFocusText(text, new Color(1f, 0.4f, 0.2f), Color.white, 8f); Plugin.Log.LogWarning((object)("DESAJUSTE DE VERSION. Yo llevo la 1.5.0. " + text + ". Los roles no van a funcionar bien hasta que todos tengan la misma DLL. Recordad que arrancar desde Steam corre el juego en vanilla sin avisar.")); } } internal static class ExtractionOnDemand { private sealed class Estado { public bool Esperando; public bool Armado; public bool AvisoMostrado; public float LuzIntensidad = -1f; public Color LuzColor; public Transform Estacion; public bool YaCompletado; public PhysGrabObject Pato; public Vector3 PatoPosicion; public Quaternion PatoRotacion; public bool Activo; public bool MetaConocida; public int FaltaBotin; } [HarmonyPatch(typeof(ExtractionPoint), "Start")] private static class ConservarBotonDeTienda { private static IEnumerable Transpiler(IEnumerable instrucciones) { MethodInfo destroy = AccessTools.Method(typeof(Object), "Destroy", new Type[1] { typeof(Object) }, (Type[])null); MethodInfo reemplazo = AccessTools.Method(typeof(ExtractionOnDemand), "DestruirSalvoQueLoConservemos", (Type[])null, (Type[])null); foreach (CodeInstruction instruccione in instrucciones) { if (destroy != null && CodeInstructionExtensions.Calls(instruccione, destroy)) { yield return new CodeInstruction(OpCodes.Call, (object)reemplazo); } else { yield return instruccione; } } } private static void Postfix(ExtractionPoint __instance, bool ___isShop) { if (Enabled.Value && BotonGrande.Value && !___isShop) { Transform shopStation = __instance.shopStation; if (!((Object)(object)shopStation == (Object)null)) { EstadoDe(__instance).Estacion = shopStation; __instance.shopStation = null; ((Component)shopStation).gameObject.SetActive(true); DesplegarEstacion(shopStation, __instance); } } } } private sealed class Vinculo { public ExtractionPoint Punto; } [HarmonyPatch(typeof(PhysGrabObject), "GrabStarted")] private static class PatoNoSeLevanta { private static bool Prefix(PhysGrabObject __instance) { if (!Enabled.Value || !UsarPato.Value) { return true; } if (!_patos.TryGetValue(__instance, out var value)) { return true; } if ((Object)(object)value.Punto != (Object)null) { if (EstadoDe(value.Punto).Esperando) { object? obj = _photonViewExtractor?.GetValue(value.Punto); PhotonView view = (PhotonView)((obj is PhotonView) ? obj : null); Plugin.Debug("Pato pulsado: lanzando la extraccion."); Solicitar(value.Punto, view); } else { AvisarPorQueNoSePuede(EstadoDe(value.Punto)); } } return false; } } [HarmonyPatch(typeof(ItemEquippable), "Update")] private static class SilenciarEquipableDelPato { private static bool Prefix(ItemEquippable __instance) { if (!Enabled.Value || _equipablesDelPato.Count == 0) { return true; } return !_equipablesDelPato.Contains(__instance); } } [HarmonyPatch(typeof(ItemRubberDuck), "Start")] private static class DesnudarPatoEnCadaCliente { private static void Postfix(ItemRubberDuck __instance) { PhotonView component = ((Component)__instance).GetComponent(); object[] array = (((Object)(object)component != (Object)null) ? component.InstantiationData : null); if (array != null && array.Length != 0 && array[0] is string text && !(text != "RepoAmigos:BotonPato")) { DesnudarPato(((Component)__instance).gameObject); } } } [HarmonyPatch(typeof(ExtractionPoint), "StateSetRPC")] private static class SonidoAlPulsar { private static void Prefix(ExtractionPoint __instance, State state, bool ___isShop) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!Enabled.Value || ___isShop || (int)state != 3) { return; } try { Estado estado = EstadoDe(__instance); Vector3 val = (((Object)(object)estado.Pato != (Object)null) ? ((Component)estado.Pato).transform.position : ((Component)__instance).transform.position); if (__instance.soundButton != null) { __instance.soundButton.Play(val, 1f, 1f, 1f, 1f); } } catch { } } } [HarmonyPatch(typeof(ExtractionPoint), "StateSet")] private static class BloquearSuccessAutomatico { private static bool Prefix(ExtractionPoint __instance, State newState, bool ___isShop) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if (!Enabled.Value) { return true; } if ((int)newState != 3) { return true; } if (___isShop) { return true; } Estado estado = EstadoDe(__instance); if (estado.Armado) { estado.Armado = false; estado.Esperando = false; estado.AvisoMostrado = false; Plugin.Debug("Extraccion autorizada por pulsacion del boton."); return true; } return false; } } [HarmonyPatch(typeof(ExtractionPoint), "Update")] private static class MantenerBotonUsable { private static void Postfix(ExtractionPoint __instance, bool ___isShop, bool ___haulGoalFetched, int ___haulCurrent, State ___currentState) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Invalid comparison between Unknown and I4 //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) if (!Enabled.Value) { return; } AsegurarRed(); Estado estado = EstadoDe(__instance); bool flag = ___haulGoalFetched && __instance.haulGoal - ___haulCurrent <= 0; bool flag2 = (estado.Esperando = !___isShop && (int)___currentState == 2 && flag); estado.Activo = (int)___currentState == 2; estado.MetaConocida = ___haulGoalFetched; estado.FaltaBotin = __instance.haulGoal - ___haulCurrent; if ((int)___currentState == 7 && !estado.YaCompletado) { estado.YaCompletado = true; if ((Object)(object)estado.Estacion != (Object)null) { ((Component)estado.Estacion).gameObject.SetActive(false); } RetirarPato(estado); Plugin.Debug("Extraccion completada: boton/pato retirado."); } if ((Object)(object)estado.Pato != (Object)null && SemiFunc.IsMasterClientOrSingleplayer()) { Transform transform = ((Component)estado.Pato).transform; Vector3 val = transform.position - estado.PatoPosicion; if (((Vector3)(ref val)).sqrMagnitude > 0.0004f) { transform.position = estado.PatoPosicion; transform.rotation = estado.PatoRotacion; } Rigidbody component = ((Component)estado.Pato).GetComponent(); if ((Object)(object)component != (Object)null && !component.isKinematic) { component.velocity = Vector3.zero; component.angularVelocity = Vector3.zero; component.isKinematic = true; } } if (flag2 && (Object)(object)estado.Pato != (Object)null && SemiFunc.IsMasterClientOrSingleplayer()) { List playerGrabbing = estado.Pato.playerGrabbing; if (playerGrabbing != null && playerGrabbing.Count > 0) { Plugin.Debug("Pato agarrado: lanzando la extraccion."); Ejecutar(__instance); } } if (!flag2) { if (estado.LuzIntensidad >= 0f && (Object)(object)__instance.buttonLight != (Object)null) { __instance.buttonLight.intensity = estado.LuzIntensidad; __instance.buttonLight.color = estado.LuzColor; estado.LuzIntensidad = -1f; } estado.AvisoMostrado = false; return; } if ((Object)(object)__instance.buttonGrabObject != (Object)null && !((Behaviour)__instance.buttonGrabObject).enabled) { ((Behaviour)__instance.buttonGrabObject).enabled = true; Plugin.Debug("Boton del extractor reactivado (estaba desactivado)."); } if ((Object)(object)__instance.buttonLight != (Object)null && !((Behaviour)__instance.buttonLight).enabled) { ((Behaviour)__instance.buttonLight).enabled = true; } if (!estado.AvisoMostrado) { Plugin.Debug($"Meta cubierta ({___haulCurrent}/{__instance.haulGoal}). Esperando pulsacion. " + "buttonGrabObject=" + (((Object)(object)__instance.buttonGrabObject == (Object)null) ? "NULO" : "ok") + " buttonLight=" + (((Object)(object)__instance.buttonLight == (Object)null) ? "NULO" : "ok") + " pedestalRescatado=" + (((Object)(object)estado.Estacion == (Object)null) ? "NO" : "SI")); EncenderBoton(__instance, estado); } if (!AvisoEnPantalla.Value || estado.AvisoMostrado) { return; } estado.AvisoMostrado = true; try { _tubeScreenTextChange.Invoke(__instance, new object[2] { TextoPantalla.Value, Color.yellow }); } catch (Exception ex) { Plugin.Log.LogWarning((object)("No se pudo cambiar el texto del extractor: " + ex.Message)); } } } [HarmonyPatch(typeof(ExtractionPoint), "OnShopClick")] private static class BotonTiendaLanzaExtraccion { private static bool Prefix(ExtractionPoint __instance, PhotonView ___photonView, bool ___isShop) { if (!Enabled.Value) { return true; } if (___isShop) { return true; } if (EstadoDe(__instance).Esperando) { Solicitar(__instance, ___photonView); return false; } AvisarPorQueNoSePuede(EstadoDe(__instance)); return false; } } [HarmonyPatch(typeof(ExtractionPoint), "OnClick")] private static class BotonLanzaExtraccion { private static bool Prefix(ExtractionPoint __instance, PhotonView ___photonView) { if (!Enabled.Value) { return true; } if (__instance.isLocked) { return true; } if (!EstadoDe(__instance).Esperando) { return true; } Solicitar(__instance, ___photonView); return false; } } internal static ConfigEntry Enabled; internal static ConfigEntry AvisoEnPantalla; internal static ConfigEntry TextoPantalla; internal static ConfigEntry BotonGrande; internal static ConfigEntry DesplazamientoX; internal static ConfigEntry DesplazamientoY; internal static ConfigEntry DesplazamientoZ; internal static ConfigEntry SoloElBoton; internal static ConfigEntry EscalaBoton; internal static ConfigEntry PiezasVisibles; internal static ConfigEntry GiroBoton; internal static ConfigEntry UsarPato; internal static ConfigEntry EscalaPato; internal static ConfigEntry NombrePato; internal static ConfigEntry GiroPatoX; internal static ConfigEntry GiroPatoY; internal static ConfigEntry GiroPatoZ; private static readonly ConditionalWeakTable _estados = new ConditionalWeakTable(); private const byte EventoPulsarBoton = 174; private static bool _redConectada; private static readonly MethodInfo _stateSet = AccessTools.Method(typeof(ExtractionPoint), "StateSet", (Type[])null, (Type[])null); private static readonly MethodInfo _tubeScreenTextChange = AccessTools.Method(typeof(ExtractionPoint), "TubeScreenTextChange", (Type[])null, (Type[])null); private static readonly FieldInfo _buttonOriginalMaterial = AccessTools.Field(typeof(ExtractionPoint), "buttonOriginalMaterial"); private const string MarcaPato = "RepoAmigos:BotonPato"; private static Item _itemPato; private static bool _patoBuscado; private static readonly ConditionalWeakTable _patos = new ConditionalWeakTable(); private static readonly FieldInfo _photonViewExtractor = AccessTools.Field(typeof(ExtractionPoint), "photonView"); private static float _ultimoAvisoPato = -10f; private static readonly HashSet _equipablesDelPato = new HashSet(); internal static void BindConfig(ConfigFile config) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Expected O, but got Unknown //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Expected O, but got Unknown //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Expected O, but got Unknown //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Expected O, but got Unknown Enabled = config.Bind("ExtraccionManual", "Activado", true, "Si esta activado, al cubrir la meta el extractor NO se dispara solo: espera a que alguien pulse el boton. Ponlo en false para volver al comportamiento original."); AvisoEnPantalla = config.Bind("ExtraccionManual", "AvisoEnPantalla", true, "Cambia el texto del tubo del extractor cuando ya esta listo, para que se vea que falta pulsarlo."); TextoPantalla = config.Bind("ExtraccionManual", "TextoAviso", "PULSA EL BOTON", "Texto que aparece en el extractor cuando la meta ya esta cubierta."); BotonGrande = config.Bind("ExtraccionManual", "BotonGrandeDeTienda", true, "Conserva el pedestal con el boton grande que los extractores solo tienen en la tienda, y lo hace aparecer cuando la meta esta cubierta. En vanilla el juego lo destruye al arrancar cualquier nivel que no sea la tienda."); DesplazamientoX = config.Bind("ExtraccionManual", "BotonLateral", 2.5f, new ConfigDescription("Mueve el boton grande a un lado u otro de la rampa, en metros.", (AcceptableValueBase)(object)new AcceptableValueRange(-20f, 20f), Array.Empty())); DesplazamientoY = config.Bind("ExtraccionManual", "BotonAltura", 1.1f, new ConfigDescription("Altura del boton sobre el suelo de la rampa, en metros.", (AcceptableValueBase)(object)new AcceptableValueRange(-20f, 20f), Array.Empty())); UsarPato = config.Bind("ExtraccionManual", "UsarPato", true, "En vez del boton de la tienda, pone un pato de goma fijo al que agarrar para lanzar la extraccion. Mucho mas visible y no hay que pelearse con la geometria del mostrador."); NombrePato = config.Bind("ExtraccionManual", "PatoNombreDelItem", "Rubber Duck", "Nombre exacto del item que se usa como boton. Si no lo encuentra, coge el primero que lleve 'duck' en el nombre. El log lista todos los disponibles."); GiroPatoX = config.Bind("ExtraccionManual", "PatoGiroX", 0f, new ConfigDescription("Inclina el pato hacia delante o atras, en grados.", (AcceptableValueBase)(object)new AcceptableValueRange(-360f, 360f), Array.Empty())); GiroPatoY = config.Bind("ExtraccionManual", "PatoGiroY", 0f, new ConfigDescription("Gira el pato sobre si mismo para que mire a donde quieras, en grados.", (AcceptableValueBase)(object)new AcceptableValueRange(-360f, 360f), Array.Empty())); GiroPatoZ = config.Bind("ExtraccionManual", "PatoGiroZ", 0f, new ConfigDescription("Ladea el pato, en grados.", (AcceptableValueBase)(object)new AcceptableValueRange(-360f, 360f), Array.Empty())); EscalaPato = config.Bind("ExtraccionManual", "PatoEscala", 2f, new ConfigDescription("Tamano del pato. 1 es su tamano normal.", (AcceptableValueBase)(object)new AcceptableValueRange(0.2f, 10f), Array.Empty())); GiroBoton = config.Bind("ExtraccionManual", "BotonGiro", 0f, new ConfigDescription("Gira el boton sobre si mismo, en grados. Prueba 180 si te da la espalda.", (AcceptableValueBase)(object)new AcceptableValueRange(-360f, 360f), Array.Empty())); DesplazamientoZ = config.Bind("ExtraccionManual", "BotonHaciaFuera", 1f, new ConfigDescription("Aleja el boton grande del extractor (positivo) o lo acerca (negativo), en metros.", (AcceptableValueBase)(object)new AcceptableValueRange(-20f, 20f), Array.Empty())); SoloElBoton = config.Bind("ExtraccionManual", "SoloElBoton", true, "El pedestal de la tienda incluye el mostrador entero. Con esto activado solo se muestran las piezas indicadas en PiezasDelBoton y se oculta el resto."); PiezasVisibles = config.Bind("ExtraccionManual", "PiezasDelBoton", "Extraction Point Side Button, Shop Button", "Piezas del pedestal que se dejan visibles, separadas por comas. Disponibles: 'Shop Button' (la placa roja, el boton en si), 'Extraction Point Side Button' (la consola sobre la que va montada la placa), 'Meshtownusa' y 'Cube (1)' (el mostrador de la tienda, un armatoste)."); EscalaBoton = config.Bind("ExtraccionManual", "BotonEscala", 1f, new ConfigDescription("Tamano del boton. 0.5 lo deja a la mitad, 2 al doble.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 5f), Array.Empty())); } private static Estado EstadoDe(ExtractionPoint punto) { return _estados.GetOrCreateValue(punto); } private static void AsegurarRed() { if (!_redConectada && PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.EventReceived += AlRecibirEvento; _redConectada = true; Plugin.Debug("Enganchado al canal de eventos de Photon."); } } internal static void DesconectarRed() { if (_redConectada) { if (PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.EventReceived -= AlRecibirEvento; } _redConectada = false; } } private static void AlRecibirEvento(EventData datos) { if (datos.Code != 174 || !SemiFunc.IsMasterClient()) { return; } try { int num = (int)datos.CustomData; PhotonView val = PhotonView.Find(num); if (!((Object)(object)val == (Object)null)) { ExtractionPoint component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && EstadoDe(component).Esperando) { Plugin.Debug($"Peticion de extraccion recibida para el extractor {num}."); Ejecutar(component); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"Error procesando el evento de extraccion: {arg}"); } } private static void Solicitar(ExtractionPoint punto, PhotonView view) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown punto.ButtonPress(); if (SemiFunc.IsMasterClientOrSingleplayer()) { Ejecutar(punto); return; } if ((Object)(object)view == (Object)null) { Plugin.Log.LogWarning((object)"Extractor sin PhotonView: no se puede avisar al master."); return; } PhotonNetwork.RaiseEvent((byte)174, (object)view.ViewID, new RaiseEventOptions { Receivers = (ReceiverGroup)2 }, SendOptions.SendReliable); Plugin.Debug($"No soy master: peticion enviada para el extractor {view.ViewID}."); } private static void Ejecutar(ExtractionPoint punto) { EstadoDe(punto).Armado = true; _stateSet.Invoke(punto, new object[1] { (object)(State)3 }); } private static void EncenderBoton(ExtractionPoint punto, Estado estado) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) try { object? obj = _buttonOriginalMaterial?.GetValue(punto); Material val = (Material)((obj is Material) ? obj : null); if ((Object)(object)val != (Object)null && (Object)(object)punto.button != (Object)null) { ((Renderer)punto.button).material = val; } if ((Object)(object)punto.buttonLight != (Object)null && estado.LuzIntensidad < 0f) { estado.LuzIntensidad = punto.buttonLight.intensity; estado.LuzColor = punto.buttonLight.color; punto.buttonLight.intensity = Mathf.Max(estado.LuzIntensidad * 3f, 5f); punto.buttonLight.color = Color.green; } if ((Object)(object)punto.buttonGrabObject != (Object)null) { Vector3 position = ((Component)punto.buttonGrabObject).transform.position; Vector3 position2 = ((Component)punto).transform.position; Plugin.Debug("Boton en " + ((Vector3)(ref position)).ToString("F1") + ", extractor en " + ((Vector3)(ref position2)).ToString("F1") + ", " + $"separacion {Vector3.Distance(position, position2):F1} m."); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("No se pudo encender el boton: " + ex.Message)); } } private static void DesplegarEstacion(Transform estacion, ExtractionPoint punto) { //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Expected O, but got Unknown //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_03f5: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Expected O, but got Unknown //IL_0467: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_0532: Unknown result type (might be due to invalid IL or missing references) //IL_0537: Unknown result type (might be due to invalid IL or missing references) //IL_0577: Unknown result type (might be due to invalid IL or missing references) //IL_057c: Unknown result type (might be due to invalid IL or missing references) //IL_05d4: Unknown result type (might be due to invalid IL or missing references) //IL_05db: Expected O, but got Unknown try { Transform[] componentsInChildren = ((Component)estacion).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } } int num = 0; int num2 = 0; Renderer[] componentsInChildren2 = ((Component)estacion).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren2) { num2++; if (!val2.enabled) { val2.enabled = true; num++; } } if (SoloElBoton.Value) { List list = new List(); string[] array = (PiezasVisibles.Value ?? "").Split(','); foreach (string text in array) { if (!string.IsNullOrEmpty(text.Trim())) { list.Add(text.Trim()); } } List list2 = new List(); foreach (Transform item in estacion) { Transform val3 = item; bool flag = false; foreach (string item2 in list) { if (string.Equals(item2, ((Object)val3).name, StringComparison.OrdinalIgnoreCase)) { flag = true; break; } } ((Component)val3).gameObject.SetActive(flag); if (!flag) { list2.Add(((Object)val3).name); } } componentsInChildren2 = ((Component)estacion).GetComponents(); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].enabled = false; } if (list2.Count > 0) { Plugin.Debug("Mobiliario oculto: " + string.Join(", ", list2.ToArray())); } } estacion.localScale = Vector3.one * EscalaBoton.Value; Vector3 val4 = (((Object)(object)punto.ramp != (Object)null) ? punto.ramp.position : (((Object)(object)punto.platform != (Object)null) ? punto.platform.position : ((Component)punto).transform.position)); Vector3 val5 = val4 - ((Component)punto).transform.position; val5.y = 0f; val5 = ((((Vector3)(ref val5)).sqrMagnitude < 0.01f) ? ((Component)punto).transform.forward : ((Vector3)(ref val5)).normalized); Vector3 val6 = Vector3.Cross(Vector3.up, val5); estacion.rotation = Quaternion.LookRotation(val5, Vector3.up) * Quaternion.Euler(0f, GiroBoton.Value, 0f); Vector3 val7 = val4 + val6 * DesplazamientoX.Value + Vector3.up * DesplazamientoY.Value + val5 * DesplazamientoZ.Value; if (UsarPato.Value) { ((Component)estacion).gameObject.SetActive(false); CrearPato(EstadoDe(punto), val7); return; } Transform val8 = null; foreach (Transform item3 in estacion) { Transform val9 = item3; if (((Component)val9).gameObject.activeSelf && string.Equals(((Object)val9).name, "Shop Button", StringComparison.OrdinalIgnoreCase)) { val8 = val9; break; } } if ((Object)(object)val8 == (Object)null) { foreach (Transform item4 in estacion) { Transform val10 = item4; if (((Component)val10).gameObject.activeSelf) { val8 = val10; break; } } } Vector3 val11 = (((Object)(object)val8 != (Object)null) ? (val8.position - estacion.position) : Vector3.zero); estacion.position = val7 - val11; Plugin.Debug("Pieza de referencia: " + (((Object)(object)val8 == (Object)null) ? "ninguna" : ((Object)val8).name) + ", desfase=" + ((Vector3)(ref val11)).ToString("F2")); string[] obj = new string[8] { "Referencia: rampa=", null, null, null, null, null, null, null }; Vector3 val12; object obj2; if (!((Object)(object)punto.ramp == (Object)null)) { val12 = punto.ramp.position; obj2 = ((Vector3)(ref val12)).ToString("F1"); } else { obj2 = "NULA"; } obj[1] = (string)obj2; obj[2] = " plataforma="; object obj3; if (!((Object)(object)punto.platform == (Object)null)) { val12 = punto.platform.position; obj3 = ((Vector3)(ref val12)).ToString("F1"); } else { obj3 = "NULA"; } obj[3] = (string)obj3; obj[4] = " haciaFuera="; obj[5] = ((Vector3)(ref val5)).ToString("F2"); obj[6] = " lateral="; obj[7] = ((Vector3)(ref val6)).ToString("F2"); Plugin.Debug(string.Concat(obj)); string[] obj4 = new string[12] { "Pedestal '", ((Object)estacion).name, "': colocado en ", ((Vector3)(ref val7)).ToString("F1"), " (extractor en ", null, null, null, null, null, null, null }; val12 = ((Component)punto).transform.position; obj4[5] = ((Vector3)(ref val12)).ToString("F1"); obj4[6] = ") "; obj4[7] = $"activoEnJerarquia={((Component)estacion).gameObject.activeInHierarchy} "; obj4[8] = "escala="; val12 = estacion.lossyScale; obj4[9] = ((Vector3)(ref val12)).ToString("F2"); obj4[10] = " "; obj4[11] = $"renderers={num2} (reactivados {num}) hijos={estacion.childCount}"; Plugin.Debug(string.Concat(obj4)); foreach (Transform item5 in estacion) { Transform val13 = item5; Plugin.Debug($" hijo '{((Object)val13).name}' activo={((Component)val13).gameObject.activeSelf}"); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Fallo al desplegar el pedestal: " + ex.Message)); } } internal static void DesnudarPato(GameObject pato) { //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pato == (Object)null) { return; } string[] array = new string[7] { "ItemRubberDuck", "HurtCollider", "ItemEquippable", "ItemBattery", "ItemToggle", "ParticleScriptExplosion", "ItemDeactivatedUntilLevel" }; MonoBehaviour[] componentsInChildren = pato.GetComponentsInChildren(true); foreach (MonoBehaviour val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } string name = ((object)val).GetType().Name; string[] array2 = array; foreach (string text in array2) { if (name == text) { Object.Destroy((Object)(object)val); break; } } } MapCustom[] componentsInChildren2 = pato.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.Destroy((Object)(object)componentsInChildren2[i]); } ItemBattery[] componentsInChildren3 = pato.GetComponentsInChildren(true); foreach (ItemBattery val2 in componentsInChildren3) { if ((Object)(object)val2.batteryTransform != (Object)null) { ((Component)val2.batteryTransform).gameObject.SetActive(false); } } componentsInChildren = pato.GetComponentsInChildren(true); foreach (MonoBehaviour val3 in componentsInChildren) { if (!((Object)(object)val3 == (Object)null)) { string name2 = ((object)val3).GetType().Name; if (name2 == "BatteryUI" || name2 == "ItemEquipCube") { ((Component)val3).gameObject.SetActive(false); } } } componentsInChildren = pato.GetComponentsInChildren(true); foreach (MonoBehaviour val4 in componentsInChildren) { if (!((Object)(object)val4 == (Object)null)) { string name3 = ((object)val4).GetType().Name; if (name3 == "ItemEquipCube" || name3 == "BatteryUI") { Object.Destroy((Object)(object)((Component)val4).gameObject); } } } Animator[] componentsInChildren4 = pato.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren4.Length; i++) { ((Behaviour)componentsInChildren4[i]).enabled = false; } AudioSource[] componentsInChildren5 = pato.GetComponentsInChildren(true); foreach (AudioSource obj in componentsInChildren5) { obj.Stop(); ((Behaviour)obj).enabled = false; } ParticleSystem[] componentsInChildren6 = pato.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren6.Length; i++) { componentsInChildren6[i].Stop(); } TrailRenderer[] componentsInChildren7 = pato.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren7.Length; i++) { ((Renderer)componentsInChildren7[i]).enabled = false; } ItemEquippable[] componentsInChildren8 = pato.GetComponentsInChildren(true); foreach (ItemEquippable val5 in componentsInChildren8) { ((Behaviour)val5).enabled = false; _equipablesDelPato.Add(val5); } Plugin.Debug($"Pato: {_equipablesDelPato.Count} ItemEquippable silenciados."); Rigidbody[] componentsInChildren9 = pato.GetComponentsInChildren(true); foreach (Rigidbody obj2 in componentsInChildren9) { obj2.isKinematic = true; obj2.useGravity = false; } RegistrarPato(pato); if (Plugin.VerboseLogging == null || !Plugin.VerboseLogging.Value) { return; } List list = new List(); Renderer[] componentsInChildren10 = pato.GetComponentsInChildren(true); foreach (Renderer val6 in componentsInChildren10) { if (val6.enabled && ((Component)val6).gameObject.activeInHierarchy) { list.Add(((Object)((Component)val6).gameObject).name + "(" + ((object)val6).GetType().Name + ")"); } } List list2 = new List(); componentsInChildren = pato.GetComponentsInChildren(true); foreach (MonoBehaviour val7 in componentsInChildren) { if ((Object)(object)val7 != (Object)null) { list2.Add(((object)val7).GetType().Name + "@" + ((Object)((Component)val7).gameObject).name); } } Plugin.Debug("Pato desnudado. Piezas visibles: " + string.Join(", ", list.ToArray())); Plugin.Debug("Componentes que quedan: " + string.Join(", ", list2.ToArray())); List list3 = new List(); ItemEquipCube[] array3 = Object.FindObjectsOfType(); foreach (ItemEquipCube val8 in array3) { float num = Vector3.Distance(((Component)val8).transform.position, pato.transform.position); if (!(num > 4f)) { Transform root = ((Component)val8).transform.root; bool flag = ((Component)val8).transform.IsChildOf(pato.transform); list3.Add($"'{((Object)((Component)val8).gameObject).name}' raiz='{((Object)root).name}' a {num:F1}m " + (flag ? "(del pato)" : "(AJENO)")); } } Plugin.Debug((list3.Count == 0) ? "No hay ningun ItemEquipCube cerca del pato." : ("Cubos de equipar cerca: " + string.Join(" | ", list3.ToArray()))); } private static void RegistrarPato(GameObject pato) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) PhysGrabObject component = pato.GetComponent(); if ((Object)(object)component == (Object)null) { return; } ExtractionPoint punto = null; float num = float.MaxValue; ExtractionPoint[] array = Object.FindObjectsOfType(); foreach (ExtractionPoint val in array) { float num2 = Vector3.Distance(((Component)val).transform.position, pato.transform.position); if (num2 < num) { num = num2; punto = val; } } if (_patos.TryGetValue(component, out var value)) { value.Punto = punto; } else { _patos.Add(component, new Vinculo { Punto = punto }); } Plugin.Debug($"Pato registrado, extractor mas cercano a {num:F1} m."); } private static void AvisarPorQueNoSePuede(Estado estado) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) string text = ((!estado.Activo) ? "Este extractor todavia no esta activo" : (estado.MetaConocida ? $"Faltan {estado.FaltaBotin:N0} de botin" : "Espera, el extractor aun no ha pedido su botin")); if (!(Time.time - _ultimoAvisoPato < 1.5f)) { _ultimoAvisoPato = Time.time; Plugin.Debug("Pato pulsado y no se puede: " + text + "."); SemiFunc.UIFocusText(text, new Color(1f, 0.6f, 0.2f), Color.white, 3f); } } private static Item BuscarItemPato() { if (_patoBuscado) { return _itemPato; } _patoBuscado = true; string text = (NombrePato.Value ?? "").Trim(); try { List list = new List(); Item[] array = Resources.LoadAll(""); foreach (Item val in array) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.itemName)) { if (string.Equals(val.itemName, text, StringComparison.OrdinalIgnoreCase)) { _itemPato = val; break; } if (val.itemName.IndexOf("duck", StringComparison.OrdinalIgnoreCase) >= 0) { list.Add(val); } } } if ((Object)(object)_itemPato == (Object)null && list.Count > 0) { _itemPato = list[0]; } if (list.Count > 0) { List list2 = new List(); foreach (Item item in list) { list2.Add("'" + item.itemName + "'"); } Plugin.Debug("Items tipo pato disponibles: " + string.Join(", ", list2.ToArray())); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Fallo buscando el item del pato: " + ex.Message)); } if ((Object)(object)_itemPato == (Object)null) { Plugin.Log.LogWarning((object)("No encontre ningun item llamado '" + text + "' ni con 'duck' en el nombre.")); } else { Plugin.Debug("Item del pato: '" + _itemPato.itemName + "' (buscaba '" + text + "')."); } return _itemPato; } private static void CrearPato(Estado estado, Vector3 posicion) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)estado.Pato != (Object)null) { return; } Item val = BuscarItemPato(); if ((Object)(object)val == (Object)null || val.prefab == null) { return; } Quaternion val2 = val.spawnRotationOffset * Quaternion.Euler(GiroPatoX.Value, GiroPatoY.Value, GiroPatoZ.Value); GameObject val3; if (GameManager.instance.gameMode == 0) { val3 = Object.Instantiate(((PrefabRef)(object)val.prefab).Prefab, posicion, val2); DesnudarPato(val3); } else { val3 = PhotonNetwork.InstantiateRoomObject(((PrefabRef)(object)val.prefab).ResourcePath, posicion, val2, (byte)0, new object[1] { "RepoAmigos:BotonPato" }); } if ((Object)(object)val3 == (Object)null) { Plugin.Log.LogWarning((object)"No se pudo crear el pato."); return; } Transform transform = val3.transform; transform.localScale *= EscalaPato.Value; estado.Pato = val3.GetComponent(); estado.PatoPosicion = posicion; estado.PatoRotacion = val2; if (Plugin.VerboseLogging != null && Plugin.VerboseLogging.Value) { List list = new List(); Component[] components = val3.GetComponents(); foreach (Component val4 in components) { if ((Object)(object)val4 != (Object)null) { list.Add(((object)val4).GetType().Name); } } Plugin.Debug("Prefab creado: '" + ((Object)val3).name + "' (ruta '" + ((PrefabRef)(object)val.prefab).ResourcePath + "'). Componentes: " + string.Join(", ", list.ToArray())); } Plugin.Debug("Pato colocado en " + ((Vector3)(ref posicion)).ToString("F1") + " (PhysGrabObject=" + (((Object)(object)estado.Pato == (Object)null) ? "NULO" : "ok") + ")."); } private static void RetirarPato(Estado estado) { if (!((Object)(object)estado.Pato == (Object)null) && SemiFunc.IsMasterClientOrSingleplayer()) { GameObject gameObject = ((Component)estado.Pato).gameObject; estado.Pato = null; if (SemiFunc.IsMultiplayer()) { PhotonNetwork.Destroy(gameObject); } else { Object.Destroy((Object)(object)gameObject); } Plugin.Debug("Pato retirado."); } } internal static void DestruirSalvoQueLoConservemos(Object objeto) { if (Enabled == null || !Enabled.Value || BotonGrande == null || !BotonGrande.Value) { Object.Destroy(objeto); } } } internal static class GeneradorDePruebas { [HarmonyPatch(typeof(RunManager), "Update")] private static class EngancheDeTeclado { private static bool _primeraVez = true; private static void Postfix() { if (_primeraVez) { _primeraVez = false; Plugin.Log.LogInfo((object)"Pruebas: RunManager.Update esta corriendo. Enganche OK."); } Tick("RunManager"); } } [HarmonyPatch(typeof(RunManager), "ChangeLevel")] private static class SondaCambioDeNivel { private static void Postfix() { Plugin.Log.LogInfo((object)"Pruebas: sonda ChangeLevel ejecutada. Los parches SI corren."); } } internal static ConfigEntry Enabled; internal static ConfigEntry Tecla; internal static ConfigEntry ValorMin; internal static ConfigEntry ValorMax; internal static ConfigEntry Cantidad; private static bool _diagnosticoEscrito; private static int _teclasRegistradas; private static int _ultimoFrame = -1; private static readonly string[] _listasPorTamano = new string[3] { "smallValuables", "tinyValuables", "mediumValuables" }; internal static void BindConfig(ConfigFile config) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown Enabled = config.Bind("Pruebas", "Activado", true, "Permite generar objetos de valor con una tecla para probar el mod. Ponlo en false cuando juegues en serio."); Tecla = config.Bind("Pruebas", "Tecla", (KeyCode)284, "Tecla que genera los objetos."); ValorMin = config.Bind("Pruebas", "ValorMinimo", 2000, new ConfigDescription("Precio minimo de cada objeto generado.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 1000000), Array.Empty())); ValorMax = config.Bind("Pruebas", "ValorMaximo", 9000, new ConfigDescription("Precio maximo de cada objeto generado.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 1000000), Array.Empty())); Cantidad = config.Bind("Pruebas", "CantidadPorPulsacion", 1, new ConfigDescription("Cuantos objetos salen con cada pulsacion.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 20), Array.Empty())); } private static bool TeclaPulsada() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) try { Keyboard current = Keyboard.current; if (current != null && Enum.TryParse(((object)Tecla.Value/*cast due to .constrained prefix*/).ToString(), ignoreCase: true, out Key result)) { KeyControl val = current[result]; if (val != null && ((ButtonControl)val).wasPressedThisFrame) { return true; } } } catch { } try { if (Input.GetKeyDown(Tecla.Value)) { return true; } } catch { } return false; } private static void EspiarTeclado() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (Plugin.VerboseLogging == null || !Plugin.VerboseLogging.Value || _teclasRegistradas >= 25) { return; } try { Keyboard current = Keyboard.current; if (current == null || !((ButtonControl)current.anyKey).wasPressedThisFrame) { return; } Enumerator enumerator = current.allKeys.GetEnumerator(); try { while (enumerator.MoveNext()) { KeyControl current2 = enumerator.Current; if (((ButtonControl)current2).wasPressedThisFrame) { _teclasRegistradas++; Plugin.Log.LogInfo((object)$"Pruebas: tecla pulsada = {current2.keyCode} (la configurada es {Tecla.Value})"); if (_teclasRegistradas >= 25) { Plugin.Log.LogInfo((object)"Pruebas: dejo de anotar teclas para no llenar el log."); break; } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } } catch { } } private static bool LegacyOperativo() { try { Input.GetKeyDown((KeyCode)294); return true; } catch { return false; } } internal static void Tick(string origen) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) if (Enabled == null || !Enabled.Value || Time.frameCount == _ultimoFrame) { return; } _ultimoFrame = Time.frameCount; if (!_diagnosticoEscrito) { _diagnosticoEscrito = true; bool flag = false; try { flag = Keyboard.current != null; } catch { } Plugin.Log.LogInfo((object)($"Pruebas: activo via {origen}. Tecla configurada = {Tecla.Value}. " + "InputSystem nuevo = " + (flag ? "SI" : "no") + ", Input clasico = " + (LegacyOperativo() ? "SI" : "no") + ".")); } EspiarTeclado(); if (!TeclaPulsada()) { return; } Plugin.Log.LogInfo((object)$"Pruebas: {Tecla.Value} detectada."); if (!SemiFunc.IsMasterClientOrSingleplayer()) { Plugin.Log.LogWarning((object)"F3: solo funciona si eres el anfitrion de la partida."); return; } if ((Object)(object)ValuableDirector.instance == (Object)null) { Plugin.Log.LogWarning((object)"F3: todavia no estas en un nivel."); return; } int num = 0; for (int i = 0; i < Cantidad.Value; i++) { if (Generar(i)) { num++; } } if (num > 0) { Plugin.Log.LogInfo((object)$"F3: generados {num} objeto(s) de prueba."); } } private static List ElegirLista() { string[] listasPorTamano = _listasPorTamano; foreach (string text in listasPorTamano) { FieldInfo fieldInfo = AccessTools.Field(typeof(ValuableDirector), text); if (!(fieldInfo == null) && fieldInfo.GetValue(ValuableDirector.instance) is List { Count: >0 } list) { return list; } } return null; } private static bool Generar(int indice) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar val = SemiFunc.PlayerAvatarLocal(); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"F3: no encuentro al jugador local."); return false; } List list = ElegirLista(); if (list == null) { Plugin.Log.LogWarning((object)"F3: las listas de objetos del nivel estan vacias."); return false; } PrefabRef val2 = list[Random.Range(0, list.Count)]; Transform transform = ((Component)val).transform; float num = (float)indice * 0.9f; Vector3 val3 = new Vector3(Mathf.Sin(num), 0f, Mathf.Cos(num)) * 0.35f; Vector3 val4 = transform.position + transform.forward * 1.4f + Vector3.up * 1.1f + val3; GameObject val5 = ((GameManager.instance.gameMode != 0) ? PhotonNetwork.InstantiateRoomObject(((PrefabRef)(object)val2).ResourcePath, val4, Quaternion.identity, (byte)0, (object[])null) : Object.Instantiate(((PrefabRef)(object)val2).Prefab, val4, Quaternion.identity)); if ((Object)(object)val5 == (Object)null) { Plugin.Log.LogWarning((object)("F3: no se pudo crear '" + ((PrefabRef)(object)val2).ResourcePath + "'.")); return false; } ValuableObject component = val5.GetComponent(); if ((Object)(object)component == (Object)null) { Plugin.Log.LogWarning((object)"F3: el prefab creado no tiene ValuableObject."); return false; } int num2 = Random.Range(ValorMin.Value, ValorMax.Value + 1); AccessTools.Field(typeof(ValuableObject), "dollarValueOverride").SetValue(component, num2); component.DollarValueSetLogic(); if (SemiFunc.IsMultiplayer()) { PhotonView component2 = val5.GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.RPC("DollarValueSetRPC", (RpcTarget)1, new object[1] { (float)num2 }); } } Plugin.Debug($"F3: '{((PrefabRef)(object)val2).PrefabName}' generado por ${num2}."); return true; } } internal static class ReviveEnExtractor { private sealed class Estado { public float Temporizador = -1f; public bool YaRevivido; } [HarmonyPatch(typeof(PlayerDeathHead), "Update")] private static class RevivirPorEstarDentro { private static void Postfix(PlayerDeathHead __instance, bool ___inExtractionPoint, bool ___triggered) { if (!Enabled.Value || !SemiFunc.IsMasterClientOrSingleplayer()) { return; } Estado orCreateValue = _estados.GetOrCreateValue(__instance); if (!___inExtractionPoint || !___triggered) { orCreateValue.Temporizador = Segundos.Value; orCreateValue.YaRevivido = false; } else if (!orCreateValue.YaRevivido) { if (orCreateValue.Temporizador < 0f) { orCreateValue.Temporizador = Segundos.Value; } orCreateValue.Temporizador -= Time.deltaTime; if (!(orCreateValue.Temporizador > 0f) && !((Object)(object)__instance.playerAvatar == (Object)null)) { orCreateValue.YaRevivido = true; Plugin.Debug("Reviviendo a " + ((Object)__instance.playerAvatar).name + " desde el extractor."); __instance.Revive(); } } } } internal static ConfigEntry Enabled; internal static ConfigEntry Segundos; private static readonly ConditionalWeakTable _estados = new ConditionalWeakTable(); internal static void BindConfig(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown Enabled = config.Bind("RevivirEnExtractor", "Activado", true, "Si esta activado, dejar la cabeza de un companero muerto dentro de un extractor lo revive tras unos segundos, sin necesidad de completar la extraccion."); Segundos = config.Bind("RevivirEnExtractor", "SegundosDeEspera", 2f, new ConfigDescription("Tiempo que la cabeza debe permanecer dentro del extractor antes de revivir. El camion usa 2 segundos en vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 30f), Array.Empty())); } } internal enum Rol : byte { Ninguno, Medico, Ingeniero, Saboteador, Rastreador } internal static class Roles { [HarmonyPatch(typeof(RunManager), "ChangeLevel")] private static class MarcarRepartoAlCambiarNivel { private static void Postfix() { ComprobacionDeVersion.AlCambiarNivel(); if (Enabled != null && Enabled.Value) { if (_repartoHecho && !RepartirCadaNivel.Value) { _esperaAnuncio = 4f; return; } _pendienteRepartir = true; _esperaReparto = 3f; Plugin.Debug("Roles: cambio de nivel, reparto pendiente."); } } } [HarmonyPatch(typeof(RunManager), "Update")] private static class TicPorFrame { private static void Postfix() { AsegurarRed(); ComprobacionDeVersion.Tick(); TicDelRecordatorio(); if (Enabled == null || !Enabled.Value) { return; } if (_pendienteRepartir) { IntentarRepartir(); } RevisarHuerfanos(); RedifundirDeVezEnCuando(); if (_esperaAnuncio > 0f) { _esperaAnuncio -= Time.deltaTime; if (_esperaAnuncio <= 0f) { _esperaAnuncio = -1f; Anunciar(); } } RolMedico.Tick(); RolIngeniero.Tick(); RolSaboteador.Tick(); RolRastreador.Tick(); } } internal enum EscribiendoResultado { No, Si, NoSePuedeSaber } internal static ConfigEntry Enabled; internal static ConfigEntry MinJugadores; internal static ConfigEntry RepartirCadaNivel; internal static ConfigEntry AnunciarRol; internal static ConfigEntry RecordarRol; internal static ConfigEntry TeclaRecordar; internal static readonly Color ColorMedico = new Color(0.4f, 1f, 0.5f); internal static readonly Color ColorIngeniero = new Color(0.4f, 0.8f, 1f); internal static readonly Color ColorSaboteador = new Color(1f, 0.3f, 0.3f); internal static readonly Color ColorRastreador = new Color(1f, 0.85f, 0.3f); internal static readonly Color ColorSinRol = new Color(0.75f, 0.75f, 0.75f); private static readonly Dictionary _asignados = new Dictionary(); private static Rol _local = Rol.Ninguno; private static bool _repartoHecho; private static bool _pendienteRepartir; private static float _esperaReparto; private static float _esperaAnuncio = -1f; private static readonly FieldInfo _campoTemporizadorUI = AccessTools.Field(typeof(MissionUI), "messageTimer"); private static bool _recordatorioEnPantalla; private static readonly FieldInfo _campoChatActivo = AccessTools.Field(typeof(ChatManager), "chatActive"); internal const byte EventoReparto = 175; internal const byte EventoSabotaje = 176; internal const byte EventoApagon = 177; internal const byte EventoVersion = 178; internal const byte EventoRecarga = 179; private static bool _redConectada; private static float _proximaRevisionHuerfanos = 5f; private static float _proximaRedifusion = 20f; internal static Rol Local { get { if (Enabled == null || !Enabled.Value) { return Rol.Ninguno; } return _local; } } internal static event Action AlRepartir; internal static void BindConfig(ConfigFile config) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown Enabled = config.Bind("Roles", "Activado", true, "Reparte roles secretos (medico, ingeniero, saboteador, rastreador) al empezar cada nivel. Cada rol se activa ademas por su cuenta en su propia seccion."); MinJugadores = config.Bind("Roles", "MinimoJugadores", 3, new ConfigDescription("Por debajo de esta cantidad de jugadores no se reparte ningun rol. Con dos personas un saboteador no tiene gracia.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 20), Array.Empty())); RepartirCadaNivel = config.Bind("Roles", "RepartirCadaNivel", true, "true: se vuelven a sortear los roles en cada nivel, asi todos van rotando. false: se sortean una vez y duran toda la partida."); AnunciarRol = config.Bind("Roles", "AnunciarRol", true, "Muestra en pantalla que rol te ha tocado al empezar el nivel. Solo lo ves tu: el reparto de los demas no se anuncia a nadie."); RecordarRol = config.Bind("Roles", "RecordarRol", true, "Permite volver a ver en cualquier momento que rol tienes y como se usa, pulsando la tecla de abajo. El aviso del principio del nivel se pierde enseguida y luego no habia forma de consultarlo."); TeclaRecordar = config.Bind("Roles", "TeclaRecordar", (KeyCode)9, "Tecla que recuerda tu rol. Tab es tambien la del mapa del juego, asi que las dos cosas salen a la vez; no se pisan, pero se puede cambiar aqui."); } internal static bool SoyEl(Rol rol) { if (rol != Rol.Ninguno) { return Local == rol; } return false; } internal static bool RolEnJuego(Rol rol) { if (Enabled == null || !Enabled.Value) { return false; } List list = SemiFunc.PlayerGetAll(); if (list == null || list.Count == 0) { return false; } foreach (KeyValuePair asignado in _asignados) { if (asignado.Value != rol) { continue; } foreach (PlayerAvatar item in list) { if (!((Object)(object)item == (Object)null) && SemiFunc.PlayerGetSteamID(item) == asignado.Key) { return true; } } } return false; } private static void IntentarRepartir() { _esperaReparto -= Time.deltaTime; if (!(_esperaReparto > 0f) && !((Object)(object)RunManager.instance == (Object)null) && SemiFunc.RunIsLevel() && !((Object)(object)PlayerAvatar.instance == (Object)null) && (!SemiFunc.IsMultiplayer() || PhotonNetwork.InRoom) && SemiFunc.IsMasterClientOrSingleplayer()) { Repartir(); } } private static void Repartir() { _pendienteRepartir = false; List list = SemiFunc.PlayerGetAll(); if (list == null || list.Count == 0) { _pendienteRepartir = true; _esperaReparto = 1f; return; } _asignados.Clear(); if (list.Count < MinJugadores.Value) { Plugin.Debug($"Roles: solo {list.Count} jugadores, minimo {MinJugadores.Value}. Sin roles."); Difundir(repartoNuevo: true); Aplicar(repartoNuevo: true); return; } List list2 = new List(); if (RolIngeniero.Enabled.Value) { list2.Add(Rol.Ingeniero); } if (RolMedico.Enabled.Value) { list2.Add(Rol.Medico); } if (RolSaboteador.Enabled.Value) { list2.Add(Rol.Saboteador); } if (RolRastreador.Enabled.Value) { list2.Add(Rol.Rastreador); } List list3 = new List(list); for (int num = list3.Count - 1; num > 0; num--) { int index = Random.Range(0, num + 1); PlayerAvatar value = list3[num]; list3[num] = list3[index]; list3[index] = value; } int num2 = 0; for (int i = 0; i < list3.Count; i++) { if (num2 >= list2.Count) { break; } string text = SemiFunc.PlayerGetSteamID(list3[i]); if (!string.IsNullOrEmpty(text)) { _asignados[text] = list2[num2]; num2++; } } _repartoHecho = true; Plugin.Debug($"Roles: repartidos {num2} de {list2.Count} entre {list.Count} jugadores."); Difundir(repartoNuevo: true); Aplicar(repartoNuevo: true); } private static void Aplicar(bool repartoNuevo) { Rol local = _local; _local = Rol.Ninguno; PlayerAvatar instance = PlayerAvatar.instance; if ((Object)(object)instance != (Object)null) { string text = SemiFunc.PlayerGetSteamID(instance); if (!string.IsNullOrEmpty(text) && _asignados.TryGetValue(text, out var value)) { _local = value; } } bool flag = _local != local; if (repartoNuevo || flag) { Plugin.Log.LogInfo((object)$"Roles: me ha tocado {_local}."); } if ((repartoNuevo || flag) && Roles.AlRepartir != null) { Roles.AlRepartir(); } if (repartoNuevo || flag) { _esperaAnuncio = (AnunciarRol.Value ? 2f : (-1f)); } } private static void Anunciar() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) switch (_local) { case Rol.Medico: SemiFunc.UIBigMessage("ERES EL MEDICO", "+", 40f, new Color(0.4f, 1f, 0.5f), Color.white); RolMedico.AvisarUso(); break; case Rol.Ingeniero: SemiFunc.UIBigMessage("ERES EL INGENIERO", "*", 40f, new Color(0.4f, 0.8f, 1f), Color.white); RolIngeniero.AvisarUso(); break; case Rol.Saboteador: SemiFunc.UIBigMessage("ERES EL SABOTEADOR", "!", 40f, new Color(1f, 0.3f, 0.3f), Color.white); RolSaboteador.AvisarUso(); break; case Rol.Rastreador: SemiFunc.UIBigMessage("ERES EL RASTREADOR", "?", 40f, new Color(1f, 0.85f, 0.3f), Color.white); RolRastreador.AvisarUso(); break; } } private static string TextoDelRecordatorio(out Color color) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) if (Enabled != null && Enabled.Value) { switch (_local) { case Rol.Medico: color = ColorMedico; return "ERES EL MEDICO - " + RolMedico.TextoDeUso(); case Rol.Ingeniero: color = ColorIngeniero; return "ERES EL INGENIERO - " + RolIngeniero.TextoDeUso(); case Rol.Saboteador: color = ColorSaboteador; return "ERES EL SABOTEADOR - " + RolSaboteador.TextoDeUso(); case Rol.Rastreador: color = ColorRastreador; return "ERES EL RASTREADOR - " + RolRastreador.TextoDeUso(); } } color = ColorSinRol; if (Enabled == null || !Enabled.Value) { return "SIN ROL - los roles estan desactivados en la configuracion"; } if (!_repartoHecho) { return "SIN ROL - todavia no se han repartido los roles de este nivel"; } int num = SemiFunc.PlayerGetAll()?.Count ?? 0; if (num >= MinJugadores.Value) { return "SIN ROL - este nivel no te ha tocado ningun rol"; } return $"SIN ROL - hacen falta {MinJugadores.Value} jugadores y sois {num}"; } private static bool MantenerAvisoVivo(float segundos) { if (_campoTemporizadorUI == null) { return false; } MissionUI instance = MissionUI.instance; if ((Object)(object)instance == (Object)null) { return false; } _campoTemporizadorUI.SetValue(instance, segundos); return true; } private static void TicDelRecordatorio() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (RecordarRol == null || !RecordarRol.Value) { return; } if (!EnPartida()) { _recordatorioEnPantalla = false; } else if (TeclaPulsada(TeclaRecordar.Value)) { SemiFunc.UIFocusText(TextoDelRecordatorio(out var color), color, Color.white, 0.4f); _recordatorioEnPantalla = true; } else if (_recordatorioEnPantalla) { if (TeclaMantenida(TeclaRecordar.Value)) { MantenerAvisoVivo(0.4f); } else { _recordatorioEnPantalla = false; } } } internal static EscribiendoResultado Escribiendo() { if (_campoChatActivo == null) { return EscribiendoResultado.NoSePuedeSaber; } ChatManager instance = ChatManager.instance; if ((Object)(object)instance == (Object)null) { return EscribiendoResultado.No; } object value = _campoChatActivo.GetValue(instance); if (!(value is bool)) { return EscribiendoResultado.NoSePuedeSaber; } if (!(bool)value) { return EscribiendoResultado.No; } return EscribiendoResultado.Si; } internal unsafe static bool TeclaMantenida(KeyCode tecla) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (Escribiendo() == EscribiendoResultado.Si) { return false; } try { Keyboard current = Keyboard.current; if (current != null && Enum.TryParse(((object)(*(KeyCode*)(&tecla))/*cast due to .constrained prefix*/).ToString(), ignoreCase: true, out Key result)) { KeyControl val = current[result]; if (val != null && ((ButtonControl)val).isPressed) { return true; } } } catch { } try { if (Input.GetKey(tecla)) { return true; } } catch { } return false; } internal unsafe static bool TeclaPulsada(KeyCode tecla) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (Escribiendo() == EscribiendoResultado.Si) { return false; } try { Keyboard current = Keyboard.current; if (current != null && Enum.TryParse(((object)(*(KeyCode*)(&tecla))/*cast due to .constrained prefix*/).ToString(), ignoreCase: true, out Key result)) { KeyControl val = current[result]; if (val != null && ((ButtonControl)val).wasPressedThisFrame) { return true; } } } catch { } try { if (Input.GetKeyDown(tecla)) { return true; } } catch { } return false; } internal static bool EnPartida() { if ((Object)(object)RunManager.instance != (Object)null && (Object)(object)PlayerAvatar.instance != (Object)null) { return SemiFunc.RunIsLevel(); } return false; } private static void AsegurarRed() { if (!_redConectada && PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.EventReceived -= AlRecibirEvento; PhotonNetwork.NetworkingClient.EventReceived += AlRecibirEvento; _redConectada = true; Plugin.Debug("Roles: enganchado al canal de eventos de Photon."); } } internal static void DesconectarRed() { if (_redConectada) { if (PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.EventReceived -= AlRecibirEvento; } _redConectada = false; } } private static void AlRecibirEvento(EventData datos) { try { switch (datos.Code) { case 175: RecibirReparto(datos.CustomData); break; case 176: if (SemiFunc.IsMasterClient()) { RolSaboteador.EjecutarBoostEnemigos(datos.CustomData); } break; case 177: RolSaboteador.EjecutarApagon(datos.CustomData); break; case 178: ComprobacionDeVersion.Recibir(datos.CustomData); break; case 179: if (SemiFunc.IsMasterClient()) { RolIngeniero.EjecutarRecargaRemota(datos.CustomData); } break; } } catch (Exception arg) { Plugin.Log.LogError((object)($"Roles: fallo procesando el evento {datos.Code}. " + $"Se ignora para no tumbar la conexion.\n{arg}")); } } private static void RevisarHuerfanos() { if (!_repartoHecho || !SemiFunc.IsMasterClientOrSingleplayer() || !EnPartida()) { return; } _proximaRevisionHuerfanos -= Time.deltaTime; if (_proximaRevisionHuerfanos > 0f) { return; } _proximaRevisionHuerfanos = 5f; List list = SemiFunc.PlayerGetAll(); if (list == null || list.Count == 0) { return; } List list2 = new List(); foreach (PlayerAvatar item in list) { if (!((Object)(object)item == (Object)null)) { string text = SemiFunc.PlayerGetSteamID(item); if (!string.IsNullOrEmpty(text)) { list2.Add(text); } } } if (list2.Count == 0) { return; } List list3 = new List(); List list4 = new List(); foreach (KeyValuePair asignado in _asignados) { if (!list2.Contains(asignado.Key)) { list3.Add(asignado.Key); list4.Add(asignado.Value); } } if (list3.Count == 0) { return; } foreach (string item2 in list3) { _asignados.Remove(item2); } List list5 = new List(); foreach (string item3 in list2) { if (!_asignados.ContainsKey(item3)) { list5.Add(item3); } } list4.Sort((Rol a, Rol b) => Prioridad(a).CompareTo(Prioridad(b))); int num = 0; for (int num2 = 0; num2 < list4.Count && num2 < list5.Count; num2++) { _asignados[list5[num2]] = list4[num2]; num++; } Plugin.Log.LogInfo((object)($"Roles: {list3.Count} rol(es) sin dueno tras una desconexion. " + $"Reasignados {num}, descartados {list4.Count - num}.")); Difundir(repartoNuevo: false); Aplicar(repartoNuevo: false); } private static int Prioridad(Rol rol) { return rol switch { Rol.Ingeniero => 0, Rol.Medico => 1, Rol.Saboteador => 2, _ => 3, }; } private static void RedifundirDeVezEnCuando() { if (_repartoHecho && SemiFunc.IsMasterClient()) { _proximaRedifusion -= Time.deltaTime; if (!(_proximaRedifusion > 0f)) { _proximaRedifusion = 20f; Difundir(repartoNuevo: false); } } } private static void Difundir(bool repartoNuevo) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown if (!SemiFunc.IsMultiplayer() || PhotonNetwork.NetworkingClient == null) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(repartoNuevo ? 'N' : 'R').Append('|'); bool flag = true; foreach (KeyValuePair asignado in _asignados) { if (!flag) { stringBuilder.Append(';'); } flag = false; stringBuilder.Append(asignado.Key).Append(':').Append((byte)asignado.Value); } PhotonNetwork.RaiseEvent((byte)175, (object)stringBuilder.ToString(), new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); } private static void RecibirReparto(object datos) { if (!(datos is string text)) { return; } int num = text.IndexOf('|'); if (num < 0) { return; } bool repartoNuevo = text.Substring(0, num) == "N"; string text2 = text.Substring(num + 1); Dictionary dictionary = new Dictionary(); if (text2.Length > 0) { string[] array = text2.Split(';'); foreach (string text3 in array) { int num2 = text3.LastIndexOf(':'); if (num2 > 0 && num2 != text3.Length - 1 && byte.TryParse(text3.Substring(num2 + 1), out var result)) { dictionary[text3.Substring(0, num2)] = (Rol)result; } } } if (EsElMismoReparto(dictionary)) { return; } _asignados.Clear(); foreach (KeyValuePair item in dictionary) { _asignados[item.Key] = item.Value; } _repartoHecho = true; Aplicar(repartoNuevo); } private static bool EsElMismoReparto(Dictionary otro) { if (!_repartoHecho) { return false; } if (_asignados.Count != otro.Count) { return false; } foreach (KeyValuePair item in otro) { if (!_asignados.TryGetValue(item.Key, out var value)) { return false; } if (value != item.Value) { return false; } } return true; } } internal static class RolIngeniero { internal static ConfigEntry Enabled; internal static ConfigEntry Tecla; internal static ConfigEntry Cargas; internal static ConfigEntry MinutosRecarga; private static int _cargas; private static float _temporizador; private static readonly FieldInfo _campoAgarrado = AccessTools.Field(typeof(PhysGrabber), "grabbedPhysGrabObject"); internal static void BindConfig(ConfigFile config) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown Enabled = config.Bind("Ingeniero", "Activado", true, "Mete el rol de ingeniero en el sorteo. El ingeniero recarga la bateria del objeto que lleve en las manos."); Tecla = config.Bind("Ingeniero", "Tecla", (KeyCode)106, "Tecla que recarga a tope el objeto que tengas agarrado."); config.Remove(new ConfigDefinition("Ingeniero", "AvisarAlRechazar")); Cargas = config.Bind("Ingeniero", "Cargas", 5, new ConfigDescription("Reparaciones disponibles a la vez.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 20), Array.Empty())); MinutosRecarga = config.Bind("Ingeniero", "MinutosRecarga", 5f, new ConfigDescription("Cada cuantos minutos se recupera UNA reparacion.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 30f), Array.Empty())); Roles.AlRepartir += delegate { if (Roles.SoyEl(Rol.Ingeniero)) { Reiniciar(); } }; } internal static void Reiniciar() { _cargas = Cargas.Value; _temporizador = MinutosRecarga.Value * 60f; } internal static string TextoDeUso() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return $"[{Tecla.Value}] recargar lo que lleves en las manos - {_cargas}/{Cargas.Value} reparaciones"; } internal static void AvisarUso() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) SemiFunc.UIFocusText(TextoDeUso(), Roles.ColorIngeniero, Color.white, 5f); } private static PhysGrabObject LoQueLlevoEnLasManos() { PhysGrabber instance = PhysGrabber.instance; if ((Object)(object)instance == (Object)null || !instance.grabbed) { return null; } if (_campoAgarrado == null) { return null; } object? value = _campoAgarrado.GetValue(instance); return (PhysGrabObject)((value is PhysGrabObject) ? value : null); } internal static void Tick() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (Enabled != null && Enabled.Value && Roles.SoyEl(Rol.Ingeniero) && Roles.EnPartida()) { RecargarCargas(); if (Roles.TeclaPulsada(Tecla.Value)) { Reparar(); } } } private static void RecargarCargas() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (_cargas < Cargas.Value) { _temporizador -= Time.deltaTime; if (!(_temporizador > 0f)) { _cargas++; _temporizador = MinutosRecarga.Value * 60f; SemiFunc.UIFocusText($"Reparacion recuperada ({_cargas}/{Cargas.Value})", new Color(0.4f, 0.8f, 1f), Color.white, 3f); Plugin.Debug($"Ingeniero: reparacion recuperada, ahora {_cargas}/{Cargas.Value}. " + $"Siguiente en {MinutosRecarga.Value * 60f:0} s."); } } } private static void Reparar() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Expected O, but got Unknown //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); ((Color)(ref val))..ctor(0.4f, 0.8f, 1f); Color val2 = default(Color); ((Color)(ref val2))..ctor(1f, 0.6f, 0.2f); if (_cargas <= 0) { int num = Mathf.CeilToInt(_temporizador); SemiFunc.UIFocusText($"Sin reparaciones - {num / 60}:{num % 60:00} para la siguiente", val2, Color.white, 3f); return; } PhysGrabObject val3 = LoQueLlevoEnLasManos(); if ((Object)(object)val3 == (Object)null) { SemiFunc.UIFocusText("Agarra algo para repararlo", val2, Color.white, 2f); return; } ItemBattery componentInChildren = ((Component)val3).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { SemiFunc.UIFocusText("Esto no lleva bateria", val2, Color.white, 2f); return; } if (componentInChildren.isUnchargable) { SemiFunc.UIFocusText("Esto no se puede recargar", val2, Color.white, 2f); return; } if (SemiFunc.IsMasterClientOrSingleplayer() && componentInChildren.batteryLife >= 99.5f) { SemiFunc.UIFocusText("Ya esta a tope de bateria", val2, Color.white, 2f); return; } _cargas--; if (_cargas == Cargas.Value - 1) { _temporizador = MinutosRecarga.Value * 60f; } if (SemiFunc.IsMasterClientOrSingleplayer()) { RecargarDelTodo(componentInChildren); SemiFunc.UIFocusText($"Bateria al maximo ({_cargas}/{Cargas.Value})", val, Color.white, 3f); Plugin.Debug($"Ingeniero: '{((Object)val3).name}' recargado. Quedan {_cargas} reparaciones."); return; } PhotonView component = ((Component)val3).GetComponent(); if ((Object)(object)component == (Object)null) { SemiFunc.UIFocusText("No puedo reparar esto por red", val2, Color.white, 2f); Plugin.Log.LogWarning((object)"Ingeniero: el objeto no tiene PhotonView; no se puede pedir la recarga."); _cargas++; } else { PhotonNetwork.RaiseEvent((byte)179, (object)component.ViewID, new RaiseEventOptions { Receivers = (ReceiverGroup)2 }, SendOptions.SendReliable); Plugin.Debug($"Ingeniero: no soy master, recarga pedida para el objeto {component.ViewID}."); SemiFunc.UIFocusText($"Recarga enviada ({_cargas}/{Cargas.Value})", val, Color.white, 3f); } } private static void RecargarDelTodo(ItemBattery bateria) { bateria.batteryLife = 100f; } internal static void EjecutarRecargaRemota(object datos) { if (!(datos is int num)) { Plugin.Log.LogWarning((object)$"Ingeniero: peticion de recarga con datos raros ({datos}). Ignorada."); return; } PhotonView val = PhotonView.Find(num); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)$"Ingeniero: recarga para el objeto {num}, que ya no existe."); return; } ItemBattery componentInChildren = ((Component)val).GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { Plugin.Log.LogWarning((object)$"Ingeniero: el objeto {num} no tiene ItemBattery."); return; } if (componentInChildren.isUnchargable) { Plugin.Log.LogWarning((object)$"Ingeniero: el objeto {num} no se puede recargar."); return; } RecargarDelTodo(componentInChildren); Plugin.Debug($"Ingeniero: recarga remota aplicada al objeto {num}."); } } internal static class RolMedico { internal static ConfigEntry Enabled; internal static ConfigEntry Tecla; internal static ConfigEntry Curacion; internal static ConfigEntry Cargas; internal static ConfigEntry MinutosRecarga; internal static ConfigEntry Alcance; private static int _cargas; private static float _temporizador; private static readonly FieldInfo _campoVida = AccessTools.Field(typeof(PlayerHealth), "health"); private static readonly FieldInfo _campoVidaMax = AccessTools.Field(typeof(PlayerHealth), "maxHealth"); private static readonly FieldInfo _campoDesactivado = AccessTools.Field(typeof(PlayerAvatar), "isDisabled"); internal static void BindConfig(ConfigFile config) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown Enabled = config.Bind("Medico", "Activado", true, "Mete el rol de medico en el sorteo."); Tecla = config.Bind("Medico", "Tecla", (KeyCode)103, "Tecla que cura al companero mas cercano que tengas a la vista."); Curacion = config.Bind("Medico", "PuntosPorCura", 20, new ConfigDescription("Vida que devuelve cada carga.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 200), Array.Empty())); Cargas = config.Bind("Medico", "Cargas", 3, new ConfigDescription("Curas disponibles a la vez.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 10), Array.Empty())); MinutosRecarga = config.Bind("Medico", "MinutosRecarga", 3f, new ConfigDescription("Cada cuantos minutos se recupera UNA carga. Con 3 cargas y 3 minutos, gastarlas todas y volver a tenerlas llenas son 9 minutos.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 30f), Array.Empty())); Alcance = config.Bind("Medico", "Alcance", 4f, new ConfigDescription("Distancia maxima para curar a un companero, en metros.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 20f), Array.Empty())); Roles.AlRepartir += delegate { if (Roles.SoyEl(Rol.Medico)) { Reiniciar(); } }; } internal static void Reiniciar() { _cargas = Cargas.Value; _temporizador = MinutosRecarga.Value * 60f; } internal static string TextoDeUso() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return $"[{Tecla.Value}] curar - {_cargas}/{Cargas.Value} cargas de {Curacion.Value} PV"; } internal static void AvisarUso() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) SemiFunc.UIFocusText(TextoDeUso(), Roles.ColorMedico, Color.white, 5f); } private static int Vida(PlayerHealth salud) { if (!(_campoVida == null)) { return (int)_campoVida.GetValue(salud); } return 0; } private static int VidaMax(PlayerHealth salud) { if (!(_campoVidaMax == null)) { return (int)_campoVidaMax.GetValue(salud); } return 0; } private static bool EstaMuerto(PlayerAvatar avatar) { if (_campoDesactivado != null) { return (bool)_campoDesactivado.GetValue(avatar); } return false; } internal static void Tick() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (Enabled != null && Enabled.Value && Roles.SoyEl(Rol.Medico) && Roles.EnPartida()) { RecargarCargas(); if (Roles.TeclaPulsada(Tecla.Value)) { Curar(); } } } private static void RecargarCargas() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (_cargas < Cargas.Value) { _temporizador -= Time.deltaTime; if (!(_temporizador > 0f)) { _cargas++; _temporizador = MinutosRecarga.Value * 60f; SemiFunc.UIFocusText($"Cura recuperada ({_cargas}/{Cargas.Value})", new Color(0.4f, 1f, 0.5f), Color.white, 3f); Plugin.Debug($"Medico: carga recuperada, ahora {_cargas}/{Cargas.Value}. " + $"Siguiente en {MinutosRecarga.Value * 60f:0} s."); } } } private static void Curar() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (_cargas <= 0) { int num = Mathf.CeilToInt(_temporizador); SemiFunc.UIFocusText($"Sin cargas - {num / 60}:{num % 60:00} para la siguiente", new Color(1f, 0.5f, 0.3f), Color.white, 3f); return; } PlayerAvatar val = BuscarHerido(); if ((Object)(object)val == (Object)null) { SemiFunc.UIFocusText("No hay nadie herido cerca", new Color(1f, 0.8f, 0.3f), Color.white, 2f); return; } _cargas--; if (_cargas == Cargas.Value - 1) { _temporizador = MinutosRecarga.Value * 60f; } val.playerHealth.HealOther(Curacion.Value, true); SemiFunc.UIFocusText($"Curado +{Curacion.Value} PV ({_cargas}/{Cargas.Value})", new Color(0.4f, 1f, 0.5f), Color.white, 3f); Plugin.Debug($"Medico: curados {Curacion.Value} PV. Quedan {_cargas} cargas."); } private static PlayerAvatar BuscarHerido() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar instance = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null) { return null; } List list = SemiFunc.PlayerGetAll(); if (list == null) { return null; } Vector3 val = (((Object)(object)instance.playerTransform != (Object)null) ? instance.playerTransform.position : ((Component)instance).transform.position); PlayerAvatar result = null; float num = float.MaxValue; foreach (PlayerAvatar item in list) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)instance) && !((Object)(object)item.playerHealth == (Object)null) && !EstaMuerto(item) && Vida(item.playerHealth) < VidaMax(item.playerHealth)) { Vector3 val2 = (((Object)(object)item.playerTransform != (Object)null) ? item.playerTransform.position : ((Component)item).transform.position); float num2 = Vector3.Distance(val, val2); if (!(num2 > Alcance.Value) && !(num2 >= num)) { result = item; num = num2; } } } return result; } } internal static class RolRastreador { internal static ConfigEntry Enabled; internal static ConfigEntry MinutosEntreAvisos; internal static ConfigEntry AlcanceMaximo; internal static ConfigEntry DecirNombre; private static float _siguienteAviso; private static readonly FieldInfo _campoEnemyParent = AccessTools.Field(typeof(Enemy), "EnemyParent"); internal static void BindConfig(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown Enabled = config.Bind("Rastreador", "Activado", true, "Mete el rol de rastreador en el sorteo."); MinutosEntreAvisos = config.Bind("Rastreador", "MinutosEntreAvisos", 2f, new ConfigDescription("Cada cuanto se marca al monstruo mas cercano.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 30f), Array.Empty())); AlcanceMaximo = config.Bind("Rastreador", "AlcanceMaximo", 60f, new ConfigDescription("Distancia maxima de deteccion, en metros. Si no hay ningun monstruo dentro de este radio, el aviso dice que la zona esta despejada.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 300f), Array.Empty())); DecirNombre = config.Bind("Rastreador", "DecirNombre", true, "Incluye el nombre del monstruo en el aviso. Si lo apagas solo se dice la distancia y la direccion, que da mas mal rollo."); Roles.AlRepartir += delegate { if (Roles.SoyEl(Rol.Rastreador)) { Reiniciar(); } }; } internal static void Reiniciar() { _siguienteAviso = MinutosEntreAvisos.Value * 60f; } internal static string TextoDeUso() { return $"Cada {MinutosEntreAvisos.Value:0} min sabras donde esta el monstruo mas cercano"; } internal static void AvisarUso() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) SemiFunc.UIFocusText(TextoDeUso(), Roles.ColorRastreador, Color.white, 5f); } internal static void Tick() { if (Enabled != null && Enabled.Value && Roles.SoyEl(Rol.Rastreador) && Roles.EnPartida()) { _siguienteAviso -= Time.deltaTime; if (!(_siguienteAviso > 0f)) { _siguienteAviso = MinutosEntreAvisos.Value * 60f; Rastrear(); } } } private static void Rastrear() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) PlayerAvatar instance = PlayerAvatar.instance; if (!((Object)(object)instance == (Object)null)) { Vector3 val = (((Object)(object)instance.playerTransform != (Object)null) ? instance.playerTransform.position : ((Component)instance).transform.position); Enemy val2 = SemiFunc.EnemyGetNearest(val, AlcanceMaximo.Value, false); if ((Object)(object)val2 == (Object)null) { SemiFunc.UIFocusText("RASTREO: zona despejada", new Color(0.5f, 1f, 0.6f), Color.white, 4f); Plugin.Debug("Rastreador: sin enemigos en rango."); return; } Vector3 position = ((Component)val2).transform.position; float num = Vector3.Distance(val, position); string arg = (DecirNombre.Value ? NombreDe(val2) : "Algo"); string arg2 = DireccionEnHoras(val, position); float num2 = Mathf.Clamp01(1f - num / AlcanceMaximo.Value); Color val3 = Color.Lerp(new Color(1f, 0.85f, 0.3f), new Color(1f, 0.25f, 0.25f), num2); SemiFunc.UIFocusText($"RASTREO: {arg} a {num:0} m {arg2}", val3, Color.white, 5f); Plugin.Debug($"Rastreador: {arg} a {num:0.0} m, {arg2}."); } } private static string NombreDe(Enemy enemigo) { if (_campoEnemyParent == null) { return "Monstruo"; } object? value = _campoEnemyParent.GetValue(enemigo); EnemyParent val = (EnemyParent)((value is EnemyParent) ? value : null); if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.enemyName)) { return "Monstruo"; } return val.enemyName; } private static string DireccionEnHoras(Vector3 origen, Vector3 destino) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) Camera val = SemiFunc.MainCamera(); if ((Object)(object)val == (Object)null) { return ""; } Vector3 val2 = destino - origen; Vector3 forward = ((Component)val).transform.forward; val2.y = 0f; forward.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.001f || ((Vector3)(ref forward)).sqrMagnitude < 0.001f) { return "encima de ti"; } float num = Vector3.SignedAngle(forward, val2, Vector3.up); if (num < 0f) { num += 360f; } int num2 = Mathf.RoundToInt(num / 30f); if (num2 == 0) { num2 = 12; } return num2 switch { 12 => "AL FRENTE", 6 => "A TU ESPALDA", 3 => "a tu derecha", 9 => "a tu izquierda", _ => $"a las {num2}", }; } } internal static class RolSaboteador { internal static ConfigEntry Enabled; internal static ConfigEntry Tecla; internal static ConfigEntry MinutosApagon; internal static ConfigEntry MinutosRecarga; internal static ConfigEntry SubirEnemigos; internal static ConfigEntry FuerzaEnemigos; private static float _recarga; private static readonly FieldInfo _campoPropLights = AccessTools.Field(typeof(LightManager), "propLights"); private static readonly FieldInfo _campoLuz = AccessTools.Field(typeof(PropLight), "lightComponent"); private static float _apagonRestante; private static float _reaplicarEn; private static readonly List _apagadas = new List(); private static readonly FieldInfo _campoEnemigos = AccessTools.Field(typeof(EnemyDirector), "enemiesSpawned"); private static readonly FieldInfo _campoSpawned = AccessTools.Field(typeof(EnemyParent), "Spawned"); private static float _boostRestante; private static float _boostSiguiente; internal static void BindConfig(ConfigFile config) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown Enabled = config.Bind("Saboteador", "Activado", true, "Mete el rol de saboteador en el sorteo."); Tecla = config.Bind("Saboteador", "Tecla", (KeyCode)104, "Tecla que dispara el apagon."); MinutosApagon = config.Bind("Saboteador", "MinutosApagon", 2f, new ConfigDescription("Cuanto duran las luces apagadas.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 15f), Array.Empty())); MinutosRecarga = config.Bind("Saboteador", "MinutosRecarga", 15f, new ConfigDescription("Recarga de la habilidad, contada desde que EMPIEZA el apagon.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 60f), Array.Empty())); SubirEnemigos = config.Bind("Saboteador", "SubirEnemigos", true, "Durante el apagon acelera la aparicion de enemigos."); FuerzaEnemigos = config.Bind("Saboteador", "FuerzaEnemigos", 10f, new ConfigDescription("Segundos que se le restan al contador de aparicion de cada enemigo dormido, una vez por segundo mientras dura el apagon. El juego usa 5 para un ruido normal, asi que 10 es aproximadamente el doble de rapido.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty())); Roles.AlRepartir += delegate { if (Roles.SoyEl(Rol.Saboteador)) { Reiniciar(); } }; } internal static void Reiniciar() { _recarga = 0f; } internal static string TextoDeUso() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return $"[{Tecla.Value}] apagon de {MinutosApagon.Value:0} min - recarga {MinutosRecarga.Value:0} min"; } internal static void AvisarUso() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) SemiFunc.UIFocusText(TextoDeUso(), Roles.ColorSaboteador, Color.white, 5f); } internal static void Tick() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (Enabled == null || !Enabled.Value || !Roles.EnPartida()) { return; } MantenerApagon(); if (SemiFunc.IsMasterClientOrSingleplayer()) { MantenerBoost(); } if (Roles.SoyEl(Rol.Saboteador)) { if (_recarga > 0f) { _recarga -= Time.deltaTime; } if (Roles.TeclaPulsada(Tecla.Value)) { Sabotear(); } } } private static void Sabotear() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown if (_recarga > 0f) { int num = Mathf.CeilToInt(_recarga); SemiFunc.UIFocusText($"Recargando - {num / 60}:{num % 60:00}", new Color(1f, 0.5f, 0.3f), Color.white, 3f); return; } float num2 = MinutosApagon.Value * 60f; _recarga = MinutosRecarga.Value * 60f; IniciarApagon(num2); if (SemiFunc.IsMultiplayer() && PhotonNetwork.NetworkingClient != null) { PhotonNetwork.RaiseEvent((byte)177, (object)num2, new RaiseEventOptions { Receivers = (ReceiverGroup)0 }, SendOptions.SendReliable); } if (SubirEnemigos.Value) { PedirBoost(num2); } SemiFunc.UIFocusText("SABOTAJE", new Color(1f, 0.2f, 0.2f), Color.white, 3f); Plugin.Log.LogInfo((object)$"Saboteador: apagon de {num2:0} s lanzado."); } internal static void EjecutarApagon(object datos) { if (datos is float) { IniciarApagon((float)datos); } } private static void IniciarApagon(float segundos) { _apagonRestante = segundos; _reaplicarEn = 0f; ApagarLoQueHaya(); } private static void MantenerApagon() { if (_apagonRestante <= 0f) { return; } _apagonRestante -= Time.deltaTime; if (_apagonRestante <= 0f) { Encender(); return; } _reaplicarEn -= Time.deltaTime; if (_reaplicarEn <= 0f) { _reaplicarEn = 0.5f; ApagarLoQueHaya(); } } private static void ApagarLoQueHaya() { IList list = ListaDeLuces(); if (list == null) { return; } foreach (object item in list) { Light val = LuzDe(item); if (!((Object)(object)val == (Object)null) && ((Behaviour)val).enabled) { ((Behaviour)val).enabled = false; _apagadas.Add(val); } } } private static void Encender() { foreach (Light apagada in _apagadas) { if ((Object)(object)apagada != (Object)null) { ((Behaviour)apagada).enabled = true; } } int count = _apagadas.Count; _apagadas.Clear(); _apagonRestante = 0f; Plugin.Debug($"Saboteador: apagon terminado, {count} luces devueltas."); } private static IList ListaDeLuces() { if ((Object)(object)LightManager.instance == (Object)null || _campoPropLights == null) { return null; } return _campoPropLights.GetValue(LightManager.instance) as IList; } private static Light LuzDe(object propLight) { if (propLight == null || _campoLuz == null) { return null; } object? value = _campoLuz.GetValue(propLight); return (Light)((value is Light) ? value : null); } private static void PedirBoost(float segundos) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown if (SemiFunc.IsMasterClientOrSingleplayer()) { _boostRestante = segundos; _boostSiguiente = 0f; } else if (PhotonNetwork.NetworkingClient != null) { PhotonNetwork.RaiseEvent((byte)176, (object)segundos, new RaiseEventOptions { Receivers = (ReceiverGroup)2 }, SendOptions.SendReliable); Plugin.Debug("Saboteador: no soy master, pedido el boost de enemigos."); } } internal static void EjecutarBoostEnemigos(object datos) { if (datos is float) { _boostRestante = (float)datos; _boostSiguiente = 0f; } } private static void MantenerBoost() { if (_boostRestante <= 0f) { return; } _boostRestante -= Time.deltaTime; _boostSiguiente -= Time.deltaTime; if (_boostSiguiente > 0f) { return; } _boostSiguiente = 1f; if ((Object)(object)EnemyDirector.instance == (Object)null || _campoEnemigos == null || !(_campoEnemigos.GetValue(EnemyDirector.instance) is IList list)) { return; } int num = 0; foreach (object item in list) { EnemyParent val = (EnemyParent)((item is EnemyParent) ? item : null); if (!((Object)(object)val == (Object)null) && (!(_campoSpawned != null) || !(bool)_campoSpawned.GetValue(val))) { val.DisableDecrease(FuerzaEnemigos.Value); num++; } } if (num > 0) { Plugin.Debug($"Saboteador: {num} enemigos acelerados ({_boostRestante:0} s restantes)."); } } } }