Jump to content

Yingzi Xue

Resident
  • Posts

    259
  • Joined

  • Last visited

Everything posted by Yingzi Xue

  1. DerekShane wrote: Hi Yingzi, Exactly, debit permissions are granted by the object owner just when a game is rezzed; in the case of most games, that's for Freeplay or regular payin mode so perhaps the L$1 represents Freeplay when the game is expecting some sort of payment. I can't think of any game except Zyngo without that L$1 requirement. For 99% of games that currently exist, if they were covered by the Policy just because of the L$1 payin issue, Linden's now clarified that doesn't invalidate their Freeplay status. And yes about the clog, but that's how it's been forever. However, the new Transaction History window is more prone to crash with 20,000+ transactions per day than the old version and that's why the "Show L$1 Transactions" box to uncheck would be really helpful. Point was the reply from Linden is good news for a lot of players because more places will be able to have Freeplay games since they aren't covered by the Policy. There's been lots of progress, we're all working directly with Linden in our cases and not posting here much. Have a great weekend! If it became such an issue for me, as a game operator, I would get with the creators and ask them to make a non-pay version so your transaction history isn't overloaded with data you don't care to see. The fact that they didn't consider it is just mind boggling to me. I think it's great that this clarification was made. I'm sure it puts a lot of minds at ease. You have a great weekend as well.
  2. Innula Zenovka wrote: Yingzi Xue wrote: Phil Deakins wrote: Yes, I know that, if an object is to take money, it still needs permission to pay out from the owner's account. That's because it will need to give money to the user if s/he either pays too much or too little. Normally, you try to set exact amount(s) for the pay window (llSetPayPrice) when possible, which keeps this from happening. I agree. I will not, in fact, on principle script vendors that offer automatic refunds, because I regard it as too risky. Instead, as you suggest, I set the exact amount in the pay window and, if the customer somehow manages to pay the wrong amount, the script tells them to contact the vendor's owner for a refund. That's because if someone actually does manage to pay the wrong amount using a pay window with one option button and no entry box, they're almost certainly using an exploit that used to enable them to obtain refunds to which they're not entitled (I don't know if the exploit still works, but it doesn't seen worth taking chances). I've only once known someone to manage to pay vendors I've made the wrong price, when someone paid several different vendors L$1 each, when the selling price of each item was several hundred L$. For some reason this person didn't ask for their money back. It would be interesting to know what allowed them to pay a wrong amount. If you can't keep fraudulent payments from happening, at least you can prevent a person's account from being drained with debit permission by not allowing it at all. Also, keep in mind (Phil) that your script is only going to pay out when it's designed to do so, which means if your script is set for split profits, for instance, the script most likely won't be exploited as they're paying in more than they're getting back. It's all in the script design and not all scripts are created equal. You'd like to think that scripters consider these things, but I don't think that's the case most of the time. With scripting comes great responsibility. :matte-motes-big-grin-wink:
  3. Phil Deakins wrote: Yes, I know that, if an object is to take money, it still needs permission to pay out from the owner's account. That's because it will need to give money to the user if s/he either pays too much or too little. Normally, you try to set exact amount(s) for the pay window (llSetPayPrice) when possible, which keeps this from happening.
  4. Without debit permission, a script can't pay out from the owner's account. Debit permissions is typically requested at the start of a script, to which the owner must Allow or Deny via a dialog window. If the dialog is ignored, the script is denied access to the owner's account. How the owner responds determines whether the script can pay out or not. If you want a script to be able to pay out or refund, debit permission has to be granted, so the script can access the owner's account, otherwise it's not possible. Paying in has nothing to do with debit permission, unless you consider the relationship between the two; that refunding a pay in is dependent on debit permission so that the refund can be paid out. Typical uses of debit permission: Refund if some requirement isn't met, since there's no way to restrict payment to a script before-hand. Commission pay or split profit pay, since only the owner is paid, others need to be paid after the fact from the owner's account. Discount percentage pay back after payment and certain requirements are met (group tag, for instance). In the case of games, pay out of winnings. Here's a similar example, for a discount percentage if group tag is active: float discount = 25.0;integer debit_granted; default{ state_entry() { llRequestPermissions(llGetOwner(),PERMISSION_DEBIT); } run_time_permissions(integer which_permissions_granted) { if (which_permissions_granted & PERMISSION_DEBIT) debit_granted = TRUE; } money(key avatar_key_that_paid, integer paid_amount) { if (debit_granted) { if (llSameGroup(avatar_key_that_paid)) { integer refund = llCeil((discount/100)*paid_amount); if (refund > 0) { llGiveMoney(avatar_key_that_paid,refund); llRegionSayTo(avatar_key_that_paid,0,"You've received a discount and have been refunded "+(string)refund+" L$ ("+(string)((integer)discount)+"%) for being in our group."); } } llRegionSayTo(avatar_key_that_paid,0,"Your item(s) are being delivered."); } // Add give inventory code here }} In response to Derek - There is no reason for a game to require a 1 L$ pay in to play, unless you wanted to track players, but that can be done just as easily without requiring a pay in. If a player can't take the time to read chat, IM or dialog menus pertaining to the status of the game, then they shouldn't be playing it in the first place. Session tracking and timeout is simple to achieve in a script, to keep other players from being able to touch and affect a current game and to kick dormant players who may have stepped away. I see the 1 L$ pay to play as lazy scripting; unnecessary and pointless. As you said, it would clog your transaction history beyond belief.
  5. Phil Deakins wrote: I've had a look and you're right. The whole post was about the Wire Act. I hadn't actually read it. I just saw links to law stuff and text about law stuff, and I asked you why you posted them. I suggested some possible reasons (you wanted to persuade LL to change the policy, and you wanted to show people why the polciy is needed were two of them). It was a genuine question. If you'd said it was just for people's interest, we wouldn't be having this conversation, but you said that creators and operaters need to know, and proceeded to argue that. That's where you went wrong. And you're still saying something similar. As for me being a troll, it's been well established in this thread that you don't understand what the word means, so we can ignore it. All you know about the word is that it can be used as an insult, like you've used other words to insult various people in this thread. I think you're the only one in this thread who's been throwing insults at those who don't agree with you. It's not a very good practise, is it? - because everyone reading the thread can see it and get to know what you are like as a person. And as for me going to have fun elsewhere, forget it. Between the two of us, your'e the noob, and noobs shouldn't get all uppity with their elders As for you not responding to those who you miscall trolls, meaning me and presumably others who you've called a troll in this thread, I'll believe it when I see it. It's not the first time you've said it so we can't take what you say as being accurate, can we? - much like some of the other things you've said in this thread 101 pages and 1001 posts so far. Throughout it all we're still no further along than the posts from Linden Lab early in the thread. Giving answers helps, but turning the thread into a mud pit of endless speculation (Sorina) isn't helping anyone. Skill Gaming Policy interpretation is up to the game creator, operator and their lawyer, who is supposed to guide the applicant and give a legal opinion. Knowing this, that the lawyer is the guide, it doesn't make sense to listen to anything anyone says in this thread about Skill Gaming Policy interpretation, including myself. Probably the best post here, aside from the LL posts, has been the transcript (page 97; Innula) that does a good job of interpreting the Skill Gaming Policy, for those that want potential answers before hiring a lawyer. We're mid-way through the month and still no games or operators listed as approved on the wiki. *sits back with popcorn*
  6. Here is an example of how to use a boolean integer as a switch to toggle modes between key list gathering and request agent data. Here we use a sensor, but you should get the gist and be able to design something similar for your project. Note the timer discipline where we stop the timer during processing, so we don't get overlap. /* Sensor and Request Agent Data Processing Script By Yingzi Xue 08-11-14 An example of how you can use an integer as a toggle switch for controlling functionality in your scripts. On touch the script gathers an avatar list with a sensor and then uses the list to request agent data for each detected avatar. The returned data is then said to the owner via chat. When all data is retrieved, the switch is thrown, the avatar list is cleared and the script goes dormant, waiting for the next touch. You may use this script or pieces parts for your projects as long as you keep this header intact. */ key request_id; // Request ID for llRequestAgentDatainteger switch; // Toggle between sensor and request agent datalist avatar_list; // Avatar list generator from sensor eventfloat interval = 0.2; // Timer interval in secondsinteger request_counter; // Avatar list pointerdefault{ touch_end(integer touches) { // Initiate processing if (switch == FALSE) llSetTimerEvent(interval); } timer() { llSetTimerEvent(0); // Stop timer to process if (switch == TRUE) // Request mode { // Done processing requests? if (request_counter == llGetListLength(avatar_list)) { avatar_list = []; request_counter = 0; switch = FALSE; // Flip our switch return; } // Request data request_id = llRequestAgentData(llList2Key(avatar_list,request_counter),DATA_BORN); llSetTimerEvent(interval); } else if (switch == FALSE) // Avatar list mode { // Sense avatars llSensor("","",AGENT_BY_LEGACY_NAME,96.0,PI); } } dataserver(key queryid, string data) { if (request_id == queryid) { // Process requested data llOwnerSay("User: "+llKey2Name(llList2Key(avatar_list,request_counter))+", Date Born: "+data); // Next avatar request_counter++; } } sensor(integer avatars) { if (avatars) { // Gather avatars found into a list of keys integer counter; for(counter = 0; counter < avatars; counter++) { if (llDetectedKey(counter) != llGetOwner()) { avatar_list += llDetectedKey(counter); } } // Start the request process by flipping our switch switch = TRUE; llSetTimerEvent(interval); } }}
  7. Ninjadanana525 wrote: Hi everybody! LSL Scripting is hard for me and my english is bad too. Php language is much easier for me >,< How I can make a chat command? Because I want to make chat command like this. /pipo (NAME) The function in the chat: /me pipoed (NAME) Or in a menu. /pipo and a menu pop up. In the menu you can choose the nearest Player. When you choosed in the chat: /me pipoed (Player what you choose) Thanks <3 The easiest way to do what you're wanting is with a gesture. You don't need a script for it. Right click in an inventory window where you want to create a gesture (usually the Gesture folder), create a new gesture and the edit window pops up. Set the trigger for "/pipo" and the replace with text as "/me pipoed" and then test it. Type in "/pipo Joe.", for instance, and you get "Youravatarname pipoed Joe." If you want to have a gesture menu, you'll probably have to write a script which requires llListen, llDialog and listen event, for starters. You can find a number of examples containing everything you need on the wiki.
  8. Vehicle types vary in functionality. You're using airplane. Look at the descriptions below: VEHICLE_TYPE_NONE - Turns off vehicle support VEHICLE_TYPE_SLED - Simple vehicle that bumps along the ground, and likes to move along its local x-axis VEHICLE_TYPE_CAR - Vehicle that bounces along the ground but needs the motors to be driven from external controls or timer events VEHICLE_TYPE_BOAT - Hovers over water with lots of friction and some angular deflection VEHICLE_TYPE_AIRPLANE - Uses linear deflection for lift, no hover and banking to turn VEHICLE_TYPE_BALLOON - Hover, and friction, but no deflection The airplane vehicle type uses linear deflection for lift and banking to turn. Because of the lift generated by linear deflection, turning is much slower. You can mitigate this somewhat with the angular, banking and vertical attraction settings, but you may not get the desired results no matter what your settings are, because of its inherent nature to want to lift. If true airplane feel isn't a priority, I suggest using the balloon type instead, which has no lift. It's possible to get a very tight turning and responsive airborne vehicle with balloon. By the way, the wiki linked to earlier explains this behavior: Linear and Angular Deflection A common feature of real vehicles is their tendency to move along "preferred axes of motion". That is, due to their wheels, wings, shape, or method of propulsion they tend to push or redirect themselves along axes that are static in the vehicle's local frame. This general feature defines a class of vehicles and included in this category a common dart is a "vehicle": it has fins in the back such that if it were to tumble in the air it would eventually align itself to move point-forward--we call this alignment effect "angular deflection". A wheeled craft exhibits a different effect: when a skateboard is pushed in some direction it will tend to redirect the resultant motion along the direction in which it is free to roll--we call this effect "linear deflection". So, a typical Second Life vehicle is an object that exhibits linear and/or angular deflection along the "preferential axes of motion". The default preferential axes of motion are the local x- (at), y- (left), and z- (up) axes of the local frame of the vehicle's root primitive. The deflection behaviors relate to the x-axis (at): linear deflection will tend to rotate its velocity until it points along its positive local x-axis while the angular deflection will tend to reorient the vehicle such that its x-axis points in the direction that it is moving. The other axes are relevant to vehicle behaviors that are described later, such as the vertical attractor which tries to keep a vehicle's local z-axis pointed toward the world z-axis (up). The vehicle axes can be rotated relative to the object's actual local axes by using the VEHICLE_REFERENCE_FRAME parameter, however that is an advanced feature and is covered in detail in a later section of these documents. Depending on the vehicle it may or may not be desirable to have lots of linear and/or angular deflection. The speed of the deflections is controlled by setting the relevant parameters using the llSetVehicleFloatParam script call. Each variety of deflection has a "timescale" parameter that determines how quickly a full deflection happens. Basically the timescale is the time coefficient for exponential decay toward full deflection. In other words, a vehicle with a small timescale will deflect quickly. For instance, a typical dart might have an angular deflection timescale of a couple of seconds but a linear deflection of several seconds; it will tend to reorient itself before it changes direction. To set the deflection timescales of a dart you might use the lines below: llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 2.0); llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 6.0); Each variety of deflection has an "efficiency" parameter that is a slider between 0.0 and 1.0. Unlike the other efficiency parameter of other vehicle behaviors, the deflection efficiencies do not slide between "bouncy" and "damped", but instead slide from "no deflection whatsoever" (0.0) to "maximum deflection" (1.0). That is, they behave much like the deflection timescales, however they are normalized to the range between 0.0 and 1.0. You'll find further details in the subsequent sections titled Moving the Vehicle, Steering the Vehicle, The Vertical Attractor, Banking and Friction Timescales
  9. Sorina Garrigus wrote: The other was someone that apparently hates games and game operators, and blames them for encouraging addiction while also stating that they also tried to make a skill game before I suppose so they could blame themselves for encouraging addiction. Then of course there is you who is hung up on a punctuation comment. Not exactly a credible we. CLEARLY you are here to disrupt things as most trolls are. So have a good day and have fun making cheap furniture. The first paragraph quoted above is aimed directly at me, so I came back to respond. I made it clear throughout the thread, I don't hate games or game operators. I called for balance, fairness and oversight. I did call into question addiction, which you acknowledged and denied multiple times. You yourself claimed to have banned addicted players because of addiction. You can't have it both ways. If it's pay to play, pays out, is addicting and skill plays second fiddle to chance then those are the hallmarks of gambling. Maybe not all games fall into that category, I acknowledged that in several posts. You deny that gambling exists in Second Life because the wagering policy doesn't allow it and LL has not taken action, taking that as proof. Then you say that some games are clear violations, which negates your argument. You paint yourself as a legal scholar and a skill gaming intellectual, which you seem to have garnered by osmosis as a game operator. Your claim of expertise by association ("experience" with "hundreds of games") hasn't shined through in your posts at all, instead you've been divisive, insulting, argumentative and contradictory. You took it upon yourself to IM me in-world, all in a tizzy over a tongue-in-cheek comment I made at the end of a post in this thread, clearly a joke. You seek out dirt and associations (or lack of) to lay claim to intellectual superiority, in an attempt to defeat arguments. Some points you simply ignore because you know it's the truth. The self-importance with which you carry yourself in this thread is evident to all. I can't name one post that has been beneficial to my understanding of the skill gaming policy. My posts have been about my own concerns, debating the skill gaming policy, expressing my convictions and my experiences (i.e. normal discourse). Your posts have been about yourself first, because you must always be right and must always have the high ground. Clear cut answers become muddled in your quest for skill gaming policy "clarity". Calling someone out as being a creator of furniture in an effort to make their posts irrelevant. Calling someone out as being an alt as if they're hiding something. Calling a scripter out for being a hater of games because they have a different opinion. These are all divisive and pointless and have no basis vs fact and opinion, which ALL are able to discern, regardless of background and experience. You so badly want your opinion to be superior to everyone else, so you find anything you can to make others look inferior. If you have to dig up perceived dirt or irrelevance to defend your position, your position doesn't have a leg to stand on. I've seen more clarity from a guy who deals in furniture and an alt than I've seen from you, the supposed gaming expert you make yourself out to be. I gave you respect, apologized and empathized with your position. I even visited your place and complimented you on the layout. I took the time to see who you were and what you do because I care about the subject matter, not whether I can be better than you or put you in your place. I was and always have been sincere in every post (joking aside). Rather than respond in kind, you chose to go a different route, which is telling. Your frantic need to be at the center of attention, be accepted and be a voice for gaming has only made things worse, not better. You counter-argue every valid point made with muddy half-truths and conjecture, serving to confuse the very community you want to be a pillar of. If you're contradicting your own points in the same thread, It's not helping at all. Lastly, no matter how you try to put words in other peoples mouths, their words are here to read in this thread. In the end, truth wins out and is self-evident. If it wasn't clear, let me reiterate: I am a scripter and builder. I love games. I've scripted and built my own games from scratch. I am for balance in gaming, to allow for profit and payout that makes sense; something that up to this point has been questionable. I am for equal rights for all residents, which means these games should not have a negative impact on region performance or personal well-being (financial, psychological). I am fully behind the wagering and skill gaming policies and how LL decides to implement them. I'm not an AR freak, I don't belong to an AR group and I have no intention of ARing unless it affects me personally. There is no grand conspiracy on my part, only strong opinion which I'm passionate about. I am passionate about all of my opinions, regardless of the subject matter and it comes through in my posts. Those are all facts. Take note. You will not put words in my mouth and you will not invalidate my opinion.
  10. I just posted a reply in a thread from a couple days ago which shows how to do this. I've copied the snippet and modded it a bit to show you how it's done. There are three examples, showing local and global storage, in this case a list to store our inventory item names. The first is a local example where the list is temporary, for use within the event or scope it was declared in. The second is a global example where the list is declared before the default state and accessible throughout the script, but contains repetitive code. In the third example we expand on the second example and create a custom function for generating an inventory list, since it's used multiple places in our script, eliminating repetitive code. The function allows you to give it the inventory type, which it uses to generate the list. These three examples are meant to be vehicles for learning. You will most likely have unique requirements you'll need to work through for your project. Hopefully this gives you a starting point. The wiki is your friend. Everything you need to know to do what you need is there. The list and inventory functions are a good place to start. // Example using local storage, list can be used within an event only // or within a scope, whichever the list is declared in // Drop inventory items in your prim to see the output of this example // which shows the data in the list separated by commas default { // Something changed, triggers changed event changed(integer change) { // Declare a list for use as storage (local) list inventory_items; // If inventory is what has changed, generate the list if (change & CHANGED_INVENTORY) { integer counter; // Declare a counter integer to use below integer item_count = llGetInventoryNumber(INVENTORY_ALL); // Loop thru inventory items for(counter = 0; counter < item_count; counter++) { // Store the item in our list inventory_items += [llGetInventoryName(INVENTORY_ALL,counter)]; } // Use the data within the list, in this case we're dumping it to // the owner in local chat llOwnerSay(llDumpList2String(inventory_items,",")); // List is cleared as soon as the event is exited } } } // Example using global storage, list can be used anywhere in // the script // Drop inventory items in your prim and touch to see the output // of this example, which shows the data in the list separated // by commas // Note the repetitive nature of the list generating code which // can be found in state_entry and changed events // We fix this in the third example by making a custom function // Declare a list for use as storage (global) list inventory_items; default { state_entry() { integer counter; // Declare a counter integer to use below integer item_count = llGetInventoryNumber(INVENTORY_ALL); // Loop thru inventory items for(counter = 0; counter < item_count; counter++) { // Store the item in our list inventory_items += [llGetInventoryName(INVENTORY_ALL,counter)]; } } changed(integer change) { if (change & CHANGED_INVENTORY) { inventory_items = []; // Clear our list first integer counter; // Declare a counter integer to use below integer item_count = llGetInventoryNumber(INVENTORY_ALL); // Loop thru inventory items for(counter = 0; counter < item_count; counter++) { // Store the item in our list inventory_items += [llGetInventoryName(INVENTORY_ALL,counter)]; } } } touch_end(integer touches) { // We can access our list data from anywhere in the script, in this case a touch event llOwnerSay(llDumpList2String(inventory_items,",")); } } // Example using global storage and the versatility of a custom// function to eliminate repetitive code // See the wiki for more information on custom functions// Drop inventory items in your prim and touch to see the output // of this example, which shows the data in the list separated // by commas// Declare a list for use as storage (global)list inventory_items;// Our inventory list getting function, simply pass the type into itget_inventory_list(integer item_type){ inventory_items = []; // Clear our list first integer counter; // Declare a counter integer to use below integer item_count = llGetInventoryNumber(item_type); // Loop thru inventory items for(counter = 0; counter < item_count; counter++) { // Store the item in our list inventory_items += [llGetInventoryName(item_type,counter)]; }}default{ state_entry() { get_inventory_list(INVENTORY_ALL); } changed(integer change) { if (change & CHANGED_INVENTORY) { get_inventory_list(INVENTORY_ALL); } } touch_end(integer touches) { // We can access our list data from anywhere in the script, in this case a touch event // Dump the list to string using a comma delimiter llOwnerSay("All items in the list: "+llDumpList2String(inventory_items,",")); // Use llList2String to get the first list element llOwnerSay("First item: "+llList2String(inventory_items,0)); // An example of a for loop to display items one at a time // Create a counter to count up integer counter; // Get the number of items in the list integer number_of_items = llGetListLength(inventory_items); // List elements always start at 0 // Loop and display each item in the list, incrementing the counter // Note how we have to convert counter to a string with typecasting for(counter = 0; counter < number_of_items; counter++) { llOwnerSay("Item #"+(string)(counter+1)+": "+llList2String(inventory_items,counter)); } }}
  11. Here's a three video series on how to use the grid for perfect alignment every time. It wouldn't let me link the playlist, so I'm putting the URL here ( ) and adding in the first video below.
  12. There is a little function found on the wiki under llStringLength that I like to use for button name lengths. Since there's the possibility that someone might try to use extended characters in a button name, it's always a good idea to find out just how long that name is in bytes, to keep from going over. Innula's example of getting the first 24 characters will cause a script error if you truncate the middle of a multi-byte character. Now granted, you're not going to necessarily have extended characters in inventory names, but just in case the possibility arises in my scripts, I always err on the side of caution and count the actual bytes, then truncate as needed. Examples: This function (from the wiki) counts the actual bytes in a string (which llStringLength doesn't do if extended characters exist in the string): integer bytes_in_string(string msg) { //Definitions: //msg == unescapable_chars + escapable_chars //bytes == unescapable_bytes + escapable_bytes //unescapable_bytes == unescapable_chars //s == unescapable_chars + (escapable_bytes * 3) string s = llEscapeURL(msg);//uses 3 characters per byte escaped. //remove 1 char from each escapable_byte's triplet. //t == unescapable_chars + (escapable_bytes * 2) string t = (string)llParseString2List(s,["%"],[]); //return == (unescapable_chars * 2 + escapable_bytes * 4) - (unescapable_chars + (escapable_bytes * 3)) //return == unescapable_chars + escapable_bytes == unescapable_bytes + escapable_bytes //return == bytes return llStringLength(t) * 2 - llStringLength(s);} Then you need to truncate the string if > 24 bytes in your code... if (bytes_in_string(button_name)>24){ // truncate based on bytes, add to button list buttons += llBase64ToString(llGetSubString(llStringToBase64(button_name), 0, 31));} else{ // length is ok, add to button list buttons += button_name;} However, let's simplify the above. I combined the two into one function. Call the function like this: button_truncate(your_button_string); string button_truncate(string msg) // Truncate the button length{ string s = llEscapeURL(msg); string t = (string)llParseString2List(s,["%"],[]); integer number_of_bytes = llStringLength(t) * 2 - llStringLength(s); if (number_of_bytes > 24) { return llBase64ToString(llGetSubString(llStringToBase64(msg), 0, 31)); } else { return msg; }} Script Example: Below is an example script I threw together for you. It contains a few functions you'll find handy, like button_truncate, order_buttons and create_button_list (which solves your problem). I also included dialog handling with timeout. One important consideration is that if your object's inventory is going to have more than 12 textures (i.e. 12 buttons), you're going to need to write some extra code to display dynamic menus (i.e. multiple menus with prev/next, based on your button list). As it is, this script only displays 12 buttons, but it's meant to be a starting point for you to learn from and design your own. This script doesn't care who touches it, it doesn't keep track of users, it just starts a new dialog with each new touch. Throw it in an object and add some textures, then touch the object for a menu. list buttons; // Buttons listinteger dialog_call; // Stores the pointer to the current listenfloat dialog_time; // Stores a point in time for menu expiryinteger dialog_channel; // Stores the dialog channel// From the wiki. Correct the button orderlist order_buttons(list buttons){ return llList2List(buttons, -3, -1) + llList2List(buttons, -6, -4) + llList2List(buttons, -9, -7) + llList2List(buttons, -12, -10);}// Truncate button name if greater than 24 characters // Takes into consideration the actual byte count of the button namestring button_truncate(string msg) // Truncate the button length{ string s = llEscapeURL(msg); string t = (string)llParseString2List(s,["%"],[]); integer number_of_bytes = llStringLength(t) * 2 - llStringLength(s); if (number_of_bytes > 24) { return llBase64ToString(llGetSubString(llStringToBase64(msg), 0, 31)); } else { return msg; }}// Creates the button listcreate_button_list(){ buttons = []; // Start anew integer counter; integer texture_count = llGetInventoryNumber(INVENTORY_TEXTURE); for(counter = 0; counter < texture_count; counter++) { buttons += [button_truncate(llGetInventoryName(INVENTORY_TEXTURE,counter))]; }}default{ state_entry() { // Create the button list, in case textures exist when we drop the script in create_button_list(); } touch_start(integer number_of_touches) { if (dialog_call) llListenRemove(dialog_call); // Remove old listen if it exists dialog_channel = (integer)(llFrand(-1000000000.0) - 1000000000.0); // Randomize dialog channel dialog_call = llListen(dialog_channel,"","",""); // Start a new listen and store its pointer // Note the use of order_buttons function, which puts them in the order they were given in the list llDialog(llDetectedKey(0),"\nPlease select an option:",order_buttons(buttons),dialog_channel); dialog_time = llGetTime(); // Store time for expiration // Turn timer on, if it isn't already on; this wouldn't be needed if timer is constantly on for other script functionality llSetTimerEvent(60); } timer() { // Check for menu expiration (greater than 60 seconds have expired) if ((llGetTime()-dialog_time) > 60.0) { llSetTimerEvent(0); // Kill timer if it's not being used for other things dialog_time = 0; if (dialog_call) llListenRemove(dialog_call); // Remove old listen if it exists llWhisper(0,"Menu has expired."); } // Need the timer for other things? Put them here // Remember to not stop the timer (above) if you need to keep it running } changed (integer change) { if (change & CHANGED_INVENTORY) { // Inventory changed, recreate the button list, create_button_list(); } } listen(integer ch, string name, key id, string message) { // We received a response, go ahead and expire the dialog listen // Note that you wouldn't turn the timer off if it's being used for other things llSetTimerEvent(0); dialog_time = 0; if (dialog_call) llListenRemove(dialog_call); // Say the button pressed, as chatted to the listen event llOwnerSay(message + " button pressed."); }} Dynamic Menus (how I did it): Create an index function to take your button list and arrange it into menus.Truncate button names as you go. First list element is the first menu and has 11 buttons (add a Next button on the end). Add the first 11 menu items from your button list. Middle menus have 10 buttons each (add Prev and Next on the end). Create menus until buttons left are less than 10. Last menu (add Prev on the end). Use a pointer (a simple integer) to keep your place in the menu list while user is navigating. Extract the element for the pointer, converting it to a list using llParseString2List, using the delimiter you chose to separate your buttons in each element. Display your dialog. Adjust pointer as next/prev buttons are pressed. Can be nested in menus wherever needed and/or adapted for endless dynamic menus with a little extra code.
  13. Yep, that's the problem. You're storing the channel as a string and not an integer. Upon further inspection, it appears you've posted a partial script, missing a number of items. The script, as posted, would never work. Channel should be an integer, not a string, in order to store a numeric value (whole number). Incoming notecard data is in the form of a string (text) and needs converted to an integer before storing into Channel. Example: Channel = (integer)value; This is called typecasting (changing from one data type to another). Since Channel is now numeric and not a string, your llListen will listen to the channel read by the notecard. Name is being converted to lowercase to negate case sensitivity, but your IF statement for channel is comparing name to "Channel". It should be "channel" because it will never match and thus never store the channel number in Channel. Use llStringTrim(mystring,STRING_TRIM); to remove leading and trailing spaces from data, so your IF statements always catch data that otherwise might not match with the extra spaces.. Your dataserver event is missing. Nothing would be read in that case. There are a number of other items missing from the script which I had to add in to make it work; taken from the wiki example. Either you didn't paste a complete script or your script has always been incomplete and never would've worked. I fixed the script you posted, to get it working. It's up to you to make it your own. integer Channel; string configurationNotecardName = "Application.Config"; key notecardQueryId; integer line; init() { // reset configuration values to default Channel = 90; if(llGetInventoryType(configurationNotecardName) != INVENTORY_NOTECARD) { // notify owner of missing file llOwnerSay("Missing inventory notecard: " + configurationNotecardName); // don't do anything else return; } // initialize to start reading from first line (which is 0) line = 0; notecardQueryId = llGetNotecardLine(configurationNotecardName, line); } processConfiguration(string data) { // if we are at the end of the file if(data == EOF) { // notify the owner llOwnerSay("We are done reading the configuration"); // notify what was read llOwnerSay("The Channel is: " + (string)Channel); // do not do anything else return; } // if we are not working with a blank line if(data != "") { // if the line does not begin with a comment if(llSubStringIndex(data, "#") != 0) { // find first equal sign integer i = llSubStringIndex(data, "="); // if line contains equal sign if(i != -1) { // get name of name/value pair string name = llGetSubString(data, 0, i - 1); // get value of name/value pair string value = llGetSubString(data, i + 1, -1); // trim name list temp = llParseString2List(name, [" "], []); name = llDumpList2String(temp, " "); // make name lowercase (case insensitive) name = llToLower(name); name = llStringTrim(name,STRING_TRIM); // trim value temp = llParseString2List(value, [" "], []); value = llDumpList2String(temp, " "); value = llStringTrim(value,STRING_TRIM); // name if(name == "channel") Channel = (integer)value; // Changed: String to Integer // unknown name else llOwnerSay("Unknown configuration value: " + name + " on line " + (string)line); } // line does not contain equal sign else { llOwnerSay("Configuration could not be read on line " + (string)line); } } } // read the next line notecardQueryId = llGetNotecardLine(configurationNotecardName, ++line); } default { on_rez(integer start_param) { init(); } changed(integer change) { if(change & (CHANGED_OWNER | CHANGED_INVENTORY)) init(); } state_entry() { init(); } dataserver(key request_id, string data) { if(request_id == notecardQueryId) processConfiguration(data); } } When you get more comfortable with scripts, here's a before and after. The data parsing code in the wiki example... // if we are not working with a blank line if(data != "") { // if the line does not begin with a comment if(llSubStringIndex(data, "#") != 0) { // find first equal sign integer i = llSubStringIndex(data, "="); // if line contains equal sign if(i != -1) { // get name of name/value pair string name = llGetSubString(data, 0, i - 1); // get value of name/value pair string value = llGetSubString(data, i + 1, -1); // trim name list temp = llParseString2List(name, [" "], []); name = llDumpList2String(temp, " "); // make name lowercase (case insensitive) name = llToLower(name); // trim value temp = llParseString2List(value, [" "], []); value = llDumpList2String(temp, " "); // name if(name == "channel") Channel = (integer)value; // unknown name else llOwnerSay("Unknown configuration value: " + name + " on line " + (string)line); } // line does not contain equal sign else { llOwnerSay("Configuration could not be read on line " + (string)line); } } } ...can be reduced to this... if (llGetSubString(data, 0, 0) != "#" && llStringTrim(data, STRING_TRIM) != "") { if (llSubStringIndex(data, "=") > -1) { list temp = llParseString2List(data, ["="], []); string name = llStringTrim(llToLower(llList2String(temp, 0)), STRING_TRIM); string value = llStringTrim(llList2String(temp, 1), STRING_TRIM); if (name == "channel") { Channel = (integer)value; } else { llOwnerSay("Unknown configuration value: " + name + " on line " + (string)line); } // Add other IF statements for your various notecard settings here. } else { llOwnerSay("Configuration could not be read on line " + (string)line); } }
  14. You didn't specify if the communication is object-to-object or avatar-to-object. Use negative channel numbers for object-to-object (inter-script communication example: llShout(-123456,"command"); and positive channel numbers for avatar-to-object (local chat example: /4 command). All notecard data is treated as text. When you parse it, you need to sort it out into the various data types your script needs. Your typical notecard data is going to have a keyword, separator and data (example: channel=-123456).
  15. Rolig is right on the money. I did this a few months ago and my avatar was deleted in 2010. That's 4 years being deleted, so your chances of recovery should be fine. They will contact you via e-mail for more information about your account though, so be ready. You'll need the e-mail address you used, (I believe) date of birth and any other information they might use from your account to verify it's you.
  16. Perrie Juran wrote: Thousands and Thousands of accounts At last check, the w-hat database had over 6 million avatar keys.
  17. I agree with everything you said. An example of the Amacci AO HUD notecard (which uses ZHAO II, the most common AO/Dance script in SL): [ Standing ]AOF_stand6|AOF_stand7|AOF_stand8|AOF_stand9|AOF_stand10[ Walking ]|Amacci Female Walk 1|Amacci Female Walk 5[ Sitting ]AOF_sit2|AOF_sit3|AOF_sit4[ Sitting On Ground ]AOF_gsit1|AOF_gsit2|AOF_gsit3 The output of my script looks like this (below). All one line (minus "[15:57] Object whispers:" from the front of the line), which can be select copy/pasted directly into the HUD notecard because it's in the format it uses. No editing out anything, it's all ready to go. Dance 1|Dance 2|Dance 3|Dance 4|Dance 5|Dance 6|dream-dance|f_dance_01|f_dance_03|f_dance_05|f_dance_06|f_dance_07|f_dance_08|f_dance_09|f_dance_10|HeadBang I use the llRemoveScript all the time. Scripts like Get Link Number (which Firestorm doesn't report correctly half the time), Get Position and Rotation, Clear Hover Text and so many other uses. A friend of mine once wanted a script that would rename an object and die, to save typing. lol The more ways the merrier, I say. Learning more than one way is most beneficial. That's how I learn most of the time, through others.
  18. Of course. Having the script auto-die makes sense if you're only doing one set of animations. I considered that he might want to do more than one set of animations at once. Having a script not die saves him having to drag and drop the script in each time to do another set, which requires scrolling to find the script to drag and drop it; it takes away focus from the animations folder, which you have to scroll back up to. You could have two inventory windows open but that's extra screen real-estate. Instead, just delete the old set of animations and add the new ones, press touch and you've got your new set to copy/paste to your notecard. Since he's going to copy/paste from chat, it's easy to avoid unwanted text (in this case, a colon) if all you're copying is the chat text with your mouse. Left click hold and drag across, highlighting the text you want, then CTRL-C (copy) and CTR-V (paste) to notecard. Keep in mind, the script prints out one line of text. If you use this copy/paste method, you don't have to worry about timestamps, colons or any unwanted text, because you're highlighting what you want to copy. Delete prim when done, gets rid of script and all in one fell swoop. Easy peasy. EDIT: I tested the one-line dump to chat with llWhisper, which has a 1024 byte limit. I was able to get 73 "Hello, Avatar" strings (13 characters apiece), including the | delimiter, before truncation. It's possible to surpass the llWhisper function's limit, but 70 13-character names is more than enough for most needs. Glad I could help, Paul.
  19. Phil Deakins wrote: It's interesting to discuss it though. Agreed. With that said, time for me to take a back seat to this thread, sit back and watch with some popcorn and see where it goes. :smileywink: Sorina should be posting any minute now. *grin*
  20. Phil Deakins wrote: @those who are involved in the current skill-chance discussion (not just you Yingzi) This is the way i see it... It doesn't matter what LL means by the words they used. It looks like they are not going to tell us but it doesn't matter. The only thing that really matters is a what a suitable lawyer thinks it means for each game that s/he's shown. If a lawyer thinks a certain game is compliant with the new rules, and the creator gets what's needed from the lawyer, LL will license the game. If the very same game is presented to a different lawyer who thought that it infringed the new rules, the creator wouldn't get what's needed from the lawyer, and the game wouldn't be licensed. Imo, this is all about LL washing their hands of any judgement calls, and making them the legal responsibility of the creators. So LL doesn't need to clarify the skill/chance part and what they meant by 'material'. They can happily leave all that to suitable lawyers, which, imo, is exactly what they've done. All LL will need to do is deal with any infringements, and they do not need to make any judgement calls at any time. I agree with what you're saying. It's just wishful thinking on my part. I remain skeptical that the wagering policy has been adhered to over the years. I suppose we'll find out eventually, when/if approved games get put to the legal test sometime in the future. If one game finds its way into hot water, the rest may fall like dominos. If it never happens I'll be surprised.
  21. Drop this script in your object, add your items to the object, then touch the object and it will give you a line in local chat with all inventory items separated with the | delimiter. Note the settings at the top of the script. string delimiter = "|"; // Delimiter; change to whatever you want integer include_me = FALSE; // Include this script in the results? TRUE or FALSE default { touch_start(integer total_number) { list items_in_inventory; integer counter; integer number_of_items = llGetInventoryNumber(INVENTORY_ALL); string item_name; do { item_name = llGetInventoryName(INVENTORY_ALL,counter); if (include_me == FALSE && item_name == llGetScriptName()) jump skip; items_in_inventory += [item_name]; @skip; counter++; } while (counter < number_of_items); llWhisper(0,llDumpList2String(items_in_inventory,delimiter)); } }
  22. llGetScriptName gives you the script name, but if you're wanting to announce other various inventory item types as they're dropped into an object, you need to detect inventory changes using the changed event. You'll probably have to keep track of what already existed or was previously dropped into inventory, to detect what new items were dropped into inventory.
  23. Innula Zenovka wrote: I don't understand. For llGetObjectDetails you need the object's uuid, which isn't going to be available while the object is inside the inventory of another object and not rezzed in world, is it? You could use llGetInventoryCreator, so long as all the object's components are by the same creator. If, though, the object in question is a scripted object and I've made the prim and you've made the script, that's not going to work (just as it won't show the object's creator on inspection in your inventory if that's the case). My apologies. I meant llGetInventoryCreator, but somehow my brain grabbed ahold if llGetObjectDetails and ran with it. There is no way to get a creator from an object's inventory using llGetObjectDetails but my mind must've been somewhere else. I remember thinking, but wait... you can get the creator from an inventory item, because I had used it as a gift card system years ago... but yeah... my brain locked on llGetObjectDetails and the rest is history. Sorry for the confusion, OP. Very good point Innula. This function is best used if you're the creator of the object and author of the script(s). Since I used it for gift cards that I made myself, it wasn't a factor.
  24. Rolig Loon wrote: I have scripted "vendors" that are really donation boxes that accept whatever the customer is willing to offer. If you donate one amount, you get one thank you gift. If you donate a higher amount, you get a different one. If you write the script to recognize different levels of giving, you can use a single PAY window to manage the whole thing. It's sort of similar to the way public TV or public radio stations give different "gifts" for different levels of donation. I've had a couple of clients who have asked for something like that. *nods* I was about to suggest that what they really want is a donation box, but it sounds like they want it as part of the display for the product, which would mean a "vendor" instead. I've done this too, in fact I was going to post the script, but then I thought--this is a simple and common enough script, they should be able to find it somewhere. Since gift vs level of donation can vary depending on the customer's needs, it would have to either be designed on a per customer basis or dynamic through something like notecard configuration, text boxes or chat commands. In the past I've tended to go overboard with features on such projects and ended up with notecard configuration to handle it all. That can be good or bad, depending on how you look at it. I've always had this irrational fear of loss of a script state, even though I've never had it happen. Where before I typically used notecard configuration, I've moved away from it because it's such a memory hog. I just finished work on an external data container system on my server, for script configuration, to free up script memory usage. The external server doesn't care what the data is, just stores and retrieves it. I can't wait to start using it. Something like this would be perfect to test it out.
  25. Dora Gustafson wrote: xBabyxDoll wrote: I thought it would be that easy as well, but the pay option actually displays a message that it will only work when a script is inserted... Right, but what is wrong with BUY instead of PAY? Buy is amount-specific. Pay (script) is dependent on what you set the pay price window to be, including the ability to add a custom amount. I wouldn't want to have to tell my customers, just open my profile and pay me what you think it's worth; that's an extra step and customers don't like extra steps.
×
×
  • Create New...