邮件框架 Mod 封面

邮件框架 Mod

星露谷物语模组工具

用于游戏内邮箱的框架。可通过控制台命令调整邮件。提供代码和内容包接口。

预览

前置 Mod

详情

目标:

简化向玩家发送邮件的过程,提供对邮件发送时机和内容的更多控制。

同时提供仅通过编辑数据文件无法实现的更多选项,例如随意更改信件的文字颜色和背景。

安装:

  1. 安装最新版本的 SMAPI。
  2. 解压 MailFrameworkMod 到 /Stardew Valley/Mods。

更新日志:

1.20.0

  • 向游戏添加了一个新的自定义资产。(DIGUS.MailFrameworkMod/MailData) 这意味着现在可以使用 Content Patcher 加载 MFM 信件,并利用其所有功能(如标记)。它支持相同的属性。
  • 内容包信件也会加载到新的自定义资产中,因此可以使用 Content Patcher 进行编辑。
  • 现在内容包在游戏启动时加载到缓存中,而不是每次加载存档时重新加载。你可以使用控制台命令强制重新加载内容包。
  • Text 和 Title 属性现在支持可标记字符串(Tokenizable string)。
  • 纹理资产现在可以是游戏资产,而不仅仅是 mod 文件夹中的资产。
  • 新增 GameStateQuery 属性作为发送信件的条件。

1.19.0

  • 新增属性,当所有条件在一天内满足但当天未阅读邮件时,保持邮件有效。
  • 新增处理随机选择附件的功能。
  • 新增属性,用于设置应从附件列表中选择多少物品进行发送。
  • 新增属性,可为附件设置 "RandomGroup",使其从该组而不是整个列表中选择。
  • 新增属性,可为给定附件设置 "Weight",用于随机选择时。
  • 新增属性,用于设置应从给定组中选择多少物品,而不是使用默认值。
  • 新增属性,用于说明给定组中的物品是否可以被多次选择。
  • 新增一组属性,用于为附件和回复设置 MailReceived 要求。
  • 新增属性,用于设置当信件被阅读或选择回复选项时要移除的 MailReceived。
  • 新增属性,用于为给定回复选项设置费用。
  • 新增 ItemType "None"。基本上用于当你希望有随机概率不发送物品,同时不在日志中触发错误/警告时。

1.18.0

  • 新增 Ids 属性,用于替代 CollectionConditions 的 Index 和 Name。它可以聚合多个物品的数量,将其值相加后与 Amount 比较。
  • 新增 ReplyConfig 属性,用于添加回复行为。你可以在玩家阅读邮件后显示一些选项,并根据所选选项添加一个或多个 MailReceived 文本。可以基于该选择实现额外的 mod 逻辑。
  • 修复带有配方的信件不支持 CustomTextColorName 属性的问题。
  • 修复当游戏中加载名称为 null 的物品时出现的空引用异常。

1.17.1

  • 带有 recipe 属性的内容包邮件如果配方未学会,需要没有附件才能重新发送。(如果有附件,recipe 属性将被忽略)
  • 修复烹饪配方,之前已对制作配方应用了相同逻辑。

1.17.0

  • 新增属性,用于设置附件的品质。
  • 带有 recipe 的内容包邮件如果配方未学会,应重新发送。
  • 修复使用限定物品 ID 时关于弹弓的警告。
  • 修复即使配方已学会,可制作物品的配方仍被发送的问题。
  • 出于兼容旧版的原因,如果在已学配方中找不到配方 ID,它将查找一个创建名称为配方 ID 的物品的配方。

1.16.1

  • 修复配方翻译名称。

1.16.0

  • 更新 mod 以兼容 Stardew Valley 1.6。
  • 新增命令以重新加载内容包。
  • 将 MailDao 名称改为 MailRepository。(仅影响使用它的 SMAPI mod)
  • 新增附件物品类型 'QualifiedItemId',如果使用正确的限定符,应适用于游戏中的每种物品类型。
  • 新增特殊日期条件属性。(婚礼和生育)
  • 新增 CustomTextColor 属性,弃用旧属性。
  • 新增 HasMods 属性。
  • 新增 RequireAllMods 属性。
  • 事件 ID 现在为字符串。(数字仍应有效)
  • 移除了从 MFM 合并到 SV 1.6 的过时逻辑。
  • 修复了 alpha 版中信件无法在邮件收集页面打开的问题。

剧透

1.15.0

  • 为 SMAPI mod 提供新的 API 接口。
  • API 方法,用于从你的 SMAPI mod 内部加载内容包文件夹。
  • API 方法,用于加载一封信件。
  • API 方法,用于获取信件数据。
  • API 方法,用于获取信件的邮件数据字符串。
  • 修复关闭信件时发生错误导致邮箱无法正常工作的问题。
  • 在这些错误上提供更好的日志。

1.14.0

  • 更多与 SMAPI 4 兼容的更改。
  • 信件类中新增属性以设置 ITranslationHelper。
  • 内容包无需更改任何内容,但此更改应避免一些罕见的 i18n 问题。
  • 通过代码使用 MFM 的 mod 可以更新其实现。

1.13.0

  • 使 mod 兼容 SMAPI 4。
  • 新增最深层矿井等级属性。
  • 新增当前金钱属性。
  • 新增总金钱收入属性。
  • 新增控制台命令,强制邮箱更新,以帮助 mod 作者调试。
  • 信件收集菜单现在也会显示自定义关闭按钮。

1.12.2

  • 使 mod 兼容 1.5.5,而无需强制 SMAPI 转换它。
  • 应修复在 Unix 操作系统上附件无法工作的一些问题。
  • 新增房屋升级等级属性。

1.12.1

  • 修复未加载 Expanded Preconditions Utility 时的错误。

1.12.0

  • 新增属性以支持使用 Expanded Preconditions
  • 新增属性,使除信件 ID 之外的文本可以添加到玩家的 MailReceived 列表中。

1.11.0

  • 支持 DGA(Dynamic Game Assets) 作为附件。

1.10.2

  • 修复由 Json Assets 添加的英文烹饪配方名称显示为 null 的问题。

1.10.1

  • 修复当存在 i18n 文件时,无文本的自动打开信件会破坏 mod 的问题。
  • 修复一个收集条件警告后内容包信件无法加载的问题。
  • 为制作配方新增收集要求类型。

1.10.0

  • 现在支持所有原版工具。
  • 支持原版弹弓作为武器。如果你使用弹弓的索引或名称,它将被正确创建为弹弓。
  • 新增 "Auto Open" 属性,用于当你希望使用 MFM 条件将信件 ID 标记为已读而不实际写一封信时。

1.9.2

  • 优化从内容包加载资产。
  • 修复当打开菜单向物品栏添加物品时,信件的回调未被调用的问题。

1.9.1

  • 修复一个 bug:当点击邮箱时如果手持物品,MFM 信件不会在当天打开并从邮箱中移除。

1.9.0

  • 新增属性,用于通过 SMAPI 创建的信件动态添加物品。
  • 新增方法,用于从邮箱中移除信件。

1.8.1

  • 修复本地合作模式中的邮件冲突。
  • 修复在罕见情况下,如果信件菜单未被游戏正确关闭,mod 会停止工作的问题。

1.8.0

  • 支持家具、武器和靴子作为附件。
  • 新增属性,用于设置附加工具的升级等级。

1.7.0

  • 支持戒指作为附件。
  • 新增配方条件。
  • 新增属性,用于通过内容包自定义背景。
  • 支持通过内容包和代码自定义关闭按钮。

1.6.0

  • 支持内容包中的 i18n。
  • 新增农场建筑的条件属性。
  • 新增收到邮件的条件属性。(用于任务标记)
  • 新增事件的条件属性。
  • 新增收集菜单物品的条件列表。
  • 新增游戏统计的条件列表。
  • 新增 NPC 友谊条件列表中的友谊状态属性。
  • 新增当组 ID 冲突时的随机功能。

1.5.1

  • 修复没有组 ID 的信件被分组在一起的问题。

1.5.0

  • 如果定义了 Title,信件现在会显示在收集菜单中。自定义纹理和颜色也会显示在收集菜单中。
  • 信件现在可以有一个组 ID。具有相同组 ID 的信件永远不会在同一天发送。
  • 内容包的新条件:"RandomChance"。
  • BigObject 现在称为 BigCraftable,与游戏代码中一致。
  • 修复模板中的拼写错误。

1.4.1

  • 添加对 Stardew Valley 1.4.0 的支持。
  • 为信件添加 Title 属性,以显示在收集菜单中。尚未完全实现,但 mod 作者可以开始设置它。

1.4.0

  • 为 mod 作者添加内容包支持,以添加自定义信件,可配置此框架提供的所有功能,并包含大多数常用的发送条件。
  • 修复控制器无法获取附加物品的问题。
  • 修复如果邮件附有多个物品时正确显示附件的问题。
  • 修复当物品栏已满并打开菜单管理时,信件不会关闭的问题。
  • 修复即使配置了堆叠物品,也不会添加到邮件的问题。
  • 添加对 SMAPI 3 的支持。

1.3.4

  • 添加对 Stardew Valley 1.3.36 的支持。

1.3.3

  • 添加对 SMAPI 3 的支持。

1.3.2

  • 添加对 Stardew Valley 1.3.32 的支持。

1.3.1

  • 添加命令以移除和添加到玩家已接收邮件列表。

1.3.0-beta.6

  • 添加对制作配方的支持。
  • 添加对自定义背景的支持。
  • 添加对自定义文字颜色的支持。
  • 打开自定义信件的新方式,现在使用 harmony。
  • 配置文件以启用打开自定义信件的旧方式。

1.2.0

  • 支持 i18n 配方。
  • 修复返回标题菜单后 mod 无法正常工作的问题。
  • 修复如果信件的条件抛出异常,则不发送邮件的问题。

1.1.0

  • 修复在睡觉并退出游戏时,如果未阅读自定义邮件,会收到 "tax passed" 邮件的问题。
  • 自定义邮件可以有配方。
  • 此版本与旧版本不兼容。Mod 需要更新才能使用此版本。

1.0.0

  • 添加自定义邮件。
  • 自定义邮件可以有物品。

供 Mod 作者使用内容包:

  • mod 文件夹内有一个模板,其中包含注释说明每个属性的作用。
  • 除条件和回调外,所有信件功能与使用框架编写代码相同。
  • 条件仅限于已实现的条件,回调始终将信件 ID 设置为已接收。如果你需要高级条件,仍应编写代码。或者你可以礼貌地建议我向内容包添加条件,如果它有意义,我可能会添加。
  • 以下是 mod 文件中添加的模板:

剧透

[
    {
        "Id": "MyMod.MyMailId", // Letter id. It's important to be an unique string to avoid conflicts. Also it shouldn't have space characters.
        "GroupId": "MyMod.MyGroupId", // Letter group id. Letters with the same group id are never delivered in the same day. Letters registered first have priority, unless the group id ends with ".Random", in that case, a random letter will be chosen. Default is null.
        "Title": "My Letter Title", // Letter title. Will be shown in the collections menu. Set it null or remove the line if you don't want the letter to appear in the collection. If an translation file is provide, you should put a translation key here, but you can still leave if null for no Title.
        "Text": "Dear @^This is my custom mail.", // Text of the letter. You can use @ to put the players name and ^ for line breaks. You can also use the base game commands to add money, items and stuff. If an translation file is provide, you should put a translation key here.
        "RandomlyChooseAttachment": 2, // If a number is set, it will choose randomly that amount of items from the attachment list, per group. Default is null.
        "RandomlyChooseAttachmentPerGroup": { "CaveItems": 3 }, // If a group and amount is set here, it will use that amount to pick items instead of the one that set on RandomlyChooseAttachment. Default is empty.
        "AttachmentGroupWithReplacement": [ "CaveItems" ], // Attachments are chosen randonly from a list without replacement by default, if you want the pick to be chosen replacing the the attachments, add the group to the list. If you didn't add groups, use an empty string. Default value is an empty list.
        "Attachments": [ // List of attachments. Remove the property to not attach items to the mail.
            {
                "Type": "Object", // [Object|BigCraftable|Tool|Ring|Furniture|Weapon|Boots|DGA|QualifiedItemId|None] Required. The type of item that will be attached. If not provided the item will be ignored. 'None' is always igored without errors in the log and should be used when you want a probability of not adding an attachment.
                "Name": "Cave Carrot", // Used to find the item index. That's required if using custom objects like Json Assets ones. Should be the full DGA ID is using DGA. If not provided, the index will be used. Default is null.
                "Index": "(0)78", // The index of an item. Should be the qualified item id as a string, but will also work as an integer for retro compatibility. If no name is provided or an item for the name is not found, the index is used. Otherwise, the attachment is ignored. Ignored if the type is DGA.
                "Stack": 1, // The stack value of the item to be delivered. Used only for Objects and BigCraftable. Default is 1.
                "Quality": 2, // The quality value of the item to be delivered. Used only for Objects. 0 = none, 1 = silver, 2 = gold, 4 = iridium. Default is 0;
                "RequireMailReceived": [ "jojaVault", "ccVault" ], // Require one of the mails to have been received. The game list also contain others thing that are not mail, like community center flags. Default is null to no require a mail received.
                "RequireAllMailReceived": false, // If true, require that all mails in the "RequireMailReceived" list to have been received. Default is false.
                "ProbabilityWeight": 1, // The weight this attachment have when choosing which one to deliver. The mod sum all weight in a given group and give it a probability dividing this weight by the total. Default is 1.
                "RandomGroup": "CaveItems" // When choosing the items randonly, group the list by the found groups and pick the amount set from each group. Default value is an empty string that function as the default group.
            },
            {
                "Type": "Tool", // When using tool, only supported ones can be attached.
                "Name": "Axe", // [Axe|Hoe|Watering Can|Pickaxe|Scythe|Golden Scythe|Milk Pail|Shears|Fishing Rod|Pan|Return Scepter] Required for tools. The name of the supported tool. Otherwise, the attachment is ignored.
                "UpgradeLevel": 1 // The upgrade level of the tool. Regular tools: 0 = stone, 1 = cooper, 2 = steel, 3 = gold, 4 = iridium. Fishing Rod: 0 = Bamboo Pole, 1 = Training Rod, 2 = Fiberglass Rod, 3 = Iridium Rod. Ignored for the other types. Default is 0.
            },
            {
                "Type": "DGA", //DGA item
                "Name": "spacechase0.DynamicGameAssets.Example/My Custom Item", // use the full DGA ID. Required.
                "Stack": 10, // The stack value of the item to be delivered. Used only for Objects and BigCraftable. Default is 1.               
                "Quality": 2 // The quality value of the item to be delivered. Used only for Objects. 0 = none, 1 = silver, 2 = gold, 4 = iridium. Default is 0;
            },
            {
                "Type": "QualifiedItemId", //Any supported item
                "Index": "(0)78", // The Qualified Item Id of an item.
                "Stack": 10, // The stack value of the item to be delivered. Used only for Objects and BigCraftable. Default is 1;
                "Quality": 2 // The quality value of the item to be delivered. Used only for Objects. 0 = none, 1 = silver, 2 = gold, 4 = iridium. Default is 0;
            }
        ],
        "Recipe": "Recipe Name", // Remove the line if you don't want to attach a recipe to the mail. It will only work if you have no other attachments to the mail. For DGA recipes only use the ID part (leave away the ModID)
        "AdditionalMailReceived": ["MyMod.AnotherMailId", "VANILLA_FLAG"], // Use this to add additional text to the MailReceived list. Can be useful to add vanilla flags or other MFM letter ids.
        "MailReceivedToRemove": ["MyMod.AnotherMailThatNeedToBeResent","MyMod.SomeFlagThatWasLockingSomeFeature"], //Text to removed from the MailReceived list. This can be used to trigger new mail, events, vanilla flags, stop other MFM mail from being sent...
        "LetterBG": "CustomLetterBG.png", // Name of the file in your content pack that has the custom letter background to use. It should follow the same structure of the game LetterBG file . WhichBG will be relative to this file for this letter. If null or removed the mod will use the game LetterBG.
        "WhichBG": 0, //The id of the letter background. 0 = classic, 1 = notepad, 2 = pyramids
        "TextColor": -1, //Remove this line to use the default color. Will be ignored if a CustomTextColor is set. -1 = Dark Red, 0 = Black, 1 = Sky Blue, 2 = Red, 3 = Blue Violet, 4 = White, 5 = Orange Red, 6 = Lime Green, 7 = Cyan, 8 = Darkest Gray
        "CustomTextColorName": "White", //The color of the text.[http://www.foszor.com/blog/xna-color-chart/] Default will use the TextColor property.
        "UpperRightCloseButton": "CustomCloseButton.png", // Name of the file in your content pack that has the custom close button to use. It should be 12 x 12 . If null or removed it will use the default button.
        "ReplyConfig": { // If you want the player to send a reply after reading the letter. It will show the reply options that will add one or more "ReceivedMail" based on the player answer. Any additional logic related to the reply needs to be implemented based on the ReceivedMail added.
            "QuestionKey": "MyMod.MyMailId.Question", //A key to identify your question. It has only internal use, but should be unique in your content pack to avoid conflict between replies.
            "QuestionDialog": "Send a reply choosing your reward:", //Your question or text that will show over the reply options. If an translation file is provided, you should put a translation key here.
            "Replies": [
                {
                    "ReplyKey": "MyMod.MyMailId.Reply1", //Must be unique between the question replies.
                    "ReplyOptionDialog": "I want seeds.", //The option text that will show in the reply list. If an translation file is provided, you should put a translation key here.
                    "RequireMailReceived": [ "jojaVault", "ccVault" ], // Require one of the mails to have been received. The game list also contain others thing that are not mail, like community center flags. Default is null to no require a mail received.
                    "RequireAllMailReceived": false, // If true, require that all mails in the "RequireMailReceived" list to have been received. Default is false.
                    "MailReceivedToAdd": [ "MyMod.MyMailId.PlayerSeedOption" ], // Text to add to the MailReceived list. This can be used to trigger new mail, events, vanilla flags, stop other MFM mail from being sent...
                    "MailReceivedToRemove": [ "MyMod.MyMailId.PlayerSapplingOption" ], //Text to removed from the MailReceived list. This can be used to trigger new mail, events, vanilla flags, stop other MFM mail from being sent...
                    "ReplyResponseDialog": "Your letter requesting seeds was sent.", //Text that will show after this reply option is chosen. If an translation file is provided, you should put a translation key here.
                    "Cost": 50 //The amount of money the player needs to have to choose this option. If they do choose it, that amount is immediately subtracted from the player's money. Always provide an option with no cost, or you mighty softlock the player.
                }
            ]
        },
        "Repeatable": false, // If true the mod won't check it the letter Id has already been delivered. Default is false.
        "AutoOpen": false, // If true the mod will open the letter at the begin of the day after the conditions are met. The letter id will be marked as read and if there is a recipe set, it will be learned. Since the letter will never show, visual properties like title, text, background... will never be used, as well as the attachments.
        // CONDITIONS FOR DELIVERY
        //Below are conditions for the delivery. Remove any of the lines if you don't want to check that condition.
        "Date": "10 spring Y1", // Must be that date or after it. The format is "[1-28] [spring|summer|fall|winter] Y[1-999]".
        "Days": [7,14,21,28], // Must be one of the days in the list.
        "Seasons": ["fall"], // Must be one of the seasons in the list. [spring|summer|fall|winter]
        "Weather": "sunny", // Must be that game weather. The format is "[sunny|rainy]".
        "HouseUpgradeLevel": 2, // House upgrade level must be equal or higher what is defined. 0 - starter house(no reason to use this, just remove the line), 1 - kitchen, 2 - second floor, 3 - cellar.
        "DeepestMineLevel": 80, // Deepest mine level must be equal or higher what is defined. 120 is the last level of the mine, 121 is the first level of the skull cavern.
        "CurrentMoney": 10000, // Current money must be equal or higher what is defined.
        "TotalMoneyEarned": 500000, // Total money earned must be equal or higher what is defined.
        "FriendshipConditions": // Each NPC of the list must check all conditions.
        [
            {
                "NpcName": "Lewis", //Name of the NPC. Can use custom NPCs.
                "FriendshipLevel": 8, // NPC must have a friendship heart level equal or higher what is defined. Default is 0.
                "FriendshipStatus": ["Dating","Engaged","Married"] // [Friendly|Dating|Engaged|Married|Divorced]  Require the NPC friendship status to be one from the list. Remove to not require a status.
            }
        ],
        "SkillConditions": // Each skill of the list must have a level equal or higher what is defined. Can use all coded skills in the vanilla game, including Luck. Can't use custom skills.
        [
            { "SkillName": "Farming", "SkillLevel": 1 }
        ],
        "StatsConditions": // Each stats of the list must have a value equal or higher what is defined. Choose a StatsName or a StatsLabel
        [
            {
                "StatsName": "CheeseMade", //[SeedsSown|ItemsShipped|ItemsCooked|ItemsCrafted|ChickenEggsLayed|DuckEggsLayed|CowMilkProduced|GoatMilkProduced|RabbitWoolProduced|SheepWoolProduced|CheeseMade|GoatCheeseMade|TrufflesFound|StoneGathered|RocksCrushed|DirtHoed|GiftsGiven|TimesUnconscious|AverageBedtime|TimesFished|FishCaught|BouldersCracked|StumpsChopped|StepsTaken|MonstersKilled|DiamondsFound|PrismaticShardsFound|OtherPreciousGemsFound|CaveCarrotsFound|CopperFound|IronFound|CoalFound|CoinsFound|GoldFound|IridiumFound|BarsSmelted|BeveragesMade|PreservesMade|PiecesOfTrashRecycled|MysticStonesCrushed|DaysPlayed|WeedsEliminated|SticksChopped|NotesFound|QuestsCompleted|StarLevelCropsShipped|CropsShipped|ItemsForaged|SlimesKilled|GeodesCracked|GoodFriends|IndividualMoneyEarned] Default is null.
                "StatsLabel": "Name", // [exMemoriesWiped|childrenTurnedToDoves|trashCansChecked|boatRidesToIsland|beachFarmSpawns|hardModeMonstersKilled|timesEnchanted] This are the current game stats that are identified by label, if more are added, they should also be supported. It will also identify custom stats labels added by other mods. Default is null.
                "Amount": 1 // The amount the status should be equal or greater for the condition to be valid.
            }
        ],
        "CollectionConditions": // Each collection condition of the list must have a value equal or higher than the defined amount.
        [
            {
                "Collection": "Shipped", //[Shipped|Fish|Artifacts|Minerals|Cooking|Crafting] Required.
                "Name": "Oil", //Deprecated, uses Ids instead. The name of the object or recipe for 'Crafting' collection. If not a crafting colection, it will look for that name in the object list to find the index. If the name is not found, the letter is ignored. Will combine with the other properties. Default is null.
                "Index": 211, //Deprecated, uses Ids instead. The index of the object. Will combine with the other properties. Default is null.
                "Ids": [ "282", "MossSoup" ], //The items ids or the crafting recipe names. Will combine with the other properties. The amounts are summed to compare with the Amount property.
                "Amount": 10 // The total amount the objects in the collection should be equal or greater for the condition to be valid.
            }
        ],
        "SpecialDateCondition": // Must be that date or after it.
        {
            "SpecialDate": "ChildBirth", //[Wedding|ChildBirth] Required
            "YearsSince": 1, //The amount of years since the date happen. 0 will match the actual date, 1 the flowing year. Default is 0.
            "WhichChild": 1 //If the SpecialDate property is ChildBirth, it will reference which chield. Default is 1;
        },
        "ExpandedPrecondition": "d Mon Fri/HasItem Pink Cake/!JojaMartComplete/!w rainy", //Needs the Expanded Preconditions Utility mod. Sees that mod documentation to see how this works. If the mod is not loaded, the letter will not be delivered.
        "ExpandedPreconditions": [ "!z spring/t 600 1000", "f Linus 1000/w rainy/z spring", "f Linus 2500" ], //Needs the Expanded Preconditions Utility mod. Sees that mod documentation to see how this works. If the mod is not loaded, the letter will not be delivered.
        "RandomChance": 0.25, // The mod will check if a random number from 0 to 1 is bellow the given number. The same save, on the same day for the same letter will always have the same result to avoid cheating.
        "Buildings": ["Coop","Big Coop","Deluxe Coop"], // Require one of the buildings to be currently constructed in the farm.
        "RequireAllBuildings": false, // If true, require that all the buildings in the "Buildings" list to be currently constructed in the farm. Default is false.
        "MailReceived": ["jojaVault","ccVault"], // Require one of the mails to have been received. The game list also contain others thing that are not mail, like community center flags.
        "RequireAllMailReceived": false, // If true, require that all mails in the "MailReceived" list to have been received. Default is false.
        "MailNotReceived": ["jojaVault","ccVault"], // Require the mails to have not been received. The game list also contain others thing that are not mail, like community center flags.
        "EventsSeen": [ "4", "32423" ], // Require one of the events to have been seen by the player. Should be a string, but will also work as an integer for retro compatibility.
        "RequireAllEventsSeen": false, // If true, require that all the events in the "EventsSeen" list to have been seen by the player. Default is false.
        "HasMods": [ "SMAPI.ConsoleCommands", "SMAPI.SaveBackup" ], // Require one of the mods to be loaded. Should be the mod UniqueID.
        "RequireAllMods": false, // If true, require that all the mods in the "HasMods" list to have been loaded. Default is false.
        "EventsNotSeen": [ "4", "32423" ], // Require the events to have not been seen by the player. Should be a string, but will also work as an integer for retro compatibility.
        "RecipeKnown": ["Pizza","Survival Burger"], // Require one of the recipes to have been learned by the player.
        "RequireAllRecipeKnown": false, // If true, require that all the recipes in the "RecipeKnown" list to have been learned by the player. Default is false.
        "RecipeNotKnown": ["Wild Bait"], // Require the recipes to have not been learned by the player.
        "KeepValid": false // If this is true, once the conditions are meet, keep the mail valid until read. Default is false.
    }
][/spoiler]

供 Mod 作者使用 API:

  • 复制 IMailFrameworkModApi 接口,包含你想从 MFM 接口使用的方法。
  • 如果某个方法需要,复制 ILetter。
  • 方法:
    • RegisterContentPack - 使用 Helper.ContentPacks.CreateTemporary 从你的 mod 加载一个包含 mail.json 和可能的 i18n 翻译文件夹的文件夹。不需要 Manifest,因为你可以使用该方法的参数。

    • RegisterLetter - 用你需要的属性填充一个 ILetter。注册信件还需要一个条件。建议使用回调,至少将信件 ID 添加为已接收。参见下面的示例,在“供 Mod 作者编写依赖 MFM 的代码”部分。

    • GetLetter- 你将获得对应信件 ID 的 ILetter 对象。

    • GetMailDataString- 你将获得对应信件 ID 的邮件数据字符串。邮件数据字符串基本上是翻译后的文本加上翻译后的标题,用 [#] 分隔。

供 Mod 作者编写依赖 MFM 的代码:

  • 在你的 SMAPI 项目中引用 MailFrameworkMod.dll。

    • 使用 MailRepository.SaveLetter(Letter) 注册你的信件。
    • 每天开始时,mod 会检查已达到发送条件的信件,并将它们添加到邮箱中。
    • 当玩家检查邮箱时,这些信件将首先被打开。
    • 当信件被打开时,它会从邮箱中移除。
    • 然后调用信件的回调条件。
    • 一天结束时,仍在邮箱中的信件将被移除,因此它们不会被游戏保存。
  • 你可以将此 mod 视为你信件的仓库。最好在游戏加载时加载所有信件。

示例:

> 剧透

加载一封简单的信件,如果之前未阅读,将向玩家显示,并且在玩家打开后不会再次发送:

MailRepository.SaveLetter(
    new Letter(
         "LetterUniqueId"
         ,"Letter custom text."
         ,(l)=>!Game1.player.mailReceived.Contains(l.Id)
          ,(l)=>Game1.player.mailReceived.Add(l.Id)
    )
);

像之前一样加载一封简单的信件,但附有 5 个绿宝石:

MailRepository.SaveLetter(
   new Letter(
    "LetterUniqueId"
    ,"Letter custom text."
    ,new List<Item> { new StardewValley.Object(60,5) }
    ,(l)=>!Game1.player.mailReceived.Contains(l.Id)
    ,(l)=>Game1.player.mailReceived.Add(l.Id)
   )
);

玩家不会收到相同的物品,而是从 getOne() 方法返回的副本。

加载一封将教授烹饪配方的简单信件,如果玩家不知道配方,它将被发送。该 mod 在玩家加载时自动教授配方,此处无需回调:

MailRepository.SaveLetter(
   new Letter(
    "LetterUniqueId"
    , "Letter custom text."
    , "RecipeUniqueName"
    , (l) => !Game1.player.cookingRecipes.ContainsKey(l.Recipe)
   )
);

"RecipeUniqueName" 必须与存储在 "Data//CookingRecipes" 或 "Data//CraftingRecipes" 中的相同。

加载一封具有不同文本和背景的简单信件:

MailRepository.SaveLetter(
   new Letter(
    "LetterUniqueId"
    ,"Letter custom text."
    ,(l)=>!Game1.player.mailReceived.Contains(l.Id)
    ,(l)=>Game1.player.mailReceived.Add(l.Id)
    1
   ){TextColor=8}
);

加载一封具有自定义背景的简单信件:

MailRepository.SaveLetter(
   new Letter(
    "LetterUniqueId"
    ,"Letter custom text."
    ,(l)=>!Game1.player.mailReceived.Contains(l.Id)
    ,Game1.player.mailReceived.Add(l.Id)
    1
   ){
    LetterTexture=helper.Content.Load<Texture2D>("CustomLetterBG.png")
    ,TextColor=4
   }
);

其中 CustomLetterBG.png 是一个遵循 "LooseSprites//letterBG" 相同结构的图像文件。

加载一封具有文本和标题翻译的简单信件。

MailRepository.SaveLetter(
    new Letter(
         "LetterUniqueId"
         ,"myletter.translation.key.text"
         ,(l)=>!Game1.player.mailReceived.Contains(l.Id)
          ,(l)=>Game1.player.mailReceived.Add(l.Id)
    ){
        Title = "myletter.translation.key.title",
        I18N = helper.Translation
    }
);

我的其他 Mod: