moved to single script repository folder for the actual scripts. updated readme.
[feisty_meow.git] / huffware / huffotronic_eepaw_knowledge / huff-pet_v18.6.txt
diff --git a/huffware/huffotronic_eepaw_knowledge/huff-pet_v18.6.txt b/huffware/huffotronic_eepaw_knowledge/huff-pet_v18.6.txt
deleted file mode 100755 (executable)
index 1397e17..0000000
+++ /dev/null
@@ -1,963 +0,0 @@
-
-// huffware script: huff-pet, by fred huffhines
-//
-// this is yet another implementation of a pet script in LSL.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//to-do zone:
-
-//hmmm: for attack mode, adjust timers and ranges.
-//  probably just define the default set and mirror that with the attack set.
-//  switch between them during mode change.
-//  reset timer and sensor for mode change!
-
-// end to-do zone.
-
-// constants for the pet that one might want to change.
-
-integer PET_CHAT_CHANNEL = 28;
-    // the channel on which the pet will listen for commands from the owner.
-
-//integer DEFAULT_PANIC_DISTANCE = 28;
-integer DEFAULT_PANIC_DISTANCE = 5;//short leash version for opensim.
-    // multiplied by the sensor range to get the distance allowed from the
-    // pet to the person it's following before a teleport is invoked.
-integer ATTACK_PANIC_DISTANCE = 13;
-    // multiplied by the sensor range to get the distance allowed from the
-    // enraged pet to the attack target before a teleport is invoked.    
-
-float DEFAULT_HEIGHT_ABOVE_FOLLOWED_OBJECT = 1.6;
-    // the height that the pet will float at above whoever it's following.
-float ATTACK_HEIGHT_ABOVE_FOLLOWED_OBJECT = 0.0;
-    // the height that the pet will float at above the attack target.
-
-float DEFAULT_BASE_VELOCITY = 0.1;
-    // the velocity of the pet when just cavorting around.
-float ATTACK_BASE_VELOCITY = 0.6;
-    // the velocity of the pet when in "angry" mode.
-
-integer DEFAULT_BUMP_SIZE = 48;
-    // the default size in meters of the displacement caused by up, down, etc commands.
-
-// the margin values below are the range of motion that the pet is allowed
-// on each axis.
-float DEFAULT_X_MARGIN = 3.0;
-float DEFAULT_Y_MARGIN = 3.0;
-float DEFAULT_Z_MARGIN = 1.0;
-// the margin for when the pet is attacking.
-float ATTACK_X_MARGIN = 0.1;
-float ATTACK_Y_MARGIN = 0.1;
-float ATTACK_Z_MARGIN = 0.2;
-
-float MAXIMUM_TARGETING_DISTANCE = 2.0;
-    // the amount of basic deviation allowed for the pet from its target spot.
-    // this is how far it's allowed to roam from the target.
-//is that right?
-
-float ATTACK_PUSH_DIST_THRESHOLD = 2.0;
-    // how close the pet should be to an attack target before trying to push.
-float ATTACK_PUSH_MAGNITUDE = 2147483646.0;  //maxint - 1, dealing with svc-2723.
-    // how much the critter should push an attack target.
-float ATTACK_PUSH_CHANCE = 0.1;
-    // how often (probability from 0.0 to 1.0) an attack target gets pushed.
-
-// other constants that are more advanced and should generally not change...
-
-float TARGETING_SENSOR_RANGE = 96.0;
-    // the maximum distance the pet will try to see the target at.
-    
-float SENSOR_INTERVAL = 0.4;
-    // how often the sensor scan will fire off.  this is the fastest we will
-    // check for our follow target, in seconds.
-
-float PERIODIC_INTERVAL = 0.42;
-    // how frequently our timer event fires.
-
-integer MAXIMUM_SLACKNESS = 28;
-    // how many timer hits we'll allow before reverting to the default state.
-
-float VELOCITY_MULTIPLIER = 1.2;
-    // the total velocity comes from the base plus an equation that multiplies
-    // this value by some function of the distance.
-
-string PET_MENU_NAME = "#woof";  // name for our menu.
-string PET_REPLY_MENU = "#aroo";  // replies with data.
-
-// symbolic labels for the different states of pet 'being'.
-integer STATE_STAY = 0;
-integer STATE_FREE = 1;  // go home.
-integer STATE_FOLLOW = 2;
-integer STATE_COME = 3;
-integer STATE_WANDER = 4;
-integer STATE_ATTACK = 9;
-
-list SUPPORTED_COMMANDS = [ "go home", "come", "stay",
-    "wander", "follow", "attack",
-    "set home", "set name", "status" ];
-    // attack = follow an avatar in a menacing way.
-    // come = follow owner.
-    // follow = follow an avatar.
-    // go home = return home, then move about freely.
-    // set home = set the home position based on owner location.
-    // set name = change the object's name.
-    // stay = sit right there.
-    // wander = roam a greater distance while following owner.
-
-// requires: jaunting library v3.4 or higher.
-//////////////
-// do not redefine these constants.
-integer JAUNT_HUFFWARE_ID = 10008;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-// commands available via the jaunting library:
-string JAUNT_COMMAND = "#jaunt#";
-    // command used to tell jaunt script to move object.  pass a vector with the location.
-string FULL_STOP_COMMAND = "#fullstop#";
-    // command used to bring object to a halt.
-string REVERSE_VELOCITY_COMMAND = "#reverse#";
-    // makes the object reverse its velocity and travel back from whence it came.
-string SET_VELOCITY_COMMAND = "#setvelocity#";
-    // makes the velocity equal to the vector passed as the first parameter.
-string JAUNT_UP_COMMAND = "#jauntup#";
-string JAUNT_DOWN_COMMAND = "#jauntdown#";
-    // commands for height adjustment.  pass a float for number of meters to move.
-string JAUNT_LIST_COMMAND = "#jauntlist#";
-    // like regular jaunt, but expects a list of vectors as the first parameter; this list
-    // should be in the jaunter notecard format (separated by pipe characters).
-    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
-//
-//////////////
-
-//requires menutini library v4.2 or better.
-//////////////
-// do not redefine these constants.
-integer MENUTINI_HUFFWARE_ID = 10009;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-// commands available via the menu system:
-string SHOW_MENU_COMMAND = "#menu#";
-    // the command that tells menutini to show a menu defined by parameters
-    // that are passed along.  these must be: the menu name, the menu's title
-    // (which is really the info to show as content in the main box of the menu),
-    // the wrapped list of commands to show as menu buttons, the menu system
-    // channel's for listening, and the key to listen to.
-    // the reply will include: the menu name, the choice made and the key for
-    // the avatar.
-//
-//////////////
-
-
-request_full_stop()
-{
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, FULL_STOP_COMMAND, "");
-}
-
-request_jaunt_up(integer distance)
-{
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_UP_COMMAND, (string)distance);
-}
-
-// global variables...
-
-key _OWNER;
-integer current_state;
-vector home_position;  // the location where the pet lives.
-
-integer pending_target = FALSE;  // is a target still being sought.
-
-integer  _COMMAND_CHANNEL;
-string   _COMMAND_MESSAGE   = "How may I assist you?";
-
-integer  _TARGET_ID;
-vector TARGET_POSITION;
-
-float    _FREE_RANGE        =  10.0;
-
-string SIT_TEXT = "Meditate";
-
-string SIT_ANIMATION = "yoga_float";
-
-vector SIT_POSITION = <0.2, 0.2, 0.4>;
-
-vector SIT_ROTATION = <0.0, 0.0, 0.0>;
-
-key      SITTING_AVATAR_KEY           = NULL_KEY; 
-
-// options for follow menu that pops up when pet is told to follow someone.
-list     _FOLLOW_KEY;
-list     _FOLLOW_NAME;  // filled in with nearby avatars.
-integer  _FOLLOW_CHANNEL;
-string   _FOLLOW_MESSAGE = "Who should I follow?";
-
-integer  seeking_avatars         = FALSE;
-key      KEY_OF_TARGET;
-
-//////////////
-
-// from hufflets...
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    }
-    return -1;
-}
-
-///////////////
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay((string)debug_num + "- " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, (string)debug_num + "- " + to_say);
-}
-
-///////////////
-
-// info...
-
-// returns a string version of the state 's'.
-string name_for_state(integer s) {
-    if (s == STATE_STAY) return "stay";
-    if (s == STATE_FREE) return "go home";
-    if (s == STATE_FOLLOW) return "follow";
-    if (s == STATE_COME) return "come";
-    if (s == STATE_WANDER) return "wander";
-    if (s == STATE_ATTACK) return "attack";
-    return "unknown";
-}
-
-// menu methods...
-
-list current_buttons;  // holds onto the set of menu options.
-
-integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
-
-string stringize_list(list to_flatten) {
-    return llDumpList2String(to_flatten, HUFFWARE_ITEM_SEPARATOR);
-}
-
-// pops up a menu to interact with the pet's owner.
-show_menu(string menu_name, string title, list buttons, integer channel)
-{
-    current_buttons = buttons;
-    key listen_to = _OWNER;
-    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
-        menu_name + HUFFWARE_PARM_SEPARATOR
-        + title + HUFFWARE_PARM_SEPARATOR + stringize_list(current_buttons)
-        + HUFFWARE_PARM_SEPARATOR + (string)channel
-        + HUFFWARE_PARM_SEPARATOR + (string)listen_to);
-}
-
-// causes a state change to make the pet stay.
-enter_stay_state()
-{
-    current_state = STATE_STAY;
-    llSensorRemove();
-    stop_pet();
-}
-
-// handle the response message when the user chooses a button.
-react_to_menu(integer sender, integer num, string msg, key id)
-{
-log_it("react menu: " + msg + " parm=" + (string)id);
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string menu_name = llList2String(parms, 0);
-    string choice = llList2String(parms, 1);
-
-    if ( (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE) || (msg != SHOW_MENU_COMMAND) ) {
-log_it("why here in react to menu, not for us?");
-        return;
-    }
-
-    if (menu_name == PET_MENU_NAME) {
-log_it("react: snd=" + (string)sender + " num=" + (string)num + " msg=" + msg + " key=" + (string)id);
-        if (find_in_list(SUPPORTED_COMMANDS, choice) < 0) {
-            llOwnerSay("i don't know what you mean...");
-            return;
-        }
-llOwnerSay("i heard you tell me: menu=" + menu_name + " choice=" + choice);
-    
-        // handle commands that are major changes in state...
-    
-        if (choice == "come") {
-            llOwnerSay("coming to find you now...");
-            current_state = STATE_COME;
-            llSetPrimitiveParams([PRIM_PHYSICS, TRUE,
-            //]);
-            PRIM_PHANTOM, TRUE]);
-            llSensorRemove();
-            llSensorRepeat("", _OWNER, AGENT, TARGETING_SENSOR_RANGE, PI, SENSOR_INTERVAL);
-        }
-        
-        if (choice == "stay") {
-            llOwnerSay("i will stay right here...");
-            enter_stay_state();
-        }
-        
-        if (choice == "wander") {
-            current_state = STATE_WANDER;
-            llOwnerSay("i'm going to wander around and kind of vaguely follow you...");
-            llSetPrimitiveParams([PRIM_PHYSICS, TRUE,
-            //]);
-             PRIM_PHANTOM, TRUE]);
-            llSensorRemove();
-            llSensorRepeat("", _OWNER, AGENT, TARGETING_SENSOR_RANGE, PI, SENSOR_INTERVAL);
-        }
-        
-        if ( (choice == "follow") || (choice == "attack") ) {
-            seeking_avatars = TRUE;
-            stop_pet();
-            llSensorRemove();
-            if (choice == "attack") {
-    // we only attack avatars.
-    //or not.  since that's boring.  watching a pet attack a physical object is fun.
-                llSensor("", NULL_KEY, AGENT | ACTIVE, TARGETING_SENSOR_RANGE, PI);
-                current_state = STATE_ATTACK;
-            } else {
-                // look for both objects and avatars to follow.
-                llSensor("", NULL_KEY, AGENT | ACTIVE, TARGETING_SENSOR_RANGE, PI);
-                current_state = STATE_FOLLOW;
-            }
-        }
-        
-        if (choice == "go home") {
-            current_state = STATE_FREE;  // free to roam about the cabin, or wherever home is.
-            llOwnerSay("i'm going home now.");
-            jaunt_to_location(home_position);
-        }
-    
-        // commands that don't lead to state changes...
-    
-        if (choice == "status") {
-            string seek_addition;
-            if (KEY_OF_TARGET != "")
-                seek_addition = "was last seeking " + llKey2Name(KEY_OF_TARGET);
-            llOwnerSay("my name is " + llGetObjectName() + " and state is '"
-                + name_for_state(current_state) + "'.\n"
-                + seek_addition);
-        }
-    
-        if (choice == "set home") {
-            list pos_list = llGetObjectDetails(llGetOwner(), [OBJECT_POS]);
-            home_position = llList2Vector(pos_list, 0);
-            llOwnerSay("i'm setting my home to " + (string)home_position);
-    //hmmm: use a rounding print to show the position.
-        }
-        if (choice == "set name") {
-            llOwnerSay("to change my name from " + llGetObjectName() + ",\ntell me my new name by typing:\n/" + (string)PET_CHAT_CHANNEL + " name My Cool New Name");
-        }
-    
-    } else if (menu_name == PET_REPLY_MENU) {
-log_it("menu-act follow: snd=" + (string)sender + " num=" + (string)num + " msg=" + msg + " id=" + (string)id);
-        llSetPrimitiveParams([PRIM_PHYSICS, TRUE,
-        //]);
-            PRIM_PHANTOM, !(current_state == STATE_ATTACK)]);
-        integer choice_indy = find_in_list(_FOLLOW_NAME, choice);
-        if (choice_indy < 0) {
-//log_it("choice was not found in list");
-//log_it("followname list is: " + (string)_FOLLOW_NAME);
-        } else {
-            string action = "follow";
-            if (current_state == STATE_ATTACK) action = "attack";
-            llOwnerSay("now " + action + "ing "
-                + llList2String(_FOLLOW_NAME, choice_indy) + "...");
-            seeking_avatars  = FALSE;
-            KEY_OF_TARGET = llList2Key(_FOLLOW_KEY, choice_indy);
-            llSensorRemove();
-            llSensorRepeat("", KEY_OF_TARGET, AGENT | ACTIVE,
-                TARGETING_SENSOR_RANGE, PI, SENSOR_INTERVAL);  
-        }
-    }
-}
-
-// processes the hits that we get back from the sensor.  the information we receive
-// is needed for most of the pet states.
-handle_sensor(integer num_detected)
-{
-    if (current_state == STATE_COME) {
-        go_to_target(_OWNER, llDetectedPos(0));
-        motivate();
-    }
-    
-    if ( (current_state == STATE_FOLLOW) || (current_state == STATE_ATTACK) ) {
-        if (seeking_avatars) {
-            // reset the list of keys and names that were found previously.
-            _FOLLOW_KEY  = [];
-            _FOLLOW_NAME = [];
-            // show the full set found if it will fit, otherwise just 12.
-            integer num_to_show = num_detected;
-            if (num_to_show > 12) num_to_show = 12;
-            // examine each of the avatars found and put them on the list.
-            integer i;
-            for (i = 0 ; i < num_to_show; i++) {
-                key to_follow = llDetectedKey(i);
-                if (to_follow != NULL_KEY) {
-                    _FOLLOW_KEY += [to_follow];
-                    string str = llDetectedName(i);
-                    // trim the menu item if it has hit the maximum limit.
-                    if (llStringLength(str) > 24) str = llGetSubString(str, 0, 23);
-                    integer name_try = 0;
-                    while (find_in_list(_FOLLOW_NAME, str) >= 0) {
-                        // this guy is already listed under that name, so change it a bit.
-                        str = llGetSubString(str, 0, 22) + (string)name_try++;
-                    }
-                    _FOLLOW_NAME += [str];
-                }
-            }
-            // now ask who to follow.
-            if (llGetListLength(_FOLLOW_KEY)) {
-                show_menu(PET_REPLY_MENU, _FOLLOW_MESSAGE, _FOLLOW_NAME, _FOLLOW_CHANNEL);
-            }
-        } else {
-            // not seeking the avatar any more; follow who was chosen.
-            go_to_target(KEY_OF_TARGET, llDetectedPos(0));
-            motivate();
-        }
-    }
-
-    if (current_state == STATE_WANDER) {
-        if (jaunt_responses_awaited) return;  // skip doing anything while we're still waiting.
-        vector pos = llDetectedPos(0);
-        float  omg = llFrand(1) * PI * 2;
-        float  t_r = llFrand(1) * _FREE_RANGE;
-        float  t_x = t_r * llCos(omg);
-        float  t_y = t_r * llSin(omg);
-        go_to_target(NULL_KEY, pos + <t_x, t_y, 0.0>);
-        motivate();
-    }
-
-}
-
-handle_timer() {
-    if (current_state != STATE_STAY) {
-        // make sure a bad jaunt didn't break our physics.
-        llSetStatus(STATUS_PHYSICS, TRUE);
-    }
-
-    if (jaunt_responses_awaited) {
-        // we are not quite there yet.
-        if (slackness_counter++ > MAXIMUM_SLACKNESS) {
-            // go back to the main state.  we took too long.
-log_it("waiting for jaunt timed out.");
-///argh?                jaunt_responses_awaited--;
-            slackness_counter = 0;
-        } else return;  // not time yet for rest of timed actions.
-    }
-    
-    // handle the free state, since we need may to readjust the target.
-    if (current_state == STATE_FREE) {
-        if (pending_target) return;  // haven't arrived at previous yet.
-        vector pos = home_position;
-        float  omg = llFrand(1) * PI * 2;
-//hmmm: make free range settable
-        float  t_r = llFrand(1) * _FREE_RANGE;
-        float  t_x = t_r * llCos(omg);
-        float  t_y = t_r * llSin(omg);
-        go_to_target(NULL_KEY, pos + <t_x, t_y, 0.0>);
-        motivate();
-    }
-}
-
-handle_hearing_voices(integer channel, string name, key id, string message)
-{
-    if (channel != PET_CHAT_CHANNEL) return;  // not our channel.
-//log_it("into handle voice, msg=" + message);
-    if (id != llGetOwner()) return;  // not authorized.
-    // we found a command.  which specific one?
-    if (is_prefix(message, "up")) {
-        // upwards bump.
-        enter_stay_state();
-        string dist = llDeleteSubString(message, 0, 2);
-        if (dist == "") dist = (string)DEFAULT_BUMP_SIZE;
-        request_jaunt_up((integer)dist);
-llOwnerSay("bumping up by " + dist);
-    } else if (is_prefix(message, "down")) {
-        // downwards bump.
-        enter_stay_state();
-        string dist = llDeleteSubString(message, 0, 4);
-        if (dist == "") dist = (string)DEFAULT_BUMP_SIZE;
-        request_jaunt_up(-(integer)dist);
-llOwnerSay("bumping down by " + dist);
-    } else if (is_prefix(message, "jaunt")) {
-        // zip to a specific place in the sim.
-        enter_stay_state();
-        string where = llDeleteSubString(message, 0, 5);
-        if (where == "") {
-            llOwnerSay("i can't jaunt to like nowhere dude.");
-            return;
-        }
-        vector loc = (vector)where;
-        if (loc == <0.0, 0.0, 0.0>) {
-            llOwnerSay("jaunt locations should be in the vector <x, y, z> format, and jaunting to <0, 0, 0> is unsupported.");
-            return;
-        }
-llOwnerSay("jaunting to " + (string)loc);
-        jaunt_to_location(loc);
-    } else if (is_prefix(message, "name")) {
-        // toss the command portion to get our new name.
-        string new_name = llDeleteSubString(message, 0, 4);
-        if (llStringLength(new_name) > 0) {
-            llOwnerSay("wheeee!  my new name is: " + new_name);
-            llSetObjectName(new_name);
-            show_title();
-        } else {
-            // no data was given for the name.
-            llOwnerSay("my name is still " + llGetObjectName());
-        }
-    } else {
-        // we support a simple translation for a few orders.
-        if (message == "free") message = "go home";
-        
-        // see if we can just flip this into a menu command instead.  we don't
-        // really care whether that works or not, since anything that doesn't work is
-        // a bogus command.
-        llMessageLinked(LINK_THIS, _COMMAND_CHANNEL, SHOW_MENU_COMMAND,
-            PET_MENU_NAME + HUFFWARE_PARM_SEPARATOR + message);
-    }
-}
-
-//////////////
-
-stop_pet()
-{
-//log_it("stopping pet from moving...");
-    llSetPrimitiveParams([PRIM_PHYSICS, FALSE,
-    //]);
-    PRIM_PHANTOM, TRUE]);
-}
-
-go_to_target(key av, vector pos)
-{
-//log_it("told to go to target: key=" + (string)av + " pos=" + (string)pos);
-    TARGET_POSITION = pos;
-    if (av != NULL_KEY) {
-        vector av_size = llGetAgentSize(av);
-
-        // if it's an object, use a different method to find its height.
-        if (av_size.z == 0.0) {
-            // use the object's height.
-            list box = llGetBoundingBox(KEY_OF_TARGET);
-            float object_height = llVecDist(llList2Vector(box, 0), llList2Vector(box, 1));
-            av_size.z = object_height;
-        }
-        // adding to get pet above target.
-        TARGET_POSITION += < 0.0, 0.0, av_size.z / 2.0>;
-//log_it("adjusted targposn: " + (string)TARGET_POSITION);
-    }
-    if (current_state == STATE_ATTACK) {
-        TARGET_POSITION += < 0.0, 0.0, ATTACK_HEIGHT_ABOVE_FOLLOWED_OBJECT>;
-        TARGET_POSITION += <llFrand(2) * ATTACK_X_MARGIN - ATTACK_X_MARGIN,
-            llFrand(2) * ATTACK_Y_MARGIN - ATTACK_Y_MARGIN,
-            llFrand(2) * ATTACK_Z_MARGIN - ATTACK_Z_MARGIN>;
-    } else {
-//log_it("normal target calc");
-        TARGET_POSITION += < 0.0, 0.0, DEFAULT_HEIGHT_ABOVE_FOLLOWED_OBJECT>;
-        TARGET_POSITION += <llFrand(2) * DEFAULT_X_MARGIN - DEFAULT_X_MARGIN,
-            llFrand(2) * DEFAULT_Y_MARGIN - DEFAULT_Y_MARGIN,
-            llFrand(2) * DEFAULT_Z_MARGIN - DEFAULT_Z_MARGIN>;
-    }
-    // trim the height a bit to keep the pet on-world.
-    if (TARGET_POSITION.z > 4095.0)
-        TARGET_POSITION.z = 4095.0;
-}
-
-integer jaunt_responses_awaited = 0;
-    // the number of pending jumps that we are hoping will happen.
-
-integer slackness_counter;
-    // how many snoozes we've had waiting for our destination.
-
-jaunt_to_location(vector target)
-{
-    // send jaunt request to get us to the specified place.
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_COMMAND, (string)target);
-    // add one to our counter so we know a jaunt is in progress.
-    jaunt_responses_awaited++;
-    // reset the overflow counter to recognize a new jaunt.
-    slackness_counter = 0;
-}
-
-vector previous_position;
-    // how far away target was last time.
-
-motivate()
-{
-    // first, let's get into the right state of existence.
-    llSetStatus(STATUS_PHYSICS, TRUE);  // we need to be able to move around here.
-    if (current_state == STATE_ATTACK) {
-        llSetStatus(STATUS_PHANTOM, FALSE);  // we can bonk into things now.
-    } else {
-        llSetStatus(STATUS_PHANTOM, TRUE);  // there are no obstructive contacts.
-    }
-
-    vector current_pos = llGetPos();
-    float distance = llVecDist(TARGET_POSITION, current_pos);
-    // a simple linear velocity calculation based on the object's distance.
-    float velocity;
-    if (current_state == STATE_ATTACK) {
-        velocity = ATTACK_BASE_VELOCITY + VELOCITY_MULTIPLIER * (distance / 10.0);
-        // beef the velocity up for attack mode.
-        velocity *= 10.0;
-    } else {
-        velocity = DEFAULT_BASE_VELOCITY + VELOCITY_MULTIPLIER * (distance / 10.0);
-    }
-
-//hmmm: make that 20 a constant
-    integer jump_regardless = FALSE;
-    if (llVecDist(current_pos, previous_position) >= 20) {
-        // we will always re-target when the distances have changed that much; this could mean
-        // the avatar is falling away.
-        jump_regardless = TRUE;
-    }
-float IN_RANGE_CHANCE_TO_BAIL = 0.9;
-float ATTACK_IN_RANGE_CHANCE_TO_BAIL = 0.5;
-    
-float NEAR_RANGE_CHANCE_TO_BAIL = 0.5;
-float ATTACK_NEAR_RANGE_CHANCE_TO_BAIL = 0.1;
-
-    if (distance <= MAXIMUM_TARGETING_DISTANCE) {
-        // damp out the equation if the target is close enough.
-        if (current_state == STATE_ATTACK) velocity = ATTACK_BASE_VELOCITY;
-        else velocity = DEFAULT_BASE_VELOCITY;
-        float within_range_chance = IN_RANGE_CHANCE_TO_BAIL;
-        if (current_state == STATE_ATTACK) within_range_chance = ATTACK_IN_RANGE_CHANCE_TO_BAIL;
-        if (llFrand(1.0) <= within_range_chance) return;  // do nothing; close enough.
-    } else if (distance <= 2.0 * MAXIMUM_TARGETING_DISTANCE) {
-        // we have a bit larger chance of setting a new target if the
-        // distance is pretty close still.
-        float near_range_chance = NEAR_RANGE_CHANCE_TO_BAIL;
-        if (current_state == STATE_ATTACK) near_range_chance = ATTACK_NEAR_RANGE_CHANCE_TO_BAIL;
-        if (llFrand(1.0) <= near_range_chance) return;
-    }
-    previous_position = current_pos;
-//log_it("dist=" + (string)distance + " vel=" + (string)velocity);
-    float  time = distance / velocity;
-    _TARGET_ID = llTarget(TARGET_POSITION, MAXIMUM_TARGETING_DISTANCE);
-    pending_target = TRUE;
-    // make sure we're in a physics mode before attempting physics changes...
-    llSetStatus(STATUS_PHYSICS, TRUE);
-    if (SITTING_AVATAR_KEY == NULL_KEY) {
-        // when we have nobody riding, we can look wherever we want.
-        llLookAt(TARGET_POSITION, 0.7, 0.5);
-    } else {
-        // if we're holding onto an avatar, we keep them pointed in a reasonable way.
-        vector curr_pos = llGetPos();
-        vector new_lookat = <curr_pos.x, curr_pos.y, curr_pos.z + 1>;
-        llLookAt(new_lookat, 0.7, 0.5);
-    }
-//log_it("setting move to target: " + (string)TARGET_POSITION);
-    llMoveToTarget(TARGET_POSITION, time);
-
-    integer panic_dist = DEFAULT_PANIC_DISTANCE;
-    if (current_state == STATE_ATTACK) {
-        panic_dist = ATTACK_PANIC_DISTANCE;
-    }
-
-    // don't try to jump if we're still awaiting a jump response.    
-    if (!jaunt_responses_awaited && (distance > panic_dist) ) {
-        // we need to shorten the distance to our buddy now.
-        jaunt_to_location(TARGET_POSITION);
-    } else if (jump_regardless || (distance > TARGETING_SENSOR_RANGE - 10)) {
-        // we are double our panic point, so jump even if still waiting for a reply.
-        // however, we don't want to queue up too many jaunts at a time either.
-        if (jaunt_responses_awaited <= 2) {
-            jaunt_to_location(TARGET_POSITION);
-        }
-    }
-
-    // push the attack target if we're close enough.
-    if ( (current_state == STATE_ATTACK) && (distance < ATTACK_PUSH_DIST_THRESHOLD) ) {
-        // only decide to push if they win the lottery here.
-        if (llFrand(1.0) < ATTACK_PUSH_CHANCE) {
-            llPushObject(KEY_OF_TARGET, ATTACK_PUSH_MAGNITUDE * llRot2Up(llGetRot()), ZERO_VECTOR, FALSE);
-        }
-    }
-    
-}
-
-show_title()
-{
-    llSetText(llGetObjectName(), <0.6, 0.3, 0.8>, 1.0);
-}
-
-// processes a link message from some other script.
-handle_link_message(integer which, integer num, string msg, key id)
-{
-//log_it("got msg=" + msg + " id=" + (string)id);
-    if (num == JAUNT_HUFFWARE_ID + REPLY_DISTANCE) {
-//log_it("link jaunt reply");
-        if (msg == JAUNT_COMMAND) {
-            jaunt_responses_awaited--;  // one less response being awaited.
-            if (jaunt_responses_awaited < 0) {
-                log_it("erroneously went below zero for jaunt responses!");
-                jaunt_responses_awaited = 0;
-            }
-            // unpack the reply.
-            list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-            integer last_jaunt_was_success = (integer)llList2String(parms, 0);
-            vector posn = (vector)llList2String(parms, 1);
-//log_it("got a reply for a jaunt request, success=" + (string)last_jaunt_was_success + " posn=" + (string)posn);
-        }
-        return;
-    }
-    if (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE) return;  // not for us.
-//log_it("menu reply");
-    react_to_menu(which, num, msg, id);
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-initialize()
-{
-    show_title();
-    llSetPrimitiveParams([PRIM_PHYSICS, FALSE,
-    //]);
-    PRIM_PHANTOM, TRUE]);
-    llSitTarget(SIT_POSITION, llEuler2Rot(SIT_ROTATION * DEG_TO_RAD));
-    llSetSitText(SIT_TEXT);
-    llSetBuoyancy(1.0);
-    _OWNER = llGetOwner();
-    _FOLLOW_KEY = [];
-    _FOLLOW_NAME = [];
-    current_state = STATE_FREE;
-    TARGET_POSITION = llGetPos();
-    llSetTimerEvent(PERIODIC_INTERVAL);
-    slackness_counter = 0;
-    _COMMAND_CHANNEL = random_channel();
-    _FOLLOW_CHANNEL = random_channel();
-    _COMMAND_CHANNEL = random_channel();
-    llListen(PET_CHAT_CHANNEL, "", llGetOwner(), "");
-    home_position = llGetPos();  // start in a known place.
-}
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        initialize();
-    }
-    
-    on_rez(integer param) { llResetScript(); }
-    
-    touch_start(integer num_detected) {
-        show_title();
-//change title to show menuing state?
-        if (_OWNER == llDetectedKey(0)) {
-            // show our menu here.
-            show_menu(PET_MENU_NAME, _COMMAND_MESSAGE, SUPPORTED_COMMANDS, _COMMAND_CHANNEL);
-        }
-    }
-
-    link_message(integer sender, integer num, string msg, key id) {
-        handle_link_message(sender, num, msg, id);
-    }
-    
-    sensor(integer num_detected) {
-//log_it("sensor found " + llDetectedName(0));
-        handle_sensor(num_detected);
-    }
-    
-    no_sensor() {
-//use another means to find the avatar?
-    }
-    
-    at_target(integer number, vector targetpos, vector ourpos) {
-//log_it("at target");
-        llTargetRemove(_TARGET_ID);
-        pending_target = FALSE;
-        llStopMoveToTarget();
-    }
-    
-    not_at_target() {
-//log_it("not at target");
-
-    }
-    
-    changed(integer change) {
-        if (change & CHANGED_LINK) {
-            key av = llAvatarOnSitTarget();
-            if (SITTING_AVATAR_KEY != NULL_KEY) {
-                if (av == NULL_KEY) {
-                    llStopAnimation(SIT_ANIMATION);
-                    SITTING_AVATAR_KEY = NULL_KEY;
-                }
-            } else {
-                if (av != NULL_KEY) {
-                    SITTING_AVATAR_KEY = av;
-                    llRequestPermissions(SITTING_AVATAR_KEY, PERMISSION_TRIGGER_ANIMATION);
-// we wish we could make the avatar a phantom here, but that's not allowed.
-                }
-            }
-        }
-    }
-
-    run_time_permissions(integer perm) {
-        key perm_key = llGetPermissionsKey();
-        if (perm_key == SITTING_AVATAR_KEY) {
-            if (perm & PERMISSION_TRIGGER_ANIMATION) {
-                list anms = llGetAnimationList(SITTING_AVATAR_KEY);
-                integer i;
-                for (i = 0 ; i < llGetListLength(anms) ; i++) {
-                    llStopAnimation(llList2Key(anms, i));
-                }
-                llStartAnimation(SIT_ANIMATION);
-            }
-        }
-    }
-
-    timer() {
-        handle_timer();
-    }
-
-    listen(integer channel, string name, key id, string message) {
-        handle_hearing_voices(channel, name, id, message);
-    }
-
-}
-
-// attributions:
-//   this script is based (a lot!) on the "pet" script that might
-// have been written by kazumasa loon.  there was no attribution
-// of author in the script, but the creator was kazumasa.  thanks dude!
-//
-// that being said, the script was redone a lot by fred huffhines,
-// mainly in the following areas:
-//
-// march or april 2008: added teleport capability to script.  pet will now attempt
-//   to keep up with the owner during follow mode by teleporting to her.
-//
-// may 2008: added ipc menu system.  now menus are dealt with by the huffware
-//    menu system, removing a lot of code from this script.
-