September Builds 0.10.6

Live Builds have been updated with version 0.10.6. This release patches a massive number of bugs, and we still made time for some new features. I’ll provide a quick summary of the major stuff first.

Quest Lists (Hazelnut)

If you enable setting Advanced > Enhancements > Guild quest player selection, then guild quest-givers will offer multiple quests at a time, rather than needing to keep clicking “no” until you see a quest you like.

 

Quests will rotate every so often to give you a fresh selection to choose from. This feature also has thanks to Firebrand who entered all the quest display names.

 

Quest Marker Refactor (Interkarma)

Quest markers are an invisible scene object onto which quests will associate various targets (NPCs, Items, Foes). From 0.10.6, Daggerfall Unity is using a new process for placing quest resources to markers that fixes a couple problems and helps the game behave more like classic.

One major issue resolved by this was introduced when DFU added the facility to move quest resources between locations. An example of this is Barenziah’s Book, which moves the target from Orsinium to Scourg Barrow if the player does not retrieve it in time. Due to an error in the resource culling code, it could sometimes remove items from other quests that used the same symbol name. For example, if the quest wanted to place/relocate an item with the symbol name _item_, it would also cull items from other executing quests that had already placed an item also using the same symbol name _item_. The quest most commonly affected by this was the Wayrest Painting.

I recommend everyone update as soon as possible to get this fix. While it was a fairly rare bug and required a specific set of circumstances, it was a showstopper if you were affected by it.

The second issue resolved by this was to make marker selection more like classic. DFU would place items to Quest Item markers and NPCs/foes to Quest Spawn markers. But sometimes a quest foe needs to be placed on an item, or an item placed onto an NPC. Classic will stack subsequent resource placements onto the first, such as the item’s guardian in screenshot below. With the new marker selection, both item and guardian will appear together as they should.

 

When loading a save game from prior to 0.10.6, DFU will migrate any marker placements to the new system automatically. This works even if you’re in the target location. Any new quest will just use the new marker system by default.

 

SDF Font Refactor & Book Reader Refactor (Interkarma)

The first implementation of SDF fonts would stretch each glyph to occupy the same physical space as the classic glyph. While this made the fonts smoother, it still had some major limitations:

  1. SDF text was stretched or squished to occupy the same physical space as its classic counterpart.
  2. SDF text was limited to using the same character type as classic, namely ASCII, which greatly limits translation support.
  3. SDF text inherited the same bad layout as classic text in places like books.
  4. Creating SDF fonts was a difficult process.

Fixing all of the above is a key part of future translation support. There’s no point in having translated text if the game is unable to render it properly. So a general rework of SDF fonts was required.

The first major change from 0.10.6 is that DFU uses a UTF32 code format internally for all SDF text. Unlike ASCII, you can throw pretty much any text at it, and provided the font has glyphs for those codes it will be rendered correctly in-game. This also means you can create SDF font atlases with thousands of characters rather than being limited to 256 for ASCII. And translators will be able to write text in their actual language rather than entering gibberish using the high-range areas of ASCII code space.

The second change is how SDF fonts are created. Rather than using external tools, you can use the TextMesh Pro font asset creator and DFU can load these assets directly. Note that DFU is currently being compiled under Unity 2018.2.x, so TMP 1.3 is still in use. DFU also does not use TMP for font rendering, as we have a very custom UI setup including fonts, but it can use these TMP font assets. I’ll post an updated article soon showing how to create new fonts and mod them in-game. Any old font mods will no longer work in DFU.

The third change is to how text is laid out on screen. DFU will no longer stretch text to match classic scale and use the actual font’s true proportions at all times. This makes for better-looking and more readable text layouts all around. It might be an unwelcome change if you’ve become adapted to the old stretchy font, but SDF text really looks better now and is far more flexible. This whole process was an important step in breaking free of classic text limitations and enabling future translation support.

Finally, the way text is laid out needed to be reworked. We’ve all seen how classic books often have text scattered all over the place. I’ve completely rebuilt the book reader to use the new text setup and automatically layout book text. This makes 99% of books more readable than ever. And they now support any left-to-right language with the right font and text driving them. The book reader will be used to help pilot all the new translation features later in Alpha lifecycle.

Here’s a screenshot of the old book reader and new book reader for comparison. I’m using a book with bad formatting layout to show how the new reader overcomes this issue present in classic data.

 

You’ll notice right away the formatting is better, the text proportions are better, and the margins have been expanded to make the text easier to read. I have also changed the book reader to use a scrolling setup rather than a page flip, as I feel this makes text much easier to follow with the eye.

 

Fix Resistance Checks & Ranged Enemy Spellcasting (Interkarma)

A bug was preventing correct resistance checks, so a character who should be 100% immune to something (e.g. Paralysis) was still occasionally stricken by that during combat. I finally got to the bottom of that problem and have resolved it now. If you have true 100% resistance to something, this will now work 100% of the time.

Note that the bug/exploits of combining High Elf Immunity to Paralysis with Critical Weakness to Paralysis still results in an impaired resistance in DFU, and that Immunity to Magic will only cover the Magic element (i.e. Arcane) not make you immune to all magic. But the problems of true 100% resistance not being correctly regarded have now been solved. During the process, I also restored the “save vs spell” message when you resist something so that you know what happened.

Also during this process, I found the cause behind enemy spell casters no longer hurling ranged spell missiles at the player. This has been fixed now, so this little green guy is properly dangerous again.

 

Virtual Mods (TheLacus)

This is a behind the scenes change to help support mod authors build and test their mods. If you’re a mod author, start with TheLacus’ description of this change in the following Issue on GitHub.

The gist is this change helps mod authors test and debug their work before bundling it as a .dfmod for end users. This is really important stuff that helps make the game and its addons better for everyone longer term. Thank you TheLacus!

 

Travel Map Refactor (Interkarma)

Over time, the travel map could leak a lot of texture memory. And if you knew how to trigger it, you could spam this leak in a few minutes to bring your game right to chugging point. I believe this issue is behind some of the problems with poor performance on systems that should be able to handle DFU just fine. If you notice your performance drops after a few hours of gameplay, and that restarting the game fixes it, this was likely the reason.

 

I had to rewrite about 50% of the travel map UI to make this change. Everything should just look and work exactly like before, except faster and without the memory leaks. I have tested this extensively before release, but if you encounter any regressions with the travel map please let me know.

 

General Fixed & Improvements

Lots of fixes this time around, large and small. So many that I’m going to sort them by developer.

FrozenFish24

  • Add exclusive fullscreen option to settings.ini – will be added to startup UI once Unity upgraded to 2018.3 or later

Ferital

  • Fixes and refinements to NPC talk reactions
  • Tone button in talk window now remembers last setting
  • Fix activation issues for Sheogorath and similar NPCs
  • Remove generic factions from rumour mill
  • Add Order of the Raven faction to their guild halls
  • Guilds now display “guild closed” instead of “shop closed”

Nystul

  • Fix for answer rumours (answers to tell me about topic) being incorrect
  • Fix automap user notes disappearing after saving and loading
  • %di macro improvements and bug fixes
  • Several talk manager fixes when asking for directions
  • Fix for talk window exception after classic save import
  • Fix %di exception when player in same building as target NPC
  • NPCs now always know the answer when NPC asked about is in the same building

Jay_H

  • Enable more classic quests
  • Several more classic quest fixes
  • Rebalance spawn rates for household vermin cleanup quests
  • Add alertness messages for vermin quests so player knows they’re in right place
  • Add delay to Morgiah’s Wedding quest so player can read invitation
  • Fix some change notes being visible in quests
  • Fixes to Dark Brotherhood acceptance quest

TheLacus

  • Sort mods by load order at startup
  • Add console commands to create specific items
  • Mod configuration now stored in persistent data
  • Automatic cleanup of mod configuration folder
  • Upgrade support for book replacement
  • Handle exception when upgrading mod config
  • Fix issues with billboard custom scale
  • Support texture replacement for cloak interior

JorisVanEijden

  • Fix arrow blood splash position
  • Fix crash for %di getting direction without location
  • Add location reference to quest when location comes from a person
  • Fix HaveItem clearing target when item is gone and revert workaround
  • Show author as unknown for broken/missing books
  • Add CAV action door type for secret doors in caves
  • Add logging to quest item creation and add error feedback to logs
  • Expand range of NPCs considered to be local residents
  • Fixes to classic quests
  • Prevent vampire sun damage in prison
  • Picking up dropped quest item will reset “has dropped” flag
  • Fixes to lycanthropy max health degrade and health top-up after curing
  • Support for magic item subclass selection from quests

Eric Prokop

  • Fix fast travel to arrive at night for characters with sunlight damage trait

Pango

  • Don’t display Find button on world map first use
  • Fix selecting EQUIP when opening inventory explicitly
  • Visually clamp difficulty dagger to gauge limits
  • Don’t ground player when onboarding ship
  • Fix fog being displayed on automap
  • Add openpotionmaker console command
  • Fixes to proximity wagon access in dungeons
  • Adjust default keybind text in tutorial quest
  • Fixes to receiving armour from knightly orders
  • Harden timescale against negative values
  • Add missing sounds for journal, notebook, and book reader
  • Fix typo in classic quest
  • Workaround for “water everywhere” tilemap issue on lower-end hardware
  • Change activation click to use button up rather than button down to prevent input fallthrough into some UIs
  • Adjust falling damage to better match classic

Hazelnut

  • Allow paintings to be sold at pawn shops
  • Fix removing single ingredient from wagon during potion making
  • Add journal message when buying a house
  • Fixes to reputation propagation for single factions
  • Fix enchanted items being regarded as ingredients
  • Update NPC presence when rest dialog dismissed
  • Cart now moves at correct slower speed
  • Fix coin anim on inventory window
  • Adjust riding volume to match footsteps
  • Add some modding facilities for horse riding
  • Fix to horse fatness by reducing width 20% to better match classic
  • Fix direct stat mods not being cleared when no effect bundle active
  • Fix default action mode not selected when opening inventory outside of dungeons

Interkarma

  • Use permanent endurance during level-up formula, as live endurance might be affected by spells/diseases/etc.
  • Fix magic item repair not working when setting is enabled
  • Vampirism/Lycanthropy lifecycle fixes to prevent stacking dreams, spells, and accidental deletion of spells
  • Refresh equipped armour values after enchanting item
  • Fixes to cleaning up objects spawned to StreamingTarget
  • Fix for evaluating travel-to location from journal clicks, now only regards locations mentioned in text
  • Fix for quest residence names being marked incorrectly on map
  • Quest-killing exceptions are now logged in save data
  • DFU version is now stored in save info
  • Remove “unmutequestnpcs”, this was only to fix a specific quest bug and is no longer required
  • Add “summondaedra” console command
  • Implement Foe item queues to support item persistence when moving Foes between locations
  • Fix fog colour turning black after entering and exiting buildings
  • Heavy weather-based fog is now already white/gray rather than atmosphere coloured
  • Fix check preventing enemies from casting ranged spells at player
  • Fix “save vs spell” not being displayed for magnitude-based spells
  • Add cursor activation toggle (default key is Enter) as part of preparing for large HUD support
  • Use building fallback for local quest places
  • Remove hanging mode, as this feature is now discontinued by Meteoric Dragon
  • Add quest NPC automatic home fallback
  • Rework quest marker selection to better match classic
  • Implement “tele2qmarker” console command, this will replace both “tele2qitem” and “tele2qspawn”
  • Fix for entering duplex homes while selecting entry position
  • Fix compass and other HUD elements being shown at wrong size/position briefly during initial startup
  • Fix magic battle-axe animation ordering
  • Travel map refactor for performance and fix memory leaks

Creating SDF Fonts For Daggerfall Unity

Introduction

All the way back in September, I upgraded font rendering in Daggerfall Unity to support Signed Distance Field (SDF) fonts. This enabled smooth high-resolution font replacements which can operate under the same “layout rules” as classic Daggerfall’s pixel fonts, with a substantial improvement to reading comfort as this comparison screenshot demonstrates.

 

Rather than storing individual display pixels of a text glpyh, SDF fonts store a distance value that can be turned into display pixels later at any resolution using a custom graphics shader. Unlike regular pixel fonts that become quite pixelated at high resolutions, SDF text can use those distance values to generate sharp detail even at UHD resolutions and beyond. If you’re interested in the inner workings of Signed Distance Fields, there are loads of great resources out on the web. This tutorial doesn’t look very deeply at SDF concepts, only the process of creating new SDF fonts for Daggerfall Unity.

 

Resources

There are a few resources you will need to work through this tutorial.

You can use whatever font or tools you like to generate your SDF font atlas. This is just the process I’m using that will generate known-good output for Daggerfall Unity. If you do use a different toolchain, the only thing that matters is the output image is a proper SDF texture and the glyphs are laid out in a specific way.

 

Continue reading

Magic & Effects Back-End

In my previous article, I showed progress on the visual side of spell-slinging and had lots of fun with casting animations and throwing around missiles with lighting effects. Now I have to regard the business end of the spell system and how all of this holds together under the hood. This article will be a lot more tech-oriented than my previous one, but may still be of interest if you’re curious about how spells will operate in Dagerfall Unity.

Please keep in mind this is all under active development so concepts discussed here are likely to be refined or expanded by the time everything rolls out.

 

Magic & Effects System

One major shift in this process was changing how I think about the spell system. I have a long list of goals I want to achieve during this stage of development, above and beyond just emulating Daggerfall’s classic roster of spells. Primarily, I want to create a central way of handling the majority of effect-based gameplay. This means advantages/disadvantages, diseases, poisons, spells, magic items, potions, and so on should all come together under the one system or group of related systems. Once I had made that decision, it no longer made sense to call it the “Spell System” as spells are just one part of the collective. So the Magic & Effects System was born.

This is why you won’t see the word “spell” very much moving forward but you will see the word “effect” a lot. In this context an effect isn’t something visual, it’s how something works. For example, an effect that heals the player is a script which increases their current health. This naming is taken from Daggerfall itself where spells and magic items reference effects directly using a type and sub-type.  You can read more about classic Daggerfall’s spells and their effect indices on this UESP page.

You will also see the term effect used by Daggerfall’s Spell Maker UI when creating a new spell. You can add up to three effects per spell as shown in screenshot below from classic Daggerfall (spell maker is not yet implemented in Daggerfall Unity).

 

Continue reading

Guild Systems

Hi everyone, Hazelnut here. Interkarma has asked me to write a blog post about some of the work I have been doing recently, so for this post Daggerfall Workshop has been taken over by me! Muhahahaha… etc. I’m sure your regularly scheduled Interkarma posts will return soon, so don’t worry.

Anyway, allow me to introduce myself, you may know me from such features as horse riding, inventory upgrades, shopping, persistent state, icons, tavern rooms, ships and houses, as well as various other bits and bobs. So why did I spring up from nowhere and start contributing to DFU?

I bought Daggerfall on xmas after its release and played like crazy for 7 days until the end of the christmas break, then stopped. Because it’s such a huge game, never really got back into it for years due to lack of time & small children – until shortly before Morrowind came out. By then the game was simply far too dated for me to persevere, especially because I forgot about the WSAD option and I was using the default control scheme of stupid mouse pointer arrows to move. So I’ve actually never played beyond the first couple of character levels. Always wanted to, and do intend to once DF Unity is done. This is why I am absent for any discussion or work around the main quest! Spoilers! Yep even after all this time.

While the progress has been fantastic (Interkarma has Orc level stamina apparently) it’s a big project and takes a long time, and since I’m a software engineer for the past 2+ decades who now does software design so don’t get to write much code at work… I figured I’d see if I could contribute. Also my kids are all teenagers now, so I have more free time than I’ve had for 2 decades. I had no knowledge of Daggerfall and its data structures, hardly ever touched C# and never used Unity before, so it’s been quite a learning curve. Anyway, after I finished my work on ships, houses, shops and taverns I asked Interkarma what he thought I should tackle next and between us we decided it was time to implement guilds. I’d already done some work with the guild services menus, but now I needed to create the guild membership systems.

Guilds

Guilds in Daggerfall follow some common rules for promotion etc but offer different services and quests. The first thing to focus on was ranks and building some foundations that would make each guild easy to implement, allowing the common behavior to be shared. I also wanted to ensure that new guilds could be added by mods, as I was sure that several people in the community were keen to add new guilds having seen discussions on the forums, and I had some ideas of my own that would be best integrated into the base game by adding a new guild. I decided early on that the guild code should be designed to support modding from the start, and the only way to ensure this was to actually implement a guild mod early on to prove the concept.

So, quite a lot to take on. Fortunately I had 3 solid days free coming up to get started on this. The fighters guild is the simplest of them all so I started with that. First step was to test classic and see how guild membership worked with rank changes etc. To support modding, the guild classes are designed so that they know about the players membership status, rank, and what benefits and services the guild provides at that rank. Service and guild management code asks the guild class by calling the appropriate method when they need to know. They also supply guild specific messages to the ranking system which is shared. This means that a new guild can simply be added by implementing a new guild class and registering it with the guild manager.

Now by this time you could join the Fighters guild.

Join Fighters

Joining the Fighters

Continue reading

Town Populations

I’ve had my head in the quest system for several months and really needed a short break. I also happened to need a solution for spawning enemies outdoors in cities (for example, the ghosts and wraiths in Daggerfall at night) and noted there was a good amount of overlap between spawning enemies and NPCs in town environments because they all need to avoid placement inside building geometry. And whatever solution I use for placement could probably be used for navigation as well. I had scheduled wandering NPCs for 0.5 cycle, but decided to make an early start on this while solving town placement and navigation. And what better way to test this solution than to actually watch NPCs walk around?

The first problem I had was how to find an appropriate placement position. My initial idea was to use the foliage placement array in exterior data. This formed a nice grid over each block, but it also marched over water and under buildings. That would not be suitable. I considered just dropping in mobiles and using a combination of rays and colliders to refine their position until they found open space, but that approach seemed way too messy and inefficient.

That’s when I had a eureka moment thinking about how perfectly automap image data lined up with the game world. Take the below screenshot as an example. In game, I’m standing outside the Odd Blades looking at the entrance door. On the automap, once unit conversions are done, I’m in exactly the same place.

 

So Daggerfall’s automap perfectly skins building footprints. This should mean I can take the inverse of automap data to work out which parts of the environment are open. I quickly prototype by placing white cubes on open environment and avoiding the building footprints. Take a look at the results.

 

This is beyond perfect. The automap doesn’t just contain data for building footprints, but for flat placement and decorative geometry as well. I have a strong suspicion Daggerfall also uses the automap data in this manner, it’s just too precise and detailed to be a coincidence.

With a solution in mind, I now have to execute the idea. I create a new class called CityNavigation which is added to the location GameObject at scene layout time by StreamingWorld. This constructs a navigation grid at the same time location and automap data is read so only a small amount of additional processing is done per location. With the inverse of automap blocked out, we get the following:

This is good – the white areas can be used for placement and navigation, but it’s not perfect. It also needs to account for tilemap under location. We can’t place NPCs on water tiles, and they should try to avoid those tiles when walking around. Rather than just block out unwalkable tiles, I take this one step further and allocate each tile a specific weight, where a higher weight means the tile is more favourable. Here’s the final navgrid where black areas are “no-go” and brighter areas are preferred over darker areas. You can probably see right away this creates a strong preference for the road network:

 

What you can’t see in the above image is that each weight occupies the upper 4 bits of a single byte. The lower 4 bits are reserved for a flag system, giving me up to 4 bits to control NPC behaviours. This will be important later in this article.

Now that I have a nice procedurally generated map of any exterior location, the next problem is converting between all the different coordinate systems. If you’ve ever tried to make a big world in Unity, you’ll know that precision problems kick in after a few thousand scene units or so from origin (position 0,0,0 in world). This manifests itself through jittery movement and shadows, imprecise feeling of control, and issues with physics system. The game map in Daggerfall rocks in over 819,000 x 409,000 scene units, way beyond what Unity can handle with fine floating-point precision. I overcame this challenge very early on by using a fixed point coordinate system for the world (Daggerfall units) and normal floating point units for the scene (Unity units). The world is built around the player in chunks close to origin, and when player runs too far in one direction, the whole world is brought back towards origin. To the player it feels like they are running continuously through a huge open world, when in fact the world is being constructed around them one chunk at a time. The player never moves more than 1000 units from origin in the X-Z plane.

What does all of this have to do with the navgrid above? Well, now I have yet another coordinate system to glue together. I have not only the Daggerfall units and Unity units, but the X,Y position inside the navgrid array where any virtual mobile objects have to move around. So the next thing I do is write some helpers in CityNavigation to convert from navgrids to world space, world space to scene space, and back again, and so on. This chewed up a solid chunk of Sunday to get working properly, and there’s still a few precision issues due to the large differences in scale. Something to refine down the track.

With all the math out of the way, I can now start placing mobile NPCs into the world. One problem though, I hadn’t written any code to render wandering NPCs yet. So I started with these guys just to confirm the navgrid through scene conversions were working. Sometimes in game development, you have to bust out some programmer art to get the job done.

 

With placement working, next came the process of building the mobile NPC billboard properly – including that stop-and-stare thing they do when you get too close to them.

Town NPC Billboards

With rendering done, I can start moving them around the navgrid using a simple motor. They will generally follow roads when encountered (because roads have a higher weight), but there’s enough randomness to let them change directions and wander around elsewhere on the grid.

And do you remember me mentioning the navgrid can store flags in the lower 4 bits? The first flag I created is an “occupied” bit that lets a mobile claim a navgrid tile before walking into it. This prevents two or more NPCs trying to occupy the same tile at a time. The next clip shows the mobile movement, path following, and dynamic avoidance of each other. I’ve cranked up the spawn count and movement speeds because it helps me observe the behaviour (and it’s kind of fun to watch).

Mobile Pathing and Dynamic Avoidance

Despite everything accomplished, I still have more to do. The next step is working out which races are placed in which towns. I put my travelling boots on and tracked around classic Daggerfall’s world until I found which races appeared in which climate zones. I built this into the helper which returns climate data for texture swaps, etc. and now the correct NPC races (either Redguard, Nord, or Breton) will appear across the game world.

 

The final step was to build a PopulationManager class. This code handles spawning/despawning of NPCs around player as you move through town environments so the location feels populated. After a bit of experimentation, I used a population index per 16 RMB blocks so that small towns feel like they have a smaller overall population than large cities. One of my challenges here is the draw distances in Daggerfall Unity are huge compared to classic Daggerfall. While classic can place NPCs safely in the fog out of sight, in Daggerfall Unity you can see two full city sizes distant across the map. This means that hiding pop-in and pop-out of NPCs is a little trickier. For now, I mitigate this by trying to only show or hide NPCs when player is not looking directly at them (as Daggerfall does) and only allow them to pop-in when a certain distance from player.

There’s still a few bugs to iron out. You can still catch them pop-in nearby if you happen to look in the right direction at the right time, and they sometimes glide slightly in the wrong direction on spawn due to precision issues as they align to the grid. And of course you can’t talk to them yet, because the “talk” system won’t be introduced until 0.5 sometime. But overall, the feeling of crowds is quite satisfactory and Daggerfall-ish, and it’s wonderful to finally see these sprite people bustling around cities.

I hope you enjoyed reading about some of the work that goes into creating even a small feature like this one. If you’d like to read more, I try to post regular micro-updates to my Twitter feed @gav_clayton.

 

Questing: Place Resource

I’ve decided to go in a slightly different direction regarding dev articles about quest system from now on. Instead of the traditional numbered sequence split into a few parts, I will post more about what I’m working on in the moment. There are two reasons for this. First, questing is a huge subject that resists being neatly split into a progressive narrative like items or streaming terrain. I often have to cross back and forth between related systems. Second, it gets a bit daunting trying to construct that narrative from such fragmented work. The end result is that I’m posting less and feeling more weight on my shoulders every time I try to construct a post. Just how do I describe to everyone I spent weeks working on research without a satisfying answer to a particular problem?

My solution is to tear the band-aid off and just post something. I’m slowly learning that many people enjoy the development process itself, including the potential for frustration and dead ends. Those outcomes aren’t particularly enjoyable for me when they happen, but maybe I can turn them into something positive and entertain my readers. This should result in more posts but they will often be shorter (which in itself might be a good thing). This post probably won’t be shorter, but it is my first in a while. 🙂

So here’s what I’ve been working through lately…

In a QBN section, Daggerfall quests defines resources that kind of glue the whole shebang together. They define places in the world, people to visit, timers, items, and enemies. Basically all the world-stuff player will contact to unroll that quest’s execution. A high-priority resource is Place, which defines locations the player must use in the quest, like a dungeon, shop, or residence. Here are some examples.

Place _mondung_ remote dungeon9
Place _house_ local house2
Place _inn_ local tavern
Place _palace_ remote palace
Place PiratesHold permanent PirateerHold1

To deconstruct the above: Place tells the compiler this is a place resource; _symbol_ is the name of that place for the compiler to reference; remote/local/permanent is where to select that place from; and the final bit is site which tells quest engine what type of place to select. The site code is actually a reference to a places data table which defines the parameters for these site types. I won’t go into these in much detail, just keep in mind they define what kind of building or dungeon to select.

Let’s use “local tavern” for now. This means find a random tavern within the same town as where player received quest. If this was “remote tavern”, we’d select a random tavern from another town in the same region. The site code “tavern” is then looked up in the places data table and the parameters tell us this is building type 15 (0x0F).

Now the quest engine knows it needs a tavern (building type 15) and it should select from the map player is currently in. Fortunately, Daggerfall keeps a handy list of buildings for every map definition in MAPS.BSA. This gives us information like the building name seed, faction, quality (“rusty relics” through “incense burning”), and best of all building type. Great! We already know we need a tavern, and it’s trivial to select taverns from this list of buildings and grab one at random. Now we have our quest location… well, almost.

A Daggerfall city is made up of geomorph-like blocks – up to 8×8 blocks for really big cities. They are like puzzle pieces laid out on a grid. Here’s the block layout for the City of Daggerfall, you might recognise this from Daggerfall Modelling.

 

Every block also carries a list of buildings it contains, sharing the same data structure as MAPS.BSA – with a few differences. One key difference is that a few of the values present at map level (e.g. name seed) are not present at block level. The reason for this is obvious when you consider how often blocks are reused across locations. If the name seed was stored in block data, our tavern would have the same name in every location that block is used. Thus the name seed is carried at map level and merged down to block level as needed. Same goes for the block texturing, which changes based on climate. Put together, this all makes blocks somewhat polymorphic in that they can take different forms depending on the location they belong to.

Back to our tavern which we found in building list at map level, how then do we map this to the actual physical building at block level? Besides other jobs like setting the correct names on automap, this is needed to determine correct physical location of quest buildings in the world. This is where some of my troubles started.

At time of writing, it is unknown exactly how Daggerfall links building data at map level down to building data at block level. To compound my problems, only a subset of buildings are represented at map level. A large city like Daggerfall will have many more physical buildings than listed for that location in MAPS.BSA. Even in small locations where the totals match, the individual building type counts don’t always match. For example, map data might define 6x House1 and 4x House2, while block data will contain 5x House1 and 5x House2. There doesn’t seem to be any consistent way to link these two sets of data together. If this were a relational database, I would expect a stable primary and foreign key matching on both sides. But not only does a key not seem to exist between them, the totals cannot be trusted to line up between map and block buildings.

Despite this, I have been able to make some good progress. I discovered that named buildings (taverns, stores, guilds, etc.) are always in the same order in the map building data as the block layout data. Couple this with the building name seed discussed a while back, it’s possible to merge down named buildings without much trouble. This is also needed for the automap like below. Credit goes to Nystul for the excellent automap implementation.

 

When it comes to generic premises like House1/House2, things become more difficult. I can’t depend on an exact match between building type distribution, and can’t find a way these could possibly be linked in a stable manner. Both Lypyl and myself have been through the binary data in great detail. Despite finding a few other interesting leads, we have not found a satisfying answer to the question of mapping non-named buildings from map level to block level.

After many frustrating weeks of searching, I’ve more or less come to the conclusion that it really doesn’t matter. The only buildings that need to be mapped 1:1 are named buildings, and I already have a working solution for this. When it comes to generic premises (which are selected randomly anyway) it should not matter which House1 or House2, etc. Daggerfall Unity selects for a quest. As long as the end behaviour closely matches that of Daggerfall by selecting a building of the correct type, I’m basically free to implement this in a manner suitable for Daggerfall Unity.

In hindsight, the apparent lack of stable linking between map and block data could account for some quirks in Daggerfall itself. For example, it’s not uncommon to find a tavern which Daggerfall thinks is a residence. And only about half the buildings in most towns can be entered anyway (“this house has nothing of value”). My feeling now is that when a location is loaded, Daggerfall simply distributes map building data amongst block buildings using some kind of algorithm where named buildings are populated first and generic buildings are distributed to best effort. As long as named buildings are handled (they are), and other buildings are selected randomly (they seem to be), then I can at least reproduce this behaviour in a way that feels exactly the same to the player. My solution might not be exactly what Daggerfall is doing, but it’s likely very close.

So that’s where I’m at right now – working through implementation of Place resource, selecting locations in the world, and ensuring this maps to physical environment correctly. During this process, I’ve added some fun bits along the way such as the flavour text when entering a dungeon area outdoors. This text is based on dungeon type and reads from strings in Daggerfall’s text database using the same variations.

The other side of a Place resource is the “pc at” condition which tests if player is at a Place or not. This is highly intertwined with Place resource handling so I’m likely to bounce back and forth between these two for a while until I’m happy.

That’s all for now. Rather than go through a long delay between posts again, I’ll try to post as regularly as possible with updates on what I’m working on at the time. Even if the post is short, I’ll try to put in some details of the development process for you to read.

If you enjoy this sort of post, please let me know! Feedback helps me work out what people enjoy reading and hopefully write better posts in the future. Thank you for reading, everyone. 🙂