User:Yumi Murakami/Golden Vendor
This is a vendor which has an additional function: an avie can click on the vendor frame and pay a small fee to "claim" the vendor. For a certain period of time, they then get commission on all sales. The idea was to combine a vendor and a game by allowing people to earn L$ by selling a product to others. Didn't take off very much, but I know some people still liked it, in part because of my super paranoid validation that the vendor is set up properly (largely because I was burned by badly set ones several times myself..).
This is in two parts: the vendor and the frame. The frame needs to be a separate object near the vendor, but not linked. Originally the frame was just that - a frame - and the vendor was just a box, but nothing in the script really requires that.
<lsl>
key currentClaimer = NULL_KEY; string currentClaimerName;
string itemToSell; string infocardName; integer itemPrice; integer claimAmount; integer claimPrice; integer claimTime;
list percentSplits;
key myFrame;
integer notecardLine; integer maxLine; string notecardName = "Configuration Notecard";
key partnerKey; string partnerName; integer partnerSplit; integer doingPartnerRequest; integer totalPartnerSplits; integer claimStartTime; key lastFrameClick; integer startUpTime;
integer totalSales; integer totalNotecards; integer totalClaims; integer totalClaimedSales;
integer autoAdjustClaim; float aaClaimMultiplier = 2.0; integer aaClaimMinimum = 4;
init() {
llSay(-593927,"reset");
partnerKey = NULL_KEY;
partnerSplit = 0;
totalPartnerSplits = 0;
doingPartnerRequest = FALSE;
autoAdjustClaim = FALSE;
llOwnerSay("Reading notecard.. (this may take a few moments)");
if (llGetInventoryType(notecardName) != INVENTORY_NOTECARD) {
llOwnerSay("Error: Configuration Notecard is missing!");
state setupError;
}
doingPartnerRequest = FALSE;
notecardLine = -1;
llGetNumberOfNotecardLines(notecardName);
}
adjustAmount() {
integer upTime = (llGetUnixTime() - startUpTime) / 60;
float spm;
if (upTime < claimTime) {
spm = 0;
} else {
spm = totalSales / upTime;
}
integer salesInTime = (integer)( spm * ((float)claimTime) );
integer targetSales;
targetSales = (integer) ( (float)salesInTime * aaClaimMultiplier);
if (targetSales < aaClaimMinimum) targetSales = aaClaimMinimum;
integer suggestPrice = claimAmount * (targetSales - 1);
if (suggestPrice != claimPrice) {
claimPrice = suggestPrice;
llInstantMessage(llGetOwner(),"Claim price auto-adjusted to L$" + (string)claimPrice + " (actual average SCP " + (string)salesInTime + ", target SCP " + (string)targetSales +")");
}
}
default {
state_entry() {
init();
}
on_rez(integer junk) {
init();
}
changed(integer theChange) {
llOwnerSay("My inventory changed! Starting again...");
llResetScript();
}
dataserver(key request, string result) {
if (doingPartnerRequest) {
llSetTimerEvent(0);
doingPartnerRequest = FALSE;
partnerName = result;
} else {
if (notecardLine == -1) {
maxLine = ((integer)result) - 1;
} else {
if (llGetSubString(result,0,2) != "//") {
integer commandBreak = llSubStringIndex(result," ");
string command = llToLower(llGetSubString(result,0,commandBreak - 1));
string rest = llGetSubString(result,commandBreak+1,-1);
if (command == "item") {
itemToSell = rest;
if (llGetInventoryType(itemToSell) == INVENTORY_NONE) {
llOwnerSay("Error: Item to sell (" + itemToSell + ") not found in inventory.");
state setupError;
return;
}
if (! ((llGetInventoryPermMask(itemToSell,MASK_OWNER)) & (PERM_COPY | PERM_TRANSFER))) {
llOwnerSay("Error: Can't sell this item, I don't have copy and transfer permission.");
state setupError;
return;
}
if (! ((llGetInventoryPermMask(itemToSell,MASK_NEXT)) & (PERM_COPY | PERM_TRANSFER))) {
llOwnerSay("Warning: Customer will get copy and transfer permission!");
}
}
if (command == "notecard") {
infocardName = rest;
if (llGetInventoryType(infocardName) != INVENTORY_NOTECARD) {
llOwnerSay("Error: Information notecard (" + infocardName + ") not found in inventory.");
state setupError;
return;
}
if (! ((llGetInventoryPermMask(infocardName,MASK_OWNER)) & (PERM_COPY | PERM_TRANSFER))) {
llOwnerSay("Error: Can't give out this information notecard, I don't have copy and transfer permission.");
state setupError;
return;
}
if (! ((llGetInventoryPermMask(infocardName,MASK_NEXT)) & (PERM_COPY | PERM_TRANSFER))) {
llOwnerSay("Error: Customer won't be able to read information notecard, you need to give them copy and transfer permission.");
state setupError;
return;
}
}
if (command == "itemprice") {
itemPrice = (integer)rest;
if (itemPrice <= 0) {
llOwnerSay("Error: Price is not valid, or is zero. (This vendor is not suitable for free items.)");
state setupError;
return;
}
}
if (command == "claimprice") {
if (rest == "auto") {
autoAdjustClaim = TRUE;
} else {
autoAdjustClaim = FALSE;
claimPrice = (integer)rest;
if ((claimPrice <= 0) && (result != "0")) {
llOwnerSay("Error: Claim price is not valid.");
state setupError;
return;
}
}
}
if (command == "claimamount") {
claimAmount = (integer)rest;
if ((claimAmount <= 0)) {
llOwnerSay("Error: Claim amount is not valid or is zero.");
state setupError;
return;
}
}
if (command == "claimtime") {
claimTime = (integer)rest;
if ((claimTime <= 0)) {
llOwnerSay("Error: Claim time is not valid or is zero.");
state setupError;
return;
}
}
if (command == "claimminimum") {
aaClaimMinimum = (integer)rest;
if ((aaClaimMinimum <= 0)) {
llOwnerSay("Error: Claim minimum is not valid or is zero.");
state setupError;
return;
}
}
if (command == "claimmultiply") {
aaClaimMultiplier = (float)rest;
if ((aaClaimMinimum <= 0.0)) {
llOwnerSay("Error: Claim multiplier is not valid or is zero.");
state setupError;
return;
}
}
if (command == "partnerkey") {
if (partnerKey != NULL_KEY){
llOwnerSay("Error: Two partnerkeys in a row with no partnersplit in between.");
state setupError;
return;
}
partnerKey = (key)rest;
llSetTimerEvent(5);
doingPartnerRequest = TRUE;
llRequestAgentData(partnerKey,DATA_NAME);
return;
}
if (command == "partnersplit") {
if (partnerKey == NULL_KEY) {
llOwnerSay("Error: Partnersplit needs to be preceded by a partnerkey.");
state setupError;
return;
}
partnerSplit = (integer)rest;
if ((partnerSplit <= 0)) {
llOwnerSay("Error: Partner split amount is not valid or is zero.");
state setupError;
return;
}
totalPartnerSplits += partnerSplit;
llOwnerSay("Partner: " + partnerName + " recieves " + (string)partnerSplit + "%.");
percentSplits += [partnerKey, partnerSplit];
partnerKey = NULL_KEY;
}
}
}
}
if (notecardLine == maxLine) {
// finalValidate();
if (claimAmount >= itemPrice) {
llOwnerSay("Error: Claim amount is greater than item price!");
state setupError;
return;
}
if (totalPartnerSplits > 100) {
llOwnerSay("Error: Partner splits add up to greater than 100%!");
state setupError;
return;
}
if ((itemPrice == 0) || (itemToSell == "") || ((claimPrice == 0) && (autoAdjustClaim == FALSE)) || (claimTime == 0) || (claimAmount == 0)) {
llOwnerSay("Error: Essential information is missing.");
llOwnerSay((string)autoAdjustClaim);
state setupError;
return;
}
state setupStage;
return;
}
notecardLine++;
llGetNotecardLine(notecardName,notecardLine);
}
timer() {
llSetTimerEvent(0);
llOwnerSay("Error: Dataserver timed out while checking information for partner key " + (string)partnerKey + ".");
llOwnerSay("This can be caused by lag, but more usually means that there's a mistake in the key.");
state setupError;
return;
}
}
state setupError {
state_entry() {
llOwnerSay("An error occured in setup. Please click me to try again.");
}
touch_start(integer junk) {
if (llDetectedKey(0) == llGetOwner()) llResetScript();
}
}
state setupStage {
state_entry() {
llListen(-593827,"",NULL_KEY,"frame");
llOwnerSay("Setting up linkage. Please click on my frame.");
}
listen(integer channel, string name, key speaker, string message) {
if (llGetOwnerKey(speaker) != llGetOwner()) return;
if (message != "frame") return;
myFrame = speaker;
llOwnerSay("Linked to frame " + (string)speaker);
llWhisper(-593827,myFrame);
llSleep(1);
llRequestPermissions(llGetOwner(),PERMISSION_DEBIT);
}
run_time_permissions(integer perms) {
if (perms & PERMISSION_DEBIT) {
state gotFrame;
} else {
llOwnerSay("Debit permissions are required for this vendor to work.");
llOwnerSay("Please click on my frame to try again.");
llWhisper(-593927,"reset");
}
}
changed(integer thechange) {
if (thechange && CHANGED_INVENTORY) {
state maint;
}
}
}
state gotFrame {
state_entry() {
llOwnerSay("Vendor setup complete and ready to sell.");
llListen(-593927,"",myFrame,"");
llSetPayPrice(PAY_HIDE,[itemPrice,PAY_HIDE,PAY_HIDE,PAY_HIDE]);
totalSales = 0;
totalNotecards = 0;
totalClaims = 0;
totalClaimedSales = 0;
startUpTime = llGetUnixTime();
if (autoAdjustClaim) adjustAmount();
llWhisper(-593927,(string)claimPrice);
llSetTimerEvent(60);
}
on_rez(integer junk) {
llResetScript();
}
touch_start(integer junk) {
if (llDetectedKey(0) != llGetOwner()) {
totalNotecards++;
if (infocardName != "") llGiveInventory(llDetectedKey(0),infocardName);
return;
} else {
llOwnerSay("I have made " + (string)totalSales + " sales (" + (string)totalClaimedSales + " while claimed), given out " + (string)totalNotecards + " notecards, and been claimed " + (string)totalClaims + " times.");
}
}
money(key giver, integer amount) {
if (amount != itemPrice) {
llGiveMoney(giver,amount);
llSay(0,llKey2Name(giver) + ", you paid the wrong amount. The price is L$" + (string)itemPrice + ".");
return;
}
totalSales++;
integer gotMoney = itemPrice;
llGiveInventory(giver,itemToSell);
if (currentClaimer != NULL_KEY) {
totalClaimedSales++;
llGiveMoney(currentClaimer,claimAmount);
gotMoney -= claimAmount;
}
integer totalSplits = 0;
if (percentSplits != []) {
integer t;
for (t=0; t<llGetListLength(percentSplits); t+=2) {
key benefit = llList2Key(percentSplits,t);
float percent = llList2Float(percentSplits,t+1);
integer share = (integer) ( ((float)gotMoney / 100.0) * percent);
llGiveMoney(benefit,share);
totalSplits += share;
}
}
string message = llKey2Name(giver) + " (" + (string)giver + ") bought a " + itemToSell + " from " + llGetRegionName() + " for L$" + (string)itemPrice + ".";
if (currentClaimer != NULL_KEY) {
message += " Vendor was claimed by " + currentClaimerName + " who recieved L$" + (string)claimAmount +".";
}
if (totalSplits != 0) {
message += " L$" + (string)totalSplits + " was paid to partners.";
}
llInstantMessage(llGetOwner(),message);
if (currentClaimer != NULL_KEY) {
llInstantMessage(currentClaimer,"A " + itemToSell + " was sold from a vendor you claimed; you win L$" + (string)claimAmount + "!");
}
}
listen(integer channel, string name, key speaker, string message) {
if (speaker != myFrame) return;
list msgFromFrame = llParseString2List(message,["|"],[]);
integer amount = (integer)(llList2String(msgFromFrame,1));
key giver = (key)(llList2String(msgFromFrame,0));
string giverName = llKey2Name(giver);
if (amount == -1) {
if (currentClaimer != NULL_KEY) {
integer passed = llGetUnixTime() - claimStartTime;
passed /= 60;
integer left = claimTime - passed;
llSay(0,"This vendor is already claimed. It will be available to claim in " + (string)left + " minutes.");
} else {
llSay(0,"This vendor is available to be claimed right now!");
}
llSay(0,"Cost to claim: L$" + (string)claimPrice + ". You earn L$" + (string)claimAmount + " per sale for " + (string)claimTime + " minute.");
llSay(0,"If you've never played a Golden Vendor before, click the frame again for an information notecard.");
llSay(0,"Note - if you just want to buy the product, ignore this message and click the white poster part itself.");
if (giver == lastFrameClick) {
llGiveInventory(giver,"About Golden Vendors");
}
lastFrameClick = giver;
return;
}
if (amount != claimPrice) {
llGiveMoney(giver,amount);
llSay(0,giverName + ", you paid the wrong amount. Price to claim the vendor is " + (string)claimPrice + ".");
return;
}
if (currentClaimer != NULL_KEY) {
llGiveMoney(giver,amount);
llSay(0,giverName + ", sorry, this vendor is already claimed.");
return;
}
totalClaims++;
llWhisper(-593927,"noclaim");
currentClaimer = giver;
currentClaimerName = giverName;
claimStartTime = llGetUnixTime();
llSay(0,currentClaimerName + ", you have claimed this vendor for " + (string)claimTime + " minutes.");
llSay(0,"Get as many other people to buy this item as you can and win money!");
}
changed(integer thechange) {
if (thechange && CHANGED_INVENTORY) {
state maint;
}
}
timer() {
if (currentClaimer != NULL_KEY) {
if (llGetUnixTime() >= (claimStartTime + (claimTime * 60))) {
llInstantMessage(currentClaimer,"Your claim time is over!");
currentClaimer = NULL_KEY;
llWhisper(-593927,"claim");
}
}
if (autoAdjustClaim) adjustAmount();
}
}
state maint {
state_entry() {
llWhisper(-593927,"noclaim");
llOwnerSay("My inventory changed. Please click me to reset..");
}
touch_start(integer count) {
if (llDetectedKey(0) == llGetOwner()) llResetScript();
}
} </lsl>
And the script for the frame..
<lsl>
key master;
init() {
llListen(-593827,"",NULL_KEY,"");
}
default {
state_entry() { init(); }
on_rez(integer junk) { init();}
touch_start(integer total_number)
{
if (llDetectedKey(0) != llGetOwner()) return;
llSay(-593827,"frame");
}
listen(integer channel, string name, key speaker, string message) {
if (llGetOwnerKey(speaker) != llGetOwner()) return;
if (((key)message) != llGetKey()) return;
master = speaker;
llOwnerSay("Frame linked to vendor key " + (string)master);
state running;
}
}
state running {
state_entry() {
llListen(-593927,"",master,"");
}
on_rez(integer junk) {
llResetScript();
}
touch_start(integer total_number) {
llSay(-593927,(string)llDetectedKey(0) + "|-1");
}
listen(integer channel, string name, key speaker, string message) {
if (speaker != master) return;
if (message == "reset") llResetScript();
if (message == "noclaim") state noClaim;
llSetPayPrice(PAY_HIDE,[(integer)message,PAY_HIDE,PAY_HIDE,PAY_HIDE]);
}
money(key giver, integer amount) {
llSay(-593927,(string)giver + "|" + (string)amount);
}
}
state noClaim {
state_entry() {
llListen(-593927,"",master,"");
}
on_rez(integer junk) {
llResetScript();
}
touch_start(integer total_number) {
llSay(-593927,(string)llDetectedKey(0) + "|-1");
}
listen(integer channel, string name, key speaker, string message) {
if (speaker != master) return;
if (message == "reset") llResetScript();
if (message == "claim") state running;
llOwnerSay(message);
llSetPayPrice(PAY_HIDE,[(integer)message,PAY_HIDE,PAY_HIDE,PAY_HIDE]);
}
} </lsl>