Author Topic: Store locations within a database  (Read 508 times)

Legacy_Ivanovich

  • Full Member
  • ***
  • Posts: 142
  • Karma: +0/-0
Store locations within a database
« on: June 08, 2011, 01:41:47 pm »


               Alright, I've finally dove in to databases.  As I scratch the surface, I want to start light.  I have a custom spell called "mark" in which a spot is marked by the caster as a "return to" location for the future.  The script stores the location into a "Starjewel" that can be used later, given to another PC, found by a PC, etc.  the script is as follows:

    object oPlayer = OBJECT_SELF;
    location lPlayer = GetLocation(oPlayer);
    string sPlayer = GetStringLeft(GetName(oPlayer), 3);
    string sArea = GetStringLeft(GetTag(GetArea(oPlayer)), 3);
    string sNewTag = sPlayer + sArea;
    ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(925), oPlayer, 0.0);
    object oJewel = CreateItemOnObject("starjewel", oPlayer, 1, sNewTag + "jewel");
    AssignCommand(oJewel, ActionDoCommand(SetCampaignLocation("starjewel_db", GetTag(oJewel), lPlayer, oJewel)));
    SetCutsceneMode(oPlayer, TRUE);
    DelayCommand(4.0, AssignCommand(oPlayer, ActionDoCommand(SetCutsceneMode(oPlayer, FALSE))));

After this Starjewel is created, the player should be able to use the Starjewel to return to the location originally marked upon it.  When I use Local variables and locations, this works just fine.  When I use Campaign ones, it does not, nor is any database created.  Here is the Starjewel script for onuse....

#include "X0_I0_SPELLS"

void main()
{
object oCaster = GetItemActivator();
location lCaster = GetLocation(oCaster);
string sJewel = GetTag(GetItemActivated());
location lDest = GetCampaignLocation("starjewel_db", sJewel, GetItemActivated());
string sRecall = GetLocalString(oCaster, "starjewel");
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lCaster , TRUE, OBJECT_TYPE_CREATURE);
location lTarget = GetLocation(oTarget);

while (GetIsObjectValid(oTarget))
     {
     ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(860), lTarget);
     AssignCommand(oTarget, ActionJumpToLocation(lDest));

     oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, lCaster, TRUE, OBJECT_TYPE_CREATURE);
     lTarget = GetLocation(oTarget);
     }
     ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(860), lDest);
}


Do I have to initialize a database somewhere?  Any ideas why this doesn't seem to store into a database as requested?

Thank you in advance.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Store locations within a database
« Reply #1 on: June 08, 2011, 02:19:35 pm »


               I'm not certain what the issue is here, but one problem I ran into with the bioware database was its inability to handle long strings. You were stuck with 32 characters. You can solve this problem with Knat's NBDE. Check it out on the vault.
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Store locations within a database
« Reply #2 on: June 08, 2011, 02:43:10 pm »


               It may be as simple a case, as that creating an item isn't instant.  Instead of using GetTag(oJewel), it might be worth trying it feeding the new tag that you're assigning the jewel in manually into the call to store the variable, and skipping the ActionDoCommand routine entirely.
 As it is, if that part is trying to run before the jewel is created, it simply won't fire off.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Store locations within a database
« Reply #3 on: June 08, 2011, 03:35:37 pm »


               You've got heaps of unnecessary functions in there. My guess is that item objects don't have action cues, and that assigning them actions has no effect, but I don't know, because I have never and would never do something like that. Here's a cleaned up version. Long story short: save Action functions for cueing up behavoir on NPCs. AssignCommand is useful for making a different object than the caller of the script run code, but there's no real reason to do that here. Lastly, the way you set the campaign location using only 3 letters from player name and area tag is...some combination of bizarre, unnecessary, or nonfunctional, but my goal for now is simply to get your script working.


    object oPlayer = OBJECT_SELF;
    location lPlayer = GetLocation(oPlayer);
    string sPlayer = GetStringLeft(GetName(oPlayer), 3);
    string sArea = GetStringLeft(GetTag(GetArea(oPlayer)), 3);
    string sNewTag = sPlayer + sArea;
    ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(925), oPlayer, 0.0);
    object oJewel = CreateItemOnObject("starjewel", oPlayer, 1, sNewTag + "jewel");
    SetCampaignLocation("starjewel_db", sNewTag + "jewel", lPlayer, oJewel);
    SetCutsceneMode(oPlayer, TRUE);
    DelayCommand(4.0, SetCutsceneMode(oPlayer, FALSE));



Funky
               
               

               


                     Modifié par FunkySwerve, 08 juin 2011 - 02:36 .
                     
                  


            

Legacy_Ivanovich

  • Full Member
  • ***
  • Posts: 142
  • Karma: +0/-0
Store locations within a database
« Reply #4 on: June 08, 2011, 03:45:30 pm »


               I've tried adding a 4 second delay to the write to the DB, but still nothing.  No Database files are being created.  I've even tried assigning the campaign location to the player, but still nothing.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Store locations within a database
« Reply #5 on: June 08, 2011, 03:52:35 pm »


               I am currentlu at work so can not fully go through it right now.  

there should be no problem with useing the created item right away, they are created right away,  It is the destroy item that has a delay .

The problem I see from a quic glance is that you are using 'starjewel' as the DB name you are writing to and 'starjewel_db' as the name of the db you are reading from.  

of cource there is no reason to use a DB for this unless you are just useing it as a learning process.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Store locations within a database
« Reply #6 on: June 08, 2011, 03:56:20 pm »


               @funky.  yes an object can take an assigned command.  It is not often needed but once in awhile it is.  an example would be setting the destroyable flag, it has to run on object self.   of cource you use nwnx so my have other options on setting the flag.
               
               

               
            

Legacy_Ivanovich

  • Full Member
  • ***
  • Posts: 142
  • Karma: +0/-0
Store locations within a database
« Reply #7 on: June 08, 2011, 04:02:02 pm »


               

FunkySwerve wrote...

You've got heaps of unnecessary functions in there. My guess is that item objects don't have action cues, and that assigning them actions has no effect, but I don't know, because I have never and would never do something like that. Here's a cleaned up version. Long story short: save Action functions for cueing up behavoir on NPCs. AssignCommand is useful for making a different object than the caller of the script run code, but there's no real reason to do that here. Lastly, the way you set the campaign location using only 3 letters from player name and area tag is...some combination of bizarre, unnecessary, or nonfunctional, but my goal for now is simply to get your script working.


    object oPlayer = OBJECT_SELF;
    location lPlayer = GetLocation(oPlayer);
    string sPlayer = GetStringLeft(GetName(oPlayer), 3);
    string sArea = GetStringLeft(GetTag(GetArea(oPlayer)), 3);
    string sNewTag = sPlayer + sArea;
    ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(925), oPlayer, 0.0);
    object oJewel = CreateItemOnObject("starjewel", oPlayer, 1, sNewTag + "jewel");
    SetCampaignLocation("starjewel_db", sNewTag + "jewel", lPlayer, oJewel);
    SetCutsceneMode(oPlayer, TRUE);
    DelayCommand(4.0, SetCutsceneMode(oPlayer, FALSE));



Funky


Thank you for your help.  After removing the "heaps" of unnecessary functions, it worked.  I apologize if my code offended you.  I am still learning.

As for the "bizarre and unnecessary" combination of the player and area tag in addition to the word "jewel", this seemed sensible given that there would be multiple star jewels all over the place from multiple players, and the only way to successfully call the right location to the right jewel would be to assign some sort of unique ID to it.  Again, if I am wrong, I apologize.  I'm trying to learn this stuff.
               
               

               
            

Legacy_Ivanovich

  • Full Member
  • ***
  • Posts: 142
  • Karma: +0/-0
Store locations within a database
« Reply #8 on: June 08, 2011, 04:03:28 pm »


               

The problem I see from a quic glance is that you are using 'starjewel' as the DB name you are writing to and 'starjewel_db' as the name of the db you are reading from.  


That's fixed '<img'>  Just an error.

of cource there is no reason to use a DB for this unless you are just useing it as a learning process.


If I don't use a database, I lose all the Starjewel "locations" on a server crash, no?
               
               

               
            

Legacy_Khuzadrepa

  • Sr. Member
  • ****
  • Posts: 347
  • Karma: +0/-0
Store locations within a database
« Reply #9 on: June 08, 2011, 04:15:54 pm »


               

Ivanovich wrote...
If I don't use a database, I lose all the Starjewel "locations" on a server crash, no?

If you store local variables on an item, and the item is in the character's inventory, then you do not lose those locations.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Store locations within a database
« Reply #10 on: June 08, 2011, 04:16:20 pm »


               

Ivanovich wrote...

If I don't use a database, I lose all the Starjewel "locations" on a server crash, no?


No, Just store it as a local on the item.  Locals on the Item are saved with the item.  
Since the locals are on the item you also will not need unique lables.   The jewel just uses the data that is stored on itsself.

also if the server crashes and the item is lost there is no need to have the data stored in the DB.  there is no item to use it,
               
               

               


                     Modifié par Lightfoot8, 08 juin 2011 - 03:17 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Store locations within a database
« Reply #11 on: June 08, 2011, 04:54:03 pm »


               

Ivanovich wrote...

FunkySwerve wrote...

You've got heaps of unnecessary functions in there. My guess is that item objects don't have action cues, and that assigning them actions has no effect, but I don't know, because I have never and would never do something like that. Here's a cleaned up version. Long story short: save Action functions for cueing up behavoir on NPCs. AssignCommand is useful for making a different object than the caller of the script run code, but there's no real reason to do that here. Lastly, the way you set the campaign location using only 3 letters from player name and area tag is...some combination of bizarre, unnecessary, or nonfunctional, but my goal for now is simply to get your script working.


    object oPlayer = OBJECT_SELF;
    location lPlayer = GetLocation(oPlayer);
    string sPlayer = GetStringLeft(GetName(oPlayer), 3);
    string sArea = GetStringLeft(GetTag(GetArea(oPlayer)), 3);
    string sNewTag = sPlayer + sArea;
    ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(925), oPlayer, 0.0);
    object oJewel = CreateItemOnObject("starjewel", oPlayer, 1, sNewTag + "jewel");
    SetCampaignLocation("starjewel_db", sNewTag + "jewel", lPlayer, oJewel);
    SetCutsceneMode(oPlayer, TRUE);
    DelayCommand(4.0, SetCutsceneMode(oPlayer, FALSE));



Funky


Thank you for your help.  After removing the "heaps" of unnecessary functions, it worked.  I apologize if my code offended you.  I am still learning.

As for the "bizarre and unnecessary" combination of the player and area tag in addition to the word "jewel", this seemed sensible given that there would be multiple star jewels all over the place from multiple players, and the only way to successfully call the right location to the right jewel would be to assign some sort of unique ID to it.  Again, if I am wrong, I apologize.  I'm trying to learn this stuff.

Offended? '<img'> Not at all. Hopefully that didn't sound too harsh. It was actually some combination of bizarre, unnecessary, or nonfunctional. The problem there is that, especially with only 3 letters, neither the player nor the area portion of that combined identifier will be guaranteed unique. Characters can have similar names (think Fred, Frederick, Fren, Frenetic Joe, etc), as well as identical names, and area tags can also be similar and identical. Either you NEED that portion of the tag as a unique identifier, or you don't. If you need it to be unique, what you have there will break quickly as more players use it - hence, nonfunctional. If you don't, it's deadweight code - hence, unnecessary. Either way, it's a bizarre thing to do.

The fix is to remove it if you don't need it, or to use truly unique identifiers if you do. I would go with the area resref and a 16-character chunk of the playername (NOT character name, which is what you are using). Having not used the bioware database in the last 5 or 6 years, I can't attest to this myself, but a poster above noted a 32-character limit for the vanilla database, or I'd be suggesting full playername.

Funky
               
               

               


                     Modifié par FunkySwerve, 08 juin 2011 - 03:54 .
                     
                  


            

Legacy_Ivanovich

  • Full Member
  • ***
  • Posts: 142
  • Karma: +0/-0
Store locations within a database
« Reply #12 on: June 08, 2011, 05:02:18 pm »


               I did not know that they retained variables through server restarts.  That solves a lot.  thanks for your help!
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Store locations within a database
« Reply #13 on: June 08, 2011, 05:20:18 pm »


               

Ivanovich wrote...
Thank you for your help.  After removing the "heaps" of unnecessary functions, it worked.  I apologize if my code offended you.  I am still learning.

As for the "bizarre and unnecessary" combination of the player and area tag in addition to the word "jewel", this seemed sensible given that there would be multiple star jewels all over the place from multiple players, and the only way to successfully call the right location to the right jewel would be to assign some sort of unique ID to it.  Again, if I am wrong, I apologize.  I'm trying to learn this stuff.

Offended? '<img'> Not at all. Hopefully that didn't sound too harsh. It was actually some combination of bizarre, unnecessary, or nonfunctional. The problem there is that, especially with only 3 letters, neither the player nor the area portion of that combined identifier will be guaranteed unique. Characters can have similar names (think Fred, Frederick, Fren, Frenetic Joe, etc), as well as identical names, and area tags can also be similar and identical. Either you NEED that portion of the tag as a unique identifier, or you don't. If you need it to be unique, what you have there will break quickly as more players use it - hence, nonfunctional. If you don't, it's deadweight code - hence, unnecessary. Either way, it's a bizarre thing to do.

The fix is to remove it if you don't need it, or to use truly unique identifiers if you do. I would go with the area resref
and a 16-character chunk of the playername (NOT character name, which is what you are using). Having not used the bioware database in the last 5 or 6 years, I can't attest to this myself, but a poster above noted a
32-character limit for the vanilla database, or I'd be suggesting full playername (resrefs are 16 characters max).

So, DO you need it? As written, I'm not sure. I do know that all the information you're storing on that will be available
when the gem is used as well, if the gem is undroppable, making it unnecessary if it's written a certain way. I don't see you setting the Cursed flag on it though. Such campaign variables can be keyed to a particular player anyway, in the optional parameter, though, for some reason, you chose to specify the jewel.

My suggestion to you as someone who's learning scripting nwscript would be to experiment enough to understand how all the parameters of the functions that you're using work. I remember being confused not just by campaign variables once, but by plain old local variables. I also remember, however, disliking how much time every little thing took to get working, since there was so much to learn. If you don't want to invest the full amount of learning time up front, but go at it gradually, I get that too.

Lastly, a warning. When you add areas to your module, I believe your stored campaign locations will subject to breakage. It might be more advisable to use a string to store the data, combining the x, y, and z coordiates with the area resref (at minimum). If you're curious about how to do that, I'll be happy to explain.

Of course, most of this is moot anyway past the learning experience, since, as other posters have noted, setting the local on the item will store it on the character's bic as soon as the character is Exported, either via the Export functions or by exiting the server.

Funky
               
               

               


                     Modifié par FunkySwerve, 08 juin 2011 - 04:29 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Store locations within a database
« Reply #14 on: June 08, 2011, 05:26:57 pm »


               

Lightfoot8 wrote...

@funky.  yes an object can take an assigned command.  It is not often needed but once in awhile it is.  an example would be setting the destroyable flag, it has to run on object self.   of cource you use nwnx so my have other options on setting the flag.

I wasn't quesitoning whether they could take assigned commands, but whether they had action queues (I've AC'd items many times). That it worked when he removed the action queue-up suggests to me that they can't. That, or you just can't ActionDoCommand a SetCampaign - wouldn't surprise me either.

Funky
               
               

               


                     Modifié par FunkySwerve, 08 juin 2011 - 04:31 .