I've cleaned up our haks somewhat, removed some legacy stuff, but - more importantly - added a metric ton of great creatures by importing the Project Q creatures hak.
The updater isn't deleting old files automatically, because that would break old FWN-sourced toolset modules, but if you don't need any of that, you can safely delete:
hak/wrm_sf10_sep.hak
hak/wrm_sf10_senadds.hak
hak/wrm_seasonalv10.hak
hak/
(I've also removed some old and broken horse phenotypes from our old _item.hak.)
As to downloads, we're adding hak/q_creatures.hak
, which is another 383MB or so on disk, and thanks to rsync you can expect only 160MB of actual transfer. Actual net disk usage as a consequence is minus 870MB if you delete all of the above.
There's some issues remaining w.r.t. additional riding phenotypes - we'll fix those as we go along.
I've also pushed a new catflap release that is a bit more verbose about expected disk usage.
Hey folks,
I haven't really done one big update, so I'll just outline what I've been up to in NWN for the last two months - which isn't all that little, but pretty spread out over the server.
Merchants
The Fork now has a few more merchants around - enough to provide most nonmagical necessities and equipment. I'd like a few more still, but new folks should be able to get most of their starting equipment together now. What's definitly missing so far is Peroks alchemical wares and a merchant at the Academy, for providing wands, potions and scrolls - especially scrolls for new wizard characters. There's the oddity that some spells aren't actually available at the minimum caster level, which would needlessly raise the price with our system - so, we'll need to take a look at that first.
There's also two merchants down in the Fardrimm, which I will elaborate on further down.
Mines and Caverns
I added a number of mines and caverns thorughout the maps - some are just small ice caves, others a bit deeper, orc nest and wolf den included, and then there is Turons Folly. Turons Folly is an old mine near Winterwatch, just across the lake from Blackfeather Tower. It was abandoned (and then unnamed) when we started the server, but it has been a source of metal and site of a resurging mining operation for some time.
So using Sens reworked Mines tilesets, I drew up new maps for that. It's most awesome feature (icy cavern variant aside) is the addition of the Raise/Lower function in it's terrain. That coupled with a 30x30 map size actually makes for a terrific cavern system - you can walk for quite some time. You can get lost, too. Right now, it's two of those maps - once ice, one normal, with the 'safe' region being all up near the entrance on the ice map.
There is a little sidemap too, where one should be wary not to blunder in carelessly. I have some plans for further expansions, towards the Fardrimm and the Upperdark in general.
The Wailing Lake and the Crypt of Falros
There is a new place in the Ghostwood, too. As a bit of history, the Ghostwood is an ancient, massive forest covering much of the area between the East Road and the Ice Mountains to the far north. It is heavily populated by undead, especially incorporeal ones, and was the home to a cult of death mages during the days of Old Ilusk.
The new area there is only the second Ghostwood one - the other being Rans witch hut, which I gave a sneak peak of in an earlier blog. It's very draft-ish still, but features a large lake, wailing sounds and partially submerged towers. I'm planning for some ghost spawns or similar, as well. For now, you can enter a series of flooded (and haunted) tunnels, and finally reach an old hideout from that death cult - namely, the Crypt of Falros. It's filled with restless cultists and incorporeal wizards, so take care!
At the moment, further plans include prettying up the areas in general (no placeables yet, even), adding more spawns, and adding interiors to the pair of towers in the lake - unconnected stairs to the towers can be found in the Crypt already.
Tjelfes Quarry and the Halfling Village
Two new maps to the southeast of the Fork. One features an abandoned halfling village (built by players long ago) that has now been taken over by goblins, and the other is the site of a stone quarry. It was built by a dwarven PC named Tjelfe Goldhand, and is the primary source of stone for the Fork, aside from all the rubble the dwarves dig out below.
It will need tunnels leading down actually, eventually connecting to the Fardrimm as well, and the halfling village will feature an interior. Who knows, maybe it'll be cleared and resettled one day?
Summon Runes and Animate Dead
As some might know, we have our own summoning system - it's rune-based, allowing you to have a similar set of possible summons as in P&P, or at least those we can roughly implement. I've been busy creating various creature templates for it's use, and the druid and ranger summons are mostly complete now - just spell levels 8 and 9 are still an issue, since those are sparse in P&P already, let alone that we could properly implement it - what is an elder tojanida anyway?
The other list - so, sorcerers, wizards, clerics and bards - is still very incomplete, with only elementals and our selfmade arcane defenders at many spell levels. Most of those creatures are a bit more work too, but with normal animals completed, creating fiendish and celestial versions of them won't be much of an issue anymore. More special stuff like devils or angels will take a bit more time.
I've started on some new templates for Animate Dead, too - weakening and downsizing mostly. The undead will still scale, but I like just having a greater variance of weak skeletons and zombies, mostly normal-sized with the occasional larger ones thrown in the mix, like a lumbering ogre zombie with a club or somesuch. Will take some tweaking. Once that is done, I will get to include Create Undead and the like into the undead controlling system.
The Fardrimm
The Fardrimm is a network of underground tunnels and roads dating back to Old Delzoun. One major route, the Lowroad, connected Delzoun to Netheril via Ascore, and it ran right below the Fork. We've had some maps of that network for some time, and recently started reworking and uploading some of them. Right below the Fork is Uldans Cross, a roadcrossing including some graves of dwarven heroes and several now resettled chambers. Those chambers include a fancy little dwarven tavern, too!
The other two maps ingame so far include Ghaurins Gate, the underground entrance to Ghaurins Hold, a famous dwarven adventurer - though the hold is unmapped for now - and Redmane Hall, a dwarven delve that was once built by players, raided by Drow and then abandoned, and now is being resettled.
I'm curious to what becomes of those areas - because we actually have a new player and builder who has started working on them instead of myself. His drafts are very promising already!
Miscellaneous
There's been various other changes, too. Probably missing a few of them as well. There's a new interior for the Temple of the Triad - an alliance of gods, including Tyr, Torm and Ilmater - and user-b0396 has built a sturdy little temple to Helm in the southwestern part of the city. Various shops received new interiors, and we're presently looking through some upgraded textures and models for several tilesets. Would be nice to have some ceilings for all the interior areas, for instance.
Well, that's it for now!
I've cloned completerc.hak to hak/silm_t_crc.hak
. This has been a "tough" decision, but in the end, probably completely banal. Complete Rural/City is the tileset we're using for most of our exterior areas, and we already have a pretty substantial patchset that adds to it. The plan for now is to fix all the niggles and add roof walkmeshes.
This alone would basically replace half the hak already, together with our textures, so I decided to just rename/copy it. Unfortunately, rsync can't be made to base chunks off a existing file without patching --fuzzy and I really don't have time to do that right now.
This means folks need to download ~50MB of addn. data and they have a obsolete hak lying around, which I can't reasonably delete automatically without breaking other PWs players might visit. So there's that.
So if you know you don't play on any server that has the same hak, namely hak/completerc.hak
, feel free to delete that.
Issues
Now, there are a few open technical issues that new players need to be aware of. I'm listing them here in order of OMG.
Server crashes
Currently, the server still crashes after reloading areas through nwnx. The crash profile is very subtle and hard to track down; it appears to be some kind of corruption in player TURDs (hey, Bioware's terms, not mine!) and only manifests sporadically on player logout. Please bear with us .. we'll get there eventually.
Gameserver rejects logins, even though masterserver accepts credentials.
This results in (not the exact verbiage but I'm sure you've seen it):
"Your login could not be verified by the server because the gamespy servers are down, but the server requires authentication."
That's not the actual Gamespy servers the message is talking about; this is a bug in nwserver sometimes ignoring my masterserver replacement. Obviously, This needs to be fixed ASAP. The only known workaround right now is to restart the game server. Luckily, this only happens after restarts and can be tested easily. The fix is to completely replace the relevant masterserver parts of CConnectionLib, which will take more doing than writing a blog post.
Restarting your game will not fix it, nor repeatedly hitting the Play button. Only hitting me will fix that.
scrollable, zoomable map.Players (or rather, builders) can place area tiles on that map and from the data gathered therein, relational data is derived (what area is next to each other; what is the actual distance between two points on the global map).
As you might have seen, FWN has aTransitions
That data is used to make area transitions. Instead of builders pasting down triggers on map edges, some crafty code walks the supermap edges and sees if there are areas bordering; and if the tiles on both sides are walkable. Triggers (placeables, actually) are generated automatically, and there is no more confusion about transition tags, broken links, or similar.
As of now, this only works for maps that can be placed on a map, not interior areas. Maps do not actually have to be overland - the system supports multiple layers, so we might have some for overland travel, some for the Fardrimm; even some for caves. The only prequisites are that they are next to each other and on the same level.
Translating Coordinates
You might not have thought it, but this was one of the trickier parts.
All map layers have a predefined origin. One might naively assume that you could just pick the upper left point of a map; however, that has some pitfalls only apparent after some careful thought.
- Having no predefined origin means, for instance, that the whole map moves if you insert a column on the left.This would mean regenerating all transitions, instead of only parts.
- Having no fixed origin from which to count from means that you would have to relocate all placed entities on the map by hand, if the origin changes.
- Once you go far (actually, really far - about 20000km in ballpark-math, thanks to NWN using floats and not doubles natively) into one direction; you run into floating point issues where the decimal part isn't wide enough to accommodate sub-meter precision. That's 200 map 10x10 tiles. Note to self: Enthusiasm about a supermap of this size might be premature.
Additionally, NWN coordinates have no ken about any relation data between areas. All any object knows is it's localspace coordinates, called a Location [ X, Y, Z ]. In the best spirit of vector mathematics, things are flipped as to what a layman might expect, where the vector origin is the bottom left corner of a map. To translate that onto a supermap, you have to take that into account, as well as the offset from the actual map origin as described above.
The next part was placing tiles in the mapping library I've decided to use. Most maps in the real world aren't actually flat! While the plethora of coordinate systems is a fascinating topic for sure, none of it fits into what I wanted to do. I need a flat, non-curved map space that ideally tanslates meters into a on-screen pixel ratio. So there was some more fiddling, since the map lib actually expects map data split up like Google Maps does it. I just wanted to feed actual minimaps into it; as a concession, I've split it up into 10x10 tiles and just fudged the numbers until the scale looked about right.
Systems integration
The map supports displaying arbitary entities (as can be seen in the screenshot). Any object wanting to display on the map needs to send out a "ping" – that is, a publish over redis that contains relevant location and naming data. As usual, this is a good, very fast (in the order of 1-2 milliseconds per object) way to decouple dependencies and make sure that nothing breaks, should a ping go amiss, or FWN crash.
Analogously, events can be sent from FWN to the gameserver over the same channel. A simple publish triggers a script inside nwserver. Use cases might include "Teleport To", "Spawn Object", and so on.
Editing
Ideally, editing would be done through FWN itself. However, that is for the future. Fow now we're simply using a Google Docs spreadsheet, that FWN reads (via the google API).
While not really a limitation of the underlying code, to make things simpler (both for builders and for managing the map), map tiles are limited to multiples of 10. So maps can be any variation of (10, 20, 30) x (10, 20, 30), to a maximum of 30x30. Each cell on the spreadsheet corresponds to a 10x10 part of a map.
There is preliminary support to place custom map markers, zones and vector lines on the map (and read those from NWScript). The idea was to disconnect spawner definitions from .git files, and maybe allow reliable cross-area waypoints. This is not implemented yet.
silm.pw runs some custom software that allows players to upload areas by themselves, with no admin, builder or DM intervention neccessary. That software is called FWN (Frankenwinter Nights, haha). The premise is to take the load off devs and allow people to build maps in a collaborative fashion that was not possible before.
So, uh, what is FWN, again?
nwn-lib on the backend. It accepts uploads of gff data (.are, .git, ..) and containers (.erf, .mod) by any authorized account, checks the uploaded files for validity, and then commits them. While this may sound fancy, it is actually quite simple for the end user.
FWN is a Rails (web) application, that is a wrapper around a git repository, held together by angular for the frontend, andFWN supports browsing commits, locking and unlocking of resrefs for modification, downloading current and past data, viewing minimaps and managing the supermap (more on that later).
The backing (bare) git repository is handled by rugged, a low-level ruby git library. It has a flat file/directory structure, closely mirroring how files are packed in a .mod; but files are stored as deserialised yaml instead of binary gff data (I chose yaml over json because it is just a tiny bit prettier). This repository isn't exactly intended to be touched out-of-band (meaning outside of FWN), but it could be done if one would want to do mass-updates, as long as no concurrent FWN access happens and the lockbox would be clear.
(Also, for a somewhat-succinct history, see FrankenWinter Nights).
Index Imagination
Each authorized account has a "staging area", which is called an index in git terminology. This is basically a serverside temporary box where data can be dropped into and then committed in a single update. If you are familiar on how git works, this is modelled after that - but reimplemented to support more fine-grained control over it that couldn't have been done with native git indices.
Lock me baby
Because no automated merging mechanism for gff trees exists yet(not actually trivial), there are safeguards in place to prevent concurrent modification of data. These safeguards are the reason why builders have to jump through some hoops, the first of which being the lockbox mechanism.
That mechanism is, at it's simplest, just a flag that tells other people "I am working on this resref!", but FWN also disallows other people to lock the same files (or, indeed, make changes to them).
Stale data is even worse than stale beer
However, that isn't enough to prevent accidental overwrites with outdated, or even completely unrelated data.
Verifying that data is not stale, thus, is important. You don't want people to be able to (accidentally) upload outdated resrefs, overwriting edits by other players. This is a problem that used to feature frequently in the past, so getting it right this time was a priority.
Each gff file downloaded from FWN is embedded with metadata describing the commit the downloaded file is based on. You can see this in the object variables for areas, or comment field for resrefs that have no VarTable (like .git). At upload time, this data is extracted again and compared to the latest commit where the resref was touched. This could obviously be fudged or simply copy/pasted if one would want to.
Only changes that are direct descendants of current data are allowed to be imported (otherwise it would overwrite changes from other players with stale data). To make this process easier, FWN has a per-account lockbox where resrefs can (and must) be put into - a simple mechanism to stop players from editing the same files concurrently.
Since authors usually don't bother updating their local metadata between commits (by fetching it from FWN again), changes to previously-new files, or files based on the same parent by the same author, are still allowed.
Rewriting your bugs on index upload
Apart from that, data is also rewritten to account for convenience fixes so builders to not have to keep track of them, or things they miss regularily. Here's a very short excerpt of things we check for, just to give you an idea on what we try to catch serverside (sources if you're interested):
- Resref naming schemes to fit our style guide.
- Rudimentary access controls (i.e. most people can upload areas, but creature templates are restricted to encounter maintainers)
- Strip out all FWN metadata (after verification)
- Doors without a transition to be locked & flagged as Plot
- CExoLocs not having multiple languages, confusing clients (we only do English)
- Transition correctness
- .. and lots more
Uploaders see warnings and errors live as files are dragged in; this allows for a very smooth workflow (that is, until a native app comes along to make it even smoother-er). The rule of thumb here is to allow as much as possible, and only fail on errors that cannot be fixed automatically or would otherwise yield results unintended by the author. The point is to not catch mischief, but to help people avoid common pitfalls.
Committing
Once the index looks about right to the author, he provides a commit message (which is just what you think it is - some human-readable details on what his changeset does), and clicks commit. Data is converted to yaml, written to the git repository with proper attribution, automatically pushed to Stash, and then deployed to the server.
Sidenote: Because not all checks can be done on import this step provides another hook for verfication – for example checking that merchants never sell resrefs that don't exist.
Deploying
Deploying files takes a bit of effort. Each commit (actually, each resref change) triggers a special asynchronous Deploy job run in the background. That job pulls YAML data out of the repository, and then runs even more script hooks.
Those hooks are there to do further mangling - especially that kind of mangling that is required for live operations, but shouldn't ever end up in the source repository; for example:
- Resrefs are once again annotated with commit data; seeing those are just local variables, any script can query them serverside to see by whom, when and why that particular object was made.
- Ensuring placeables are flagged static or non-static where required (think AnimationState, readable descriptions; load & render performance).
- .. and so on ..
Additionally, metadata like extended tile information is being extracted, collated with what is available in game resources not otherwise accessible from scripting (like model names, tile IDs), and put into Redis as well, so that it can be accessed at very little cost. We also make extra minimap pngs and cache them for the web frontend.
The actual resulting gff data is serialised and put into Redis too, which nwserver now is free to access (nwnx_redis supports ResMan after all). nwserver is notified through Redis pubsub support, and a very simple script handler (see include) reloads the area with nwnx_areas.
Changes to non-area resrefs are handled a bit different. Those obviously only take effect when a new instance is spawned. Existing creatures, items, and so on stay where they are (but merchant objects are re-instanced on the fly as well by comparing commit sha on each access).
The net effect is that changes are live pretty much immediately after clicking the "Commit" button, with no further effort required on my part.
Upcoming on this blog: automatic, clickable area transitions, courtesy of FWN and a crufty google docs sheet.
Imagine, for a second, you're running a PW. Not the cool kind of imagining, of having a hundred players or a million areas that slithers along smoothly powered by six DMs running quests every evening. No, imagine the bits that are actual work. Renting a physical or virtual server, administrating it, managing scripting functionality, database schema, web frontends, writing nwnx code, building areas, managing custom content, and so on.
.rar yay
As it started out in the far past, the usual process of working on a PW was to send around a .mod - probably packaged up as a .rar - with people making edits and then sending it on (or back to you, for you to copy it onto the server, restart, and hope nothing breaks). You wouldn't really have backups of it (or if you did, it wasn't automated or scheduled). Edits would on occasion be overwritten by other authors, with little oversight on who made what change, who broke the latest script, or who slipped in undesired game-changing content (exploit or otherwise). You'd never do it this way, of course, but that's the Status Quo, so why not stick with it for just a moment.
Now, considering that you do software for a living, you quickly come to the conclusion that the current process sucks and you go about automating things. First the small bits - like setting up a source code repository. Then writing up some scripts to build a .mod and deploy it on the server, in varying degrees of sophistication. Maybe even convert all module data into YAML, because the diffs look much nicer this way. Of course, to do that, you'd have to write a library/toolkit because none of the existing tickle your fancy, so you set off with that and waste a few weeksmonths on it.
A Jenkins instance follows quickly because you can't be arsed to package and upload manually. Maybe Jenkins even restarts your server once no players are online (and you swiftly notice that that's a bad idea, as soon as the first DM comes a-crying about his lost quest setup). This works well enough, for a few monthsyears, but eventually ..
Imagine you have spent considerable time setting up a build chain like this, for yourself, on the assumption you will be the only one deploying content for the forseeable future. You consider yourself the gatekeeper, because - well, someone has to keep an eye on quality control, right?
Eventually, you decide that this process, in fact, sucks even more. All you managed to do is make MORE work for yourself - you spent time writing all those scripts to help you, true, but everything still passes through you. You decided to lock everyone else out of quality control, so you're kind of expected to test things yourself too! This is not acceptable.
What if I don't care anymore, with even more MediaWiki
So, you decide to re-engineer your whole process again. You have a vague vision of what it looks like - from a technical standpoint, you start eyeballing MediaWiki and wonder if you can just, like, .. adaptit to suit your purposes (figuratively speaking! Don't look at me like that!). Of course, just sloshing 500 areas into a Wiki engine doesn't work, so you start exploring options on how to go about making collaborative editing of a NWN PW a reality. You stopped caring about politics (after all, we're all adults and if the system isn't robust enough to catch trolls, why bother?) and you just focus on the technical bits. In fact, by just giving everyone write access, just maybe something fantastic will come into reality!
Your aims are laid out in a simple fashion, actually:
- A web interface that shows "some kind of map" where people can drag and drop areas to make up your world note to future self: make it pretty
- Ideally, it would hook into the toolset and you could just one-click areas to upload them
- Some kind of versioned storage that takes all module data. Maybe even custom content, but that would require 2da tracking .. eh, nevermind. Let's stick to module data.
- Verification of said content, so people don't break the server by uploading invalid files, crashy areas, infinitely-looping merchants, and so on.
- Maybe some small scripts to rewrite/change content as it is uploaded.
You spend some monthstime brooding over this, while life moves on and you are generally busy/lazy, and eventually see that you actually can't do this right now in the way you want to. You'd first have to write some more glue code. You need reliable pubsub messaging (no, database polling doesn't count), and if you could hook ResMan into that to load content on the fly (via nwnx_areas which was still broken at the time), that'd be great. So you sit down one evening, in a train - seriously, what's it with trains and shoddy hotel rooms that makes you desperately productive, and start hacking on something you had no idea about. Eventually, nwnx_redis appears - a plugin linking redis, pubsub, script execution, resman and SCO/RCO together.
Various iterations of a web frontend quickly follows (well, not quickly - you decide to refactor the player-facing vault first, wasting another few weeks of off-hours work), and foolish as you are you think that you should just reinvent the wheel. A hacky handrolled database-based storage system for your module data migrates from IDEA to whereever deleted inodes go. You settle on GIT for backend storage instead, read up on rugged, and because you have a very naive, misguided vision of players writing their own tools in this shiny future of yours, you set up the frontend as a API-based angular app, with proper authentication and everything.
Even more glue code later and a million bugfixes later - memory leaks in NWNX, your plugins, and even in nwserver itself you didn't even know existed; pointer double frees that you decided to just ignore by taping it over with libdiehard, and so on - you actually have a proof of concept working. You can upload areas (.are & .git, really) into your fancy new frontend and they magically appear in the DM chooser list. You can jump into them, see everything live; click on objects and even get data on what bugger spent time making the area. Success!
Wait, what?
Not so successful. Now you notice that this was just half the work you needed to do. Those politics you ignored at first? Turns out, it doesn't really work without them. You need some kind of logical framework on how to manage content. Those "some small scripts" you briefly thought about a year ago? They're kind of essential. You start drawing up a "module schema" - much like for a database, but for content instead. How to name things, how to organise resrefs; what can be committed and what cannot.
This project quickly balloons into a full Development Wiki, and a refactor of your whole upload/commit/deploy process (taking another few time units of off-hour evening work) so you can hook into the process at any and all points. You figure that enforcing some rules isn't so bad after all, because having a big furball made by people letting their creativity go wild is vastly different from people just not knowing better and making a hash of things.
But with all that now well underway, all it takes is the occasional bugfix or addition and things are going well enough - not smoothly, but amiably.
This is the first part in a series on FWN; just some background history on what it took to make such a simple thing. The articles to follow will go into painful detail on how the actual bits work.
Vault now supports HTML5 desktop notifications. These are little popups that newer browsers show; you might know them from GMail or similar. This is why the Vault will ask you for permission to "Show Notifications". (If you accidentally click on Deny, you'll have to manually allow it again for our domain somewhere buried in the browser settings for this to work.)
TheYou can toggle it in the Account menu at the top right, where the sound notifications are as well. The idea is so you can simply leave the Vault open in a background tab and not bother with our crufty XMPP bot. I might add the same to FWN later.
I've tested it on current Firefox and Chrome and called it a day.
This should be pretty self-explainatory:
/** * Creates a parametrised polymorph effect. * * Implementation details: This operation is currently not atomic; it needs to be applied BEFORE * creating any other custom polymorph effects. This may change in the future, so the call semantics * remain as they are. */ effect EffectPolymorphCustom(int appearanceType, int racialType, int portraitId = -1, int str = -1, int con = -1, int dex = -1, int acBonus = 0, int hpBonus = 0, int spell1 = -1, int spell2 = -1, int spell3 = -1, string portrait = "", string equipped = "", string crWeapon1 = "", string crWeapon2 = "", string crWeapon3 = "", string hideItem = "", bool locked = false); /** * Allow/disallow the given creature to use items while polymorphed. * * Implementation details: This just sets an lvar, and as such will apply to ALL * polymorph states this creature enters. Semantics of this call will change. */ void SetCreatureAllowPolymorphUseItem(object creature, bool allowed);
The API really isn't as clean as I want it to be, but it'll do for now. I really need to stop adding bells and whistles and get back to the encounter/spawning system. *snooze*
Looking at the D&D dragon disciple, I always wondered what this class is even supposed to be. Browsing the internet for some insights, nobody really knew and it was considered a waste of levels by all sane beings. Even when viewed from a fluff perspective, it never really offered much atmosphere. Even worse, the standard NWN implementation does not even offer the same amount of features as the SRD variant would normally offer and limits players to the red dragon variant.
It was time to fix this class
Knowing that pathfinder always knows how to fix D&D issues, it was my first source in getting some insights how they approached the dragon disciple. In the pathfinder world, the dragon disciple clearly is a melee combat oriented class with a continuing arcane caster level progression. It has the best hit die possible (d12), extra combat feats and a powerful breath weapon (1d10 per level, 1 use/level). Even better, he can transform into a dragon later on! Great concept!
So what changes make sense for our dragon disciple?
First of all, the dragon disciple is a melee combat oriented class, so I removed the staged d6, d8 and d10 hit die that made no sense at all and replaced it with a d12, just like dragons. I also replaced the breath weapon with the pathfinder variant. The NWN breath weapon had a static DC of 19, worked only once per day and had an underwhelming damage that was no danger to any character or monster of the same level. The damage is now changed to 1d10/level, usage is 1 per level and the DC is 10 + level + CON modifier (same as dragons). So now the dragon disciple has a serious weapon at his disposal that exceeds even the damage of a fireball!
Second, I added the feats from the pathfinder draconic bloodline extra feat list. Blind sense with blind fighting is now easily possible.
The third was to compensate the missing arcane caster progression. This is something not done well in NWN and so I scrapped the whole requirement to be a spontaneous caster. To compensate even more, I increased the skill points from 2 to 4. Also, the whole immunity thing comes too abrupt in D&D and the other 9 levels, the dragon disciple does not even get a small resistance so I decided to change the immunity too. A dragon disciple now receives a percentual damage immunity, 10% per level, resulting in a 100% energy immunity at level 10.
Bloodlines
The most annoying thing with the NWN dragon disciple was, that it was actually only a red dragon disciple. There was no option to be a silver, black or blue dragon disciple. The new implementation will allow this. The player has to decide what bloodline the disciple belongs to which then in turn determines the energy type and immunity. This is a tricky one because NWN does not allow feats to be chosen only once. A feat gets available and stays there, for the rest of the character's progression which is not what we want since this would mean a character can choose multiple bloodlines. So the actual decision for the bloodline has to be made outside the character progression screen via scripting.
What about dragon shape?
Pathfinder gives a dragon disciple the ability to change into a dragon for a certain time. Will this come next? Maybe, this is not decided yet but will be after a first evaluation how the new dragon disciple fares.
3.5 Armor values are pretty weird. I mean, just look at it! Some of them are just plain useless even in P&P; and most are not available in NWN as-is anyways, for example, the differentiation between a +6 Splint and a +6 Banded.
So the Silver Marches Rule Kobolds decided to rework them, and here is what they came up with.
Armor
ACP = AC - 2
ASF = AC * 5
AC | MaxDex | ACP | ASF% | ASF% (Bards) | |
---|---|---|---|---|---|
Clothing | 0 | - | - | - | - |
Light | 1 | 8 | - | 5 | - |
Light | 2 | 7 | - | 10 | - |
Light | 3 | 6 | 1 | 15 | - |
Medium | 4 | 5 | 2 | 20 | 20 |
Medium | 5 | 4 | 3 | 25 | 25 |
Heavy | 6 | 3 | 4 | 30 | 30 |
Heavy | 7 | 2 | 5 | 35 | 35 |
Heavy | 8 | 1 | 6 | 40 | 40 |
Shields
ACP = AC
ASF = AC * 10
AC | ACP | ASF% | |
---|---|---|---|
Light (incl. Buckler) | 1 | 1 | 10 |
Heavy | 2 | 2 | 20 |
Tower | 4 | 4 | 40 |
The keen observer will notice that tower shields are now AC4 instead of AC3.
We hope this clears things up a lot, and will make calculating things in your head simpler too. Our resident Drow has been volunteered for sacrificial testing. Happy bashing.
I've added some tweaks and patches to the server so that shield, armour and weapon proficiencies are handled as they are written in the 3.5 SRD (or Pathfinder, where it makes sense).
Proficiencies
Armour and shield proficiencies have been softened; meaning anyone can equip any defensive gear now. Doing so with things you have no proficiency for (as in, the feats) with will apply the penalties transparently that one would expeect:
A character who is wearing armor with which she is not proficient applies its armor check penalty to attack rolls and to all skill checks that involve moving, including Ride.
When you are using a shield with which you are not proficient, you take the shield’s armor check penalty on attack rolls and on all skill checks that involve moving, including Ride checks.
Haha-sidenote: Funnily enough, hooking CNWSCreatureStats::GetSkillRank(*this, uint8 skill, *versus, bool a3)
, completely ignoring a3, and expecting everything to go smoothly was a bit naive in hindsight. Turns out that is actually ranks_only
just like the script call advertises, and the Save-to-servervault method actually calls this too .. Oh well, restore from backup .. When called with false it actually returns all the feat-modifiers and properties anyways, so might as well inject myself there and no harm was done.
As well, wielding a tower shield will provide you with a fancy -2 penalty on AB; which is something NWN did not do before. A very minor issue.
The same goes for weapons you are not versed with; however, here the penalty is a tough -4 to AB:
When using a weapon with which you are not proficient, you take a –4 penalty on attack rolls.
Right now, that penalty applies whenever you wield a weapon you are a noob with; no matter if offhand or mainhand (but only once, you know where to send the money!). Not too sure what to do about that, since AB would have to be hooked separately for each hand I think, and I didn't find the right place. I suspect it doesn't actually exist, and I furthermore suspect it doesn't actually matter in real-life. Might be better off if I had chosen to use engine effects, but that would have been cludgy at best. Right now I'm feeling pretty good just ignoring it!
duplicates some fields provides data to all provides data to some AI-related methods makes a copy for sending to clients does magic, and once that was hooked just so (AB 180/175/170/165 sounds about right, right? Right?) it worked. I'm pretty sure the whole thing breaks if a DM does #set bab something something but don't tell anyone. The worst part was actually finding the places where the UI is updated (you know, the charsheet!). Turns out, there is some mysterious method pair CNWSCreatureStats::UpdateCombatInformation and CNWSCreatureStats::UpdateLastStatsObject that
Special Attacks
Special attacks are all attacks that are inserted into the combat round - like TripKnockdown, Disarm, Stunning Fist, Critical Strike, and so on. I've hooked those as well, so that one can run arbitary effects instead of the hardcoded ones. Right now, the only fix applied is to reduce stun duration for Stunning Fist to one round (was three!), and completely disable Disarm and TripKnockdown, because frankly they suck donkey. There was talk about reworking all those feats into PW-compatible Combat Maneuvers inspired by Pathfinder. Real Soon Now.
Bards
In the same vein, I've deleted the shoddy scripts that used to apply a -20% ASF on light armour worn by bards, and made it into a core override instead to GetASF (actually, I am mid-method hooking Get2DAFloat inside of CNWSCreature::ComputeArmourClass (sic), but who cares about that, right?). So yeah, this is now handled natively as well, making it much more robust (and transparent) to the user. Someone just needs to go and edit the TLK entries for light armour to show that fact to attentive readers.
In any case, This is in line with our aim in getting rid of all the NWN-isms that don't make much sense in a persistent world setting.
Witch Casterlevels
The Witch PRC outlined (okay, it was more than an outline I guess!) in a previous blahg post required some intrinsic tweaks, so that the taken Witch class levels are added onto the Druid class levels for the purpose of spell CL/DC calculation. That has been done as well, and should work transparently with no script-side monkeypatching required. The same mechanism can be used to augment any non-spellbook caster PRC to provide full CL progression for it's base classes, but for now, it's just the Witch. Drawback right now is that it only makes sense build on the Druid class; and a multiclass character cannot pick onto which base class the Witch should gloop on.
Technical Background
All of this code goes into a custom NWNX plugin that will eventually be published for other PWs. Goal is to provide a drop-in plugin that just 3.5ifies your server, with no scripting necessary. The actual code is in our silm-specific NWNX plugin (and 3.5ify-plugin here), and will eventually be bumped onto Github as well (another long-waiting thing to be pushed is nwnx_redis ..). So that this doesn't conflict with other plugins that might conceivably hook these methods (although I can't think of one offhand!), I might have to introduce some new core events in nwnx2. We'll see.
Pointy thing
). Better not mess with that one!
Also, I made a new rapier, in the style of older sideswords (or so I've been told). Design target was a character of mine, aiming for a really elegant-but-sinister look, but I suppose it would look just as fierce in the hands of a drow (although it might be too big for them
One of the oldest and most used areas in the earlier days, still on silbermarken.de, were the great forests taken directly from the setting. The more important one was Arn Forest, the largest set of maps we had back then - I think it was more than 40 maps, all 10x10 tiles. Real centre of player activity for elves, druids and other nature types. Alchemist gathering place too, for a while. Banditry happened in there, goblins attacked the elven tree settlement, and at some point its western flanks were set on fire, causing a lot of characters normally at odds with each other to work together to stop the fire. Fond memories there.
Well, the playerbase has changed - though activity flared up again thanks to Vashandos rangers and the keep they built, most activity really shifted towards the Fork again, with the Arn Forest being a fondly remembered but rarely visited backdrop - mostly travelled through to get to Arnkeep or for the odd character living in the woods. For myself, at least, it didn't help much either that the classic NWN forest tileset was fairly bland in appearance. I mean, we didn't even have altitude variation, and it certainly did not feel like a northern pine forest to me. I visited it truly rarely, the last years.
Rebuilding
Part of our rebuilding effort was doing the wilderlands - the 'Realmspeak' word for the wilderness - better justice, trying to create outdoor maps closer to what the area should look like in-setting. So, after the most important map updates - i.e., those people were using on a regular basis - we eventually pondered what we would be doing with our woodlands to the east - especially since we had to put Arnkeep nearby somewhere. Can't have that without the accompanying forest. And there was a player with a tower in those woods, second-home at the Fork nonwithstanding. Still, second-rate would not do, so we checked out some tilesets.
I'll say it right here - the only tileset that was ever truly an option was Mountainous Forest by Baba Yaga, and expanded on by Zwerkules. I was quite skeptical even there since it's quite lacking in building options, and doesn't even have water terrain aside from your normal stream - two items that are rather compulsory for our past history in those woods. Other tilesets had those, but, no or lousy pines.
In the end, I just tried it out. And damn, am I happy I did. Honestly, it looks awesome. With just a bit of terrain variation and lighting play, you can create dense and thick pine forest without too much repetition, and with our weather system providing fog, you can and will get lost in those ancient deep forests. The terrain groups and features may be limited, but together with some placeable work, you can do far more than I had initially feared.
So far, the Arn Forest consists of four 30x30 maps, with quite a bit more to come - just to cover the most important areas, such as Quintars tower, the ranger camp, and the river leading to Arnkeep.
Watcher's Rise
This is actually a new place that didn't exist in earlier iterations of the forest. It features a stone platform with four great dwarven statues, all set on a stony crag rising up over the trees. A leftover of Old Delzoun, the great dwarven realm that ruled about all the place over a millenia ago.
I'm pondering to add a bit of dwarven ruins underneath it, too - probably once I get around expanding the Fardrimm (a dwarven tunnel network, similar to the Deep Roads of Dragon Age if you're familiar with that) into that direction.
It's a pretty cool landmark, all in all. Could see folks meeting there simply for it being a good point of reference.
River Icespear
The Icespear is actually coming down from the Nether Mountains near the Fork, and then flows west - we invented our own little spin-off going east instead, towards Arnkeep. Should probably give it a new name. As it is, it goes through three forestmaps (two of which are mapped so far) and then stops right at the walls of Arnkeep, large enough to accomodate river barges.
As mentioned before, the tileset only supports small streams - completely unsuitable to the large river I had in mind. So, being as lazy as I am,I dug a trench, removed the trees inside with an overuse of the clearing feature, and filled it with placeable water.
Funny how well lazy ideas work at times. Since it's normal terrain down there too, you can even walk around in the riverbed if one wants to roleplay some swimming. Doesn't look any worse than actual watertiles in most cases - the only issue I found was that certain lighting effects can look a bit odd if you're standing just at the boundary between two connecting water placeables; but since they are four tiles (40 metres!) long, that doesn't happen all that often. Well, that, and it not really showing on the minimap.
Buildings
As said, the tileset doesn't really have much in the way of buildings. Two tower variants and a tree hut with two terrain variants. And by 'hut' I really mean a tree trunk with a door and windows. We have a ton of building placeables, but being placeables they don't have door nodes. Still, they can be used now and then - say, a log-cabin like addition to the side of Quintars tower, with the tileset tower holding the door node, or by fiddling with one of the NWN2 Mulsantir houses to place it ontop of the tree hut exactly right for the placeable doorway to align with the hut door node. That fussing about with placeables actually makes me wonder - why not just add invisible door nodes to normal tiles, then put placeables on top? Hmm!
This mulsantir house is actually in Ghostwood, not Arn Forest, and features in the only Ghostwood map that exists so far - I'll write more about that particular spookywood in a later blog. Consider this a sneak-peak.
Arnkeep
Arnkeep was actually simpler than I thought. It's not directly inside the forest, so I fell back to good olde CompleteRC, and finally got the opportunity to play around with those city and castle construction tiles. Doing quite well for a first draft, even though there is something wrong with the door node on the castle gates. For some reason, it freezes loading screens upon entering the area - but only when I place it within a certain distance of the rest of the castle on it's hill. Anywhere else, it works. Heh.
No matter, I'll keep the gates open for now - as they'll usually be for roleplaying, anyway - and bug niv to fix it at some later point. After all, there is a lot of work to be done still with this initial draft, and I have haven't even started with the insides yet! First will be new, more rustic textures for the castle itself, for certain, and the little village nearby - simple folk producing charcoal, which, together with the iron mined one Arn Forest map to the east, is used to make steel at the keep, and later shipped to the Fork. On that - I need movable river barges!
So much for the first few Arn Forest maps. I'll be doing some brief military service starting thursday, so expect a new blog post or content in general from me either far off until March if I'm busy, or pretty damn soon and/or often if I'm not. I really have no idea yet.
So, let's talk about adding new spellcaster classes to NWN.
It doesn't work. Not easily anyway. Most of the stuff is hardcoded right into the game, no matter how often you set that spellcaster flag in classes.2da to true, and no matter how many spellgain tables you define. There's a few ways to work around, with feats, subradial spells and so on, or with all the heavy scripting the Player Resource Compendium employs, but it's clunky, I tell you - no fancy, easy spellhandling like with the existing classes, suitable at best for a secondary caster with limited spellcasting - say, if we ever get around to implement a proper assassin or blackguard.
It's pretty much why I built my witch character as a druid. It was close enough to what I wanted. But, alas, it was not perfect. So, how to get a set of nifty witch abilities while avoiding the entire "make a new spellcaster base class" issue? The answer will be obvious to those of you playing any of the P&P 3.x derivates - a prestige class. Easy solution, right?
Except not. NWN has a funny way of handling spellcaster progression in it's prestige classes, so, I started experimenting and taking notes. I took the Champion of Torm, and gave it full progression, arcane and divine, and removed the prerequisites. As expected, I did gain new spells per day, and even access to new spell levels precisely as I should, no matter the class, just as if I had taken levels in whatever base class I started out with.
That was pretty much where it stopped working right, however.
First off, the most glaring issue with all classes - it does not advance caster level. So even though you might cast the same number of spells as a pure-classed wizard; if you are a Wizard 5 / Loremaster 10, your Chain Lightning spell stops at 5d6 compared to your Wiz15 buddy's 15d6, and your roll for dispel and spell resistance checks is at a meager +5 instead of +15. In other words, in many cases you effectively neuter yourself.
The second issue - not for everyone, but just as or even more showstopping: Spells Known. While a PrC can advance your spells per day, it does not, in fact, grant you new spells to fill those slots. For divine casters, this is a non-issue - they know all spells on their lists right from the start. Wizards do not gain their two free spells per level, but could at least learn new ones via means of scrolls. Sorcerers and bards? Nada. You do not learn new spells through prestige classes, ever. As a sorcerer 5 / prc 5, you might have fifth level slots - but you know only second level spells, exactly the same as any other fifth level sorcerer.
In other words: I found that PrCs as-is are not worth it at all for bards and sorcerers, and are only of marginal use to everyone else, at least if you want to play a primary spellcaster.
That is, until niv told me that he could probably get the caster level progression working.
Making a Witch
So, a druid-based caster PrC with actual caster level progression? It's a divine class, so getting new spells isn't an issue. What's to stop me, then? All I need is, effectively, there, or at least possible.
Still, it took me a while to really get along to it. Started writing down some random thoughts a good six months ago, and every now and then between other things. Nothing in engine, all in a shiny, SRD like google-documents table. Read through various other sources for inspiration. The Pathfinder Witch for instance is pretty cool, and has been part of the character's inspiration in the first place. Elsewhere, too - monster abilities, other games, books, whatever I could think of. Eventually, I cut most of the random ideas away and reduced it to something that seemed well suited to replace the normal druid progression early on - and grant a new or improved ability every level, too.
So, three days ago or so, I actually started putting that fancy document into NWN. Lots of 2da work there - classes.2da first, of course. One long line handling things from it's hit dice or skillpoints over references to other assorted tables to NWNs weird calculation method for challenge rating. I mean, what is the point of setting the CR gain for each individual level? No matter, the hardest part about that line was finding an appropriate icon - a thing we have many of, luckily. Check silm_icon.hak if interested.
Thus, the class was theoretically in the game. Without any text labels, let alone abilities, and probably making the game crash due to a lack of related data. So, I copied a few other tables - the wizard saving throw table, the druid class and bonus feat table, and of course a table for the prestige class prerequisites, and renamed the class designator to 'witch'.
Prerequisites first - after some back and forth about what was even possible within NWN limitations I flat out required druid levels, and 5 ranks of survival. That way, you'd need to be a second level druid to get access to the prestige class, which was my intent. Aside from some odd multiclass combinations, this pretty much ensures it being an alternate for the druid only, and replaces most druid abilities with witch abilities. The PrC has 18 levels, and then goes into epic, granting a bonus feat every third one.
So, now I have a prestige class requiring essentially druid 2, and granting... still druid abilities, but with a worse base attack. Need to edit cls_feat_witch.2da for that. That, however, references feats, it does not define them. Thus I need to add my abilities to feats.2da, and there, reference a new line from spells.2da for all the active feats, create a spellscript for those feats, create feat duplicates for those changing with level in uses per day and define each one's succeeding feat, and when all's done, list them to be granted on the appropriate level in cls_feat_witch.2da. Oh, and remove all those druid and epic druid feats from it, too. And on top of that, I need to add tlk-entries, often two or per line in classes.2da, feats.2da and spells.2da, and reference them by line number in those files.
Witch Spells!
Well, at least most of that was tedious, but easy. Spells needed some fiddling to get their casting behaviour right, and it took me a while to get appropriate sound effects - the Cackle ability even actually cackles, with different voice sets for male and female. With that done, and about an hour of icon-delving, I moved on to spellscripts - first to test the 2da entries by means of the usual Hello World stuff, then for real. Making Curse of the Witch was easy - it's only a variant of Bestow Curse after all, though there I already realised that I needed my own functions for the caster level and saving throw DC since I was casting via feat, not druid spells, which will be handled by niv's adjustments to GetCasterLevel() later on. So, extra mini-library to be included. Easy.
Then I tried to quickly modify the Entangle script for my Vile Roots variant which does roughly the same as the spell, just with a difference in save DC. Easy - or is it?
I tell you, that spellscript is a mess. Or rather, those spellscripts, because due to it being an AoE, it actually has a spell script fired on cast as well as a onHeartbeat and onExit script for the AoE - and it would have had an onEnter script too had it been done properly. There are multiple variables declared that later remain unused, the comments sometimes speak of completely different terms than what's actually there, and the actual entanglement is deeply hidden inside a ridiculously multi-layered maze of while()'s and if()'s - and in dissecting that maze, I found that the NWN variant of Entangle works completely different from the D&D 3.5 Entangle spell too.
After much back and forth, I finally decided to nearly completely redesign the spell itself, and the scripts. A generic script containing ApplyEntangle() and RemoveEntangle() that I could use for the normal spell, too, and four new scripts for my Vile Roots, handling caster level and save DCs separately. Upside: I get to bypass another NWN issue with area spells. Since GetSpellSaveDC() always applies to the last spell the AoE creator cast, casting Entangle and then, say Flame Strike actually causes saves required by Entangle after the second spell to use that spell's save DC instead of its own. Vile Roots uses the scaling DC from my witch abilities, and passes that number onto ApplyEntangle(). Bit trickier to fix for Entangle itself, but I get around to fixing that spell once I'm certain my own works perfectly.
My other active engine spell feats were, again, fairly easy - Eternal Slumber is just a single target sleep after all, and Cackle throws a fear effect on every hostile creature within range - I blatantly stole most of that code from Fear and Wail of the Banshee.
So, after some more local testing, the class was pretty much done, with the majority of the work done in maybe seven or eight hours of work. That's... not too bad actually. Granted, a lot of abilities are for roleplaying use only and have no NWN engine effect, but still.
What now?
The PrC is online. Rebuilt my character, and aside an already corrected oversight with the class skills, seems to work as intended. The GetCasterLevel() fix is there too, though niv still has to look into a few spells using core libraries - don't really want to recompile every core script to make it work. Most however work, in most respects. Spell resistance and dispel checks are a hassle. At that, I might still need to write my own resist function for the feat-based spells unless he manages to get that factored in correctly.
If all works well, I'll look into adapting the original Entangle too, and maybe add active spell scripts to the Tongue of the Wild and On Wings of Black abilities. Certainly gained some insight into all those .2da files too, and I already have a few other ideas. Maybe finally make some assassin or blackguard spellcasting, as hinted earlier? Shouldn't be too difficult once we get all the save, resist and caster level stuff out of the way. For the divine side of spellcasters, it's very doable. For the non-magical ones, sure.
Still sucks for the arcanists, though. Maybe one day.
I'll have the class details up on the web page soon, too, for all those who are interested.
Edit: Class Writeup is online: Witch of the Wilds
Added a feat that allows darkvision toggling; which can be quickslotted or radial-toggled like any other state.
Adding this feat was a bit fiddly. For icons to appear in the radial menu, they must be added to the cls_feat_*
lists - all of them. Due to this, the icon may appear multiple times in the class radial menu. This is something to be fixed clientside (NWNCX) in the future and cannot be helped at this time. While ugly, I don't think it's a big deal, as it only affects multiclassed characters and is hidden out of the way nearly all of the time.
As well, darkvision is now done solely through a visual effect - the engine effect itself (that the hardcoded feat grants) has been reverted to normal human vision. The upside of this is that darkvision got much slicker. It will no longer jump into normal vision as soon as a dynamic light source gets near enough; the player has control on when to enable it, as well as some scripted triggers that toggle it for you automatically (i,.e. when night falls). The downside is that possessed creatures may need additional tweaks to make it work well.
Please keep in mind though that this is a OOC-only feature for design aesthetics/personal preference. Most creatures do not actually have the ability to turn off their darkvision at will!
Winters are dark, in case you were wondering. As of now, there is a experimental patch online that tweaks light values to be more in line what the SRD claims darkvision, low-light vision and human vision is like.
Things may seem very dark at the start; however, that is intended. The baseline I chose was for areas with no light at all - a moonless, colourless, lightless void. Humans see about 1 meter, low-light is two, with a nice hue to it; and darkvision is blue-ish (to simulate greyscale which cannot be done with the nwn1 lighting engine)! There is only one type of darkvision for now, and as a compromise I've set it at about 90ft (2-ish tiles) to accomodate both the 60ies and 120ies.
Having a proper zero-baseline means that area creators have a much wider creativity range with area lighting, and the weather system can adjust area lighting to match moon phaseeventually; but this will also mean that torches and other light sources are actually much more useful because noone likes to run into things. Please don't tweak area lighting yet to accomodate the new lighting scheme. It is experimental, after all.
As a side-effect, Ultravision (that garish pink effect) is now gone and replaced with the exact same visuals as darkvision itself, so the spell works again as intended by Ao. Or something.
For the curious, the patch in question is fx_light_clr.mdl
in silm_merge.hak
.