Post tutorial RSS Altering the ASOD Universe, part 3 (NPCs)

Adding NPCs to ASOD is somewhat tricky, but rewarding. You need the code from asod.dev.java.net .

Posted by on - Intermediate Client Side Coding

I'm assuming you have done the previous tutorials first.

Files Involved
Main.java - Stores the NPCs
Rat.java - Defines a specific NPC
Cosmos.java - Defines groups of NPCs

Ok, we will be focusing on adding the declarations in Main.java in this tutorial to add NPCs to a system. Make sure you have the code. This tutorial adds to the game concepts that arent in the game at the time of this tutorial's release. They are only in the source-code version as of March 26, 2009.

Step 1, Adding NPCs

space[14] = new cosmos(5, 500, 580, "RATS");
            space[14].ratGroup = new Rat[2];
            space[14].solar = "Pionis";
            space[14].faction = "Slasher";

That is sample code for adding some rats. The type is 5, meaning NPCs. NPCs in ASOD are stored in arrays, this array holds 2 rats and are members of the Slasher faction. This code goes near the top of Main.java with the rest of the cosmic delcarations. Please note that type info is specified later.

Step 2, Generating the NPCs

for (int i = 0; i < space[14].ratGroup.length; i++) {
                space[14].ratGroup[i]= new Rat(1, 5, 5, 0, -2233 + i * 30 - 15, 1622 + i + 30 * i);
                space[14].ratGroup[i].patroller = true;
            }

Ok that looks ugly. Let me break down the Rat method.

public Rat(int type, int shield, int hull, int intelligence, int x, int y)

Within this class, you can set the shield and hull points of the rats, intelligence (set it to 0 for turrets, 1 for NPCs that move), and the initial position. Type here is different that in cosmos. It refers to specific rat types inside the class. Adding those will be discussed in a later tutorial

Now the NPCs have a system to live in and a faction and ship to fly. The problem is, they lose position! So, to let em show up where you want em, you hook this:

public void configureRatPositions()

That code sets the correct position of your rats when you enter a system. Note, you only need to hook this if you dont want your rats to trade/patrol. Otherwise, skip to step 3.

If you do want to have them at a fixed point in a system, you use code similair to this:

for (int i = 0; i < space[14].ratGroup.length; i++) {
                space[14].ratGroup[i]= new Rat(1, 5, 5, 0, -2233 + i * 30 - 15, 1622 + i + 30 * i);
                space[14].ratGroup[i].patroller = true;
            }

Familiar? Its the same code as before. You just copy it over.

Step 3, making them interact
This is a new feature only in the updated online source code at the time of writing (as of March 26, 2009). It allows your NPCs to patrol and trade.

They work by picking random sources and destinstions and flying to them then generating a new one. Simple and effective. To specify a trader:

space[40] = new cosmos(5, 8900, -1000, "RATS");
            space[40].ratGroup = new Rat[6]; //seed the system well to guarantee encounters
            space[40].solar = "Ziaac";
            space[40].faction = "Merchants Guild"; // "yay"

for (int i = 0; i < space[40].ratGroup.length; i++) {
                space[40].ratGroup[i]= new Rat(3, 2400, 1000, 0, -2000, 3000);
                space[40].ratGroup[i].type = 3;
                space[40].ratGroup[i].pursuePlayer = false;
            }

Notice that pursuePlayer is false, this is essential. Type is 3, that is the trader freighter that exists in this game at time of writing. The positions do not matter really. They will be changed as soon as the game starts.

Patrollers are slightly different. You specify like normal, except you do patrolPlayer as false and space[14].patroller = true; . They use the same logic as traders except they break off and pursue an agressing player. Remember not to hook either of these rats into configureRatPositions().

Step 4, Regeneration

You may want your rats to return. A good example is traders/patrols who techically (only in code) "die" when the route completes.

You go to Main and find updateRatBullets(). Scroll till you see

for (int sys = 0; sys < space.length; sys++) {

This is the start. Youll see a list of what rats do when they die. Here's an example for a trader:

if (sys == 40) {
                                                    hud.currentMessage = "Merchant: THIS IS MERCHANT " + space[30].ratGroup[group] + " I NEED....";
                                                    //respawn him
                                                    space[40].ratGroup[group] = new Rat(3, 2400, 1000, 0, -2000, 3000);
                                                    space[40].ratGroup[group].type = 3;
                                                    space[40].ratGroup[group].pursuePlayer = false;
                                                }

Combat rats can come back as well, here is a sample of that.

if (sys == 23) {
                                                    space[23].ratGroup[group] = new Rat(0, 30, 40, 0, space[19].positionX + group * 30 - 15, space[19].positionY + group + 30 * group);
                                                    hud.currentMessage = "Slasher Guard: DIE BASTARD!";
                                                    space[23].ratGroup[group].patroller = true;
                                                }

Notice that the code is the same as you used to declare it. That's because the rat comes back the same way.

Here is the entire method, so you can see where im talking about:

private void updateRatBullets() {
        int tmpx = 0;
        int tmpy = 0;
        //update bullets
        //check distance traveled to determine if it is ok to play an effect
        for (int sys = 0; sys < space.length; sys++) {
            try {
                if (space[sys].type == 5) {
                    for (int group = 0; group < space[sys].ratGroup.length; group++) {
                        if (space[sys].ratGroup[group].alive &amp;&amp; space[sys].solar.matches(player.currentSolarSystem)) {
                            //probe their bullets for living ones with a travel distance less than 2
                            //2 gives the threat a chance to keep up the sound in sync
                            for (int b = 0; b < space[sys].ratGroup[group].bullet.length; b++) {
                                if (space[sys].ratGroup[group].bullet[b].alive &amp;&amp;
                                        space[sys].ratGroup[group].bullet[b].traveled < 2) {
                                    //play the correct sound based on the bullet
                                    switch (space[sys].ratGroup[group].bullet[b].type) {

                                        case -2:
                                            this.playSoundEffect("Slasher Particle Rifle");
                                            break;
                                        case -1:
                                            this.playSoundEffect("Improved Particle Rifle");
                                            break;
                                        case 0:
                                            this.playSoundEffect("Particle Rifle");
                                            break;
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (player.ship.cruising == false) {
            if (player.getFacingLeft()) {
                tmpx = player.ship.speed * -1;
            }
            if (player.getFacingRight()) {
                tmpx = player.ship.speed * 1;
            }
            if (player.getFacingUp()) {
                tmpy = player.ship.speed;
            }
            if (player.getFacingDown()) {
                tmpy = player.ship.speed * -1;
            }
        }
        if (player.ship.cruising == true) {
            if (player.getFacingLeft()) {
                tmpx = player.ship.cruise * -1;
            }
            if (player.getFacingRight()) {
                tmpx = player.ship.cruise * 1;
            }
            if (player.getFacingUp()) {
                tmpy = player.ship.cruise;
            }
            if (player.getFacingDown()) {
                tmpy = player.ship.cruise * -1;
            }
        }
        for (int sys = 0; sys < space.length; sys++) {
            try {
                if (space[sys].type == 5) {
                    for (int group = 0; group < space[sys].ratGroup.length; group++) {
                        if (space[sys].ratGroup[group].alive &amp;&amp; space[sys].solar.matches(player.currentSolarSystem)) {
                            //check for rat-player bullet collisions
                            for (int p = 0; p < player.bullet.length; p++) {
                                if (player.bullet[p].type != -100) {
                                    if (space[sys].ratGroup[group].getBounds().intersects(player.bullet[p].bounds())) {
                                        player.bullet[p].updatePosition(6000, 6000);
                                        space[sys].ratGroup[group].shield = space[sys].ratGroup[group].shield - player.bullet[p].getDamage() - 1;
                                        space[sys].ratGroup[group].patroller = false;
                                        for (int rat = 0; rat < space[sys].ratGroup.length; rat++) {
                                            space[sys].ratGroup[rat].pursuePlayer = true;
                                        }
                                        space[sys].ratGroup[group].pursuePlayer = true;
                                        if (space[sys].ratGroup[group].shield <= 0) {
                                            space[sys].ratGroup[group].hull = space[sys].ratGroup[group].hull - player.bullet[p].getDamage() - 1;
                                            space[sys].ratGroup[group].shield = 0;
                                            if (space[sys].ratGroup[group].hull < 0) {
                                                space[sys].ratGroup[group].alive = false;
                                                player.currentWallet += space[sys].ratGroup[group].bounty;
                                                if (sys == 12) {
                                                    space[12].ratGroup[group] = new Rat(0, 20, 10, 0, space[9].positionX + sys * 3 - 15, space[9].positionY + sys + 3 * sys);
                                                    space[12].ratGroup[group].patroller = true;
                                                    hud.currentMessage = "Slasher Guard: Area compromised! Reinforcements needed!";
                                                }
                                                if (sys == 13) {
                                                    hud.currentMessage = "Rogue Pirate: Gate commander come in! Perimeter breached!";
                                                }
                                                if (sys == 14) {
                                                    space[14].ratGroup[group] = new Rat(1, 5, 5, 0, space[9].positionX + sys * 3 - 15, space[9].positionY + sys + 3 * sys);
                                                    hud.currentMessage = "Slasher Miner: AAAAAAAAAAAAA!!!!!!!!";
                                                    space[14].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 16) {
                                                    space[16].ratGroup[group] = new Rat(0, 50, 25, 0, space[15].positionX + group * 30 - 15, space[15].positionY + group + 30 * group);
                                                    hud.currentMessage = "Slasher Guard: You cannot escape! You will be made an example of!";
                                                    space[16].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 20) {
                                                    space[20].ratGroup[group] = new Rat(-1, 30, 40, 0, space[19].positionX + group * 30 - 15, space[19].positionY + group + 30 * group);
                                                    hud.currentMessage = "MP: FREEZE! You are under arrest!";
                                                    space[20].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 23) {
                                                    space[23].ratGroup[group] = new Rat(0, 30, 40, 0, space[19].positionX + group * 30 - 15, space[19].positionY + group + 30 * group);
                                                    hud.currentMessage = "Slasher Guard: DIE BASTARD!";
                                                    space[23].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 30) {
                                                    hud.currentMessage = "Station Commander: HQ! HQ! WE ARE UNDER ATTACK!";
                                                    space[30].ratGroup[group] = new Rat(-1, 30, 20, 0, 600 + (group * 70), 860 - (group * 70));
                                                    space[30].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 37) {
                                                    hud.currentMessage = "Rogue Pirate: GET THE HELL OUT OF OUR SPACE!";
                                                }
                                                if (sys == 40) {
                                                    hud.currentMessage = "Merchant: THIS IS MERCHANT " + space[30].ratGroup[group] + " I NEED....";
                                                    //respawn him
                                                    space[40].ratGroup[group] = new Rat(3, 2400, 1000, 0, -2000, 3000);
                                                    space[40].ratGroup[group].type = 3;
                                                    space[40].ratGroup[group].pursuePlayer = false;
                                                }
                                                if (sys == 41) {
                                                    hud.currentMessage = "Merchant: THIS IS MERCHANT " + space[30].ratGroup[group] + " I NEED....";
                                                    //respawn him
                                                    space[41].ratGroup[group] = new Rat(3, 2400, 1000, 0, -2000, 3000);
                                                    space[41].ratGroup[group].type = 3;
                                                    space[41].ratGroup[group].pursuePlayer = false;
                                                }
                                                //make sure the new rat attacks the player
                                                space[sys].ratGroup[group].pursuePlayer = true;
                                                //call the standings system to adjust based on these deaths.
                                                standings.mutateStandings(space[sys].faction, -5);
                                                System.out.println("Standings loss toward " + space[sys].faction + " of 5");
                                                //agress that faction so that rats auto engage you
                                                standings.agressFaction(space[sys].faction);
                                            }
                                        }
                                    }
                                }
                            }
                            for (int fin = 0; fin < space[sys].ratGroup[group].bullet.length; fin++) {
                                //update the bullets
                                space[sys].ratGroup[group].bullet[fin].updatePosition(tmpx, tmpy);
                                //check for player-rat bullet collisions
                                if (space[sys].ratGroup[group].bullet[fin].type != -100) {
                                    if (space[sys].ratGroup[group].bullet[fin].bounds().intersects(player.getBounds())) {
                                        //damage the shields
                                        space[sys].ratGroup[group].bullet[fin].alive = false;
                                        player.ship.shield = player.ship.shield - (int) (space[sys].ratGroup[group].bullet[fin].getDamage() * 0.5) - 1;
                                        if (player.ship.shield <= 0) {
                                            player.ship.hull = player.ship.hull - (int) (space[sys].ratGroup[group].bullet[fin].getDamage() * 0.5) - 1;
                                            player.ship.shield = 0;
                                            if (player.ship.hull < 0) {
                                                player.alive = false;
                                                loadGame();
                                                //reset the messages in the hud
                                                hud.currentMessage = "";
                                                //reset standings and bring the player back
                                                standings.resetAgresion();
                                                space[sys].ratGroup[group].patroller = true;
                                                space[sys].ratGroup[group].pursuePlayer = false;
                                                player.alive = true;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

and here is the part I'm reffering to:

if (sys == 12) {
                                                    space[12].ratGroup[group] = new Rat(0, 20, 10, 0, space[9].positionX + sys * 3 - 15, space[9].positionY + sys + 3 * sys);
                                                    space[12].ratGroup[group].patroller = true;
                                                    hud.currentMessage = "Slasher Guard: Area compromised! Reinforcements needed!";
                                                }
                                                if (sys == 13) {
                                                    hud.currentMessage = "Rogue Pirate: Gate commander come in! Perimeter breached!";
                                                }
                                                if (sys == 14) {
                                                    space[14].ratGroup[group] = new Rat(1, 5, 5, 0, space[9].positionX + sys * 3 - 15, space[9].positionY + sys + 3 * sys);
                                                    hud.currentMessage = "Slasher Miner: AAAAAAAAAAAAA!!!!!!!!";
                                                    space[14].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 16) {
                                                    space[16].ratGroup[group] = new Rat(0, 50, 25, 0, space[15].positionX + group * 30 - 15, space[15].positionY + group + 30 * group);
                                                    hud.currentMessage = "Slasher Guard: You cannot escape! You will be made an example of!";
                                                    space[16].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 20) {
                                                    space[20].ratGroup[group] = new Rat(-1, 30, 40, 0, space[19].positionX + group * 30 - 15, space[19].positionY + group + 30 * group);
                                                    hud.currentMessage = "MP: FREEZE! You are under arrest!";
                                                    space[20].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 23) {
                                                    space[23].ratGroup[group] = new Rat(0, 30, 40, 0, space[19].positionX + group * 30 - 15, space[19].positionY + group + 30 * group);
                                                    hud.currentMessage = "Slasher Guard: DIE BASTARD!";
                                                    space[23].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 30) {
                                                    hud.currentMessage = "Station Commander: HQ! HQ! WE ARE UNDER ATTACK!";
                                                    space[30].ratGroup[group] = new Rat(-1, 30, 20, 0, 600 + (group * 70), 860 - (group * 70));
                                                    space[30].ratGroup[group].patroller = true;
                                                }
                                                if (sys == 37) {
                                                    hud.currentMessage = "Rogue Pirate: GET THE HELL OUT OF OUR SPACE!";
                                                }
                                                if (sys == 40) {
                                                    hud.currentMessage = "Merchant: THIS IS MERCHANT " + space[30].ratGroup[group] + " I NEED....";
                                                    //respawn him
                                                    space[40].ratGroup[group] = new Rat(3, 2400, 1000, 0, -2000, 3000);
                                                    space[40].ratGroup[group].type = 3;
                                                    space[40].ratGroup[group].pursuePlayer = false;
                                                }
                                                if (sys == 41) {
                                                    hud.currentMessage = "Merchant: THIS IS MERCHANT " + space[30].ratGroup[group] + " I NEED....";
                                                    //respawn him
                                                    space[41].ratGroup[group] = new Rat(3, 2400, 1000, 0, -2000, 3000);
                                                    space[41].ratGroup[group].type = 3;
                                                    space[41].ratGroup[group].pursuePlayer = false;
                                                }

Thank you for using this tutorial. Good luck.

Post a comment
Sign in or join with:

Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.