public static void SpawnJunimoAtPosition(Vector2 pos, JunimoHut hut, int junimoNumber) { if (hut == null) { return; } Farm farm = Game1.getFarm(); /* * Added by Mizzion. This will set the color of the junimos based on what gem is inside the hut. */ bool isPrismatic = false; Color?gemColor = getGemColor(ref isPrismatic, hut);//Reflection.GetMethod(hut, "getGemColor").Invoke<Color>(isPrismatic); /* * End added By Mizzion */ JunimoHarvester junimoHarvester = new JunimoHarvester(pos, hut, junimoNumber, gemColor); junimoHarvester.isPrismatic.Value = isPrismatic; //Added by Mizzion, Fixes the Prismatic Junimos. farm.characters.Add((NPC)junimoHarvester); hut.myJunimos.Add(junimoHarvester); if (Game1.isRaining) { var alpha = Reflection.GetField <float>(junimoHarvester, "alpha"); alpha.SetValue(Config.FunChanges.RainyJunimoSpiritFactor); } if (!Utility.isOnScreen(Utility.Vector2ToPoint(pos), 64, farm)) { return; } farm.playSound("junimoMeep1"); }
public CachedMessageEmojis(IModHelper helper, int numberVanillaEmojis) { Reflection = helper.Reflection; messagesField = Reflection.GetField <List <ChatMessage> >(Game1.chatBox, "messages"); cheatHistoryPositionField = Reflection.GetField <int>(Game1.chatBox, "cheatHistoryPosition"); choosingEmojiField = Reflection.GetField <bool>(Game1.chatBox, "choosingEmoji"); emojiMenuIconField = Reflection.GetField <ClickableTextureComponent>(Game1.chatBox, "emojiMenuIcon"); formatMessageMethod = Reflection.GetMethod(Game1.chatBox, "formatMessage"); messageColorMethod = Reflection.GetMethod(Game1.chatBox, "messageColor"); PlayerMessageList = new List <PlayerMessage>(); NumberVanillaEmoji = numberVanillaEmojis; chatCommandsIsLoaded = helper.ModRegistry.IsLoaded("cat.chatcommands"); if (chatCommandsIsLoaded) { displayLineIndexField = Reflection.GetField <int>(Game1.chatBox, "displayLineIndex"); getEndDisplayIndexMethod = Reflection.GetMethod(Game1.chatBox, "GetEndDisplayIndex"); } SubscribeEvents(); }
public ServerMenuSlot(CoopMenu menu, IReflectionHelper reflection, string serverName, string ip) : base(menu) { this.ServerName = serverName; this.IP = ip; this.reflection = reflection; this.menu = menu; var menuSlotsField = reflection.GetField <List <MenuSlot> >(menu, "menuSlots");//menuSlots for Join, hostSlots for Host var list = menuSlotsField.GetValue(); deleteButton = new ClickableTextureComponent("", new Rectangle(0, 0, 48, 48), "", "Delete", Game1.mouseCursors, new Rectangle(322, 498, 12, 12), 3f, false); CoopMenuPerformLeftClickPreListenerAndOverrider.PerformLeftClick += (x) => { if (deleteButton.bounds.Contains(Game1.getMousePosition()) && reflection.GetField <CoopMenu.Tab>(menu, "currentTab").GetValue() == CoopMenu.Tab.JOIN_TAB && reflection.GetField <List <MenuSlot> >(menu, "menuSlots").GetValue() != null) { DeleteBookmark?.Invoke(menu, this); x.Override = true; } }; }
/// <summary>Apply the mod textures to the given menu, if applicable.</summary> /// <param name="menu">The menu to change.</param> /// <param name="isFarmExpansion">Whether the menu is the Farm Expansion build menu.</param> /// <param name="isPelicanFiber">Whether the menu is the Pelican Fiber build menu.</param> /// <param name="isGarage">Whether a blueprint is for a tractor garage.</param> /// <param name="reflection">The SMAPI API for accessing internal code.</param> public void ApplyTextures(IClickableMenu menu, bool isFarmExpansion, bool isPelicanFiber, Func <BluePrint, bool> isGarage, IReflectionHelper reflection) { // vanilla menu if (menu is CarpenterMenu carpenterMenu) { if (isGarage(carpenterMenu.CurrentBlueprint)) { Building building = reflection.GetField <Building>(carpenterMenu, "currentBuilding").GetValue(); if (building.texture.Value != this.GarageTexture && this.GarageTexture != null) { building.texture = new Lazy <Texture2D>(() => this.GarageTexture); } } return; } // Farm Expansion & Pelican Fiber menus if (isFarmExpansion || isPelicanFiber) { BluePrint currentBlueprint = reflection.GetProperty <BluePrint>(menu, isFarmExpansion ? "CurrentBlueprint" : "currentBlueprint").GetValue(); if (isGarage(currentBlueprint)) { Building building = reflection.GetField <Building>(menu, "currentBuilding").GetValue(); if (building.texture.Value != this.GarageTexture && this.GarageTexture != null) { building.texture = new Lazy <Texture2D>(() => this.GarageTexture); } } } }
public void Shake(IReflectionHelper helper, Vector2 tile) { // can't just call shake because it drops items. We don't want to drop items. // see Tree::shake for the logic this replicates // already shaking if (helper.GetField <float>(tree, "maxShake").GetValue() != 0) { return; } tree.shakeLeft.Value = this.left; helper.GetField <float>(tree, "maxShake").SetValue((float)(tree.growthStage.Value >= 5 ? Math.PI / 128f : Math.PI / 64f)); if (tree.growthStage.Value >= 3 && !tree.stump.Value) { if (tree.growthStage.Value >= 5) { if (Game1.random.NextDouble() < 0.66) { List <Leaf> leaves = helper.GetField <List <Leaf> >(this.tree, "leaves").GetValue(); int num = Game1.random.Next(1, 6); for (int index = 0; index < num; ++index) { leaves.Add(new Leaf(new Vector2((float)Game1.random.Next((int)((double)tile.X * 64.0 - 64.0), (int)((double)tile.X * 64.0 + 128.0)), (float)Game1.random.Next((int)((double)tile.Y * 64.0 - 256.0), (int)((double)tile.Y * 64.0 - 192.0))), (float)Game1.random.Next(-10, 10) / 100f, Game1.random.Next(4), (float)Game1.random.Next(5) / 10f)); } } if (Game1.random.NextDouble() < 0.01 && (this.tree.currentLocation.GetSeasonForLocation().Equals("spring") || this.tree.currentLocation.GetSeasonForLocation().Equals("summer") || this.tree.currentLocation.GetLocationContext() == GameLocation.LocationContext.Island)) { while (Game1.random.NextDouble() < 0.8) { location.addCritter((Critter) new Butterfly(new Vector2(tile.X + (float)Game1.random.Next(1, 3), tile.Y - 2f + (float)Game1.random.Next(-1, 2)), this.tree.currentLocation.GetLocationContext() == GameLocation.LocationContext.Island)); } } } else { if (Game1.random.NextDouble() < 0.66) { List <Leaf> leaves = helper.GetField <List <Leaf> >(this.tree, "leaves").GetValue(); int num = Game1.random.Next(1, 3); for (int index = 0; index < num; ++index) { leaves.Add(new Leaf(new Vector2((float)Game1.random.Next((int)((double)tile.X * 64.0), (int)((double)tile.X * 64.0 + 48.0)), (float)((double)tile.Y * 64.0 - 32.0)), (float)Game1.random.Next(-10, 10) / 100f, Game1.random.Next(4), (float)Game1.random.Next(30) / 10f)); } } } } else { if (tree.stump.Value) { helper.GetField <float>(tree, "shakeTimer").SetValue(100); } } }
/// <summary>Render the UI.</summary> /// <param name="spriteBatch">The sprite batch being drawn.</param> public override void draw(SpriteBatch spriteBatch) { // disable when game is using immediate sprite sorting if (!ValidatedDrawMode) { IReflectedField <SpriteSortMode> sortModeField = Reflection.GetField <SpriteSortMode>(Game1.spriteBatch, "spriteSortMode", required: false) // XNA ?? Reflection.GetField <SpriteSortMode>(Game1.spriteBatch, "_sortMode"); // MonoGame if (sortModeField.GetValue() == SpriteSortMode.Immediate) { Monitor.Log("Aborted the weather draw because the game's current rendering mode isn't compatible with the mod's UI. This only happens in rare cases (e.g. the Stardew Valley Fair).", LogLevel.Warn); exitThisMenu(playSound: false); return; } ValidatedDrawMode = true; } // calculate dimensions int x = xPositionOnScreen; int y = yPositionOnScreen; const int gutter = 15; float leftOffset = gutter; float topOffset = gutter; float contentWidth = width - gutter * 2; float contentHeight = height - gutter * 2; // get font SpriteFont font = Game1.smallFont; float lineHeight = font.MeasureString("ABC").Y; //at this point I'm going to manually put this in as I don't need in many places, // and I kinda want to have this where I can understand what it's for float spaceWidth = DrawHelper.GetSpaceWidth(font); // draw background // (This uses a separate sprite batch because it needs to be drawn before the // foreground batch, and we can't use the foreground batch because the background is // outside the clipping area.) spriteBatch.DrawSprite(Sprites.Letter.Sheet, Sprites.Letter.Sprite, x, y, scale: width / (float)Sprites.Letter.Sprite.Width); // begin draw // draw weather icon spriteBatch.Draw(IconSheet.WeatherSource, new Vector2(x + leftOffset, y + topOffset), IconSheet.GetWeatherSprite(CurrentWeather.GetCurrentConditions()), Color.White); leftOffset += 72; // draw text as sent from outside the menu float wrapWidth = width - leftOffset - gutter; { Vector2 textSize = spriteBatch.DrawTextBlock(font, MenuText, new Vector2(x + leftOffset, y + topOffset), wrapWidth); topOffset += textSize.Y; topOffset += lineHeight; } drawMouse(Game1.spriteBatch); }
/// <summary>Raised after the player presses a button on the keyboard, controller, or mouse.</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event data.</param> private void OnButtonPressed(object sender, ButtonPressedEventArgs e) { if (Game1.activeClickableMenu is GameMenu gameMenu && gameMenu.currentTab == GameMenu.mapTab) { if (modHelper.Input.IsDown(SButton.LeftAlt) && modHelper.Input.IsDown(SButton.MouseLeft)) { MapPage mapPage = (MapPage)Reflection.GetField <List <IClickableMenu> >(gameMenu, "pages").GetValue()[GameMenu.mapTab]; Vector2 mapCoord = new Vector2(Reflection.GetField <int>(mapPage, "mapX").GetValue(), Reflection.GetField <int>(mapPage, "mapY").GetValue()); //Vector2 mapPos = Utility.getTopLeftPositionForCenteringOnScreen(Sprites.Map.SourceRectangle.Width * Game1.pixelZoom, Sprites.Map.SourceRectangle.Height * Game1.pixelZoom); Vector2 pingedCoord = new Vector2(e.Cursor.ScreenPixels.X - mapCoord.X, e.Cursor.ScreenPixels.Y - mapCoord.Y); int mapWidth = Sprites.Map.SourceRectangle.Width * Game1.pixelZoom; int mapHeight = Sprites.Map.SourceRectangle.Height * Game1.pixelZoom; if (IsPingWithinMapBounds(mapWidth, mapHeight, pingedCoord)) { //TODO: Send ping to players if (config.ShowPingsInChat) { string hoverText = Reflection.GetField <string>(mapPage, "hoverText").GetValue(); if (!String.IsNullOrWhiteSpace(hoverText)) { hoverText = $"\"{GetHoverTextLocationName(hoverText)}\""; } if (!MapPings.ContainsKey(Game1.player)) { MapPings.Add(Game1.player, new PlayerMapPing(Color.Red)); } MapPings[Game1.player].AddPing(Game1.player, pingedCoord, hoverText); string messageKey = "UserNotificationMessageFormat"; string messageText = $"{Game1.player.Name} pinged {hoverText} [X:{pingedCoord.X}, Y:{pingedCoord.Y}]"; if (Game1.IsMultiplayer) { Multiplayer multiplayer = Reflection.GetField <Multiplayer>(typeof(Game1), "multiplayer").GetValue(); multiplayer.globalChatInfoMessage(messageKey, messageText); } else { Game1.chatBox.addInfoMessage(Game1.content.LoadString("Strings\\UI:Chat_" + messageKey, messageText)); } } #if DEBUG ModEntry.ModLogger.Log($"MapCoords => (x: {pingedCoord.X}, y: {pingedCoord.Y})"); ModEntry.ModLogger.Log($"Map (X: {mapCoord.X}, Y: {mapCoord.Y})"); #endif } modHelper.Input.Suppress(SButton.MouseLeft); } } }
public CommandEmojiMenu(IReflectionHelper reflection, ChatBox chatBox, Texture2D emojiTexture, Texture2D chatBoxTexture) : base(chatBox, emojiTexture, chatBoxTexture) { this.bUpArrow = reflection.GetField <ClickableComponent>(this, "upArrow").GetValue(); this.bDownArrow = reflection.GetField <ClickableComponent>(this, "downArrow").GetValue(); this.bSendArrow = reflection.GetField <ClickableComponent>(this, "sendArrow").GetValue(); this.bEmojiSelectionButtons = reflection.GetField <List <ClickableComponent> >(this, "emojiSelectionButtons").GetValue(); this.bPageStartIndex = reflection.GetField <int>(this, "pageStartIndex"); this.bUpArrowPressed = reflection.GetMethod(this, "upArrowPressed"); this.bDownArrowPressed = reflection.GetMethod(this, "downArrowPressed"); }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="recipe">The recipe to parse.</param> /// <param name="reflectionHelper">Simplifies access to private game code.</param> /// <param name="translations">Provides translations stored in the mod folder.</param> public RecipeModel(CraftingRecipe recipe, IReflectionHelper reflectionHelper, ITranslationHelper translations) : this( key : recipe.name, type : recipe.isCookingRecipe ? RecipeType.Cooking : RecipeType.Crafting, displayType : translations.Get(recipe.isCookingRecipe ? L10n.RecipeTypes.Cooking : L10n.RecipeTypes.Crafting), ingredients : reflectionHelper.GetField <Dictionary <int, int> >(recipe, "recipeList").GetValue(), item : item => recipe.createItem(), mustBeLearned : true, outputItemIndex : reflectionHelper.GetField <List <int> >(recipe, "itemToProduce").GetValue()[0] ) { }
public void Shake(IReflectionHelper helper, Vector2 tile) { // can't just call shake because it drops items. We don't want to drop items. // unfortunately almost identical, but different from, TreeShaker // see FruitTree::shake for the logic this replicates // already shaking if (helper.GetField <float>(fruitTree, "maxShake").GetValue() != 0) { return; } fruitTree.shakeLeft.Value = this.left; helper.GetField <float>(fruitTree, "maxShake").SetValue((float)(fruitTree.growthStage.Value >= 5 ? Math.PI / 128f : Math.PI / 64f)); if (fruitTree.growthStage.Value >= 3 && !fruitTree.stump.Value) { if (fruitTree.growthStage.Value >= 4) { if (Game1.random.NextDouble() < 0.66) { List <Leaf> leaves = helper.GetField <List <Leaf> >(this.fruitTree, "leaves").GetValue(); int num = Game1.random.Next(1, 6); for (int index = 0; index < num; ++index) { leaves.Add(new Leaf(new Vector2((float)Game1.random.Next((int)((double)tile.X * 64.0 - 64.0), (int)((double)tile.X * 64.0 + 128.0)), (float)Game1.random.Next((int)((double)tile.Y * 64.0 - 256.0), (int)((double)tile.Y * 64.0 - 192.0))), (float)Game1.random.Next(-10, 10) / 100f, Game1.random.Next(4), (float)Game1.random.Next(5) / 10f)); } } } else { if (Game1.random.NextDouble() < 0.66) { List <Leaf> leaves = helper.GetField <List <Leaf> >(this.fruitTree, "leaves").GetValue(); int num = Game1.random.Next(1, 3); for (int index = 0; index < num; ++index) { leaves.Add(new Leaf(new Vector2((float)Game1.random.Next((int)((double)tile.X * 64.0), (int)((double)tile.X * 64.0 + 48.0)), (float)((double)tile.Y * 64.0 - 32.0)), (float)Game1.random.Next(-10, 10) / 100f, Game1.random.Next(4), (float)Game1.random.Next(30) / 10f)); } } } } else { if (fruitTree.stump.Value) { helper.GetField <float>(fruitTree, "shakeTimer").SetValue(100); } } }
private bool ShouldDrawIndicator(NPC npc) { IReflectionHelper reflection = QuestFrameworkMod.Instance.Helper.Reflection; return(npc.isVillager() && this.ActiveIndicators.Contains(npc.Name) && !npc.IsInvisible && !npc.IsEmoting && !npc.isSleeping.Value && !Game1.eventUp && reflection.GetField <int>(npc, "textAboveHeadTimer").GetValue() <= 0 && reflection.GetField <string>(npc, "textAboveHead").GetValue() == null); }
public void Shake(IReflectionHelper helper, Vector2 tile) { // can't just call shake because it drops items. We don't want to drop items. // see Bush::shake for the logic this replicates // already shaking if (helper.GetField <float>(this.bush, "maxShake").GetValue() != 0) { return; } helper.GetField <bool>(this.bush, "shakeLeft").SetValue(this.left); helper.GetField <float>(this.bush, "maxShake").SetValue((float)Math.PI / 128f); }
/// <summary>Construct an instance.</summary> /// <param name="recipe">The recipe to parse.</param> /// <param name="reflectionHelper">Simplifies access to private game code.</param> public RecipeModel(CraftingRecipe recipe, IReflectionHelper reflectionHelper) : this( key : recipe.name, type : recipe.isCookingRecipe ? RecipeType.Cooking : RecipeType.Crafting, displayType : recipe.isCookingRecipe ? L10n.RecipeTypes.Cooking() : L10n.RecipeTypes.Crafting(), ingredients : reflectionHelper.GetField <Dictionary <int, int> >(recipe, "recipeList").GetValue(), item : item => recipe.createItem(), mustBeLearned : true, outputItemIndex : reflectionHelper.GetField <List <int> >(recipe, "itemToProduce").GetValue()[0], minOutput : recipe.numberProducedPerCraft, isForMachine : obj => false ) { }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="reflection">Simplifies access to private code.</param> /// <param name="options">The available dropdown options.</param> /// <param name="selected">The selected key, if any.</param> /// <param name="getKeyString">The logic to get the </param> public SimpleDropdown(IReflectionHelper reflection, IEnumerable <KeyValuePair <TKey, string> > options, TKey?selected = default, Func <TKey, string>?getKeyString = null) { getKeyString ??= raw => raw.ToString() ?? string.Empty; // parse options var optionKeys = new List <string?>(); var optionLabels = new List <string>(); var lookup = new List <Tuple <string, TKey, string> >(); foreach ((TKey key, string value) in options) { string keyStr = getKeyString(key); optionKeys.Add(keyStr); optionLabels.Add(value); lookup.Add(Tuple.Create(keyStr, key, value)); } // build dropdown this.Options = lookup; this.Dropdown = new OptionsDropDown(null, -int.MaxValue) { dropDownOptions = optionKeys, dropDownDisplayOptions = optionLabels }; this.IsExpandedField = reflection.GetField <bool>(this.Dropdown, "clicked"); // select element this.TrySelect(selected); }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="contentPack">The content pack from which the patch was loaded.</param> /// <param name="name">The raw patch name to display in error messages.</param> /// <param name="patch">The patch instance from Content Patcher.</param> /// <param name="reflection">Simplifies access to private code.</param> /// <param name="reflection">Simplifies access to game content.</param> public PatchData(IContentPack contentPack, string name, object patch, IReflectionHelper reflection) { this.ContentPack = contentPack; this.Name = name; this.Reflection = reflection; this.LastChangedTickProperty = reflection.GetProperty <int>(patch, "LastChangedTick"); this.IsReadyProperty = reflection.GetProperty <bool>(patch, "IsReady"); this.IsAppliedProperty = reflection.GetProperty <bool>(patch, "IsApplied"); this.FromAssetProperty = reflection.GetProperty <string>(patch, "FromAsset"); this.TargetAssetProperty = reflection.GetProperty <IAssetName>(patch, "TargetAsset"); this.FromAreaProperty = reflection.GetField <object>(patch, "FromArea"); this.ToAreaProperty = reflection.GetField <object>(patch, "ToArea"); this.RefreshIfNeeded(); }
public int GetClickedItemIndex(IReflectionHelper reflection, ShopMenu shopMenu, Point p) { int currentItemIndex = reflection.GetField <int>(shopMenu, "currentItemIndex").GetValue(); int saleButtonIndex = shopMenu.forSaleButtons.FindIndex(button => button.containsPoint(p.X, p.Y)); return(saleButtonIndex > -1 ? currentItemIndex + saleButtonIndex : -1); }
private static void DoEmote_Postfix(Farmer __instance, int whichEmote) { if (Context.IsMultiplayer && __instance is Farmer && __instance.IsLocalPlayer && __instance.IsEmoting) { // Traverse.Create(typeof(Game1)).Field("multiplayer").GetValue<Multiplayer>().BroadcastEmote(whichEmote); Reflection.GetField <Multiplayer>(typeof(Game1), "multiplayer").GetValue().BroadcastEmote(whichEmote); } }
/// <summary>Helper method getting which item in the shop was clicked.</summary> /// <param name="reflection">Reflection helper.</param> /// <param name="shopMenu">Native shop menu.</param> /// <param name="p">Mouse location.</param> /// <returns>The clicked item or null if none was clicked.</returns> public static ISalable GetClickedShopItem(IReflectionHelper reflection, ShopMenu shopMenu, Point p) { var itemsForSale = reflection.GetField <List <ISalable> >(shopMenu, "forSale").GetValue(); int index = GetClickedItemIndex(reflection, shopMenu, p); Debug.Assert(index < itemsForSale.Count); return(index >= 0 ? itemsForSale[index] : null); }
/// <summary>Construct an instance.</summary> /// <param name="recipe">The recipe to parse.</param> /// <param name="reflectionHelper">Simplifies access to private game code.</param> public RecipeModel(CraftingRecipe recipe, IReflectionHelper reflectionHelper) : this( key : recipe.name, type : recipe.isCookingRecipe ? RecipeType.Cooking : RecipeType.Crafting, displayType : recipe.isCookingRecipe ? I18n.RecipeType_Cooking() : I18n.RecipeType_Crafting(), ingredients : reflectionHelper .GetField <Dictionary <int, int> >(recipe, "recipeList").GetValue() .Select(p => new RecipeIngredientModel(p.Key, p.Value)), item : item => recipe.createItem(), mustBeLearned : true, minOutput : recipe.numberProducedPerCraft, machineParentSheetIndex : null, isForMachine : obj => false ) { this.OutputItemIndex = reflectionHelper.GetField <List <int> >(recipe, "itemToProduce").GetValue()[0]; this.OutputItemType = this.GetItemType(recipe, this.OutputItemIndex.Value); }
private void MenuEvents_MenuChanged(object sender, EventArgsClickableMenuChanged e) { if (Game1.activeClickableMenu is GameMenu gameMenu) { if (gameMenu.currentTab == GameMenu.mapTab) { mapPage = (MapPage)Reflection.GetField <List <IClickableMenu> >(gameMenu, "pages").GetValue()[GameMenu.mapTab]; mapXField = Reflection.GetField <int>(mapPage, "mapX"); mapYField = Reflection.GetField <int>(mapPage, "mapY"); IsMapOpen = true; } else { IsMapOpen = false; } } }
public void BroadcastEmote(int whichEmote) { TemporaryAnimatedSprite emoteStart = new TemporaryAnimatedSprite("TileSheets\\emotes", new Rectangle(0, 0, 16, 16), new Vector2(Game1.player.Position.X, Game1.player.Position.Y - 160), false, 0f, Color.White) { interval = 80f, animationLength = 4, scale = 4f, layerDepth = 0.9f, local = false, timeBasedMotion = true, attachedCharacter = Game1.player, extraInfoForEndBehavior = 0, endFunction = FinishedAnimation }; TemporaryAnimatedSprite emote = new TemporaryAnimatedSprite("TileSheets\\emotes", new Rectangle(0, whichEmote * 16, 16, 16), new Vector2(Game1.player.Position.X, Game1.player.Position.Y - 160), false, 0f, Color.White) { delayBeforeAnimationStart = 100, interval = 250f, animationLength = 4, scale = 4f, layerDepth = 1f, local = false, timeBasedMotion = true, attachedCharacter = Game1.player, extraInfoForEndBehavior = 1, endFunction = FinishedAnimation }; TemporaryAnimatedSprite emoteEnding = new TemporaryAnimatedSprite("TileSheets\\emotes", new Rectangle(0, 0, 16, 16), new Vector2(Game1.player.Position.X, Game1.player.Position.Y - 160), false, 0f, Color.White) { delayBeforeAnimationStart = 800, interval = 80f, animationLength = 4, scale = 4f, layerDepth = 0.9f, local = false, timeBasedMotion = true, pingPong = true, // This makes the animation play, forwards, and when finished backwards sourceRect = new Rectangle(48, 0, 16, 16), // Set the current sprite position to the last animation image currentParentTileIndex = 3, // To play the animation backwards, we tell it that its in the last frame attachedCharacter = Game1.player, extraInfoForEndBehavior = 2, endFunction = FinishedAnimation }; temporaryAnimationList = new List <TemporaryAnimatedSprite>() { emoteStart, emote, emoteEnding }; Multiplayer multiplayer = Reflection.GetField <Multiplayer>(typeof(Game1), "multiplayer").GetValue(); multiplayer.broadcastSprites(Game1.player.currentLocation, temporaryAnimationList); }
public List <string>?GetCookingRecipes() { if (!IsLoaded || Entry == null) { return(null); } List <string>?removed = Helper.GetField <List <string> >(Entry, "_cookingRecipesToRemove", false)?.GetValue(); if (removed == null) { return(null); } Log($"Removed {removed.Count} cooking recipes due to CCS.", LogLevel.Debug); return(Self.Recipes.GetRecipes(true).Select(v => v.Name).Where(v => !removed.Contains(v)).ToList()); }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="town">The town to search.</param> /// <param name="tile">The machine's position in its location.</param> /// <param name="trashCanIndex">The trash can index.</param> /// <param name="reflection">Simplifies access to private game code.</param> public TrashCanMachine(Town town, Vector2 tile, int trashCanIndex, IReflectionHelper reflection) { this.Tile = tile; this.TrashCansChecked = reflection.GetField <IList <bool> >(town, "garbageChecked").GetValue(); if (trashCanIndex >= 0 && trashCanIndex < this.TrashCansChecked.Count) { this.TrashCanIndex = trashCanIndex; } }
private void Update(object sender, EventArgsInput e) { if (!(Game1.activeClickableMenu is GameMenu)) { return; } var menuList = _reflection.GetField <List <IClickableMenu> >(Game1.activeClickableMenu, "pages").GetValue(); foreach (var menu in menuList) { if (!(menu is InventoryPage)) { continue; } var item = _reflection.GetField <Item>(menu, "hoveredItem").GetValue(); if (item == null) { return; } var newSlot = -1; var oldSlot = Game1.player.Items.IndexOf(item); foreach (var ent in _keyBindings) { foreach (var inputButton in ent.Value) { if (inputButton.key.ToString().Equals(e.Button.ToString())) { newSlot = ent.Key; } } } if (newSlot == -1) { return; } var currentItem = Game1.player.Items[newSlot]; Game1.player.items[newSlot] = item; Game1.player.items[oldSlot] = currentItem; } }
public BetterSlingshot(IReflectionHelper reflection, BetterSlingshotsConfig config, SObject currentProjectile, bool isActionButtonDown, int which) : base(which) { this.attachments[0] = currentProjectile; this.reflection = reflection; this.config = config; this.isActionButtonDown = isActionButtonDown; this.autoFireRate = this.GetFireRate(); this.baseCanPlaySound = reflection.GetField <bool>(this, "canPlaySound"); this.isAutomatic = config.AutomaticSlingshots.IndexOf(Enum.GetName(typeof(SlingshotType), SlingshotManager.GetTypeFromIndex(this.initialParentTileIndex)), StringComparison.InvariantCultureIgnoreCase) != -1; }
/// <summary>Update the indoor pot state on load for automation.</summary> /// <param name="indoorPot">The indoor pot to update.</param> /// <param name="reflection">Simplifies access to private code.</param> /// <remarks>Derived from <see cref="IndoorPot.updateWhenCurrentLocation"/>. When an indoor pot is loaded from the save file, the bush it contains isn't updated immediately. Instead it's marked dirty and will call <see cref="Bush.loadSprite"/> when the player first enters the location. For Automate, that means a bush that's already harvested may reset and produce a new harvest for the day.</remarks> private void UpdateIndoorPotOnLoad(IndoorPot indoorPot, IReflectionHelper reflection) { NetBool bushLoadDirty = reflection.GetField <NetBool>(indoorPot, "bushLoadDirty").GetValue(); if (bushLoadDirty.Value) { indoorPot.bush.Value.loadSprite(); bushLoadDirty.Value = false; } }
/// <summary> /// Called after a game menu is opened, closed, or replaced. /// Responsible for displaying the actual content of a [Tool-Upgrade] mail, such as /// whether to show an attached tool, set the attached tool. /// </summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event arguments.</param> private void OnMenuChanged(object sender, MenuChangedEventArgs e) { if (!(e.OldMenu is LetterViewerMenu) && e.NewMenu is LetterViewerMenu letterViewerMenu) { var mailTitle = reflectionHelper.GetField <string>(letterViewerMenu, "mailTitle").GetValue(); if (mailTitle == null || !mailGenerator.IsToolMail(mailTitle)) { return; } ToolUpgradeInfo upgradeInfo = mailGenerator.GetMailAssignedToolUpgrade(mailTitle); if (upgradeInfo == null) { monitor.Log("Failed to retrive tool data from mail!", LogLevel.Error); } Tool toolForMail = Game1.player.toolBeingUpgraded.Value; /* * Check if the current upgrade tool matches with the tool which was assigned to this mail. * * Since the upgrade-mail content is generated when the mail is opened, the current upgrade tool * could have changed in the meantime. In this case, no tool will be included in this mail. */ if (toolForMail != null && (toolForMail.GetType() != upgradeInfo.ToolType || toolForMail.UpgradeLevel != upgradeInfo.Level)) { toolForMail = null; } // Bonus: Set the water level to full for the upgraded watering can. if (toolForMail is WateringCan can) { can.WaterLeft = can.waterCanMax; } var mailMessage = reflectionHelper.GetField <List <string> >(letterViewerMenu, "mailMessage").GetValue(); var itemMenu = new ItemLetterMenuHelper(mailMessage[0], toolForMail); itemMenu.MenuClosed += OnToolMailClosed; itemMenu.Show(); } }
public override void Activate() { Console.WriteLine($"Clicked bookmark: {ServerName} at {IP}"); CoopMenu menu = TitleMenu.subMenu as CoopMenu; //IP in format of 127.0.0.1:1234 var multiplayer = reflection.GetField <Multiplayer>(typeof(Game1), "multiplayer"); var setMenuMethod = reflection.GetMethod(menu, "setMenu", true); setMenuMethod.Invoke(new FarmhandMenu(multiplayer.GetValue().InitClient(new LidgrenClient(IP)))); }
public void FillUIElements(CoopMenu menu) { //Add server buttons string text = "Add server"; int width = (int)Game1.dialogueFont.MeasureString(text).X + 64; Vector2 pos = new Vector2(menu.backButton.bounds.Right - width, menu.backButton.bounds.Y - 128 - 150); addServerButton = new ClickableComponent(new Rectangle((int)pos.X, (int)pos.Y, width, 96), "", text); //Servers var menuSlotsField = reflection.GetField <List <MenuSlot> >(menu, "menuSlots");//menuSlots for Join, hostSlots for Host var list = menuSlotsField.GetValue(); list.RemoveAll((x) => x is ServerMenuSlot);//So there are no duplicates foreach (var x in bookmarks.Bookmarks) { list.Add(new ServerMenuSlot(menu, reflection, x.Key, x.Value)); } }
public override void Resolve(GameLocation location, BaseFeatureSaveData featureSaveData) { Tree currentTree = location.terrainFeatures[featureSaveData.featurePosition] as Tree; TreeSaveData treeSaveData = featureSaveData as TreeSaveData; currentTree.stump = false; currentTree.health = treeSaveData.health; reflectionHelper.GetField <bool>(currentTree, "falling").SetValue(false); monitor.Log($"Stopped {currentTree.GetType()} at position {featureSaveData.feature} from falling.", LogLevel.Trace); }