Jump to content

Helium Loon

Resident
  • Posts

    309
  • Joined

  • Last visited

Everything posted by Helium Loon

  1. For around $500 USD, you will not get a laptop with graphics capable of handling shadows/lighting and have it run good. You'll need at least a mid-range GPU to even begin to handle shadows/lighting well, and really need an enthusiast or gaming class GPU to do it right. Most laptops that have enthusiast/gaming GPUs run $900 USD or more. If you drop the shadows/lighting restriction, you can find some decent ones that will run SL well around that price. http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=5250511&CatId=4948 http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=631887&CatId=4938 http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=631879&CatId=4938 http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=6471592&CatId=4948 But it is going to be hard to find a decent GPU laptop in that price range. Good luck! (ETA last link, that refurb will almost do it with the lighting/shadows.....it has an nvidia 260 in it!)
  2. Leeza Catteneo wrote: I wonder why my ~5000 Tris item has a way higher PE than your 4000 Tris items =) BTW: Everything tested was not rigged and uploaded only in the highest LOD spot. All other 3 spots where set to NONE and are empty. That. When you put the other LODs to none, you lose all the benefits (and the PE savings) from having lower poly LODs. Each LOD should be made to be about 1/2 to 1/4 the number of polys of the next higher LOD (this maximizes the PE savings). So, to get the cheapest PE, your mesh should have a highest LOD of ~5000 tris, the next LOD should have ~1250 tris, the next should have ~315 tris, and the lowest LOD should have ~75 tris. Also, make sure to define the physics shape or as simply as possible (especially for attachments) since they'll be phantom anyway when attached. A simple 12 triangle box or even a 4 tri tetrahedron will do. This will also reduce the calculated PE.
  3. Yes, it looks like the problem is your loops. Link IDs start at 1 (for the root prim) and go up. Start your loops at 1, not 0. Also, you don't have to do all the funky string stuff (lists can be cast to strings directly): ...list primscale = [];list primpos = [];integer p = 1; // This gets us to start our loop at LINK_ROOT, not at unlinked!integer numprims = llGetNumberOfPrims();for(; p <= numprims; ++p){ primscale += llList2Vector(llGetLinkPrimitiveParams(p,[PRIM_SIZE]),0); primpos += llList2Vector(llGetLinkPrimitiveParams(p,[PRIM_POSITION]),0);}llOwnerSay("Output Positions = [" + (string)primpos + "]");llOwnerSay("Output Scales = [" + (string)primscale + "]");... Each element should be in order, so storing the link IDs isn't really necessary. BUT, remember that the lists index at ZERO, not 1. So llList2Vector(primscale,0) is the value for prim 1....not prim 0. Now that you have stored the initial scales & positions (save the above lists to globals somewhere instead of local variables), to restore them somewhere, just do: ...integer p = 1;integer numprims = llGetNumberOfPrims();for(; p <= numprims; ++p){ llSetLinkPrimitiveParamsFast(p,[PRIM_SIZE, llList2Vector(primscale,p-1), PRIM_POSITION, llList2Vector(primpos,p-1)]);}... If what you want is a script that when you click the object it goes back to it's initial position: list prim_sizes = [];list prim_positions = [];integer numprims;default{ state_entry() { integer p; numprims = llGetNumberOfPrims(); for(p=1; p <= numprims; ++p) { prim_sizes += llList2Vector(llGetLinkPrimitiveParams(p,[PRIM_SIZE]),0); prim_positions += llList2Vector(llGetLinkPrimitiveParams(p,[PRIM_POSITION]),0); } } touch_start(integer num_detected) { llOwnerSay("Touched! Reverting to initial position and size!"); integer p; for(p=1; p <= numprims; ++p) llSetLinkPrimitiveParamsFast(p, [PRIM_SIZE, llList2Vector(prim_sizes,p-1), PRIM_POSITION, llList2Vector(prim_positions, p-1)]); }} Now, this stores the values at rez/startup. From then on, whenever it is clicked on, it will revert the prims back to their original stored positions/sizes. Note, whenever the script is reset, it will re-store the current scale/position values!
  4. Hmmn.....it's basically just voxel rendering. Evidently they've worked out (supposedly) a way of reducing the data point clouds dynamically in real time based on distance. I also note they aren't animating any objects, everything was static. Maybe some mechanism for condensing the point cloud data dynamically. Hard to say, and they are being very tight lipped about it (aside from a small blurb at the bottom about it being some search algorithm.....) It has potential, obviously.....and if GPUs continue to get more powerful and sophisticated in handling floating-point calcs, we may see real-time raytracing become feasible for games, which would really make things look incredible. (note, there are already some simple ray-tracing game demos using high-end GPUs, so it isn't that much of a stretch.)
  5. Sorry if I was a bit too technical there, I wasn't sure what level you are at...... The content tab of the Cauldron object is it's "inventory". You can't put folders in there, just objects, notecards, textures, etc. The generic script you posted does all of its work in the touch_start() event. There are other events you can 'catch' when they happen. Some happen automatically, some happen when certain things occur (like touch_start() is called whenever someone touches the object the script is in.) So you would drop the various 'candy' objects into the cauldrons' content tab. Then, when your script calls integer num_objects = llGetInventoryNumber(INVENTORY_OBJECT); You get the number of 'objects' the cauldron has in it. You can then use string obj_name = llGetInventoryName(INVENTORY_OBJECT, rand_num); to get the 'name' of the object. "rand_num" is an integer between 0 and num_objects-1. So if num_objects is 5, rand_num could be 0,1,2,3, or 4. You can use the llFrand() function to generate a random number, as you can see in the generic giver script you posted. Now you know the object name, you can 'give' it to someone: llGiveInventory(to_who, obj_name); where "to_who" is the key of the person you want to give it to. Note, if the object in the Cauldron's content tab is no-copy, then it will give that copy to the person, and remove it from the Cauldron, so the next time there wouldn't be one to give! Now, a few additions to make the script a little more efficient. If we don't think the Cauldron's inventory (i.e., the content tab contents) is going to change, we don't need to worry about the changed() event. So we'll leave that off for now. We'll add the candy objects, and then reset the object so it starts up fresh on next rez. Then the script would be something like this: integer num_objects;// this is a 'global' variable. It isn't declared inside an event, function, or state....so it can be accessed from ANY // event, function or state in the script default{ // state_entry() is called whenever this state first starts up. state_entry() { num_objects = llGetInventoryNumber(INVENTORY_OBJECT); // we set this only once this way.... }// on_rez() is called whenever this object rezzes on_rez(integer rez_param) { llResetScript(); // this just insures we go through state_entry() each time // this object is rezzed. } // touch_start() is called whenever the object is touched by an avatar touch_start(integer num_touchers) { integer random_num = (integer)llFrand((float)num_objects); // This gives us a number from 0 to (num_objects - 1) string obj_name = llGetInventoryName(INVENTORY_OBJECT, random_num); // This gets the name of that object llGiveInventory(llDetectedKey(0), obj_name); // This gives that object to the first detected toucher. llSay(0, "Happy Halloween, " + llDetectedName(0) + "! Have some candy!"); // This just says something on the public channel so you know it did it! }} Now, in the above, I did it step-by-step, rather than combining things a bit (like in the example script you posted) and added a few comments on each step so you could see exactly what was being done. Now, a little explanation on the 'touch_start' events parameter.... Several events populate some information your script can access via a set of functions that all start with "llDetected", and are very useful. Many of these events handle MULTIPLE people at once. This is why the parameter for touch_start() and some others I labelled 'num_detected'......you could theoretically have 4 or 5 touches at essentially the same time. In which case, the number would be passed into the event via that parameter. That parameter is used in the various "llDetected" functions. So above, when I called to "llDetectedKey(0)", that gives me the key of the first touch detected in this event. If 'num_detected' was more than 1, then you really should call the same stuff in a loop over each.....which would look something like this: ... touch_start(integer num_detected) { integer i; for(i=0; i < num_detected; i++) { integer rand_num = (integer)llFrand((float)num_objects); string obj_name = llGetInventoryName(INVENTORY_OBJECT,rand_num); llGiveInventory(llDetectedKey(i), obj_name); llSay(0, llDetectedName(i) + " got some candy!"); } }... But generally, touches don't accumulate like that except in special cases, and you can just assume you'll only have num_detected is 1. Sensor() and other events you can't make that assumption though! Hopefully, this has helped explain how/why these things work.....if you have any questions, feel free to ask!
  6. As far as having the cauldron give out candy when touched, that's pretty simple. Just have the candy objects in the inventory of Cauldron. In the state_entry() or on_rez() event, build a list of the candy objects in the inventory (and possibly in the changed() event, if you want it to update dynamically.) Then, in the touch_start() event, have it do a llGiveInventory() and give a random entry from the list to the toucher. Now, as for the particles..... For smoke, I'd go with a cone pattern, that is wide, to start. If the min of something is less than the max, it automatically gets set to the max, as I recall. Might want to adjust those to more correct values. Then just experiment with other parameters.
  7. This is why multiple scripts within a single prim are usually constructed so that each prim handles only certain functionality.....such as animations, or sounds, or communications, etc. Then handle script messages (via llMessageLinked & the link_message events) to allow scripts that handle all the synchronizing and logic and dialogs to tell the other scripts what needs to be done at that moment. It can get pretty complicated pretty quickly. The more functionality you put in your scripts, the quicker you have to start doing things like this. Even with one-liners like Void comes up with can take up a good bit of memory server-side, and enough of them will eventually bump up against the limits. When that happens, you break the script down into two (or more) scripts that communicate what the other needs to handle. The communications has some overhead too, in each script. So use link messages, and keep your scripts as independant as possible!
  8. To put it in simple functional terms: Using a bitwise-AND (&) will only let those bits that are set in BOTH values appear in the result. This lets it be used to 'mask off' bits we aren't interested in (by putting zeros in those bits in our 'mask' value. Using a bitwise-OR (|) will set those bits that are in the 'mask' in the result, all others will be what was present in the other value. So if I had an integer, and I was only interested in the 2nd bit, I could do this: integer result = 0x02 & value; The 0x02 is the 'mask' (00000010b), and the only possible values for result are either 0 or 2. Say I wanted to SET some bits to a specific value.....as an example, I wanted to make sure the top bit (sign bit) of a 32-bit integer was set (no normal reason to do this, but as an example.) Then I could do this: integer result = value | 0x80000000; The 0x80000000 is our 'mask' (10000000000000000000000000000000b), and the top bit of the result will ALWAYS be set. In the example you gave, with a mask of 0x7F8, (0000011111111000b), you can see that by using a bitwise-AND, all the bits above the 11th, and the lowest 3 bits, will be zero. Whatever the other bits of the value was, will be present in the same positions in the result. So, as another example, say I wanted to put a value that was always between 0 and 12 together with a value that was always between 0 and 9, and store them as a single integer. Both will fit in 4 bits (can represent 0-15 in 4 bits), but are too big for 3 bits (can represent 0-7 in 3 bits.) We'll call the first one value1, and the second value2. integer compressed = (value2 << 4) & (value1); The << and >> operators are the left and right bitshift operators. They shift the bits in a value by the number of places specified. So in the above, value2 gets shifted left (up) by four places (by the way, this is the same as multiplying the value by 2 for each 'place' shifted....so in the above, it is effectively multiplied by 16.) Then we bitwise-AND the lower value with it (which, since it will always be below 13, means the low 4 bits will be the only ones which could be non-zero. Now, what if we want to extract those values back out? integer value1 = compressed & 0x0F;integer value2 = (compressed & 0xF0) >> 4; We 'mask' off the bits we want to pull out, and in the case of value2, we shift them back to their original position. Viola! Bitwise operators can be very handy, though you can go overboard with them. But they are very fast, compared to most math operations. When you need to multiply by a power of two, always shift instead.
  9. Nvidia GeForce FX5600 had a triangle rate of 100 MTri/s. That's about about 1/4the the rate of the GeForce FX6600. I can't even find info for a FX5400. The FX5200 had a rate of 81 MTri/s. So, if the 6600 could get a max of 70fps, I'd expect the 5600 to get about 20-25 fps maximum. With the memory limit (FX5600 had a max of 256MB VRAM), most SL scenes would be texture bound, more than triangle bound. Realize, as you go further and further back, the memory limits (due to textures) will overrun the render speed. If a card only has 256MB of RAM, and the scene you are rendering uses more than that in textures, it's having to reload textures from main memory every frame. Can make a big hit. There are other considerations.....render size (which is affected by pixel-fill rate) means more pixels for a given triangle in a frame. It also means more texels. Older cards don't scale up as well. There are other limits to the reported render speed in the 'statistics bar' that aren't representative of the actual rendering speed. If the viewer is busy calculating animations, switching texture coords, changing other things, and handling a lot of other stuff, even with multi-threaded rendering turned on you can get delays that have nothing to do with the full-on rendering speed. (I did mention this in my notes....though perhaps not explicitly enough!) For most purposes, I base realistic performance at about HALF of theoretical. So, I'd expect an nVidia GeForce FX5600 to get around 10-12 fps typically in SL. The FX6600 (the suggested minimum supported) would get around 35 fps. These are assuming you have a few additional things turned on, and running at a decent resolution. (I should note here, my older machine is running a GeForce FX7950 GTKO, and with custom High graphics settings in SL at 1680x1050 resolution, I'm still getting 30-40 fps. (as a note, the 7900 was rated at 1400 MTri/s, almost 4 times more powerful than the 6600....)
  10. Noe, while I agree (to an extent) the comparisons you are using are a little off. Comparing the CryEngine2 to the render pipeline in SL is a bit disengenious. Scenes for the CryEngine (and most game engines for FPS games) have to be pre-compiled and optimized. They don't change dynamically while playing (the terrain does not actually change, trees don't change position, etc....things can animate and such, but the definitions of the scene remain fixed) where the SL environment does. That said, I still agree with you. To wit: The nVidia GeForce MX 440 card from back in the old AGP8x days (a decade ago, and way below the 'minimum' requirements listed for SL), could T&L 34 MTri/s. So assuming very low graphics settings, such a card (with a 2.5MTri/s per region limit, which works out to an average of 167 tri/prim) would still deliver around 14 fps. (yes, this is simplified, as there are a lot of other factors....setup time before the T&L pipeline as well as cache changes would tend to push this down quite a bit.) Even half that (7 fps) is playable.....not very aestetically pleasing, but doable. And this is based on a card that is over a decade old. Now, the minimum suggested graphics is the same class as the nVidia 6600 (mid 2004 date, about 7 years old tech) which clocks in at around 375 MTri/s......That's 10 TIMES the performance. This means the MINIMUM suggested card, on low graphics settings in SL, should be getting 70+ FPS. (In fact, with the improvements in the setup pipeline and memory for cache, in general the performance will be much closer to the theoretical top......in this case, 150 fps.) Put simply, if you are running the minimum suggested GPU or better, you should be able to (with the graphics settings ALL THE WAY DOWN, except for draw-distance) get 60+ fps easily. They could triple the given 'max' triangle count in view and STILL not hurt frame rate enough to be an issue. (note: due to skinning, pixel-shaders, and more, these calculations are strictly theoretical maximums. But, as I said, this is the minimum suggested card on SL's own System Requirements page......you would not expect to get 70 fps on Ultra with a card that old and outdated.) Now, let's compare to a couple ol years later.....the nVidia GeForce 7600GT GO (yes, that's right, an integrated mobile GPU.) It's rated for peak performance of 550 MTri/s. Almost 16 TIMES the performance of the old MX440, and almost 1.5 times the performance of the 6600 series. And it's a MOBILE GPU. The current 'triangle budgets' are woefully outdated. I would consider a 15 fps render rate to be the baseline. For the 6600 series, that would translate (at peak) to 25 MTris in view. Assume it for the whole region. That's still 10 TIMES the current budget. Either there are render cost we aren't being told about (which could reduce it considerably), or the server costs for physics are completely overblowing the rendering speed. If that's the case, they need to invest in some nvidia physX cards for the servers and take some of that physics load OFF the CPUs. Yeah, it'd be a major re-write (unless the utilized Havok version supports it directly) but the benefits to the visual quality budget would be enormous. If we look at a midrange card (GeForce GT450, multiple kinds available at newegg for $100-$150), then the vertex rate (they stopped rating tri/s a long time ago) is about 37600 MVtx/s (which would work out to around 12800 MTri/s)......assuming a peak rate, at 60 fps, that gives us 213 MTri per region.....about 75 TIMES what the budget is. Note again, I haven't touched gamer/enthusiast cards......this has all been mid range and below. And, I've used peak ratings for the most part. Even given all that....with the minimum suggested system requirements GPU, the 'triangle budget' they are basing these calcluations off of is woefully outdated. If they are basing it off of physics, they need to realize that most physics shapes will be optimized and less complex, so the budget relationship should be a LOT higher than it is currently. Penalize heavy physics cost (since that is server side), but don't limit static, simple, optimized meshes the same heavy-handed way.
  11. The W coordinate from UVW textures really goes back to the old days of 3D rendering..... In order to speed up the code (and simplify the data structures), the programmers often re-used the 'vertex' structure for holding UV texture info (rather than create a new structure that only held two floating point values. Since it had a third parameter, it gave them a way to hold an extra bit of data for whatever they might need it for. And if they kept it at zero, most of the standard vertex functions that might be used (and defined in a 'vertex' object, like distance, etc.) will work on the texture space as well. Later, when volumetric textures and procedural textures were developed, the W parameter became an additional dimension, allowing for textures which changed based on the W parameter. This was also used heavily in ray-tracing and other graphics where objects were solid (and lend themselves to procedural texturing well), instead of polygonal.
  12. Knowing the list length isn't an issue, since it is available using llGetListLength(list). The typical way of doing this is already laid out in the wiki as an example function from the LSL_List page, though you'd have to alter it to use an index instead of 'searching' the list for a match (which isn't hard.) ListItemReplace function If you want to have it do something other than strings, you can change the function parameters to utilize another type, or even generalize the function by extending it to take in an integer that is the return from a llGetListEntryType() call, and use that to convert the input 'newvalue' to the correct type.
  13. The problem is your dialog button labels are too long. As an example: list buttons = [ "this label is much too long for the dialog button", "this is ok" ];default{ state_entry() { llListen(-123, "", NULL_KEY, ""); } touch_start(integer num_detected) { llDialog(llDetectedKey(0), "Dialog Test!", buttons, -123); }} This will generate the error you are getting, because the first button is over 24 characters long. Try something like this instead: list buttons = [ "this label is much too long for the dialog button", "this is ok" ];list buttons_truncated;default{ state_entry() { llListen(-123, "", NULL_KEY, ""); for(i=0; i < llGetListLength(buttons); ++i) buttons_truncated += [ llGetSubString(llList2String(buttons,0),0,23) ]; } touch_start(integer num_detected) { llDialog(llDetectedKey(0), "Dialog Test!", buttons_truncated, -123); }} which uses llGetSubString() to truncate each element to 24 characters in length and adds it to a new list, that is used in the llDialog() function.
  14. Japanese kanji were imported from china during the Heian period (IIRC). So yes, they look virtually identical. That kanji is 夢, which can be pronounced as either "mu" (む) or as "yume" (ゆめ, pronounced "yuu-meh") in japanese. It means "a dream, a vision, or an illusion."
  15. @Void: Absolutely correct. Time is the zeroth dimension; Any object needing to exist in one or more dimensions must have time to exist in. I'm so happy a few others have figured this out too.... :matte-motes-sunglasses-1: ...though I'd argue the unidirectional requirement for time. Personally I describe time as separate, but not quite so limited, as a 'dimension'. Time is actually an n-dimensional volume where discrete potential outcomes split from each previous result. Hence, all possible eventualities do exist, simultaneously. Time paradox is eliminated, and the only question then becomes how does one travel ACROSS time, as well as up/down it....... @OP: We actually have quite a few dimensions we are building in in SL.....a 'dimension' is simply an independant quantifiable quality an object can possess. Height, width, depth....but also color, glow, twist, cut, and more are also dimensions within the qualities that define a 'prim'.
  16. If you have a close approximation to the total sound length of the elements, llSetSoundQueueing() may be the simplest way to get it to work, like you said. Although it only allows two sounds queued currently (there is a JIRA in place to increase the queue depth), if one does like this (this assumes the sounds are at least several seconds long each....) llPreloadSound("Sound1"); llPreloadSound("Sound2"); llSetSoundQueueing(TRUE); llPlaySound("Sound1",1.0); llPlaySound("Sound2",1.0); llSetTimerEvent(sound1duration+sound2duration-0.5); Then in the timer() event, have it play the next sound in sequence and set the timer to the next duration. That way, the queue should always have room for the next sound, and each should start immediately after the prior one. If this is what you are already doing, and you are still getting issues, you'll probably just have to use your own sounds that you create to specific durations you know precisely. And you may still get issues as timers are affected by sim time dilation.....
  17. Nope, no additional rotations. However, I had forgotten about being able to restrict the rotations....that may be an interim fix, though I'd still like to find an answer to WHY it is happening.....
  18. I tried unlinking all the prims (only 6), and everything is set to the default (ZERO_ROTATION). There aren't any rotations set beyond the ZERO_ROTATION that is passed in during the llRezObject(). After the physics/buoyancy are set, it rotates OFF from zero. I can't find any explanations. All the prims (including the root prim) in the linkset are all set to zero rotation. I don't think the sit target is affecting it. I've tried modifying the sit target location, and it doesn't seem to have any effect on the rotation it ends up at.
  19. I've run into a problem, and it's only half-scripting related..... I've got a multi-prim object that is being rezzed by another. After it is rezzed, I set it physical, and set buoyancy up. Everything works fine....except it rotates to an odd angle. I've tried everything to get it to rotate to a normal angle, but it seems determined to go to that angle as it's 'default' rotation.....and I've tried adjusting it from a manual rez and putting a new copy into the rezzing object, but no go. Any ideas on what could be causing it, or how to fix it?
  20. PeterCanessa Oh wrote: Not so Helium. All child prims in a link-set have the same, root, parent. You cannot have a 'heirarchy of prims' - just root and children. As Winter said, if you want to move/change only 'some' child prims you have to address them individually. It may be possible to do that quickly enough using llSetLinkPrimitiveParamsFast() but for any realistic number of child prims there will be a visible delay between the first and last moving. If there are fewer prims in the 'base' than the 'wheel' it may be more effective to move the whole thing and then move each base-prim back to their original position, rather than moving each wheel-prim. The same visual delay is likely though, unfortunately. You are absolutely right, Peter. I stand corrected.....and somewhat dismayed. That's a shortcut in the rendering/building pipeline that shouldn't have been taken, IMO. Virtually all rendering engines support heirarchical linking for animation purposes......why would LL have deliberately taken a shortcut there? The storage cost per prim? That doesn't hold up, since link numbers (due to limits) for children don't add up to that many bytes. Seems strange to me. The computations for rotations? That doesn't really hold up either, since those matrix ops have been highly optimized over the years.....I really do wonder why they did that. The only reason I could possibly fathom was the database retrieval and parsing of objects would be simplified by having a single root with all other prims being children of that root. Oh well.....means a few designs I have in my head simply won't work now. I'll have to figure out some workarounds.....or wait for mesh to go live.
  21. However, rotating the 'wheel' of the build is possible. The base could be a heirarchy of prims, with an 'axle' as the single prim that links between it and the 'wheel' prims (which would allow it to form a heirarchical chain of prims, maintaining the single-parent-to-any-number-of-children rule. The script can then rotate THAT prim (requires some additional math work, since you have to calculate the rotations about the child, not the root) and the prims that are children of it will move with it as desired.
  22. Sorry, but as far as I know, any single prim can have only one prim as a parent. Even if you were to link a bunch together as a single object, it still has a root. If you select that object, then another prim, and link them, the root prim of the multi-prim object is the 'prim' selected in that object....and is what the other gets linked to. Linking is a parent-child relationship between two prims. Each prim can have one parent, but can have many child prims. This allows heirarchies to be built....but one child prim cannot have two parent prims.
  23. I use something similar to the 'getLinkNum' function.....along with a couple of variations (that use llGetSubString) to match based on the prim name starting with or ending with a certain string, and returning a list of all matching prim numbers. list GetLinkNumsByStart(string s){ integer i; list t = []; for(i=0; i < llGetNumberOfPrims(); ++i) if(llGetSubString(llGetLinkName(i),0,llStringLength(s)-1) == s) t+=[i]; return t;} The GetLinkNumsByEnd(string s) function is the same, only it uses indexes on the llGetSubString() from -(llStringLength(s)) to -1. With careful naming of prims, you can easily control whole sets pretty easily. And you only have to run the functions once (unless you are linking/unlinking prims in script too....) after rez to fill in the lists. It works for full names too, but you have to pull out the single list element (an extra step, if you don't need the list capability.)
  24. Unfortunately, LSL isn't a full programming language......it's simply a scripting language, and it's functionality is limited to what LL decides to expose, as well as the event-driven nature of the design. #include would be nice, however it has its own problems....LSL isn't an optimizing compiler....so any functions you '#include'd would always appear in the resulting compiled code, even if they were never called in the script. So a large library would typically eat up memory while only providing a very few functions that get used. I try to keep a 'library' file of useful routines on my personal box, and when I need one of those functions in a script, I C&P it into it. Keeps things from getting bloated. I also occasionally go through those functions to try to optimize them as much as possible (both from memory usage and speed). There are considerably more pressing issues concerning LSL, even in my mind......I'd still like to see a 'llDialogOrdinal() ' function that returns the INDEX of the button pressed, and not its text. Numeric comparisons are a LOT more efficient than string comparisons unless you carefully choose your strings (which isn't always an option.) It is possible to put together a 'library' script with useful functions that can be called via chats or link messages with a well-defined API so that you could just drop that script into the object, and write your other code to send and receive the data for the functions......but it wouldn't be synchronous, as others have mentioned.
  25. Sorry about those errors.....I was posting from work, several interruptions, and no chance to proof it. Glad you got it working though. And as many others have already noted, FOR() loops may be marginally slower, but in a simple loop like this, the savings of going with a WHILE() isn't really worth the potential issues with different list lengths.
×
×
  • Create New...