Player Resource Consortium

Neverwinter Nights => Help => Topic started by: r00tsnatty on March 17, 2014, 01:50:28 AM

Title: Archivist High-level Spells
Post by: r00tsnatty on March 17, 2014, 01:50:28 AM
First off, PRC is totally awesome.  A lot of work must have gone into this.

My question is about the archivist base class.  I cannot learn 8th/9th level spells from any source when I level one (an archivist character) up.  I can't use the "learn spell" radial menu option on any high-level scroll, nor can I select spells of those levels when I level up all the way as a straight archivist.

I have been reading around on this forum and so far this is what I have tried to correct the problem:
1. Fresh install of NWN 1.69 Diamond Edition then use the PRC3.5 executable to install the PRC, run the updater for my modules, then run the oc fix for them
2. Delete the PRC_DATA files from the database directory and start a new game with an updated module to have them re-created
3. Delete those same files and replaced them with the same files from the PRC35.rar manual install archive
4. Replace the PRC_2das.hak file in my hak directory with one from the above archive

Please note, the above attempts have all come from other members advice on this forum - I know very little about the actual mechanics of the PRC.  Anyone wishing to help should therefore write to me as if I were a small, helpless child.

Last, I should probably explain that I have the GOG version of the game.  Not sure if this matters, but, in the interest of completeness, now you know.
Title: Re: Archivist High-level Spells
Post by: Loggy on March 18, 2014, 11:56:47 AM
By any chance, do you have 17 intelligence? You need a key attribute score of 10+the spell's level to cast spells, and (without looking) it would make sense if that limitation was enforced on learning spells as well.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 18, 2014, 01:07:49 PM
I suppose I deserved that for the small child thing, but no, any archivist I make will have over 19 intelligence by CL 17.  High wisdom as well.  It doesn't say in their PRC description but in p&p wisdom always determined their bonus spells, and to be safe I just keep both stats high to cover my bases.

By all appearances I should be able to cast the 8s and 9s.  I mean the game recognizes that I can, it gives me the slots in my spellbook, but I just can't learn any scrolls of those levels and when I level all the way up as a straight archivist I can select those levels to learn bonus spells from, but when I do the only option is something like [learn all spells of this level] and when I pick it nothing happens - no knew spells in the spellbook and no bonus spell picks get used up.

I've read on here elsewhere that the archivist spell list is just too long for the game to cache properly sometimes so the higher levels get left out, but like I said before I have tried all the things I can find that have been recommended to fix that problem but it always ends up the same when I get to 15th or 17th level.
Title: Re: Archivist High-level Spells
Post by: ThE LoSt BoY on March 18, 2014, 03:20:58 PM
If you knew the Archivist spell feat number(s), could add manually w/ PRC Leto.

No guarantee they would show up in the Archivist radials.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 18, 2014, 05:12:13 PM
Not a bad idea. I don't know the exact feat numbers, and the PRC version of LETO (at least the one that I have) won't load the PRC 3.5 feat list on the regular feat screen, but it would be easy enough to look them up and add them via the advanced editor. Ctrl.-F to search the feats in the advanced editor has really helped me cheat when I'm feeling inclined. :)

But wait, my version doesn't have the archivist material. Is there a way to import a numbered feat list from the 3.5 version of PRC to browse in the advanced editor?

Also, I dig the advice, but I'd really like to know how to just make the damn game/mod work properly if anyone has some advice on that.

I've wondered if there is a way to just manually insert the archivist spells, or at least the ones that I want to take, into the cached database files. I, however, don't know the first thing about how to go about that or if it would even help.
Title: Re: Archivist High-level Spells
Post by: Loggy on March 18, 2014, 06:07:08 PM
You could indeed just add all the relevant spells to your character. The way I'd go about doing this might actually be to make a fake spellscript of a spell that you can already cast and stick it in your override folder for a few minutes to add level 8/9 spells, but then again I have no knowledge whatsoever of how the caching system works. Just adding the spell feats isn't enough: you have to set a load of variables on you/your hidetoken (it's been long enough since I dabbled in this stuff, I forget). The PRC spellbook keeps track of which spells you know independently of the feats you have - it only sticks the feats on your hide when you have that spell memorised, IIRC. I'm pretty sure that just adding the control feats will mean that the spells don't appear in the spellbook, so you won't have the ability to cast the things. I've never looked at leto, but unless having the PRC letoscript switch set changes the entirety of the spellbook mechanics then that should be the case.

If you're into scripty stuff, one of the spell/spellbook related prc scripts has a fairly detailed description of the array structures. If memory serves, it's got "spell" or "spellb" or something in the name.

When I'm more awake and have a little more time tomorrow, I'll have a little play around to see if I can come up with something that'll sort it out.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 18, 2014, 06:31:38 PM
Loggy, thank you for the advice. I do not know how to write scripts, but I don't think it would be beyond my ability to do that if you could provide some guidance when you get the chance to check things out. Appreciate the help.

What I don't get is why my archivist isn't working properly if others get them to work as all I have installed is NWN diamond edition and a fresh install of the PRC 3.5. No other mods, no settings messed with, etc.
Title: Re: Archivist High-level Spells
Post by: ThE LoSt BoY on March 18, 2014, 08:06:48 PM
FYI:

http://prc.athasreborn.com/index.php/topic,1771.msg7984.html#msg7984 (http://prc.athasreborn.com/index.php/topic,1771.msg7984.html#msg7984)

http://prc.athasreborn.com/index.php/topic,1784.msg8072.html#msg8072 (http://prc.athasreborn.com/index.php/topic,1784.msg8072.html#msg8072)

http://prc.athasreborn.com/index.php/topic,1535.msg6766.html#msg6766 (http://prc.athasreborn.com/index.php/topic,1535.msg6766.html#msg6766)

http://prc.athasreborn.com/index.php/topic,640.msg3174.html#msg3174 (http://prc.athasreborn.com/index.php/topic,640.msg3174.html#msg3174)

Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 18, 2014, 09:42:24 PM
Ya, those were the posts I was referring to in my first post. Tried those things already. No dice.

The second link was new to me, though, but that's not the problem I am having. I can open the spellbook fine, and for the most part it works properly, just not when trying to learn (in any fashion) or prepare 8th or 9th level spells.

I'm about to try it with a non-GOG version version of the game. Seems like a long shot at best, but at this point I'm willing to try anything. I figure (complete and utter conjecture) that maybe the GOG version caches things differently and if I use the regular game it might work. I have no idea why this might be, but I'm gonna try.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 19, 2014, 12:30:15 AM
Nope, that didn't work either. But I now have the non-GOG version of the game. Feels better.
Title: Re: Archivist High-level Spells
Post by: Loggy on March 19, 2014, 12:20:23 PM
I made a little quick and nasty script that gives you all 8/9 archivist spells without checking for any requirements whatsoever (in theory you could even not be an archivist and this would work...)

Code: [Select]
#include "prc_alterations"

void SpellLoop(int nRow, int nBlanks=0);

void main()
{
    //Don't try this on non-PCs as it's rather pointless
    if (!GetIsPC(OBJECT_SELF))
    {
        return;
    }

    SpellLoop(0);
}

void SpellLoop(int nRow, int nBlanks=0)
{
    //If more than 20 blank simultaneous rows, return as it's probably the end of the file
    if (nBlanks >= 20)
    {
        return;
    }
    string sSpellID = Get2DAString("cls_spell_archv", "RealSpellID", nRow);
    int nSpellID = StringToInt(sSpellID);

    //Check for blanks, continue if one is found
    if (sSpellID == "")
    {
        nBlanks++;
        DelayCommand(0.01f, SpellLoop(nRow + 1, nBlanks + 1));
        return;
    }

    //Make sure it isn't a metamagic version
    if (Get2DAString("cls_spell_archv", "ReqFeat", nRow) != "")
    {
        //Complain and abort...
        SendMessageToPC(OBJECT_SELF, PRC_TEXT_RED + "Unexpected metamagic feat at line " + IntToString(nRow));
        return;
    }

    int nSpellLevel = Get2DAString("cls_spell_archv", "Level", nRow);
    string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("spells", "Name", nSpellID)));

    if (nSpellLevel > 7)
    {
        object oToken = GetHideToken(OBJECT_SELF);
        sArrName = "Spellbook_Known_"+IntToString(CLASS_TYPE_ARCHIVIST)+"_"+IntToString(nSpellLevel);

        //Ensure the array exists
        if (!array_exists(oToken, sArrName))
        {
            array_create(oToken, sArrName);
        }

        //Add the spellbook id (which is the same thing as the row in cls_spell_archv) to the array
        array_set_int(oToken, sArrName, array_get_size(oToken, sArrName), nRow);
        SendMessageToPC(OBJECT_SELF, "Added spell " + sSpellName);
    }
    else
    {
        SendMessageToPC(OBJECT_SELF, PRC_TEXT_LIGHT_GRAY + "Did not add " + sSpellName + " as it is only level " + IntToString(nSpellLevel));
    }

    //Now skip all the metamagic versions of the same spell
    while (1)
    {
        if (Get2DAString("cls_spell_archv", "RealSpellID", nRow + 1) == sSpellID)
        {
            nRow++;
        }
        else
        {
            break;
        }
    }

    //Next iteration: blank count will now be 0
    DelayCommand(0.01f, SpellLoop(nRow + 1));
}

I couldn't get it to work via override so in the end I used a blank PRC enabled module to do it in. I suppose you could drop a script into the haks and run it via the debug console, too.

(I attached the compiled version, but the extension will need changing back to .ncs to use it)

That still doesn't answer the question of why the scroll spellgiver doesn't work. If it's really a caching problem then this might avoid it as I'm not using the Get2DACache function added in PRC as I'm not sure there's any point in caching all these values. I'm honestly not sure how that function works, anyhow :P
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 19, 2014, 01:50:12 PM
Wow thanks for doing that. So now that I have the script, what do I do with it? Sorry that I need a step-by-step, but I've never worked with scripts.
Title: Re: Archivist High-level Spells
Post by: Loggy on March 19, 2014, 03:25:29 PM
You have several options...

1) Stick it into a PRC hakpak, use it, then remove it again.

Assuming that you don't have one of many community-made hak editors, you should be able to do that by using nwhak.exe found in NWN/utils. Anyway, once the file is in (don't forget to change the extension!), you'll need to put the following into the debug console.

DebugMode 1
runscript arch_spellget (or whatever you want to call it) - if it works it will spam your chatbox with messages.

It's not an ideal solution as you will probably want to take it out your haks again.

2) Make a module in the toolset with the script in. This might be better seeing as you'll be able to use it again if you bump into problems in the future, however it will require you to export your character and restart whatever module you're in which isn't so great.

- Open nwtoolset.exe, in your NWN folder
- Make a new module, create any area you want
- Close the toolset, use the PRC module installer (which will add the right hakpaks to the module, or you won't be able to be an archivist in it)
- Open the toolset again
- Copy the ncs file into NWN/modules/temp0
- Save the module, play it
- Use the same console commands as above

You could compile it yourself, but as Bioware's compiler can't handle PRC scripts then it's more trouble than it's worth unless you plan on doing more with it.

I must admit, the override solution would have been a lot nicer, but alas I just can't seem to figure out why I can't change spellscripts with it. I haven't tried the first method above, but seeing how hakpaks work I can't see any reason for it to go wrong.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 19, 2014, 03:36:30 PM
Ya, the second option sounds great. I just don't know where to insert it into a hak file, so I will just make a "leveling module" and use the debug menu to run the script and then level my archivist up to 17 and add the spells I want. Or do I even need to level him/her up and add the spells after I run the script or can I just export the 1st level character after I run the script?

Also, to make the file an ncs file do I just change the extension in Windows explorer or do I need to get a program to convert it?
Title: Re: Archivist High-level Spells
Post by: Loggy on March 19, 2014, 04:26:16 PM
You can just change the extension using explorer. The forums don't allow attachments of other types, so I changed it from ncs to txt to be able to put it on here.

I'm not sure what will happen if you run the script on a 1st level character. It seems unlikely that anything will remove those variables as you shouldn't be able to have them in the first place, so I suppose it should work.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 19, 2014, 05:11:21 PM
Perfect. Thank you so much for the help. As I have the day off, I will just finish watching this episode of the Mentalist and then I'll try out the script and post my results!
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 19, 2014, 06:32:45 PM
Genius! That appears to have worked first try! I still can't select bonus spells to learn or learn them from scrolls, but it added EVERY 8th and 9th level spell to my spellbook. And the proper ones too. Haven't tried exporting yet, but I ran the script at level 1 and used the console in my new "Archivist's Sanctum" module to level up to 17 and there they are in my spellbook.

Wait, they show up in my spellbook, and I can stick them in empty slots, and then they appear in my radial menu, but I can't cast them after I rest. Self-target spells just do nothing (but the cursor displays that I am a valid target) and other spells give the message "you have no uses of acid fog remaining." Obviously I am not even trying to cast acid fog.

Damn, that seemed like it was gonna work.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 19, 2014, 06:37:38 PM
The spells from levels 1-7 still work fine, can be cast, etc.
Title: Re: Archivist High-level Spells
Post by: Loggy on March 19, 2014, 07:44:35 PM
Acid fog is spell id 0, so it tends to crop up in odd places when something's going wrong.

I'll have a peek through the uses remaining stuff tomorrow and see if I can figure out what's failing. If it's the cache that's broken then it seems as though I'm going to need to pay that a little visit...

(It would perhaps make sense, too. I'd forgotten that it crops up on every spell cast as well as learning)
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 19, 2014, 07:56:15 PM
Thank you for going to all the trouble. I think I might start pulling my hair out soon.
Title: Re: Archivist High-level Spells
Post by: Loggy on March 20, 2014, 12:47:23 PM
EDIT: Try xwarren's below first. I don't entirely know what I'm doing here, and he does, soooo.... :P

There's also a little mistake in what I've written, but it isn't critical. If it works then I'll fix it, lol. (note to self: nRetVal is getting overwritten from ADDED)

It is unfortunately impossible for me to test anything before posting as I have never had the problems you're describing.

I won't pretend that I fully understand the PRC caching system, nor why the lookups aren't working for you. The fact that the script I gave you worked (which ignores the cache and reads the .2da files straight out the hakpaks) implies that your 2da cache is broken for some reason. From the reading I've just done it suggests that it is saved to the campaign database on a regular basis - the exact frequency (in seconds) is equal to the value of the prc switch PRC_USE_BIOWARE_DATABASE (which defaults to 300) multiplied by six - for a recache every half hour.

In theory then, it should be possible to just change the cached values on the caching golem, then force a rewrite of the database. Whether this will work, or continue working forever is something I am unsure of. If weird things happen you should just be able to delete the PRC_DATA_* files in your NWN/database folder, and that should sort anything unexpected out.

The following is a result of modifying Get2DACache so that it will throw the given columns of any given .2da file into the cache. I can't really test it, so I've added a number of debugging options that might make things a little easier if it doesn't work as expected. If it does work (I'm probably getting ahead of myself here!) and you need to run it on another 2da file, then it would be a lot easier if you were to edit it yourself, which will mean that you'll have to recompile it. I did leave a way for you to operate it without doing this, but setting all the variables correctly from the debug console is going to be rather difficult.

As you already have a PRC module set up, you can do this by...

1) Get a community made compiler. Bioware's one in the toolset dislikes the quantity of constants and other things in the PRC scripts. There's a link to the download at the top of the page: PRC downloads -> PRC script compiler. That is a command line interface, so setting up a batch file to compile stuff with is the advisable option, something like this will do...

Code: [Select]
CD C:\NeverwinterNights\NWN\modules\temp0
C:\NeverwinterNights\NWN\utils\nwnnsscomp.exe -cego *.nss
CD ..
PAUSE

You'll need to change the paths to whatever they are on your system, but that should give you the right idea.

2) Add prc_include to your module's hak list. In the toolset, go edit->module properties->custom content, and add prc_include in anywhere. Don't click OK just yet, as the toolset decides to try and build the module after this - which involves compiling all scripts. As Bioware's compiler can't handle that, unless you stop it within a few seconds the toolset will crash. After clicking OK, the toolset will unpack the hakpaks as it does when you first open the module, and it will then throw up an interface with a cancel button. Sometimes it just isn't possible to be fast enough to hit cancel, if you can't seem to do it then there are other ways to get it in the list and happy, but unfortunately you'll need other software to do this.

3) Now, go tools->script editor, and paste the script in and save it as something. The Bioware compiler will then attempt to compile it and give you a lovely "unknown state in compiler" error, which is fine. Run the batch file (or otherwise compile your script) save your module and you should be good to go.

Anyway, here's the script that may or may not work...

Code: [Select]
#include "prc_alterations"

//These are for Force2DACache
const int FORCE_CACHE_CORRECT = 1;
const int FORCE_CACHE_ADDED = 2;
const int FORCE_CACHE_WRONG = 3;

const int FORCE_CACHE_SKIP_UNCACHED = 1;

//These are for main()
const string FORCE_CACHE_DEBUG_LEVEL = "2DACacherDebugLevel"; //Int: 0 = quiet, any other value = noisy. Default 0
const string FORCE_CACHE_RATE = "2DACacherRate"; //Int: Default and maximum 100. Number of lines processed per second.
const string FORCE_CACHE_MODE = "2DACacherMode"; //Int: Flags passed to the nMode parameter of Force2DACache. Default 0
const string FORCE_CACHE_FILE = "2DACacherFile"; //String: Default cls_spell_archv
const string FORCE_CACHE_COLUMNS = "2DACacherColumns"; //Array name where columns are set.

//Sets the value of the PRC cache so that it may retrieve the given data value correctly.
//Returns one of the following:
//FORCE_CACHE_CORRECT - 2DA cache was already correct
//FORCE_CACHE_ADDED - Value not previously cached
//FORCE_CACHE_WRONG - Value was previously wrong
//nMode can accept the following flags:
//FORCE_CACHE_SKIP_UNCACHED - if set, values not already in the cache will not be inserted. Will still return FORCE_CACHE_ADDED in such cases.
int Force2DACache(string s2DA, string sColumn, int nRow, int nMode=0);
void ForceBiowareDatabaseRecache();

//With that many arguments, making a mistake in code I can't test is too risky
//This cuts down the scope for wrong ordering rather a lot
struct CacheLoopArgs
{
    int nDebug;
    float fDelay;
    int nFlags;
    string sFile;
    int bDeleteColumnArray;
    int nCorrects;
    int nAddeds;
    int nWrongs;
    int nBlanks;
    int nLine;
};


void CacheLoop(struct CacheLoopArgs sArgs);

void main()
{
    struct CacheLoopArgs sArgs;

    int nRate = GetLocalInt(OBJECT_SELF, FORCE_CACHE_RATE);
    sArgs.nDebug = GetLocalInt(OBJECT_SELF, FORCE_CACHE_DEBUG_LEVEL);
    if (nRate == 0) { sArgs.fDelay = 0.01f; }
    else
    {
        sArgs.fDelay = 1.0f/IntToFloat(nRate);
        if (sArgs.fDelay < 0.01f) { sArgs.fDelay = 0.01f; }
    }
    sArgs.nFlags = GetLocalInt(OBJECT_SELF, FORCE_CACHE_MODE);

    //This sets the columns/file to cache
    sArgs.sFile = GetLocalString(OBJECT_SELF, FORCE_CACHE_FILE);
    if (sArgs.sFile == "") { sArgs.sFile = "cls_spell_archv"; }

    if (!array_exists(OBJECT_SELF, FORCE_CACHE_COLUMNS))
    {
        array_create(OBJECT_SELF, FORCE_CACHE_COLUMNS);
        array_set_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, 0, "Level");
        array_set_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, 1, "FeatID");
        array_set_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, 2, "IPFeatID");
        array_set_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, 3, "SpellID");
        array_set_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, 4, "RealSpellID");
        array_set_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, 5, "ReqFeat");
        array_set_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, 6, "AL");
        sArgs.bDeleteColumnArray = TRUE; //Mark that array for deletion at the end
    }

    CacheLoop(sArgs);
}

void CacheLoop(struct CacheLoopArgs sArgs)
{
    if (sArgs.nBlanks > 20)
    {
        //Probably EOF, this writes the output
        string sMessage = sArgs.sFile + ": Finished caching ";
        int i;
        for (i=0; i<array_get_size(OBJECT_SELF, FORCE_CACHE_COLUMNS); i++)
        {
            sMessage += array_get_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, i) + ", ";
        }
        SendMessageToPC(OBJECT_SELF, IntToString(sArgs.nAddeds) + " values added to cache.");
        SendMessageToPC(OBJECT_SELF, IntToString(sArgs.nWrongs) + " values corrected in cache.");
        SendMessageToPC(OBJECT_SELF, IntToString(sArgs.nCorrects) + " values were already correct in cache.");
        if (sArgs.bDeleteColumnArray)
        {
            array_delete(OBJECT_SELF, FORCE_CACHE_COLUMNS);
        }

        //Aaand force the database to recache
        ForceBiowareDatabaseRecache();

        SendMessageToPC(OBJECT_SELF, "Database should now be recached.");

        return;
    }
    int i;
    int bLineIsBlank = TRUE;

    if (sArgs.nDebug)
    {
        SendMessageToPC(OBJECT_SELF, "Line " + IntToString(sArgs.nLine) + ":");
    }

    for (i=0; i<array_get_size(OBJECT_SELF, FORCE_CACHE_COLUMNS); i++)
    {
        string sColumn = array_get_string(OBJECT_SELF, FORCE_CACHE_COLUMNS, i);
        //First, test for blank lines
        if (bLineIsBlank)
        {
            string sReal = Get2DAString(sArgs.sFile, sColumn, sArgs.nLine);
            if (sReal != "")
            {
                bLineIsBlank=FALSE;
                sArgs.nBlanks = 0; //Set blank line counter to 0, if not already
            }
        }

        //Do the actual caching and increment the variables
        int nRet = Force2DACache(sArgs.sFile, sColumn, sArgs.nLine, sArgs.nFlags);
        switch (nRet)
        {
            case FORCE_CACHE_CORRECT: sArgs.nCorrects++; break;
            case FORCE_CACHE_ADDED: sArgs.nAddeds++; break;
            case FORCE_CACHE_WRONG: sArgs.nWrongs++; break;
        }

        //If heavy debugging enabled, print it all out
        if (sArgs.nDebug)
        {
            switch (nRet)
            {
                case FORCE_CACHE_CORRECT: SendMessageToPC(OBJECT_SELF, PRC_TEXT_LIGHT_BLUE + sColumn + " was correct."); break;
                case FORCE_CACHE_ADDED: SendMessageToPC(OBJECT_SELF, PRC_TEXT_ORANGE + sColumn + " was added."); break;
                case FORCE_CACHE_WRONG: SendMessageToPC(OBJECT_SELF, PRC_TEXT_RED + sColumn + " was wrong!"); break;
            }
        }
    }
    //Increment line, and keep going
    sArgs.nLine++;
    DelayCommand(sArgs.fDelay, CacheLoop(sArgs));
}

//Easy one first.
void ForceBiowareDatabaseRecache()
{
    SetLocalInt(GetModule(), "Bioware2dacacheCount", GetPRCSwitch(PRC_USE_BIOWARE_DATABASE));
    //Forcing it can't hurt - assuming the HB will fire is incorrect if it's not set as the module heartbeat for some weird reason
    ExecuteScript("prc_onheartbeat", GetModule());
}


int Force2DACache(string s2DA, string sColumn, int nRow, int nMode=0)
{
    //lower case the 2da and column
    s2DA = GetStringLowerCase(s2DA);
    sColumn = GetStringLowerCase(sColumn);

    //get the chest that contains the cache
    object oCacheWP = GetObjectByTag("Bioware2DACache");
    //if no chest, use HEARTOFCHAOS in limbo as a location to make a new one
    if (!GetIsObjectValid(oCacheWP))
    {
        if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Cache container creature does not exist, creating new one");
        //oCacheWP = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_chest2",
        //    GetLocation(GetObjectByTag("HEARTOFCHAOS")), FALSE, "Bioware2DACache");
        //has to be a creature, placeables cant go through the DB
        oCacheWP = CreateObject(OBJECT_TYPE_CREATURE, "prc_2da_cache",
                                GetLocation(GetObjectByTag("HEARTOFCHAOS")), FALSE, "Bioware2DACache");
    }

    //get the token for this file
    string sFileWPName = s2DA + "_" + sColumn + "_" + IntToString(nRow / 1000);
    //if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Token tag is " + sFileWPName);
    object oFileWP = GetObjectByTag(sFileWPName);
    //token doesnt exist make it

    //EVERYTHING above this point is taken directly from Get2DACache

    //If the FORCE_CACHE_SKIP_UNCACHED flag is set, don't do any more as we don't want to
    if (nMode & FORCE_CACHE_SKIP_UNCACHED)
    {
        return FORCE_CACHE_ADDED;
    }

    int nRetVal;

    if(!GetIsObjectValid(oFileWP))
    {
        if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Token does not exist, creating new one");

        // Use containers to avoid running out of inventory space
        int nContainer = 0;
        string sContainerName = "Bio2DACacheTokenContainer_" + GetSubString(s2DA, 0, 1) + "_";
        object oContainer     = GetObjectByTag(sContainerName + IntToString(nContainer));

        // Find last existing container
        if(GetIsObjectValid(oContainer))
        {
            if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Seeking last container in series: " + sContainerName);
            // find the last container
            nContainer = GetLocalInt(oContainer, "ContainerCount");
            oContainer = GetObjectByTag(sContainerName + IntToString(nContainer));

            if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Found: " + DebugObject2Str(oContainer));

            // Make sure it's not full
            if(GetLocalInt(oContainer, "NumTokensInside") >= 34) // Container has 35 slots. Attempt to not use them all, just in case
            {
                if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Container full: " + DebugObject2Str(oContainer));
                oContainer = OBJECT_INVALID;
                ++nContainer; // new container is 1 higher than last one
            }
        }
        // We need to create a container
        if(!GetIsObjectValid(oContainer))
        {
            if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Creating new container");

            oContainer = CreateObject(OBJECT_TYPE_ITEM, "nw_it_contain001", GetLocation(oCacheWP), FALSE, sContainerName + IntToString(nContainer));
            DestroyObject(oContainer);
            oContainer = CopyObject(oContainer, GetLocation(oCacheWP), oCacheWP, sContainerName + IntToString(nContainer));
            // store the new number of containers in this series
            if (nContainer)
                SetLocalInt( GetObjectByTag(sContainerName + "0"), "ContainerCount", nContainer);
            // else this is the first container - do nothing as this is the same as storing 0 on it.
            // Also here we still have 2 objects with the same tag so above code may get
            // the object destroyed at the end of the function if this is the first container.
        }

        if(DEBUG_GET2DACACHE) DoDebug("Get2DACache: Using container: " + DebugObject2Str(oContainer));

        // Create the new token
        /*oFileWP = CreateObject(OBJECT_TYPE_ITEM, "hidetoken", GetLocation(oCacheWP), FALSE, sFileWPName);
        DestroyObject(oFileWP);
        oFileWP = CopyObject(oFileWP, GetLocation(oCacheWP), oCacheWP, sFileWPName);*/
        oFileWP = CreateItemOnObject("hidetoken", oContainer, 1, sFileWPName);

        //SetName(oFileWP, "2da Cache - " + sFileWPName);

        // Increment token count tracking variable
        SetLocalInt(oContainer, "NumTokensInside", GetLocalInt(oContainer, "NumTokensInside") + 1);

        //Set return value to indicate that it was not already there
        nRetVal = FORCE_CACHE_ADDED;
    }

    string sReal = Get2DAString(s2DA, sColumn, nRow);
    //Convert to **** here, as that is what gets saved
    if (sReal == "") { sReal = "****"; }

    string sCurrent = GetLocalString(oFileWP, s2DA+"|"+sColumn+"|"+IntToString(nRow));

    if (sReal == sCurrent)
    {
        return FORCE_CACHE_CORRECT;
    }
    else
    {
        SetLocalString(oFileWP, s2DA+"|"+sColumn+"|"+IntToString(nRow), sReal);
        return FORCE_CACHE_WRONG;
    }
}

You can change a few things about how this runs using the debug console. The commands "SetVarInt" and "SetVarString" allow you to set variables on objects. You can use them like this (They are case sensitive):

SetVarInt 2DACacherDebugLevel 1

The game will then prompt you to target that at something - you need to set it on your character. The variables supported by the script can be found towards the top of the source above. You CAN indeed change the file and the fields to cache using this, however as the fields are set in an array, the way you set them in-game is a little different. If you use "dm_dumplocals" on your character while the script is running, you should be able to find the array produced by the script - I haven't really paid much attention to how they are stored, but it should look something like this...

2DACacherColumns - 7 [INT]
2DACacherColumns_0 - "Level" [STR]
2DACacherColumns_1 - "FeatID" [STR]
2DACacherColumns_2 - "IPFeatID" [STR]
2DACacherColumns_3 - "SpellID" [STR]
2DACacherColumns_4 - "RealSpellID" [STR]
2DACacherColumns_5 - "ReqFeat" [STR]
2DACacherColumns_6 - "AL" [STR]

The first one (it may be a string, I honestly don't remember) signifies the length of the array. You'll need to change that to a more appropriate value if you want to run the script this way, or, as I said above, you could just recompile it all yourself. The values of an array are always stored as strings, regardless of whether they are numerical or not.

Hopefully this works, if it doesn't then I'm a little out of ideas I'm afraid.
Title: Re: Archivist High-level Spells
Post by: xwarren on March 20, 2014, 01:45:13 PM
I really thought I have fixed this issue. Could you test my script file, please?

To check if it works please do the following:
1. make sure NWN/NWServer is not running
2. go to NWN/database directory and delate all prc*_data.* files
3. download the attached zip file and extract it somewhere
4. use nwhak.exe from NWN/utils directory and replace prc_onmodload.ncs in prc_scripts.hak (or put it in prc_2das.hak)
5. run the game and load any PRC module (new game - not a save!) - when the character selection screen loads, let the game run for a while and do not touch anything (2 - 3 minutes should be more than enough)
6 optional - exit the game and check if new prc_data files were created in NWN/database directory
7. load the game and check if your archivist can learn high level spells.

Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 20, 2014, 07:29:14 PM
Xwarren, reading on here, it seems that you are the big cheese when it comes to the PRC, correct? If so, thank you for your attention and thanks for the hard work. (Actually, thanks for the first thing no matter who you are).

I just got home and will try your fix presently. One thing, when I deleted those database files and started a new game before, I did not wait on the character selection screen (I'm supposing that means the "select premade character" menu), I just picked one real quick and started it. Perhaps that was my problem. Well, here goes nothing. Fingers crossed and all that.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 20, 2014, 07:46:16 PM
@Loggy, man that was a lot of work on your part. Thank you very much. I almost hope Xwarren's solution doesn't work (not really) so I can at least give yours the attention it deserves! I'll find out shortly here and report back.

An aside:

A caching golem? Is that seriously what it's called?!
How many hit dice does that have?
Is it immune to magic?
Is it one of those rare golems with an intelligence score?

;) Sorry! That was a totally lame joke, but far too ironic to pass up considering the game we are both playing. I am picturing some fusion of d&d and tron - a mindless construct endlessly shuttling script around.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 20, 2014, 08:44:03 PM
Xwarren, that made it significantly worse... the problem is still the same, but now I can only learn first level spells, and of all the spells usually available to a first level archivist as bonus spells, only like seven were selectable.

Just to clarify what I did for completeness-sake, I followed your directions to the letter and the part about the nwhak.exe, I opened that program, chose file > open, opened the prc_scripts.hak, dragged the extracted file you posted into the list, it asked to replace (or overwrite, can't remember which), I clicked yes, and then I saved and exited.

I should note that the file I put in there (the one you posted) was 50% smaller than the one that was placed there by prc35.exe. ~80kb (extracted ncs from your post) vs. ~120kb (original ncs).

Included those last two comments to give as detailed an explanation of my actions as possible. I imagine this is the process through which bugs are hammered out.

Going to replace prc_scripts.hak with the original from the PRC35 archive (the manual install) to get back to where I was, erase and recreate database files by starting a new game again, then try Loggy's solution.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 20, 2014, 09:56:26 PM
Xwarren, sorry for the multiple posts, something just struck me:

Since changing that ncs file had the opposite effect, that must be the issue. That is, whatever you changed addressed PRECISELY the problem at hand, it just perhaps didn't address it in the correct manner/change the correct parameters.

Also, from reading the past posts examining this issue it seems the archivist class did not have this problem until the final version of PRC 3.5. At least confirmed through the second beta. So would it be possible to replace the onmodload.ncs in prc_scripts.hak with one from the beta or an earlier version, or would that interfere with the regular caching of the database files? Or, would it be possible for me to simply install an older version of the PRC - somewhere between 3.3H and 3.5 beta 2 - to a unmodded nwn to play my archivist? If I lose a few spells because they don't exist in the earlier versions I probably won't mind. Really a mostly complete archivist spell list with access to the runecaster and master of shrouds/fist of raziel (evil/good) prestige classes would make me a happy camper. Because I deleted my GOG version and decided to delete my saves as well I'm starting over from level 1 no matter what when this problem gets fixed. Unfortunately PRC 3.3G is the only other version I can find online and it doesn't have the archivist.

My suggestions are coming from an "out on a limb" position, however, because I really don't understand how it all works mechanically. Just some application of logic which may be misguided/uninformed.

I should say also that simply settling for an earlier version is just acceptable for me personally, but I am at your disposal to help you sort this all out if you want to get to the bottom of what is happening here.
Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 20, 2014, 11:19:15 PM
Problem solved!

I replaced the PRC_scripts.hak with the one from the 3.5 manual install .rar archive.
Deleted the PRC_data.* files from the database folder.
Started a new game.
Bingo.

My only conclusion is that perhaps the prc_onmodload.ncs from the 3.5 exe installer is not correct while the one from the 3.5 manual install archive is correct. I applied the exe install to two fresh installs (different versions) of the game and the archivist did not work. The only thing I changed was replacing the prc_scripts.hak with the one from the archive. Now it works. I suppose it could be one of the other scripts within that file, but the problem is certainly (well maybe not certainly...) somewhere in prc_scripts.hak.

Thanks for everyone's help with this one! I can't believe there is this much support for a mod from such an old game. You guys are great!
Title: Re: Archivist High-level Spells
Post by: xwarren on March 21, 2014, 12:22:44 AM
The file I sent you is a latest version - hopefully will be included in next PRC release. I have optimized some functions, and that's why it is smaller than original ncs.

I have compared both packs (exe and rar) in a diffing program - the files are exactly the same, just distributed differently. I am glad it works for you now, but I have no clue why my new script didn't fixed the problem (I am using it currently and my archivist can learn spells at all levels) or why replacing prc_scripts.hak did. Anyway - let me know if this happens again. Thanks

Title: Re: Archivist High-level Spells
Post by: r00tsnatty on March 22, 2014, 01:15:29 PM
Hmmmm... Very strange. The only thing, other than switching that file, which I did differently was wait maybe three minutes on the character select screen. Maybe that was the key. But I did that with the onmodload.ncs file you posted as well.

Another thing I noticed that might be of interest is that before it was working properly all cloaks had no icons. They just showed up as white rectangles in the inventory. I didn't really care because all their stats were there and working properly, they could be bought and sold, and could be equipped. But now that the archivist is working, the cloaks have icons as well.

Two birds, one stone I suppose.

Thanks for all your hard work on this one. I am having a lot of fun with my archivist.