// XyTextDriver // Provides an interface for writing to the xytext screen. // Portions Copyright (C) 2005-2006 Francisco V. Saldana // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // Francisco V. Saldana can be contacted using his email account // username: dressedinblue, at domain: gmail.com // and in Second Life by IMming Christopher Omega // This script is responsible for taking text sent to it via its // link_message methodName setLineText and commanding the xytext to // set the text on the specified line. It also implements a setLineColor // link_message method, that allows for other components to set the color // of a line. The controller encapsulates all the intracasies of setting up // and giving commands to the XyText. // Its basically a heavily modified version of the main setup script // used in Xylor's notecard reading screen, so props to him for a good // portion of the stuff in here (that's also why some of it is inconsistant // with the message protocol used by the other modules, I didn't feel like // like modifying it *too* much ^_^). integer NUMBER_OF_ROWS = 13; integer CELLS_IN_ROW = 10; integer CHARS_PER_CELL = 6; integer SET_CELL_INFO = 204004; integer SET_CELL_COLOR_INFO = 205001; integer REQUEST_LINK_NUMBERS = 7000; integer RETURN_TOP_LEFT_CELL = 7001; integer CELL_CHANNEL_BASE = 9000000; integer COLOR_CHANNEL_BASE = 8000000; setCharPrimInfo(integer textChannel, integer charPosition) { llMessageLinked(LINK_SET, SET_CELL_INFO, llList2CSV([textChannel, charPosition]), ""); } initializeCells(integer top_left_cell) { // Set up message channels for all XyText cells. // Set up each cell, row by row. integer CellChannel = CELL_CHANNEL_BASE; integer ColorChannel = COLOR_CHANNEL_BASE; integer CellCharPos = 0; integer CharsPerRow = CELLS_IN_ROW * CHARS_PER_CELL; integer LineNum = 0; integer LastCell = top_left_cell + NUMBER_OF_ROWS * CELLS_IN_ROW - 1; integer i; for (i = top_left_cell; i <= LastCell; i++) { // Set the info for this cell. llMessageLinked(i, SET_CELL_INFO, llList2CSV([CellChannel, CellCharPos]), ""); llMessageLinked(i, SET_CELL_COLOR_INFO, (string) ColorChannel, ""); // Move to the next cell. CellCharPos += CHARS_PER_CELL; // Have we reached the end of the row? if (CellCharPos >= CharsPerRow) { // Yes, go to the next row. CellChannel++; ColorChannel++; LineNum++; CellCharPos = 0; } } } integer getTrueLineNum(integer lineNum) { if (lineNum < 0) { lineNum += NUMBER_OF_ROWS; } return lineNum; } setLineText(integer line, string text) { line = getTrueLineNum(line); if (text != "") { linesWithText = linesWithText | (integer) llPow(2, line); } else { linesWithText = linesWithText & ~(integer) llPow(2, line); } integer lineChannel = CELL_CHANNEL_BASE + line; llMessageLinked(LINK_SET, lineChannel, text, ""); } setLineColor(integer line, vector color) { line = getTrueLineNum(line); integer lineChannel = COLOR_CHANNEL_BASE + line; llMessageLinked(LINK_SET, lineChannel, (string) color, ""); } integer linesWithText = -1; integer lineHasText(integer lineNum) { lineNum = getTrueLineNum(lineNum); integer bit = (integer) llPow(2, lineNum); return ((bit & linesWithText) == bit); } cls() { integer i; for(i = 0; i < NUMBER_OF_ROWS; i++) { if (lineHasText(i)) { setLineText(i, ""); } } linesWithText = 0; } // ========== For method invocation ========== string randomStr(string chars, integer len) { integer numChars = llStringLength(chars); string ret; integer i; for (i = 0; i < len; i++) { integer randIndex = llFloor(llFrand(numChars)); ret += llGetSubString(chars, randIndex, randIndex); } return ret; } string SEPERATOR_CHARS = "`~!@#$%^&*()-_+[]{}\|'\";/?.>,<"; integer SEPERATOR_LEN = 3; string dumpList2String(list src) { // Generate a seperator not present in any of the // elements in the list. string chars = (string) src; // Squashes all elements together. string seperator; do { seperator = randomStr(SEPERATOR_CHARS, SEPERATOR_LEN); } while (llSubStringIndex(chars, seperator) != -1); return seperator + llDumpList2String(src, seperator); } list parseStringKeepNulls(string src) { // The seperator should be the first SEPERATOR_LEN // characters in the string. return llParseStringKeepNulls(llDeleteSubString(src, 0, SEPERATOR_LEN - 1), [llGetSubString(src, 0, SEPERATOR_LEN - 1)], []); } callMethod(integer callId, string methodName, list parameters) { llMessageLinked(LINK_THIS, callId, dumpList2String(parameters), methodName); } returnValue(string methodName, integer methodIdentifyer, list value) { llMessageLinked(LINK_THIS, methodIdentifyer, dumpList2String(value), methodName + "_ret"); } // ============================================= trigger_pong(string moduleName) { callMethod(0, "pong", [moduleName]); } string this; default { state_entry() { this = llGetScriptName(); llMessageLinked(LINK_SET, REQUEST_LINK_NUMBERS, "", ""); } link_message(integer sender, integer channel, string parameters, key methodName) { if (channel == RETURN_TOP_LEFT_CELL) { // This conditional one is for setting up the XyText, it is // A call specific to it. // Use the sender's link as the top left cell, and initialize the grid. llSay(0, "Initializing cells..."); initializeCells(sender); cls(); state main; } } } state main { state_entry() { llSay(0, "Cells initilized."); } link_message(integer sender, integer callId, string parameters, key methodName) { if (methodName == "setDisplayLineText") { list paramList = parseStringKeepNulls(parameters); // Method signature: // setLineText(integer line, string text) integer line = (integer) llList2String(paramList, 0); string text = llList2String(paramList, 1); setLineText(line, text); } else if (methodName == "setDisplayLineColor") { list paramList = parseStringKeepNulls(parameters); // Method signature: // setLineColor(integer line, vector color) integer line = (integer) llList2String(paramList, 0); vector color = (vector) llList2String(paramList, 1); setLineColor(line, color); } else if (methodName == "resetScreen") { // Method signature: // resetScreen(); cls(); } else if (methodName == "getScreenSize") { // Method signature: // [int, int] getScreenSize() // Return value: getScreenSize_ret(integer width, integer height) returnValue(methodName, callId, [CELLS_IN_ROW * CHARS_PER_CELL, NUMBER_OF_ROWS]); } else if (methodName == "screenTest") { // Method signature: // screenTest() integer i; integer j; integer charsPerLine = CELLS_IN_ROW * CHARS_PER_CELL; for (i = 0; i < NUMBER_OF_ROWS; ++i) { string lineText; for (j = 0; j < charsPerLine; j += llStringLength((string)i)) { lineText += (string) i; } setLineText(i, lineText); } } else if (methodName == "ping") { list paramList = parseStringKeepNulls(parameters); // Method signature: // ping(string moduleName) string moduleName = llList2String(paramList, 0); if (moduleName == this) trigger_pong(this); } } }