Gibt es irgendwo öffentliche Dokumentationen, Beschreibungen oder Informationen zum Binärformat der Skripte und/oder der binären Skriptdaten aus Spielständen?
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
Aus den fehlenden Antworten schließe ich mal ein "Nein".
Anbei eine erste Beschreibung des Binärformats.
Fehler meinerseits sind nicht ausgeschlossen. Die Beschreibung der gespeicherten globalen Int-Variablen ohne Flags (const, ...) eines Spielstandes (SaveDat.sav) fehlt, da diese Datei einiges mehr enthält und die verschiedenen Archivtypen (ASCII, BinarySafe, ...) dokumentiert werden müssten.
Fragen bitte in diesem Thread.
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
Externals die einen string zurückgeben, schreiben das Ergebnis in eine lokale statische Variable. Wenn man solch eine Funktion mehrmals in einem Ausdruck verwendet, dann wird das Ergebnis der vorherigen Aufrufe überschrieben.
Beispiel: ConcatStrings(IntToString(1), IntToString(2)) = "22"
func string Externals:
ConcatStrings
FloatToString
IntToString
NPC_GetDetectedMob
NPC_GetNearestWP
NPC_GetNextWP
--- Achtung (2) ---
Externals die eine instance zurückgeben, schreiben das Ergebnis in ein globales Symbol (ÿINSTANCE_HELP).
---
Auf dem Daten-Stack befinden sich normalerweise Wert/Typ-Paare (Token_PushInt, 42). Dies gilt nicht für instance-Werte (dort fehlt der Typ).
PopValue() ist mit Vorsicht zu betrachten, da der Stack (abhängig von dessen Inhalt) anders hinterlassen werden kann. So könnte man Token_PushInt, 0-Parameter "optimieren" (bzw. für Verwirrung sorgen), indem man als Typ etwas anderes als Token_PushInt/Token_PushVar auf den Stack legt (mit Token_PushInstance) und den Wert weglässt.
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
Eine Liste der Funktionen, die durch die Engine bzw. das Spiel aufgerufen werden (können - es tauchen dort Dinge auf, die in Gothic nicht verwendet werden oder so nicht im Spiel vorkommen):
Wann und unter welchen Bedingungen die Funktionen aufgerufen werden ist teilweise schwer zu beantworten (und würde den Rahmen des Threads sprengen). Detailfragen können (wenn möglich) hier im Thread geklärt werden.
ps: Alle Informationen beziehen sich auf Version 2.6.
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
Hier eine Liste der Skriptklassen (Beschreibung eines zusammenhängenden Speicherbereichs eines Objekts zur Laufzeit in der Engine, auf den in den Skripten zugegriffen werden kann), deren Größen und/oder Offsets in der Engine überprüft werden:
sizeof(Camera.CCamSys)
sizeof(Gothic.C_Info)
offset(Gothic.C_Item)
sizeof(Gothic.C_Item)
sizeof(Gothic.C_ItemReact)
sizeof(Gothic.C_Mob)
offset(Gothic.C_Npc)
sizeof(Gothic.C_Npc)
sizeof(Music.C_MusicJingle)
sizeof(Music.C_MusicSys_Cfg)
sizeof(Music.C_MusicTheme)
sizeof(ParticleFX.C_ParticleFX)
sizeof(SFX.C_SFX)
sizeof(SFX.C_SndSys_Cfg)
sizeof(VisualFX.CFX_Base)
sizeof(VisualFX.C_ParticleFxEmitKey)
Im Gegensatz zu C_Item und C_Npc initialisiert die Engine den Klassenoffset für C_Mob (wäre wie bei den anderen beiden sizeof(oCVob)...) nicht nach dem Laden/Parsen der Gothic.dat. Dadurch ist die Nutzbarkeit von C_Mob (wenn sie in den Skripten vorhanden wäre) mehr als fragwürdig.
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
Neben den Schlüsselwörtern SELF (innerhalb der Funktion einer Instanz) und NOFUNC (es wird Symbolindex -1 für einen FUNC-Parameter übergeben), gibt es noch NULL (es wird Symbolindex 0 für einen Objektreferenz-Parameter übergeben). Aber dies ist mit Vorsicht zu genießen. Wie oben schon erwähnt, ist das Symbol mit dem Index 0 ÿINSTANCE_HELP und wird für den Rückgabewert von Externals verwendet, die eine Objektreferenz zurückgeben. Bei Externals funktioniert NULL wie erwartet, weil das Symbol mit dem Index 0 nicht als Parameter akzeptiert wird (die Objektreferenz wird nicht aus dem Symbol gelesen und der Standardwert für ungültige Symbole ist ein Nullzeiger). Diverse Folgefehler dieses Verhaltens von Externals können nicht auftreten, weil der Parser es nicht erlaubt, den Rückgabewert einer Funktion direkt als Parameter für eine Objektreferenz zu verwenden. Allerdings muss man bei eigenen Funktionen aufpassen, da dort der Symbolindex 0 durchaus gültig ist:
Code:
func int NullTest_GetNpcId(var C_NPC Character)
{
// push_inst NullTest_GetNpcId.Character
// assign_inst
// push_inst NullTest_GetNpcId.Character
// call_external Hlp_GetInstanceID
// return
return Hlp_GetInstanceID(Character);
// return
};
func void NullTest()
{
var int HeroId;
var C_NPC HeroInst;
var int NullId;
var C_NPC NullInst;
var int Book;
// push_inst hero
// call_external Hlp_GetInstanceID
// push_var NullTest.HeroId
// assign
HeroId = Hlp_GetInstanceID(hero);
// push_var NullTest.HeroId
// call_external Hlp_GetNpc // result in symbol 0 (ÿINSTANCE_HELP)
// push_inst NullTest.HeroInst
// assign_inst
HeroInst = Hlp_GetNpc(HeroId);
/* NullId = Hlp_GetInstanceID(Hlp_GetNpc(HeroId)); // does not compile */
/* NullId = NullTest_GetNpcId(Hlp_GetNpc(HeroId)); // does not compile */
/* NullId = Hlp_GetInstanceID(NULL); // externals do not read symbol 0 */
// push_inst ÿINSTANCE_HELP
// call NullTest_GetNpcId
// push_var NullTest.NullId
// assign
NullId = NullTest_GetNpcId(NULL); // does not what a reader would expect :)
// Attention: NullId could be the symbol index of an item (Npc_GetEquippedXxx)
NullInst = Hlp_GetNpc(NullId);
Book = Doc_Create();
Doc_SetPages(Book, 2);
Doc_SetPage(Book, 0, "BOOK_MAGE_L.TGA", FALSE);
Doc_SetMargins(Book, 0, 275, 20, 30, 20, TRUE);
Doc_SetPage(Book, 1, "BOOK_MAGE_R.TGA", FALSE);
Doc_SetMargins(Book, 1, 30, 20, 275, 20, TRUE);
Doc_SetFont(Book, -1, "FONT_15_BOOK.TGA");
Doc_PrintLine(Book, 0, "Hello, HERO");
Doc_PrintLine(Book, 1, "Hello, NULL");
Doc_SetFont(Book, -1, "FONT_10_BOOK.TGA");
Doc_PrintLine(Book, 0, ConcatStrings("id = ", IntToString(HeroId)));
Doc_PrintLine(Book, 1, ConcatStrings("id = ", IntToString(NullId)));
Doc_PrintLine(Book, 0, ConcatStrings("name = ", HeroInst.Name));
Doc_PrintLine(Book, 1, ConcatStrings("name = ", NullInst.Name));
Doc_Show(Book);
};
instance ANullTest(C_Item)
{
name = "NullTest";
mainflag = ITEM_KAT_DOCS;
flags = ITEM_MISSION;
value = 42;
visual = "ItWr_Book_02_05.3ds";
material = MAT_LEATHER;
scemeName = "MAP";
on_state[0] = NullTest;
};
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
Interessant, ich wusste gar nicht, dass es NULL in Daedalus gibt. Eine Frage hätte ich allerdings. Macht es überhaupt irgendwo Sinn, Null bei Externals zu verwenden? Ich bin da gerade ein wenig unkreativ
Macht es überhaupt irgendwo Sinn, Null bei Externals zu verwenden?
Nein, in den meisten Fällen sollten/müssen die Objektreferenzen gültig sein.
Lediglich Npc_SendPassivePerc/Npc_HasNews/Npc_MemoryEntry[Guild] lassen sich für Spezialfälle missbrauchen (wenn VICTIM und/oder OTHER ungültig sein können/sollen).
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
AI_ContinueRoutine(npc) macht im Endeffekt nichts anderes als AI_StandUpQuick(npc), AI_StopLookAt(npc), AI_StopPointAt(npc), AI_RemoveWeapon(npc) und AI_StartState(npc, 0, FALSE, ""). Wobei der spezielle Wert 0 für die Zustandsfunktion bedeutet: verwende den, der aktuellen Weltzeit entsprechenden, Eintrag des Tagesablaufs. Allerdings ist es nicht möglich, Integer-Literale, FUNC-Variablen oder FUNC-Klassenfelder zu verwenden. Die einizige "Konstante" ist NOFUNC (die entspricht aber -1). Allerdings erlaubt der Parser die Verwendung von Instanzen/Prototypen als FUNC-Parameter (es wird der Symbolindex übergeben). Und das Symbol mit dem Index 0 ist ÿINSTANCE_HELP
Code:
func void AI_StartRoutineState(var C_NPC npc, var int end, var string wp)
{
// AI_StartState has a special value of 0 for the second parameter
// to start the current daily routine entry. But the script parser
// does not allow to pass integer constants as FUNC parameters and
// at run-time an error is raised if a FUNC variable or FUNC class
// member is used as parameter. However, the script parser accepts
// instances/prototypes as FUNC parameter (symbol index is pushed)
// and the special ÿINSTANCE_HELP symbol has always the index 0...
AI_StartState(npc, ÿINSTANCE_HELP, end, wp);
};
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor