Library: FOSSL Vending System v1.1 enabling income splitting and more
|
Fleur Dollinger
Registered User
Join date: 31 Mar 2007
Posts: 8
|
04-30-2008 18:32
I found the FOSSL set of scripts made by Ilobmirt Tenk when I was looking for options and information on how to create a vendor for my product. I thought it looked pretty good, but I wanted to be able to distribute vendors to other sellers and enable income splitting and so I had to make some modifications to suit my purpose. I tried to retain the customisable and open structure and something of the style used by Ilobmirt. Am posting my results here to say thanks to Ilobmirt. *************************************** INCOME SPLITTING *************************************** Scripts required for income splitting - FOSSLVendorBuyModule (Original version 1 Script modified) - FOSSL_BUY_SETTINGS (New settings card for the buy module) Essential Settings -------------------- split = 1 SPLIT 1 KEY = cc3012aa123some-avatars-key0000-123456 SPLIT 2 KEY = 3ddccc30123some-avatars-key0000-123456 SPLIT 3 KEY = cc2212aa123some-avatars-key0000-123456 SPLIT 1 AMOUNT = 50 SPLIT 3 AMOUNT = 25 SPLIT 2 AMOUNT = 5 NB: you only need to include lines for number of splits. Amounts are percentages unless SPLITS 1-3 FLAT are changed to 1. Optional -------------- deed to group = 0 The 'deed to group' default is 0 so this parameter only required in settings card if changing to 1 .. this is NOT recommended and will be reset to 0 if split is set to 1. You would only set deed to group = 1 (which would allow the owner to deed the vendor to a group) if you didn't want to pay anyone from the vendor. Note that this includes not paying your customer a refund if they paid in too much money. SPLIT 1 FLAT = 1 SPLIT 2 FLAT = 1 SPLIT 3 FLAT = 1 SPLIT 1-3 FLAT default is 0 so only required in settings card if changing to 1. If changed to 1 instead of the AMOUNT being a percentage, it will be a flat figure - eg $10 instead of 10%. Anything left over after splitting is retained by the vendor owner, effectively enabling a 4-way split if necessary. Does a couple of things - the new notecard enables you to set up the splits - the script now disallows 'Deed to Group' by default This is important because a vendor deeded to a group cannot pay anyone, not even refund overpayments. Thanks to my pal mrBrett for alerting me to this potential pitfall. So deeding the vendor to a group will deactivate it. Although not recommended in any circumstances, this functionality can be altered by changing a couple of settings. ********************************************** SERVE A SEPARATE INFO CARD FOR EACH PRODUCT ********************************************** I wanted to be able to serve a separate notecard for each product rather than one notecard per vendor. This required a few more changes: - FOSSLVendorMainClient (Original Version 1 script modified) - FOSSL_CLIENT_SETTINGS (additional parameters) separate info = 1 info suffix = SomeText ********************************************** GIVE AWAY YOUR VENDORS TO OTHER SELLERS ********************************************** One more thing which wasn't obvious to me at first, if you want to be able to give away your no-modify vendors to other sellers so they can sell your products on your behalf, and you're using the server version of FOSSL you also have to make a change to the settings card for the server. - FOSSL_SERVER_SETTINGS anon access = 1 Since there were some warnings associated with changing this setting, I have also added a script to my vendors which allows me to send an individual one a message and kill it if necessary  This is dependent on them telling me when they're rezzed. Since this part of the scripted solution isn't as elegant or complete as the FOSSL mods I haven't included them here. See replies for scripts
|
Fleur Dollinger
Registered User
Join date: 31 Mar 2007
Posts: 8
|
FOSSLVendorBuyModule Revised to enable income splitting
04-30-2008 18:34
//FOSSLVendorBuyModule //---------------------------------------------------------------------------------// //Copyright Info Below... Please Do not Remove // //---------------------------------------------------------------------------------//
//(c)2007 Ilobmirt Tenk
//This file is part of the FOSSL Vendor Project
// FOSSL Vendor is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version.
// FOSSL Vendor is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details.
// You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------------// //Copyright Info Above... Please Do not Remove // //---------------------------------------------------------------------------------// // modified by Fleur Dollinger 6 April 2008 - enable income splitting // modified by Fleur Dollinger 28 April 2008 - option to disable deed to group
//=================================================================// //List all the global variables here... //=================================================================//
integer intCurrentPrice = 0;
integer intListenChannel = 40;
//count of the current Notecard line to read integer intSettingLines = 0;
//key of the notecard line to be read key keySettingsId;
//determines if this object displays debugging output integer blnDebug = FALSE;
//income can be split between up to 3 avatars (as well as owner) make split=1 and set splits & keys in notecard integer split = FALSE;
//3 separate splits allows up to 4-way split if vendor owner is not one of the 3 keys key split1 = NULL_KEY; key split2 = NULL_KEY; key split3 = NULL_KEY;
//change to TRUE to pay a flat amount instead of a percentage integer split1flat = FALSE; integer split2flat = FALSE; integer split3flat = FALSE;
// if split1flat = FALSE, amount is percentage, otherwise it is a $ amount float split1amount; float split2amount; float split3amount;
//DEFAULT IS TO DISABLE DEED TO GROUP // note that that the vendor will not be able to refund overpayments or split and distribute money if the vendor is deeded to group so its recommended to always leave this disabled integer intDeedToGroup = FALSE; //get the object's owner - NULL_KEY list groupD;
//This displays messages to the owner if debug mode has been set to true debugMessage(string strMessage){
if(blnDebug == TRUE){
llOwnerSay("FOSSLVendorBuy: " + strMessage); } }
//if SPLIT=1 splitMoney(integer amount) { if (split1 != NULL_KEY && split1 != llGetOwner() && split1 != "") { if (split1flat == TRUE) { if (amount > split1amount) { llGiveMoney(split1, (integer) split1amount); } } else { if ((integer) (split1amount*amount/100) >= 1) { llGiveMoney(split1,(integer) (amount*split1amount/100)); } } }
if (split2 != NULL_KEY && split2 != llGetOwner() && split2 != "") { if (split2flat == TRUE) { if (amount > split2amount) { llGiveMoney(split2, (integer) split2amount); } } else { if ((integer) (split2amount*amount/100) >= 1) { llGiveMoney(split2,(integer) (amount*split2amount/100)); } } }
if (split3 != NULL_KEY && split3 != llGetOwner() && split3 != "") { if (split3flat == TRUE) { if (amount > split3amount) { llGiveMoney(split3, (integer) split3amount); } } else { if ((integer) (split1amount*amount/100) >= 1) { llGiveMoney(split3,(integer) (amount*split3amount/100)); } } } }
//In this state, vendor must accept debit permissions before using the vendor default {
state_entry() { groupD = llGetObjectDetails(llGetOwner(), [OBJECT_GROUP]); debugMessage("GroupD:" + (string) llList2String(groupD,0));
//request permission on startup if ((intDeedToGroup == 0 && (key) llList2String(groupD,0) == NULL_KEY) || intDeedToGroup == 1) { llRequestPermissions(llGetOwner(),PERMISSION_DEBIT); //Asks store owner for the ability to sell things. } else { llWhisper(0,"Deeding this vendor to a group is not permitted. Transaction permission has been revoked. I hope you didn't really want to steal $$ from the creator of these products."); } }
on_rez(integer start_param) {
//reset script upon rezz llResetScript(); }
listen( integer channel, string name, key id, string message ){
if(id == llGetOwner()){
//Enable or disable verbose output if(message == "debug"){
blnDebug = !blnDebug; llOwnerSay("FOSSLVendorBuy: Debug Mode set to: " + (string) blnDebug); llMessageLinked(LINK_SET,0,"debugMode#" + (string) blnDebug,NULL_KEY);
} } }
link_message(integer sender_number, integer number, string message, key id) { //Separate the linked message into the function and variables list lstMessage = llParseString2List(message,["#"],[]); string strFunction = llList2String(lstMessage,0);
if(message == "goingOnline"){
//prevent vendor from staying online untill permissions are granted llMessageLinked(LINK_SET,0,"goOffline",NULL_KEY); //Tell Vendor to go offline if not already
} //debugMode#blnEnabled else if(strFunction == "debugMode"){
blnDebug = (integer) llList2String(lstMessage,1); } }
//Depending on if avatar accepts or declines request, either stay in this state, or move on... run_time_permissions(integer permissions) {
//if user accepted debit permissions if(permissions & PERMISSION_DEBIT){
llMessageLinked(LINK_SET,0,"goOnline",NULL_KEY); //Tell Vendor to go online if not already state transactionsAcceptable; //Change state to allow for transactions } else if(!(permissions & PERMISSION_DEBIT)){
llOwnerSay("Sorry, but this vendor requires its owner to allow for debit permissions."); llOwnerSay("To enable vendor service, touch the containing prim of the payment script, and accept the debit request."); } }
touch(integer total_number) { if ((intDeedToGroup == 0 && (key) llList2String(groupD,0) == NULL_KEY) || intDeedToGroup == 1) { llRequestPermissions(llGetOwner(),PERMISSION_DEBIT); //Asks store owner for the ability to sell things. } else { llWhisper(0,"Transaction permission has been denied/revoked for this vendor."); } } }
//In this state, vendor has accepted debit permissions //Allow transactions to commence state transactionsAcceptable { state_entry(){
llOwnerSay("Vendor is now able to make transactions with this script."); //Obtain the first line of the vendor link settings; keySettingsId = llGetNotecardLine("FOSSL_BUY_SETTINGS", intSettingLines);
} changed( integer vBitChanges ){ //detect change of owner on the ground, as this may indicate that the owner has deeded this object to the group, in which case we may want to disable transactions. //If any kind of split is activated you will have to disallow deeding this vendor to the group as groups cannot 'pay' other ppl out of the split. //This is really only relevant if you are giving this vendor to other people to sell your products for you. if (vBitChanges & CHANGED_OWNER){ llResetScript(); } }
on_rez(integer start_param){ llResetScript(); }
//set the current price to the value of num. This is incase that the user over/under pays for the item link_message(integer sender_num, integer num, string str, key id){ if(str == "updatePrice"){ intCurrentPrice = num; } }
//Whenever an avatar pays an object that this script is in, check for correct amount. //Then if correct amount is payed, notify the system of a sale money(key giver, integer amount) { // has the user paid the correct amount? if (amount == intCurrentPrice) { // if so, thank the payer by name. llSay(0,"Thank you, " + llKey2Name(giver) + "."); //give them the lovely object displayed on the vendor //send message back to root object to give out product llMessageLinked(LINK_ROOT,0,"itemBought#" + (string)giver,NULL_KEY); // if settings card includes split details if (split == TRUE) { splitMoney (amount); } } // is the amount paid less than it needs to be? else if (amount < intCurrentPrice) { // if so, tell them they're getting a refund, then refund their money. llSay(0,"You didn't pay enough, " + llKey2Name(giver) + ". Refunding your payment of L$" + (string)amount + "."); llGiveMoney(giver, amount); // refund amount paid. } // if it's not exactly the amount required, and it's not less than the amount required, // the payer has paid too much. else { // tell them they've overpaid. integer intRefund = amount - intCurrentPrice; // determine how much extra they've paid. llSay(0,"You paid too much, " + llKey2Name(giver) + ". Your change is L$" + (string)intRefund + "."); llGiveMoney(giver, intRefund); // refund their change. //give them the lovely object displayed on the vendor
//send message back to root object to give out product. llMessageLinked(LINK_ROOT,0,"itemBought#" + (string)giver,NULL_KEY);
} } //Read the link settings notecard. Configure the link based on each line. dataserver(key query_id, string data) { if (query_id == keySettingsId) { if (data != EOF) { // not at the end of the notecard
debugMessage("Notecard Line = \"" + data + "\""); //split the record into variable names and values list lstSplit = llParseString2List(data,["="],[]); string strVariable = llToUpper(llStringTrim(llList2String(lstSplit,0),STRING_TRIM)); string strValue = llStringTrim(llList2String(lstSplit,1),STRING_TRIM); // get setting for intDeedToGroup (default is 0 = disable) if(strVariable == "DEED TO GROUP"){
intDeedToGroup = (integer) strValue; debugMessage("intDeedToGroup = " + (string) split); }
// get settings for splits if(strVariable == "SPLIT"){
split = (integer) strValue; //if income splitting is enabled, must disable Deed To Group if (split == 1) { intDeedToGroup = 0; debugMessage("DEED TO GROUP DISABLED AS INCOME SPLITTING HAS BEEN ACTIVATED"); }; debugMessage("SPLIT = " + (string) split); } if(strVariable == "SPLIT 1 KEY"){
split1 = (key) strValue; debugMessage("split1 = " + (string) split1); } if(strVariable == "SPLIT 2 KEY"){
split2 = (key) strValue; debugMessage("split2 = " + (string) split2); } if(strVariable == "SPLIT 3 KEY"){
split3 = (key) strValue; debugMessage("split3 = " + (string) split3); } if(strVariable == "SPLIT 1 FLAT"){
split1flat = (integer) strValue; debugMessage("split1flat = " + (string) split1flat); } if(strVariable == "SPLIT 2 FLAT"){
split2flat = (integer) strValue; debugMessage("split2flat = " + (string) split2flat); } if(strVariable == "SPLIT 3 FLAT"){
split3flat = (integer) strValue; debugMessage("split3flat = " + (string) split3flat); } if(strVariable == "SPLIT 1 AMOUNT"){
split1amount = (float) strValue; debugMessage("split1amount = " + (string) split1amount); } if(strVariable == "SPLIT 2 AMOUNT"){
split2amount = (float) strValue; debugMessage("split2Amount = " + (string) split2amount); } if(strVariable == "SPLIT 3 AMOUNT"){
split3amount = (float) strValue; debugMessage("split3amount = " + (string) split3amount); } if(strVariable == "CHANNEL"){
intListenChannel = (integer) strValue; debugMessage("intListenChannel = " + (string) intListenChannel); }
keySettingsId = llGetNotecardLine("FOSSL_BUY_SETTINGS", ++intSettingLines); // request next line } else{ } }
//Capture toggle of Debug Setings llListen(intListenChannel,"",llGetOwner(),"debug"); } }
|
Fleur Dollinger
Registered User
Join date: 31 Mar 2007
Posts: 8
|
FOSSLVendorMainClient Pt1 revised to enable separate info cards per product
04-30-2008 18:38
//FOSSLVendorMainClient //---------------------------------------------------------------------------------// //Copyright Info Below... Please Do not Remove // //---------------------------------------------------------------------------------//
//(c)2007 Ilobmirt Tenk
//This file is part of the FOSSL Vendor Project
// FOSSL Vendor is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version.
// FOSSL Vendor is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details.
// You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>.
//---------------------------------------------------------------------------------// //Copyright Info Above... Please Do not Remove // //---------------------------------------------------------------------------------//
//=================================================================// //List all the global variables here... //=================================================================//
string strCurrentItem = ""; //This is the current item that the product index is on // the server, store the notecards in the server string strINFO = " Info"; //This is the suffix for the info notecard - create one for each product - if using integer intSeparateInfo = TRUE; //SET TRUE OR FALSE - if true the vendor will deliver a separate card for each item
list lstItemRequestList; //List of items to be requested from the server //each record is in the form of "Category#SubCategory#DatabaseKey"
list lstDisplays; //List of displays to render products on //Each display has a record of "Link#absoluteCategory#Category#absoluteSubCategory#SubCategory"
integer intHashCounter = -2147483646; //Used in the creation of a unique request
integer intSettingLines = 0; //Total # of lines in the settings notecard
integer intProductLines = 0; //Total # of lines in the products notecard
integer intItemRequestList = 0; //Number of item database requests to send to the server
integer intProductIndexCategory = 0; //Current index of visible product shown by Category
integer intProductIndexSubCategory = 0; //Current index of visible product shown by sub Category
integer intProductIndexMaxCategory = 0; //Maximum index of categorys
integer intProductIndexMaxSubCategory = 0; //Maximumindex of SubCategorys
integer intInfoCount = 0; //Number of times people clicked on the info button
integer intEmailRequestStarted = 0; //Last time an e-mail was sent out to the server
integer intLastProductUpdate = 0; //Last time product list was updated
key keySettingsId; //Used to load system Settings
key keyProductsUUID; //The uuid of the notecard to be read for products
key keyProductCategories; //The key of the line being read from the products card to determine length of categories
integer blnWaitingForServer = FALSE; //Used to determine if vendor is currently requesting a uuid for the product notecard
integer blnServerDown = TRUE; //Used to determine if the in-world server is down
integer blnDebug = FALSE; //Used to determine if vendor will output debugging information
//=================================================================// //Customize the following variables //=================================================================//
key keyTexLoading = "56617727-a972-f7d2-a730-484644a1fcb7"; //Texture UUID to represent that an item is loading
key keyTexOffline = "b8426d53-221d-9fc2-5b29-3ef16e2bd7a3"; //Texture UUID to represent the vendor has no connection to the server
key keyTexNothing = "93481f65-67ff-f166-cc64-e6fe1069c1c1"; //Texture UUID to represent that there is no item for this index
key keyServer = NULL_KEY; //This is a pointer to an object server. If this is not NULL_KEY, the vending system will consider selling items from that server.
string strInfoCardName = ""; //Name of the information notecard that talks about your company
string strProductsCardName = "FOSSL_PRODUCTS_LIST"; //Name of the products card to read off of
string strEncryptionKey = ""; //Key to encrypt its communications with
integer intBuffer = 0; //How big do you want you product inventory to be? This goes beyond the # of displays
float fltInventoryRefresh = 3600.0; //Time delay before vendor clears its product inventory and makes another request for more items
integer intServerTimeout = 60; //Time in seconds before vendor is considered down
integer intCommChannel = 939; //Channel in which you can communicate to your vending machine
integer blnEmailAgents = FALSE; //Can this script export the task of sending e-mails to other in-world objects?
//=================================================================// //Customize the above variables //=================================================================//
//=================================================================// //Define global Functions here... //=================================================================//
//This displays messages to the owner if debug mode has been set to true debugMessage(string strMessage){
if(blnDebug == TRUE){
llOwnerSay("FOSSLVendorMainClient: " + strMessage); } }
//Used for encrypting/decrypting communications between itself and the inworld server string crypt(string strPayload){
//If there is an encryption key... if(strEncryptionKey != ""){
//Use this simple Algrorythm to encrypt/decrypt input string return llBase64ToString(llXorBase64StringsCorrect(llStringToBase64(strPayload), llStringToBase64(strEncryptionKey))); } //otherwise... else{
//Just return the string as is. return strPayload; } }
//Enters the vending system into an offline mode if not offline already goOffline(){
blnServerDown = TRUE; //Set state of vendor to be offline clearRequests(); //Clear any pending requests for products llMessageLinked(LINK_SET,0,"goingOffline",NULL_KEY); //Notify system its going offline displaysOffline(); //Reflect the changes on display
}
//Restores functionality to the vending machine from an offline mode goOnline(){
blnServerDown = FALSE; //Set state of vendor to be online llMessageLinked(LINK_SET,0,"goingOnline",NULL_KEY); displaysLoading(); //reflect changes on display }
//This will set each display to a loading texture //This will also send out database requests for each link displaysLoading(){
list lstDisplay = []; integer intIndex = 0; integer intDisplayIndex = 0; integer intDisplays = llGetListLength(lstDisplays); integer blnDisplayAbsoluteCategory = 0; integer blnDisplayAbsoluteSubCategory = 0; integer intDisplayCategory = 0; integer intDisplaySubCategory = 0; integer intDisplayRelativeCategory = 0; integer intDisplayRelativeSubCategory = 0;
strCurrentItem = ""; updatePrices();
//Loop through each index of the available displays for(; intIndex < intDisplays; intIndex++){
//collect prim location, then texturethem with the offline texture //Link#absoluteCategory#Category#absoluteSubCategory#SubCategory lstDisplay = llParseString2List(llList2String(lstDisplays,intIndex),["#"],[]); intDisplayIndex = (integer) llList2String(lstDisplay,0);
intDisplayRelativeCategory = (integer) llList2String(lstDisplay,2); blnDisplayAbsoluteCategory = (integer) llList2String(lstDisplay,1); blnDisplayAbsoluteSubCategory = (integer) llList2String(lstDisplay,3); intDisplayRelativeSubCategory = (integer) llList2String(lstDisplay,4); //Obtain displayed category if(blnDisplayAbsoluteCategory == TRUE){
intDisplayCategory = intDisplayRelativeCategory; debugMessage("Display category is Absolute");
} else{
intDisplayCategory = intDisplayRelativeCategory + intProductIndexCategory; debugMessage("Display category is Relative"); }
debugMessage("Normalising Category index"); //Make sure displayed Category is between 0 and the maximum category while(intDisplayCategory > intProductIndexMaxCategory){
intDisplayCategory -= (intProductIndexMaxCategory + 1);
}
while(intDisplayCategory < 0){
intDisplayCategory += (intProductIndexMaxCategory + 1);
}
//Obtain displayed SubCategory if(blnDisplayAbsoluteSubCategory == TRUE){
intDisplaySubCategory = intDisplayRelativeSubCategory; debugMessage("Display subcategory is Absolute");
} else{
intDisplaySubCategory = intDisplayRelativeSubCategory + intProductIndexSubCategory; debugMessage("Display subcategory is relative"); }
//Make sure displayed SubCategory is between 0 and the maximum category while(intDisplaySubCategory > intProductIndexMaxSubCategory){
intDisplaySubCategory -= (intProductIndexMaxSubCategory + 1);
}
while(intDisplaySubCategory < 0){
intDisplaySubCategory += (intProductIndexMaxSubCategory + 1) ;
}
debugMessage("Display Categories found @ " + (string) intDisplayCategory + "#" + (string) intDisplaySubCategory);
llSetLinkTexture(intDisplayIndex, keyTexLoading ,ALL_SIDES);
debugMessage("Item Request for link # "+ (string) intDisplayIndex +" = " + (string) intDisplayCategory + "#" + (string) intDisplaySubCategory); itemRequest(intDisplayCategory,intDisplaySubCategory,intDisplayIndex);
} }
//This will Update all visible displays with the offline texture //Also, it will prevent payments to be made to the machine displaysOffline(){
list lstDisplay = []; integer intIndex = 0; integer intDisplayIndex = 0; integer intDisplays = llGetListLength(lstDisplays);
strCurrentItem = ""; updatePrices();
//Loop through each index of the available displays for(; intIndex < intDisplays; intIndex++){
//collect prim location, then texturethem with the offline texture lstDisplay = llParseString2List(llList2String(lstDisplays,intIndex),["#"],[]); intDisplayIndex = (integer) llList2String(lstDisplay,0); llSetLinkTexture(intDisplayIndex, keyTexOffline ,ALL_SIDES);
}
}
//This will update a single screen with an associated texture updateDisplay(string strReturnQuery){
debugMessage("strReturnQuery for texturing = " + strReturnQuery); //Extract the query into its elements //return query = "dbResults#ReturnQuery#(productRecord)" //ProductRecord = "Category#Subcategory#Price#Name#TextureUUID" list lstReturnQuery = llParseString2List(strReturnQuery,["#"],[]);
//extract the query ID into its elements //queryID = "linkNumber^queryHash" list lstQuery = llParseString2List(llList2String(lstReturnQuery,1),["#"],[]); string strTextureElement = llList2String(lstReturnQuery,6);
integer intLinkNumber = (integer) llList2String(lstQuery,0); debugMessage("Texture for Prim #"+ (string) intLinkNumber +" = " + strTextureElement );
//Granted, the image for the item index is available, texure it. if( (strTextureElement != "") && (strTextureElement != "NO_IMAGE_AVAILABLE") ){
llSetLinkTexture(intLinkNumber,(key) strTextureElement,ALL_SIDES);
} //If there doesn't appear to be an image for the product, give it the nothing texture else{
llSetLinkTexture(intLinkNumber,keyTexNothing,ALL_SIDES); }
//If query returned something that is equal to product index, capture it as a current index if((llList2String(lstReturnQuery,2) + "#" + llList2String(lstReturnQuery,3)) == ((string)intProductIndexCategory + "#" + (string)intProductIndexSubCategory )){
strCurrentItem = llDumpList2String(llList2List(lstReturnQuery,2,-1),"#"); //change the info card name if (intSeparateInfo == TRUE) { // use the product name plus the strINFO suffix to identify the notecard to deliver; strInfoCardName = llList2String(llList2List(lstReturnQuery,2,-1), 3) + strINFO; }; //NB if FALSE the originally set info card wil be used instead; debugMessage("Current Info name:" + strInfoCardName); //Update prices updatePrices(); } }
//This makes the vendor update the price based upon current Index as well as the displayed objects. updatePrices(){
list lstParsedItem = []; integer intPrice = 0;
if(strCurrentItem != ""){
lstParsedItem = llParseString2List(strCurrentItem,["#"],[]); intPrice = (integer) llList2String(lstParsedItem,2); if((intPrice > 0) && (blnServerDown == FALSE) ){
llSetPayPrice(PAY_HIDE, [intPrice, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
} else{
llSetPayPrice(PAY_HIDE, [PAY_HIDE, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
}
llMessageLinked(LINK_SET,intPrice,"updatePrice",NULL_KEY); //set the prices for the buy/gift buttons } else{
llSetPayPrice(PAY_HIDE, [PAY_HIDE, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
}
}
//This function adds item requests to the buffer before it starts obtaining them from the database itemRequest(integer intCategory, integer intSubCategory, integer intLink){
//keep hash counter going. Never let it reach its end if(intHashCounter == 2147483646 ){
intHashCounter = -2147483646; }
string strQueryID = (string)intLink + "^" + llMD5String("H@5h",++intHashCounter); //take that record and add it to the waitlist lstItemRequestList = llListReplaceList((lstItemRequestList = []) + lstItemRequestList,[(string)intCategory + "#" + (string)intSubCategory + "#" + strQueryID ],intItemRequestList,intItemRequestList);
//increment # of items on the waitlist intItemRequestList++;
llMessageLinked(LINK_SET,0,"dbRequest#" + strQueryID + "#" + (string) intCategory + "#" + (string) intSubCategory ,NULL_KEY);
}
//This function removes item requests by their index removeItemRequest(integer intIndex){
//remove the item by index lstItemRequestList = llDeleteSubList((lstItemRequestList = []) + lstItemRequestList,intIndex,intIndex); //decrement # of items on the waitlist intItemRequestList--; }
//clears the request buffer clearRequests(){
lstItemRequestList= []; intItemRequestList = 0;
}
//Proccesses the dbQuery to see if it matches a request processQuery(string strDBQuery){ integer intIndex = -1; integer blnFound = FALSE; string strQueryID = llList2String(llParseString2List(strDBQuery,["#"],[]),1); list lstParsedRequest = [];
debugMessage("FOSSLVendorClient: Proccessing Query = " + strQueryID );
//loop while there are requests to proccess and if the query doesn't match do{
++intIndex; //advance an index
lstParsedRequest = llParseString2List(llList2String(lstItemRequestList,intIndex),["#"],[]); if(strQueryID == llList2String(lstParsedRequest,2) ){
blnFound = TRUE;
updateDisplay(strDBQuery); removeItemRequest(intIndex); }
}while( (intIndex < intItemRequestList) && (blnFound == FALSE) ); }
default { //Activated upon the beginning of script execution //Start setting up vendor settings state_entry() {
//Keep debug mode in all scripts the same on startup or reset llMessageLinked(LINK_SET,0,"debugMode#"+ (string) blnDebug ,NULL_KEY); llOwnerSay("FOSSLVendorClient: Loading Settings..."); keySettingsId = llGetNotecardLine("FOSSL_CLIENT_SETTINGS", intSettingLines); //Obtain the first line of the vendor settings //llRequestPermissions(llGetOwner(),PERMISSION_DEBIT); //Asks store owner for the ability to sell things. }
//Activated upon rezzing of its container prim //Use this event to update the settings of the vending system on_rez(integer start_param){
//reset the script when I rez it llResetScript();
}
//Activated upon modification of vendor's inventory //Reset script to make use of possible changes changed(integer change){
// If I change the contents of the vendor if(change & CHANGED_INVENTORY){
//reset the script to make use of the changes llResetScript();
}
}
//Activate this event when a companion script sends out a linked message //Use this event to determine if that script is making a request or response of this script //This script accepts requests to go online of offline, link clicked requests, //screen addition requests, buying requests, and info requests link_message(integer sender_num, integer num, string str, key id){
debugMessage("Link message recieved = " + str);
list lstMessage = llParseString2List(str,["#"],[]); string strFunction = llList2String(lstMessage,0);
//Vendor module wants vendor to go online if(strFunction == "goOnline"){
goOnline();
} //Vendor module wants vendor to go offline if(strFunction == "goOffline"){
goOffline(); } //"linkClicked#absoluteCategory#CategoryShift#absoluteSubcategory#SubCategoryShift" if(strFunction == "linkClicked"){
integer intDiffCategory = (integer) llList2String(lstMessage,2); integer intDiffSubCategory = (integer) llList2String(lstMessage,4); integer blnAbsoluteCategory = (integer) llList2String(lstMessage,1); integer blnAbsoluteSubCategory = (integer) llList2String(lstMessage,3);
//Determine Category if(blnAbsoluteCategory == TRUE){ intProductIndexCategory = intDiffCategory; } else{
intProductIndexCategory += intDiffCategory; }
//Determine Subcategory if(blnAbsoluteSubCategory == TRUE){ intProductIndexSubCategory = intDiffSubCategory; } else{
intProductIndexSubCategory += intDiffSubCategory; }
//Keep Category larger than 0 while(intProductIndexCategory < 0){
intProductIndexCategory += (intProductIndexMaxCategory + 1);
}
//Keep SubCategory larger than 0 while(intProductIndexSubCategory < 0){
intProductIndexSubCategory += (intProductIndexMaxSubCategory + 1);
}
//Keep Category less than or equal to max while(intProductIndexCategory > intProductIndexMaxCategory){
intProductIndexCategory -= (intProductIndexMaxCategory+1);
}
//Keep SubCategory less than or equal to max while(intProductIndexSubCategory > intProductIndexMaxSubCategory){
intProductIndexSubCategory -= (intProductIndexMaxSubCategory + 1);
}
clearRequests(); displaysLoading();
} //"addScreen#absoluteCategory#CategoryShift#absoluteSubcategory#SubCategoryShift" else if(strFunction == "addScreen"){
debugMessage("Screen added ... Updating the screens");
lstDisplays += [(string) sender_num + "#" + llList2String(lstMessage,1) + "#" + llList2String(lstMessage,2) + "#" + llList2String(lstMessage,3) + "#" + llList2String(lstMessage,4) ]; clearRequests(); llMessageLinked(LINK_SET,0,"addBuffer" ,NULL_KEY); //set new Buffer Length displaysLoading();
} //"itemBought#BuyerUUID" else if(strFunction == "itemBought"){
key keyBuyerUUID = (key)llList2String(lstMessage,1); list lstItemBought = llParseString2List(strCurrentItem,["#"],[]); string strItemBought = llList2String(lstItemBought,3);
debugMessage( llKey2Name(keyBuyerUUID) + " has bought your item."); llWhisper(0,"Thank you " + llKey2Name(keyBuyerUUID) + " for purchasing the " + strItemBought +".");
//If this is networked, request server to distribute object if(keyServer != NULL_KEY){
//Send another E-mail Request hopefully, its just a missed e-mail request //Make Request for product card UUID //If there are available scripts dedicated to offloading the delay in llEmail, do so. //If not, make the e-mail request within this script taking into account the 20 second //script delay set in by LL to prevent e-mail spam. <:P if(blnEmailAgents == TRUE){
llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ crypt("Give Item") +"#" + crypt((string) keyBuyerUUID + "^" + strItemBought) ,NULL_KEY);
} else{
llEmail((string) keyServer + "@lsl.secondlife.com",crypt("Give Item"),crypt((string) keyBuyerUUID + "^" + strItemBought));
}
} //Otherwise, give the person the object in its own inventory else{
llGiveInventory(keyBuyerUUID, strItemBought); }
} //"infoRequested#requesterUUID" else if(strFunction == "infoRequested"){
intInfoCount++; key keyRequesterUUID = (key)llList2String(lstMessage,1); debugMessage( llKey2Name(keyRequesterUUID) + " wants to know more about your business."); // llGiveInventory(keyRequesterUUID,strInfoCardName); // intInfoCount++; // // } //If this is networked, request server to distribute notecard if(keyServer != NULL_KEY){
//Send another E-mail Request hopefully, its just a missed e-mail request //Make Request for product card UUID //If there are available scripts dedicated to offloading the delay in llEmail, do so. //If not, make the e-mail request within this script taking into account the 20 second //script delay set in by LL to prevent e-mail spam. <:P if(blnEmailAgents == TRUE){
llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ crypt("Give Note") +"#" + crypt((string) keyRequesterUUID + "^" + strInfoCardName) ,NULL_KEY);
} else{
llEmail((string) keyServer + "@lsl.secondlife.com",crypt("Give Note"),crypt((string) keyRequesterUUID + "^" + strInfoCardName));
}
} //Otherwise, give the person the object in its own inventory else{
llGiveInventory(keyRequesterUUID, strInfoCardName); }
} //dbResults#QueryID#(product data) else if(strFunction == "dbResults"){
processQuery(str);//check if response was needed } else{
//Ignore the message
}
} //SEE NEXT REPLY FOR PART 2
|
Fleur Dollinger
Registered User
Join date: 31 Mar 2007
Posts: 8
|
FOSSLVendorMainClient Pt2
04-30-2008 18:40
//PART 2 //used to read vendor settings, calculate index lengths, and retrieve product data dataserver(key query_id, string data) {
//Whenever vendor is reading the settings notecard. //This usually happens once during script initialization //Data should be an assignment per line //Record format should be "variable=value" if (query_id == keySettingsId) { if (data != EOF) { // not at the end of the notecard
//split the record into variable names and values list lstSplit = llParseString2List(data,["="],[]); string strVariable = llToUpper(llStringTrim(llList2String(lstSplit,0),STRING_TRIM)); string strValue = llStringTrim(llList2String(lstSplit,1),STRING_TRIM);
if(strVariable == "LOADING TEXTURE"){
keyTexLoading = (key) strValue;
} if(strVariable == "EMAIL"){
llMessageLinked(LINK_ROOT,950,strValue,"");
} if(strVariable == "SEPARATE INFO"){ intSeparateInfo = (integer) strValue; } if(strVariable == "INFO SUFFIX"){ strINFO = strValue; debugMessage("INFO CARD SUFFIX:" + strINFO); } if(strVariable == "OFFLINE TEXTURE"){
keyTexOffline = (key) strValue;
} if(strVariable == "NOTHING TEXTURE"){
keyTexNothing = (key) strValue;
} if(strVariable == "SERVER"){
keyServer = (key) strValue;
} if(strVariable == "PRODUCT CARD"){
strProductsCardName = strValue;
} if(strVariable == "INFO CARD"){
strInfoCardName = strValue;
} if(strVariable == "COMM CHANNEL"){
intCommChannel = (integer) strValue;
} if(strVariable == "REFRESH"){
fltInventoryRefresh = (float) strValue;
} if(strVariable == "TIMEOUT"){
intServerTimeout = (integer) strValue; } if(strVariable == "BUFFER"){
intBuffer = (integer) strValue;
} if(strVariable == "EMAIL AGENTS"){
blnEmailAgents = (integer) strValue;
} if(strVariable == "KEY"){
strEncryptionKey = strValue;
} keySettingsId = llGetNotecardLine("FOSSL_CLIENT_SETTINGS", ++intSettingLines); // request next line } //Settings notecard has been read, proceed with obtaining products card. else{
llOwnerSay("FOSSLVendorClient: Vendor Settings loaded."); llListen(intCommChannel,"",llGetOwner(),"count"); //activate listen event whenever I say count on the listening channel llListen(intCommChannel,"",llGetOwner(),"debug"); //activate listen event whenever I say debug on the listening channel llListen(intCommChannel,"",llGetOwner(),"reset"); //activate listen event whenever I say reset on the listening channel llListen(intCommChannel,"",llGetOwner(),"online"); //activate listen event whenever I say online on the listening channel llListen(intCommChannel,"",llGetOwner(),"offline"); //activate listen event whenever I say offline on the listening channel llListen(intCommChannel,"",llGetOwner(),"memory"); //activate listen event whenever I say memory on the listening channel //Is this vendor networked? if(keyServer != NULL_KEY){
llOwnerSay("FOSSLVendorClient: Vendor is networked. Contacting Server for Product List.");
//If there are available scripts dedicated to offloading the delay in llEmail, do so. //If not, make the e-mail request within this script taking into account the 20 second //script delay set in by LL to prevent e-mail spam. <:P if(blnEmailAgents == TRUE){
llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ crypt("Requesting Product List") + "#" + crypt("NULL"),NULL_KEY);
} else{
llEmail((string) keyServer + "@lsl.secondlife.com",crypt("Requesting Product List"),crypt("NULL"));
} blnWaitingForServer = TRUE; intEmailRequestStarted = llGetUnixTime(); llSetTimerEvent(1.0); } //Otherwise, if it is not networked, load the product list uuid locally else{
llOwnerSay("FOSSLVendorClient: Vendor is not networked. Obtaining Product List locally."); keyProductsUUID = llGetInventoryKey(strProductsCardName); llOwnerSay("FOSSLVendorClient: Determining Maximums for Categories and Subcategories. This may take a while..."); //start obtaining the # of categories and subcategories keyProductCategories = llGetNotecardLine(keyProductsUUID,intProductLines); }
//Update database buffer to the length specified by notecard llMessageLinked(LINK_SET, 0, "setBuffer#" + (string) intBuffer, NULL_KEY); } } //Whenever vendor is reading the products notecard to determine size of its categories and subcategories. else if(query_id == keyProductCategories){
//If the products notecard needs to be read further... if(data != EOF){
list lstProductParsedLine = llParseString2List(data,["#"],[]); //Parse the line into a list
//Determine if current Category # is the current Maximum if(intProductIndexMaxCategory < (integer) llList2String(lstProductParsedLine,0)){
intProductIndexMaxCategory = (integer) llList2String(lstProductParsedLine,0); }
//Determine if current SubCategory # is the current Maximum if(intProductIndexMaxSubCategory < (integer) llList2String(lstProductParsedLine,1)){
intProductIndexMaxSubCategory = (integer) llList2String(lstProductParsedLine,1); }
//Read the next line of the products notecard keyProductCategories = llGetNotecardLine(keyProductsUUID,++intProductLines); } //After reading the notecard, vendor is ready to operate else{
llOwnerSay("FOSSLVendorClient: Categories and SubCategories determined. Vendor is now able to load products.");
intProductLines = 0; //clear this for later updates clearRequests(); //clear any requests for products if any llMessageLinked(LINK_SET,0,"setBuffer#" + (string) intBuffer ,NULL_KEY);//clear the current list of products in buffer, if any llMessageLinked(LINK_SET, 0, "setDB#" + (string) keyProductsUUID, NULL_KEY); //Tell Database where it gets its data goOnline();
//Request displays to register if there are none already if(lstDisplays == []){
llMessageLinked(LINK_SET,0,"getDisplays",NULL_KEY); //request all screens to register
}
//Only refresh the inventory if it is networked if(keyServer != NULL_KEY){
llSetTimerEvent(fltInventoryRefresh); //Set timer to request product notecard uuid at a set interval
} } } }
timer(){
//Depending on if the vendor is waiting from a response from the server, //either wait for an e-mail from the server, or make a request for an updated product list if(blnWaitingForServer == TRUE){
if(llGetUnixTime() - intEmailRequestStarted < intServerTimeout){
llGetNextEmail((string) keyServer + "@lsl.secondlife.com",crypt("Update Product List")); //llGetNextEmail("",""); } else{
//take vendor offline if not done already goOffline();
//Send another E-mail Request hopefully, its just a missed e-mail request //Make Request for product card UUID //If there are available scripts dedicated to offloading the delay in llEmail, do so. //If not, make the e-mail request within this script taking into account the 20 second //script delay set in by LL to prevent e-mail spam. <:P if(blnEmailAgents == TRUE){
llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ crypt("Requesting Product List") + "#" + crypt("NULL"),NULL_KEY);
} else{
llEmail((string) keyServer + "@lsl.secondlife.com",crypt("Requesting Product List"),crypt("NULL"));
}
intEmailRequestStarted = llGetUnixTime(); //After this, timer loop will look for a server response }
} else{
//Make Request for product card UUID //If there are available scripts dedicated to offloading the delay in llEmail, do so. //If not, make the e-mail request within this script taking into account the 20 second //script delay set in by LL to prevent e-mail spam. <:P if(blnEmailAgents == TRUE){
llMessageLinked(LINK_SET,0,"EmailRequest#" + (string) keyServer + "@lsl.secondlife.com#"+ crypt("Requesting Product List") + "#" + crypt("NULL"),NULL_KEY);
} else{
llEmail((string) keyServer + "@lsl.secondlife.com",crypt("Requesting Product List"),crypt("NULL"));
}
blnWaitingForServer = TRUE; intEmailRequestStarted = llGetUnixTime(); //After this, timer loop will look for a server response llSetTimerEvent(1.0);
}
}
email(string time, string address, string subject, string body, integer remaining){
debugMessage("Recieved E-mail from : " + address);
if (address == (string) keyServer + "@lsl.secondlife.com") { //don't wait for more e-mail blnWaitingForServer = FALSE;
//make this the last time products were updated intLastProductUpdate = llGetUnixTime(); //Remove e-mail header to generate the new uuid key keyNewUUID = (key) crypt(llDeleteSubString(body, 0, llSubStringIndex(body, "\n\n") + 1));
//New product notecard uuid is in the message keyProductsUUID = keyNewUUID;
//start obtaining the # of categories and subcategories keyProductCategories = llGetNotecardLine(keyProductsUUID,intProductLines);
//polling for further e-mails using the timer event is no longer neccesary llSetTimerEvent(0.0); }
//} if(remaining > 0 ){
//load the next e-mail in que to try and clear the e-mail buffer llGetNextEmail((string) keyServer + "@lsl.secondlife.com",crypt("Update Product List")); // llGetNextEmail("",""); // llGetNextEmail("",""); } }
listen( integer channel, string name, key id, string message ){
if(id == llGetOwner()){
//Count the number of times users requested information if(message == "count"){ llOwnerSay("FOSSLVendorClient: Notecard info request at " + (string)intInfoCount + "."); } //Enable or disable verbose output else if(message == "debug"){
blnDebug = !blnDebug; llOwnerSay("FOSSLVendorClient: Debug Mode set to: " + (string) blnDebug); llMessageLinked(LINK_SET,0,"debugMode#" + (string) blnDebug,NULL_KEY);
}
//Make the vendor go online else if(message == "online"){
goOnline(); debugMessage("Vendor attempting to go online"); } //Make the vendor go offline else if(message == "offline"){
goOffline(); debugMessage("Vendor attempting to go offline"); } //Reset the scripts else if(message == "reset"){ llResetScript();
} //Get the current free memory in script else if(message == "memory"){
llOwnerSay("FOSSLVendorClient: Memory = " + (string) llGetFreeMemory() +"/16000 Bytes"); llMessageLinked(LINK_SET,0,"getMemory",NULL_KEY); //If other scripts understand this, have them output free memory also } else{ llOwnerSay("FOSSLVendorClient: I dunno what youre talking about."); } }
}
}
|
Kinji Lockjaw
Registered User
Join date: 2 Aug 2008
Posts: 1
|
Fossly vending for magazines
08-03-2009 13:48
I bought the Fossl vending system but I don't want to sell items just use it to provide copyable, transfer vendors for my magazine. How do i go about doing that?
|
Rolig Loon
Not as dumb as I look
Join date: 22 Mar 2007
Posts: 2,482
|
08-03-2009 14:27
If you're not going to be handling any money, this script may be overkill. I think all your vendor units need is a way to update their contents every time you have a new issue to distribute, and then a way to hand a free copy of the issue to a customer. Take a look at  for another, easier way to do that first task. The second task, handing out free copies, is just a matter of putting llGiveInventory(llDetectedKey(0), llGetInventoryName(INVENTORY_OBJECT,0)) in a touch_start event. You can build in bells and whistles to gather circulation statistics and such, but if all you need are these relatively simple tasks, why go with all that extra freight?
_____________________
It's hard to tell gender from names around here but if you care, Rolig = she. And I exist only in SL, so don't ask....  Look for my work in XStreetSL at 
|