Modding Tutorials: World Data, Quest Packs & New Guilds

Discuss modding questions and implementation details.
Post Reply
User avatar
Hazelnut
Posts: 720
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Modding Tutorials: World Data, Quest Packs & New Guilds

Post by Hazelnut » Fri Mar 16, 2018 3:17 pm

There are two distinct parts of creating a new guild for DFU; the guild implementation itself, and overriding world data to integrate the implementaion into the daggerfall world.

Planning

Before you start, you should plan what you want your guild to provide. Things like, name, npcs, services, benefits, rank titles etc. You will also need to allocate a faction id for the guild, as well as faction id's for every npc with a custom service. Classic faction id's are all less than 1000, so I've allocated id's 1000-1009 for the Archaeologists (only using 2 for now) so the next quild can use 1010-1019. I don't see more than 10 id's ever being needed. You will need to allocate one of the unused FactionFile.GuildGroup values for your guild. (don't use GeneralPopulace - that's the Thieves guild) Any of the GGroupX are fine to use, I used GGroup0 for Archaeologists. The others should be left for appropriate mods e.g. Bards.

See the Archaeologist mod thread for an example of the pre-planning. This assumes that your guild will work like existing DF guilds, but you have the power to create anything you like. Bear in mind that the more you diverge from the standard DFU guild behaviour, the less you will be able to rely on the foundation functionality I've written into DFU. Also note that temples (and to a lesser extent knightly orders) have sub-variants of a guild but this is not something that can easily be added by a mod.


Next decision is to decide how to insert your guild into the existing DF world - by either finding an unused building or a group of unused npc's. I will talk about the first since that is harder and what I've done for Archaeologists.

Find an unused building that is present in locations that matches the guild design. This will have to be a compromise unless you want to get into editing locations and the blocks they use which is a big can of worms I'm leaving well alone. Since blocks are generally either generic residential or have a specific use this can be tricky. For Archaeologists I found a pair of buildings that game considers one that were pretty much empty, and didn't look like homes, and were present in enough locations without being repeated too much (several places have 2 Arch guild halls though which is not ideal) - other good candidates are blocks with taverns / shops that are not matched by location map data (you will need to check this is 100% true) so don't work. These buildings look a bit more like guild halls than most houses, which unsurprisingly... look like homes. Alternatively with a bit more work a building could be replaced with another model and the map adjusted accordingly. I stuck to just modifying the interior, only briefly testing replacing a tavern model with a knighly guild - main issue was the tavern sign was half in half out of the new model. There will probably be other issues but I am pretty sure it's possible. So lets discuss the actual override data.

User avatar
Hazelnut
Posts: 720
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: Modding Tutorials: World Data Overriding & New Guilds

Post by Hazelnut » Fri Mar 16, 2018 3:18 pm

Overriding world data

To assist with overriding world data I've added three new console commands to DFU that dump various world data into JSON files. The files go into the folder where you can find the DFU settings file and do nothing at all. They are just put there for you to move them wherever you like and copy JSON chunks from.
  • dumpblock - Dump a RMB block to JSON file. e.g. "dumpblock RESIAM10.RMB"
  • dumplocblocks - Dump the names of blocks for each location, or locations for a block, to JSON file. With no argument you get a list of blocks for all locations which will take a while so be patient. Providing a blockname gives a list of all locations split by region that contain that block. e.g. "dumplocblocks RESIAM10.RMB"
  • dumpbuilding - Dump the RmbSubRecord of current building player is inside to JSON file. e.g. "dumpbuilding"
Along with the other asset replacement functionality availiable for modding DFU, I've added the WorldDataReplacement class to enable selective replacement of the world data from classic gamefiles. Currently it only allows buildings within a map block record (RMB) to be replaced. This could be expanded in future if a compelling use case is found. The way it works is that you create a JSON file containing data for the BuildingReplacementData struct in the WorldDataReplacement class and place it in StreamingAssets/WorldData. It needs to be named like this:

Code: Select all

string.Format("{0}-{1}-building{2}.json", blockName, blockIndex, recordIndex)
= blockName-blockIndex-building#.json
For example, the file I created for the Archaeologists mod is called RESIAM10.RMB-543-building10.json and overrides building 10 of RMB block RESIAM10. (refer to it as an example, and compare it with the default data dumped by command to see what I changed)

To create a JSON BuildingReplacementData file simply start with the JSON file produced by the dumpbuilding command as detailed below and edit the values. You will need to put the top level guild faction id and the building type of 11 which is for a guild hall, but this can be any of DFLocation.BuildingTypes. Quality is only important for shops as far as I know, so put a 10 or 11 middle of the road number in here. The remaining two members of the structure are RmbSubRecord which is where the specific building data goes and AutoMapData which is optional but allows the map data for the block to be adjusted to be consistent with the updated building.

Code: Select all

{
    "FactionId": 1010,
    "BuildingType": 11,
    "Quality": 11,
    "RmbSubRecord": {
        ... Rmb block dump in here ...
    },
    "AutoMapData": [
        ... paste automap byte array dump in here (optional) ...
    ]
}

RmbSubRecord

You should start by using the dumpbuilding command to get a file with same name as you need with the RmbSubRecord JSON data from classic data files. Put the file in StreamingAssets/WorldData to have it replace dynamically when you run the game and test it works. Later you'll need to package it with the mod, but for development, testing and debugging streaming assets is the way to go.

The subrecord has 2 sections 'Exterior' and 'Interior', I am only changing and discussing the interior. This is split into following: Header, Block3dObjectRecords, BockFlatObjectRecords, BlockSection3Records, BlockPeopleRecords, and BlockDoorRecords. To add new things to the building (i.e. npc's, furniture etc), add json blocks to the following sections and increment the apprpriate count in the header.
  • Block3dObjectRecords - 3d models, including the walls etc. Add new furniture like beds, shelves, chairs, tables in here. I found AlexanderSig's list of models he's replacing was really helpful to find the model id's, and you can also use the DF modeling tool as well.
  • BockFlatObjectRecords - Flat sprites used for decorations etc.
  • BlockPeopleRecords - Flat sprites used for npcs. The position field is filled from the position within the blocks file, just set it to a unique number within the list for the name seeding code. (start with 1 and count up...)
Next duplicate one of the existing things from one of these lists and change the coords a bit, increment count in header, and then check that you see the duplicated thing in game and the file is overriding the classic world data okay.

From here it's simply a case of adding all of the models, flats and npcs one by one. Getting them all in the right place is a case of trial an error. There's probably a way to calculate it but I gave up because DF coords and Unity coords are on different scales and each child is relative to parent coords in editor. Basically I calculated a rough position (i.e. in the right building) and then adjusted the coords, saved JSON file, exited and re-entered the building ingame - iterate like this until each thing is positions how you want. After a bit of practice it's not too bad. Someone could write an editor utility, but I wont be - it really is easy enough to edit data in JSON format.


AutoMapData

This is optional and to find the original data you will have to run dumpblock for the block the building is in. Each block has a 64x64 byte array for the automap. Cut this data out and reformat into 64 lines of 64 byte values that line up. I did this using editor find and replace but it was awkward. All 1 & 2 digit bytes need replacing with 3 character equivalents (e.g. '0' -> ' 0', '19' -> ' 19') so it all lines up, then put a newline after each bunch of 64 numbers. Then you can see the whole map chunk and should be able to easily edit the building shape and type. For a guild hall you will be changing 19's to 12's which makes each pixel blue rather than grey. You may also want to fix the shape if it's wrong (like the one I used) or alter it if you replaced the building model.

Once this block of data is edited, simply paste into the relevant part of the building JSON and test it.

User avatar
Hazelnut
Posts: 720
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: Modding Tutorials: World Data Overriding & New Guilds

Post by Hazelnut » Fri Mar 16, 2018 3:18 pm

Guild Implementation

Implementing the guild class

To implement the guild behaviour you need to initialise the guild by registering the factions, services etc that the guild class requires, as well as implementing a guild class in c#. This class should extend the DaggerfallWorkshop.Game.Guilds.Guild abstract class which will provide much of the basics and default functionality. Here's a list of the essentials that your guild class will need to override & provide:
  • FactionId property - read only static property returning faction id of guild
  • GetFactionId() method - returning faction id of guild
  • RankTitles - return array of rank titles
  • GuildSkills, TrainingSkills - return lists of skills for guild ranks and training service (if provided by the guild)
  • TokensPromotion, TokensIneligible, TokensEligible, TokensWelcome - return arrays of TextFile.Token's defining the messages displayed when each of these messages are displayed. NOTE: if you use any macros (%pcn) in these messages you must clone the static data before returning, else the static data will be modified. (TokensDemotion & TokensExpulsion use generic messages, but these can be overridden)
  • CanAccessService method - this defines what services are availiable to each rank, so you will almost certainly want to override the defaults
  • Benefit methods - override any benefit methods that the guild provide
Then add the extra code you need to implement new services or whatever you come up with.


Initialising the mod

I based putting all this together into a mod on Nystul's mod code where you create a _startupMod class which can be used from the mod management or added as a component to a game object in the unity editor for testing and debugging. I also referred to the tutorials on packaging mods and also TheLacus mod code to figure out how to pack it all up, took several days before I got the process right. Anyway follow this way and it will fit into a mod package no problem. Inside the startup class, you will have an InitMod() method which needs to register the various things that the guild will need to operate correctly.
  • Factions - register any new factions you need using FactionFile.RegisterCustomFaction(). Will need at least one for the guild, and then one for each custom service you implement.
  • Guild - register the guild class using GuildManager.RegisterCustomGuild(), check that the guild group is not already in use and throw exception if it is.
  • Guild services - register each service using Services.RegisterGuildService(), there are two signatures. One for allocating an existing DFU service to a new faction id used on an npc, and another to define a new service method handler and name. (Archaeologists has an example of each)
  • Quests - assuming you have quests you need to register the quest list but only when running from a mod package. For debugging this will need to be picked up from StreamingAssets/QuestPacks.

There you go! Now you too can implement a new guild as a mod for DFU. It is a fair amount of work but I've overcome all of the obstacles and proved it can be done. Refer to the Archaeologists mod in my github repo (https://github.com/ajrb/dfunity-mods) for more examples and details.

I look forward to seeing what the community comes up with.

User avatar
Hazelnut
Posts: 720
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: Modding Tutorials: World Data Overriding & New Guilds

Post by Hazelnut » Fri Mar 16, 2018 8:22 pm

Quest Packs

Figured I should also briefly describe the new quest pack mechanism added to support pure quest mod packs where the author has no need or desire to package their quests into a dfmod package. Basically each author should create a folder in StreamingAssets/QuestPacks with their name (online handle or whatever) and then a sub-folder with each pack of quests inside. Alongside these quest files have one or more quest lists which are auto-detected by DFU. They simply have to be named QuestList-name.txt where name is whatever you want to call it. The quest list is the same format as the two that are in StreamingAssets/Tables and at present only allow for new guild offered quests.

This can be zipped up and distributed and players can delete each pack or all an authors' packs easily without affecting anything else. This is also how quests are loaded for guild mods when running debug in the editor. (same as the StreaminAssets/WorldData for the building JSON file)

User avatar
RH666
Posts: 45
Joined: Mon Feb 12, 2018 6:07 am
Location: Koegria

Re: Modding Tutorials: World Data, Quest Packs & New Guilds

Post by RH666 » Wed Mar 28, 2018 6:16 am

So, then if you didn't worry about the exterior certain taverns could be converted into guildhalls? I'm thinking of finding suggestively named taverns in the capital cities (Particularly Daggerfall, Wayrest and Sentinel) for the Prostitutes' guildhall.

User avatar
Hazelnut
Posts: 720
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: Modding Tutorials: World Data, Quest Packs & New Guilds

Post by Hazelnut » Wed Mar 28, 2018 2:50 pm

RH666 wrote:
Wed Mar 28, 2018 6:16 am
So, then if you didn't worry about the exterior certain taverns could be converted into guildhalls? I'm thinking of finding suggestively named taverns in the capital cities (Particularly Daggerfall, Wayrest and Sentinel) for the Prostitutes' guildhall.
That doesn't make sense to me, because if you're going to convert a building into a guildhall it will no longer work as a tavern or have that name. (maybe I misunderstand what you mean here?)

You can only override a specific building within a specific RMB block, so choosing a random selection of taverns (which are most likely all different buildings in different blocks) isn't going to be very useful. Additionally, while possible, I think overriding working & already used buildings should be avoided without good reason just to ensure mod is acceptable to widest audience. (this is just a personal point of view, and not a technical issue, so ignore freely - it's your mod)

I don't want to sound negative, I'm actually really pleased that someone else is going to give creating a new guild a try, and I do want to help try avoid you setting off in the wrong direction. (Must admit, I expected Witches or Bards to be attempted first :)) These considerations are not immediately obvious, so give the section on overriding world data another read and play with the console commands to look at the data files output. (Atom is a great editor for this because it recognises JSON and provides little arrows in the left margin so you can collapse and expand sections of JSON data - makes looking and editing large files soooo much easier)

If you would like more guidance I'm happy to offer it, but will need a bit more idea of how you intend the guild to work. Not the details yet, just about how you see a players role (active pro, or support staff, or both?), services offered and guild hall like other guilds i.e. 'Prostitutes Guild' or more de-centralised? Either post in the existing Pros Guild thread, create a new thread or PM me.

User avatar
Hazelnut
Posts: 720
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: Modding Tutorials: World Data, Quest Packs & New Guilds

Post by Hazelnut » Wed Mar 28, 2018 3:08 pm

Hazelnut wrote:
Wed Mar 28, 2018 2:50 pm
RH666 wrote:
Wed Mar 28, 2018 6:16 am
So, then if you didn't worry about the exterior certain taverns could be converted into guildhalls? I'm thinking of finding suggestively named taverns in the capital cities (Particularly Daggerfall, Wayrest and Sentinel) for the Prostitutes' guildhall.
Additionally, while possible, I think overriding working & already used buildings should be avoided without good reason just to ensure mod is acceptable to widest audience. (this is just a personal point of view, and not a technical issue, so ignore freely - it's your mod)
It has occurred to me that maybe enhancing an existing large Tavern which already has attended bedrooms may work quite well...

User avatar
RH666
Posts: 45
Joined: Mon Feb 12, 2018 6:07 am
Location: Koegria

Re: Modding Tutorials: World Data, Quest Packs & New Guilds

Post by RH666 » Wed Mar 28, 2018 10:47 pm

I'd love some guidance, and yeah let's take it to the existing thread so the folks here can see it all happen in real time. Thanks :)

User avatar
Hazelnut
Posts: 720
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: Modding Tutorials: World Data, Quest Packs & New Guilds

Post by Hazelnut » Tue Oct 16, 2018 8:35 pm

Just wanted to add something I missed in my instructions.. how to find a blockname. Assuming you're running in the Unity Editor, in the Hierarchy window/tab open the following when you're in the location:

DaggerfallUnityGame->Exterior->StreamingTarget->DaggerfallLocation [Name="PLACEYOUWANT"]->DaggerfallBlock [BLOCKNAME]

Post Reply