• warning: Creating default object from empty value in /home/ordinal/ordinalmalaprop.com/engine/modules/taxonomy/taxonomy.pages.inc on line 34.
  • GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.
  • GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.
  • strict warning: Non-static method view::load() should not be called statically in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/views.module on line 906.
  • strict warning: Declaration of views_handler_field_comment::init() should be compatible with views_handler_field::init(&$view, $options) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/modules/comment/views_handler_field_comment.inc on line 49.
  • strict warning: Declaration of views_handler_filter::options_validate() should be compatible with views_handler::options_validate($form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/handlers/views_handler_filter.inc on line 607.
  • strict warning: Declaration of views_handler_filter::options_submit() should be compatible with views_handler::options_submit($form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/handlers/views_handler_filter.inc on line 607.
  • strict warning: Declaration of views_handler_filter_node_status::operator_form() should be compatible with views_handler_filter::operator_form(&$form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/modules/node/views_handler_filter_node_status.inc on line 13.
  • strict warning: Declaration of views_plugin_row::options_validate() should be compatible with views_plugin::options_validate(&$form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/plugins/views_plugin_row.inc on line 134.
  • strict warning: Declaration of views_plugin_row::options_submit() should be compatible with views_plugin::options_submit(&$form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/plugins/views_plugin_row.inc on line 134.
  • strict warning: Non-static method view::load() should not be called statically in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/views.module on line 906.
  • strict warning: Declaration of views_handler_argument::init() should be compatible with views_handler::init(&$view, $options) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/handlers/views_handler_argument.inc on line 744.
  • strict warning: Declaration of views_handler_filter_boolean_operator::value_validate() should be compatible with views_handler_filter::value_validate($form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/handlers/views_handler_filter_boolean_operator.inc on line 159.
  • strict warning: Non-static method view::load() should not be called statically in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/views.module on line 906.

Scripting Examples

A Useful Script - "Mass Distribution by List of Names in a Notecard"

I recently had cause to distribute a number of items to a large number of people, whose names I was in possession of a list of, but not, of course, their keys.

The appalling lack of a useful llName2Key function unfortunately makes it a little challenging to send things out, but this is a problem that I have encountered before, and the obvious course of action is to

  1. put all of the items to be sent out into a prim;
  2. add a notecard containing the list of names to which these items are to be sent;
  3. add a script which simply goes through these names, queries one of the several "name2key" databases in existence, and, should it find an appropriate key, sends the items out.

For general use I include such a script herein.

In this I included features which tell one how many lines of the names notecard remain, and an estimate of the how much time remains, as well, though this may or may not be terribly accurate.

I am aware that it could be made considerably faster by the use of subscripts to send the inventory items, but that would make for a rather poor example script; I would prefer to keep the whole affair as simple as possible, in other words, in one script that is put into one prim. The introduction of inventory-giving subscripts is left as an exercise for the keen student.

~*~

As a further note, a future script using this sort of system to be published here will be a vendor that optionally sends the item to another person - in other words, a gift-giver that allows people to purchase copy/no-trans goods for others, which will allow those who had been forced to rely upon Xstreet for this the opportunity to abandon the dratted site.

Mass distribution script

Code summary: 

Sends inventory contents to each named individual on a list, by trying to get their key from a series of databases. This would be so much easier if there was a name2key function. But there isn't.

To use this script: place it in a prim, along with some other items that you want to send to people, and a notecard called "Names" which has a list of avatar names to send items to, one per line without spaces before or after them. (Blank lines will be ignored; anything else, and the script will try to find the line as if it were a name, and fail, and tell you that it has failed.)

Then, touch to start sending. There will be a display of names left to check and estimated time remaining.

There is no way of determining whether an object has been successfully sent by script, or whether somebody was in busy mode (this is the usual culprit when people complain of not receiving an item - either that, or they did receive it but can't find it) or declined the item. My apologies.

// Mass distribution script // Ordinal Malaprop 2010-01-15 11:29 //..................................................................... // Sends inventory contents to each named individual on a list, by trying to get their key from a series of databases. This would be so much easier if there was a name2key function. But there isn't. // To use this script: place it in a prim, along with some other items that you want to send to people, and a notecard called "Names" which has a list of avatar names to send items to, one per line without spaces before or after them. (Blank lines will be ignored; anything else, and the script will try to find the line as if it were a name, and fail, and tell you that it has failed.) // Then, touch to start sending. There will be a display of names left to check and estimated time remaining. // There is no way of determining whether an object has been successfully sent by script, or whether somebody was in busy mode (this is the usual culprit when people complain of not receiving an item - either that, or they did receive it but can't find it) or declined the item. My apologies. // The original script can be found at http://ordinalmalaprop.com/engine/code/mass-distribution-script //--------------------------------------------------------------------- // LICENCE - Creative Commons "Attribution" 3.0 // http://creativecommons.org/licenses/by/3.0/ // Basically use it how you like, but if you do, please include a mention somewhere of me, and if possible a link to the original script. //--------------------------------------------------------------------- // Globals and constants // Configurable string NAME_NOTECARD = "Names"; // Change this if you want to call the notecard with your list of names on it something else. float TIMEOUT = 10.0; // There is no particular reason you would change this but you might wish to perhaps. integer TEST = FALSE; // change to TRUE to just run through the names in your notecard without sending anything // Not configurable - leave these alone key gQuery = NULL_KEY; string gAvName = ""; integer gLine = 0; integer gNumberOfLines = 0; list gItems = []; list gNotFound = []; integer gQuerySource = -1; //--------------------------------------------------------------------- // Functions // Looks for the next name on the list get_next_name() { llSetTimerEvent(TIMEOUT); if (gNumberOfLines == 0) { llSetText("Checking list size", <1.0, 1.0, 0.0>, 1.0); gQuery = llGetNumberOfNotecardLines(NAME_NOTECARD); } else { gQuery = llGetNotecardLine(NAME_NOTECARD, gLine++); update(); } } // Updates the prim display update() { integer line = gLine - 1; integer done = llRound(100 * line / gNumberOfLines); float x = (float)done / 100.0; llSetColor(, ALL_SIDES); llSetText((string)done + "% done (" + (string)line + "/" + (string)gNumberOfLines + ")\nRemaining time: " + time_left(line), <1.0, 1.0, 0.0>, 1.0); } string time_left(integer line) { if (gNumberOfLines == 0) return "unknown"; if (line == 0) { llResetTime(); return "unknown"; } float timePerLine = llGetTime() / line; return minutes_seconds(llRound(timePerLine * (float)(gNumberOfLines - line))); } string minutes_seconds(integer seconds) { if (seconds < 60) return (string)seconds + "s"; integer minutes = seconds / 60; seconds -= minutes * 60; string msg = (string)minutes + "m"; if (seconds > 0) msg += (string)seconds + "s"; return msg; } // This function sends queries to web databases to get keys from names. It moves through a series of different ones based on the current value of gQuerySource - if a query fails, it moves to the next one. I think that three different databases should eventually provide a reasonable result. Note that you can move the databases around according to your preference by cutting and pasting within the "if ... else" blocks. make_key_request(string name) { gAvName = name; llSetTimerEvent(TIMEOUT); gQuerySource++; string source = ""; if (gQuerySource == 0) { // modularsystems.sl name2key service source = "lawlinter.net"; gQuery = llHTTPRequest("http://lawlinter.net/secondlifeutility/name2key.php5?name=" + llEscapeURL(name), [HTTP_METHOD, "GET"], ""); } else if (gQuerySource == 1) { // visiontech - slow, but claims to be complete source = "VisionTech"; name = llDumpList2String(llParseString2List(name, [" "], []), "_"); gQuery = llHTTPRequest("http://vision-tech.org/name2key/search.php?name=" + name, [HTTP_METHOD, "GET"], ""); } else if (gQuerySource == 2) { // w-hat source = "w-hat"; gQuery = llHTTPRequest("http://w-hat.com/name2key?terse=1&name=" + llEscapeURL(name), [HTTP_METHOD, "GET"], ""); } if (source == "") { // failed, try a new one llOwnerSay("All sources failed to find a key for '" + gAvName + "', moving on."); gQuerySource = -1; gNotFound = (gNotFound = []) + gNotFound + [gAvName]; get_next_name(); } else if (gQuerySource > 0) { llOwnerSay("Trying " + source + " database..."); } } // Gets all of the items to be sent, and sets text based on what they are list get_item_list() { integer f = llGetInventoryNumber(INVENTORY_ALL) - 1; list items = []; string thisScript = llGetScriptName(); while (f >= 0) { string name = llGetInventoryName(INVENTORY_ALL, f); if (name != "" && name != thisScript && name != NAME_NOTECARD) { items = (items = []) + items + [name]; } f--; } if (llGetListLength(items) > 0) { string msg = "Sending:\n" + llDumpList2String(items, "\n"); if (TEST) msg = "[TEST] Not " + (msg = "") + msg; llSetText(msg, <0.0, 1.0, 0.0>, 1.0); } else { llSetText("No items found to send", <1.0, 0.0, 0.0>, 1.0); } return items; } // Sends the actual items to a particular avatar send_items(key id) { integer f = llGetListLength(gItems) - 1; llOwnerSay("Giving items..."); while (f >= 0) { string name = llList2String(gItems, f); if (TEST) llSleep(2.0); else llGiveInventory(id, name); f--; } llOwnerSay("Done."); } //--------------------------------------------------------------------- // Main // The default state is "not sending anything right at this moment". default { state_entry() { llSetText("", <0.0, 0.0, 0.0>, 1.0); llSetColor(<1.0, 1.0, 1.0>, ALL_SIDES); gItems = get_item_list(); llOwnerSay(llGetScriptName() + " ready, touch to start sending inventory."); } on_rez(integer p) { llResetScript(); } touch_start(integer n) { if (llGetListLength(gItems) == 0) { llOwnerSay("Nothing suitable in this item's inventory to give!"); } else if (llGetInventoryType(NAME_NOTECARD) == INVENTORY_NONE) { llOwnerSay("You need a notecard called '" + NAME_NOTECARD + "' in this item for it to send its contents to people."); } else { state sending; } } changed(integer change) { if (change & CHANGED_INVENTORY) llResetScript(); } } // In "sending" state, we are actually reading names, finding keys and sending things out. state sending { state_entry() { gNumberOfLines = 0; gLine = 0; gNotFound = []; gQuerySource = -1; llOwnerSay("Beginning send - take into inventory to stop this."); get_next_name(); } on_rez(integer p) { llResetScript(); } dataserver(key query, string data) { if (query != gQuery) return; if (data == EOF) { llOwnerSay("All notecard lines scanned."); state default; } else if (gNumberOfLines == 0) { gNumberOfLines = (integer)data; get_next_name(); } else if (data != "") { make_key_request(data); } else get_next_name(); } http_response(key query, integer status, list metadata, string data) { if (query != gQuery) return; llSetTimerEvent(0.0); key avKey = (key)data; if (llStringLength(data) == 36 && avKey != NULL_KEY) { llOwnerSay("Found key for '" + gAvName + "' : " + (string)avKey); gQuerySource = -1; send_items(avKey); } else { llOwnerSay("ERROR: Could not find avatar name '" + gAvName + "' in database."); make_key_request(gAvName); } get_next_name(); } timer() { llOwnerSay("ERROR: timed out looking for avatar name '" + gAvName + "'."); make_key_request(gAvName); } state_exit() { llOwnerSay("Names not found: " + llList2CSV(gNotFound)); float time = llGetTime(); llOwnerSay("Total time: " + minutes_seconds((integer)time) + " seconds (" + (string)(time / gNumberOfLines) + " seconds per line)."); } }

Ordinal Christmas Particle Tree

// Christmas Particle Tree // Ordinal Malaprop 2009-12-22 // LICENCE // Creative Commons Attribution-Noncommercial 3.0 // See http://creativecommons.org/licenses/by-nc/3.0/ for more details //--------------------------------------------------------------------- // Play with these values if you wish float HEIGHT = 4.0; float MAX_BEND = 0.05; float BRANCH_LENGTH = 1.0; integer BRANCH_DENSITY = 20; vector BASE_COLOUR = <0.25, 0.75, 0.25>; //--------------------------------------------------------------------- leaves(float z) { z /= HEIGHT; llParticleSystem([ PSYS_PART_FLAGS, PSYS_PART_FOLLOW_VELOCITY_MASK | PSYS_PART_EMISSIVE_MASK, PSYS_PART_START_COLOR, BASE_COLOUR * ((z * 0.7) + llFrand(0.3)), PSYS_PART_START_ALPHA, 1.0, PSYS_PART_START_SCALE, <0.1, BRANCH_LENGTH, 0.0>, PSYS_PART_MAX_AGE, 30.0, PSYS_SRC_ACCEL, <0.00,0.00,0.0>, PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_ANGLE_CONE, PSYS_SRC_ANGLE_BEGIN, PI * (0.5 + z * 0.4), PSYS_SRC_ANGLE_END, PI * (0.5 + z * 0.4), PSYS_SRC_BURST_RATE, 0.05, PSYS_SRC_BURST_PART_COUNT, BRANCH_DENSITY, PSYS_SRC_BURST_RADIUS, BRANCH_LENGTH * 0.62, PSYS_SRC_BURST_SPEED_MIN, 0.0, PSYS_SRC_BURST_SPEED_MAX, 0.05, PSYS_SRC_MAX_AGE, 0.0 ]); llSleep(0.8); llParticleSystem([]); } //--------------------------------------------------------------------- default { state_entry() { llSetAlpha(0.0, ALL_SIDES); llSetRot(ZERO_ROTATION); vector startPos = llGetPos(); vector pos = startPos; pos.z += 1.0; rotation direction = llEuler2Rot(<0.0, 0.0, llFrand(TWO_PI)>); float bendiness = llFrand(MAX_BEND); llSetRot(direction); while (pos.z < startPos.z + HEIGHT) { llSetPos(pos); leaves(pos.z - startPos.z); llSetRot(llEuler2Rot(<0.0, bendiness + llFrand(0.05), 0.0>) * llGetRot()); pos += <0.0, 0.0, 0.5> * llGetRot(); } llSetRot(ZERO_ROTATION); llSetPos(startPos); llSetAlpha(1.0, ALL_SIDES); } on_rez(integer p) { llResetScript(); } touch_start(integer n) { llResetScript(); } }

Attachments, Mono and the Gallows

I was informed a little while ago of a JIRA issue that has consequences for those Scripters who - firstly - make scripts for attachments, or vehicles, or regularly rezzed items, which is quite a few of us, and - secondly - compile things with "Mono", which is also a popular pastime.

I made a note of this in my TwitterThing and, in recent days, have seen at least three separate references to the problem, despite the issue first being raised in SVC-3895 in February of this year (so, a very young JIRA issue, then).

Of course, on the TwitterThing one is restricted as to the length of explanation, and on that basis I would like to make brief mention here. My analysis is the following:

  1. The initial JIRA issue and subsequent comments indicate that rezzing Mono scripted objects is murderous to the FPS and performance of a region.

  2. "Rezzing" in this instance is not only rezzing objects via script - which would mean bullets - but also, vehicles and attachments entering the region.

  3. Mono scripts still have the usual advantages regarding efficiency and such after they are rezzed. (They do I am told use more memory which might be significant if script limits are enacted - but that is a different issue.)

  4. Therefore: for anything which might regularly be rezzed, most significantly bullets but also attachments and vehicles, which are re-rezzed on teleport or region crossing, I would advise recompiling in LSL to avoid the apparently noticeable performance impact. (I have not tested this myself beyond the odd unrepresentative experiment, but many scripters in the comments of the JIRA whom I personally trust and respect have done so.) For static devices, sales boxes, vendors, servers of all flavours, I would advise using Mono.

~*~

On a separate note, it is perhaps an indication of how long it has been since I properly wandered the Grid that I am shocked at the current state of Region Crossing. It really is like participating in some sort of novelty fairground attraction, where one is attached to a long piece of stretchy substance, flies off into the distance (without being able to control the process) and then is rapidly thrown backwards. This sort of thing might be amusing to the Young but really does not divert me, and I cannot help but question the Laboratory's decision in implementing it now.

Oh - and somebody erected a gallows next to my small Library plot in Zindra, which in another world might be taken as a threat, but here, is more of a welcome sign.

A script in haiku

which, itself, says a haiku.

For no easily identifiable reason.

[geshifilter-code]// LSL Haiku, first attempt // Ordinal Malaprop // Sat Aug 22 15:20:04 BST 2009 // RULES: // Each function must be a haiku including the declaration, // though only identifiable words and numbers need be included, not // punctuation. // Events must contain a haiku i.e. be three lines, 5/7/5. // "0" can be pronounced zero or "oh" to make things slightly easier. string say(string toSay) { llSay(0, toSay); return toSay + " said."; } string theFirstLinePlease() { string firstLine = "This is the first"; return firstLine + " line."; } string theSecondLine() { string lineTwo = "the second line."; return "This, " + lineTwo; } string andTheThirdLine() { string thirdLine = "it really the"; return thirdLine + " last?"; } default { state_entry() { say(theFirstLinePlease()); say(theSecondLine() + " Or is,"); say(andTheThirdLine()); } }[/geshifilter-code]

An Inventory Permissions Checking Script

I was reminded recently of a script that I wrote quite some time ago and appear not to have published anywhere. I did mean to. Perhaps I did, and have simply forgotten. In any case, it can be found here:

The task that I use it to accomplish is to check the permissions of the contents of an item before sale or distribution.

In Which Ordinal Belatedly Answers Questions that She Herself Actually Requested Folk To Post

An Unpredicted Event has occurred! Namely, that I have shuffled off the Chains of Idleness and Attempted to provide Answers Of Some Use to the questions which I Previously Invited regarding Scriptery. I believe that blithely promising a Weekly Session was somewhat ambitious of me, but I really should not have taken such a ridiculous length of time.

In any case, Self-Flagellation aside, here the Curious and Unjustly Delayed might find responses of some sort. Please, sir or madam, do feel free to request further detail, correct my undoubtedly innumerable errors, berate me for Flippancy, and also, ask more questions, which I shall try not to take Quite So Long To Answer in the future.

A Simple yet Convenient Inventory-Confirming Script

subtitled: "Part the Twenty-Somethingth of Ordinal's Scripting Primer"

When selling Items, I believe that the importance of setting their Permissions is well-known, lest either customers be unable to use the things or able to sell them on willy-nilly, and part of this process is making sure that the contents of an Item also have the correct Permissions. There are numerous instances where this can cause a bother.

Syndicate content