Join us in Outworldz at www.outworldz.com:9000 or follow us:

Animated Zombie  Script

This animated script makes a zombie walk around waving his arms and it makes it fall apart when you click it to death. You can ride the zombie and kill it over and over again.  This system works in Second Life only (not OpenSim). This Zombie is based upon a build by Eric90MX.

First, get the Zombie and the textures and sound  from this zip file:

Zip file

Log into Second Life and upload the zombie as a DAE mesh file:
Zombie uploader

You can set the Level of Detail (LOD) to all zeros to get the minimum number of prims possible.

Now select the Physics tab and set it to zero:
{hysics tab

Now set the size to 0.2

Textures

Rez the zombie in world. Apply the textures for the bloody face and feet, then apply the jeans texture to all of it's surfaces. You should get this:

Edit the zombie and set it to physics type None:

Set physics to None

 

Add a single cube prim under the zombie, make it flat and wide, and set the Shape to Prim and the Type to GLASS (glass has lowest friction ).

Physics Prim

Prim animation

This zombie uses two scripts from my Prim Animation Compiler project. You will need to get those two scripts and add them to the zombie base.

Put both animator scripts in the zombie and record these animations:

stand      Just standing there, every prim reset to a start position. Move all of them slightly, except the root prim
attack     Arm waving, whetever  it needs to do when it reaches a waypoint
left       Left foot forward
right      ditto
hit        when clicked, it play this movement.   Make his head lean back and his arms go out
bighit    when clicked and you get a big hit, it will play this movement.   Make his head fall off and his body lean way back, or fall over 
die        fall to pieces - scatter all the prims around on the ground.

The sequence you will use is to click the zombie to get a menu. Then Click NAME, type in the name "stand", move the prims so the zombie is standing, then click RECORD. Click NAME again, type in "attack", and move the zombie where it appears to be trying to grab you. Click RECORD. Repeat until you have recorded all the above animations.

When done, click COMPILE, and copy and paste the output into a new script. Search and Replace the Date and Time stamps, and save it.

Follow the instructions in the Compiler article for more details.

Sounds

Once you have animated each movement, and saved them in a script, you should add these sound files:

footstepmuffled.wav

Monster1.wav

Zdeath.wav

Monster2.wav

Pose ball script:

Add one more prim near the back of the zombie.  Do not link it, we will need to adjust it first.

Upload this animation and add it to the prims inventory:

piggyback-sit.bvh

These are the settings for the upload:   Priority should be 4 so it overrides your AO, and it should have looped checked.

Animation settings

Now add this script to the new prim:

 

// Send a link message to another script when sat on or unsat
// will play back the first animation it finds in inventory

// position to sit on the ball e.g <0.0, 0.0, 0.43>
// sit  1.7 metes above the base., slight backwards 
vector POSITION=<0.6, 0.0,1.7>;

// Just code below here

string animation;

default
{
    state_entry()
    {
        llSetSitText("Ride Me");
        llSitTarget(POSITION, ZERO_ROTATION);
    }

    changed(integer change)
    {
        if (change & CHANGED_LINK)
        {
            if (llAvatarOnSitTarget() != NULL_KEY)
            {
                llRequestPermissions(llAvatarOnSitTarget(), PERMISSION_TRIGGER_ANIMATION);
            }
            else
            {
                integer perm=llGetPermissions();
                if ((perm & PERMISSION_TRIGGER_ANIMATION) && llStringLength(animation)>0)
                    llStopAnimation(animation);
                animation="";
                llMessageLinked(LINK_SET,2,"unsit",llAvatarOnSitTarget()); 
            }
        }
    }
    run_time_permissions(integer perm)
    {
        if (perm & PERMISSION_TRIGGER_ANIMATION)
        {
            llStopAnimation("sit");
            animation=llGetInventoryName(INVENTORY_ANIMATION,0);
            llStartAnimation(animation);
            llMessageLinked(LINK_SET,2,"sit",llAvatarOnSitTarget()); // left foot forward

        }
    }

}

 

Now that you have the script and animation in the prim, right click and sit on the prim by selecting RIDE ME.

Position the prim behind the zombie so that you appear to be riding it.

Ride em!

  When you have it correctly positioned, hop off, select the prim and then the zombie last,. and press Ctrl-L to link them. 

 

Now go into edit linked parts, and set the alpha on the riding prim to 1.00 Alpha to make it invisible:

100% alpha

 

Zombie Script

Now its time to ride!

 

Add the zombie script to the base of the zombie.

 

Zombie script:

// Animated wandering rideable zombie script.
// by Ferd Frederix
//  Sets Home point where rezzed.
//  Will drive around like a vehicle so it works on most surfaces.

// Sounds:
// footstepmuffled when walking
// Zdeath when clicked
// Monster2 and Monster1 sounds when it reaches a destination

// Some tunables:

integer debug = FALSE;

float forward_power = 3; //Power used to go forward (1 to 30), massive objects may need larger number
float reverse_power = -2; //Power ued to go reverse (-1 to -30)
float turning_ratio = .5; //How sharply the vehicle turns. Le
vector start_pos;          // home point     

vector Destination;        // we head thataway
float roam_range = 10;     // and go no furtherfrom home than this
float STRENGTH = 4.0;  // how hard to turn, bigger = ?
float DAMPING = 0.2;    // and how soon
vector direction = <6,0,0>; // push 3
vector last_pos = <0,0,0>;  // save last position so we can detect when to walk
vector curpos;            // you are here
list buttons = ["Range","Home","Help"];
integer listener;           // handle for menus to use
key Owner;                    // you
integer channel;            // random channel for listener
integer counter = 0;       // l-r walk counter
key agent ;
float FORCE = 1;            // bigger numbers make us move faster
integer timeout;            // give us the gas if we are late


DEBUG(string str)
{
    if (debug)
    llOwnerSay(str);
}
// talk Menu to the client

tMenu()
{
    channel = llCeil(llFrand(10000) + 876);
    listener = llListen(channel,"","","");
    llDialog(Owner,"Choose an item",buttons,channel);
}

// sets up the vehicle as a car
Physics()
{
    llSetBuoyancy(0.0);    
    llSetVehicleFlags(-1);
    llSetVehicleType(VEHICLE_TYPE_CAR);
    llRemoveVehicleFlags(VEHICLE_FLAG_LIMIT_MOTOR_UP | VEHICLE_FLAG_LIMIT_ROLL_ONLY);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0.8);
    llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 0.8);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, .1);
    llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, .1);
    llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.8);  // hover for lightnes on massive objects
    llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, .1);
    llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, .1);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, .1);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, .1);
    llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <1.0, .1, 1000.0>);
    llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <.1, .1, .1>);
    llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, .8);
    llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, .1);
    llSetVehicleFloatParam(VEHICLE_BANKING_EFFICIENCY, 0.25);
    llSetVehicleFloatParam(VEHICLE_BANKING_TIMESCALE, 0.1);

}

// points the animal in the correct diriction and give it a walk-like push
DoMove()
{
    llStopLookAt();
    llPlaySound("footstepmuffled",1.0);
    llRotLookAt(llRotBetween(<1,0,0>, Destination - llGetPos()), STRENGTH, DAMPING);
    llSleep(DAMPING*3);
    llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, FORCE * direction);
    llSleep(0.1);
    llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, ZERO_VECTOR);

}

// get a new destination
next_move()
{
    // random direction and height        // we will ignore Y
    Destination = llGetPos();
    Destination.x += llFrand(roam_range *2 ) - roam_range;    // +/- roam range
    Destination.y += llFrand(roam_range *2 ) - roam_range;
}

DoMenu(string msg)
{

    if (msg == "Range")
    {
        llDialog(Owner,"Range from Home:",["5","10","15","20","25","30","40","50","75"],channel);
    }
    else if (msg == "Home")
    {
        start_pos = llGetPos(); // remember our home
        llListenRemove(listener);
        llOwnerSay("Home is set, wander distance is set to " + (string) roam_range + " meters");
    }
    else if (msg == "Help")
    {
        llLoadURL(Owner,"Click for Help", "http://www.outworldz.com/Secondlife/Posts/Prim-Animator");
        llListenRemove(listener);
    }
    else
    {
        roam_range = (float) msg;
        llOwnerSay("Range set to " + (string) roam_range + " meters");
        llListenRemove(listener);
    }

}

integer score;

// startup state where we sit, stand and wag tail
default
{
    state_entry()
    {
         llSetStatus(STATUS_PHYSICS, FALSE);

        Owner = llGetOwner();
        llOwnerSay("Range set to " + (string) roam_range + " meters");
        llOwnerSay("Home set to this spot");
        llOwnerSay("Click me for help");
        start_pos = llGetPos(); // remember our home

        state sitting;
    }
}

state sitting
{
    state_entry()
    {
        llSetStatus(STATUS_PHYSICS, FALSE);


        llOwnerSay("Animation test");
        llOwnerSay("stand");
        llMessageLinked(LINK_SET,1,"stand","");
        llSleep(1);

        llOwnerSay("attack");
        llMessageLinked(LINK_SET,1,"attack","");
        llSleep(1);

        llOwnerSay("walking");
        llMessageLinked(LINK_SET,1,"stand","");
        llMessageLinked(LINK_SET,1,"left","");
        llSleep(0.5);
        llMessageLinked(LINK_SET,1,"right","");
        llSleep(0.5);
        llMessageLinked(LINK_SET,1,"left","");
        llSleep(0.5);
        llMessageLinked(LINK_SET,1,"right","");
        llSleep(0.5);


        llOwnerSay("hit");
        llMessageLinked(LINK_SET,1,"hit","");
        llSleep(1);

        llOwnerSay("bighit");
        llMessageLinked(LINK_SET,1,"stand","");
        llMessageLinked(LINK_SET,1,"bighit","");
        llSleep(2);
        llMessageLinked(LINK_SET,1,"die","");
        llSleep(2);

        llMessageLinked(LINK_SET,1,"stand","");
        llOwnerSay("Test end");

        state  moving;
    }



    on_rez(integer p)
    {
        llResetScript();
    }


}

// walking around
state moving
{
    state_entry()
    {
        Physics();
        llMessageLinked(LINK_SET,1,"stand",""); // stand on all 4's
        llSetStatus(STATUS_PHYSICS, TRUE);      // get ready to move
        llSetTimerEvent(0.5);
    }

    listen(integer channel,string name, key id, string msg)
    {
        DoMenu(msg);
    }

    touch_start(integer n)
    {
        if (llDetectedKey(0) == Owner)
            tMenu();
            
           
        if (llFrand(5.0)  < 3)
        {
            llPlaySound("Zdeath",1.0);
            llMessageLinked(LINK_SET,1,"hit",""); // smack it
            score++;
        }
        else
        {
            llPlaySound("Zdeath",1.0);
            llMessageLinked(LINK_SET,1,"hit",""); // smack it
            score+=3;
        }

        llSleep(1);
        llMessageLinked(LINK_SET,1,"stand","");

        if (score > 10) 
        {
            llMessageLinked(LINK_SET,1,"die","");
            llSleep(20.0);
            llMessageLinked(LINK_SET,1,"stand","");
            score = 0;
        }
    }


    timer()
    {
        DoMove();


        if (llVecDist(last_pos, llGetPos()) > .1)
        {
            
            llMessageLinked(LINK_SET,1,"left",""); // left foot forward
            llSleep(.3);
            llMessageLinked(LINK_SET,1,"right",""); // right foot forward;
            last_pos = llGetPos();
        }
        
        if (llVecDist(start_pos,llGetPos()) > roam_range + 2)
        {
            DEBUG("too far");
            timeout++;
            Destination = start_pos;
            FORCE = timeout /2;
            llPlaySound("Monster2",1.0);
            llMessageLinked(LINK_SET,1,"attack","");
        }
        else
        {
            timeout = 0;
            FORCE = 1;
        }

        if (llVecDist(start_pos,llGetPos()) < .5)       // at home
        {
            DEBUG("at home");
            llPlaySound("Monster2",1.0);
            llMessageLinked(LINK_SET,1,"attack","");

            next_move();
        }
        vector myPos = llGetPos();
        
        if (llVecDist(,myPos) < .5)     // at destination in X and Y only
        {
            
            DEBUG("at dest");
            llMessageLinked(LINK_SET,1,"attack","");
            llPlaySound("Monster1",1.0);
            llSleep(2);
            llMessageLinked(LINK_SET,1,"stand","");
            next_move();
        }


    }

    on_rez(integer p)
    {
        llResetScript();
    }

    link_message(integer sender,integer num,string str, key id)
    {
        if (num ==2)
        {
            if (str == "sit")
            {
                agent = id;
                state riding;
            }
            else
            {
                llSleep(.1);
                llReleaseControls();
                llMessageLinked(LINK_SET,1,"die","");
                llSleep(5);
                llMessageLinked(LINK_SET,1,"stand","");


                state moving;
            }
        }
    }


}

state riding
{
    state_entry()
    {
        Physics();
        llWhisper(0,"Use the arrow keys to control the zombie");
        llSetStatus(STATUS_PHYSICS, TRUE);      // get ready to move
        llStopLookAt();
        llRequestPermissions(agent, PERMISSION_TAKE_CONTROLS);
    }
    run_time_permissions(integer perm)
    {
        if (perm)
        {
            llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_DOWN | CONTROL_UP | CONTROL_RIGHT |
                CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT, TRUE, FALSE);
            llSetTimerEvent(.5);
        }
    }

    timer()
    {
        if (llVecDist(curpos,llGetPos()) > 0.2)
        {
            curpos = llGetPos();
            if (counter++ %2 == 0)
                llMessageLinked(LINK_SET,1,"left",""); // left foot forward
            else
                llMessageLinked(LINK_SET,1,"right",""); // right foot forward
        }
    }

    control(key id, integer level, integer edge)
    {
        // llOwnerSay((string) edge);
        integer reverse=1;
        vector angular_motor;

        //get current speed
        vector vel = llGetVel();
        float speed = llVecMag(vel);

        //car controls
        if(level & CONTROL_FWD)
        {
            llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,  );
            reverse=1;
        }
        if(level & CONTROL_BACK)
        {
            llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,  );
            reverse = -1;
        }

        if(level & (CONTROL_RIGHT|CONTROL_ROT_RIGHT))
        {
            angular_motor.z -= speed / turning_ratio * reverse;
        }

        if(level & (CONTROL_LEFT|CONTROL_ROT_LEFT))
        {
            angular_motor.z += speed / turning_ratio * reverse;
        }

        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, angular_motor);

    } //end control

    link_message(integer sender,integer num,string str, key id)
    {
        if (num ==2)
        {
            if (str == "sit")
            {
                agent = id;
                state riding;
            }
            else
            {
                llSleep(.1);
                llReleaseControls();
                llMessageLinked(LINK_SET,1,"die","");
                llSleep(5);
                
                state moving;
            }
        }
    }

    on_rez(integer p)
    {
        llResetScript();
    }
}

Uses

The zombie should start to move around.  Click the zombie to set the distance it is allowed to roam.  Have someone click the zombie. It should animate each time they click it.  If they click it enough, it should fall apart, then re-assemble itself.

Now right click the zombie and select RIDE ME.  You should be able to drive the zombie around.    When you hop off, it will fall apart, reassemble iteself and then walk back home.

 

 

 

 

.