Custom Museum Framework

Essential Data

In order to create a custom museum, you will first want to do an edit targeting Spiderbuttons.CMF/Museums to add a new museum entry. The model is described below with an example Content Patcher edit further down. This documentation will not explain the process of adding the location itself, as it is no different from adding any other location. It will also not explain the map making process in detail, however there is important map-related documentation you will need to read on the Museum Maps page of this documentation.

Table of Contents

MuseumData Model

Your museum data must exist when a save is loaded. You may not conditionally patch in a custom museum. You may edit your museum data whenever you would like afterwards, but it must exist in some form in Spiderbuttons.CMF/Museums by the time the player goes to load a save, as this is when Custom Museum Framework will connect your data to the matching in-game location (which must also be present when a save is loaded and never conditionally appear or disappear from Data/Locations).

Spiderbuttons.CMF/Museums consists of a string to MuseumData dictionary,? where MuseumData is a model with the following fields:

FIELD PURPOSE
Id The string Id of your museum. This must match both the key you used for this entry and the ID of the location you want to use as a museum. This should also be globally unique, so using the {{ModId}} Content Patcher token is highly recommended.
Owner (Optional) An OwnerData object describing who runs your museum and what their "working zone" is. See Museum Ownership.
Default null
Bounds (Optional) A Rectangle in the form of { "X": 0, "Y": 0, "Width": 0, "Height": 0} that encompasses all (or at least most) of the valid item pedestal locations in your museum.[1]
DonationRequirements A list of DonationRequirement objects that define the criteria an item must meet in order to be donated to your museum. If an item meets any requirement in this list, it will be considered a valid donation item. See Donation Requirements.
CompletionNumber (Optional) An int that determines at what number of donations should your museum be considered complete. If set to null, this number will be set to the number of items in the game that are valid donation items. See Completion Requirements.
Default null
CountInvalidDonations (Optional) A bool that determines whether or not to count items that are not valid donation items, but are currently present in your museum nevertheless, in various features that check donation counts. See Invalid Donations.
AllowRetrieval (Optional) A bool for whether or not players can remove items from your museum after they have been donated. Items that have been removed will affect museum completion but may be re-donated again later. The player will not receive infinite rewards for removing and re-donating items. See Item Retrieval to understand the implications of this.
Default false
ShowDonationHint (Optional) A bool for whether or not items that can be donated to your museum will have a hint added to their description ala "Gunther can tell you more about this..."
Default true
OverrideDescription (Optional) A bool for whether or not your museum will completely override the description of items that can be donated to it and only show the hint. Does nothing if ShowDonationHint is false.
Default false
PedestalAction (Optional) An InteractionData object defining what should occur when a player interacts with a donated item on its item pedestal. See Pedestal Interactions.
Rewards (Optional) A list of CustomMuseumReward objects describing what rewards the player can earn for donating items. See Museum Rewards.
Milestones (Optional) A list of integers. When a milestone number of items have been donated to your museum, a customizable message will be displayed in chat.
Strings (Optional) A string to string dictionary for you to override the default strings that are shown when certain events occur. See Museum Strings.[2]

[1] This area is where the game will look for item pedestals when donating an item via trigger action actions or when a menu is force-closed and it needs to safely place an item down. While this field is optional, you should really fill it in!

[2] Many of the default strings are set to use lines found in the vanilla game, and therefore will be written with Gunther in mind. It is highly recommended to fill out all of the string overrides for this reason.

Completion Requirements

By default, Custom Museum Framework will use the total number of valid donation items in the game as the target number for museum completion. If there are 50 items in the game that meet your requirements, for example, then your museum will be considered complete once 50 items are donated. However, by altering your CompletionNumber, you can change when your museum will be considered complete. Continuing our previous example, if there were 50 items possible to donate, but you set your CompletionNumber to 20, then your museum will be complete once there are 20 items in your museum; the other 30 items will be ignored.

Once your museum is complete, the player will no longer be able to donate any items. Donation hints will no longer be shown for your museum on items that have not been donated. If there are any museum rewards that require an item to be donated that has not been earned yet, they will become unavailable as long as the museum remains complete. Quests may become impossible to finish while the museum remains completed if the required quest items have not yet been donated.

It is possible for your museum to become incomplete again after it has been completed once. You can remove donations with an action, via the item retrieval menu, or with a console command. If an item is removed from your completed museum, then it will no longer be considered complete. Pre-completion museum strings may be shown again. Donation hints will also be shown on qualifying items again. The player will be allowed to donate items again as long as the museum remains incomplete. Unclaimed museum rewards that required all items to be donated will become unclaimable, but they can be earned again once the museum is completed again.

However, some things are irreversible. The mail flag earned for museum completion will not be removed. The OnCompletion museum string will not be shown more than once per save file. Milestones will also only be reached once per save file. Claimed rewards that required museum completion will of course not be revoked nor will any of their mail flags be removed.

See also: Invalid Donations.

Museum Ownership

While the vanilla museum has an owner, your custom museum does not need to have one. It can be a location with nobody in it while still allowing the player to donate items. If you do not wish for your museum to be run by any NPC in particular, you would set the entire Owner field to null in your JSON.

However, if you do wish to have an NPC running your museum, then an OwnerData object consists of the following fields:

FIELD PURPOSE
Name The internal name of the NPC that runs your museum.
RequiredForDonation (Optional) A bool for whether or not the owner must be present and "clocked in" for the player to be allowed to donate items.
Default false
Area (Optional) A Rectangle in the form of { "X": 0, "Y": 0, "Width": 0, "Height": 0} that defines the area in which the owner must be standing in order to be considered "clocked in" and for the player to be allowed to donate items. If no area is set, then the owner only must be present anywhere in your museum to be considered clocked in. This field only affects donating if RequiredForDonation is true, however it may still matter for your museum strings.
Default null

Donation Requirements

If you do not set any donation requirements for your museum, then your museum will accept no items at all, and will hardly be worthy of being called a museum. In order to determine what items the player can donate to your museum, you must provide the DonationRequirements field of your MuseumData with a list of DonationRequirement objects. Each DonationRequirement object consists of the following fields:

FIELD PURPOSE
Id The string Id of this entry in your DonationRequirements list. While this does not need to be globally unique, it must be unique across all of the requirements in your museum.
Categories (Optional) A list of integers where each integer corresponds to a category of items. You may add any number of categories to this list and, if an item matches any of them, it will meet this category requirement.
Default null
ContextTags (Optional) A list of context tags. You may add any number of context tags to this list and, if an item has any of them, it will meet this context tag requirement.
Default null
ItemIds (Optional) A list of qualified item Ids. You may add any number of item IDs to this list and, if an items qualified item ID matches any of them, it will meet this item ID requirement.
Default null
MatchType (Optional) Determines whether an item must meet every filled out requirement or any filled out requirement in order to be considered a valid donation. Allowed values are All and Any respectively. See below for further explanation.
Default Any

As you can see, all three of Categories, ContextTags, and ItemIds are optional. However, you must fill out at least one of them for it to be a valid requirement, otherwise it will be skipped. As long as at least one of those fields is filled out, then any requirement type that is not filled out will be ignored when checking whether an item is a valid donation. For example, if you provide a list of categories, but leave the context tag and item Ids null or do not include them, then Custom Museum Framework will only check whether a potential donation has any of the categories in your list. Similarly, if you provide a list of categories and a list of item IDs, then Custom Museum Framework will check the category and item ID of a potential donation in order to see if it's valid, but it will not look at the context tags of the item.

MatchType All vs. Any

The MatchType comes into play when you fill out two or more of the requirement types. If MatchType is set to All, then an item must pass every listed requirement in order to be donated. For example, if you gave it a list of categories and a list of item Ids, then an item must have one of those item Ids and have one of the listed categories at the same time in order to be donated. If MatchType is set to Any, then the item only needs to pass at least one of the requirements. Using the same example, if the item had one of the listed item IDs but did not match any category, it would still be a valid donation, and vice versa if it had one of the listed categories but did not match any listed item ID. This MatchType behaviour applies if you fill out all three of the requirement types as well.

Remember, DonationRequirements is a list. Feel free to add as many different requirements as you'd like. However, be aware that the MatchType behaviour described above will only apply on a per DonationRequirementbasis and will not apply any restrictions or freedoms to other DonationRequirement objects in your list. If an item passes at least one of the DonationRequirement objects in your list, it will be considered a valid donation item.

Pedestal Interactions

In the vanilla museum, when you interact with an item that has been donated to the museum, you get a little pop-up message on your screen with the name of the item and its description. In Custom Museum Framework, you are able to customize this interaction behaviour for your items. An InteractionData object consists of the following fields:

FIELD PURPOSE
Id The string Id of this InteractionData object.
InteractionType (Optional) The type of interaction that should occur when the player clicks on an item in a pedestal. Allowed values are Default, Sign, Message, Letter, Custom, or None. A value of Default in the context of item pedestal interactions is equivalent to Sign, which is the same behaviour as the vanilla museum. Message and Letter perform identically to their respective map actions. Custom will tell Custom Museum Framework to do whatever action you wrote in the Action field (described below) instead of displaying a message. A value of None means nothing will happen at all when the player clicks on an item pedestal.
Default Default
Text (Optional) The text that will be displayed when showing a Default, Sign, Message, or Letter interaction. This field is ignored if InteractionType is set to Custom or None. This field will apply text substitutions, meaning that if you write {0}, {1}, {2}, or {3} inside your text, those bits will be replaced with the item display name, item description, museum display name, and item qualified ID respectively. This field also supports tokenizable strings which will be parsed after the aforementioned substitutions.
Default - {0} - ^{1}

Substitutions will replace numbers within braces. For example, {0} - ^{1} may become Parsnip - ^A spring tuber closely related to the carrot.

Action (Optional) An action string that will be run when the player interacts with an item pedestal. This field will get the same substitutions described in the Text field above applied in the same order.
Default null

In addition to PedestalAction, which is applied globally to every donatable item, you can also choose to use a custom interaction on a per-item basis by adding some data to that items CustomFields section in its Data/Objects entry. You must add a new CustomFields entry with the key Spiderbuttons.CMF/PedestalAction and a value that is an action string that you would like to run when that item is interacted with on a museum pedestal. You may also add another custom field with the key Spiderbuttons.CMF/PedestalOverride and a value of either true or false. If you set this entry to false, then both the global PedestalAction and your action described in CustomFields will both run, with your CustomFields action running first. If you set this override value to true or omit it entirely (since true is the default), then only the action string defined in your Spiderbuttons.CMF/PedestalAction entry will run, skipping the global PedestalAction entirely.

Like with the global PedestalAction, an action string defined in an objects CustomFields dictionary will also receive the same substitutions described in the table above. An example is shown below:

 1
{
 2
   "Action": "EditData",
 3
   "Target": "Data/Objects",
 4
   "Fields": {
 5
      "24": {
 6
         "CustomFields": {
 7
            "Spiderbuttons.CMF/PedestalAction": "AddMail Current {{ModId}}_Interaction_{3} now",
 8
            "Spiderbuttons.CMF/PedestalOverride": "false"
 9
         }
10
      }
11
   }
12
}

Museum Rewards

The reward system for your custom museum works the same way that the reward system does for the vanilla museum, however the fields you will need to fill out are slightly different, both to account for the more flexible donation criteria that Custom Museum Framework allows and to allow more possibilities for the rewards themselves. A CustomMuseumReward object consists of the following fields:

FIELD PURPOSE
Id The string ID of this entry in your Rewards list. While this does not need to be globally unique, it must be unique across all of the rewards in your museum.
Requirements A list of CountableDonationRequirement objects defining what items must be donated to your museum in order to earn this reward. These CountableDonationRequirement objects contain the same fields as a DonationRequirement object as well as the following additional field:
  • Count - (Optional) An integer for how many items matching this requirement must be donated in order to earn the reward. Default 1
For reward data, you are allowed to leave all three of ItemIds, ContextTags, and Categories as null. If you do, then Custom Museum Framework will only check if there are Count items of any kind donated to your museum.
Every requirement in this list of requirements must be met in order for the player to earn this reward.
RewardItems A list of generic item spawn objects. Every item in this list will be given as a reward when the requirement is met.[3]
Action[4] (Optional) An action string that will be run when the player collects the reward (not when it is earned).
Default null
Actions[4] (Optional) A list of action strings that will be run when the player collects the reward (not when it is earned).
Default null
RewardIsSpecial (Optional) A bool for whether or not the items from this reward should be marked "special." Special items cannot be trashed or lost on death. In the context of a museum, it also means that any item gained from this reward can only ever be gained the one time, even if another reward contains an identical item. This "special" check is also done in some other miscellaneous places in the vanilla game. Unless you're sure of what this does, you should probably just leave this false.
Default false
FlagOnCompletion (Optional) A bool for whether or not the game should set a mail flag when the player collects the reward (not when it is earned). See Mail Flags.
Default true

This is used to track whether or not the player has collected the reward and should almost always be true. If both this and RewardIsSpecial are false, then the player will be able to collect this reward infinite times.

[3] If you are using an item query that involves choosing a random item, be aware that the RNG is seeded based on the reward Id, generic item spawn Id, and save file Id. This means that, all else being equal, the reward will not change depending on when the player earns or collects it.

[4] You may fill out both the Action field and the Actions field if you'd like, though you should probably just choose one for simplicity. The former will run first.

Rewards are checked after the player manually donates an item directly to your museum and not when the donation is the result of a trigger action. If the player earns a reward with their latest donation, sparkly text will appear on screen to let them know, just like the vanilla museum. In order for the player to collect the reward, they must interact with the MuseumMenu tile in your museum map to access the reward collection option. The museum owner (should they exist) does not need to be present for the player to be able to collect their rewards.

Museum Strings

Custom Museum Framework lets you customize nearly any text related to your museum that might be displayed to the player at some point. Any string that you do not choose to customize will display a default message instead, which you can check by looking in the i18n folder of the Custom Museum Framework mod itself.[5] You can choose to customize all of these strings or none of these strings or anything in between, therefore all of these fields can be considered optional. All of these strings support tokenizable strings, but only some will receive text substitutions, which will be documented where applicable.

These are the strings that you are able to customize:

FIELD PURPOSE
OnDonation The message shown in chat when a player donates an item to your museum. The text substitutions are {0} for the player name, {1} for the item display name, and {2} for the museum display name. If you specifically set this to null, then no message will be shown in chat at all.
OnMilestone The message shown in chat when the player(s) reaches a milestone of donated items. The text substitutions are {0} for the farm name, {1} for the number of items donated, and {2} for your museum's display name. If you specifically set this to null, then no message will be shown in chat at all.
OnCompletion The message shown in chat when the player(s) completes your museum collection. The text substitutions are {0} for the farm name and {1} for the museum display name. If you specifically set this to null, then no message will be shown in chat at all.
MenuDonate The text for the dialogue choice that opens the donation menu from the MuseumMenu tile interaction.
MenuCollect The text for the dialogue choice that opens the reward collection menu from the MuseumMenu tile interaction.
MenuRearrange The text for the dialogue choice that opens the rearrangement menu from the Rearrange tile interaction.
MenuRetrieve The text for the dialogue choice that opens the item retrieval menu from the Rearrange tile interaction. This is only shown if AllowRetrieval is true.
ClockedOut The message shown when the player tries to interact with the MuseumMenu tile when the owner is not clocked in. This is only shown if the owner is required to be present.
Busy_Owner The message shown when your museum's owner is busy and cannot interact with the player. This is only shown when an owner exists and is currently clocked in. This string supports the standard NPC dialogue format.[6]
Busy_NoOwner The message shown when your museum is busy and a player cannot interact with it. This is only shown when an owner does not exist or is currently clocked out.
MuseumComplete_Owner The message shown when the player interacts with the MuseumMenu tile after your museum is completed. This is only shown when an owner exists and is currently clocked in. This string supports the standard NPC dialogue format.[6]
MuseumComplete_NoOwner The message shown when the player interacts with the MuseumMenu tile after your museum is completed. This is only shown when an owner does not exist or is currently clocked out.
NothingToDonate_Owner The message shown when the player interacts with the MuseumMenu tile but has nothing to donate and no rewards to collect. This is only shown when an owner exists and is currently clocked in. This string supports the standard NPC dialogue format.[6]
NothingToDonate_NoOwner The message shown when the player interacts with the MuseumMenu tile but has nothing to donate and no rewards to collect. This is only shown when an owner does not exist or is currently clocked out.
NoDonations_Owner The message shown when the player interacts with the MuseumMenu tile but has nothing to donate and there are no donations in your museum yet. This is only shown when an owner exists and is currently clocked in. This string supports the standard NPC dialogue format.[6]
NoDonations_NoOwner The message shown when the player interacts with the MuseumMenu tile but has nothing to donate and there are no donations in your museum yet. This is only shown when an owner does not exist or is currently clocked out.
CanBeDonated The hint shown in an item description to let the player know that the item can be donated to your museum. This string is only shown if ShowDonationHint is true.

[5] Some of the default strings have text substitutions in them that are not documented here. These text substitutions are unnecessary if you have complete control over the string when customizing them and may be subject to changing or being removed completely in future Custom Museum Framework versions. Therefore, you should not rely on any undocumented text substitutions when customizing your strings.

[6] While you can use the standard NPC dialogue format here, be aware that any dialogue that requires the player to interact with the NPC again to finish the rest of the dialogue will not be shown. Once the dialogue box is closed, the interaction is over.

Item Retrieval

In vanilla, once you donate an item to the museum, there is no way to get that item back. By default, this is the case with your custom museum as well, however you have the option to change that if you wish by setting the AllowRetrieval property in your museum data to true. Whether or not you actually would want to is entirely up to you, but you should carefully consider it if your museum accepts items that the player may not want to lose, even if they can get them back via other means. For example, if your museum accepts tools, the player would probably be unhappy if they accidentally donated their pickaxe or hoe and had no option to get it back. On the other hand, if your museum only accepts custom items that you've created whose sole purpose is to be donated to your museum, then the player probably doesn't need to retrieve them again in the future.

If you do allow item retrieval, then the player will have an extra option available to them when interacting with your museum tiles (see the Museum Maps documentation). Once the player selects the option to retrieve items from your museum, a chest menu will open on their screen containing every item currently in your museum (though it will only display up to whatever the maximum size of a normal chest is). As long as this chest remains open, the player can freely take items out. They can also freely place items back in as long as the item in question was taken out of this chest menu during this interaction. Once an item is removed from this chest, it is removed from the museum. Any relevant mail flags will not be removed, however unclaimed rewards requiring that item may disappear if the player no longer meets the reward requirements, in which case the reward can be re-earned once the item is donated again.

If your museum only accepts items that a player should be fine with losing permanently, then you are safe to disallow item retrieval entirely. However, be aware that the player may still retrieve items from your museum if they use the included console commands to do so, which will always allow item retrieval in case of a bug or other reason that a player may need to force item retrieval.

Invalid Donations

It is possible to end up with items donated to your museum that do not actually meet any of your donation requirements and thus don't actually belong in your museum according to its data. This may or may not be intentional or desired. By default, these invalid donations do not count towards museum progress in any regard. They will not count towards museum completion or milestones, they will not count for certain[7] museum rewards, they will not count for certain[7] museum quests, and they will not count for the MUSEUM_DONATIONS or IS_ITEM_DONATED game state queries.[8] They will remain in your museum and the player can still interact with them, but the museum will ignore them otherwise.

However, if you set your CountInvalidDonations field to true instead, then invalid donations will be counted for all of those things. Your museum will no longer care whether or not the item belongs, it will only care about the fact that the item is donated and count it alongside the valid donations. If any of your quests or rewards rely on invalid donations being counted in order for the player to earn or complete them, you will probably want to set CountInvalidDonations to true.

[7] Rewards and quests that only require a certain number of items donated without any other requirement will not count invalid donations by default. However, if the reward or quest specifies other requirements, then invalid donations will be counted no matter what so long as they meet those requirements.

[8] Invalid donations will still be checked when using the MUSEUM_HAS_ITEM game state query.

Complete Example

 1
{
 2
   "Action": "EditData",
 3
   "Target": "Spiderbuttons.CMF/Museums",
 4
   "Entries": {
 5
      "{{ModId}}_Museum": {
 6
         "Id": "{{ModId}}_Museum",
 7
         "Owner": {
 8
            "Name": "Penny",
 9
            "Area": {
10
               "X": 4,
11
               "Y": 9,
12
               "Width": 5,
13
               "Height": 5
14
            }
15
         },
16
         "Bounds": {
17
            "X": 10,
18
            "Y": 10,
19
            "Width": 13,
20
            "Height": 7
21
         },
22
         "ShowDonationHint": true,
23
         "OverrideDescription": false,
24
         "PedestalAction": {
25
            "Id": "{{ModId}}_MyInteractionData",
26
            "InteractionType": "Letter",
27
            "Text": "Wow! {0} was donated to {2} and it says {1} on it..."
28
         },
29
         "DonationRequirements": [
30
            {
31
               "Id": "{{ModId}}_RedStuffPlusOthers",
32
               "ItemIds": [
33
                  "(O)24",
34
                  "(O)60",
35
                  "(W)47"
36
               ],
37
               "ContextTags": [
38
                  "color_red"
39
               ],
40
               "Categories": null,
41
               "MatchType": "Any"
42
            }
43
         ],
44
         "AllowRetrieval": true,
45
         "Rewards": [
46
            {
47
               "Id": "{{ModId}}_FirstReward",
48
               "Requirements": [
49
                  {
50
                     "Id": "{{ModId}}_ParsnipRequirement",
51
                     "ItemIds": [
52
                        "(O)24"
53
                     ],
54
                     "Count": 1
55
                  }
56
               ],
57
               "RewardItems": [
58
                  {
59
                     "Id": "{{ModId}}_EmeraldReward",
60
                     "ItemId": "(O)60"
61
                  }
62
               ]
63
            }
64
         ],
65
         "Milestones": [
66
            5,
67
            10,
68
            15,
69
            20
70
         ],
71
         "Strings": {
72
            "OnDonation": "{0} donated a {1} to {2}!",
73
            "OnMilestone": "{0} donated {1} pieces to the {2}!",
74
            "OnCompletion": "{0} completed the {1} collection!",
75
            "MenuDonate": "Donate Item",
76
            "MenuCollect": "Collect your stuff",
77
            "MenuRearrange": "Rearrange Museum",
78
            "MenuRetrieve": "Retrieve Items",
79
            "Busy_Owner": "I'm busy right now.",
80
            "Busy_NoOwner": "Someone else is using the museum.",
81
            "MuseumComplete_Owner": "Wow, you found all the items! Thank you so much!",
82
            "MuseumComplete_NoOwner": "The museum is finished. Done. Complete. Nothing left...",
83
            "NothingToDonate_Owner": "You don't have anything to donate...$s#$b#Come back when you do, okay?",
84
            "NothingToDonate_NoOwner": "don't have have anything to donate.",
85
            "NoDonations_Owner": "Yeah... we don't have anything donated yet. Sorry!",
86
            "NoDonations_NoOwner": "There is nothing in any of the displays."
87
         }
88
      }
89
   }
90
}