Skip to content

More cars per game TUTORIAL by Ten Graves

cravxx edited this page May 22, 2021 · 4 revisions

In this tutorial I will show you how to easily alter the number of cars per game with a single variable (which I call "nplayers") so you can change it very easily as you please. Not only that, but you can even vary how many cars there are per race depending on the stage (e.g. you can have something like 15 cars in Stage 16, but maybe Stage 6 can be a 1v1). It's very flexible.

First, you have to define a maximum number of cars/game NFM 2 will be able to support. While you can, in theory, make it as high as you want, having too many cars in a game can make it very laggy. The maximum I use is 51 cars (which is the maximum this tutorial assumes you are using), which already is quite laggy on its own, so I don't recommend going far beyond that.

I highly recommend having at least some knowledge of NFM's java before attempting this hack.

The classes you'll have to edit are as follows:

  1. Control - very little to edit.
  2. Madness - little to edit
  3. CheckPoints - a fair amount to edit.
  4. GameSparker - a decent amount to edit.
  5. Record - a lot to edit.
  6. xtGraphics - a ton to edit.

Before we start, you'll first have to declare nplayers (as an integer) in xtGraphics. For example:

Control

First, find this:

public void preform(Madness madness, ContO conto, CheckPoints checkpoints, Trackers trackers)

and replace it with this:

public void preform(Madness madness, ContO conto, CheckPoints checkpoints, Trackers trackers, int ncars)

The only difference is that I added "int ncars" at the end. Note that it does not necessarily have to be called ncars; it can be called whatever you want :P.

Now find this:

while(++i4 < 7);

and replace the "7" with "ncars" (or whatever name you gave it).

The game would not know what ncars is supposed to represent though, so go to GameSparker and find this:

u[l12].preform(amadness[l12], aconto1[l12], checkpoints, trackers);

and replace it with this:

u[l12].preform(amadness[l12], aconto1[l12], checkpoints, trackers, xtgraphics.nplayers);

Madness

Now replace this:

dominate = new boolean[7];
caught = new boolean[7];

with this:

dominate = new boolean[51];
caught = new boolean[51];

assuming 51 is the maximum number of cars per game you want your NFM to be able to support.

You'll also need to change the 7 here to 51:

do
{
    dominate[j] = false;
    caught[j] = false;
} while(++j < 7);

CheckPoints

You'll first need to change pos to be able to support 51 cars, like this:

In addition, change the following 7s to 51s:

clear = new int[7];
dested = new int[7];
opx = new int[7];
opz = new int[7];
onscreen = new int[7];
omxz = new int[7];

Now replace this:

public void checkstat(Madness amadness[], ContO aconto[], Record record)

with this:

public void checkstat(Madness amadness[], ContO aconto[], Record record, int ncars)

Like in Control, the game does not know what int ncars is supposed to be yet, so go to Gamesparker and find this:

checkpoints.checkstat(amadness, aconto1, record);

and replace it with this:

checkpoints.checkstat(amadness, aconto1, record, xtgraphics.nplayers);

Note that there are 2 instances of the above code, so make sure you edit both.

Now search for this code (in CheckPoints this time):

< 7

Replace all 6 of the instances of it with this:

< ncars

GameSparker

First, replace this:

u = new Control[7];

with this:

u = new Control[51];

As with the rest of the tutorial, I'm assuming 51 cars is the maximum you want your NFM to be able to handle.

Do the same with this too:

Madness amadness[] = new Madness[7];

Now replace all instances (except one) of this:

< 7

with this:

< xtgraphics.nplayers

The one instance which isn't changed in this way is here:

int l = 0;
        do
        {
            amadness[l] = new Madness(medium, record, xtgraphics, l);
            u[l] = new Control(medium);
        } while(++l < 7);    

Do NOT change the 7 here to xtgraphics.nplayers, change it to 51.

You'll also need to find this piece of code (in void loadstage):

nob = 7;

Replace the 7 with xtgraphics.nplayers.

In addition, search for this code:

int k5 = 7

This should be in a for statement. Again, replace the 7 with xtgraphics.nplayers.

Record

You'll first need to edit the size of the hfix and hdest arrays so that they can support 51 slots each instead of just 7. These arrays can be found where all the other variables are declared; either at the very top or at the very bottom. Assuming you want the game to be able to handle 51 cars/game, it should look like this:

First, find the following method:

public void reset(ContO aconto])

In this method change both instances of this:

while(++i < 7);

to this:

while(++i < 51);

You'll also have to replace the 7 with a 51 in the code below:

while(++j < 7);

Now, find this:

public Record(Medium medium)

In this method change all instances of [7] to [51], APART FROM THE FOLLOWING (indicated as x):

ry = new int[51][4][x];
magy = new int[51][4][x];
mtouch = new boolean[51][x];

rx = new int[51][4][x];
magx = new int[51][4][x];

rz = new int[51][4][x];
magz = new int[51][4][x];

hry = new int[51][4][x];
hmagy = new int[51][4][x];

hrx = new int[51][4][x];
hmagx = new int[51][4][x];

hrz = new int[51][4][x];
hmagz = new int[51][4][x];
hmtouch = new boolean[51][x];

Finally, find this method:

public void cotchinow(int i)

Change all 4 instances of this:

while(++j < 7);

with this:

while(++j < 51);

You'll also have to replace this:

while(++k < 7);

with this:

while(++k < 51);

xtGraphics

First, remove the arrays int xstart and int zstart completely. We'll make the game determine the starting positions of the cars itself.

Go to GameSparker and find the following code:

aconto[j1] = new ContO(aconto1[xtgraphics.sc[j1]], xtgraphics.xstart[j1], 250 - aconto1[xtgraphics.sc[j1]].grat, xtgraphics.zstart[j1], 0);

and replace it with this:

if(j1 % 3 == 0)
{
    aconto[j1] = new ContO(aconto1[xtgraphics.sc[j1]], 0, 250 - aconto1[xtgraphics.sc[j1]].grat, -760 + ((j1 / 3) * 760), 0);
} 
if(j1 % 3 == 1)
{
    aconto[j1] = new ContO(aconto1[xtgraphics.sc[j1]], -350, 250 - aconto1[xtgraphics.sc[j1]].grat, -380 + ((int)(j1 / 3) * 760), 0);
}
if(j1 % 3 == 2)
{
    aconto[j1] = new ContO(aconto1[xtgraphics.sc[j1]], 350, 250 - aconto1[xtgraphics.sc[j1]].grat, -380 + ((int)(j1 / 3) * 760), 0);
}

Now, the game will determine the starting positions itself, no matter how many cars you have per game.

After that, go to void arrow in xtGraphics and find this code:

} while(++l2 < 7);

and replace it with this:

} while(++l2 < nplayers);

Now go to void stat and find this:

if(checkpoints.wasted == 6)

and replace it with this:

if(checkpoints.wasted == nplayers - 1)

In the same method find this piece of code:

Replace the < 7 with < nplayers.

Now, find this code (again, in void stat):

if(m.flex != 2)
                {
                    rd.drawImage(dmg, 470, 7, null);
                    rd.drawImage(pwr, 470, 27, null);
                    rd.drawImage(lap, 19, 7, null);
                    rd.setColor(new Color(0, 0, 100));
                    rd.drawString("" + (madness[0].nlaps + 1) + " / " + checkpoints.nlaps + "", 51, 18);
                    rd.drawImage(was, 92, 7, null);
                    rd.setColor(new Color(0, 0, 100));
                    rd.drawString("" + checkpoints.wasted + " / 6", 150, 18);
                    rd.drawImage(pos, 42, 27, null);
                    rd.drawImage(rank[checkpoints.pos[madness[0].im]], 110, 28, null);
                    m.flex++;
                } else
                {
                    if(posit != checkpoints.pos[madness[0].im])
                    {
                        rd.drawImage(rank[checkpoints.pos[madness[0].im]], 110, 28, null);
                        posit = checkpoints.pos[madness[0].im];
                    }
                    if(wasted != checkpoints.wasted)
                    {
                        rd.setColor(new Color(m.csky[0], m.csky[1], m.csky[2]));
                        rd.fillRect(150, 8, 30, 10);
                        rd.setColor(new Color(0, 0, 100));
                        rd.drawString("" + checkpoints.wasted + " / 6", 150, 18);
                        wasted = checkpoints.wasted;
                    }
                    if(laps != madness[0].nlaps)
                    {
                        rd.setColor(new Color(m.csky[0], m.csky[1], m.csky[2]));
                        rd.fillRect(51, 8, 40, 10);
                        rd.setColor(new Color(0, 0, 100));
                        rd.drawString("" + (madness[0].nlaps + 1) + " / " + checkpoints.nlaps + "", 51, 18);
                        laps = madness[0].nlaps;
                    }
                }

The code above may not be exactly the same for you. You should be able to figure out what you need to remove though.

Either way, you'll need to replace it with this code:

rd.drawImage(dmg, 470, 7, null);
                rd.drawImage(pwr, 470, 27, null);
                rd.drawImage(lap, 19, 7, null);
                rd.setColor(new Color(0, 0, 100));
                rd.drawString("" + (madness.nlaps + 1) + " / " + checkpoints.nlaps + "", 51, 18);
                rd.drawImage(was, 92, 7, null);
                rd.setColor(new Color(0, 0, 100));
                rd.drawString("" + checkpoints.wasted + " / " + (nplayers - 1), 150, 18);
                rd.drawImage(pos, 42, 27, null);
                rd.setFont(adventure.deriveFont(1, 17F));
                String suffix = "";
                int position = checkpoints.pos[0] + 1;
                if((position - 1) % 10 == 0 && position != 11)
                {
                    suffix = "st";
                }
                if((position - 2) % 10 == 0 && position != 12)
                {
                    suffix = "nd";
                }
                if((position - 3) % 10 == 0 && position != 13)
                {
                    suffix = "rd";
                }
                if(position % 10 == 0 || position % 10 >= 4 || position == 11 || position == 12 || position == 13)
                {
                    suffix = "th";
                }
                rd.drawString("" + position + suffix + "", 110, 43); 
                rd.setFont(new Font("Arial", 1, 11));

The above code is basically the same as it was before except that unnecessary code was removed, I changed "/ 6" to "/ " + (nplayers - 1) and, most importantly, the game now writes in the position you're at instead of just using an image. The main reason for doing this is because drawing every image for each extra position you'll need would take a very long time. Feel free to make your own images for the extra positions if you want though, but in this tutorial I'll assume you don't.

Note that the code above assumes your game has the adventure font in madness.jar. If it doesn't, just replace this:

rd.setFont(adventure.deriveFont(1, 17F));

with this:

rd.setFont(new Font("Arial", 1, 11));

You'll also need to get rid of the same piece of code above at the very bottom of the large chunk of code above that, since it's unnecessary now.

In addition, since you no longer need the images of the positions, go remove the following "if" statements (and the code within each one) in void loadimages:

if(s.equals("1.gif"))
if(s.equals("2.gif"))
if(s.equals("3.gif"))
if(s.equals("4.gif"))
if(s.equals("5.gif"))
if(s.equals("6.gif"))
if(s.equals("7.gif"))

You should also remove 1,gif, 2.gif, etc. in images.radq (in the data folder) as they are no longer needed.

Finally, find the following pieces of code and remove them completely:

Image orank[];
Image rank[];

do
{
     rank[j] = loadsnap(orank[j]);
} while(++j < 7);
j = 0;

orank = new Image[7];
rank = new Image[7];

Basically, you're removing the rank and orank variables in general, since they're no longer needed.

At the bottom of void stat, find this code:

while(++k < 7);

and replace it with this:

while(++k < nplayers);

Next, go to void sortcars and change this:

boolean aflag[] = new boolean[7];

to this:

boolean aflag[] = new boolean[nplayers];

Now replace this:

sc[6] = 7 + (i + 1) / 2;

with this:

sc[nplayers - 1] = 7 + (i + 1) / 2;

Now replace both instances of this code (both instances are in void sortcars):

} while(++k < 6);

with this code:

} while(++k < nplayers - 1);

Also, find this piece of code (near the top of void sortcars):

if(i == 14)
                {
                    if(sc[0] != 12)
                    {
                        sc[5] = 12;
                    } else
                    {
                        sc[5] = 1;
                    }
                    if(sc[0] != 10)
                    {
                        sc[4] = 10;
                    } else
                    {
                        sc[4] = 1;
                    }
                    aflag[4] = true;
                    aflag[5] = true;
                    k = (int)(Math.random() * 3D + 1.0D);
                    if(sc[0] != 9)
                    {
                        sc[k] = 9;
                        aflag[k] = true;
                        if(++k == 4)
                        {
                            k = 1;
                        }
                    }
                    if(sc[0] != 5)
                    {
                        sc[k] = 5;
                        aflag[k] = true;
                        if(++k == 4)
                        {
                            k = 1;
                        }
                    }
                    if(sc[0] != 8)
                    {
                        sc[k] = 8;
                        aflag[k] = true;
                        if(++k == 4)
                        {
                            k = 1;
                        }
                    }
                }
                if(i == 16)
                {
                    k = 4;
                    byte byte1 = 5;
                    byte byte2 = 1;
                    byte byte3 = 2;
                    if(Math.random() > Math.random())
                    {
                        k = 5;
                        byte1 = 4;
                    }
                    if(Math.random() < Math.random())
                    {
                        byte2 = 2;
                        byte3 = 1;
                    }
                    if(sc[0] != 12)
                    {
                        sc[k] = 12;
                    } else
                    {
                        sc[k] = 14;
                    }
                    if(sc[0] != 10)
                    {
                        sc[byte1] = 10;
                    } else
                    {
                        sc[byte1] = 14;
                    }
                    if(sc[0] != 11)
                    {
                        sc[byte2] = 11;
                    } else
                    {
                        sc[byte2] = 14;
                    }
                    if(sc[0] != 13)
                    {
                        sc[byte3] = 13;
                    } else
                    {
                        sc[byte3] = 14;
                    }
                    if(sc[0] <= 9)
                    {
                        sc[3] = 14;
                    } else
                    {
                        sc[3] = 9;
                    }
                    int j3 = 1;
                    do
                    {
                        aflag[j3] = true;
                    } while(++j3 < 6);
                }

This code basically determines what cars appear in stages 14 and 16 when you haven't completed them yet. You can either get rid of them OR you can keep them for reference by putting the whole code within this if statement:

if(nplayers == 7)

After that, replace this:

while(++l < 7);

with this:

while(++l < nplayers);

Now, find this:

if(k != l && sc[k] == sc[l])

and replace it with this:

if(k != l && sc[k] == sc[l] && nplayers <= 9)

Find this:

if(i == 11 && (sc[k] == 0 || sc[k] == 1 || sc[k] == 2 || sc[k] == 3 || sc[k] == 4 || sc[k] == 7))

and replace it with this:

if(i == 11 && (sc[k] == 0 || sc[k] == 1 || sc[k] == 2 || sc[k] == 3 || sc[k] == 4 || sc[k] == 7) && nplayers <= 8)

And find this code:

if((i == 12 || i == 15) && sc[k] <= 4)

and replace it with this:

if((i == 12 || i == 15) && sc[k] <= 4 && nplayers <= 9)

Now we'll tweak the rules as to what cars can appear in individual stages so it has support for our "nplayers" variable. Find these pieces of code (again, in void sortcars):

while(++i1 < 6);
while(++j1 < 6);
while(++k1 < 6);
while(++l1 < 6);
while(++i2 < 6);
while(++j2 < 6);

and just replace < 6 with < nplayers - 1 for each one.

Now find this (still in void sortcars):

byte byte0 = 7;

and replace it with this:

int byte0 = nplayers;

Just below it, replace this:

sc[6] = 7 + (i + 1) / 2;
byte0 = 6;

with this:

sc[nplayers - 1] = 7 + (i + 1) / 2;
byte0 = nplayers - 1;

Note that the variable byte0 might not be called byte0 in your java, though the general code should still be the same (i.e. just the names are different).

Now find the piece of code that looks like this (it may not be exactly the same but you should recognise it anyway):

and replace it with this code:

int g = 0;
                    do
                    {
                        if(k2 != g && sc[k2] == sc[g] && nplayers <= 9)
                        {
                            aflag[k2] = false;
                        }
                    } while(++g < nplayers);

Now find this code:

while(++l2 < 6);

and replace it with this:

while(++l2 < nplayers - 1);

(This code should be right at the bottom of void sortcars).

After that, find this code:

int j = 0;
        do
        {
            dested[j] = 0;
        } while(++j < 7);

and replace the 7 with nplayers.

Now find these pieces of code:

sc = new int[7];
dested = new int[7];

and replace those with these:

sc = new int[51];
dested = new int[51];

We're almost done. The last thing we have to do is let the game determine what nplayers should be. To do this, first replace all instances of this code:

fase = 2;

with this:

fase = 58;

Then go to GameSparker and find this piece of code:

if(xtgraphics.fase == 2)
            {
                xtgraphics.loadingstage(checkpoints.stage);
                loadstage(aconto1, aconto, medium, trackers, checkpoints, xtgraphics, amadness, record);
                u[0].falseo();
            }

Paste the following code above it:

if(xtgraphics.fase == 58)
{
    xtgraphics.carspergame();
}

Now go back to xtGraphics and delcare this:

boolean setnumber;

Go to void resetstat, and just below it put this code:

setnumber = false;

It should look something like this:

Now do the same with public xtGraphics. Again, it should look something like this:

Finally, find this code (which is near the top):

public boolean over(Image image, int i, int j, int k, int l)

and paste the following code above it:


public void carspergame()
    {
        if(!setnumber)
        {
            nplayers = any number you want from 2 to 51!
            setnumber = true;
        } else
        {
            fase = 2;
        }
    }

After that, compile everything and it should work. Enjoy!

NOTE: If you're planning to add a lot of cars, you may need to hack the stage limit as well (each car counts as a piece). Go here for the tutorial on that:

https://aimgames.forummotion.com/t3223-unlimited-stage-size-hack-nfm-2

https://github.com/cravxx/unfm2jg/wiki/Unlimited-stage-size-hack-by-Ten-Graves