예제 #1
0
        private void UpdateLocators()
        {
            this.Locators = new Dictionary <string, List <Locator> >();

            foreach (var character in this.Characters)
            {
                if (character.currentLocation == null)
                {
                    continue;
                }
                if (!this.Config.ShowHorses && character is Horse || this.Config.ShowFarmersOnly && (character is NPC && !(character is Horse)))
                {
                    continue;
                }
                if (!this.SyncedLocationData.Locations.TryGetValue(character.Name, out var npcLoc) && character is NPC)
                {
                    continue;
                }
                if (character is NPC npc && this.Config.ShowQuestsAndBirthdaysOnly)
                {
                    bool isBirthday = false;
                    bool hasQuest   = false;
                    // Check if gifted for birthday
                    if (npc.isBirthday(Game1.currentSeason, Game1.dayOfMonth))
                    {
                        isBirthday = Game1.player.friendshipData.ContainsKey(npc.Name) && Game1.player.friendshipData[npc.Name].GiftsToday == 0;
                    }

                    // Check for daily quests
                    foreach (var quest in Game1.player.questLog)
                    {
                        if (quest.accepted.Value && quest.dailyQuest.Value && !quest.completed.Value)
                        {
                            hasQuest = quest.questType.Value switch
                            {
                                3 => ((ItemDeliveryQuest)quest).target.Value == npc.Name,
                                4 => ((SlayMonsterQuest)quest).target.Value == npc.Name,
                                7 => ((FishingQuest)quest).target.Value == npc.Name,
                                10 => ((ResourceCollectionQuest)quest).target.Value == npc.Name,
                                _ => hasQuest
                            }
                        }
                        ;
                    }

                    if (!isBirthday && !hasQuest)
                    {
                        continue;
                    }
                }

                string playerLocName = Game1.player.currentLocation.uniqueName.Value ?? Game1.player.currentLocation.Name;
                string charLocName   = character is Farmer
                  ? character.currentLocation.uniqueName.Value ?? character.currentLocation.Name
                  : npcLoc.LocationName;
                bool isPlayerLocOutdoors = Game1.player.currentLocation.IsOutdoors;

                LocationContext playerLocCtx;
                LocationContext characterLocCtx;

                // Manually handle mines
                {
                    string charMineName   = this.LocationUtil.GetLocationNameFromLevel(charLocName);
                    string playerMineName = this.LocationUtil.GetLocationNameFromLevel(playerLocName);

                    if (isPlayerLocOutdoors)
                    {
                        // If inside a generated level, show characters as inside same general mine to player outside
                        charLocName = charMineName ?? charLocName;
                    }

                    if (playerMineName != null && charMineName != null)
                    {
                        // Leave mine levels distinguished in name if player inside mine
                        playerLocCtx    = this.LocationUtil.TryGetContext(playerMineName, mapGeneratedLevels: false);
                        characterLocCtx = this.LocationUtil.TryGetContext(charMineName, mapGeneratedLevels: false);
                    }
                    else
                    {
                        if (!this.LocationUtil.TryGetContext(playerLocName, out playerLocCtx))
                        {
                            continue;
                        }
                        if (!this.LocationUtil.TryGetContext(charLocName, out characterLocCtx))
                        {
                            continue;
                        }
                    }
                }

                if (this.Config.SameLocationOnly && characterLocCtx.Root != playerLocCtx.Root)
                {
                    continue;
                }

                var characterPos = Vector2.Zero;
                var playerPos    =
                    new Vector2(Game1.player.position.X + Game1.player.FarmerSprite.SpriteWidth / 2 * Game1.pixelZoom,
                                Game1.player.position.Y);
                bool isWarp     = false;
                bool isOutdoors = false;
                bool isHorse    = character is Horse;

                Vector2 charPosition;
                int     charSpriteHeight;

                if (character is Farmer farmer)
                {
                    charPosition     = character.Position;
                    charSpriteHeight = farmer.FarmerSprite.SpriteHeight;
                }
                else
                {
                    charPosition     = new Vector2(npcLoc.X, npcLoc.Y);
                    charSpriteHeight = character.Sprite.SpriteHeight;
                }

                // Player and character in same location
                if (playerLocName == charLocName)
                {
                    // Don't include locator if character is visible on screen
                    if (Utility.isOnScreen(charPosition, Game1.tileSize / 4))
                    {
                        continue;
                    }

                    characterPos = new Vector2(charPosition.X + charSpriteHeight / 2 * Game1.pixelZoom, charPosition.Y);
                }
                else
                {
                    // Indoor locations
                    // Intended behavior is for all characters in a building, including rooms within the building
                    // to show up when the player is outside. So even if an character is not in the same location
                    // ex. Maru in ScienceHouse, Sebastian in SebastianRoom, Sebastian will be placed in
                    // ScienceHouse such that the player will know Sebastian is in that building.
                    // Once the player is actually inside, Sebastian will be correctly placed in SebastianRoom.

                    // Finds the upper-most indoor location that the player is in
                    isWarp = true;
                    string indoor = this.LocationUtil.GetBuilding(charLocName, curRecursionDepth: 1);
                    if (this.Config.SameLocationOnly)
                    {
                        if (indoor == null)
                        {
                            continue;
                        }
                        if (playerLocName != characterLocCtx.Root && playerLocName != indoor)
                        {
                            continue;
                        }
                    }
                    charLocName = isPlayerLocOutdoors || characterLocCtx.Type != LocationType.Room
                        ? indoor
                        : charLocName;

                    // Neighboring outdoor warps
                    if (!isPlayerLocOutdoors)
                    {
                        if (characterLocCtx.Root != playerLocCtx.Root || characterLocCtx.Parent == null)
                        {
                            continue;
                        }

                        // Doors that lead to connected rooms to character
                        if (characterLocCtx.Parent == playerLocName)
                        {
                            characterPos = characterLocCtx.GetWarpPixelPosition();
                        }
                        else
                        {
                            LocationContext characterParentContext = this.LocationUtil.TryGetContext(characterLocCtx.Parent);
                            characterPos = characterParentContext.GetWarpPixelPosition();
                        }
                    }
                    else
                    {
                        if (characterLocCtx.Root == playerLocCtx.Root)
                        {
                            // Point locators to the neighboring outdoor warps and
                            // doors of buildings including nested rooms
                            LocationContext indoorContext = this.LocationUtil.TryGetContext(indoor);
                            characterPos = indoorContext.GetWarpPixelPosition();
                        }
                        else if (!this.Config.SameLocationOnly)
                        {
                            // Warps to other outdoor locations
                            isOutdoors = true;
                            if ((characterLocCtx.Root != null && playerLocCtx.Neighbors.TryGetValue(characterLocCtx.Root, out Vector2 warpPos)) || charLocName != null && playerLocCtx.Neighbors.TryGetValue(charLocName, out warpPos))
                            {
                                charLocName  = characterLocCtx.Root;
                                characterPos = LocationContext.GetWarpPixelPosition(warpPos);
                            }
                            else
                            {
                                continue;
                            }
                        }
                    }

                    // Add character to the list of locators inside a building
                    if (!this.ActiveWarpLocators.ContainsKey(charLocName))
                    {
                        this.ActiveWarpLocators.Add(charLocName, new LocatorScroller()
                        {
                            Location   = charLocName,
                            Characters = new HashSet <string>()
                            {
                                character.Name
                            },
                            LocatorRect = new Rectangle((int)(characterPos.X - 32), (int)(characterPos.Y - 32),
                                                        64, 64)
                        });
                    }
                    else
                    {
                        this.ActiveWarpLocators[charLocName].Characters.Add(character.Name);
                    }
                }

                bool isOnScreen = Utility.isOnScreen(characterPos, Game1.tileSize / 4);

                var locator = new Locator
                {
                    Name       = character.Name,
                    Farmer     = character as Farmer,
                    Marker     = character is NPC ? character.Sprite.Texture : null,
                    Proximity  = this.GetDistance(playerPos, characterPos),
                    IsWarp     = isWarp,
                    IsOutdoors = isOutdoors,
                    IsOnScreen = isOnScreen,
                    IsHorse    = isHorse
                };

                double angle      = this.GetPlayerToTargetAngle(playerPos, characterPos);
                int    quadrant   = this.GetViewportQuadrant(angle, playerPos);
                var    locatorPos = this.GetLocatorPosition(angle, quadrant, playerPos, characterPos, isWarp);

                locator.X        = locatorPos.X;
                locator.Y        = locatorPos.Y;
                locator.Angle    = angle;
                locator.Quadrant = quadrant;

                if (this.Locators.TryGetValue(charLocName, out var warpLocators))
                {
                    if (!warpLocators.Contains(locator))
                    {
                        warpLocators.Add(locator);
                    }
                }
                else
                {
                    warpLocators = new List <Locator> {
                        locator
                    };
                }

                this.Locators[charLocName] = warpLocators;
            }