eveofdarkness.org

Zombies, giants, wolves, and demons

Milestone 7's goal was to build a walkable world with zones that include NPCs and creatures, that looks like DAoC: textures, scenery, skinned models and animation. It's also the milestone targeted as the MVP (minimum viable product). We checked it by walking around Camelot Hills: the keep, the village, the water and the sky look like DAoC, and so do the player, the guards, the townsfolk and the wildlife.

The final work session took one more day of fixes.

Zombies were capsules

When the client has no model for a creature, it draws a grey capsule, so a missing model is easy to spot. Zombies, ghosts, ogres and giants were all still capsules. About 65 model ids use DAoC figure files in NIF 4.x, an older version of the file format, and our reader could read their shapes but not their skins: the data that ties a mesh to its skeleton so it can move.

The 4.x skin blocks have a slightly different layout from the later versions. One reference is missing, and before 4.2.1.0 one byte is missing too. Our reader expected the newer layout!

Once the reader handled both, the old creatures took the same path as the newer ones. Zombies and spirits now walk and animate, and 2,136 model ids convert instead of 2,071. A test checks the zombie's rest pose and fails if the skin's bind data is dropped. (commit)

A grey-green zombie in a loincloth, hunched mid-stride on the grass in Camelot Hills, with a boulder and trees behind it.

A zombie in Camelot Hills, drawn from its NIF 4.x figure.

Giants were never drawn

Giants are 22 model ids, jotuns and cyclopes among them, with 434 spawns between them. None of them appeared. The converter asked the asset index for giant.nif and got a zone statue of the same name from a zone archive, not the creature figure.

Our converter pipeline, which takes the Windows client's assets and converts them to a format we can use in Godot, conflated identical filenames! (notionally: figures/Giant.NIF vs. a giant.nif inside zones/Nifs/GIANT.npk)

Figures now come only from the install's figures folder, and giants use figures/Giant.NIF.

A giant seen from behind at close range on Salisbury Plains: furry legs, big boots and blue-grey fists, taller than the frame.

A giant on Salisbury Plains, from the creature figure this time, not the statue.

The wolf wore a rug

The giant was one case of a wider problem. The Windows game installation reuses names across folders for different files, and our asset index kept only one location per name.

A creature skin packed with the figures lost out to a loose housing texture of the same name, so a wolf was wearing the texture layout of the wolf-skin rug. Hilarious looking, but wrong! Item skins lost the same way to zone textures. In all, 135 lookups returned a different file from the one the game uses.

The index now keeps every location specifically and separately noted. Figures, items and effects read from their own folders, and when a file differs from the zone file with the same name, we store it separately for that kind of model.

Our asset audit tool already checked every file in the install for the problems we knew about. We added this one: it now lists every file name that's shared across folders, for each kind of asset, so the next clash shows up in the audit before it shows up on screen.

A related bug turned up in the same pass. Textured figure parts were still being tinted by the NIF's material colour, so a brown horse came out pale green. Textured parts now drop that colour. (commit)

A stone stable in Camelot Hills with a white horse inside. A flat, pale green horse stands outside beside a villager, and red figures crowd the field behind.

Before: a pale green horse by the stable, and the red "demons" in the field behind it.

A grey wolf and a brown horse with white socks, on a dirt path.

After: the wolf in its own skin and the horse brown again.

The teleporter's ring

OpenDAoC marks a teleporter with an untargetable NPC, model 1923. We drew it as a grey capsule beside the teleporter. In the game's own tables, that model has an effect attached: a ring on the ground. The creature table names an effect set for each model, and three more tables give each effect's file, the bone or node it hangs on, and the distance at which it shows. Reading those gives 72 effects on 86 model ids, and model 1923 is now the ring at the teleporter's feet. (commit)

A robed figure stands on a thick, bright blue ring on the ground beside Prydwen Keep's wall.

The first version: a thick, deep-blue band.

The first version drew a thick, deep-blue band, but retail gameplay shows a thin, faint blue line in mist as seen in online screenshots of channelers and teleporters. The original blends effects additively, adding light to what's behind them, and uses glow and dark maps that we had skipped. The Godot-readable glTF format has no additive mode, so the converter records it alongside the material, and the client draws those materials with a small shader. The ring now shows its thin edge over the mist. (commit)

The player at Prydwen Keep's gate. A guard and a villager stand by the archway, and a robed figure stands on a thin blue ring on the ground.

At Prydwen Keep's gate: the teleporter's ring, on the right.

Nineteen red demons in a field

Just past the green horses, nineteen red demons stood in a Camelot Hills field. This is the field where the zombie boars sleep. These weren't demons. Watching packets between our OpenDAoC server and client showed why. OpenDAoC hides a night spawn during the day by sending it again as model 1, untargetable and with its name hidden. In the client's tables, model 1 is a Demon, so we drew it faithfully - not knowing that "daytime = don't draw it."

A field in Camelot Hills with a dozen red demon figures standing in it, and small grey boars lying among them.

Before the fix: hidden night spawns drawn as demons, with the zombie boars asleep among them.

Those creatures are now hidden. When one is shown again, it leaves the hidden set and its movements count again. We haven't confirmed what the original client draws in this case, so it's listed as an open question. (commit)

What's next

Most of these came down to which file, which table or which packet field the game really uses, and the fix was usually to read one more of them the way the original does. The rest of the plan is on the roadmap on the home page.