|
Voici la 1.82; deux nouveautés:
- une limite en prims animables: cela permet d'utiliser l'engine 2 dans un linkset de 100 ou plus prims en n'en animant que 20 par exemple.
Alors cela se règle avec la variable iLimitPrims en tête du script engine; laisser 0 si vous voulez animer tout le linkset.
La précaution à prendre est que les prims animables doivent être sélectionnées en dernier quand on lie.
J'ai eu le cas sur un bateau où il n'y avait à animer que la passerelle de débarquement.
- la possibilité de jouer les snapshots par tranche : par exemple de la frame 1 à la 10, puis séparément de la 11 à la 20. Cela ouvre la porte à plusieurs animations distinctes. Bien sur, on ne peut pas les jouer ensemble.
Bon cela fait des triggers compliqués, vu qu'il faut verrouiller la possibilité de jouer une animation quand on en joue une autre.
Pour reprendre l'exemple du bateau, vous pouvez faire une animation pour la passerelle et une autre pour l'ancre.
// Script Name: OPRIAN engine 2 : OPen_PRIm_ANimator engine only changes
// Version 1.82; limit prims and play slice
// Original Author: Todd Borst
// Downloaded from : http://www.free-lsl-scripts.com/freescripts.plx?ID=1580
// engine 2 for use in set scripts OPRIAN: Author : Elenia Boucher
// This program is free software; you can redistribute it and/or modify it.
// License information must be included in any script you give out or use.
// This script is licensed under the Creative Commons Attribution-Share Alike 3.0 License
// from http://creativecommons.org/licenses/by-sa/3.0 unless licenses are
// included in the script or comments by the original author,in which case
// the authors license must be followed.
// Please leave any authors credits intact in any script you use or publish.
////////////////////////////////////////////////////////////////////
string sTypEngine = "2";
// 30 is a reasonnable limit for an animable linkset;
// set to 0 if you want anime all the linkset
// otherwise, only the lastest selected before link will be animable
integer iLimitPrims = 0;//number of animable prims in the linkset - let 0 for all the linkset
integer iPrimCount;
integer iTotalPrims;
list lPos;
list lRot;
list lScale;
list lNumPrims;
list lNbPrimsByFrame;
list lDelay;
integer iNbPrimsInFrame;
integer iCurrentSnapshot = 1;
integer iRecordedSnapshots = 0;
integer iEndFrame;
integer iStartFrame;
integer iIndexChange;
integer iFrame;
float fDelay = 1.0;
integer iReverse;
vector vRootScale = ZERO_VECTOR;
vector vScaleChange = <1,1,1>;
// For tracking memory usage. The amount of snapshots you can record is based
// on the number of prims and available memory. Less prims = more snapshots
integer iMaxMemory = 0;
integer iFreeMemory = 0;
integer iPlayAnimationStyle = 0;
// The values for iPlayAnimationStyle means
// 0 = no animation playing
// 1 = play animation once
// 2 = play animation looping
// 4 = play animation reverse mode
// 8 = play animation symmetry mode
// binary values can be combined
//dialog constants - naming: R request, A answer, C command - direction setup/triggers -> engine
integer C_PLAY_FRAME = 1;
integer C_PLAY_ANIM = 2;
integer C_STOP_ANIM = 3;
integer C_LOOP_ON = 4;
integer C_LOOP_OFF = 5;
integer C_REVERSE_ON = 6;
integer C_REVERSE_OFF = 7;
integer C_SYMMETRY_ON = 8;
integer C_SYMMETRY_OFF= 9;
integer C_PLAY_SLICE = 10;
integer R_MAX_MEMORY = 20;
integer A_MAX_MEMORY = 21;
integer R_FREE_MEMORY= 22;
integer A_FREE_MEMORY= 23;
integer R_TOTAL_FRAMES = 24;
integer A_TOTAL_FRAMES = 25;
integer R_ACTUAL_FRAME = 26;
integer A_ACTUAL_FRAME = 27;
integer A_PLAYING_FRAME = 28;
integer A_END_ANIMATION = 29;
integer A_START_ANIMATION = 30;
integer R_SCALE = 31;
integer A_SCALE = 32;
integer R_DELAY_FRAME = 33;
integer A_DELAY_FRAME = 34;
integer R_CHG_DELAY_FRAME = 35;
integer R_PRIM_COUNT = 36;
integer A_PRIM_COUNT = 37;
integer C_RECORD_FRAME = 40;
integer A_RECORD_FRAME = 41;
integer C_RECORD_PRIM = 42;
integer A_RECORD_PRIM = 43;
integer C_END_FRAME = 44;
integer C_DUMP_FRAME = 45;
integer A_DUMP_FRAME = 46;
integer R_TYP_ENGINE = 47;
integer A_TYP_ENGINE = 48;
integer A_DUMP_PRIM = 49;
integer C_RESET = 50;
integer A_RESET = 51;
integer A_OUT_MEMORY = 52;
showSnapshot(integer snapNumber)
{
if(snapNumber > 0 && snapNumber <= iRecordedSnapshots )
{
llMessageLinked(LINK_THIS, A_PLAYING_FRAME, (string)snapNumber, "");
vector pos;
rotation rot;
vector scale;
float delay;
//passe++;//mesure
vector rootPos = llGetPos();
// Might want to move llGetRot() into the loop for fast rotating objects.
// Rotation during the animation playback may cause errors.
rotation rootRot = llGetRot();
integer end = iIndexChange + llList2Integer(lNbPrimsByFrame, snapNumber - 1);
for(iIndexChange; iIndexChange < end; iIndexChange ++){
pos = llList2Vector(lPos, iIndexChange);
rot = llList2Rot(lRot, iIndexChange);
scale = llList2Vector(lScale, iIndexChange);
//Adjust for scale changes
if( vRootScale.x != 1.0 || vRootScale.y != 1.0 || vRootScale.z != 1.0 )
{
pos.x *= vScaleChange.x;
pos.y *= vScaleChange.y;
pos.z *= vScaleChange.z;
scale.x *= vScaleChange.x;
scale.y *= vScaleChange.y;
scale.z *= vScaleChange.z;
}
llSetLinkPrimitiveParamsFast( llList2Integer(lNumPrims, iIndexChange),
[ PRIM_POSITION, pos,
PRIM_ROTATION, rot/rootRot,
PRIM_SIZE, scale ] );
}
if(iPlayAnimationStyle > 0){
delay = llList2Float(lDelay, snapNumber -1);
if(delay == .0) delay = llList2Float(lDelay, iRecordedSnapshots - 1);
llSetTimerEvent(delay);
}
}
}
//find the first record of a snapshot in the list
integer findFirstChange(integer snapshot){
integer i;
integer s;
integer end = snapshot - 1;
for(i=0; i < end; i++)
s += llList2Integer(lNbPrimsByFrame, i);
return s;
}
playAnimation(){
iIndexChange = findFirstChange(iCurrentSnapshot);
if(iPlayAnimationStyle == 0) iPlayAnimationStyle = 1;//one shot direct play by default
llSetTimerEvent(0.1);
}
default
{
state_entry()
{
iMaxMemory = llGetFreeMemory();
iFreeMemory = llGetFreeMemory();
iTotalPrims = llGetNumberOfPrims();
if(iTotalPrims > (iLimitPrims + 1) && iLimitPrims > 1) iPrimCount = iLimitPrims +1;
else iPrimCount = iTotalPrims;
//setting initial root scale. this allows the animation to scale if the root size is changed afterwards.
vRootScale = llGetScale();
llMessageLinked(LINK_THIS, A_RESET, "", "");
}
changed(integer chg)
{
//this is needed to detect scale changes and record the differences in order to adjust the animation accordingly.
if (chg & CHANGED_SCALE)
{
if (vRootScale != ZERO_VECTOR)
{
vector newScale = llGetScale();
//since change_scale is triggered even with linked prim changes,
//this is to filter out non-root changes.
if( ( newScale.x / vRootScale.x) != vScaleChange.x ||
( newScale.y / vRootScale.y) != vScaleChange.y ||
( newScale.z / vRootScale.z) != vScaleChange.z )
{
vScaleChange.x = newScale.x / vRootScale.x;
vScaleChange.y = newScale.y / vRootScale.y;
vScaleChange.z = newScale.z / vRootScale.z;
llMessageLinked(LINK_THIS, A_SCALE, (string)vScaleChange, "");
}
}
}
// if new prims are added or removed from this object then the script resets
// because the animations are now broken.
else if (chg & CHANGED_LINK)
{
if( iTotalPrims != llGetNumberOfPrims() )
{
llOwnerSay("Link change detected, reseting script.");
llResetScript();
}
}
}
link_message(integer sender_num, integer num, string str, key id){
if(num == C_PLAY_FRAME){
integer snapshot = (integer)str;
iIndexChange = findFirstChange(snapshot);
iCurrentSnapshot = snapshot;
showSnapshot(snapshot);
llMessageLinked(LINK_THIS, A_ACTUAL_FRAME, (string)iCurrentSnapshot, "");
}else if(num == C_PLAY_ANIM ){
if(iRecordedSnapshots == 0) return;
iStartFrame = 1;
iEndFrame = iRecordedSnapshots;
if(iPlayAnimationStyle & 4){//reverse mode
iCurrentSnapshot--;//Start animation at the previous frame
if(iCurrentSnapshot <= 1) iCurrentSnapshot = iRecordedSnapshots;
}else{//direct mode
iCurrentSnapshot++; //Start animation at the next frame
if(iCurrentSnapshot >= iRecordedSnapshots) iCurrentSnapshot = 1;
}
playAnimation();
}else if(num == C_PLAY_SLICE ){
iStartFrame = (integer)str;
iEndFrame = (integer)((string)id);
if(iStartFrame >= iEndFrame || iStartFrame < 1 || iEndFrame > iRecordedSnapshots) return;
if(iCurrentSnapshot < iStartFrame || iCurrentSnapshot > iEndFrame){
if(iPlayAnimationStyle & 4)//reverse mode
iCurrentSnapshot = iEndFrame;
else
iCurrentSnapshot = iStartFrame;
}
playAnimation();
}else if(num == C_STOP_ANIM){
iPlayAnimationStyle = 0;
llSetTimerEvent(0);
}else if(num == C_LOOP_ON){
iPlayAnimationStyle = iPlayAnimationStyle | 2;
}else if(num == C_LOOP_OFF){
iPlayAnimationStyle = iPlayAnimationStyle & 0xD;
}else if(num == C_REVERSE_ON){
iPlayAnimationStyle = iPlayAnimationStyle | 4 & 7;//Reverse excludes symmetry
}else if(num == C_REVERSE_OFF){
iPlayAnimationStyle = iPlayAnimationStyle & 0xB;
}else if(num == C_SYMMETRY_ON){
iPlayAnimationStyle = iPlayAnimationStyle | 8 & 0xB;//symmetry excludes reverse
}else if(num == C_SYMMETRY_OFF){
iPlayAnimationStyle = iPlayAnimationStyle & 7;
}else if(num == R_MAX_MEMORY){
llMessageLinked(LINK_THIS, A_MAX_MEMORY, (string)iMaxMemory, "");
}else if(num == R_FREE_MEMORY){
if(iFreeMemory > llGetFreeMemory()) iFreeMemory = llGetFreeMemory();
else iFreeMemory--;//little cheat because the garbage collector has sometime a strange behavior
llMessageLinked(LINK_THIS, A_FREE_MEMORY, (string)iFreeMemory, "");
}else if(num == R_TOTAL_FRAMES){
llMessageLinked(LINK_THIS, A_TOTAL_FRAMES, (string)iRecordedSnapshots, "");
}else if(num == R_ACTUAL_FRAME){
llMessageLinked(LINK_THIS, A_ACTUAL_FRAME, (string)iCurrentSnapshot, "");
}else if(num == R_PRIM_COUNT){
llMessageLinked(LINK_THIS, A_PRIM_COUNT, (string)iPrimCount, "");
}else if(num == R_SCALE){
llMessageLinked(LINK_THIS, A_SCALE, (string)vScaleChange, "");
}else if(num == R_DELAY_FRAME){
integer index = (integer)((string)id) - 1;
llMessageLinked(LINK_THIS, A_DELAY_FRAME, llList2String(lDelay, index), id);
}else if(num == R_CHG_DELAY_FRAME){
integer index = (integer)((string)id) - 1;
lDelay = llListReplaceList(lDelay, [(float)str], index, index);
}else if(num == C_RECORD_FRAME){
iFreeMemory = llGetFreeMemory();
if(iFreeMemory < 200)
llMessageLinked(LINK_THIS, A_OUT_MEMORY, (string)iFreeMemory, "");
else{
iNbPrimsInFrame = 0;
iFrame = (integer)str;
llMessageLinked(LINK_THIS, A_RECORD_FRAME, (string)iFrame, "");
}
}else if(num == C_RECORD_PRIM){//inline function more faster and economic
integer index = llSubStringIndex(str, ";");
integer numprim = (integer)llGetSubString(str, 0, index -1);
str = llDeleteSubString(str, 0, index);
index = llSubStringIndex(str, ";");
if(index > -1){
if(numprim == 1) {//scale root
vRootScale = (vector)llGetSubString(str, 0, index -1);
vector newScale = llGetScale();
if(vRootScale != newScale){
vScaleChange.x = newScale.x / vRootScale.x;
vScaleChange.y = newScale.y / vRootScale.y;
vScaleChange.z = newScale.z / vRootScale.z;
}
}else{//current prims
iNbPrimsInFrame++;
lNumPrims += [numprim];
lPos += [(vector)llGetSubString(str, 0, index -1)];
str = llDeleteSubString(str, 0, index);
index = llSubStringIndex(str, ";");
lRot += [(rotation)llGetSubString(str, 0, index -1)];
str = llDeleteSubString(str, 0, index);
index = llSubStringIndex(str, ";");
lScale += [(vector)llGetSubString(str, 0, index -1)];
str = llDeleteSubString(str, 0, index);
index = llSubStringIndex(str, ";");
fDelay = (float)llGetSubString(str, 0, index -1);
str = llDeleteSubString(str, 0, index);
if(fDelay < .1) fDelay = 1.0;
}
}
iFreeMemory = llGetFreeMemory();
if(iFreeMemory < 300){
lNumPrims = llDeleteSubList(lNumPrims, -iNbPrimsInFrame, -1);
lPos = llDeleteSubList(lPos, -iNbPrimsInFrame, -1);
lRot = llDeleteSubList(lRot, -iNbPrimsInFrame, -1);
lScale = llDeleteSubList(lScale, -iNbPrimsInFrame, -1);
llMessageLinked(LINK_THIS, A_OUT_MEMORY, (string)iFreeMemory, "");
}
else llMessageLinked(LINK_THIS, A_RECORD_PRIM, "", "");
}else if(num == C_END_FRAME){
lNbPrimsByFrame += [iNbPrimsInFrame];
lDelay += [fDelay];
iRecordedSnapshots++;
iCurrentSnapshot++;
iFreeMemory = llGetFreeMemory();
llMessageLinked(LINK_THIS, A_FREE_MEMORY, (string)iFreeMemory, "");
}else if(num == C_DUMP_FRAME){
integer frame = (integer)str;
integer index = findFirstChange(frame);
integer end = index + llList2Integer(lNbPrimsByFrame, frame - 1);
if(frame == 1 && end > 0) llMessageLinked(LINK_THIS, A_DUMP_PRIM, "1;" +
(string)vRootScale + ";", (key)((string)frame));
for(index ; index < end; index ++){
llMessageLinked(LINK_THIS, A_DUMP_PRIM,
llList2String(lNumPrims, index) + ";" +
llList2String(lPos, index) + ";" + llList2String(lRot, index) + ";" +
llList2String(lScale, index) + ";" + llList2String(lDelay, frame-1) + ";", (key)((string)frame));
}
llMessageLinked(LINK_THIS, A_DUMP_FRAME, str, "");
}else if(num == R_TYP_ENGINE){
llMessageLinked(LINK_THIS, A_TYP_ENGINE, sTypEngine, "");
}else if(num == C_RESET){
llResetScript();
}
}
//Timer event is used to handle the animation playback.
timer() {
showSnapshot(iCurrentSnapshot);
if(iPlayAnimationStyle & 4){//reverse playback
//if not at the first frame, decrement the counter
if(iCurrentSnapshot > iStartFrame){
iCurrentSnapshot--;
iIndexChange = iIndexChange - llList2Integer(lNbPrimsByFrame, iCurrentSnapshot)
- llList2Integer(lNbPrimsByFrame, iCurrentSnapshot-1);
}else {
if( iPlayAnimationStyle & 2){//if looping?
if(iPlayAnimationStyle & 8){//symmetry mode if looping
iIndexChange = findFirstChange(iStartFrame);
iPlayAnimationStyle = iPlayAnimationStyle & 0xB;//take off the reverse mode next play start frame
}else{// if animation is looping and no symmetry mode, set the counter at the last frame
iCurrentSnapshot = iEndFrame;
iIndexChange = findFirstChange(iEndFrame);
}
}else{// if animation isn't looping, stop the animation
llMessageLinked(LINK_THIS, A_START_ANIMATION, "", "");
iIndexChange = 0;
llSetTimerEvent(0);
iPlayAnimationStyle = 0;
}
}
}else{//direct playback
//if not at the end of the animation, increment the counter
if(iCurrentSnapshot < iEndFrame)
iCurrentSnapshot++;
else{
if(iPlayAnimationStyle & 8){//symmetry mode
iPlayAnimationStyle = iPlayAnimationStyle | 4; //set the reverse mode next play iRecordedSnapshots - 1
iCurrentSnapshot--;
iIndexChange = iIndexChange - llList2Integer(lNbPrimsByFrame, iCurrentSnapshot-1) -
llList2Integer(lNbPrimsByFrame, iCurrentSnapshot) ;
// if animation is looping and no symmetry mode , set the counter back to 1
}else if( iPlayAnimationStyle & 2){
iCurrentSnapshot = iStartFrame;
iIndexChange = findFirstChange(iStartFrame);
}else{// if animation isn't looping, stop the animation
llMessageLinked(LINK_THIS, A_END_ANIMATION, "", "");
llSetTimerEvent(0);
iIndexChange = 0;//for the next animation if published
iPlayAnimationStyle = 0;
}
}
}
}
}
// Script Name: OPRIAN setup : OPen_PRIm_ANimator setup
// Version 1.82; limit prims and play slice
// Original Author: Todd Borst
// Downloaded from : http://www.free-lsl-scripts.com/freescripts.plx?ID=1580
// Setup script for use in set scripts OPRIAN - Author: Elenia Boucher
// This program is free software; you can redistribute it and/or modify it.
// License information must be included in any script you give out or use.
// This script is licensed under the Creative Commons Attribution-Share Alike 3.0 License
// from http://creativecommons.org/licenses/by-sa/3.0 unless licenses are
// included in the script or comments by the original author,in which case
// the authors license must be followed.
// Please leave any authors credits intact in any script you use or publish.
////////////////////////////////////////////////////////////////////
string sTypEngine;
integer COMMAND_CHANNEL = 32;
integer iPrimCount = 0;
integer iListenerHandle = -1;
integer iCurrentSnapshot = 1;
integer iRecordedSnapshots = 999;
integer iMaxMemory = 0;
integer iFreeMemory = 0;
integer iPrevMemory;
list lPrevSnap;
vector vScaleChange;
integer iFirstInitDone;
integer iInit;
integer iAskDump;
integer iAskPlay;
integer iPlaySnapshot = 999;
integer iLoad;
integer iFrameLoad;
string sPrimLoad;
integer iEOF;
integer iRecordByMenu;
float fDelay;
integer iPrimCounter;
string sNotecardPRS;
key kHandlePRS;
integer iLinePRS;
//dialog constants - naming: R request, A answer, C command - direction setup/triggers -> engine
integer C_PLAY_FRAME = 1;
integer C_PLAY_ANIM = 2;
integer C_STOP_ANIM = 3;
integer C_LOOP_ON = 4;
integer C_LOOP_OFF = 5;
integer C_REVERSE_ON = 6;
integer C_REVERSE_OFF = 7;
integer C_SYMMETRY_ON = 8;
integer C_SYMMETRY_OFF= 9;
integer R_MAX_MEMORY = 20;
integer A_MAX_MEMORY = 21;
integer R_FREE_MEMORY= 22;
integer A_FREE_MEMORY= 23;
integer R_TOTAL_FRAMES = 24;
integer A_TOTAL_FRAMES = 25;
integer R_ACTUAL_FRAME = 26;
integer A_ACTUAL_FRAME = 27;
integer A_PLAYING_FRAME = 28;
integer A_END_ANIMATION = 29;
integer A_START_ANIMATION = 30;
integer R_SCALE = 31;
integer A_SCALE = 32;
integer R_DELAY_FRAME = 33;
integer A_DELAY_FRAME = 34;
integer R_CHG_DELAY_FRAME = 35;
integer R_PRIM_COUNT = 36;
integer A_PRIM_COUNT = 37;
integer C_RECORD_FRAME = 40;
integer A_RECORD_FRAME = 41;
integer C_RECORD_PRIM = 42;
integer A_RECORD_PRIM = 43;
integer C_END_FRAME = 44;
integer C_DUMP_FRAME = 45;
integer A_DUMP_FRAME = 46;
integer R_TYP_ENGINE = 47;
integer A_TYP_ENGINE = 48;
integer A_DUMP_PRIM = 49;
integer C_RESET = 50;
integer A_RESET = 51;
integer A_OUT_MEMORY = 52;
//use only by trigger
integer C_PUBLISHED = 60;
integer C_UNPUBLISHED = 61;
// This shows the edit menu
showMenuDialog()
{
string temp = (string)((float)iFreeMemory/(float)iMaxMemory * 100.0);
string menuText = "Available Memory: " + (string)iFreeMemory + " (" + llGetSubString(temp, 0, 4) +"%)" +
"\nCurrent Snapshot: " + (string)iCurrentSnapshot +"\tSnapshots Recorded: " + (string)iRecordedSnapshots +
"\n\t\tDelay : " + llDeleteSubString((string)fDelay, -4, -1) +" secondes" +
"\n[ Record ] - Record a snapshot of prim positions\n[ Play ] - Play back all the recorded snapshots" +
"\n[ Publish ] - Finish the recording process\n[ Show Next ] - Show the next snapshot" +
"\n[ Show Prev ] - Show the previous snapshot\n[ Dump ] - Dump memory\n[ Load ] - Load the notecard";
list buttons = ["Record","Play","Publish","Show Prev","Show Next", "Dump", "Load"];
llDialog(llGetOwner(), menuText, buttons, COMMAND_CHANNEL);
}
recordPrim(){
integer change = FALSE;
string str;
vector rootPos = llGetPos();
vector pos = llList2Vector(llGetLinkPrimitiveParams(iPrimCounter, [PRIM_POSITION]),0);
//need to convert into local position
pos.x -= rootPos.x;
pos.z -= rootPos.z;
pos.y -= rootPos.y;
pos = pos / llGetRot();
rotation rot = llList2Rot(llGetLinkPrimitiveParams(iPrimCounter, [PRIM_ROTATION]),0);
//Converting into local rot
rot = rot / llGetRot();
vector scale = llList2Vector(llGetLinkPrimitiveParams(iPrimCounter, [PRIM_SIZE]),0);
change = (pos != llList2Vector(lPrevSnap, 0)) || (rot != llList2Rot(lPrevSnap, 1)) ||
(scale != llList2Vector(lPrevSnap, 2)) || (iRecordedSnapshots == 0);
if(change) iRecordByMenu = 2;
if(iRecordedSnapshots > 0) lPrevSnap = llDeleteSubList(lPrevSnap, 0, 2);
lPrevSnap += [pos, rot, scale];
if( vScaleChange.x != 1.0 || vScaleChange.y != 1.0 || vScaleChange.z != 1.0 )
{
pos.x /= vScaleChange.x;
pos.y /= vScaleChange.y;
pos.z /= vScaleChange.z;
scale.x /= vScaleChange.x;
scale.y /= vScaleChange.y;
scale.z /= vScaleChange.z;
}
if(change || sTypEngine == "1"){
str += (string)iPrimCounter + ";" + (string)pos + ";" + (string)rot + ";" +
(string)scale + ";" + (string)fDelay + ";" ;
}
llMessageLinked(LINK_THIS, C_RECORD_PRIM, str, (key)((string)iCurrentSnapshot));
}
errorLine(string note){
llDialog(llGetOwner(), "error at line " + (string)iLinePRS + "\nin notecard\n" + note + "\n loading stop here",
["Ok"], - 32768);
iLoad = FALSE;
llMessageLinked(LINK_THIS, C_END_FRAME, "", "");
llOwnerSay("End reading notecard on error\nTotal number of snapshots loaded: " + (string)iRecordedSnapshots);
}
recordPrevSnap(){//record list lPrevSnap after notecard or analys
lPrevSnap = [];
vector pos;
rotation rot;
vector scale;
integer i;
vector rootPos = llGetPos();
for(i = 2; i <= iPrimCount; i++){
vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]),0);
//need to convert into local position
pos.x -= rootPos.x;
pos.z -= rootPos.z;
pos.y -= rootPos.y;
pos = pos / llGetRot();
rotation rot = llList2Rot(llGetLinkPrimitiveParams(i, [PRIM_ROTATION]),0);
//Converting into local rot
rot = rot / llGetRot();
vector scale = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]),0);
lPrevSnap += [pos, rot, scale];
}
}
reset(){
lPrevSnap = [];
iCurrentSnapshot = 1;
iRecordedSnapshots = 999;
llMessageLinked(LINK_THIS, R_MAX_MEMORY, "", "");
llMessageLinked(LINK_THIS, R_FREE_MEMORY, "", "");
llMessageLinked(LINK_THIS, R_PRIM_COUNT, "", "");
llMessageLinked(LINK_THIS, R_TYP_ENGINE, "", "");
llMessageLinked(LINK_THIS, R_TOTAL_FRAMES, "", "");
llMessageLinked(LINK_THIS, R_SCALE, "", "");
}
default{
state_entry(){
if(!iFirstInitDone) state wait;
iListenerHandle = llListen(COMMAND_CHANNEL,"", llGetOwner(), "");
llMessageLinked(LINK_THIS, R_SCALE, "", "");
if(!iLoad){
iInit = TRUE;
reset();
llMessageLinked(LINK_THIS, C_UNPUBLISHED, "", "");
}else{//return in this state after loading
iLoad = FALSE;
showMenuDialog();
}
}
link_message(integer sender_num, integer num, string str, key id){
iPrevMemory = iFreeMemory;
if(num == A_MAX_MEMORY){
iMaxMemory = (integer)str;
}else if(num == A_FREE_MEMORY){
iFreeMemory = (integer)str;
//memory answer after record snapshot
if(iFreeMemory < iPrevMemory){
iRecordedSnapshots++;
iCurrentSnapshot++;
llOwnerSay("Total number of snapshots recorded: " + (string)iRecordedSnapshots);
showMenuDialog();
}
}else if(num == A_TOTAL_FRAMES){
iRecordedSnapshots = (integer)str;
llMessageLinked(LINK_THIS, R_DELAY_FRAME, "", (key)str);
if(iAskDump){
llMessageLinked(LINK_THIS, C_DUMP_FRAME, "1", "");
}
}else if(num == A_ACTUAL_FRAME){
iCurrentSnapshot = (integer)str;
llMessageLinked(LINK_THIS, R_DELAY_FRAME, "", (key)str);
}else if(num == A_PRIM_COUNT){
iPrimCount = (integer)str;
llOwnerSay((string)(iPrimCount - 1) + " animable prims on " + (string)llGetNumberOfPrims() + " total prims");
}else if(num == A_SCALE){
vScaleChange = (vector)str;
}else if(num == A_DELAY_FRAME){
fDelay = (float)str;
if(fDelay == .0) fDelay = 1.0;
if(!iInit) showMenuDialog();
}else if(num == A_RESET){
llOwnerSay("Reset scripts - Engine is empty");
reset();
}else if(num == A_RECORD_FRAME){
//record by commande first prim
iPrimCounter = 2;
recordPrim();
}else if(num == A_RECORD_PRIM){
iPrimCounter++;
if(iPrimCounter > iPrimCount){
if(iRecordByMenu == 2) //change detected in frame
llMessageLinked(LINK_THIS, C_END_FRAME, "", "");
else showMenuDialog();
iRecordByMenu = 0;
}else recordPrim();
}else if(num == A_OUT_MEMORY){
iRecordByMenu = 0;
iFreeMemory = (integer)str;
llDialog(llGetOwner(),"No enough memory", ["Ok"], -32768);
}else if(num == A_DUMP_PRIM){
string name = llGetObjectName();
llSetObjectName("");
llSay(0,(string)id + ";" + str);
llSetObjectName(name);
}else if(num == A_DUMP_FRAME){
iAskDump++;
if(iAskDump > iRecordedSnapshots){
llOwnerSay("Dump done !!");
iAskDump = 0;
return;
}
llMessageLinked(LINK_THIS, C_DUMP_FRAME, (string)iAskDump, "");
}else if(num == A_TYP_ENGINE){
sTypEngine = str;
}else if(num == A_END_ANIMATION){
iCurrentSnapshot = iRecordedSnapshots;
recordPrevSnap();
showMenuDialog();
}
//if we have all the init answers to work
if(iMaxMemory && iFreeMemory && iRecordedSnapshots < 999 && sTypEngine != "" &&
vScaleChange != ZERO_VECTOR && fDelay > .0 && iPrimCount && iInit && !iAskPlay){
if(iRecordedSnapshots > 0){
llOwnerSay((string)iRecordedSnapshots + " registred snapshot(s) found - Playing for analys ...");
iAskPlay = iRecordedSnapshots;
llMessageLinked(LINK_THIS, C_PLAY_ANIM, "", "");
}else{
iCurrentSnapshot = 1;
iInit = FALSE;
showMenuDialog();
}
}
//end init after play animation
if(iCurrentSnapshot == iAskPlay ){
iInit = FALSE;
iAskPlay = 0;
}
}
touch_start(integer tot){
if( !iInit) showMenuDialog();
}
//This event handler takes care of all the editing commands.
//Available commands are: record, play, publish, show next, show prev, show #
listen(integer channel, string name, key id, string message)
{
list parsedMessage = llParseString2List(message, [" "], []);
string firstWord = llToLower(llList2String(parsedMessage,0));
string secondWord = llToLower(llList2String(parsedMessage,1));
//display a snapshot
if("show" == firstWord && iRecordedSnapshots > 0){
if(secondWord == "next"){
iPlaySnapshot = iCurrentSnapshot + 1;
if(iPlaySnapshot > iRecordedSnapshots)
iPlaySnapshot = 1;
}else if(secondWord == "prev"){
iPlaySnapshot = iCurrentSnapshot - 1;
if(iPlaySnapshot == iRecordedSnapshots) //prev at the end
iPlaySnapshot = iRecordedSnapshots - 1;
if(iPlaySnapshot < 1 ) //prev at the first or only one frame recorded
iPlaySnapshot = iRecordedSnapshots;
}else{
// when the conversion fails, snapshotNumber = 0
iPlaySnapshot = (integer)secondWord;
if(iPlaySnapshot > 0 && iPlaySnapshot <= iRecordedSnapshots ){
llOwnerSay("Showing snapshot: "+(string)iPlaySnapshot);
}else{
llOwnerSay("Invalid snapshot number given: " + (string) iPlaySnapshot +
"\nA valid snapshot number is between 1 and " + (string)iRecordedSnapshots +
"\nAssuming " + (string)iRecordedSnapshots);
iPlaySnapshot = iRecordedSnapshots;
}
}
llMessageLinked(LINK_THIS, C_PLAY_FRAME, (string)iPlaySnapshot, "");
}
//record a snapshot
else if(firstWord == "record"){
//record only at the end
if(iCurrentSnapshot <= iRecordedSnapshots) iCurrentSnapshot = iRecordedSnapshots + 1;
iRecordByMenu = 1;
llMessageLinked(LINK_THIS, C_RECORD_FRAME, (string)iCurrentSnapshot, "");
}
//play the animation from beginning to end once without looping.
else if (firstWord == "play"){
//float delay = (float)secondWord;
//iCurrentSnapshot = 1;
llMessageLinked(LINK_THIS, C_PLAY_ANIM, "", "");
}
//publish disables the recording features and enables the on-touch trigger
else if("publish" == firstWord){
state published;
}else if (firstWord == "dump"){
iAskDump = 1;
llMessageLinked(LINK_THIS, R_TOTAL_FRAMES, "", "");
}else if (firstWord == "load"){
iLoad = TRUE;
llDialog(llGetOwner(), "Load notecard?\nThis will erase the current animation\nConfirm?",
["Yes", "No"], COMMAND_CHANNEL);
}else if (firstWord == "yes" && iLoad){
state loading;
}else if (firstWord == "no"){
iLoad = FALSE;
}else if (firstWord == "delay"){
float delay;
integer frame;
if(secondWord == "snapshot"){
frame = (integer)llList2String(parsedMessage,2);
if(frame < 1 || frame > iRecordedSnapshots){
llOwnerSay("Invalid snapshot number given: " + (string) frame +
"\nA valid snapshot number is between 1 and " + (string)iRecordedSnapshots);
return;
}
delay = (float)llList2String(parsedMessage,3);
}else delay = (float)secondWord;
if(delay < 0.1) {
llOwnerSay("Invalid delay number given: " + (string)delay +
"\nA valid delay number is greater than or equal 0.1\n...assuming 0.1 secondes");
delay = 0.1;
}
if(secondWord == "snapshot"){
llMessageLinked(LINK_THIS, R_CHG_DELAY_FRAME, (string)delay, (key)((string)frame));
llOwnerSay("Change delay snapshot " + (string)frame + " for " +
llDeleteSubString((string)delay, -4, -1) + " secondes");
if(frame == iRecordedSnapshots) fDelay = delay;
}else{
llOwnerSay("delay for the next taken snapshot : " +
llDeleteSubString((string)delay, -4, -1)+ " secondes");
fDelay = delay;
}
}
}
}
state loading{
state_entry(){
//search notecard PRS
sNotecardPRS = "";
integer nb = llGetInventoryNumber(INVENTORY_NOTECARD);
integer i;
for(i=0; i<nb; i++){
string name = llGetInventoryName(INVENTORY_NOTECARD, i);
if(~llSubStringIndex(name, "OPRIAN PRS")) sNotecardPRS = name;
}
if(sNotecardPRS == ""){//no found
llDialog(llGetOwner(), "Not notecard 'OPRIAN PRS'", ["Ok"], -32768);
state default;
}
//erase current animation
llMessageLinked(LINK_THIS, C_RESET, "", "");
iRecordedSnapshots = 0;
iCurrentSnapshot = 0;
lPrevSnap = [];
kHandlePRS = llGetNotecardLine(sNotecardPRS, iLinePRS = 0);// request first line
}
dataserver(key query_id, string data){
if (query_id == kHandlePRS) {
if (data != EOF){
if(data == ""){//empty line
kHandlePRS = llGetNotecardLine(sNotecardPRS, ++iLinePRS);
return;
}
integer index = llSubStringIndex(data, ": ");
if(index == -1){ errorLine(sNotecardPRS); return;}
data = llDeleteSubString(data, 0, index + 1);//delete time stamp and ': '
iFrameLoad = (integer)llGetSubString(data, 0, index -1);
if(iFrameLoad == 0 || index == -1) { errorLine(sNotecardPRS); return;}
index = llSubStringIndex(data, ";");
sPrimLoad = llDeleteSubString(data, 0, index);//delete the frame number
if(iFrameLoad == iCurrentSnapshot + 1){//new frame
if(iFrameLoad > 1){//end previous frame
llOwnerSay("Snapshot " + (string)(iFrameLoad - 1) + " loaded");
llMessageLinked(LINK_THIS, C_END_FRAME, "", "");//triggers an answer free memory
}else{ //first frame
iCurrentSnapshot = 1;
llMessageLinked(LINK_THIS, C_RECORD_FRAME, (string)iFrameLoad, "");
llOwnerSay("begin reading notecard");
}
}else{
llMessageLinked(LINK_THIS, C_RECORD_PRIM, sPrimLoad, "");
}
}else{//end notecard
iEOF = TRUE;
llMessageLinked(LINK_THIS, C_END_FRAME, "", "");
llOwnerSay("Snapshot " + (string)(iRecordedSnapshots + 1) + " loaded");
llOwnerSay("End reading notecard");
}
}
}
link_message(integer sender_num, integer num, string str, key id){
if(num == A_FREE_MEMORY){//memory answer after C_END_FRAME
iFreeMemory = (integer)str;
iRecordedSnapshots++;
if(iEOF) llMessageLinked(LINK_THIS, R_DELAY_FRAME, "", (key)((string)iCurrentSnapshot));
llMessageLinked(LINK_THIS, C_PLAY_FRAME, (string)iCurrentSnapshot, "");
iCurrentSnapshot++;
}else if(num == A_ACTUAL_FRAME){//answer after playing frame
recordPrevSnap();
if(iEOF){
iEOF = FALSE;
state default;
}else llMessageLinked(LINK_THIS, C_RECORD_FRAME, (string)iFrameLoad, "");//next frame
}else if(num == A_RECORD_FRAME){//answer after C_RECORD_FRAME
// new frame first prim
iPrimCounter = (integer)llGetSubString(sPrimLoad, 0, llSubStringIndex(sPrimLoad, ";") -1);
llMessageLinked(LINK_THIS, C_RECORD_PRIM, sPrimLoad, "");
}else if(num == A_RECORD_PRIM){
kHandlePRS = llGetNotecardLine(sNotecardPRS, ++iLinePRS);//read the next notecard line
}else if(num == A_DELAY_FRAME){
fDelay = (float)str;
}else if(num == A_OUT_MEMORY){
iFreeMemory = (integer)str;
iEOF = FALSE;
llDialog(llGetOwner(),"No enough memory", ["Ok"], -32768);
state default;
}
}
}
state wait{//to let the engine start on reset all scripts
state_entry(){
iFirstInitDone = TRUE;
llSleep(2.0);
state default;
}
}
state published{
state_entry(){
llOwnerSay("Recording disabled. Publish complete.\nClick me to toggle animation on/off.");
//enable trigger
llMessageLinked(LINK_THIS, C_PUBLISHED, "", "");
//llRemoveInventory(llGetScriptName());
}
}
un trigger tordu comme exemple; joue 1 à 10 en boucle directe sur click, et 11 à 20 sur commande chat 'go2' en symmetry one shot.
// Script Name: OPRIAN click+chat trigger slice: OPen_PRIm_ANimator trigger on click and chat after publishing
// Playing two slice : once looped in direct mode on click, the other one shot in symmetry mode on chat command 'go2'
// Version V1.8
// trigger script for use in set scripts OPRIAN author Elenia Boucher
//must be in objet BEFORE publishing
// This program is free software; you can redistribute it and/or modify it.
// License information must be included in any script you give out or use.
// This script is licensed under the Creative Commons Attribution-Share Alike 3.0 License
// from http://creativecommons.org/licenses/by-sa/3.0 unless licenses are
// included in the script or comments by the original author,in which case
// the authors license must be followed.
// Please leave any authors credits intact in any script you use or publish.
////////////////////////////////////////////////////////////////////
integer C_STOP_ANIM = 3;
integer C_LOOP_ON = 4;
integer C_LOOP_OFF = 5;
integer C_REVERSE_ON = 6;
integer C_REVERSE_OFF = 7;
integer C_SYMMETRY_ON = 8;
integer C_SYMMETRY_OFF= 9;
integer C_PLAY_SLICE = 10;
integer A_START_ANIMATION = 30;
integer C_PUBLISHED = 60;
integer C_UNPUBLISHED = 61;
stop(){
llMessageLinked(LINK_THIS, C_LOOP_OFF, "", "");
llMessageLinked(LINK_THIS, C_STOP_ANIM, "", "");//comment to stop at the end of loop
}
default{
link_message(integer sender_num, integer num, string str, key id){
if(num == C_PUBLISHED) state wait;
}
}
state wait{
state_entry(){
llListen(0, "", "", "go2");
}
link_message(integer sender_num, integer num, string str, key id){
if(num == C_UNPUBLISHED) state default;
}
touch_start(integer total_number){
state ON_click;
}
listen(integer chan, string name, key id, string mess){
state GO2;
}
}
state ON_click{
state_entry(){
llMessageLinked(LINK_THIS, C_LOOP_ON, "", "");//comment to one shot animation
llMessageLinked(LINK_THIS, C_PLAY_SLICE, "1", (key)"10");//play animation to snapshot 1 to 10
}
touch_start(integer total_number){
stop();
state wait;
}
link_message(integer sender_num, integer num, string str, key id){
if(num == C_UNPUBLISHED){
stop();
state default;
}
}
}
state GO2{
state_entry(){
llMessageLinked(LINK_THIS, C_SYMMETRY_ON, "", "");//one shot animation in symmetry mode
llMessageLinked(LINK_THIS, C_PLAY_SLICE, "11", (key)"20");//play animation to snapshot 11 to 20
}
link_message(integer sender_num, integer num, string str, key id){
if(num == C_UNPUBLISHED){
stop();
state default;
}else if(num == A_START_ANIMATION){
llMessageLinked(LINK_THIS, C_SYMMETRY_OFF, "", "");//dont forget
state wait;
}
}
}
|