Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of BigWillyMod v1.0.2
BigWillyMod.dll
Decompiled a week agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Http; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading.Tasks; using BigWillyMod; using BigWillyMod.Items; using BigWillyMod.NPCs; using BigWillyMod.Quests; using BigWillyMod.Services; using BigWillyMod.Utils; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using S1API.Console; using S1API.Economy; using S1API.Entities; using S1API.Entities.Customer; using S1API.Entities.Dialogue; using S1API.Entities.NPCs.Northtown; using S1API.Entities.Relation; using S1API.Entities.Schedule; using S1API.GameTime; using S1API.Graffiti; using S1API.Internal.Abstraction; using S1API.Internal.Utils; using S1API.Items; using S1API.Lifecycle; using S1API.Map; using S1API.Map.Buildings; using S1API.Messaging; using S1API.Products; using S1API.Properties; using S1API.Properties.Interfaces; using S1API.Quests; using S1API.Quests.Constants; using S1API.Rendering; using S1API.Saveables; using S1API.Shops; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "BigWillyMod", "1.0.2", "Bars", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BigWillyMod")] [assembly: AssemblyConfiguration("CrossCompat")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+586648b3e17bd7e3ebaabc451a94ef341333e147")] [assembly: AssemblyProduct("BigWillyMod")] [assembly: AssemblyTitle("BigWillyMod")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 BigWillyMod { public class Core : MelonMod { private bool _itemsInitialized = false; private bool _shopsInitialized = false; private static MelonPreferences_Category? _preferencesCategory; private static MelonPreferences_Entry<bool>? _debugLogsEntry; private static MelonPreferences_Entry<bool>? _liveNotificationsEntry; private static MelonPreferences_Entry<int>? _liveCheckIntervalEntry; public static Core? Instance { get; private set; } public static bool DebugLogsEnabled => _debugLogsEntry?.Value ?? false; public static bool LiveNotificationsEnabled => _liveNotificationsEntry?.Value ?? true; public static int LiveCheckIntervalMinutes => _liveCheckIntervalEntry?.Value ?? 10; public override void OnLateInitializeMelon() { Instance = this; _preferencesCategory = MelonPreferences.CreateCategory("BigWillyMod"); _debugLogsEntry = _preferencesCategory.CreateEntry<bool>("DebugLogs", false, "Enable Debug Logs", "Show detailed debug messages in the console", false, false, (ValueValidator)null, (string)null); _liveNotificationsEntry = _preferencesCategory.CreateEntry<bool>("LiveNotifications", true, "Live Stream Notifications", "Send in-game text when Big Willy goes live on Twitch", false, false, (ValueValidator)null, (string)null); _liveCheckIntervalEntry = _preferencesCategory.CreateEntry<int>("LiveCheckInterval", 10, "Live Check Interval (minutes)", "How often to check if Big Willy is streaming", false, false, (ValueValidator)null, (string)null); _preferencesCategory.SaveToFile(false); GraffitiQuestTracker.Initialize(); GameLifecycle.OnPreLoad += OnPreLoad; ((MelonBase)this).LoggerInstance.Msg("BigWillyMod v1.0.2 initialized"); } public override void OnApplicationQuit() { LiveStreamChecker.StopPolling(); GraffitiQuestTracker.Cleanup(); Instance = null; } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName == "Main") { if (!_shopsInitialized) { } LiveStreamChecker.StartPolling(); } else if (sceneName == "Menu") { LiveStreamChecker.StopPolling(); LiveStreamChecker.Reset(); _itemsInitialized = false; _shopsInitialized = false; } } private void OnPreLoad() { if (!_itemsInitialized) { StaySillyCapCreator.Initialize(); _itemsInitialized = true; ((MelonBase)this).LoggerInstance.Msg("Adding Big Willy to your game..."); } } } } namespace BigWillyMod.Services { public static class LiveStreamChecker { [CompilerGenerated] private sealed class <PollStreamStatus>d__8 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private Task<bool> <checkTask>5__1; private bool <isLive>5__2; private float <intervalSeconds>5__3; private Exception <ex>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PollStreamStatus>d__8(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <checkTask>5__1 = null; <ex>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(10f); <>1__state = 1; return true; case 1: <>1__state = -1; goto IL_0186; case 2: <>1__state = -1; break; case 3: { <>1__state = -1; <checkTask>5__1 = null; goto IL_0186; } IL_0186: <checkTask>5__1 = CheckTwitchLiveAsync(); break; } if (!<checkTask>5__1.IsCompleted) { <>2__current = null; <>1__state = 2; return true; } <isLive>5__2 = false; try { <isLive>5__2 = <checkTask>5__1.Result; } catch (Exception ex) { <ex>5__4 = ex; DebugLog.Msg("[LiveStreamChecker] Error checking stream status: " + <ex>5__4.Message); } if (<isLive>5__2 && !_wasLiveLastCheck) { DebugLog.Msg("[LiveStreamChecker] Stream just went live!"); if (!_notifiedThisSession) { SendLiveNotification(); _notifiedThisSession = true; } } else if (!<isLive>5__2 && _wasLiveLastCheck) { DebugLog.Msg("[LiveStreamChecker] Stream ended, resetting notification flag"); _notifiedThisSession = false; } _wasLiveLastCheck = <isLive>5__2; <intervalSeconds>5__3 = (float)Core.LiveCheckIntervalMinutes * 60f; <>2__current = (object)new WaitForSeconds(<intervalSeconds>5__3); <>1__state = 3; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly HttpClient _httpClient; private static object? _pollingCoroutine; private static bool _wasLiveLastCheck; private static bool _notifiedThisSession; static LiveStreamChecker() { _httpClient = new HttpClient(); _wasLiveLastCheck = false; _notifiedThisSession = false; _httpClient.Timeout = TimeSpan.FromSeconds(10.0); } public static void StartPolling() { if (_pollingCoroutine != null) { DebugLog.Msg("[LiveStreamChecker] Polling already running"); return; } if (!Core.LiveNotificationsEnabled) { DebugLog.Msg("[LiveStreamChecker] Live notifications disabled, not starting polling"); return; } _pollingCoroutine = MelonCoroutines.Start(PollStreamStatus()); DebugLog.Msg("[LiveStreamChecker] Started polling for live streams"); } public static void StopPolling() { if (_pollingCoroutine != null) { MelonCoroutines.Stop(_pollingCoroutine); _pollingCoroutine = null; DebugLog.Msg("[LiveStreamChecker] Stopped polling"); } } public static void Reset() { _wasLiveLastCheck = false; _notifiedThisSession = false; } [IteratorStateMachine(typeof(<PollStreamStatus>d__8))] private static IEnumerator PollStreamStatus() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PollStreamStatus>d__8(0); } private static async Task<bool> CheckTwitchLiveAsync() { try { string trimmed = (await _httpClient.GetStringAsync("https://decapi.me/twitch/uptime/itsbigwilly_")).Trim(); if (trimmed.Equals("offline", StringComparison.OrdinalIgnoreCase)) { DebugLog.Msg("[LiveStreamChecker] Stream check: offline"); return false; } string[] uptimeIndicators = new string[3] { "second", "minute", "hour" }; if (Array.Exists(uptimeIndicators, (string indicator) => trimmed.Contains(indicator, StringComparison.OrdinalIgnoreCase))) { DebugLog.Msg("[LiveStreamChecker] Stream check: LIVE (uptime: " + trimmed + ")"); return true; } DebugLog.Msg("[LiveStreamChecker] Unexpected response, assuming offline: " + trimmed); return false; } catch (HttpRequestException ex4) { HttpRequestException ex3 = ex4; DebugLog.Error("[LiveStreamChecker] HTTP error checking Twitch: " + ex3.Message); DebugLog.Error("[LiveStreamChecker] Stack trace: " + ex3.StackTrace); return false; } catch (TaskCanceledException ex5) { TaskCanceledException ex2 = ex5; DebugLog.Error("[LiveStreamChecker] Twitch check timed out: " + ex2.Message); DebugLog.Error("[LiveStreamChecker] Stack trace: " + ex2.StackTrace); return false; } catch (Exception ex6) { Exception ex = ex6; DebugLog.Error("[LiveStreamChecker] Unexpected error: " + ex.Message); DebugLog.Error("[LiveStreamChecker] Stack trace: " + ex.StackTrace); return false; } } private static void SendLiveNotification() { try { NPC val = NPC.Get<BigWilly>(); if (val == null) { DebugLog.Error("[LiveStreamChecker] BigWilly NPC not found, cannot send notification"); return; } string text = "Yo! I'm live right now, come hang out! https://www.twitch.tv/itsbigwilly_"; val.SendTextMessage(text, (Response[])null, 1f, true); DebugLog.Msg("[LiveStreamChecker] Sent live notification to player"); } catch (Exception ex) { DebugLog.Error("[LiveStreamChecker] Failed to send notification: " + ex.Message); DebugLog.Error("[LiveStreamChecker] Stack trace: " + ex.StackTrace); } } } } namespace BigWillyMod.Items { public static class StaySillyCapCreator { private const string ITEM_ID = "stay_silly_cap"; private const string ITEM_NAME = "Stay Silly Cap"; private const string ITEM_DESCRIPTION = "A custom cap that helps you stay silly at all times. Never take life too seriously!"; private const string SOURCE_CAP_PATH = "avatar/accessories/head/cap/Cap"; private const string CUSTOM_CAP_RESOURCE_PATH = "BigWillyMod/Accessories/StaySillyCap"; public static void Initialize() { try { if (!CreateCustomAccessory()) { MelonLogger.Error("[StaySillyCap] Failed to create custom accessory"); } else if (!CreateClothingItem()) { MelonLogger.Error("[StaySillyCap] Failed to create clothing item"); } } catch (Exception ex) { MelonLogger.Error("[StaySillyCap] Initialization failed: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } public static void AddToShops() { try { ItemDefinition itemDefinition = ItemManager.GetItemDefinition("stay_silly_cap"); if (itemDefinition == (ItemDefinition)null) { MelonLogger.Error("[StaySillyCap] Item 'stay_silly_cap' not found in registry"); } else { int num = ShopManager.AddToCompatibleShops(itemDefinition, (float?)null); } } catch (Exception ex) { MelonLogger.Error("[StaySillyCap] Failed to add to shops: " + ex.Message); } } private static bool CreateCustomAccessory() { try { if (RuntimeResourceRegistry.IsRegistered("BigWillyMod/Accessories/StaySillyCap")) { MelonLogger.Msg("[StaySillyCap] Custom accessory already registered at 'BigWillyMod/Accessories/StaySillyCap', skipping creation"); return true; } Assembly executingAssembly = Assembly.GetExecutingAssembly(); Texture2D val = TextureUtils.LoadTextureFromResource(executingAssembly, "BigWillyMod.Resources.StaySillyCap.stay_silly_cap_texture.png", (FilterMode)1, (TextureWrapMode)1); if ((Object)(object)val == (Object)null) { MelonLogger.Error("[StaySillyCap] Failed to load custom texture from resources"); return false; } Dictionary<string, Texture2D> dictionary = new Dictionary<string, Texture2D> { { "_MainTex", val }, { "_BaseMap", val }, { "_Albedo", val } }; return AccessoryFactory.CreateAndRegisterAccessory("avatar/accessories/head/cap/Cap", "BigWillyMod/Accessories/StaySillyCap", "StaySillyCap", dictionary, (Color?)null); } catch (Exception ex) { MelonLogger.Error("[StaySillyCap] Failed to create accessory: " + ex.Message); MelonLogger.Error(ex.StackTrace); return false; } } private static bool CreateClothingItem() { //IL_00df: Unknown result type (might be due to invalid IL or missing references) try { ClothingItemDefinitionBuilder val = ClothingItemCreator.CloneFrom("cap"); if (val == null) { MelonLogger.Error("[StaySillyCap] Failed to clone base cap - 'cap' item not found"); return false; } Assembly executingAssembly = Assembly.GetExecutingAssembly(); Sprite val2 = ImageUtils.LoadImageFromResource(executingAssembly, "BigWillyMod.Resources.StaySillyCap.icon.png", 100f, (FilterMode)1); if (!RuntimeResourceRegistry.IsRegistered("BigWillyMod/Accessories/StaySillyCap")) { MelonLogger.Warning("[StaySillyCap] Custom accessory not registered at 'BigWillyMod/Accessories/StaySillyCap'. Model may not load correctly."); } ClothingItemDefinition val3 = val.WithBasicInfo("stay_silly_cap", "Stay Silly Cap", "A custom cap that helps you stay silly at all times. Never take life too seriously!").WithClothingAsset("BigWillyMod/Accessories/StaySillyCap").WithColorable(false) .WithDefaultColor((ClothingColor)0) .WithPricing(75f, 0.5f) .WithKeywords(new string[5] { "cap", "hat", "silly", "custom", "bigwilly" }) .WithLabelColor(new Color(1f, 0.8f, 0.2f)) .Build(); if ((Object)(object)val2 != (Object)null) { ((ItemDefinition)val3).Icon = val2; } if ((ItemDefinition)(object)val3 == (ItemDefinition)null) { MelonLogger.Error("[StaySillyCap] Failed to build clothing item"); return false; } return true; } catch (Exception ex) { MelonLogger.Error("[StaySillyCap] Failed to create clothing item: " + ex.Message); MelonLogger.Error(ex.StackTrace); return false; } } } } namespace BigWillyMod.NPCs { public sealed class BigWilly : NPC { [Serializable] private class PersistedData { public bool QuestCompleted = false; } [SaveableField("BigWillyData")] private PersistedData _data = new PersistedData(); public override bool IsPhysical => true; protected override void ConfigurePrefab(NPCPrefabBuilder builder) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) Building goblinHideBuilding = Building.Get<GoblinHideBuilding>(); Building arcade = Building.Get<Arcade>(); Building val = Building.Get<Casino>(); builder.WithIdentity("big_willy", "BigWilly", "").WithAppearanceDefaults((Action<AvatarDefaultsBuilder>)delegate(AvatarDefaultsBuilder av) { //IL_003a: 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_0070: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0166: 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_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) av.Gender = 0f; av.Height = 1f; av.Weight = 1f; av.SkinColor = new Color32((byte)223, (byte)189, (byte)161, byte.MaxValue); av.LeftEyeLidColor = new Color(0.875f, 0.741f, 0.631f); av.RightEyeLidColor = new Color(0.875f, 0.741f, 0.631f); av.EyeBallTint = new Color(1f, 0.655f, 0.655f); av.HairColor = new Color(0.122f, 0.075f, 0.043f); av.HairPath = "Avatar/Hair/bowlcut/BowlCut"; av.EyeballMaterialIdentifier = "Default"; av.PupilDilation = 1f; av.EyebrowScale = 1.169f; av.EyebrowThickness = 1.111f; av.EyebrowRestingHeight = 0.32419f; av.EyebrowRestingAngle = -10f; av.LeftEye = (0.39435f, 0.26935f); av.RightEye = (0.39435f, 0.26935f); av.WithFaceLayer("Avatar/Layers/Face/Face_SlightSmile", new Color(0f, 0f, 0f)); av.WithBodyLayer("Avatar/Layers/Top/Overalls", new Color(0f, 0f, 0.502f)); av.WithBodyLayer("Avatar/Layers/Top/FlannelButtonUp", new Color(0.863f, 0.078f, 0.235f)); av.WithBodyLayer("Avatar/Layers/Bottom/CargoPants", new Color(0.149f, 0.149f, 0.149f)); av.WithAccessoryLayer("Avatar/Accessories/Head/PorkpieHat/PorkpieHat", new Color(0.824f, 0.706f, 0.549f)); av.WithAccessoryLayer("Avatar/Accessories/Feet/CombatBoots/CombatBoots", new Color(0.824f, 0.706f, 0.549f)); av.WithAccessoryLayer("Avatar/Accessories/Head/SmallRoundGlasses/SmallRoundGlasses", new Color(0f, 0f, 0f)); }).WithSpawnPosition(new Vector3(-35.7332f, -4.035f, 52.2295f)) .EnsureCustomer() .WithCustomerDefaults((Action<CustomerDataBuilder>)delegate(CustomerDataBuilder cd) { cd.WithSpending(400f, 900f).WithOrdersPerWeek(1, 3).WithPreferredOrderDay((Day)0) .WithOrderTime(900) .WithStandards((CustomerStandard)2) .AllowDirectApproach(true) .WithMutualRelationRequirement(2.5f, 4f) .WithCallPoliceChance(0.15f) .WithDependence(0.1f, 1.1f) .WithAffinities((IEnumerable<ValueTuple<DrugType, float>>)new(DrugType, float)[2] { ((DrugType)0, 0.45f), ((DrugType)2, -0.2f) }) .WithPreferredProperties((PropertyBase[])(object)new PropertyBase[3] { Property.CalorieDense, Property.ThoughtProvoking, Property.Laxative }); }) .WithRelationshipDefaults((Action<NPCRelationshipDataBuilder>)delegate(NPCRelationshipDataBuilder r) { r.WithDelta(1f).SetUnlocked(false).SetUnlockType((UnlockType)1) .WithConnections<KyleCooley, LudwigMeyer, AustinSteiner>(); }) .WithSchedule((Action<PrefabScheduleBuilder>)delegate(PrefabScheduleBuilder plan) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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) //IL_0086: 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_00aa: 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_0127: Unknown result type (might be due to invalid IL or missing references) plan.EnsureDealSignal().StayInBuilding(goblinHideBuilding, 700, 100, (int?)null, (string)null).WalkTo(new Vector3(-61.2776f, 1.065f, 55.6136f), 900, true, 1f, false, (Vector3?)null, (string)null) .WalkTo(new Vector3(-64.553f, 1.065f, 48.3866f), 1000, true, 1f, false, (Vector3?)(Quaternion.Euler(0f, 220f, 0f) * Vector3.forward), (string)null) .WalkTo(new Vector3(-44.2771f, -2.935f, 136.0889f), 1330, true, 1f, false, (Vector3?)null, (string)null) .StayInBuilding(arcade, 1400, 100, (int?)null, (string)null) .UseSlotMachineUntilTime(1630, 2300, new Vector3(23.4776f, 1.8546f, 95.6571f), 10, 10f, true, 5f, (Building)null, (string)null) .WalkTo(new Vector3(93.5044f, -5.535f, 7.0331f), 2300, true, 1f, false, (Vector3?)null, (string)null) .StayInBuilding(goblinHideBuilding, 2330, 250, (int?)null, (string)null); }) .WithInventoryDefaults((Action<RandomInventoryItemsBuilder>)delegate(RandomInventoryItemsBuilder inv) { inv.WithStartupItems(new string[3] { "donut", "horsesemen", "megabean" }).WithRandomCash(500, 5000).WithClearInventoryEachNight(false); }); } protected override void OnLoaded() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 ((Saveable)this).OnLoaded(); BigWillyGraffitiQuest bigWillyGraffitiQuest = QuestRegistry.GetBigWillyGraffitiQuest(); if (bigWillyGraffitiQuest != null && (int)bigWillyGraffitiQuest.QuestState == 2) { _data.QuestCompleted = true; } } protected override void OnCreated() { ((NPC)this).OnCreated(); ((NPC)this).Appearance.Build(); ((NPC)this).Schedule.Enable(); ((NPC)this).Region = (Region)0; SetupDialogue(); } private void SetupDialogue() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 try { BigWillyGraffitiQuest bigWillyGraffitiQuest = QuestRegistry.GetBigWillyGraffitiQuest(); if (_data.QuestCompleted || (bigWillyGraffitiQuest != null && (int)bigWillyGraffitiQuest.QuestState == 2)) { return; } BuildQuestDialogueContainer(); ((NPC)this).Dialogue.OnChoiceSelected("ACCEPT_HELP", (Action)delegate { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Invalid comparison between Unknown and I4 try { int count = GraffitiManager.UntaggedSpraySurfaces.Count; BigWillyGraffitiQuest bigWillyGraffitiQuest5 = QuestRegistry.CreateBigWillyGraffitiQuest(); if (bigWillyGraffitiQuest5 != null) { int requiredTagCount = Math.Min(Math.Max(count, 1), 5); bigWillyGraffitiQuest5.SetRequiredTagCount(requiredTagCount); if ((int)bigWillyGraffitiQuest5.QuestState != 1) { ((Quest)bigWillyGraffitiQuest5).Begin(); } } ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "QUEST_ACCEPTED", false); } catch (Exception ex5) { MelonLogger.Error("[BigWilly] Failed to start quest: " + ex5.Message); ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "EXIT", false); } }); ((NPC)this).Dialogue.OnChoiceSelected("ACCEPT_HAT", (Action)delegate { try { StaySillyCapCreator.Initialize(); ItemDefinition itemDefinition = ItemManager.GetItemDefinition("stay_silly_cap"); if (itemDefinition == (ItemDefinition)null) { MelonLogger.Error("[BigWilly] Failed to find 'stay_silly_cap' item definition!"); } else { ConsoleHelper.AddItemToInventory("stay_silly_cap", (int?)1); _data.QuestCompleted = true; Saveable.RequestGameSave(false); } ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "GIVE_HAT_DIRECTLY", false); } catch (Exception ex4) { MelonLogger.Error("[BigWilly] Failed to give hat directly: " + ex4.Message); MelonLogger.Error(ex4.StackTrace); ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "EXIT", false); } }); ((NPC)this).Dialogue.OnChoiceSelected("TURN_IN", (Action)delegate { try { BigWillyGraffitiQuest bigWillyGraffitiQuest4 = QuestRegistry.GetBigWillyGraffitiQuest(); if (bigWillyGraffitiQuest4 != null && bigWillyGraffitiQuest4.IsReadyToTurnIn) { if (((Quest)bigWillyGraffitiQuest4).QuestEntries.Count >= 2) { ((Quest)bigWillyGraffitiQuest4).QuestEntries[1].Complete(); } bigWillyGraffitiQuest4.GiveReward(); _data.QuestCompleted = true; Saveable.RequestGameSave(false); } ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "TURN_IN_REWARD", false); } catch (Exception ex3) { MelonLogger.Error("[BigWilly] Failed to complete quest: " + ex3.Message); ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "EXIT", false); } }); ((NPC)this).Dialogue.OnChoiceSelected("THANKS", (Action)delegate { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 try { BigWillyGraffitiQuest bigWillyGraffitiQuest3 = QuestRegistry.GetBigWillyGraffitiQuest(); if (bigWillyGraffitiQuest3 != null && (int)bigWillyGraffitiQuest3.QuestState == 1) { ((Quest)bigWillyGraffitiQuest3).Complete(); } } catch (Exception ex2) { MelonLogger.Error("[BigWilly] Failed to complete quest in THANKS handler: " + ex2.Message); } ((NPC)this).Dialogue.StopOverride(); }); ((NPC)this).Dialogue.OnChoiceSelected("CHECK_PROGRESS", (Action)delegate { ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "PROGRESS_UPDATE", false); }); ((NPC)this).Dialogue.OnChoiceSelected("LEAVE", (Action)delegate { ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "LEAVE_RESPONSE", false); }); ((NPC)this).Dialogue.OnChoiceSelected("DECLINE", (Action)delegate { ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "DECLINE_RESPONSE", false); }); ((NPC)this).Dialogue.OnChoiceSelected("GOT_IT", (Action)delegate { ((NPC)this).Dialogue.StopOverride(); }); ((NPC)this).Dialogue.OnChoiceSelected("OK", (Action)delegate { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 BigWillyGraffitiQuest bigWillyGraffitiQuest2 = QuestRegistry.GetBigWillyGraffitiQuest(); if ((_data.QuestCompleted || (bigWillyGraffitiQuest2 != null && (int)bigWillyGraffitiQuest2.QuestState == 2)) && (bigWillyGraffitiQuest2 == null || !bigWillyGraffitiQuest2.IsReadyToTurnIn)) { if (!_data.QuestCompleted) { _data.QuestCompleted = true; Saveable.RequestGameSave(false); } ((NPC)this).Dialogue.StopOverride(); } else { ((NPC)this).Dialogue.JumpTo("BigWillyQuestDialogue", "EXIT", false); } }); ((NPC)this).Dialogue.UseContainerOnInteract("BigWillyQuestDialogue"); } catch (Exception ex) { MelonLogger.Error("[BigWilly] Failed to setup dialogue: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } public void RebuildQuestDialogue() { DebugLog.Msg("[BigWilly] RebuildQuestDialogue called - rebuilding dialogue container"); BuildQuestDialogueContainer(); ((NPC)this).Dialogue.UseContainerOnInteract("BigWillyQuestDialogue"); } private void BuildQuestDialogueContainer() { DebugLog.Msg("[BigWilly] BuildQuestDialogueContainer called"); ((NPC)this).Dialogue.BuildAndRegisterContainer("BigWillyQuestDialogue", (Action<DialogueContainerBuilder>)delegate(DialogueContainerBuilder c) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) BigWillyGraffitiQuest currentQuest = QuestRegistry.GetBigWillyGraffitiQuest(); DebugLog.Msg(string.Format("[BigWilly] Building container - Quest: {0}, QuestCompleted flag: {1}", (currentQuest != null) ? "EXISTS" : "NULL", _data.QuestCompleted)); if (currentQuest != null) { DebugLog.Msg($"[BigWilly] Quest state: {currentQuest.QuestState}, Tagged: {currentQuest.TaggedCount}/{currentQuest.RequiredTagCount}, ReadyToTurnIn: {currentQuest.IsReadyToTurnIn}"); } c.AddNode("ENTRY", GetEntryDialogueText(), (Action<ChoiceList>)delegate(ChoiceList ch) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Invalid comparison between Unknown and I4 //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Invalid comparison between Unknown and I4 //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Invalid comparison between Unknown and I4 //IL_021f: Unknown result type (might be due to invalid IL or missing references) DebugLog.Msg("[BigWilly] ENTRY node choices callback executing"); if (_data.QuestCompleted) { DebugLog.Msg("[BigWilly] Quest completed path - adding OK choice"); ch.Add("OK", "Thanks for the help!", "EXIT"); } else if (currentQuest == null || (int)currentQuest.QuestState == 0) { DebugLog.Msg("[BigWilly] Quest inactive/null path"); int count = GraffitiManager.UntaggedSpraySurfaces.Count; if (count == 0) { DebugLog.Msg("[BigWilly] No graffiti spots - offering hat directly"); ch.Add("ACCEPT_HAT", "Sure, I'll take the hat!", "GIVE_HAT_DIRECTLY").Add("DECLINE", "Not right now", "DECLINE_RESPONSE"); } else { DebugLog.Msg($"[BigWilly] {count} graffiti spots available - offering quest"); ch.Add("ACCEPT_HELP", "Yeah, I'll spread the word", "QUEST_ACCEPTED").Add("DECLINE", "Not right now", "DECLINE_RESPONSE"); } } else if ((int)currentQuest.QuestState == 2) { DebugLog.Msg("[BigWilly] Quest state is Completed - marking in saved state"); _data.QuestCompleted = true; Saveable.RequestGameSave(false); ch.Add("OK", "Thanks for the help!", "EXIT"); } else if ((int)currentQuest.QuestState == 1) { if (currentQuest.IsReadyToTurnIn) { DebugLog.Msg("[BigWilly] Quest active and ready to turn in - adding TURN_IN choice"); ch.Add("TURN_IN", string.Format("I've tagged {0} {1}!", currentQuest.RequiredTagCount, (currentQuest.RequiredTagCount == 1) ? "spot" : "spots"), "TURN_IN_REWARD"); } else { DebugLog.Msg("[BigWilly] Quest active but not ready - adding progress choices"); ch.Add("CHECK_PROGRESS", "How am I doing?", "PROGRESS_UPDATE").Add("LEAVE", "I'll keep working on it", "LEAVE_RESPONSE"); } } else { DebugLog.Warning($"[BigWilly] Unexpected quest state: {currentQuest.QuestState}"); ch.Add("OK", "Okay", "EXIT"); } }); c.AddNode("QUEST_ACCEPTED", GetQuestAcceptedText(), (Action<ChoiceList>)delegate(ChoiceList ch) { ch.Add("GOT_IT", "Got it!", "EXIT"); }); c.AddNode("GIVE_HAT_DIRECTLY", "Stay silly, brother!", (Action<ChoiceList>)delegate(ChoiceList ch) { ch.Add("THANKS", "Thanks!", "EXIT"); }); c.AddNode("DECLINE_RESPONSE", "Alright, let me know if you change your mind!", (Action<ChoiceList>)null); c.AddNode("PROGRESS_UPDATE", GetProgressUpdateText(), (Action<ChoiceList>)null); c.AddNode("LEAVE_RESPONSE", "Thanks for helping spread the word!", (Action<ChoiceList>)null); c.AddNode("TURN_IN_REWARD", "Great work brother! Spreading the word like a pro. Here, take this cap.", (Action<ChoiceList>)delegate(ChoiceList ch) { ch.Add("THANKS", "Thanks!", "EXIT"); }); c.AddNode("EXIT", "Stay silly, brother!", (Action<ChoiceList>)null); }); } private string GetEntryDialogueText() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Invalid comparison between Unknown and I4 //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Invalid comparison between Unknown and I4 //IL_0109: Unknown result type (might be due to invalid IL or missing references) BigWillyGraffitiQuest bigWillyGraffitiQuest = QuestRegistry.GetBigWillyGraffitiQuest(); DebugLog.Msg(string.Format("[BigWilly] GetEntryDialogueText - Quest: {0}, QuestCompleted: {1}", (bigWillyGraffitiQuest != null) ? "EXISTS" : "NULL", _data.QuestCompleted)); if (bigWillyGraffitiQuest == null || (int)bigWillyGraffitiQuest.QuestState == 0) { int count = GraffitiManager.UntaggedSpraySurfaces.Count; if (count == 0) { DebugLog.Msg("[BigWilly] Entry text: No spots, offering hat"); return "Hey brother, have you heard of the Stay Silly merchandise? Here, take this Stay Silly hat!"; } DebugLog.Msg($"[BigWilly] Entry text: {count} spots, offering quest"); return "Hey brother, I need your help spreading the word of the big willy business, think you can help me?"; } if ((int)bigWillyGraffitiQuest.QuestState == 1) { if (bigWillyGraffitiQuest.IsReadyToTurnIn) { DebugLog.Msg("[BigWilly] Entry text: Quest ready to turn in"); return "Hey brother! I see you've been busy spreading the word. Great work!"; } DebugLog.Msg("[BigWilly] Entry text: Quest in progress"); return "Hey brother! How's the tagging going?"; } if ((int)bigWillyGraffitiQuest.QuestState == 2) { DebugLog.Msg("[BigWilly] Entry text: Quest completed"); return "Looking silly, brother! Thanks for the help."; } DebugLog.Msg($"[BigWilly] Entry text: Unknown state {bigWillyGraffitiQuest.QuestState}"); return "Hey brother, what's up?"; } private string GetQuestAcceptedText() { BigWillyGraffitiQuest bigWillyGraffitiQuest = QuestRegistry.GetBigWillyGraffitiQuest(); if (bigWillyGraffitiQuest != null) { int requiredTagCount = bigWillyGraffitiQuest.RequiredTagCount; return string.Format("Great! Tag {0} {1} with graffiti for Big Willy. I'll know when you're done!", requiredTagCount, (requiredTagCount == 1) ? "spot" : "spots"); } return "Great! Tag some spots with graffiti for Big Willy. I'll know when you're done!"; } private string GetProgressUpdateText() { BigWillyGraffitiQuest bigWillyGraffitiQuest = QuestRegistry.GetBigWillyGraffitiQuest(); if (bigWillyGraffitiQuest != null) { int taggedCount = bigWillyGraffitiQuest.TaggedCount; int num = bigWillyGraffitiQuest.RequiredTagCount - taggedCount; if (num == 1) { return string.Format("Keep it up brother, you've tagged {0} {1}. Just one more to go!", taggedCount, (taggedCount == 1) ? "spot" : "spots"); } return string.Format("Keep it up brother, you've tagged {0} {1}. Just {2} more to go!", taggedCount, (taggedCount == 1) ? "spot" : "spots", num); } return "Keep it up brother! Just a few more to go!"; } } } namespace BigWillyMod.Quests { public class BigWillyGraffitiQuest : Quest { [CompilerGenerated] private sealed class <UpdatePOIToNearestUntaggedSurfaceDelayed>d__23 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public BigWillyGraffitiQuest <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <UpdatePOIToNearestUntaggedSurfaceDelayed>d__23(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this.UpdatePOIToNearestUntaggedSurface(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <WaitForBigWillyAndAttachToEntry>d__22 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public BigWillyGraffitiQuest <>4__this; private float <timeout>5__1; private float <waited>5__2; private float <checkInterval>5__3; private NPC <bigWilly>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForBigWillyAndAttachToEntry>d__22(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <bigWilly>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <timeout>5__1 = 10f; <waited>5__2 = 0f; <checkInterval>5__3 = 1f; break; case 1: <>1__state = -1; <waited>5__2 += <checkInterval>5__3; <bigWilly>5__4 = null; break; } if (<waited>5__2 < <timeout>5__1) { <bigWilly>5__4 = NPC.Get<BigWilly>(); if (<bigWilly>5__4 != null) { if (<>4__this._returnEntry != null) { <>4__this._returnEntry.SetPOIToNPC(<bigWilly>5__4); } return false; } <>2__current = (object)new WaitForSeconds(<checkInterval>5__3); <>1__state = 1; return true; } DebugLog.Msg("[BigWillyGraffitiQuest] Timeout waiting for Big Willy NPC to spawn. Quest entry created without NPC attachment."); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string QUEST_ID = "big_willy_graffiti_quest"; [SaveableField("taggedSurfaces")] private HashSet<string> _taggedSurfaceIds = new HashSet<string>(); [SaveableField("rewardGranted")] private bool _rewardGranted = false; [SaveableField("requiredTagCount")] private int _requiredTagCount = 5; private QuestEntry _tagEntry; private QuestEntry _returnEntry; public int RequiredTagCount => _requiredTagCount; protected override string Title => "Spread the Word"; protected override string Description => "Big Willy needs your help spreading the word about his business! " + string.Format("Tag {0} {1} around town with graffiti to help promote Big Willy's enterprise. ", _requiredTagCount, (_requiredTagCount == 1) ? "spot" : "different spots") + string.Format("Once you've completed all {0} {1}, return to Big Willy to claim your reward.", _requiredTagCount, (_requiredTagCount == 1) ? "tag" : "tags"); protected override bool AutoBegin => false; public int TaggedCount => _taggedSurfaceIds.Count; public bool IsReadyToTurnIn { get { bool flag = _taggedSurfaceIds.Count >= _requiredTagCount; DebugLog.Msg($"[BigWillyGraffitiQuest] IsReadyToTurnIn check: {flag} (Tagged: {_taggedSurfaceIds.Count}/{_requiredTagCount})"); return flag; } } public QuestState QuestState => ((Quest)this).QuestState; public void SetRequiredTagCount(int count) { if (count <= 0) { MelonLogger.Warning("[BigWillyGraffitiQuest] Required tag count must be greater than 0, using 1"); _requiredTagCount = 1; } else { _requiredTagCount = count; } } protected override void OnCreated() { //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Invalid comparison between Unknown and I4 //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Invalid comparison between Unknown and I4 //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Invalid comparison between Unknown and I4 ((Registerable)this).OnCreated(); if (base.QuestEntries.Count == 0) { _tagEntry = ((Quest)this).AddEntry(string.Format("Tag {0} {1} for Big Willy ({2}/{3})", _requiredTagCount, (_requiredTagCount == 1) ? "spot" : "spots", _taggedSurfaceIds.Count, _requiredTagCount), (Vector3?)null); _tagEntry.Begin(); MelonCoroutines.Start(UpdatePOIToNearestUntaggedSurfaceDelayed()); _returnEntry = ((Quest)this).AddEntry("Return to Big Willy", (Vector3?)null); _returnEntry.SetState((QuestState)0); MelonCoroutines.Start(WaitForBigWillyAndAttachToEntry()); } else { if (base.QuestEntries.Count >= 1) { _tagEntry = base.QuestEntries[0]; } if (base.QuestEntries.Count >= 2) { _returnEntry = base.QuestEntries[1]; } UpdateTagEntryText(); if (_tagEntry != null && (int)_tagEntry.State == 1) { MelonCoroutines.Start(UpdatePOIToNearestUntaggedSurfaceDelayed()); } MelonCoroutines.Start(WaitForBigWillyAndAttachToEntry()); if (_taggedSurfaceIds.Count >= _requiredTagCount) { if (_tagEntry != null && (int)_tagEntry.State != 2) { _tagEntry.Complete(); } if (_returnEntry != null && (int)_returnEntry.State == 0) { _returnEntry.SetState((QuestState)1); _returnEntry.Begin(); } } } ((Quest)this).OnComplete += HandleQuestComplete; } private void HandleQuestComplete() { if (!_rewardGranted) { GiveReward(); } Saveable.RequestGameSave(false); } protected override void OnLoaded() { ((Saveable)this).OnLoaded(); if (base.QuestEntries.Count == 0) { _tagEntry = ((Quest)this).AddEntry(string.Format("Tag {0} {1} for Big Willy ({2}/{3})", _requiredTagCount, (_requiredTagCount == 1) ? "spot" : "spots", _taggedSurfaceIds.Count, _requiredTagCount), (Vector3?)null); _returnEntry = ((Quest)this).AddEntry("Return to Big Willy", (Vector3?)null); MelonCoroutines.Start(WaitForBigWillyAndAttachToEntry()); } else { if (base.QuestEntries.Count >= 1) { _tagEntry = base.QuestEntries[0]; } if (base.QuestEntries.Count >= 2) { _returnEntry = base.QuestEntries[1]; } MelonCoroutines.Start(WaitForBigWillyAndAttachToEntry()); } } public void RegisterTag(string surfaceGuid) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Invalid comparison between Unknown and I4 if (string.IsNullOrEmpty(surfaceGuid)) { DebugLog.Warning("[BigWillyGraffitiQuest] Attempted to register tag with null/empty GUID"); } else { if (_taggedSurfaceIds.Contains(surfaceGuid)) { return; } _taggedSurfaceIds.Add(surfaceGuid); UpdateTagEntryText(); Saveable.RequestGameSave(false); SendProgressTextMessage(); if (_tagEntry != null && (int)_tagEntry.State == 1) { UpdatePOIToNearestUntaggedSurface(); } if (_taggedSurfaceIds.Count >= _requiredTagCount) { if (_tagEntry != null && (int)_tagEntry.State != 2) { _tagEntry.Complete(); } else if (_tagEntry == null) { DebugLog.Warning("[BigWillyGraffitiQuest] _tagEntry is null, cannot complete"); } if (_returnEntry != null) { _returnEntry.SetState((QuestState)1); _returnEntry.Begin(); } else { DebugLog.Warning("[BigWillyGraffitiQuest] _returnEntry is null, cannot activate!"); } RebuildBigWillyDialogue(); Saveable.RequestGameSave(false); } } } private void UpdateTagEntryText() { if (_tagEntry != null) { _tagEntry.Title = string.Format("Tag {0} {1} for Big Willy ({2}/{3})", _requiredTagCount, (_requiredTagCount == 1) ? "spot" : "spots", _taggedSurfaceIds.Count, _requiredTagCount); } } public void GiveReward() { if (_rewardGranted) { DebugLog.Msg("[BigWillyGraffitiQuest] Reward already granted, skipping."); return; } try { StaySillyCapCreator.Initialize(); ItemDefinition itemDefinition = ItemManager.GetItemDefinition("stay_silly_cap"); if (itemDefinition == (ItemDefinition)null) { MelonLogger.Error("[BigWillyGraffitiQuest] Failed to find 'stay_silly_cap' item definition!"); return; } ConsoleHelper.AddItemToInventory("stay_silly_cap", (int?)1); _rewardGranted = true; Saveable.RequestGameSave(false); } catch (Exception ex) { MelonLogger.Error("[BigWillyGraffitiQuest] Failed to give reward: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } private void SendProgressTextMessage() { try { NPC val = NPC.Get<BigWilly>(); if (val == null) { DebugLog.Msg("[BigWillyGraffitiQuest] Big Willy NPC not found, cannot send text message"); return; } string text; if (_taggedSurfaceIds.Count >= _requiredTagCount) { text = string.Format("Brother! You've tagged all {0} {1}! Come see me and I'll give you something special!", _requiredTagCount, (_requiredTagCount == 1) ? "spot" : "spots"); } else { int num = _requiredTagCount - _taggedSurfaceIds.Count; text = string.Format("Nice work brother! You've tagged {0} spot{1}. Just {2} more to go!", _taggedSurfaceIds.Count, (_taggedSurfaceIds.Count == 1) ? "" : "s", num); } val.SendTextMessage(text, (Response[])null, 1f, true); } catch (Exception ex) { MelonLogger.Error("[BigWillyGraffitiQuest] Failed to send progress text message: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } [IteratorStateMachine(typeof(<WaitForBigWillyAndAttachToEntry>d__22))] private IEnumerator WaitForBigWillyAndAttachToEntry() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitForBigWillyAndAttachToEntry>d__22(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<UpdatePOIToNearestUntaggedSurfaceDelayed>d__23))] private IEnumerator UpdatePOIToNearestUntaggedSurfaceDelayed() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <UpdatePOIToNearestUntaggedSurfaceDelayed>d__23(0) { <>4__this = this }; } private void UpdatePOIToNearestUntaggedSurface() { //IL_0035: 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_00e9: Unknown result type (might be due to invalid IL or missing references) if (_tagEntry == null) { return; } try { Player local = Player.Local; if (local == null) { DebugLog.Msg("[BigWillyGraffitiQuest] Player.Local is null, cannot update POI"); return; } SpraySurface val = GraffitiManager.FindNearestUntaggedSurface(local.Position); if (val != null) { string item = val.GUID.ToString(); if (!_taggedSurfaceIds.Contains(item)) { _tagEntry.SetPOIToSpraySurface(val); return; } List<SpraySurface> list = (from s in GraffitiManager.GetUntaggedSpraySurfaces() where !_taggedSurfaceIds.Contains(s.GUID.ToString()) select s).ToList(); if (list.Count > 0) { SpraySurface val2 = null; float num = float.MaxValue; foreach (SpraySurface item2 in list) { float num2 = Vector3.Distance(local.Position, item2.Position); if (num2 < num) { num = num2; val2 = item2; } } if (val2 != null) { _tagEntry.SetPOIToSpraySurface(val2); } } else { DebugLog.Msg("[BigWillyGraffitiQuest] No untagged surfaces found to point to"); } } else { DebugLog.Msg("[BigWillyGraffitiQuest] No untagged surfaces found in the game"); } } catch (Exception ex) { MelonLogger.Error("[BigWillyGraffitiQuest] Failed to update POI to nearest untagged surface: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } private void RebuildBigWillyDialogue() { try { NPC val = NPC.Get<BigWilly>(); if (val is BigWilly bigWilly) { DebugLog.Msg("[BigWillyGraffitiQuest] Quest ready to turn in - rebuilding Big Willy's dialogue"); bigWilly.RebuildQuestDialogue(); } else { DebugLog.Warning("[BigWillyGraffitiQuest] Big Willy NPC not found, cannot rebuild dialogue"); } } catch (Exception ex) { MelonLogger.Error("[BigWillyGraffitiQuest] Failed to rebuild Big Willy dialogue: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } } public static class GraffitiQuestTracker { private static bool _subscribed; public static void Initialize() { if (!_subscribed) { GraffitiEvents.GraffitiCompleted += OnGraffitiCompleted; _subscribed = true; } } public static void Cleanup() { if (_subscribed) { GraffitiEvents.GraffitiCompleted -= OnGraffitiCompleted; _subscribed = false; } } private static void OnGraffitiCompleted(SpraySurface spraySurface) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Invalid comparison between Unknown and I4 try { if (spraySurface == null) { return; } string surfaceGuid = spraySurface.GUID.ToString(); BigWillyGraffitiQuest bigWillyGraffitiQuest = QuestRegistry.GetBigWillyGraffitiQuest(); if (bigWillyGraffitiQuest != null && ((Quest)bigWillyGraffitiQuest).QuestEntries != null && ((Quest)bigWillyGraffitiQuest).QuestEntries.Count != 0) { QuestEntry val = ((Quest)bigWillyGraffitiQuest).QuestEntries[0]; if ((int)val.State == 1) { bigWillyGraffitiQuest.RegisterTag(surfaceGuid); } } } catch (Exception ex) { MelonLogger.Error("[GraffitiQuestTracker] Error in OnGraffitiCompleted: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } } public static class QuestRegistry { private static BigWillyGraffitiQuest? _cachedQuest; private static List<Quest> QuestManagerQuests => (List<Quest>)typeof(QuestManager).GetField("Quests", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null); public static BigWillyGraffitiQuest? GetBigWillyGraffitiQuest() { if (_cachedQuest != null) { if (QuestManagerQuests.Contains((Quest)(object)_cachedQuest)) { return _cachedQuest; } _cachedQuest = null; } Quest questByName = QuestManager.GetQuestByName("Spread the Word"); if (questByName is BigWillyGraffitiQuest cachedQuest) { _cachedQuest = cachedQuest; return _cachedQuest; } for (int i = 0; i < QuestManagerQuests.Count; i++) { if (QuestManagerQuests[i] is BigWillyGraffitiQuest bigWillyGraffitiQuest) { _cachedQuest = bigWillyGraffitiQuest; return bigWillyGraffitiQuest; } } return null; } public static BigWillyGraffitiQuest CreateBigWillyGraffitiQuest() { BigWillyGraffitiQuest bigWillyGraffitiQuest = GetBigWillyGraffitiQuest(); if (bigWillyGraffitiQuest != null) { return bigWillyGraffitiQuest; } Quest val = QuestManager.CreateQuest<BigWillyGraffitiQuest>((string)null); if (val is BigWillyGraffitiQuest bigWillyGraffitiQuest2) { _cachedQuest = bigWillyGraffitiQuest2; return bigWillyGraffitiQuest2; } MelonLogger.Error("[QuestRegistry] Failed to create BigWillyGraffitiQuest - wrong type returned"); return null; } public static void ClearCache() { _cachedQuest = null; } } } namespace BigWillyMod.Utils { public static class Constants { public static class Game { public const string GAME_STUDIO = "TVGS"; public const string GAME_NAME = "Schedule I"; } public static class LiveStream { public const string TWITCH_URL = "https://www.twitch.tv/itsbigwilly_"; public const string CHECK_URL = "https://decapi.me/twitch/uptime/itsbigwilly_"; } public const string MOD_NAME = "BigWillyMod"; public const string MOD_VERSION = "1.0.2"; public const string MOD_AUTHOR = "Bars"; public const string PREFERENCES_CATEGORY = "BigWillyMod"; } public static class DebugLog { public static void Msg(string message) { if (Core.DebugLogsEnabled) { MelonLogger.Msg(message); } } public static void Warning(string message) { MelonLogger.Warning(message); } public static void Error(string message) { MelonLogger.Error(message); } } }