Reign of the Undead - Revolution

Full Version: How RotU works
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello Zombie-Community.

I got many requests from modders and scripters, how the RotU mod works. In the following lines I will explain as short as possible how I made the mod working like that.

Everything is based on the Quake 3 Engine.
First of all I had to patch some .exe and .dll files to protect the server of being flooded or crashed (If you want the fixed files please feel free to contact me via PM or E-Mail).

The mod itself is based on kilometers of C++ codes. It took me quiet a long time to write about 15.000 lines of code.

Now how it is coded....
Every map has around 300 waypoints. Every waypoint is connected to all other waypoints in range. So I get a list of waypoints which looks like this:

Code:
main()
{
    level.waypoints = [];

    level.waypoints[0] = spawnstruct();
    level.waypoints[0].origin = (-10155.5,-8417.45,0.124996);
    level.waypoints[0].childCount = 2;
    level.waypoints[0].children[0] = 1;
    level.waypoints[0].children[1] = 39;
    level.waypoints[1] = spawnstruct();
    level.waypoints[1].origin = (-10196.9,-8574.94,0.124996);
    level.waypoints[1].childCount = 2;
    level.waypoints[1].children[0] = 2;
    level.waypoints[1].children[1] = 0;
    level.waypoints[2] = spawnstruct();
    level.waypoints[2].origin = (-10384.7,-8622.07,0.124996);
    level.waypoints[2].childCount = 2;
    level.waypoints[2].children[0] = 3;
    level.waypoints[2].children[1] = 1;
    level.waypoints[3] = spawnstruct();
    level.waypoints[3].origin = (-10620.7,-8626.96,0.124996);
    level.waypoints[3].childCount = 2;
    level.waypoints[3].children[0] = 4;
    level.waypoints[3].children[1] = 2;
    level.waypoints[4] = spawnstruct();
    level.waypoints[4].origin = (-10798.3,-8591.58,0.124996);
    level.waypoints[4].childCount = 2;
    level.waypoints[4].children[0] = 5;
    level.waypoints[4].children[1] = 3;
    level.waypoints[5] = spawnstruct();
    level.waypoints[5].origin = (-11024.3,-8618.33,0.124996);
    level.waypoints[5].childCount = 2;
    level.waypoints[5].children[0] = 6;
    level.waypoints[5].children[1] = 4;
    .
    .
    .
}

To add those waypoints I wrote another "RotU-Developer-Tool" also based on automatically working methods (Just a Beta... I still add many waypoints by hand).

Now we got a list of around 300 waypoints.
Let's say we spawn a zombie on point A and we want him moving to point B behind a wall. The zombie has to calculate the shortest way to its destination around the wall while staying to the waypoints.

The method I used is named A*-Search.
This is a highly effective alrogithm that findes the shortest way to the destination waypoint.

Here is some code of the A*-Search method in my mod:
Code:
AStarSearch(startWp, goalWp)
{
    self endon("player_killed");

    pQOpen = [];
    pQSize = 0;
    closedList = [];
    listSize = 0;
    s = spawnstruct();
    s.g = 0; //start node
    s.h = distance(level.waypoints[startWp].origin, level.waypoints[goalWp].origin);
    s.f = s.g + s.h;
    s.wpIdx = startWp;
    s.parent = spawnstruct();
    s.parent.wpIdx = -1;

    pQOpen[pQSize] = spawnstruct();
    pQOpen[pQSize] = s; //push s on Open
    pQSize++;

    while(!PQIsEmpty(pQOpen, pQSize))
    {
        //wait 0.01; //todo
        n = pQOpen[0];
        highestPriority = 9999999999;
        bestNode = -1;
        for(i = 0; i < pQSize; i++)
        {
            if(pQOpen[i].f < highestPriority)
            {
                bestNode = i;
                highestPriority = pQOpen[i].f;
            }
        }
    
        if(bestNode != -1)
        {
            n = pQOpen[bestNode];
            //remove node from queue    
            for(i = bestNode; i < pQSize-1; i++)
            {
                pQOpen[i] = pQOpen[i+1];
            }
            pQSize--;
        }
        else
        {
            return;
        }  

        //if n is a goal node; construct path, return success
        if(n.wpIdx == goalWp)
        {
            x = n;
            for(z = 0; z < 1000; z++)
            {
                parent = x.parent;
                if(parent.parent.wpIdx == -1)
                {    
                    return x.wpIdx;

                }
                x = parent;
            }
            return;      
        }
    .
    .
    .
    .
    .
    .
    .
    .

    }

}

The method always returns the next waypoint the zombie should walk to. So if we repeat this method some times, the zombie will reach his destination at a time x. The time is calculated by DISTANCE/SPEED = TIME.

The rest of the mod is pretty simple coding.

For example setting up the waveorder:

Code:
setupwaves()
{
    level.wave_type = [];
    level.wave_type[0] = "normal";

    ////// wavetypes here //////

    //normal, toxic, freeze, speed, burning, chaos, boss1, boss3, endboss

    level.wave_type[1] = "normal";
    level.wave_type[2] = "toxic";
    level.wave_type[3] = "normal";
    level.wave_type[4] = "speed";
    level.wave_type[5] = "pseudo";
    level.wave_type[6] = "mixed";
    level.wave_type[7] = "normal";
    level.wave_type[8] = "freeze";
    level.wave_type[9] = "burning";
    level.wave_type[10] = "pseudo";
    level.wave_type[11] = "normal";
    level.wave_type[12] = "chaos";
    level.wave_type[13] = "normal";
    level.wave_type[14] = "mixed";
    level.wave_type[15] = "pseudo";
    level.wave_type[16] = "boss1";
    level.wave_type[17] = "freeze";
    level.wave_type[18] = "chaos";
    level.wave_type[19] = "pseudo";
    level.wave_type[20] = "boss3";
    level.wave_type[21] = "normal";
    level.wave_type[22] = "mixed";
    level.wave_type[23] = "endboss";


    level.maxwaves = 23;

    //////////////////////////////
}

Another aspect I got asked very often is how about saving the levels. How does this system work?
Well, all levels are sticked to your GUID (your CD key). But not only the levels. Everything is saved in a packet as a serverside variable.

For example this is my data packet (my GUID is replaced by *):
Code:
set data_****** 200-51264650-35-27-35-35-0-0-179-1-0-6910-0-181-0-90-0-0-0-6910-0-4-1-35-35-1

Another program running on my root machine saves the data packets to a mysql database.
So if the server restarts the datas are not lost.
This is made possible by the following code written in PHP (only a part of it):
Code:
.
.
.
    $result = $con->rcon($ip, $port, $password, "cvarlist data_");
    $pattern = '|^[A-Z ]{7} (\w+) "(.*)"$|i';
    foreach(array_map("rtrim", explode("\n", $result)) as $value)
    {
        if(preg_match($pattern, $value, $subpatterns))
        {
            $data = $subpatterns[2]."-".preg_replace("/data_/", "", $subpatterns[1]);
            $cvars[strtolower($subpatterns[1])] = explode("-", $data);
            }
    }
.
.
.

To read the data on server side I used the following code to explode "-":
Code:
    parms = explode(var, "-");
    self.rotu_level = (int)parms[0];
    self.rotu_points = (int)parms[1];
    self.skill_armored = (int)parms[2];
    self.skill_soldier = (int)parms[3];
    self.skill_engineer = (int)parms[4];
    self.skill_medic = (int)parms[5];
    self.skillpoints_available = (int)parms[6];
        .
        .
        .
        .

---------------------------------------------------------------------------------------------------

Of course there is much more behind the mod to make it working as it works now.
This was just an extrem short description where the mod is based on!
If you have further questions please feel free to ask in this topic.

---------------------------------------------------------------------------------------------------

If you want to buy the whole server side scripts (including levelsaver, serverfiles and developer-tool) please contact me via Mail or PM.

And always remember: I'm still doing my best to fix bugs and release new updates.
Buy Premium and get many new features in the next update package.

---------------------------------------------------------------------------------------------------

Regards,
Fabio
fabio,
you should add one more voting option - ''I'm too lazy to read all this stuff''
Done Smile
I will vote "I don't understand that the compiler accept this" Huh

I assume you stripped a lot of the real code (includes, defines, variable declarations, functions, etc).
If not then I would like to know which compiler you uses.
Because its making programming a lot easier then Smile.
Well, this is based on C++ but you don't have to include anything. Also no declarations..
You declare vars and functions like this:

number = 1;
string = "lol";

myFuncion(parameter){ //anything }

The code isn't compiled. It is open source in the serverside pk3 file Wink
So it's more scripting then writing real code that have to be compiled.
Then I misinterpreted the first post a bit.
Yea, it's a engine based programming language. Just some parts of C++ and Java...
But all those scripting languages are mostly the same