Don't click here unless you want to be banned.

LSL Wiki : EcoAnimal09e

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are ia360925.us.archive.org

Animal Scripts v0.9e

by NeverRust

This open-source code is part of the Ecosystem project. Please read the EcosystemDisclaimer before using.
Please do not edit the code below on this page unless you've already tested it to ensure it works. If you make minor changes, please add a note describing the change. For major changes, it's better to start a new wiki page and add a link on the Ecosystem page. Thanks.

Script 1 - Main & Life


////////////////////////////////////////////
  //  Animal/Eco-Name Script by Never Rust  //
 ////////////////////////////////////////////
//  Modified by:                          //
///////////////////////////////////////////

// Modified version of the fish script i wrote for the Flounder
// Added functionality to use the Eco-Name
// To see how it works, see the specialized functions below and look for "!!!!!!!!!" comments below
// Also see the food code (in the "Spore Food" object)



string VersionInfo = "Animal Script v0.9e";
string NamingVersion = "0";

integer IsActive = FALSE;
integer IsBusy = FALSE;

vector BirthSize = <0.3, 0.3, 0.3>; 
vector MaxSize = <1, 1, 1>;
float MaxGrowthStep = 0.1;          // max size increase per growth spurt

float Speed = 2.0;                  // meters per second
integer WanderDist = 5;             // how far does it wander
float TimerTime = 4;               // how often do we hit the timer
//float MaxWaterDepth = 100;           // the max depth the fish likes to swim
float MaxGroundHeight = 2;           // the max height the fish likes to go from the bottom

integer SeedNumber = 1;             // the number of seeds to birth at a time
integer MaxSeedNumber = 6;          // the max # of seeds per lifetime
integer CurrentSeedNumber = 0;      // currently how many seeds have been born
integer MyGeneration;               // generation of plant
integer MaxGeneration = 7;          // max # of generations to prevent

float ActionStartTime;
float ActionTimeMax = 12;
string ActionName;

integer Age;
integer FertileAge = 20;
integer OldAge = 600;
float Health = 100;
integer MaxHealth = 100;
float Energy = 100;
integer MaxEnergy = 100;

integer TargetHandle;

string MyProperName = "Plob";           //!!!!!!!!!! These need to be defined for the Eco-Name
string MyEcoNameVersion = "A0";
string MyEcoType = "A";                     //A=Animal, P=Plant, R=Robot
string MyDietType = "P";


/////////////////################## functions ######################/////////////


//************* F e e d b a c k ***************//

talk(string m) {
    llWhisper(0, "/me "+ m);
}

display(string m, float Wait) {
    llSetText(//ActionName +"("+ (string)IsBusy +")\n"+ 
    m, <0.5, 1.0, 1.0>, 0.8);
    if (Wait > 0.0) {
        llSleep(Wait);
        llSetText("", <0,0,0>, 0.0);
    }
}

debug(string m) {
    llOwnerSay("/me (debug): " + m);
}

TellAboutSelf() {
    talk("is generation " + (string)MyGeneration + " and Age " + (string)Age +". Energy="+ (string)Energy +"/"+ (string)MaxEnergy +", Health="+ (string)Health +"/"+ (string)MaxHealth + "Action: "+ ActionName);
}

//                        ~ ECO-NAME                                                                                     ~//
// These are the standard functions to access the Eco-Name.
// If you're going to make changes these to these, please speak with Never Rust or others working on the
// Eco-system project to establish a new version number.
//
// Version A0 ("alpha zero" / initial testing)
// 0 - Proper Name (unchanging species name)
// 1 - Eco-Name version
// 2 - Type: "P"lant, "A"nimal, "R"obot, etc.
// 3 - Food/Energy amount from root
// 4 - Food/Energy amount from leaf
// 5 - Action ("EAT")
// 6 - Target Key
// 7 - Requested Food (how much you intend on eatting)

SetEcoName(integer FoodRoot, integer FoodLeaf, string Action, key TargetKey, integer EnergyRequested) {
    list EcoName = [MyProperName, MyEcoNameVersion, MyEcoType, FoodRoot, FoodLeaf, Action, TargetKey, EnergyRequested];
    llSetObjectName(llList2CSV(EcoName));
}

string EcoName2ProperName(string name) {
    //if (EcoNameVersion(name) == MyEcoNameVersion) 
    return llList2String(llCSV2List(name), 0);
    //else return "";
}

string EcoNameVersion(string name) {
    return llList2String(llCSV2List(name), 1);
}

integer EcoName2FoodRootAmount(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2Integer(llCSV2List(name), 3);
    else return 0;
}  

integer EcoName2FoodLeafAmount(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2Integer(llCSV2List(name), 4);
    else return 0;
}  
string EcoName2Action(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2String(llCSV2List(name), 5);
    else return "";
}

key EcoName2TargetKey(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2Key(llCSV2List(name), 6);
    else return NULL_KEY;
}

integer EcoName2RequestedFood(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2Integer(llCSV2List(name), 7);
    else return 0;
}



//******************8******** M o v e m e n t *****************************8******//

MoveTo(vector T) {
    IsBusy = TRUE;
    
    AnimateMove(TRUE);

    llTargetRemove(TargetHandle);       // remove last target
    TargetHandle = llTarget(T, 0.1);
    
    vector MyPos = llGetPos();
    llRotLookAt(getRotToPointAxisAt(<1,0,0>, <T.x, T.y, MyPos.z>), 1.0, 1.0);
    
    float distance = llVecDist(MyPos, T);
    
    ModifyEnergy(-distance);
    ActionStartTime = llGetGMTclock();
    llMoveToTarget(T, distance / Speed);

}

StopMove() {

    llStopMoveToTarget();
    llTargetRemove(TargetHandle);

    llApplyImpulse(-llGetMass()*llGetVel(),FALSE);
    
    vector x = llRot2Euler(llGetRot());
    //talk(" --- MyRot ---" + (string)llGetRot() + " -- Euler: " + (string)x);
    
    
  //  vector dir = llVecNorm(targetPos - llGetPos());
  
    rotation rot = llRotBetween(<0.0, 0.0, 0.0>, <x.x, x.y, 0>); 

    llRotLookAt(rot, 0.5, 0.5);
    AnimateMove(FALSE);    
    llSleep(1);
    IsBusy = FALSE;

}
    
    

AnimateMove(integer T) {
    //llSetRot(ZERO_ROTATION);
    llMessageLinked(LINK_ALL_CHILDREN, T, "head down", NULL_KEY);

}


rotation getRotToPointAxisAt(vector axis, vector target) {
    return llGetRot() * llRotBetween(axis * llGetRot(), target - llGetPos());
}

vector CorrectTarget(vector PT) {       // Don't want a land animal to fly or a fish to get out of water
                                        // needs fixin'
    
        float ground = llGround(PT - llGetPos());
        float water = llWater(PT - llGetPos());
        //llSay(0, "PT in: "+ (string)PT + " / ground: "+ (string)ground + " / water" + (string)water + " / MyPos =" + (string)llGetPos()); 
        if (PT.z < (ground + 0.01))  PT = <PT.x, PT.y, ground + 0.01>; 
        //if (PT.z > water)  PT = <PT.x, PT.y, water>;
        if (PT.z - ground > MaxGroundHeight)  PT = <PT.x, PT.y, ground + MaxGroundHeight>;
        //if (PT.z < (water - MaxWaterDepth))  PT = <PT.x, PT.y, water - MaxWaterDepth>;
        
        return PT;
}


//************* The Lifecycle: Birth, Growth, Aging & Reproduction ***************//

Birth() {
    llSetText("",<0,0,0>, 0);
    llSetObjectName(MyProperName);
    talk("is born (" + VersionInfo + " by Never Rust)");
    if (MyGeneration > 0) {
        //llSetScale(BirthSize);
        IsActive = TRUE;
        llSetTimerEvent(TimerTime);
    } else IsActive = FALSE;
    AnimateMove(FALSE);
    Age = 0;
    Energy = MaxEnergy * 0.3;
    CurrentSeedNumber = 0;
    llSetRot(ZERO_ROTATION);
    llSetStatus(STATUS_PHYSICS, TRUE);
    llSetBuoyancy(0.0);
    llGroundRepel(0.3, FALSE, 1.0);

}

Grow(float GrowthFraction) {
    vector size = llGetScale();
    float GrowthFactor = 1 + (MaxGrowthStep * GrowthFraction);
    
    if (CanGrow(size * GrowthFactor)) {
        //talk("is growing. (GrowthFactor: " + (string)GrowthFactor+ ")");
        ResizeAll(GrowthFactor);
    }
}

integer CanGrow(vector newsize) {
    // if we haven't reached max size and we're not in old age
    if (MaxSize.z > newsize.z && Age < OldAge)
        return TRUE;
    else return FALSE;
}

ResizeAll(float scale) {
    llMessageLinked(LINK_SET, -1, (string)scale, NULL_KEY);
}


integer Reproduce() {
    if (CanReproduce()) {
        // reproduce here
        return TRUE;
    } else return FALSE;
}

integer CanReproduce() {
    return FALSE;
}

MakeOlder(integer t) {                          // Increases age and checks for death
                                                // Generation zero is immortal
    if (t > 0) {
        Age += t;
        //if (MyGeneration > 0 && Age == OldAge) display("I'm getting old!", 2);
        if (MyGeneration > 0 && Age >= OldAge) ModifyHealth(-t);
        ModifyEnergy(-t);
    }
    if (MyGeneration > 0 && Health <= 0) Die(); 
}

Die() {
    //llMessageLinked(LINK_SET, TRUE, "DIE", NULL_KEY);
    llDie();
}


//************* Eating, Energy, Health & Combat ***************//

ModifyHealth(float n) {
    Health = Health + n;
    if (Health <= 0) { 
        Health = 0;
        MakeOlder(0);
    }
    else if (Health > MaxHealth) Health = MaxHealth;
}

ModifyEnergy(float n) {
    Energy = Energy + n;
    if (Energy < 0) Energy = 0;
    else if (Energy > MaxEnergy) Energy = MaxEnergy;
}  

integer IsHungry() {
    if (Energy < (0.8 * MaxEnergy)) return TRUE;
    else return FALSE;
}

float Eat(float FoodEnergy) {
    float Hunger = MaxEnergy - Energy;
    if (Hunger > 0) {
        float EatEnergy = 0;
        if (FoodEnergy < Hunger) EatEnergy = FoodEnergy;
        else EatEnergy = Hunger;
    
        ModifyEnergy(EatEnergy);
        display("Yum! (+" + (string)llFloor(EatEnergy) +" / "+ (string)llFloor(Energy) +")", 3);
        display("just ate", 0);
        return EatEnergy;
    } else return 0;
}



//************* Activity ***************//

DoSomething() {
    if (IsActive && Health > 0 && Energy > 0) {

        if (Energy == MaxEnergy) {
            AnimateMove(TRUE);
            display("Zzzz...", 10);
            MakeOlder(10);
            AnimateMove(FALSE);
        }

        llMessageLinked(LINK_SET, IsHungry(), "Look", NULL_KEY);
        //debug("sent look msg");
        
    }
}





//####################### D # E # F # A # U # L # T ###############################//

default
{
    state_entry()
    {
        Birth();

    }
    
    on_rez(integer start_param) {
        //llResetScript();
        MyGeneration = start_param;
        llSleep(2);

        Birth();
    }


    touch_start(integer total_number)       // pauses when touched
    {
        TellAboutSelf();
        
        if (llDetectedKey(0) == llGetOwner()) {
            llTargetRemove(TargetHandle);
        
            IsActive = !IsActive;
        
            if (IsActive) {
                display("", 0);
                //AnimateMove(TRUE);
                llSetTimerEvent(TimerTime);
                DoSomething();
            }
            else {
                ActionName = "";
                IsBusy = FALSE;
                display("INACTIVE", 0);
            
                AnimateMove(FALSE);
                StopMove();
                llSetTimerEvent(0);
                //AnimateSwim(FALSE);
            }
        }
        
    }
    
    object_rez(key child) 
    { 
        // Give copy of child to child
        llGiveInventory(child, llKey2Name(llGetKey())); 
    } 
    
    
    timer()
    {
        if (IsBusy && llGetGMTclock() > ActionStartTime + ActionTimeMax) {
            display("Action timed out", 1);
            ActionName = "";
            StopMove();
        }
        MakeOlder(llFloor(TimerTime));    // it's been at least TimerTime since the last call, so age
        ModifyEnergy(llFloor(TimerTime/2.0));
        if (!IsBusy) {
            ActionName = "";
            DoSomething();
        }
            
    }
    
    at_target(integer tnum, vector targetpos, vector ourpos)
    {
        llTargetRemove(tnum);
        display("reached target", 0.5);
        StopMove();
    }
    not_at_target()
    {
        llApplyImpulse(<0.0, 0.0, 0.01>, FALSE);
    }
        

    
    collision(integer num_detected)                                 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
    {
        if (EcoName2TargetKey(llKey2Name(llGetKey())) == llDetectedKey(0)   // if we hit the targeted obj
                && EcoName2Action(llKey2Name(llGetKey())) == "EAT")         // and eating it...
        {
            StopMove();
            
            integer FoodAmount = EcoName2FoodRootAmount(llDetectedName(0));
            if (FoodAmount > 0) {                                   // if it gives energy then eat and remember
                Eat(FoodAmount);
                
                llMessageLinked(LINK_SET, FoodAmount, (string)llDetectedPos(0), llDetectedKey(0));  // Send info to script 2 for memory
                //AddFoodMemory(EcoName2ProperName(llDetectedName(0)), FoodAmount, llDetectedPos(0));
            } else {
                llMessageLinked(LINK_SET, 0, "Inedible", llDetectedKey(0));     // remember what's not edible
                //RememberInedible(EcoName2ProperName(llDetectedName(0)));
            }
            
            
        } else if (FALSE) {
            // check predator list
        } else {


        }
    }
        
        
    link_message(integer sender_num, integer num, string str, key id)   // used for growing
    {
         if(sender_num == 1) {
             if (num == -2) {
                MoveTo((vector)(str));
            }
        
        
            if (num == -1) {
                float scale = (float)str; // size factor
                list primparams = [PRIM_SIZE, llGetScale() * scale];    //resize
        
                llSetPrimitiveParams(primparams);
            }
        }
        

    }
        
}


Script 2 - Scanning & Memory



//////////    2     ///////////

integer IsHungry = FALSE;

list FoodMemory = [];
list PredatorMemory = [];
list FriendsMemory = [];
list InedibleMemory = [];

string MyProperName = "Plob";           //!!!!!!!!!! These need to be defined for the Eco-Name
string MyEcoNameVersion = "A0";
string MyEcoType = "A";                     //A=Animal, P=Plant, R=Robot
string MyDietType = "P";


/////////////////################## functions ######################/////////////

//************* F e e d b a c k ***************//

debug(string m) {
    llOwnerSay("/me (debug): " + m);
}

display(string m, float Wait) {
    llSetText(//ActionName +"("+ (string)IsBusy +")\n"+ 
    m, <0.5, 1.0, 1.0>, 0.8);
    if (Wait > 0.0) {
        llSleep(Wait);
        llSetText("", <0,0,0>, 0.0);
    }
}

//                        ~ ECO-NAME                                                                                     ~//
// These are the standard functions to access the Eco-Name.
// If you're going to make changes these to these, please speak with Never Rust or others working on the
// Eco-system project to establish a new version number.
//
// Version A0 ("alpha zero" / initial testing)
// 0 - Proper Name (unchanging species name)
// 1 - Eco-Name version
// 2 - Type: "P"lant, "A"nimal, "R"obot, etc.
// 3 - Food/Energy amount from root
// 4 - Food/Energy amount from leaf
// 5 - Action ("EAT")
// 6 - Target Key
// 7 - Requested Food (how much you intend on eatting)

SetEcoName(integer FoodRoot, integer FoodLeaf, string Action, key TargetKey, integer EnergyRequested) {
    list EcoName = [MyProperName, MyEcoNameVersion, MyEcoType, FoodRoot, FoodLeaf, Action, TargetKey, EnergyRequested];
    llSetObjectName(llList2CSV(EcoName));
}

string EcoName2ProperName(string name) {
    //if (EcoNameVersion(name) == MyEcoNameVersion) 
    return llList2String(llCSV2List(name), 0);
    //else return "";
}

string EcoNameVersion(string name) {
    return llList2String(llCSV2List(name), 1);
}

integer EcoName2FoodRootAmount(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2Integer(llCSV2List(name), 3);
    else return 0;
}  

integer EcoName2FoodLeafAmount(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2Integer(llCSV2List(name), 4);
    else return 0;
}  
string EcoName2Action(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2String(llCSV2List(name), 5);
    else return "";
}

key EcoName2TargetKey(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2Key(llCSV2List(name), 6);
    else return NULL_KEY;
}

integer EcoName2RequestedFood(string name) {
    if (EcoNameVersion(name) == MyEcoNameVersion) return llList2Integer(llCSV2List(name), 7);
    else return 0;
}


//************* Eating, Energy, Health & Combat ***************//

AddFoodMemory(string FoodName, float FoodEnergy, vector FoodPos) {
    if (llGetListLength(FoodMemory) > 6) FoodMemory = llDeleteSubList(FoodMemory, 0, 0);
    FoodMemory += [FoodName];    
    // change to a more organized FoodMemory list of [FoodName, FoodEnergy, FoodPos]
    // check to make sure the foodname isn't already there
    // if it is, then update the pos and energy
}
    
    
RememberInedible(string FoodName) {
    if (llGetListLength(InedibleMemory) > 6) InedibleMemory = llDeleteSubList(InedibleMemory, 0, 0);
    InedibleMemory += [FoodName];
}

//************* Sensory & Communication ***************//

LookAround() {
    llSensor("", NULL_KEY, ACTIVE | PASSIVE, 10, TWO_PI);
}

PostScan(list SpottedFood, list SpottedUnknown, list SpottedPredators, list SpottedFriends) {   

        //debug("--MEM:" + (string)llGetFreeMemory());
        //debug("--Food:" + llList2CSV(SpottedFood));
        //debug("--??:" + llList2CSV(SpottedUnknown));
        //debug("--Preds:" + llList2CSV(SpottedPredators));
        //debug("--Amigos:" + llList2CSV(SpottedFriends));
        
        display("Figuing out what to do...", 0.3);
      
        string PredatorToFear = IsDangerous(SpottedPredators);
        if (PredatorToFear != "") {
            // run away from him
            
        } else if (IsHungry) {                                                       
            if (llGetListLength(SpottedFood) > 0) {
                
                display("I see something I like to eat!", 1);
                
                integer FoodNum = 0;                                    // Should look for nearest
                                                                        // for now, just use first one
                vector TargetPos = llList2Vector(SpottedFood, FoodNum + 1); 
                key TargetKey = llList2Key(SpottedFood, FoodNum + 2);
                
                                                                    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
                string ActionName = "EAT";
                SetEcoName(0, 0, ActionName, TargetKey, 100);       // before trying to eat an object, you
                                                                    // must set your Eco-Name so that
                                                                    // your action is "EAT" and you are
                                                                    // targeting the food's key
                llMessageLinked(LINK_SET, -2, (string)(TargetPos), NULL_KEY);

            } else if (llGetListLength(SpottedUnknown) > 0) {
                
                integer FoodNum = 0;                                    // Should look for nearest
                                                                        // for now, just use first one
                vector TargetPos = llList2Vector(SpottedUnknown, FoodNum + 1); 
                key TargetKey = llList2Key(SpottedUnknown, FoodNum + 2);
                
                display("I'll try to eat the nearest unknown object...", 0);
                string ActionName = "EAT";
                SetEcoName(0, 0, ActionName, TargetKey, 100);
                llMessageLinked(LINK_SET, -2, (string)(TargetPos), NULL_KEY);
            }
            
        } //else if (want to socialize) {
          //  do something social
        //} 

}

string IsDangerous(list SpottedPredators) {
    
    // go thru list, return the name of the predator to fear, if any
    return "";
}



//####################### D # E # F # A # U # L # T ###############################//

default
{
    state_entry()
    {
        //llSay(0, "Hello, Avatar!");
    }

    touch_start(integer total_number)
    {
        //llSay(0, "Touched.");
    }
    
    sensor(integer num_detected) 
    {
        
        display("I see " + (string)num_detected + " things.", 0.5);
        if (num_detected > 0) {
            
            list SpottedFood = [];
            list SpottedUnknown = [];
            list SpottedPredators = [];
            list SpottedFriends = [];
        
            display("Categorizing everything...", 0.3);
            integer i;
            integer t;
            for (i = 0; i < num_detected; i++) {                        // look at all things sensed  
                string SeeName = EcoName2ProperName(llDetectedName(i));
                vector SeePos = llDetectedPos(i); 
                key SeeKey = llDetectedKey(i);
                integer Found = FALSE;
                
                for (t = 0; t < llGetListLength(FoodMemory); t++) {    // compare to list of food
                    if (SeeName == llList2String(FoodMemory, t)) {
                        SpottedFood += [SeeName, SeePos, SeeKey];
                        Found = TRUE;
                    }
                }
                
                for (t = 0; t < llGetListLength(PredatorMemory) && !Found; t++) {    // compare to list of predators
                    if (SeeName == llList2String(PredatorMemory, t)) {
                        SpottedPredators += [SeeName, SeePos, SeeKey];
                        Found = TRUE;
                    }
                }
                
                for (t = 0; t < llGetListLength(FriendsMemory) && !Found; t++) {    // compare to list of friends
                    if (SeeKey == llList2String(FriendsMemory, t)) {
                        SpottedFriends += [SeeName, SeePos, SeeKey];
                        Found = TRUE;
                    }
                }

                
                for (t = 0; t < llGetListLength(InedibleMemory) && !Found; t++) {     // compare to list of things known to be inedible
                    
                    if (SeeName == llList2String(InedibleMemory, t)) {
                        Found = TRUE;
                    }
                }
                
                if (!Found) SpottedUnknown += [SeeName, SeePos, SeeKey];
            }
            
           PostScan(SpottedFood, SpottedUnknown, SpottedPredators, SpottedFriends); // decide what to do!
            

        }
    }
    
    link_message(integer sender_num, integer num, string str, key id)
    {
        if (sender_num == 1) {
            if (str == "Look") {
                IsHungry = num;
                LookAround(); 
            
            } else if (str == "Inedible") {                                 // get inedible collisions from script 1 to remember
                RememberInedible( EcoName2ProperName(llKey2Name(id)) );
                
            } else if (id != NULL_KEY && num > 0) {                         // get food collisions from script 1 to remember
                AddFoodMemory( EcoName2ProperName(llKey2Name(id)), num, (vector)str );
                
            
            }            
        }
    }
}


EcosystemWorkingGroup | Ecosystem
There is no comment on this page. [Display comments/form]