Author Topic: Pass number of Items to Persistent variable  (Read 345 times)

Legacy_jimbobx

  • Newbie
  • *
  • Posts: 12
  • Karma: +0/-0
Pass number of Items to Persistent variable
« on: November 16, 2010, 04:37:15 pm »


               Having trouble with this. Parameters not matching or somesuch. Haven't scripted anything in 3 or 4 years which is why this is proving tricksy.
I'm trying to create a Score board where the amount of ears in the players inventory will increment a Persistent variable.
A little help would be great.
[nwscript]
int GetNumItems(object oTarget,string sItem)
{
int nNumItems = 0;
object oItem = GetFirstItemInInventory(oTarget);
while (GetIsObjectValid(oItem) == TRUE)
{
if (GetTag(oItem) == sItem)
{
nNumItems = nNumItems + GetNumStackedItems(oItem);
}
oItem = GetNextItemInInventory(oTarget);
}
return nNumItems;
}

void main
(
SetCampaignInt("H2_TESTMODULE", "BUGBEAR KILLS", GetNumItems,GetPCSpeaker());
)
[/nwscript]
               
               

               
            

Legacy_KenquinnTheInsaneOne

  • Newbie
  • *
  • Posts: 48
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #1 on: November 16, 2010, 05:14:51 pm »


               It may have something to do with you not passing any variables to GetNumItems. The main function should look something like this assuming you want the int added to the speaker.

void main
{
object oPC = GetPCSpeaker();
SetCampaignInt("H2_TESTMODULE", "BUGBEAR KILLS", GetNumItems(oPC, "insert_item_tag_here"), GetPCSpeaker());
}
               
               

               


                     Modifié par KenquinnTheInsaneOne, 16 novembre 2010 - 05:15 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #2 on: November 16, 2010, 05:17:59 pm »


                #include "nw_i0_plot"
void main()
{
    SetCampaignInt("H2_TESTMODULE", "BUGBEAR KILLS", GetNumItems(GetPCSpeaker(), "TagOfEars"
),GetPCSpeaker());
}
 

EDIT:  If you include nw_I0_plot you can use the GetNumItems function from that include.

Errors in your script are as follows:

You did not give your GetNumItems function any arguments when trying to use it in your main.
You used (brackets) instead of {curly braces} for your main body.
               
               

               


                     Modifié par Lightfoot8, 16 novembre 2010 - 05:26 .
                     
                  


            

Legacy_Mudeye

  • Full Member
  • ***
  • Posts: 238
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #3 on: November 16, 2010, 05:23:38 pm »


               I'm not 100% sure what you are after but I suspect you want to set the int to the number of items that the pc has. 

1) GetPCSpeaker() only works in a conversation so hopefully that is where you are using it.
2) In the main procedure you needs to be changed to something like:

void main()
{
    object pc = GetPCSpeaker();
    SetCampaignInt(    "H2_TESTMODULE", "BUGBEAR KILLS",
                    GetNumItems( pc, "itemTag" ),
                    pc );
}

"itemTag" needs to be whatever the tag is for the ears.
               
               

               
            

Legacy_jimbobx

  • Newbie
  • *
  • Posts: 12
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #4 on: November 17, 2010, 10:01:57 am »


               Thanks for the quick replies. I'd forgotten that GetNumItems was already there as an include.



Now I want to display the kills tally on a Noticeboard.



I have this on the OnUsed of a placeable. But this will only let the PC see their own score tally.



#include "nw_i0_tool"



void main()

{

object oPC = GetLastUsedBy();

int nBugBearKills = GetCampaignInt("H2_TESTMODULE", "BUGBEAR KILLS", oPC);

string sName = GetName(oPC);



SendMessageToPC(oPC, "The Bugbear Kill tally for " + sName + "is " + IntToString(nBugBearKills));

}



Is there a way to display other players Kill tallys?
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #5 on: November 17, 2010, 02:28:21 pm »


               This kind of thing is something the bioware database is very poorly suited to doing. With NWNX-MySQL, it's very easy - in fact, we do a leaderboard for our arena this way. With the bioware database, it is prohibitively slow. You would have to store the variables in such a way that you could pull every such score up. The most likely way to do this is by an incrementing count in the variable name, something like ArenaKills1, ArenaKills2, and so on. You would then store both the name and the kill count in a string, separated by some kind of divider, in the variable value (it'd have to be a persistent string). One of the major reasons this is expensive is the sorting. Just to add an entry, you'd have to check every existing entry in the database with an incrementing count, so that you'd know where the current list ends, to know what number to put in the var name. You'd have to follow a similar procedure when posting the scores, to pull them all up.

Given the speed of the bioware database, this just isn't feasible, though you might look into Knat's database extender on the vault, since I think it's set up to handle such things as best as is possible.

Really, though, you want MySQL for something like this, if it's at all possible, because it's built to do things like this, and allows easy sorting. Here's the code for the command our players use to check the arena top scores:


                string sSQL, sD1, sD2, sD3, sD4, sArenaReport;
                int nX;

                for (nX = 5; nX > 0; nX--) {
                    sSQL =
                        "SELECT monsters,helllevel,playercount,playernames FROM arena WHERE paragon = " + IntToString(nX) +
                        " ORDER BY monsters DESC, helllevel DESC, playercount LIMIT 5";
                    SQLExecDirect(sSQL);
                    sArenaReport = sArenaReport + COLOR_GOLD + "[Monster Level: " + IntToString(nX) + "]" + COLOR_END + NEWLINE;

                    while (SQLFetch() != SQL_ERROR)
                        sArenaReport += COLOR_GREEN + "[Monster Number: " + SQLGetData(1) + "]" + COLOR_BLUE + " [Area Level: " +
                            SQLGetData(2) + "]" + COLOR_PURPLE + " [Team: " + SQLDecodeSpecialChars(SQLGetData(4)) + "]" + COLOR_END +
                            NEWLINE;
                }

                SendMessageToPC(oCPC, sArenaReport);

Likewise, entering the data doesn't require any convoluted backflips either, as compared to the things you have to do to make the bioware db do this. Here's the entirety of the script that writes this data, which does so only when all the critters in the arena have been killed, and teleports the players out of the arena:


int GetAreAllSpawnsInAreaDead(object oArea) {
    object oCritter = GetFirstObjectInArea(oArea);

    while (GetIsObjectValid(oCritter)) {
        if (GetLocalString(oCritter, "ES_Death") == "fky_arena_7death" && !GetIsDead(oCritter) && oCritter != OBJECT_SELF)
            return FALSE;
        oCritter = GetNextObjectInArea(oArea);
    }

    return TRUE;
}

void main() {
    object oArea = GetArea(OBJECT_SELF);

    if (GetAreAllSpawnsInAreaDead(oArea)) {
        object oWay = GetWaypointByTag("HellGateExit");
        location lWay = GetLocation(oWay);
        object oDevice = GetNearestObjectByTag("HellGatePortal", oWay);

        /* insert data into database */
        int nParagon = GetLocalInt(oDevice, "Paragon");
        int nHellLevel = GetLocalInt(oDevice, "HellLevel");
        int nMonsters = GetLocalInt(oDevice, "Monsters");
        int nPlayers = GetLocalInt(oDevice, "PlayerCount");

        string sPlayerNames = GetLocalString(oDevice, "PlayerNames");
        string sSQL =
            "INSERT INTO arena (paragon, helllevel, monsters, playercount, recorddate, playernames) VALUES (" +
            IntToString(nParagon) + ", " + IntToString(nHellLevel) + ", " + IntToString(nMonsters) + ", " +
            IntToString(nPlayers) + ", DATE_ADD(NOW(), interval 7 day),'" + SQLEncodeSpecialChars(sPlayerNames) + "')";
        SQLExecDirect(sSQL);
        object oPC = GetFirstPC();

        while (GetIsObjectValid(oPC)) {
            if (GetArea(oPC) == oArea)
                ForceJump(oPC, lWay);
            oPC = GetNextPC();
        }
    }
}


If you have more questions, please feel free to ask, but no matter which option you pick, the setup is going to be complicated.

Funky
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #6 on: November 19, 2010, 06:37:35 am »


               I myself do not see why the bioware DB can not be used to do what you are trying to do.  You just have to script it with the limitations of the DB in mind.  The first problem you are going to run into with the current way you are setting your values into theDB :

SetCampaignInt("H2_TESTMODULE", "BUGBEAR KILLS", nKills,oPC);

With useing the last Argument ( oPC) to set the entry to a PC, There is no way to retrive that value unless the PC is currently on the server.  If you are however just wanting the PC currently on the server to be on your Score Board then this method will work fine, But then again you would not even need the DB to do it this way. 

In order to be able to access the data without the PC being on the server you will need to figure out a way to identfy each entry into the DB by the name of the var alone.  The method I like best is to give each PC a unique ID# that you store on an item that you place on the PC.  Then you Add the Id to your var name to get the kills for the requested PC.  In the case above "BUGBEAR KILLS" would become "BUGBEAR KILLS1"  for the PC with the ID# of 1.  In script it would look more like. 

sVarName = "BUGBEAR KILLS"+ IntToString( nID); 

There have of course been a many other way People have defined the unique ID for the DB var. One of the more comon ways was to use a combanation for the PC account name and character name.

Another major problem with the Bioware DB is the fact that it bloats.  The bloating of the DB is caused by the fact that any Complex data type entered into the DB is never deleted or overwriten.  For example if you entered a string(a complex data type) into the DB like so:

SetCampaignString("MyDB", "TestString" , "Mary had a little lamb");

Then later decided to change the entry and did.

SetCampaignString("MyDB", "TestString" , "Mary lost her lambs.");
 
The DB would not remove the first entry from the DB.  It would just mark it as unused and creat a new entry for the "TestString" var. 

With that fact known you will want to limit the amount of times that you rewrite Complex data types to the DB.  if over done the DB can bloat in size at a very fast rate.  The Int is not a Complex Data Type and will not cause the DB to bloat reguardless of how many times you rewrite it. 

How you proceed from here has a lot to do with how you want your score board to work.  Did you want it to list the standing of all players who have ever turned in a ear?  I myself think this could go a little overboard.   I would say a top 10 or 100 board would do the job just as well.  Perhapes even have two boards.  One for all players and another for just the players loged on at the moment. 

With your current method of useing a turn in point for the ears, I do not see there being so many reads and writes to the DB to make the standard DB inpractical.  You would only realy need to read from the DB when the module loaded to set up the score board and on Client enter to get that players current score.   Writing to the DB would only need to happen when a player checked in there ears. 

It will take a little work and planning, But there is no reason it can not be done without a Plugin.   
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #7 on: November 19, 2010, 07:30:17 am »


               

It will take a little work and planning, But there is no reason it can not be done without a Plugin.   


Except for the one reason I mentioned, that you failed to - speed.

The technical hurdles you mention are negligible - you simply use the module as the object in the Persistent function, and any database is going to need a unique way of identifying pcs (though just using player and character name is insufficent by itself, as players can simply make another character of the same name - you'd need a scripted check against that at a minimum). The rest is simply handled by storing one or more 'columns' in a single string with a divider character, as I explained to you in another post. None of that is in the least problematic, though it's certainly clunky. In theory, everything is basically gravy.

The problem lies in practice - specifically, when attempting to access the stored data in a useful way - like a sort. Should you actually attempt something like this, you'll quickly discover as much. I did, and suffice it to say, there's a reason I use MySQL. There's simply no good reason not to use it if you're making a PW (as opposed to a SP mod). I'm self taught at nwscript, MySQL, C, letoscript, the whole schebang. It's really not that hard, and, unlike the bioware database, MySQL is actually designed to be used in exactly this fashion. In fact, you could probably pick up enough MySQL in the time it would take you to code up the unnecessarily convoluted bioware db method. Don't let me stop you from trying though - no better way to learn than to do. '^_^'

Funky
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #8 on: November 20, 2010, 05:24:19 am »


               On a side note. you can also store this type of info on a persistent item the player might have and then retrieve the info from the item. I still prefer this method to using the NWN database.

You could then loop through all players and retrieve the info from each of their items and then sort it via scripting.

Just another option. Good luck.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Pass number of Items to Persistent variable
« Reply #9 on: November 20, 2010, 08:58:26 am »


               Of course, that would only display kill tallies of those ingame at the moment. That might be a reasonable compromise, if you're intimidated by the other options.



Funky