Ein Messageboard

Projekt:

Eines Tages wollte ich mir mal ein neues Message-Board bauen. Ich hatte zwar schon welche, aber keins das fürs Osgrid geeignet wäre. Das lag an den fehlenden Texturen für die 10-Seiten-Prims. Also entschied ich mich für ein 5-seitiges Prim; das hat auch noch den Vorteil, dass nur eine Textur pro Zeichnsatz benötigt wird und somit das ständige Nachladen der Textur (= graue Felder) entfällt. Der Nachteil sind natürlich mehr Prims, aber das ist im OS schon zu verkraften. Daraus ist dieses Tutorial entstanden, ich hab es so gehalten dass auch Anfänger damit zurecht kommen sollten. Die benötigten Skripte stehen am Ende des Textes.

Vorbereitung

Ja es ist etwas Vorbereitung für das Board notwendig, das ist aber nur einmal nötig, dann könnt ihr das Ausgangsprim immer wieder verwenden.
Als erstes benötige ich das Skript, um ein Prim so zu verformen, dass es 5 Anzeigeflächen hat. Das gibt's auf dieser Webseite, ich poste es auch mal hier, da ich es etwas abgeändert hab. Die beiden Texturen müssen auch ersetzt werden. Für die FACE_TEXTURE nehme ich einfach eine quadratische Textur, für die transparente benutze ich die Textur clear aus der OpenSim library (eine andere durchsichtige Textur tuts natürlich auch), ihr müsst halt nur eure Texturen im Skript eintragen.

Ich erzeuge ein neues Prim, lege die beiden Texturen und dann das Skript hinein. Sofort verformt sich das Prim und ich nehme es ins Inventar.

Ich rezze ich es dann gleich zweimal (bitte nicht die Grösse verändern, das könnt ihr dann beim fertigen Board machen, ich hab die Grössen in den Skripten der Einfachheit halber hardcodet). Das eine Prim nenne ich board (wichtig das muss so heissen, ausser ihr ändert das Root-Skript). Ich lege das Skript rezzboard hinein und nehme es ins Inventar. Dann rezze ich einen gewöhnlichen Würfel, stelle die Textur auf Leer, nenne es back (auch wichtig) und lege das Skript rezzback hinein.

Auch dieses Prim kommt ins Inventar. In das übriggebliebene Prim lege ich nun: die eben erstellten Prims namens back und board sowie das Skript rezzroot. Auch dieses Prim nehme ich ins Inventar, das ist das Basisprim meines Boards. Die anderen beiden Prims lösche ich gleich wieder, sie werden nun nicht mehr benötigt. Damit ist die Vorbereitung abgeschlossen, für das Board wird nur das letzte Prim gebraucht.

Fertigstellung

Ich rezze das Basisprim und trage in die Objektbeschreibung die Anzahl der Zeilen und die Anzahl der Zeichen / 5 ein (weil ein Boardprim jeweils 5 Zeichen anzeigt), durch einen Schrägstrich getrennt. Also in meinem Beispiel sind es 5 Zeilen mit je 20 Zeichen, ich trage also 5/4 ein. Nun klicke ich das Prim an und das Board baut sich auf. Ich muss etwas warten bis alles zusammengelinkt ist.
Beim Zusammenbau löscht sich übrigens auch alles was drin ist, so dass ich am Ende ein leeres Board vor mir habe.

Zu guter Letzt erzeuge ich mir einen neuen Würfel, stelle beim Reiter xxx den Wert hohl auf 89% und dehne ihn so lange, bis er genau um die Anzeigezeilen passt. Das ist jetzt der Rahmen. Den verlinke ich mit dem Board. Muss nicht sein aber ich mags eben so :-) Damit wäre das Board fertig, nun benötige ich ein Skript.

Das Basis-Skript hab ich von hier. Allerdings musste ich es umschreiben, weil es für meine Zwecke nicht gepasst hat. Ich wollte nur ein Skript für das Board und nicht in jedem Prim eins. Zudem war zuviel drin, was ich nicht gebraucht hab. Ausserdem hab ich noch die Steuerung per Notecard eingefügt. Das Ergebnis ist weiter unten (display.lsl).

Im Skript könnt ihr oben die Standardfarben und -zeichensatz eintragen, wie sie nach jedem Rücksetzen angezeicht werden sollen. Bei mir ist das "courier new bold" (die Textur muss sich natürlich auch im Board befinden) sowie weiss als Vordergrund- und schwarz als Hintergrund (in den Zeilen mit DefaulTexture, DefaultTextColor und DefaultBackColor).
Damit ist das Board einsatzbereit. Es fehlt nur noch eine Notecard zum Ansteuern, damit man überhaupt etwas sieht.

Steuerung per Notecard

Dazu gehört eine Notecard namens playcard, die ihr nach euren Wünschen ausfüllen könnt. Eine Beispiel-NC, wie ich sie in meinem Demo habe, ist weiter unten. Legt die NC ins Board, sie wird automatisch eingelesen, auch wenn sie mal geändert wird. Auf Klick wird der Ablauf gestartet, ein weiterer Klick stoppt ihn wieder.

Die Notecard sieht folgendermassen aus:

Kommando = Argument1 = Argument2

Bei einigen Kommandos ist nur ein Argument notwendig, Reset braucht gar keins. Gross/Kleinschreibung ist egal, ausser bei der Angabe eines Zeichensatzes. Leerzeichen können auch vorkommen, nur der auszugebende Text muss direkt hinter dem Gleichheitszeichen stehen, sonst werden die Leerzeichen davor ebenfalls mit ausgegeben. Bei der Angabe der Zeilennummer kann auch -1 benutzt werden, dann gilt das Kommando für das gesamte Board. Z.B. Left = -1 = löscht das Board und BackColor = -1 = <0,0,0> setzt den gesamten Hintergrund auf schwarz.

Es stehen folgende Kommandos zur Verfügung:

Loop = x

die NC wird x mal abgearbeitet. Ist x = -1 dann endlos. Ohne Loop oder bei Loop = 0 wird die Notecard nur einmal durchlaufen

Wait = x.y

das Skript macht eine Pause von x.y Sekunden

Charset = x

für alle weiteren Textausgaben wird die Textur (=Zeichensatz) x verwendet, sie muss sich im Board befinden

Left = Zeile =Text

Text wird linksbündig ausgegeben

Center = Zeile =Text

Text wird zentriert ausgegeben

Right = Zeile =Text

Text wird rechtsbündig ausgegeben

Color = Zeile =Text

der Text der Zeile wird gefärbt

BackColor = Zeile =Text

der Hintergrund der Zeile wird gefärbt

FadeIn = Zeile =Text

der Text wird eingeblendet

FadeOut = Zeile =Text

der Text wird ausgeblendet

Reset

die Anzeige wird zurückgesetzt

Für die Darstellung farbiger Einzelbuchstaben bzw. Textstücke gibt es noch zwei Spezialkommandos:

SetLinePos = Zeile = Spalte

die interne Position für Drawletters wird auf das entprechende Zeichen gesetzt

DrawLetters = Farbvektor = Zeichen

der Text wird ab der internen Position in der angegebenen Farbe dargestellt, dabei wird die interne Position weitergeschaltet

Eine Beispiel-Notecard gibt es hier.

Eigene Zeichensätze (Texturen)

Auf der Seite mit dem Skript findet sich auch ein Python-Fu (ein Skript) für GIMP, um Texturen für verschiedene Zeichensätze zu erzeugen. Ich füge es mal der Vollständigkeit halber hier dazu, wenn jemand was dagegen hat lösche ich es wieder.

Ich speichere dieses Skript in eine Textdatei, hänge die Endung .py an und kopiere es ins GIMP-Plugin-Verzeichnis, bei mir C:\GIMP-2.0\lib\gimp\2.0\plug-ins. Bei Neustart von GIMP ist hier das Python-Fu unter dem Namen "Xy Text1CharE" zu finden.

Falls nicht und das "Python-Fu" im Menü ist ausgegraut, habt ihr Python bei der Installation nicht gewählt. Am besten installiert ihr GIMP noch mal und macht bei der Installation ein Häkchen bei Python.
Wenn ich nun dieses Python-Fu anklicke, erscheint diese Auswahl:

Oben kann ich den gewünschten Zeichensatz einstellen, darunter die Farbe (sollte aber weiss bleiben, damit man die Schrift auf dem Board färben kann) und die Zeichenhöhe. Da hat sich 36 - 46 gut bewährt, müsst ihr halt ausprobieren. Es eignen sich auch nur monospace-Zeichensätze, also solche mit fester Breite. Da gibts aber genug im Internet zum kostenlosen Download, einfach mal googlen. Und dann auf dem PC installieren natürlich.
Nach dem Klick auf "Ok" erhalte ich so ein Bildchen:

Ich exportiere es als TGA-Datei, indem ich im Menü auf Datei - Exportieren gehe, den Dateinamen mit der Endung .tga eingebe und auf Exportieren klicke. Bei der folgenden Abfrage entferne ich das Häkchen bei RLE-Kompression und klicke nochmals auf Exportieren. Nun kann ich die Textur im OS oder SL hochladen.

Wer sich nicht alles kopieren und/oder das Board mal anschauen will, kann mich ja mal im OSgrid besuchen, es steht da full perm zum ausprobieren. Darin enthalten ist alles was ihr braucht: das Rootprim sowie alle Skripte, die Demo-Playcard, einige Zeichensätze, eine Notecard mit den Sonderzeichen sowie eine Kurzanleitung. Die Adresse ist:

hg.osgrid.org:80:Bekkas Dream2

Achso ja, und für Kritiken, Verbesserungen oder eigene Wünsche hab ich auch immer beide Ohren offen :-) Ist ja nicht das Non-plus-Ultra was ich hier geschrieben hab. Könnt mich in-world im OSgrid, GermanGrid oder SL ansprechen, ich heisse überall Rebekka Revnik. Oder ne Mail an rebekkarevnik@yahoo.de. Oder im Fratzenbuch, aber da bin ich nur noch selten.

Und hier die Skripte:

Prim-Setup (das Original ist hier)


////////////////////////////////////////////
// XyText Prim Setup
//
// Written by Gearsawe Stonecutter
////////////////////////////////////////////

string FACE_TEXTURE = "AquaCube001"; // Textur für die Vorderseite
string  TRANSPARENT = "clear";       // Transparente Textur

default
{
    state_entry()
    {
        llSetPrimitiveParams([

            PRIM_TYPE, PRIM_TYPE_PRISM, PRIM_HOLE_DEFAULT, <0.199, 0.8, 0.0>, 0.68,
            ZERO_VECTOR, <1.0, 1.0, 0.0>, ZERO_VECTOR,

            // display a default face texture
            PRIM_TEXTURE, 1, FACE_TEXTURE, <2.48, 1.0, 0.0>, <-0.740013, 0.0, 0.0>, 0.0,
            PRIM_TEXTURE, 6, FACE_TEXTURE, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, 0.0,
            PRIM_TEXTURE, 4, FACE_TEXTURE, <-14.75, 1.0, 0.0>, <0.130009, 0.0, 0.0>, 0.0,
            PRIM_TEXTURE, 7, FACE_TEXTURE, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, 0.0,
            PRIM_TEXTURE, 3, FACE_TEXTURE, <2.48, 1.0, 0.0>, <-0.255989, 0.0, 0.0>, 0.0,

            // show transparent textures for the other sides
            PRIM_TEXTURE, 0, TRANSPARENT, <0.1, 0.1, 0>, ZERO_VECTOR, 0.0,
            PRIM_TEXTURE, 2, TRANSPARENT, <0.1, 0.1, 0>, ZERO_VECTOR, 0.0,
            PRIM_TEXTURE, 5, TRANSPARENT, <0.1, 0.1, 0>, ZERO_VECTOR, 0.0,

            PRIM_SIZE, <0.03, 2.89, 0.5>
                ]);

            // Remove ourselves from inventory.
            llRemoveInventory(llGetInventoryName(INVENTORY_TEXTURE, 0));
            llRemoveInventory(llGetInventoryName(INVENTORY_TEXTURE, 0));
        llRemoveInventory(llGetScriptName());
    }
}

rezzboard.lsl - Skript für die Boardteile


default
{
    on_rez(integer start_param)
    {
        integer Row = start_param / 100;
        integer Col = start_param % 100;
        llSetObjectName((string)Row + "/" + (string)Col);
        llRemoveInventory(llGetScriptName());
    }
}

rezzback.lsl - Skript für die Rückwand


float Width = 0.8333;
float Height = 0.1665;
integer Cols;
integer Row;

default
{
    on_rez(integer start_param)
    {
        Cols = start_param % 100;
        Row = start_param / 100;
        llSetScale(<0.01, Width * Cols, Height>);
        llSetObjectName("back" + (string)Row);
        llRemoveInventory(llGetScriptName());
    }
}

rezzroot.lsl - Skript für das Basisprim


string Board = "board";
string Back = "back";
float Width = 0.8333;
float Height = 0.1665;
integer Count;
default
{
    touch_start(integer total_number)
    {
        llRequestPermissions(llDetectedKey(0), PERMISSION_CHANGE_LINKS);
    }
    run_time_permissions(integer permissions)
    {
        integer i;
        integer j;
        list l = llParseString2List(llGetObjectDesc(), ["/"], []);
        integer Rows = llList2Integer(l, 0);
        integer Cols = llList2Integer(l, 1);
        Count = Rows * Cols - 1 + Rows;
        llSetObjectName((string)Rows + "/1");
        for(i = Rows; i > 0; i--)
        {
            for(j = 1; j <= Cols; j++)
            {
                if(!(i == Rows && j == 1))
                llRezObject(Board, llGetPos() + <0, (j - 1) * Width, (Rows - i) * Height>, ZERO_VECTOR, llGetRot(), i * 100 + j);
            }
        }
        for(i = Cols; i > 0; i--)
        {
            float p = (Cols * Width) / 2 - Width / 2;
            llRezObject(Back, llGetPos() + <-0.01, p, (Rows - i) * Height>, ZERO_VECTOR, llGetRot(), i * 100 + Cols);
        }
    }
    object_rez(key id)
    {
        llCreateLink(id, TRUE);
        Count--;
        if(Count == 0)
        {
            llRemoveInventory(Board);
            llRemoveInventory(Back);
            llRemoveInventory(llGetScriptName());
        }
    }
}

display.lsl - Hauptskript für die Anzeige



////////////////////////////////////////////
// XyText v1.2 Script (5 Face, Single Texture)
//
// Written by Xylor Baysklef
//
// Modified by Kermitt Quirk 19/01/2006
// To add support for 5 face prim instead of 3
//
// Heavily modified by Rebekka Revnik 2012
//
////////////////////////////////////////////
string DefaultFont = "courier new bold";	// Standardzeichensatz
vector DefaultTextColor = <1,1,1>;			// Standard-Vordergrundfarbe
vector DefaultBackColor = <0,0,0>;			// Standard-Hintergrundfarbe

integer DISPLAY_STRING      = 204000;
integer CENTER_STRING		= 204002;
integer RIGHT_STRING        = 204004;
integer SET_LINE_POS        = 204006;
integer DRAW_LETTERS        = 204007;
integer SET_COLOR           = 204008;
integer SET_BACKGROUND		= 204009;
integer FADE_IN				= 204010;
integer FADE_OUT            = 204011;
integer CHARSET				= 204016;
integer WAIT				= 204017;
integer RESET				= 204018;

integer FACE_1          = 3;
integer FACE_2          = 7;
integer FACE_3          = 4;
integer FACE_4          = 6;
integer FACE_5          = 1;

list c1;
list c2;
list c3;
list c4;
list c5;

string gFontTexture = "courier new bold";

string gCharIndex;

list utf =
	["%C3%87", "%C3%BC", "%C3%A9", "%C3%A2", "%C3%A4", "%C3%A0", "%C3%A5", "%C3%A7", "%C3%AA", "%C3%AB",
	"%C3%A8", "%C3%AF", "%C3%AE", "%C3%AC", "%C3%84", "%C3%85", "%C3%89", "%C3%A6", "%C3%AE", "%E2%96%B6",
	"%C3%B6", "%C3%B2", "%C3%BB", "%C3%B9", "%C3%BF", "%C3%96", "%C3%9C", "%C2%A2", "%C2%A3", "%C2%A5",
	"%C3%82", "%C2%A9", "%C3%A1", "%C3%AD", "%C3%B3", "%C3%BA", "%C3%B1", "%C3%91", "%C2%AA", "%C2%BA",
	"%C2%BF", "%C3%94", "%C2%AC", "%C2%BD", "%C2%BC", "%C2%A1", "%C2%AB", "%C2%BB", "%CE%B1", "%C3%9F",
	"%CE%93", "%CF%80", "%CE%A3", "%CF%83", "%C2%B5", "%CF%84", "%CE%A6", "%CE%98", "%CE%A9", "%CE%B4",
	"%C5%AC", "%C5%AD", "%CE%B5", "%E2%88%A9", "%E2%89%A1", "%C2%B1", "%E2%89%A5", "%E2%89%A4", " ", " ",
	"%C3%81", "%C3%80", "%C3%A3", "%C3%83", "%C3%8A", "%C3%8D", "%C3%93", "%C3%B5", "%C3%95", "%C3%B4"];

ResetCharIndex() {
	gCharIndex  = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`";
	gCharIndex += "abcdefghijklmnopqrstuvwxyz{|}~\n\n\n\n\n";
	integer i;
	for(i = 0; i < llGetListLength(utf); i++) gCharIndex += llUnescapeURL(llList2String(utf, i));
	integer x = llStringLength(gCharIndex);
	c1 = [];
	c2 = [];
	c3 = [];
	c4 = [];
	c5 = [];
	for(i = 0; i < x; i++)
	{
		c1 += [< -0.445 + 0.1 * (i % 10) + 0.045, 0.422 + -0.05 * (i / 10 - 1), 0.0>];
		c2 += [< -0.445 + 0.1 * (i % 10), 0.422 + -0.05 * (i / 10 - 1), 0.0>];
		c3 += [< -0.445 + 0.1 * (i % 10) - 0.284, 0.422 + -0.05 * (i / 10 - 1), 0.0>];
		c4 += [< -0.445 + 0.1 * (i % 10), 0.422 + -0.05 * (i / 10 - 1), 0.0>];
		c5 += [< -0.445 + 0.1 * (i % 10) - 0.046, 0.422 + -0.05 * (i / 10 - 1), 0.0>];
	}
}

RenderString(integer link, string str)
{
	llSetLinkPrimitiveParamsFast(link, [
		PRIM_TEXTURE, FACE_1, (string)gFontTexture, <0.15, 0.05, 0>, llList2Vector(c1, llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0))), 0.0,
		PRIM_TEXTURE, FACE_2, (string)gFontTexture, <0.06, 0.05, 0>, llList2Vector(c2, llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1))), 0.0,
		PRIM_TEXTURE, FACE_3, (string)gFontTexture, <-0.86, 0.05, 0>, llList2Vector(c3, llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2))), 0.0,
		PRIM_TEXTURE, FACE_4, (string)gFontTexture, <0.06, 0.05, 0>, llList2Vector(c4, llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3))), 0.0,
		PRIM_TEXTURE, FACE_5, (string)gFontTexture, <0.15, 0.05, 0>, llList2Vector(c5, llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4))), 0.0
			]);
}

RenderChar(integer link, integer pos, string char)
{
	if(pos == 0) llSetLinkPrimitiveParamsFast(link, [PRIM_TEXTURE, FACE_1, (string)gFontTexture, <0.15, 0.05, 0>, llList2Vector(c1, llSubStringIndex(gCharIndex, char)), 0.0]);
	else if(pos == 1) llSetLinkPrimitiveParamsFast(link, [PRIM_TEXTURE, FACE_2, (string)gFontTexture, <0.06, 0.05, 0>, llList2Vector(c2, llSubStringIndex(gCharIndex, char)), 0.0]);
	else if(pos == 2) llSetLinkPrimitiveParamsFast(link, [PRIM_TEXTURE, FACE_3, (string)gFontTexture, <-0.86, 0.05, 0>, llList2Vector(c3, llSubStringIndex(gCharIndex, char)), 0.0]);
	else if(pos == 3) llSetLinkPrimitiveParamsFast(link, [PRIM_TEXTURE, FACE_4, (string)gFontTexture, <0.06, 0.05, 0>, llList2Vector(c4, llSubStringIndex(gCharIndex, char)), 0.0]);
	else if(pos == 4) llSetLinkPrimitiveParamsFast(link, [PRIM_TEXTURE, FACE_5, (string)gFontTexture, <0.15, 0.05, 0>, llList2Vector(c5, llSubStringIndex(gCharIndex, char)), 0.0]);
}

FadeIn(integer line)
{
	integer i;
	integer j;
	integer start = line;
	integer end = line + 1;
	if(line == -1)
	{
		start = 0;
		end = MaxRow;
	}
	for(j = start; j < end; j++) for(i = 0; i < MaxCol; i++) llSetLinkAlpha(llList2Integer(Display, j * MaxCol + i), 0.00, ALL_SIDES);
	float Alpha;
	for (Alpha = 0.05; Alpha <= 1.0; Alpha += 0.05)
	{
		for(j = start; j < end; j++) for(i = 0; i < MaxCol; i++) llSetLinkAlpha(llList2Integer(Display, j * MaxCol + i), Alpha, ALL_SIDES);
		llSleep(0.2);
	}
}

FadeOut(integer line)
{
	integer i;
	integer j;
	integer start = line;
	integer end = line + 1;
	if(line == -1)
	{
		start = 0;
		end = MaxRow;
	}
	for(j = start; j < end; j++) for(i = 0; i < MaxCol; i++) llSetLinkAlpha(llList2Integer(Display, j * MaxCol + i), 1.0, ALL_SIDES);
	float Alpha;
	for (Alpha = 0.95; Alpha > 0.00; Alpha -= 0.05)
	{
		for(j = start; j < end; j++) for(i = 0; i < MaxCol; i++) llSetLinkAlpha(llList2Integer(Display, j * MaxCol + i), Alpha, ALL_SIDES);
		llSleep(0.2);
	}
	for(j = start; j < end; j++) for(i = 0; i < MaxCol; i++) llSetLinkAlpha(llList2Integer(Display, j * MaxCol + i), 0.0, ALL_SIDES);
}

integer MaxRow;
integer MaxCol;
list Display;
integer CurLine;
integer CurPos;
list Back;

Collect()
{
	integer x = llGetNumberOfPrims();
	integer i;
	integer j;
	integer row;
	integer col;
	string s;
	MaxRow = 0;
	MaxCol = 0;
	list l = [];
	list l1;
	list l2 = [];
	for(i = 1; i <= x; i++)
	{
		s = llGetLinkName(i);
		l1 = llParseString2List(s, ["/"], []);
		row = llList2Integer(l1, 0);
		col = llList2Integer(l1, 1);
		if(row > 0 && col > 0)
		{
			if(row > MaxRow) MaxRow = row;
			if(col > MaxCol) MaxCol = col;
			l += [row * 100 + col, i];
		} else if(llGetSubString(s, 0, 3) == "back")
	{
		l2+= [s, i];
	}
	}
	l = llListSort(l, 2, TRUE);
	Display = [];
	for(i = 0; i < MaxRow; i++)
	{
		for(j = 0; j < MaxCol; j++)
		{
			x = llListFindList(l, [(i + 1) * 100 + j + 1]);
			if(x != -1) Display += [llList2Integer(l, x + 1)]; else Display += [0];
		}
	}
	l2 = llListSort(l2, 2, TRUE);
	Back = [];
	for(i = 1; i < llGetListLength(l2); i += 2) Back += [llList2Integer(l2, i)];
}

Render(integer line, string text)
{
	integer i;
	integer j;
	integer start = line;
	integer end = line + 1;
	if(line == -1)
	{
		start = 0;
		end = MaxRow;
	}
	for(j = start; j < end; j++)
	{
		for(i = 0; i < MaxCol; i++) RenderString(llList2Integer(Display, j * MaxCol + i), llGetSubString(text, i * 5, i *5 + 4));
	}
}

SetColor(integer line, vector color)
{
	integer i;
	integer j;
	integer start = line;
	integer end = line + 1;
	if(line == -1)
	{
		start = 0;
		end = MaxRow;
	}
	for(j = start; j < end; j++)
	{
		for(i = 0; i < MaxCol; i++) llSetLinkColor(llList2Integer(Display, j * MaxCol + i), color, ALL_SIDES);
	}
}

Draw(vector v, string s)
{
	integer i;
	integer p = CurPos;
	integer l = CurLine;
	integer link;
	integer f;
	for(i = 0; i < llStringLength(s); i++)
	{
		if(p >= MaxCol * 5)
		{
			l++;
			p = 0;
		}
		link = llList2Integer(Display, l * MaxCol + p / 5);
		f = p % 5;
		if(f == 0) llSetLinkColor(link, v, FACE_1);
		else if(f == 1) llSetLinkColor(link, v, FACE_2);
		else if(f == 2) llSetLinkColor(link, v, FACE_3);
		else if(f == 3) llSetLinkColor(link, v, FACE_4);
		else if(f == 4) llSetLinkColor(link, v, FACE_5);
		RenderChar(link, f, llGetSubString(s, i, i));
		p++;
	}
	CurLine = l;
	CurPos = p;
}

SetBackground(integer line, vector v)
{
	integer i;
	integer start = line;
	integer end = line + 1;
	if(line == -1)
	{
		start = 0;
		end = MaxRow;
	}
	for(i = start; i < end; i++) llSetLinkColor(llList2Integer(Back, i), v, ALL_SIDES);
}

string Center(string s)
{
	while(llStringLength(s) < MaxCol * 5) s = " " + s + " ";
	return s;
}
string Left(string s)
{
	while(llStringLength(s) < MaxCol * 5) s += "     ";
	return s;
}

string Right(string s)
{
	while(llStringLength(s) < MaxCol * 5) s = " " + s;
	return s;
}

Init()
{
	gFontTexture = DefaultFont;
	integer i;
	for(i = 0; i < llGetListLength(Display); i++) llSetLinkAlpha(llList2Integer(Display, i), 1.0, ALL_SIDES);
	for(i = 0; i < llGetListLength(Back); i++) llSetLinkAlpha(llList2Integer(Back, i), 1.0, ALL_SIDES);
	SetColor(-1, DefaultTextColor);
	Render(-1, Left("     "));
	SetBackground(-1, DefaultBackColor);
}

list COMMANDS = ["wait", "loop", "left", "center", "right", "color", "backcolor", "fadein", "fadeout", "setlinepos", "drawletters", "charset", "reset"];
list CODES = [204017, 0, 204000, 204002, 204004, 204008, 204009, 204010, 204011, 204006, 204007, 204016, 204018];
integer Loop;
list Commands;
list Args;
integer LoopCount;
integer Pos;
integer Pos2;

string NCNAME = "playcard";
integer NCLine;
key NCid;
integer On;

GetCommand(string s)
{
	list l = llParseString2List(s, ["="], []);
	string c = llToLower(llStringTrim(llList2String(l, 0), STRING_TRIM));
	string a1 = llToLower(llStringTrim(llList2String(l, 1), STRING_TRIM));
	string a2 = llToLower(llStringTrim(llList2String(l, 2), STRING_TRIM));
	integer x = llListFindList(COMMANDS, [c]);
	if(x == -1) return;
	x = llList2Integer(CODES, x);
	if(c == "reset")
	{
		Commands += [x];
		return;
	}
	if(c == "wait" || c == "loop" || c == "charset" || c == "fadein" || c == "fadeout")
	{
		if(llGetListLength(l) < 2) return;
		if(c == "loop") Loop = (integer)a1;
		else
		{
			Commands += [x];
			Args += [a1];
		}
		return;
	}
	if(llGetListLength(l) < 3) return;
	integer y = llSubStringIndex(s, "=");
	s = llDeleteSubString(s, 0, y);
	y = llSubStringIndex(s, "=");
	s = llDeleteSubString(s, 0, y);
	Commands += [x];
	Args += [a1];
	if(c == "color" || c == "backcolor") Args += [a2]; else Args += [s];
}

PlayStep()
{
	llSetTimerEvent(0);
	if(Pos >= llGetListLength(Commands))
	{
		if(LoopCount > 0) LoopCount--;
		if(LoopCount == 0)
		{
			On = FALSE;
			return;
		} else
		{
			Pos = 0;
			Pos2 = 0;
		}
	}
	integer c = llList2Integer(Commands, Pos++);
	if(c == WAIT) llSleep(llList2Float(Args, Pos2++));
	else if(c == FADE_IN) FadeIn(llList2Integer(Args, Pos2++));
	else if(c == FADE_OUT) FadeOut(llList2Integer(Args, Pos2++));
	else if(c == CHARSET) gFontTexture = llList2String(Args, Pos2++);
	else if(c == RESET) Init();
	else if(c == DISPLAY_STRING) Render(llList2Integer(Args, Pos2++), llList2String(Args, Pos2++));
	else if(c == CENTER_STRING) Render(llList2Integer(Args, Pos2++), Center(llList2String(Args, Pos2++)));
	else if(c == RIGHT_STRING) Render(llList2Integer(Args, Pos2++), Right(llList2String(Args, Pos2++)));
	else if(c == SET_COLOR) SetColor(llList2Integer(Args, Pos2++), llList2Vector(Args, Pos2++));
	else if(c == SET_BACKGROUND) SetBackground(llList2Integer(Args, Pos2++), llList2Vector(Args, Pos2++));
	else if(c == SET_LINE_POS)
		{
			CurLine = llList2Integer(Args, Pos2++);
			CurPos = llList2Integer(Args, Pos2++);
		} else if(c == DRAW_LETTERS) Draw(llList2Vector(Args, Pos2++), llList2String(Args, Pos2++));
	llSetTimerEvent(0.01);
}

Init1()
{
	On = FALSE;
	Loop = 0;
	llSetTimerEvent(0);
	if(llGetInventoryType(NCNAME) != INVENTORY_NONE)
	{
		llWhisper(0, "Lese playcard...");
		NCLine = 0;
		NCid = llGetNotecardLine(NCNAME, NCLine++);
	} else llWhisper(0, "Keine playcard vorhanden");
}

default
{
	state_entry()
	{
		Collect();
		ResetCharIndex();
		Init();
		Init1();
	}
	on_rez(integer start_param)
	{
		llResetScript();
	}
	changed(integer change)
	{
		if(change & CHANGED_INVENTORY) llResetScript();
	}
	touch_start(integer total_number)
	{
		if(llGetListLength(Commands) == 0)
		{
			llWhisper(0, "Keine Daten vorhanden.");
			return;
		}
		On = !On;
		if(On)
		{
			Pos = 0;
			Pos2 = 0;
			LoopCount = Loop;
			PlayStep();
		} else llSetTimerEvent(0);
	}
	dataserver(key requested, string data)
	{
		if(requested == NCid)
		{
			if(data != EOF)
			{
				GetCommand(data);
				NCid = llGetNotecardLine(NCNAME, NCLine++);
			}
			else llWhisper(0, "playcard wurde gelesen.");
		}
	}
	timer()
	{
		PlayStep();
	}
}

playcard - Demo-Notecard für die playcard


Loop = -1
Reset
Left = -1 = 
BackColor = -1 =  <0,0,0>
Color = -1 = <1,1,1>
BackColor = 0 = <0,1,1>
BackColor = 1 = <0,1,0>
BackColor = 2 = <1,0,1>
BackColor = 3 = <1,0,0>
BackColor = 4 = <1,1,1>

Color = 0 = <0,0,1>
Color = 1 = <0,0,0>
Color = 2 = <0,1,1>
Color = 3 = <1,0,1>
Color = 4 = <0,0,0>
Center = 0 =Willkommen
Left = 1 =zu
Right = 2 =diesem
Center =3 =Board-Demo
SetLinePos = 4 = 0
DrawLetters = <1,0.0> =G
DrawLetters = <0,1,0> =r
DrawLetters = <0,0,1> =ü
DrawLetters = <1,1,0> =ß
DrawLetters = <1,0,1> =e
DrawLetters = <0,1,1> = R
DrawLetters = <0,1,0> =e
DrawLetters = <1,0,0> =b
DrawLetters = <1,0,1> =e
DrawLetters = <1,1,0> =k
DrawLetters = <1,0,0> =k
DrawLetters = <0,0,1> =a
DrawLetters = <0,1,1> =:-)
SetLinePos = 4 = 13
DrawLetters = <1,0,0> =:-)
SetLinePos = 4 = 13
DrawLetters = <0,1,0> =:-)
SetLinePos = 4 = 13
DrawLetters = <1,0,1> =:-)
SetLinePos = 4 = 13
DrawLetters = <0,0,0> =:-)
SetLinePos = 4 = 13
DrawLetters = <0,0,1> =:-)
SetLinePos = 4 = 13
Drawletters = <1,1,0> =:-)
Wait = 10
Center = 0 =Ich
Center = 1 =blende
Center = 2 =mich
Center = 3 =mal
Center = 4 =   
Color = 4 = <0,0,0>
Center = 4 =aus
Wait = 3
FadeOut = -1
Wait = 5
Center = 0 =und
Center = 1 =schon
Center = 2 =wieder
Center = 3 =da
Center = 4 =;-)
FadeIn = -1
Wait = 5
Center = 0 =Andere
Center = 1 = Zeichensätze:
Charset =lucida
Center = 2 =etwa so
Charset =larabie
Center = 3 =oder so
Charset =origami momma
Center = 4 =oder auch so
Wait = 10
Charset =courier new bold
Center =0 =Es geht auch
Center = 1 =durcheinander
Center = 2 =aber wer
Center = 3 =kann das lesen
Center = 4 =    
SetLinePos = 4 = 7
Charset =monospace bold italic
DrawLetters = <0,0,0> =L
Charset =origami momma
DrawLetters = <0,0,0> =a
Charset =monofur
DrawLetters = <0,0,0> =L
Charset =admono32
DrawLetters = <0,0,0> =a
Charset =telegrama
DrawLetters = <0,0,0> =L
Charset =Cousine bold
DrawLetters = <0,0,0> =a
Wait = 10
Center = -1 = 
BackColor = -1 = <0,1,1>
Color = -1 = <0,0,1>
Charset =courier new bold
Center = 0 =Viel Spaß!
Center = 4 =Free to copy
Left = 2 =?
Left = 2 = ?
Left = 2 =  ?
Left = 2 =   ?
Left = 2 =    ?
Left = 2 =     ?
Left = 2 =      ?
Left = 2 =       ?
Left = 2 =        ?
Left = 2 =         ?
Left = 2 =          ?
Left = 2 =           ?
Left = 2 =            ?
Left = 2 =             ?
Left = 2 =              ?
Left = 2 =               ?
Left = 2 =                ?
Left = 2 =                 ?
Left = 2 =                  ?
Left = 2 =                   ?
Left = 2 =   
Wait = 2

Xytext.py - Python-Fu-Skript für GIMP (das Original ist hier)


#! /usr/bin/env python
from gimpfu import *
 
def python_log_init():
    fileHandle = open( 'python.log', 'w')
    fileHandle.close()
 
def python_log(s):
    fileHandle = open ( 'python.log', 'a' )
    fileHandle.write(str(s)+"\n")
    fileHandle.close() 
 
def python_xytext(font,color,size,limit):
  """Print the arguments on standard output"""
  python_log_init()
  python_log("font: %s color: <%d,%d,%d> size: %d limit: %d" % ( font, color[0], color[1], color[2], size, limit ))
  chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~     "
  
  decode=  ["\xC3\x87", "\xC3\xBC", "\xC3\xA9", "\xC3\xA2", "\xC3\xA4", "\xC3\xA0", "\xC3\xA5", "\xC3\xA7", "\xC3\xAA", "\xC3\xAB" ]  
  decode+=["\xC3\xA8", "\xC3\xAF", "\xC3\xAE", "\xC3\xAC", "\xC3\x84", "\xC3\x85", "\xC3\x89", "\xC3\xA6", "\xC3\xAE", "\xE2\x96\xB6" ]
  decode+=["\xC3\xB6", "\xC3\xB2", "\xC3\xBB", "\xC3\xB9", "\xC3\xBF", "\xC3\x96", "\xC3\x9C", "\xC2\xA2", "\xC2\xA3", "\xC2\xA5"]
  decode+=["\xC3\x82", "\xC2\xA9", "\xC3\xA1", "\xC3\xAD", "\xC3\xB3", "\xC3\xBA", "\xC3\xB1", "\xC3\x91", "\xC2\xAA", "\xC2\xBA"]
  decode+=["\xC2\xBF", "\xC3\x94", "\xC2\xAC", "\xC2\xBD", "\xC2\xBC", "\xC2\xA1", "\xC2\xAB", "\xC2\xBB", "\xCE\xB1", "\xC3\x9F"]
  decode+=["\xCE\x93", "\xCF\x80", "\xCE\xA3", "\xCF\x83", "\xC2\xB5", "\xCF\x84", "\xCE\xA6", "\xCE\x98", "\xCE\xA9", "\xCE\xB4"]
  decode+=["\xC5\xAC", "\xC5\xAD", "\xCE\xB5", "\xE2\x88\xA9", "\xE2\x89\xA1", "\xC2\xB1", "\xE2\x89\xA5", "\xE2\x89\xA4", " ", " "]
 
  decode+=["\xC3\x81", "\xC3\x80", "\xC3\xA3", "\xC3\x83", "\xC3\x8A", "\xC3\x8D", "\xC3\x93", "\xC3\xB5", "\xC3\x95", "\xC3\xB4" ];
 
  width=512
  height=1024
  img = gimp.Image(width, height, RGB)
  layer = gimp.Layer(img, "my font", width, height, RGB_IMAGE, 100, NORMAL_MODE)
  img.add_layer(layer, 0)
  layer.add_alpha()
  gimp.set_foreground(color)
  pdb.gimp_selection_all(img)
  pdb.gimp_edit_clear(layer)
  pdb.gimp_selection_none(img)
 
  index=0
  extra=-1
  #pdb.gimp_text_fontname(img,layer,50,50,"\xC3\x87",0,TRUE,size,PIXELS,font)
  try:
    for row in range(20):
       for col in range(10):
 
          if extra<0:
             try:
                el=chars[index]
                index=index+1
             except:
                extra=0
 
          if extra>-1:
             el=decode[extra]
             extra=extra+1
  
          python_log(str(row)+","+str(col)+":  "+el)
 
          y=col*51.2+12
          x=row*51.2+5
          pdb.gimp_text_fontname(img,layer,y,x,el,0,TRUE,size,PIXELS,font)
 
  except:
     pass
 
  # Now ready to display this image
  img.merge_visible_layers(0)
  gimp.Display(img)
 
register(
  "xytext", "", "", "", "", "",
  "<Toolbox>/Xtns/_XyText1CharE", "",
  [
  (PF_FONT, "font", "Font to use", "Arial"),
  (PF_COLOR,"color","Color to use", (255,255,255) ),
  (PF_INT,    "size", "Font size", 45          ),
  (PF_INT,  "limit", "limit font generation ", 180          ),
 
  ],
  [],
  python_xytext
  )
 
main()