xs_foodbowl.lsl 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // :CATEGORY:XS Pet
  2. // :NAME:XS Pet Xundra Snowpaw Original Quail
  3. // :AUTHOR:Xundra Snowpaw
  4. // :CREATED:2013-09-06
  5. // :EDITED:2013-09-18 15:39:11
  6. // :ID:989
  7. // :NUM:1481
  8. // :REV:1
  9. // :WORLD:Second Life, Opensim
  10. // :DESCRIPTION:
  11. // Original Pet Quail
  12. // :CODE:
  13. string SECRET_PASSWORD = "top secret";
  14. integer UNITS_OF_FOOD = 168;
  15. key YOUR_UUID = "00000000-0000-0000-0000-000000000000";
  16. integer FOOD_CHANNEL = -999191;
  17. integer ANIMAL_CHANNEL = -999192;
  18. integer FOOD_TYPE = 0;
  19. // LINK MESSAGE FOOD DECREASE, NUMBER 100, STRING amount
  20. //
  21. // DON'T CHANGE THE FOLLOWING! (Unless you know what you are doing!)
  22. integer XTEA_DELTA = 0x9E3779B9; // (sqrt(5) - 1) * 2^31
  23. integer xtea_num_rounds = 6;
  24. list xtea_key = [0, 0, 0, 0];
  25. integer hex2int(string hex) {
  26. if(llGetSubString(hex,0,1) == "0x")
  27. return (integer)hex;
  28. if(llGetSubString(hex,0,0) == "x")
  29. return (integer)("0"+hex);
  30. return(integer)("0x"+hex);
  31. }
  32. // Convers any string to a 32 char MD5 string and then to a list of
  33. // 4 * 32 bit integers = 128 bit Key. MD5 ensures always a specific
  34. // 128 bit key is generated for any string passed.
  35. list xtea_key_from_string( string str )
  36. {
  37. str = llMD5String(str,0); // Use Nonce = 0
  38. return [ hex2int(llGetSubString( str, 0, 7)),
  39. hex2int(llGetSubString( str, 8, 15)),
  40. hex2int(llGetSubString( str, 16, 23)),
  41. hex2int(llGetSubString( str, 24, 31))];
  42. }
  43. // Encipher two integers and return the result as a 12-byte string
  44. // containing two base64-encoded integers.
  45. string xtea_encipher( integer v0, integer v1 )
  46. {
  47. integer num_rounds = xtea_num_rounds;
  48. integer sum = 0;
  49. do {
  50. // LSL does not have unsigned integers, so when shifting right we
  51. // have to mask out sign-extension bits.
  52. v0 += (((v1 << 4) ^ ((v1 >> 5) & 0x07FFFFFF)) + v1) ^ (sum + llList2Integer(xtea_key, sum & 3));
  53. sum += XTEA_DELTA;
  54. v1 += (((v0 << 4) ^ ((v0 >> 5) & 0x07FFFFFF)) + v0) ^ (sum + llList2Integer(xtea_key, (sum >> 11) & 3));
  55. } while( num_rounds = ~-num_rounds );
  56. //return only first 6 chars to remove "=="'s and compact encrypted text.
  57. return llGetSubString(llIntegerToBase64(v0),0,5) +
  58. llGetSubString(llIntegerToBase64(v1),0,5);
  59. }
  60. // Decipher two base64-encoded integers and return the FIRST 30 BITS of
  61. // each as one 10-byte base64-encoded string.
  62. string xtea_decipher( integer v0, integer v1 )
  63. {
  64. integer num_rounds = xtea_num_rounds;
  65. integer sum = XTEA_DELTA*xtea_num_rounds;
  66. do {
  67. // LSL does not have unsigned integers, so when shifting right we
  68. // have to mask out sign-extension bits.
  69. v1 -= (((v0 << 4) ^ ((v0 >> 5) & 0x07FFFFFF)) + v0) ^ (sum + llList2Integer(xtea_key, (sum>>11) & 3));
  70. sum -= XTEA_DELTA;
  71. v0 -= (((v1 << 4) ^ ((v1 >> 5) & 0x07FFFFFF)) + v1) ^ (sum + llList2Integer(xtea_key, sum & 3));
  72. } while ( num_rounds = ~-num_rounds );
  73. return llGetSubString(llIntegerToBase64(v0), 0, 4) +
  74. llGetSubString(llIntegerToBase64(v1), 0, 4);
  75. }
  76. // Encrypt a full string using XTEA.
  77. string xtea_encrypt_string( string str )
  78. {
  79. // encode string
  80. str = llStringToBase64(str);
  81. // remove trailing =s so we can do our own 0 padding
  82. integer i = llSubStringIndex( str, "=" );
  83. if ( i != -1 )
  84. str = llDeleteSubString( str, i, -1 );
  85. // we don't want to process padding, so get length before adding it
  86. integer len = llStringLength(str);
  87. // zero pad
  88. str += "AAAAAAAAAA=";
  89. string result;
  90. i = 0;
  91. do {
  92. // encipher 30 (5*6) bits at a time.
  93. result += xtea_encipher(llBase64ToInteger(llGetSubString(str, i, i + 4) + "A="), llBase64ToInteger(llGetSubString(str, i+5, i + 9) + "A="));
  94. i+=10;
  95. } while ( i < len );
  96. return result;
  97. }
  98. // Decrypt a full string using XTEA
  99. string xtea_decrypt_string( string str ) {
  100. integer len = llStringLength(str);
  101. integer i=0;
  102. string result;
  103. //llOwnerSay(str);
  104. do {
  105. integer v0;
  106. integer v1;
  107. v0 = llBase64ToInteger(llGetSubString(str, i, i + 5) + "==");
  108. i+= 6;
  109. v1 = llBase64ToInteger(llGetSubString(str, i, i + 5) + "==");
  110. i+= 6;
  111. result += xtea_decipher(v0, v1);
  112. } while ( i < len );
  113. // Replace multiple trailing zeroes with a single one
  114. i = llStringLength(result) - 1;
  115. while ( llGetSubString(result, i - 1, i) == "AA" ){
  116. result = llDeleteSubString(result, i, i);
  117. i--;
  118. }
  119. i = llStringLength(result) - 1;
  120. // while (llGetSubString(result, i, i + 1) == "A" ) {
  121. // i--;
  122. // }
  123. result = llGetSubString(result, 0, i+1);
  124. i = llStringLength(result);
  125. integer mod = i%4; //Depending on encoded length diffrent appends are needed
  126. if(mod == 1) result += "A==";
  127. else if(mod == 2 ) result += "==";
  128. else if(mod == 3) result += "=";
  129. return llBase64ToString(result);
  130. }
  131. string base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  132. integer food_left;
  133. default
  134. {
  135. state_entry()
  136. {
  137. if (llGetOwner() != YOUR_UUID) {
  138. // someone not the creator reset the script. Thats naughty.
  139. state dead;
  140. }
  141. llSetText("", <1,1,1>, 1.0);
  142. xtea_key = xtea_key_from_string(SECRET_PASSWORD);
  143. food_left = UNITS_OF_FOOD;
  144. llListen(FOOD_CHANNEL, "", "", "");
  145. }
  146. touch_start(integer total_number)
  147. {
  148. llSetTimerEvent(20.0);
  149. llSetText((string)food_left + " servings remaining.", <1,1,1>, 1.0);
  150. }
  151. timer()
  152. {
  153. llSetTimerEvent(0.0);
  154. llSetText("", <1,1,1>, 1.0);
  155. }
  156. listen(integer channel, string name, key id, string message)
  157. {
  158. list data = llParseString2List(xtea_decrypt_string(message), ["^"] , []);
  159. if (llList2String(data, 0) == "XSPET") {
  160. if (llList2String(data, 1) == "FOOD_LOCATION") {
  161. integer random_key = llList2Integer(data, 2);
  162. key animal_key = llList2Key(data, 3);
  163. llSay(ANIMAL_CHANNEL, xtea_encrypt_string("XSPET^FOOD_LOCATION^" + (string)random_key + "^" + (string)llGetPos() + "^" + (string)animal_key));
  164. }
  165. if (llList2String(data, 1) == "FOOD_CONSUME") {
  166. if (llList2Key(data, 2) == llGetKey()) {
  167. integer random_key = llList2Integer(data, 3);
  168. key animal_key = llList2Key(data, 4);
  169. food_left--;
  170. llMessageLinked(LINK_SET, 100, "1", "");
  171. llSay(ANIMAL_CHANNEL, xtea_encrypt_string("XSPET^FOOD_CONSUME^" + (string)random_key + "^" + (string)animal_key + "^" + (string)FOOD_TYPE));
  172. if (food_left <= 0) {
  173. state empty;
  174. }
  175. }
  176. }
  177. }
  178. }
  179. }
  180. state dead
  181. {
  182. state_entry()
  183. {
  184. llSetText("This food bowl has been broken.", <1,0,0>, 1.0);
  185. }
  186. }
  187. state empty
  188. {
  189. state_entry()
  190. {
  191. llSetObjectName("XS Food Bowl (Empty)");
  192. llSetText("Empty", <1,0,0>, 1.0);
  193. }
  194. }