CatgirlKat149 Posted March 21, 2022 Share Posted March 21, 2022 Hello! I'm fairly new to scripting in SL and am currently working on a flying airship-type vehicle using modifiable pre-existing scripts. Part of the plan was to have turrets that are rooted to the ship itself that move with the camera movement of a user, not necessarily the driver. The issue I am having is this: The turret script works properly to rotate the child (which houses the script) when linked with the root, as long as it is not physical. If the object becomes physical, as is the case with the airship when it is flying, the turret script then rotates the whole object (both root and children). I would only like the child object to rotate based on camera movement, even if the entire object is physical. The turret script allows an object to be rotated through the same rotation as the person who clicked the object's camera. The airship's script turns the airship physical during flight Turret Script: key toucher; string toucherS; float SPEED = 40.0; integer LIFETIME = 7; float DELAY = 0.2; vector vel; vector pos; rotation rot; integer in_use; integer have_permissions = FALSE; integer armed = TRUE; fire() { rot = llGetRot(); vel = llRot2Fwd(rot); pos = llGetPos(); pos = pos + vel; pos.z += 0.0; vel = vel * SPEED; llTriggerSound("shoot", 1.0); llRezObject("bullet", pos, vel, rot, 1); } default { state_entry() { in_use = FALSE; } touch_start(integer total_number) { if(in_use == FALSE) { toucher = llDetectedKey(0); llRequestPermissions(toucher, PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION); llSetText("Requesting Permissions", <1,1,1>, 1); } if(in_use == TRUE) { if(llDetectedKey(0) == toucher) { llReleaseControls(); llSensorRemove(); llSetRot(<-0.00000, -0.00000, 0.70711, 0.70711>); llSetText("", <1,1,1>, 1); in_use = FALSE; } } } sensor(integer sense) { rotation k = llDetectedRot(0); llRotLookAt(k, .1, .1); } no_sensor() { llReleaseControls(); llSensorRemove(); llSetRot(<-0.00000, -0.00000, 0.70711, 0.70711>); llSetText("", <1,1,1>, 1); in_use = FALSE; } run_time_permissions(integer perm) { if(perm) { llSetText("", <1,1,1>, 1); llTakeControls(CONTROL_ML_LBUTTON, TRUE, FALSE); llSensorRepeat("", toucher, AGENT, 20, TWO_PI, .1); llSetText("Current User: "+llKey2Name(toucher), <1,1,1>, 1); in_use = TRUE; } else { in_use = FALSE; llSetText("", <1,3,1>, 1); } } control(key name, integer levels, integer edges) { if ((levels & CONTROL_ML_LBUTTON) == CONTROL_ML_LBUTTON) { fire(); } } } // END // Airship Script: // SoloFlight // by Solo Mornington // This script is based on the HC-1 flight script by illume Skallagrimson // but VERY HEAVILY MODIFIED. :-) // we only have a position for the sit target, no rotation. it is assumed that // this script is in the root prim of a zero-rotation object. vector gSitTarget = <2.01, 0.002, 9.005>; string gSitText = "Fly away"; // Text to show in the pie menu for sitting string gAnimationName; // this will be the first animation in inventory string gLoopSound = "tugboat"; // the sound to loop during flying. key gPilot = NULL_KEY; // who's flying? (distinct from passengers) // these are values for the vehicle motors // they'd more properly be state-scope variable for state flying. // https://jira.secondlife.com/browse/SVC-3297 vector linear; vector angular; float water_offset = 1.6; // Defining the Parameters of the normal driving camera. // This will let us follow behind with a loose camera. list gDriveCam =[ CAMERA_ACTIVE, TRUE, CAMERA_BEHINDNESS_ANGLE, 0.0, CAMERA_BEHINDNESS_LAG, 0.5, CAMERA_DISTANCE, 2.0, CAMERA_PITCH, 05.0, CAMERA_FOCUS_LAG, 0.05, CAMERA_FOCUS_LOCKED, FALSE, CAMERA_FOCUS_THRESHOLD, 0.0, CAMERA_POSITION_LAG, 0.5, CAMERA_POSITION_LOCKED, FALSE, CAMERA_POSITION_THRESHOLD, 0.0, CAMERA_FOCUS_OFFSET, <0,0,0>]; // lists of which prims are legs and wings, so we can do special effects list gWingPrims; list gLegPrims; setVehicle() { llCollisionSound("", 0.0); llSetVehicleType(VEHICLE_TYPE_AIRPLANE); // linear friction llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <100.0, 100.0, 100.0>); // uniform angular friction llSetVehicleFloatParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, 1.0); // linear motor llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0.0, 0.0, 0.0>); llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, .5); llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 1.0); // angular motor llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <0.0, 0.0, 0.0>); llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, .4); llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 2.0); // hover llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, 0.0); llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.0); llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 350.0); llSetVehicleFloatParam(VEHICLE_BUOYANCY, 1.0); // linear deflection llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 0.5); llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 1.0); // angular deflection llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0.25); llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 100.0); // vertical attractor llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0.75); llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1.0); // banking llSetVehicleFloatParam(VEHICLE_BANKING_EFFICIENCY, 0.0); llSetVehicleFloatParam(VEHICLE_BANKING_MIX, 1.0); llSetVehicleFloatParam(VEHICLE_BANKING_TIMESCALE, 360.0); // default rotation of local frame llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME, <0.0, 0.0, 0.0, 1.0>); // removed vehicle flags llRemoveVehicleFlags(VEHICLE_FLAG_NO_DEFLECTION_UP | VEHICLE_FLAG_HOVER_WATER_ONLY | VEHICLE_FLAG_HOVER_TERRAIN_ONLY | VEHICLE_FLAG_HOVER_UP_ONLY | VEHICLE_FLAG_LIMIT_MOTOR_UP | VEHICLE_FLAG_LIMIT_ROLL_ONLY); // set vehicle flags llSetVehicleFlags(VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT); } loadLegAndWingPrims() { gWingPrims = []; gLegPrims = []; integer i; list params; // use llGetObjectPrimCount() so we don't include seated avatars. integer count = llGetObjectPrimCount(llGetKey()); for (i=1; i<=count; ++i) { params = llGetLinkPrimitiveParams(i, [PRIM_DESC]); string desc = llList2String(params, 0); if (desc == "leg") gLegPrims += [i]; if (desc == "wing") gWingPrims += [i]; } } newAnimationCheck() { // we might have a new animation in inventory // and if we do, stop the old one and play the new one. if (gPilot != NULL_KEY) { llStopAnimation(gAnimationName); gAnimationName = llGetInventoryName(INVENTORY_ANIMATION, 0); llStartAnimation(gAnimationName); return; } gAnimationName = llGetInventoryName(INVENTORY_ANIMATION, 0); } primAlpha(list prims, float alpha) { // set prims to be transparent integer i; integer count = llGetListLength(prims); for (i=0; i<count; ++i) { llSetLinkAlpha(llList2Integer(prims, i), alpha, ALL_SIDES); } } wingFlapAlpha() { integer i; integer count = llGetListLength(gWingPrims); for (i=0; i<count; ++i) { if (llFrand(1.0) > 0.5) llSetLinkAlpha(llList2Integer(gWingPrims, i), 0.7, ALL_SIDES); else llSetLinkAlpha(llList2Integer(gWingPrims, i), 0.3, ALL_SIDES); } } default { state_entry() { // load up the exception prims loadLegAndWingPrims(); // some basic initializations gPilot = NULL_KEY; newAnimationCheck(); llSitTarget(gSitTarget, ZERO_ROTATION); llSetSitText(gSitText); state atRest; } } state atRest { // state atRest is the state we should be in when the vehicle is at rest // just sitting there, as in we just rezzed it, or the avatar stood up from it. // mainly this state is responsible for starting the flying sequence when // the owner sits on the vehicle. state_entry() { // nobody flying the thing... gPilot = NULL_KEY; // hide the wings and show the legs primAlpha(gWingPrims, 0.0); primAlpha(gLegPrims, 1.0); // turn off vehicle stuff. llSetStatus(STATUS_PHYSICS, FALSE); // TODO: make the vehicle right itself. // let the whole object know we're at rest. } changed(integer what) { // Whenever an av sits on or stands up from an object, it is treated as if it // were being linked or unlinked. // Unfortunately, there are a whole bunch of other things that cause CHANGED_LINK // as well, so we have to allow for them. // Things that can cause CHANGED_LINK: 1) linking in new prims, 2) unlinking prims // 3) avatars sitting, 4) avatars unsitting if (what & CHANGED_LINK) { // are there *any* seated avatars? if (llGetNumberOfPrims() != llGetObjectPrimCount(llGetKey())) { // we have seated avs, so let's find the sit target one key agent = llAvatarOnSitTarget(); if(llSameGroup(agent)) { gPilot = agent; // ask politely for permission do to stuff. // These will be automatically granted. llRequestPermissions(agent,PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS | PERMISSION_TRACK_CAMERA | PERMISSION_CONTROL_CAMERA); } if(llSameGroup(agent) != TRUE) // sit target agent is not the owner { llUnSit(agent); llWhisper(0,"Only the Kumiho Family can drive this vehicle."); } } else // there are no seated avatars... { if (gPilot != NULL_KEY) { // since there are no seated avs, but we still know about // the pilot, they must have just stood up. // we need to release controls and do other cleanup llSetTimerEvent(0); llReleaseControls(); llClearCameraParams(); llStopLookAt(); llStopAnimation(gAnimationName); gPilot = NULL_KEY; llMessageLinked(LINK_ALL_OTHERS, 0, "stop", NULL_KEY); } } } if (what & CHANGED_INVENTORY) { // someone might have dropped in a new animation newAnimationCheck(); } } run_time_permissions(integer perm) { // to be correct, we really should check the perms and make sure we // got the ones we need. but this will usually work: if (perm) state flying; } on_rez(integer foo) { state default; } } state flying { // state flying assumes we have permission to take controls, run animations, // and control the camera. state_entry() { // hide the legs, show the wings... primAlpha(gLegPrims, 0.0); wingFlapAlpha(); // play the flying sound llLoopSound(gLoopSound, 1.0); llSetTimerEvent(0.05); llTakeControls( CONTROL_FWD | CONTROL_BACK | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT | CONTROL_UP | CONTROL_DOWN | CONTROL_LBUTTON | CONTROL_ML_LBUTTON, TRUE, FALSE); setVehicle(); llSetCameraParams(gDriveCam); llStartAnimation(gAnimationName); vector current_pos = llGetPos(); llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, current_pos.z); llSetStatus(STATUS_PHYSICS, TRUE); // let the rest of the object know we're flying llMessageLinked(LINK_ALL_OTHERS, 0, "flying", NULL_KEY); } changed(integer what) { // Whenever an av sits on or stands up from an object, it is treated as if it // were being linked or unlinked. // Unfortunately, there are a whole bunch of other things that cause CHANGED_LINK // as well, so we have to allow for them. // Things that can cause CHANGED_LINK: 1) linking in new prims, 2) unlinking prims // 3) avatars sitting, 4) avatars unsitting if (what & CHANGED_LINK) { // are there *any* seated avatars? if (llGetNumberOfPrims() == llGetObjectPrimCount(llGetKey())) { // there are no seated avatars... if (gPilot != NULL_KEY) { // since there are no seated avs, but we still know about // the pilot, they must have just stood up, so let's rest. state atRest; } } } if (what & CHANGED_INVENTORY) { newAnimationCheck(); } } // The control event is what we get when the user mashed down the keys // we asked about in llTakeControls(). control(key id, integer levels, integer edges) { if(llGetStatus(STATUS_PHYSICS)!=TRUE) llSetStatus(STATUS_PHYSICS, TRUE); if ((edges & levels & CONTROL_UP)) { linear.z += 12.0; } else if ((edges & ~levels & CONTROL_UP)) { linear.z -= 12.0;} if ((edges & levels & CONTROL_DOWN)) { linear.z -= 12.0; } else if ((edges & ~levels & CONTROL_DOWN)) { linear.z += 12.0;} if ((edges & levels & CONTROL_FWD)) { linear.x += 14.0; } else if ((edges & ~levels & CONTROL_FWD)) { linear.x -= 14.0;} if ((edges & levels & CONTROL_BACK)) { linear.x -= 14.0; } else if ((edges & ~levels & CONTROL_BACK)) { linear.x += 14.0;} if ((edges & levels & CONTROL_LEFT)) { linear.y += 8.0; } else if ((edges & ~levels & CONTROL_LEFT)) { linear.y -= 8.0;} if ((edges & levels & CONTROL_RIGHT)) { linear.y -= 8.0; } else if ((edges & ~levels & CONTROL_RIGHT)) { linear.y += 8.0;} if ((edges & levels & CONTROL_ROT_LEFT)) { angular.z += (PI / 180) * 55.0; angular.x -= PI * 4; } else if ((edges & ~levels & CONTROL_ROT_LEFT)) { angular.z -= (PI / 180) * 55.0; angular.x += PI * 4;} if ((edges & levels & CONTROL_ROT_RIGHT)) { angular.z -= (PI / 180) * 55.0; angular.x += PI * 4; } else if ((edges & ~levels & CONTROL_ROT_RIGHT)) { angular.z += (PI / 180) * 55.0; angular.x -= PI * 4; } if ((edges & levels & CONTROL_ML_LBUTTON)) { llMessageLinked(LINK_ALL_OTHERS, 0, "fire", NULL_KEY); } } timer() { wingFlapAlpha(); if (llGetAgentInfo(gPilot) & AGENT_MOUSELOOK) { vector rot = llRot2Euler(llGetCameraRot()); llRotLookAt(llEuler2Rot(<0,0,rot.z>),0.1,1); } else { llStopLookAt(); } vector vel = llGetVel(); float water = llWater(vel * 0.05); float ground = llGround(vel * 0.05); if (water > ground) { // above water vector MahPos = llGetPos(); if (MahPos.z < water+water_offset){ llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.5); llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 0.1); llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, water + water_offset); } else { llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.0); llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 350.0); } } else { // above ground llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.0); llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 350.0); } llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, linear); llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, angular); } state_exit() { // we need to release controls and do other cleanup llStopSound(); llSetTimerEvent(0); llStopLookAt(); llReleaseControls(); llClearCameraParams(); llStopAnimation(gAnimationName); llMessageLinked(LINK_ALL_OTHERS, 0, "stop", NULL_KEY); } on_rez(integer foo) { state default; } } //END// Link to comment Share on other sites More sharing options...
Rolig Loon Posted March 21, 2022 Share Posted March 21, 2022 It's always hard to modify someone else's script. It takes you almost as long as it would to write your own from scratch, and then you've inherited someone else's ideas about how it ought to work. Still, it's instructive to see what another scripter did. We can learn from each other. The partial answer to your immediate challenge is that the turret script is using llSetRot instead of changing the turret's local rotation, relative to the ship. You can either use llSetLocalRot or, better, use llSetLinkPrimitiveParamsFast (with its PRIM_ROT_LOCAL parameter), which does not have a built-in delay. The more serious challenge, as you have discovered, is that once you make the ship physical, none of those functions will work. In a physical object, you'll want to use llRotLookAt, which will take a bit of work. 1 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted March 21, 2022 Share Posted March 21, 2022 The 'obvious' workaround is to set the object non-physical before doing the child prim rotation, and set it back to physical afterwards*, although that's playing with fire a bit, and not something I'd recommend a novice scripter try and debug. *I would either try to do it as all one llSLPPF call, or failing that, add a short sleep (or use the non-fast llSLPP ) after the call to turn non-physical, and increase the interval on the timer (sensor in the OP) accordingly. Link to comment Share on other sites More sharing options...
arton Rotaru Posted March 22, 2022 Share Posted March 22, 2022 The problem here is the llRotLookAt function in the sensor() event. That does only work in child prims when it's non-physical. llSetLocalRot() and PRIM_ROT_LOCAL will work in child prims even if the object is set physical. It might be not recommended to do that while physical, but I never had a problem with doing just that actually. If you replace llRotLookAt(k, ,1, .1) with llSetLocalRot(k / llGetRootRotation()) in the sensor() event, the turet should work even when the vehicle is physical. However, since this is just detecting the rotation of the avatar who touched the turret, I don't know what the purpose of this script is actually. When that gunner Avatar is seated on the vehicle as well, it would have to rotate the seated AV in order to rotate the turret. There is nothing in this turret script that would take the avatars camera into account actually. 1 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted March 22, 2022 Share Posted March 22, 2022 1 hour ago, arton Rotaru said: There is nothing in this turret script that would take the avatars camera into account actually. I could be remembering wrong, but I thought rotations were reported fairly accurately for avatars in mouselook. Link to comment Share on other sites More sharing options...
arton Rotaru Posted March 22, 2022 Share Posted March 22, 2022 34 minutes ago, Quistess Alpha said: I could be remembering wrong, but I thought rotations were reported fairly accurately for avatars in mouselook. Now that you say it. Haven't thought about mouselook actually. Link to comment Share on other sites More sharing options...
Recommended Posts
Please take a moment to consider if this thread is worth bumping.
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now