A big stretch since the weather post. The remake now has a proper opening to a new journey, an inventory with a working lantern, the status and equipment screens, a level up system, and a long list of fixes that came out of playtesting. Here is what changed and a few lessons worth sharing.

Starting a new journey

Pressing New Game now plays out like the original. First comes the brightness screen: two dragon emblems on black, where A should be visible and B barely visible, adjusted with a dagger slider from 0 to 20. The value is applied as output gamma rather than exposure, so dark scenes lift without blowing out the highlights:

C++
float UDDGameUserSettings::GammaForBrightness(float Value)
{
	// The final image is raised to 1 / gamma, so a bigger value lifts the darks. 10 is neutral.
	return 2.2f * FMath::Pow(2.0f, (FMath::Clamp(Value, MinBrightness, MaxBrightness) - DefaultBrightness) / MaxBrightness);
}

One Unreal catch: the engine's display gamma doesn't touch UMG widgets, so the calibration emblems would never change while you move the slider. They are drawn through a small UI material that applies the same curve.

After that, the screen stays black while the opening line is written out in flowing script, then the words fade and the camera drifts down from high above the Arisen and settles behind them. The handwriting is a clipping box that widens across each line with a soft ink edge. The first version slid black blocks over the text instead, and the long tails of the script font poked out past them, so the second line showed at the edges before it was written.

Loading screens, done properly

Two loading bugs are gone. Launching the game from the editor passed the editor's open map on the command line, so the game loaded that map, flashed it, and then loaded the main menu with a second loading screen. The game instance now drops that argument before the first load (a -SkipMenu flag still opens a map directly for quick tests).

The second one is a lesson. To hide the level until the intro's black screen was up, the loading screen was set to wait for a manual stop. The game then sat on the loading screen forever. While a loading screen waits for a manual stop, the engine blocks the game thread, so nothing in the level can ever stop it. The fix was simpler than the bug: widgets added in BeginPlay are already on screen when an auto closing loading screen goes away. The loading screen also gained a thin white progress line with soft fades above and below.

Inventory and a lantern that burns

I or Tab opens the inventory: five tabs (Curatives, Tools, Materials, Special, Other), a four column grid with stack counts, and the party's health, stamina, level and carried weight on the left. Items stack, curatives heal but never past the grey part of the health bar lost to heavy hits, and using an item goes through the server so it works in co-op.

The lantern hangs on the right hip and follows the pelvis through every animation. Its oil burns while it is lit, and the item itself changes as it runs low, the way the original names it:

C++
FString DDInventory::LanternName(const FDDInventoryItemDefinition& Lantern, float Fuel)
{
	const FString Name = Lantern.DisplayName.ToString();
	if (Fuel <= 0.0f)            { return Name + TEXT(" (No Fuel)"); }
	if (Fuel <= LanternLowFuel)  { return Name + TEXT(" (Low)"); }
	if (Fuel <= LanternHalfFuel) { return Name + TEXT(" (Half-Full)"); }
	return Name;
}

An empty lantern won't light until you add a flask of oil. The glass glows with the flame through a masked emissive, the lantern model no longer casts shadows from the light inside it, and unequipping it puts it out and hides it.

A small attachment lesson from this: the lantern first refused to follow the hips. It attached in its component's BeginPlay, which runs before the character swaps in its real body mesh, so the hip bone didn't exist yet and it quietly fell back to the capsule. It now re-attaches once the body is on.

Status, equipment and levelling

The pause menu got its breathing red hover, and behind it sit the status screen (portrait, categories, two columns of stats that refresh in place) and the equipment screen: a grid of item icons, a turning preview of the character, stat comparisons in blue when better and red when worse, usable vocations, and a mark on anything your vocation can't wear. Swords, shields and clothing now show on the character. Levelling follows the original's experience curve and stat growth, and a notice slides in at the top of the screen when someone levels up.

Weather, round two

  • Rain is thin drops now, with splashes that bounce on the ground and on the sea.
  • Auroras only appear over some regions, like rain does.
  • "Clear" really means clear: zero clouds hides the cloud layer entirely.
  • The night sky has a visible moon and a faint band of stars instead of a white haze.
  • Levels can start in fixed weather. The first level opens cloudy with light rain.

One bug here made every level darker than it should be. The weather manager remembered the level's fog tint from a value that is black by default, then wrote that black back into the fog every frame, turning the fog into a dark veil. It now falls back to a soft grey blue.

The crash that only happened sometimes

Every so often the game crashed while walking, usually right after closing a menu. Footstep sounds were cached in a map of arrays, which can't be a UPROPERTY, so the garbage collector couldn't see those pointers. After a collection the cache pointed at freed sounds, and the next footstep played one. The fix is to keep every loaded sound in a tracked array next to the lookup:

C++
/** Lookup only: a TMap of arrays can't be a UPROPERTY, so the GC doesn't see these pointers. */
TMap<FString, TArray<TObjectPtr<USoundBase>>> FootstepSounds;

/** Every sound in FootstepSounds, held here so garbage collection can't free them. */
UPROPERTY(Transient)
TArray<TObjectPtr<USoundBase>> LoadedFootstepSounds;

A scan of every header for other object pointers outside a UPROPERTY came back clean.

Smaller things

  • Death: the body stays down and plays out a two part death, and the game over screen comes up sooner.
  • Footprints look like boots instead of hooves, and footsteps play per surface.
  • A stopping animation when you let go of the stick at a run, and a lower jump.
  • Stairs are no longer mistaken for ledges.
  • A developer sound picker: cycle through every menu sound in game and assign hover, confirm, back, open and close by ear.

A decision for later

Characters won't be premade models. Every protagonist, pawn and villager will be the same base human built from parts, described by a config: body and face sliders, hair, scars, colours, clothing, armour and weapons. The character creator, the game and NPC spawns will all load the same way, so anything made in the creator can be given to anyone. That work starts once the character creation scene exists.

Next up

  • The first level still looks too dark and too shiny. Its materials and lighting are the next fix.
  • Softer shadows and the brightness setting in Options.
  • The character creation scene.