Combat System Scripting II: slightly buffer target

Ah, now I remember! Before going on to other things besides the basic target, I was first going to make the basic target a little less basic.

In this posting, we’ll make the targets a little more robust, so it takes more than one collision to make them Cease To Be (or, in more violent language, more than one shot to kill them).

We’ll also, by the end, stick some nice color-changing floaty text over them, so you can tell how many collisions away from Ceasing to Be they are. (I’m sort of swerving between showing how a combat system might work, and giving little lectures on programming style, here, but it’s my weblog and I can do what I want! Feedback welcome if you’d like to see it go faster or slower or whatever, although I don’t promise to necessarily do what any feedback might suggest.)

The nice simple target script from last time was this:

process_collision(integer index) {
    if (llVecMag(llDetectedVel(index))>15) {
        llSay(0,"boom");
        llDie();
    } else {
        llSay(0,"clunk");
    }
}
default {
    collision_start(integer n) {
        integer i;
        for (i=0;i<n;i++) process_collision(i);
    }
}

To make the target a little harder to kill, we’ll add a “health” variable to keep track of just how many more hits it has left, and update process_collision to count that variable down, and do the Cease to Be thing only when it reaches zero. Other hits will just make some I dunno “pow” noise. So:

integer health = 20;

process_collision(integer index) {
    if (llVecMag(llDetectedVel(index))>15) {
        health = health - 1;
        if (health<=0) {
            llSay(0,"boom");
            llDie();
        } else {
            llSay(0,"pow");
        }
    } else {
        llSay(0,"clunk");
    }
}

The rest of the script (the collision_start() handler in the default state there) stays the same.

So play with that a little. It’s very nice, but it’s lacking some indication of how damaged the target is. We’ll add the floaty-text for that. It’ll require a new event handler in the default state to initialize the floaty text in the first place, and then some new code in process_collision to update the text when it’s hit.

That gets us to something like this:

integer health = 20;

process_collision(integer index) {
    if (llVecMag(llDetectedVel(index))>15) {
        health = health - 1;
        llSetText((string)health+"/20",<1,1,1>,1);
        if (health<=0) {
            llSay(0,"boom");
            llDie();
        } else {
            llSay(0,"pow");
        }
    } else {
        llSay(0,"clunk");
    }
}
default {
    state_entry() {
        llSetText("20/20",<1,1,1>,1);
    }
    collision_start(integer n) {
        integer i;
        for (i=0;i<n;i++) process_collision(i);
    }
}

This works nicely, but it is Evil because very similar llSetText() calls appear in two different places, and the “20” appears in four different places, which means that if I decided to change it to only take 10 hits, say, I would be sure to miss at least one of them.

With the maintainability improved, it does exactly the same thing, but looks nicer:

integer MAX_HEALTH = 20;
integer health = MAX_HEALTH;

show_health(integer h,integer max) {
    llSetText((string)h+"/"+(string)max,<1,1,1>,1);
}

process_collision(integer index) {
    if (llVecMag(llDetectedVel(index))>15) {
        health = health - 1;
        show_health(health,MAX_HEALTH);
        if (health<=0) {
            llSay(0,"boom");
            llDie();
        } else {
            llSay(0,"pow");
        }
    } else {
        llSay(0,"clunk");
    }
}
default {
    state_entry() {
        show_health(health,MAX_HEALTH);
    }
    collision_start(integer n) {
        integer i;
        for (i=0;i<n;i++) process_collision(i);
    }
}

Much better.

And for one final touch, we can make the floaty text be green or yellow or red depending on how damaged the thing is, by just changing the <1,1,1> in show_health(), which causes it to always appear white, to a call to yet another function that will calculate the right color for us.

The final form for today, then:

integer MAX_HEALTH = 20;
integer health = MAX_HEALTH;

vector color_for(integer h,integer max) {
    float ratio = (float)h/(float)max;
    if (ratio>0.666) return <0,1,0>;   // Green
    if (ratio>0.333) return <1,1,0>;   // Yellow
    return <1,0,0>;  // Red
}

show_health(integer h,integer max) {
    llSetText((string)h+"/"+(string)max,color_for(h,max),1);
}

process_collision(integer index) {
    if (llVecMag(llDetectedVel(index))>15) {
        health = health - 1;
        show_health(health,MAX_HEALTH);
        if (health<=0) {
            llSay(0,"boom");
            llDie();
        } else {
            llSay(0,"pow");
        }
    } else {
        llSay(0,"clunk");
    }
}
default {
    state_entry() {
        show_health(health,MAX_HEALTH);
    }
    collision_start(integer n) {
        integer i;
        for (i=0;i<n;i++) process_collision(i);
    }
}

Isn’t Nature Wonderful?

Next time, maybe: target, heal thyself!

Advertisements

2 Responses

  1. […] Combat System Scripting II: slightly buffer target […]

  2. […] have suddenly remembered this here series of combat scripting posts that I was doing the other Geological […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: