// Get location and area of location component private Rectangle GetLocationRect(string location) { // Set origin to center return(new Rectangle( (int)ModMain.LocationToMap(location).X - locationRects[location].width / 2, (int)ModMain.LocationToMap(location).Y - locationRects[location].height / 2, locationRects[location].width, locationRects[location].height )); }
// Map menu that uses modified map page and modified component locations for hover public ModMapPage( HashSet <CharacterMarker> npcMarkers, Dictionary <string, bool> secondaryNpcs, Dictionary <long, CharacterMarker> farmerMarkers, Dictionary <string, int> MarkerCropOffsets, Dictionary <string, KeyValuePair <string, Vector2> > farmBuildings, Texture2D buildingMarkers, IModHelper helper, ModConfig config, string mapName = null, Dictionary <string, MapVector[]> customMapLocations = null, Texture2D CustomMarkerTex = null ) : base(Game1.viewport.Width / 2 - (800 + IClickableMenu.borderWidth * 2) / 2, Game1.viewport.Height / 2 - (600 + IClickableMenu.borderWidth * 2) / 2, 800 + IClickableMenu.borderWidth * 2, 600 + IClickableMenu.borderWidth * 2) { this.NpcMarkers = npcMarkers; this.SecondaryNpcs = secondaryNpcs; this.FarmerMarkers = farmerMarkers; this.MarkerCropOffsets = MarkerCropOffsets; this.FarmBuildings = farmBuildings; this.BuildingMarkers = buildingMarkers; this.Helper = helper; this.Config = config; this.MapName = mapName; this.CustomMapLocations = customMapLocations; this.CustomMarkerTex = CustomMarkerTex; map = Game1.content.Load <Texture2D>("LooseSprites\\map"); drawPamHouseUpgrade = Game1.MasterPlayer.mailReceived.Contains("pamHouseUpgrade"); Vector2 center = Utility.getTopLeftPositionForCenteringOnScreen(map.Bounds.Width * 4, 720, 0, 0); mapX = (int)center.X; mapY = (int)center.Y; var regionRects = RegionRects().ToList(); for (int i = 0; i < this.points.Count; i++) { var rect = regionRects.ElementAt(i); this.points[i].bounds = new Rectangle( // Snaps the cursor to the center instead of bottom right (default) (int)(mapX + ModMain.LocationToMap(rect.Key).X - rect.Value.Width / 2), (int)(mapY + ModMain.LocationToMap(rect.Key).Y - rect.Value.Height / 2), rect.Value.Width, rect.Value.Height ); } }
// For drawing farm buildings on the map // and getting positions relative to the farm private void UpdateFarmBuildingLocs() { farmBuildings = new Dictionary <string, KeyValuePair <string, Vector2> >(); foreach (Building building in Game1.getFarm().buildings) { if (building == null) { continue; } if (building.nameOfIndoorsWithoutUnique == null || building.nameOfIndoors == null || building.nameOfIndoors.Equals("null")) // Some actually have value of "null" { continue; } Vector2 locVector = LocationToMap( "Farm", // Get building position in farm building.tileX.Value, building.tileY.Value ); // Using buildingType instead of nameOfIndoorsWithoutUnique because it is a better subset of currentLocation.Name // since nameOfIndoorsWithoutUnique for Barn/Coop does not use Big/Deluxe but rather the upgrade level string commonName = building.buildingType.Value ?? building.nameOfIndoorsWithoutUnique; if (commonName.Contains("Barn")) { locVector.Y += 3; } // Format: { uniqueName: { commonName: positionOnFarm } } // buildingType will match currentLocation.Name for commonName farmBuildings[building.nameOfIndoors] = new KeyValuePair <string, Vector2>(building.buildingType.Value, locVector); } // Greenhouse unlocked after pantry bundles completed if (((CommunityCenter)Game1.getLocationFromName("CommunityCenter")).areasComplete[CommunityCenter.AREA_Pantry]) { Vector2 locVector = ModMain.LocationToMap("Greenhouse"); locVector.X -= 5 / 2 * BUILDING_SCALE; locVector.Y -= 7 / 2 * BUILDING_SCALE; farmBuildings["Greenhouse"] = new KeyValuePair <string, Vector2>("Greenhouse", locVector); } }
// Draw event // Subtractions within location vectors are to set the origin to the center of the sprite public void DrawMarkers(SpriteBatch b) { if (Config.ShowFarmBuildings && FarmBuildings != null && BuildingMarkers != null) { var sortedBuildings = FarmBuildings.ToList(); sortedBuildings.Sort((x, y) => x.Value.Value.Y.CompareTo(y.Value.Value.Y)); foreach (KeyValuePair <string, KeyValuePair <string, Vector2> > building in sortedBuildings) { if (ModConstants.FarmBuildingRects.TryGetValue(building.Value.Key, out Rectangle buildingRect)) { if (MapName == "starblue_map") { buildingRect.Y = 7; } else if (MapName == "eemie_recolour_map") { buildingRect.Y = 14; } } b.Draw( BuildingMarkers, new Vector2( mapX + building.Value.Value.X - buildingRect.Width / 2, mapY + building.Value.Value.Y - buildingRect.Height / 2 ), new Rectangle?(buildingRect), Color.White, 0f, Vector2.Zero, 3f, SpriteEffects.None, 1f ); } } // ===== Custom locations ===== if (Config.CustomMapMarkers != null && CustomMarkerTex != null) { foreach (var location in Config.CustomMapMarkers) { if (CustomMapLocations.TryGetValue(location.Key, out var locationVector) && Config.CustomMapMarkers.TryGetValue(location.Key, out var locationRects)) { var fromAreaRect = locationRects.GetValue("FromArea"); var toAreaRect = locationRects.GetValue("ToArea"); var srcRect = new Rectangle(fromAreaRect.Value <int>("X"), fromAreaRect.Value <int>("Y"), fromAreaRect.Value <int>("Width"), fromAreaRect.Value <int>("Height")); b.Draw(CustomMarkerTex, new Vector2(mapX + toAreaRect.Value <int>("X"), mapY + toAreaRect.Value <int>("Y")), srcRect, Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); } } } // Traveling Merchant if (Config.ShowTravelingMerchant && SecondaryNpcs["Merchant"]) { Vector2 merchantLoc = new Vector2(ModConstants.MapVectors["Merchant"][0].MapX, ModConstants.MapVectors["Merchant"][0].MapY); b.Draw(Game1.mouseCursors, new Vector2(mapX + merchantLoc.X - 16, mapY + merchantLoc.Y - 15), new Rectangle?(new Rectangle(191, 1410, 22, 21)), Color.White, 0f, Vector2.Zero, 1.3f, SpriteEffects.None, 1f); } // Farmers if (Context.IsMultiplayer) { foreach (Farmer farmer in Game1.getOnlineFarmers()) { // Temporary solution to handle desync of farmhand location/tile position when changing location if (FarmerMarkers.TryGetValue(farmer.UniqueMultiplayerID, out CharacterMarker farMarker)) { if (farMarker == null || farMarker.MapLocation.X < 0) { continue; } } if (farMarker != null && farMarker.DrawDelay == 0) { farmer.FarmerRenderer.drawMiniPortrat(b, new Vector2(mapX + farMarker.MapLocation.X - 16, mapY + farMarker.MapLocation.Y - 15), 0.00011f, 2f, 1, farmer); } } } else { Vector2 playerLoc = ModMain.LocationToMap(Game1.player.currentLocation.uniqueName.Value ?? Game1.player.currentLocation.Name, Game1.player.getTileX(), Game1.player.getTileY(), CustomMapLocations, true); if (playerLoc.X >= 0) { Game1.player.FarmerRenderer.drawMiniPortrat(b, new Vector2(mapX + playerLoc.X - 16, mapY + playerLoc.Y - 15), 0.00011f, 2f, 1, Game1.player); } } // NPCs // Sort by drawing order if (NpcMarkers != null) { var sortedMarkers = NpcMarkers.ToList(); sortedMarkers.Sort((x, y) => x.Layer.CompareTo(y.Layer)); foreach (CharacterMarker npcMarker in sortedMarkers) { // Skip if no specified location if (npcMarker.MapLocation.X < 0 || npcMarker.Marker == null || !MarkerCropOffsets.ContainsKey(npcMarker.Npc.Name)) { continue; } // Dim marker for hidden markers var markerColor = npcMarker.IsHidden ? Color.DimGray * 0.7f : Color.White; // Draw NPC marker b.Draw(npcMarker.Marker, new Rectangle((int)(mapX + npcMarker.MapLocation.X), (int)(mapY + npcMarker.MapLocation.Y), 32, 30), new Rectangle?(new Rectangle(0, MarkerCropOffsets[npcMarker.Npc.Name], 16, 15)), markerColor); // Draw icons for quests/birthday if (Config.MarkQuests) { if (npcMarker.IsBirthday) { // Gift icon b.Draw(Game1.mouseCursors, new Vector2(mapX + npcMarker.MapLocation.X + 20, mapY + npcMarker.MapLocation.Y), new Rectangle?(new Rectangle(147, 412, 10, 11)), markerColor, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } if (npcMarker.HasQuest) { // Quest icon b.Draw(Game1.mouseCursors, new Vector2(mapX + npcMarker.MapLocation.X + 22, mapY + npcMarker.MapLocation.Y - 3), new Rectangle?(new Rectangle(403, 496, 5, 14)), markerColor, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } } } } }
private void DrawMarkers() { var b = Game1.spriteBatch; var color = Color.White; var offsetMmX = mmX + offset; var offsetMmLoc = new Vector2(mmLoc.X + offset + 2, mmLoc.Y + 2); // // ===== Farm types ===== // // The farms are always overlayed at (0, 43) on the map // The crop position, dimensions, and overlay position must all be adjusted accordingly // When any part of the cropped farm is outside of the minimap as player moves var farmWidth = 131; var farmHeight = 61; var farmX = NormalizeToMap(MathHelper.Clamp(offsetMmLoc.X, offsetMmX, offsetMmX + mmWidth)); var farmY = NormalizeToMap(MathHelper.Clamp(offsetMmLoc.Y + 172, mmY, mmY + mmHeight) + 2); var farmCropX = (int)MathHelper.Clamp((offsetMmX - offsetMmLoc.X) / Game1.pixelZoom, 0, farmWidth); var farmCropY = (int)MathHelper.Clamp((mmY - offsetMmLoc.Y - 172) / Game1.pixelZoom, 0, farmHeight); // Check if farm crop extends outside of minimap var farmCropWidth = (farmX / Game1.pixelZoom + farmWidth > (offsetMmX + mmWidth) / Game1.pixelZoom) ? (int)((offsetMmX + mmWidth - farmX) / Game1.pixelZoom) : farmWidth - farmCropX; var farmCropHeight = (farmY / Game1.pixelZoom + farmHeight > (mmY + mmHeight) / Game1.pixelZoom) ? (int)((mmY + mmHeight - farmY) / Game1.pixelZoom) : farmHeight - farmCropY; // Check if farm crop extends beyond farm size if (farmCropX + farmCropWidth > farmWidth) { farmCropWidth = farmWidth - farmCropX; } if (farmCropY + farmCropHeight > farmHeight) { farmCropHeight = farmHeight - farmCropY; } switch (Game1.whichFarm) { case 1: b.Draw(ModMain.Map, new Vector2(farmX, farmY), new Rectangle(0 + farmCropX, 180 + farmCropY, farmCropWidth, farmCropHeight), color, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 2: b.Draw(ModMain.Map, new Vector2(farmX, farmY), new Rectangle(131 + farmCropX, 180 + farmCropY, farmCropWidth, farmCropHeight), color, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 3: b.Draw(ModMain.Map, new Vector2(farmX, farmY), new Rectangle(0 + farmCropX, 241 + farmCropY, farmCropWidth, farmCropHeight), color, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 4: b.Draw(ModMain.Map, new Vector2(farmX, farmY), new Rectangle(131 + farmCropX, 241 + farmCropY, farmCropWidth, farmCropHeight), color, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; } // // ===== Pam house upgrade ===== // if (drawPamHouseUpgrade) { var houseLoc = ModMain.LocationToMap("Trailer_Big"); if (IsWithinMapArea(houseLoc.X, houseLoc.Y)) { b.Draw(ModMain.Map, new Vector2(NormalizeToMap(offsetMmLoc.X + houseLoc.X - 13), NormalizeToMap(offsetMmLoc.Y + houseLoc.Y - 16)), new Rectangle(263, 181, 8, 8), color, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); } } // // ===== Farm buildings ===== // if (ModMain.Globals.ShowFarmBuildings && FarmBuildings != null && BuildingMarkers != null) { var sortedBuildings = FarmBuildings.ToList(); sortedBuildings.Sort((x, y) => x.Value.Value.Y.CompareTo(y.Value.Value.Y)); foreach (var building in sortedBuildings) { if (ModConstants.FarmBuildingRects.TryGetValue(building.Value.Key, out var buildingRect)) { if (IsWithinMapArea(building.Value.Value.X - buildingRect.Width / 2, building.Value.Value.Y - buildingRect.Height / 2)) { // if (Customizations.MapName == "starblue_map") // buildingRect.Y = 7; // else if (Customizations.MapName == "eemie_recolour_map") // buildingRect.Y = 14; b.Draw( BuildingMarkers, new Vector2( NormalizeToMap(offsetMmLoc.X + building.Value.Value.X - (float)Math.Floor(buildingRect.Width / 2.0)), NormalizeToMap(offsetMmLoc.Y + building.Value.Value.Y - (float)Math.Floor(buildingRect.Height / 2.0)) ), buildingRect, color, 0f, Vector2.Zero, 3f, SpriteEffects.None, 1f ); } } } } // // ===== Traveling Merchant ===== // if (ModMain.Config.ShowTravelingMerchant && ConditionalNpcs["Merchant"]) { Vector2 merchantLoc = new Vector2(ModConstants.MapVectors["Merchant"][0].MapX, ModConstants.MapVectors["Merchant"][0].MapY); if (IsWithinMapArea(merchantLoc.X - 16, merchantLoc.Y - 16)) { b.Draw(Game1.mouseCursors, new Vector2(NormalizeToMap(offsetMmLoc.X + merchantLoc.X - 16), NormalizeToMap(offsetMmLoc.Y + merchantLoc.Y - 15)), new Rectangle(191, 1410, 22, 21), Color.White, 0f, Vector2.Zero, 1.3f, SpriteEffects.None, 1f); } } if (Context.IsMultiplayer) { foreach (var farmer in Game1.getOnlineFarmers()) { // Temporary solution to handle desync of farmhand location/tile position when changing location if (FarmerMarkers.TryGetValue(farmer.UniqueMultiplayerID, out var farMarker)) { if (farMarker.MapLocation.Equals(Vector2.Zero)) { continue; } if (farMarker.DrawDelay == 0 && IsWithinMapArea(farMarker.MapLocation.X - 16, farMarker.MapLocation.Y - 15)) { farmer.FarmerRenderer.drawMiniPortrat(b, new Vector2(NormalizeToMap(offsetMmLoc.X + farMarker.MapLocation.X - 16), NormalizeToMap(offsetMmLoc.Y + farMarker.MapLocation.Y - 15)), 0.00011f, 2f, 1, farmer); } } } } else { if (!playerLoc.Equals(Vector2.Zero)) { Game1.player.FarmerRenderer.drawMiniPortrat(b, new Vector2(NormalizeToMap(offsetMmLoc.X + playerLoc.X - 16), NormalizeToMap(offsetMmLoc.Y + playerLoc.Y - 15)), 0.00011f, 2f, 1, Game1.player); } } // // ===== NPCs ===== // // Sort by drawing order if (NpcMarkers != null) { var sortedMarkers = NpcMarkers.ToList(); sortedMarkers.Sort((x, y) => x.Layer.CompareTo(y.Layer)); foreach (var npcMarker in sortedMarkers) { // Skip if no specified location if (npcMarker.MapLocation.Equals(Vector2.Zero) || npcMarker.Marker == null || !Customizations.NpcMarkerOffsets.ContainsKey(npcMarker.Npc.Name) || !IsWithinMapArea(npcMarker.MapLocation.X, npcMarker.MapLocation.Y)) { continue; } var markerColor = npcMarker.IsHidden ? Color.DimGray * 0.7f : Color.White; // Draw NPC marker b.Draw(npcMarker.Marker, new Rectangle(NormalizeToMap(offsetMmLoc.X + npcMarker.MapLocation.X), NormalizeToMap(offsetMmLoc.Y + npcMarker.MapLocation.Y), 30, 32), new Rectangle(0, Customizations.NpcMarkerOffsets[npcMarker.Npc.Name], 16, 15), markerColor); // Icons for birthday/quest if (ModMain.Config.MarkQuests) { if (npcMarker.IsBirthday) { b.Draw(Game1.mouseCursors, new Vector2(NormalizeToMap(offsetMmLoc.X + npcMarker.MapLocation.X + 20), NormalizeToMap(offsetMmLoc.Y + npcMarker.MapLocation.Y)), new Rectangle(147, 412, 10, 11), markerColor, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } if (npcMarker.HasQuest) { b.Draw(Game1.mouseCursors, new Vector2(NormalizeToMap(offsetMmLoc.X + npcMarker.MapLocation.X + 22), NormalizeToMap(offsetMmLoc.Y + npcMarker.MapLocation.Y - 3)), new Rectangle(403, 496, 5, 14), markerColor, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } } } } }
public void Update() { // Note: Absolute positions relative to viewport are scaled 4x (Game1.pixelZoom). // Positions relative to the map are not. center = ModMain.LocationToMap(Game1.player.currentLocation.uniqueName.Value ?? Game1.player.currentLocation.Name, Game1.player.getTileX(), Game1.player.getTileY(), Customizations.MapVectors, true); // Player in unknown location, use previous location as center if (center.Equals(Vector2.Zero) && prevCenter != null) { center = prevCenter; } else { prevCenter = center; } playerLoc = prevCenter; center.X = NormalizeToMap(center.X); center.Y = NormalizeToMap(center.Y); // Top-left offset for markers, relative to the minimap mmLoc = new Vector2(mmX - center.X + (float)Math.Floor(mmWidth / 2.0), mmY - center.Y + (float)Math.Floor(mmHeight / 2.0)); // Top-left corner of minimap cropped from the whole map // Centered around the player's location on the map cropX = center.X - (float)Math.Floor(mmWidth / 2.0); cropY = center.Y - (float)Math.Floor(mmHeight / 2.0); // Handle cases when reaching edge of map // Change offsets accordingly when player is no longer centered if (cropX < 0) { center.X = mmWidth / 2; mmLoc.X = mmX; cropX = 0; } else if (cropX + mmWidth > 1200) { center.X = 1200 - mmWidth / 2; mmLoc.X = mmX - (1200 - mmWidth); cropX = 1200 - mmWidth; } if (cropY < 0) { center.Y = mmHeight / 2; mmLoc.Y = mmY; cropY = 0; } // Actual map is 1200x720 but map.Height includes the farms else if (cropY + mmHeight > 720) { center.Y = 720 - mmHeight / 2; mmLoc.Y = mmY - (720 - mmHeight); cropY = 720 - mmHeight; } }
// Map menu that uses modified map page and modified component locations for hover public ModMapPage( HashSet <CharacterMarker> npcMarkers, Dictionary <string, bool> conditionalNpcs, Dictionary <long, CharacterMarker> farmerMarkers, Dictionary <string, KeyValuePair <string, Vector2> > farmBuildings, Texture2D buildingMarkers, ModCustomizations customizations ) : base(Game1.viewport.Width / 2 - (800 + IClickableMenu.borderWidth * 2) / 2, Game1.viewport.Height / 2 - (600 + IClickableMenu.borderWidth * 2) / 2, 800 + IClickableMenu.borderWidth * 2, 600 + IClickableMenu.borderWidth * 2) { this.NpcMarkers = npcMarkers; this.ConditionalNpcs = conditionalNpcs; this.FarmerMarkers = farmerMarkers; this.FarmBuildings = farmBuildings; this.BuildingMarkers = buildingMarkers; this.Customizations = customizations; map = Game1.content.Load <Texture2D>("LooseSprites\\map"); drawPamHouseUpgrade = Game1.MasterPlayer.mailReceived.Contains("pamHouseUpgrade"); Vector2 center = Utility.getTopLeftPositionForCenteringOnScreen(map.Bounds.Width * 4, 720, 0, 0); mapX = (int)center.X; mapY = (int)center.Y; var regionRects = RegionRects().ToList(); var customTooltips = Customizations.Tooltips.ToList(); for (int i = 0; i < regionRects.Count; i++) { var rect = regionRects.ElementAtOrDefault(i); this.points[i].bounds = new Rectangle( // Snaps the cursor to the center instead of bottom right (default) (int)(mapX + ModMain.LocationToMap(rect.Key).X - rect.Value.Width / 2), (int)(mapY + ModMain.LocationToMap(rect.Key).Y - rect.Value.Height / 2), rect.Value.Width, rect.Value.Height ); if (ModMain.IsSVE) { // Adventure's Guild is in a different location in SVE if (this.points[i].myID == 1025) { this.points[i].bounds = new Rectangle(mapX + 682, mapY + 451, 22, 30); } // Remove sewer which gets replaced by Adventure Guild else if (this.points[i].myID == 1018) { this.points[i].bounds.Width = 0; this.points[i].bounds.Height = 0; } // So it doesn't cover up the other new points in the railroad else if (this.points[i].myID == 1034) { this.points[i].bounds.Width /= 2; } } } int idx = 0; // Add custom tooltips for (int i = regionRects.Count; i < regionRects.Count + customTooltips.Count; i++) { var tooltip = customTooltips.ElementAtOrDefault(idx); if (tooltip == null) { break; } var point = new ClickableComponent(new Rectangle( tooltip.bounds.X + mapX, tooltip.bounds.Y + mapY, tooltip.bounds.Width, tooltip.bounds.Height ), tooltip.name); if (this.points.Count <= i) { this.points.Add(point); } else { this.points[i] = point; } idx++; } }
// Draw event // Subtractions within location vectors are to set the origin to the center of the sprite public void DrawMarkers(SpriteBatch b) { if (Config.ShowFarmBuildings && FarmBuildings != null) { var sortedBuildings = ModMain.FarmBuildings.ToList(); sortedBuildings.Sort((x, y) => x.Value.Value.Y.CompareTo(y.Value.Value.Y)); foreach (KeyValuePair <string, KeyValuePair <string, Vector2> > building in sortedBuildings) { if (ModConstants.FarmBuildingRects.TryGetValue(building.Value.Key, out Rectangle buildingRect)) { b.Draw(BuildingMarkers, new Vector2(building.Value.Value.X - buildingRect.Width / 2, building.Value.Value.Y - buildingRect.Height / 2), new Rectangle?(buildingRect), Color.White, 0f, Vector2.Zero, 3f, SpriteEffects.None, 1f); } } } // Traveling Merchant if (Config.ShowTravelingMerchant && SecondaryNpcs["Merchant"]) { Vector2 merchantLoc = ModMain.LocationToMap("Forest", 28, 11); b.Draw(Game1.mouseCursors, new Vector2(merchantLoc.X - 16, merchantLoc.Y - 15), new Rectangle?(new Rectangle(191, 1410, 22, 21)), Color.White, 0f, Vector2.Zero, 1.3f, SpriteEffects.None, 1f); } // Farmers if (Context.IsMultiplayer) { foreach (Farmer farmer in Game1.getOnlineFarmers()) { // Temporary solution to handle desync of farmhand location/tile position when changing location if (FarmerMarkers.TryGetValue(farmer.UniqueMultiplayerID, out FarmerMarker farMarker)) { if (farMarker.DrawDelay == 0) { farmer.FarmerRenderer.drawMiniPortrat(b, new Vector2(farMarker.Location.X - 16, farMarker.Location.Y - 15), 0.00011f, 2f, 1, farmer); } } } } else { Vector2 playerLoc = ModMain.GetMapPosition(Game1.player.currentLocation, Game1.player.getTileX(), Game1.player.getTileY()); Game1.player.FarmerRenderer.drawMiniPortrat(b, new Vector2(playerLoc.X - 16, playerLoc.Y - 15), 0.00011f, 2f, 1, Game1.player); } // NPCs // Sort by drawing order var sortedMarkers = NpcMarkers.ToList(); sortedMarkers.Sort((x, y) => x.Layer.CompareTo(y.Layer)); foreach (NpcMarker npcMarker in sortedMarkers) { // Skip if no specified location if (npcMarker.Location == Rectangle.Empty || npcMarker.Marker == null || !MarkerCrop.ContainsKey(npcMarker.Npc.Name)) { continue; } // Tint/dim hidden markers if (npcMarker.IsHidden) { b.Draw(npcMarker.Marker, npcMarker.Location, new Rectangle?(new Rectangle(0, MarkerCrop[npcMarker.Npc.Name], 16, 15)), Color.DimGray * 0.7f); if (npcMarker.IsBirthday) { // Gift icon b.Draw(Game1.mouseCursors, new Vector2(npcMarker.Location.X + 20, npcMarker.Location.Y), new Rectangle?(new Rectangle(147, 412, 10, 11)), Color.DimGray * 0.7f, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } if (npcMarker.HasQuest) { // Quest icon b.Draw(Game1.mouseCursors, new Vector2(npcMarker.Location.X + 22, npcMarker.Location.Y - 3), new Rectangle?(new Rectangle(403, 496, 5, 14)), Color.DimGray * 0.7f, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } } else { b.Draw(npcMarker.Marker, npcMarker.Location, new Rectangle?(new Rectangle(0, MarkerCrop[npcMarker.Npc.Name], 16, 15)), Color.White); if (npcMarker.IsBirthday) { // Gift icon b.Draw(Game1.mouseCursors, new Vector2(npcMarker.Location.X + 20, npcMarker.Location.Y), new Rectangle?(new Rectangle(147, 412, 10, 11)), Color.White, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } if (npcMarker.HasQuest) { // Quest icon b.Draw(Game1.mouseCursors, new Vector2(npcMarker.Location.X + 22, npcMarker.Location.Y - 3), new Rectangle?(new Rectangle(403, 496, 5, 14)), Color.White, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } } } }
// Map menu that uses modified map page and modified component locations for hover public ModMapPage( Dictionary <string, NpcMarker> npcMarkers, Dictionary <string, bool> conditionalNpcs, Dictionary <long, FarmerMarker> farmerMarkers, Dictionary <string, KeyValuePair <string, Vector2> > farmBuildings, Texture2D buildingMarkers, ModCustomizations customizations ) : base(Game1.viewport.Width / 2 - (800 + IClickableMenu.borderWidth * 2) / 2, Game1.viewport.Height / 2 - (600 + IClickableMenu.borderWidth * 2) / 2, 800 + IClickableMenu.borderWidth * 2, 600 + IClickableMenu.borderWidth * 2) { this.NpcMarkers = npcMarkers; this.ConditionalNpcs = conditionalNpcs; this.FarmerMarkers = farmerMarkers; this.FarmBuildings = farmBuildings; this.BuildingMarkers = buildingMarkers; this.Customizations = customizations; Vector2 center = Utility.getTopLeftPositionForCenteringOnScreen(ModMain.Map.Bounds.Width * 4, 720); drawPamHouseUpgrade = Game1.MasterPlayer.mailReceived.Contains("pamHouseUpgrade"); drawMovieTheaterJoja = Utility.doesMasterPlayerHaveMailReceivedButNotMailForTomorrow("ccMovieTheaterJoja"); drawMovieTheater = Utility.doesMasterPlayerHaveMailReceivedButNotMailForTomorrow("ccMovieTheater"); mapX = (int)center.X; mapY = (int)center.Y; var regionRects = RegionRects().ToList(); for (int i = 0; i < regionRects.Count; i++) { var rect = regionRects.ElementAtOrDefault(i); var locationName = rect.Key; // Special cases where the name is not an ingame location switch (locationName) { case "Spa": locationName = "BathHouse_Entry"; break; case "SewerPipe": locationName = "Sewer"; break; default: break; } var locVector = ModMain.LocationToMap(locationName); this.points[i].bounds = new Rectangle( // Snaps the cursor to the center instead of bottom right (default) (int)(mapX + locVector.X - rect.Value.Width / 2), (int)(mapY + locVector.Y - rect.Value.Height / 2), rect.Value.Width, rect.Value.Height ); } var customTooltips = Customizations.Tooltips.ToList(); foreach (var tooltip in customTooltips) { var vanillaTooltip = this.points.Find(x => x.name == tooltip.name); var customTooltip = new ClickableComponent(new Rectangle( mapX + tooltip.bounds.X, mapY + tooltip.bounds.Y, tooltip.bounds.Width, tooltip.bounds.Height ), tooltip.name); // Replace vanilla with custom if (vanillaTooltip != null) { vanillaTooltip = customTooltip; } else // If new custom location, add it { this.points.Add(customTooltip); } } // If two tooltip areas overlap, the one earlier in the list takes precendence // Reversing order allows custom tooltips to take precendence this.points.Reverse(); }
// Draw event // Subtractions within location vectors are to set the origin to the center of the sprite public void DrawMarkers(SpriteBatch b) { if (ModMain.Globals.ShowFarmBuildings && FarmBuildings != null && BuildingMarkers != null) { var sortedBuildings = FarmBuildings.ToList(); sortedBuildings.Sort((x, y) => x.Value.Value.Y.CompareTo(y.Value.Value.Y)); foreach (KeyValuePair <string, KeyValuePair <string, Vector2> > building in sortedBuildings) { if (ModConstants.FarmBuildingRects.TryGetValue(building.Value.Key, out Rectangle buildingRect)) { b.Draw( BuildingMarkers, new Vector2( mapX + building.Value.Value.X - buildingRect.Width / 2, mapY + building.Value.Value.Y - buildingRect.Height / 2 ), new Rectangle?(buildingRect), Color.White, 0f, Vector2.Zero, 3f, SpriteEffects.None, 1f ); } } } // Traveling Merchant if (ModMain.Config.ShowTravelingMerchant && ConditionalNpcs["Merchant"]) { Vector2 merchantLoc = new Vector2(ModConstants.MapVectors["Merchant"][0].MapX, ModConstants.MapVectors["Merchant"][0].MapY); b.Draw(Game1.mouseCursors, new Vector2(mapX + merchantLoc.X - 16, mapY + merchantLoc.Y - 15), new Rectangle?(new Rectangle(191, 1410, 22, 21)), Color.White, 0f, Vector2.Zero, 1.3f, SpriteEffects.None, 1f); } // NPCs // Sort by drawing order if (NpcMarkers != null) { var sortedMarkers = NpcMarkers.ToList(); sortedMarkers.Sort((x, y) => x.Value.Layer.CompareTo(y.Value.Layer)); foreach (var npcMarker in sortedMarkers) { var name = npcMarker.Key; var marker = npcMarker.Value; // Skip if no specified location or should be hidden if (marker.Sprite == null || ModMain.Globals.NpcBlacklist.Contains(name) || (!ModMain.Config.ShowHiddenVillagers && marker.IsHidden) || (ConditionalNpcs.ContainsKey(name) && !ConditionalNpcs[name]) ) { continue; } // Dim marker for hidden markers var markerColor = marker.IsHidden ? Color.DarkGray * 0.7f : Color.White; // Draw NPC marker var spriteRect = marker.Type == Character.Horse ? new Rectangle(17, 104, 16, 14) : new Rectangle(0, marker.CropOffset, 16, 15); b.Draw(marker.Sprite, new Rectangle((int)(mapX + marker.MapX), (int)(mapY + marker.MapY), 32, 30), new Rectangle?(spriteRect), markerColor); // Draw icons for quests/birthday if (ModMain.Config.MarkQuests) { if (marker.IsBirthday && (Game1.player.friendshipData.ContainsKey(name) && Game1.player.friendshipData[name].GiftsToday == 0)) { // Gift icon b.Draw(Game1.mouseCursors, new Vector2(mapX + marker.MapX + 20, mapY + marker.MapY), new Rectangle?(new Rectangle(147, 412, 10, 11)), markerColor, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } if (marker.HasQuest) { // Quest icon b.Draw(Game1.mouseCursors, new Vector2(mapX + marker.MapX + 22, mapY + marker.MapY - 3), new Rectangle?(new Rectangle(403, 496, 5, 14)), markerColor, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } } } } // Farmers if (Context.IsMultiplayer) { foreach (Farmer farmer in Game1.getOnlineFarmers()) { // Temporary solution to handle desync of farmhand location/tile position when changing location if (FarmerMarkers.TryGetValue(farmer.UniqueMultiplayerID, out FarmerMarker farMarker)) { if (farMarker == null) { continue; } } if (farMarker != null && farMarker.DrawDelay == 0) { farmer.FarmerRenderer.drawMiniPortrat(b, new Vector2(mapX + farMarker.MapX - 16, mapY + farMarker.MapY - 15), 0.00011f, 2f, 1, farmer); } } } else { Vector2 playerLoc = ModMain.LocationToMap(Game1.player.currentLocation.uniqueName.Value ?? Game1.player.currentLocation.Name, Game1.player.getTileX(), Game1.player.getTileY(), Customizations.MapVectors, Customizations.LocationBlacklist, true); Game1.player.FarmerRenderer.drawMiniPortrat(b, new Vector2(mapX + playerLoc.X - 16, mapY + playerLoc.Y - 15), 0.00011f, 2f, 1, Game1.player); } }
// Draw map to cover base rendering public void DrawMap(SpriteBatch b) { int boxY = mapY - 96; int mY = mapY; Game1.drawDialogueBox(mapX - 32, boxY, (ModMain.Map.Bounds.Width + 16) * 4, 848, false, true, null, false); b.Draw(ModMain.Map, new Vector2((float)mapX, (float)mY), new Rectangle(0, 0, 300, 180), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.86f); float scroll_draw_y = yPositionOnScreen + height + 32 + 16; float scroll_draw_bottom = scroll_draw_y + 80f; if (scroll_draw_bottom > (float)Game1.viewport.Height) { scroll_draw_y -= scroll_draw_bottom - (float)Game1.viewport.Height; } Game1.drawDialogueBox(mapX - 32, boxY, (ModMain.Map.Bounds.Width + 16) * 4, 848, speaker: false, drawOnlyBox: true); b.Draw(ModMain.Map, new Vector2(mapX, mY), new Rectangle(0, 0, 300, 180), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.86f); switch (Game1.whichFarm) { case 1: b.Draw(ModMain.Map, new Vector2(mapX, mY + 172), new Rectangle(0, 180, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 2: b.Draw(ModMain.Map, new Vector2(mapX, mY + 172), new Rectangle(131, 180, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 3: b.Draw(ModMain.Map, new Vector2(mapX, mY + 172), new Rectangle(0, 241, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 4: b.Draw(ModMain.Map, new Vector2(mapX, mY + 172), new Rectangle(131, 241, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 5: b.Draw(ModMain.Map, new Vector2(mapX, mY + 172), new Rectangle(0, 302, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; } if (drawPamHouseUpgrade) { var houseLoc = ModMain.LocationToMap("Trailer_Big"); b.Draw(ModMain.Map, new Vector2(mapX + houseLoc.X - 16, mapY + houseLoc.Y - 11), new Rectangle(263, 181, 8, 8), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); } if (drawMovieTheater || drawMovieTheaterJoja) { var theaterLoc = ModMain.LocationToMap("JojaMart"); b.Draw(ModMain.Map, new Vector2(mapX + theaterLoc.X - 20, mapY + theaterLoc.Y - 11), new Rectangle(275, 181, 15, 11), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); } var playerLocationName = getPlayerLocationNameForMap(); if (playerLocationName != null) { SpriteText.drawStringWithScrollCenteredAt(b, playerLocationName, base.xPositionOnScreen + base.width / 2, base.yPositionOnScreen + base.height + 32 + 16, "", 1f, -1, 0, 0.88f, false); } }
// Draw map to cover base rendering public void DrawMap(SpriteBatch b) { int boxY = mapY - 96; int mY = mapY; Game1.drawDialogueBox(mapX - 32, boxY, (ModMain.Map.Bounds.Width + 16) * 4, 848, false, true, null, false); b.Draw(ModMain.Map, new Vector2((float)mapX, (float)mY), new Rectangle(0, 0, 300, 180), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.86f); switch (Game1.whichFarm) { case 1: b.Draw(ModMain.Map, new Vector2((float)mapX, (float)(mY + 172)), new Rectangle(0, 180, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 2: b.Draw(ModMain.Map, new Vector2((float)mapX, (float)(mY + 172)), new Rectangle(131, 180, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 3: b.Draw(ModMain.Map, new Vector2((float)mapX, (float)(mY + 172)), new Rectangle(0, 241, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; case 4: b.Draw(ModMain.Map, new Vector2((float)mapX, (float)(mY + 172)), new Rectangle(131, 241, 131, 61), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); break; } if (drawPamHouseUpgrade) { var houseLoc = ModMain.LocationToMap("Trailer_Big"); b.Draw(ModMain.Map, new Vector2((float)(mapX + houseLoc.X - 13), (float)(mapY + houseLoc.Y - 16)), new Rectangle(263, 181, 8, 8), Color.White, 0f, Vector2.Zero, 4f, SpriteEffects.None, 0.861f); } var player = Game1.player; int x = player.getTileX(); int y = player.getTileY(); string playerLocationName = null; switch (player.currentLocation.Name) { case "Saloon": playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11172"); break; case "Beach": playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11174"); break; case "Mountain": if (x < 38) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11176"); } else if (x < 96) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11177"); } else { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11178"); } break; case "Tunnel": case "Backwoods": playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11180"); break; case "FarmHouse": case "Barn": case "Big Barn": case "Deluxe Barn": case "Coop": case "Big Coop": case "Deluxe Coop": case "Cabin": case "Slime Hutch": case "Greenhouse": case "FarmCave": case "Shed": case "Farm": playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11064", player.farmName.Value); break; case "Forest": if (y > 51) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11186"); } else if (x < 58) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11186"); } else { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11188"); } break; case "Town": if (x > 84 && y < 68) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } else if (x > 80 && y >= 68) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } else if (y <= 42) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } else if (y > 42 && y < 76) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } else { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } break; case "Temp": if (player.currentLocation.Map.Id.Contains("Town")) { if (x > 84 && y < 68) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } else if (x > 80 && y >= 68) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } else if (y <= 42) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } else if (y > 42 && y < 76) { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } else { playerLocationName = Game1.content.LoadString("Strings\\StringsFromCSFiles:MapPage.cs.11190"); } } break; } if (playerLocationName != null) { SpriteText.drawStringWithScrollCenteredAt(b, playerLocationName, base.xPositionOnScreen + base.width / 2, base.yPositionOnScreen + base.height + 32 + 16, "", 1f, -1, 0, 0.88f, false); } }
// Draw event // Subtractions within location vectors are to set the origin to the center of the sprite public void DrawMarkers(SpriteBatch b) { if (ModMain.Globals.ShowFarmBuildings && FarmBuildings != null && BuildingMarkers != null) { var sortedBuildings = FarmBuildings.ToList(); sortedBuildings.Sort((x, y) => x.Value.Value.Y.CompareTo(y.Value.Value.Y)); foreach (KeyValuePair <string, KeyValuePair <string, Vector2> > building in sortedBuildings) { if (ModConstants.FarmBuildingRects.TryGetValue(building.Value.Key, out Rectangle buildingRect)) { // if (Customizations.MapName == "starblue_map") // buildingRect.Y = 7; // else if (Customizations.MapName == "eemie_recolour_map") // buildingRect.Y = 14; b.Draw( BuildingMarkers, new Vector2( mapX + building.Value.Value.X - buildingRect.Width / 2, mapY + building.Value.Value.Y - buildingRect.Height / 2 ), new Rectangle?(buildingRect), Color.White, 0f, Vector2.Zero, 3f, SpriteEffects.None, 1f ); } } } // Traveling Merchant if (ModMain.Config.ShowTravelingMerchant && ConditionalNpcs["Merchant"]) { Vector2 merchantLoc = new Vector2(ModConstants.MapVectors["Merchant"][0].MapX, ModConstants.MapVectors["Merchant"][0].MapY); b.Draw(Game1.mouseCursors, new Vector2(mapX + merchantLoc.X - 16, mapY + merchantLoc.Y - 15), new Rectangle?(new Rectangle(191, 1410, 22, 21)), Color.White, 0f, Vector2.Zero, 1.3f, SpriteEffects.None, 1f); } // NPCs // Sort by drawing order if (NpcMarkers != null) { var sortedMarkers = NpcMarkers.ToList(); sortedMarkers.Sort((x, y) => x.Layer.CompareTo(y.Layer)); foreach (CharacterMarker npcMarker in sortedMarkers) { // Skip if no specified location if (npcMarker.MapLocation.Equals(Vector2.Zero) || npcMarker.Marker == null) { continue; } // Dim marker for hidden markers var markerColor = npcMarker.IsHidden ? Color.DimGray * 0.7f : Color.White; var offset = 1; Customizations.NpcMarkerOffsets.TryGetValue(npcMarker.Npc.Name, out offset); // Draw NPC marker var spriteRect = npcMarker.Npc is Horse ? new Rectangle(17, 104, 16, 14) : new Rectangle(0, offset, 16, 15); b.Draw(npcMarker.Marker, new Rectangle((int)(mapX + npcMarker.MapLocation.X), (int)(mapY + npcMarker.MapLocation.Y), 32, 30), new Rectangle?(spriteRect), markerColor); // Draw icons for quests/birthday if (ModMain.Config.MarkQuests) { if (npcMarker.IsBirthday) { // Gift icon b.Draw(Game1.mouseCursors, new Vector2(mapX + npcMarker.MapLocation.X + 20, mapY + npcMarker.MapLocation.Y), new Rectangle?(new Rectangle(147, 412, 10, 11)), markerColor, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } if (npcMarker.HasQuest) { // Quest icon b.Draw(Game1.mouseCursors, new Vector2(mapX + npcMarker.MapLocation.X + 22, mapY + npcMarker.MapLocation.Y - 3), new Rectangle?(new Rectangle(403, 496, 5, 14)), markerColor, 0f, Vector2.Zero, 1.8f, SpriteEffects.None, 0f); } } } } // Farmers if (Context.IsMultiplayer) { foreach (Farmer farmer in Game1.getOnlineFarmers()) { // Temporary solution to handle desync of farmhand location/tile position when changing location if (FarmerMarkers.TryGetValue(farmer.UniqueMultiplayerID, out CharacterMarker farMarker)) { if (farMarker == null || farMarker.MapLocation.Equals(Vector2.Zero)) { continue; } } if (farMarker != null && farMarker.DrawDelay == 0) { farmer.FarmerRenderer.drawMiniPortrat(b, new Vector2(mapX + farMarker.MapLocation.X - 16, mapY + farMarker.MapLocation.Y - 15), 0.00011f, 2f, 1, farmer); } } } else { Vector2 playerLoc = ModMain.LocationToMap(Game1.player.currentLocation.uniqueName.Value ?? Game1.player.currentLocation.Name, Game1.player.getTileX(), Game1.player.getTileY(), Customizations.MapVectors, true); if (!playerLoc.Equals(Vector2.Zero)) { Game1.player.FarmerRenderer.drawMiniPortrat(b, new Vector2(mapX + playerLoc.X - 16, mapY + playerLoc.Y - 15), 0.00011f, 2f, 1, Game1.player); } } }