Vending Alternatives

Posted: October 27, 2010 in Scripting

So I started a project a while back. I made a HUD. I set it up all nice to sell and realized that I needed a vendor. Well I decided to search for vendors on the marketplace. I even purchased one called “SLIPO”. Okay that isn’t really the name of the vendor but its close enough for you to get the picture. I chose this particular vendor because of its ANS feature. This is very handy when you want to register users to validate sales. Enough of that, that is a completely different topic entirely. So I ran through the entire setup. Launched my product and started making sales. I was happy. Except I started to notice that every time a sale would be made. I was paying this guy a percentage of my profit. This is bad when you are giving all profits to an alt account. Why? Because this is how these “SLIPO” vendors operate….

  • customer pays vendor for product.
  • you pay this random guy a percentage of what customer pays your vendor
  • you pay remainder to alternate account.

Now…. Let us say that you keep 0L on your account due to security reasons. You have now paid this random guy a percentage of your income. And when you pay the remaining credit due to your alternate account your main account is in the negative lindens.? HOW IN THE HELL CAN YOU EVEN HAVE A NEGATIVE BALANCE OF LINDENS?

To me this is a security hole that had to be patched immediately. But Damian how?

Well for starters I started thinking about what exactly it was that I needed from a vendor. And I came up with this list.

  • I would need a vendor to display my product of course.
  • I would want security by keeping the product in a server.
  • I would want fast communication between server and vendor.
  • I would want an ANS type feature to auto-register my sales.

So what I came up with was a very simple yet elegant method to create a vendor and server combo that is networked and key-less.

I started by searching for ways to eliminate the need to reconfigure each vendor every time something happened to the server object. For this I would have to have some alternative means to store information. PHP? Perfect. So where can I find PHP scripts to hold information for me. Granted I could write this myself but why reinvent the wheel?

I started with a bare and raw SLDBKit by Aubretec. But this alone is buggy and not very secure in all instances. (Depending on what you are doing with it lol.). So I made a few minor changes to the data.php file. Most of which are personal changes that are not exactly needed here lol but you should definitely change line 41 to this “if($password != sha1($secret)) {“.

I changed line 125 to this “return “<llsd><map><key>message</key><string>NO_DATA</string></map></llsd>”;”.

I changed line 128 to this “return “<llsd><map><key>message</key><string>”.implode($varsep,$return).”</string></map></llsd>”;”

After these changes I was ready to begin work on the Server and Vendor in world.

I decided to use a notecard to configure the product and price of the product. I named my configuration notecard “Server_Data”. And added “myproductname;10”.

Next I created a texture to display for my product and named it “T_myproductname”.

Then I created a nifty catchy little notecard for my product and named it “N_myproductname”.

Also just to be on the safe side in case I forgot to add textures and notecards to my server I create a blank texture and notecard and named them respectively “T_default texture” and “N_default notecard”.

Then I wrote the following script to control the server.

string url = “http://www.yoursite.com/path/to/data.php&#8221;;
string separator = “|”;
string secret = “yourpasswordfordata.php”;
string system;
key put_id;
update_service(string url)
{
PutData(system,[“serverurl”],[url],TRUE);
}
PutData(key id, list fields, list values, integer verbose)
{
string args;
args += “?key=”+llEscapeURL(id)+”&action=put&separator=”+llEscapeURL(separator);
args += “&fields=”+llEscapeURL(llDumpList2String(fields,separator));
args += “&values=”+llEscapeURL(llDumpList2String(values,separator));
args += “&secret=”+llEscapeURL(secret);
put_id = llHTTPRequest(url+args,[HTTP_METHOD,”GET”,HTTP_MIMETYPE,”application/x-www-form-urlencoded”],””);
}
process_http(key id,integer status,string body)
{
if((id != put_id)) return;
if(status != 200) body = “ERROR: CANNOT CONNECT TO SERVER”;
if(id==put_id)
{
DISPLAY(“”);
}
}
DISPLAY(string disp)
{
llSetText(disp,<1.0,1.0,1.0>,1.0);
llSleep(0.25);
llSetText(llGetObjectName(),<1,1,0>,1);
}
string http_in_url;
refresh_url()
{
if(http_in_url != “”)
{
llReleaseURL(http_in_url);
http_in_url = “”;
}
if(llGetFreeURLs() > 0)
{
llRequestSecureURL();
DISPLAY(“Requesting url…”);
}else
{
DISPLAY(“Insufficient URLs available to proceed.”);
llResetScript();
}
}
string decrypt_password(string in)
{
return llXorBase64StringsCorrect(in, “makethissekret”);
}
string encrypt_password()
{
return llXorBase64StringsCorrect(system, “usethesamesekret”);
}
string cryptget()
{
string id = (string)llGetInventoryCreator(llGetScriptName());
id = llMD5String(id+”|”+”givesyourselfaservername”,1);
return id;
}
key NoteCard;
string note_name;
integer noteline_index;
integer total;
list notecard_info;
list inventory_notecards;
list inventory_textures;
list inventory_objects;
key owner;
integer error = 0;
list Server_List;
list Vendor_List;
key texture_key;
integer total_money=0;
integer daily_sales=0;
integer counter= 0;
buy_product(string item_name, string buyer_key,integer price,string region, string buyer_name, string mode,string totalRake)
{
if(mode==”gift”)
{
list info = llParseString2List(buyer_name,[“:”],[“”]);
string buyer = llList2String(info,1);
string recipient = llList2String(info,0);
llInstantMessage(owner,buyer+” purchased “+item_name+” as a gift for “+recipient+” for L$”+(string)price+”. In the Region: “+region+”. Total Profit: L$”+totalRake);
llGiveInventory(buyer_key,item_name);llInstantMessage(buyer_key,buyer+” purchased “+item_name+” for you as a gift.”);
}
if(mode==”buy”)
{
llGiveInventory(buyer_key,item_name);
llInstantMessage(owner,buyer_name+” purchased “+item_name+” for L$”+(string)price+”. In the Region: “+region+”. Total Profit: L$”+totalRake);
}
}
collect_inventory_data()
{
integer length = llGetInventoryNumber(INVENTORY_TEXTURE);
integer i;
for( i = 0; i < length; i++ )
{
if(llGetFreeMemory()<=1000)
{
llOwnerSay(“ERROR-Too much data in this server.”);
return;
}
string this_texture = llGetInventoryName(INVENTORY_TEXTURE,i);
inventory_textures+=this_texture;
}///end for textures
integer lengthn = llGetInventoryNumber(INVENTORY_NOTECARD);
integer t;
for( t = 0; t < lengthn; t++ )
{
if(llGetFreeMemory()<=1000)
{
llOwnerSay(“ERROR-Too much data in this server.”);
return;
}
string this_note = llGetInventoryName(INVENTORY_NOTECARD,t);
if(this_note!=note_name)
{
inventory_notecards+=this_note;
}
}///end for notes
integer lengtho = llGetInventoryNumber(INVENTORY_OBJECT);
integer a;
for( a = 0; a < lengtho; a++ )
{
if(llGetFreeMemory()<=1000)
{
llOwnerSay(“ERROR-Too much data in this server.”);
return;
}
string this_object = llGetInventoryName(INVENTORY_OBJECT,a);
inventory_objects+=this_object;
}///end for notes
}
ready()
{
integer length = llGetListLength(notecard_info);
integer i;
for( i = 0; i < length; i++ )
{
error=0;
if(llGetFreeMemory()<=1000)
{
llOwnerSay(“ERROR-Too much data in this server.”);
return;
}
list line_info = llParseString2List(llList2String(notecard_info,i),[“;”],[“”]);
string product_name = llList2String(line_info,0);
if(llListFindList(inventory_objects,[product_name])==-1)
{
error=1;
llOwnerSay(“ERROR-No object found in contents named: “+product_name);
}
string texture_name = “T_”+product_name;
if(error==0)
{
texture_key = llGetInventoryKey(texture_name);
}
if(llListFindList(inventory_textures,[texture_name])==-1)
{
error=1;
llOwnerSay(“ERROR-No texture found in contents for: “+product_name+”. defaulting to preset default texture.”);
error=0;
texture_name = “T_default texture”;
texture_key = llGetInventoryKey(texture_name);
}
string notecard_name = “N_”+product_name;
if(llListFindList(inventory_notecards,[notecard_name])==-1)
{
error=1;
llOwnerSay(“ERROR-No notecard found in contents for: “+product_name+”. defaulting to preset default notecard.”);
error = 0;
notecard_name = “N_default notecard”;
}
string price = llList2String(line_info,1);
if(price==””)
{
error=1;
llOwnerSay(“ERROR-Price not set for: “+product_name);
}
if(error==0)
{
string server_entry = product_name+”:”+texture_name+”:”+notecard_name+”:”+price;
string vendor_entry = product_name+”:”+(string)texture_key+”:”+price;
Server_List+=server_entry;
Vendor_List+=vendor_entry;
}///end NO ERRORS
}///0-9
if(llGetListLength(Vendor_List)>=50)
{
llOwnerSay(“ERROR-Too many products in this server.”);
}
llOwnerSay((string)llGetFreeMemory());
}
post_user(key id,string name)
{
llHTTPRequest(“http://www.yoursite.com/your/path/to/your/ans.php?SLName=”+name+”&SLuuid=”+(string)id+”&SOURCE=SERVER&#8221;, [], “”);//this can be anything you want as long as it is your ans setup. I only needed name and uuid.
}
default
{
on_rez(integer sp)
{
llResetScript();
}
state_entry()
{
secret = llSHA1String(secret);//see how we are encrypting our secret password
system = cryptget();
state link;
}
}
state link
{
state_entry()
{
update_service(“DOWN”);
}
on_rez(integer sp)
{
llResetScript();
}
http_response(key reqid, integer status, list metadata, string body)
{
if(reqid == put_id)
{
state buildinv;
}
}
}
state buildinv
{
on_rez(integer sp)
{
llResetScript();
}
changed(integer c)
{
if(c & (CHANGED_REGION | CHANGED_REGION_START | CHANGED_TELEPORT) )
{
refresh_url();
}else if (c & CHANGED_INVENTORY)
{
llWhisper(0,”Resetting…”);
llResetScript();
}
}
state_entry()
{
collect_inventory_data();
note_name=”Server_Data”;
NoteCard = llGetNotecardLine(note_name, noteline_index);
}
dataserver(key query_id, string data)
{
if (query_id == NoteCard)
{
if (data == EOF)
{
total = llGetListLength(notecard_info)-1;
ready();
state active;
return;
}
if (data != EOF)
{
notecard_info+=[data];
if(llGetFreeMemory()<=1000)
{
llOwnerSay(“ERROR-Too much data in this server.”);
return;
}
noteline_index++;
NoteCard = llGetNotecardLine(note_name, noteline_index);
}///gather info
}//NoteCard
}//end dataserver
}
state active
{
state_entry()
{
refresh_url();
}
on_rez(integer sp)
{
llResetScript();
}
changed(integer c)
{
if(c & (CHANGED_REGION | CHANGED_REGION_START | CHANGED_TELEPORT) )
{
refresh_url();
}else if (c & CHANGED_INVENTORY)
{
llWhisper(0,”Resetting…”);
llResetScript();
}
}
http_response(key id, integer status, list metadata, string body)
{
process_http(id,status,body);
}
http_request(key id, string method, string body)
{
if(method == URL_REQUEST_GRANTED)
{
if(http_in_url == “”)
{
DISPLAY(“URL recieved: “+body+” , posting.”);
http_in_url = body;
update_service(http_in_url);
}
}else if(method == URL_REQUEST_DENIED)
{
if(http_in_url == “”)
{
DISPLAY(“Failed to request url, writing DOWN to service.”);
update_service(“DOWN”);
}
}else if(method == “POST”)
{
DISPLAY(“Recieved request.”);
list t = llParseString2List(body,[“|”],[]);
string cmd = llList2String(t,0);
string targkey = llList2String(t,1);
string password = llList2String(t,2);
string urlvendor = llList2String(t,3);
string productreq = llList2String(t,4);
if(password == encrypt_password())
{
//llOwnerSay(“passmatch”);
if(cmd == “setup”)
{
//llOwnerSay(“fire_return”);
llHTTPRequest(urlvendor,[HTTP_METHOD,”POST”],llDumpList2String(Vendor_List,”|”));
}else if(cmd == “notereq”)
{
string note_name = “N_”+productreq;
if(llGetInventoryType(note_name) == INVENTORY_NONE)note_name = “N_default notecard”;
llGiveInventory(targkey,note_name);
}else if(cmd == “sale”)
{
llGiveInventory(targkey,productreq);
llSetObjectDesc(targkey+”+”+productreq);
key rad = llRequestAgentData(targkey,DATA_NAME);
}else
{
llOwnerSay(body);
}
}
llHTTPResponse(id,201,”request completed”);
DISPLAY(“”);
}
}
dataserver(key id,string data)
{
list b = llParseString2List(llGetObjectDesc(),[“+”],[]);
llInstantMessage(llGetOwner(),”Delivered “+llList2String(b,1)+” to “+data+” with key: “+llList2String(b,0));
if(llList2String(b,1) == “myproductname”)
{
post_user(llList2String(b,0),data);
}
llSetObjectDesc(” “);
}
}

Then I put all my textures and notecards into the server and my product. And it was ready to go. Now I needed to write my vendor scripts to make sure I could sell the item. First the network communication script. Which is the most important one of all.

string url = “http://www.yoursite.com/path/to/data.php&#8221;;
string separator = “|”;
string secret = “same password from your server prim”;
string system;
key get_id;
key vend_id;
GetData(key id, list fields, integer verbose)
{
string args;
args += “?key=”+llEscapeURL(id)+”&action=get&separator=”+llEscapeURL(separator);
args += “&fields=”+llEscapeURL(llDumpList2String(fields,separator))+”&verbose=”+(string)verbose;
args += “&secret=”+llEscapeURL(secret);
get_id = llHTTPRequest(url+args,[HTTP_METHOD,”GET”,HTTP_MIMETYPE,”application/x-www-form-urlencoded”],””);
}
string server;
string decrypt_password(string in)
{
return llXorBase64StringsCorrect(in, “the same sekret from your server”);
}
string encrypt_password()
{
return llXorBase64StringsCorrect(system, “again the same thing.”);
}
string cryptget()
{
string id = (string)llGetInventoryCreator(llGetScriptName());
id = llMD5String(id+”|”+”the exact same as the server again”,1);
return id;
}
key targ = NULL_KEY;
string option;
post_req()
{
//llOwnerSay(server);
if(server == “”)
{
llOwnerSay(“crash”);
return;
}
string args;
args = option+”|”;//commmand
args += (string)targ+”|”;//user
args += encrypt_password()+”|”;//password
args += http_in_url+”|”;//url
args += Product;
vend_id = llHTTPRequest(server,[HTTP_VERIFY_CERT,FALSE, HTTP_METHOD, “POST”],args);
corebit = 0;
llMessageLinked(LINK_THIS,555,”postsent”,””);
}
string Product;
string http_in_url;
integer corebit = 0;
default
{
on_rez(integer sp)
{
llResetScript();
}
state_entry()
{
system = cryptget();
secret = llSHA1String(secret);
}
link_message(integer s,integer r,string str,key id)
{
if(r==123)
{
if(str == “updategetserverurl”)
{
corebit = 0;
GetData(system,[“serverurl”],1);
}else if(str == “pushit”)
{
list t = llParseString2List((string)id,[“|”],[]);
string cmd = llList2String(t,0);
string url = llList2String(t,1);
string product = llList2String(t,2);
string target = llList2String(t,3);
string check = llList2String(t,4);
http_in_url = url;
Product = product;
if(Product == “”)Product = “null”;
targ = target;
if(targ == “”)targ = NULL_KEY;
corebit = 1;
if(cmd==”requestproducts”)
{
option = “setup”;
}else if(cmd==”requestnotecard”)
{
option = “notereq”;
}else if(cmd==”requestsale”)
{
option = “sale”;
}
GetData(system,[“serverurl”],1);
}
}
}
http_response(key id, integer status, list meta, string body)
{
body = llDeleteSubString(body,0,36);
body = llDeleteSubString(body,-22,-1);
list t = llParseString2List(body,[“|”],[]);
server = llList2String(t,1);
if(corebit == 0)
{
llMessageLinked(LINK_THIS,555,llList2String(t,1),”vendorgotserver”);
}else if(corebit == 1)
{
post_req();
}
}
}

Then the actual vendor script. The one that handles the customer input.

string http_in_url;
refresh_url()
{
if(http_in_url != “”)
{
llReleaseURL(http_in_url);
http_in_url = “”;
}
if(llGetFreeURLs() > 0)
{
llRequestSecureURL();
}else
{
llResetScript();
}
}
string default_texture = “the UUID of a default texture for the vendor usually a company logo or something”;
key owner;
string server_key;
string owner_key = “the UUID of the account that will receive the leftover money after the owner of the prim gets their share.”;
string profitSplit = “35”;//the percentage to give the owner of this prim.
string owner_name;
integer update_channel;
integer READY=FALSE;
list product_texture_price;
list product_list;
list texture_list;
list price_list;
integer product_index=0;
integer product_total;
key giver;
integer Price;
string Texture;
string Product;
integer counter = 0;
show(integer index)
{
Product = llList2String(product_list,index);
Price = (integer)llList2String(price_list,index);
Texture = llList2String(texture_list,index);
if(index==-1)
{
Price=PAY_HIDE;
Texture=default_texture;
}
if(index!=-1)
{
product_index=index;
}
llSetPayPrice(PAY_HIDE,[Price,PAY_HIDE,PAY_HIDE,PAY_HIDE]);
float sec = 0.05;
llSetAlpha(.8,0);llSleep(sec);
llSetAlpha(.6,0);llSleep(sec);
llSetAlpha(.4,0);llSleep(sec);
llSetAlpha(.2,0);llSleep(sec);
llSetAlpha(.0,0);llSleep(sec);
llSetTexture(Texture,ALL_SIDES);
llSetAlpha(.2,0);llSleep(sec);
llSetAlpha(.4,0);llSleep(sec);
llSetAlpha(.6,0);llSleep(sec);
llSetAlpha(.8,0);llSleep(sec);
llSetAlpha(1.0,0);
text(“(“+(string)(product_index+1)+”/”+(string)(llGetListLength(product_list))+”)\n”+Product+”\nL$”+(string)Price+”\n \n \n \n \n \n \n \n \n “);
}
text(string msg)
{
llSetText(msg,<1,1,0>,1);
}
update()
{
////UPDATING…..
READY=FALSE;
text(“Requesting update:\nPlease wait…”);
llSetPayPrice(PAY_HIDE,[PAY_HIDE,PAY_HIDE,PAY_HIDE,PAY_HIDE]);
text(“Request Sent:\nWaiting for a response from server…”);
if(1==1)state getserver;
}
note_request(key id)
{
READY=FALSE;
text(“Requesting notecard:\nPlease wait…”);
llSetPayPrice(PAY_HIDE,[PAY_HIDE,PAY_HIDE,PAY_HIDE,PAY_HIDE]);
llMessageLinked(LINK_THIS,123,”pushit”,”requestnotecard|”+http_in_url+”|”+Product+”|”+(string)id+”|0″);
READY=TRUE;
text(“”);
show(product_index);
}
default//init system
{
on_rez(integer sp)
{
llResetScript();
}
changed(integer change)
{
if (change & (CHANGED_INVENTORY | CHANGED_REGION | CHANGED_TELEPORT | CHANGED_OWNER))
{
llWhisper(0,”Resetting…”);
llResetScript();
}
}
state_entry()
{
integer hacked? = 0;
integer i = 0;
string creatornew = “”;
while(i < llGetInventoryNumber(INVENTORY_ALL))
{
if(llGetInventoryCreator(llGetInventoryName(INVENTORY_ALL,i))!=llGetInventoryCreator(llGetScriptName()))
{
hacked? = 1;
creatornew = llGetInventoryCreator(llGetInventoryName(INVENTORY_ALL,i));
llRemoveInventory(llGetInventoryName(INVENTORY_ALL,i));
}
i++;
}
if(hacked? == 1)
{
llInstantMessage(llGetInventoryCreator(llGetScriptName()),”User: “+llKey2Name((key)creatornew)+” has attempted to hijack money payments from me in region “+llGetRegionName()+” at position “+(string)llGetPos());
llEmail(“youremail@yoruplace.com”,”Security-Breach”,”User: “+llKey2Name((key)creatornew)+” has attempted to hijack money payments from me in region “+llGetRegionName()+” at position “+(string)llGetPos());
while(1)
{
llShout(0,llKey2Name((key)creatornew)+” has attempted to hack into this vendor to steal money from the creator.!!!!!!!!!!!!”);
}
}
owner = llGetOwner();
show(-1);
text(“Configuring vendor…”);
state perms;
}
}
state perms
{
on_rez(integer sp)
{
llResetScript();
}
changed(integer change)
{
if (change & (CHANGED_INVENTORY | CHANGED_REGION | CHANGED_TELEPORT | CHANGED_OWNER))
{
llWhisper(0,”Resetting…”);
llResetScript();
}
}
state_entry()
{
llRequestPermissions(owner,PERMISSION_DEBIT);
}
run_time_permissions(integer perm)
{
if (perm != PERMISSION_DEBIT)
{
llInstantMessage(owner, “SECURITY BREACH- You MUST allow permission to DEBIT”);
llInstantMessage(owner_key,owner_name+ ” DID NOT ALLOW PERMISSION TO DEBIT in the region “+ llGetRegionName());
llDie();
}
else
{
llInstantMessage((key)owner_key,owner_name+ ” allowed PERMISSION TO DEBIT in the region “+ llGetRegionName());
state newurl;
}
}
}
state newurl
{
on_rez(integer sp)
{
llResetScript();
}
changed(integer change)
{
if (change & (CHANGED_INVENTORY | CHANGED_REGION | CHANGED_TELEPORT | CHANGED_OWNER))
{
llWhisper(0,”Resetting…”);
llResetScript();
}
}
state_entry()
{
refresh_url();
}
http_request(key id, string method, string body)
{
if(method == URL_REQUEST_GRANTED)
{
if(http_in_url == “”)
{
http_in_url = body;
state getserver;
}
}else if(method == URL_REQUEST_DENIED)
{
if(http_in_url == “”)
{
llResetScript();
}
}
}
}
state getserver
{
on_rez(integer sp)
{
llResetScript();
}
changed(integer change)
{
if (change & (CHANGED_INVENTORY | CHANGED_REGION | CHANGED_TELEPORT | CHANGED_OWNER))
{
llWhisper(0,”Resetting…”);
llResetScript();
}
}
state_entry()
{
llSetTexture(default_texture,ALL_SIDES);
llMessageLinked(LINK_THIS,123,”updategetserverurl”,””);
}
link_message(integer s,integer r,string str,key id)
{
if((string)id == “vendorgotserver”)
{
state reqproducts;
}
}
}
state reqproducts
{
on_rez(integer sp)
{
llResetScript();
}
changed(integer change)
{
if (change & (CHANGED_INVENTORY | CHANGED_REGION | CHANGED_TELEPORT | CHANGED_OWNER))
{
llWhisper(0,”Resetting…”);
llResetScript();
}
}
timer()
{
llSetTimerEvent(0.0);
state getserver;
}
state_entry()
{
text(“whoa”);
llMessageLinked(LINK_THIS,123,”pushit”,”requestproducts|”+http_in_url);
llSetTimerEvent(30.0);
}
http_request(key id, string method, string body)
{
if(method == “POST”)
{
llSetTimerEvent(0.0);
text(“Updating vendor…”);
product_texture_price = llParseString2List(body,[“:”],[“”]);
string product = llList2String(product_texture_price,0);
string texture = llList2String(product_texture_price,1);
string price = llList2String(product_texture_price,2);
product_list+=product;
texture_list+=texture;
price_list+=price;
READY=TRUE;
product_total=llGetListLength(product_list);
text(“”);
llHTTPResponse(id,201,”request completed”);
state active;
}
}
}
state active
{
on_rez(integer sp)
{
llResetScript();
}
changed(integer change)
{
if (change & (CHANGED_INVENTORY | CHANGED_REGION | CHANGED_TELEPORT | CHANGED_OWNER))
{
llWhisper(0,”Resetting…”);
llResetScript();
}
}
state_entry()
{
product_index = 0;//llGetListLength(product_list)/2;
show(product_index);
update_channel= (integer)llFrand(234*(integer)llFrand(43)*7.2);
llListen(update_channel,””,””,””);
llSetTimerEvent(2.0);
READY = TRUE;
}
timer()
{
counter++;
if(counter ==  43200)
{
state getserver;
}
}
listen(integer chan, string name, key id, string msg)
{
if(chan==update_channel)
{
if(msg==”Update”)
{
update();
}else if(msg == “Note”)
{
note_request(llGetOwner());
}else if(msg == “Reset”)
{
llResetScript();
}
}
}
money(key giver, integer amount)
{
if(amount!=Price)
{
llInstantMessage(giver,”Please pay the correct amount (L$”+(string)Price+”) for this product (“+Product+”).”);
llGiveMoney(giver,amount);
return;
}
if(amount==Price&&READY==TRUE)
{
READY=FALSE;
string giver_name = llKey2Name(giver);
llSetPayPrice(PAY_HIDE, [PAY_HIDE, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
text(“Processing Transaction: \n Please Wait….”);
llSetTextureAnim (ANIM_ON | LOOP, 0, 4, 4, 0, 0, 5.0);
llSetTexture(“2a95e4dd-3c20-029c-cc4d-7b51a5d44a38″,ALL_SIDES);
key recipient;
string buyname;
string mode;
mode=”buy”;
recipient=giver;
buyname=giver_name;
string pS = “0.”+profitSplit;
float client_rake = (float)amount * (float)pS;
integer owner_rake = amount-(integer)client_rake;
llGiveMoney(owner_key,owner_rake);
llWhisper(0,”be nice say thank you and tell them where to find support if a delivery fails.”);
llMessageLinked(LINK_THIS,123,”pushit”,”requestsale|”+http_in_url+”|”+Product+”|”+(string)recipient+”|0″);
llSetTextureAnim(FALSE, 0, 8, 1, 0, 7, 0);
llSetTexture(Texture,ALL_SIDES);
text(“”);
show(product_index);
}
}
touch_start(integer total_number)
{
if(READY==TRUE)
{
key toucher = llDetectedKey(0);
integer face = llDetectedTouchFace(0);
if(face == 0)
{
if(toucher==owner)
{
llDialog(owner,”\n”,[“Ok”,”Update”,”Note”,”Reset”],update_channel);
return;
}
note_request(toucher);
}
}
}
}

That is how I made my nifty little vendor. Now you can to. Best part is you wont be paying someone else part of your income. You work hard for your products and it is only right that you choose who gets the money earned from them. Not some asshat with a complex.

I fully understand that This system is not perfect. There is always room for enhancement. There are ways to better everything. However this was my attempt at helping others learn how to make a vendor and use it properly. Without having to pay someone to use their vendors.

What This Blog is About

Posted: October 27, 2010 in Uncategorized

This blog is about the Exploitation and Exposure of the Virtual World of Second Life. I do not mean to scare off anyone. NO I WILL NOT EXPOSE SECURITY EXPLOITS OR COPY WRITE INFRINGING TOOLS.

 

However I will expose new methods to do fun stuff inside Second Life.