Hello there! My name is hidama, and I've started this post (the first in a series of posts) in order to help people understand the tribes rpg code. I'm not sure if I should put this in Assistance or Development, so I was told to just put it in general discussion for now, and ask for it to be moved to where it is supposed to be after. Sorry it is so long, but I needed to show people who are new to coding just how it works. If I do another lesson, it won't be so long.
Before we get started, I feel there is some need to introduce some basic functions to everyone reading this, since even people who have played this mod for a long time and know the code somewhat well do not know what the functions floor or cap are.
Once we get going, we'll start looking at some more advanced code, and eventually learn things like how spells work, the basics of mining, and how a player or bot is damaged.
For our first trip into trpg code, we're going to visit rpgfunk.cs, a file found in scripts.vol (in the Tribes\RPG folder). You can open rpgfunk.cs or any .cs file with notepad, and you can extract the contents of scripts.vol with volumer (available at particle's site- thank you so much!).
rpgfunk.cs contains many internal functions in the tribes rpg code, functions that are called often (string and saveworld functions), and functions that just don't have any place anywhere else.
We're going to look at a few basic functions in rpgfunk.cs, the first of which being a simple one in which I can describe some basic coding styles to you. I'll go over a few more functions, then show the function that determines the LCK cost.
function OddsAre(%n)
{
dbecho($dbechoMode, "OddsAre(" @ %n @ ")");
%a = floor(getRandom() * %n);
if(%a == %n-1)
return True;
else
return False;
}
I am going to explain this code piece by piece. The first part "function OddsAre(%n)" tells the code that it is starting a new function called OddsAre, which takes an input %n (which is really any number in this function).
You could call this function from within some other code by placing "OddsAre(8);" in that code (that is an actual example from the trpg code).
Let's say we do call it with OddsAre(8);
The function is contained within the brackets { } so the first line that is processed is the dbecho line. This is just for if you are hosting a server I think, so don't worry about it.
The next line is %a = floor(getRandom() * %n);
First off, %n is interpreted as 8, and getRandom() will return a number between 0 and 1 (well, getRandom() never returns 1, but a number just slightly under it at most).
When this random number is multiplied times %n (8), it gives a number between 0 and 8, but not 8 itself.
Then the floor() function is called. What floor does is cut the decimal points off of a number, always rounding down.
floor(8.4); returns 8, floor(0.5); returns 0, floor(7.9999); returns 7.
Let's say getRandom() * %n gives 7.9 (or anything above 7.0) so that the floor function returns 7.
%a is set to the number 7, so %a equals 7 (doing %a = something; assigns %a a value of 7).
The next line is an if statement, it will test whether something is true or not. If whatever is tested inside parentheses is true, then it executes the line below it, if it is false, then the line below the else is executed.
This if statement tests if %a is equal to %n - 1 (it says %a == %n-1 because == tests equality).
If %a is equal to %n - 1, then it returns true, and the line of code below it is executed.
We had %a equals 7, and %n is 8, so %n - 1 equals 8 - 1 which is 7. So the line "return True;" is executed. This means the function returns "true" to "OddsAre(8);". So if you do %t = OddsAre(8); it would set %t equal to "true" in this case.
If %a is not equal to 7, say 6 or 0, then the if statement returns false, and the line of code below the else is executed, which returns "false".
The point of this function is, on average 1/8 of the time %a equals 7, and 7/8 of the time it equals any number from 0 through 6. So only 1/8 of the time it returns true.
The next function we are looking at is the round(); function, which takes a number and rounds it.
function round(%n)
{
// dbecho($dbechoMode, "round(" @ %n @ ")");
if(%n < 0)
{
%t = -1;
%n = -%n;
}
else if(%n >= 0)
%t = 1;
%f = floor(%n);
%a = %n - %f;
if(%a < 0.5)
%b = 0;
else if(%a >= 0.5)
%b = 1;
return (%f + %b) * %t;
}
This function takes an input (number), just like OddsAre. Notice the // at the beginning of the first line. This makes the line a comment, so the dbecho isn't called.
First, an if statement is used to test if your number was negative (%n < 0), if it is below 0. If so, %t is set to -1, and %n is set to the negative of itself (which will make it positive).
If %n is more than or equal to zero, the else if returns true and %t is set to 1, %n stays the same.
%f is set to the floor of %n (%n with the decimal points taken out of it), and then %a is set to the original number %n minus the floored number %f. This makes %a the decimal points of %n without the whole number. This is used to determine if %n was 8.5, 8.4, 8.8, etc. by making %a equal to 0.5, 0.4, 0.8, etc. and then testing it using the if statements.
The next statement tests if %a (the decimal portion of %n) is less than 0.5. If it is, then %b is set equal to 0, which means rounding down.
If %a is not less than 0.5, then it is equal to 0.5 or more than 0.5, in which case, %b is set to 1.0 (rounding up).
Then %f (the whole number) plus %b (either 0 or 1, rounding up or down) is returned, times %t, which will keep the number negative if it is negative.
So round(8.4); returns 8, round(8.5); return 9, round(8.999); returns 9, and round(-8.5); returns -9.0.
Now to the cap function, which is very important. The input is %n, any number, a lower bound %lb and an upper bound %ub.
This function will return %n if it is between the lower bound and upper bound, return the lower bound if %n is lower than it, and return the upper bound if %n is higher than it.
function Cap(%n, %lb, %ub)
{
dbecho($dbechoMode, "Cap(" @ %n @ ", " @ %lb @ ", " @ %ub @ ")");
if(%lb != "inf")
{
if(%n < %lb)
%n = %lb;
}
if(%ub != "inf")
{
if(%n > %ub)
%n = %ub;
}
return %n;
}
At first, a test is done to see if the lower bound is input as "inf". if %lb is "inf", then the lower bound is infinitely low, and %n can be very low without any problems.
If %lb is not inf, then a test is done to see if %n is lower than the lower bound, if so, %n is set equal to the lower bound, and the lower bound is returned.
If the upper bound is inf, then a number can be infinitely large without any problems.
If the upper bound is not inf, then a test is done to see if %n is larger than the upper bound. If it is, then %n is set equal to the upper bound.
%n is then returned, if it was too high then the upper bound is returned, if it is too low then the lower bound is returned.
Often, a lower bound of 1 is set so that numbers do not get too low.
Cap(5, 0, 10); will return 5 since it is between 0 and 10, Cap(5, 0, 3); will return 3, since 5 is above 3, and Cap(0.3333, 1, inf); will return 1, since 0.3333 is below 1.
Cap(any number, inf, inf); is completely useless, since it returns the number. Cap(10000, 0, inf); will return 10000, since the number can be infinitely high. Cap(-5, inf, 10); will return -5, since the number can be infinitely low.
Here is a fun function I just wanted to introduce. It takes a number and makes it not have such long decimals, partly by rounding.
function FixDecimals(%c)
{
dbecho($dbechoMode, "FixDecimals(" @ %c @ ")");
%d = round(%c * 10);
%m = (%d / 10) * 1.000001;
return %m;
}
This takes a number %c (lets say, 0.49999), multiplies it by 10, and then rounds it.
%d is set to this number (0.49999 * 10 is 4.9999, then rounding it 5.0).
%m is set to %d divided by 10 (5.0 / 10 equals 0.5) then multiplied by 1.000001 (to get any long decimals out of it).
So this returns 0.5 if you input 0.49999. It takes all of the long decimal points out of there except for the first one.
Alright, now that we're done with this lesson, lets look at a use of it.
Ah, the GetLCKcost function, also in rpgfunk.cs, this function determines the LCK cost based upon how many you already have.
function GetLCKcost(%clientId)
{
dbecho($dbechoMode, "GetLCKcost(" @ %clientId @ ")");
%a = floor( pow(2, Cap(fetchData(%clientId, "LCK"), 0, 26)) * 15 ) + 100;
return Cap(%a, 0, "inf");
}
The input is %clientId, a number (usually above 2048) that is assigned to each player and bot.
The line of code that determines lck cost is a long one, lets take this from the middle of the line out.
fetchdata(%clientId, "LCK") is called, I won't tell you what this is now, but fetchdata just returns how much LCK you have.
The Cap function makes sure that if you have less than 0 lck (I don't know how), then the cost is determined like you have 0 LCK, and if you have more than 26 LCK, the cost is determined like you have 26 LCK.
Then the pow function is called, this just raises 2 to the power of the next number, which is pretty much your LCK amount. so pow(2, 0); returns 2^0 = 1, pow(2, 1); returns 2^1 = 2, and pow(2, 2); returns 2 squared (2^2) = 4.
Then the number is multiplied by 15. It is floored so taht any decimals are not there, and then 100 is added to it.
The returned number (cost) cannot be less than 0, but can be infinitely high.
If you have 0 LCK, the first LCK cost is 2^0 = 1, times 15 = 15, plus 100 = 115.
The second LCK cost is 2^1 = 2, times 15 = 30, plus 100 = 130.
The third is LCK cost is 160, the fourth is 220, the fifth is 340, the sixth is 580, and so on.
The highest lck can cost is when you have 26 LCK, from which you calculate (2^26 * 15 + 100) is 1,006,633,060 coins for the 27th LCK point. Needless to say, people only have over this much LCK from quests.
Well, that concludes this class. Next time we will go over some basic string functions in rpgfunk.cs
I promise the next lesson won't be so long! bye bye