Change font size
It is currently Thu Nov 22, 2018 6:26 am

Forum rules


{L_IMAGE}



Post a new topicPost a reply Page 2 of 2   [ 17 posts ]
Go to page Previous  1, 2
Author Message
 Post subject: Simple Remote Light and Switch
PostPosted: Fri Jan 21, 2011 3:09 pm 
OSG Elite
User avatar

Joined: Thu Dec 11, 2008 7:51 am
Posts: 392
Location: England UK
Here is a very simple remote light switch. One script goes in one prim for the switch, the other goes in another prim for the light. It uses llRegionSay so will work anywhere on a sim. If you need more than one light to run from different switches make sure you change the channel in both scripts to the same.

Switch Script:
{L_CODE}:
//Simple remote light switch by Adelle Fitzgerald. Use as you like but please keep this header.

integer channel = 20; //Set this to the same channel as your light
integer isOn;

default
{
    state_entry()
    {
    }
   
    touch_start(integer num)
    {
        if (!isOn)
        {
            isOn = TRUE;
            llRegionSay(channel, "on");
        }
        else
        {
            isOn = FALSE;
            llRegionSay(channel, "off");
        }
    }
}


Light Script:
{L_CODE}:
//Simple remote light by Adelle Fitzgerald. Use as you like but please keep this header.

integer channel = 20; //Set this to the same channel as your switch. If you want to operate more than one light individually then set to a diffetent channel (not 0) and set the same channel in the switch script
float intensity = 1.0; //Set this to the brightness of the light (0.0 - 1.0)
float radius = 10; //Set this to the light radius in meters (0.0 - 20.0)
float falloff = 0.75; //Set this to the falloff of the light (0.0 - 2.0)
vector colour = <1,1,1>; //colour of the light <R,G,B> (0.0 - 1.0)

default
{
    state_entry()
    {
        llListen(channel,"","","");
    }
   
    listen (integer channel, string name, key id, string message)
    {
        if (message == "on")
        {
            llSetPrimitiveParams([PRIM_POINT_LIGHT,TRUE,colour,intensity,radius,falloff]);
        }
        if (message == "off")
        {
            llSetPrimitiveParams([PRIM_POINT_LIGHT,FALSE,colour,intensity,radius,falloff]);
        }
    }   
}

_________________
"Nothing lasts forever; It's scientific"
~David Byrne (Talking Heads)


Top
 Profile  
 
 Post subject: Re: Object to object communication
PostPosted: Fri Aug 05, 2011 1:00 pm 
OSG Elite

Joined: Wed Aug 05, 2009 1:59 am
Posts: 417
Here are a couple of scripts I use for lightning (in linksets).
Look in all the scripts for the line:
{L_CODE}:
string  CONTROLLER_ID = "A"; // This should be the same ("A") in the other scripts!!

Make sure all the scripts have the same CONTROLLER_ID. (In this case A)

First a "Touch" script:
This script detects if the lamp is touched, and sends a command (On or off) to the lamp.

{L_CODE}:
//// "Touch Toggle" CONTROLLER TEMPLATE v1 - by Jopsy Pendragon - 4/8/2008
//// You are free to use this script as you please, so long as you include this line:
//** The original 'free' version of this script came from THE PARTICLE LABORATORY. **//

// EFFECT: 'Touching' this prim will ACTIVATE or DEACTIVE particles.

// SETUP:  Drop this CONTROLLER TEMPLATE script into any prim of the same
// linked object as your PARTICLE TEMPLATE. It should be responsive immediately.

integer PLAY_SOUND = TRUE; // TRUE for a click-sound, FALSE for silent.
string  SOUND = "bac3e333-9624-4b1a-ade2-d2b01d5960aa"; // a click sound

string  CONTROLLER_ID = "A"; // This should be the same ("A") in the other scripts!!

integer mode = 0; // keep track of whether particles are ON(1) or OFF(0).

default {
   
    touch_start(integer total_number) {
   
        if ( PLAY_SOUND ) llPlaySound( SOUND, 0.5 ); 
       
        mode = ! mode; // flip on to off, (or off to on).
       
        llMessageLinked( LINK_SET, mode, CONTROLLER_ID, NULL_KEY ); // send command
    }
   
    // Listen for other controllers sending ON/OFF commands and remember changes:
    link_message( integer sibling, integer num, string controller_id, key ignore ) {
       
        if ( controller_id != CONTROLLER_ID ) return; // this message is not for us.
       
        mode = num;
    }
}


The second script is a Night control script. This script looks if its night in OSgrid, and turns lights on or off.
(this is an optional script, works best for street lights and stuff)

{L_CODE}:
//// "Night Toggle" CONTROLLER TEMPLATE v1 - by Jopsy Pendragon - 4/8/2008
//// You are free to use this script as you please, so long as you include this line:
//** The original 'free' version of this script came from THE PARTICLE LABORATORY. **//

integer NIGHT = TRUE;

vector sunpos;
integer mode;
integer last_check=-1;

string  CONTROLLER_ID = "A";

default {
    state_entry() {
        llSetTimerEvent(60.0);
    }

    timer() {
        sunpos = llGetSunDirection();
       
        if ( sunpos.z < 0.0 )
            mode = NIGHT;
        else
            mode = ! NIGHT;
       
        if ( mode != last_check ) {
            llMessageLinked( LINK_SET, mode, CONTROLLER_ID, NULL_KEY );
            last_check = mode;
        }
    }
}


Here is an actual light script.

{L_CODE}:
//// "Light" TEMPLATE v1 - by Jopsy Pendragon - 4/8/2008
//// You are free to use this script as you please, so long as you include this line:
//** The original 'free' version of this script came from THE PARTICLE LABORATORY. **//
vector color = <0.9,0.9,1>; // red, green and blue values 0.00(dark) to 1.00(bright)
float intensity = 0.5;  // % brightness:  0.0 to 1.0
float    radius = 10.00;  // range/distance of light:  0.0 to 20.0 meters
float   falloff = 0.5;  // % brightness at max distance 0.00 to 1.00



string  CONTROLLER_ID = "A"; //
integer AUTO_START = FALSE;   // Optionally FALSE only if using CONTROLLERS.

rotation adjustment = ZERO_ROTATION;

default {
    state_entry() {
               
        if ( AUTO_START )
            llSetPrimitiveParams( [PRIM_POINT_LIGHT, TRUE, color , intensity, radius, falloff]);
       
    }
   
    link_message( integer sibling, integer num, string mesg, key target_key ) {
        if ( mesg != CONTROLLER_ID ) { // this message isn't for me.  Bail out.
            return;
        } else if ( num == 0 ) { // Message says to turn particles OFF:
            llSetPrimitiveParams( [PRIM_POINT_LIGHT, FALSE, ZERO_VECTOR , 0.0, 0.0, 0.0 ]);
        } else if ( num == 1 ) { // Message says to turn particles ON:
            llSetPrimitiveParams( [PRIM_POINT_LIGHT, TRUE, color , intensity, radius, falloff]);
        } else { // bad instruction number
            // do nothing.
        }           
    }
       
}


And finally, a glow script. Put this in a light beam (linked to the main lamp), set the transparency on the light beam to 99%. (And don't forget to make the whole light system phantom!)

{L_CODE}:
//// "Glow" EFFECT TEMPLATE v1 - by Jopsy Pendragon - 4/8/2008
//// You are free to use this script as you please, so long as you include this line:
//** The original 'free' version of this script came from THE PARTICLE LABORATORY. **//

// SETUP:  Drop one optional particle texture and this script into a prim.
// Particles should start automatically. (Reset) the script if you insert a
// particle texture later on.  Add one or more CONTROLLER TEMPLATES to any
// prims in the linked object to control when particles turn ON and OFF.

// Rotate the prim to direction of spray.

// Customize the particle_parameter values below to create your unique
// particle effect and click SAVE.  Values are explained along with their
// min/max and default values further down in this script.

// PURPOSE:  This script will start a client side "spin" effect on any prim it's
// added to.  (the whole object will spin if added to root prim).
// This is an 'illusionary' effect, not a physical one.

// !!! NOTE !!! -->  This is not a PARTICLE effect!  This sets GLOW on the faces of a prim! =)
// Setting GLOW on a prim is a very new LSL feature.  This script may become obsolete
// if there are changes in LSL to how GLOW is set.


integer side = ALL_SIDES; // replace with a digit to affect one side of the prim.
float intensity = 0.50; // 0.00(no-glow) to 1.00(max)

string  CONTROLLER_ID = "A"; // See comments at end regarding CONTROLLERS.
integer AUTO_START = TRUE;   // Optionally FALSE only if using CONTROLLERS.


default {
    state_entry() {
       
        if ( AUTO_START ) llSetPrimitiveParams( [25, ALL_SIDES, 0.0 ]); 
       
    }
   
    link_message( integer sibling, integer num, string mesg, key target_key ) {
        if ( mesg != CONTROLLER_ID ) { // this message isn't for me.  Bail out.
            return;
        } else if ( num == 0 ) { // Message says to turn particles OFF:
           
            llSetPrimitiveParams( [PRIM_GLOW, side, 0.0 ]); 
           
        } else if ( num == 1 ) { // Message says to turn particles ON:
           
            llSetPrimitiveParams( [PRIM_GLOW, side, intensity ]); 
       
        } else { // bad instruction number
            // do nothing.
        }           
    }
       
}




Hope this helps.

Greets,
Oddy


Top
 Profile  
 
 Post subject: Re: Object to object communication
PostPosted: Sat Aug 06, 2011 3:47 am 
Furious Typer

Joined: Fri Dec 11, 2009 10:24 am
Posts: 52
Hi
I have been working on lights for a long time
I have a set of club lights which Is controlled by touch of a master prim
controls 32 lights in 4 rings of 8
light pattens are user created by note card ( mine tend to be Over the top)
notecards auto add to the menu
you can take a copy from port Azure - east - Tashas Night Club or IM me in world
Take the controller from stage and the red ring above you -center room ( the ring rezzes the lights )

New versions will be released soon - Under test - a week or two
adding:
1) The ability to run loops within patterns. ( this is the bit causing delay - lots of safety testing to do )
2) Timed sequences
3) up to 64 displays of 64 rings of 64 lights ( not that you ever want to do that )
4) Removes need for red ring ie all is rezzed from one prim
5) Single location for textures ( currently each light has its own - new version they dont)
6) Ability to trigger lights from external source
7) Ability for external source to trigger lights.
8) light throtelling ( ie if 32 avatars in range reduce lights - if 64 in range stop lights - user settable )

I ASK A FAVOUR IN RETURN!
If you make a good light pattern - let me have a copy - art is not my strength - Pretty Please!

Happy to collaborate with anyone that wants

Re original question:
I have never had an issue with Say,shout,regionsay etc then listen in the prim so not sure what the issue is.
all prims with script will get the message but I use a filter straight away so
llRegionSay("1:hello") will be used by prim 1.llRegionSay("2:hello"will be used by prim 2 etc...

With lights I use llRegionSay("1:2:3:Something") each light has a number (1) a group (2) and a big group(3)
and 0 (zero) is wildcard - that way you can address 1 light or a group of lights at once.
Doing that reduces chatter ( in my case ) by about 90% and improves syncing because you can load up all the instructions to the slave prims then send "0:0:0:GO" to make them all act at same time
You can use anything ( doesnt need to be numbers) but integers are handy as you can pass them as a param on rezatroot
you could use the prim name as the filter.

If you want it to work across region borders then http send to a php script and back works well as long as
you keep your php script running and as long as you can accept slow downs when internet is busy

Regards Tasha xxx


Top
 Profile  
 
 Post subject: Re: Object to object communication
PostPosted: Thu Aug 25, 2011 9:39 pm 

Joined: Thu Aug 25, 2011 9:07 pm
Posts: 2
Making objects not in the same region talk to each other is a nut I want to crack soon. I had high hopes for osMessageObject, but that only works inside the same region. Still very useful, and thank you to whoever is responsible for it.

So, the best I've been able to brainstorm so far is to use llHTTP commands to send and receive data via an external server. Biggest problem is there is no way to know when a new message is up, so it would have to constantly poll the external server and see if there were any update in the data. From what I've read, LSL XML-RPC is unreliable at best and probably not worth my attention. Second biggest problem is my knowledge of PHP is limited at best. :?

Has anyone else tackled this? Any brilliant solutions?


Top
 Profile  
 
 Post subject: Re: Object to object communication
PostPosted: Fri Aug 26, 2011 4:00 am 
Furious Typer
User avatar

Joined: Fri Aug 19, 2011 7:10 pm
Posts: 236
Location: UK
Does llListen not work for everyone? I wrote a scaleable set of scripts for controlling stage curtains using a central control, and simple had the control speak to the different curtains on a negative channel (e.g. -1):
{L_CODE}:
llSay(-1,"some message");


then in the curtains themselves:

{L_CODE}:
default {
    state_entry() {

        listen_handle = llListen(-1, "",NULL_KEY, "" );
       
    }
   
    listen ( integer channel, string name, key id, string message )

    {
       
    if (message == "whatever") {
          continue with your own code
    }
}


Of course you could replace llSay with llRegionSay or llShout depending on proximity. Using a negative channel means that the chat can't be intercepted by nor faked by other AVs (well, not directly, and not without them knowing which negative channel number you use).

_________________
50's sim based at Rumbled on OSGrid
happily running on Debian Linux on a VPS since June 10 2013


Top
 Profile  
 
 Post subject: Re: Object to object communication
PostPosted: Wed Nov 09, 2011 7:06 pm 

Joined: Wed Apr 13, 2011 8:39 am
Posts: 8
The enclosed Intercom script allows object to object communication, and provides for communication from one linked object to another in either the same or different prims. It only works if prims are in the same region. It includes extensive diagnostic and error recovery function. Each prim must know the names of the prims with which it wants to communicate. Generally you also want to know the names of the links, but this is not always necessary. The TestBlip script does not need to know the link names.

Intercom worries about a lot of things you might not need to worry about. It may have more function than you want or need. It does contain some handy-dandy subroutines that you might find useful, though. It's pretty well commented and modular, so you should be able to able to extract (or subtract) parts of it that you need (or don't need.)

You do not modify the Intercom script in order to use it. It's controlled by link messages sent from linked prims. Only one script per link may use Intercom facilities, but there is no effective limit on the number of linked prims.

The Intercom script itself must reside in the root prim, and communicators CANNOT be in the root prim. The test script, TestBlip.lsl, demonstrates the usage of Intercom features.

Build instructions:
Create a linked prim (one with one or more links.) Give each link an interesting name, so you can tell what's going on. The root prim is to be named either COMM1, COMM2, or COMM3. (See the .COMMLIST notecard.) The root prim contains the Intercom script and the .COMMLIST notecard, linked prims each contain the TestBlip script.

The MIT license effectively allows you to freely use the code in almost any way you want to. The intent is to allow everyone the freedom to use this code, and to prevent anyone else from inhibiting your freedom to use it.

{L_CODE}:
//----------------------------------------------------------------------------
//
// Copyright-
//       Copyright (C) 2011 Roberto Crafter (OS Grid Avatar)
//
// License-
//       Licensed under the MIT license:
//       http://www.opensource.org/licenses/mit-license.php
//
// Title-
//       Intercom.lsl               (2011/03/31 00:00)
//
// Purpose-
//       Facilitate communication between scripts in separate prims.
//
// Restrictions-
//       Names may not contain blanks, periods, or commas. The declaration
//       of such a prim name will put intercom.lsl into the "error" state.
//       This applies to all prims using intercom, including the root prim.
//
//       Only one script in a PRIM can use intercom facilities. If you need
//       more, create a new PRIM or route messages from a control script.
//
//       The intercom script must reside in the root prim.
//
// Usage-
//       To send a message, invoke
//           llMessageLinked(link, path, message, target), where
//           link    *MUST BE* LINK_ROOT,
//           path    *MUST BE* PATH_MP2C,
//           message is the message to be sent, and
//           target  is the target comm.prim name.
//
//           To broadcast a message to all prims in a COMM, use "comm.*" as
//           the target.
//
//           To transmit a message to a prim in this COMM, use "" as the
//           comm name.
//
//       To receive a message, in
//           link_message(link, path, message, source), where
//           link    *MUST BE* LINK_ROOT, // (Unchecked)
//           path    *MUST BE* PATH_MC2P,
//           message is the message received, and
//           source  is the source comm.prim name.
//
//           You will NOT receive intercom messages unless they are directed
//           to your prim.
//
//       When a message from an external prim is received, this script invokes
//           llMessageLinked(child, PATH_MC2P, message, source), where
//           child   is the target prim link number,
//           message is the message received, and
//           source  is the source comm.prim name.
//
//       When an external prim is recognized, this script invokes
//           llMessageLinked(child, PATH_CC2P, "COMM "+key, source), where
//           key     is the source comm key, and
//           source  is the source comm name.
//
//       When an external prim stops pinging, this script invokes
//           llMessageLinked(child, PATH_CC2P, "EXIT "+key, source), where
//           key     is the source comm key, and
//           source  is the source comm name.
//
//       On startup, this script invokes
//           llMessageLinked(LINK_SET, PATH_CP2C, "PING", comm), where
//           comm    is the name of *this* comm.
//
//           To this request, you must respond:
//           llMessageLinked(LINK_ROOT, PATH_CP2C, "PONG", prim), where
//           prim    is YOUR unqualified prim name.
//
//       On startup, you must invoke
//           llMessageLinked(LINK_ROOT, PATH_CP2C, "INIT", prim), where
//           prim    is YOUR unqualified prim name.
//
// The .COMMLIST notecard-
//       We read the .COMMLIST notecard in order to determine which other
//       intercom scripts we will communicate with. This notecard contains
//       the list of partner COMM root prims. We only communicate with them.
//
// Control commands-
//       llMessageLinked(LINK_ROOT, PATH_CP2C, "DUMP", "")
//           Diagnostic: See control_DUMP.
//
//       llMessageLinked(LINK_ROOT, PATH_CP2C, "GET " + tag, value)
//           Diagnostic: See control_GET.
//
//       llMessageLinked(LINK_ROOT, PATH_CP2C, "SET " + tag, value)
//           Diagnostic: See control_SET.
//
//       llMessageLinked(LINK_ROOT, PATH_CP2C, "UUID " + name, key), where
//           name    is the target.prim name, and
//           key     is the target comm key.
//
//           This message unconditionally RESETs any current connection.
//           The name must be present in the .COMMLIST notecard, but
//           does not need to match the true name of the COMM prim.
//
//       llMessageLinked(LINK_ROOT, PATH_CP2C, "RESET", n/a)
//           This message RESETs this script. See control_MESS.
//
// External intercom to intercom chat messages-
//       This script broadcasts an "IDENT" chat message to tell other intercom
//       scripts it is present. This message is sent every ping interval if a
//       partner intercom script is missing.
//
//       Every ping interval, this script directs a "PING" chat message to
//       every connected intercom script. This is a "keep-alive" message that
//       tells partner intercom script that this script is still active.
//
//       If we miss 4 consecutive "PING" message from partner scripts, we
//       declare that partner inactive. Any normal message subtitutes for
//       a PING message. Ping timeout takes between 2 and 2 1/2 minutes.
//
// Comm to comm external chat message format-
//       .to.from message, where
//           .to     is the target prim name,
//           .from   is the source prim name, and
//           message is the message to be transmitted
//
//       The associated COMM names are implied by the chat channel and the
//       source uuid supplied to the listen method.
//
//       Since messages are transmitted on the unique intercom channel and the
//       source key and name are provided by the listen interface, there is
//       no need to pass the comm name in the message.
//
// Implementation notes-
//       debug(4, "hard core debug mode")  // Written if DEBUG_LEVEL >= 5
//       debug(3, "hard core trace mode")  // Written if DEBUG_LEVEL >= 4
//       debug(2, "You want to know this") // Written if DEBUG_LEVEL >= 3
//       debug(1, "You need to know this") // Written if DEBUG_LEVEL >= 2
//       debug(0, "You HAVE to know this") // Written if DEBUG_LEVEL >= 1
//       DEBUG_LEVEL = 5            // Hard Core Debug Mode
//       DEBUG_LEVEL = 4            // Hard Core Trace Mode
//       DEBUG_LEVEL = 3            // INTERCOM debugging
//       DEBUG_LEVEL = 2            // INTERCOM user debugging
//       DEBUG_LEVEL = 1            // Normal production level
//       DEBUG_LEVEL = 0            // No debugging messages
//
//----------------------------------------------------------------------------
// Internal constants
integer  DEBUG_LEVEL = 2;           // Debugging level: None(0) .. (5)Full
string   MESS_IDENT = "IDENT COMM 2011-01-01"; // Intercom IDENT message w/ID

integer  CHAN_COMM = 4095;          // ICOMM chat broadcast channel

string   NAME_QUAL = ".";           // Intercom name qualifier
string   MESS_COMM = "COMM";        // Intercom COMM message
string   MESS_EXIT = "EXIT";        // Intercom EXIT message
string   MESS_INIT = "INIT";        // Intercom INIT message
string   MESS_PING = "PING";        // Intercom PING message
string   MESS_PONG = "PONG";        // Intercom PONG message

integer  PATH_MC2P = 4095;          // COMM => PRIM link_message message path
integer  PATH_MP2C = 4094;          // PRIM => COMM link_message message path
integer  PATH_CC2P = 4093;          // COMM => PRIM link_message control path
integer  PATH_CP2C = 4092;          // PRIM => COMM link_message control path

integer  PING_COUNT = 4;            // Starting value for ping_comm entry
float    PING_TIMER = 30.0;         // Time between ping events

// Control variables
string   current = "*initial*";     // The current state name
list     hand = [];                 // Listen channel handle list

// Working variables
integer  line;                      // The loader line number
integer  thisTargetX;               // Our comm_list index
string   thisObjName;               // Our llGetObjectName

//----------------------------------------------------------------------------
// The comm_list: All lists are of length comm_size.
//   list_comm variables contain the state of external COMM partners.
//   This list is built on startup using the .COMMLIST notecard.
//
//   name_comm Contains the list of intercom names. Duplicates are disallowed.
//   ping_comm The receive ping counter. Reset to PING_COUNT when any message
//             is received. Decremented for each timer interval. If zero,
//             the connection is RESET.
//   send_comm The outbound message indicator. Set TRUE whenever a message
//             is transmitted. If false, the ping timer will transmit a PING
//             in the timer method.
//   uuid_comm The uuid associated with a COMM name. Set to NULL_KEY when a
//             connection is reset.
//
// There are two special entries in the comm_list.
//   Element[0] has a name of "", and is reserved for *THIS*.
//   Optionally, an element may contain the name of this prim. This element
//   never becomes operational.
//
integer  comm_size = 0;             // The number of entries in the lists
list     name_comm = [];            // List of intercom names
list     ping_comm = [];            // Associated ping receipt counter
list     send_comm = [];            // Associated message sent indicator
list     uuid_comm = [];            // Associated uuid

//----------------------------------------------------------------------------
// The prim_list: All lists are of length prim_size
//   list_prim variables contain the state of internal PRIM partners.
//   This list is dynamically expanded and never contracted.
//
//   prim_name Contains the list of known internal prims. Duplicates are not
//             allowed, and result in this script going into error state.
integer  prim_size = 0;             // The number of entries in the lists
list     name_prim = [];            // List of our prim names
list     link_prim = [];            // Associated link number

//===================================================================
debug(integer L, string str) {      // Debug message w/LEVEL
    if( DEBUG_LEVEL > L )
        llOwnerSay(llGetScriptName() + ":" + current + ": " + str);
}

error(integer L, string str) {      // Error message w/LEVEL
    debug(L, "ERROR: " + str);
}

owner(string str) {                // Owner message
    llOwnerSay(llGetScriptName() + ": " + str);
}

hcdm(string str) {                  // Hard Core Debug Message
    owner(str);
}

debugLI(integer p0, string p1, key p2, string p3) { // Debug LIsten message
    debug(4, "listen(" + p0 + "," + p1 + "," + p2 + "," + p3 + ")");
}

debugLM(integer p0, integer p1, string p2, key p3) { // Debug Link Message
    debug(4, "link_message(" + p0 + "," + p1 + "," + p2 + "," + p3 + ")");
}

onExit() {                          // Clean up at state exit
    llSetTimerEvent(0.0);

    integer i;
    integer m = llGetListLength(hand);
    for(i= 0; i<m; ++i) {
        llListenRemove(llList2Integer(hand, i));
    }
    hand = [];
}

integer channel(key uuid) {         // Get channel from uuid
    integer result = (integer)("0x"+llGetSubString((string)uuid,-8,-1));
    result = result & 0x7fffffff;
    if( result < 4096 ) {
        result = (integer)("0x"+llGetSubString((string)uuid,0,8));
        result = result & 0x7fffffff;
        if( result < 4096 )
            result = 4096;
    }

    return result;
}

control_DUMP() {
    owner("control_DUMP()");

    integer x;
    for(x= 0; x<comm_size; ++x) {
        owner("COMM[" + x + "] " + llList2Integer(ping_comm, x)
             + " " + llList2Integer(send_comm, x)
             + " '" + llList2String(name_comm, x) + "'"
             + " = " + llList2Key(uuid_comm,x)
             );
    }

    for(x= 0; x<prim_size; ++x) {
        owner("PRIM[" + x + "] "+ llList2Integer(link_prim,x)
             + " = '" + llList2String(name_prim, x) + "'"
             );
    }
}

integer control_GET(list mList, string value, integer link) {
    integer err = FALSE;            // Resultant
   
    if( llGetListLength(mList) < 2 )
        err = TRUE;
    else {
        string mItem = llList2String(mList, 1);
        if( mItem == "LEVEL" ) {
            llMessageLinked(link, PATH_CC2P, "GOT LEVEL", (string)DEBUG_LEVEL);
        } else if( mItem == "SENSE" ) {
            string s = (string)comm_size+" "+prim_size;
            llMessageLinked(link, PATH_CC2P, "GOT SENSE", s);
        } else if( mItem == "SENSE_COMM" ) {
            integer x = (integer)value;
            string  s = value
                      + " " + llList2Integer(name_comm,x)
                      + " " + llList2Integer(ping_comm,x)
                      + " " + llList2Integer(uuid_comm,x)
                      + " " + llList2Integer(send_comm,x)
                      ;
            llMessageLinked(link, PATH_CC2P, "GOT SENSE_COMM", s);
        } else if( mItem == "SENSE_PRIM" ) {
            integer x = (integer)value;
            string  s = value
                      + " " + llList2Integer(name_prim,x)
                      + " " + llList2Integer(link_prim,x)
                      ;
            llMessageLinked(link, PATH_CC2P, "GOT SENSE_PRIM", s);
        } else {
            err = TRUE;
        }
    }

    return err;
}

integer control_SET(list mList, string value) {
    integer err = FALSE;
   
    if( llGetListLength(mList) < 2 )
        err = TRUE;
    else {
        string mItem = llList2String(mList, 1);
        if( mItem == "LEVEL" )
            DEBUG_LEVEL = (integer)value;
        else
            err = TRUE;
    }

    return err;
}

integer control_UUID(list mList, string uuid) {
    integer err = FALSE;
   
    if( llGetListLength(mList) < 2 )
        err = TRUE;
    else {
        string name = llList2String(mList, 1);
        integer commX = indexOfComm(name);
        if( commX <= 0 )
            err = TRUE;
        else {
            removeCOMM(commX);
            registerCOMM(name, uuid);
            llRegionSay(CHAN_COMM, MESS_IDENT);
        }
    }

    return err;
}

control_MESS(integer link, string mess, string value) {
    integer err = FALSE;

    list mList = llParseString2List(mess, [" "], []);
    if( llGetListLength(mList) < 1 )
        err = TRUE;
    else {
        string mItem = llList2String(mList, 0);
        if( mItem == "DUMP" )
            control_DUMP();
        else if( mItem == "GET" )
            err = control_GET(mList, value, link);
        else if( mItem == "SET" )
            err = control_SET(mList, value);
        else if( mItem == "UUID" )
            err = control_UUID(mList, value);
        else if( mItem == "RESET" )
            state reset;
        else if( mItem == "ERROR" )
            state error;
        else
            err = TRUE;
    }

    if( err )
        error(0, "control("+link+","+mess+","+value+")");
}

integer indexOfComm(string comm) {  // Return index of COMM element
    return llListFindList(name_comm, [ comm ]);
}

integer indexOfLink(integer link) { // Return index of PRIM element
    return llListFindList(link_prim, [ link ]);
}

integer indexOfPrim(string prim) {  // Return index of PRIM element
    return llListFindList(name_prim, [ prim ]);
}

integer indexOfUuid(key uuid) {     // Return index of COMM element
    return llListFindList(uuid_comm, [ uuid ]);
}

integer nameCheck(string name) {    // Check prim name (TRUE iff error)
    string err = "";

    if( llSubStringIndex(name, " ") >= 0 )
        err = "blank";

    if( llSubStringIndex(name, ",") >= 0 )
        err = "comma";

    if( llSubStringIndex(name, NAME_QUAL) >= 0 )
        err = "period";

    if( err != "" ) {
        error(0, "name(" + name + ") fmt: " + err);
        return TRUE;
    }

    return FALSE;
}

registerCOMM(string name, key uuid) { // Handle COMM register event
    integer x = indexOfComm(name);
    if( x <= 0 )                    // Ignore name if not interesting
        return;

    if( name == thisObjName )       // Do not register external duplicate name
        return;

    key curr = llList2Key(uuid_comm, x);
    if( curr == NULL_KEY ) {
        debug(2, "regCOMM(" + name + "," + uuid + ") inserted");
//////  name_comm = llListReplaceList(name_comm, [ name ], x, x);
        ping_comm = llListReplaceList(ping_comm, [ PING_COUNT ], x, x);
        send_comm = llListReplaceList(send_comm, [ FALSE ], x, x);
        uuid_comm = llListReplaceList(uuid_comm, [ uuid ], x, x);

        xmitControls(MESS_COMM + " " + uuid, name);
        llRegionSay(CHAN_COMM, MESS_IDENT);
    } else if( curr != uuid )
        error(1, "regCOMM("+name+","+uuid+") dup: "+curr);
}

registerPRIM(string name, integer link) { // Handle PRIM register event
    debug(4, "regPRIM(" + name + "," + link + ")");

    if( nameCheck(name) )
        state error;

    integer x = indexOfPrim(name);
    if( x >= 0 ) {
        if( llList2Integer(link_prim, x) == link )
            return;

        owner("regPRIM("+name+","+link+") dup: "+llList2Integer(link_prim,x));
        state error;
    }

    debug(2, "regPRIM(" + name + "," + link + ") inserted");
    prim_size++;
    name_prim += [ name ];
    link_prim += [ link ];
}

removeCOMM(integer commX) {         // Handle COMM de-register event
    key uuid = llList2Key(uuid_comm, commX);
    if( uuid == NULL_KEY )
        return;

    string name = llList2String(name_comm, commX);
    debug(2, "COMM(" + name + ") inactive");

    xmitControls(MESS_EXIT + " " + uuid, name);
    ping_comm = llListReplaceList(ping_comm, [ 0 ], commX, commX);
    uuid_comm = llListReplaceList(uuid_comm, [ NULL_KEY ], commX, commX);
}

xmitControls(                       // Control message broadcast
        string  mess,               // The message
        string  data)               // The data
{
    integer x;
    for(x= 1; x<prim_size; x++) {   // Broadcast control message
        integer link = llList2Integer(link_prim, x);
        llMessageLinked(link, PATH_CC2P, mess, data);
    }
}

xmitExternal(                       // Send message to external prim
        string   target,            // Target COMM.PRIM name
        string   source,            // Source .PRIM name
        string   mess)              // The message
{
    integer x = llSubStringIndex(target, NAME_QUAL);
    if( x < 0 ) {
        error(0, "xmitEX("+target+","+source+","+mess+") no . in target");
        return;
    }

    string comm = llGetSubString(target, 0, x-1);  // Target COMM
    string prim = llGetSubString(target, x+1, -1); // Target PRIM
    integer targetX = indexOfComm(comm);
    if( x == 0 )                    // If internal message
        targetX = 0;

    if( targetX < 0 ) {             // If target unknown
        error(1, "xmitEX("+target+","+source+","+mess+") unknown COMM");
        return;
    }

    if( targetX == thisTargetX ) {  // If pseudo-external
        source = thisObjName + source; // Include our COMM in source name
        targetX = 0;
    }

    if( targetX == 0 ) {            // If internal message
        xmitInternal(prim, source, mess);
        return;
    }

    integer L = 2; string err = " *OFFLINE*";
    key uuid = llList2Key(uuid_comm, targetX);
    if( uuid != NULL_KEY ) {
        L = 3; err = "";
        mess = NAME_QUAL + prim + source + " " + mess;

        llRegionSay(channel(uuid), mess);
        send_comm = llListReplaceList(send_comm, [ TRUE ], targetX, targetX);
    }

    debug(L, "xmitEX("+target+","+source+","+mess+")" + err );
}

xmitInternal(                       // Send message to internal prim
    string   target,                // Target PRIM name
    string   source,                // Source COMM.PRIM name
    string   mess)                  // The message
{
    integer targetX = indexOfPrim(target);
    if( targetX < 0 ) {
        error(1, "xmitIN("+target+","+source+","+mess+") unknown PRIM");
        return;
    }

    if( targetX == 0 ) {            // If broadcast message
        targetX++;
        while( targetX < prim_size ) {
            integer link = llList2Integer(link_prim, targetX);
            llMessageLinked(link, PATH_MC2P, mess, source);

            targetX++;
        }
    } else {
        integer link = llList2Integer(link_prim, targetX);
        llMessageLinked(link, PATH_MC2P, mess, source);
    }
}

//----------------------------------------------------------------------------
// state: default
default {
    state_entry() {
        current = "default";
        debug(3, "state_entry " + llGetKey());

        // Initialize the lists
        comm_size = 1;              // External intercom list
        name_comm = [ "" ];         // (The THIS name)
        ping_comm = [ PING_COUNT ]; // (Never changes)
        send_comm = [ FALSE ];      // (Never checked)
        uuid_comm = [ llGetKey() ]; // (Never used)

        prim_size = 1;              // Internal prim list
        name_prim = [ "*" ];        // (The broadcast prim)
        link_prim = [   0 ];        // (The broadcast link)

        llSetTimerEvent(0.5);
    }

    state_exit() {
        debug(3, "state_exit");
        onExit();
    }

    on_rez(integer n) {
        debug(3, "on_rez");
        state reset;
    }

    timer() {
        state loading;
    }
}

//----------------------------------------------------------------------------
// state: active
state active {
    state_entry() {
        current = "active";
        debug(3, "state_entry");

        // Initialize listen channels
        integer chan = channel(llGetKey());
        hand += [ llListen(chan, "", NULL_KEY, "") ];
        hand += [ llListen(CHAN_COMM, "", NULL_KEY, "") ];

        // Set ping timer
        llSetTimerEvent(PING_TIMER);

        // Initialization messages
        llRegionSay(CHAN_COMM, MESS_IDENT); // External IDENT
        llMessageLinked(LINK_SET, PATH_CC2P, MESS_PING, thisObjName);
    }

    state_exit() {
        debug(3, "state_exit");
        onExit();
    }

    on_rez(integer n) {
        debug(3, "on_rez");
        state reset;
    }

    link_message(integer link, integer path, string mess, key target) {
        debugLM(link, path, mess, target);
        if( path == PATH_CP2C ) {   // If control message
            if( mess == MESS_INIT ) { // If identification message
                registerPRIM(target, link);

                llMessageLinked(link, PATH_CC2P, MESS_PING, thisObjName);
                return;
            }

            if( mess == MESS_PONG ) { // If identification message
                registerPRIM(target, link);

                // After PONG we must also send MESS_COMM messages
                // These may be duplicated, but they may also be missing
                integer i;
                for(i= 1; i<comm_size; ++i) {
                    if( i != thisTargetX ) {
                        key uuid = llList2Key(uuid_comm,i);
                        if( uuid != NULL_KEY ) {
                            string name = llList2Key(name_comm,i);
                            mess = MESS_COMM+" "+uuid;
                            llMessageLinked(link, PATH_CC2P, mess, name);
                        }
                    }
                }
                return;
            }

            control_MESS(link, mess, target);
            return;
        }

        if( path != PATH_MP2C )     // If not for us
            return;

        integer x = indexOfLink(link);
        if( x < 0 ) {               // If source unknown
            error(0, "errorLM("+link+","+mess+","+target+") link??");
            return;
        }
        string source = NAME_QUAL + llList2String(name_prim, x);

        xmitExternal(target, source, mess);
    }

    listen(integer chan, string name, key uuid, string mess) {
        debugLI(chan, name, uuid, mess);

        if( chan == CHAN_COMM ) {   // Broadcast message
            if( mess != MESS_IDENT ) // Ignore invalid IDENT message
                return;

            registerCOMM(name, uuid);
            return;
        }

        integer commX = indexOfUuid(uuid);
        if( commX < 0 ) {
            error(2, "message(" + mess + "), "
                   + "source(" + name + "," + uuid + ") unknown");
            return;
        }

        // Update the PING counter
        ping_comm = llListReplaceList(ping_comm, [ PING_COUNT ], commX, commX);
        if( mess == MESS_PING )
            return;

        // Verify the message format
        string source = llList2String(name_comm, commX);
        if( llGetSubString(mess, 0, 0) != "." ) {
            error(2, "message("+source+","+mess+") name delimiter 1");
            return;
        }

        // Extract the target and source names
        string target = mess;
        integer i = llSubStringIndex(mess, " ");
        if( i > 0 ) {
            target = llGetSubString(mess, 1, i-1); // Without "."
            if( i >= (llStringLength(mess)-1) )
                mess = "";
            else
                mess = llGetSubString(mess, i+1, -1); // Without " "
        } else {
            target = llGetSubString(mess, 1, -1); // Without "."
            mess = "";
        }

        i = llSubStringIndex(target, NAME_QUAL);
        if( i < 0 ) {
            error(2, "message("+source+","+mess+") name delimiter 2");
            return;
        }
        source = source + llGetSubString(target, i, -1);
        target = llGetSubString(target, 0, i-1);

        // Send the message to our prim
        xmitInternal(target, source, mess);
    }

    timer() {
        integer x;

        integer missing = FALSE;
        for(x= 1; x<comm_size; ++x) {
            if( x != thisTargetX ) {
                integer ping = llList2Integer(ping_comm, x);
                key     uuid = llList2Key(uuid_comm, x);
                if( ping <= 0 ) {
                    missing = TRUE;
                    removeCOMM(x);
                } else {                // Ping required
                    if( llList2Integer(send_comm,x) )
                        send_comm = llListReplaceList(send_comm, [ FALSE ], x, x);
                    else
                        llRegionSay(channel(uuid), MESS_PING);
                    ping_comm = llListReplaceList(ping_comm, [ (ping-1) ], x, x);
                }
            }
        }

        if( missing )
            llRegionSay(CHAN_COMM, MESS_IDENT);
    }
}

//----------------------------------------------------------------------------
// state: error
state error {
    state_entry() {
        current = "error";
        debug(0, "state_entry");
    }

    on_rez(integer n) {
        debug(3, "on_rez");
        state reset;
    }

    // We only process "RESET" messages in error state
    link_message(integer link, integer path, string mess, key target) {
        debugLM(link, path, mess, target);

        if( path == PATH_CP2C ) {   // If control message
            if( mess == "RESET" )   // If "RESET" message
                state reset;
        }
    }
}

//----------------------------------------------------------------------------
// state: loading
state loading {
    state_entry() {
        current = "loading";
        debug(3, "state_entry");

        line= 0;
        thisTargetX = (-1);
        thisObjName = llGetObjectName();

        debug(4, "Loading .COMMLIST");
        llGetNotecardLine(".COMMLIST",0);
    }

    on_rez(integer n) {
        debug(3, "on_rez");
        state reset;
    }

    dataserver(key query_id, string data) {
        integer i;

        if( data == EOF ) {
            integer err = FALSE;
            if( comm_size == 1 ) {
                err = TRUE;
                owner(".COMMLIST empty");
            }

            integer x;
            for(x= 0; x<comm_size; ++x) {
                string s = llList2String(name_comm,x);
                if( s == thisObjName )
                    thisTargetX = x;

                err = err | nameCheck(s);
                for(i= x+1; i<comm_size; ++i) {
                    if( s == llList2String(name_comm,i) ) {
                        err = TRUE;
                        owner(".COMMLIST duplicated(" + s + ")");
                    }
                }
            }

            if( err )
                state error;
            state active;
        }

        debug(4, "dataserver(" + data + ")");
        i = llSubStringIndex(data,"//");
        if( i != -1 ) {
            if( i == 0 )
                data = "";
            else
                data = llGetSubString(data, 0, i-1);
        }

        data = llStringTrim(data, STRING_TRIM);
        if( data != "" ) {
            name_comm += [ data ];
            ping_comm += [ 0 ];
            send_comm += [ FALSE ];
            uuid_comm += [ NULL_KEY ];

            ++comm_size;
        }

        ++line;
        llGetNotecardLine(".COMMLIST",line);
    }
}

//----------------------------------------------------------------------------
// state: reset
state reset {
    state_entry() {
        current = "reset";
        debug(0, "state_entry");
        llSetTimerEvent(1.0);
    }

    timer() {
        llSetTimerEvent(0.0);
        llResetScript();
    }
}


The .COMMLIST notecard
{L_CODE}:
//----------------------------------------------------------------------------
//
// Title-
//       .COMMLIST.txt
//
// Purpose-
//       Contains the list of communicating root (COMM) prims.
//
// Format-
//       Each interesting object is on its own line in this list.
//       Comment lines begin with '//'
//
// Restrictions-
//       Blanks at the end of object names are ignored.
//       Names may not contain blanks, commas, or periods.
//
//----------------------------------------------------------------------------
COMM1                               // Test object, one of which is us
COMM2                               // Test object, one of which is us
COMM3                               // Test object, one of which is us


The example usage script, TestBlip
{L_CODE}:
//----------------------------------------------------------------------------
//
// Title-
//       TestBlip.lsl
//
// Purpose-
//       Test Intercom.lsl in prim.
//
// Activity-
//       Sends "BLIP" messages to all partner prims.
//       Responds "BLOP" to "BLIP" messages.
//
//----------------------------------------------------------------------------
integer  DEBUG_LEVEL = 5;           // Debugging level: None(0) .. (5)Full

integer  PATH_MC2P = 4095;          // COMM => PRIM link_message message path
integer  PATH_MP2C = 4094;          // PRIM => COMM link_message message path
integer  PATH_CC2P = 4093;          // COMM => PRIM link_message control path
integer  PATH_CP2C = 4092;          // PRIM => COMM link_message control path

string   MESS_COMM = "COMM";        // Intercom COMM message
string   MESS_EXIT = "EXIT";        // Intercom EXIT message
string   MESS_PING = "PING";        // Intercom PING message
string   MESS_PONG = "PONG";        // Intercom PONG message
string   NAME_QUAL = ".";           // Intercom name qualifier

string   current = "*initial*";     // The current state name
list     hand = [];                 // Listen channel handle list

string   comm = "<COMM>:";          // Default COMM name
string   CSV = "";                  // The CSV source list

//===================================================================
debug(integer L, string str) {      // Debug message w/LEVEL
    if( DEBUG_LEVEL > L )
        llOwnerSay(comm + llGetScriptName() + ":" + current + ": " + str);
}

error(integer L, string str) {      // Error message w/LEVEL
    debug(L, "ERROR: " + str);
}

owner(string str) {                 // Owner message
    llOwnerSay(llGetScriptName() + ": " + str);
}

hcdm(string str) {                  // Hard Core Debug Message
    llOwnerSay(llGetScriptName() + ": " + str);
}

debugLM(integer p0, integer p1, string p2, key p3) { // Debug Link Message
    debug(4, "link_message(" + p0 + "," + p1 + "," + p2 + "," + p3 + ")");
}

onExit() {                          // Clean up at state exit
    llSetTimerEvent(0.0);

    integer i;
    integer m = llGetListLength(hand);
    for(i= 0; i<m; ++i) {
        llListenRemove(llList2Integer(hand, i));
    }
    hand = [];
}

string csvAppend(string CSV, string name) { // Append name to CSV list
    string result = CSV;

    if( result != "" )
        result += ", ";
    result += name;

    return result;
}

string csvRemove(string CSV, integer x) { // Remove element at index
    list mList = llCSV2List(CSV);
    integer m = llGetListLength(mList);
    if( x < 0 || x >= m )           // If out of range
        return CSV;                 // Silently ignore removal

    if( x == 0 ) {                  // If removing first element
        if( m == 1 )                // If removing only element
            return "";

        mList = llList2List(mList, 1, -1);
    } else if( x == (m-1) ) {       // If removing last element
        mList = llList2List(mList, 0, -2);
    } else {
        mList = llList2List(mList, 0, x-1) + llList2List(mList, x+1, -1);
    }

    return llList2CSV(mList);
}

integer csvIndexOf(string CSV, string name) { // Return index of element
    list mList = llCSV2List(CSV);
    integer m = llGetListLength(mList);
    if( CSV == "" )
        m = 0;

    integer i;
    for(i= 0; i<m; ++i) {
        if( name == llList2String(mList,i) )
            return i;
    }

    return (-1);
}

integer register(string source) {   // Handle source registration event
    debug(4, "register(" + source + ")");

    integer x = csvIndexOf(CSV, source);
    if( x >= 0 )
        return FALSE;

    CSV = csvAppend(CSV, source);
    debug(2, "register(" + source + ") inserted");

    return TRUE;
}

remove(string source) {             // Handle source de-registration event
    debug(4, "remove(" + source + ")");

    integer x = csvIndexOf(CSV, source);
    if( x < 0 ) {
        error(0, "register(" + source + ") NOT REGISTERED");
        return;
    }

    CSV = csvRemove(CSV, x);
    debug(2, "remove(" + source + ") removed");
}

string route2COMM(string route) {   // Extract COMM from route
    integer x = llSubStringIndex(route, NAME_QUAL);
    if( x > 0 )
        route = llGetSubString(route, 0, x-1);

    return route;
}

string route2PRIM(string route) {   // Extract PRIM from route
    integer x = llSubStringIndex(route, NAME_QUAL);
    if( x > 0 )
        route = llGetSubString(route, x+1, -1);
    else
        route = "";

    return route;
}

//----------------------------------------------------------------------------
// state: default
default {
    state_entry() {
        current = "default";
        debug(3, "state_entry " + llGetKey());

        // Initialize variables
        CSV = "";

        // Initialization messages
        llMessageLinked(LINK_ROOT, PATH_CP2C, MESS_PONG, llGetObjectName());
        llSetTimerEvent(30.0);
    }

    state_exit() {
        debug(3, "state_exit");
        onExit();
    }

    on_rez(integer n) {
        debug(3, "on_rez");
        state reset;
    }

    link_message(integer link, integer path, string mess, key source) {
        debugLM(link, path, mess, source);

        integer i;
        list mList = llParseString2List(mess, [" "], []);
        integer m = llGetListLength(mList);
        string cmd = llList2String(mList, 0);
        if( path == PATH_CC2P ) {   // If control message
            if( cmd == MESS_COMM ) {
                llMessageLinked(link, PATH_MP2C, "PRIM", source + ".*");
                return;
            }

            if( cmd == MESS_EXIT ) {
                string comm = route2COMM(source);
                mList = llCSV2List(CSV);
                m = llGetListLength(mList);
                if( CSV == "" )
                    m = 0;

                for(i= 0; i<m; ++i) {
                    string item = llList2String(mList,i);
                    if( comm == route2COMM(item) )
                        remove(item);
                }

                return;
            }

            if( cmd == MESS_PING ) {
                comm = source + ":";
                llMessageLinked(link, PATH_CP2C, MESS_PONG, llGetObjectName());
                return;
            }

            error(0, "CONTROL message(" + mess + ")");
        }

        if( path != PATH_MC2P )     // If unknown message
            return;

        if( cmd == "BLIP" ) {
            llMessageLinked(link, PATH_MP2C, "BLOP", source);
            return;
        }

        if( cmd == "BLOP" ) {
            return;
        }

        if( cmd == "PRIM" ) {
            register(source);
            return;
        }

        if( cmd == MESS_EXIT ) {
            remove(source);
            return;
        }

        error(0, "EXTERNAL message(" + mess + ")");
    }

    timer() {
        debug(5, "timer()");
        list mList = llCSV2List(CSV);
        integer m = llGetListLength(mList);
        if( CSV == "" )
            m = 0;

        integer i;
        for(i= 0; i<m; ++i) {
            string source = llList2String(mList,i);
            llMessageLinked(LINK_ROOT, PATH_MP2C, "BLIP", source);
        }
    }
}

//----------------------------------------------------------------------------
// state: reset
state reset {
    state_entry() {
        current = "reset";
        debug(0, "state_entry");
        llSetTimerEvent(1.0);
    }

    timer() {
        llSetTimerEvent(0.0);
        llResetScript();
    }
}


Top
 Profile  
 
 Post subject: Re: Object to object communication
PostPosted: Wed Nov 09, 2011 7:38 pm 
OSG Elite

Joined: Tue Dec 21, 2010 8:01 pm
Posts: 370
Incidentally.. Oddball's lighting is top drawer. We used it for our halloween dance. Works great, highly recommend it...

_________________
Walter Balazic
Littlefield Systems
http://www.lfgrid.com


Top
 Profile  
 
Display posts from previous:  Sort by  
Post a new topicPost a reply Page 2 of 2   [ 17 posts ]
Go to page Previous  1, 2


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
610nm Style by Daniel St. Jules of Gamexe.net