To enable one of the example mods, rename its DLL file from .dll-disabled
to .dll
.
To enable a mod you downloaded, add its DLL file to the CustomMods folder in your installation folder.
If you're using the Steam version of Dawnsbury Days, you can also subscribe to mods from the Steam Workshop.
Mods don't run in any sandbox. They're executable .NET code which has full privileges on your computer. You should download mods only from authors or platforms you trust.
- Create a new .NET class library project, for example using Microsoft Visual Studio.
- Set the platform to
x64
, platform target tox64
and the target framework tonet9.0-windows
. - Reference the following assemblies from your installation folder as assembly references of your project:
- the assembly
Data/Dawnsbury Days.dll
; - the assembly
Data/Common.dll
; - the assembly
Data/MonoGame.Framework.dll
.
- the assembly
- In any one class in your project, add a public static method annotated with the attribute
DawnsburyDaysModMainMethodAttribute
. Dawnsbury Days will invoke that method when it starts up. - Add any code you want your mod to execute on startup into that method. For example, you can use
ModManager.AddFeat(...)
to add custom feats, ancestries, etc. to the game.
You can then build your project and put the output assembly .dll file into the CustomMods
folder in the installation folder, then start Dawnsbury Days. Your mod should be loaded.
It may be useful for you to set up a post-build setup that will automatically place your output assembly into the CustomMods folder for faster iteration. The file Dawnsbury.Mod.targets
in this folder can help you with that.
Or, instead of creating a .NET class library project from scratch, you can copy the project Dawnsbury.Mods.Feats.General.ImpossibleToughness
from this folder, which is a small "Hello, world"-style project, and start by modifying it. See the Example mods section just below.
You can use the example mods in this folder as inspiration, or you can decompile the Dawnsbury Days.dll
file in Data folder to check how built-in classes, feats and spells are implemented.
The example mods are:
- Dawnsbury.Mods.Feats.General.ImpossibleToughness. This is a "Hello, world!" mod which only adds one simple general feat.
- Dawnsbury.Mods.Feats.General.ABetterFleet. This mod shows how to replace an existing feat.
- Dawnsbury.Mods.Spellbook.AcidicBurst. This mod shows how to add a new spell to the game.
- Dawnsbury.Mods.Demo.Miscellaneous. This mod shows miscellaneous ModManager endpoints, such how to replace an existing spell or how to add new items.
- Dawnsbury.Mods.Creatures.Scarecrow. This mod demonstrates how to create new creatures and maps that make use of those creatures.
- Dawnsbury.Mods.Variants.AutomaticBonusProgression. This mod implements the Automatic Bonus Progression variant rule showing off some more advanced techniques.
- Dawnsbury.Mods.Ancestries.Kobold. This is a more advanced mod which adds an entire ancestry, its heritages and its ancestry feats and shows off some more advanced modding options.
- Dawnsbury.Mods.Classes.Portalist. This is another advanced mod which adds an entire class, the portalist.
Assemblies. Dawnsbury Days itself consists of two main assemblies, Dawnsbury Days.dll
and Common.dll
, both in the Data folder. The Dawnsbury Days.exe
file in the Data folder is a native launcher for that DLL file and you can't reference it.
The Dawnsbury Days.exe
file in the main game folder is a .NET Framework launcher that does nothing except launch the Dawnsbury Days.exe file in the Data folder. You can't reference it either.
The main assembly is Dawnsbury Days.dll
and it contains xmldoc documentation for many important public classes and methods in the file Dawnsbury Days.xml
right next to it. Your IDE's IntelliSense should pick it up automatically when you reference the assembly.
Namespaces. Dawnsbury Days is split into the following main namespaces:
- Audio. Contains the static class
Sfxs
that you can use to play music, voice lines and sound effects. - Auxiliary. Contains the Auxiliary framework, which is built on top of Monogame and is responsible for input/output and drawing.
- Campaign.Encounters. Defines and loads adventure path encounters, the tutorial and random encounters.
- Campaign.Path. Defines and handles savegames, player progression through the adventure path and what happens during each "campaign stop" such as an encounter, a long rest or a level up.
- Core. This is the main namespace mods may want to use. It contains the main rules subsystem, the definitions of feats, spells, monsters, combat actions and generally implements the PF2E ruleset. It contains many child namespaces.
- Animations. Contains code for particles and creatures moving across screen, as well as code for cutscenes.
- CharacterBuilder. Contains code for
CharacterSheet
, which represents a player character's character sheet and all the classes it needs. This system is further described in Dawnsbury Days rules system architecture. - CharacterBuilder.FeatsDb. The classes in this namespace implement ancestries, backgrounds, classes, class features, feats, impulses, and spells.
If you want to create a mod that adds a new feature like this, you can use the existing definitions here for inspiration and add the new feature usingModManager.AddFeat
.
If you want to update an existing feature, such as by adding a new heritage to an existing ancestry or changing the rules or properties of a feat or feature, you can make those changes to the static propertyAllFeats.All
as demonstrated by the example modDawnsbury.Mods.Feats.General.ABetterFleet
. - Coroutines. This contains the fairly complex definition of the async/await coroutine engine. If you need to have a player make a choice during the resolution of a combat action in combat, and it can't be solved by targeting, you'll need to use the
await battle.SendRequest(...)
to ask the player to make a choice. If you need to take an action that might require a player choice—which is almost anything, because almost anything can be interrupted by a reaction which needs to ask the player whether to take it—then that action will also be async and you will need toawait
it. You can find some of such common actions inCommonSpellEffects
. - Creatures. This contains information about a creature in combat, as opposed to a player character's character sheet. Monsters don't have character sheets and during combat gameplay, even a player's character sheet is mostly irrelevant and in any case read-only, and the player characters are also represented as a
Creature
. Each character sheet is converted to a Creature as a combat begins. - Intelligence. This contains pathfinding code, as well as tactics used by the computer-controlled creatures. Each creature has its own instance of the
AI
class, which determines how it values each option it can take: Each time a creature is asked to make a choice, such as if it's that creature's turn and it can move into various spaces or take various combat actions, code in this namespace evaluates most possible choices and then causes the creature to select the option with the highest value (called "AI usefulness" in the code). The creature's particular values in its AI class instance determine how it values each option. For example, normal enemies value flanking, but mindless enemies don't value flanking at all. - Mechanics. This large namespace deals with making "main checks" (attack rolls and saving throws), dealing damage, targeting, traits, bonuses and penalties, and items. The class CombatActionExecution wraps the evaluation of each combat action and uses many of these things. Determining the final check bonus and the final DC is done mostly by the static class Checks.
- Possibilities. When it's your turn, the bottom bar of the in-game screen shows all the "possibilities" that you have. Two possibilities are the most common: the ActionPossibility, which enables you to take a combat action, and the SubmenuPossibility, which expands a secondary (or potentially tertiary) bottom bar.
- Roller. These classes deal with die rolling.
- StatBlocks. These classes contain the definition of each monster, NPC or interactible item or obstacle.
- Tiles. The code of Dawnsbury Days doesn't use feet, but instead uses "tiles" or "squares", and this namespace contains code for the battlemap and the tiles.
- Display. This namespace and its child namespaces contain code that draws data on screen, manipulates text, controls drag-and-drop and it also contains some user interface controls that are not part of Auxiliary, such as the ScrollPane.
- IO. Contains auxiliary classes and methods for save/load, serialization, settings, logging, telemetry and other interaction with the outside world.
- Modding. Contains helper classes meant to help with creating custom mods. All classes in this namespace are fully documented.
- Phases. Contains so-called "phases" which represent screens. For example, MainMenuPhase represents the main menu, SettingsPhase represents the settings window and BattlePhase represents the main in-game screen. The child namespace CampaignViews contains the sections of the adventure path, such as Retraining and Shop; and the child namespace CharacterBuilderPages contains the user interface controls of the character builder, such as feat selection, spell selection or daily preparations.
All the code that pertains to combat rules, classes, feats, spells, monsters, maps and actions in combat is in the namespace Dawnsbury.Core
.
A character that you can build is represented by a CharacterSheet
in the campaign and in the random encounter mode menu, and as a Creature
during an encounter. Enemies are represented as Creature
and don't have character sheets.
Almost all choices you make during character creation, except for spells and choosing ability scores, are represented as a Feat
. Your ancestry, heritage, background, class, subclass, deity, domain and bloodline are Feat
, as are general feats, class feats and ancestry feats. These "true feats" are represented as TrueFeat
.
The way a character sheet's values (CharacterSheet.Calculated
) and choices are determined is called recalculation and is done by CharacterSheet.Recalculate
. Essentially, a character sheet begins with three choices, "ancestry", "background" and "class". Each choice allows you to choose a feat (remember, everything is a feat), and each feat may have an .OnSheet
action and an .OnCreature
action.
- The
.OnCreature
action is executed at the very end of recalculation and updates the creature's statistics and abilities during encounters, when it's represented as a Creature. - The
.OnSheet
action is executed at an appropriate point of recalculation and may cause more choices to be given to you. For example, choosing cleric as your class will give you a "doctrine" choice. Recalculation proceeds from ancestry, background and class through choices in the order they're generated, applying them as it goes, until all choices are applied or missing, at which point.OnCreature
actions of all feats are executed and recalculation concludes.
When a character sheet is serialized into your save file (during the campaign) or into your character library (during random encounter mode), only the selections you make for each choice are serialized, not the calculated values themselves.
Each action a creature can take is a CombatAction
. A combat action represents a spell, feat or action in combat directly usable by a creature, whether it needs zero actions, one action or more. For example, 'Strike (+1 longsword)', 'Demoralize' and 'Magic Missile' are combat actions. Combat actions are usually wrapped in a Possibility
object, which determines how they're displayed in the bottom bar.
A combat action contains a Target
object which represents targeting requirements or area of effect of the action, traits and whether the main roll is an attack roll, a saving throw or none. It also includes the effect of the combat action.
Spells are a good way to learn about how different kinds of effects can be coded. Look for them in the types Cantrips
, Level1Spells
and Level2Spells
, or you can look at fighter feats for some other kinds of actions in FighterFeatsDb
.
Dawnsbury Days use the async
/await
keywords to implement coroutines and allow animations and player choices to be made within the code that resolves an effect. Despite the name of the keywords, the rules system code of Dawnsbury Days is single-threaded.
In Dawnsbury Days rules code, such as within the effect code of a combat action, await
means that the rules code acknowledges that the called method may take a long time (e.g. if it's an animation or a request for player to take an action) and suspends further rules code execution until that animation completes or the player makes a decision.
Some async
methods don't run animations or request decisions but are async anyway because they might play an animation or request a decision, for example, if they contain an extension point that a creature's ability might use to interrupt an action in progress.
As a rule, if a method returns a Task, always await
it.
Conditions, auras, passive abilities, temporary markers and other status that needs to be attached to a creature are represented as a QEffect
. A QEffect has an owner, an expiration, and a large number of delegate properties (events) that generally tend to be empty. These properties are extension points that a QEffect can use to affect the game state.
For example, you may set a QEffect's BonusToDefenses
property to add a bonus to its owner's saving throws or AC; or you may set a QEffect's AfterYouDealDamage
property to code that will be executed each time its owner deals at least 1 damage to a creature.
One of the these property is called StateCheck
and it's performed during each state-check.
State-check (the name comes from "state-based effects", a similar concept from Magic: the Gathering) is an event that happens each time a creature takes its turn, each time a combat action ends and at some other times, and it recalculates the current values of all properties of all creatures.
A state-check proceeds like this:
- For each creature, many calculated properties, such as weaknesses, resistances and all effects with the expiration time of
Ephemeral
are removed. - For each creature, the
StateCheck
code of each of its QEffects applies. - If at least one StateCheck event applied during step 2, the state-check repeats from step 2. This way, you can use a StateCheck event to create another Ephemeral QEffect on yourself or another creature.
- When no more state-check events apply during step 3, the state-check ends.
To create new creatures, check the file [ABOUT CREATURE MODS.txt](Dawnsbury.Mods.Creatures.Scarecrow/ABOUT CREATURE MODS.txt) in the example Scarecrow mod.
Missing async. Some decompilers, such as the JetBrains decompiler, omit the keyword "async" in their decompiled async lambda methods. If you copy-paste such decompiled code into your project, it will either fail to compile (if it contains an await
expression) or it will function incorrectly and produce a warning. To fix this, and as a general rule, if a method signature contains Task
or Task<something>
as the return value, you must declare that method as async
. See Async/await coroutine engine.
System.Drawing.Color vs. Microsoft.Xna.Color. If your mod adds visual elements, such as a flyout overhead, it may need to specify a color using the type Microsoft.Xna.Color
. To refer to that type, your project must either reference the NuGet package MonoGame.Framework.WindowsDX
or must reference the assembly MonoGame.Framework.dll
that you'll find in the Data
folder of the game, in the same folder as Dawnsbury Days.dll
. To fix this error, add the Data/MonoGame.Framework.dll
assembly as a reference to your project.
Missing IllustrationName. If your mod adds something that needs an illustration, such as a new item or QEffect, you may want to use an existing illustration by referring to its IllustrationName
. This enum is in the Common.dll
library that you'll find in the Data
folder of the game and must also reference. To fix this error, add the Data/Common.dll
assembly as a reference to your project.
If you want to share your mod with others, and your mod contains content that you only have permission to distribute through the Open Game License or the through the ORC License, you must distribute a copyright notice alongside your mod. To do so, create your own HTML file based on the OGL template or the ORC template, and add that file into the root folder of your mod (just outside the folder CustomMods).
See the subfolder "Steam Workshop Uploader" in the game main folder for technical instructions on how to share your Dawnsbury Days mods with others using the Steam Workshop.
Dawnsbury Days has two main branches: the main branch, which most players are playing now; and the V3 version, which is an experimental prerelease branch that brings in levels 5–8 and other content that will become available when the expansion, The Profane Barrier, releases. You can switch to the V3 version by going to Steam properties of Dawnsbury Days and choosing Betas->V3.0.
If you want to publish your mod, however, you should use the main branch and you should compile your code against the main branch binary of Dawnsbury Days. That way, everyone will be able to play your mod without the mod crashing.
But if you want to prepare your mod for the new v3 version, you can create two different versions of it: you compile one against the main version of Dawnsbury Days, and one against the V3 version. You can look at the Dawnsbury.Mods.Ancestries.Kobold for inspiration on how to do this.
It's somewhat complicated:
- To create the V2 version, you must switch Steam to the main branch, set your code to be as for the V2 version, compile, and store your resultant assembly somewhere.
- To create the V3 version, you must switch Steam to the V3.0 branch, set your code to be as for the V3 version, compile, and store your assembly somewhere.
- Now place the first assembly into your workshop staging area in the folder CustomMods.
- And place the second assembly into your workshop staging area in the folder CustomModsV3.
- When you upload this into the Steam Workshop, the game will automatically select the DLL from the folder that corresponds to its version, so your mod will work the best with both versions of the base game.
If you're interested in doing this, you can read more in the readme file in the SteamWorkshopUploader folder in the main game folder, or you can reach out to me on Discord in the #mod-support channel.
Also, to prevent yourself from accidentally making a mistake, use ModManager.AssertV2()
and ModManager.AssertV3()
respectively to make sure you're compiling against the correct binaries. Again the Kobold mod can serve as inspiration.
Some parts of this repository are Open Game Content. See the individual folders for copyright notices and definitions of Open Game Content and Product Identity.
I give permission to you to use any such Product Identity for any purpose (this includes all the actual code in this repository other than rules descriptions). It doesn't include the code of the base game, which is not so openly licensed, and it doesn't apply to any images or sounds in this folder which are under a separate license.
However, I give permission to decompile, use and modify the decompiled code specifically for the purpose of creating Dawnsbury Days mods. For example, if you want to adjust how some feat works, it is okay to copy its decompiled code into your own mod, or to use it as a base for your own feat.
Note that if you create and distribute your own mod for Dawnsbury Days, and your mod makes use of OGL or ORC content, you will need to include an appropriate OGL or ORC copyright notice with your mod. The instructions on how to do so are in the Steam Workshop Uploader folder within the game.
I'm dawnsbury
on Discord and I'll be happy to answer any questions or help you with creating mods in the #mod-support
channel on the Dawnsbury Discord server.