Decompiled source of ScrapOutside v1.0.0

Tomatobird.ScrapOutside.dll

Decompiled 10 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Tomatobird.ScrapOutside")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+1294e05c7062828bc41b5fcb74fdd9427f263f89")]
[assembly: AssemblyProduct("LC_ScrapOutside")]
[assembly: AssemblyTitle("Tomatobird.ScrapOutside")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 LC_ScrapOutside
{
	[BepInPlugin("Tomatobird.ScrapOutside", "LC_ScrapOutside", "1.0.0")]
	public class LC_ScrapOutside : BaseUnityPlugin
	{
		public enum Algorithm
		{
			Static,
			Random,
			Dynamic
		}

		public static ConfigEntry<Algorithm> scrapCountAlgorithm;

		public static ConfigEntry<float> chanceToSpawn;

		public static ConfigEntry<int> staticScrapToSpawn;

		public static ConfigEntry<int> randomScrapMin;

		public static ConfigEntry<int> randomScrapMax;

		public static ConfigEntry<float> dynamicBaseScrapAmount;

		public static ConfigEntry<bool> scaleScrapByLuck;

		public static ConfigEntry<bool> useInternalLuckValue;

		public static ConfigEntry<float> luckMultiplier;

		public static ConfigEntry<bool> scaleScrapByQuota;

		public static ConfigEntry<bool> inverseQuotaBasedMultiplier;

		public static ConfigEntry<int> baselineQuotaValue;

		public static ConfigEntry<float> quotaValueMultiplierScalar;

		public static ConfigEntry<bool> scaleScrapByMoonScrapAmount;

		public static ConfigEntry<float> baselineMoonScrapAmount;

		public static ConfigEntry<float> moonScrapAmountDifferenceScalar;

		public static ConfigEntry<bool> scaleScrapByWeather;

		public static ConfigEntry<string> weatherMultipliers;

		public static ConfigEntry<bool> extraVariance;

		public static ConfigEntry<float> extraVarianceMin;

		public static ConfigEntry<float> extraVarianceMax;

		public static ConfigEntry<int> minScrapToSpawn;

		public static ConfigEntry<int> maxScrapToSpawn;

		public static LC_ScrapOutside Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static Harmony? Harmony { get; set; }

		private void Awake()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			scrapCountAlgorithm = ((BaseUnityPlugin)this).Config.Bind<Algorithm>("General", "Scrap Count Algorithm", Algorithm.Dynamic, "Which method to use for calculating scrap amount.");
			chanceToSpawn = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Chance To Spawn", 1f, new ConfigDescription("Chance for outside scrap to spawn. 0 for never, 1 for always", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			staticScrapToSpawn = ((BaseUnityPlugin)this).Config.Bind<int>("Static", "Scrap Amount", 6, "Amount of scrap to spawn outside.");
			randomScrapMin = ((BaseUnityPlugin)this).Config.Bind<int>("Random", "Minimum", 4, "Minimum amount of scrap to spawn. Inclusive. This should always be lower than Maximum.");
			randomScrapMax = ((BaseUnityPlugin)this).Config.Bind<int>("Random", "Maximum", 8, "Maximum amount of scrap to spawn. Inclusive.");
			dynamicBaseScrapAmount = ((BaseUnityPlugin)this).Config.Bind<float>("Dynamic", "Base Scrap Amount", 6f, "Base amount of scrap to spawn.");
			scaleScrapByLuck = ((BaseUnityPlugin)this).Config.Bind<bool>("Dynamic", "Use Furniture Luck", true, "Should scrap amount scale by luck value?");
			useInternalLuckValue = ((BaseUnityPlugin)this).Config.Bind<bool>("Dynamic", "User Internal Luck Value", false, "Instead of calculating the current furniture luck immediately from the currently placed furniture, should the internal luck value be used? The internal value only updates each quota after quota 2.");
			luckMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Dynamic", "Furniture Luck Multiplier", 2f, "How much is furniture luck scaled by for the multiplication?");
			scaleScrapByQuota = ((BaseUnityPlugin)this).Config.Bind<bool>("Dynamic", "Use Quota Value", true, "Should scrap amount scale by quota value?");
			baselineQuotaValue = ((BaseUnityPlugin)this).Config.Bind<int>("Dynamic", "Baseline Quota Value", 1000, "The quota value baseline. Values below are decrease scrap amount, values above increase it.");
			inverseQuotaBasedMultiplier = ((BaseUnityPlugin)this).Config.Bind<bool>("Dynamic", "Inverse Quota Based Multiplier", false, "Should scrap amount decrease as quota increases?");
			quotaValueMultiplierScalar = ((BaseUnityPlugin)this).Config.Bind<float>("Dynamic", "Quota Value Multiplier Scalar", 0.5f, "How effective is the multiplier? Multiplier^Scalar = Final Multiplier. 1.0 makes this not affect it. Lower values reduce the effect, higher values strengthen it.");
			scaleScrapByMoonScrapAmount = ((BaseUnityPlugin)this).Config.Bind<bool>("Dynamic", "Use Moon Scrap Amount", true, "Should scrap amount be based on how many items there are on the moon on average?");
			baselineMoonScrapAmount = ((BaseUnityPlugin)this).Config.Bind<float>("Dynamic", "Baseline Moon Scrap Amount", 18f, "The baseline item count where the scrap amount is decreased if the moon average item count is lower, and increased if its higher.");
			moonScrapAmountDifferenceScalar = ((BaseUnityPlugin)this).Config.Bind<float>("Dynamic", "Moon Scrap Amount Difference Scalar", 0.5f, "How effective should the moon scrap amount multiplier be?");
			scaleScrapByWeather = ((BaseUnityPlugin)this).Config.Bind<bool>("Dynamic", "Use Weather", true, "Should weathers affect the scrap amount?");
			weatherMultipliers = ((BaseUnityPlugin)this).Config.Bind<string>("Dynamic", "Weather Multipliers", "none:1.0,rainy:1.1,foggy:1.2,flooded:1.3,stormy:1.4,eclipsed:1.5", "Weather Multipliers. Format: weathername:float_value,weathername:float_value");
			extraVariance = ((BaseUnityPlugin)this).Config.Bind<bool>("Dynamic", "Extra Variance Multiplier", true, "Should scrap amount be multiplied by a random multiplier between the random variance min and max?");
			extraVarianceMin = ((BaseUnityPlugin)this).Config.Bind<float>("Dynamic", "Extra Variance Minimum", 0.7f, "Minimum multiplier for extra variance. Make sure this is lower than maximum variance multiplier.");
			extraVarianceMax = ((BaseUnityPlugin)this).Config.Bind<float>("Dynamic", "Extra Variance Maximum", 1.3f, "Maximum multiplier for extra variance.");
			minScrapToSpawn = ((BaseUnityPlugin)this).Config.Bind<int>("Dynamic", "Min Scrap To Spawn", 1, "Minimum amount of scrap to spawn. Make sure this is lower than maximum scrap to spawn.");
			maxScrapToSpawn = ((BaseUnityPlugin)this).Config.Bind<int>("Dynamic", "Max Scrap To Spawn", 250, "Maximum amount of scrap to spawn.");
			Patch();
			Logger.LogInfo((object)"Tomatobird.ScrapOutside v1.0.0 has loaded!");
		}

		internal static void Patch()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony = new Harmony("Tomatobird.ScrapOutside");
			}
			Logger.LogDebug((object)"Patching...");
			Harmony.PatchAll();
			Logger.LogDebug((object)"Finished patching!");
		}

		internal static void Unpatch()
		{
			Logger.LogDebug((object)"Unpatching...");
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Logger.LogDebug((object)"Finished unpatching!");
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Tomatobird.ScrapOutside";

		public const string PLUGIN_NAME = "LC_ScrapOutside";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace LC_ScrapOutside.Patches
{
	[HarmonyPatch]
	public class SpawnScrap
	{
		[HarmonyPatch(typeof(RoundManager), "waitForScrapToSpawnToSync")]
		[HarmonyPrefix]
		public static void WaitForScrapToSpawn_Prefix(ref NetworkObjectReference[] spawnedScrap, ref int[] scrapValues)
		{
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			Random random = new Random(StartOfRound.Instance.randomMapSeed + 69420 - 67);
			if (random.NextDouble() >= (double)LC_ScrapOutside.chanceToSpawn.Value)
			{
				LC_ScrapOutside.Logger.LogInfo((object)$"Unlucky! No scrap will spawn due to ChanceToSpawn: {LC_ScrapOutside.chanceToSpawn.Value} being lower than the chosen random value.");
				return;
			}
			if (LC_ScrapOutside.extraVarianceMin.Value > LC_ScrapOutside.extraVarianceMax.Value)
			{
				LC_ScrapOutside.Logger.LogWarning((object)"ExtraVarianceMin was smaller than ExtraVarianceMax. Please readjust your configuration.");
				LC_ScrapOutside.extraVarianceMin.Value = LC_ScrapOutside.extraVarianceMax.Value;
				((ConfigEntryBase)LC_ScrapOutside.extraVarianceMin).ConfigFile.Save();
				LC_ScrapOutside.Logger.LogWarning((object)"ExtraVarianceMin was replaced with ExtraVarianceMax to avoid errors.");
			}
			if (LC_ScrapOutside.minScrapToSpawn.Value > LC_ScrapOutside.maxScrapToSpawn.Value)
			{
				LC_ScrapOutside.Logger.LogWarning((object)"MinScrapToSpawn was smaller than MaxScrapToSpawn. Please readjust your configuration.");
				LC_ScrapOutside.minScrapToSpawn.Value = LC_ScrapOutside.maxScrapToSpawn.Value;
				((ConfigEntryBase)LC_ScrapOutside.minScrapToSpawn).ConfigFile.Save();
				LC_ScrapOutside.Logger.LogWarning((object)"MinScrapToSpawn was replaced with MaxScrapToSpawn to avoid errors.");
			}
			if (LC_ScrapOutside.randomScrapMin.Value > LC_ScrapOutside.randomScrapMax.Value)
			{
				LC_ScrapOutside.Logger.LogWarning((object)"RandomScrapMin was smaller than RandomScrapMax. Please readjust your configuration.");
				LC_ScrapOutside.randomScrapMin.Value = LC_ScrapOutside.randomScrapMax.Value;
				((ConfigEntryBase)LC_ScrapOutside.randomScrapMin).ConfigFile.Save();
				LC_ScrapOutside.Logger.LogWarning((object)"RandomScrapMin was replaced with RandomScrapMax to avoid errors.");
			}
			int scrapSpawnAmount = GetScrapSpawnAmount();
			if (scrapSpawnAmount <= 0)
			{
				LC_ScrapOutside.Logger.LogInfo((object)"No scrap to spawn outside.");
				return;
			}
			LC_ScrapOutside.Logger.LogInfo((object)$"Spawning {scrapSpawnAmount} scrap objects outside.");
			List<Item> list = SelectScrap(scrapSpawnAmount);
			List<int> list2 = new List<int>();
			List<NetworkObjectReference> list3 = new List<NetworkObjectReference>();
			List<Vector3> list4 = (from n in GameObject.FindGameObjectsWithTag("OutsideAINode")
				select n.transform.position).ToList();
			if (list4.Count <= 0)
			{
				LC_ScrapOutside.Logger.LogWarning((object)"No outside nodes found. Outside scrap cannot be spawned.");
				return;
			}
			for (int num = 0; num < list.Count; num++)
			{
				Vector3 randomNavMeshPositionInBoxPredictable = RoundManager.Instance.GetRandomNavMeshPositionInBoxPredictable(list4[Random.Range(0, list4.Count)], 10f, RoundManager.Instance.navHit, random, -1, 1f);
				GameObject val = Object.Instantiate<GameObject>(list[num].spawnPrefab, randomNavMeshPositionInBoxPredictable + Vector3.up * list[num].verticalOffset, Quaternion.identity, RoundManager.Instance.spawnedScrapContainer);
				GrabbableObject component = val.GetComponent<GrabbableObject>();
				((Component)component).transform.rotation = Quaternion.Euler(component.itemProperties.restingRotation);
				component.fallTime = 0f;
				list2.Add((int)((float)Random.Range(list[num].minValue, list[num].maxValue) * RoundManager.Instance.scrapValueMultiplier));
				component.scrapValue = list2[list2.Count - 1];
				NetworkObject component2 = val.GetComponent<NetworkObject>();
				component2.Spawn(false);
				list3.Add(NetworkObjectReference.op_Implicit(component2));
			}
			List<NetworkObjectReference> list5 = spawnedScrap.ToList();
			List<int> list6 = scrapValues.ToList();
			for (int num2 = 0; num2 < list3.Count; num2++)
			{
				list5.Add(list3[num2]);
				list6.Add(list2[num2]);
			}
			spawnedScrap = list5.ToArray();
			scrapValues = list6.ToArray();
		}

		internal static List<Item> SelectScrap(int amount)
		{
			Random random = new Random(StartOfRound.Instance.randomMapSeed + 64208);
			List<Item> list = new List<Item>();
			List<int> list2 = new List<int>();
			for (int i = 0; i < RoundManager.Instance.currentLevel.spawnableScrap.Count; i++)
			{
				list2.Add(RoundManager.Instance.currentLevel.spawnableScrap[i].rarity);
			}
			int[] array = list2.ToArray();
			for (int j = 0; j < amount; j++)
			{
				list.Add(RoundManager.Instance.currentLevel.spawnableScrap[RoundManager.Instance.GetRandomWeightedIndex(array, random)].spawnableItem);
			}
			return list;
		}

		internal static float GetExtraVariance()
		{
			Random random = new Random(StartOfRound.Instance.randomMapSeed + 35121);
			return (float)random.NextDouble() * (LC_ScrapOutside.extraVarianceMax.Value - LC_ScrapOutside.extraVarianceMin.Value) + LC_ScrapOutside.extraVarianceMin.Value;
		}

		internal static int GetScrapSpawnAmount()
		{
			return LC_ScrapOutside.scrapCountAlgorithm.Value switch
			{
				LC_ScrapOutside.Algorithm.Static => GetStaticScrapAmount(), 
				LC_ScrapOutside.Algorithm.Random => GetRandomScrapAmount(), 
				LC_ScrapOutside.Algorithm.Dynamic => Mathf.RoundToInt(GetDynamicScrapAmount()), 
				_ => 0, 
			};
		}

		internal static int GetStaticScrapAmount()
		{
			return (LC_ScrapOutside.staticScrapToSpawn.Value >= 0) ? LC_ScrapOutside.staticScrapToSpawn.Value : 0;
		}

		internal static int GetRandomScrapAmount()
		{
			Random random = new Random(StartOfRound.Instance.randomMapSeed + 64914);
			return random.Next(LC_ScrapOutside.randomScrapMin.Value, LC_ScrapOutside.randomScrapMax.Value + 1);
		}

		[MethodImpl(MethodImplOptions.NoOptimization)]
		internal static float GetDynamicScrapAmount()
		{
			float num = 1f;
			LC_ScrapOutside.Logger.LogDebug((object)$"Multiplier at Start: {num}");
			if (LC_ScrapOutside.scaleScrapByLuck.Value)
			{
				num *= CalculateLuckValue() * LC_ScrapOutside.luckMultiplier.Value + 1f;
				LC_ScrapOutside.Logger.LogDebug((object)$"Multiplier after luckBasedScrapMultiplier: {num}");
			}
			if (LC_ScrapOutside.scaleScrapByQuota.Value)
			{
				num *= Mathf.Pow(LC_ScrapOutside.inverseQuotaBasedMultiplier.Value ? ((float)LC_ScrapOutside.baselineQuotaValue.Value / (float)TimeOfDay.Instance.profitQuota) : ((float)TimeOfDay.Instance.profitQuota / (float)LC_ScrapOutside.baselineQuotaValue.Value), LC_ScrapOutside.quotaValueMultiplierScalar.Value);
				LC_ScrapOutside.Logger.LogDebug((object)$"Multiplier after quotaBasedScrapMultiplier: {num}");
			}
			if (LC_ScrapOutside.scaleScrapByMoonScrapAmount.Value)
			{
				float num2 = (RoundManager.Instance.currentLevel.maxScrap + RoundManager.Instance.currentLevel.minScrap) / 2;
				num *= Mathf.Pow(num2 / LC_ScrapOutside.baselineMoonScrapAmount.Value, LC_ScrapOutside.moonScrapAmountDifferenceScalar.Value);
				LC_ScrapOutside.Logger.LogDebug((object)$"Multiplier after moonScrapAmountBasedMultiplier: {num}");
			}
			if (LC_ScrapOutside.scaleScrapByWeather.Value)
			{
				Dictionary<string, float> weatherMultipliersDict = GetWeatherMultipliersDict();
				if (weatherMultipliersDict != null)
				{
					if (weatherMultipliersDict.TryGetValue(((object)Unsafe.As<LevelWeatherType, LevelWeatherType>(ref RoundManager.Instance.currentLevel.currentWeather)/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(), out var value))
					{
						num *= value;
					}
					else
					{
						LC_ScrapOutside.Logger.LogWarning((object)("Couldn't get weather multiplier for " + ((object)Unsafe.As<LevelWeatherType, LevelWeatherType>(ref RoundManager.Instance.currentLevel.currentWeather)/*cast due to .constrained prefix*/).ToString().ToLower() + ". weathername:multiplier not found in config."));
					}
				}
				LC_ScrapOutside.Logger.LogDebug((object)$"Multiplier after weatherBasedMultiplier: {num}");
			}
			if (LC_ScrapOutside.extraVariance.Value)
			{
				num *= GetExtraVariance();
				LC_ScrapOutside.Logger.LogDebug((object)$"Multiplier after extraVariance: {num}");
			}
			return Mathf.Clamp(LC_ScrapOutside.dynamicBaseScrapAmount.Value * num, (float)LC_ScrapOutside.minScrapToSpawn.Value, (float)LC_ScrapOutside.maxScrapToSpawn.Value);
		}

		internal static Dictionary<string, float>? GetWeatherMultipliersDict()
		{
			try
			{
				Dictionary<string, float> dictionary = new Dictionary<string, float>();
				string[] array = LC_ScrapOutside.weatherMultipliers.Value.Split(',');
				if (array.Length == 0)
				{
					return null;
				}
				string[] array2 = array;
				foreach (string text in array2)
				{
					string[] array3 = text.Split(":");
					if (array3.Length > 1 && float.TryParse(array3[1].Trim(), out var result))
					{
						dictionary.Add(array3[0].Trim().ToLowerInvariant(), result);
					}
				}
				return dictionary;
			}
			catch (Exception ex)
			{
				LC_ScrapOutside.Logger.LogError((object)("Failed to get weather multipliers: " + ex));
				return null;
			}
		}

		internal static float CalculateLuckValue()
		{
			if (LC_ScrapOutside.useInternalLuckValue.Value)
			{
				return TimeOfDay.Instance.luckValue;
			}
			float num = 0f;
			List<int> list = new List<int>();
			AutoParentToShip[] array = Object.FindObjectsByType<AutoParentToShip>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i].unlockableID != -1 && StartOfRound.Instance.unlockablesList.unlockables[array[i].unlockableID].spawnPrefab)
				{
					list.Add(array[i].unlockableID);
				}
			}
			for (int j = 0; j < list.Count; j++)
			{
				if (list[j] > StartOfRound.Instance.unlockablesList.unlockables.Count)
				{
					LC_ScrapOutside.Logger.LogWarning((object)$"'Lucky' furniture with id {list[j]} exceeded the unlockables list size; skipping");
				}
				num = Mathf.Clamp(num + StartOfRound.Instance.unlockablesList.unlockables[list[j]].luckValue, -1f, 10f);
			}
			LC_ScrapOutside.Logger.LogDebug((object)$"Luck calculated: {num}");
			return num;
		}
	}
}