Author Topic: Dynamic PC Rumor Generation  (Read 578 times)

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Dynamic PC Rumor Generation
« on: October 24, 2011, 09:04:05 pm »


                 Starting a new topic for it, as Rolo suggested, so that the UoA thread can stay for if anyone gets any more info on it.

Edit: Updated  Erf download link Here

This system is set up for using Set/GetPersistentString under the table "pwrumors", which it will create and initialize if hooked into the OnModule load.

  If the persistence isn't needed, or someone wants to use it without NWNX, those calls can be commented out, and the Get/SetLocalString calls can be commented instead.  I use those for quick testing of changes, but they would work for SP module use since the variables on the PC would be saved in that case.

  I'll be expanding the options for what the NPCs will say later, that's the only part that's still quite obviously unfinished.  It works, but there's only three variations at the moment.  I figured out how I want to do it now though, so in a day or two I'll have an easily expandable and customizable framework in for that part of it as well.

  If there are any suggestions for other rumour worthy acts, I'll expand that as well.  I just went with the obvious ones to start.  Here's the ones in now:

const int RUMOR_TYPE_SLAY_ENEMY = 1;
const int RUMOR_TYPE_ROB_ENEMY  = 2;
const int RUMOR_TYPE_BETRAYAL   = 3;
const int RUMOR_TYPE_DEFEAT_BY_ENEMY = 4;
const int RUMOR_TYPE_SAVE_ALLY  = 5;


  There's an option to have it check for only a specific rumor type that I haven't finished writing in.  At the moment it only finds the highest weighted one that the NPC can make the lore check for.  It's just a few if statements to add that I haven't gotten around to yet.

  The biggest drawback of the system, is that creatures named by type are "spoken back" in a very fluid way, since they're missing the "a" or "the" needed.  There's a variable check in to allow for giving them a more fluid name for rumours, but that's only an option for non-default creatures.

  The biggest advantage, is that it can hook into any existing system without affecting others, since it just stores and writes variables, and occasionally makes an NPC speak a string.
               
               

               


                     Modifié par Failed.Bard, 30 octobre 2011 - 10:01 .
                     
                  


            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #1 on: October 24, 2011, 09:37:58 pm »


               <rubs his hands...>

Failed.Bard wrote...
  Starting a new topic for it, as Rolo suggested, so that the UoA thread can stay for if anyone gets any more info on it.

*Or* their tasty AI routines ;-)

Erf download link Here:

Tucked away for later perusal :-)

This system is set up for using Set/GetPersistentString under the table "pwrumors", which it will create and initialize if hooked into the OnModule load.
...
If there are any suggestions for other rumour worthy acts, I'll expand that as well.  I just went with the obvious ones to start.  Here's the ones in now:

const int RUMOR_TYPE_SLAY_ENEMY = 1;
const int RUMOR_TYPE_ROB_ENEMY  = 2;
const int RUMOR_TYPE_BETRAYAL   = 3;
const int RUMOR_TYPE_DEFEAT_BY_ENEMY = 4;
const int RUMOR_TYPE_SAVE_ALLY  = 5;

How about  _QUEST_INFO to be able to dynamically insert rumors about quests...?
and _RUNAWAY_RUNAWAY for when the PC chooses discretion :-)

Thanks a lot FB :-) I can really see a use for this.  I'll also be looking at the stuff Squatting Monk pointed out when I get somewhere that doesn't block the Vault :-/

<...in Glee™>
               
               

               


                     Modifié par Rolo Kipp, 24 octobre 2011 - 08:38 .
                     
                  


            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #2 on: October 24, 2011, 11:47:45 pm »


               SQL Tip: In the FB_SetUpRumorDatabase() function, use CREATE TABLE IF NOT EXISTS instead of making an entry in the pwdata table that it exists. This will make it so you don't have to have three separate NWNX calls the first time you set it up, and will allow you to easily DROP the pwrumors table without having to go into pwdata and clear the marker. Cleaner code all around, too.

Suggested rewrite of that function:

void FB_SetupRumorDatabase ()
{
    // Comment out if already initialized elsewhere.
    SQLInit();
 
    SQLExecDirect("CREATE TABLE IF NOT EXISTS pwrumors (" +
        "player varchar(64) NOT NULL default '~'," +
        "tag varchar(64) NOT NULL default '~'," +
        "name varchar(64) NOT NULL default '~'," +
        "val text," +
        "expire int(11) default NULL," +
        "last timestamp NOT NULL default current_timestamp," +
        "PRIMARY KEY (player,tag,name))");
}

               
               

               


                     Modifié par Squatting Monk, 24 octobre 2011 - 10:48 .
                     
                  


            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #3 on: October 25, 2011, 12:36:46 am »


               The check was made in the pwrumors table, not pwdata, though the IF NOT EXISTS suggestion is still a valid one.  I'll likely not change it in my own though, since I keep a server log shortcut on my desktop and I can more easily check if it set up properly there as the script is.
               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #4 on: October 25, 2011, 12:40:35 am »


               D'oh! I see that now.
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #5 on: October 25, 2011, 06:15:58 am »


                 I updated the erf, at the original download link.  It's got a compartmentalized structure for putting the rumour parts together, to allow for easier adding and customizing of variants.  I also added rumour types based on class and racial groupings, to allow for more specific rumours to be stored by plot events.

Here's the updated rumour type list:

const int RUMOR_TYPE_SLAY_ENEMY = 1;
const int RUMOR_TYPE_ROB_ENEMY  = 2;
const int RUMOR_TYPE_BETRAYAL   = 3;
const int RUMOR_TYPE_DEFEAT_BY_ENEMY = 4;
const int RUMOR_TYPE_SAVE_ALLY  = 5;
const int RUMOR_TYPE_RUNAWAY    = 6;
const int RUMOR_TYPE_ROMANTIC   = 7;
const int RUMOR_TYPE_QUEST_INFO = 9;

Only the first five can be easily hooked to generate them automatically off PC or creature events.

Edit:  I changed it to have class and race of the rumor target stored as subtypes, as well as the inverse of the targets alignment.  I just realized I'll need to add a seperate alignment check for the romantic subtype though, since that's the only one that wouldn't need the inverting.
               
               

               


                     Modifié par Failed.Bard, 25 octobre 2011 - 03:31 .
                     
                  


            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #6 on: October 26, 2011, 03:12:34 am »


               I'm playing around with the idea of an override version of it as well at the moment.  It might make for some interesting variance in the OC and expansions if the NPCs were a bit more active in the background.
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #7 on: October 30, 2011, 10:19:31 am »


                 I made a few small changes to the include, added a check to ensure a particular rumour base isn't stored multiple times, and a routine to help hook the OnPLayerDeath event.

  I ended up having to run GetLastDamager() in the OnPLayerDeath hook, since even running it in a script with the PC as the caller I could only ever get GetLastKiller() to return the module.
  It might end up catching the wrong object in some cases due to that, particularly in the case of instant death spells/effects.  I'm not going to try to make a change to correct that though, since I think the occasional false rumour could actually make the system more believable from a purely IC standpoint.

  The next change will have some extra constants and a switch added to allow the messages to be done by stringref.  The main advantage I see in that, is the ease in which it would be to configure "accents" in the NPCs repeating the rumours.  Obviously, servers not using a custon tlk simply won't turn on the option.
  This will likely be at least a week away.  I expect real life will keep me pretty busy through the next while.

 The download link in the original post has been updated.  I'm trying to keep the link just in that post, so anyone wanting to take a look at it won't have to sift through dead links to find the current one.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #8 on: October 30, 2011, 02:09:39 pm »


               <covering his mouth...>

Failed.Bard wrote...
...
  I ended up having to run GetLastDamager() in the OnPLayerDeath hook, since even running it in a script with the PC as the caller I could only ever get GetLastKiller() to return the module.
  It might end up catching the wrong object in some cases due to that, particularly in the case of instant death spells/effects.  I'm not going to try to make a change to correct that though, since I think the occasional false rumour could actually make the system more believable from a purely IC standpoint.

I was actually going to suggest a mechanism for injecting false leads... =) Works for me! 
"The reports of my death are greatly exaggerated"

  The next change will have some extra constants and a switch added to allow the messages to be done by stringref.  The main advantage I see in that, is the ease in which it would be to configure "accents" in the NPCs repeating the rumours.  Obviously, servers not using a custon tlk simply won't turn on the option.
  This will likely be at least a week away.  I expect real life will keep me pretty busy through the next while.

Thanks FB. You are so much faster than I and I like what you've put together.  Take some time off NwN. Relax. Work <he's snickering. you should know that> Only 'cuz I'm jealous. :-P

The download link in the original post has been updated.  I'm trying to keep the link just in that post, so anyone wanting to take a look at it won't have to sift through dead links to find the current one.

That's the way I like to do it, too (see my CCC posts). Makes things tidier =) <tidier? *snort*> What? I can be tidy. I can!

<...and spreading rumours>
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #9 on: October 30, 2011, 03:16:21 pm »


               

Rolo Kipp wrote...

<covering his mouth...>

Failed.Bard wrote...
...
  I ended up having to run GetLastDamager() in the OnPLayerDeath hook, since even running it in a script with the PC as the caller I could only ever get GetLastKiller() to return the module.
  It might end up catching the wrong object in some cases due to that, particularly in the case of instant death spells/effects.  I'm not going to try to make a change to correct that though, since I think the occasional false rumour could actually make the system more believable from a purely IC standpoint.

I was actually going to suggest a mechanism for injecting false leads... =) Works for me! 
"The reports of my death are greatly exaggerated"

<...and spreading rumours>


  You can manually inject false rumors through the script as it is now, though the current system requires an object to be entered.  I can add a routine that allows for the relevent details to be added directly as strings for times when an object isn't present to use as the base, or where a group needs to be represented instead of an individual.
               
               

               
            

Legacy_QlippothVI

  • Full Member
  • ***
  • Posts: 197
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #10 on: October 30, 2011, 09:03:17 pm »


               You know, for some time I've been thinking I'd like a system for intercreature communications. In a living module there should be method for npcs to cause a flow of information across the module. If a forester is run out of their area by a monster, this is something they should convey to authorities, who in turn can farm out securing that area for the forester again. So this system might be a good start.
               
               

               
            

Legacy_QlippothVI

  • Full Member
  • ***
  • Posts: 197
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #11 on: October 30, 2011, 09:06:43 pm »


               I also need a way for PCs to add to the flow, like _runaway_runaway to tell NPC authorities about said monster in some other area, via dialogs
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #12 on: October 30, 2011, 09:42:36 pm »


               

Failed.Bard wrote...

  I updated the erf, at the original download link.  It's got a compartmentalized structure for putting the rumour parts together, to allow for easier adding and customizing of variants.  I also added rumour types based on class and racial groupings, to allow for more specific rumours to be stored by plot events.

Here's the updated rumour type list:

const int RUMOR_TYPE_SLAY_ENEMY = 1;
const int RUMOR_TYPE_ROB_ENEMY  = 2;
const int RUMOR_TYPE_BETRAYAL   = 3;
const int RUMOR_TYPE_DEFEAT_BY_ENEMY = 4;
const int RUMOR_TYPE_SAVE_ALLY  = 5;
const int RUMOR_TYPE_RUNAWAY    = 6;
const int RUMOR_TYPE_ROMANTIC   = 7;
const int RUMOR_TYPE_QUEST_INFO = 9;

.


hmm, When scaning past this, I can not help but think that you would have more dynamic universal options in the system if you changed your rumor constants to bit flags,  instead of just linear constants.  
i.e.

const int RUMOR_TYPE_SLAY_ENEMY = 1;                //0x01   or %0000_0001
const int RUMOR_TYPE_ROB_ENEMY  = 2;                //0x02    or %0000_0010
const int RUMOR_TYPE_BETRAYAL   = 4;                   //0x04   or %0000_0100
const int RUMOR_TYPE_DEFEAT_BY_ENEMY = 8;  //0x08    or %0000_1000
const int RUMOR_TYPE_SAVE_ALLY  = 16;               //0x10     or %0001_0000
const int RUMOR_TYPE_RUNAWAY    = 32;               // 0x20    or %0010_0000 
const int RUMOR_TYPE_ROMANTIC   = 64;               // 0x40    or %0100_0000  
const int RUMOR_TYPE_QUEST_INFO = 128;          //0x80    or %1000_0000

of cource the benifit here is that you would be able to use the same var to hold more then one rumor type without fear of them overwritting  a differant type that they already have.   

e.g. 

int nRumors  = GetRumorTypesFrom( oTarget);
int nSAVEnSLAY =RUMOR_TYPE_SLAY_ENEMY+RUMOR_TYPE_SAVE_ALLY;
if (nSAVEnSLAY & nRumors == nSAVEnSLAY  )
{
    // I have a rumor about saving and slaying.  Of cource you would want to work out wether it was one event or two.   
}

Just a thought of a different way you might want to do it.
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #13 on: November 01, 2011, 12:00:37 pm »


               

Lightfoot8 wrote...

Failed.Bard wrote...

 ...

.


hmm, When scaning past this, I can not help but think that you would have more dynamic universal options in the system if you changed your rumor constants to bit flags,  instead of just linear constants.  
i.e.

const int RUMOR_TYPE_SLAY_ENEMY = 1;                //0x01   or %0000_0001
const int RUMOR_TYPE_ROB_ENEMY  = 2;                //0x02    or %0000_0010
const int RUMOR_TYPE_BETRAYAL   = 4;                   //0x04   or %0000_0100
const int RUMOR_TYPE_DEFEAT_BY_ENEMY = 8;  //0x08    or %0000_1000
const int RUMOR_TYPE_SAVE_ALLY  = 16;               //0x10     or %0001_0000
const int RUMOR_TYPE_RUNAWAY    = 32;               // 0x20    or %0010_0000 
const int RUMOR_TYPE_ROMANTIC   = 64;               // 0x40    or %0100_0000  
const int RUMOR_TYPE_QUEST_INFO = 128;          //0x80    or %1000_0000

of cource the benifit here is that you would be able to use the same var to hold more then one rumor type without fear of them overwritting  a differant type that they already have.   

e.g. 

int nRumors  = GetRumorTypesFrom( oTarget);
int nSAVEnSLAY =RUMOR_TYPE_SLAY_ENEMY+RUMOR_TYPE_SAVE_ALLY;
if (nSAVEnSLAY & nRumors == nSAVEnSLAY  )
{
    // I have a rumor about saving and slaying.  Of cource you would want to work out wether it was one event or two.   
}

Just a thought of a different way you might want to do it.


  I think I might include this method for handling rumour specialties stored on NPCs, to allow for the potential a particular NPC might have multiple areas they know more about.

  Trying to include all the verbage combinations needed in order to support dual type rumours wouldn't be feasible with the rumours portion, since the rumours themselves are assembled at the time the NPC speaks them to allow maximum variance and customizing of them off of the stored target name and optional descriptor.
               
               

               
            

Legacy_Failed.Bard

  • Hero Member
  • *****
  • Posts: 1409
  • Karma: +0/-0
Dynamic PC Rumor Generation
« Reply #14 on: November 08, 2011, 01:20:30 pm »


               

const int RUMOR_TYPE_SLAY_ENEMY = 1;
const int RUMOR_TYPE_ROB_ENEMY  = 2;
const int RUMOR_TYPE_BETRAYAL   = 3;
const int RUMOR_TYPE_DEFEAT_BY_ENEMY = 4;
const int RUMOR_TYPE_SAVE_ALLY  = 5;
const int RUMOR_TYPE_RUNAWAY    = 6;
const int RUMOR_TYPE_ROMANTIC   = 7;
const int RUMOR_TYPE_QUEST_INFO = 9;

const int RUMOR_SPECIALTY_SLAY_ENEMY = 1;      // 1
const int RUMOR_SPECIALTY_ROB_ENEMY  = 2;      // 2
const int RUMOR_SPECIALTY_BETRAYAL   = 4;      // 3
const int RUMOR_SPECIALTY_DEFEAT_BY_ENEMY = 8; // 4
const int RUMOR_SPECIALTY_SAVE_ALLY  = 16;     // 5
const int RUMOR_SPECIALTY_RUNAWAY    = 32;     // 6
const int RUMOR_SPECIALTY_ROMANTIC   = 64;     // 7
const int RUMOR_SPECIALTY_QUEST_INFO =  256; //9


  I'm starting to incorporate Lightfoot8's suggestion, but I'm not sure I'm doing the conversion from whole number to bitwise digit properly.
  At the moment I'm using this:

nTestType   = 0 << FB_GetRumorType (sTest);

  Will it work properly starting from zero, since there isn't a 1 present yet to shift?  The intention is that it will shift it one for each point in the type to make a bitwise to compare to the one used for the specialty, which I think I can compare just using the &, if I read it right.  I'm still trying to learn how to use these properly.


  I can convert it to something like this if necessary, but it seems a bit of a waste if I can start from zero:
 
  nTestType = FB_GetRumorType (sTest);
  if (nTestType) nTestType = 1 << (FB_GetRumorType (sTest) - 1);
               
               

               


                     Modifié par Failed.Bard, 08 novembre 2011 - 01:21 .