Jump to content

Quistess Alpha

Resident
  • Posts

    3,731
  • Joined

  • Last visited

Everything posted by Quistess Alpha

  1. That looks somewhat like URL encoding, which llUnescapeURL would fix, but doesn't look like that fixes that specific example.
  2. Try not to mix movement methods 'Omega': definitely isn't what you want, because it can only do fixed speed rotation well, and ideally a continuous circle that rarely if ever changes. can lead to different perception for different observers. Physics based movement: could be interesting to try, but you don't get a lot of specific control over how it works. KFM: probably your best option for a final product, but it can be quite finicky to get the data it needs in the format it wants, and to control its numerical drift. For anything that's set to run for a long time, turn off KFM and set it to a fixed position and rotation on occasion, maybe once an hour. repeated llSetLinkPrimitiveParamsFast: can work, and could be useful for prototyping different path equations before dealing with reformatting the data for KFM. Be aware of your object's center, a sanely built object will help immensely with how you script it. For a pendulum, you probably either want the rod to be the root prim and built as a cylinder with 'slice' set to <0, 0.5, 0>, and only control the pendulum through its rotation, OR cast a particle stream with PSYS_PART_LINEAR_MASK between the anchor and weight (would have to be separate objects if using KFM) as a stand-in for the rod.
  3. So someone asked me to make a few tweaks to a really old script for an item that is set to sale. Ideally, the script should do a thing and delete itself the first time it's rezzed after having been bought when the original in-world copy by the seller has 'for sale' (copy) enabled in its build parameters. Is there a way to do that in a way that would also work if the seller buys their own object? Interesting aside: when a copy of an object is bought by not-the-owner, a changed (CHANGED_OWNER) event is triggered in both the inventory copy and the one in-world, even though in the in-world copy, llGetOwner() hasn't changed since state_entry().
  4. There is no way to change that behavior of the on-prim browser from within the media-content (webpage) or media params. The best you can do is try and direct the link to your script, from which you can bounce the link back at the user to open in a tab or wherever. That's a bit tricky because media doesn't know who's interacting with it, but as a proof of concept: (not a complete script, boilerplate media stuff removed) // in the 'webpage' : <a href="./redir/www.duckduckgo.com"> redirect </a> // the '.' at the front is verfy important. // .... http_request(key ID, string Method, string Body) { if(ID==ghRequestURL) { gsURL=Body; llSetLinkMedia(LINK_THIS,2, [ PRIM_MEDIA_HOME_URL, gsURL+"/home", // 'home' is arbitrary, but you must at a minimum add '/' to the end of the suppliued URL in order for local links (href ="./something") to correctly parse back to your prim's namespace. PRIM_MEDIA_CURRENT_URL, gsURL+"/home", PRIM_MEDIA_AUTO_PLAY, TRUE, PRIM_MEDIA_PERMS_CONTROL, PRIM_MEDIA_PERM_NONE, // don't show nav-bar. PRIM_MEDIA_PERMS_INTERACT, PRIM_MEDIA_PERM_NONE // does not actually prevent loading different links, just causes media to reload the previous page after any link is touched. PRIM_MEDIA_PERM_ANYONE would be more sane for this use-case. ]); }else { string PATH = llGetHTTPHeader(ID,"x-path-info"); if("/home"==PATH) { llSetContentType(ID,CONTENT_TYPE_XHTML); llHTTPResponse(ID,200,gNCText); // where gNCText is the content of the webpage containing the link }else { llHTTPResponse(ID,204,"no content"); // don't confuse the browser. if("/redir/"==llGetSubString(PATH,0,6)) { llSensor("","",AGENT,7.5,PI); // if only owner can use the media, like a HUD, would not need to sensor. gsURLRedir = "http://"+llDeleteSubString(PATH,0,6); } } } } sensor(integer n) { while(~--n) { llLoadURL(llDetectedKey(n),"open a new tab?",gsURLRedir); } }
  5. adding a number to all numbers in a column is especially easy in certain text editors (like vim).
  6. I like vim, but I'm a linux nerd. Surprisingly my distribution came with LSL syntax highlighting. it's out of date, but the syntax color file is very human-readable, I've not bothered updating it though. . .
  7. For this sort of thing, it's more about information flow than the math. Figure out what information you have, what information you need, and then find a way to convert one to the other. Thinking about it backwards starting with the 'want': a spherical arc between 2 points needs a center, then once you have that, there are probably several ways to turn that into an arc, but fixing the thing I wrote years ago to include a center rather than just assuming <0,0,0> is the center: // 2 points, a center and a list of percents along the circular arc to return. percent=0->A, percent=1.0->B // assumes A,center,B is an isosceles triangle, which in general it won't be. list sphere_interpolate(vector A,vector B, vector center, list percents) { // return A when percent ==0, B when percent==1 A = A-center; B = B-center; rotation rot = llRotBetween(A,B); vector axis = llRot2Axis(rot); vector angle = llRot2Angle(rot); list rets; integer i = llGetListLength(percents); while(~--percents) { //vector ret = center + A * llAxisAngle2Rot(axis,percent*angle); rets+= ( center + A*llAxisAngle2Rot(axis,angle*llList2Float(percents,i)) ); } return rets; } but if I'm understanding you right, we don't know what point is the center of our hypothetical sphere, we only have a normal to the plane, and a radius (or some other measure of the curvature. After looking at some quick sketch diagrams, the most intuitive and easy to work with piece of information is the inner angle of the curve). Would need some debugging, but my first try would probably go something like: // UNTESTED! // angle in radians, TWO_PI -> return midpoint of A&B; PI -> return center that makes a quarter arc.; 0-> math error (point at infinity). vector find_center(vector A, vector B, vector normal, float angle) { vector average = 0.5*(B+A); // point between B&A. vector delta = average-A; // could use (B-A)/2, but this makes a bit more sense since we'll use average for the last step. float halfChord = llVecMag(delta); // half the distance from A to B. float dist = halfChord*llTan(0.5*angle); // distance from average to center vector cross = llVecNorm(normal%delta); // should point from midpoint of B&A to center. return average + dist*cross; } Big picture idea is that whenever you have a normal vector, you almost always want to take a cross product with some vector that lies in the plane of interest, giving you 2 vectors in that plane, from which you should be able to make any other point in that plane as ( (some point in the plane) + (a weighted sum of those 2 vectors) ).
  8. I thought I mentioned this in my rambles above, but I'm not finding it in a brief skim, and it's conceptually important: Vectors can represent both positions in-world, and global changes to position. To 'apply' a change to a position in-world, you simply add a change vector to a position vector, and set the position of something to that new position. For example: llSetPos(llGetPos()+<1,0,0>); // move 1 unit in the x-direction. Rotations can be used in a similar way, but with a few important differences: rotations are less trivial to express on their own. One of the best ways of creating a rotation 'from scratch' is to use llAxisAngle2Rot() rotations are multiplied instead of added together. the order of multiplication matters. that last point can be confusing at first, but once you understand what each order does, it can be very useful: In LSL, when you multiply in the order orientation*change, you rotate around the world x,y,z axes (like you would see when editing an object with 'snap world' checked); when you multiply in the order change*orientation, you rotate around the object's intrinsic axes (like you would see when editing an object with 'snap local' checked) As a practical example, say you're scripting something like a turret that can aim up and down and move left and right. To aim up you might use something like llSetRot(llAxisAngle2Rot(<0,1,0>,-15*DEG_TO_RAD) * llGetRot() ); // apply local rotation on y axis to move the gun up around its y axis, independent of whatever direction it's facing, but to aim left/right you would use: llSetRot(llGetRot() * llAxisAngle2Rot(<0,0,1>, 15* DEG_TO_RAD) ); // apply global rotation on z axis Of course, for an actual turret, you might want to apply the rotations to different links, but the same principals apply.
  9. It shouldn't be impossible to do what you're looking for, or even particularly difficult, but yeah, there's really no telling what no-mod scripts might be doing. you'd probably need/want something written from scratch. I would actually recommend 3 prims, the first or "root" prim defines the center of rotation for llTargetOmega(). if an avatar sits on the root prim while it's spinning and the sit-target doesn't have a large offset, they will spin in place like a balerina, which doesn't sound like what you want. You can of course set a different offset in the script, but for things like this, I usually find it's easier to change the position and rotation of a prim than to get your head around the numbers in the script.
  10. The 'correct' solution is to add extra prims to your object, one for each person who is going to sit on it, and then use llLinkSitTarget() to set a sit target for each of the prims, for example: default { state_entry() { // optionally prevent avatars from sitting on the root prim rather than designated seats: llSetLinkPrimitiveParamsFast(1,[SCRIPTED_SIT_ONLY,TRUE]); llLinkSitTarget(2, <0,0,0.1>, ZERO_ROTATION); llLinkSitTarget(3, <0,0,0.1>, ZERO_ROTATION); // if more sit target prims, repeat similarly. . . } } then, when sitting on the link, avatars will sit with an orientation and position determined by the rotation and position of the new prims. editing the prims while an avatar is seated on it will NOT adjust the seated avatar, to make adjustments with this method, the avatar has to stand up and sit back down after any change. -- A less correct solution would be to make sure you are 'outside' (not within the convex hull of some mesh or prim) and make your single prim something relatively large that 'looks like' it has room for more than one person to sit on. Sitting without designated sit-targets is possible, but IMO rather fiddly.
  11. As far as I know, the only way to set the default attach point is to actually attach to an avatar. Closest thing would be to llAttachToAvatar (NOT the temp version, which would destroy the object) then llDetachFromAvatar immediately after attached in the attach() event. Unfortunately it is also impossible to 'drop' (detach, then rez self on ground) an object via script. <technical meandering> It's probable that 'default attach point' is a property of inventory assets, and not the actual objects themselves, which would mean setting it without it being attached would be basically impossible to implement. </technical meandering>
  12. This was kinda fun to think through. integer within_hull(vector test, list points) { integer ind_a= 0; integer ind_b= 1; integer ind_c= 2; // indexes for 3 points from points. vector a = llList2Vector(points,ind_a); vector b = llList2Vector(points,ind_b); vector c = llList2Vector(points,ind_c); integer len = llGetListLength(points); // for all pairs of 3 points a,b,c: while(ind_c<len) { vector normal = (b-a)%(c-a); integer side = (test-a)*normal >0; // on which side of the plane defined by a,b,c is test? integer outside = TRUE; //early return variable. integer ind_p = len; // for each other point p: while(~--ind_p) { if(ind_p!=ind_a && ind_p!=ind_b && ind_p!=ind_c) { vector p = llList2Vector(points,ind_p); if( (((p-a)*normal)>0) != side) { //llOwnerSay("point del"); // p is on opposite side from test: // remove it from list. points = llDeleteSubList(points,ind_p,ind_p); // fix indexes! --len; if(ind_c>ind_p) --ind_c; if(ind_b>ind_p) --ind_b; if(ind_a>ind_p) --ind_a; }else { // it is possible test is within points: outside = FALSE; } } } if(outside) // there were no points on the same side of a,b,c as test, therefore it is impossible it is within the cloud: { return FALSE; } // set indexes for next loop: if((ind_a+1)<ind_b) { a = llList2Vector(points,++ind_a); }else { a = llList2Vector(points,ind_a=0); if((ind_b+1)<ind_c) { b = llList2Vector(points,++ind_b); }else { b = llList2Vector(points,ind_b=1); c = llList2Vector(points,++ind_c); } } //llOwnerSay("Debug: "+llList2CSV([ind_a,ind_b,ind_c])); } // either the initial point list had fewer than 4 points, or test is within the convex hull: return TRUE; } default { touch_start(integer total_number) { // for debug, determine if this object is within the convex hull of all nearby objects named "Test Point" llSensor("Test Point","",PASSIVE,7.0,PI); } sensor(integer n) { llOwnerSay("Found "+(string)n+" test points."); list points; while(~--n) { points+=llDetectedPos(n); } integer inside = within_hull(llGetPos(),points); if(inside) { llOwnerSay("Within hull!"); }else { llOwnerSay("Out of bounds!"); } } } I'm pretty sure it works, but I didn't test it super rigorously.
  13. As long as we're bringing up the dead, you can also do it with a media face. Media 'knows' where you're touching if you've touched it once to let it grab your mouse. I know I posted a demo long time passing. . . but easier to find it in my inventory than on the forums so. . . Too complicated for a simple use-case like in the OP, but it's a fun proof-of-concept.
  14. Not to toot my own horn, but the tv script I wrote (see above) is a minimally viable example of doing exactly that (pause/restart, or skip back/forward all resync everyone.). As for how to do that with any other specific product. . . do they have a support group or anything?
  15. Something something, scripting forum isn't the place to ask for custom scripts etc. etc. but I was bored, so. . . (quote reduces spaminess)
  16. Since I haven't read the movie or watched the book in years, I looked it up. The Harry potter wiki says: On its face, seems like a rather simple idea, but there are a lot of fiddly nuances depending on exactly how you'd want it to work. I don't know of anywhere in-world that would magically have exactly what you're looking for.
  17. AVsitter uses notecards to store pose information; in the case of things that advertise 1000+ animations, that can take a lot of time to read in and process.
  18. llGetRegionList returns up to 100 avatars, in no sensible order; Sensor only up to 20 or so, and sorted by distance. In the (extremely unlikely) case that there are over 100 agents in the region, you may fail to find one even if it's right in front of you.
  19. not directly, you have to do math, but assuming the object has a flat face (like a cube), with sane texture mapping, the math wouldn't be too bad. for your use-case (I'm envisioning something like a dartboard) just converting the region coordinates to object coordinates should be sufficient? (hit_pos-object_pos)/object_rotation; for a cube, could then divide that by half the object's scale, (component wise, <a.x/b.x, a.y/b.y, a.z/b.z> ) then the coordinate that is almost exactly +- 1.0 would tell you the face, and the other two coordinates the position on the face in coordinates ranging from -1 to +1 with 0,0 being the center.
  20. modulus by 0 (and maybe also 1?) has bitten me a few times. You could argue it's divide by zero in disguise, but it's a good disguise to look for.
  21. It's priority 1, which is extremely low. Whatever it is, it's very probably not going to suddenly mess up some other animation.
  22. using linkset data can greatly simplify remembering handles: Instead of: key gHandleRequestStat; // global variable //... later in some event: gHandleRequestStat=llReadKeyValue("my_stat"); //... dataserver(key ID,string value) { if(ID==gHandleRequestStat) { /*...*/ } } consider: llLinksetDataWrite("Handle:"+(string)llReadKeyValue("my_stat"),"read:my_stat"); //... dataserver(key ID,string data) { string request = llLinksetDataRead("Handle:"+(string)ID); // semi-important ETA: delete the stored key after use! llLinksetDataDelete("Handle:"+(string)ID); // also in 'real code', check request!="" for sanity. if(0==llSubStringIndex(request,"read:")) { string stat = llGetSubString(request,5,-1); // set stat to data }// ...else ... }
×
×
  • Create New...