Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Avatar Magnet

Intent Unknown
Registered User
Join date: 16 Nov 2005
Posts: 82
05-13-2006 22:55
CODE

// Avatar Magnet Script 0.1
// a simple avatar magnet with some "nice" features built in
// if you turn these features off *please*
// don't use it outside of a combat area
// even if you leave them on this script uses push to simulate a
// magnet effect it *will* register as PvP outside combat areas
//
// if you turn OBJECTS on it will attract physical objects too
// but it doesn't work very well
// especially with small objects as they usually end up flying off world
//
// this script is mostly untested
// if you have problems let me know and i'll try to fix them


// whether the object asks permission to attract or not
// be nice and ask ;)
integer REQUIRE_PERMISSION = TRUE;

// if we are requiring permissions set this based on whether
// you want it to prompt nearby users for permissions
// or require them to touch this object to be asked permission
// TRUE means it will ask without touching
// FALSE means they must touch it to be asked
integer UNSOLICITED = TRUE;

// how far to look around for targets
// this is highly dependant on the mass of this object
// and the mass of the target
// small objects might not have enough energy to attract far away targets
// maximum of 96.0 meters
float RADIUS = 30.0;

// how forceful you want to the magnet to be
// if you set this too high it's hard for the magnet to keep up
// with the velocity of the target so you get a lot of "ping-pong" effect
// if you set it too low then the target can break away easily
// if it has the ability to apply its own impulse
// (an avatar can fly away from the magnet if it's set too low ...
// but this may be a good thing)
// the maximum amount is effectively 2147483647
// but really > 100 is too much
float FORCE = 20.0;

// attract avatars
integer AVATARS = TRUE;

// attract physical objects
// this really doesn't work very well, especially for small objects
integer OBJECTS = FALSE;

// if we're asking permission we need to keep a list of people
// who have accepted and people who have declined
// unfortunately due to memory constraints these lists will be capped
// i haven't tested this!
// if you get stack-heap errors you will need to lower the cap
integer CAP = 50;
list declined;
list accepted;

// listener handle
integer listener;

askPermission(key avatar) {
// build the message based on the settings
string message = "May this magnet attract ";
if (AVATARS) message += "you";
if (OBJECTS && AVATARS) message += " and ";
if (OBJECTS) message += "your objects";
message += "?";

// build dialog button list
// based on whether or not this is the owner
list buttons = ["Accept", "Decline"];
if (avatar == llGetOwner()) buttons += ["Turn Off"];

llDialog(avatar, message, buttons, -38739454);
}

default {
state_entry() {
// turn of collision effects
llCollisionSprite("");
llCollisionSound("", 0.0);

llSetText("Magnet Off", <1.0, 1.0, 1.0>, 1.0);

llOwnerSay("Magnet Off");
}

touch_start(integer touches) {
// turn the magnet on
if (llDetectedKey(0) == llGetOwner()) state magnetized;
}
}

state magnetized {
on_rez(integer start) {
llResetScript();
}

state_entry() {
// clear out the accepted list
accepted = [];

llSetText("Magnet On", <1.0, 1.0, 1.0>, 1.0);

llOwnerSay("Magnet On");

// the magnet shouldn't be phantom or you get weird results
llSetStatus(STATUS_PHANTOM, FALSE);

// figure out which types of targets we're attracting
integer types;
if (AVATARS) types = types | AGENT;
if (OBJECTS) types = types | ACTIVE;

// set our sensor
llSensorRepeat("", "", types, RADIUS, TWO_PI, 0.1);

// listen for dialog responses if we're asking permission
if (REQUIRE_PERMISSION)
listener = llListen(-38739454, "", "", "");
}

listen(integer channel, string name, key id, string message) {
// only listen to avatars
if (llGetOwnerKey(id) == id) {
if (message == "Accept") {
// if they were already on the accepted list
// remove their earlier entry
integer index = llListFindList(accepted, [id]);

if (index > -1)
accepted = llDeleteSubList(accepted, index, index);

// add to the end of the accepted list
accepted += [id];

// make sure our list isn't bigger than the cap
if (llGetListLength(accepted) > CAP)
accepted = llDeleteSubList(accepted, 0, 0);

// remove from the declined list if they're on it
index = llListFindList(declined, [id]);

if (index > -1)
declined = llDeleteSubList(declined, index, index);
} else if (message == "Decline") {
// remove from the accepted list if they're on it
integer index = llListFindList(accepted, [id]);

if (index > -1)
accepted = llDeleteSubList(accepted, index, index);

// if they were already on the declined list
// remove their earlier entry
index = llListFindList(declined, [id]);

if (index > -1)
declined = llDeleteSubList(declined, index, index);

// add to the end of the declined list
declined += [id];

// make sure our list isn't bigger than the cap
if (llGetListLength(declined) > CAP)
declined = llDeleteSubList(declined, 0, 0);
} else if (message == "Turn Off" && id == llGetOwner()) {
state default;
}
}
}

touch_start(integer touches) {
key toucher = llDetectedKey(0);

if (REQUIRE_PERMISSION) {
askPermission(toucher);

return;
}

if (toucher == llGetOwner()) state default;
}

sensor(integer sensed) {
integer i;

for (i = 0; i < sensed; i ++) {
key target_key = llDetectedKey(i);

// if we're getting permission
// we need to see if we've alreay bothered this person
if (REQUIRE_PERMISSION) {
// since we may be attracting objects too
// we need to make sure we're asking the owner
key owner_key = llDetectedOwner(i);

// if this person has not already accepted
// don't attract them
if (llListFindList(accepted, [owner_key]) == -1) {
// but if we haven't already bothered them
// we need to ask them
if (llListFindList(declined, [owner_key]) == -1) {
// put their name on the denied list
declined += [owner_key];

// make sure our list isn't bigger than the cap
if (llGetListLength(declined) > CAP)
declined = llDeleteSubList(declined, 0, 0);

if (UNSOLICITED) askPermission(owner_key);
}

return;
}
}

// the position of our target
vector target_pos = llDetectedPos(i);

vector my_pos = llGetPos();

// normalized vector describing the direction
// from our target to us
// this is a negative vector
// which will draw the object towards us
vector direction = llVecNorm(my_pos - target_pos);

// apply set amount of force
// in the direction from the target to this object
vector impulse = FORCE * direction;

// equalize for the targets mass so pull is consistent
impulse *= llGetObjectMass(target_key);

// equalize for the distance of the target
// so pull is consistent
impulse *= llPow(llVecDist(my_pos, target_pos), 3.0);

// negate the targets current velocity
impulse -= llDetectedVel(i);

llPushObject(target_key, impulse, ZERO_VECTOR, FALSE);
}
}

state_exit() {
// we don't actually need to do this any more because
// listeners are cleaned up on state change but we might as well
if (REQUIRE_PERMISSION) llListenRemove(listener);
}
}
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Discussion Thread
05-15-2006 07:26
/54/c0/106825/1.html
_____________________
i've got nothing. ;)