Monday, February 27, 2006

Animated discourse

Vitruvian plywood I have often complained about the lack of suitable animations in Second Life of use to a designer of mechanical items, such as myself. I have often complained at quite tedious length, in fact; I was doing so just yesterday. The issue is that the standard method of creating these thing is a program called Poser, which I'm sure is a fine piece of software but seems not only over-featured for use with SL, but also overpriced.

I was therefore extremely pleased to come across a forum thread devoted to a free animation production program called Avimator. It is claimed that it is still in an early stage of development but I found it perfectly adequate and, indeed, intuitive for the production of custom animations and poses. For instance, my Mk909 Engine Rifle and swordstick (both unreleased at this stage) now have holding poses more suitable for their designs than the standard, and I produced a "lunge" animation for the swordstick far more appropriate than the existing "sword_slash_r" (only a very poor fencer would swish their blade about in such a manner).

Sunday, February 26, 2006

SLurling and the status of aeroplanes

Those who publish pieces regarding Second Life on the internet will be interested to learn of a service known as SLurl, which allows once to easily link to a location in Second Life and have the viewer taken to a map of it and given the option to visit, whether they have the Second Life client installed or not.

I consider this a most useful service to provide, and a simple SLurl is just of the form:

http://slurl.com/secondlife/Acontia/56/186/86/

which one would hope that anyone could construct. However, the building of a customised SLurl that utilises the full range of other options is somewhat time-consuming and a little daunting to the novice.

To save time in this matter, I have created what seems to me a useful web page that allows one to simply fill in the blanks on a form and produce a SLurl. It is called SLurlBuilder. Please feel free to use it as desired.

Me with paper aeroplane

If anyone was concerned with the progress of my paper aeroplane investigations, I can announce that I did, in the end, come up with a design for the aeroplanes that seems to provide reasonable results. Rather than calculating the angle of attack each time, I simply assumed that it would always be zero given that the plane does turn to face its direction of movement anyway.

The plane now basically works with lift and drag, both proportional to the velocity. Lift applies in its local Z-axis, and drag in its local X-axis. Using llSetForce with the local flag set really does save a lot of time as far as calculating the correct co-ordinates is concerned.

The resulting item is now available at Ordinal Laboratories, but one can also scan the aeroplane code here and now should one wish (pretty colourised HTML version).

Wednesday, February 22, 2006

On the use of paper to construct small flying devices

I confess that I have been building weaponry yet again, and this time some of the most devastating and immoral devices ever created. Yes, I have been building paper aeroplanes.

small paper plane The basic launching device is quite simple, just a paper aeroplane that you hold in your hand and which throws a sub-aeroplane of identical appearance but quite different behaviour. The sub-aeroplane (which I shall term the plane, as opposed to the launcher, for convenience's sake) is the issue here. It's quite simple to give the plane a high buoyancy and just let it fly across the landscape or classroom:

// Simple paper aeroplane script
// Ordinal Malaprop
// 2006-02-21

default
{
on_rez(integer param)
{
llSetBuoyancy(0.9);
}

collision_start(integer n)
{
llTriggerSound("pop", 1.0);
if (llDetectedType(0) & AGENT) {
llWhisper(0, llDetectedName(0) + " has been hit by a
paper aeroplane from " + llKey2Name(llGetOwner()) +
"!");
}
llDie();
}

land_collision_start(vector pos)
{
llDie();
}
}


(Note the telltale element there in the script, designed to prevent pupils from pretending that it was not they who committed the offence.) This looks perfectly fine and would allow one to rain paper aeroplanes on Philip Linden quite effectively - as long as one throws them horizontally. At a steeper angle, however, they look a little ridiculous. Firstly they travel quite happily at the same speed a great distance into the air, which real aeroplanes do not do. Secondly, as they fall, they retain the precise same angle that they had at launch, which again, real aeroplanes do not do.

It would seem that the best idea would be to have a simple simulation of aerofoil lift combined with the "point in the direction of travel" mechanism described in my previous post concerning rocketry, and on investigating this I really do mean simple. Lift appears to be proportional to the square of the speed, and I plan to simplify the lift co-efficient drastically, so that it simply goes to zero after the plane goes outside a certain angle. I shall remove the buoyancy too, as I am not actually using Cavorite-impregnated paper.

A useful enhancement to the launcher here would be to allow the wielder to hold down their mouse button to increase the speed at which the plane will be launched, releasing it to throw, as this will affect its behaviour.

Please do not ask how I plan to deal with planes that have rolled around their forward axis, because I will make a face as if sucking on a sherbet lemon.

Sunday, February 19, 2006

On the matter of the serving of refreshments; an eye on intrusion

I have recently expanded and redeveloped my showroom area and to celebrate this, have constructed a device of great social import - an Automated Champagne Waiter, controlled by its own specialised engine and the most accurate thermometers available to chill the vintage champagne to the perfect temperature and pour it as if one was in the finest Paris hotel. Moreover, it has the capacity to top up one's glass as often as desired. (It will not actually follow one around doing this. That is a project for later I feel.)

Champagne machine

I think, though, that it could be improved. Dear reader, what is it that you would most like to see from a champagne device? I'm at a bit of a loss for ideas for improvement.

Incidentally, I would hope that no visitors consume so much champagne that they come to believe that damaging the highly volatile fuel tank on the dirigible deck is a good idea. A few impacts from high-velocity items such as bullets and... well, I'm not responsible for the consequences, and my lawyers confirm this.

I would also appreciate it if they did not use the high-speed transit chairs if their stomachs are feeling a tad unstable, as there is nobody to clean the area apart from myself, and I am a modern woman who does not feel it is her place to do such a thing. We are not living in the eighteenth century any more. I trust that anyone becoming ill after a jaunt will bring their own mop and bucket.

---

More practically, I note that folk are still complaining about the interference of ne'r-do-wells in their home areas, and I agree that it is most improper occurrence should someone return again and again to taunt a lady or gentlemen, and take photographs of their bedroom activities, which I am informed is a common pastime of such people. With this in mind there is now a Defensive Panopticon available, easily updatable with specific names, that warns one when any of those on the list of unwelcome people is around.

Defensive Panopticon

Of course, there is always the ban tool on a land parcel, but that does not help anyone who has chosen to make their home some way above the ground, and if one has a somewhat small area it is quite possible for a ruffian to sit very close and listen in to one's private conversations. For this reason, the Panopticon alerts people whenever offenders come within ninety-six metres, over one's land or not, and has the potential (if so desired) to eject them at any altitude should they trespass.

I have often pledged never to produce any so-called "security" item that is indiscriminate in its effects, throwing pilots out of aeroplanes and so forth, but one which requires specific names to be added I feel is quite legitimate. This is a simple device, which I designed some time ago, and have been meaning to release for some time once it has developed a friendlier interface.

It must be said that it might be considered somewhat, well, intimidating in appearance.

Friday, February 17, 2006

A polite notice

A polite notice

Vending devices in Second Life are often distinctly brusque and indeed even rude, as well as being festooned with garish floating text. Last night, whilst designing a device of similar purpose for my own potential use - I have not made up my mind - I decided that in any case mine would be more polite.

(Also note a new spinning FOR SALE sign... *sigh* I really need to move out of this area.)

Tuesday, February 14, 2006

Communications and so forth

A perpetual problem for myself and others whose body clocks are tuned to Greenwich Mean Time is that of communication with other residents of Second Life. A gap of eight hours between London and the Western coast of the Americas means that, when dealing with those resident in the Colonies, one spends much of one's time asleep when they are awake, and then wakes and is eager to speak, but is unable to actually enter Second Life due to the demands of work and has to wait for many hours, tapping fingers irritably and perhaps forgetting what one meant to say.

(This is not to mention the much greater irritation caused by not being able to attend events, but there is little to be done about that apart from demanding that they start earlier. LSL doesn't have any time machine functions it appears.)

an old telephone There are also other occasions when one is trapped in the Other World for extended periods - say, on account of one's Powerbook having broken down again - with access to email but not to Second Life itself. It would be nice to be able to at least initiate messages, and at the moment one cannot do this. Most people are aware that instant messages from within Second Life can be forwarded as email, and many of those people are also aware that replying to the email will send an instant message back.

What fewer people are aware of is that the address that one replies to is actually only a temporary session one, and is not reliable for long term use. Normally, to send an email into Second Life one addresses it to key-of-the-recipient@lsl.secondlife.com, and when one receives an email from an instant message, the reply address is similarly key-of-the-sender@lsl.secondlife.com.

And that's all well and good when dealing with objects. Objects retain their key indefinitely, so I can save the key of an object somewhere, send it emails until the end of the world at the same address and it will always pick them up. But this does not work for communicating with people - the value of key-of-the-sender above when they send you email via IM is not their actual key.

I am not sure whether addressing mail to actual-avatar-key-of-the-recipient@lsl.secondlife.com works, but it's inconvenient to carry around an address book, or keyring I suppose, full of impossible-to-remember keys. If this doesn't work, and it's only temporary keys that do, which may be an attempt to limit people harassing others via email sent from the Other World (laudable intention, annoying results for me) there is no way to initiate a conversation from outside.

(Yes, Ordinal, get to the point.) So, anyway, here is my temporary solution - a script that waits for email and turns it into instant messages. Say I wanted to send a message to my friend Professor Jefferson Gould but was unable to log on. When I first set the object going, it said three things which hopefully I recorded somewhere:

Email-IM Gateway: My email address is some-key-or-other@lsl.secondlife.com
Email-IM Gateway: Security key is *12345678* - include this as the subject of the email
Email-IM Gateway: Polling for email every 60.00000 seconds


Actually I don't need to record the last one, that's a bit irrelevant, but the first two I do. I compose a short message to Professor Gould and send an email in the following format:

To: some-key-or-other@lsl.secondlife.com
Subject: *12345678*
---
Jefferson Gould//Mr Watson - come here!


The gateway receives the email and sends two instant messages to Professor Gould:

Email-IM Gateway: Ordinal Malaprop has sent you the following message - please use the IM tool to reply to them directly
Email-IM Gateway: Mr Watson - come here!


"Aha!" I hear those of you who script thinking, "How does it know the proper key just from the name Jefferson Gould? You need a key to send a message with llInstantMessage. You're cheating, aren't you?" Er, that's the problem really. There is no way of getting a key directly from a name in LSL. So I have to have keys and names listed in a notecard, and the script reads through the lines of the notecard until it finds the right name, then takes the key from that. Which is a pain because they need gathering first, which means that I won't be able to send an email to anyone whose key I have not already obtained, unless I can find a public key database somewhere.

I've not tested the script for this so I won't post it up right now - in any case this entry is getting rather long. Once I do so, though, I will, and also the script for the key harvester that I use, and they'll be in the showroom as usual, which could get a bit crowded. Maybe I should script a vendor too so that not all of these things need to have their own prims, even if I do quite like the current layout.

The issue of keys and names is an interesting one. People do feel protective about their keys being recorded. I wonder how much of that is just simple suspicion at surveillance. Perhaps that's something for another entry.

*thinks* I might integrate this into my existing "contact me" object, to produce a Multi-Functional Communications Engine.

---

Edit: I've been informed that there are public name to key databases in existence that can be used for this purpose - for instance, the one maintained by Ulrika Zugzwang or this one on w-hat.com. These are not entirely complete, and would take a long time for a script to search if fully included - but the public web lookup pages give one the option of finding a key from a name and then sending to that. I shall modify the script so that one can specify either a key or a name to send to.

Sunday, February 12, 2006

Scripting tips

Tip jar
Tip jar,
originally uploaded by Ordinal Malaprop.
I have changed the manner in which my showroom operates. Instead of having a few free things and the rest being all very cheap (nothing over L$50), items are now either free or cost L$1 - the latter helping me keep records of who has bought what.

In the corner is the Lurking Crate, which reacts... unusually for a crate, when approached. This contains random items that I've designed but which aren't serious or detailed or working well enough to warrant my building a whole retail box for them. These are all free.

Almost everything should be full mod/copy, although doubtless I've failed sometimes since I am appalling with permissions. Let me know if anything does not meet this standard. New scripts should now have the following licence header however:

// ---LICENCE START---
// The latest version of this script is always available for free
// from Ordinal Malaprop via dispenser in my home area or directly.

// This script may be distributed as desired and used as desired
// under the condition that:

// - this header licence information is not altered;
// - it is clear in the documentation of any item using it that
// the script is being used, with author (just a quick mention
// is fine, e.g. "Uses <script name> by Ordinal Malaprop");
// - it is not sold BY ITSELF, UNMODIFIED.

// I would appreciate it if you let me know if you are using the
// script yourself, but that's not part of the licence.
// ---LICENCE END---


If you are a past customer and I have not already contacted you regarding a refund, do please let me know and I will send you back the difference in prices.

The only real income that my establishment will now generate is via the tip jar. If anyone feels that products from here are useful or entertaining or otherwise worth something, and feels like expressing their appreciation, that is one option. One could also rate me up if one was moved to spend - I do appreciate this as well.

Wednesday, February 08, 2006

Leave of absence

My lovely Powerbook has just this afternoon gone in for repair, and may be some time (well, hopefully it will be back before the end of the week). Until then however I will not be Second Living, so don't complain if you need to speak to me and I'm not around.

My last act was to modify the rocket mentioned below so that it fires out submunitions on detonation which themselves detonate in random colours half a second later, providing a rather extensive and messy shower of particles.

Monday, February 06, 2006

Not as hard as I thought

Well, colour me an embarrassed shade of mauve - after lots of faffing about with llSetTorque et cie, I find that llRotLookAt does work with physical objects, it's just that you need rather inflated parameters to get it to do anything.

If we declare

float strength;
float damping;


at the top of the script, and set those variables to be

strength = llGetMass()*3;
damping = strength/3;


in state_entry(), things work out quite well if we just add the instruction to rotate to set_engine, which now looks like this:

set_engine(vector dir)
{
vector vel = llGetVel();
vector drag = vel / gMaxSpeed;
rotation rot = llGetRot();
llRotLookAt(rot * llRotBetween(<1,0,0> * rot, vel),
strength, damping);

llSetForce((dir - drag) * gAcceln * gTimer, FALSE);
gFuel -= gTimer;
if (gFuel <= 0) explode();
}

And thus we have a rocket that now moves to point in its direction of travel, calculating the rotation between its forward axis and the velocity using llRotBetween, multiplying that by its actual rotation and then turning there. Don't ask me how that works. I really don't understand rotations very well, still, I'm afraid. I got a lot of that from the wiki page about llLookAt.

Firing and ejecting

I also added a longer detection spike, to let the maximum speed go up a bit, and added a little more flash to the launcher - now, once you run out of ammunition, the Harlequin ejects the empty cartridge (which bounces about for a bit on the ground and emits smoke) and you go through a reloading animation. I think it looks rather good, personally.

What remains is to give the rockets a slight heat-seeking element, pointing them a little towards the nearest avatar. This will probably just make them miss, but should help at long ranges. Not that I can see anything past 96m in any case.

Sunday, February 05, 2006

A project proceeding

Readers interested in Victoriana, steampunk or just good taste and design might be interested to see the preliminary model of a dedicated steampunk sim that is being planned at this very moment.

Jefferson's sim plan model

This impressive maquette was built by Professor Jefferson Gould and continues to grow every day. If all goes to plan I shall personally be involved in the scripting of some of the infrastructure - automated hansom cabs, balloon tours, communications, that sort of thing. Obviously there needs to be investment in the project, but given that everywhere that the model goes people, flock around it and make comments such as "that looks great, when can I visit?", "I'd rent a house in a place like that", "I'd love to set up a shop/gallery/other there" I believe that it would definitely be economically viable.

There will be more publicity for it in coming weeks, but for now, here are a few photographs. You can see the full-size model quite frequently on evenings in Cordova Sandbox; I'd host it myself but alas, I do not have the spare prims in my home area.

---

Edit: The model has found a home at Acontia 52,186,86 - click to visit it. To see the whole collection of pictures, including the latest design, visit my gallery on the subject.

Saturday, February 04, 2006

Looking at solutions

Edit: Turning problems detailed in this post have been solved, and some of the conclusions proved incorrect - see above.

---

One would think that llLookAt and llRotLookAt would be the ideal functions for use with a guided physical projectile that one wishes to have pointing in a certain direction. Certainly, in the wiki, it says "this function works for both physical and non-physical objects".

Does it? No, unless I'm doing something horribly wrong.

This evening I have been engaging in a little rocket science, trying to build a projectile that

(a) accelerates constantly in the direction that it is pointing until it runs out of fuel. This is fairly straightforward, it just requires using llSetForce. I added in a drag co-efficient that represents air resistance, proportional to the current velocity, as well, so as to limit the speed.

(b) moves to point in the direction that it is moving in, more or less. (Aerodynamic objects tend to do this - think paper aeroplanes.) It's easy to make vehicles do this, there are automatic parameters to set, but for physical objects I can't see any mechanism apart from applying a force or impulse myself. And that's where I'm having the problem.

Me with rocket launcher

First things first; the basic motor. (I was told earlier on today that I didn't post enough code examples so I'm doing a little of that now.) Here are my global variables:

float gFuel; // current fuel
float gFuelMax = 10.0; // seconds of flight time
float gMaxSpeed; // calculated based on FPS
float gAcceln = 10; // metres per second per second
float gTimer = 0.2; // check every X seconds


On entry, gFuel is set to gFuelMax, and gMaxSpeed... well, that is set to llGetRegionFPS() * 1.5. Why? Well, the rocket itself has an invisible central prim that is 1.5m long, for collision detection, and I am assuming that llGetRegionFPS() will give me the physics framerate. Any faster than the above and there will be "gaps" between the positions of the rocket meaning that a collision might not be detected. See the previous post that I made about bullets for more on this.

Crucible rocket

Anyway, also on entry we set a timer with a frequency of gTimer. All that the timer event does is call set_engine(llRot2Fwd(llGetRot())), to set the engine going in the rocket's current forward direction. set_engine is a function that takes a direction as a parameter and consists of the following code:

set_engine(vector dir)
{
vector vel = llGetVel();
vector drag = vel / gMaxSpeed;
llSetForce((dir - drag) * gAcceln * gTimer, FALSE);
gFuel -= gTimer;
if (gFuel <= 0) explode();
}


The value of the vector drag varies depending on the current velocity, and is a push in the opposite direction to the rocket's current movement - note, not the direction parameter sent to the function. At maximum speed, drag will have a magnitude of 1, which should cancel out the rocket motor if that is acting in that direction. Okay, the drag should really be different for different directions, since the forward drag on a rocket is much less than the drag on other axes, but give me a break, it's only alive for a few seconds. Er, I mean, that's an optional project for advanced students.

That all works fairly well it seems. The problem is that the rocket should really turn in the direction of movement - real rockets do that. Only I can't seem to get that working. I can't use llSetRot, that's only for non-physical objects, and when I try to use llLookAt or llRotLookAt, they just don't do anything at all. I tried building a sensor object that used those functions to look at the nearest avatar to test this. When it was non-physical, it turned fine (and I've used this many times before). When it was physical, it just didn't move.

I don't know if I'm screwing up some parameters or not - I'm sure I've used llLookAt with physical objects before - but it is annoying me greatly at the moment. Once I find a solution (if ever) that doesn't involve the use of llApplyRotationalImpulse, which I don't understand and which scares me, I'll post something on the matter.

As a post scriptum, hold_R_bazooka is all very well as an animation, but why on earth does aim_R_bazooka have to involve your left hand entirely changing position?

Friday, February 03, 2006

I demand compensation

Two outages within twenty four hours? I am entitled to permanent service from Linden Labs, all day, every day. God dammit, I pay their wages. Haven't they ever heard of customer service?

I demand compensation for this outrage. It just isn't good enough. Linden Labs are a disgrace. They release clients with critical flaws like, um, the display box in llDialog() being one whole line smaller now - they destroy my grid-famous Avtrap Mall by introducing point-to-point teleporting - and they're going to cripple the TringoChairCasino that I built just to help newbies, out of the goodness of my heart, by removing DI. They're stealing from me. This is theft. They're like some sort of Communists!

WHERE IS MY MONEY, LINDEN LABS?

I'm going to hold my breath until I get it.

Wednesday, February 01, 2006

By my command

Here's a script that I could have found very useful recently:

string gKillCode;
string gOwnerEmail = "owner@somewhere.com";

default
{
on_rez(integer p)
{
llResetScript();
}

state_entry()
{
// Generate random kill code
// This stops just anyone killing the object
// if they get its key

// Email this to the owner
gKillCode = "*" + (string)llRound(llFrand(2000000000)) + "*";
llEmail(gOwnerEmail, "Kill object by email",
"My kill code is " + gKillCode);
// Now set to poll email every five minutes
llSetTimerEvent(300.0);
}

timer()
{
llGetNextEmail("", "");
}

email(string time, string address, string subj,
string message, integer num_left)
{
// If the message contains the kill code,
// email a confirmation and die

if (llSubStringIndex(message, gKillCode) != -1) {
llEmail(gOwnerEmail, "Confirmation of receipt of kill email",
"Dying now");
llDie();
}
if (num_left > 0) llGetNextEmail("", "");
}
}

That's just off the top of my head right now so there may be the odd bug, but I think the basic idea is sound.

If one creates anything that might annoy other people, one should include some sort of emergency kill script, or even

llListen(999, "", llGetOwner(), "die");

and

listen(integer channel, string name, key id, string msg)
{
llOwnerSay("Dying now");
llDie();
}

so you can go around shouting "/999 die" to purge the area if it ever comes down to it. (The above obviously needs changing if you have other listens running. Don't blame me if you just stick it into your code and your objects die at odd times.)

One other thing that I have learnt recently is that I'm getting much too involved in certain factional fighting, and it's causing me to make mistakes and bother people who are uninvolved. It's also getting in the way of other things that I am doing. I don't want this to happen, so I'm going to pull back - I'll provide scripting support, alerts, presence loggers (not chat loggers, no, that's against ToS if you're not there and they don't consent) etc but I'm not taking an active part any more.

(Unless I change my mind of course.)

I've had enough of building weapon delivery systems; after I've fulfilled the responsibilities that I already have, I might build a sandwich delivery system.