Scaling/Rotation/Positioning is always centered on the prim's center. If you're really set on not moving the prim, there is another alternative. It is possible to cut a prim so that it's only half there, that way it will only scale on one side. (This is the trick that one-prim doors use to rotate on their centers yet turn on one edge.) For example lf the prim is a Box, you could set the Path Cuts to 0.375 and 0.875, and then change the script to scale on the Y side instead. Note that this limits the max size to 5m instead of 10m.
For a circle, change the cuts to 0.25 and 0.75 and scale on Y.
For a cylinder, it's a bit trickier, you have to change it to a sphere, with cuts 0 and 1, then change the Dimple to 0.5 and 1.0, then change it back to Cylinder and scale on Z. (This is known as a "tortured prim" where you change something on the sphere and it affects the cylinder's shape.)
For the other prims you can experiment with combinations of Profile Cut (which is the same as a sphere's Dimple) and Path Cut to find the shape you want, then pick the appropriate direction to scale. I think you get the idea.
=-=-=-=-=-=-=-=-=
Otherwise, for scaling only one side of a WHOLE prim, here's a version of your code that moves only in on one side (the positive direction) of each axis (yes it will work for more than one, and anchor one corner instead of one side).
I made a few other changes too... I have moved the lines which save the original scale/pos to inside the start function, in case the object moves after the script is reset. I also removed the while loop on resetting the scale/pos because one call should do it. It wasn't even necessary for scaling (only setpos can fail) and in this case we'll never move so far that we're beyond the 10m setpos limit. Finally, I changed it to scale larger over time instead of using a random amount, and to start/reset on a channel listen event. This takes care of all four items on your list.
integer counter;
vector startScale;
vector startPos;
// Note: this represents the direction (1 or -1)
// divided by 2 because we only want
// to move half of the scale amount to keep
// one side in place. (we're just pre-calculating this)
float scaleFrac = -0.5; // which way to scale, 0.5 or -0.5
float tick = 0.25; // time for each change, must be > 0.2
integer channel = 2468; // channel to listen for start/reset
start()
{
if (counter != 0) // b ail if already running
return;
startScale = llGetScale();
startPos = llGetLocalPos();
counter = 0;
llSetTimerEvent( tick );
}
reset()
{
llSay(channel, "reset");
// restore only if script was triggered
if (startScale != ZERO_VECTOR && startPos != ZERO_VECTOR)
llSetPrimitiveParams( [PRIM_SIZE, startScale,
PRIM_POSITION, startPos] );
llResetScript();
}
default
{
state_entry()
{
counter = 0;
llListen(channel, "", "", "start");
llListen(channel + 1, "", "", "reset");
}
touch_start(integer total_number)
{
start();
}
listen(integer chan, string name, key id, string msg)
{
if (chan == channel)
start();
if (chan == channel + 1)
reset();
}
timer()
{
counter = counter + 1;
float seconds = tick * counter;
if ( seconds > 10 )
reset(); // restores and resets the script
vector scalevec = <0.0, 0.0, 0.1>; // direction of scaling
scalevec = scalevec * seconds;
vector newScale = startScale + scalevec;
rotation rot = llGetLocalRot();
vector newPos = startPos + ( scalevec * scaleFrac * rot );
llSetPrimitiveParams( [PRIM_SIZE, newScale,
PRIM_POSITION, newPos] );
}
}
Note that I also factored in the prim's rotation just in case it's not 0,0,0. I used llGetLocalPos() and llGetLocalRot() instead of llGetPos() and llGetRot() to allow this to work in a linked prim as well.
Also note that the scaling will NOT work if the object is physical, but the movement will. You'll have to disable physics momentarily if you need to scale while physical.
~Boss