← README
Content pack guide
aka how to use JSON API for creating content packs with your custom quests.
Introduction
What is quest framework?
Quest framework is a "core" mod which provides a tools for work with quests in StardewValley. In the JSON api you can do these things:
- Create custom quests
- Handle quests with predefined hooks
Define quest
Prepare content pack
For more info about SMAPI content packs see How to create content pack
Create your manifest.json
file which must contains these minimum contents:
{
"Name": "Your Project Name",
"Author": "your name",
"Version": "1.0.0",
"Description": "One or two sentences about the mod.",
"UniqueID": "YourName.YourProjectName",
"MinimumApiVersion": "3.6.0",
"UpdateKeys": [],
"ContentPackFor": {
"UniqueID": "PurrplingCat.QuestFramework", // Quest Framework unique id must be here
"MinimumVersion": "1.2.0" // optional
}
}
Then create file quests.json
and follow next instructions.
The content pack format
Your quests.json
has this format:
{
"Format": "1.0", // this is required
"Quests": [
// (optional) quests are defined here
],
"Offers": [
// (optional) quest offers are defined here
],
"CustomBoards": [
// (optional) define your custom quest or special order boards here
],
"CustomDropBoxes": [
// (optional) define your custom drop boxes for your special orders here
],
}
Quest basics
In the Quests
section you can define one ore more custom quests. Quest definition has these fields:
Field | Required? | Description |
---|---|---|
Name | required | string Name (UID) of your quest (this never shows to player) |
Type | required | string Vanilla SDV quest type (see quest type) |
CustomTypeId | int Custom Quest type id (see custom quest types in advanced API). Can be handled by any other mod. |
|
Title | required | string Quest title in the quest log |
Description | string Quest description |
|
Objective | required | string Quest objective |
NextQuests | string[] One of more next quests which will be added to player's quest log when this quest is completed. |
|
DaysLeft | int If this field is filled or is greater than 0, this quest is marked as daily and limited for specified number of days here. |
|
Reward | int|string Reward in SDV currency "golds". If this field is not defined or has value 0 , then player will receive no money reward. |
|
RewardType | RewardType Type of reward for player. (default: Money) |
|
RewardAmount | int Amount of reward items. Only for Object reward type. |
|
RewardDescription | string Reward description |
|
Cancelable | boolean Can player cancel this quest? |
|
ReactionText | string NPC's reaction text when you complete this quest (only for quests which interacts with NPCs) |
|
Trigger | string Completion trigger (see quest types for more info) Supports JSON Assets |
|
Texture | string Path to PNG file with custom background texture for this quest in quest log menu. Path is relative to your content pack root directory. |
|
Colors | QuestLogColors Settings of font colors for this quest in the quest log menu. |
|
FriendshipGain | {[string]: int} Additional friendship points for enumarated NPCs which player gains after this quest was completed. |
|
Hooks | Hook[] Quest hooks (see hooks for more info) |
|
ConversationTopic | ConversationTopic Add or remove conversation topic (see conversation topic for more info) |
|
AddMailOnComplete | Receive the mail(s) by player after quest is completed. Supported multiple letter names. See Completion Mails for more details | |
RemoveMailOnComplete | Remove already received mail from player (clear mail flag) after quest is completed. Supported multiple letter names. See Completion Mails for more details |
Example
{
"Format": "1.0",
"Quests": [
{
"Name": "abigail_amethyst", // No id needed, will be automatically generated
"Type": "ItemDelivery", // Vanilla quest type
"Title": "The purple lunch",
"Description": "Abigail are very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"DaysLeft": 5, // If player don't complete this quest until 5 days, this quest will be removed from quest log automatically without completion
"Reward": 300, // 300g
"RewardType": "Money",
"Cancelable": true, // This quest can be cancelled by player
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, it's looks delicious. I am really hungry.",
"FriendshipGain": {
"Abigail": 100 // Gain 100 additional friendship points when this quest was completed
}
}
]
}
Quest types
This part describes only vanilla StardewValley quest types existing in the game. If you want to define custom quests, see the Advanced API guide or Hooks bellow. For more information about SDV quests see the Quests wiki and Modding quest data
Basic
The basic SDV quest which is handled properly by the game (this is hardcoded in vanilla game).
Trigger: No trigger for this quest type
Building
Build a building quest. Hardcoded in SDV, but you can define which building type must player build for complete this quest (in the Trigger
property)
Trigger: Building type name (like Coop
). For available building types see Data/Blueprints
SDV content resource.
Crafting
Craft a specified item.
Trigger: <int:item_id> <boolean:is_bigcraftable>
(like 13 true
for craft furance to complete this quest).
See the Data/ObjectInformation
game resource for available items.
ItemDelivery
Deliver specified item to specified NPC.
Trigger: <string:NPC_name> <int:object_id> [<int:count>]
like Abigail 66
for bring Amethyst to Abigail, Abigail 66 5
for bring 5 pieces of Amethyst to Abigail; or Willy {{ja:Fish Oil}}
if you want to use JsonAssets item (JsonAssets required for use JA token)
See the Data/ObjectInformation
game resource for available items.
This quest type accepts ReactionText
.
ItemHarvest
Harvest or pick specific count of specific items.
Trigger: <int:item_id> <int:count>
like 334 3
for harvest 3 pieces of copper bar to complete this quest.
See the Data/ObjectInformation
game resource for available items.
Location
Go to specified location.
Trigger: Location name like Town
for complete this quest when player enters Town.
LostItem
Find a lost item and deliver it to an NPC.
Trigger: <string:NPC_name> <int:item_id> <string:Location_name> <int:TileX> <int:TileY>
like Robin 788 Forest 110 81
bring Robin Axe to robin which are spawned in Forest on tile location X=110; Y=81
.
See the Data/ObjectInformation
game resource for available items.
This quest type accepts ReactionText
.
Monster
Slay a specified count of specified monster.
Trigger: <string:Monster_name> <int:count> [<string:talkWithNpc>]
(monster name can't contain spaces. Replace spaces with _
in monster name) like Green_Slime 10
slay 10 Green slimes to complete this quest. Bat 5 Lewis
means slay five bats and then talk with Lewis to complete this quest.
SecretLostItem
Same usage as LostItem
Custom
Custom quest type. You can specify field CustomTypeId
for more explicit which custom quest type. In JSON api you can use hooks to create custom quest handling.
You can define custom quest via setup value Custom
into field Type
or in format <modUID>/<QuestTypeName>
for custom quests defined by other mods which exposes their quest types for content packs.
Trigger: Custom defined. In JSON api use hooks instead for handle your pure JSON custom quest. If you target a custom quest type defined by any other mod in your JSON content pack, follow instructions of the source mod of this quest type.
Needs more quest types?
The Quest Essentials offers some new custom types for Quest Framework, like multi-staged quests, earn money quest type and etc.
Rewards
There are supported some reward types for quests. You can specify reward type in field RewardType
in your quest definition. Reward is paid to player after quest is completed by clicking the reward in questlog menu (in quest details for completed quest)
Reward type | Description |
---|---|
Money | Amount of money player earn by complete this quest |
Object | Which item player gets by complete this quest. You can specify your item by name (JSON assets items supported) or via their id (integer). Also you can specify amount (stack) of this item in field RewardAmount |
Weapon | Which weapon player gets by complete this quest. You can specify your weapon by name (JSON assets items supported) or via their id (integer) |
Examples
{
"Format": "1.0",
"Quests": [
{
"Name": "abigail_amethyst1",
"Type": "ItemDelivery",
"Title": "The purple lunch",
"Description": "Abigail are very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"DaysLeft": 5,
"Reward": "Chocolate Cake",
"RewardType": "Object"
"RewardAmount": 2, // Player gets two chocolate cakes after complete this quest
"Cancelable": true, // This quest can be cancelled by player
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, it's looks delicious. I am really hungry."
},
{
"Name": "abigail_amethyst2",
"Type": "ItemDelivery",
"Title": "The purple lunch again",
"Description": "Abigail are very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"DaysLeft": 3,
"Reward": "Emerald", // Reward is 1x emerald for this quest
"RewardType": "Object"
"Cancelable": true, // This quest can be cancelled by player
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, it's looks delicious. I am really hungry."
},
{
"Name": "clint_copperbar",
"Type": "ItemDelivery",
"Title": "Clint needs a copper bar",
"Description": "Clint asked you if you can bring him a copper bar.",
"Objective": "Bring a copperbar to Clint",
"Reward": 320, // Reward is 320g
"RewardType": "Money"
"Cancelable": true,
"Trigger": "Clint 334", // Bring copper bar to Clint
"ReactionText": "Thanks."
},
{
"Name": "marlon_slay_bats",
"Type": "Monster",
"Title": "Dangerous mine bats",
"Description": "Marlon wants help with slay dangerous bats which threaten villagers in the mountains every night",
"Objective": "Slay 10 bats",
"DaysLeft": 2,
"Reward": "Pirate's Sword", // Pirate's Sword is an reward for this quest
"RewardType": "Weapon"
"Cancelable": true,
"Trigger": "Bat 10", // Kill 10 bats
}
]
}
Completion mails
By adding fields AddMailOnComplete
and/or RemoveMailOnComplete
you can specify which mails will player receive after quest is completed, or which already received mail will be forgotten by player.
Add mail on complete is usefull for controll your custom events based on quests or for some other purposes. You can use mail name of received mail with Content Patcher in their condition system for control loading assets in dependency on quest completion and etc. You can specify multiple mails and with some flags. The format of a mail entry is:
<letterId> [noletter|tomorrow|everyone]
noletter
mail is received immediatelly without letter in farmer's mailboxtomorrow
mail will be received at morning (next day)everyone
mail will be received by farmer and by all farmhands recognized in multiplayer game (for single player is the same behaviour as without this flag)
You can combine all of these flags per letter record. For the RemoveMailOnComplete
you can use only the flag everyone
. Mails to remove are removed immediatelly after complete quest, other flags are ignored and unread mails in the mailbox are not affected.
{
"Format": "1.0",
"Quests": [
{
"Name": "abigail_amethyst1",
"Type": "ItemDelivery",
"Title": "The purple lunch",
"Description": "Abigail are very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"DaysLeft": 5,
"Reward": "Chocolate Cake",
"RewardType": "Object"
"RewardAmount": 2, // Player gets two chocolate cakes after complete this quest
"Cancelable": true, // This quest can be cancelled by player
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, it's looks delicious. I am really hungry."
"AddMailOnComplete:" "happy_abby noletter, abby_eats_rocks tomorrow everyone" // two mails will be received after this quest is completed
}
]
}
Colors & Texture
Be different! You can specify background texture of quest details window in quest log menu. Just specify an relative path to your content pack root in field Texture
for your quest. Also you can customize text colors for this quest with field Colors
.
Color property | Type | Desription |
---|---|---|
TitleColor | int |
Color of quest title. |
TextColor | int |
Standard quest color (for decription) |
ObjectiveColor | int |
Color of quest objective |
Available colors
Color id | Description |
---|---|
0 | Black |
1 | Sky Blue |
2 | Red |
3 | Purple |
4 | White |
5 | Orange Red |
6 | Lime Green |
7 | Cyan |
8 | Grey |
Example
{
"Format": "1.0",
"Quests": [
{
"Name": "abigail_amethyst", // No id needed, will be automatically generated
"Type": "ItemDelivery", // Vanilla quest type
"Title": "%i18n:abigail_amethyst.title",
"Description": "Abigail is very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"DaysLeft": 10,
"Reward": 1000,
"RewardType": "Money",
"Cancelable": true,
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, this looks so delicious. I am really hungry, thank you, @!$h",
"CustomField": "%i18n:custom.field",
"Texture": "assets/wizardQuest.png",
"Colors": {
"TitleColor": 4,
"TextColor": 4,
"ObjectiveColor": 1
}
}
]
}
Conversation topic
Conversation topic can make the character speak of certain dialogue when the specific conversation topic is active. Please refer to the conversation topic explanation on the wiki before using this feature. With this field you can make NPCs give dialogue when a quest is accepted, cancelled, and or completed. The respective dialogue itself must be added using Content patcher
Options
Valid field | Example value | Description |
---|---|---|
AddWhenQuestAccepted | AbigailLookingForward 2 CarolineConcerned 5 |
The keys of the conversation topic to be added and its duration after a quest is accepted. In the example after the quest is accepted it will activate two conversation topics: AbigailLookingForward for 2 days and CarolineConcerned for 5 days. |
AddWhenQuestRemoved | AbigailDisappointed 3 |
The keys of the conversation topic to be added and its duration after a quest is removed. In the example after the quest is removed it will activate a conversation topic: AbigailDisappointed for 3 days. |
AddWhenQuestCompleted | AbigailSeenEatingRock 10 AbigailHappier 2 |
The keys of the conversation topic to be added and its duration after a quest is completed. In the example after the quest is completed it will activate two conversation topics: AbigailDisappointed for 3 days and AbigailHappier 2. |
RemoveWhenQuestAccepted | AbigailLookingForward |
The key of the conversation topic to be removed. The conversation topic will end before the set when the quest is accepted. In the example after the quest is acappted it will remove the conversation topics: AbigailLookingForward. |
RemoveWhenQuestRemoved | AbigailLookingForward |
The key of the conversation topic to be removed. The conversation topic will end before the set when the quest is removed. |
RemoveWhenQuestCompleted | AbigailLookingForward |
The key of the conversation topic to be removed. The conversation topic will end before the set when the quest is completed. |
Example
{
"Format": "1.0",
"Quests": [
{
"Name": "abigail_amethyst", // No id needed, will be automatically generated
"Type": "ItemDelivery", // Vanilla quest type
"Title": "The purple lunch",
"Description": "Abigail are very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"DaysLeft": 5, // If player don't complete this quest until 5 days, this quest will be removed from quest log automatically without completion
"Reward": 300, // 300g
"Cancelable": true, // This quest can be cancelled by player
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, it's looks delicious. I am really hungry.",
"ConversationTopic": {
"AddWhenQuestAccepted": "add_abigail_amethyst_accepted 7",
"AddWhenQuestRemoved": "add_abigail_amethyst_removed 7",
"AddWhenQuestCompleted": "add_abigail_amethyst_completed 7",
"RemoveWhenQuestAccepted":"remove_abigail_amethyst_accepted",
"RemoveWhenQuestRemoved": "remove_abigail_amethyst_removed",
"RemoveWhenQuestCompleted": "remove_abigail_amethyst_completed",
// Use only what is needed. The field explain itself.
// Any string is fine as long as it is unique. You'll need to add the same key to respective character dialogue using content patcher.
}
}
]
}
Common global conditions
These global conditions can be used in hooks or in the quest offers.
Condition name | Example value | Description |
---|---|---|
Weather | sunny |
Current weather. Allowed values: rainy , snowy , stormy , cloudy , sunny |
Date | 17 spring , 5 summer Y2 |
Game date in format <day> <season> or <day> <season> Y<year> |
Days | 2 6 12 |
Trig action only when today is one of these days. You can specify any count of days. |
Seasons | summer fall |
Trig action only when current season is on of these seasons. You can specify any count of seasons. |
DaysOfWeek | monday wednesday |
Trig action when today's weekday is one of these weekdays. You can specify any count of weekdays. |
FriendshipLevel | Abigail 8 , Maru 5 Shane 4 |
Trig action when friendship heart level is the same as specified value for specified NPC. You can specify more than one friendship heart level conditions. Replacement for the previous Friendship. |
FriendshipStatus | Abigail Dating , Maru Divorced Shane Married |
Trig action when friendship status is the same as specified value for specified NPC. You can specify more than one friendship status conditions. Allowed status values: Friendly , Engaged , Married , Divorce |
MailReceived | CF_Fish |
Trig action when mail with the specified id was received by farmer. |
EventSeen | 3910674 |
Trig action when event with this event id seen by player. |
MinDaysPlayed | 34 |
Minimum played days from start of new game (from 1 spring year 1) |
MaxDaysPlayed | 51 |
Maximum played days from start of new game (from 1 spring year 1) |
DaysPlayed | 19 |
Total played days from start of new game (from 1 spring year 1) |
IsPlayerMarried | yes or no |
Is player married? |
QuestAcceptedInPeriod | season or season year or today or season year weekday |
Checks if this quest was accepted in current specified time period. The input could be combinations of: day , weekday , season , year , date . Value season year means quest was accepted in this year in current season and in any day; season means quest was accepted in current season in any year and any day; today means quest was accepted just today. |
QuestAcceptedDate | 17 spring , 5 summer Y2 |
Checks if this quest was accepted in specified date. Game date in format <day> <season> or <day> <season> Y<year> |
QuestCompletedDate | 17 spring , 5 summer Y2 |
Check if this quest was completed in specified date. Game date in format <day> <season> or <day> |
QuestAcceptedToday | yes or no |
Check if this quest was (or wasn't) accepted today |
QuestCompletedToday | yes or no |
Check if this quest was (or wasn't) completed today |
QuestNeverAccepted | yes or no |
Check if this quest was (or wasn't) never accepted yet |
QuestNeverCompleted | yes or no |
Check if this quest was (or wasn't) never completed yet |
SkillLevel | Farming 1 , Foraging 2 Fishing 3 Mining 2 |
Check if player skill level equal or higher than what is defined. Allowed skill values: Farming , Fishing , Foraging , Mining , Combat , Luck |
IsCommunityCenterCompleted | yes or no |
Check if community center is already completed. |
BuildingConstructed | Coop or Deluxe_Coop Well Coop |
Check if specified building is currently present in farm. |
KnownCraftingRecipe | Furnace |
Player knows specified crafting recipe. |
KnownCookingRecipe | Fried Egg |
Player knows specified cooking recipe. |
HasMod | PurrplingCat.NpcAdventure |
Checks if mod with specified mod UID(s) are loaded in SMAPI. You can put here one or more mod UIDs. |
Random | 52 or 22.272 |
A random chance in % (0 - 100). Number 52 means 52% of chance, number 22.272 means 22.272% of chance. |
EPU | EPU string like !z spring/t 600 1000 |
Condition processed by Expanded Preconditions Utility. For use this condition, EPU must be installed in SDV mods folder. See EPU docs for more information. |
HasItemInInventory | Battery Pack , item_amethyst , food_sweet, food_bakery |
Check if player has an item in inventory matches given name or context tags. |
HasActiveQuest | myQuest@purrplingcat.myquestpack , myQuest@purrplingcat.myquestpack another@obamoose.questpack |
Check if one or more of named quests are active in player's quest log. Named quests must be managed by QF. |
CurrentLocation | Town , Farm and etc |
Check if player's current location is the specified location in this condition by location name. |
Every condition name enlisted in this common conditions list you can prefix with not:
for negate condition result.
For example: not:EventSeen
means event with specified id was not seen by player;
Also you can chain condition values with OR
logic function with character separator |
:
{
"Weather": "rainy | snowy", // Means current weather is 'rainy' OR 'snowy'
"Date": "6 summer Y1 | 19 fall Y1 | 24 spring Y3", // Means current date is '6th summer year 1' OR '19th fall year 1' OR '24th spring year 3'
"EventSeen": "335478 | 44125", // Means player seen event ID 335478 OR event ID 44125
"not:MailReceived": "ccComplete | jojaMember" // Player NOT received mail 'ccComplete' OR 'jojaMember'
}
Offers
You can define offers. Offers are descriptions of when and by which source your quest will be delivered to player to accept (add to quest log). You can define one or more offers (for different or for the same quest).
Field | Description |
---|---|
QuestName | (string) Quest for schedule to offer (available for add to quest log). |
OfferedBy | (string) Which source offers this quest to accept. (See quest sources bellow) |
OfferDetails | (custom) Details for quest offer. This field is customized. (Optional. See quest sources bellow) |
When | (dictionary<string, string>) When this quest will be offered (see environment conditions). |
OnlyMainPlayer | (boolean) Set to true if you want to offer this quest only for main player (server). |
Quests sources
These are the available quests sources provided by native Quest Framework. Some sources require defined offer details. There are different offer details based on the source.
Bulletinboard
Offers quest on bulletinboard located in front of the seeds shop (Pierre). Quest is offered on the board every day (morning).
This source NOT requires or accepts any offer details
{
"Format": "1.0",
"Quests": [
{
"Name": "abigail_amethyst", // No id needed, will be automatically generated
"Type": "ItemDelivery", // Vanilla quest type
"Title": "The purple lunch",
"Description": "Abigail are very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"Reward": 300, // 300g
"Cancelable": true,
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, it's looks delicious. I am really hungry.",
}
],
"Offers": [
{
"QuestName": "abigail_amethyst",
"OfferedBy": "Bulletinboard",
"When": {
"DaysOfWeek": "Monday Thursday Friday",
"Seasons": "spring fall",
}
}
]
}
Custom board
You can offer your quest on your custom quest board. Just use Board:<boardName>
in quest offer field OfferedBy
.
Quest is offered on the board every day (morning).
This source NOT requires or accepts any offer details
{
"Format": "1.0",
"Quests": [
{
"Name": "bat_problem",
"Type": "Monster",
"Title": "The bat problem",
"Description": "Bats are attacking the town every night. Slay some bats and make town more safe.",
"Objective": "Slay 10 bats",
"Reward": 500, // 500g
"DaysLeft": 10,
"Cancelable": false,
"Trigger": "Bat 10"
}
],
"Offers": [
{
"QuestName": "bat_problem",
"OfferedBy": "Board:TestBoard",
},
"When": {
"Weather": "sunny"
}
}
],
"CustomBoards": [
{
"BoardName": "TestBoard",
"Location": "Farm",
"Tile": "70,8"
}
]
}
NPC
NPC can offer your quest via dialogue (speak with them and get a quest)
Requires these offer details
Field | Description
------------ | -----------
NpcName | (string) Which NPC offers this quest.
DialogueText | (string) What to NPC say to offer this quest.
Secret | (bool) If this is true
, then the quest exclamation mark indicator about NPC head is hidden. (default is false
)
NOTE: If you are using a Random
condition in offer conditions, it's highly recommended set Secret
in the offer details to true
. Otherwise the quest exclamaiton mark indicator may blink!
{
"Format": "1.0",
"Quests": [
{
"Name": "abigail_amethyst", // No id needed, will be automatically generated
"Type": "ItemDelivery", // Vanilla quest type
"Title": "The purple lunch",
"Description": "Abigail is very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"Reward": 300, // 300g
"Cancelable": true,
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, this looks so delicious. I am really hungry, thank you, @!$h"
}
],
"Offers": [
{
"QuestName": "abigail_amethyst",
"OfferedBy": "NPC",
"OfferDetails": {
"NpcName": "Abigail", // Speak with Abigail to get this quest
"DialogueText": "I have a craving for something special.#$b#@, can you bring me amethyst?"
},
"When": {
"DaysOfWeek": "Monday Thursday Friday",
"Seasons": "spring fall"
}
}
]
}
Farmer can get a quest via received letter in their mailbox on the farm. Letter with offered quest is delivered to player's mailbox in the morning.
Requires these offer details Field | Description ------------ | ----------- Topic | (string) Title or topic of the letter (optional) Text | (string) Text of the quest source letter (required)
{
"Format": "1.0",
"Quests": [
{
"Name": "bat_problem",
"Type": "Monster",
"Title": "The bat problem",
"Description": "Bats are attacking the town every night. Slay some bats and make town more safe.",
"Objective": "Slay 10 bats",
"Reward": 500, // 500g
"Cancelable": false,
"Trigger": "Bat 10 Lewis", // Slay 10 bats and then talk with Lewis
"ReactionText": "Good job, @. Our town is safe for this time.#$b#Bats are big problem after mines in mountains are open again. We must be carefull."
}
],
"Offers": [
{
"QuestName": "bat_problem",
"OfferedBy": "Mail",
"OfferDetails": {
"Topic": "The bat problem",
"Text": "Hi, @,^Our town is not safe during nights, because agressive kind of bats attacking villagers and they are scared. Reduce the bat population and make this town safe again. Thanks ^ -Mayor Lewis"
},
"When": {
"Weather": "cloudy",
"Seasons": "spring summer",
"Days": "4 11 24"
}
}
]
}
Custom boards (for quests and special orders)
With the Quest Framework you can define your custom board for offer your custom quests or special orders. You can do it with field CustomBoards
in root element of quests.json
definition. This field provides an array with custom board definitions. Quest board definition contains these fields:
Field name | Type | Description |
---|---|---|
BoardName | string |
Name of your custom board |
BoardType | enum |
Type of your board. Allowed values is Quests , SpecialOrders . Default value: Quests |
Location | string |
Name of the location where is the board placed |
Tile | Point |
Tile where is the board placed. Format is <x>,<y> . |
UnlockWhen | Dict<string, string> |
(optional) Required conditions to unlock this board. When this field is not defined, no conditions are required - The board is always unlocked. |
ShowIndicator | bool |
(optional) Show the ! indicator on the board tile when the board has an active quest which can be accepted? (default is true ) |
IndicatorOffset | Vector2 |
(optional) Position offset of exclamation mark indicator on the board tile (offset is in px) |
Texture | string |
(optional) Path to a custom background texture. Path can locate local PNG asset inside content pack folder or game asset. For locate background in game assets load this texture with Content Patcher first (or by another mod, which can inject custom game assets). If this field is not defined, then board menu uses default texture. |
Custom board is placed as actionable tile to specified position in defined location. If the board is unlocked and player clicks to the board tile a board menu is shown. This board menu offers quests which refers this board. How to refer custom board in quest or special order see bellow.
Custom quest board
- Define custom board in
quests.json
in fieldCustomBoards
, give them a valid **name ** and specify the type as Quests. Also you can specify custom texture, unlock condition or disable the available quest indicator. - Create a quest offer in
quests.json
and in their fieldOfferedBy
setBoard:<yourCustomBoardName
like Board:MyQuestBoard if your board is named as MyQuestBoard in the custom board definition.
// quests.json in your content pack folder
{
/* ... */
"Offers": [
{
"QuestName": "bat_problem",
"OfferedBy": "Board:MyQuestBoard",
},
"When": {
"Weather": "sunny"
}
}
],
"CustomBoards": [
{
"BoardName": "MyQuestBoard",
"Location": "Farm",
"Tile": "70,8",
"Texture": "LooseSprites/MyQuestBoard", // This texture is added with Content Patcher
"UnlockWhen": {
"DaysPlayed": 28 // This board can be open by player after 28 days from first game day.
}
}
]
}
NOTE: Texture size for Quests
board type must be 338x198 px
.
Custom special orders board
Custom special orders are defined with Quest Framework in quests.json
in your QF content pack folder. Then you can refer your board in your special order in the content pack, which adds your special orders. Special Orders can't be defined directly with Quest Framework, you must define them with Content Patcher by editing content target Data/SpecialOrders
. In your order definition set QF:<boardName>
to field OrderType
. This special order will be offered only in your custom special orders board.
- Define custom board in
quests.json
in fieldCustomBoards
, give them a valid **name ** and specify the type as SpecialOrders. Also you can specify custom texture, unlock condition or disable the available quest indicator. - In your order definition (in Content Patcher
content.json
inEditData
change forData/SpecialOrders
) setQF:<boardName>
to fieldOrderType
. This special order will be offered only in your custom special orders board.
// quests.json in your QF content pack
{
/* ... */
"CustomBoards": [
{
"BoardName": "MySpecialOrdersBoard",
"Location": "Farm",
"Tile": "70,8",
"Texture": "LooseSprites/MySpecialOrdersBoard", // This texture is added with Content Patcher
"UnlockWhen": {
"DaysPlayed": 28 // This board can be open by player after 28 days from first game day.
}
}
]
}
// content.json in your Content Patcher content pack which adds your special orders
{
/* ... */
"Changes": [
{
"Action": "EditData",
"Target": "Data/SpecialOrders",
"Entries": {
"PurrplingCat.PurrplingOrders.AbbyRockLunch": {
"Name": "[PurrplingCat.PurrplingOrders.AbbyRockLunch_Name]",
"Requester": "Abigail",
"Duration": "Week",
"Repeatable": "True",
"RequiredTags": "",
"OrderType": "QF:MySpecialOrdersBoard", // Offer this order on MySpecialOrdersBoard custom special orders board
/* ... */
},
/* ... */
}
}
]
}
NOTE: Special orders board custom background texture must be 338x198 px
Custom drop boxes (for special orders)
If you need define special orders with objective type donation and do you want define your custom donation drop box for your special orders, we have good news for you. With Quest Framework you can do it! Just define your drop boxes in field CustomDropBoxes
in root element of your quests.json
file in your QF content pack folder. Then you can refer your drop boxes in your special orders defined with Content Patcher what you want.
Field name | Type | Description |
---|---|---|
Name | string |
Name of your custom drop box. |
Location | string |
Name of location where your drop box is placed. |
Tile | Point |
Tile where is your drop box placed. Format is <x>,<y> . |
// quests.json in QF content pack folder
{
/* ... */
"CustomDropBoxes": [
{
"Name": "MyDropBox",
"Location": "Farm",
"Tile": "69,8"
}
]
}
// content.json in your Content Patcher content pack
{
/* ... */
"Changes": [
{
"Action": "EditData",
"Target": "Data/SpecialOrders",
"Entries": {
"PurrplingCat.PurrplingOrders.AbbyRockLunch": {
"Name": "[PurrplingCat.PurrplingOrders.AbbyRockLunch_Name]",
"Requester": "Abigail",
"Duration": "Week",
"Repeatable": "True",
"RequiredTags": "",
"OrderType": "", // Or put `QF:<boardName>` you can specify which custom board offer this order (must be defined in `CustomBoards` in QF content pack field first)
"Objectives": [
{
"Type": "Donate",
"Text": "[Lumisteria.SpecialOrders.DemetriusCrabPotStudy_Objective_1_Text]",
"RequiredCount": "25",
"Data": {
"DropBox": "MyDropBox", // Your drop box name here
"DropBoxGameLocation": "Farm",
"DropBoxIndicatorLocation": "69 7",
"AcceptedContextTags": "mineral_amethyst"
}
}
],
/* ... */
},
/* ... */
}
}
]
}
Compatibility with other mods
Json Assets support
Quest Framework is compatible with JsonAssets mod. The framework supports JsonAssets objects for the Trigger
quest field via token named ja
and supports two item types: object
and bigcraftable
.
Token looks like: {{ja: <itemName> [|bigcraftable]}}
If you add suffix |bigcraftable
after item name, then Quest Framework looks in the BigCraftable sheet. Otherwise looks in Object sheet.
Example
{
"Format": "1.0",
"Quests": [
{
"Name": "willy_fish_oil", // No id needed, will be automatically generated
"Type": "ItemDelivery", // Vanilla quest type
"Title": "Fish Oil needed",
"Description": "Hi. I need a fish oil. ASAP please.\n - Willy",
"Objective": "Bring Fish Oil to Willy",
"Reward": 220, // 220g
"Cancelable": true,
"Trigger": "Willy {{ja:Fish Oil}}", // Bring Fish Oil to Willy (this item is from JA items)
"ReactionText": "This one smells very intensive! Thank you so much, @!$h"
}
]
}
Outbound
Add quest via NPC dialogue (external)
You can add known quest in Quest Framework via NPC dialogues. You can define it with content patcher (Patch Dialogue/<NPC_name>
) and add your dialogue which adds a quest to the player's questlog or edit existing dialogue line.
By place [quest:<questname> <modUID>]
to the dialogue player get a quest when speak with NPC and this dialogue line is shown.
// Some dialogue definition file
{
"yourDialogueKey": "Can you bring me an Amethyst? [´quest:bringAmethyst purrplingcat.myquestmod]"
"anotherDIalogue": "What's up? $h#$b#Are you interested to small fighting adventure?#$b#Bless your sword! [quest:slayMonsters purrplingcat.myquestmod]"
}
NOTE: By add quest via dialogue in this outbound way, you can't check the QF conditions and no exclamation mark will be shown above NPC head. But in this way you can offer a quest via question dialogue.
Hooks (obsolete)
HOOKS ARE OBSOLETE! It's not recomended this feature, because it will be removed in future versions Some of hooks features are replaced with Quest Essential's Adventure Quests.
You can add some "magic" to your custom quests with hooks. Hooks do specified action with your quests when something was triggered in the game.
Hooks has conditions for check if the action of hook will be triggered or not. There are two types of conditions: local and environment. You don't must specify all available conditions. You can specify conditions which you need.
Field | Description |
---|---|
When | When this hook will be trigered (see hook types) |
Action | Which action will be executed (see actions) |
Has | Conditions for execute the hook (see conditions and hook types). |
Example
{
"Format": "1.0",
"Quests": [
{
"Name": "my_custom_quest",
"Type": "ItemDelivery", // Vanilla quest type
"Title": "The purple lunch",
"Description": "Abigail are very hungry. She wants to eat something special from mines.",
"Objective": "Bring amethyst to Abigail",
"Reward": 300, // 300g
"Cancelable": true,
"Trigger": "Abigail 66", // Bring amethyst to Abby
"ReactionText": "Oh, it's looks delicious. I am really hungry.",
"Hooks": [
// Quest will be accepted (added to quest log)
// when farmer go near the tree on the west side of graveyard in Town
// and when is sunny weather today
{
"When": "Tile",
"Has": {
"Location": "Town",
"Area": "2038 5573 326 245",
"Weather": "sunny"
},
"Action": "Accept"
}
]
}
]
}
Actions
There are these types of actions:
Action name | Description |
---|---|
Complete | Complete the quest |
Remove | Remove the quest from player's questlog (quest is not considered complete, just removed) |
CheckIfComplete | Handles completion checker and complete the quest if inner quest conditions are met. |
Accept | Accept this quest and add it to player's quest log as new quest (has the sign new in quest log). |
Hook types
Some hook types has own specific conditions. See them bellow.
NOTE: For specialized hook type's conditions you cant't use the negation not:
prefix. This prefix is only for common conditions and for global custom conditions.
Location
This hook is triggered when player entered or leaved specific location and all other conditions are met.
Local condition | Description |
---|---|
Enter | Name of the location the player enter |
Leave | Name of the location the player left |
If you specify both, then the hook action will be triggered when player left the Leave location and entered the Enter location. For example:
Enter condition is Town
and leave condition is BusStop
. This hook trigs their action when player entered Town from the Bus Stop.
Tile
This hook is triggered when player stands on specific tile position or in specific area of specific location.
Local condition | Description |
---|---|
Location | Game location |
Position | Standing tile position (X, Y). Example 13 10 |
Area | Specified standing area (X, Y, Width, Height) Example: 2038 5573 326 245 |
TouchAction | Touch action property value must be this defined value for trig hook's action. |