Mod:Nebula's Mission Board/ Job callbacks
The library contains a callback system that allows modders to attach code to specific jobs to customize their behavior. It functions very similarly to how the base game handles scripted events: you attach a function name and a series of arguments to an id, and the system will fetch a function from somewhere, passing those arguments to it. Let's see exactly how this works.
Events
There are a few places in which the library checks a job's Callback field. These are called "events", and there are ten in total. Most events can also be interrupted; we will discuss how to do that next.
"JobTake": Happens when a job is taken using the board menu, or whenMissionGen:TakeJob(<board_id>, <index>)is called directly. Interrupting this event will cause it to not add the job to the taken list or mark it as taken."JobActivate": Called when a job is activated from the taken menu, or whenMissionGen:ToggleTakenJob(<index>)is called directly on a currently inactive job. Interrupting this event will cause the job to not be activated."JobDeactivate": Called when a job is deactivated from the taken menu, or whenMissionGen:ToggleTakenJob(<index>)is called directly on a currently active job. Interrupting this event will cause the job to not be deactivated."DungeonStart": Called right before checking if the job is supposed to have a guest. This event cannot be interrupted."DungeonEnd": Called right before checking for job completion. This event cannot be interrupted."FloorStart": Called at the start of the destination floor of a job, right after applying the segment's generation steps but before applying the floor's specific generation steps. Interrupting this event will prevent any battle event and floor generation step normally required by the job's type from being added to the queue."JobComplete": Called when a job is marked as completed, or whenMissionGen:MarkJobCompleted(<job>)is called directly. Interrupting this event will prevent the job from being marked as completed."JobFail": Called when a job is marked as failed, or whenMissionGen:MarkJobFailed(<job>)is called directly. Interrupting this event will prevent the job from being marked as failed."BeforeReward": Called right before the reward cutscene is about to start for a specific job. Interrupting this event will skip the cutscene altogether."AfterReward": Called right after the reward cutscene ends for a specific job. Interrupting this event will prevent the job from being removed from the taken list.
By attaching code to these events, one can change how the library handles a job; jobs that unlock their target dungeons when activated become possible, for example. Expert modders might even be able to create completely new types of jobs, given enough effort.
The Event Table
When an event is called, a small table of data is generated and then passed to whatever callback is assigned to it. This table contains the following data:
cancel-boolean: Begins equal to false. If true, it will interrupt the event if possible.job-JobTable: The job that this instance of the event applies to.data-table: Some extra parameters that may be useful to the callback.
This gives you full access to all data stored inside the job table, making it easy to write general purpose functions. Plus, as you can see, interrupting an event is as easy as setting cancel to true. This is not all, though; the data table might contain different properties depending on the event. If an event is not on this list, its data table will be empty:
"JobTake":board-string: the id of the board this job is being taken from.
"JobActivate": Nothing."JobDeactivate": Nothing."DungeonStart": Nothing."DungeonEnd":result-ResultType: The final result of this exploration.
"FloorStart":zoneContext-ZoneGenContextthe collection of zone gen data associated to the current taskcontext- anyBaseMapGenContextimplementation: an object that describes the map in its during-generation statequeue-StablePriorityQueue<Priority,any IGenStep implementation>: the list of floor generation steps to apply after this callback returns.seed-integer: the numeric seed supplied to the ZoneStep that is handling this code.
"BeforeReward":zone-stringthe id of the zone the player is currently in.map-integerthe index of the map the player is currently in.
"AfterReward":zone-stringthe id of the zone the player is currently in.map-integerthe index of the map the player is currently in.
After the callback returns, the table will be returned to the event-calling code, which will check for the field's state and react accordingly.
Callbacks
To use the callback system, you first need to set the mission_callback_root setting to a global table of your choice. All callbacks will then need to be stored inside that table. Furthermore, this is what their signature should look like:
function(<evt>, <args>)
where:
evtis the event table discussed aboveargsis the list of arguments set when registering the callback.
Any changes to the job table will be kept after the callback ends, so you can even use this to change the job's properties if you want.
Registering a callback
Once you have your callback ready, you need to register it to a job. This is done by using this function:
MissionGen:RegisterCallback(<job>, <event>, <func>, <args>)
where:
jobis the job table to add the callback to.eventis the id of the event to subscribe to, as discussed at the top.funcis the name of the callback function.eventis optional, and is the table of arguments to pass to this instance of the callback. If not set, it defaults to an empty table. You should not save C# objects or functions in here, because they wouldn't be saved correctly.
This will make it so that the given function is called when the given event is triggered. Do keep in mind that only one callback per event can be registered inside a job. Trying to register a second function will remove the previous one.
Once your callback is registered, just give the job to the player in some way, and you're good to go.
