Jump to content

Fenix Eldritch

Resident
  • Posts

    769
  • Joined

Everything posted by Fenix Eldritch

  1. To enable it on a given script, look at the bottom of the script's editor window and you'll find a checkbox "Use Experience". When checked, it presents a dropdown menu listing all the experiences you are allowed to contribute to. Select the desired experience and save/recompile the script. To enable an experience on your land, Open the About Land window and in the Experiences tab, add it to the Allowed Experiences section. Here's the KB article as well:
  2. Be sure to read the documentation for the function over on the wiki: http://wiki.secondlife.com/wiki/LlGetNotecardLine llGetNotecardLine takes two parameters: a string which is the name of the notecard you want to read from, and an integer which specifies what line you wish to read. So yes, it can only read from one notecard at a time. If you want to read the from two different notecards, then you need two different calls to llGetNotecardLine, each one specifying a single target notecard. This also means if you're reading from two notecards to combine the data, that you will need to process two separate dataserver events. You'll need to structure your code to be able to handle that - and this is where the handle key returned by llGetNotecardLine becomes important. You will use that to determine which read has just happened. A very simple example, using your two notecards above (assume they are named "noteA" and "noteB" in the object's inventory: //Reading from notecard demo. //Owner will speak the line number they wish to have read. key readLineA; //handler to idenfify reads to noteA key readLineB; //handler to idenfify reads to noteB string output; default { state_entry() { llListen(0,"",llGetOwner(),""); //setup listen to drive demo. Say a number from 0 to 5 } listen(integer chan, string name, key id, string msg) { //when we hear a number 0-5, use that as a line number to read from both notecards readLineA = llGetNotecardLine("noteA",(integer)msg); readLineB = llGetNotecardLine("noteB",(integer)msg); } dataserver(key id, string data) { if(data == EOF) { llOwnerSay("no data, end of file"); return; } if(id == readLineA) // process first read { output = data; //initialize global variable } if(id == readLineB) // process second read and then output result { output += " " + data; //append to global variable llOwnerSay(output); //print combined output output = ""; //reset for next demo } } } In this example, we queue up two reads and then structure the dataserver event to be able to handle them both. In reality, the dataserver event will be invoked twice, so we use the handler keys to figure out what to do on each iteration.
  3. It depends on how your plush toy object is constructed... If the object is mesh and properly rigged, you can enable it to be an animesh object which allows it to use existing avatar animations. And yes, these kinds of animations are created outside of SL. Though you may be able to find a suitable one for sale on the marketplace or inworld. On the other hand, if the object is not rigged, then you won't be able to use conventional animations. If the object is comprised of multiple parts, (like one object for each limb, head, etc) then you can create a crude animation with a script - which would amount to a sequence of llSetPrimitiveParamsFast function calls which reposition and rotate each limb to create new poses for the figure, essentially creating your own frames of animation that way. Generally speaking, attachments that appear to walk with the avatar are commonly attached to the "Avatar Center" attachment point and positioned off to the side. This is done to avoid having other animations playing on the avatar affecting the walker attachment's position. You'll also want to have your script running a polling loop to continually check the status of the avatar (much like the older animation overrides). You want to know when the avatar is running/walking/flying/etc and when they are, you would have the plush toy perform complementary animations on itself (which would be one of the two discussed above).
  4. Click the top face twice. (And wait a couple seconds between each click) First click triggers the touch_start event which actually configures the top face to be prim media for the first time. You'll see the control bar hover over the face briefly and then fade away, but the media won't show yet. Second click actually enables the prim media face to be active and visible on your viewer. The face should become highlighted with a selection border and begin to load up whatever url was last set. Remember, once the prim media is configured, you and everyone who wants to see it must click on the prim media face for the first time to activate it for their view. It's common for creators to somehow label the face with instructions saying as much. To cycle to random images, click any other face on the prim besides the top face, as the prim media face will not relay further clicks on it to the script once the prim media is active. This awkwardness is due to my bare bones minimalist example: because the demo only contains a touch_start event, everything is driven by it. You could add a state_entry and another llSetPrimMedia in it to automatically configure the face for prim media when the script first starts. That would save you one click. But you'd still need to click on the media face at least once to enable it on your viewer.
  5. Ah yes, some additional caveats... First make sure your viewer preferences are set to enable the showing of media (many people have it disabled). In the official SL viewer you can find it in Preferences > Sound & Media > and ensure the "Enabled" checkbox for Media is on. Secondly, even with media enabled, you still need to click on the prim's media face in order to initialize the browser. My demo uses face 0, which would be the "top" face of a default cube. Click it and the media face should activate. THEN you need to click on any OTHER face on that prim to trigger the touch_start event and thus run the demo code. Any clicks to the media face on the prim get directed into the browser and are not seen by the script. If you want the picture change to happen automatically, you would want to use a timer event instead of a touch event. Edit: So after looking at it again, I see that in my attempt to write a minimalist example, I made it behave awkardly... Click the top face twice. The first click will run the touch_start event which sets up the face as media on a prim. THEN clicking the top face a second time will activate the browser in your viewer. After that, clicks to any other face on the prim will run the touch_start event and cycle the picture. Sorry about the confusion.
  6. A long time ago, the Lindens had set up an avatar parked outside one of the welcome area sandboxes and had its camera view being projected to a live stream on their site. I think the account was called "Video Linden" or something to that effect. Similarly, some time later I encountered an avatar with a prim cube over their head with the forward face being a live feed from their own webcam. It was an interesting sight. On the subject of mirrors, you can fake the effect of a mirror with clever use of projectors as seen here. But it only works for static scenery: you have to take a picture to use as a texture for the "reflection". There is also a trick where you can get a single perfect real-time mirror by using the region's water surface with appropriate graphics settings and water presets. An older example can be found here. Of course, since you're using the region's natural water, you have to orient everything around that. No too big of a deal for taking pictures, but if you want a scene that people can walk around in, it's going to be much more difficult.
  7. While you can construct a web page that randomly displays content using javascript, as others have suggested, it is also quite possible to do the random selection from within an LSL script and just point to a directory of images. Using your example, if the URL to your directory is "someserver.com/art-quotes/" and all of the files within follow the same naming scheme of "quote-X.jpg", then the only part that actually needs to change is the X portion of the filename. If they're just integers, you can easily use llFrand() to choose a random number within a range and construct the full url to the image with it. string url = "someserver.com/art-quotes/quote-"; integer img_count = 100; default { touch_start(integer total_number) { integer x = (integer)llFrand(img_count)+1; //random number of range 1 to img_count llSetPrimMediaParams(0, [ PRIM_MEDIA_CURRENT_URL, url + (string) x +".jpg" ]); } } A similar thing can be done for the artwork images. However, if you give both the art and quote files the same generic base name and only differentiated them by a number at the end, then you can use the above code for cover both at the same time. The only downside is that you lose some implicit descriptiveness about the file from the name.
  8. You've got the right idea with the sample script you found. It can be as simple as setting the prim to glow in the collision_start event, and removing the glow on collision_end. However, I've observed that for solid objects, the collision_end will trigger even if the avatar is still standing on top of it. One way around that is to make the object use llVolumeDetect. This make the object phantom, but still raises collision events. We want this because by making it volumeDetect, the avatar will pass through the object and not raise collision_end events prematurely. Also, I suspect you want to object to glow as long as at least one person still stands on it. For that, we need to set up a variable to keep track of how many people are currently colliding with it. We do this because if two people are colliding with the object, and one moves off it, that will raise a collision_end event and prematurely stop the glow. Below is a commented demo of one way to do this: integer count=0; //keep track of how many people currently coliding with object default { state_entry() { llVolumeDetect(TRUE); //makes object intangable, but will still trigger collision events } collision_start(integer num_detected) { count += num_detected; //colision started, so increment counter llSetPrimitiveParams([PRIM_GLOW, ALL_SIDES, 1.0]); //set glow } collision_end(integer num_detected) { count -= num_detected; //colliiosn stopped, decrement counter if(count <1) //if counter is less than 1, assume no one is colliding anymore { llSetPrimitiveParams([PRIM_GLOW, ALL_SIDES, 0]); //clear glow count = 0; //reset counter just in case it somehow became negative. } } } Edit1: Completely forgot to say, that by making this prim volumeDetect, you'll obviously need a second object to act as the floor to walk upon of there isn't one there already. Edit2: incrementing and decrementing the counter by num_detected is better as it covers the edge case if multiple people manage to start (or stop) colliding at the exact same time.
  9. I believe the script fails to compile because you have an extra curly brace "{" which is misplaced and confusing the compiler. Normally these are used to define scope for functions, states, or other flow control blocks of code. They must always be balanced - in other words every "{" must have a corresponding "}" to close it off. You have an extra one at line 55, right before the "listener = llListen(chan,"","","");" If you remove that, it should let your script compile. if (message == "Call On") { { chan = 0x80000000 | (integer)("0x"+(string)llGetOwner()); chan += offset ; chan = -chan; owner_key = llGetOwner(); owner = llGetDisplayName( owner_key ); } { listener = llListen(chan,"","",""); // <-- extra unbalanced "{" at start of line. Remove it. As a side note, the extra set of curly braces for the block of code just after the if statement above are not necessary, though they won't cause any compile time errors. You can leave them if you want, though it might be better to remove them and redo your indentation to make everything a little more easy to read and follow. I am assuming that code it intended to be within the if block, yes? Here's what I mean: if (message == "Call On") { chan = 0x80000000 | (integer)("0x"+(string)llGetOwner()); chan += offset ; chan = -chan; owner_key = llGetOwner(); owner = llGetDisplayName( owner_key ); listener = llListen(chan,"","",""); After that, you will have another problem that needs to be addressed. In your listen event, you cannot use llDetectedKey() to get the uuid for the avatar who clicked the object because the llDetected* functions only work in touch and collision and sensor events. You can however make use of the "id" parameter in the listen event handler. It will be populated with the uuid of the avatar who spoke the message that the script heard - and in this case, when the avatar clicks the dialog box button, they are effectively speaking to the object so it will get their uuid that way. toucher = llGetDisplayName( id ); llSay(0, toucher + " has called on " + owner );
  10. Reread the last two posts prior to your own. You were given a link to examples regarding llGetAgentList by Profaitchikenz. And Lucia gave you a link to the in-world employment forum if you instead want to commission someone to write the script for you.
  11. I assumed larger regions would be difficult to reconcile with all the scripted functions that expect a region to always be 256x256 horizontally. I do wonder though if a possible workaround would be to emulate the appearance of multiple adjacent 256x256 regions on a single SIM. For all outward appearances to users and scripts, it would look like a collection of connected traditional regions - but under the hood, they're all on the same SIM and the mechanism for transferring agents/objects between these virtual regions is streamlined since it's not actually transferring them to a different host. (Not trying to trivialize the undertaking it would be to set that up, just thinking out loud) I have a pipe dream of making a few games within SL like this that make heavy use of miniature vehicles and scaled terrain to simulate a larger play area. But one of the barriers that I'm facing is that the pilot's physics shape is larger than the vehicle itself. It would be so helpful if we could temporarily alter or disable a seated avatar's collision shape.
  12. Was going to say that I looked and wasn't able to reproduce your issue - but I am also only using the official SL viewer. As a side note, when you attempt to stop the anim, you don't need to call llSetTextureAnim(FALSE...) for each potential face being animated. Calling the function once with mode FALSE will stop the texture animation regardless of what face you specify in the function call.
  13. My first thought is to check if you are hitting the maximum number of allowed attachments. From the temp attachments page caveats:
  14. This seems like it would be a good use case for expanding llRequestInventoryData. At present it only returns info for landmark inventory assets, but I could see it being augmented to get frame count, framerate, priority, etc on animation assets.
  15. You can use llGetObjectDetails in conjunction with OBJECT_SERVER_COST, OBJECT_STREAMING_COST, and OBJECT_PHYSICS_COST to determine the land impact of an object. Of those three flags, the highest would represent the object's land impact. You can also limit touch access to just be the object's owner by putting a check at the beginning of the touch_start event which aborts if the uuid of the avatar who touched it isn't the owner. Something like if(llDetectedKey(0) != llGetOwner()) { return; } Computing the total land impact for an arbitrary volume of objects is considerably more complicated, but I suppose it might be possible, if some concessions are made.A major obstacle, as Qie points out, is that sensors only detect 16 things at a time. So you would have to perform multiple scans, likely with a somewhat small radius (perhaps half of the radius of your target volume), moving the sensor origin each time to hopefully have the best chance of scanning all potential objects. You'll also have to deal with filtering out objects that are not within your volume, and have also already been scanned and accounted for. Off the top of my head, I suppose you could structure your sensor event such that it first checks if the scanned object's position is within the bounding box of the house itself. The "isInPrim" user function on the wiki page for llGetBoundingBox would be useful for that, assuming the house itself is a complete linkset. Secondly, if the object is in the house's volume, check if the object's key is in a master list. If it already is, then we know we've already scanned it and can ignore it now. If it's not in the list, add it. Given the unknown number of objects, you may want to consider employing some compression on the keys, and this pack/unpack routine by Mollymews would be very useful. Given that approach, you would basically do the scan, move the senor a little and repeat all around the house's volume. It's not exact, and I don't know if it can guarantee it wouldn't miss some objects, given the 16 results limit per single scan. Eventually, when you feel you've run a sufficient amount of scans and built your master list of object uuids that are within the house's volume, do another loop to run though each entry in that list and calculate a running total of LI based on each object's highest OBJECT_*_COST from llGetObjectDetails.
  16. A general thing to consider is that you need to structure your code to accommodate the fact that events, like KT explains, are going to be processed start-to-finish before any other event will get a chance to run. With that in mind, the notion of creating a busy while-loop won't go well because the event in which the loop is running will never release execution, and thus never allow any other events (like the dataserver) to begin. Most of the time, scripts are going to be sitting idle, waiting for an event to trigger. So part of the process in LSL scripting is choosing the right events for the task - as well as where to place pertinent code. If you need to wait on information from an asynchronous event (like dataserver) then one way to do so would be by placing the remainder of your code in the dataserver event. Alternatively, if you really want to do something like a busy loop, then using a timer event to periodically check the status of global variables (which could be updated by other events) would be a safer approach.
  17. For what it's worth, this can be guarded against with PRIM_SCRIPTED_SIT_ONLY. Setting that on even one link in the set will prevent all further manual sit attempts on links which don't have a sit target defined (and also on those with sit targets where PRIM_SCRIPTED_STY_ONLY was also explicitly set to true). If PRIM_SCRIPTED_SIT_ONLY is set somewhere, and there are links which do have a sit target, are unoccupied, and aren't explicitly set to have PRIM_SCRIPTED_SIT_ONLY as true for that specific link, then the avatar can manually sit there and only there.
  18. Yes. The server would see multiple instances of the compiled script with the same uuid and thus would use mono's bytecode sharing feature. Even so, they each have their own runtime memory for state and variables. How exactly the server keeps them separate, I do not know, but it certainly does manage to do so. You can demonstrate this by rezzing a cube, creating a new script and supplying this code: integer count = 0; default { touch_start(integer total_number) { string name = llGetInventoryName(INVENTORY_SCRIPT, 0); if (name) // if it exists ... { key uuid = llGetInventoryKey(name); if (uuid) // if the uuid is valid ... llOwnerSay( "The UUID of '" + name + "' is " + (string) uuid); else // item was not full-perm llOwnerSay( "The UUID of '" + name + "' could not be determined"); } count++; llOwnerSay("This object has been clicked "+(string)count+" times"); } } Save it, then click the cube. It will speak the uuid of the script and how many times it's been clicked. For demonstration purposes, name this object something like "first". After clicking it a few more times, duplicate the object (Ctrl+D). Rename that new object to something like "second" and click on it. Notice that both objects report their scripts have the exact same uuid, but they maintain their own memory of how many times they've been clicked (with the second object starting fresh). Take a copy of the first object into your inventory, making sure to leave the original and duplicate still rezzed. Click on both still rezzed objects a few more times. Rename the copy you took into inventory to something like "third" and rez it. When clicked, this third object will also report its script having the same uuid as the other two. Since this was taken as a copy, its own memory will be a clone of the first at the time you took it into inventory. Finally, take a copy of the script from the first object (drag it to your inventory). Rez a new cube, name it "fourth" and drag the copy of the script into it. Clicking this object will report the script have the same uuid as the other scripts from before, though this will be initialized like when we used Ctrl+D to duplicate the first object. In all cases, each script retains its own block of memory for variables and thus is distinct from the others despite sharing the same script uuid and as such, the same bytecode. Edited to add: You can even drop multiple instances of the script from inventory into the same prim. When clicked, both scripts will run, each reporting the same uuid, but also each reporting their own number of clicks.
  19. A scripted object cannot directly reposition another discrete object. However, you can accomplish a similar effect if the two objects can communicate with each other. Basically, have your teleporter object send a message to the vehicle. When the vehicle hears that message, it will be the one who actually handles the repositioning to a different location within the region. The function llSetRegionPos can be used to move an object to any valid position within a region - providing the object does not have physics enabled. So upon receiving the signal from the teleporter object, your vehicle would need to disable its physics, use llSetRegionPos, and then re-enable physics. This of course assumes you have edit access to the vehicles in question. If you don't have edit access then another option would be to construct a ferry of some sort to physically carry/push the vehicle to a new location. This would be a more cumbersome task though.
  20. If nothing else, I suppose having fewer list elements to process might be more efficient, if marginally in this case.
  21. You can't. All you can do is edit it to remove the contents and perhaps replace it with a "whoops, double post" message. And even then, we can only edit our messages for up to 24 hours after their initial posting. Speaking of which, the OP may want to amend their post as they reference llRand instead of presumably llRound. Regarding the topic at hand, I have in my notes a generic "rounding truncate to a specific precision for display" function that I picked up somewhere. I don't remember who originally wrote it, so I sadly cannot provide due credit. string fixedPrecision(float input, integer precision) { if((precision = (precision - 7 - (precision < 1))) & 0x80000000) //masking with 0x80000000 guards against negative index return llGetSubString((string)input, 0, precision); return (string)input; } Edit: it's actually truncation, not rounding.
  22. Yup, the function returns the size of the bounding box for the avatar's physics representation - which terminates at eye level and is where the camera is positioned in mouselook.
×
×
  • Create New...