Author Topic: Learning about the TRPG code: Lesson 2  (Read 4520 times)

0 Members and 1 Guest are viewing this topic.

Hidama

  • Gnoll Fighter
  • **
  • Posts: 72
  • Reputation: +0/-0
Learning about the TRPG code: Lesson 2
« on: March 23, 2005 01:36 pm CST »
Note: I didn't mean for this lesson to be really long, but I had to explain for loops, and these string functions are just complicated. If you read along with what I say I hope it will explain these functions so that you can understand them. If you do read this, I'm sure you will be ready for any other functions in the tribes rpg code. Sorry it is so long.


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

Yay! time for the second lesson in trpg code. Now we're going to look at some basic string functions that had to be created for the game. Functions like String::getSubStr and String::findSubStr already existed in the tribes code, but new functions had to be made, and some had to be recreated. String functions are especially important for lines of code that are saved in the game, including item lines, item lists in a pack, and storage lines.

But what is a string? A string is just another form of saving information. Earlier, we did commands like

%x = 3;   or   %x = %y + 1;

which are stored as numbers basically. A string is a piece of text that usually isn't interpreted in any math command. You assign a string like this:

%x = "hihi";   or   %x = "What a stupid example";

If you were to echo these in another function, it would just say hihi or What a stupid example. It just has the quotation marks around it so that it is known as a string. If you did %x = hihi; it might say Hihi unknown command.

These functions just have a String:: on their name so that you know they work with strings. Let's look at an example of a function that works with strings.



Code: [Select]
function String::create(%c, %len)
{
dbecho($dbechoMode, "String::create(" @ %c @ ", " @ %len @ ")");

%f = "";
for(%i = 1; %i <= %len; %i++)
%f = %f @ %c;

return %f;
}

This function takes two inputs, %c and %len. %c is usually just a small word, or one character, and %len is the number of times it is repeated. Let's see what this function does.

First, %f is set to blank, or nothing. This is the empty string, just used at the beginning of the next string.

Next there is something called a for loop. I will explain what this does. A for loop, like an if statement, can have one line after it, or have { } brackets which contain many lines. This example contains one line (the %f = %f @ %c; line under it). In the for loop, %i is set to 1. It will enter the for loop if %i, 1, is less than or equal to %len, lets say we had %len as 5. 1 is less than 5, so it enters the for loop.

%f is set to itself (the empty string) combined with %c, lets say %c equals "c". The @ is for string concatenation, which combines two strings. So, %f is combined with %c, "" is combined with "c" to make "c" in this example.

The first loop of the for loop is done, so the command %i++ is done. What this means is that after the for loop has gone through, %i goes up by one. so now %i equals 2, and the middle segment of the for loop is executed again.

If %i, now 2, is less than %len which is 5, then the statement in the for loop is executed again (%f = %f @ %c;). It is, so %f = %f @ %c; is executed again.

But notice now that %f equals "c", so what this command does is appends %f to %c, "c" to "c", so we end up with "c" @ "c" which equals "cc".

The for loop adds 1 to %i again, now it is 3. The middle statement is executed again, 3 is less than 5, so the line under it is gone through again. %f is set to itself @ %c, which is %f @ %c, which is "cc" @ "c", which is "ccc".

This continues, %i is set to 4, %f is set to "cccc", %i is set to 5, %f is set to "ccccc", then %i is set to 6, and the middle statement is %i <= %len, 6 <= 5, is false, and so the for loop ends, with %f equal to "ccccc", five c's. %f is then returned. What this did is took our %c, which we had as "c", and made a string of 5 of them.

If you input String::create("la ", 7);, you'd have "la la la la la la la ".
If you input String::create("spam", 100);, you'd have a lot of spam.

There is only one example of the use of this code I know of, and it's in the PostAttackGraphBar, which I don't think any server uses. But it's good for an example.



//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

Here is another function that works with strings, it takes one input, %string, and has two for loops. Apparently JI recreated the function in order to make it faster.

Code: [Select]
//rewrote String::len from scratch, which is now approximately 6.5 times faster than the previous one i had from PSS.
function String::len(%string)
{
//dbecho($dbechoMode, "String::len(" @ %string @ ")");

%chunk = 10;
%length = 0;

for(%i = 0; String::getSubStr(%string, %i, 1) != ""; %i += %chunk)
%length += %chunk;
%length -= %chunk;

%checkstr = String::getSubStr(%string, %length, 99999);
for(%k = 0; String::getSubStr(%checkstr, %k, 1) != ""; %k++)
%length++;

if(%length == -%chunk)
%length = 0;

return %length;
}

This is the String::len function, which returns the length of the string entered. First, the chunk length is set to 10, and the current length is set to 0.

In the for loop, %i is set to 0 (%i is usually set to 0 or 1), and the next line is something you will encounter a lot in the middle of for loops:

String::getSubStr(%string, %i, 1) != "";
if     Some variable thing     is inequal to    ""

This means, as long as whatever getSubStr returns is not the empty string, or in other words the string exists, the for loop goes. It goes until there are no more strings left in a list. This type of line is used a lot, that and != -1, to test for existence of strings.

Anyways, that String::getSubStr function. It takes 3 inputs, here they are the string %string, the position %i, and 1. How the String::getSubStr function works is that you put in a string (here %string), and you give a position in the string (%i is the position), and the third parameter is the length of the substring you want returned (here it is 1).

So in this example, we have %string, %i is 0, and the third parameter is 1. This returns, from %string, a substring of it that starts at the 0th position and has a length of 1. So if you put in String::getSubStr("string", 0, 1); it returns "s", String::getSubStr("string", 0, 2); returns "st".

Basically, if a substring of %string at position %i with a character length of 1 character exists, then the for loops goes through. When it stops going through, the position %i is probably too far and there is nothing ahead in the string.

But anyways, the first character exists (like "s" from "string", using String::getSubStr(%string, %i, 1); with a 1 for the third parameter means a length of 1 which means 1 character), so the for loops goes through.

When the for loop goes through, %length is at first 0, and then the line
%length += %chunk;
is executed. This means that %length is set equal to   %length + %chunk. += means %length is set equal to itself plus %chunk, so it is increased by %chunk. So %chunk is 10, and %length is 0, so %length is set to 0 + 10 which is 10. Then at the end, %i is increased by %chunk also.

It continues to count 10 character chunks in the string, until there are no characters after, say, the 80th or 90th position in the string. The only way the for loop ends is if the position %i is past the actual length of the string, in which there is no character after it. This means %length, which increased right along with %i, is too big, and so after the for loop is done, it is decreased by %chunk, which makes the %length just a bit lower than the length of the string. The point is, %length now got all the 10's out of %string that it could, so the length of the string is at least say 80 or 90. And %length -= %chunk just does %length - %chunk, %length is decreased by %chunk.

%checkstr = String::getSubStr(%string, %length, 99999);
Now this is called, and what it tries to do is get a substring from %string, starting from %length (the highest multiple of 10), and gets a substring of length 99999 that starts from the position %length. It doesn't actually return a string of length 99999, but this is just here to say that the substring returned can be any length, no matter how big. This is used a lot in String::getSubStr, which is used to get the remaining part from a string that starts at %length. Doing String::getSubStr(%string, 0, 99999); returns the whole string.

Anyways, if there are any more characters after %length (in other words, the string is not say, 60, 70, 80, or 90 characters long), then %checkstr is set to those characters (like if %string has 93 characters, %checkstr would be set equal to the last 3 characters).

The next for loop goes through if %checkstr has any characters, if %checkstr exists, namely if the amount of characters in %string is not a multiple of 10. This means other characters, maybe 3, 5, 6, or 9 more have to be accounted for, and this for loop determines their length.

The for loop goes through just like the other one, except that %length++ and %k++ are used instead. These mean that 1 is added to %length and %k, %length and %k are increased by 1. In this for loop, it is going by chunks of 1 instead of 10, so when the for loop fails, it cannot find a character (a string of length 1) anymore after a given length, and that is the length of the whole string.

The last part is only if the length of the string is 0 (the empty string ""). In this case, the %length starts out at 0, and never enters the for loop because the first substring of length 1 does not exist, so %length is never increased. Then %length is decreased by %chunk, to be -10. This last part says that if %length is negative, then the length must be 0. In actuality, Jeremy Irons could have just put

if (String::getSubStr(%string, 0, 1) == "")
return 0;

at the beginning. Either way works.

Anyways, this function just returns the string length. It is faster because it counts quickly in 10 length chunks, and then when it gets all the tens out of a string, it counts how many ones are left in it. This requires a lot less String::getSubStr functions than if you just counted by one (a string of length 93 would require 94 String::getSubStr calls in this case, but in this function there are at first 10 calls counting by 10, then 4 calls counting by 1, making for just 14).

This is a good use of String::getSubStr to find out how long a string is. However, in this next example, we are finding out why it has its flaws.



//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------


Code: [Select]
//$tst = "I am typing a whole bunch of bull$#!& on this screen so I can fix this stupid bug concerning the storage. The string::getsubstr function can only get two-hundred fifty five (255) characters from a string, so whenever this function was performed on the storage stuff string, alot of info would get lost. Players were actually capable of spawning items that aren't normally supposed to be spawned, like the Deployable Base for example. This is a big problem, but with this NEWgetSubStr function that I wrote, which splits up strings into chunks of 255 in order to get the string portion properly, the storage bug should go away and there should be a hell of a lot less cheating.";
function String::NEWgetSubStr(%s, %x, %y)
{
dbecho($dbechoMode, "String::NEWgetSubStr(" @ %s @ ", " @ %x @ ", " @ %y @ ")");

%len = %y;
%chunks = floor(%len / 255) + 1;

%q = %len;
%nx = %x;
%final = "";

for(%i = 1; %i <= %chunks; %i++)
{
%q = %q - 255;
if(%q <= 0)
%chunkLen = %q+255;
else
%chunkLen = 255;

%final = %final @ String::getSubStr(%s, %nx, %chunkLen);
%nx = %nx + %chunkLen;
}

return %final;
}

Ah, the String::NEWgetSubStr function. As the beginning statement says, String::getSubStr can only give you the first 255 characters of the substring you want. The problem is, storage strings are a lot longer, and an item name can be cut off. A lot of information would get lost as well, and you could have an item that is a fragment of an item's name. I guess Tribes never needed to get a substring longer than 255 characters, but the rpg mod does.

That being said, let's look at this function. It takes input string %s, just like String::getSubStr, and it takes position %x, just like %i in String::len, and it takes length %y, which is just like the length of 1 in String::getSubStr that we seen in String::len.

%len is set to the length %y of the substring, and %chunks is set to how many 255 length chunks there are in %len (the length of the substring we want). Oh! here's a use of the floor function! You take %len and divide it by 255 to see how many chunks of 255 there are in %len. Let's say %len is 2559, so 2559 / 255 is 10.something since 255 goes into 2550. The floor of 10.something is 10, and then 1 is added to it. 1 is added to it because it accounts for the extra characters (in this example, 9). So %chunks is equal to the amount of chunks of length 255 in %len, + 1, since it adds an extra chunk for the last characters of the string.

%q is set to %len, since %q is going to be worked upon in the for loop. %nx is set to the position %x, and %final, the string to be returned, is set to "". Then the for loop goes through, %i is set to 1, for the 1st chunk of length 255, and continues until the 11th chunk, which is the one of length 9.

The unit string length 255 is taken away from %q, and then an if else statement is made. Ignore the if for now, it happens at the last loop of the for loop. %q is not negative, so %chunkLen is set equal to 255. Then, since %final equals "", %final is set equal to just the String::getSubStr function. It takes from string %s, at position %nx, a substring of length %chunkLen (255). This is the first 255 characters of the string %s starting at position %nx. Then %nx is set equal to itself plus %chunkLen, which is 255. So now, %nx is the position just ahead of the substring we made %final equal to. This is important, because we keep getting substrings of length 255 and concatenating them next to each other.

On the second run of the for loop,  %i is 2, for the second chunk of length 255. %q is made 255 less, and %final is concatenated with the next 255 characters, since %nx starts at 255 characters after the original %x. This is done every time the for loop is gone through. A length of 255 is subtracted from %q every time a substring of length 255 is concatenated to %final, and 255 is added to %nx.

This is done until %i is 11, for the 11th chunk. By now, %q is 9, and %nx is 2550 more than %x. %final contains 2550 of the 2559 characters. %q is made 255 less than it is was, which is negative, and so the if statement is true, and %chunkLen is equal to %q + 255 (which is 9). Then a substring is added to %final, from position %x + 2550 (which is %nx), of length 9.

%i is set to 12, which is higher than %chunks which is 11, and the for loop ends. %final is returned, which is all of the 2559 characters we wanted. String::NEWgetSubStr just returns, from %s, a substring that starts at %x and is %y characters long. This has input and output just like the String::getSubStr function, but makes sure that all of the characters are returned.

String::NEWgetSubStr uses String::getSubStr calls in order to accomplish its task. It is just a way of getting around the error of String::getSubStr by using a series of it's calls, this is what String::NEWgetSubStr is.

In normal tribes, 255 characters was the maximum length of what could be returned by the getSubString function because only a certain amount of space is set aside for it, 256 is 2^8, or 2 times itself 8 times, which is a common unit of space in computers. 2^9 is 512, which is sometimes seen, and 2^10 is 1024, which is the actual size of a kilobyte (not 1000 bytes). They just wanted to only set aside so much space for this, and the people who created tribes figured that they would never have a string 255 characters long to be returned from getSubString. This is what I am thinking, at least.


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

Whew! That was something. Now to look at a use of this String::NEWgetSubStr function.


Code: [Select]
function String::ofindSubStr(%s, %f, %o)
{
dbecho($dbechoMode, "String::ofindSubStr(" @ %s @ ", " @ %f @ ", " @ %o @ ")");

%ns = String::NEWgetSubStr(%s, %o, 99999);
return String::findSubStr(%ns, %f);
}

This function is very simple, it just takes three inputs, %s the string, %f a small string, and %o, a position to start at. I should explain the String::findSubStr function first. It works just like the String::getSubStr function, except that it returns the position just before the substring. String::getSubStr will need a string %s, a position %x, and a length %y, to return a substring of %s starting at position %x of length %y.

String::findSubStr just needs a string %s and a smaller string %f. If it find this string %f in %s, it returns it's position (if you did String::findSubStr("this is long","long"); it would find the string "long" in "this is long" and return the position, which is 9).

This function starts out by assigning %ns to what is returned by String::NEWgetSubStr(%s, %o, 99999); Here is that 99999 again, indicating that it wants the string returned to be the last part, all the way to the end, regardless of how long it is. It takes from %s a substring starting at %o until the end of the string. So %ns is just the end of the string, where it starts is specified by %o.

What it returns is what String::findSubStr(%ns, %f); returns. This will find the position of the string %f in %ns. So what this returns is where it finds %f in the later part of the string %s, specified to start at %o.

This function is just a use of the String::findSubStr function, just like String::NEWgetSubStr, it uses the original function to do something else. This function just finds a string and returns it's position, just like String::findSubStr, but after the point %o. So if you wanted to find a string, say "mode" in a string "mode say mode run mode fire" but you already got past "mode say" in some other part of a function, you can do String::ofindSubStr("mode say mode run mode fire", "mode", 9); or if you have %x = "mode say mode run mode fire" and %y = "mode", you can do String::ofindSubStr(%x, %y, 9);

One thing to note about this function, it uses String::NEWgetSubStr, not String::getSubStr, this is because it needs to returns a whole actual string, not just see if there are any characters left.


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

Now a bit more complicated use of the String::NEWgetSubStr function.


Code: [Select]
function String::replace(%string, %search, %replace)
{
dbecho($dbechoMode, "String::replace(" @ %string @ ", " @ %search @ ", " @ %replace @ ")");

%loc = String::findSubStr(%string, %search);

if(%loc != -1)
{
%ls = String::len(%search);

%part1 = String::NEWgetSubStr(%string, 0, %loc);
%part2 = String::NEWgetSubStr(%string, %loc + %ls, 99999);

%string = %part1 @ %replace @ %part2;
}

return %string;
}


This function seeks to replace a substring in a string with something else. It takes 3 inputs, %string, the big string, %search, a smaller string to be searched for, and %replace, the string to replace %search with.

First, the location of the string %search is found in %string, and set to %loc. Then, if %loc is not equal to -1, that is, if %loc exists, and %search is in %string, then the rest of the function goes through, otherwise %string itself is just returned, unreplaced. %ls is set to the length of the string %search.

%part1 is the beginning part of the string, before %search. String::NEWgetSubStr is used here because the actual substring returned is needed, and can be many characters long. It returns a substring of %string, from position 0 (the beginning), to %loc, the beginning of the string %search. Then %part2 is set to the substring of %string between %loc + %ls and 99999, so it means the string starting at %loc + %ls, which is the position where it found %search + the length of %search, until the end of the string. So %part2 is the substring of %string that is after %search. %part1 and %part2 do not include %search, so they are the substrings before and after %search.

%string is then set to the concatenation of %part1, %replace, and %part2. %search is replaced with %replace.



Wow, that was long. Sorry I went through those in such detail, but if I didn't you might only half understand them, like I did. Think about the function calls such as

%ns = String::NEWgetSubStr(%s, %o, 99999); and

%part2 = String::NEWgetSubStr(%string, %loc + %ls, 99999);

tell me what is bad with using 99999 for the String::NEWgetSubStr function (something happens in the actual function String::NEWgetSubStr), and how it could be fixed in the String::NEWgetSubStr function.
« Last Edit: December 31, 1969 06:00 pm CST by Hidama »
for all of you who say I am nice, thank you thank you thank you :) :)

Lidge Farkley

  • Uber Menace
  • *******
  • Posts: 1,357
  • Reputation: +2/-3
    • http://www.angelfire.com/ca2/psychosworld2/
(No subject)
« Reply #1 on: March 24, 2005 07:24 pm CST »
Hidama... have you visited the Clan Orb forums/website?  They may be interested in your documentation as well.  I know I had started to give them some stuff... but that tapered off when life got demanding.  I have since not done a thing with it... and haven't visited them in far too long.  I don't know if they're still in to TRPG modding, but it's worth it just to pass along the info to you/them.  Peace.
Link: http://www.clanorb.com/forums/
« Last Edit: December 31, 1969 06:00 pm CST by Lidge Farkley »
Lend your heart unto the divine mineral TOPAZ;
from which our reverent hearts and minds sprang.
Also Known As:  Alcoholic 007
My Page of tribes Tools and Helpful "FAQ" Stuff

Kyrie

  • Orb Member
  • Uber Menace
  • ***
  • Posts: 1,014
  • Reputation: +5/-4
(No subject)
« Reply #2 on: March 24, 2005 07:32 pm CST »
I'm sure that there are a couple there that are still interested in trpg modding. We may have mostly moved beyond that in to WoW, though. gl and nice tutorial.
« Last Edit: December 31, 1969 06:00 pm CST by Kyrie »







Lidge Farkley

  • Uber Menace
  • *******
  • Posts: 1,357
  • Reputation: +2/-3
    • http://www.angelfire.com/ca2/psychosworld2/
(No subject)
« Reply #3 on: March 25, 2005 01:32 am CST »
Cool. :-)  I don't know if you remember me stopping by there... I think my user name there is "Alcoholic007" Kyrie.

Peace, and thanks for the support!
« Last Edit: December 31, 1969 06:00 pm CST by Lidge Farkley »
Lend your heart unto the divine mineral TOPAZ;
from which our reverent hearts and minds sprang.
Also Known As:  Alcoholic 007
My Page of tribes Tools and Helpful "FAQ" Stuff

Hidama

  • Gnoll Fighter
  • **
  • Posts: 72
  • Reputation: +0/-0
(No subject)
« Reply #4 on: March 25, 2005 10:48 am CST »
Wow, you mean, people actually read this? I didn't think anyone would, because it's so long. I don't really wanna post this on clanorb, this is just for a lot of people who read the pcrpg forums and just want to know about how the scripts work and stuff. Sorry, but I just wanna post here for now. Thanks for telling me that idea though.

lol lidge, alcoholic007 :)
« Last Edit: December 31, 1969 06:00 pm CST by Hidama »
for all of you who say I am nice, thank you thank you thank you :) :)

Kyrie

  • Orb Member
  • Uber Menace
  • ***
  • Posts: 1,014
  • Reputation: +5/-4
(No subject)
« Reply #5 on: March 25, 2005 11:32 am CST »
http://www.clanorb.com/forums/viewforum.php?f=19

A few threads dealing with TRPG specifically, and a few dealing with Tribes in general.
« Last Edit: December 31, 1969 06:00 pm CST by Kyrie »







Hidama

  • Gnoll Fighter
  • **
  • Posts: 72
  • Reputation: +0/-0
(No subject)
« Reply #6 on: March 25, 2005 11:36 am CST »
:) There was a nice tutorial on terrains. thanks though :)
« Last Edit: December 31, 1969 06:00 pm CST by Hidama »
for all of you who say I am nice, thank you thank you thank you :) :)

Lidge Farkley

  • Uber Menace
  • *******
  • Posts: 1,357
  • Reputation: +2/-3
    • http://www.angelfire.com/ca2/psychosworld2/
(No subject)
« Reply #7 on: March 26, 2005 06:41 pm CST »
I was going to make an updated version of my TRPG FAQ but I have time and dedication issues in my life..
;-p

I think I let Lucid down a bit with that.  I should finish it... but I want to rework the TRPG code itself in so many ways that I am not sure it is worth it at the current time.  My help pages were mod specific, not as generally helpful as your information.

Peace.
« Last Edit: December 31, 1969 06:00 pm CST by Lidge Farkley »
Lend your heart unto the divine mineral TOPAZ;
from which our reverent hearts and minds sprang.
Also Known As:  Alcoholic 007
My Page of tribes Tools and Helpful "FAQ" Stuff