/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="player">The player.</param> /// <param name="npc">The NPC.</param> /// <param name="constants">The constant assumptions.</param> /// <param name="friendship">The current friendship data.</param> public FriendshipModel(SFarmer player, NPC npc, Friendship friendship, ConstantData constants) { // flags this.CanDate = npc.datable.Value; this.IsDating = friendship.IsDating(); this.CanHousemate = npc.Name == "Krobus"; this.IsSpouse = friendship.IsMarried() && !this.CanHousemate; this.IsHousemate = friendship.IsMarried() && this.CanHousemate; this.IsDivorced = friendship.IsDivorced(); this.Status = friendship.Status; this.TalkedToday = friendship.TalkedToToday; this.GiftsToday = friendship.GiftsToday; this.GiftsThisWeek = friendship.GiftsThisWeek; // points this.MaxPoints = this.IsSpouse || this.IsHousemate ? constants.SpouseMaxFriendship : NPC.maxFriendshipPoints; this.Points = friendship.Points; this.PointsPerLevel = NPC.friendshipPointsPerHeartLevel; this.FilledHearts = this.Points / NPC.friendshipPointsPerHeartLevel; this.LockedHearts = this.CanDate && !this.IsDating ? constants.DatingHearts : 0; this.EmptyHearts = this.MaxPoints / NPC.friendshipPointsPerHeartLevel - this.FilledHearts - this.LockedHearts; if (this.IsSpouse || this.IsHousemate) { this.StardropPoints = constants.SpouseFriendshipForStardrop; this.HasStardrop = !player.mailReceived.Contains(Constants.Constant.MailLetters.ReceivedSpouseStardrop); } }
private void drawFarmerSlot(SpriteBatch b, int i) { long farmerID = (long)names[i]; Farmer farmer = Game1.getFarmerMaybeOffline(farmerID); if (farmer != null) { int gender = (!farmer.IsMale) ? 1 : 0; ClickableTextureComponent clickableTextureComponent = sprites[i]; int x = clickableTextureComponent.bounds.X; int y = clickableTextureComponent.bounds.Y; Rectangle origClip = b.GraphicsDevice.ScissorRectangle; Rectangle newClip = origClip; newClip.Height = Math.Min(newClip.Bottom, rowPosition(i)) - newClip.Y - 4; b.GraphicsDevice.ScissorRectangle = newClip; FarmerRenderer.isDrawingForUI = true; try { farmer.FarmerRenderer.draw(b, new FarmerSprite.AnimationFrame(farmer.bathingClothes ? 108 : 0, 0, secondaryArm: false, flip: false), farmer.bathingClothes ? 108 : 0, new Rectangle(0, farmer.bathingClothes ? 576 : 0, 16, 32), new Vector2(x, y), Vector2.Zero, 0.8f, 2, Color.White, 0f, 1f, farmer); } finally { b.GraphicsDevice.ScissorRectangle = origClip; } FarmerRenderer.isDrawingForUI = false; Friendship friendship = Game1.player.team.GetFriendship(Game1.player.UniqueMultiplayerID, farmerID); bool spouse = friendship.IsMarried(); float lineHeight = Game1.smallFont.MeasureString("W").Y; float russianOffsetY = (LocalizedContentManager.CurrentLanguageCode == LocalizedContentManager.LanguageCode.ru) ? ((0f - lineHeight) / 2f) : 0f; b.DrawString(Game1.dialogueFont, farmer.Name, new Vector2(xPositionOnScreen + IClickableMenu.borderWidth * 3 / 2 + 96 - 20, (float)(sprites[i].bounds.Y + 48) + russianOffsetY - 24f), Game1.textColor); string text2 = (LocalizedContentManager.CurrentLanguageCode != LocalizedContentManager.LanguageCode.pt) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635") : ((gender == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635").Split('/').First() : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635").Split('/').Last()); if (spouse) { text2 = ((gender == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11636") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11637")); } else if (farmer.isMarried() && !farmer.hasRoommate()) { text2 = ((gender == 0) ? Game1.content.LoadString("Strings\\UI:SocialPage_MarriedToOtherPlayer_MaleNPC") : Game1.content.LoadString("Strings\\UI:SocialPage_MarriedToOtherPlayer_FemaleNPC")); } else if (!Game1.player.isMarried() && friendship.IsDating()) { text2 = ((gender == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11639") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11640")); } else if (friendship.IsDivorced()) { text2 = ((gender == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11642") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11643")); } int width = (IClickableMenu.borderWidth * 3 + 128 - 40 + 192) / 2; text2 = Game1.parseText(text2, Game1.smallFont, width); Vector2 textSize = Game1.smallFont.MeasureString(text2); b.DrawString(Game1.smallFont, text2, new Vector2((float)(xPositionOnScreen + 192 + 8) - textSize.X / 2f, (float)sprites[i].bounds.Bottom - (textSize.Y - lineHeight)), Game1.textColor); if (spouse) { b.Draw(Game1.objectSpriteSheet, new Vector2(xPositionOnScreen + IClickableMenu.borderWidth * 7 / 4 + 192, sprites[i].bounds.Y), Game1.getSourceRectForStandardTileSheet(Game1.objectSpriteSheet, 801, 16, 16), Color.White, 0f, Vector2.Zero, 2f, SpriteEffects.None, 0.88f); } else if (friendship.IsDating()) { b.Draw(Game1.objectSpriteSheet, new Vector2(xPositionOnScreen + IClickableMenu.borderWidth * 7 / 4 + 192, sprites[i].bounds.Y), Game1.getSourceRectForStandardTileSheet(Game1.objectSpriteSheet, 458, 16, 16), Color.White, 0f, Vector2.Zero, 2f, SpriteEffects.None, 0.88f); } } }
/// <summary>Raised after the game state is updated (≈60 times per second).</summary> /// <param name="sender">The event sender.</param> /// <param name="e">The event data.</param> private void OnUpdateTicked(object sender, UpdateTickedEventArgs e) { if (!Context.IsWorldReady || !this.IsReady) { return; } foreach (KeyValuePair <string, Friendship> pair in Game1.player.friendshipData.Pairs) { // get friend info if (!this.Characters.TryGetValue(pair.Key, out CharacterInfo friend)) { continue; } // get friendship Friendship friendship = pair.Value; if (friendship.IsDivorced()) { continue; } // track gift if (friendship.GiftsToday == 1) { friend.ReceivedGift = true; } // track talk & apply nearby NPC bonuses if (Game1.player.hasTalkedToFriendToday(friend.Name)) { if (!friend.HasTalked) { IList <Character> charactersWithinDistance = ModEntry.AreThereCharactersWithinDistance(Game1.player.getTileLocation(), 20, Game1.player.currentLocation); foreach (Character nearbyNpc in charactersWithinDistance) { // get nearby character's info if (nearbyNpc == null || nearbyNpc.Name == friend.Name) { continue; } if (!this.Characters.TryGetValue(nearbyNpc.Name, out CharacterInfo nearbyCharacter)) { continue; } if (!Game1.player.friendshipData.TryGetValue(nearbyNpc.Name, out Friendship nearbyFriendship)) { continue; } // ignore if divorced if (nearbyFriendship.IsDivorced()) { nearbyNpc.doEmote(Character.angryEmote); continue; } // add witness bonus nearbyCharacter.NearbyTalksSeen++; nearbyNpc.doEmote(Character.happyEmote); this.AddFriendshipPoints(nearbyNpc as NPC, this.Config.WitnessBonus); this.Monitor.Log($"{nearbyNpc.Name} saw you taking to {friend.Name}. +{this.Config.WitnessBonus} Friendship: {nearbyNpc.Name}", LogLevel.Info); } friend.HasTalked = true; } } } // check if shopping //TODO: Add the Bus/Pam if (Game1.activeClickableMenu is ShopMenu shopMenu && this.Shops.TryGetValue(Game1.currentLocation.Name, out string shopOwnerName)) { // get shopkeeper if (!this.Characters.TryGetValue(shopOwnerName, out CharacterInfo shopkeeper)) { return; } // mark shopped if (!shopkeeper.HasShopped && this.Helper.Reflection.GetField <Item>(shopMenu, "heldItem").GetValue() != null) { shopkeeper.HasShopped = true; if (shopkeeper.TryGetNpc(out NPC shopkeeperNpc)) { this.AddFriendshipPoints(shopkeeperNpc, this.Config.UjamaaBonus); this.Monitor.Log($"{shopOwnerName}: Pleasure doing business with you!", LogLevel.Info); } } } // check if player entered a festival if (!this.HasEnteredEvent && Game1.currentLocation?.currentEvent?.isFestival == true) { Utility.improveFriendshipWithEveryoneInRegion(Game1.player, this.Config.UmojaBonusFestival, 2); foreach (KeyValuePair <string, Friendship> pair in Game1.player.friendshipData.Pairs) { string name = pair.Key; Friendship friendship = pair.Value; if (this.Characters.TryGetValue(name, out CharacterInfo character) && character.TryGetNpc(out NPC npc) && object.ReferenceEquals(npc.currentLocation, Game1.currentLocation)) { npc.doEmote(friendship.IsDivorced() ? Character.angryEmote : Character.happyEmote); } } this.Monitor.Log("The villagers are glad you came!", LogLevel.Info); this.HasEnteredEvent = true; } // check if player is getting married or having a baby if ((Game1.weddingToday || Game1.farmEvent is BirthingEvent) && !this.HasEnteredEvent && this.Characters.TryGetValue(Game1.player.spouse, out CharacterInfo spouse)) { foreach (CharacterRelationship relation in spouse.Relationships) { if (!relation.Character.TryGetNpc(out NPC relationNpc)) { continue; } if (relation.IsFamily) { this.AddFriendshipPoints(relationNpc, this.Config.UmojaBonusMarry); this.Monitor.Log($"{relation}: Married into the family, received +{this.Config.UmojaBonusMarry} friendship", LogLevel.Info); } else { this.AddFriendshipPoints(relationNpc, this.Config.UmojaBonusMarry / 2); this.Monitor.Log($"{relation}: Married a friend, received +{this.Config.UmojaBonusMarry / 2} friendship", LogLevel.Info); } } this.HasEnteredEvent = true; } // check if player completed daily quest if (Game1.stats.questsCompleted > this.CurrentNumberOfCompletedDailyQuests) { this.CurrentNumberOfCompletedDailyQuests = Game1.stats.questsCompleted; this.DaysAfterCompletingLastDailyQuest = 0; this.HasRecentlyCompletedQuest = true; } }