// :CATEGORY:XS Pet // :NAME:XS Pet Quail Modified // :AUTHOR:Xundra Snowpaw, Ferd Frederix // :CREATED:2013-09-06 // :EDITED:2013-09-18 15:39:10 // :ID:987 // :NUM:1429 // :REV:1 // :WORLD:Second Life, Opensim // :DESCRIPTION: // Modified Pet Quail // :CODE: // Version .24 10-3-2011 // script by Xundra Snowpaw // mods by Ferd Frederix // // New BSD License: http://www.opensource.org/licenses/bsd-license.php // Copyright (c) 2010, Xundra Snowpaw // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: //* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. //* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //////////////////////////////////////////////////////////////////// integer API_CHANNEL = -999198; float VERSION = 0.23; string SECRET_PASSWORD = "top secret"; integer SECRET_NUMBER = 99999; integer ANIMAL_CHANNEL = -999192; integer BOX_CHANNEL = -999195; // 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); } string base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; vector colour1; vector colour2; integer gen; integer shine; float glow; key uuid; integer listener; integer owner_touch; integer sex; integer age; integer hunger; string myname; integer glow_gene; string special; say_details() { string mysex; string myshine; if (sex == 1) { mysex = "Male"; } else if (sex == 2) { mysex = "Female"; } else { mysex = (string)sex; } if (shine == 0) { myshine = "None"; } else if (shine == 1) { myshine = "Low"; } else if (shine == 2) { myshine = "Medium"; } else if (shine == 3) { myshine = "High"; } llWhisper(0, "Head/Body Colour: " + (string)colour1); llWhisper(0, "Tail/Wing Colour: " + (string)colour2); llWhisper(0, "Shine: " + myshine); llWhisper(0, "Glow: " + (string)((integer)(glow * 100)) + "%"); llWhisper(0, "Special: " + special); llWhisper(0, "Sex: " + mysex); llWhisper(0, "Age: " + (string)age + " days"); llWhisper(0, "Generation: " + (string)gen); llSay(API_CHANNEL, "XSQuail^" + (string)llGetKey() + "^" + (string)colour1 + "^" + (string)colour2 + "^" + (string)shine + "^" + (string)glow + "^" + special + "^" + (string)gen + "^" + (string)sex + "^" + (string)age + "^XSQuailEnd"); } set_colours(vector c1, vector c2, integer shine, float glow) { llSetPrimitiveParams([PRIM_COLOR, 0, c1, 1.0, PRIM_COLOR, 1, c1, 1.0, PRIM_COLOR, 3, c1, 1.0, PRIM_COLOR, 5, c1, 1.0, PRIM_COLOR, 2, c2, 1.0, PRIM_COLOR, 4, c2, 1.0, PRIM_BUMP_SHINY, ALL_SIDES, shine, PRIM_BUMP_NONE, PRIM_GLOW, ALL_SIDES, glow]); } default { state_entry() { xtea_key = xtea_key_from_string(SECRET_PASSWORD); uuid = NULL_KEY; listener = llListen(BOX_CHANNEL, "", "", ""); } touch_start(integer num) { llWhisper(0, "This Cryo-Crate is v" + (string)VERSION); } listen(integer channel, string name, key id, string msg) { if (llGetOwnerKey(id) != llGetOwner()) { return; } list data = llParseString2List(xtea_decrypt_string(msg), ["^"], []); if (uuid == NULL_KEY) { if (llList2String(data, 0) == "XSPET" && llList2String(data, 2) == "CRATE_PING") { uuid = id; llSay(ANIMAL_CHANNEL, xtea_encrypt_string("XSPET^CRATE_PONG^" + (string)id + "^" + (string)VERSION)); llSetTimerEvent(15.0); } } else if (uuid == id) { if (llList2String(data, 0) == "XSPET" && llList2Key(data, 1) == llGetKey()) { llSetTimerEvent(0.0); colour1 = (vector)llList2String(data, 2); colour2 = (vector)llList2String(data, 3); shine = llList2Integer(data, 4); glow = llList2Float(data, 5); gen = llList2Integer(data, 6); sex = llList2Integer(data, 7); age = llList2Integer(data, 8); hunger = llList2Integer(data, 9); myname = llList2String(data, 10); glow_gene = llList2Integer(data, 11); special = llList2String(data, 12); llListenRemove(listener); llSay(ANIMAL_CHANNEL, xtea_encrypt_string("XSPET^CRATE_DIE^" + (string)id + "^" + (string)VERSION)); state full; } else if (llList2String(data, 0) == "XSPET" && llList2Key(data, 1) != llGetKey()) { uuid = NULL_KEY; } } } timer() { llSetTimerEvent(0.0); uuid = NULL_KEY; } } state full { state_entry() { llSetObjectName("XS Cryo-Crate: " + myname); set_colours(colour1, colour2, shine, glow); llListen(API_CHANNEL, "", "", ""); } touch_start(integer num) { owner_touch = 0; say_details(); if (llDetectedKey(0) == llGetOwner()) { owner_touch = 1; integer chan = (integer)llFrand(10000.0) + 1000; listener = llListen(chan, "", llGetOwner(), ""); llDialog(llGetOwner(), "Would you like to unpackage me?", ["Yes", "No"], chan); } llSetTimerEvent(20.0); } timer() { //llOwnerSay("Menu timeout."); if (owner_touch == 1) { llListenRemove(listener); } llSetTimerEvent(0.0); } listen(integer channel, string name, key id, string msg) { if (channel == API_CHANNEL) { list data = llParseString2List(msg, ["^"], []); if (llList2String(data, 0) == "XSQuail" && llList2Key(data, 1) == llGetKey()) { llSay(API_CHANNEL, "XSQuail^" + (string)llGetKey() + "^" + (string)colour1 + "^" + (string)colour2 + "^" + (string)shine + "^" + (string)glow + "^" + special + "^" + (string)gen + "^" + (string)sex + "^" + (string)age + "^XSQuailEnd"); } } else { llListenRemove(listener); if (msg == "Yes") { state unbox; } } } } state unbox { state_entry() { llRezObject("Quail", llGetPos() + <0.0, 0.0, 0.25>, ZERO_VECTOR, ZERO_ROTATION, SECRET_NUMBER); } object_rez(key id) { listener = llListen(BOX_CHANNEL, "", id, ""); } listen(integer channel, string name, key id, string msg) { if (channel == BOX_CHANNEL) { list data = llParseString2List(xtea_decrypt_string(msg), ["^"], []); if (llList2String(data, 0) == "XSPET" && llList2String(data, 1) == "READY") { llGiveInventory(id, "XS Egg"); llGiveInventory(id, "Quail"); llSay(ANIMAL_CHANNEL, xtea_encrypt_string("XSPET^CONFIG^" + (string)id + "^" + (string)colour1 + "^" + (string)colour2 + "^" + (string)sex + "^" + (string)shine + "^" + (string)glow + "^" + (string)gen + "^" +(string)age + "^" + (string)hunger + "^" + myname + "^" + (string)glow_gene + "^" + special)); llDie(); } } } }