Author Topic: nwn database help - basic select statement  (Read 1950 times)

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #15 on: November 08, 2010, 05:09:14 am »


               custom talk files would need to go into the tlk folder not the override folder.   They would also have to be there at module load.  not sure if you would even be able to replace the exsisting talk file durning play since it would most likely be in an open state by the game.  



2da file droped in the override folder durning play would not take effect untill the game was loaded again.  The resource list the game draws from is created at module load.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #16 on: November 08, 2010, 05:14:05 am »


               

FunkySwerve wrote...

If I am off base here and you can get a VarName to hold more then one data type and get the game to read it durning play, I would sure like to hear about it.

Of course you can. Just concatenate, with a separator, in string format. I used to do this quite a bit before I swapped to NWNX.

Funky


Thanks funky,

But that was not really the subject.  A string is still a string even if it is packed data.    If you look at the link he had there.  It looked like he was trying to use more then one collumn from the nwn DB at a time. 
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #17 on: November 08, 2010, 05:21:04 am »


               Yes, I know what he's trying to do. You can accomplish that by packing data in either the var name (key) or the value, or both. You then convert the string to whatever other types you need. This is, in fact, precisely how NWNX-MySQL works - EVERYTHING passing in and out is a string until converted. You simply use StringToInt, StringToFloat, etc etc.



Funky
               
               

               
            

Legacy_Calgacus

  • Full Member
  • ***
  • Posts: 195
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #18 on: November 08, 2010, 06:08:18 am »


               

Lightfoot8 wrote...

custom talk files would need to go into the tlk folder not the override folder.   They would also have to be there at module load.  not sure if you would even be able to replace the exsisting talk file durning play since it would most likely be in an open state by the game.  

2da file droped in the override folder durning play would not take effect untill the game was loaded again.  The resource list the game draws from is created at module load.


I don't need to the new 2DAs to be refreeshed during play, but at the load of a saved game would be good - not entirely necessary though.  The main thing is that after a play through of the mod, if  a person wanted to play again then they could get a new puzzle DB  or 2DA file, drop it in to the override or database folder and when they play the game  the new contents would be available.  A tiny DB file would just contain a single integer which gives the puzzle number to use.  So i guess  the 2DA method makes the most sense, using one 2DA for each puzzle I could have any number of instances of that puzzle in the file, and each time i read one up i increment the integer in the DB so the next time one  is read up it gets the next puzzle.   The tlk option doesn't work unless i can drop them into the override.   I want the puzzles to exist outside the mod so I can distribute them separetly.

Lets see, lets say I am doing a Clue game, in a given mansion  I want a murder mystery puzzle so i store the puzzles for that location in a 2DA file.  Other puzzles for other places fget stored in their own 2DA.  The first time through a mod the mod uses puzzles with id==1, then on a second playthrough puzzles with id==2 etc.

But what if I want an area to refresh its puzzle during play?  I guess I should use a different databse for each puzzle so the id can be different for each.  ok, I guess as long as the 2DA's let me use long strings i'm ok with that.

A limited number of cached 2DAs eh?  does that limit include the standard 2DAs?
Any more thoughts?

Thanks.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #19 on: November 08, 2010, 06:47:16 am »


               

Calgacus wrote...
But what if I want an area to refresh its puzzle during play?  I guess I should use a different databse for each puzzle so the id can be different for each.  ok, I guess as long as the 2DA's let me use long strings i'm ok with that.

A limited number of cached 2DAs eh?  does that limit include the standard 2DAs?
Any more thoughts?

Thanks.

You're putting way too much emphasis on hot-dropping updates, ESPECIALLY for a SP mod.

The default limit for cached 2das is 10. You CAN increase that, but I wouldn't by too much. 1 2da per game is far too many - like I said above, you want 5-8 total. I would suggest perhaps 1 2da per puzzle TYPE.

The caching limit includes any 2da you call up, standard or otherwise.

Funky
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #20 on: November 08, 2010, 07:08:59 am »


               Just out of curiosity..why not just store all the puzzle/s variables you need on objects that can be imported/exported as erfs or saved in the NWN database as well? Then you could store all the puzzles and puzzle info for one area on each object. You could put different puzzle "levels" on these objects..etc.

I'm pretty sure that reading(fetching) the information from in game objects is faster than any database method. And retrieving one object from the NWN database and then fetching and writing info from and to it is also fairly fast(err..well not as fast as NWNX+ODBC).

The first time through a mod the mod uses puzzles with id==1, then on a second playthrough puzzles with id==2 etc.

In this scenario for example you could simply put a variable on the player once he completed the first run through. Then on his second run through the area the puzzles would change based on the variable that is stored on the player.

Perhaps I am just not grasping what type of scenario would require you to go to the lengths that you are going to to go about this.
               
               

               


                     Modifié par GhostOfGod, 08 novembre 2010 - 07:15 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #21 on: November 08, 2010, 07:45:42 am »


               Local reads are faster, by necessity, than NWNX-ODBC, since it hooks Set/GetLocalString to do its stuff. '<img'>

There are other things to consider besides speed and hot-dropping, like ease of data entry/access/editing, for example. I for one wouldn't want to use the NWN DB for ANYTHING for that reason, though Knat's helps considerably. Simply storing puzzling data in a script and making use of override to update is probably the best solution for everything except tracking puzzle completion across playthroughs, which you should probably use the NWN DB for, despite the suck factor.

Funky
               
               

               


                     Modifié par FunkySwerve, 08 novembre 2010 - 07:45 .
                     
                  


            

Legacy_Calgacus

  • Full Member
  • ***
  • Posts: 195
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #22 on: November 09, 2010, 02:25:32 am »


               GOG, you suggest  I store a puzzle index var on the player, but what if they use a different character in a SP mod?  Will that var it still be accessible?

Funky,  the hot swap is important to me even if its not of truly  great practical use, I just obsess over issues of replayablility and like the idea  of distributing  bundles of puzzles to players and even other modders for their use.  
A puzzle needs to have:
1)  an ID
2) a Name
3) an introduction - text maybe 1000 characters or so long
4) up to a dozen or so clues - each maybe up to a couple hundred characters long
5) a solution, not sure yet how I want to present it to scripting as it has to be interpreted by a script as it is at least a little more meaningfully than sticking some strings into a convo or book; eg  if the solution is "Fire first, Cold second, Acid third" then some object needs to be hit by those effects in that order to  be destroyed.  The solution exists first in the puzzle, not hardcoded anywhere in the module.

I like the idea of keeping these puzzles together in an easily updated, easily read file and 2DA  is starting to seem the easiest to copy-n-paste the puzzle info into from the web page where the finished puzzle is first made, even easier than the  foxpro files now that I understand their guts.

Any more thoughts, keep em coming, they are helping!!

  To do  it in a script I'd have to make up variable names or maybe  a linked list of structs if nwscript supports such things, how else would I store a bunch of puzzles in a script?
               
               

               


                     Modifié par Calgacus, 09 novembre 2010 - 02:27 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #23 on: November 09, 2010, 02:57:23 am »


               Nwscript does NOT support nested structs (or pointers), but you don't need them. You can store basically anything you want in script - 2das are actually more limited, because scripts are much better suited to storing relational data. That's not a particular obstacle to 2da use, since they're always used in tandem with scripts - I'm simply pointing out the additional flexibility. Actually, if you want a prime example, look at the Legendary Level scripts - they were all done originally with all the feat, skill, etc, data coded into switches in script, because they were done before the improved 2da caching was implemented. When it was, I rewrote them to do 2da reads. I'll see if I can dig up an example.



Funky
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #24 on: November 09, 2010, 03:28:20 am »


               Here's a chunk from a massive switch that replicates a column from a dozen different 2das:

//--------------------------------DECLARATIONS--------------------------------//

// This function returns the level at which the specified class gets the specified feat.
// If the feat is epic only, it will return -1 in most cases, though it will also return
// 21 on occasion, as with Epic Spells, which actually require 21 levels of the class rather
// than just epic character status. It replicates EXACTLY the cls_feat 2da for each of the
// respective classes, though the order of feats has been shuffled to accomodate the switch
// statements, and a few duplicate cases in the 2das were removed. If the feat input is not
// a class feat (and therefore not found in the 2da), this function will return -2. If the
// class input is not a valid class int, the function returns -3. Although Harper Scout could
// not possibly be a character's control class for legendary levels, it is included at the end
// of the switch so that the function can be of broader use to the community. Several feats were
// added as class feats for Palemasters, including Spell Focuses and Greater Spell Focuses
// (since they get Epic Focuses). They are marked in the function. The class switches are
// in aphabetical order by 2da file (which is slightly different than class name).
int GetclassLevelReqForFeat(int nFeat, int nclass, object oPC);
// This function returns TRUE if the feat specified is a general feat, avalable to all classes.
int GetIsGeneralFeat(int nFeat);

//----------------------------------FUNCTIONS---------------------------------//

int GetclassLevelReqForFeat(int nFeat, int nclass, object oPC)
{
int nInt = -2, nQuasi;

switch(nclass)
{
    case  class_TYPE_ARCANE_ARCHER:
        switch(nFeat/250)
        {
            case 0:
                switch(nFeat/25)
                {
                case 0: //0-24
                    switch(nFeat){
case  1 : nInt =  -1 ; break;
case  3 : nInt =  1 ; break;
case  4 : nInt =  1 ; break;
default : nInt =  -2 ; break;}; break;
                case 1: //25-49
                    switch(nFeat){
case  32 : nInt =  1 ; break;
case  41 : nInt =  -1 ; break;
case  44 : nInt =  -1 ; break;
case  45 : nInt =  1 ; break;
case  46 : nInt =  1 ; break;
default : nInt =  -2 ; break;}; break;
                case 2: //50-74
                    switch(nFeat){

The full thing is 6596 lines long, but it runs quite quickly, because of the switch structure. Here's the same thing, redone to use two 2da-based functions:


int GetIsFeatExceptionFrom2da(int nFeat, int nclass, object oPC) {

    int nRace = GetRacialType(oPC);
    switch(nFeat) {
        case 424: if (GetLocalInt(oPC, "Quasiclass") == QUASIclass_DWARVEN_WARCHANTER) return -1; break;//lingering song
        case 870: if (GetLocalInt(oPC, "Quasiclass") == QUASIclass_DWARVEN_WARCHANTER) return -1; break;//lasting inspiration
        //spell feats below:
        case 35:case 166:case 167:case 168:case 169:case 170:case 171:case 172: //spell foci
        case 36:case 401:case 618:  if (GetLocalInt(oPC, "Quasiclass")) return -1; break;//spell penetration feats
        //general feats below:
        case 290: //Creature Weapon Spec
        case 694: if (GetLevelByclass(class_TYPE_DRUID, oPC) > 0) return -1; break; //Epic CW Spec
        case 311:case 313:case 314:case 315:case 316:case 317:case 321:case 322:case 325: if (GetKnowsFeat(FEAT_EPIC_PLANAR_TURNING, oPC)) return -1; break; //cleric domains
        case HGFEAT_LEG_SKILL_AFFINITY_LISTEN:
        case HGFEAT_LEG_SKILL_AFFINITY_SPOT: if (GetRacialType(oPC) == RACIAL_TYPE_HALFELF) return -1; break;
        case HGFEAT_LEG_SKILL_AFFINITY_TAUNT: if (GetLocalInt(oPC, "SubraceID") == 37) return -1; break;
    }
    return -2;
}

int GetclassLevelReqForFeat_2da(int nFeat, int nclass, object oPC) {

    string s2da = Getclass2daName(nclass);
    string sVal = "Nothing";
    int nCount = 0, nVal, nRet;
    while (sVal != "") {
        sVal = Get2DAString(s2da, "FeatIndex", nCount);
        nVal = StringToInt(sVal);
        if (nVal == nFeat) {
            nRet = StringToInt(Get2DAString(s2da, "GrantedOnLevel", nCount));
            return nRet;
        }
        nCount++;
    }
    nRet = GetIsFeatExceptionFrom2da(nFeat, nclass, oPC);
    return nRet;
}

In this case, after the improvement in 2da caching, the 2da approach is by far the better one. Despite that, that massive function didn't take all that long to create, thanks to excel scripting. In your case, since you're able to determine structure up front, you can structure your code so that either option will work well, and you won't wind up with huge switch functions unless you REALLY have a lot of data to enter - it just doesn't sound like you do, far from it.

If I were coding functions for your puzzles, I would probably do something like:

string GetPuzzleName(int nPuzzle);
string GetIntroduction(int nPuzzle);
string GetPuzzleClue(int nPuzzle, int nClueNumber);
(solution)

You're going to wind up with the same functions either way; the only thing to decide is whether they're going to contain switches or 2da reads (or database, but I really don't recommend that). There are, of course, other options, like variable pseudohashes - look at OldManWhistler's spell system, for example (no good for strings like yours) - or real hashsets (only if using NWNX, not a good option for SP).

In summary, it sounds like you need to figure out EXACTLY what your puzzles will look like. My guess is you'll want a scripted solution, which is more flexible. You'll be able to hotdrop more easily as well. 2das, by contrast, will shine if your relational data is minimalistic and easy organization is more important.

Funky
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
nwn database help - basic select statement
« Reply #25 on: November 09, 2010, 03:31:25 am »


               

Calgacus wrote...

GOG, you suggest I store a puzzle index var on the player, but what if they use a different character in a SP mod? Will that var it still be accessible?


By no means did GOG state that you should store the Puzzles on the player.  I did state that you could store the state and wich  puzzles the player has already done on the player. 

If the Object here is to just store stings GOG's Idea has merrit. I was thinking of stating the Idea myself last night.  But as ussal GOG beat me to it.   But it is starting to sound like each of your puzzles are each  going to have there  own Unique logic to them.  If that is the case a script for each puzzle would be the best.  If not the Storage of the data on items would work.

You could just create an item for each puzzle and store the data as locals on the item.  Each Item then could be placed on an NPC ( I would clear all the scripts from the NPC's events since they would not be needed and spawn him into  a private area in the module).   The NPC would then be able to be stored into the DB as one unit.  That however would no longer be needed.  The NPC with all the puzzle Item on him becomes your Data Base.  You can have a default one on the palette of your module.  If you wanted to change him later you could just drop a the new blueprint of  him in the override folder  to change your so call DB.