This was written by Nikkesa:
integer timer_on = 0; list newPositions; //the list of positions to apply to the segments list newRotations; //the list of rotations to apply to the segments float curve_location_x = 360; //the position we are on the curve... float distance_between_segments = 0.1; //the distance between each segment vector segment_size = <0.01,0.1,0.1>; //let's start setting this **bleep**... //Note: may want to incorporate support for different types of segments, such as if we had 3 different cones per segment... integer number_of_segments; list command_list; integer i; float counter = 0; //setup vector position_offset; //part 1 float myAngle1; //the new angle thingy... used later //part 3 rotation rotation_between; //the rotation between two segments... vector childPos1; vector childPos2; vector newValue; //////////////////////////// list position_cache; list rotation_cache; integer toggle_building_setting = 0; /////////////////////////// vector childPos(integer segment_id){ return llList2Vector( llGetLinkPrimitiveParams(segment_id, [PRIM_POSITION] ), 0 ); } rotation childRot(integer segment_id){ return llList2Rot(llGetLinkPrimitiveParams(segment_id, [PRIM_ROT_LOCAL]), 0); } vector childPosLocal(integer segment_id){ return llList2Vector(llGetLinkPrimitiveParams(segment_id,[PRIM_POSITION]), 0) - llGetPos(); } vector buildPositionOffset(rotation rotation_amount, vector current_position, vector axis_position, rotation base_rotation){ //builds the position offset relative to the rotation_amount relative to the base_rotation (which should be the root prims rotation) return ((axis_position - current_position) - ((axis_position - current_position) * rotation_amount)) * base_rotation; //this will return the amount we have to move Smiley Very Happy } list fix_position_offsets(list myList, float limit_distance){ //in here we want to basically scale the distance between segments so that it's always the same... list newList = myList; integer j=1; vector segmentPos1; vector segmentPos2; vector vector_between; float distance_between; for (;j < llGetListLength(myList);j++){ segmentPos2 = llList2Vector(newList, j); segmentPos1 = llList2Vector(newList, j-1); vector_between = segmentPos2 - segmentPos1; distance_between = llVecMag(vector_between); //get the distance between the segments... if (distance_between != limit_distance) { //here we scale the distance between the segments vector_between = vector_between * (limit_distance / distance_between); //I suspect this is where the math error is coming from. //and apply it to the list. newList = llListReplaceList(newList, [segmentPos1 + vector_between], j, j); } } return newList; } //for a rotation: //[((childPos(segment_id) - llGetPos()) / llGetLocalRot()) + (buildPositionOffset(llEuler2Rot(llRot2Euler(rotation_amount)*segment_id/10), childPos(segment_id), llGetPos() ) * childRot(segment_id))]; //offset_rotaton = llAtan2(llSin(new_curve_mod), new_curve_mod) integer sign(float input){ if (input > 0) return 1; if (input < 0) return -1; return 0; } /* OKAY, NEW PLAN -------------- We are going to pre-cache all of the positions and rotations for the animation sequence, and apply them over the animation sequence! so yeah, whatever. */ default { state_entry() { integer i = 2; for (;i<=llGetNumberOfPrims();i++){ llSetLinkPrimitiveParamsFast(i,[PRIM_POS_LOCAL,<(float)(i-1) * distance_between_segments,0.0,0.0>,PRIM_ROT_LOCAL,ZERO_ROTATION, PRIM_SIZE, segment_size * i/(i+1)]); } number_of_segments = llGetNumberOfPrims() - 1; //we want to ignore any avatars,especially in case of attachment and such... if (number_of_segments > 1){ while (llGetAgentSize(llGetLinkKey(number_of_segments))){ --number_of_segments; } } } touch_start(integer total_number) { if (llDetectedKey(0) == llGetOwner()){ if (timer_on == 0){ timer_on = 1; llSetTimerEvent(0.04); } else { timer_on = 0; llSetTimerEvent(0.0); llResetScript(); } } // let us start the building of the cache. } timer(){ i = 0; counter++; if (toggle_building_setting == 0) { curve_location_x = curve_location_x - 12; if (curve_location_x <= -1) { curve_location_x = 360; llOwnerSay("Done Caching... " + (string)counter); counter = 0; toggle_building_setting = 1; } command_list = []; newPositions = []; newRotations = []; for (;i < number_of_segments;i++){ //part 1 - set up the new positions for each segment. //use i+2 myAngle1 = llSin(( (float)(i+2) * (PI/2 / number_of_segments) )+( curve_location_x*TWO_PI/360 )) * 0.5; newValue = (llGetPos() - childPos(i+2)); //llOwnerSay((string)myAngle1); //newPositions += [<(float)(i+2)/(1 / distance_between_segments*0.9),0.0,0.0> + <0.0,llVecMag(newValue) * llSin(myAngle1),0.0>]; newPositions += [<(float)(i+2)/(1 / distance_between_segments),0.0,0.0> + ((newValue) - (newValue * llEuler2Rot( <0.0,0.0,myAngle1> ))) + <0.0,0.0,(llCos((TWO_PI * 3/4) * ((float)1 / (float)26) * (float)i) - 1)/2>]; //newPositions += [<(float)(i+2)/(distance_between_segments),0.0,0.0> + buildPositionOffset(llEuler2Rot( <0.0,myAngle1,myAngle1> ),childPos(i+2), llGetPos(),llGetRot())]; //newPositions += [<(1/distance_between_segments)*(curve_location_x/360)*i,0.0,0.0>]; //part 3 - set the rotations of the tail segments /* */ //part 4 - build the command list for our setlinkprimparamsfast function // } newPositions = fix_position_offsets(newPositions, distance_between_segments); i = 0; for (;i, childPos2 - childPos1); newRotations += [rotation_between]; } rotation_cache += newRotations; } else { if (counter == 30){ counter = 0; } i = 0; command_list = []; for (;i