Difference between revisions of "Chapter 5"

From SphereWiki
Jump to: navigation, search
Line 223: Line 223:
  
 
Unlike TAGs, CTAGs and VARs, LOCALs ''do not'' have a LOCAL0 equivalent. This is because LOCALs will always return 0 when they empty (and so, they can ''never'' be blank/empty).
 
Unlike TAGs, CTAGs and VARs, LOCALs ''do not'' have a LOCAL0 equivalent. This is because LOCALs will always return 0 when they empty (and so, they can ''never'' be blank/empty).
 +
 +
 +
==Floats==
 +
This is the most simple. Since you know many variables at this point and know how to use them. FLOATs are almost the same as LOCALs, just a difference. LOCALs store only text or entire numbers (34 or 12), while FLOATs stores decimals (23.1 or 45.3). Another difference is the EVAL here is changed to FLOATVAL. This is one example of FLOAT used to calculate hit speed:
 +
 +
 +
<tt><font color="darkblue">[EVENTS e_test]<br />
 +
ON=@HitTry<br />
 +
:FLOAT.FSPEED = &lt;FLOATVAL &lt;SERV.SPEEDSCALEFACTOR&gt; / ((&lt;DEX&gt; + 100) * &lt;ARGO.SPEED&gt; + 1)&gt;<br />
 +
:ARGN1 = &lt;FLOAT.FSPEED&gt;<br /></font></tt>

Revision as of 13:41, 1 June 2009

(incomplete)

Tags

All these things you have learned so far seem rather restrictive don't you think? Well, I personally don't think they are very restrictive and I was able to script most things that people are scripting today in about version .40. But think about it. Items are restricted to MORE, MORE2, etc. Those poor characters only have PLOT2 to store stuff in before you have to start resorting to storing information on the variables of their backpack.


So SPHERE developers gave us a long-awaited feature:


The TAG.


Important TAG principle number one, even before you know how to use them:


ALL TAGS ARE STRINGS. PERIOD.


They are also just about the simplest part of SPHERE you will ever use. Here is an example of a tag:


SRC.TAG.JOE = 1


What did we just do? We just CREATED a variable on the SRC of this script. This variable is named TAG.JOE and has a value of 01. (Keep in mind that is the string 01, not the number 01.) It will be saved with the character and we can put ANYTHING WE WANT into it.


How's that for powerful?


Here are some more examples of TAGs:


ON=@DClick

SRC.TAG.CLICKS += 1
RETURN 1


ON=@Equip

SRC.TAG.GOOFYTAG = This is a really stupid tag.
SRC.SYSMESSAGE <SRC.TAG.GOOFYTAG> // Will see "This a really stupid tag."
RETURN 0 // Allow them to equip


ON=@UnEquip

SRC.TAG.GOOFYTAG = // remove the tag
RETURN 0 // Allow them to unequip


In those three examples, you have the three ways you can use a TAG.

  1. A TAG can store a number as in the first example. Unfortunately, it stores that number as a string, so we must use EVAL every time we want to use that number.
  2. A TAG can store a string, as in the second example. Actually TAGs always store strings, but this one is obviously a string.
  3. You can delete a TAG. We do this by typing the name of the tag and then an equal sign with nothing after it. Why would we ever want to delete a TAG? Well, TAGs, like everything else, use memory. The more memory you use, the more lag your server has.


TAG principle number two:


ALWAYS DELETE A TAG YOU ARE FINISHED USING.


You may not be finished using a TAG at the end of a script. Or even when the server shuts down. In fact, there are some TAGs you'll want to stay on the character forever. However, if you finish using a TAG for any reason, DELETE IT. It conserves memory and is good scripting practice in general.


Here is another important TAG principle. While the TAG is a very powerful feature, it has its limits. A TAG can ONLY be used on the following objects:

  1. Characters.
  2. Items.
  3. Regions. Yes, regions can have TAGs.


It's very hard to give examples of the use of TAGs without going into a complex system. Most complex systems will use two, three, or more PERMANENT tags. For example, a system involving experience points might store numbers in TAG.CURRENT_EXPERIENCE_POINTS and TAG.CURRENT_LEVEL. You'll find a good example of when to use TAGs to your advantage in chapters from now on, as I present more and more complex scripts. BTW, when you're dealing with tags, sometimes you need to check if a tag exists or if it has a value. If it doesn't exist SPHERE gives a stupid error on the console. To avoid that, we make TAG's default to 0 by using TAG0 instead of TAG if the tag doesn't exist. If you want to you can always use TAG0 instead of TAG to be safe. Say you write this line of code:


MORE = <EVAL <TAG.JOE>>


If TAG.JOE contains no value (or hasn't been defined yet), you will get an error on the console that says something like this: Undefined value ' '. To complicate matters, the value of MORE will not change, which will severely screw up your script. To prevent this, use the following method:


MORE = <EVAL <TAG0.JOE>>


In this case we have used TAG0 to access the TAG value. Accessing the TAG in this manner will return the value as normal, except for when TAG.JOE is undefined a "0" will be returned rather than a script error being raised.


The same trick can also be used when setting the value of a TAG. For example:


TAG0.JOE = <MORE>


As you may expect, this sets the value of TAG.JOE to whatever value is held in MORE. The difference however is that because we have used TAG0 when setting the value, if the value of MORE is zero then TAG.JOE will actually be cleared! This may initially sound undesirable but it offers the benefit of reducing the number of TAGs stored on the object. Since we can use TAG0 to retrieve a value of zero when a tag doesn't exist then you may be wasting memory by storing a large number of TAGs all with a value of zero. Of course if you do decide to use TAG0 when setting the value of a TAG then you should ensure that you also use TAG0 when reading that value back, or else you will quickly run into the aforementioned "Undefined value" script error.


CTags

CTAGs are temporary versions of TAGs that are only available with objects (i.e. online player characters). CTAGs are not saved and will be cleared when the player logs out. This means that you don't have to worry about removing the tag after using it, assuming the player logs out one day :). You can use CTAG0 too, used just the same as you can with TAG0. In short, if you are going to use tags that will no longer be needed after logging out, it is probably a good idea to consider using a CTAG.


Note: CTAG can only be used with online players. Attempting to read from or write to a CTAG on a logged out player will raise a script error.


Useful TAG/CTAG Functions

CLEARTAGS Removes all TAGs on an object, eg SRC.CLEARTAGS. Be careful with this as once the tag is gone there is no way to get it back.
CTAGLIST Displays a list of tags on a client to SRC.
CTAGLIST LOG Displays a list of tags on a client to the Sphere console (but not into logfile).
TAGAT.x.KEY Returns the name of the TAG at position x. (the first TAG is at position 0)
TAGAT.x.VALUE Returns the value of the TAG at position x. (the first TAG is at position 0)
TAGCOUNT This function returns the number of TAGs on an object.
TAGLIST Displays a list of tags on an object to SRC.
TAGLIST LOG Displays a list of tags on an object to the Sphere console (but not into logfile).


Vars

Perhaps you're wondering if there is a less memory-consuming method. Of course you were, don't deny it.


And here I present it to you:


VAR.CHEESE = 1


Important VAR principles:

  1. Like TAGs, VARs are always stored as strings.
  2. Unlike TAG, VARs are not attached to any particular object. You never EVER use [obj].VAR.BLAH.
  3. VAR variables are GLOBAL, meaning they can be accessed from any script.
  4. Never assume a VAR has a specific value stored at the beginning of an event, especially if the same VAR is used in multiple scripts.
  5. Like TAGs, VARs can have any name. VAR.CHEESE, VAR.BLAH, VAR.WORLD_TIME, VAR.HELLO_WORLD
  6. If you don't need a value to be permanent, but need a place to store it temporarily during a script, use LOCAL, not TAG, not VAR.


VARs are global TAGs. That's about it.


If you want to get list of all VARs on your server type (into client or console): SERV.VARLIST, and if you want to log them into console write SERV.VARLIST LOG (this will not be saved into logfile).


If you want to remove all server variables (VARs) type SERV.CLEARVARS.


And that's your entire lesson on the VAR feature. I told you it would be short. As with TAG0 and CTAG0, you can also do VAR0. It works just like TAG0 or CTAG0 does. If that variable has no value then VAR0 will return 0 instead of nothing.


Locals

LOCALs are like VARs except they are only accessible within the script block they are defined in (i.e. a function or trigger) and then they are immediately cleared. The advantage is that they are much faster than VARs and you also don't have to worry about different scripts interfering with each other.


The following script demonstrates why you may want to use a LOCAL rather than a VAR:


[FUNCTION f_var_joe]
VAR.NAME = Joe
F_VAR_BOB
SYSMESSAGE <VAR.NAME>
RETURN

[FUNCTION f_var_bob]
VAR.NAME = Bob
SYSMESSAGE <VAR.NAME>
RETURN


The idea with the two functions above is that F_VAR_JOE will show the message "Joe" and F_VAR_BOB will show the message "Bob". However, if you were to go ingame and type .F_VAR_JOE, you would receive two messages saying "Bob". Why is this?


Well, if you look closely at F_VAR_JOE you will see that after setting VAR.NAME to Joe, it then executes the function F_VAR_BOB and inside F_VAR_BOB we then set VAR.NAME to Bob. Because VARs are global variables, this inadvertently affects the behaviour of F_VAR_JOE and we don't get the output that we were after. Another flaw you may have not spotted with this script is that we haven't cleared VAR.NAME before the script ends and so Sphere still has VAR.NAME stored in memory (which in this particular case is a waste of resources as we have no further use for VAR.NAME).


In this particular scenario we could modify the functions to use different VAR names but unless we intend to manually check every script on the server we could easily end up using a VAR that another script is using and prevent that from working instead.


This is where the LOCAL comes in to play, see the following example:


[FUNCTION f_local_joe]
LOCAL.NAME = Joe
F_LOCAL_BOB
SYSMESSAGE <LOCAL.NAME>
RETURN

[FUNCTION f_local_bob]
LOCAL.NAME = Bob
SYSMESSAGE <LOCAL.NAME>
RETURN


The above functions are identical to the previous ones, except they use LOCAL instead of VAR. This time when you type .F_LOCAL_JOE ingame you will receive "Joe" and "Bob" messages as we originally intended.


This is because the LOCALs only exist within the functions that define them. When F_LOCAL_BOB attempted to use LOCAL.NAME it received its own version of the variable that doesn't interfere with the one defined in F_LOCAL_JOE. When F_LOCAL_BOB returns, F_LOCAL_JOE still has its original LOCAL.NAME with "Joe" still stored inside it.


Of course there may come a time where you do want to share LOCALs with another function, and this can be accomplished by using the CALL command. When you use the CALL command to run a function instead of running the function directly the LOCALs are shared between both scripts, for example:


[FUNCTION f_bla]
LOCAL.DUDE = Bob
RETURN

[FUNCTION f_bleep]
CALL F_BLA
NAME = <LOCAL.DUDE>
RETURN


When we run the F_BLEEP function above, the CALL line allows LOCAL.DUDE to be set in F_BLA and be accessible to F_BLEEP afterwards. Therefore, the NAME = <LOCAL.DUDE> line will set the name of the object to whatever the F_BLA function set LOCAL.DUDE to (in this case "Bob").


Unlike TAGs, CTAGs and VARs, LOCALs do not have a LOCAL0 equivalent. This is because LOCALs will always return 0 when they empty (and so, they can never be blank/empty).


Floats

This is the most simple. Since you know many variables at this point and know how to use them. FLOATs are almost the same as LOCALs, just a difference. LOCALs store only text or entire numbers (34 or 12), while FLOATs stores decimals (23.1 or 45.3). Another difference is the EVAL here is changed to FLOATVAL. This is one example of FLOAT used to calculate hit speed:


[EVENTS e_test]
ON=@HitTry

FLOAT.FSPEED = <FLOATVAL <SERV.SPEEDSCALEFACTOR> / ((<DEX> + 100) * <ARGO.SPEED> + 1)>
ARGN1 = <FLOAT.FSPEED>