Guest
Feb 5, 2012, 9:13 pm UTCHome arrow Commands arrow Then Do Something arrow Special Commands arrow Tutorials arrow WolfScript And Database's
header image
WolfScript And Database's
Written by Dream Dancer   
Jun 22, 2008 at 09:12 PM

Name: Table Maker Procedure
No Additional Conditions.
THEN:
$DATABASE: Open database {[appdir]dmg.mdb} to filenumber {1} (1-4)
$DATABASE: Create table {members} in database {1}
$DATABASE: Create field {member} in database {1} in table {members}
$DATABASE: Create field {share} in database {1} in table {members}
$DATABASE: Create field {greet} in database {1} in table {members}
$DATABASE: Create field {greeting} in database {1} in table {members}
$DATABASE: Create field {joined} in database {1} in table {members}
$DATABASE: Close database {1}

Well now, with that out the way, lets turn this into an explaination of FurBot DataBase's and the bot's working with them.

First though, we need to discuss some actual database do's, don't's, planning, and creation habits you need to develop with furbot database's

Before even creating your database, take into consideration that you don't need multiple database's to handle things, you can have quite a few tables in a single database. The only real reason to have two actual different files is in case you want to delete and completely rebuild one from scratch. But with careful planning, you can avoid that drastic a measure and make something which works great with what you want to do with the bot at the start, and leave it open for possible future expansion. From the creation above, we get a database that looks like this:

Pick on a few furre's. But that table above is something that you should of planned out on paper before opening the bot and writing a creation function. Every database table the bot creates will be created with the first field called ID, this is what you store records under, and with FurBot, you're not limited to using names for the ID, you can use numbers for the ID field.

Unlike many other tutorial's out there, this is not one of them, I will probably be more inclined to explain how the bot works with the database. This will also get heavily into using WolfScript for the database because you can get a lot more horsepower from the database once you start figuring out how to access data from the database using FOR loops in WS.

Name: List Members Public
 Stop Action Search if TRUE
  If {*} Whispers me {list members}
   No Additional Conditions.
THEN:
$ Wolfscript
// list members
&newvar #count
&newvar #total
&newvar #name
&newvar #result
&newvar #check
&newvar #whoasks &getvar(player)
&dbopen 1 {SELECT * FROM members ORDER BY ID}
&set #count &dbrecordcount(1)
&ifn #count > 0
  &dbmovelast 1
  &dbmovefirst 1
  &set #count &dbrecordcount(1)
  &for #index=1 to #count
    &set #name &dbtostr(&dbf(1 ID))
    &set #check &dbf(1 member)
    &ifs #check = MEMBER
      &join #result &dbtostr(#name)
      &join #result { }
      &add #total 1
    &endif
    &ifs #check = PENDING
      &join #result &dbtostr(#name)
      &join #result { }
      &add #total 1
    &endif
    &ifs #check = APPRENTICE
      &join #result &dbtostr(#name)
      &join #result { }
      &add #total 1
    &endif
    &dbmovenext 1
  &endfor
  &set #result &replace(&rtrim(#result) { } {, })
  &join #result { - }
  &join #result #total
  &join #result { members}
  &whisper #whoasks #result
&endif

Well now, there's a nice complicated example to start with, this makes a pass through the database, examining each record, and if the members field matches one of three conditions, add it to the result string. You can't quite do filtering like this with the normal commands, they make lists of everything:

$DATABASE: Set variable {[tmp]} to contain list of all entrys in db {1}
in table {members} field {ID}

Gets them all.

On the other hand, by using WolfScript, one can make targeted lists, of say, just the Apprentice's in the database just by checking the value of the member field, if the value is APPRENTICE, add it to the result, that script above for example, does not get any record in which the member field is NOT member, apprentice, or pending. So, I can hide people in the database, grant them privileges, and not have them show up in the member list! Sneaky. Yet, by using a kin script, I can look at the list of them, so in the following example, I will break up the code, and get around to explaining what each section does, and why you're not going to bother my bot un-necessarily, you dig?

Name: List Stuff
 Stop Action Search if TRUE
  If {*} Whispers me {list *}
   No Additional Conditions.
THEN:
$ Wolfscript
// list other stuff
&newvar #total
&newvar #name
&newvar #result
&newvar #whoasks &getvar(player)

Note that now we have the name of the player who is asking for the list in Furcadia Format, the default character set of the game system is terribly unsafe for use with database's, mainly, you can use characters in names which are reserved in the database, hence, the next step is to run the name through a function which renders the name DataBase Safe.

// check if authorized, find if council or controller
&newvar #council {FALSE}
&newvar #sql {SELECT * FROM members WHERE ID LIKE '}
&join #sql &strtodb(#whoasks)
&join #sql {' ORDER BY ID}
&dbopen 1 #sql
&newvar #count &dbrecordcount(1)

The resulting #SQL string uses the ID field because that is how you access data from the database, most of the simple commands have this built in, you don't have to worry about the syntax when using simple commands, but when doing WS, you need to understand how it works. There's plenty of SQL references out there on the internet, even understanding how MySQL works will aid you in understanding the Query Language. Unlike MySQL however, you're limited to using SELECT on furbot database's, the command which process's the SQL statement won't allow you to do more complex operations. Namely, the command uses the dbquery method of accessing the database. With that out the way

ELECT * FROM members WHERE ID LIKE 'Dreamless Dancer' ORDER BY ID
is how the resulting query will read. So, if you whisper my bot for one of the "Non-Public" lists, to begin with, you'd better be in the main table of the database, otherwise the script dumps out if there's no record with your name. :-)

&ifn #count = 0
  &exitwolf
&endif

Well, if you got past that first check, the next thing this script checks for is whether or not you're authorized to view the list you're asking for. Note that we have not even bothered checking which list you're asking for, no sense in letting people randomly asking stuff of the bot what they SHOULD be looking for, right? So on with the next check where we check to see if you're an authorized asker:

&newvar #check &dbf(1 controller)
&ifs #check = {TRUE}
  &set #council {TRUE}
&endif
&set #check &dbf(1 taneest)
&ifs #check = {TRUE}
  &set #council {TRUE}
&endif

&ifs #check = {FALSE}
  &exitwolf
&endif

Ahh, you've gotten this far, you must be either Council member or a Controller of the bot. Very good, let's proceed and determine if you manage to ask for a valid list that this script is designed to deliver. Remember, quite a few commands used by this scipt is specific to FurBotSK, like the EXITWOLF and the below function ARRAY.  (See the WolfScript reference on what is available in FurBotSK.) For now, remembering that ARRAY uses a Zero based index into the string for splitting, the function acts like [WORD2] in this instance and returns the list we desire to view. But before we do that, we start by building our "hunter" string with a +, then we JOIN the list name, and follow it with another + sign. This is called "bounding", where you put specific terminators on either side of the search term so that it matches an exact match. Kind of like putting quotes around a search query on a search engine page.

// authorized, check for valid list
&newvar #list {+}
&join #list &ucase(&array(&getvar(message) { } 1))
&join #list {+}
&set #check &instr(1 {+ALL+PENDING+APPRENTICE+SHARED+COUNCIL+TANEEST+} #list)

&ifn #check = 0
  &whisper #whoasks {Invalid list: All, Member, Pending, Council,
Apprentice, Shared, Ban, Legend}
  &exitwolf
&endif

If we get this far, then it's a valid list, however, something which should be pointed out is that the above list is not complete, nor accurate to my bot, this is an example after all. Also, seeing as we may be doing other list functions with other chunks, this becomes a handy catching point to reply with the invalid list if one is looking for, say, the ban list. The ban is handled with a different function extirely for it access's a completely different database table, you just simply don't want your ban list mixed in with your member list.

&set #list &ucase(&array(&getvar(message) { } 1))
&ifs #list = {COUNCIL}
  &set #list {TANEEST}
&endif
&newvar #tag
&newvar #livename

&dbopen 1 {SELECT * FROM members ORDER BY ID}
&set #count &dbrecordcount(1)
&ifn #count > 0
  &dbmovelast 1
  &dbmovefirst 1
  &set #count &dbrecordcount(1)
  &for #index=1 to #count
    &set #tag {}
    &set #livename NULL
    &set #name &dbtostr(&dbf(1 ID))
    &set #check &dbf(1 member)

Here you have one record from the database, or rather the results from the query you made of the database. The thing to remember about database's and query's is that the query produces a sublist of the database, except in those instances where you constuct the query to get them all, as in this instance. This particular query could also be written as:

SELECT * FROM members WHERE

member='MEMBER'

OR member='APPRENTICE'
OR member='PENDING' ORDER BY ID

And you would get back just the results from the member types you're interested in. Now this particular function can also be written to produce three different sets of results, and join the three results into one reply, that is, you deliver first the member members, then pending, then apprentice's, it's all how you want the information to be returned to the user of the bot. In this instance, I wanted all the M.A.P. member types returned as a single list, sorted, without indicating who's who. Matter of fact, this example really no longer quite follows what is current working in the bot, this is supposed to remain simple enough to follow along. But as the above query shows, if you construct it right, when someone whispers the bot for the MEMBER MEMBER list, and you have a large number of names in the database of varying types, you can save a few steps in looping through the result set by restricting the query to strictly "WHERE member='MEMBER' " and will get back just a subsection of the database.

    &ifs #check = MEMBER
      &ifs #list = MEMBER
        &set #livename &dbtostr(#name)
      &endif
      &ifs #list = ALL
        &set #livename &dbtostr(#name)
        &set #tag {M}
      &endif
    &endif
    &ifs #check = APPRENTICE
      &ifs #list = APPRENTICE
        &set #livename &dbtostr(#name)
      &endif
      &ifs #list = ALL
        &set #livename &dbtostr(#name)
        &set #tag {A}
      &endif
    &endif
    &ifs #check = PENDING
      &ifs #list = PENDING
        &set #livename &dbtostr(#name)
      &endif
      &ifs #list = ALL
        &set #livename &dbtostr(#name)
        &set #tag {P}
      &endif
    &endif

Chopped some intermediate processing out here which does other checks on other variables about the members in the database, things like share, whether they get a custom greeting, and so on. If you paid attention to something above, I set the #LIVENAME variable to NULL as an indicator that the name did not match any of my criteria and should not be included in the results, hence if any of the checks match the bot user's query, the variable gets the name of the player in the database, and this next section adds it to the results variable. In addition to bumping my total.

    &ifs #livename <> NULL
      &join #result #livename
      &ifs #list = ALL
        &join #result {(}
        &join #result #tag
        &join #result {)}
      &endif
      &join #result { }
      &add #total 1
    &endif

Once we've made any possible additions to the results, we then need to bump the results pointer to the next record. If you take a bit of time and scroll back up, you will find that I did a &DBMOVELAST and &DBMOVEFIRST right before getting the number of records that the query returned.

CRITICAL NOTE: Unless you do that, you do not have a count of the number of results because the result set at this point can only indicate that it has more than ZERO results. Once you bump the results pointer to the bottom of the results, you then have a valid count to work with, however, failing to put the pointer back at the top will result in an error, and you get back garbage.

    &dbmovenext 1
  &endfor
  &set #result &replace(&rtrim(#result) { } {, })
  &join #result { - }
  &join #result #total
  &join #result { }
  &join #result &lcase(#list)
  &whisper #whoasks #result
&endif

And then we finally dress up the results by replacing the spaces in the string with a comma, then a space, appending the total number of results on the end, and whispering back the message to the user. I do hope that this helps you in understanding how database's are arranged and used by the bot.

Last Updated ( Jun 23, 2008 at 06:48 PM )
<Previous
header image