/// <summary> /// Adds an extra Junimo to the goodbye dance, as the number of Junimos added is otherwise hardcoded. /// </summary> public static bool StartGoodbyeDance_Prefix(CommunityCenter __instance) { try { if (!Bundles.IsCommunityCentreKitchenEnabledByHost()) { return(true); } Bundles.DrawStarInCommunityCentre(__instance); var junimo = __instance.getJunimoForArea(Bundles.CommunityCentreAreaNumber); junimo.Position = new Vector2(22f, 12f) * 64f; junimo.stayStill(); junimo.faceDirection(1); junimo.fadeBack(); junimo.IsInvisible = false; junimo.setAlpha(1f); junimo.sayGoodbye(); } catch (Exception e) { Log.E($"Error in {nameof(StartGoodbyeDance_Prefix)}: {e}"); } return(true); }
public static bool CheckForMissedRewards_Prefix( CommunityCenter __instance) { try { Dictionary <int, List <int> > areaNumbersAndBundleNumbers = Reflection.GetField <Dictionary <int, List <int> > > (__instance, "areaToBundleDictionary") .GetValue(); __instance.missedRewardsChest.Value.items.Clear(); bool hasUnclaimedRewards = false; List <Item> rewards = new(); foreach (KeyValuePair <int, List <int> > areaAndBundles in areaNumbersAndBundleNumbers) { int areaNumber = areaAndBundles.Key; bool isRewardUnclaimed = areaAndBundles.Value.Any() && areaAndBundles.Value .All(bundleNumber => __instance.bundleRewards.TryGetValue(bundleNumber, out bool isUnclaimed) && isUnclaimed); if (!isRewardUnclaimed || __instance.areasComplete.Count() <= areaNumber || !__instance.areasComplete[areaNumber]) { continue; } hasUnclaimedRewards = true; rewards.Clear(); JunimoNoteMenu.GetBundleRewards(areaNumber, rewards); foreach (Item item in rewards) { __instance.missedRewardsChest.Value.addItem(item); } } if ((hasUnclaimedRewards && !__instance.missedRewardsChestVisible.Value) || (!hasUnclaimedRewards && __instance.missedRewardsChestVisible.Value)) { if (!hasUnclaimedRewards) { Vector2 missedRewardsChestTile = Reflection.GetField <Vector2> (obj: __instance, name: "missedRewardsChestTile") .GetValue(); Bundles.BroadcastPuffSprites( multiplayer: null, location: __instance, tilePosition: missedRewardsChestTile); } } __instance.showMissedRewardsChestEvent.Fire(arg: hasUnclaimedRewards); __instance.missedRewardsChestVisible.Value = hasUnclaimedRewards; return(false); } catch (Exception e) { HarmonyPatches.ErrorHandler(e); } return(true); }
public static bool MarkAreaAsComplete_Prefix( CommunityCenter __instance, int area) { try { if (Bundles.IsCustomArea(area)) { if (Game1.currentLocation is CommunityCenter) { Bundles.CustomAreasComplete[area] = true; if (__instance.areAllAreasComplete()) { Reflection.GetField <bool> (obj: __instance, name: "_isWatchingJunimoGoodbye") .SetValue(true); } } return(false); } } catch (Exception e) { HarmonyPatches.ErrorHandler(e); } return(true); }
private void ActivateMod(CommunityCenter cc) { GameState.Current.Activated = true; ModEntry.InvalidateCache(); bundler.FixBundles(true); Warped(cc); }
internal static void InvokeOnResetSharedState(CommunityCenter communityCentre) { ResetSharedState?.Invoke( sender: null, e: new ResetSharedStateEventArgs( communityCentre: communityCentre)); }
/// <summary>Get unfinished bundles which require this item.</summary> /// <param name="item">The item for which to find bundles.</param> private IEnumerable <BundleModel> GetUnfinishedBundles(SObject item) { // no bundles for Joja members if (Game1.player.hasOrWillReceiveMail(Constant.MailLetters.JojaMember)) { yield break; } // get community center CommunityCenter communityCenter = Game1.locations.OfType <CommunityCenter>().First(); if (communityCenter.areAllAreasComplete()) { yield break; } // get bundles if (item.GetType() == typeof(SObject) && !item.bigCraftable.Value) // avoid false positives with hats, furniture, etc { foreach (BundleModel bundle in this.GameHelper.GetBundleData()) { // ignore completed bundle if (communityCenter.isBundleComplete(bundle.ID)) { continue; } bool isMissing = this.GetIngredientsFromBundle(bundle, item).Any(p => this.IsIngredientNeeded(bundle, p)); if (isMissing) { yield return(bundle); } } } }
/// <summary> /// GetNotePosition() throws FatalEngineExecutionError when patched. /// Mimics ShouldNoteAppearInArea() using a static position in place of GetNotePosition(). /// </summary> public static bool ShouldNoteAppearInArea_Prefix(CommunityCenter __instance, ref bool __result, int area) { try { if (Bundles.IsCommunityCentreComplete() && Bundles.IsAbandonedJojaMartBundleAvailable() && (Game1.netWorldState.Value.BundleData.Keys.Any(key => key.StartsWith(Bundles.CommunityCentreAreaName)))) { Log.D($"ShouldNoteAppearInArea removing custom bundle data.", ModEntry.Instance.Config.DebugMode); Bundles.SaveAndUnloadBundleData(); } if (area != Bundles.CommunityCentreAreaNumber) { return(true); } __result = !Bundles.IsCommunityCentreKitchenComplete() && __instance.numberOfCompleteBundles() > (ModEntry.Instance.Config.DebugMode ? 0 : 2); return(false); } catch (ArgumentOutOfRangeException e) { Log.D($"Error in {nameof(ShouldNoteAppearInArea_Prefix)}, may be non-critical:\n{e}", ModEntry.Instance.Config.DebugMode); return(false); } catch (Exception e) { Log.E($"Error in {nameof(ShouldNoteAppearInArea_Prefix)}:\n{e}"); } return(true); }
private void ActivateMod(CommunityCenter cc) { GameState.Current.Activated = true; ModEntry.Instance.Invalidate(); Bundles.Fix(true); Warped(cc); }
private void process() { CommunityCenter center = Game1.getLocationFromName(name) as CommunityCenter; if (center == null) { return; } switch (reason) { case (byte)Reason.BundlesProgress: center.bundles = Util.deserialize <SerializableDictionary <int, bool[]> >(xml); break; case (byte)Reason.BundlesCompleted: for (int i = 0; i < 6; ++i) { if (center.areasComplete[i] && completed[i]) { center.areaCompleteReward(i); } } center.areasComplete = completed; break; case (byte)Reason.BundlesRewards: center.bundleRewards = Util.deserialize <SerializableDictionary <int, bool> >(xml); break; } Multiplayer.locations[center.name].updateCommunityCenterCache(); message(); }
/// <summary> /// GetNotePosition() throws FatalEngineExecutionError when patched. /// Mimics SetViewportToNextJunimoNoteTarget() using a static p value in place of GetNotePosition(). /// </summary> public static bool SetViewportToNextJunimoNoteTarget_Prefix(CommunityCenter __instance) { try { var viewportTargets = ModEntry.Instance.Helper.Reflection.GetField <List <int> >( __instance, "junimoNotesViewportTargets").GetValue(); if (viewportTargets.Count < 1 || viewportTargets[0] != Bundles.CommunityCentreAreaNumber || !Bundles.IsCommunityCentreKitchenEnabledByHost()) { return(true); } var reachedTarget = ModEntry.Instance.Helper.Reflection.GetMethod(__instance, "afterViewportGetsToJunimoNotePosition"); var endFunction = ModEntry.Instance.Helper.Reflection.GetMethod(__instance, "setViewportToNextJunimoNoteTarget"); var p = Bundles.CommunityCentreNotePosition; Game1.moveViewportTo(new Vector2(p.X, p.Y) * 64f, 5f, 2000, () => reachedTarget.Invoke(), () => endFunction.Invoke()); return(false); } catch (ArgumentException e) { Log.D($"Error in {nameof(SetViewportToNextJunimoNoteTarget_Prefix)}, may be non-critical:\n{e}", ModEntry.Instance.Config.DebugMode); return(false); } catch (Exception e) { Log.E($"Error in {nameof(SetViewportToNextJunimoNoteTarget_Prefix)}:\n{e}"); } return(true); }
public static void AreAllAreasComplete_Postfix( CommunityCenter __instance, ref bool __result) { bool resultModifier = Bundles.AreaAllCustomAreasComplete(__instance); __result &= resultModifier; }
internal static void InvokeOnAreaLoaded(CommunityCenter communityCentre, string areaName, int areaNumber) { AreaLoaded?.Invoke( sender: null, e: new AreaLoadedEventArgs( communityCentre: communityCentre, areaName: areaName, areaNumber: areaNumber)); }
public BundleRoom(CommunityCenterBundles Bundles, string Name, List <Tuple <int, string> > Tasks) { this.Bundles = Bundles; this.Name = Name; int RoomNumber = CommunityCenter.getAreaNumberFromName(Name); this.DisplayName = CommunityCenter.getAreaDisplayNameFromNumber(RoomNumber); this.Tasks = Tasks.Select(x => new BundleTask(this, x.Item1, x.Item2)).ToList().AsReadOnly(); }
private void MenuChanged(object sender, MenuChangedEventArgs e) { var shop = e.NewMenu as StardewValley.Menus.ShopMenu; if (shop == null || Game1.currentLocation.Name != "Forest" || !shop.potraitPersonDialogue.Contains("hats")) { return; } // no bundles for Joja members if (Game1.player.hasOrWillReceiveMail("JojaMember")) { return; } CommunityCenter communityCenter = Game1.locations.OfType <CommunityCenter>().First(); if (communityCenter.areAllAreasComplete()) { return; } IReflectedField <Dictionary <Item, int[]> > inventoryInformation = this.Helper.Reflection.GetField <Dictionary <Item, int[]> >(shop, "itemPriceAndStock"); Dictionary <Item, int[]> itemPriceAndStock = inventoryInformation.GetValue(); IReflectedField <List <Item> > forSaleInformation = this.Helper.Reflection.GetField <List <Item> >(shop, "forSale"); List <Item> forSale = forSaleInformation.GetValue(); foreach (var bundle in GetBundles()) { if (communityCenter.isBundleComplete(bundle.ID)) { continue; } foreach (var ing in bundle.Ingredients) { if (communityCenter.bundles[bundle.ID][ing.Index]) { continue; } int itemId = ing.ItemID; var objectToAdd = new StardewValley.Object(Vector2.Zero, itemId, ing.Stack); objectToAdd.Quality = ing.Quality; if (objectToAdd.Name.Contains("rror")) { continue; } itemPriceAndStock.Add(objectToAdd, new int[2] { 5000, ing.Stack }); forSale.Add(objectToAdd); } } inventoryInformation.SetValue(itemPriceAndStock); forSaleInformation.SetValue(forSale); }
/// <summary> /// Loads bundle information. /// </summary> public void Startup() { communityCenter = Game1.getLocationFromName("CommunityCenter") as CommunityCenter; var raw = Game1.content.Load <Dictionary <string, string> >("Data\\Bundles" + Locale.GetCurrentLocaleName()); foreach (var pair in raw) { var key = pair.Key.Split('/'); var id = int.Parse(key[1]); var value = pair.Value.Split('/'); var english = value[0]; var locale = value.Last(); var slots = int.Parse(value[value.Length - 2]); if (value.Length == 5) { slots = 0; } var bundle = new Bundle(id, english, locale, slots); bundles.Add(bundle); var netbundle = communityCenter.bundles[id]; var rawIngredients = value[2].Split(' '); for (var i = 0; i < rawIngredients.Length; i += 3) { var objectId = int.Parse(rawIngredients[i]); var objectCount = int.Parse(rawIngredients[i + 1]); var objectQuality = int.Parse(rawIngredients[i + 2]); if (!IsObjectExists(objectId)) { continue; } var objectName = LoadObjectName(objectId); var donated = netbundle[i / 3]; var ingredient = new BundleIngredient(objectId, i / 3, objectName, objectCount, objectQuality, donated); bundle.AddIngredient(ingredient); } if (bundle.Slots == 0) { bundle.Slots = bundle.Ingredients.Count; } if (netbundle.All(x => x == true)) { bundle.IsComplete = true; } } }
/// <summary> /// Add junimos for extra bundles to the CC completion goodbye dance. /// </summary> public static void StartGoodbyeDance_Prefix( CommunityCenter __instance) { Bundles.SetUpJunimosForGoodbyeDance(cc: __instance); List <Junimo> junimos = __instance.getCharacters().OfType <Junimo>().ToList(); foreach (Junimo junimo in junimos) { junimo.sayGoodbye(); } }
public static void ShouldNoteAppearInArea_Postfix( CommunityCenter __instance, ref bool __result, int area) { if (Bundles.IsAbandonedJojaMartBundleAvailableOrComplete() || !Bundles.IsCustomArea(area) || !Bundles.AreAnyCustomAreasLoaded()) { return; } __result = Bundles.ShouldNoteAppearInCustomArea(cc: __instance, areaNumber: area); }
// Not applied in .NET Framework versions below 5.0: FatalExecutionEngineError public static void GetNotePosition_Postfix( CommunityCenter __instance, ref Point __result, int area) { CustomCommunityCentre.Data.BundleMetadata bundleMetadata = Bundles.GetCustomBundleMetadataFromAreaNumber(area); if (Bundles.IsAbandonedJojaMartBundleAvailableOrComplete() || bundleMetadata == null) { return; } __result = bundleMetadata.NoteTileLocation; }
public static void AreaNameFromNumber_Postfix( CommunityCenter __instance, ref string __result, int areaNumber) { string name = Bundles.GetCustomAreaNameFromNumber(areaNumber: areaNumber); if (Bundles.IsAbandonedJojaMartBundleAvailableOrComplete() || string.IsNullOrEmpty(name)) { return; } __result = name; }
/********* ** Public methods *********/ /// <summary>The mod entry point, called after the mod is first loaded.</summary> /// <param name="helper">Provides simplified APIs for writing mods.</param> public override void Entry(IModHelper helper) { config = helper.ReadConfig <ModConfig>(); helper.Events.Player.InventoryChanged += CheckInventory; helper.Events.Input.ButtonsChanged += CheckHotkey; helper.Events.Display.RenderedHud += CheckBestItemHeld; helper.Events.GameLoop.SaveLoaded += SetPlayerNumber; helper.Events.Multiplayer.PeerDisconnected += ReleasePlayer; helper.Events.GameLoop.SaveLoaded += (object sender, SaveLoadedEventArgs e) => { _communityCenter = Game1.getLocationFromName("CommunityCenter") as CommunityCenter; _bundleData = Game1.netWorldState.Value.BundleData; }; }
public static void JunimoNoteMenu_ctor_Postfix( JunimoNoteMenu __instance, bool fromGameMenu, int area, bool fromThisMenu) { CommunityCenter cc = Bundles.CC; if (Bundles.IsAbandonedJojaMartBundleAvailableOrComplete()) { return; } IReflectedField <int> whichAreaField = Reflection.GetField <int> (__instance, "whichArea"); bool isAreaSet = false; bool isNavigationSet = false; foreach (string areaName in Bundles.GetAllAreaNames()) { int areaNumber = CommunityCenter.getAreaNumberFromName(areaName); // Set default area for menu view with custom areas if (!isAreaSet && fromGameMenu && !fromThisMenu && !isAreaSet && cc.shouldNoteAppearInArea(areaNumber) && !Bundles.IsAreaComplete(cc: cc, areaNumber: areaNumber)) { area = areaNumber; whichAreaField.SetValue(area); isAreaSet = true; } // Show navigation arrows when custom areas if (!isNavigationSet && areaNumber >= 0 && areaNumber != area && cc.shouldNoteAppearInArea(areaNumber)) { __instance.areaNextButton.visible = true; __instance.areaBackButton.visible = true; isNavigationSet = true; } if (isAreaSet && isNavigationSet) { break; } } }
private void handleMasterBook(CommunityCenter cc) { helper.Content.Load <Dictionary <string, string> >("Strings/UI", ContentSource.GameContent); Func <string, Translation> t = helper.Translation.Get; if (!GameState.Current.Activated) { // initial choice to use mod or dimiss it forever. var menu = new MyDialogueBox(t("noteActivate"), new List <MyResponse> { new MyResponse(t("noteActivateY"), () => ActivateMod(cc)), new MyResponse(t("noteActivateN"), () => DeclineMod(cc)) }, helper); Game1.activeClickableMenu = menu; } else { // are we already working on a reward? if (Game1.MasterPlayer.mailForTomorrow.Any(x => x.StartsWith("cc"))) { var db = new DialogueBox(t("noteRewardsAlreadyWorking")); Game1.activeClickableMenu = db; } else { var responses = new List <MyResponse>(); var rooms = new Dictionary <string, int> { { "Pantry", 70000 }, { "CraftsRoom", 50000 }, { "Vault", 80000 }, { "FishTank", 40000 }, { "BoilerRoom", 30000 }, }; foreach (var kvp in rooms) { if (!Game1.MasterPlayer.hasOrWillReceiveMail($"cc{kvp.Key}")) { var text = ModEntry.VanillaRewards[kvp.Key] + $" ({kvp.Value:n0}g)"; responses.Add(new MyResponse(text, () => buildUpgrade($"cc{kvp.Key}", kvp.Value))); } } var menu = new MyDialogueBox(t("noteRewards"), responses, helper); Game1.activeClickableMenu = menu; } } }
public static void LoadArea_Postfix( CommunityCenter __instance, int area) { if (area == CommunityCenter.AREA_JunimoHut) { // Update map if Junimo Hut area is being restored, // assuming all areas have been completed __instance.mapPath.Value = "Maps\\CommunityCenter_Refurbished"; __instance.updateMap(); } string areaName = CommunityCenter.getAreaNameFromNumber(area); CustomCommunityCentre.Events.Game.InvokeOnAreaLoaded(communityCentre: __instance, areaName: areaName, areaNumber: area); }
public static bool MessageForAreaCompletion_Prefix(CommunityCenter __instance, ref string __result) { try { if (!Bundles.IsAbandonedJojaMartBundleAvailable()) { __result = Game1.content.LoadString("Strings\\Locations:CommunityCenter_AreaCompletion" + __instance.areasComplete.Count(_ => _), Game1.player.Name); } return(string.IsNullOrEmpty(__result)); } catch (Exception e) { Log.E($"Error in {nameof(MessageForAreaCompletion_Prefix)}:\n{e}"); } return(true); }
/// <summary>Get unfinished bundles which require this item.</summary> /// <param name="item">The item for which to find bundles.</param> private IEnumerable <BundleModel> GetUnfinishedBundles(SObject item) { // no bundles for Joja members if (Game1.player.hasOrWillReceiveMail(Constant.MailLetters.JojaMember)) { yield break; } // avoid false positives if (item.bigCraftable.Value || item is Cask or Fence or Furniture or IndoorPot or Sign or Torch or Wallpaper) { yield break; // avoid false positives } // get community center CommunityCenter communityCenter = Game1.locations.OfType <CommunityCenter>().First(); bool IsBundleOpen(int id) { try { return(!communityCenter.isBundleComplete(id)); } catch { return(false); // invalid bundle data } } // get bundles if (!communityCenter.areAllAreasComplete() || IsBundleOpen(36)) { foreach (BundleModel bundle in this.GameHelper.GetBundleData()) { if (!IsBundleOpen(bundle.ID)) { continue; } bool isMissing = this.GetIngredientsFromBundle(bundle, item).Any(p => this.IsIngredientNeeded(bundle, p)); if (isMissing) { yield return(bundle); } } } }
/// <summary> /// Adds an extra Junimo to the goodbye dance, as the number of Junimos added is otherwise hardcoded. /// </summary> public static bool JunimoGoodbyeDance_Prefix(CommunityCenter __instance) { try { if (!Bundles.IsCommunityCentreKitchenEnabledByHost()) { return(true); } __instance.getJunimoForArea(Bundles.CommunityCentreAreaNumber).Position = new Vector2(22f, 12f) * 64f; } catch (Exception e) { Log.E($"Error in {nameof(JunimoGoodbyeDance_Prefix)}:\n{e}"); } return(true); }
public static void ResetSharedState_Postfix( CommunityCenter __instance) { if (Game1.MasterPlayer.mailReceived.Contains("JojaMember")) { return; } if (__instance.areAllAreasComplete()) { if (Bundles.AreAnyCustomAreasLoaded()) { __instance.numberOfStarsOnPlaque.Value += 1; } } else { if (__instance.mapPath.Value == "Maps\\CommunityCenter_Refurbished") { // When all base areas are complete, // CommunityCenter.TransferDataFromSavedLocation() will call CommunityCenter.areAllAreasComplete(), // which will return true and set the map as if the CC were complete. // If any custom areas are incomplete, // we undo the map change here to revert to the incomplete state map. __instance.mapPath.Value = "Maps\\CommunityCenter_Ruins"; __instance.updateMap(); } foreach (int areaNumber in Bundles.CustomAreasComplete.Keys) { if (Bundles.ShouldNoteAppearInCustomArea(cc: __instance, areaNumber: areaNumber)) { string areaName = Bundles.GetCustomAreaNameFromNumber(areaNumber); CustomCommunityCentre.Data.BundleMetadata bundleMetadata = Bundles.GetAllCustomBundleMetadataEntries() .First(bmd => bmd.AreaName == areaName); Vector2 tileLocation = Utility.PointToVector2(bundleMetadata.NoteTileLocation + bundleMetadata.JunimoOffsetFromNoteTileLocation); Junimo j = new (position : tileLocation * Game1.tileSize, whichArea : areaNumber); __instance.characters.Add(j); } } } CustomCommunityCentre.Events.Game.InvokeOnResetSharedState(communityCentre: __instance); }
public void ToggleOption(bool showItemHoverInformation) { PlayerEvents.InventoryChanged -= PopulateRequiredBundles; GraphicsEvents.OnPostRenderEvent -= DrawAdvancedTooltipForMenu; GraphicsEvents.OnPostRenderHudEvent -= DrawAdvancedTooltipForToolbar; GraphicsEvents.OnPreRenderEvent -= GetHoverItem; if (showItemHoverInformation) { _communityCenter = Game1.getLocationFromName("CommunityCenter") as CommunityCenter; _bundleData = Game1.content.Load <Dictionary <String, String> >("Data\\Bundles"); PopulateRequiredBundles(null, null); PlayerEvents.InventoryChanged += PopulateRequiredBundles; GraphicsEvents.OnPostRenderEvent += DrawAdvancedTooltipForMenu; GraphicsEvents.OnPostRenderHudEvent += DrawAdvancedTooltipForToolbar; GraphicsEvents.OnPreRenderEvent += GetHoverItem; } }
public static void AreaNumberFromLocation_Postfix( CommunityCenter __instance, ref int __result, Vector2 tileLocation) { CustomCommunityCentre.Data.BundleMetadata bundleMetadata = Bundles.GetAllCustomBundleMetadataEntries() .FirstOrDefault(bmd => bmd.AreaBounds.Contains(Utility.Vector2ToPoint(tileLocation))); int areaNumber = bundleMetadata != null ? Bundles.GetCustomAreaNumberFromName(bundleMetadata.AreaName) : -1; if (Bundles.IsAbandonedJojaMartBundleAvailableOrComplete() || areaNumber < 0) { return; } __result = areaNumber; }
public void ToggleOption(bool showItemHoverInformation) { _events.Player.InventoryChanged -= OnInventoryChanged; _events.Display.Rendered -= OnRendered; _events.Display.RenderedHud -= OnRenderedHud; _events.Display.Rendering -= OnRendering; if (showItemHoverInformation) { _communityCenter = Game1.getLocationFromName("CommunityCenter") as CommunityCenter; _bundleData = Game1.content.Load <Dictionary <String, String> >("Data\\Bundles"); PopulateRequiredBundles(); _events.Player.InventoryChanged += OnInventoryChanged; _events.Display.Rendered += OnRendered; _events.Display.RenderedHud += OnRenderedHud; _events.Display.Rendering += OnRendering; } }