Neverwinter Nights: Enhanced Edition (v74)
Patch Details:
WARNING! AS OF THIS PATCH, ALL MODULES CREATED/SAVED WITH THE VERSION 74 TOOLSET ARE TAGGED AS REQUIRING VERSION 74 OR HIGHER OF NEVERWINTER NIGHTS GAME OR TOOLSET.
Neverwinter Nights: Enhanced Edition is installable through the Beamdog Client and Steam
The game uses an install directory (read-only), and a user directory
for your content and save-games that is independent of the install directory.
This user folder can be found in:
[My Documents]\Neverwinter Nights (Windows)
~/Documents/Neverwinter Nights (macOS)
~/.local/share/Neverwinter Nights (Linux)
Launching executables with the command-line option -userDirectory alternative_directory will use alternative_directory instead of the one specified.
Linux Install Rebuilt
For nwmain, we now link against a different set of libraries for audio and movies.
macOS Support Updated
Both the main game and the standalone-server should now run on macOS (OS X) 10.9 Mavericks or later.
Upscaled UIs Added
When in full-screen, Neverwinter Nights: Enhanced Edition will automatically use your desktop resolution. The UI will now upscale to the largest resolution possible (3x scaling on a 4k monitor).
Master Server Support and Networking
The in-game server browser now works again for v74 multiplayer games.
LAN enumeration has been improved.
Servers respond and connect faster.
Networking has been made much more robust:
Game servers, both in client and standalone, support UPnP (on Windows only) to map their port.
Game servers will attempt STUN-like udp hole punching to allow clients to connect even when no ports are mapped.
If all else fails (as can be on some NAT types), game clients will use Beamdog-provided infrastructure to relay traffic for players. This connection is fully authenticated and transparent to both the player and the server admin. Servers will still see the player IP address and PORT through scripting and the admin console. A script command has been added to query relay status of any player connection.
Audio System Changes
The audio system (miles) has been replaced with OpenAL and OpenMP3.
Movie Changes
The movie system (Bink) has been replaced with WEBM.
Steam Support
Players on Steam can join their friends by clicking Join Game or using the Friends tab on the Multiplayer browser.
Workshop support has been added. You can package and upload content to the Steam workshop (see Workshop_README.txt for details).
Gamespy (Unique Player Names Support) Removed
Now that Gamespy no longer operates, unfortunately we can no longer guarantee player names are unique across the community.
Your identity is now based around your public CD key (granted through Beamdog servers).
You can configure servervault behaviour on a per-server basis (see below).
Languages Updated
French, German, Italian, Polish and Spanish translations of v74 have been completed. NWN 1.69 was English only.
Server Changes
Optimized multiple hotspots in the servers to speed up processing speed.
Exposed new .ini option to let servers use less CPU when not enough players are connected, but run at full throttle once enough players are connected.
Conversation performance dramatically improved on busy servers.
Servervault characters will be saved by public cdkey (secured via master server) instead of by player name.
Features added for server admins to allow them to switch servervaults from NWN 1.69 to v74 (see official Beamdog forums for more information on what clients and servers must do to make this work).
Added a crash reporter to the Linux server that will enable server administrators to easily report issues.
Servers can now host all premium modules in multiplayer. Note that not all premium modules are meant to be played that way.
Linux servers now run on file systems that do not have a 32bit API anymore (such as Docker-For-Mac/Windows).
New nwnplayer.ini Options
Option added to allow users to claim names permanently and associate the name with their CD Key. Off by default. Turn on ONLY if you are running a persistent world.
[Server Options]
Sticky Player Names=0
When Sticky Player Names is set, this allows the old NWN 1.69 servervault characters saved by player name directory behaviour. Recommended for old persistent worlds that do not want to swap to the new servervault format.
[Server Options]
Server Vault By Player Name=0
Specify the number of clients required to be connected to a server before it stops aggressively attempting reduce its CPU usage via sleep().
[Server Options]
Clients Required To Disable CPU Sleep=1
Specifies the maximum number of scripting instructions available to run within a given script before the script is assumed to be in an infinite loop and terminated (was 131042 in NWN 1.69, minimum = 131042, maximum = 16777216)
[Script Options]
Instruction Limit=524288
Determines whether combat modes are turned off by movement. The standard behaviour is 0, movement turns off combat modes. When the value is 1, combat modes become sticky and not interrupted by movement.
[Server Options]
StickyCombatModes=0
For those of you who want to play around with bigger textures without downsampling in your module, set the maximum texture memory used by the engine on your local machine in megabytes. Minimum 64, Maximum 2047. You should only RELY on 64 MB of texture space for your module if you intend on giving it to others!
[Video Options]
MaxTextureMemory=64
You can configure hard limits on various bonuses and penalties. These ini configuration options can be overridden with the provided script calls (see below).
[Server Options]
AttackBonusLimit=20
DamageBonusLimit=100
SavingThrowBonusLimit=20
AbilityBonusLimit=12
AbilityPenaltyLimit=30
SkillBonusLimit=50
You can now adjust the camera distance and pitch limits through nwnplayer.ini. On the first run, the following values are populated:
[Control Options]
CameraMaxDist=25.000000
CameraMinDist=1.000000
CameraMaxPitch=89.000000
CameraMinPitch=1.000000
New nwn.ini option
[Display Options]
language=en
If you wish to override the language choice as specified by the Beamdog Client, you may set this entry directly in nwn.ini.
Choices Available Are:
German: de
English: en
Spanish: es
French: fr
Italian: it
Polish: pl
Note that if language selected does not exist in your build, English will be selected by default.
SetUIScale: The UI attempts to resize to the maximum scale possible (when at the default value of 0). However, if this UI choice given is too large for you, you may set the UI Scale to a lower number.
If the number is set to a value between 1 and 8, it will attempt to give you that exact UI scale. The game may decide to override this value if you are running at a resolution that does not allow this value properly on the screen.
[Video Options]
SetUIScale=0
The music theme to play on the main menu. By popular request, now defaults to the original NWN theme.
Additional choices include:
mus_theme_main (Original Campaign main theme)
mus_x2theme (HotU main theme)
mus_dd_witchwake (Witch's Wake main theme)
mus_wc_theme (Wyvern Crown of Cormyr main theme)
Add your own bmu file in your install dir/data/mus/
[Sound Options]
Main Menu Music Theme=mus_theme_main
New Advanced Graphics Options (nwn.ini)
Advanced Frame-Buffer Effect (High Contrast): Increases the colour contrast throughout the entire viewport.
[Video Options]
Enable FBEffect High Contrast=1
Advanced Frame-Buffer Effect (Vibrance): Boosts saturation (or colour vibrancy) in areas that are monochrome.
[Video Options]
Enable FBEffect Vibrance=1
Advanced Frame-Buffer Effect (Depth of Field): Causes more distant pixels to be blurred. This effect only becomes visible as the camera zooms in close to the player character.
[Video Options]
Enable FBEffect Depth of Field=1
Advanced Frame-Buffer Effect (SSAO): Screen Space Ambient Occlusion causes edges where objects meet to be darker, resulting in more natural-looking lighting.
[Video Options]
Enable FBEffect Ambient Occlusion=1
New materials and content authoring tools
We added support for normal and specular mapping on any texture.
We added support for .mtr files, which describe a material that can be applied on a per-mesh basis, including fragment- and vertex-shaders. This is still work-in-progress and will be documented once finalised.
Crashes Fixed
Game running on some ATI/AMD graphics cards (updated water support).
Creatures containing more than 255 memorized spell slots for a level.
Using Smite Evil and Smite Good against non-creature objects.
Polymorph spell and items with constitution bonus (in some situations).
Using NWScript's GetReputation() on area of effects created by modules and areas.
Player starts barter with a stackable undroppable (cursed) item.
(Rare) objects deleted while contained in an area of effect.
(Rare) divide by zero crash in the particle system (hellball VFX creates this infrequently).
Entries longer than 255 characters in .2DA files.
Opening the second page of the epic spell radial menu.
Case-sensitive filesystems (Linux) with non-lowercase resources in override.
New Scripting Commands
void SetTag(object oObject, string sNewTag);
// Sets a new tag for oObject.
// Will do nothing for invalid objects or the module object.
//
// Note: Care needs to be taken with this function.
// Changing the tag for creature with waypoints will make them stop walking them.
// Changing waypoint, door or trigger tags will break their area transitions.
string GetEffectTag(effect eEffect);
// Returns the string tag set for the provided effect.
// - If no tag has been set, returns an empty string.
effect TagEffect(effect eEffect, string sNewTag);
// Tags the effect with the provided string.
// - Any other tags in the link will be overwritten.
int GetEffectCasterLevel(effect eEffect);
// Returns the caster level of the creature who created the effect.
// - If not created by a creature, returns 0.
// - If created by a spell-like ability, returns 0.
int GetEffectDuration(effect eEffect);
// Returns the total duration of the effect in seconds.
// - Returns 0 if the duration type of the effect is not DURATION_TYPE_TEMPORARY.
int GetEffectDurationRemaining(effect eEffect);
// Returns the remaining duration of the effect in seconds.
// - Returns 0 if the duration type of the effect is not DURATION_TYPE_TEMPORARY.
string GetItemPropertyTag(itemproperty nProperty);
// Returns the string tag set for the provided item property.
// - If no tag has been set, returns an empty string.
itemproperty TagItemProperty(itemproperty nProperty, string sNewTag);
// Tags the item property with the provided string.
// - Any tags currently set on the item property will be overwritten.
int GetItemPropertyDuration(itemproperty nProperty);
// Returns the total duration of the item property in seconds.
// Returns 0 if the duration type of the item property is not DURATION_TYPE_TEMPORARY.
int GetItemPropertyDurationRemaining(itemproperty nProperty);
// Returns the remaining duration of the item property in seconds.
// - Returns 0 if the duration type of the item property is not DURATION_TYPE_TEMPORARY.
object CreateArea(string sResRef, string sNewTag = "", string sNewName = "");
// Instances a new area from the given resref, which needs to be a existing module area.
// Will optionally set a new area tag and displayed name. The new area is accessible
// immediately, but initialisation scripts for the area and all contained creatures will only
// run after the current script finishes (so you can clean up objects before returning).
//
// Returns the new area, or OBJECT_INVALID on failure.
//
// Note: When spawning a second instance of a existing area, you will have to manually
// adjust all transitions (doors, triggers) with the relevant script commands,
// or players might end up in the wrong area.
int DestroyArea(object oArea);
// Destroys the given area object and everything in it.
//
// Return values:
// 0: Object not an area or invalid.
// -1: Area contains spawn location and removal would leave module without entrypoint.
// -2: Players in area.
// 1: Area destroyed successfully.
object CopyArea(object oArea);
// Creates a copy of a existing area, including everything inside of it (except players).
//
// Returns the new area, or OBJECT_INVALID on error.
//
// Note: You will have to manually adjust all transitions (doors, triggers) with the
// relevant script commands, or players might end up in the wrong area.
object GetFirstArea();
// Returns the first area in the module.
object GetNextArea();
// Returns the next area in the module (after GetFirstArea), or OBJECT_INVALID if no more
// areas are loaded.
void SetTransitionTarget(object oTransition, object oTarget);
// Sets the transition target for oTransition.
//
// Notes:
// - oTransition can be any valid game object, except areas.
// - oTarget can be any valid game object with a location, or OBJECT_INVALID (to unlink).
// - Rebinding a transition will NOT change the other end of the transition; for example,
// with normal doors you will have to do either end separately.
// - Any valid game object can hold a transition target, but only some are used by the game engine
// (doors and triggers). This might change in the future. You can still set and query them for
// other game objects from nwscript.
// - Transition target objects are cached: The toolset-configured destination tag is
// used for a lookup only once, at first use. Thus, attempting to use SetTag() to change the
// destination for a transition will not work in a predictable fashion.
void SetHiddenWhenEquipped(object oItem, int nValue);
// Sets whether the provided item should be hidden when equipped.
// - The intended usage of this function is to provide an easy way to hide helmets, but it
// can be used equally for any slot which has creature mesh visibility when equipped,
// e.g.: armour, helm, cloak, left hand, and right hand.
// - nValue should be TRUE or FALSE.
int GetHiddenWhenEquipped(object oItem);
// Returns whether the provided item is hidden when equipped.
int SetTileExplored(object creature, object area, int x, int y, int newState);
// Sets if the given creature has explored tile at x, y of the given area.
// Note that creature needs to be a player- or player-possessed creature.
//
// Keep in mind that tile exploration also controls object visibility in areas
// and the fog of war for interior and underground areas.
//
// Return values:
// -1: Area or creature invalid.
// 0: Tile was not explored before setting newState.
// 1: Tile was explored before setting newState.
int GetTileExplored(object creature, object area, int x, int y);
// Returns whether the given tile at x, y, for the given creature in the stated
// area is visible on the map.
// Note that creature needs to be a player- or player-possessed creature.
//
// Keep in mind that tile exploration also controls object visibility in areas
// and the fog of war for interior and underground areas.
//
// Return values:
// -1: Area or creature invalid.
// 0: Tile is not explored yet.
// 1: Tile is explored.
object CopyItemAndModify(object oItem, int nType, int nIndex, int nNewValue, int bCopyVars=FALSE);
// Creates a new copy of an item, while making a single change to the appearance of the item.
// Helmet models and simple items ignore iIndex.
// iType iIndex iNewValue
// ITEM_APPR_TYPE_SIMPLE_MODEL [Ignored] Model #
// ITEM_APPR_TYPE_WEAPON_COLOR ITEM_APPR_WEAPON_COLOR_* 1-4
// ITEM_APPR_TYPE_WEAPON_MODEL ITEM_APPR_WEAPON_MODEL_* Model #
// ITEM_APPR_TYPE_ARMOR_MODEL ITEM_APPR_ARMOR_MODEL_* Model #
// ITEM_APPR_TYPE_ARMOR_COLOR ITEM_APPR_ARMOR_COLOR_* [0] 0-175 [1]
//
// [0] Alternatively, where ITEM_APPR_TYPE_ARMOR_COLOR is specified, if per-part coloring is
// desired, the following equation can be used for nIndex to achieve that:
//
// ITEM_APPR_ARMOR_NUM_COLORS + (ITEM_APPR_ARMOR_MODEL_ * ITEM_APPR_ARMOR_NUM_COLORS) + ITEM_APPR_ARMOR_COLOR_
//
// For example, to change the CLOTH1 channel of the torso, nIndex would be:
//
// 6 + (7 * 6) + 2 = 50
//
// [1] When specifying per-part coloring, the value 255 is allowed and corresponds with the logical
// function 'clear colour override', which clears the per-part override for that part.
int SetCreatureExploresMinimap(object creature, int newState);
// Sets the creature to auto-explore the map as it walks around.
//
// Keep in mind that tile exploration also controls object visibility in areas
// and the fog of war for interior and underground areas.
//
// This means that if you turn off auto exploration, it falls to you to manage this
// through SetTileExplored(); otherwise, the player will not be able to see anything.
//
// Valid arguments: TRUE and FALSE.
// Does nothing for non-creatures.
// Returns the previous state (or -1 if non-creature).
int GetCreatureExploresMinimap(object creature);
// Returns TRUE if the creature is set to auto-explore the map as it walks around (on by default).
// Returns FALSE if creature is not actually a creature.
int GetSurfaceMaterial(location at);
// Get the surface material at the given location. (This is
// equivalent to the walkmesh type).
// Returns 0 if the location is invalid or has no surface type.
float GetGroundHeight(location at);
// Returns the z-offset at which the walkmesh is at the given location.
// Returns -6.0 for invalid locations.
// Gets the attack bonus limit.
// - The default value is 20.
int GetAttackBonusLimit();
// Gets the damage bonus limit.
// - The default value is 100.
int GetDamageBonusLimit();
// Gets the saving throw bonus limit.
// - The default value is 20.
int GetSavingThrowBonusLimit();
// Gets the ability bonus limit.
// - The default value is 12.
int GetAbilityBonusLimit();
// Gets the ability penalty limit.
// - The default value is 30.
int GetAbilityPenaltyLimit();
// Gets the skill bonus limit.
// - The default value is 50.
int GetSkillBonusLimit();
// Sets the attack bonus limit.
// - The minimum value is 0.
void SetAttackBonusLimit(int nNewLimit);
// Sets the damage bonus limit.
// - The minimum value is 0.
void SetDamageBonusLimit(int nNewLimit);
// Sets the saving throw bonus limit.
// - The minimum value is 0.
void SetSavingThrowBonusLimit(int nNewLimit);
// Sets the ability bonus limit.
// - The minimum value is 0.
void SetAbilityBonusLimit(int nNewLimit);
// Sets the ability penalty limit.
// - The minimum value is 0.
void SetAbilityPenaltyLimit(int nNewLimit);
// Sets the skill bonus limit.
// - The minimum value is 0.
void SetSkillBonusLimit(int nNewLimit);
int GetIsPlayerConnectionRelayed(object oPlayer);
// Get if oPlayer is currently connected over a relay (instead of directly).
// Returns FALSE for any other object, including OBJECT_INVALID.
string GetEventScript(object oObject, int nHandler);
// Returns the event script for the given object and handler.
// Will return "" if unset, the object is invalid, or the object cannot
// have the requested handler.
int SetEventScript(object oObject, int nHandler, string sScript);
// Sets the given event script for the given object and handler.
// Returns 1 on success, 0 on failure.
// Will fail if oObject is invalid or does not have the requested handler.
Modified Existing Scripting Instructions
object GetTransitionTarget(object oTransition);
// Get the destination object for the given object.
//
// All objects can hold a transition target, but only Doors and Triggers
// will be made clickable by the game engine (This may change in the
// future). You can set and query transition targets on other objects for
// your own scripted purposes.
//
// * Returns OBJECT_INVALID if oTransition does not hold a target.
void SetName(object oObject, string sNewName="");
// Set the name of oObject.
// - oObject: the object for which you are changing the name (a creature, placeable, item, or door).
// - sNewName: the new name that the object will use.
// Note: SetName() does not work on player objects.
// Setting an object's name to "" will make the object
// revert to using the name it had originally before any
// SetName() calls were made on the object.
void BootPC(object oPlayer, string sReason = "");
// Remove oPlayer from the server.
// You can optionally specify a reason to override the text shown to the player.
New Console Command
MakePano {yaw_steps=18} {pitch_steps=4} {view_angle=40}
This command will generate a sequenced series of pictures in your screenshots directory.
You can use the resulting files to stitch together a 360 panoramic.
They are labelled with their respective yaw and pitch angles: MakePano_p{pitch}_y{yaw}.tga
view_angle describes the camera FOV in degrees.
The center point is the camera position, not the player position.
Only one panoramic sequence can be taken at a time. Repeated calls overwrite the previous sequence.
Make sure to provide sane values, otherwise your game might hang while the disk fills up.
You can omit the arguments to use the defaults as stated above.
Toolset Improvements
The toolset is now much faster in many situations, like opening and editing objects.
Numerous crashes and memleaks have been fixed.
The toolset will no longer move objects down to the walkmesh z-level when clicking/editing them.
Undo/redo is supported for object moving.
Objects can be edited by double-clicking them.
The toolset keeps variables on triggers and encounters when repainting their polygon.
The script compiler identifier limit has been bumped to 16K (from 8K).
Other Issues
Fixed aggressive removal of spell uses for bards/sorcerers when charisma bonus is removed from the character.
Fixed DC checks for spell-like abilities (instant feats).
Local variables are now copied correctly to items purchased from an infinite-stack in stores.
OnHit::SpellCast property will no longer overwrite properties of spell currently being cast by creature.
Fixed an issue using EnforceLegalCharacters where feats were temporarily removed, causing spell slots to disappear.
Fixed an issue where spell slots are removed because of premature calculation of primary statistic as we equip the character during validation.
Fixed an issue where item properties can be attributed permanently to a creature without having the item equipped.
Fixed an issue where placeables could get stuck open/closed.
No longer remove creature weapons/armor when ItemLevelRestrictions or EnforceLegalCharacters is on (since this is how horses are generated).
Ensure the PC is actually saved when a PC has been dominated (was saving the dominator's creature data in its place).
Binarized some of the 1.69 MDL files (horses, dragon wings) to improve the speed of loading them into the game.
Dispel Check calculation now takes a tie as a remove effect, as specified in the Player's Handbook.
Counterspell cleaned up properly, no longer grants a wizard with an instananeous spell cast after it is finished.
OnClientLeave event is now called before the creature is physically removed from the area, instead of after, to allow scripting to determine the creature's position as it leaves.
Assassins with Death Attack can now use Improved Sneak Attack without having Sneak Attack 1.
Player Party Changes will only cause other players to stop hostile actions against the creature that has now become friendly, instead of all hostile actions against all creatures everywhere.
Casting a metamagic spell will no longer add the metamagic to the item used immediately afterwards.
Weapon Focus (Trident) should now work properly.
Prevent characters, when being moved in drive mode, from rarely appearing in incorrect locations after area transitions.
Ensure that the module's desired HAK and TLK files are loaded before we attempt to start character creation within a multiplayer module (allows servers to specify their own set of additional base classes, races, et cetera)
Area of Effect objects (in areas containing PCs) have a higher AI priority.
Area of Effect objects now move each time their creature moves (to prevent creatures from outrunning their own auras in busy areas).
Character sheet will now be refreshed when a player loses a level.
Attempting to buy a non-infinite item from a store when you have a full inventory will no longer cause the item to disappear from store.
Fixed rules for deflecting arrows (use the target, not the shooter, to measure whether we must wield the current weapon with both hands).
Properly linked item property to their associated game effects (removal of temporary game effects would occasionally remove the item property effects instead).
Metamagic slots are now properly removed, if the metamagic feat is lost.
Assassin's Death Attack balanced to only fire once per round (first attack).
Assassin's Death Attack paralysis length is based only on assassin level, not total character level.
Quivering Palm will no longer work against Pale Masters with Deathless mastery (immunity system fixed).
For feat-based spells (such as Harper Scout sleep), GetSpellSaveDC now computed properly when the base ability score for the character is less than 10.
Extra spell slots earned from items are unreadied instead of cleared when shapeshifting/polymorphing.
Dungeon Master limboing a sitting creature will no longer make the placeable they were sitting on unusable.
Triggers and doors will no longer run default.nss for scripting events if no script has been declared for the event within the Aurora Toolset.
Spells cast with cones will never target the caster (when launched in some directions, the cone would sometimes encompass the caster)
Applying EffectDeath() on a target immune to death magic will no longer cause the creature to stop all of its actions.
Remove all bad effects from a creature properly (some bad effects were ignored).
Fix to Uncanny Dodge 2 feat (higher-level rogues are now allowed to attack lesser rogues with Sneak/Death attacks).
Increase maximum number of charges that can be placed on items from 50 to 250.
Scripting command CopyItemAndModify can now modify colours 1-9 for custom-content weapons (note that all standard content only has four colours)
Weapon Master prestige class: For the Ki Critical feat, the offhand weapon will no longer use weapon of choice of onhand weapon.
Monk's Circle Kick: When current target leaves maximum attack range, we will now pick a new target within attack range instead of standing and doing nothing.
Defensive Stance mode will be canceled properly when casting spell or using an item.
Fixed issues with saving a character while polymorphed/shapeshifted (temporarily removing the polymorph, saving the creature and reapplying the polymorph).
Greater Sanctuary now stacks properly with Invisibility (True Seeing no longer pierces both effects).
Spell-like abilities assigned in Special Ability tab in creature properties will be cast at level as set by builder (was ignored and set to innate caster level).
Combat modes are now terminated properly when swapping from one combat mode to another.
EffectDeaf() should now work properly for perception.
Monk's Stunning Fist: Balance change to last only one round instead of three rounds.
Party list UI element should function correctly now when one has a large party list and many members leave/rejoin.
Custom-content added base classes can now be selected during character creation.
Players cannot cancel actions through the UI when character is non-commandable (for example, while confused).
Special abilities and cleric domain feats can now coexist in the Special Abilities radial menu if there are >= 8 elements.
Added Rob Krajacarski and Jenny McKearney to the English XP2 credits (they were in the credits for all other language builds).
Combined credits list for all languages into a unified credits movie for XP1 and XP2.
Updated embedded zlib library.
Fixed case where Enforce Legal Characters could prevent a character from multiclassing into a new class with a larger hit dice than the one previously selected.
Removed ability for shapeshifting players to abuse the UI and use their normal spells while shapeshifted.
Skinned animations no longer go out of sync in some corner cases (like editing creature/armor appearances.)
Skybox position is now centered on the character, so skybox warping will no longer be apparent when youre at the edge of large maps.
A crash has been fixed that would occur when modding restduration.2da to very short values.
A crash with reading broken PLTs has been fixed.
A crash related to script caching was fixed.
A set of memleaks in resource handling was fixed.
A serious issue with how shadow edges are generated has been fixed. This happened with complex custom models, like some Project Q creatures, and resulted in visual corruption and delayed, hard-to-fathom gameplay crashes.
A crash with delayed effects applying after a player has left the server has been fixed.
A rare cornercase has been fixed where removing an ability penalty would not remove a linked movement speed penalty (and possibly others).
The limit for SetDescription() has been bumped to 128KB (was: 8KB). Be aware that descriptions sent this way will be transmitted over the network each time a player views it.
A crash triggered by damaging a caster-class player and having them roll a concentration check after having left the server has been fixed.
A rare cornercase crash in applying True Seeing has been fixed.
A bug has been fixed where a immortal bodybag would still despawn after a DestroyObject was queued.
Drag-rotating the window viewport with middle mouse is now framerate- and resolution-independent.
A lot of crashes in the networking protocol handling and related game state manipulation have been fixed.
Security audit; removed numerous hacking methods from codebase.