CODE
// branch
// script for making growable trees
float symmetry = 3.2; // values around 3 are good for trees, use 4 for growable buildings, 6 is for hexagonal builds
vector direction = <0,0,1>; // orientation of your piece
vector branch_offset = <0,0,-1>; // offset at which branches grow
vector forkaxis = <0,1,0>; // axis around which new branches are rotated to, well, "branch" out
string decoration;
string buildelement = "platform";
vector correction_rotation = <0,0,135>; // rotation applied when piece is rezzed by another piece, in degrees
vector correction_offset;
// communication
integer listen_handle;
integer global_handle;
integer my_channel;
integer global_channel = 12345;
integer next_son = FALSE;
integer PermNeeded;
perm()
{
integer a=llGetPermissions();
if ((a&PermNeeded)!=PermNeeded)
llRequestPermissions(llGetOwner(),PermNeeded);
}
extend()
{
if (next_son)
{
return;
} else {
next_son = TRUE;
llRezObject(llGetObjectName(), ((llGetScale() * direction) * direction) * llGetRot() + llGetPos(), ZERO_VECTOR, llGetRot(), TRUE);
}
}
branch()
{
rotation rot;
vector offset;
rot = llEuler2Rot((PI/symmetry) * forkaxis); // use TWO_PI in non-tree growable objects
offset = (0.5 * llGetScale() * direction) * direction * rot + branch_offset;
offset = offset * llGetRot();
llRezObject(llGetObjectName(), offset + llGetPos(), ZERO_VECTOR, rot * llGetRot(), FALSE);
spin(2);
}
build(string obj)
{
llRezObject(obj, llGetPos(), ZERO_VECTOR, llGetRot(), TRUE);
spin(2);
}
spin(integer n)
{
llSetRot(llEuler2Rot( (PI/symmetry) * n * direction) * llGetRot());
}
change_channel()
{
llListenRemove(listen_handle);
my_channel = (integer)llFrand(10000000) + global_channel + 5;
listen_handle = llListen(my_channel, "", "", "");
}
default
{
state_entry()
{
PermNeeded = FALSE;
perm();
llSetTouchText("Menu");
global_handle = llListen(global_channel, "", "", "");
}
touch_start(integer counter)
{
change_channel();
llDialog(llDetectedKey(0),
"GROW=make it grow in length, BRANCH=make branch, BLOOM=make leaves, BUILD=make platform, CCW/CW=spin, FREEZE=remove all growth scripts of the tree, KILL=delete the tree",
["GROW", "BRANCH", "BLOOM", "BUILD", "CCW", "CW", "FREEZE", "KILL"],
my_channel);
llSetTimerEvent(20.0);
}
timer()
{
llListenRemove(listen_handle);
llSetTimerEvent(0.0);
}
listen(integer chan, string nom, key grower, string mesg)
{
llListenRemove(listen_handle);
if ((grower != llGetOwner()) && (llGetOwnerKey(grower) != llGetOwner()))
{
return;
}
if (mesg == "GROW")
{
extend();
} else if (mesg == "BRANCH")
{
branch();
} else if (mesg == "BLOOM")
{
build(decoration);
} else if (mesg == "BUILD")
{
build(buildelement);
} else if (mesg == "CCW")
{
spin(-1);
} else if (mesg == "CW")
{
spin(1);
} else if (mesg == "FREEZE")
{
if (chan != global_channel)
{
llListenRemove(global_channel);
llSay(global_channel, "FREEZE");
}
llRemoveInventory(llGetScriptName());
} else if (mesg == "KILL")
{
if (chan != global_channel)
{
llSleep(6.0);
llSay(global_channel, "KILL");
}
llDie();
}
}
run_time_permissions(integer a)
{
perm();
}
object_rez(key target)
{
if (next_son)
{
llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_CYLINDER,
0, <0.0, 1.0, 0.0>, // holeshape, cut
0.0, <0.0, 0.0, 0.0>, // hollow, twist
<1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>]); // topsize, topshear
}
llGiveInventory(target, llGetObjectName());
llGiveInventory(target, decoration);
llGiveInventory(target, buildelement);
}
on_rez(integer a)
{
rotation rot;
vector pos;
perm();
decoration = llGetObjectName() + "let";
next_son = FALSE;
if (a)
{
llSetRot(llEuler2Rot((llFrand(.5) + 1.0) * correction_rotation * DEG_TO_RAD) * llGetRot());
}
}
}
My trees use one main branch element and one secondary, smaller element, this is the script for smaller element:
CODE
float symmetry = 3.0;
vector direction = <0,0,1>;
vector correction_offset = <0,0,1>;
vector correction_rotation = <60,0,0>;
// communication
integer listen_handle;
integer global_handle;
integer my_channel;
integer global_channel = 12345;
spin(integer n)
{
if (llGetLinkNumber() < 2)
{
llSetRot(llEuler2Rot( (PI/symmetry) * n * direction) * llGetRot());
} else {
llSetLocalRot(llEuler2Rot( (PI/symmetry) * n * direction) * llGetLocalRot());
}
}
change_channel()
{
llListenRemove(my_channel);
my_channel = (integer)llFrand(10000000) + global_channel + 5;
listen_handle = llListen(my_channel, "", "", "");
}
default
{
state_entry()
{
global_handle = llListen(global_channel, "", "", "");
}
touch_start(integer counter)
{
change_channel();
llDialog(llDetectedKey(0),
"CCW/CW=spin, FREEZE=end growth of tree, KILL=delete the tree",
["CCW", "CW", "FREEZE", "KILL"],
my_channel);
llSetTimerEvent(20.0);
}
timer()
{
llListenRemove(my_channel);
}
listen(integer chan, string nom, key grower, string mesg)
{
llListenRemove(listen_handle);
if ((grower != llGetOwner()) && (llGetOwnerKey(grower) != llGetOwner()))
{
return;
}
if (mesg == "CW")
{
spin(-1);
} else if (mesg == "CCW")
{
spin(1);
} else if (mesg == "FREEZE")
{
if (chan != global_channel)
{
llListenRemove(global_channel);
llSay(global_channel, "FREEZE");
}
llRemoveInventory(llGetScriptName());
} else if (mesg == "KILL")
{
if (chan != global_channel)
{
llListenRemove(global_channel);
llSay(global_channel, "KILL");
}
llDie();
}
}
on_rez(integer a)
{
rotation rot;
vector pos;
if (a)
{
if ((correction_offset != ZERO_VECTOR) || (correction_rotation != ZERO_VECTOR))
{
rot = llEuler2Rot(correction_rotation * DEG_TO_RAD);
pos = 0.5 * (llGetScale() * direction) * direction;
llSetPos( ((pos * rot) - pos + correction_offset) * llGetRot() + llGetPos());
llSetRot(rot * llGetRot());
}
}
}
}
Both scripts are set for cylinders.
Here's the script for making the leaves (a prim linked to other elements, big or small) change color with "season" (needs a dead leaves texture, the Faster and Slower commands only take effect at season change):
CODE
// seasons
// seasonal colors control
// Author: Jesrad Seraph
// Modify and redistribute freely
integer season = 1;
// 0 spring, 1 summer, 2 autumn, 3 winter
integer season_channel = 111333;
integer season_handle;
// colors are in rotation format so we can store alpha
rotation springcolor = <0,1,0,1>;
rotation summercolor = <1,1,1,1>;
rotation autumncolor = <1,.3,0,0.9>;
rotation wintercolor = <1,0.5,0,0>;
vector leavescolor = <0.9,0.2,0>;
string leavestexture = "dead leaves";
vector leavessize = <0.08,0.16,0.0>;
float delay = 1.6;
float steps = 21.0;
float n;
rotation a;
rotation b;
integer target_season;
fade()
{
vector trans;
vector col;
float ratio;
float opacity;
ratio = n / steps;
col.x = (1.0 - ratio) * a.x + ratio * b.x;
col.y = (1.0 - ratio) * a.y + ratio * b.y;
col.z = (1.0 - ratio) * a.z + ratio * b.z;
llSetColor(col, ALL_SIDES);
llSetAlpha( ( (1.0 - ratio) * a.s + ratio * b.s), ALL_SIDES);
}
next_colors()
{
if (season == 0)
{
a = springcolor;
b = summercolor;
} else if (season == 1)
{
a = summercolor;
b = autumncolor;
} else if (season == 2)
{
llParticleSystem([PSYS_PART_FLAGS, PSYS_PART_WIND_MASK | PSYS_PART_FOLLOW_VELOCITY_MASK,
PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_ANGLE_CONE,
PSYS_PART_START_COLOR, leavescolor,
PSYS_PART_START_SCALE, leavessize,
PSYS_PART_END_SCALE, leavessize,
PSYS_SRC_ANGLE_BEGIN, 0.0,
PSYS_SRC_ANGLE_END, PI,
PSYS_PART_MAX_AGE, (steps*delay/2.0),
PSYS_SRC_ACCEL, <0,0,-0.4>,
PSYS_SRC_BURST_RATE, delay/steps,
PSYS_SRC_BURST_PART_COUNT, 2,
PSYS_SRC_TEXTURE, leavestexture
]);
a = autumncolor;
b = wintercolor;
} else if (season == 3)
{
llParticleSystem([]);
a = wintercolor;
b = springcolor;
}
}
default
{
timer()
{
++n;
if (n <= steps)
{
fade();
} else {
n = 0.0;
++season;
if (season > 3)
season = 0;
next_colors();
if (season == target_season)
{
llSetTimerEvent(0.0);
}
}
}
state_entry()
{
n = 0.0;
a = summercolor;
b = autumncolor;
llListenRemove(season_handle);
season_handle = llListen(season_channel, "", "", "");
}
on_rez(integer startparam)
{
n = 0.0;
a = summercolor;
b = autumncolor;
llListenRemove(season_handle);
season_handle = llListen(season_channel, "", "", "");
}
touch_start(integer a)
{
season_handle = llListen(season_channel, "", "", "");
llDialog(llDetectedKey(0),
"Season:",
["Spring", "Summer", "Autumn", "Winter"],
season_channel);
}
listen(integer chan, string nom, key grower, string mesg)
{
if ((grower != llGetOwner()) && (llGetOwnerKey(grower) != llGetOwner()))
{
return;
}
if (mesg == "Spring")
{
target_season = 0;
} else if (mesg == "Summer")
{
target_season = 1;
} else if (mesg == "Autumn")
{
target_season = 2;
} else if (mesg == "Winter")
{
target_season = 3;
} else if (mesg == "Faster")
{
delay /= 2.0;
if (delay < 0.5)
delay = 0.5;
} else if (mesg == "Slower")
{
delay *= 2.0;
}
if (season != target_season)
llSetTimerEvent(delay);
}
}
The scripts auto-adjust for size of elements they're in so you should be able to slap the season one on an alpha-textured prim, link it to a cylinder, put the second script in that cylinder, then put the first in a bigger (for looks) cylinder, copy this cylinder, then add the small element and the big element to the copy of the big element = new tree.