Hello friends,

Today we're shipping a hefty new patch️ for Neverwinter Nights: Enhanced Edition on Windows, macOS and Linux!

Huge thanks goes out to our heroic community members who helped test the many features and fixes in development patches over the last several months.

Read on for full details!

PATCH NOTES

Version Notes:

Patch 1.80 (Version 8193.9)

Contains cumulative features / fixes since Patch 1.79 (version 8193.5)

For platforms Windows, macOS & Linux, available from Steam, GOG and the Beamdog Store.

New Features

Customize weapons-related feats in baseitems.2da

Weapons-related feats (Focus, Epic Focus, Spec, Epic Spec, Improved Crit, Overwhelming Crit, Devastating Crit, Weapon of Choice) can now be customised on a per-baseitem case.

Please refer to baseitems.2da for the new columns: WeaponFocusFeat EpicWeaponFocusFeat WeaponSpecializationFeat EpicWeaponSpecializationFeat WeaponImprovedCriticalFeat EpicWeaponOverwhelmingCriticalFeat EpicWeaponDevastatingCriticalFeat WeaponOfChoiceFeat

Custom weapon visual effects

Weapons can now have custom visual effects (in addition to the stock fire, ice, electricity, etc.)

Please refer to the new file iprp_visualfx.2da for details.

Custom spellcaster classes

We've added (somewhat partial) support for custom spellcaster classes by "unhardcoding" a lot of the builtin constants and references.

Please refer to classes.2da for the new columns: MemorizesSpells SpellbookRestricted PickDomains PickSchool LearnScroll Arcane ASF SpellcastingAbil SpellTableColumn CLMultiplier MinCastingLevel MinAssociateLevel CanCastSpontaneously

Note that not all combinations are valid. We recommend cloning one of the existing caster classes and then start customising from there. When adding spellcasting to new classes, remember to also update existing columns.

There is also a new ruleset entry: COMPANION_LEVELS_STACK, defaulting to 0.

Level of Detail

You can now specify LODs via a new file type ".lod". When the game loads the model mymodel.mdl, it will look up mymodel.lod. Inside that file, add the following lines:

mymodel_0

40 mymodel_1

80.5 mymodel_2

The game supports LOD files with up to three levels, as shown above. You may omit the last entry. The first line is the high-resolution model; the other two are meant to be lower-resolution model files, that will be dynamically swapped out as the camera reaches the given distance.

Please note that LODs are highly dependent on the screen resolution of the client. The actual mechanisms here need to still be figured out; but for now, we'd suggest choosing LOD distances as if the user had a 1080p screen. To support other resolutions, there is a configuration slider in the debug settings (Ctrl-Shift-F12, select "Config", key: "graphics.lod.scale-factor") that users can influence LOD distances with.

Animation Slots

The game now supports 50 more custom animation slots (LOOPING_CUSTOM21 -> 70).

Script call to swap out textures on the fly

A new script call was added:

// Makes oPC load texture sNewName instead of sOldName.

// If oPC is OBJECT_INVALID, it will apply the override to all active players

// Setting sNewName to "" will clear the override and revert to original.

void SetTextureOverride(string sOldName, string sNewName = "", object oPC = OBJECT_INVALID);

Changes made through this call will appear immediately on clients.

NWSync

When downloading something via NWSync, disk writes now happen asynchronously while more content is downloaded. This should minimise occurrences of "Waiting On Storage". If this is giving you grief, you can turn it off in settings via the key "nwsync.transfer.flush.async".

The NWSync Downloader UI was swapped out with a new version, which is now rendered in Nuklear. It has a fancy graph and a pause button.

Finally, the Storage Manager (Options -> NWSync) now has two tabs: Servers, and Modules. Server manifests (i.e. when joining a PW that offers files) show up in the Server tab.

The Modules tab will show all singleplayer/offline modules you have downloaded via NWSync. To facilitate this, the Storage Manager UI now can download offline modules for you; however, by default, no remote repositories offering this are added to your game. Stay tuned on the community websites for upcoming download repositories of offline modules!

Modules downloaded this way will show up under "Other Modules" when clicking Singleplayer -> New Game.

New Scripting Functions

GetSpecialization(), GetDomain()

int DOMAIN_AIR = 0;

int DOMAIN_ANIMAL = 1;

int DOMAIN_DEATH = 3;

int DOMAIN_DESTRUCTION = 4;

int DOMAIN_EARTH = 5;

int DOMAIN_EVIL = 6;

int DOMAIN_FIRE = 7;

int DOMAIN_GOOD = 8;

int DOMAIN_HEALING = 9;

int DOMAIN_KNOWLEDGE = 10;

int DOMAIN_MAGIC = 13;

int DOMAIN_PLANT = 14;

int DOMAIN_PROTECTION = 15;

int DOMAIN_STRENGTH = 16;

int DOMAIN_SUN = 17;

int DOMAIN_TRAVEL = 18;

int DOMAIN_TRICKERY = 19;

int DOMAIN_WAR = 20;

int DOMAIN_WATER = 21;

// Returns oCreature's spell school specialization in nClass (SPELL_SCHOOL_* constants)

// Unless custom content is used, only Wizards have spell schools

// Returns -1 on error

int GetSpecialization(object oCreature, int nClass = CLASS_TYPE_WIZARD);

// Returns oCreature's domain in nClass (DOMAIN_* constants)

// nDomainIndex - 1 or 2

// Unless custom content is used, only Clerics have domains

// Returns -1 on error

int GetDomain(object oCreature, int nDomainIndex = 1, int nClass = CLASS_TYPE_CLERIC);

PostString()

int SCREEN_ANCHOR_TOP_LEFT = 0;

int SCREEN_ANCHOR_TOP_RIGHT = 1;

int SCREEN_ANCHOR_BOTTOM_LEFT = 2;

int SCREEN_ANCHOR_BOTTOM_RIGHT = 3;

int SCREEN_ANCHOR_CENTER = 4;

// Displays sMsg on oPC's screen.

// The message is displayed on top of whatever is on the screen, including UI elements

// nX, nY - coordinates of the first character to be displayed. The value is in terms

// of character 'slot' relative to the nAnchor anchor point.

// If the number is negative, it is applied from the bottom/right.

// nAnchor - SCREEN_ANCHOR_* constant

// fLife - Duration in seconds until the string disappears.

// nRGBA, nRGBA2 - Colors of the string in 0xRRGGBBAA format. String starts at nRGBA,

// but as it nears end of life, it will slowly blend into nRGBA2.

// nID - Optional ID of a string. If not 0, subsequent calls to PostString will

// remove the old string with the same ID, even if it's lifetime has not elapsed.

// Only positive values are allowed.

// sFont - If specified, use this custom font instead of default console font.

void PostString(object oPC, string sMsg, int nX = 0, int nY = 0, int nAnchor = SCREEN_ANCHOR_TOP_LEFT, float fLife = 10.0f, int nRGBA = 2147418367, int nRGBA2 = 2147418367, int nID = 0, string sFont="");

Performance

Overall game performance has been improved drastically - in some cases, up by 200%. Lower bound performance should be vastly improved, especially on slower hardware.

Perf optimisation: Timer-related updates with many AI objects.

Perf optimisation: The config system is now smarter in tracking updates.

Perf optimisation: Shadows are now much cheaper on the cpu.

Perf optimisation: Texture units are now managed more efficiently.

Perf optimisation: Transformation matrix updates have been optimised.

Perf optimisation: Buffer uploads to the GPU have been made smarter.

Perf optimisation: Texture caching has been optimised.

A new renderhint "NormalTangents" was added, that omits checking for specular maps.

Perf optimisation: nwsync setup and updates now avoid excess memcpys and should be much faster.

Pathfinding

Pathfinding when clicking near objects was improved:

Fixes to Wyvern: Crown of Cormyr

The module now includes all script sources

Fixed "horse hat", and "cannot mount, your tail is in the way" issues

Lucinda's Warhorse sometimes vanished upon creation, in Thunderstone

Empty joust journal entries now read properly

Tile repairs (Castle Barrow, end game bridge, a couple odds & ends)

Soundset.2da conflicts with Heros of Neverwinter fixed

Realigned all horse and snake blue prints to use proper soundsets

Removed duplicate/conflicting SET, ITP, 2DA and TGA files

Lifted a Z-fighting prop in Jousting Grounds

Replaced missing doors in Polter's Fort (Lower/Upper)

Fixed broken transition between Wyvernwater Castle Stables and Wyvernwater Castle

Fixes to Pirates Of The Sword Coast

The module now includes all script sources

Eliminated content from haks duplicated in XP3.bif, merged 2DA's where possible

Performance fixes for PotSC-Exclusive tiles (TCN01)

Fixed a few cases where henchmen could go hostile in cutscenes and break the game

Misc

Module compatibility has been bumped to 1.80.

ResMan can now use more than 256MB of memory for caching. There is a configuration option to specify the percentage of detected physical memory that ResMan can use. Additionally, new defaults in place will avoid I/O churn, resulting in vastly improved performance in complex scenes.

[Windows] We fixed large strings, such as chat logs, disappearing if they exceed 1024 characters.

We addressed an issue where models/resources would leak over when hopping servers, sometimes resulting in a crash.

We updated the crash reporter text and URL.

The data build has been updated, containing the mentioned tileset fixes (ovr/ has been cleaned out into the keyfiles as well, in case you were wondering).

ruleset.2da now exposes the following chargen-related constants: CHARGEN_ENABLED_PHENOTYPES, CHARGEN_ABILITY_COST_INCREMENT2, CHARGEN_ABILITY_COST_INCREMENT3, CHARGEN_ABILITY_COST_INCREMENT4, CHARGEN_BASE_ABILITY_MIN, CHARGEN_BASE_ABILITY_MIN_PRIMARY, CHARGEN_BASE_ABILITY_MAX, CHARGEN_ABILITY_NEUTRAL_VALUE, CHARGEN_ABILITY_MODIFIER_INCREMENT, CHARGEN_SKILL_MAX_LEVEL_1_BONUS

Chargen combinations with any domain, school, spell, and companion should now work fine.

Radial subspell count has been upped to 8 (from 5).

Chargen now allows customisation of class, race, gender, and alignment starting clothes (chargenclothes.2da).

We fixed cls_stat_ tables erroneously being read off by one when validating characters.

[Windows] We fixed fullscreen resolution not being detected on first start.

We fixed Creature and Heartbeat logging settings being conflated.

We fixed GetCasterLevel() on AOEs/SLAs erroneously invalid values.

We fixed Linux Steam CD key provisioning.

Fixed tile path nodes not showing up.

We fixed ground triggers disappearing or losing tint.

Lighting oddities in GUI scenes with some advanced shader mechanisms have been addressed.

The premium module Wyvern: Crown Of Cormyr no longer crashes the game.

The GetDurationRemaining-like script calls now work properly when the duration is longer than one day.

The game now defaults to fullscreen on all platforms except MacOS.

[Mac] Screen Edge Camera Turning when using the MacOS builtin maximise works again.

CopyObject() with a new tag specified no longer erroneously adds the object to the old tag lookup.

The player name is now properly sent to the server even if the Remember checkbox is not checked.

racialtypes.2da no longer divides by zero when the FeatPerLevel columns are 0.

The lightning flash model was resized to full even large screens.

pregen.2da now contains all builtin bics so they don't litter the character selection anymore.

The parameter +password on the command line was fixed.

Human female PLT textures now fall back to male if missing.

Intro movies now again play correctly.

Windows server now shows and advertises the patch revision.

The NWSync Downloader now shows a more verbose error if it is unavailable.

A crash in chargen when adding more lines to skills.2da has been fixed.

A rare nullptr dereference when adding unknown party members has been fixed.

ActivatePortal() now properly uses relays if needed.

Learn Scroll no longer hangs the server.

ELC for Sorcerer and Bards with too many spells has been fixed.

Class IDs > 15 now get spells in the radial.

Support for >17 bones.

When reading configuration variables, 't' and 'true' are now valid trueish.

When reading configuration environment override variables, . and - are now replaced with _.

Spells in the spellbook are now sorted (alphabetically). You can turn this off in settings.tml: ui.spellbook.sort-spells

New ruleset.2da toggle: ALLOW_CUSTOM_PORTRAITS (in chargen)

Fixes

The priorities of userpatch, modules, haks, and override have been restored.

We fixed a shader issue that would result in illumination appearing on content that was intended to be black (e.g. the tile borders in the “Dungeon” tileset).

We fixed mipmaps not being generated for non-compressed textures.

Toolset

Toolset now allows selection of heads from custom slots 50-99.

The up and down arrow keys for Adjust Position now progress in perfect sequence.

We fixed a bug where double-clicking on an area entry could cause parts of the toolbar to grey out.

We fixed a truncation issue when using search & replace in the script editor.

You can now add a NAME CExoString field to your custom tileset palettes, instead of having to put a STRREF.

Object descriptions over 2000 characters long are no longer truncated.

The toolset no longer crashes when moving the start location between areas open in multiple tabs.

A group of raised objects now retains their z-level when moved.

The script editor no longer freezes when trying to compile **/**.

Shield equipping logic in the creature editor was fixed.

Tileset changes