Portal-Zone Gothic-Zone Gothic II-Zone Gothic 3-Zone Gothic 4-Zone Modifikationen-Zone Download-Zone Foren-Zone RPG-Zone Almanach-Zone Spirit of Gothic

 

Results 1 to 16 of 16
  1. Visit Homepage View Forum Posts #1 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline

    Lightbulb [Script] Schleifen

    Mittlerweile halte ich es für praktischer Ikarus für Schleifen zu verwenden (mit Hilfe von Sprüngen, Stichwort: MEM_StackPos.position).

    Mir ist es gelungen einigermaßen vernünftige Schleifen in Daedalus einzubauen, wenn auch naturgemäß in einer besonderen Notation (mit Triggerschleifen mit Verzögerungen hat das nichts zu tun, ich spreche von Schleifen wie sie in den meisten Programmiersprachen von Haus aus zu finden sind).

    Insbesondere spreche ich von for-Schleifen (mit Zählvariable) und while Schleifen (mit Abbruchbedingung).

    Das folgende Script kann so wie es ist zum Beispiel als \Scripts\Intern\Loops.d gespeichert werden. Es kann direkt nach Classes.d geparst werden (benötigt keine weiteren Scripte). Es sind auch keine weiteren Anpassungen an anderen Scripten nötig. Die Funktionalität der Schleifen ist sofort verfügbar.
    Einzige notwendige Bedingung ist das Vorhandensein eines WPs mit dem Namen "TOT" in der Welt.

    Eine Dokumentation der zur Verfügung stehenden Funktionen sowie drei Beispiele sind beigefügt. Ich habe mich zudem bemüht den Code gut zu Kommentieren, damit interessierte ihn verstehen können.

    Code:
    /*
    Version: 1.2 (Oktober 09)
    Autor: Sektenspinner
    Thread: http://forum.worldofplayers.de/forum/showthread.php?p=10845158
    */
    
    /*######################################################
    //
    //		Dokumentation:
    //
    //######################################################
    
    	Dieses Script stellt eine Implementierung von Schleifen zur Verfügung (das hat NICHTS mit Triggerschleifen mit fireDelay zu tun! Es handelt sich um gewöhnliche Schleifen wie man sie in fast allen Programmiersprachen findet).
    	
    	Dazu übergibt man an die Funktionen aus diesem Script je nachdem was passieren soll, Referenzen auf anderen Funktionen, die als Abbruchbedingungen, Schleifenrümpfe usw. fungieren.
    	
    	Funktionen die Referenziert werden sollen müssen vom Muster sein:
    	Rtn_<name>_0
    	wobei <name> frei wählbar ist und die Referenz auf diese Funktion darstellt.
    	
    	Zum Beispiel kann folgende Funktion:
    	
    	func void Rtn_Blubb_0() {
    		//tu was
    	};
    	
    	über den Namen "blubb" identifiziert werden (Groß-/Kleinschreibung ist egal).
    	Das das Präfix Rtn_ und das Suffix _0 vorhanden sein muss, hat einen Grund (Implementierung läuft über Routinen).
    	
    	//--------------------------------------
    	// Enthaltene Funktionen
    	//--------------------------------------
    	
    	//---------------
    	// CallByString:
    	//---------------
    	
    	func void CallByString (var string name);
    	
    	Ruft die Funktion "Rtn_<name>_0" auf. (Hat nichts mit Schleifen zu tun, kann aber unter Umständen auch nützlich sein)
    		
    	//---------------
    	// whileDo:
    	//---------------
    	
    	func void whileDo (var string condition, var string do);
    	
    	Ruft die Funktion "Rtn_<do>_0" auf, solange "Rtn_<condition>_0" einen wahren Wert in die globale Variable "continue" schreibt.
    	
    	Konkreter Ablauf:
    		(1) Setze continue = FALSE
    		(2) Rufe "Rtn_<condition>_0" auf
    		(3) Falls continue nicht mehr FALSE:
    			(3.1) Rufe "Rtn_<do>_0" auf
    			(3.2) Gehe zurück zu Schritt (1)
    		(4) continue == FALSE -> tue nichts mehr
    	
    	//---------------
    	// doWhile:
    	//---------------
    	
    	func void doWhile (var string do, var string condition);
    	
    	Ähnlich wie whileDo, führt aber "Rtn_<do>_0" mindestens einmal aus.
    	
    	Konkreter Ablauf:
    		(0) Rufe "Rtn_<do>_0" auf
    		(1) Setze continue = FALSE
    		(2) Rufe "Rtn_<condition>_0" auf
    		(3) Falls continue nicht mehr FALSE:
    			(3.1) Rufe "Rtn_<do>_0" auf
    			(3.2) Gehe zurück zu Schritt (1)
    		(4) continue == FALSE -> tue nichts mehr
    	
    	//---------------
    	// repateUntil:
    	//---------------
    	
    	func void repeatUntil (var string do, var string condition)
    	
    	repeatUntil ist ein Alias für doWhile (die beiden Funktionen machen genau das gleiche)
    		
    	//---------------
    	// forInitCondCountDo:
    	//---------------
    	
    	forInitCondCountDo (var string Initialisation, var string condition, var string countingExp, var string do);
    	
    	Mäßig praktische, aber C-Ähnliche For Schleife. Zusätzlich zur while Schleife gibt es eine explizite Initialisierungsfunktion und eine Funktion für den Weiterzähl-Befehl.
    	
    	Konkreter Ablauf:
    		(0) Rufe "Rtn_<Initialisation>_0" auf
    		(1) Setze continue = FALSE
    		(2) Rufe "Rtn_<condition>_0" auf
    		(3) Falls continue nicht mehr FALSE:
    			(3.1) Rufe "Rtn_<do>_0" auf
    			(3.1) Rufe "Rtn_<countingExp>_0" auf
    			(3.2) Gehe zurück zu Schritt (1)
    		(4) continue == FALSE -> tue nichts mehr
    	
    	//---------------
    	// forVarFromToDo:
    	//---------------
    	
    	func void forVarFromToDo  (var int loopVar_Inst, var int from, var int to, var string do);
    	
    	Eine Pascal-Artige Forschleife, die "Rtn_<do>_0" für jeden Wert from <= x <= to einmal aufruft. Zählvariablen können i, j oder k sein. Um andere Zählvariablen zu benutzen genügt es entsprechende Instanzen zu erstellen (siehe unten unter dem Prototypen "LOOPVAR").
    	
    	Um in einem Schleifendurchlauf auf den Wert der Schleifenvariable zuzugreifen ist die Funktion GetVal nötig (siehe unten).
    	
    	Konkreter Ablauf:
    		(0) Setze die Zählvariable <loopVar_Inst> auf den Wert <from>
    		(1) Rufe "Rtn_<do>_0" auf.
    			( ) Innerhalb von "Rtn_<do>_0" kann auf den Wert der Zählvariablen mit Hilfe von GetVal (<loopVar_Inst>) zugegriffen werden.
    		(2) Erhöhe den Wert Zählvariable um den Wert 1.
    		(3) Falls die Zählvariable kleine oder gleich <to> ist, weiter bei Schritt (1)
    		(4) Ansonsten -> tue nichts mehr
    	
    	//---------------
    	// forVarFromToDo:
    	//---------------
    	
    	func void forVarFromToStepDo (var int loopVar_Inst, var int from, var int to, var int step, var string do);
    	
    	Genau wie forVarFromToDo, nur dass in Schritt (2) die Zählvariable um den Wert <step> erhöht wird.
    	
    	//---------------
    	// GetVal
    	//---------------
    	
    	func int GetVal (var int loopVar_Inst);
    	
    	Ermittelt den aktuellen Wert der Zählvariable <loopVar_Inst>
    	
    	//---------------
    	// Break
    	//---------------
    	
    	func void break();
    
    	Bricht die übergeordnete Schleife. Das heißt für diese Schleife wird unabhängig von allen anderen Umständen kein weiterer Durchlauf mehr gestartet. Der aktuelle Durchlauf wird zu Ende geführt (sofern kein "return" auf das break folgt).
    	
    	//--------------------------------------
    	// Besonderheiten
    	//--------------------------------------
    	
    	(1) Innerhalb von Schleifen ist die globale Variable "self" verändert (Sie enthält einen Hilfs-Npc, der nach außen hin ohne Bedeutung ist).
    		Nach dem Beenden der äußersten Schleife ist der ursprüngliche Inhalt von self allerdings wiederhergestellt.
    		Während einer Schleife kann der ursprüngliche Inhalt von "self" in der globalen Variablen selfBackUp abgefragt werden. Falls nützlich kann "self" jederzeit beliebig überschrieben werden (die Schleifenimplementierung gerät deshalb nicht durcheinander).
    	
    	
    //######################################################
    //
    //	Beispiele:
    //
    //######################################################
    
    //-----------------------------------------------------
    // Beispiel 1: Aus "Schattenläufer"
    // wird "Schattenläufer123456789!"
    // (genutzt wird eine for-Schleife)
    //-----------------------------------------------------
    
    	func void Rtn_RENAME_0() {
    		//An den Namen von selfBackUp wird der Wert der Schleifenvariable als String angehängt
    		//Achtung: Es muss selfBackUp statt self benutzt werden, da self innerhalb von Schleifen ungültig ist.
    		selfBackup.name = ConcatStrings (selfBackup.name, IntToString (GetVal(i)));
    	};
    	
    	func void foo() {
    		forVarFromToDo (i, 1, 9, "RENAME");
    		
    		//Hier, nach der Schleife, ist self wieder gültig
    		self.name = ConcatStrings (self.name, "!");
    	};
    	
    	//Ergebnis: Wenn self gerade ein "Schattenläufer" ist, der auch "Schattenläufer" heißt,
    	//dann wird dieser nach dem Aufruf von foo "Schattenläufer123456789!" heißen.
    	
    	//Achtung: i ist in der Implementierung als Zählvariable deklariert.
    	//Soll eine andere Zählvariable als i, j oder k benutzt werden,
    	//so muss diese in der Implementierung unterhalb des Prototypen LOOPVAR eingeführt werden.
    
    //--------------------------------------------------
    // Beispiel 2: Ein Gitter aus lauter "X"
    // (genutzt werden zwei geschachtelte for-Schleifen)
    //--------------------------------------------------
    
    //Ein Aufruf von bar gibt ein Gitter von "X"en auf dem Bildschirm aus.
    //(man beachte auch: Es ist egal, in welcher Reihenfolge diese drei Funktionen definiert werden)
    
    func void bar() {
    	forVarFromToStepDo (i, 10, 80, 10, "PRINTLINE");
    };
    
    func void Rtn_Printline_0() {
    	forVarFromToStepDo (j, 10, 80, 10, "PRINTSPOT");
    };
    
    func void Rtn_PrintSpot_0() {
    	var int ival;
    	var int jval;
    	ival = GetVal (i);
    	jval = GetVal (j);
    	
    	PrintScreen ("X", jval, ival, FONT_SCREEN, 1);
    };
    
    //--------------------------------------------------
    // Beispiel 3: Ziffern zählen
    // (genutzt wird eine while Schleife)
    //--------------------------------------------------
    //--------------------------------------------------------
    
    //Ein Aufruf von foobar gibt aus, wieviele Bits die Zahl in Binärdarstellung belegt.
    //Achtung: Funktioniert nur mit nicht negativen Zahlen!
    //Beispiel: Wenn testInt am Anfang 42 ist (Binärdarstellung 101010)
    //wird 6 ausgegeben.
    
    var int testInt;
    var int shiftCount;
    
    func void foo() {
    	//testInt = 42;
    	shiftCount = 0;
    	whileDo ("NOTNULL", "SHIFTRIGHT");
    	
    	Print (IntToString (shiftCount));
    };
    
    func void Rtn_ShiftRight_0() {
    	testInt = testInt >> 1; //entspricht einer division durch 2
    	shiftCount += 1;
    };
    
    func void Rtn_NotNull_0() {
    	continue = testInt != 0; //falls testInt == 0, dann continue = 0, ansonsten continue = 1
    };
    
    */
    
    //######################################################
    //
    // IMPLEMENTIERUNG - IMPLEMENTIERUNG - IMPLEMENTIERUNG
    //
    //######################################################
    
    //######################################################
    //	FUNKTIONSPOINTER: Ausgangspunkt für die Schleifen
    //######################################################
    
    //Hilfsnpc, der einmal pro Welt eingefügt wird
    
    INSTANCE CallHelper(C_Npc)			
    {
    	name = "Call-Helper";
    	
    	id = 0; //Andere IDs würde andere Namenskonventionen für die zu referenzierenden Funktionen fordern
    	
    	flags = 2; //Er stirbt nicht
    	attribute	[ATR_HITPOINTS_MAX]	=	1;
    	attribute	[ATR_HITPOINTS]		=	1;
    	
    	Mdl_SetVisual (self, "Meatbug.mds"); //Fehlt dies, stürzt Gothic beim zerstören des Npcs ab.
    };
    
    func void Rtn_VALIDTASTATE_0() {
    	TA (self, 0,1, ZS_Unconscious, "TOT");
    	TA (self, 1,0, ZS_Unconscious, "TOT");
    };
    
    //Backup für den Wert in Self
    var C_NPC selfBackup;
    
    //Wld_InsertNpc Funktion, die self erhält:
    func void Wld_InsertNpc_keepSelf (var int inst, var string wp) {
    	var C_NPC slfBak;
    	slfBak = Hlp_GetNpc (self);
    	Wld_InsertNpc (inst, wp);
    	self = Hlp_GetNpc (slfBak);
    };
    
    //Ruft die Funktion "Rtn_[name]_0" auf und sichert "self" in "selfBackup"
    //In "Rtn_[name]_0" steht in self dann NICHT der Npc, der zum Zeitpunkt des Aufrufs von CallByString in self stand.
    //Nach dem der Aufruf von CallByString zurückkehrt ist self aber wieder im Ursprungszustand.
    func void CallByString_Core (var string name) {
    	var C_NPC callHelperNpc;
    	callHelperNpc = Hlp_GetNpc (CallHelper);
    	
    	if (!Hlp_IsValidNpc (callHelperNpc)) {
    		Wld_InsertNpc_keepSelf (callHelper, "TOT");
    		callHelperNpc = Hlp_GetNpc (CallHelper);
    	};
    	
    	//Wenn ich hier was schachtle, bloß nicht einen ungültigen self speichern
    	if (Hlp_GetInstanceID (self) != CallHelper) {
    		selfBackup = Hlp_GetNpc (self);
    	};
    	
    	Npc_ExchangeRoutine (CallHelperNpc, name);
    };
    
    //WICHTIG: Beim Speichern / Laden muss der CallHelper in einem GÜLTIGEN TA sein
    //Das heißt insbesondere WP Bindung, Zeiteinteilung usw.
    //Das Spiel stürzt sonst sporadisch mit einem Runtime Error ab.
    func void RectifyCallHelperTA() {
    	var C_NPC callHelperNpc;
    	callHelperNpc = Hlp_GetNpc (CallHelper);
    	Npc_ExchangeRoutine (CallHelperNpc, "VALIDTASTATE");
    };
    
    //Die öffentliche Funktion lässt den Call-Helper in einem gültigen TA zurück!
    func void CallByString (var string name) {
    	CallByString_Core (name);
    	RectifyCallHelperTA();
    };
    
    //######################################################
    //	Schleifenimplementierungen
    //######################################################
    
    //Verschiedene interne Parameter werden in Npcs zwischengespeichert.
    PROTOTYPE LoopHelper(C_Npc)			
    {
    	name = "Loop-Helper";
    	
    	flags = 2; //He does not die.
    	attribute	[ATR_HITPOINTS_MAX]	=	1;
    	attribute	[ATR_HITPOINTS]		=	1;
    	
    	daily_routine = Rtn_VALIDTASTATE_0;
    };
    
    //Es können maximal (Loop_Max - Loop0) Schleifen ineinander geschachtelt sein.
    //In der Praxis kommt man meist mit maximal 2 bis 3 Ineinanderschachtelungen aus. Es sollte also genügen.
    //Falls 10 Schleifen nicht genügen sollte, einfach nach Loop9 und vor Loop_Max noch ein paar Instanzen nach dem gleichen Muster deklarieren.
    
    INSTANCE Loop0 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop1 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop2 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop3 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop4 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop5 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop6 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop7 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop8 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop9 (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE Loop_Max (LoopHelper) { Mdl_SetVisual (self, "Meatbug.mds"); };
    
    //---------------------------------------
    // Variablen und Konstanten
    //---------------------------------------
    
    //Vom Nutzer in der Abbruchbedingung zu setzender Ergebniswert. Zum Beispiel in while-Schleifen.
    var int continue;
    
    //Interner Zähler, wie tief die Schleife im Moment ist.
    var int CurrLoopNesting;
    
    //Verweisen auf den aktuellen Schleifenhelfer
    var int currLoopInst; //auf Instanz
    var C_NPC currLoopNpc; //auf Npc
    
    //---- Im Schleifenhelfer wird gespeichert: ----
    // (*) c_npc.name   -> Verweis auf Schleifenrumpf (das was getan werden soll)
    // (*) c_npc.Effect -> Verweis auf Zählausdruck (nach jedem Durchlauf, aber vor der Abbruchbedingung)
    // (*) c_npc.slot   -> Verweis auf Abbruchbedingung
    //
    //Das "Rtn_" und "_0" fehlt natürlich in diesen strings
    //----------------------------------------------
    
    //Neue Bedeutung der aivars:
    const int AIV_MaxForkDepth  = 0; //Nötig für Verzweigung zur Vermeidung von Stack-Overflows
    const int AIV_CurrForkDepth = 1;
    const int AIV_Dead			= 2; //Ist die Schleife schon "tot", d.h. gebrochen oder Bedingung nicht erfüllt?
    const int AIV_LoopVarInst	= 3; //Verweis auf die Zählvariable, falls vorhanden (for-Schleife)
    const int AIV_LoopVarTo		= 4; //Der Endwert der Zählvariable, falls vorhanden (for-Schleife)
    const int AIV_LoopVarStep	= 5; //Die Schrittgröße der Zählvariable, falls vorhanden (for-Schleife)
    
    //Bedingung für die for-Schleifen:
    //Siehe unten für die eigentlich Einführung der For-Schleife.
    //Steht hier, weil DoLoop ForCond direkt anspricht.
    func void Rtn_ForCond_0() {
    	//Schleifenvariable wird im Schleifen-Helfer referenziert
    	var int loopVar_Inst;
    	loopVar_Inst = currLoopNpc.aivar[AIV_LoopVarInst];
    	
    	//Schleifenvariable holen
    	var C_NPC loopVar_npc;
    	loopVar_npc = Hlp_GetNpc (loopVar_Inst);
    	
    	//Schleifenvariable erhöhen
    	loopVar_npc.id += currLoopNpc.aivar[AIV_LoopVarStep];
    	//Es geht genau dann weiter, wenn der Endwert noch nicht überschritten wurde.
    	continue = loopVar_npc.id <= currLoopNpc.aivar[AIV_LoopVarTo];
    };
    
    //Übernimmt einen Schleifendurchlauf:
    func void DoLoop() {
    	//Standardmäßig werden Schleifen nicht fortgesetzt
    	continue = FALSE;
    	
    	//Abbruchbedingung hat die Chance "continue" zu ändern.
    	//Ein paar häufige Spezialfälle abfangen und direkt einbeziehen
    	//da CallByString vergleichsweise teuer ist
    	if (Hlp_StrCmp (currLoopNpc.slot, "TRUE")) {
    		continue = TRUE;
    	} else if (Hlp_StrCmp (currLoopNpc.slot, "FALSE")) {
    		continue = FALSE;
    	} else if (Hlp_StrCmp (currLoopNpc.slot, "FORCOND")) {
    		Rtn_ForCond_0();
    	} else {
    		CallByString_Core (currLoopNpc.slot);
    	};
    	
    	if (continue) {
    		//Wenn die Schleife weiterläuft, dann zunächst den Rumpf aufrufen
    		if (!Hlp_StrCmp (currLoopNpc.name, "DONOTHING")) {
    			CallByString_Core (currLoopNpc.name);
    		};
    		
    		//Dann die Zählanweisung
    		if (!Hlp_StrCmp (currLoopNpc.effect, "DONOTHING")) {
    			CallByString_Core (currLoopNpc.effect);
    		};
    	} else {
    		//Andernfalls ist die Schleife tot, sie wird nicht mehr gestartet.
    		currLoopNpc.aivar[AIV_Dead] = TRUE;
    	};
    };
    
    func void break() {
    	//Die Schleife wird manuell beendet.
    	//Kein weiterer durchlauf wird mehr gestartet werden.
    	currLoopNpc.aivar[AIV_Dead] = TRUE;
    };
    
    //---------------------------------------------------
    // Binärbaum beim erzeugen der einzelnen Durchläufe
    //---------------------------------------------------
    
    /* Naheliegend wäre zunächst der Code:
    
    func void ForkLoop() {
    	if ("LoopIsNotDead") {
    		DoLoop();
    		ForkLoop();
    	};
    };
    
    Das hat den entscheidenden Nachteil, dass Schleifen, die n mal durchlaufen werden,
    auch mindestens n Funktion auf den Stack schieben. Der Stack läuft in Gothic aber schnell über.
    
    Daher spaltet sich ForkLoop zunächst immer weiter auf, wodurch ein Binärbaum erzeugt wird.
    Ein Binärbaum ist ein Baum, bei dem sich jeder Knoten (der kein Blatt ist) in zwei weitere aufspaltet.
    An den Blättern des Baumes (die Knoten die sich nicht weiter aufspalten) finden dann die Funktionsaufrufe statt.
    Für 2^n aufrufe von DoLoop wird der Stack nur mit ungefähr n Funktionen belastet. Das ist wenig. */
    
    func void ForkLoop() {
    	//Wenn der Loop schon tot ist, dann nichts machen
    	if (currLoopNpc.aivar[AIV_Dead]) {
    		return;
    	};
    	
    	if (currLoopNpc.aivar[AIV_CurrForkDepth] < currLoopNpc.aivar[AIV_MaxForkDepth]) {
    		//Wenn noch nicht die gewünschte Baumtiefe erreicht ist, weiter aufspalten!
    		currLoopNpc.aivar[AIV_CurrForkDepth] += 1;
    		ForkLoop();
    		ForkLoop();
    		currLoopNpc.aivar[AIV_CurrForkDepth] -= 1;
    	} else {
    		//Wenn die gewünschte Tiefe erreicht ist, dann einen Schleifendurchlauf machen.
    		DoLoop();
    	};
    };
    
    //Es ist im allgemeinen nicht vorhersehbar, wie oft eine Schleife durchlaufen werden wird (Beispiel: While Schleife)
    //Daher weiß ich auch nicht, wie tief der Binärbaum am besten sein soll.
    //Also fange ich mit einem kleinen Baum an, und mache dann immer tiefere Bäume, bis die Schleife irgendwann tatsächlich fertig ist.
    //Egal wie lange die Schleife tatsächlich braucht und wieviele Baumgrößen ich auch durchprobiere:
    //Der Stack wird nur logarithmisch stark belastet. Ungefähr 2*log_2 (n) für n Schleifendurchläufe.
    func void ForkLoop_IncreaseDepth() {
    	ForkLoop();
    	
    	if (!currLoopNpc.aivar[AIV_Dead]) {
    		currLoopNpc.aivar[AIV_MaxForkDepth] += 1;
    		ForkLoop_IncreaseDepth();
    	};
    };
    
    //--------------------------------------
    // Eine Schleife wird gestartet
    //--------------------------------------
    
    //condition: Referenz auf Abbruchbedingung
    //do: Referenz auf den Schleifenrumpf
    //countingExp: Referenz auf die Zählanweisung
    
    //loopVar_inst: Bei for-Schleifen: Instanz des Schleifenvariablen-Helper-Npcs
    //loopVar_to: Bei for-Schleifen: Bis dorthin soll die Schleifenvariable zählen
    //loopVar_step: Bei for-Schleifen: So viel soll jedesmal auf die Schleifenvariable addiert werden
    
    func void RunLoop_WithLoopVar (var string condition, var string do, var string countingExp, var int loopVar_inst, var int loopVar_to, var int loopVar_step) {
    	//Der für diese Schachtelungstiefe zuständige SchleifenHelfer wird geholt.
    	currLoopInst = Loop0 + CurrLoopNesting;
    	currLoopNpc = Hlp_GetNpc (currLoopInst);
    	
    	//Fehlermeldung falls zu tief geschachtelt
    	if (currLoopInst > Loop_Max) {
    		Print ("RunLoop: Too deep loop nesting!");
    	} else	
    	//Es kann sein, dass der Schleifenhelfer noch gar nicht erstellt wurde,
    	//dann noch schnell einfügen
    	if (!Hlp_IsValidNpc (currLoopNpc)) {
    		Wld_InsertNpc_keepSelf (currLoopInst, "TOT");
    		currLoopNpc = Hlp_GetNpc (currLoopInst);
    	};
    	
    	//Schachtelungstiefe aktuell halten
    	CurrLoopNesting += 1;
    	
    	//Schleifenhelfer mit Standardwerten, bzw. den übergebenen Werten füllen
    	currLoopNpc.aivar[AIV_MaxForkDepth] = 0;
    	currLoopNpc.aivar[AIV_CurrForkDepth] = 0;
    	currLoopNpc.aivar[AIV_Dead] = 0;
    	
    	currLoopNpc.slot = condition;
    	currLoopNpc.name = do;
    	currLoopNpc.effect = countingExp;
    	
    	//Nur bei for-Schleifen
    	currLoopNpc.aivar[AIV_LoopVarInst] = loopVar_inst;
    	currLoopNpc.aivar[AIV_LoopVarTo] = loopVar_to;
    	currLoopNpc.aivar[AIV_LoopVarStep] = loopVar_step;
    	
    	//Die Schleife sooft durchführen, bis die Bedingung nicht mehr erfüllt ist
    	ForkLoop_IncreaseDepth ();
    	
    	//Die Schleife ist vorbei, Schachtelungstiefe aktuell halten
    	CurrLoopNesting -= 1; //Loop ist abgearbeitet
    	
    	//Die übergeordnete Schleife (falls vorhanden) rechnet nicht damit,
    	//dass sich currLoopNpc ändert. Die Variable habe ich aber in der inneren Schleife
    	//gerade für meine Zwecke benutzt. Also wiederherstellen!
    	if (CurrLoopNesting) {
    		currLoopInst = Loop0 + CurrLoopNesting - 1;
    		currLoopNpc = Hlp_GetNpc (currLoopInst);
    	} else {
    		//CallHelper in gültigen TA versetzen
    		RectifyCallHelperTA();
    	};
    };
    
    //Kurzform ohne die for-Schleifen-spezifischen Parameter
    func void RunLoop (var string condition, var string do, var string countingExp) {
    	RunLoop_WithLoopVar (condition, do, countingExp, -1, -1, -1);
    };
    
    //--------------------------------------
    // Aus der allgemeinen Schleife werden
    // nun die typischen Schleifentypen
    // abgeleitet.
    //--------------------------------------
    
    //Die while-Schleife braucht keinen Zählausdruck und nutzt diese leere Funktion dafür
    func void Rtn_DONOTHING_0 () {};
    
    func void whileDo (var string condition, var string do) {
    	RunLoop (condition, do, "DONOTHING");
    };
    
    //repeatUntil ist fast das selbe wie eine whileSchleife
    func void repeatUntil (var string do, var string condition) {
    	CallByString_Core (do);
    	whileDo (condition, do);
    };
    
    //ein alias für Leute, die sich nicht in Pascal, sondern eher in C heimisch fühlen
    func void doWhile (var string do, var string condition) {
    	repeatUntil (do, condition);
    };
    
    //Ein Monstrum von Funktion für C Liebhaber.
    //Ist aber eher unpraktisch. Die Initialisierung und das weiterzählen von Variablen
    //kann man auch vor die Schleife bzw. in den Schleifenrumpf packen.
    func void forInitCondCountDo (var string Initialisation, var string condition, var string countingExp, var string do) {
    	CallByString_Core (initialisation);
    	RunLoop (condition, do, countingExp);
    };
    
    //Um schnell eine scheinbare Endlosschleife bauen zu können (die nur über break beendet werden kann):
    func void Rtn_TRUE_0() {
    	continue = TRUE;
    };
    
    //--------------------------------------
    // For Schleife, wie z.B. in Pascal
    // Vorbereitung: Schleifenvariablen
    //--------------------------------------
    
    //Da Gothic kein Call by Reference unterstützt sind Schleifenvariablen nicht ganz trivial.
    //Man kann eben nicht sagen: Funktion, mach mal was mit dieser Variable, da nur ihr aktueller Inhalt übergeben wird und die Funktion nicht selbst schreibend auf sie zugreifen kann.
    //Ich habe mich dazu entschieden Schleifenvariablen als Npcs zu implementieren.
    //Als Referenz dient die Instanz.
    //Achtung Falle: Um den Inhalt der Schleifenvariablen zu lesen muss GetVal benutzt werden. Wenn man einfach die Instanz den Hilfs-Npcs hinschreibt wird das zwar kompiliert, aber anstelle des Werts der Schleifenvariable bekommt man nur eine Art Addresse (also die Instance-ID des Schleifenvariablen-Hilfs-Npcs).
    
    //Selbstverständlich sollten geschachtelte Schleifen für jede einzelne Schleife eine andere Schleifenvariable verwenden. Man kann nicht in einer äußeren Schleife über i zählen und in einer darin liegenden Schleife wieder über i.
    
    PROTOTYPE LOOPVAR (C_Npc)			
    {
    	name = "Loop-Variable";
    	
    	flags = 2; //It does not die.
    	attribute	[ATR_HITPOINTS_MAX]	=	1;
    	attribute	[ATR_HITPOINTS]		=	1;
    	
    	daily_routine = Rtn_VALIDTASTATE_0;
    };
    
    //Für weitere Schleifenvariablen einfach weitere Instanzen dieser Art anfügen:
    INSTANCE i (LOOPVAR) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE j (LOOPVAR) { Mdl_SetVisual (self, "Meatbug.mds"); };
    INSTANCE k (LOOPVAR) { Mdl_SetVisual (self, "Meatbug.mds"); };
    
    //Holt den Wert der Schleifenvariablen (die id des Npcs)
    func int GetVal (var int loopVar_Inst) {
    	var C_NPC loopVar_npc;
    	loopVar_npc = Hlp_GetNpc (loopVar_Inst);
    	
    	if (!Hlp_IsValidNpc (loopVar_npc)) {
    		Print ("GetVal: Value of uninitialized loop-Variable requested!");
    		return -1;
    	} else {
    		return loopVar_npc.id;
    	};
    };
    
    //------------------------------
    // Die Eigentliche for-Schleife
    //
    // (*) loopVar_inst: Die Schleifenvariable auf der gezählt werden soll, zum Beispiel "i"
    // (*) from: Erster Schleifendurchlauf passiert mit diesem Wert.
    // (*) to: Die Schleife wird ausgeführt solange die Schleifevariable nicht größer als dieser Wert ist
    // (*) step: Nach jedem durchlauf wird dieser Wert auf die Schleife addiert.
    // (*) do: Referenz auf den Schleifenrumpf
    //-----------------------------
    
    func void forVarFromToStepDo (var int loopVar_Inst, var int from, var int to, var int step, var string do) {
    	//Zunächst die Schleifenvariable holen
    	var C_NPC loopVar_npc;
    	loopVar_npc = Hlp_GetNpc (loopVar_Inst);
    	
    	if (!Hlp_IsValidNpc (loopVar_npc)) {
    		//Falls die Schleifenvariable noch gar nicht in der Welt herumsteht,
    		//wird sie hier noch schnell eingefügt
    		Wld_InsertNpc_keepSelf (loopVar_Inst, "TOT");
    		loopVar_npc = Hlp_GetNpc (loopVar_Inst);
    	};
    	
    	//Variable auf Startwert setzen (abzüglich step, da step vor dem ersten Aufruf schon wieder draufaddiert wird)
    	loopVar_npc.id = from - step;
    	
    	//Nutze die bestehende Implementierung mit eine besonderen Bedingung (siehe unten)
    	RunLoop_WithLoopVar ("FORCOND", do, "DONOTHING", loopVar_Inst, to, step);
    };
    
    //Das selbe wie oben, aber Standardschrittweite 1 schon eingesetzt
    func void forVarFromToDo  (var int loopVar_Inst, var int from, var int to, var string do) {
    	 forVarFromToStepDo (loopVar_Inst, from, to, 1, do);
    };
    Hiernochmal die selben Bespiele wie im Script, aber nicht auskommentiert und damit eingefärbt:
    Code:
    //######################################################
    //
    //	Beispiele:
    //
    //######################################################
    
    //-----------------------------------------------------
    // Beispiel 1: Aus "Schattenläufer"
    // wird "Schattenläufer123456789!"
    // (genutzt wird eine for-Schleife)
    //-----------------------------------------------------
    
    	func void Rtn_RENAME_0() {
    		//An den Namen von selfBackUp wird der Wert der Schleifenvariable als String angehängt
    		//Achtung: Es muss selfBackUp statt self benutzt werden, da self innerhalb von Schleifen ungültig ist.
    		selfBackup.name = ConcatStrings (selfBackup.name, IntToString (GetVal(i)));
    	};
    	
    	func void foo() {
    		forVarFromToDo (i, 1, 9, "RENAME");
    		
    		//Hier, nach der Schleife, ist self wieder gültig
    		self.name = ConcatStrings (self.name, "!");
    	};
    	
    	//Ergebnis: Wenn self gerade ein "Schattenläufer" ist, der auch "Schattenläufer" heißt,
    	//dann wird dieser nach dem Aufruf von foo "Schattenläufer123456789!" heißen.
    	
    	//Achtung: i ist in der Implementierung als Zählvariable deklariert.
    	//Soll eine andere Zählvariable als i, j oder k benutzt werden,
    	//so muss diese in der Implementierung unterhalb des Prototypen LOOPVAR eingeführt werden.
    
    //--------------------------------------------------
    // Beispiel 2: Ein Gitter aus lauter "X"
    // (genutzt werden zwei geschachtelte for-Schleifen)
    //--------------------------------------------------
    
    //Ein Aufruf von bar gibt ein Gitter von "X"en auf dem Bildschirm aus.
    //(man beachte auch: Es ist egal, in welcher Reihenfolge diese drei Funktionen definiert werden)
    
    func void bar() {
    	forVarFromToStepDo (i, 10, 80, 10, "PRINTLINE");
    };
    
    func void Rtn_Printline_0() {
    	forVarFromToStepDo (j, 10, 80, 10, "PRINTSPOT");
    };
    
    func void Rtn_PrintSpot_0() {
    	var int ival;
    	var int jval;
    	ival = GetVal (i);
    	jval = GetVal (j);
    	
    	PrintScreen ("X", jval, ival, FONT_SCREEN, 1);
    };
    
    //--------------------------------------------------
    // Beispiel 3: Ziffern zählen
    // (genutzt wird eine while Schleife)
    //--------------------------------------------------
    //--------------------------------------------------------
    
    //Ein Aufruf von foobar gibt aus, wieviele Bits die Zahl in Binärdarstellung belegt.
    //Achtung: Funktioniert nur mit nicht negativen Zahlen!
    //Beispiel: Wenn testInt am Anfang 42 ist (Binärdarstellung 101010)
    //wird 6 ausgegeben.
    
    var int testInt;
    var int shiftCount;
    
    func void foo() {
    	//testInt = 42;
    	shiftCount = 0;
    	whileDo ("NOTNULL", "SHIFTRIGHT");
    	
    	Print (IntToString (shiftCount));
    };
    
    func void Rtn_ShiftRight_0() {
    	testInt = testInt >> 1; //entspricht einer division durch 2
    	shiftCount += 1;
    };
    
    func void Rtn_NotNull_0() {
    	continue = testInt != 0; //falls testInt == 0, dann continue = 0, ansonsten continue = 1
    };
    Ich hoffe die Implementierung kann dem einen oder anderen helfen.

    Danke an Sumpfi für den Farbeimer.

    Edit: 09/10/09 00:36 Uhr: Korrektur getätigt, die einen schweren Fehler behebt. Details: Das Zurücklassen des Call-Helpers in einem TA, die eigentlich eine Schleifenprozedur ist, führte gelegentlich zu einem Runtime Error beim Laden eines Spielstands. Der Fehler ist korrigiert.
    Edit: 09/10/09 09:06 Uhr: Beschleunigung der for-Schleife um 66% und Beschleunigung der while-Schleife um 33%.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts
    Last edited by Sektenspinner; 07.03.2011 at 15:47.

  2. View Forum Posts #2 Reply With Quote
    Deus Oparilames's Avatar
    Join Date
    May 2004
    Location
    ex contrariis
    Posts
    10,958
     
    Oparilames is offline
    Eine Frage:
    Gibt es Leistungsunterschiede zwischen dieser Methode und einer Triggerscriptschleife?
    Oparilames nachdem er seinen Gesellenbrief erhalten hat:
    »Das war's mit dir, du Mistvieh!«

  3. Visit Homepage View Forum Posts #3 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Quote Originally Posted by Oparilames View Post
    Eine Frage:
    Gibt es Leistungsunterschiede zwischen dieser Methode und einer Triggerscriptschleife?
    Quote Originally Posted by mir
    (mit Triggerschleifen mit Verzögerungen hat das nichts zu tun, ich spreche von Schleifen wie sie in den meisten Programmiersprachen von Haus aus zu finden sind)
    Triggerschleifen, wie sie oft in unseren Kreisen verwendet werden, sind dafür da, Code in bestimmten Zeitabständen immer wieder auszuführen.

    Die hier vorgestellten Schleifen sind dafür da, einen Haufen Arbeit, dem eine bestimmte regelmäßige Struktur innewohnt, am Stück zu erledigen.

    Beispiele für Triggerschleife: Prüfe jede Sekunde ob ein Ereignis eingetreten ist.
    Beispiel für klassische Scriptschleife (wenn ich sie mal so nennen darf): Rechne n! aus (= 1 * 2 * 3 * ... * n) und zwar jetzt sofort.

    Triggerschleifen und Scriptschleifen lösen verschiedene Probleme und sind daher nicht wirklich vergleichbar.

    Anmerkung: Man kann auf die Idee kommen Scriptschleifen auch über Triggerscripte realisieren zu wollen, aber dann braucht man erstmal für jedes Problem einen neuen Trigger in der Welt und noch etwas mehr drumherum (was nicht Sinn der Sache ist).
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  4. View Forum Posts #4 Reply With Quote
    Deus Oparilames's Avatar
    Join Date
    May 2004
    Location
    ex contrariis
    Posts
    10,958
     
    Oparilames is offline
    Ok da hast du recht aber ich habe halt so meine Zweifel, ob es wirklich "gesund" ist, für so viele verschiedenen Möglichkeiten NPCs zu "missbrauchen".
    Man denke an die z.B. Arrays.

    Die instinktive Angst vor Speicherplatzverschwendung war mein Beweggrund.
    Oparilames nachdem er seinen Gesellenbrief erhalten hat:
    »Das war's mit dir, du Mistvieh!«

  5. Visit Homepage View Forum Posts #5 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Wegen Speicherplatz brauchst du dir keine Sorgen zu machen. Die Schleifen brauchen sehr wenig Speicherplatz.

    @all: Korrigierte Version gepostet, die einen Runtime Fehler behebt, der beim Laden auftreten kann (aber nicht muss). War einer der ganz üblen Sorte, nämlich einer der nichts über sich verrät. Glückerweise habe ich die Ursache erraten können.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  6. View Forum Posts #6 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,307
     
    Lehona is offline
    Interessante Sache, das Ganze.
    Ich nehme an, das wird in etwa so schnell wie eine Rekursion funktionieren?

    Auch wenn es nicht ganz zum Thema passt: Beim dritten Beispiel kam mir die Frage: Gibt es eigentlich den %-Operator in Gothic? Oder könnte man den implementieren?

  7. Visit Homepage View Forum Posts #7 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Quote Originally Posted by Lehona View Post
    Interessante Sache, das Ganze.
    Ich nehme an, das wird in etwa so schnell wie eine Rekursion funktionieren?
    Nein, bedeutend langsamer. Ich habe das gerade mal ausgetestet.

    Ein einfacher Rekursionsschritt braucht auf meiner Maschine etwa 3 Mikrosekunden.
    Der Schleifendurchlauf einer for-Schleife braucht (nach zwei naheliegenden Optimierungen) ungefähr 400 Mikrosekunden. Sind also nur ungefähr hundert Schleifendurchläufe ohne spürbares Ticken drin und für zeitkritische Dinge sind diese Schleifen gar nicht geeignet.

    Die "naheliegenden Optimierungen" habe ich oben eingepflegt. Dadurch werden for-Schleifen dreimal so schnell und while Schleifen um 1/3 schneller.

    Auch wenn es nicht ganz zum Thema passt: Beim dritten Beispiel kam mir die Frage: Gibt es eigentlich den %-Operator in Gothic? Oder könnte man den implementieren?
    Den gibts. Implementieren könnte man den aber ziemlich leicht. Für positive Zahlen (bei negativen definiert das sowieso jede Programmiersprache anders):

    Code:
    func void mod(var int divident, var int divisor) {
    	return divident - (divident / divisor) * divisor;
    };
    Aber wie gesagt, ist nicht nötig, da % schon vorhanden ist.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  8. View Forum Posts #8 Reply With Quote
    banned
    Join Date
    Aug 2009
    Posts
    4,156
     
    Kratos is offline
    #Deleted!#
    Last edited by Kratos; 19.03.2011 at 15:37.

  9. View Forum Posts #9 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,307
     
    Lehona is offline
    Quote Originally Posted by Sektenspinner View Post
    Nein, bedeutend langsamer. Ich habe das gerade mal ausgetestet.

    Ein einfacher Rekursionsschritt braucht auf meiner Maschine etwa 3 Mikrosekunden.
    Der Schleifendurchlauf einer for-Schleife braucht (nach zwei naheliegenden Optimierungen) ungefähr 400 Mikrosekunden. Sind also nur ungefähr hundert Schleifendurchläufe ohne spürbares Ticken drin und für zeitkritische Dinge sind diese Schleifen gar nicht geeignet.

    Die "naheliegenden Optimierungen" habe ich oben eingepflegt. Dadurch werden for-Schleifen dreimal so schnell und while Schleifen um 1/3 schneller.

    Den gibts. Implementieren könnte man den aber ziemlich leicht. Für positive Zahlen (bei negativen definiert das sowieso jede Programmiersprache anders):

    Code:
    func void mod(var int divident, var int divisor) {
    	return divident - (divident / divisor) * divisor;
    };
    Aber wie gesagt, ist nicht nötig, da % schon vorhanden ist.
    400 Mikrosekunden sind 4ms? Kenn mich mit allem was kleiner als Mili ist nicht aus^^


    Diese Idee kam mir dann auch... Allerdings war der PC dann schon aus, sonst hätt ichs hinzugefügt^^

  10. View Forum Posts #10 Reply With Quote
    now also in your universe  Milky-Way's Avatar
    Join Date
    Jun 2007
    Posts
    14,047
     
    Milky-Way is offline
    Quote Originally Posted by Lehona View Post
    400 Mikrosekunden sind 4ms? Kenn mich mit allem was kleiner als Mili ist nicht aus^^
    400 Mikrosekunden sind 400 * 10^-9 Sekunden = 4 * 10^-7 Sekunden
    4 Millisekunden sind 4* 10^-6 Sekunden.

    400 Mikrosekunden = 0,4 ms.

  11. View Forum Posts #11 Reply With Quote
    Dea
    Join Date
    Jul 2007
    Posts
    10,307
     
    Lehona is offline
    Quote Originally Posted by Milky-Way View Post
    400 Mikrosekunden sind 400 * 10^-9 Sekunden = 4 * 10^-7 Sekunden
    4 Millisekunden sind 4* 10^-6 Sekunden.

    400 Mikrosekunden = 0,4 ms.
    Dann kann einem das also ziemlich egal sein. Zumindest wüsste ich jetzt kein Beispiel, bei dem es auf eine solche Zeiteinheit ankommt.

  12. Visit Homepage View Forum Posts #12 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Quote Originally Posted by Milky-Way View Post
    400 Mikrosekunden sind 400 * 10^-9 Sekunden = 4 * 10^-7 Sekunden
    Nein. Auch wenn Milli sich wie Millionstel anhört, es ist ein tausendstel.

    Milli = 10^(-3)
    Mikro = 10^(-6)
    Nano = 10^(-9)

    400 Mikrosekunden sind also 4*10^(-4) Sekunden = 0.0004 Sekunden, also ziemlich viel.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  13. View Forum Posts #13 Reply With Quote
    now also in your universe  Milky-Way's Avatar
    Join Date
    Jun 2007
    Posts
    14,047
     
    Milky-Way is offline
    Quote Originally Posted by Sektenspinner View Post
    Nein. Auch wenn Milli sich wie Millionstel anhört, es ist ein tausendstel.

    Milli = 10^(-3)
    Mikro = 10^(-6)
    Nano = 10^(-9)

    400 Mikrosekunden sind also 4*10^(-4) Sekunden = 0.0004 Sekunden, also ziemlich viel.
    Oh, eigentlich wusste ich das. Da habe ich nicht aufgepasst. Ich sollte wohl besser mal schlafen gehen.
    Die Grundaussage 400 Mikrosekunden ungleich 4 Millisekunden bleibt aber gleich.

  14. Visit Homepage View Forum Posts #14 Reply With Quote
    Benutzer, die ihr Benutzerkonto per E-Mail bestätigen müssen Player140's Avatar
    Join Date
    Jul 2004
    Posts
    3,111
     
    Player140 is offline
    Hört sich ja mal wieder nach ner tollen Sache an

    Was ich aber gut fände (allgemein für so was):
    • Dokumentation auf englisch falls des englischen mächtig, damit auch die Modder aus anderen Ländern was damit anfangen können. Halte mich aber leider selbst bei meinem aktuellen Projekt nicht wirklich dran
    • Version+Datum in die Doku und den Namen des Erstellers, vllt. sogar Link zum Foren-Thread. Könnte ja sein dass noch mehr Bugs gefixt oder Verbesserungen implementiert werden und dann kann die Verwirrung irgendwann groß sein. Ist außerdem immer nett zu wissen wer so was implementiert hat. Gerade wenn man im Team arbeitet u. neue Skripter kommen, alte gehen und irgendwann dieses Stück Code da ist und niemand mehr weiß, woher der Code eigentlich stammt.

  15. Visit Homepage View Forum Posts #15 Reply With Quote
    Exodus Sektenspinner's Avatar
    Join Date
    Jul 2004
    Location
    Karlsruhe
    Posts
    7,827
     
    Sektenspinner is offline
    Quote Originally Posted by Player140 View Post
    • Dokumentation auf englisch falls des englischen mächtig, damit auch die Modder aus anderen Ländern was damit anfangen können. Halte mich aber leider selbst bei meinem aktuellen Projekt nicht wirklich dran
    Ich wollte es erst auf englisch machen. Aber es gibt wohl mehr deutsche Modder die kein Englisch können, als englische Modder. Und bislang gibt es insgesamt relativ geringes Interesse, wenn ich das so sehe.
    Dieses Script ist wohl mehr theoretisch interessant. Wirklich nutzen werden es nur wenige. Ist sogar ziemlich schwierig sich sinnvolle Anwendungen zu überlegen.
    Von daher spar ich mir erstmal die Mühe das zu Übersetzen.

    • Version+Datum in die Doku und den Namen des Erstellers, vllt. sogar Link zum Foren-Thread. Könnte ja sein dass noch mehr Bugs gefixt oder Verbesserungen implementiert werden und dann kann die Verwirrung irgendwann groß sein. Ist außerdem immer nett zu wissen wer so was implementiert hat. Gerade wenn man im Team arbeitet u. neue Skripter kommen, alte gehen und irgendwann dieses Stück Code da ist und niemand mehr weiß, woher der Code eigentlich stammt.
    Ok, guter Hinweis. Wird gemacht.
    Für Spieler:
    Velaya # Velaya in English # Exodus Demo # Irrwichtel
    Tools für Modder:
    DiaDepp # DOPA-PARTER # zSlang
    Scripte für Modder:
    Ikarus Skriptpaket # Floats # Broadcasts

  16. Visit Homepage View Forum Posts #16 Reply With Quote
    Benutzer, die ihr Benutzerkonto per E-Mail bestätigen müssen Player140's Avatar
    Join Date
    Jul 2004
    Posts
    3,111
     
    Player140 is offline
    Würde ich auch nicht erwarten oder für besonders wichtig halten das jetzt nachträglich zu übersetzen wenn du selbst meinst dass es sich wohl nicht lohnt mangels interesse/einsatzmöglichkeiten.

    Aber für zukünftige derartige Dinge könnte es sich ja lohnen gleich auf englisch zu dokumentieren. Ich denke die meisten die sich ernsthaft mit Programmierung beschäftigen, und wenn es "nur" deadalus ist, sollten in der Lage sein etwas englisch zu können. Die Funktionsnamen und Befehle usw. sind ja auch größtenteils englisch.
    Ich denke auch diejenigen die auf solche komplexen Skripte zurückgreifen sind die erfahrenen Skripter von denen man wohl noch eher davon ausgehen kann dass sie englisch können denke ich.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
Impressum | Link Us | intern
World of Gothic © by World of Gothic Team
Gothic, Gothic 2 & Gothic 3 are © by Piranha Bytes & Egmont Interactive & JoWooD Productions AG, all rights reserved worldwide