Jump to content

Fenix Eldritch

Resident
  • Posts

    770
  • Joined

Everything posted by Fenix Eldritch

  1. Yes, very possible. Use a timer event to continually check the actual time with something like llWallclock. The llWallclock's wiki page gives an example on how to do this: checking the time every 60 seconds, which is sufficient for something operating across a daily schedule. Once you have the current time, perform some checks to determine if it falls within the 8 am to 4 pm range to be open, otherwise assume it's not and lock it. Since llWallclock returns the time in seconds since midnight, that actually makes the logic to check the time very easy - you just need to remember to work exclusively in seconds (for example: 4:00 am would be 14400 seconds since midnight). Locking can be accomplished by maintaining a global integer variable and setting the value TRUE or FALSE as appropriate. Then in the part of your code that reacts to user input (I would guess a touch_start event), first check the status of the global variable. If the value indicates the door is unlocked, proceed with the door action, else do nothing. Group overrides would be similar to the above. Assuming the object will be set to a group and you expect the overriding agents to have that same group active, then you can use llDetectedGroup to verify if they're the same. Then modify your lock checking logic to account for that as well. [Post redacted for clarity after thread merge]
  2. As you've already seen, attempting to use llgetOwnerKey on an incoming message from an object that just detached will not work, because the owner info is already lost. The function will just return the same key that was fed to it. From the caveats of llGetOwnrKey: So to add an extra layer of security to your message processing, you'll have to get creative with existing listen filters. A shared secret channel both objects know about is an obvious start. There are methods for generating a number based off of a supplied key, so your clothing and listener could use that formula and supply the same key (you, the owner). After that, you could try giving your objects a common naming convention and then have your listener inspect the incoming message's speaker's name to see if it fits your template. Similarly, you could do the same for the actual message itself. Depending on how your system works, you could have a separate listener just for the detaches, where your clothing objects broadcast the same detach message that the listener is explicitly listening for (meaning it would reject all other messages that aren't an exact match to what it expects. Also, it may be prudent to have your clothing attachments communicate their detach messages via llRegionSayTo, targeting their owner (i.e. you). Messages sent to avatars on non-public channels aren't seen by the viewer, but all worn scripted attachments listening on that channel can hear it. This would be a good way to ensure your clothing items are only talking to you (or your listener) and not sending their messages out for anyone who happens to be listening on the same channel to hear and potentially try to spoof.
  3. When debugging problems, one of the first things one does is to put additional llOwnerSay commands throughout the code to report the values of relevant variables. In this case, I wanted to report what the fetched sound name and i_playcounter were just before the code actually tries to play or preload a sound. As it turns out, the value of i_playcounter is going out of bounds: it increments to 6 when it should be staying within the range of 0 to 5. Your code gets the sound names by inventory index... so when you try to fetch an inventory item by the 6'th index, that won't exist. Change the two if statements in your timer event as instructed by the comments below if( i_playcounter > (total_wave_files ) ) //should be >= ... if(i_playcounter + waves_to_preload <= (total_wave_files )) //should be < As for skipping playing the first sound on each successive iteration, that I think is happening because of where you increment i_playecounter. You have that statement at the very end of your timer, outside any checks, so it will happen each and every time the timer goes off - which I don't think is what you want. Instead, move it up one scope level into the end of the else part of the timer's first if/else statement. That way, you only increment the counter if you just played a sound.
  4. Interestingly, this is in fact documented on the wiki page: And my op referred to the termination component not accepting this - but I called it the "condition" in following with the wiki's naming convention - but yeah it's interesting how the for statement seems to get this special case!
  5. A recent jira caught my eye calling attention to an (as far as I'm aware) undocumented feature in LSL: the initializer and incrementer components of the for-loop header can accept comma separated statements. I don't know much about this, but it's apparently a feature of C (though I'm having trouble searching for the correct terminology). integer a; integer b; integer c; for (a=0, b=1, c=2; a < 10; a++, b*=2, c--) { llOwnerSay(" A=" + (string)a + " B=" + (string)b + " C=" + (string)c ); } The above sample will compile in LSL and print out: A=0 B=1 C=2 A=1 B=2 C=1 A=2 B=4 C=0 A=3 B=8 C=-1 A=4 B=16 C=-2 A=5 B=32 C=-3 A=6 B=64 C=-4 A=7 B=128 C=-5 A=8 B=256 C=-6 A=9 B=512 C=-7 The condition segment of the loop header doesn't seem to accept similar comma separated statements - but that can easily be recreated with a more complex conditional in the first place. This might be obvious to more experienced coders, but thought it would be good to share this here regardless.
  6. Slight tangent, but that reminds me of a feature I'd been thinking of proposing. It's basically a LSL function that resolves a given UIR into a regular string so that it could be put into other elements that don't normally resolve UIRs, like hovertex for example. This could also be beneficial since a resolved URI still counts as the full url text for the purposes of string length. So getting just the resolved final text could be helpful in dense readout messages where the user doesn't care about clicking on the resulting URI text. Thoughts? Edit: I'm not sure it it's even feasible, given the local nature of the URI. I suppose the local result would need to transmitted back to the server to be serialized into a regular string?
  7. Dynamically referencing generic controls, no matter what the end user has configured locally on their viewer. This becomes very useful now that the viewer allows us to remap so many of the keybindings. An in-world product/tutorial can now accurately tell the user what key to use instead of assuming the classic "Press W to move forward" kind of deal.
  8. Ah the spacebar... or as I like to call it the "avatar handbrake". How silly of me to forget it. That does seem to be working more or less as what I would expect. Save for the extra label/prefix for the target control - I'm in agreement with Bleuhazenfurfle, it's a bit too verbose. I wouldn't mind an extra suffix to these URIs to add or suppress it.
  9. Ah that could be. My mind was focused on the basic keyboard inputs and forgot about the alternate auto walk to functionality and the like.
  10. At least, that was the intent when I filed the feature request... However looking at the listed URIs, a few of them seem odd if they are indeed following my suggestion. Like, what would "stop_moving" return? Some generic "release the held key" label?
  11. When you call llRequestAgentData with DATA_PAYINFO, the data returned will not be a "regular" integer number. Rather, it will be a bit field... which is still an integer, but it's treated differently from standard numbers.. Bit fields interpret the integer as a series of individual boolean flags, examining each raw bit in the data structure. Recall that a bit (binary digit) can only have two possible values: one or zero. 00000000 │└─PAYMENT_INFO_ON_FILE (0x01) └──PAYMENT_INFO_USED (0x02) The above is an example byte written out in binary (each digit is a single bit, eight in total). And the last two "bits" are labeled PAYMENT_INFO_ON_FILE and PAYMENT_INFO_USED, and their numerical values are listed next to them as well (they're written in hexadecimal, but for this explanation, treat them as if they were decimal numbers 1 and 2 respectively). PAYMENT_INFO_ON_FILE is a constant that has a value of 1. If we were to write that out in binary as a byte like the one above, it would look like this: PAYMENT_INFO_ON_FILE = 00000001 Similarly, PAYMENT_INFO_USED is a constant that has a value of 2. Written out in binary as a byte like the others above, it would look like this: PAYMENT_INFO_USED = 00000010 Did you notice the difference? 2 written in binary is "10" and 1 written in binary is "01" (for this demonstration, I'm padding the values here with leading zeros to be consistent). So what does 3 look like in binary? 00000011 Both bits are set: "11" is the binary representation of 3. So in the case of your avatar's payment info, you know that you have both PAYMENT_INFO_USED and PAYMENT_INFO_ON_FILE, which means the data you get from llRequestAgentInfo would look like this: 00000011 │└─PAYMENT_INFO_ON_FILE (0x01) └──PAYMENT_INFO_USED (0x02) The bit field has both bits set, indicating both flags are true. That binary "11", if interpreted as a regular integer would equal 3. That is the power of bit fields! The ability to efficiently store a bunch of yes/no or TRUE/FALSE flags in a compact format. And since SL uses 32-bit integers, that means we can store 32 flags in a single integer. How to actually check what value you have in a given bit field generally involves bitwise operations using & or | with the bitfield and another number that serves as a bit mask. For example key query; default { state_entry() { query = llRequestAgentData(llGetOwner(), DATA_PAYINFO); } dataserver(key queryid, string data) { if ( query == queryid ) { integer x = (integer)data; if(x & PAYMENT_INFO_ON_FILE) //bitwise AND of the data and the mask PAYMENT_INFO_ON_FILE { llOwnerSay("onfile"); //only spoken if agent has pay info on file } if(x & PAYMENT_INFO_USED) //bitwise AND of the data and the mask PAYMENT_INFO_USED { llOwnerSay("used"); //only spoken if agent has their pay info used } } } } The above demonstrates how to check individual sections of a bit field. Recall how the PAYMENT_INFO_* constants are set to specific values... which are in fact the same as the binary representation where just one specific bit is set. This is a "mask" for the bit we wish to inspect. So doing a bitwise AND on this mask with the full bit field will evaluate to true if both those specific bits are set. We check each separately because it's possible for both bits to be set, one of them to be set, or none of them to be set. This is in contrast to your initial approach where you tried to see if the entire bit field was equal to one of the PAYMENT_INFO_* constants... which would only work if one or the other was set. But since both are, that's why you got the result to you did.
  12. The attach event will be called when you detach the object - though in that scenario, the id parameter will be NULL_KEY. And like Quistess says, you will have a very limited amount of time to do anything before it's derzzed back to inventory, so don't try to do anything complicated. Additionally, if the object was temp attached, it won't trigger the attach event on detach and will just delete itself immediately.
  13. Are we certain of this? Just because llGetAgentinfo returns a 32-bit integer bitfield, doesn't necessarily mean that's how the data is stored internally. For all we know, the function may simply be generating that for the return value and is instead reading the data from multiple other sources. It's possible that the function itself is working as intended, but whatever source it pulls from got corrupted on some accounts - hence support being able to rectify it on the reported account. Garbage in, garbage out as the saying goes. Edit: Also, AGENT_AUTOMATED is just a constant... a mask that can be applied to the bitfield returned by llGetAgentInfo. As you say, with a value of 0x4000, that means the 15'th bit (and only the 15'th bit) is set. So there is nothing wrong with the constant itself, because again, it's just a mask for checking the 15'th bit of any integer. As far as I'm aware, llGetAgentInfo doesn't use any of the AGENT_* constants for generating the returned bitfield. Rather, we as users utilize those constants to make sense of the bitfled ourselves. That's why I'm leaning more towards thinking the problem is per-account rather than anything with the function itself.
  14. It may be prudent to also file a support ticket for your affected accounts. It's possible that maybe there is some breakdown in communication under the hood between your dashboard and wherever llGetAgentInfo reads its data to generate the bitfiled it returns.
  15. Oh! That looks a lot like https://jira.secondlife.com/browse/BUG-233095 I hadn't quite figured out the true cause when I filed that, but Bleuhazenfurle's explanation makes a lot of sense. Especially since when I tried to reproduce it with a simpler script like NephilimSpark's, it didn't happen. I guess the string I tried storing wasn't splitting a unicode character on a block boundary by dumb luck. ETA: The workaround I did with my instance was to clear out the string after I was done with it. Perhaps you could do the same? Maybe clearing it on derez and repopulating it on rez or as needed?
  16. That's interesting... I recall reading that line, but never giving it much thought until now and pretty much defaulted to also assuming the select detection events only. But it definitely looks as Frionil explains. Here's a demo I threw together. It tests a two-deep function call from touch_start and a sensor event. The sensor will pick up anything in its short range. // Demo of calling llDetected* in user functions from detection events function1(integer n) { function2(n); } function2(integer n) { while(~--n) { string x = "Name: " +llDetectedName(n) +"\nKey: " +(string)llDetectedKey(n) +"\nPos: " +(string)llDetectedPos(n) +"\nRot: " +(string)llDetectedRot(n) +"\nGrab: " +(string)llDetectedGrab(n) +"\nGroup: " +(string)llDetectedGroup(n) +"\nLinkNo: " +(string)llDetectedLinkNumber(n) +"\nOwner: " +(string)llDetectedOwner(n) +"\nTouchBin: " +(string)llDetectedTouchBinormal(n) +"\nTouchFace: "+(string)llDetectedTouchFace(n) +"\nTouchNorm: "+(string)llDetectedTouchNormal(n) +"\nTouchPos: " +(string)llDetectedTouchPos(n) +"\nTouchST: " +(string)llDetectedTouchST(n) +"\nTouchUV: " +(string)llDetectedTouchUV(n) +"\nType: " +(string)llDetectedType(n) +"\nVel: " +(string)llDetectedVel(n); llOwnerSay(x+"\n "); } } default { touch_start(integer total_number) { llOwnerSay("touch_start detected function:"); function1(total_number); llSensor("","", AGENT|ACTIVE|PASSIVE, 3.0, PI); } sensor(integer num_detected) { llOwnerSay("sensor detected function: ("+(string)num_detected+")"); function1(num_detected); } }
  17. I made a few changes to the initial variables just to get a better idea of how this currently works at slower speeds and larger movement distances... since as written, the thing vibrates far too quickly over such a short distance for me to tell anything useful. vector startPos=<47, 91, 30>; //simply a more convienent start positon for where I was float rate = 2.0; float zdelta = 1.5; With the above changes, I observed that the object would oscillate up and then down from its starting position. This is the opposite of what you stated in your post... did you mean to say it the other way around? The dir variable (likely short for "direction") seems to indeed be responsible for controlling the direction the object will move in at any given time. These lines (and their comments in particular) indicate as such: dir = 1; // Forces first movement to be UP dir = -dir; //Reverse direction on subsequent moves. The comments align with what I am seeing. When dir=1, the object will move upwards from its start position. Negating the value of dir will change the direction, according to the comments. And if we look at where dir is actually used in the llTarget and llMovettoTarget functions, we see that it is simply multiplying itself with the xyz delta vector. That basically means when dir's value is negative 1, it will result in a negative delta vector, and thus opposite movement direction. So to reverse the behavior from what the script currently does, replace the three instances of dir=1 with dir=-1 Edit: I feel I should point out that if all you need this thing to do is move up and down, and not be knocked off course, you may want to consider trying keyframed motion instead of this type of physical movement. You would have much more control over it.
  18. llMessageLinked has been around since pretty much the beginning. I can find posts from the SL forums archive dating back to 2003 that reference the function: https://forums-archive.secondlife.com/8/39/7055/1.html
  19. Not quite, but almost. Your listen event looks good. Just make sure you have the necessary closing brackets "}" to properly terminate the listen event. Every opening bracket "{" must have a closing counterpart. And as currently written, you'd need one more to close out the listen event (at least from what I'm seeing from your post). Consistent indentation can really help visualize that. However your touch_start event now has a problem. It can't use the _i variable because that was only defined for the listen event. No other event knows about it and therefore cannot reference it. The thing is, you can use llDetectedKey(0) in a touch_start event, as I mentioned in my previous post. So your original code for that part was fine all along. Whether you're writing scripts yourself or modifying existing ones, it really does help to have a basic knowledge on how these things work. I would highly recommend reading through the LSL wiki's tutorials to get an nice introduction on the basics. These two are pretty good: https://wiki.secondlife.com/wiki/A_Basic_LSL_Tutorial (single page) https://wiki.secondlife.com/wiki/LSL_101/A_Gentle_Introduction (much longer, but quite in-depth and assumes no programming experience)
  20. They've intentionally omitted the full script, since they purchased it with full-perms from someone else. But it was there in the original version of the OP. @TheGreatWolfFenrir the "detected" category of functions only work in a subset of events: collision, collision_start, collision_end, sensor, touch, touch_start, touch_end. It won't work in a listen event. Instead, you can use the "_i" variable from the listen event handler which contains the key of the entity who spoke the triggering message.
  21. As per the caveats on llGiveInventoryList's wiki page, that function does not work with no-copy items. However, llGiveInventory will. The difference between them (among other things) is that this function works with a single inventory item as opposed to a list of them. So you could move the give function inside the loop that constructs the list and just piecemeal give out each item right there. Also, I would probably not post the script you purchased in full, as that kinda undercuts the creator's ability to sell future copies. Make sure they don't have some terms/conditions prohibiting you from reposting the script elsewhere.
  22. Yeah that's wild. I think I will at least report that and let LL figure it out. Thanks for shedding light on this mystery - it had perplexed me for a long, long time.
  23. Oh... OH! I see what's happening now: that appears to trigger when any tooltip is up. What gets injected at the cursor appears to be the first line(?) of whatever is in the tooltip. So if for example, my mouse is hovering over a string and I press tab, I'll get "String literal" inserted at the cursor. Just ran through a quick list of various things and it seems pretty consistent now. default Type: , Value: state state <target> state_entry state_entry() integer 32 bit integer value. float 32 bit floating point value. vector A vector is a data type that contains a set of three float values. rotation The rotation type is one of several ways to represent an orientation in 3D. quaternion The quaternion type is a left over from way back when LSL was created. It was later renamed to <rotation> to make it more user friendly, but it appears someone forgot to remove it ;-) list A collection of other data types. key A 128 bit unique identifier (UUID). string Text data. "string" String literal // Comment (single-line) /* */ Comment (multi-line) if if / else block else if / else block while while loop do do / while loop for for loop return Leave current event or function. jump jump statement ZERO_VECTOR Type: vector, Value: <0.0, 0.0, 0.0> So I guess the moral of the story is to watch where you park your mouse when pressing tab while writing code in the viewer. If a tooltip is rendering, you'll scoop up some of its text. On the fence as to whether I should write up a bug report... as it kinda doesn't seem intentional in my opinion....
  24. The other way I've seen LSL editor indentation glitch out is that sometimes when I try to indent with the tab key, it will paste a portion of the clipboard... or something else, I'm not entirely sure. Been meaning to try and nail down what is actually happening for a proper bug report.
×
×
  • Create New...