/rental-system/rental-system.lsl |
@@ -0,0 +1,975 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
// escapes a string in conformance with RFC1738 |
string wasURLEscape(string i) { |
string o = ""; |
do { |
string c = llGetSubString(i, 0, 0); |
i = llDeleteSubString(i, 0, 0); |
if(c == "") jump continue; |
if(c == " ") { |
o += "+"; |
jump continue; |
} |
if(c == "\n") { |
o += "%0D" + llEscapeURL(c); |
jump continue; |
} |
o += llEscapeURL(c); |
@continue; |
} while(i != ""); |
return o; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
// unescapes a string in conformance with RFC1738 |
string wasURLUnescape(string i) { |
return llUnescapeURL( |
llDumpList2String( |
llParseString2List( |
llDumpList2String( |
llParseString2List( |
i, |
["+"], |
[] |
), |
" " |
), |
["%0D%0A"], |
[] |
), |
"\n" |
) |
); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
string wasKeyValueEncode(list data) { |
list k = llList2ListStrided(data, 0, -1, 2); |
list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); |
data = []; |
do { |
data += llList2String(k, 0) + "=" + llList2String(v, 0); |
k = llDeleteSubList(k, 0, 0); |
v = llDeleteSubList(v, 0, 0); |
} while(llGetListLength(k) != 0); |
return llDumpList2String(data, "&"); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
string wasKeyValueGet(string k, string data) { |
if(llStringLength(data) == 0) return ""; |
if(llStringLength(k) == 0) return ""; |
list a = llParseString2List(data, ["&", "="], []); |
integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]); |
if(i != -1) return llList2String(a, 2*i+1); |
return ""; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
list wasCSVToList(string csv) { |
list l = []; |
list s = []; |
string m = ""; |
do { |
string a = llGetSubString(csv, 0, 0); |
csv = llDeleteSubString(csv, 0, 0); |
if(a == ",") { |
if(llList2String(s, -1) != "\"") { |
l += m; |
m = ""; |
jump continue; |
} |
m += a; |
jump continue; |
} |
if(a == "\"" && llGetSubString(csv, 0, 0) == a) { |
m += a; |
csv = llDeleteSubString(csv, 0, 0); |
jump continue; |
} |
if(a == "\"") { |
if(llList2String(s, -1) != a) { |
s += a; |
jump continue; |
} |
s = llDeleteSubList(s, -1, -1); |
jump continue; |
} |
m += a; |
@continue; |
} while(csv != ""); |
// postcondition: length(s) = 0 |
return l + m; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
integer wasDateTimeToStamp( |
integer year, |
integer month, |
integer day, |
integer hour, |
integer minute, |
integer second |
) { |
month -= 2; |
if (month <= 0) { |
month += 12; |
--year; |
} |
return |
( |
(((year / 4 - year / 100 + year / 400 + (367 * month) / 12 + day) + |
year * 365 - 719499 |
) * 24 + hour |
) * 60 + minute |
) * 60 + second; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
float wasFmod(float a, float p) { |
if(p == 0) return (float)"nan"; |
return a - ((integer)(a/p) * p); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
// Original: Clive Page, Leicester University, UK. 1995-MAY-2 // |
/////////////////////////////////////////////////////////////////////////// |
list wasUnixTimeToDateTime(integer seconds) { |
integer mjday = (integer)(seconds/86400 + 40587); |
integer dateYear = 1858 + (integer)( (mjday + 321.51) / 365.25); |
float day = (integer)( wasFmod(mjday + 262.25, 365.25) ) + 0.5; |
integer dateMonth = 1 + (integer)(wasFmod(day / 30.6 + 2.0, 12.0) ); |
integer dateDay = 1 + (integer)(wasFmod(day,30.6)); |
float nsecs = wasFmod(seconds, 86400); |
integer dateSeconds = (integer)wasFmod(nsecs, 60); |
nsecs = nsecs / 60; |
integer dateMinutes = (integer)wasFmod(nsecs, 60); |
integer dateHour = (integer)(nsecs / 60); |
return [ dateYear, |
dateMonth, dateDay, dateHour, dateMinutes, dateSeconds ]; |
} |
|
// for changing states |
string nextstate = ""; |
|
// notecard reading |
integer line = 0; |
list tuples = []; |
|
// corrade data |
key CORRADE = NULL_KEY; |
string GROUP = ""; |
string PASSWORD = ""; |
// the owner of the rental system |
// the dude or dudette that gets paid |
key OWNER = NULL_KEY; |
// the price of the rent |
integer PRICE = 0; |
// the time for the rent in seconds |
integer RENT = 0; |
string URL = ""; |
// the role to invite rentants to |
string ROLE = ""; |
|
default { |
state_entry() { |
if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { |
llSetText("Sorry, could not find an inventory notecard.", <1, 0, 0>, 1.0); |
return; |
} |
llSetText("Reading configuration notecard...", <1, 1, 0>, 1.0); |
llGetNotecardLine("configuration", line); |
} |
dataserver(key id, string data) { |
if(data == EOF) { |
// invariant, length(tuples) % 2 == 0 |
if(llGetListLength(tuples) % 2 != 0) { |
llSetText("Error in configuration notecard.", <1, 0, 0>, 1.0); |
return; |
} |
CORRADE = (key)llList2String( |
tuples, |
llListFindList( |
tuples, |
[ |
"corrade" |
] |
) |
+1); |
if(CORRADE == NULL_KEY) { |
llSetText("Error in configuration notecard: corrade", <1, 0, 0>, 1.0); |
return; |
} |
GROUP = llList2String( |
tuples, |
llListFindList( |
tuples, |
[ |
"group" |
] |
) |
+1); |
if(GROUP == "") { |
llSetText("Error in configuration notecard: group", <1, 0, 0>, 1.0); |
return; |
} |
PASSWORD = llList2String( |
tuples, |
llListFindList( |
tuples, |
[ |
"password" |
] |
) |
+1); |
if(PASSWORD == "") { |
llSetText("Error in configuration notecard: password", <1, 0, 0>, 1.0); |
return; |
} |
OWNER = (key)llList2String( |
tuples, |
llListFindList( |
tuples, |
[ |
"owner" |
] |
) |
+1); |
if(OWNER == NULL_KEY) { |
llSetText("Error in configuration notecard: owner", <1, 0, 0>, 1.0); |
return; |
} |
PRICE = (integer)llList2String( |
tuples, |
llListFindList( |
tuples, |
[ |
"price" |
] |
) |
+1); |
if(PRICE == 0) { |
llSetText("Error in configuration notecard: price", <1, 0, 0>, 1.0); |
return; |
} |
RENT = (integer)llList2String( |
tuples, |
llListFindList( |
tuples, |
[ |
"rent" |
] |
) |
+1); |
if(RENT == 0) { |
llSetText("Error in configuration notecard: rent", <1, 0, 0>, 1.0); |
return; |
} |
ROLE = llList2String( |
tuples, |
llListFindList( |
tuples, |
[ |
"role" |
] |
) |
+1 |
); |
if(ROLE == "") { |
llSetText("Error in configuration notecard: role", <1, 0, 0>, 1.0); |
return; |
} |
|
llSetText("Read configuration notecard.", <0, 1, 0>, 1.0); |
|
// if data is set switch to rented state |
if(llGetObjectDesc() != "") state rented; |
// otherwise switch to the payment state |
state payment; |
} |
if(data == "") jump continue; |
integer i = llSubStringIndex(data, "#"); |
if(i != -1) data = llDeleteSubString(data, i, -1); |
list o = llParseString2List(data, ["="], []); |
// get rid of starting and ending quotes |
string k = llDumpList2String( |
llParseString2List( |
llStringTrim( |
llList2String( |
o, |
0 |
), |
STRING_TRIM), |
["\""], [] |
), "\""); |
string v = llDumpList2String( |
llParseString2List( |
llStringTrim( |
llList2String( |
o, |
1 |
), |
STRING_TRIM), |
["\""], [] |
), "\""); |
if(k == "" || v == "") jump continue; |
tuples += k; |
tuples += v; |
@continue; |
llGetNotecardLine("configuration", ++line); |
} |
on_rez(integer num) { |
llResetScript(); |
} |
changed(integer change) { |
if(change & CHANGED_INVENTORY) { |
llResetScript(); |
} |
} |
} |
|
state trampoline { |
state_entry() { |
llSetTimerEvent(5); |
} |
timer() { |
llSetTimerEvent(0); |
// State jump table |
if(nextstate == "url") state url; |
if(nextstate == "getmembers") state getmembers; |
if(nextstate == "getrolemembers") state getrolemembers; |
if(nextstate == "addtorole") state addtorole; |
if(nextstate == "invite") state invite; |
if(nextstate == "rented") state rented; |
if(nextstate == "demote") state demote; |
// automata in invalid state |
} |
on_rez(integer num) { |
llResetScript(); |
} |
changed(integer change) { |
if(change & CHANGED_INVENTORY) { |
llResetScript(); |
} |
} |
} |
|
state payment { |
state_entry() { |
llSetPayPrice(PRICE, [PRICE]); |
llSetClickAction(CLICK_ACTION_PAY); |
llSetText("☀ Touch me to rent this place! ☀", <0, 1, 0>, 1.0); |
} |
money(key id, integer amount) { |
// Get the current time stamp. |
list stamp = llList2List( |
llParseString2List( |
llGetTimestamp(), |
["-",":","T", "."],[""] |
), |
0, 5 |
); |
// convert to seconds and add the rent |
integer delta = wasDateTimeToStamp( |
llList2Integer(stamp, 0), |
llList2Integer(stamp, 1), |
llList2Integer(stamp, 2), |
llList2Integer(stamp, 3), |
llList2Integer(stamp, 4), |
llList2Integer(stamp, 5) |
) + |
// the amount of time is the amount paid |
// times the rent time divided by the price |
amount * (integer)( |
(float)RENT / |
(float)PRICE |
); |
// convert back to a timestamp |
stamp = wasUnixTimeToDateTime(delta); |
// and set the renter and the eviction date |
llSetObjectDesc( |
wasKeyValueEncode( |
[ |
"rentantUUID", id, |
"rentantName", llKey2Name(id), |
"expiresDate", llList2String(stamp, 0) + |
"-" + llList2String(stamp, 1) + |
"-" + llList2String(stamp, 2) + |
"T" + llList2String(stamp, 3) + |
":" + llList2String(stamp, 4) + |
":" + llList2String(stamp, 5) |
] |
) |
); |
nextstate = "getmembers"; |
state url; |
} |
on_rez(integer num) { |
llResetScript(); |
} |
changed(integer change) { |
if(change & CHANGED_INVENTORY) { |
llResetScript(); |
} |
} |
} |
|
state url { |
state_entry() { |
// release any previous URL |
llReleaseURL(URL); |
// request a new URL |
llRequestURL(); |
} |
http_request(key id, string method, string body) { |
if(method != URL_REQUEST_GRANTED) { |
llSetText("☀ Unable to get an URL! ☀", <1, 0, 0>, 1.0); |
nextstate = "url"; |
state trampoline; |
} |
URL = body; |
// state URL jump table |
if(nextstate == "getmembers") state getmembers; |
if(nextstate == "demote") state demote; |
// automata in invalid state |
} |
on_rez(integer num) { |
llResetScript(); |
} |
changed(integer change) { |
if(change & CHANGED_INVENTORY) { |
llResetScript(); |
} |
} |
} |
|
state getmembers { |
state_entry() { |
llSetText("☀ Getting group members... ☀", <1, 1, 0>, 1.0); |
llInstantMessage(CORRADE, |
wasKeyValueEncode( |
[ |
"command", "getmembers", |
"group", wasURLEscape(GROUP), |
"password", wasURLEscape(PASSWORD), |
// we just care if the agent is in the group |
// so we use Corrade's sifting ability in order |
// to reduce the script memory usage |
"sift", wasURLEscape( |
"(" + |
wasKeyValueGet( |
"rentantUUID", |
llGetObjectDesc() |
) + |
")*" |
), |
"callback", wasURLEscape(URL) |
] |
) |
); |
llSetTimerEvent(60); |
} |
http_request(key id, string method, string body) { |
if(wasKeyValueGet("success", body) != "True") { |
llSetText("☀ Could not get group members! ☀", <1, 0, 0>, 1.0); |
nextstate = "getmembers"; |
state trampoline; |
} |
// check that the payer is part of the role |
integer i = |
llListFindList( |
wasCSVToList( |
wasURLUnescape( |
wasKeyValueGet( |
"data", |
body |
) |
) |
), |
(list)wasKeyValueGet( |
"rentantUUID", |
llGetObjectDesc() |
) |
); |
llSetTimerEvent(0); |
// if they are in the group then check roles. |
if(i != -1) state getrolemembers; |
// otherwise invite them to the group role. |
state invite; |
} |
timer() { |
llSetTimerEvent(0); |
nextstate = "getmembers"; |
state trampoline; |
} |
on_rez(integer num) { |
llResetScript(); |
} |
changed(integer change) { |
if(change & CHANGED_INVENTORY) { |
llResetScript(); |
} |
} |
} |
|
state getrolemembers { |
state_entry() { |
llSetText("☀ Getting role members... ☀", <1, 1, 0>, 1.0); |
llInstantMessage(CORRADE, |
wasKeyValueEncode( |
[ |
"command", "getrolemembers", |
"group", wasURLEscape(GROUP), |
"password", wasURLEscape(PASSWORD), |
"role", wasURLEscape(ROLE), |
// we just care if the agent is in the renter role |
// so we use Corrade's sifting ability in order |
// to reduce the script memory usage |
"sift", wasURLEscape( |
"(" + |
wasKeyValueGet( |
"rentantUUID", |
llGetObjectDesc() |
) + |
")*" |
), |
"callback", wasURLEscape(URL) |
] |
) |
); |
llSetTimerEvent(60); |
} |
http_request(key id, string method, string body) { |
if(wasKeyValueGet("success", body) != "True") { |
llSetText("☀ Could not get role members! ☀", <1, 0, 0>, 1.0); |
nextstate = "getrolemembers"; |
state trampoline; |
} |
// check that the payer is part of the role |
integer i = |
llListFindList( |
wasCSVToList( |
wasURLUnescape( |
wasKeyValueGet( |
"data", |
body |
) |
) |
), |
(list)wasKeyValueGet( |
"rentantUUID", |
llGetObjectDesc() |
) |
); |
llSetTimerEvent(0); |
// if they are in the role then skip inviting them. |
if(i != -1) state rented; |
// otherwise add them to the land role. |
state addtorole; |
} |
timer() { |
llSetTimerEvent(0); |
nextstate = "getrolemembers"; |
state trampoline; |
} |
on_rez(integer num) { |
llResetScript(); |
} |
changed(integer change) { |
if(change & CHANGED_INVENTORY) { |
llResetScript(); |
} |
} |
} |
|
state addtorole { |
state_entry() { |
llSetText("☀ Adding to role... ☀", <1, 1, 0>, 1.0); |
llInstantMessage(CORRADE, |
wasKeyValueEncode( |
[ |
"command", "addtorole", |
"group", wasURLEscape(GROUP), |
"password", wasURLEscape(PASSWORD), |
"agent", wasURLEscape( |
wasKeyValueGet( |
"rentantUUID", |
llGetObjectDesc() |
) |
), |
"role", wasURLEscape(ROLE), |
"callback", wasURLEscape(URL) |
] |
) |
); |
llSetTimerEvent(60); |
} |
http_request(key id, string method, string body) { |
if(wasKeyValueGet("success", body) != "True") { |
llSetText("☀ Could not add to role! ☀", <1, 0, 0>, 1.0); |
nextstate = "addtorole"; |
state trampoline; |
} |
// otherwise invite them to the group role. |
state rented; |
} |
timer() { |
llSetTimerEvent(0); |
nextstate = "addtorole"; |
state trampoline; |
} |
on_rez(integer num) { |
llResetScript(); |
} |
changed(integer change) { |
if(change & CHANGED_INVENTORY) { |
llResetScript(); |
} |
} |
} |
|
state invite { |
state_entry() { |
llSetText("☀ Please accept the group invite! ☀", <1, 1, 0>, 1.0); |
// invite the agent to the land group |
llInstantMessage(CORRADE, |
wasKeyValueEncode( |
[ |
"command", "invite", |
"group", wasURLEscape(GROUP), |
"password", wasURLEscape(PASSWORD), |
"agent", wasURLEscape( |
wasKeyValueGet( |
"rentantUUID", |
llGetObjectDesc() |
) |
), |
"role", wasURLEscape(ROLE), |
"callback", wasURLEscape(URL) |
] |
) |
); |
// handle any Corrade timeouts |
llSetTimerEvent(60); |
} |
http_request(key id, string method, string body) { |
llHTTPResponse(id, 200, "OK"); |
// Checks if the invite was sent successfully or if that fails but the |
// agent is already in the group (status 15345) then continue. |
// Otherwise, jump to the trampoline and send the invite again. |
// Status codes: |
// http://grimore.org/secondlife/scripted_agents/corrade/status_codes/progressive |
if(wasKeyValueGet("success", body) != "True" && |
wasKeyValueGet("status", body) != "15345") { |
llSetText("☀ Group invite could not be sent! ☀", <1, 0, 0>, 1.0); |
nextstate = "invite"; |
state trampoline; |
} |
llSetText("☀ Group invitation sent! ☀", <1, 1, 0>, 1.0); |
llSetTimerEvent(0); |
state rented; |
} |
timer() { |
llSetTimerEvent(0); |
nextstate = "invite"; |
state trampoline; |
} |
} |
|
state rented { |
state_entry() { |
// Get the expiration date |
list expires = llList2List( |
llParseString2List( |
wasKeyValueGet( |
"expiresDate", |
llGetObjectDesc() |
), |
["-",":","T", "."],[""] |
), |
0, 5 |
); |
// Get the current date |
list stamp = llList2List( |
llParseString2List( |
llGetTimestamp(), |
["-",":","T", "."],[""] |
), |
0, 5 |
); |
|
integer delta = wasDateTimeToStamp( |
llList2Integer(expires, 0), |
llList2Integer(expires, 1), |
llList2Integer(expires, 2), |
llList2Integer(expires, 3), |
llList2Integer(expires, 4), |
llList2Integer(expires, 5) |
) - wasDateTimeToStamp( |
llList2Integer(stamp, 0), |
llList2Integer(stamp, 1), |
llList2Integer(stamp, 2), |
llList2Integer(stamp, 3), |
llList2Integer(stamp, 4), |
llList2Integer(stamp, 5) |
); |
|
// the rent has expired, now evict the rentant |
if(delta <= 0) { |
llSetTimerEvent(0); |
nextstate = "demote"; |
state url; |
} |
|
// otherwise, update the remaining time |
list remaining = wasUnixTimeToDateTime(delta); |
remaining = llListReplaceList(remaining, [ llList2Integer(remaining, 0)-1970 ], 0, 0); |
remaining = llListReplaceList(remaining, [ llList2Integer(remaining, 1)-1 ], 1, 1); |
remaining = llListReplaceList(remaining, [ llList2Integer(remaining, 2)-1 ], 2, 2); |
|
llSetText( |
"☀ Private property! ☀" |
+ "\n" + |
"Rented by: " + |
wasKeyValueGet( |
"rentantName", |
llGetObjectDesc() |
) |
+ "\n" + |
"Expires on: " + |
wasKeyValueGet( |
"expiresDate", |
llGetObjectDesc() |
) |
+ "\n" + |
"Remaining: " + |
llList2String(remaining, 0) + "-" + |
llList2String(remaining, 1) + "-" + |
llList2String(remaining, 2) + " " + |
llList2String(remaining, 3) + ":" + |
llList2String(remaining, 4) |
+ "\n" + |
"Touch to extend rent.", |
<0, 1, 1>, |
1.0 |
); |
llSetPayPrice(PRICE, [PRICE]); |
llSetClickAction(CLICK_ACTION_PAY); |
// set the countdown every minute |
llSetTimerEvent(60); |
} |
money(key id, integer amount) { |
// Get the expiration date |
list stamp = llList2List( |
llParseString2List( |
wasKeyValueGet( |
"expiresDate", |
llGetObjectDesc() |
), |
["-",":","T", "."],[""] |
), |
0, 5 |
); |
// convert to seconds and add the extended rent |
integer delta = wasDateTimeToStamp( |
llList2Integer(stamp, 0), |
llList2Integer(stamp, 1), |
llList2Integer(stamp, 2), |
llList2Integer(stamp, 3), |
llList2Integer(stamp, 4), |
llList2Integer(stamp, 5) |
) + |
// the amount of time to extend is the amount |
// paid times the rent time divided by the price |
amount * (integer)( |
(float)RENT / |
(float)PRICE |
); |
// convert back to a timestamp |
stamp = wasUnixTimeToDateTime(delta); |
// and set the renter and the eviction date |
llSetObjectDesc( |
wasKeyValueEncode( |
[ |
"rentantUUID", wasKeyValueGet( |
"rentantUUID", |
llGetObjectDesc() |
), |
"rentantName", wasKeyValueGet( |
"rentantName", |
llGetObjectDesc() |
), |
"expiresDate", llList2String(stamp, 0) + |
"-" + llList2String(stamp, 1) + |
"-" + llList2String(stamp, 2) + |
"T" + llList2String(stamp, 3) + |
":" + llList2String(stamp, 4) + |
":" + llList2String(stamp, 5) |
] |
) |
); |
llSetText("☀ Updating... ☀", <1, 1, 0>, 1.0); |
llSetTimerEvent(0); |
nextstate = "rented"; |
state trampoline; |
} |
timer() { |
// Get the expiration date |
list expires = llList2List( |
llParseString2List( |
wasKeyValueGet( |
"expiresDate", |
llGetObjectDesc() |
), |
["-",":","T", "."],[""] |
), |
0, 5 |
); |
// Get the current date |
list stamp = llList2List( |
llParseString2List( |
llGetTimestamp(), |
["-",":","T", "."],[""] |
), |
0, 5 |
); |
|
integer delta = wasDateTimeToStamp( |
llList2Integer(expires, 0), |
llList2Integer(expires, 1), |
llList2Integer(expires, 2), |
llList2Integer(expires, 3), |
llList2Integer(expires, 4), |
llList2Integer(expires, 5) |
) - wasDateTimeToStamp( |
llList2Integer(stamp, 0), |
llList2Integer(stamp, 1), |
llList2Integer(stamp, 2), |
llList2Integer(stamp, 3), |
llList2Integer(stamp, 4), |
llList2Integer(stamp, 5) |
); |
|
// the rent has expired, now evict the rentant |
if(delta <= 0) { |
llSetTimerEvent(0); |
nextstate = "demote"; |
state url; |
} |
|
// otherwise, update the remaining time |
list remaining = wasUnixTimeToDateTime(delta); |
remaining = llListReplaceList(remaining, [ llList2Integer(remaining, 0)-1970 ], 0, 0); |
remaining = llListReplaceList(remaining, [ llList2Integer(remaining, 1)-1 ], 1, 1); |
remaining = llListReplaceList(remaining, [ llList2Integer(remaining, 2)-1 ], 2, 2); |
|
llSetText( |
"☀ Private property! ☀" |
+ "\n" + |
"Rented by: " + |
wasKeyValueGet( |
"rentantName", |
llGetObjectDesc() |
) |
+ "\n" + |
"Expires on: " + |
wasKeyValueGet( |
"expiresDate", |
llGetObjectDesc() |
) |
+ "\n" + |
"Remaining: " + |
llList2String(remaining, 0) + "-" + |
llList2String(remaining, 1) + "-" + |
llList2String(remaining, 2) + " " + |
llList2String(remaining, 3) + ":" + |
llList2String(remaining, 4) |
+ "\n" + |
"Touch to extend rent.", |
<0, 1, 1>, |
1.0 |
); |
|
} |
on_rez(integer num) { |
llResetScript(); |
} |
changed(integer change) { |
if(change & CHANGED_INVENTORY) { |
llResetScript(); |
} |
} |
} |
|
state demote { |
state_entry() { |
llSetText("☀ Rent has expired! ☀", <1, 0, 0>, 1.0); |
// demote the agent from the renter role |
llInstantMessage(CORRADE, |
wasKeyValueEncode( |
[ |
"command", "deletefromrole", |
"group", wasURLEscape(GROUP), |
"password", wasURLEscape(PASSWORD), |
"agent", wasURLEscape( |
wasKeyValueGet( |
"rentantUUID", |
llGetObjectDesc() |
) |
), |
"role", wasURLEscape(ROLE), |
"callback", wasURLEscape(URL) |
] |
) |
); |
// handle any Corrade timeouts |
llSetTimerEvent(60); |
} |
http_request(key id, string method, string body) { |
llHTTPResponse(id, 200, "OK"); |
// Checks if the demote was sent successfully or if that fails but the |
// agent has already left the group (status 11502) then continue. |
// Otherwise, jump to the trampoline and send the demote again. |
// Status codes: |
// http://grimore.org/secondlife/scripted_agents/corrade/status_codes/progressive |
if(wasKeyValueGet("success", body) != "True" && |
wasKeyValueGet("status", body) != "11502") { |
llSetText("☀ Could not demote! ☀", <1, 0, 0>, 1.0); |
nextstate = "demote"; |
state trampoline; |
} |
llSetText("☀ Renter demoted! ☀", <1, 1, 0>, 1.0); |
llSetTimerEvent(0); |
|
// Now clean up the rental and restart. |
llSetObjectDesc(""); |
llResetScript(); |
} |
timer() { |
llSetTimerEvent(0); |
nextstate = "demote"; |
state trampoline; |
} |
} |
|