Contents |
This is not supposed to be a "tutorial", which most people seem to think of as a list of things they did that got the right result, regardless of whether they were needed, and without any explanation of why they were done. Rather, I will (hopefully) explain how things works, and why things are done a particular way, so you can make informed decisions when attempting similar mods.
These are the pieces of Furniture where you can make things. The term includes carpenters' workbenches, cookpots, forges, and alchemy labs, as well as the less obvious drafting tables, arcane enchanters, and grindstones. They all operate by consuming some item or items that the player has in his inventory, and creating another item in the player's inventory. There will also be conditions that must be met (such as sufficient skill) for the recipe to work.
What you can make at a crafting station is determined by keywords on the crafting station itself matching those on the items you make. In most cases in the base game, these are generic ones such as "ArmorMaterialDaedric" or "CraftingCookpot" but those used in house-building are, more often than not, specific to a single item. This was done so that items could be built in more than one room of a house, and each instance would end up in the right place. And that's particularly important if you have a choice of which room is built as the North Wing. You don't want bedroom furniture in the greenhouse.
The other keyword you might have noticed below the one for the constructed items - i.e. BYOHCarpenterTable - associates the animation with the furniture. Since we want the same animation, we can leave this as it is.
The things you need to change for your mod are the keywords - in my case there's only one, as this one builds all the interior items - amd the script. The default script calls BYOHHouseBuilding to tell it whether you're building at Lakeview, Windstad, or Heljarchen, and of course you aren't. You can do that on each placed instance of the BYOH workbenches, but I duplicated and edited the base form instead.
The final piece is the recipe - called a Constructible Object in the CK. It determines what inventory items make the resulting item, and what conditions must be met for that to happen. In the Hearthfires DLC, most of the conditions are that you haven't already built that particular piece, or ones to make sure you build in a logical order. Note that Tempering a sword is a recipe that takes an untempered sword, an ingot of the right metal, and produces a tempered sword of the higher level. Some recipes, like iron ingots, may only need one ingredient, and others can produce multiple results, such as leather strips. In all case, the ingredients are removed from the player's inventory, and the constructed item placed into it. Any item not consumed is referenced in the conditions, and is unaffected by the crafting (i.e it's a pure catalyst).
There are even a few recipes that have no ingredients! If you look at the ones for the workbenches, you'll find that they have conditions only. You're actually making an item that disables a workbench with half of them.
Recipes also have keywords to connect them to the crafting stations, which makes sure that you can't make leather strips at a forge, even though you can use them there. This also allows the Skyforge to make items normal forges can't, as it has an extra keyword.
The distiction between Recipes and Tempering appears to be that the Tempering always produces the same item as input, but changes its level. Although cooking food appears to be the same, the cooked and uncooked foods are different forms, so that's a recipe. It's not the name that makes the difference, however; that's inherent in the crafting station. A grindstone only tempers, and a forge only creates.
The problem with using the crafting mechanism for house-building is that the result ends up in your inventory. Even if you just made the foundations of a house, or its cellar. So the majority of recipes added by Hearthfires produce an invisible token, which is defined as a MiscItem, that can enter your inventory, but are not marked as playable, which means you can't equip, drop, or even see them. I include the term Token in the names of mine to remind me that it's not the actual item that's being made.
The keyword is used to group the item in the list of things that can be contructed at the workbench. You probably won't need to add any new keywords, but you can.
These all have scripts attached, which are triggered by the OnContainerChanged event that happens when the recipe completes, and the item passes from nowhere to the player (as a container). The script confirms that the old container was none, and the new one is the player, and then calls the house building script that does the real work. This is the (roughly) same script for all items, so the properties determine what happen next. The important ones are: an indentifying number used to look the item up in lists, a reference to the item itself (so that the script can use it directly) and of course the reference of the script it calls to place the results in the game. There are other properies that are used for exceptional cases, such as a list of items to remove from the player (if you can't have both a kitchen and a library, for example), and flags for whether a building part starts or completes a room, since the latter means that some exterior has just become interior, and load doors get replaced by regular doors or vice-versa. Since the self-reference property can't be filled until the form is saved, do so and re-open it to set that, then save it again. The first time you save, you're creating a new form; the second time, you're not!
Since there are enough differences in processing between house parts (which need tests for room completion etc), exterior items like stables and gardens, and interior items, there are three separate scripts for those types. Some code is common to all three, but not enough to justify making it a single, more complex script.
You'll also note that there are almost-indentical MiscItems that represent each instance of an item that can be in any one room. So if a room somewhere has five barrels (and they get built separately) then there have to be Barrel1, Barrel2 ... Barrel5 tokens for them. But then Barrel1 to 3 can be used again in another room, as the Holding Chest mechanism below takes care of that. Barrels, chests, beds, shelves, and wall sconces all do this.
Not every placed item needs a MiscItem to represent it. You don't make sacks, but the Hearthfires homes have many of them. Typically, a number of minor items gets enabled when a parent object is added, such as clutter on each shelf, and candlesticks on night tables. These are simply initially disabled, with the named item as parent. There are some quirks when the main item is a mannequin, or weapon rack, as these have scripts to enable and disable parts, so parenting has to be avoided in some cases.
There is a single BYOHHouseBuildingScript, attached to the BYOHHouseBuilding Quest, and a single BYOHHouseScript, which is attached to each of the three Quests to build the player homes. All these quests start at the beginning of the game, so their properties are baked into every save, once the DLC is enabled.
The BYOHHouseBuildScript has properties for each of the three locations (and no more), making it impossible to use it for extra locations, in any game that's already been started, and changing it would also make it incompatible with anyone else's home-building mod that did so. So this script has to be cloned under a new name.
The BYOHHouseScript is shared by all three homes, Falkreath (Lakeview Manor), Pale (Heljarchen Hall), and Hjaalmarch (Windstad Manor) so you might hope to re-use that, but unfortunately it is much too dependent on the BYOHHouseBuildingScript being unchanged (such as the location index being 0,1 or 2). Also, certain features like the connections of the balconies, and which room is a bedroom, are hard-coded into it. This is one reason that there isn't any variation between the locations, a reason you might want to make your own mod in the first place.
Much of the logic is quite re-usable, but I'd expect anyone building a mod to strip a lot out. The things to keep would be the mechanisms for looking up parts lists, and enabling and disabling world items as the inventory items are made.
You also need your workbench and trigger zone scripts to refer to your building scripts, not the DLC one, so it's easiest to clone those, too, and make the appropriate changes of script type. In principle, if your building scripts extend the Bethsoft ones, they're acceptable, but extending doesn't really describe what's going on. They should really both extend/implement a purely virtual object, but that didn't happen.
To keep the scope of each workbench manageable, and to prevent items from being created at the wrong location, there are trigger zones around each crafting station which transfer the miscellaneous items from the player's inventory to a Holding Chest when he leaves the zone, and puts them back when he returns. This ensures that you can't carry a token to another room or house, and enable the corresponding item there. The script that does this is quite usable in other mods, but you need to create a new Holding Chest (use the PlayerHouseChest container form) to correspond to each crafting station, which you can add to the same holding cell (the unreachable interior cell BYOHHouseUtilityCell) that the DLC uses. Update the properties of each trigger as you place it with the reference to its own Holding Chest. Entering the trigger zone doesn't transfer the items to player, activating the workbench does that. That way, just walking past doesn't make the scripting engine do unnecessary work. The existence of this mechanism is why the OnContainerChanged event handler on each MiscItem token checks the old and new containers before calling the building script. Those things will be changing containers a lot of times!
This applies also to the exterior structure of the building, and the workbench outside. The drafting table acts as part of the exterior workbench so it's inside the same trigger. There is a Holding Chest for the exterior parts of the building, too.
All the items you can build at one workbench are collected as a FormList - which is a list of base forms, not references. The correspondence between forms and references has to be made by looking up the form in the list, getting its index, and then picking the matching entry in an array of references, which is a property of the quest script for the specific location. There is a FormList for exterior parts, and a FormList for each Room type. The starter home actually has two lists, one as a small house, and one as an entryway. When you "remodel" you're switching lists.
The array of RefIds that represent the actual pieces (unique in world) is a property of the instance of BYOHHouseScript that is itself a property of the quest for each location. You'll have replaced that script with your own, so this becomes a property of your script, instead. In the DLC, there is a separate array for each room and the indexes correspond to those of the tokens in the FormList of tokens for the room. In theory, this could have allowed different styles of furnishings in each house, but it didn't.
The process of building a house part or furnishing item goes like this:
Note that the MiscItem is kept by the player, as its presence in inventory is used to check that a piece isn't built twice. It's only taken away when they are all moved to the holding chest.
Since the area you can walk over changes every time something new is built, the bare site, and the empty interiors, are nav-meshed for actors to go everywhere, and then this is restricted by enabling collision boxes (of type L_NAVCUT) around each item that obstructs movement. These are initially disabled, and have the house parts or furniture items as enable parents. You build an item, and now actors will walk around it, as the piece of mesh has just been cut away. However, you should consider the location of the built items when placing the nav-mesh, as whole triangles will be affected. A possible compromise method is to nav-mesh with the furniture in place, working around it, and then fill the holes in nav-mesh-only view.
A log pile consists of a number of TreePineForestCutLog01A and B statics, arranged as tidily (or not) as you like. When you've placed them, select them all and surround them with first a collison box, changing its prinitive to L_NAVCUT, and then with a BYOHHouseLogPileActivator (which is a trigger box). Make sure the activator can be activated, by checking the "Player Activation" box on the Primitive tab! Then place an X-marker nearby and link everything to it as an enable parent. Everything should be initially disabled, as this will appear only when you have logs.
What the late Sir Terry Pratchett would have described as an "embuggerance" is that the log piles share a single Global variable for the player's log count, but the pieces of the script that maintain it only process the DLC log piles, and won't do anything for extra ones. You can resynch the global with the actual count of the log token in the player's inventory when you use logs, but your log piles may show a low count after you purchase or cut more logs.
The dialog for buying lumber also has a "gotcha", in that it's conditioned on testing whether the player has purchased any of the three DLC plots directly, rather than having a Global variable hold that information. So owning the fourth of the three won't let you buy logs. I got around this by copying the dialog with a different condition, that you own none of the DLC plots, but do own the new one. Thus, only one of the two can be true, and you'll only get the dialog option appearing once, and then only if at least one is owned. I would have like to convert to using a Global, but that would meaning finding a way to trigger its update from the DLC. If I create a second mod, I'll have to revisit that, as it won't work twice, and I'll need a Global to summarize my non-DLC ownership status.
Cutting your own lumber depends on settings made by the dialog you've cloned, so you need the same script fragments in your own mod, which will have to call code in your script, not the the DLC one. That means keeping the event handler for the mill animation etc. in your cloned house building script, together with the associated properties.
The physical models of the logs are just there for show. The real "pile" is a activator wrapped around them which has "Log Count (xxx)" in place of the usual Activate prompt, and substitutes the value of the Global when it's "used". The Global substitution part is dependent on the log pile activator being an alias of a running quest, or else you won't get a value shown. You also have to use the Display Name box to select the BYOHLogPileName or it won't work. Since the log pile will normally be disabled when the quest starts don't forget to allow that by checking the "Allow Disabled" box.
The quest that this alias belongs to should be the one that constructs the specific house, as the script for that will be doing the work of enabling and disabling the log pile. Since you only want a pile at an active construction site, having the house script do the work ensures that it's only done when you need it. It appears that the quest needs to be "start enabled" rather than one that is initiated later, so that's another reason for connecting to the building quest, instead of a "buy the house" or similar that's started during play.
This is the list of things you need to do if you want to add another constructed item to your house.
Since this process changes a property of the building quest, which is started at the beginning of the game, start a new character to test the change! And this means going through the whole cart-ride (or using an alternate start mod). Loading a character from after the tutorial is too late, as the aliases for the quest are already filled and committed.
Home is one place you'd like to be able to fast-travel, so a map marker is placed on the site, but initially disabled. This marker can be set to be initially discovered, so you can fast-travel there right away, or not, as you choose. The quests for the DLC homes enable this map marker (which needs to be discovered) when you purchase the property, at the same time that they enable the crafting cluster (Workbench, drafting table, chest and anvil). The quest will also give the player 20 logs - enough for the starter home - which indirectly enables the log pile. These things can be separated, so a home location could be discovered, rather than bought, and the workbenches would be the necessary purchase afterward. If construction can start without logs, they'd be optional.
You can add new recipes, and use other ingredients in them. My own Orc Hearthfires has two Mammoth Tusks in the recipe for the Longhouse exterior, for example. The only requirement is that the ingredients of a recipe must be inventory items, (which includes clothing, weapons, potions, etc.) I've considered creating a recipe for glass (melt down empty wine bottles at a smelter), and making straw harvestable, so that no ingredient needs to be bought from a merchant.
If you use the "showinventory" console command for the player, while in the trigger zone around a crafting station, you can see the invisible tokens in the list. That can help determine why your recipes aren't working, such as testing for an item that's made somewhere else.