Implemented basic water well and water bucket
This commit is contained in:
parent
f928139088
commit
3dbc618418
17 changed files with 862 additions and 0 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "LSL/external/ServiceCheck"]
|
||||
path = LSL/external/ServiceCheck
|
||||
url = git@github.com:AriasCreations/AriasCreations
|
1
LSL/external/ServiceCheck
vendored
Submodule
1
LSL/external/ServiceCheck
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 116681ba4fe093f0206542313d1b2b431445a9ac
|
195
LSL/includes/Common.lsl
Normal file
195
LSL/includes/Common.lsl
Normal file
|
@ -0,0 +1,195 @@
|
|||
string PSK = "MTcxNjMxODQwNzo1ZTdiMzNjNS0zNmQ4LTQyNjItOGI4My00MDg5MDAxMWMzOGY=";
|
||||
|
||||
list g_lDevelopers = ["5556d037-3990-4204-a949-73e56cd3cb06","27a0ae67-30d9-4fbc-b9fb-fd388c98c202"];
|
||||
|
||||
integer getIngredientChannel(key kID) {
|
||||
integer MSB = (integer)("0x" + llGetSubString(kID,0,4));
|
||||
integer LSB = (integer)("0x" + llGetSubString(kID,llStringLength(kID)-4, llStringLength(kID)));
|
||||
|
||||
integer ingredientOffset = 0x9F052124;
|
||||
return ingredientOffset + MSB - LSB;
|
||||
}
|
||||
|
||||
list StrideOfList(list src, integer stride, integer start, integer end)
|
||||
{
|
||||
list l = [];
|
||||
integer ll = llGetListLength(src);
|
||||
if(start < 0)start += ll;
|
||||
if(end < 0)end += ll;
|
||||
if(end < start) return llList2List(src, start, start);
|
||||
while(start <= end)
|
||||
{
|
||||
l += llList2List(src, start, start);
|
||||
start += stride;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
// DON'T CHANGE THE FOLLOWING! (Unless you know what you are doing!)
|
||||
|
||||
integer XTEA_DELTA = 0x9E3779B9; // (sqrt(5) - 1) * 2^31
|
||||
integer xtea_num_rounds = 6;
|
||||
list xtea_key = [0, 0, 0, 0];
|
||||
|
||||
integer hex2int(string hex) {
|
||||
if(llGetSubString(hex,0,1) == "0x")
|
||||
return (integer)hex;
|
||||
if(llGetSubString(hex,0,0) == "x")
|
||||
return (integer)("0"+hex);
|
||||
return(integer)("0x"+hex);
|
||||
}
|
||||
|
||||
// Convers any string to a 32 char MD5 string and then to a list of
|
||||
// 4 * 32 bit integers = 128 bit Key. MD5 ensures always a specific
|
||||
// 128 bit key is generated for any string passed.
|
||||
list xtea_key_from_string( string str )
|
||||
{
|
||||
str = llMD5String(str,0); // Use Nonce = 0
|
||||
return [ hex2int(llGetSubString( str, 0, 7)),
|
||||
hex2int(llGetSubString( str, 8, 15)),
|
||||
hex2int(llGetSubString( str, 16, 23)),
|
||||
hex2int(llGetSubString( str, 24, 31))];
|
||||
}
|
||||
|
||||
// Encipher two integers and return the result as a 12-byte string
|
||||
// containing two base64-encoded integers.
|
||||
string xtea_encipher( integer v0, integer v1 )
|
||||
{
|
||||
integer num_rounds = xtea_num_rounds;
|
||||
integer sum = 0;
|
||||
do {
|
||||
// LSL does not have unsigned integers, so when shifting right we
|
||||
// have to mask out sign-extension bits.
|
||||
v0 += (((v1 << 4) ^ ((v1 >> 5) & 0x07FFFFFF)) + v1) ^ (sum + llList2Integer(xtea_key, sum & 3));
|
||||
sum += XTEA_DELTA;
|
||||
v1 += (((v0 << 4) ^ ((v0 >> 5) & 0x07FFFFFF)) + v0) ^ (sum + llList2Integer(xtea_key, (sum >> 11) & 3));
|
||||
|
||||
} while( num_rounds = ~-num_rounds );
|
||||
//return only first 6 chars to remove "=="'s and compact encrypted text.
|
||||
return llGetSubString(llIntegerToBase64(v0),0,5) +
|
||||
llGetSubString(llIntegerToBase64(v1),0,5);
|
||||
}
|
||||
|
||||
// Decipher two base64-encoded integers and return the FIRST 30 BITS of
|
||||
// each as one 10-byte base64-encoded string.
|
||||
string xtea_decipher( integer v0, integer v1 )
|
||||
{
|
||||
integer num_rounds = xtea_num_rounds;
|
||||
integer sum = XTEA_DELTA*xtea_num_rounds;
|
||||
do {
|
||||
// LSL does not have unsigned integers, so when shifting right we
|
||||
// have to mask out sign-extension bits.
|
||||
v1 -= (((v0 << 4) ^ ((v0 >> 5) & 0x07FFFFFF)) + v0) ^ (sum + llList2Integer(xtea_key, (sum>>11) & 3));
|
||||
sum -= XTEA_DELTA;
|
||||
v0 -= (((v1 << 4) ^ ((v1 >> 5) & 0x07FFFFFF)) + v1) ^ (sum + llList2Integer(xtea_key, sum & 3));
|
||||
} while ( num_rounds = ~-num_rounds );
|
||||
|
||||
return llGetSubString(llIntegerToBase64(v0), 0, 4) +
|
||||
llGetSubString(llIntegerToBase64(v1), 0, 4);
|
||||
}
|
||||
|
||||
// Encrypt a full string using XTEA.
|
||||
string xtea_encrypt_string( string str )
|
||||
{
|
||||
// encode string
|
||||
str = llStringToBase64(str);
|
||||
// remove trailing =s so we can do our own 0 padding
|
||||
integer i = llSubStringIndex( str, "=" );
|
||||
if ( i != -1 )
|
||||
str = llDeleteSubString( str, i, -1 );
|
||||
|
||||
// we don't want to process padding, so get length before adding it
|
||||
integer len = llStringLength(str);
|
||||
|
||||
// zero pad
|
||||
str += "AAAAAAAAAA=";
|
||||
|
||||
string result;
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
// encipher 30 (5*6) bits at a time.
|
||||
result += xtea_encipher(llBase64ToInteger(llGetSubString(str, i, i + 4) + "A="), llBase64ToInteger(llGetSubString(str, i+5, i + 9) + "A="));
|
||||
i+=10;
|
||||
} while ( i < len );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Decrypt a full string using XTEA
|
||||
string xtea_decrypt_string( string str ) {
|
||||
integer len = llStringLength(str);
|
||||
integer i=0;
|
||||
string result;
|
||||
//llOwnerSay(str);
|
||||
do {
|
||||
integer v0;
|
||||
integer v1;
|
||||
|
||||
v0 = llBase64ToInteger(llGetSubString(str, i, i + 5) + "==");
|
||||
i+= 6;
|
||||
v1 = llBase64ToInteger(llGetSubString(str, i, i + 5) + "==");
|
||||
i+= 6;
|
||||
|
||||
result += xtea_decipher(v0, v1);
|
||||
} while ( i < len );
|
||||
|
||||
// Replace multiple trailing zeroes with a single one
|
||||
|
||||
i = llStringLength(result) - 1;
|
||||
while ( llGetSubString(result, i - 1, i) == "AA" ){
|
||||
result = llDeleteSubString(result, i, i);
|
||||
i--;
|
||||
}
|
||||
i = llStringLength(result) - 1;
|
||||
// while (llGetSubString(result, i, i + 1) == "A" ) {
|
||||
// i--;
|
||||
// }
|
||||
result = llGetSubString(result, 0, i+1);
|
||||
i = llStringLength(result);
|
||||
integer mod = i%4; //Depending on encoded length diffrent appends are needed
|
||||
if(mod == 1) result += "A==";
|
||||
else if(mod == 2 ) result += "==";
|
||||
else if(mod == 3) result += "=";
|
||||
|
||||
return llBase64ToString(result);
|
||||
|
||||
}
|
||||
|
||||
XteaKey(string pwd)
|
||||
{
|
||||
xtea_key = [0,0,0,0];
|
||||
xtea_key = xtea_key_from_string(pwd);
|
||||
}
|
||||
|
||||
|
||||
PROTECT() {
|
||||
|
||||
if(llListFindList(g_lDevelopers, [(string)llGetOwner()]) == -1) {
|
||||
llSay(0, "You were not meant to be able to reset this script. Goodbye");
|
||||
llDie();
|
||||
}else {
|
||||
llSay(0, "Developer detected, proceeding with FTS");
|
||||
}
|
||||
}
|
||||
|
||||
string DecipherService(string payload, string ident)
|
||||
{
|
||||
if(llJsonValueType(payload,[ident]) == JSON_INVALID)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return llJsonGetValue(payload, [ident,"protocol"]) + "://" + llJsonGetValue(payload,[ident,"host"]) + ":" + llJsonGetValue(payload,[ident,"port"]);
|
||||
}
|
||||
integer global_ingredients;
|
||||
string SERVER_PSK = "8597f-f19f0eec-cc526aa87-152ac84-326";
|
||||
|
||||
string g_sServerID = "";
|
||||
|
||||
requestProductForDelivery(string sProduct, string sID) {
|
||||
llEmail(g_sServerID+"@lsl.secondlife.com", "RequestProductDelivery", "S;;" + xtea_encrypt_string(llList2Json(JSON_OBJECT, [
|
||||
"item", sProduct,
|
||||
"id", sID
|
||||
])) + ";;X");
|
||||
}
|
210
LSL/raw/basic_ingredient.lsl
Normal file
210
LSL/raw/basic_ingredient.lsl
Normal file
|
@ -0,0 +1,210 @@
|
|||
#include "Common.lsl"
|
||||
|
||||
key g_kID=NULL_KEY;
|
||||
string g_sIngredientType = "none";
|
||||
integer g_iQuantity = 0;
|
||||
key g_kFollow = NULL_KEY;
|
||||
integer g_iProdLink=3;
|
||||
integer g_iDies=FALSE;
|
||||
vector g_vScale;
|
||||
|
||||
setText() {
|
||||
llSetText(g_sIngredientType + ": " + (string)g_iQuantity, <1,1,1>, 1);
|
||||
}
|
||||
|
||||
setProductTexture(key kID) {
|
||||
#ifdef PRODUCT_PRIM
|
||||
if(g_iProdLink!=-99) {
|
||||
#ifdef PRODUCT_FACE
|
||||
llSetLinkTexture(PRODUCT_PRIM, kID, PRODUCT_FACE);
|
||||
#else
|
||||
llSetLinkTexture(PRODUCT_PRIM, kID, ALL_SIDES);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
stopFollowing(float fOffset) {
|
||||
if(g_kFollow == NULL_KEY)return;
|
||||
g_kFollow = NULL_KEY;
|
||||
llSetTimerEvent(0);
|
||||
llSetPos(llGetPos() - <0,0,fOffset>);
|
||||
}
|
||||
|
||||
follow(key kID) {
|
||||
g_kFollow = kID;
|
||||
llSetTimerEvent(1);
|
||||
}
|
||||
|
||||
vector g_vParticleColor = ZERO_VECTOR;
|
||||
|
||||
particles(key kTarget) {
|
||||
if(kTarget == NULL_KEY) llParticleSystem([]);
|
||||
else {
|
||||
llParticleSystem(
|
||||
[
|
||||
// texture parameters:
|
||||
PSYS_SRC_TEXTURE , "",
|
||||
PSYS_PART_START_SCALE , <0.67,0.58,0.00>, PSYS_PART_END_SCALE , <0.09,0.09,0.00>,
|
||||
PSYS_PART_START_COLOR , g_vParticleColor, PSYS_PART_END_COLOR , <0.16,0.71,0.83>,
|
||||
PSYS_PART_START_ALPHA , (float)1.00, PSYS_PART_END_ALPHA , (float)1.00,
|
||||
// production parameters:
|
||||
PSYS_SRC_BURST_PART_COUNT , 16,
|
||||
PSYS_SRC_BURST_RATE , (float)0.10,
|
||||
PSYS_PART_MAX_AGE , (float)6.54,
|
||||
PSYS_SRC_MAX_AGE , (float)0.18,
|
||||
// placement parameters:
|
||||
PSYS_SRC_PATTERN , 2,
|
||||
PSYS_SRC_BURST_SPEED_MIN , (float)1.00, PSYS_SRC_BURST_SPEED_MAX , (float)1.00,
|
||||
PSYS_SRC_BURST_RADIUS , (float)0.00,
|
||||
// placement parameters (for angles only):
|
||||
PSYS_SRC_ANGLE_BEGIN , (float)0.00,
|
||||
PSYS_SRC_ANGLE_END , (float)0.00,
|
||||
PSYS_SRC_OMEGA , <0.00,0.00,0.00>,
|
||||
// after-effects & influences:
|
||||
PSYS_SRC_ACCEL , <0.00,0.00,0.00>,
|
||||
PSYS_SRC_TARGET_KEY , kTarget,
|
||||
PSYS_PART_FLAGS , ( 0 // texture & influence options:
|
||||
// | PSYS_PART_INTERP_COLOR_MASK
|
||||
| PSYS_PART_INTERP_SCALE_MASK
|
||||
// | PSYS_PART_BOUNCE_MASK
|
||||
// | PSYS_PART_WIND_MASK
|
||||
// | PSYS_PART_FOLLOW_SRC_MASK
|
||||
| PSYS_PART_FOLLOW_VELOCITY_MASK
|
||||
| PSYS_PART_TARGET_POS_MASK
|
||||
// | PSYS_PART_TARGET_LINEAR_MASK
|
||||
| PSYS_PART_EMISSIVE_MASK
|
||||
)] );
|
||||
}
|
||||
}
|
||||
|
||||
default
|
||||
{
|
||||
state_entry() {
|
||||
llLinksetDataReset();
|
||||
llSetText("Empty", <1,1,1>, 1);
|
||||
llSay(0, "Freshly initialized");
|
||||
PROTECT();
|
||||
|
||||
XteaKey(PSK);
|
||||
|
||||
global_ingredients = getIngredientChannel(NULL_KEY);
|
||||
llListen(global_ingredients, "", "", "");
|
||||
particles(NULL_KEY);
|
||||
setProductTexture(TEXTURE_TRANSPARENT);
|
||||
llSay(0, "Ready to package");
|
||||
}
|
||||
|
||||
touch_start(integer num_detected)
|
||||
{
|
||||
llParticleSystem([]);
|
||||
if(g_kFollow == NULL_KEY) {
|
||||
follow(llDetectedKey(0));
|
||||
}else {
|
||||
stopFollowing(g_vScale.z-0.2);
|
||||
}
|
||||
}
|
||||
|
||||
timer () {
|
||||
g_vScale = llGetAgentSize(g_kFollow);
|
||||
if(g_vScale == ZERO_VECTOR) {
|
||||
stopFollowing(g_vScale.z-0.2);
|
||||
}else {
|
||||
list lData = llGetObjectDetails(g_kFollow, [OBJECT_POS, OBJECT_ROT]);
|
||||
vector vPos = llList2Vector(lData,0);
|
||||
rotation rPos = llList2Rot(lData,1);
|
||||
llSetRegionPos(vPos + <1.1, -1, 1> * rPos);
|
||||
}
|
||||
}
|
||||
|
||||
on_rez(integer n) {
|
||||
llSetText("Empty", <1,1,1>, 1);
|
||||
|
||||
llListen(getIngredientChannel(llGetKey()), "", "", "");
|
||||
setProductTexture(TEXTURE_TRANSPARENT);
|
||||
|
||||
// Check if ingredient type was already set. This is not a storage container.
|
||||
if(g_sIngredientType != "none") {
|
||||
llWhisper(0, "I spilled in your inventory, consider using a sealed storage container.");
|
||||
if(g_iDies) llDie();
|
||||
#ifdef DIES
|
||||
llDie();
|
||||
#endif
|
||||
|
||||
g_sIngredientType = "none";
|
||||
g_iQuantity = 0;
|
||||
g_vParticleColor = ZERO_VECTOR;
|
||||
setProductTexture(NULL_KEY);
|
||||
}else {
|
||||
// Inform any nearby object that is waiting that we've been rezzed
|
||||
llWhisper(global_ingredients, xtea_encrypt_string(llList2Json(JSON_OBJECT, ["cmd", "alive", "type", INGREDIENT_HOLDER_TYPE])));
|
||||
}
|
||||
}
|
||||
|
||||
listen(integer c,string n,key i,string m) {
|
||||
// Decode message
|
||||
string params = xtea_decrypt_string(m);
|
||||
|
||||
// Get operation
|
||||
if(c == global_ingredients) {
|
||||
if(g_kID == NULL_KEY) return;
|
||||
else {
|
||||
if(llJsonGetValue(params, ["cmd"]) == "query") {
|
||||
llRegionSayTo(i,c,xtea_encrypt_string(llList2Json(JSON_OBJECT, ["cmd", "reply", "ingredient", g_sIngredientType, "id", g_kID])));
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if(llJsonGetValue(params, ["cmd"]) == "init") {
|
||||
g_kID = llGenerateKey();
|
||||
llSetText("Initializing...", <0.5,0,0>, 1);
|
||||
} else if(llJsonGetValue(params, ["cmd"]) == "deposit") {
|
||||
if(g_sIngredientType == "none" || g_sIngredientType == llJsonGetValue(params, ["type"])) {
|
||||
g_sIngredientType = llJsonGetValue(params, ["type"]);
|
||||
string sStatus = "fail";
|
||||
|
||||
if(g_iQuantity == 0) {
|
||||
g_iQuantity += (integer)llJsonGetValue(params, ["amount"]);
|
||||
sStatus = "ok";
|
||||
setProductTexture(llJsonGetValue(params, ["texture"]));
|
||||
g_vParticleColor = (vector)llJsonGetValue(params, ["particle"]);
|
||||
g_iDies = (integer)llJsonGetValue(params, ["dies"]);
|
||||
|
||||
particles(llGetKey());
|
||||
llMessageLinked(LINK_SET, 0, "", "");
|
||||
}
|
||||
|
||||
setText();
|
||||
|
||||
|
||||
llRegionSayTo(i, getIngredientChannel(NULL_KEY), xtea_encrypt_string(llList2Json(JSON_OBJECT, ["cmd", "deposit_reply", "status", sStatus])));
|
||||
|
||||
particles(NULL_KEY);
|
||||
}
|
||||
|
||||
} else if(llJsonGetValue(params, ["cmd"]) == "use" && llJsonGetValue(params, ["id"]) == g_kID) {
|
||||
particles(i);
|
||||
if(g_iQuantity==0) {
|
||||
llRegionSayTo(i,global_ingredients,llList2Json(JSON_OBJECT, ["cmd", "use_reply", "id", NULL_KEY, "amount", 0]));
|
||||
return;
|
||||
}
|
||||
g_iQuantity--;
|
||||
llRegionSayTo(i,global_ingredients,llList2Json(JSON_OBJECT, ["cmd", "use_reply", "id", g_kID, "amount", 1, "ingredient", g_sIngredientType]));
|
||||
|
||||
setText();
|
||||
if(g_iQuantity<=0) {
|
||||
g_iQuantity=0;
|
||||
setProductTexture(TEXTURE_TRANSPARENT);
|
||||
|
||||
g_sIngredientType = "none";
|
||||
|
||||
#ifdef DIES
|
||||
llDie();
|
||||
#endif
|
||||
|
||||
if(g_iDies) llDie();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
41
LSL/raw/discord.lsl
Normal file
41
LSL/raw/discord.lsl
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "Common.lsl"
|
||||
|
||||
|
||||
|
||||
SendUserMessage(string sMessage, integer iError) {
|
||||
integer iUseTitle=1;
|
||||
if(llStringLength(sMessage) > 255) iUseTitle=0;
|
||||
|
||||
string sJson = llList2Json(JSON_OBJECT, [
|
||||
"content", JSON_NULL,
|
||||
"attachments", llList2Json(JSON_ARRAY, []),
|
||||
"username", "Farm Servers",
|
||||
"avatar_url", "https://media.discordapp.net/attachments/836451385733021706/1238977979141591081/second-life-icon-25-3810850605.png?ex=66413fa9&is=663fee29&hm=f92e5dceb842992fcc56cfde3dce306da91412eb12f3ca8ebfab4ed2c163115a&=&format=webp&quality=lossless&width=500&height=500",
|
||||
"embeds", llList2Json(JSON_ARRAY, [
|
||||
llList2Json(JSON_OBJECT, [
|
||||
"footer", llList2Json(JSON_OBJECT, [
|
||||
"text", "Aria's Creations Discord Relay v" + VERSION
|
||||
]),
|
||||
"timestamp", llGetTimestamp()
|
||||
])
|
||||
])
|
||||
]);
|
||||
|
||||
if(iUseTitle)
|
||||
sJson = llJsonSetValue(sJson, ["embeds", 0, "title"], sMessage);
|
||||
else sJson = llJsonSetValue(sJson, ["embeds", 0, "description"], sMessage);
|
||||
|
||||
llHTTPRequest(g_sNotifyURL, [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/json"], sJson);
|
||||
|
||||
llSay(0, "Message Sent!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
default
|
||||
{
|
||||
state_entry()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
89
LSL/raw/item_server.lsl
Normal file
89
LSL/raw/item_server.lsl
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include "Common.lsl"
|
||||
|
||||
string API_SERVER;
|
||||
integer g_iActive = 1;
|
||||
integer g_iRegistered=0;
|
||||
|
||||
default {
|
||||
state_entry() {
|
||||
llSay(0, "Server '" + llGetObjectDesc() + "' is starting up...");
|
||||
llMessageLinked(LINK_SET, 2, "", "");
|
||||
llMessageLinked(LINK_SET, -1, "", "");
|
||||
|
||||
XteaKey(PSK);
|
||||
}
|
||||
|
||||
link_message(integer s,integer n,string m,key i) {
|
||||
if(n == 0x004f) {
|
||||
API_SERVER = DecipherService(m, "api");
|
||||
if(g_iRegistered)return;
|
||||
|
||||
// Register the server object ID
|
||||
llHTTPRequest(API_SERVER + "/zni/Put_Server_ID.php?NAME=" + llEscapeURL(llGetObjectDesc()) + "&PSK=" + llEscapeURL(SERVER_PSK), [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/json"], llList2Json(JSON_OBJECT, ["id", llGetKey()]));
|
||||
llMessageLinked(LINK_SET, 1, "", "");
|
||||
}
|
||||
}
|
||||
|
||||
http_response(key k, integer s, list m, string b) {
|
||||
if(s == 200) {
|
||||
llMessageLinked(LINK_SET, 0, "", "");
|
||||
llSay(0, "Server '" + llGetObjectDesc() +"' is now ready");
|
||||
|
||||
g_iRegistered=TRUE;
|
||||
|
||||
llSetTimerEvent(1);
|
||||
}
|
||||
}
|
||||
|
||||
touch_start(integer t) {
|
||||
if(llDetectedKey(0) == llGetOwner()) {
|
||||
g_iActive = 1-g_iActive;
|
||||
if(g_iActive) {
|
||||
llSay(0, "Server '" + llGetObjectDesc() + "' reactivating...");
|
||||
llResetScript();
|
||||
} else {
|
||||
llMessageLinked(LINK_SET, 2, "", "");
|
||||
llSay(0, "Server '" + llGetObjectDesc() + "' has been taken offline for maintenance. Any pending requests will still be processed, but any new ones will be blocked");
|
||||
llHTTPRequest(API_SERVER + "/zni/Del_Server_ID.php?NAME=" + llEscapeURL(llGetObjectDesc()) + "&PSK=" + llEscapeURL(SERVER_PSK), [], "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer() {
|
||||
llGetNextEmail("", "");
|
||||
}
|
||||
|
||||
on_rez(integer t) {
|
||||
llResetScript();
|
||||
}
|
||||
|
||||
email(string time, string address, string subject, string body, integer num_remain) {
|
||||
if(subject == "RequestProductDelivery") {
|
||||
//llSay(0, "EMAIL : " + body);
|
||||
llMessageLinked(LINK_SET, 1, "", "");
|
||||
list lPar = llParseString2List(body, [";;"], []);
|
||||
|
||||
string sPayload = xtea_decrypt_string(llList2String(lPar,1));
|
||||
// Check what object is being requested and by who
|
||||
string sRequest = llJsonGetValue(sPayload, ["item"]);
|
||||
string sID = llJsonGetValue(sPayload, ["id"]);
|
||||
|
||||
// Forbid giving scripts
|
||||
if(llGetInventoryType(sRequest) == INVENTORY_SCRIPT) return;
|
||||
|
||||
// Deliver if we have the item
|
||||
if(llGetInventoryType(sRequest) != INVENTORY_NONE) {
|
||||
llGiveInventory(sID, sRequest);
|
||||
llWhisper(999, sPayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Log this as an error in delivery
|
||||
llWhisper(998, sPayload);
|
||||
}
|
||||
|
||||
llSleep(0.25);
|
||||
llMessageLinked(LINK_SET, 0, "", "");
|
||||
}
|
||||
}
|
||||
}
|
67
LSL/raw/tests/item_sink.lsl
Normal file
67
LSL/raw/tests/item_sink.lsl
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "Common.lsl"
|
||||
|
||||
integer global_ingredients;
|
||||
list g_lDiscovered = [];
|
||||
key g_kAv;
|
||||
integer g_iChannel;
|
||||
integer g_iListen;
|
||||
|
||||
|
||||
default
|
||||
{
|
||||
state_entry()
|
||||
{
|
||||
XteaKey(PSK);
|
||||
|
||||
global_ingredients = getIngredientChannel(NULL_KEY);
|
||||
llListen(global_ingredients, "", "", "");
|
||||
llOwnerSay("Listening on " + (string)global_ingredients);
|
||||
}
|
||||
|
||||
touch_start(integer t) {
|
||||
if(g_kAv != "") {
|
||||
return;
|
||||
}
|
||||
g_lDiscovered = [];
|
||||
llSay(0, "Looking for nearby ingredients...");
|
||||
|
||||
llWhisper(global_ingredients, xtea_encrypt_string(llList2Json(JSON_OBJECT, ["cmd", "query"])));
|
||||
|
||||
llSetTimerEvent(3);
|
||||
g_kAv = llDetectedKey(0);
|
||||
}
|
||||
|
||||
timer() {
|
||||
list lOpts = StrideOfList(g_lDiscovered, 3, 1, -1);
|
||||
g_iChannel = llRound(llFrand(0xFFFF));
|
||||
g_iListen = llListen(g_iChannel, "", "", "");
|
||||
|
||||
llDialog(g_kAv, "What item do you want to delete?", lOpts, g_iChannel);
|
||||
|
||||
llSetTimerEvent(0);
|
||||
}
|
||||
|
||||
listen(integer c,string n,key i,string m) {
|
||||
if(c == global_ingredients) {
|
||||
|
||||
string params = xtea_decrypt_string(m);
|
||||
if(llJsonGetValue(params,["cmd"]) == "reply"){
|
||||
g_lDiscovered += [llJsonGetValue(params,["id"]), llJsonGetValue(params, ["ingredient"]), i];
|
||||
llWhisper(0, "Discovered: " + llJsonGetValue(params, ["ingredient"]));
|
||||
}
|
||||
} else if(c == g_iChannel) {
|
||||
integer iIndex = llListFindList(g_lDiscovered, [m]);
|
||||
if(iIndex == -1) {
|
||||
llResetScript();
|
||||
} else {
|
||||
string sID = llList2String(g_lDiscovered, iIndex-1);
|
||||
string sObj = llList2String(g_lDiscovered, iIndex+1);
|
||||
|
||||
integer iChan = getIngredientChannel(sObj);
|
||||
llRegionSayTo(sObj, iChan, xtea_encrypt_string(llList2Json(JSON_OBJECT, ["cmd", "use", "id", sID])));
|
||||
|
||||
llResetScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
LSL/raw/tree.lsl
Normal file
13
LSL/raw/tree.lsl
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "Common.lsl"
|
||||
|
||||
integer g_iStartedGrowing;
|
||||
integer g_iWater;
|
||||
|
||||
default
|
||||
{
|
||||
state_entry()
|
||||
{
|
||||
g_iStartedGrowing = (integer)llLinksetDataRead("progress");
|
||||
g_iWater = (integer)llLinksetDataRead("water");
|
||||
}
|
||||
}
|
215
LSL/raw/water_well.lsl
Normal file
215
LSL/raw/water_well.lsl
Normal file
|
@ -0,0 +1,215 @@
|
|||
#include "Common.lsl"
|
||||
|
||||
integer g_iLastFillTime;
|
||||
integer g_iTotalWater;
|
||||
integer g_iWellChannel;
|
||||
integer g_iWellListener;
|
||||
string WATER_TEXTURE = "333d2eb0-f8c3-2c2e-3371-43df880ad2bf";
|
||||
vector WATER_PARTICLE = <0.20,0.36,0.79>;
|
||||
string API_SERVER="nset";
|
||||
key g_kAv=NULL_KEY;
|
||||
float g_fEmpty = -1.142;
|
||||
float g_fFull = -0.202;
|
||||
integer g_iRequestTime = 0;
|
||||
string WATER_WELL_NAME = "WoodStoneWaterWell";
|
||||
string VERSION = "1.0.0";
|
||||
integer g_iWaterPrim;
|
||||
integer g_iRoofPrim;
|
||||
integer g_iDestroyed = 0;
|
||||
|
||||
|
||||
float getScaledValue(integer percentage) {
|
||||
// Ensure the percentage is within the range 0-100
|
||||
if (percentage < 0) percentage = 0;
|
||||
if (percentage > 100) percentage = 100;
|
||||
|
||||
// Calculate the scaled value
|
||||
float scaledValue = g_fEmpty + ((g_fFull - g_fEmpty) * (percentage / 100.0));
|
||||
return scaledValue;
|
||||
}
|
||||
|
||||
setText() {
|
||||
llSetText("Water Well\nFill Level: " +(string)g_iTotalWater + "%", <1,1,1>, 1);
|
||||
}
|
||||
|
||||
updateLevel() {
|
||||
llSetLinkPrimitiveParams(2, [PRIM_POS_LOCAL, <0,0,getScaledValue(g_iTotalWater)>]);
|
||||
}
|
||||
|
||||
SCAN() {
|
||||
integer i;
|
||||
integer end = llGetNumberOfPrims();
|
||||
for(i=LINK_ROOT;i<=end;i++){
|
||||
string sName = llGetLinkName(i);
|
||||
if(sName == "water") g_iWaterPrim = i;
|
||||
if(sName == "roof") g_iRoofPrim = i;
|
||||
}
|
||||
|
||||
if(!g_iWaterPrim || !g_iRoofPrim) {
|
||||
llSay(0, "Something is wrong, either the water of roof was not detected");
|
||||
}
|
||||
}
|
||||
|
||||
default
|
||||
{
|
||||
state_entry()
|
||||
{
|
||||
llLinksetDataReset();
|
||||
XteaKey(PSK);
|
||||
PROTECT();
|
||||
llSay(0, "Scanning for needed linked prims...");
|
||||
SCAN();
|
||||
llSay(0, "Scan completed");
|
||||
|
||||
llSay(0, "Ready to be packaged");
|
||||
global_ingredients = getIngredientChannel(NULL_KEY);
|
||||
llListen(global_ingredients, "", "", "");
|
||||
g_iTotalWater = 100;
|
||||
|
||||
updateLevel();
|
||||
setText();
|
||||
|
||||
}
|
||||
|
||||
listen(integer c,string n,key i,string m) {
|
||||
string sJson = xtea_decrypt_string(m);
|
||||
if(llJsonGetValue(sJson, ["cmd"]) == "alive" && llJsonGetValue(sJson, ["type"]) == "Bucket") {
|
||||
|
||||
if(g_kAv != NULL_KEY) {
|
||||
|
||||
g_iTotalWater--;
|
||||
g_iLastFillTime = llGetUnixTime();
|
||||
llSetTimerEvent(1);
|
||||
g_kAv = NULL_KEY;
|
||||
|
||||
|
||||
integer iChannel = getIngredientChannel(i);
|
||||
llSleep(2);
|
||||
llRegionSayTo(i, iChannel, xtea_encrypt_string(llList2Json(JSON_OBJECT, ["cmd", "init"])));
|
||||
llSleep(1);
|
||||
|
||||
llRegionSayTo(i, iChannel, xtea_encrypt_string(llList2Json(JSON_OBJECT, ["cmd", "deposit", "type", "Water", "amount", 4, "texture", WATER_TEXTURE, "particle", WATER_PARTICLE, "dies", 1])));
|
||||
|
||||
setText();
|
||||
updateLevel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
on_rez(integer t) {
|
||||
// Start the timer
|
||||
g_iLastFillTime = llGetUnixTime();
|
||||
llSetTimerEvent(1);
|
||||
|
||||
if(g_iWellChannel != 0) {
|
||||
llListenRemove(g_iWellListener);
|
||||
}
|
||||
g_iWellChannel = (integer)("0x" + llGetSubString(llGetKey(), 0, 5));
|
||||
g_iWellListener = llListen(g_iWellChannel, "", "", "");
|
||||
|
||||
setText();
|
||||
}
|
||||
|
||||
link_message(integer s,integer n,string m,key i) {
|
||||
if(n == 0x004f) {
|
||||
API_SERVER = DecipherService(m, "api") + "/zni";
|
||||
}
|
||||
}
|
||||
|
||||
changed(integer c) {
|
||||
if(c & CHANGED_OWNER) {
|
||||
// pre-fill water
|
||||
g_iTotalWater = 100;
|
||||
} else if(c & CHANGED_REGION_START) {
|
||||
// Check for a product update
|
||||
llHTTPRequest(API_SERVER + "/Modify_Product_V2.php", [HTTP_MIMETYPE, "application/json", HTTP_METHOD, "POST"], llList2Json(JSON_OBJECT, ["psk", SERVER_PSK, "op", "get", "name", WATER_WELL_NAME]));
|
||||
}
|
||||
}
|
||||
|
||||
timer() {
|
||||
if(llGetUnixTime() > (g_iLastFillTime + 30)) {
|
||||
g_iLastFillTime = llGetUnixTime();
|
||||
g_iTotalWater ++;
|
||||
|
||||
updateLevel();
|
||||
|
||||
if(g_iTotalWater >= 100) {
|
||||
g_iTotalWater = 100;
|
||||
llSetTimerEvent(0);
|
||||
llLinksetDataWrite("water", (string)g_iTotalWater);
|
||||
}
|
||||
|
||||
setText();
|
||||
}
|
||||
}
|
||||
|
||||
touch_start(integer t) {
|
||||
if(g_iDestroyed) {
|
||||
llSay(0, "The well appears to have sustained a lot of damage. You'll need to construct a new one.");
|
||||
return;
|
||||
}
|
||||
if(g_iTotalWater == 0) {
|
||||
llSay(0, "The well is currently empty. Come back later");
|
||||
return;
|
||||
}
|
||||
|
||||
if(API_SERVER == "nset") {
|
||||
llWhisper(0, "Still waiting for API Server...");
|
||||
llMessageLinked(LINK_SET, -1, "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
if(g_kAv == NULL_KEY) {
|
||||
|
||||
g_kAv = llDetectedKey(0);
|
||||
g_iRequestTime = llGetUnixTime();
|
||||
//llRezObject("Water Bucket [AC]", llGetPos() + <2,0,0>, ZERO_VECTOR, ZERO_ROTATION, g_iWellChannel);
|
||||
llHTTPRequest(API_SERVER + "/Get_Server_ID.php?NAME=Farming", [], "");
|
||||
|
||||
llWhisper(0, "Requesting a bucket...");
|
||||
llSetText("BUSY", <1,0,0>,1);
|
||||
} else {
|
||||
if(llGetAgentSize(g_kAv) == ZERO_VECTOR) {
|
||||
llWhisper(0, "I was previously in use, the person seems to have left the region. Try again now");
|
||||
g_kAv = NULL_KEY;
|
||||
setText();
|
||||
}else {
|
||||
llWhisper(0, "I am currently in use, please be patient");
|
||||
|
||||
if(llGetUnixTime() > g_iRequestTime + 120) {
|
||||
llWhisper(0, "2 minutes have passed, clearing busy status");
|
||||
g_kAv = NULL_KEY;
|
||||
g_iRequestTime = 0;
|
||||
setText();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
http_response(key kID, integer iStatus, list lMeta, string sBody) {
|
||||
list lParams = llParseString2List(sBody, [";", ";;"], []);
|
||||
string sScript = llList2String(lParams,0);
|
||||
|
||||
//llSay(0, sBody);
|
||||
|
||||
if(sScript == "GetServerID") {
|
||||
string sJson = llList2String(lParams,1);
|
||||
g_sServerID = llJsonGetValue(sJson, ["id"]);
|
||||
requestProductForDelivery("Water Bucket [AC]", g_kAv);
|
||||
}else if(sScript == "Modify_ProductV2") {
|
||||
// Gives the version information
|
||||
string sJson = llList2String(lParams,1);
|
||||
if(llJsonGetValue(sJson, ["status"]) == "ok") {
|
||||
// We now have the effective version, check it
|
||||
if(llJsonGetValue(sJson, ["version"]) != VERSION) {
|
||||
// Do what needs doing
|
||||
llSetLinkTexture(g_iRoofPrim, TEXTURE_TRANSPARENT, ALL_SIDES);
|
||||
llSetLinkTexture(g_iWaterPrim, TEXTURE_TRANSPARENT, ALL_SIDES);
|
||||
|
||||
g_iDestroyed=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
LSL/src/Ingredient [AC].lsl
Normal file
3
LSL/src/Ingredient [AC].lsl
Normal file
|
@ -0,0 +1,3 @@
|
|||
#define INGREDIENT_HOLDER_TYPE "Basket"
|
||||
|
||||
#include "../raw/basic_ingredient.lsl"
|
1
LSL/src/Item Server [AC].lsl
Normal file
1
LSL/src/Item Server [AC].lsl
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../raw/item_server.lsl"
|
1
LSL/src/ItemSink.lsl
Normal file
1
LSL/src/ItemSink.lsl
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../raw/tests/item_sink.lsl"
|
15
LSL/src/README.md
Normal file
15
LSL/src/README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
Farming System
|
||||
==========
|
||||
|
||||
## Why did I choose this way of doing things?
|
||||
I wanted to ensure that I can continue to update the sub-products. Say I fix a bug in the water well, I don't want to force anybody to go return to get a new one. The way I came up with instead is to enable everything, all products, to be craftable with my system, including tree saplings. The current architecture may change. That is why I designed it this way. It is not to punish the player, or anti-cheat. This is purely to ensure updates can be delivered in a more or less friendly way. In the future the products will check for a newer version, if there is one, it'll start the decay timer. Currently the decay timer is just always on. 5000 uses till decayed.
|
||||
|
||||
## How can I craft something?
|
||||
|
||||
When you purchased the starter kit, you would have received a HUD. That is how you craft. The starter kit will have come with three things.
|
||||
|
||||
1. Tree Sapling
|
||||
2. Water Well
|
||||
3. Iron Mine
|
||||
|
||||
The iron mine will often produce stone, you won't get 100% iron yield out of your mine. That would be unrealistic. You can use that stone to craft the water well. Use some of the wood to craft the roof of the well. The HUD will have a recipe search to aid in getting materials loaded, you will not need to memorize anything.
|
1
LSL/src/Service Daemon [AC].lsl
Normal file
1
LSL/src/Service Daemon [AC].lsl
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../external/ServiceCheck/ServiceDaemon.lsl"
|
1
LSL/src/Tree [AC].lsl
Normal file
1
LSL/src/Tree [AC].lsl
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../raw/tree.lsl"
|
5
LSL/src/Water Bucket [AC].lsl
Normal file
5
LSL/src/Water Bucket [AC].lsl
Normal file
|
@ -0,0 +1,5 @@
|
|||
#define PRODUCT_PRIM 2
|
||||
#define DIES 1
|
||||
#define INGREDIENT_HOLDER_TYPE "Bucket"
|
||||
|
||||
#include "../raw/basic_ingredient.lsl"
|
1
LSL/src/Water Well [AC].lsl
Normal file
1
LSL/src/Water Well [AC].lsl
Normal file
|
@ -0,0 +1 @@
|
|||
#include "../raw/water_well.lsl"
|
Loading…
Add table
Add a link
Reference in a new issue