Jump to content

Wulfie Reanimator

Resident
  • Posts

    5,752
  • Joined

Everything posted by Wulfie Reanimator

  1. Read the link. You have to replace part of the link with the animation's UUID that you can copy from your inventory. For example, and this is an animation I created: http://asset-cdn.glb.agni.lindenlab.com/?animatn_id=21bbda13-f47a-e080-3f8a-d5a88c68167e P.S. Pointing out this url is kind of questionable, since animation UUIDs are very easily seen in-viewer even if you don't own them. Edit: Or I guess not. The downloaded file is 1 KB, so it's not valid.
  2. The "backend" is the "plugins and settings" panel for the forum as a whole. Regular moderators on our forum don't have access to fiddle with how the forum generally functions. And even if we could, we wouldn't, because it shouldn't be up to the whims of a single moderator which features are enabled at any moment. Things like that would be discussed as a group, and changes would be made only if a positive consensus was made. You are sort of correct in that "if LL wanted to do it, they would've done it already." Maybe the necroposting hasn't been a big enough issue from their perspective. My observations of how the Lindens moderate could indicate many reasons why certain decisions are/aren't made.
  3. No, I'm not part of the web team that maintains the backend.
  4. This one does for a fact. I'm a moderator on another forum with the same software.
  5. There are a bunch of forums that auto-lock threads due to age. It takes zero manpower. Especially with prepackaged forum software like this forum, it's a matter of changing a setting.
  6. Well, if this is what you want then there is a function called llSetScriptState. It can turn on/off other scripts in the object's inventory. This would work as a toggle for another script (even if it uses an infinite loop like yours), for example: string script_name = "this must exist"; integer status = TRUE; default { touch_start(integer n) { llSetScriptState(script_name, status = !status); } }
  7. Let's just say "the fourth dimension" to keep it simple. (It's not actually a rotation in 4D space, but it might as well be.) Here's a little "visualization" (kind of): default { state_entry() { rotation direction = llGetRot(); // original rotation, "quaternion" llOwnerSay("rotation: " + (string)direction); vector euler = llRot2Euler(direction); // converted to "euler angles" llOwnerSay("euler: " + (string)euler); vector degrees = euler * RAD_TO_DEG; // convert "radians to degrees" llOwnerSay("degrees: " + (string)degrees); } } If I put this script into an object that is rotated (in the edit window) like: X = 0, Y = 0, Z = 90 The output from the script is: rotation: <0.00000, 0.00000, 0.70711, 0.70711> euler: <0.00000, 0.00000, 1.57080> degrees: <0.00000, 0.00000, 90.00000> For X = 0, Y = 0, Z = 270 (or Z = -90): rotation: <-0.00000, 0.00000, -0.70711, 0.70711> euler: <0.00000, 0.00000, -1.57080> degrees: <0.00000, 0.00000, -90.00000> So there's also your answer I guess, if you really want to stick to "real" rotations and bang your head again later. A much simpler way to set the rotation to something you actually want goes something like this... vector degrees = <0, 0, 270>; // convert degrees back to radians rotation direction = llEuler2Rot(degrees * DEG_TO_RAD); llSetRot(direction); vector degrees = <0, 0, 270>; llSetRot(llEuler2Rot(degrees * DEG_TO_RAD)); llSetRot(llEuler2Rot(<0, 0, 270> * DEG_TO_RAD)); (They all do exactly the same thing, pick the one you prefer and put it anywhere in the script where rotation needs to be set.) P.S. I'm online inworld in case you want personal help.
  8. If you can't edit the script, you'll just need a new one. If you can, the change should be trivial (unless the "floating" happens within an infinite loop). Either way, we'd have to see the script to be able to tell what the exact course of action should be.
  9. This simply requires a seamless texture. The "edge" you are seeing is the seam. Don't confuse "seamless" with those random/repeating textures usually used for surfaces like the ground, walls, etc. A nature/cityscape background can also be made repeating/seamless on the sides (but obviously not top and bottom).
  10. I can explain this in much greater detail and even help you inworld once I get home (very soon), but in short, "rotation" in LSL is also known as a quaternion. They are Infamously mind-bending to use directly to describe a specific rotation (besides 90 degree increments), so it is better to use a regular "vector" with 3 values instead if you wanted to define a set rotation. We'd also need to know what the "upright" rotation is, among other minor details.
  11. Because the diamonds are probably pretty small (certainly not even 0.5 meters on any side), you can and should use a smaller texture, like 512x512 or even 256x256. The reason for this is because having a larger texture will take up more video memory in each user's own viewer -- which you don't have an infinite amount of -- and the texture is going to take up a tiny amount of space on their screen, so there is no benefit to using a larger texture as all the details in it will be simply lost to distance. As for the UV thing, it really depends on what you want to do, and there are no wrong answers. There is no Land Impact penalty between the two options, and LI doesn't matter for attachments anyway. (There is no maximum LI limit to them.)
  12. But to be fair, I don't think there's any harm in announcing those that are registered.
  13. Every object in SL is going to have its own UV map, even if they are all laid out identically. That said, you should always have matching UVs whenever possible, because it makes it the easiest to create multiple textures that will also work for every other gem type. Just make sure you don't use 1024x1024 textures.
  14. Firstly, you need to post here: https://community.secondlife.com/forums/forum/312-inworld-employment/ Secondly, since you also linked these pictures in another thread and said they were by "another artist," you should just post a picture of whatever HUD you already have (and give a copy to the scripter) and list all of the features the HUD should have, unless you expect the scripter to create the HUD as well.
  15. The "Student/Brat/Prefect" are roles within a single group. OBJECT_GROUP_TAG returns a string (not UUID) which is the role title on an avatar. But you are quite right that an external server doesn't help in getting someone's active role, as LSL can do it without any.
  16. To clarify a little bit, Omega appliers can only work for bodies that follow the standard SL body UV map layout.
  17. They should all be kept together, but you can put them wherever you want the "light on" to happen. The other scripts you've seen, where the "stuff" happens before state_entry are either global variables or custom functions. Explaining these in wider context would take a bit of time and should probably be done in a different thread (or you can read the wiki pages on them). I also added some extra, general tips to my post.
  18. llSetPrimitiveParams has an equivalent llGetPrimitiveParams which does the opposite. Instead of applying a list of parameters, it gives (returns) a list of parameters. (wiki) Reading the wiki page for it is unfortunately not as neat, but if you follow the left-most side of the table (the "Parameter" column), you'll know what to type in for the llGetPrimitveParams list. Since you want to get the prim's color, see: list params = llGetPrimitiveParams([PRIM_COLOR, 0]); This gets the color of face 0 (first face). If you use ALL_SIDES instead, you get a bigger list with the colors of each face included. (Probably not needed if all faces are the same color.) So now you have the result stored in a list called "params". The list actually has two values, the color vector and the alpha. To get the color, you can use llList2Vector: list params = llGetPrimitiveParams([PRIM_COLOR, 0]); vector color = llList2Vector(params, 0); Again, this simply returns the first (0) item in the params list as a vector (a thing containing 3 float values). And now you can use the "color" variable for the llSetPrimitiveParams list to re-use that same color. list params = llGetPrimitiveParams([PRIM_COLOR, 0]); vector color = llList2Vector(params, 0); llSetPrimitiveParams([PRIM_POINT_LIGHT, TRUE, color, 1.0, 10.0, 0.75]); P.S. There are some things that are super helpful (even for me) to figure out how stuff works or what it looks like. llOwnerSay is by far my most used function, I use it a lot whenever I write scripts to make sure I don't make silly mistakes (as often). Everything you give to llOwnersay must be a string, though. You can change a value's type by typecasting it like this: vector color = llList2Vector(params, 0); llOwnerSay( (string)color ); And whenever I'm working with lists, I like seeing the entire list. There's a couple ways to do it, like these: list params = llGetPrimitiveParams([PRIM_COLOR, 0]); llOwnerSay( llList2CSV(params) ); // looks like: <1.000000, 1.000000, 1.000000>, 1.000000 llOwnerSay( llDumpList2String(params, "|") ); // looks like: <1.000000, 1.000000, 1.000000>|1.000000
  19. I didn't just read it, I wrote it and tested it. From scratch. It's certainly faster to write/test/read/understand/use than your example. (28 vs 739 lines)
  20. With just about 100 SLOC (yes I counted), here's a little thing I made (with questionable origins) back in 2014, last updated in 2018. I thought I already posted this here though, but couldn't find it. This obviously doesn't come with any songs, but you can get free and fullperm ones from here: https://marketplace.secondlife.com/p/Trotman-Music-Notecards/7297342 (The Trotman is NOT mine nor have I worked on it.) I'm gonna post the code below, but let's start with the user-manual first: // For reading the notecard: string notecardName; integer notecardLine; key notecardRequest; // For playing a song: list soundList = []; // all clips integer soundCurrent = 0; // current clip float soundDelay = 0; // timer until next clip float soundVolume = 1; // duh // For playing all songs: integer songAutoplay = 0; // move to next song when current one ends integer songCount = 0; // inventory notecard count, 0 is user manual! integer songCurrent = 0; // tracking for autoplay PlayNextSoundOrSong() { // Play next sound, then increment for the next clip. llPlaySound(llList2String(soundList, soundCurrent++), soundVolume); // If the next clip is past the end of the song.. if(soundCurrent >= llGetListLength(soundList)) { if(songAutoplay) // Start loading the next song. { LoadFromNotecard(++songCurrent); return; } else soundCurrent = 0; // Or loop the current song. } // Note: Preload is limited by distance and is somewhat unreliable. llPreloadSound(llList2String(soundList, soundCurrent)); } LoadFromNotecard(integer inventoryNum) { StopAndCleanUp(); // Range-validity check (Inventory is 0-based but 0 is the "info" notecard) if(inventoryNum >= llGetInventoryNumber(INVENTORY_NOTECARD)) inventoryNum = 1; else if(inventoryNum < 1) inventoryNum = llGetInventoryNumber(INVENTORY_NOTECARD)-1; songCurrent = inventoryNum; notecardName = llGetInventoryName(INVENTORY_NOTECARD, inventoryNum); notecardRequest = llGetNotecardLine(notecardName, notecardLine); llOwnerSay("Loading: "+ notecardName +" ("+ (string)inventoryNum +")"); } StopAndCleanUp() { llSetText("", <1,1,1>, 1); llSetTimerEvent(0); llStopSound(); soundList = []; soundCurrent = 0; notecardLine = 0; } default { state_entry() { StopAndCleanUp(); llListen(1, "", llGetOwner(), ""); songCount = llGetInventoryNumber(INVENTORY_NOTECARD)-1; // Allows up to 2 sounds be queued for play. (current and ONE awaiting to be played) // Prevents skipping when llPlaySound is used before the currently playing sound has ended. // The next sound (but only one) will always be kept queued. (adding more sounds to queue will be discarded) llSetSoundQueueing(TRUE); } dataserver(key current_query, string data) { if(data != EOF) // Read until End Of File { if(notecardLine) // Reading sound UUIDs. { // Start preloading the first sound already to avoid silence. if(notecardLine == 1) llPreloadSound(data); soundList += [data]; } else soundDelay = (float)data; // Reading the first line. (time) // Move onto the next line. notecardRequest = llGetNotecardLine(notecardName, ++notecardLine); } else // End of File { llSetTimerEvent(soundDelay - 0.01); llSetText(notecardName, <1,1,1>, 1.0); PlayNextSoundOrSong(); } } timer() { PlayNextSoundOrSong(); } listen(integer c, string n, key id, string m) { // Play a random song. if(m == "random") { LoadFromNotecard(llFloor(llFrand(llGetInventoryNumber(INVENTORY_NOTECARD)))); } // Play the n-th song, based on its position in the inventory. // This check MUST be done before the "play" check to avoid bugs. else if(llGetSubString(m,0,5) == "playid" || llGetSubString(m,0,5) == "songid") { string inputNumberStr = llGetSubString(m,7,-1); if(inputNumberStr != "0" && !(integer)inputNumberStr) { llOwnerSay("ID must be a number!"); return; } if((integer)inputNumberStr >= llGetInventoryNumber(INVENTORY_NOTECARD)) LoadFromNotecard(llGetInventoryNumber(INVENTORY_NOTECARD)-1); else LoadFromNotecard((integer)inputNumberStr); } // Play a specific song. else if(llGetSubString(m,0,3) == "play" || llGetSubString(m,0,3) == "song") { // Get the song name. (rest of the message) string inputName = llGetSubString(m,5,-1); // If the name is found in the object's inventory.. if(llGetInventoryType(inputName) == INVENTORY_NOTECARD) { StopAndCleanUp(); // Loop through inventory until a matching name is found. integer inventoryNum; while(llGetInventoryName(INVENTORY_NOTECARD, inventoryNum) != inputName) { ++inventoryNum; } songCurrent = inventoryNum; // Save the notecard name and start reading. notecardRequest = llGetNotecardLine(notecardName = inputName, notecardLine); llOwnerSay("Loading."); } else llOwnerSay("Invalid name!"); } // Play the next song. else if (llGetSubString(m, 0, 3) == "next") { LoadFromNotecard(++songCurrent); } // Play the last song. else if (llGetSubString(m, 0, 3) == "last") { LoadFromNotecard(--songCurrent); } // Stop the song. else if(m == "stop") { StopAndCleanUp(); } else if(llGetSubString(m,0,3) == "find") { string inputSearch = llGetSubString(m, 5, -1); list matches; llOwnerSay("Searching for songs with \"" + inputSearch + "\""); integer i = llGetInventoryNumber(INVENTORY_NOTECARD)-1; while(i--) { if(~llSubStringIndex(llGetInventoryName(INVENTORY_NOTECARD, i), inputSearch)) matches += llGetInventoryName(INVENTORY_NOTECARD, i); } llOwnerSay("Found: " + llList2CSV(matches)); } // Set the volume. else if(llGetSubString(m,0,2) == "vol") // New short chat command { // Check for old longer command to take volume value from the right place. // Get the value, divide to scale it roughly within the range of 0.0-1.0 if(llGetSubString(m,3,5) == "ume") // ┏━ Notice here soundVolume = (float)llGetSubString(m,7,-1)/100; else soundVolume = (float)llGetSubString(m,4,-1)/100; // Correct large numbers (only necessary for OwnerSay display) if(soundVolume > 1) soundVolume = 1; // Set the new volume. llAdjustSoundVolume(soundVolume); // Type-cast to integer to truncate decimals for cleaner display. llOwnerSay("Volume: "+ (string)((integer)(soundVolume*100)) +"%"); } // Toggle autoplay else if(llGetSubString(m,0,7) == "autoplay") { string inputState = llGetSubString(m,9,-1); // Set autoplay and display confirmation. if(inputState == "on") { songAutoplay = 1; llOwnerSay("Autoplay enabled."); } else if(inputState == "off") { songAutoplay = 0; llOwnerSay("Autoplay disabled."); } else llOwnerSay("Invalid command. (on/off)"); } else if(llGetSubString(m,0,3) == "help") { llOwnerSay("\nThere should also be an included \"info\" notecard in the contents!" + "\n\nCurrently usable chat commands:" + "\nrandom" + "\nfind [partial name]" + "\nplay [notecard name]" + "\nplayid [inventory number]" + "\nstop" + "\nautoplay [on/off]" + "\nvol [0-100]"); } } on_rez(integer param) { StopAndCleanUp(); } changed(integer change) { if(change & CHANGED_OWNER) llResetScript(); } }
  21. There is absolutely no need for you to use an external server for what you're asking. @Ruthven Willenov already answered your question with all of the essential info, but if you don't even know where to begin with his answer, it's probably better that you tried posting in the Wanted or Inworld Employment section so you could find a scripter willing to create exactly what you want. (We don't even know how your script is interacted with.) But in an attempt to undo yet another one of Steph's misleadings, here is an example of how you would check if an avatar is in a specific group before they can touch an object: // For example: key group = "0375a183-05f6-450d-f0db-888574fdeea8"; string group_tag = "Errorist"; default { touch_start(integer n) { // Get the touching avatar's group and tag. list info = llGetObjectDetails(llDetectedKey(0), [OBJECT_GROUP_TAG]); string avatar_tag = llList2String(info, 0); // (Fun fact: Avatar's group can be found through their attachments.) info = llGetAttachedList(llDetectedKey(0)); info = llGetObjectDetails(llList2Key(info, 0), [OBJECT_GROUP]); key avatar_group = llList2Key(info, 0); // If the avatar's group or tag is not correct, // don't let them touch the object. if( (avatar_group != group) || (avatar_tag != group_tag) ) { llOwnerSay("You must be displaying the group tag!"); return; } // Interaction as normal goes here. llOwnerSay("Welcome!"); } } Tadaa, no external servers! I also noticed that if the person has the "hide group title" setting enabled, the script will not detect their group tag even if it's "active." (P.S. For you script-savvy people, I don't like defaulting to llSameGroup because it requires the object containing this script to be set to a specific group. That's not an option in all cases, so I prefer checking attachments instead.)
  22. Now that everything important has been said: This isn't how it works though, right? You can't "win" in your own casino, because it's your own money you're winning.
  23. Hence why only mild. I can't prove one way or another and I'm not knowledgeable enough to look into it or make an educated guess.
×
×
  • Create New...