using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LevelEditor;
using TMPro;
using UnityEngine;
using WeaponFramework;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyCompany("PoisonGuns")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.2.0")]
[assembly: AssemblyInformationalVersion("1.1.2")]
[assembly: AssemblyProduct("PoisonGuns")]
[assembly: AssemblyTitle("PoisonGuns")]
[assembly: AssemblyVersion("1.1.2.0")]
namespace PoisonGuns;
internal static class FrameworkBridge
{
private static readonly string[,] names = new string[6, 3]
{
{ "vanilla.snakegun", "SNAKE GUN", "POISON GUN" },
{ "vanilla.snakeshotgun", "SNAKE SHOTGUN", "POISON SHOTGUN" },
{ "vanilla.snakegrenade", "SNAKE GRENADE", "POISON GRENADE" },
{ "vanilla.snakelauncher", "SNAKE LAUNCHER", "POISON LAUNCHER" },
{ "vanilla.snakeminigun", "SNAKE MINIGUN", "POISON MINIGUN" },
{ "vanilla.flyingsnake", "FLYING SNAKE", "FLYING POISON" }
};
private static readonly Dictionary<string, int> gameTickets = new Dictionary<string, int>();
public static void Start()
{
WeaponRegistry.Ready += Apply;
EventHandler eventHandler = delegate
{
Apply();
};
Plugin.ReplaceSnakeGuns.SettingChanged += eventHandler;
Plugin.RenameSnakeToPoison.SettingChanged += eventHandler;
Plugin.LauncherMatchesRpgRarity.SettingChanged += eventHandler;
Plugin.SeekerMatchesRpgRarity.SettingChanged += eventHandler;
}
private static void Apply()
{
try
{
bool value = Plugin.ReplaceSnakeGuns.Value;
bool flag = value && Plugin.RenameSnakeToPoison.Value;
for (int i = 0; i < names.GetLength(0); i++)
{
WeaponRegistry.SetName(names[i, 0], flag ? names[i, 2] : names[i, 1]);
}
WeaponRegistry.SetCategoryName("snake", flag ? "POISON" : "SNAKE");
WeaponInfo val = WeaponRegistry.Get("vanilla.rpg");
int rpgTickets = ((val != null) ? val.DefaultTickets : 2);
Tickets("vanilla.snakelauncher", value && Plugin.LauncherMatchesRpgRarity.Value, rpgTickets);
Tickets("vanilla.flyingsnake", value && Plugin.SeekerMatchesRpgRarity.Value, rpgTickets);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Couldn't update Weapon Framework's weapon list: " + ex));
}
}
private static void Tickets(string id, bool rpgRare, int rpgTickets)
{
WeaponInfo val = WeaponRegistry.Get(id);
if (val != null)
{
if (!gameTickets.TryGetValue(id, out var value))
{
value = val.DefaultTickets;
gameTickets[id] = value;
}
WeaponRegistry.SetDefaultTickets(id, rpgRare ? rpgTickets : value);
}
}
}
internal static class MenuRename
{
[HarmonyPatch(typeof(WeaponSelectionHandler), "Start")]
private static class WeaponMenuStart
{
[HarmonyPostfix]
private static void Postfix(WeaponSelectionHandler __instance)
{
if (Plugin.WithFramework)
{
return;
}
s_Handler = __instance;
if (!Wanted)
{
return;
}
try
{
Apply(__instance, rename: true);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to rename weapon menu: " + ex));
}
}
}
[HarmonyPatch(typeof(WeaponSelectionHandler), "ToggleWeaponActive")]
private static class ToggleWeaponFix
{
[HarmonyPrefix]
private static void Prefix(ref string weaponName, List<SingleWeaponUI> ___m_Weapons)
{
if (___m_Weapons != null)
{
foreach (SingleWeaponUI ___m_Weapon in ___m_Weapons)
{
if (string.Equals(___m_Weapon.WeaponName, weaponName, StringComparison.OrdinalIgnoreCase))
{
return;
}
}
}
weaponName = Original(weaponName);
}
}
[HarmonyPatch(typeof(WeaponSelectionHandler), "ToggleCategoryActive")]
private static class ToggleCategoryFix
{
[HarmonyPrefix]
private static void Prefix(ref string categoryName)
{
categoryName = Original(categoryName);
}
}
[HarmonyPatch(typeof(GunButtonUI), "Init")]
private static class GunButtonFix
{
[HarmonyPostfix]
private static void Postfix(GunButtonUI __instance)
{
if (Plugin.RenameSnakeToPoison.Value && Plugin.ReplaceSnakeGuns.Value)
{
TextMeshProUGUI componentInChildren = ((Component)__instance).GetComponentInChildren<TextMeshProUGUI>();
if ((Object)(object)componentInChildren != (Object)null)
{
((TMP_Text)componentInChildren).text = Rename(((TMP_Text)componentInChildren).text);
}
}
}
}
private static readonly Dictionary<string, string> s_Originals = new Dictionary<string, string>();
private static readonly string[,] s_Pairs = new string[6, 2]
{
{ "SNAKES", "POISON" },
{ "Snakes", "Poison" },
{ "snakes", "poison" },
{ "SNAKE", "POISON" },
{ "Snake", "Poison" },
{ "snake", "poison" }
};
private static readonly FieldRef<WeaponSelectionHandler, List<SingleWeaponUI>> s_MenuWeapons = AccessTools.FieldRefAccess<WeaponSelectionHandler, List<SingleWeaponUI>>("m_Weapons");
private static WeaponSelectionHandler s_Handler;
private static bool Wanted
{
get
{
if (Plugin.RenameSnakeToPoison.Value)
{
return Plugin.ReplaceSnakeGuns.Value;
}
return false;
}
}
internal static string Rename(string text)
{
if (string.IsNullOrEmpty(text) || text.IndexOf("snake", StringComparison.OrdinalIgnoreCase) < 0)
{
return text;
}
string text2 = text;
for (int i = 0; i < s_Pairs.GetLength(0); i++)
{
text2 = text2.Replace(s_Pairs[i, 0], s_Pairs[i, 1]);
}
if (text2 != text)
{
s_Originals[text2] = text;
}
return text2;
}
internal static string Original(string text)
{
if (text == null || !s_Originals.TryGetValue(text, out var value))
{
return text;
}
return value;
}
private static void Apply(WeaponSelectionHandler handler, bool rename)
{
TextMeshProUGUI[] componentsInChildren = ((Component)handler).GetComponentsInChildren<TextMeshProUGUI>(true);
foreach (TextMeshProUGUI val in componentsInChildren)
{
string text = Shown(((TMP_Text)val).text, rename);
if (text != ((TMP_Text)val).text)
{
((TMP_Text)val).text = text;
}
}
List<SingleWeaponUI> list = s_MenuWeapons.Invoke(handler);
if (list == null)
{
return;
}
foreach (SingleWeaponUI item in list)
{
item.WeaponName = Shown(item.WeaponName, rename);
}
}
private static string Shown(string text, bool rename)
{
string text2 = Original(text);
if (!rename)
{
return text2;
}
return Rename(text2);
}
internal static void Relabel()
{
if (Plugin.WithFramework || (Object)(object)s_Handler == (Object)null)
{
return;
}
try
{
Apply(s_Handler, Wanted);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to rename weapon menu: " + ex));
}
}
}
[BepInPlugin("stickfight.poisonguns", "PoisonGuns", "1.1.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const string Guid = "stickfight.poisonguns";
public const string Name = "PoisonGuns";
public const string Version = "1.1.2";
private const string FrameworkGuid = "stickfight.weaponframework";
internal static bool WithFramework;
internal static ManualLogSource Log;
internal static ConfigEntry<bool> ReplaceSnakeGuns;
internal static ConfigEntry<bool> RenameSnakeToPoison;
internal static ConfigEntry<string> TemplateWeapon;
internal static ConfigEntry<bool> LogWeaponList;
internal static ConfigEntry<string> BulletColor;
internal static ConfigEntry<float> BulletSpeed;
internal static ConfigEntry<float> BulletOrbSize;
internal static ConfigEntry<float> BulletLifetime;
internal static ConfigEntry<float> ImpactDamageMultiplier;
internal static ConfigEntry<float> PoisonDamageMultiplier;
internal static ConfigEntry<float> MinigunRecoilMultiplier;
internal static ConfigEntry<float> ShotgunPelletSpread;
internal static ConfigEntry<float> RocketModelScale;
internal static ConfigEntry<float> RocketSpinSpeed;
internal static ConfigEntry<bool> LauncherMatchesRpgRarity;
internal static ConfigEntry<bool> SeekerMatchesRpgRarity;
internal static ConfigEntry<float> RocketSpeed;
internal static ConfigEntry<float> RocketOrbSize;
internal static ConfigEntry<float> RocketImpactDamage;
internal static ConfigEntry<float> RocketBlastPoison;
internal static ConfigEntry<float> RocketBlastRadius;
internal static ConfigEntry<float> SeekerSpeed;
internal static ConfigEntry<float> SeekerOrbSize;
internal static ConfigEntry<float> SeekerImpactDamage;
internal static ConfigEntry<float> SeekerBlastPoison;
internal static ConfigEntry<float> SeekerBlastRadius;
internal static ConfigEntry<float> SeekerTurnRate;
internal static ConfigEntry<float> SeekerRange;
internal static ConfigEntry<float> GrenadeBlastPoison;
internal static ConfigEntry<float> GrenadeBlastRadius;
internal static ConfigEntry<bool> BlastHitsShooter;
internal static ConfigEntry<float> PoisonDuration;
internal static ConfigEntry<float> PoisonTickInterval;
internal static ConfigEntry<int> MaxStackedDoses;
internal static ConfigEntry<bool> PoisonParticles;
internal static Color ParsedColor = new Color(0.33f, 1f, 0.2f, 1f);
private void Awake()
{
//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
//IL_04a9: Unknown result type (might be due to invalid IL or missing references)
//IL_054f: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
ReplaceSnakeGuns = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ReplaceSnakeGuns", true, "Replace the snakes fired by snake weapons with poison projectiles. Snakes spawned by maps are never touched.");
RenameSnakeToPoison = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RenameSnakeToPoison", true, "Show 'Poison' instead of 'Snake' in the weapon menus (only while ReplaceSnakeGuns is on).");
TemplateWeapon = ((BaseUnityPlugin)this).Config.Bind<string>("General", "TemplateWeapon", "Pistol", "Name (or part of the name) of the gun whose bullet is copied to make poison bullets.");
LogWeaponList = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogWeaponList", true, "Write every weapon and what it fires to the BepInEx log once per launch.");
BulletColor = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Color", "#55FF33", "Colour of all poison projectiles and effects, as an HTML hex colour.");
BulletSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonBullet", "Speed", 14f, "Used by the Poison Gun, Poison Minigun and each Poison Shotgun pellet. A normal pistol bullet is 120.");
BulletOrbSize = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonBullet", "OrbSize", 0.35f, "Diameter of the glowing ball at the front of the bullet.");
BulletLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonBullet", "Lifetime", 10f, "Seconds before a poison projectile that hit nothing disappears.");
ImpactDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonBullet", "ImpactDamage", 0.5f, "Damage dealt instantly on hit. Damage values are multiples of one normal pistol bullet.");
PoisonDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonBullet", "PoisonDamage", 1f, "Damage dealt over time after a hit. Damage values are multiples of one normal pistol bullet.");
MinigunRecoilMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonBullet", "MinigunRecoilMultiplier", 1.6f, "Recoil of the Poison Minigun compared to the original Snake Minigun.");
ShotgunPelletSpread = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonBullet", "ShotgunPelletSpread", 7f, "Random spread, in degrees, added to each Poison Shotgun pellet. The game's normal shotguns use 7.");
RocketSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonRocket", "Speed", 7f, "Poison Launcher projectile speed.");
RocketModelScale = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonRocket", "SizeVsRPG", 1f, "Size of the poison rocket compared to the RPG's rocket. 1 = identical.");
LauncherMatchesRpgRarity = ((BaseUnityPlugin)this).Config.Bind<bool>("PoisonRocket", "SameRarityAsRPG", true, "Make the Poison Launcher spawn as rarely as the RPG (the Snake Launcher is normally as common as the pistol). Local play only.");
RocketSpinSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonRocket", "SpinSpeed", 401f, "How fast the rocket rolls, in degrees per second. 401 matches the RPG rocket.");
RocketOrbSize = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonRocket", "OrbSize", 1f, "Diameter of the fallback ball, only used if the RPG rocket model can't be found.");
RocketImpactDamage = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonRocket", "ImpactDamage", 1f, "Instant damage to a player hit directly. Damage values are multiples of one normal pistol bullet.");
RocketBlastPoison = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonRocket", "BlastPoison", 2f, "Poison given to everyone in the blast (half at the edge). Damage values are multiples of one normal pistol bullet.");
RocketBlastRadius = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonRocket", "BlastRadius", 4f, "Blast radius.");
SeekerSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonSeeker", "Speed", 8f, "Flying Poison projectile speed.");
SeekerOrbSize = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonSeeker", "OrbSize", 0.8f, "Diameter of the seeker's ball.");
SeekerImpactDamage = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonSeeker", "ImpactDamage", 0.75f, "Instant damage to a player hit directly. Damage values are multiples of one normal pistol bullet.");
SeekerBlastPoison = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonSeeker", "BlastPoison", 1.5f, "Poison given to everyone in the blast (half at the edge). Damage values are multiples of one normal pistol bullet.");
SeekerBlastRadius = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonSeeker", "BlastRadius", 3f, "Blast radius.");
SeekerMatchesRpgRarity = ((BaseUnityPlugin)this).Config.Bind<bool>("PoisonSeeker", "SameRarityAsRPG", true, "Make the Flying Poison spawn as rarely as the RPG (the Flying Snake is normally as common as the pistol). Local play only.");
SeekerTurnRate = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonSeeker", "TurnRate", 45f, "How hard it homes, in degrees per second. Higher = sharper turns.");
SeekerRange = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonSeeker", "HomingRange", 40f, "Only players closer than this are chased.");
GrenadePoisonDefaults();
BlastHitsShooter = ((BaseUnityPlugin)this).Config.Bind<bool>("PoisonEffect", "SelfDamage", true, "Whether your own poison blasts (launcher, seeker, grenade) poison you too, like normal explosions do.");
PoisonDuration = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonEffect", "Duration", 3f, "Seconds the poison takes to deal its damage. Another hit adds more poison and restarts the timer.");
PoisonTickInterval = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonEffect", "TickInterval", 0.5f, "Seconds between poison damage ticks.");
MaxStackedDoses = ((BaseUnityPlugin)this).Config.Bind<int>("PoisonEffect", "MaxStackedDoses", 3, "Most hits' worth of poison a player can have stored at once.");
PoisonParticles = ((BaseUnityPlugin)this).Config.Bind<bool>("PoisonEffect", "Particles", true, "Puff green particles from a poisoned player on every tick.");
Color parsedColor = default(Color);
if (ColorUtility.TryParseHtmlString(BulletColor.Value, ref parsedColor))
{
ParsedColor = parsedColor;
}
else
{
Log.LogWarning((object)("Could not read Color '" + BulletColor.Value + "', using default green."));
}
EventHandler eventHandler = delegate
{
RarityFix.Rebuild();
};
ReplaceSnakeGuns.SettingChanged += eventHandler;
LauncherMatchesRpgRarity.SettingChanged += eventHandler;
SeekerMatchesRpgRarity.SettingChanged += eventHandler;
EventHandler eventHandler2 = delegate
{
MenuRename.Relabel();
};
ReplaceSnakeGuns.SettingChanged += eventHandler2;
RenameSnakeToPoison.SettingChanged += eventHandler2;
new Harmony("stickfight.poisonguns").PatchAll(typeof(Plugin).Assembly);
WithFramework = Chainloader.PluginInfos.ContainsKey("stickfight.weaponframework");
if (WithFramework)
{
FrameworkBridge.Start();
}
Log.LogInfo((object)("PoisonGuns 1.1.2 loaded" + (WithFramework ? " (with Weapon Framework)." : ".")));
}
private void GrenadePoisonDefaults()
{
GrenadeBlastPoison = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonGrenade", "BlastPoison", 2f, "Poison given to everyone in the blast (half at the edge). Damage values are multiples of one normal pistol bullet.");
GrenadeBlastRadius = ((BaseUnityPlugin)this).Config.Bind<float>("PoisonGrenade", "BlastRadius", 4.5f, "Blast radius.");
}
}
public class PoisonBullet : MonoBehaviour
{
public const string HitMessage = "PoisonGunsHit";
public float poisonDamage;
private void PoisonGunsHit(Rigidbody rig)
{
if (!((Object)(object)rig == (Object)null) && !(poisonDamage <= 0f))
{
BodyPart component = ((Component)rig).GetComponent<BodyPart>();
if (!((Object)(object)component == (Object)null) && !component.isGun && !((Object)(object)component.health == (Object)null))
{
ProjectileCollision component2 = ((Component)this).GetComponent<ProjectileCollision>();
PoisonEffect.Apply(component.health, ((Object)(object)component2 != (Object)null) ? component2.damager : null, poisonDamage);
}
}
}
}
public class PoisonProjectile : MonoBehaviour
{
public GameObject orb;
public float blastRadius;
public float blastPoison;
public GameObject blastVisual;
private RayCastForward m_Mover;
private ProjectileCollision m_Collision;
private bool m_Finished;
private void Start()
{
m_Mover = ((Component)this).GetComponent<RayCastForward>();
m_Collision = ((Component)this).GetComponent<ProjectileCollision>();
}
private void LateUpdate()
{
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
if (!m_Finished && !((Object)(object)m_Mover == (Object)null) && !((Behaviour)m_Mover).enabled)
{
m_Finished = true;
if ((Object)(object)orb != (Object)null)
{
orb.SetActive(false);
}
if (blastRadius > 0f)
{
PoisonBlast.Trigger(((Component)this).transform.position, ((Object)(object)m_Collision != (Object)null) ? m_Collision.damager : null, blastRadius, blastPoison, blastVisual);
}
}
}
}
public class PoisonSpin : MonoBehaviour
{
public float degreesPerSecond = 401f;
private void Update()
{
((Component)this).transform.Rotate(0f, 0f, degreesPerSecond * Time.deltaTime, (Space)1);
}
}
public class PoisonHoming : MonoBehaviour
{
public float turnRate = 45f;
public float range = 40f;
private RayCastForward m_Mover;
private ProjectileCollision m_Collision;
private Transform m_Target;
private float m_Retarget;
private static readonly Dictionary<Controller, Transform> s_Torsos = new Dictionary<Controller, Transform>();
private void Start()
{
m_Mover = ((Component)this).GetComponent<RayCastForward>();
m_Collision = ((Component)this).GetComponent<ProjectileCollision>();
}
private void FixedUpdate()
{
//IL_0067: 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_0077: 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)
//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_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: 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)
//IL_00e1: 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)
if ((Object)(object)m_Mover == (Object)null || !((Behaviour)m_Mover).enabled)
{
return;
}
m_Retarget -= Time.fixedDeltaTime;
if (m_Retarget <= 0f)
{
m_Retarget = 0.2f;
m_Target = FindTarget();
}
if (!((Object)(object)m_Target == (Object)null))
{
Vector3 val = m_Target.position - ((Component)this).transform.position;
val.x = 0f;
if (!(((Vector3)(ref val)).sqrMagnitude < 0.001f))
{
Vector3 forward = ((Component)this).transform.forward;
forward.x = 0f;
Vector3 val2 = Vector3.RotateTowards(((Vector3)(ref forward)).normalized, ((Vector3)(ref val)).normalized, turnRate * ((float)Math.PI / 180f) * Time.fixedDeltaTime, 0f);
((Component)this).transform.rotation = Quaternion.LookRotation(val2);
}
}
}
private Transform FindTarget()
{
//IL_00a6: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
GameManager instance = GameManager.Instance;
if ((Object)(object)instance == (Object)null || instance.playersAlive == null)
{
return null;
}
Controller val = (((Object)(object)m_Collision != (Object)null) ? m_Collision.damager : null);
Transform result = null;
float num = range * range;
foreach (Controller item in instance.playersAlive)
{
if ((Object)(object)item == (Object)null || (Object)(object)item == (Object)(object)val)
{
continue;
}
CharacterInformation component = ((Component)item).GetComponent<CharacterInformation>();
if ((Object)(object)component != (Object)null && component.isDead)
{
continue;
}
Transform val2 = TorsoOf(item);
if (!((Object)(object)val2 == (Object)null))
{
Vector3 val3 = val2.position - ((Component)this).transform.position;
val3.x = 0f;
if (((Vector3)(ref val3)).sqrMagnitude < num)
{
num = ((Vector3)(ref val3)).sqrMagnitude;
result = val2;
}
}
}
return result;
}
private static Transform TorsoOf(Controller c)
{
if (s_Torsos.TryGetValue(c, out var value) && (Object)(object)value != (Object)null)
{
return value;
}
if (s_Torsos.Count >= 16)
{
PruneTorsos();
}
Torso componentInChildren = ((Component)c).GetComponentInChildren<Torso>();
value = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).transform : ((Component)c).transform);
s_Torsos[c] = value;
return value;
}
private static void PruneTorsos()
{
List<Controller> list = new List<Controller>();
foreach (KeyValuePair<Controller, Transform> s_Torso in s_Torsos)
{
if ((Object)(object)s_Torso.Key == (Object)null || (Object)(object)s_Torso.Value == (Object)null)
{
list.Add(s_Torso.Key);
}
}
foreach (Controller item in list)
{
s_Torsos.Remove(item);
}
}
}
public class PoisonGrenade : MonoBehaviour
{
public float fuse = 2f;
public float blastRadius;
public float blastPoison;
public GameObject blastVisual;
private Controller m_Damager;
private bool m_Done;
private void Start()
{
SpawnObjectAfterDelay component = ((Component)this).GetComponent<SpawnObjectAfterDelay>();
if ((Object)(object)component != (Object)null)
{
m_Damager = component.damager;
((Behaviour)component).enabled = false;
}
RandomValue component2 = ((Component)this).GetComponent<RandomValue>();
if ((Object)(object)component2 != (Object)null && component2.value > 0f)
{
fuse *= component2.value;
}
}
private void Update()
{
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
if (!m_Done)
{
fuse -= Time.deltaTime;
if (!(fuse > 0f))
{
m_Done = true;
PoisonBlast.Trigger(((Component)this).transform.position, m_Damager, blastRadius, blastPoison, blastVisual);
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}
}
}
internal static class PoisonBlast
{
public static void Trigger(Vector3 pos, Controller damager, float radius, float poison, GameObject visual)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
pos.x = 0f;
if ((Object)(object)visual != (Object)null)
{
ScaleParticles(Object.Instantiate<GameObject>(visual, pos, Quaternion.identity), Mathf.Max(0.3f, radius / 4f));
}
if (poison <= 0f || radius <= 0f)
{
return;
}
Dictionary<HealthHandler, float> dictionary = new Dictionary<HealthHandler, float>();
Collider[] array = Physics.OverlapSphere(pos, radius);
foreach (Collider val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
BodyPart componentInParent = ((Component)val).GetComponentInParent<BodyPart>();
if (!((Object)(object)componentInParent == (Object)null) && !componentInParent.isGun && !((Object)(object)componentInParent.health == (Object)null) && (Plugin.BlastHitsShooter.Value || !((Object)(object)damager != (Object)null) || !((Object)(object)((Component)componentInParent.health).transform.root == (Object)(object)((Component)damager).transform.root)))
{
Vector3 val2 = ((Component)val).transform.position - pos;
val2.x = 0f;
float magnitude = ((Vector3)(ref val2)).magnitude;
if (!dictionary.TryGetValue(componentInParent.health, out var value) || magnitude < value)
{
dictionary[componentInParent.health] = magnitude;
}
}
}
foreach (KeyValuePair<HealthHandler, float> item in dictionary)
{
float num = Mathf.Lerp(1f, 0.5f, Mathf.Clamp01(item.Value / radius));
PoisonEffect.Apply(item.Key, damager, poison * num);
}
}
private static void ScaleParticles(GameObject root, float scale)
{
//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_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
if (Mathf.Approximately(scale, 1f))
{
return;
}
ParticleSystem[] componentsInChildren = root.GetComponentsInChildren<ParticleSystem>(true);
foreach (ParticleSystem obj in componentsInChildren)
{
MainModule main = obj.main;
if (((MainModule)(ref main)).startSize3D)
{
((MainModule)(ref main)).startSizeXMultiplier = ((MainModule)(ref main)).startSizeXMultiplier * scale;
((MainModule)(ref main)).startSizeYMultiplier = ((MainModule)(ref main)).startSizeYMultiplier * scale;
((MainModule)(ref main)).startSizeZMultiplier = ((MainModule)(ref main)).startSizeZMultiplier * scale;
}
else
{
((MainModule)(ref main)).startSizeMultiplier = ((MainModule)(ref main)).startSizeMultiplier * scale;
}
((MainModule)(ref main)).startSpeedMultiplier = ((MainModule)(ref main)).startSpeedMultiplier * scale;
ShapeModule shape = obj.shape;
((ShapeModule)(ref shape)).radius = ((ShapeModule)(ref shape)).radius * scale;
}
}
}
public class PoisonEffect : MonoBehaviour
{
private HealthHandler m_Health;
private Controller m_Damager;
private ParticleSystem m_Particles;
private Transform m_Torso;
private float m_Remaining;
private float m_TimeLeft;
private float m_TickTimer;
private float m_LastSinceSpawn;
public static void Apply(HealthHandler health, Controller damager, float amount)
{
if (!((Object)(object)health == (Object)null) && !(amount <= 0f))
{
PoisonEffect poisonEffect = ((Component)health).GetComponent<PoisonEffect>();
if ((Object)(object)poisonEffect == (Object)null)
{
poisonEffect = ((Component)health).gameObject.AddComponent<PoisonEffect>();
}
poisonEffect.Add(health, damager, amount);
}
}
private void Add(HealthHandler health, Controller damager, float amount)
{
if ((Object)(object)m_Health == (Object)null)
{
m_Health = health;
DamageParticle componentInChildren = ((Component)health).GetComponentInChildren<DamageParticle>();
if ((Object)(object)componentInChildren != (Object)null)
{
m_Particles = ((Component)componentInChildren).GetComponent<ParticleSystem>();
}
Torso componentInChildren2 = ((Component)health).GetComponentInChildren<Torso>();
m_Torso = (((Object)(object)componentInChildren2 != (Object)null) ? ((Component)componentInChildren2).transform : ((Component)health).transform);
}
if ((Object)(object)damager != (Object)null)
{
m_Damager = damager;
}
float num = Mathf.Max(amount * (float)Mathf.Max(1, Plugin.MaxStackedDoses.Value), m_Remaining);
m_Remaining = Mathf.Min(m_Remaining + amount, num);
m_TimeLeft = Mathf.Max(0.05f, Plugin.PoisonDuration.Value);
m_LastSinceSpawn = health.sinceSpawn;
}
private void Clear()
{
m_Remaining = 0f;
m_TimeLeft = 0f;
m_TickTimer = 0f;
}
private void Update()
{
//IL_0110: 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_011a: 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)
if ((Object)(object)m_Health == (Object)null || m_Remaining <= 0f)
{
return;
}
if (m_Health.sinceSpawn < m_LastSinceSpawn || m_Health.health <= 0f)
{
Clear();
return;
}
m_LastSinceSpawn = m_Health.sinceSpawn;
float num = Mathf.Max(0.05f, Plugin.PoisonTickInterval.Value);
m_TickTimer += Time.deltaTime;
if (!(m_TickTimer < num))
{
m_TickTimer -= num;
int num2 = Mathf.Max(1, Mathf.CeilToInt(m_TimeLeft / num));
float num3 = m_Remaining / (float)num2;
m_Remaining -= num3;
m_TimeLeft -= num;
if (m_TimeLeft <= 0f)
{
m_Remaining = 0f;
}
Controller val = m_Damager;
if ((Object)(object)val != (Object)null && !val.HasControl)
{
val = null;
}
if (m_Health.TakeDamage(num3, val, (DamageType)2, false, default(Vector3), default(Vector3)) && Plugin.PoisonParticles.Value)
{
Puff();
}
}
}
private void Puff()
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: 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_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_0049: 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)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: 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)
if (!((Object)(object)m_Particles == (Object)null) && !((Object)(object)m_Torso == (Object)null))
{
Color parsedColor = Plugin.ParsedColor;
for (int i = 0; i < 6; i++)
{
EmitParams val = default(EmitParams);
((EmitParams)(ref val)).position = m_Torso.position + Vector2.op_Implicit(Random.insideUnitCircle * 0.4f);
((EmitParams)(ref val)).velocity = new Vector3(0f, Random.Range(1f, 4f), Random.Range(-2f, 2f));
((EmitParams)(ref val)).startColor = Color32.op_Implicit(parsedColor);
((EmitParams)(ref val)).applyShapeToPosition = false;
m_Particles.Emit(val, 1);
}
}
}
}
internal static class RarityFix
{
[HarmonyPatch(typeof(WeaponSelectionHandler), "GenerateWeaponRarityArray")]
private static class AfterBagBuilt
{
[HarmonyPostfix]
private static void Postfix(WeaponSelectionHandler __instance)
{
s_Handler = __instance;
s_LastBuiltOnline = MatchmakingHandler.IsNetworkMatch;
if (Plugin.WithFramework || s_LastBuiltOnline || !Plugin.ReplaceSnakeGuns.Value)
{
return;
}
try
{
FindWeapons();
List<byte> list = s_Bag.Invoke(__instance);
if (list != null && s_RpgRarity >= 0)
{
if (Plugin.LauncherMatchesRpgRarity.Value)
{
SetWeight(list, s_LauncherIndex, s_RpgRarity);
}
if (Plugin.SeekerMatchesRpgRarity.Value)
{
SetWeight(list, s_SeekerIndex, s_RpgRarity);
}
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to adjust launcher rarity: " + ex));
}
}
}
[HarmonyPatch(typeof(WeaponSelectionHandler), "GetRandomWeaponIndex")]
private static class BeforeDraw
{
[HarmonyPrefix]
private static void Prefix(WeaponSelectionHandler __instance)
{
if (s_LastBuiltOnline != MatchmakingHandler.IsNetworkMatch && (object)s_Generate != null)
{
s_Generate.Invoke(__instance, null);
}
}
}
private static readonly FieldRef<WeaponSelectionHandler, List<byte>> s_Bag = AccessTools.FieldRefAccess<WeaponSelectionHandler, List<byte>>("m_WeaponRaritiesArray");
private static readonly MethodInfo s_Generate = AccessTools.Method(typeof(WeaponSelectionHandler), "GenerateWeaponRarityArray", (Type[])null, (Type[])null);
private static WeaponSelectionHandler s_Handler;
private static bool s_LastBuiltOnline;
private static int s_LauncherIndex = -2;
private static int s_SeekerIndex = -1;
private static int s_RpgRarity = -1;
private static void FindWeapons()
{
if (s_LauncherIndex != -2)
{
return;
}
s_LauncherIndex = -1;
ResourcesManager instance = ResourcesManager.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)instance.CharacterObject == (Object)null)
{
s_LauncherIndex = -2;
return;
}
Transform val = instance.CharacterObject.transform.Find("Weapons");
if ((Object)(object)val == (Object)null)
{
return;
}
for (int i = 0; i < val.childCount; i++)
{
Transform child = val.GetChild(i);
Weapon component = ((Component)child).GetComponent<Weapon>();
if ((Object)(object)component == (Object)null || (Object)(object)component.projectile == (Object)null)
{
continue;
}
string[] array = ((Object)child).name.Split(new char[1] { ' ' });
if (array.Length != 0 && byte.TryParse(array[0], out var result))
{
if (((Object)component.projectile).name == "SnakeBulletBig")
{
s_LauncherIndex = result;
}
else if (((Object)component.projectile).name == "SnakeBulletBigFly")
{
s_SeekerIndex = result;
}
else if (((Object)component.projectile).name == "Rocket" && component.isGun)
{
s_RpgRarity = component.Rarity;
}
}
}
if (s_RpgRarity < 0)
{
Plugin.Log.LogWarning((object)"Could not find the RPG; launcher and seeker rarity left unchanged.");
s_LauncherIndex = -1;
s_SeekerIndex = -1;
}
else
{
Plugin.Log.LogInfo((object)("Poison Launcher / Flying Poison spawn weight set to the RPG's (" + s_RpgRarity + ") in local play."));
}
}
private static void SetWeight(List<byte> bag, int index, int weight)
{
if (index >= 0 && bag.RemoveAll((byte b) => b == index) != 0)
{
for (int num = 0; num < weight; num++)
{
bag.Add((byte)index);
}
}
}
internal static void Rebuild()
{
if ((Object)(object)s_Handler == (Object)null || (object)s_Generate == null)
{
return;
}
try
{
s_Generate.Invoke(s_Handler, null);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to rebuild the spawn bag: " + ex));
}
}
}
[HarmonyPatch(typeof(Fighting), "Start")]
internal static class SnakeGunSwapper
{
private enum Kind
{
None,
Bullet,
Shotgun,
Rocket,
Seeker,
Grenade
}
private class WeaponState
{
public GameObject snakeProjectile;
public GameObject poisonProjectile;
public float snakeRecoil;
public float snakeTorsoRecoil;
public float poisonRecoil;
public float poisonTorsoRecoil;
}
[HarmonyPatch(typeof(Weapon), "ActuallyShoot")]
private static class BeforeShot
{
[HarmonyPrefix]
private static void Prefix(Weapon __instance)
{
if (s_States.TryGetValue(__instance, out var value))
{
ApplyMode(__instance, value);
}
}
}
private static GameObject s_Holder;
private static bool s_Built;
private static bool s_Logged;
private static GameObject s_PlainBullet;
private static GameObject s_OrbSource;
private static GameObject s_BlastVisual;
private static GameObject s_RocketSource;
private static float s_BaseDamage = 32f;
private static readonly Dictionary<GameObject, GameObject> s_Replacements = new Dictionary<GameObject, GameObject>();
private static readonly HashSet<GameObject> s_PoisonProjectiles = new HashSet<GameObject>();
private static readonly Dictionary<GameObject, bool> s_SnakeCache = new Dictionary<GameObject, bool>();
private static readonly Dictionary<Weapon, WeaponState> s_States = new Dictionary<Weapon, WeaponState>();
private static int s_GameWeaponCount = -1;
private static readonly Dictionary<Material, Material> s_Tinted = new Dictionary<Material, Material>();
private static void ApplyMode(Weapon w, WeaponState st)
{
bool flag = Plugin.ReplaceSnakeGuns.Value && !MatchmakingHandler.IsNetworkMatch;
w.projectile = (flag ? st.poisonProjectile : st.snakeProjectile);
w.recoil = (flag ? st.poisonRecoil : st.snakeRecoil);
w.torsoRecoil = (flag ? st.poisonTorsoRecoil : st.snakeTorsoRecoil);
}
private static void PruneStates()
{
if (s_States.Count < 400)
{
return;
}
List<Weapon> list = new List<Weapon>();
foreach (Weapon key in s_States.Keys)
{
if ((Object)(object)key == (Object)null)
{
list.Add(key);
}
}
foreach (Weapon item in list)
{
s_States.Remove(item);
}
}
[HarmonyPostfix]
private static void Postfix(Fighting __instance)
{
try
{
Weapon[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Weapon>(true);
if (componentsInChildren.Length == 0)
{
return;
}
if (!s_Built)
{
s_Built = true;
BuildSharedParts(componentsInChildren);
}
Weapon[] array = componentsInChildren;
foreach (Weapon val in array)
{
if ((Object)(object)val.projectile == (Object)null || s_States.ContainsKey(val) || s_PoisonProjectiles.Contains(val.projectile) || !IsGameWeapon(val))
{
continue;
}
Kind kind = KindOf(val.projectile);
GameObject replacement = GetReplacement(val.projectile);
if (!((Object)(object)replacement == (Object)null))
{
WeaponState weaponState = new WeaponState
{
snakeProjectile = val.projectile,
poisonProjectile = replacement,
snakeRecoil = val.recoil,
snakeTorsoRecoil = val.torsoRecoil,
poisonRecoil = val.recoil,
poisonTorsoRecoil = val.torsoRecoil
};
if (kind == Kind.Bullet && val.fullAuto && ((Object)val).name.ToLowerInvariant().Contains("minigun"))
{
float num = Mathf.Max(0f, Plugin.MinigunRecoilMultiplier.Value);
weaponState.poisonRecoil *= num;
weaponState.poisonTorsoRecoil *= num;
}
s_States[val] = weaponState;
ApplyMode(val, weaponState);
}
}
PruneStates();
if (Plugin.LogWeaponList.Value && !s_Logged)
{
s_Logged = true;
LogWeapons(componentsInChildren);
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to swap snake weapons: " + ex));
}
}
private static bool IsGameWeapon(Weapon w)
{
if (s_GameWeaponCount < 0)
{
ResourcesManager instance = ResourcesManager.Instance;
Transform val = (((Object)(object)instance != (Object)null && (Object)(object)instance.CharacterObject != (Object)null) ? instance.CharacterObject.transform.Find("Weapons") : null);
if ((Object)(object)val == (Object)null)
{
return true;
}
s_GameWeaponCount = val.childCount;
}
Transform parent = ((Component)w).transform.parent;
if ((Object)(object)parent == (Object)null || ((Object)parent).name != "Weapons")
{
return true;
}
return ((Component)w).transform.GetSiblingIndex() < s_GameWeaponCount;
}
private static Kind KindOf(GameObject projectile)
{
if ((Object)(object)projectile == (Object)null || !SpawnsSnakes(projectile))
{
return Kind.None;
}
return ((Object)projectile).name switch
{
"BulletShotgunSnake" => Kind.Shotgun,
"SnakeBulletBig" => Kind.Rocket,
"SnakeBulletBigFly" => Kind.Seeker,
"SnakeGrenade" => Kind.Grenade,
_ => Kind.Bullet,
};
}
private static bool SpawnsSnakes(GameObject go)
{
if ((Object)(object)go == (Object)null)
{
return false;
}
if (s_SnakeCache.TryGetValue(go, out var value))
{
return value;
}
bool flag = SpawnsSnakes(go, 0, new HashSet<GameObject>());
s_SnakeCache[go] = flag;
return flag;
}
private static bool SpawnsSnakes(GameObject go, int depth, HashSet<GameObject> seen)
{
if ((Object)(object)go == (Object)null || depth > 5 || !seen.Add(go))
{
return false;
}
if ((Object)(object)go.GetComponentInChildren<SnakeAI>(true) != (Object)null)
{
return true;
}
if ((Object)(object)go.GetComponentInChildren<SnakeSpawner>(true) != (Object)null)
{
return true;
}
ProjectileCollision[] componentsInChildren = go.GetComponentsInChildren<ProjectileCollision>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
if (SpawnsSnakes(componentsInChildren[i].spawnObject, depth + 1, seen))
{
return true;
}
}
SpawnObject[] componentsInChildren2 = go.GetComponentsInChildren<SpawnObject>(true);
for (int i = 0; i < componentsInChildren2.Length; i++)
{
if (SpawnsSnakes(componentsInChildren2[i].obj, depth + 1, seen))
{
return true;
}
}
SpawnObjectAfterDelay[] componentsInChildren3 = go.GetComponentsInChildren<SpawnObjectAfterDelay>(true);
for (int i = 0; i < componentsInChildren3.Length; i++)
{
if (SpawnsSnakes(componentsInChildren3[i].objectToSpawn, depth + 1, seen))
{
return true;
}
}
SpawnObjectInRandomRange[] componentsInChildren4 = go.GetComponentsInChildren<SpawnObjectInRandomRange>(true);
for (int i = 0; i < componentsInChildren4.Length; i++)
{
if (SpawnsSnakes(componentsInChildren4[i].obj, depth + 1, seen))
{
return true;
}
}
SpawnStickyObject[] componentsInChildren5 = go.GetComponentsInChildren<SpawnStickyObject>(true);
for (int i = 0; i < componentsInChildren5.Length; i++)
{
if (SpawnsSnakes(componentsInChildren5[i].stickyObject, depth + 1, seen))
{
return true;
}
}
return false;
}
private static bool IsPlainBullet(GameObject p)
{
if ((Object)(object)p == (Object)null || (Object)(object)p.GetComponent<RayCastForward>() == (Object)null)
{
return false;
}
ProjectileCollision component = p.GetComponent<ProjectileCollision>();
if ((Object)(object)component == (Object)null || component.damage <= 0f || (Object)(object)component.spawnObject != (Object)null)
{
return false;
}
if ((Object)(object)p.GetComponent<ProjectileBounce>() != (Object)null || (Object)(object)p.GetComponent<Gravity>() != (Object)null)
{
return false;
}
if ((Object)(object)p.GetComponent<SpawnStickyObject>() != (Object)null || (Object)(object)p.GetComponent<StickyObject>() != (Object)null)
{
return false;
}
return !SpawnsSnakes(p);
}
private static void BuildSharedParts(Weapon[] weapons)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Expected O, but got Unknown
//IL_025d: Unknown result type (might be due to invalid IL or missing references)
s_Holder = new GameObject("PoisonGuns_Templates");
s_Holder.SetActive(false);
Object.DontDestroyOnLoad((Object)(object)s_Holder);
string text = (Plugin.TemplateWeapon.Value ?? string.Empty).Trim().ToLowerInvariant();
Weapon val = null;
GameObject val2 = null;
foreach (Weapon val3 in weapons)
{
if ((Object)(object)val3.projectile != (Object)null && ((Object)val3.projectile).name == "SnakeGrenade")
{
val2 = val3.projectile;
}
if ((Object)(object)val3.projectile != (Object)null && ((Object)val3.projectile).name == "Rocket")
{
s_RocketSource = val3.projectile;
}
if (val3.isGun && IsPlainBullet(val3.projectile))
{
if (text.Length > 0 && ((Object)val3).name.ToLowerInvariant().Contains(text) && ((Object)(object)val == (Object)null || !((Object)val).name.ToLowerInvariant().Contains(text)))
{
val = val3;
}
if ((Object)(object)val == (Object)null)
{
val = val3;
}
}
}
if ((Object)(object)val == (Object)null)
{
Plugin.Log.LogError((object)"Could not find a normal gun to copy a bullet from. Snake weapons were left unchanged.");
return;
}
s_PlainBullet = val.projectile;
s_BaseDamage = s_PlainBullet.GetComponent<ProjectileCollision>().damage;
Plugin.Log.LogInfo((object)("Poison bullets are built from '" + ((Object)val).name + "' (" + ((Object)s_PlainBullet).name + ", " + s_BaseDamage + " damage)."));
if ((Object)(object)val2 != (Object)null)
{
Transform val4 = val2.transform.Find("Sphere");
if ((Object)(object)val4 != (Object)null)
{
s_OrbSource = ((Component)val4).gameObject;
}
SpawnObjectAfterDelay component = val2.GetComponent<SpawnObjectAfterDelay>();
if ((Object)(object)component != (Object)null && (Object)(object)component.objectToSpawn != (Object)null)
{
Transform val5 = component.objectToSpawn.transform.Find("ExplosionSmaller");
if ((Object)(object)val5 != (Object)null)
{
s_BlastVisual = Object.Instantiate<GameObject>(((Component)val5).gameObject, s_Holder.transform);
((Object)s_BlastVisual).name = "PoisonBlast";
Tint(s_BlastVisual, Plugin.ParsedColor);
}
}
}
if ((Object)(object)s_OrbSource == (Object)null)
{
Plugin.Log.LogWarning((object)"Snake grenade ball not found; poison projectiles will have no orb.");
}
if ((Object)(object)s_BlastVisual == (Object)null)
{
Plugin.Log.LogWarning((object)"Snake bomb explosion not found; poison blasts will be invisible.");
}
}
private static GameObject GetReplacement(GameObject original)
{
if (s_Replacements.TryGetValue(original, out var value))
{
return value;
}
GameObject val = null;
Kind kind = KindOf(original);
if (kind != Kind.None && (Object)(object)s_PlainBullet != (Object)null)
{
switch (kind)
{
case Kind.Bullet:
val = MakeBullet("PoisonBullet", s_Holder.transform);
break;
case Kind.Shotgun:
val = MakeShotgun(original);
break;
case Kind.Rocket:
val = MakeRocket(seeker: false);
break;
case Kind.Seeker:
val = MakeRocket(seeker: true);
break;
case Kind.Grenade:
val = MakeGrenade(original);
break;
}
if ((Object)(object)val != (Object)null)
{
s_PoisonProjectiles.Add(val);
Plugin.Log.LogInfo((object)("Built " + ((Object)val).name + " to replace " + ((Object)original).name + "."));
}
}
s_Replacements[original] = val;
return val;
}
private static GameObject BuildFlyingProjectile(string name, Transform parent, float speed, float orbSize, float impact, float poisonOnHit, float trailWidth)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0171: Unknown result type (might be due to invalid IL or missing references)
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
//IL_0215: Unknown result type (might be due to invalid IL or missing references)
GameObject val = Object.Instantiate<GameObject>(s_PlainBullet, parent);
((Object)val).name = name;
val.transform.localPosition = Vector3.zero;
val.transform.localRotation = Quaternion.identity;
RayCastForward[] componentsInChildren = val.GetComponentsInChildren<RayCastForward>(true);
foreach (RayCastForward obj in componentsInChildren)
{
obj.speed = Mathf.Max(0.5f, speed);
obj.friction = 0f;
}
RemoveAfterSeconds[] componentsInChildren2 = val.GetComponentsInChildren<RemoveAfterSeconds>(true);
foreach (RemoveAfterSeconds obj2 in componentsInChildren2)
{
obj2.time = Mathf.Max(obj2.time, Plugin.BulletLifetime.Value);
}
ProjectileCollision component = val.GetComponent<ProjectileCollision>();
component.damage = s_BaseDamage * Mathf.Max(0f, impact);
component.SpecialEffect = "PoisonGunsHit";
component.secondsToDestroyAfterCollision = Mathf.Min(component.secondsToDestroyAfterCollision, 3f);
val.AddComponent<PoisonBullet>().poisonDamage = s_BaseDamage * Mathf.Max(0f, poisonOnHit);
Tint(val, Plugin.ParsedColor);
TrailRenderer[] componentsInChildren3 = val.GetComponentsInChildren<TrailRenderer>(true);
foreach (TrailRenderer obj3 in componentsInChildren3)
{
obj3.widthMultiplier *= trailWidth;
}
PoisonProjectile poisonProjectile = val.AddComponent<PoisonProjectile>();
if ((Object)(object)s_OrbSource != (Object)null)
{
GameObject val2 = Object.Instantiate<GameObject>(s_OrbSource, val.transform);
((Object)val2).name = "PoisonOrb";
val2.SetActive(true);
val2.transform.localPosition = Vector3.zero;
val2.transform.localRotation = Quaternion.identity;
val2.transform.localScale = Vector3.one * Mathf.Max(0.05f, orbSize);
Collider[] componentsInChildren4 = val2.GetComponentsInChildren<Collider>(true);
for (int i = 0; i < componentsInChildren4.Length; i++)
{
Object.DestroyImmediate((Object)(object)componentsInChildren4[i]);
}
Rigidbody[] componentsInChildren5 = val2.GetComponentsInChildren<Rigidbody>(true);
for (int i = 0; i < componentsInChildren5.Length; i++)
{
Object.DestroyImmediate((Object)(object)componentsInChildren5[i]);
}
MonoBehaviour[] componentsInChildren6 = val2.GetComponentsInChildren<MonoBehaviour>(true);
for (int i = 0; i < componentsInChildren6.Length; i++)
{
Object.DestroyImmediate((Object)(object)componentsInChildren6[i]);
}
Tint(val2, Plugin.ParsedColor);
poisonProjectile.orb = val2;
}
return val;
}
private static GameObject MakeBullet(string name, Transform parent)
{
return BuildFlyingProjectile(name, parent, Plugin.BulletSpeed.Value, Plugin.BulletOrbSize.Value, Plugin.ImpactDamageMultiplier.Value, Plugin.PoisonDamageMultiplier.Value, 1.5f);
}
private static GameObject MakeShotgun(GameObject original)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: 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_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("PoisonShotgunShell");
val.transform.SetParent(s_Holder.transform, false);
val.AddComponent<RemoveAfterSeconds>().time = Plugin.BulletLifetime.Value + 4f;
List<Vector3> list = new List<Vector3>();
List<float> list2 = new List<float>();
SnakeSpawner componentInChildren = original.GetComponentInChildren<SnakeSpawner>(true);
if ((Object)(object)componentInChildren != (Object)null && AccessTools.Field(typeof(SnakeSpawner), "Spawns").GetValue(componentInChildren) is List<Spawn> list3)
{
foreach (Spawn item in list3)
{
list.Add(item.Rot);
list2.Add(item.Pos.y);
}
}
if (list.Count == 0)
{
list.Add(Vector3.zero);
list2.Add(0f);
list.Add(new Vector3(-20f, 0f, 0f));
list2.Add(0.4f);
list.Add(new Vector3(20f, 0f, 0f));
list2.Add(-0.4f);
}
for (int i = 0; i < list.Count; i++)
{
GameObject obj = MakeBullet("PoisonPellet" + i, val.transform);
obj.transform.localRotation = Quaternion.Euler(list[i]);
obj.transform.localPosition = new Vector3(0f, list2[i], 0f);
RayCastForward[] componentsInChildren = obj.GetComponentsInChildren<RayCastForward>(true);
for (int j = 0; j < componentsInChildren.Length; j++)
{
componentsInChildren[j].spread = Mathf.Max(0f, Plugin.ShotgunPelletSpread.Value);
}
}
return val;
}
private static GameObject MakeRocket(bool seeker)
{
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
GameObject val;
PoisonProjectile component;
if (!seeker)
{
val = BuildFlyingProjectile("PoisonRocket", s_Holder.transform, Plugin.RocketSpeed.Value, Plugin.RocketOrbSize.Value, Plugin.RocketImpactDamage.Value, 0f, 2f);
component = val.GetComponent<PoisonProjectile>();
component.blastRadius = Plugin.RocketBlastRadius.Value;
component.blastPoison = s_BaseDamage * Plugin.RocketBlastPoison.Value;
GameObject val2 = BuildRocketModel(val.transform);
if ((Object)(object)val2 != (Object)null)
{
if ((Object)(object)component.orb != (Object)null)
{
Object.DestroyImmediate((Object)(object)component.orb);
}
component.orb = val2;
TrailRenderer[] componentsInChildren = val.GetComponentsInChildren<TrailRenderer>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
((Renderer)componentsInChildren[i]).enabled = false;
}
val2.AddComponent<PoisonSpin>().degreesPerSecond = Plugin.RocketSpinSpeed.Value;
}
}
else
{
val = BuildFlyingProjectile("PoisonSeeker", s_Holder.transform, Plugin.SeekerSpeed.Value, Plugin.SeekerOrbSize.Value, Plugin.SeekerImpactDamage.Value, 0f, 3f);
component = val.GetComponent<PoisonProjectile>();
component.blastRadius = Plugin.SeekerBlastRadius.Value;
component.blastPoison = s_BaseDamage * Plugin.SeekerBlastPoison.Value;
TrailRenderer[] componentsInChildren = val.GetComponentsInChildren<TrailRenderer>(true);
foreach (TrailRenderer val3 in componentsInChildren)
{
val3.time = 0.7f;
val3.minVertexDistance = 0.05f;
val3.widthCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f);
val3.widthMultiplier = Mathf.Max(0.05f, Plugin.SeekerOrbSize.Value);
val3.endColor = new Color(val3.endColor.r, val3.endColor.g, val3.endColor.b, 0f);
}
PoisonHoming poisonHoming = val.AddComponent<PoisonHoming>();
poisonHoming.turnRate = Plugin.SeekerTurnRate.Value;
poisonHoming.range = Plugin.SeekerRange.Value;
}
component.blastVisual = s_BlastVisual;
Object.DestroyImmediate((Object)(object)val.GetComponent<PoisonBullet>());
val.GetComponent<ProjectileCollision>().SpecialEffect = string.Empty;
return val;
}
private static GameObject BuildRocketModel(Transform parent)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Expected O, but got Unknown
//IL_0046: 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_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Expected O, but got Unknown
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
//IL_01be: Unknown result type (might be due to invalid IL or missing references)
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)s_RocketSource == (Object)null)
{
Plugin.Log.LogWarning((object)"RPG rocket not found; the poison rocket keeps the plain orb.");
return null;
}
GameObject val = new GameObject("PoisonRocketModel");
val.transform.SetParent(parent, false);
val.transform.localScale = s_RocketSource.transform.localScale * Mathf.Max(0.1f, Plugin.RocketModelScale.Value);
val.transform.localRotation = Quaternion.identity;
foreach (Transform item in s_RocketSource.transform)
{
Transform val2 = item;
if (!((Component)val2).gameObject.activeSelf)
{
continue;
}
GameObject val3 = Object.Instantiate<GameObject>(((Component)val2).gameObject, val.transform);
((Object)val3).name = ((Object)val2).name;
val3.transform.localPosition = val2.localPosition;
val3.transform.localRotation = val2.localRotation;
val3.transform.localScale = val2.localScale;
Joint[] componentsInChildren = val3.GetComponentsInChildren<Joint>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
}
Collider[] componentsInChildren2 = val3.GetComponentsInChildren<Collider>(true);
for (int i = 0; i < componentsInChildren2.Length; i++)
{
Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
}
Rigidbody[] componentsInChildren3 = val3.GetComponentsInChildren<Rigidbody>(true);
for (int i = 0; i < componentsInChildren3.Length; i++)
{
Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
}
MonoBehaviour[] componentsInChildren4 = val3.GetComponentsInChildren<MonoBehaviour>(true);
for (int i = 0; i < componentsInChildren4.Length; i++)
{
Object.DestroyImmediate((Object)(object)componentsInChildren4[i]);
}
ParticleSystem component = val3.GetComponent<ParticleSystem>();
if (!((Object)(object)component != (Object)null) || !((Object)(object)val3.GetComponent<MeshRenderer>() == (Object)null))
{
continue;
}
MainModule main = component.main;
((MainModule)(ref main)).startColor = new MinMaxGradient(Plugin.ParsedColor);
ParticleSystemRenderer component2 = val3.GetComponent<ParticleSystemRenderer>();
if ((Object)(object)component2 != (Object)null)
{
Material[] sharedMaterials = ((Renderer)component2).sharedMaterials;
for (int j = 0; j < sharedMaterials.Length; j++)
{
sharedMaterials[j] = TintedMaterial(sharedMaterials[j], Plugin.ParsedColor);
}
((Renderer)component2).sharedMaterials = sharedMaterials;
}
}
return val;
}
private static GameObject MakeGrenade(GameObject original)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = Object.Instantiate<GameObject>(original, s_Holder.transform);
((Object)obj).name = "PoisonGrenade";
Tint(obj, Plugin.ParsedColor);
PoisonGrenade poisonGrenade = obj.AddComponent<PoisonGrenade>();
SpawnObjectAfterDelay component = obj.GetComponent<SpawnObjectAfterDelay>();
if ((Object)(object)component != (Object)null)
{
poisonGrenade.fuse = component.secondsBeforeSpawn;
((Behaviour)component).enabled = false;
}
poisonGrenade.blastRadius = Plugin.GrenadeBlastRadius.Value;
poisonGrenade.blastPoison = s_BaseDamage * Plugin.GrenadeBlastPoison.Value;
poisonGrenade.blastVisual = s_BlastVisual;
return obj;
}
private static void Tint(GameObject root, Color color)
{
//IL_0011: 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_001d: 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_002e: 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_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: 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_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: 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: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: 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)
//IL_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_018e: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
TrailRenderer[] componentsInChildren = root.GetComponentsInChildren<TrailRenderer>(true);
foreach (TrailRenderer val in componentsInChildren)
{
val.startColor = new Color(color.r, color.g, color.b, val.startColor.a);
val.endColor = new Color(color.r, color.g, color.b, val.endColor.a);
((Renderer)val).sharedMaterial = TintedMaterial(((Renderer)val).sharedMaterial, color);
}
LineRenderer[] componentsInChildren2 = root.GetComponentsInChildren<LineRenderer>(true);
foreach (LineRenderer val2 in componentsInChildren2)
{
val2.startColor = new Color(color.r, color.g, color.b, val2.startColor.a);
val2.endColor = new Color(color.r, color.g, color.b, val2.endColor.a);
((Renderer)val2).sharedMaterial = TintedMaterial(((Renderer)val2).sharedMaterial, color);
}
SpriteRenderer[] componentsInChildren3 = root.GetComponentsInChildren<SpriteRenderer>(true);
foreach (SpriteRenderer val3 in componentsInChildren3)
{
val3.color = new Color(color.r, color.g, color.b, val3.color.a);
}
MeshRenderer[] componentsInChildren4 = root.GetComponentsInChildren<MeshRenderer>(true);
foreach (MeshRenderer obj in componentsInChildren4)
{
((Renderer)obj).sharedMaterial = TintedMaterial(((Renderer)obj).sharedMaterial, color);
}
ParticleSystem[] componentsInChildren5 = root.GetComponentsInChildren<ParticleSystem>(true);
for (int i = 0; i < componentsInChildren5.Length; i++)
{
MainModule main = componentsInChildren5[i].main;
((MainModule)(ref main)).startColor = new MinMaxGradient(color);
}
}
private static Material TintedMaterial(Material original, Color color)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Expected O, but got Unknown
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: 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_0064: 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_008b: 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_0097: 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: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)original == (Object)null)
{
return null;
}
if (s_Tinted.TryGetValue(original, out var value))
{
return value;
}
value = new Material(original);
((Object)value).name = ((Object)original).name + " (Poison)";
if (value.HasProperty("_Color"))
{
value.SetColor("_Color", new Color(color.r, color.g, color.b, value.GetColor("_Color").a));
}
if (value.HasProperty("_TintColor"))
{
value.SetColor("_TintColor", new Color(color.r, color.g, color.b, value.GetColor("_TintColor").a));
}
if (value.HasProperty("_EmissionColor"))
{
value.SetColor("_EmissionColor", color);
}
s_Tinted[original] = value;
s_Tinted[value] = value;
return value;
}
private static void LogWeapons(Weapon[] weapons)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Snake weapons swapped (weapon | now fires):");
foreach (Weapon val in weapons)
{
if (s_States.TryGetValue(val, out var value))
{
stringBuilder.Append(" ").Append(((Object)val).name).Append(" | ")
.Append(((Object)value.poisonProjectile).name)
.AppendLine();
}
}
stringBuilder.Append("(Online matches use the original snakes.)");
Plugin.Log.LogInfo((object)stringBuilder.ToString());
}
}