PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [Skriptpaket] LeGo #2



Seiten : [1] 2

Gottfried
22.03.2012, 13:27
Anmerkung der Moderation:
Dieses Thema ist nicht aktuell (und ohnehin geschlossen). Das Folge-Thema ist hier zu finden:
http://forum.worldofplayers.de/forum/threads/1408430-Skriptpaket-LeGo-3






$$\.................$$$$$$\..............$$$$$$\..
$$.|...............$$..__$$\............$$..__$$\.
$$.|......$$$$$$\..$$./..\__|.$$$$$$\...\__/..$$.|
$$.|.....$$..__$$\.$$.|$$$$\.$$..__$$\...$$$$$$..|
$$.|.....$$$$$$$$.|$$.|\_$$.|$$./..$$.|.$$..____/.
$$.|.....$$...____|$$.|..$$.|$$.|..$$.|.$$.|......
$$$$$$$$\\$$$$$$$\.\$$$$$$..|\$$$$$$..|.$$$$$$$$\.
\________|\_______|.\______/..\______/..\________|


»Es gibt Lego, es gibt Minecraft, aber nichts ist so toll wie LeGo \o/«
-Lehona


LeGo [LehonaGottfried] ist, wie aus dem Titel ersichtlich, ein Skriptpaket das auf Ikarus aufbaut. Während Ikarus grundlegende Möglichkeiten bereitstellt, wird hier der Fokus auf die praktische Anwendung gelegt. Alle enthaltenen Funktionen sind sehr einfach gehalten und müssen nicht in ein tolles Script eingeflochten werden um Sinn zu ergeben, sondern sind auch alleinstehend mächtig. Über pixelgenaues Erzeugen von Texten und Texturen auf dem Bildschirm und einem schönen Interface für Trialoge (eigentlich "Polyloge"), bis hin zu "Triggerlosen Triggerschleifen" die mit nur einer Zeile aktiviert werden können beinhaltet LeGo sicher für jeden Scripter eine interressante Erweiterung die ihm von Nutzen sein kann.
Sicher sind manche Pakete sehr speziell oder einfach nur nutzloser als andere, das liegt daran dass LeGo nicht aus einer Idee "Lass uns ein Scriptpaket machen!" entstanden ist. Ursprünglich war alles was hier zu finden ist als Grundlage für unseren Beitrag zum Modding-Contest gedacht, da Lehona und ich aber leider nicht fertig geworden sind (aus eigener Faulheit, zugegebenermaßen) lag dieser Featurehaufen noch ungeordnet und ohne Nutzen auf unseren Platten. Nun, da wir beide nette Menschen sind haben wir uns überlegt den ganzen Kram zu sortieren, kommentieren und zu erklären (was bei unserer Arbeitweise beim besten Willen nicht einfach war) und hier zur Verfügung zu stellen.
Sektenspinners zweifellos vorhandene Unterstützung sei natürlich auch noch erwähnt. Ohne ihn hätte sich der Release entweder noch um ein paar Jahren hingezogen oder es gäbe gar keinen :)

LeGo wird (wenn interresse besteht) laufend erweitert, nicht zuletzt wenn DU gute Vorschläge für weitere Funktionen hast, daher eröffnen wir hier mal ganz konservativ mit der Version 1.0 :)
Zur Version 1.0 sei noch folgendes gesagt: Da LeGo mit momentan 15 Päckchen ziemlich umfangreich geworden ist können wir beide keine Fehlerfreiheit garantieren. Jedes Paket wurde bereits genutzt und sollte im Normalfall funktionieren, allerdings wurde in den letzten Tagen noch sehr viel modifiziert um es möglichst Nutzerfreundlich zu gestalten. Wenn du einen Fehler entdecken solltest (oder ein grundlosen Absturz bekommst, was auch immer ;)) dann schreib doch ein paar Zeilen in diesen Thread in denen du kurz erläuterst was genau du getan hast und welche der Pakete aktiv waren.


Ältere Threads


[Skriptpaket] LeGo (http://forum.worldofplayers.de/forum/threads/1023720-Skriptpaket-LeGo)


Wiki


Beispiele und Dokumentationen aller Funktionen innerhalb des Scriptpaketes
Startseite (http://gottfried.milgo.de/LeGo/?)


Anwendungsbeispiele






Hook Einsammeln von Items (http://forum.worldofplayers.de/forum/threads/1023720-Skriptpaket-LeGo?p=16744409&viewfull=1#post16744409)

Sektenspinner & Milky-Way





Adresse von Funktionen zum Hooken mitsamt allen wichtigen Informationen (http://forum.worldofplayers.de/forum/threads/1023720-Skriptpaket-LeGo?p=17631567&viewfull=1#post17631567)

Zerxes





Respawn von Monstern - Ein Tutorial zu PermMem (http://forum.worldofplayers.de/forum/threads/1023720-Skriptpaket-LeGo?p=18317833&viewfull=1#post18317833) (Version 2) (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=19677272&viewfull=1#post19677272)

Lehona





Wichtige Grafik zur Benutzung von LeGo (http://forum.worldofplayers.de/forum/attachment.php?attachmentid=37602&d=1330992211)

Sektenspinner





Respawn von Pflanzen (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=18718274&viewfull=1#post18718274)

Umfi





Die Benutzung von ForEachHndl() (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=18727799&viewfull=1#post18727799)

Gottfried





Itemnamen im Inventar einfärben (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=19052987&viewfull=1#post19052987)

Lehona





Aufruf des Charaktermenüs überschreiben (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=19139009&viewfull=1#post19139009)

Lehona





Eine eigene Schadensberechnung (http://forum.worldofplayers.de/forum/threads/1149697-Script-Eigene-Schadensberechnung)

Lehona





Kollision von Pfeilen mit Triggerzonen ausschalten (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=20894916&viewfull=1#post20894916)

Sektenspinner





Zusätzliche Informationen im Charaktermenü (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=20906914&viewfull=1#post20906914)

Sektenspinner





Verkaufspreise kontextbasiert anpassen (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=21130811&viewfull=1#post21130811)

Lehona





Die Dialogliste im Dialog aktualisieren (http://forum.worldofplayers.de/forum/threads/1126551-Skriptpaket-LeGo-2?p=21187930&viewfull=1#post21187930)

Lehona & redleha






Download


Releaseversionen
LeGo 2.3 (http://upload.worldofplayers.de/files9/LeGo_2_3_0.7z)
LeGo 2.2.2 (https://subversion.assembla.com/svn/lego2/Release/LeGo_2_2_2.7z)
LeGo 2.2.1 (https://subversion.assembla.com/svn/lego2/Release/LeGo_2_2_1.7z)
LeGo 2.2 (https://subversion.assembla.com/svn/lego2/Release/LeGo_2_2.7z)
LeGo 2.1 (https://subversion.assembla.com/svn/lego2/Release/LeGo_2_1.7z)
LeGo 2.0.1 (https://subversion.assembla.com/svn/lego2/Release/LeGo_2_0_1.7z)
LeGo 2.0 (https://subversion.assembla.com/svn/lego2/Release/LeGo_2_0.7z)
LeGo 1.0.1 (https://subversion.assembla.com/svn/lego2/Release/LeGo_1_0_1.7z)

Letzte Revision
LeGo.zip (https://subversion.assembla.com/svn/lego2/LeGo.zip)
Link zum SVN (https://www.assembla.com/code/lego2/subversion/nodes)




Viel Spaß mit diesem Paket wünschen euch
Gottfried und Lehona

Icebox
22.03.2012, 19:23
So direkt mal ne Frage reinwerf, die ich nicht durch ne anständige Recherche (Thread durchsuchen) im alten Thread klären konnte. §cry

Arbeite gerade an Trialogen und ich will, dass die beiden Gesprächspartner miteinander reden. Habt ihr dafür auch ne Funktion? Weil in eurem Beispiel redet ja immer nur ein NPC mit dem Hero, aber niemals ein anderer mit einem anderen :(

PS:


AI_Output (Henk, self, "DIA_Malte_TRIALOG_HENK_PAKET_15_0"); //Was? Wer behauptet denn so einen Mist? Das Paket ist doch hier.

Klappt leider nicht, also der einfachste Weg ist schon mal gescheitert :(

Fisk2033
22.03.2012, 19:54
Sry,wenn das totaler Mist ist..Könntest du nicht einfach immer mit Tria_Next und TurntoNPC arbeiten?^^

Icebox
22.03.2012, 20:18
TRIA_NEXT überschreibt laut doku nur Self, was mir ja nicht viel bringen würden, denn es müsste ja im Grunde Other (Also der Held) überschrieben werden

Gottfried
22.03.2012, 21:01
Fisk hat schon Recht. Du musst zwangsweise immer "other" ansprechen, auch wenn er gar nicht damit gemeint ist.

Du kannst es etwa so machen:


// [...]

AI_TurnToNpc(Skipper, Bob);
AI_WaitTillEnd(self, Skipper); // Wenn Skipper nicht self ist sollte gewartet werden

TRIA_Next(Skipper);
AI_TurnToNpc(Bob, Skipper);
AI_Output(self, other, "somedia_020"); // Hey, mein Name ist Skipper. Wie heißt du?

TRIA_Next(Bob);
AI_Output(self, other, "somedia_021"); // Ich bin Bob.

TRIA_Next(Skipper);
AI_Output(self, other, "somedia_022"); // Toll.Dass da in Wirklichkeit immer der Held angesprochen wird, merkt ja keiner ;)

MfG Gottfried

Icebox
22.03.2012, 21:34
Ui super :gratz Solltet ihr vielleicht in Euer Tutorial einbinden, ich denke die Frage könnte öfters kommen ^^

Gut doch net so okay -.-

Jetzt sprechen die NPCs zwar miteinander, aber grundsätzlich verkehrt herum -.- Heißt der Eine sagt das vom anderen und andersrum


Func void DIA_Malte_TRIALOG_HENK_PAKET_Info()
{
var c_npc Malte; Malte = Hlp_GetNpc(VLK_119_Malte);
var c_npc Henk; Henk = Hlp_GetNpc(VLK_114_Henk);

TRIA_Invite(Henk);
TRIA_Start();
//Malte spricht Henk An
//TRIA_Next(Malte);

AI_TurnToNpc(Malte, Henk);
AI_WaitTillEnd(self, Malte);

TRIA_Next(Malte);
AI_TurnToNpc(Henk, Malte);
AI_Output(self, other, "DIA_Malte_TRIALOG_HENK_PAKET_1_3"); // Sag mal, was erzählst du da für einen Mist? Du hast mein Paket nicht mehr?
TRIA_Next(Henk);
AI_Output(self, other, "DIA_Malte_TRIALOG_HENK_PAKET_15_0"); // Was? Wer behauptet denn so einen Mist? Das Paket ist doch hier.

TRIA_Next(Malte);
AI_Output(self, other, "DIA_Malte_TRIALOG_HENK_PAKET_1_4"); // Mein Sohn sagt, du hättest es nicht?

TRIA_Next(Henk);
AI_Output(self, other, "DIA_Malte_TRIALOG_HENK_PAKET_15_1"); // Was? Den Kerl hab ich noch nie gesehen

TRIA_Next(Malte);
AI_TurnToNpc(Malte, PC_Hero);
AI_Output (self, other, "DIA_Malte_TRIALOG_HENK_PAKET_1_5"); //Stimmt das?
AI_Output (other, self, "DIA_Malte_TRIALOG_HENK_PAKET_15_2"); //Äh, eigentlich ...
AI_Output (self, other, "DIA_Malte_TRIALOG_HENK_PAKET_1_6"); //Ich bin ja enttäuschungen von dir gewohnt, aber das du mich auch noch belügst ist wirklich sehr enttäuschend ... Darüber reden wir später!
TRIA_Finish(); // und Ende
AI_StopProcessInfos (self);


};


Überseh ich irgendwo was oder hab ich einfach nur zu wenig kaffee intus um das problem zu erkennen? :dnuhr:

Fisk2033
23.03.2012, 12:56
Ich möchte wieder keinen Mist erzählen, aber ich habe schon von 3 anderen Usern mitbekommen(bei mir war es auch so) das die Trialoge in der jetztigen, Release Version fehlerhaft sind. Bei der noch nicht veröffentlichten Version geht das alles wieder super, also denk ich mal,dass es bei dir auch gehen wird.. Bei der neuen Version,wenn sie denn mal raus kommt^^.


Vielleicht liegt das Problem auch wirklich nur irgendwo im Script.. Keine Ahnung.

Gottfried
24.03.2012, 03:21
Überseh ich irgendwo was oder hab ich einfach nur zu wenig kaffee intus um das problem zu erkennen? :dnuhr:Vielleicht habe ich gerade zu viel Alkohol intus, aber...

Bei der noch nicht veröffentlichten Version geht das alles wieder superschätze ich.

Ich habe mich letztens erst mit den Trialogen befasst und diese Fehler mit der Reihenfolge beseitigt.
Um davon zu profitieren musst du dir entweder die letzte inoffizielle LeGo.zip (https://www.assembla.com/code/lego2/subversion/nodes/LeGo.zip) herunterladen oder direkt das SVN (https://www.assembla.com/code/lego2/subversion/nodes) auschecken.

Wenn dir das zu viel Aufwand ist kannst du wie Fisk sagt auch einfach warten bis wir einen neuen offiziellen Release raushauen. Gibt momentan noch ein paar kleine Problemchen mit A8

MfG Gottfried

Bisasam
26.03.2012, 17:33
Ich verstehe eure AI-Functions trotz kommentaren nicht. welche funktion muss ich nehmen, wenn ich einen wld_sendtrigger verzögern will? welche muss ich nehmen, wenn ich eine print-funktion verzögert aufrufen will? und vor allem: woran erkennt man das genau?

Milky-Way
26.03.2012, 17:43
Du musst halt gucken, was für Parameter du der Funktion mitgeben musst. Sowohl Wld_SendTrigger als auch Print bekommen einen String. Also benutzt du AI_Function_S.
Alternativ kann man natürlich auch alles schon festlegen und mit AI_Function eine (eigene) Funktion ohne Parameter aufrufen, die dann immer dasselbe macht (oder globale Variablen nutzen und die jeweils vorher verändern).

Gottfried
27.03.2012, 20:00
Nur um die Ausführung von Milky noch mit konkreten Beispielen zu untermauern:

Wld_SendTrigger erwartet einen String, folglich musst du AI_Function_S verwenden. Könnte so aussehen:
AI_Function_S(hero, Wld_SendTrigger, "MYTRIGGER");

Alternativ um es so zu verpacken wie Milky es bereits angedeutet hat:

func void AI_SendTrigger(var c_npc slf, var string trigger) {
AI_Function_S(hero, Wld_SendTrigger, trigger);
};Dann würde
AI_SendTrigger(hero, "MYTRIGGER");
ebenfalls tun was du haben willst.

AI_Function sollte allerdings nicht benutzt werden um etwas zeitverzögert aufzurufen, sondern nur um etwas nach den Aktionen eines Npc auszuführen. (Das ist ein kleiner, aber feiner Unterschied)

Wenn du Wld_SendTrigger nach 50 Sekunden aufrufen willst solltest du die FF verwenden:

func void DelayedTrigger() {
FF_ApplyExt(FireMyTrigger, 50000, 1); // 50sec, einmalig
};

func void FireMyTrigger() {
Wld_SendTrigger("MYTRIGGER");
};


MfG Gottfried

Lehona
30.03.2012, 03:31
Die Prints sollten jetzt allesamt funktionieren, wäre ganz nett wenn so einige mal eben updaten können (Diejenigen ohne SVN-Client: LeGo.zip ist auch auf dem neuesten Stand) und etwaige Fehler melden können. Wir haben auch das Problem mit PrintScreen behoben (Wobei wir PrintScreen jetzt quasi zu einer normalen Scriptfunktion degradiert haben :p), es wird also nicht mehr eingefärbt sondern bleibt weiß. Wir hoffen, dass wir im Laufe des morgigen Tages auch eine finale Version auf den SVN laden können und dann - wenn es keine direkten Fehler gibt - diese LeGo 2.2 nennen können ;)

Dada
30.03.2012, 07:45
Klingt doch super. Mal schaun, ob sich meine ständigen Abstürze jetzt beheben lassen.

Wenn ich wieder zu Hause bin, gibts Feedback :-)

Umfi
30.03.2012, 13:02
Die Prints sollten jetzt allesamt funktionieren, wäre ganz nett wenn so einige mal eben updaten können (Diejenigen ohne SVN-Client: LeGo.zip ist auch auf dem neuesten Stand) und etwaige Fehler melden können. Wir haben auch das Problem mit PrintScreen behoben (Wobei wir PrintScreen jetzt quasi zu einer normalen Scriptfunktion degradiert haben :p), es wird also nicht mehr eingefärbt sondern bleibt weiß. Wir hoffen, dass wir im Laufe des morgigen Tages auch eine finale Version auf den SVN laden können und dann - wenn es keine direkten Fehler gibt - diese LeGo 2.2 nennen können ;)


Danke, ich werd es heute am Abend nochmal alles durchtesten, danach gib ich hier Bescheid ob alles funktioniert. §wink

EDIT: Hab jetzt nochmal alles getest. Scheint jetzt keine Probleme mehr zu geben. Das Problem mit PrintScreen() <-> PrintS() wurde auch behoben. :)
Abstürze hab ich auch keine mehr gehabt, hab viele Situationen getestet, und immer wieder Laden lönnen.
Also danke das ihr LeGo jetzt perfektioniert habt. :)

Dada
30.03.2012, 13:44
Sooo, Feedback :D

Scheinbar funktioniert das, was bisher immer für Abstürze gesorgt hat, nämlich die PrintS's, sorgen für keine Abstürze mehr :)

Respekt *Symbolisch die Blumen und die Flasche Bier rüberreich* und Danke :gratz

Gottfried
01.04.2012, 17:44
Guten Abend werte Gemeinschaft!

Lehona und ich waren uns einig heute die Version 2.2 als vollwertig zu kennzeichnen und zu releasen.

Da Origo in nicht all zu langer Zeit schließen wird, waren wir gezwungen uns eine Alternative zu suchen. Auf das Wiki wollten wir nicht verzichten, schon deshalb weil es auch uns selbst bei der Organisation dieses Projektes hilft. (Sofern man das was wir hier verzapfen überhaupt als "Organisation" bezeichnen kann.)
Diese Alternative ist noch nicht ganz fertig, es fehlt noch ein wenig Feinschliff. Trotz des unfertigen Zustandes wollen wir sie euch nicht vorenthalten.
Hier (http://gottfried.milgo.de/LeGo/) ist unsere neue Seite, gehostet vom hochverehrten Meister Milgo. Vielen Dank dafür! :gratz

Seit LeGo 2.1 hat sich wieder sehr vieles geändert. Fast jedes Paket hat eine Aufwertung oder (mindestens) einen Fix erhalten.
PermMem (http://gottfried.milgo.de/LeGo/?PermMem) wurde im Hintergrund komplett neu aufgebaut, die Dialoggestures (http://gottfried.milgo.de/LeGo/?Dialoggestures) sehen nun auch nach außen hin komplett anders aus, sie nutzen keine Overlays mehr (dank eines Denkanstoßes von Zaphod). Die Locals (http://gottfried.milgo.de/LeGo/?Locals) wurden mit großer Beihilfe von Sektenspinner ebenfalls neu aufgebaut, sie sind um ein achtfaches schneller geworden, was sich auch wesentlich auf die Geschwindigkeit von PermMem auswirkt, das zu großen Teilen damit arbeitet.
Wie immer sind auch einige neue Pakete hinzugekommen. EventHandler (http://gottfried.milgo.de/LeGo/?EventHandler), Gamestate (http://gottfried.milgo.de/LeGo/?Gamestate), Timer (http://gottfried.milgo.de/LeGo/?Timer), Buttons (http://gottfried.milgo.de/LeGo/?Buttons) und StringBuilder (http://gottfried.milgo.de/LeGo/?StringBuilder). Ein Blick darauf lohnt sich :)

Bugfixing wurde wie gesagt auch im großen Stil praktiziert. Der Changelog (http://gottfried.milgo.de/LeGo/?Changelog#2.2 (01.04.2012)) spricht eine deutliche Sprache in dieser Hinsicht.

Zu den meisten neuen Paketen sind bereits Beispiele vorhanden, Lehona wird ein Beispielscript für die Buttons noch nachreichen, die Dialoggestures werden ebenfalls demnächst folgen.
Lehona und ich werden uns bemühen auch Tutorials und ähnliches für Neueinsteiger zu verfassen, um bald ein nach außen hin schönes Gesamtpaket liefern zu können ;)

Wie ihr sehen könnt habe ich den Einleitungspost stark kastriert, auch hier werde ich in den folgenden Tagen Hand anlegen.

So weit so gut. Ich bin erstmal bis Dienstag weg. Viel [hoffentlich bugfreien] Spaß mit LeGo 2.2!

MfG Gottfried

Fisk2033
01.04.2012, 18:20
Glückwunsch und Danke für den Release. Das mit den Tutorials ist sehr gut §wink Vielleicht kann ich dann mal etwas mehr anstellen,außer ein paar Prints verändern und Trialoge machen ^^

Mark56
01.04.2012, 18:36
Scripts parsed but at the end of loading this error apeared :(
00:36 Fatal:-1 C: zCPar_DataStack :: Push(): stack overflow!!! ....

Bonne6
01.04.2012, 18:38
Hab's mal eben reingeladen und gleich ein paar Probleme gesehen:

1. Cursor verwendet jetzt offenbar eine andere Textur, die fehlt aber.

2. PrintScreen zentriert jetzt??? Meine Zeitanzeige, die früher immer in der rechten oberen Ecke war, ist jetzt in der oberen Mitte.

3. Meine Formel für die Koordinatenberechnung in meinem kleinen Minispiel in XR funktioniert nicht mehr, aber da weiß ich noch nicht mehr, muss ich mal, wenn ich irgendwann mal wirklich wieder Zeit hab, gucken, woran das liegt.

Roshi
01.04.2012, 19:03
Scripts parsed but at the end of loading this error apeared :(
00:36 Fatal:-1 C: zCPar_DataStack :: Push(): stack overflow!!! ....

Maybe its GTools fault? Try switching it off before you run the game.


I have a question. Why are the Shield.d and Quickslots.d put as deprecated? Are they abandoned now?

Mark56
01.04.2012, 20:29
Hmmm turned gtools off but nothing changed :dnuhr:
Any suggestions ?

Roshi
01.04.2012, 20:49
Hmmm turned gtools off but nothing changed :dnuhr:
Any suggestions ?

Since I am almost 100% sure you are using newest ikarus and I tested the newest LeGo myself and I know it works, I can only imagine that you had to mess something up with either ini file (not very likely it is very tolerant) or some scripts. Try switching off all of the scripts packets and see if it isn't some gothic random bug which I have experienced few times too.

Fisk2033
01.04.2012, 21:24
Why are the Shield.d and Quickslots.d put as deprecated? Are they abandoned now?

Lehona says to me, the both feature are buggy :dnuhr:

Lehona
01.04.2012, 21:44
Lehona says to me, the both feature are buggy :dnuhr:

The shields kinda work, but to a standard that is unacceptable for LeGo.
Quickslots probably crash whenever someone tries to use magic so... yeah, I guess you can say they're buggy :p

Fisk2033
01.04.2012, 21:59
But for Ambient-NPCs it works!

Okay, Schluss mit dem Grundschul English :D

Roshi
02.04.2012, 01:47
Quickslots probably crash whenever someone tries to use magic so... yeah, I guess you can say they're buggy :p

Well, this is true, gothic crashes if you try to put some scroll or rune in quickslots, however I have found a way around it. It is very simple, after disabling the deactivation of rune magic (yours hookengne) and making a very easy combination of giving hero a rune, equipping it and taking it back right after the game started, everything works fine.
The only problem I have found unsolvable was to put item render of item in quickslot view, as you did on one of the screenshots back on orgio.


And with the shield, do you mean that they can not use ZS_SHIELD, ZS_LEFTARM and I think few more ZS's? I have been cleaver enough to find a way around it too, again it's dead simple, all you need to do is to play one frame ani with
*eventSwapMesh(4 "ZS_LONGSWORD" "ZS_SHIELD") on shield equip, and similar with on shield draw and undraw.

This actually leads me quite nicely to my question. Would that be possible to access model tags by scripts? Asking only because I was thinking about it recently and couldn't find the answer myself.

Neok
02.04.2012, 15:44
Nachdem Update auf die letzte Version (01.04.12) und Ikarus 1.2 Alpha funktioniert plötzlich Wld_SendTrigger("MP_MENU_CAMERA"); auf meine Kamera nicht mehr, hab nix anderes gemacht ausser Ikarus und Lego Update. §weissnich

Lehona
02.04.2012, 21:16
Nachdem Update auf die letzte Version (01.04.12) und Ikarus 1.2 Alpha funktioniert plötzlich Wld_SendTrigger("MP_MENU_CAMERA"); auf meine Kamera nicht mehr, hab nix anderes gemacht ausser Ikarus und Lego Update. §weissnich

Wo rufst du das denn auf? Wir haben an der Kamera eigentlich nix gemacht (Die Trialoge beeinflussen die Kamera meines Wissens, aber höchstens während eines Trialoges).

Sektenspinner
02.04.2012, 22:14
MEM_Camera ist nicht zuverlässig initialisiert, falls MEM_InitAll nur in INIT_GLOBAL aufgerufen wird (weil da die Kamera noch nicht existiert). Aber das betrifft dich nur falls du die Objektvariable MEM_Camera nutzt (was nicht der Fall zu sein scheint). Mit anderen Worten: Keine Ahnung, was dein Problem auslösen könnte.

Mark56
02.04.2012, 23:07
After solving stack owerflow , Gothic started freezing just at the end of loading . I had to fix it turning all FF_apply functions off... Did something changed in this function ?

Neok
03.04.2012, 08:40
Wo rufst du das denn auf? Wir haben an der Kamera eigentlich nix gemacht (Die Trialoge beeinflussen die Kamera meines Wissens, aber höchstens während eines Trialoges).
Evtl. könnt ihr das ja reproduzieren, ich habe per Spacer eine neue Kamera (1 keyframe, loop) eingefügt.

//Startup.d
func void INIT_GLOBAL()
{
// wird fuer jede Welt aufgerufen (vor INIT_<LevelName>)
Game_InitGerman();
MEM_InitAll();
MoreAlphaVobs(2048);
MoreAlphaPolys(16384);
LeGo_Init(LeGo_All);
};

//........

func void INIT_Testwelt ()
{
B_InitMonsterAttitudes ();
B_InitGuildAttitudes();
B_InitNpcGlobals ();
neok_mp_init();
INIT_SUB_Testwelt();
};


func void neok_mp_init()
{
Wld_SendTrigger("MP_MENU_CAMERA");
//.....
};

Sektenspinner
03.04.2012, 08:54
Da zum Zeitpunkt von INIT_GLOBAL noch keine Kamera existiert würde ich davon abraten schon einen Trigger an eine Kamera abzusetzen. Probier mal sowas:


{ [...] FF_ApplyExt(triggerIntro, FLOATNULL, 1); };

func void triggerIntro() {
Wld_SendTrigger("MP_MENU_CAMERA");
};In Velaya habe ich das (mit bescheideneren Werkzeugen) auch so gemacht, vermutlich nicht grundlos.

Neok
03.04.2012, 09:00
Kommt dasselbe bei raus, hab allerdings einfach mal anstatt FLOATNULL 2000 genommen und es funktioniert wieder leider (logischerweise) mit 2 Sekunden Verzögerung :(

Edit: 500 klappt ganz gut ohne merkbare Verzögerung, aber wie zuverlässig ist das auf einem leistungsschwächerem PC? 200 ist zu wenig

Bonne6
03.04.2012, 09:02
Hast du mal ein paar andere Verzögerungen ausprobiert? Muss ja nicht unbedingt 2 Sekunden sein, vielleicht reichen ja auch 10 MSec :dnuhr:

Milky-Way
03.04.2012, 09:13
Man muss die Geschichte aber auch mal ohne MarvinMode und in einer nicht-Modder-Installation ausprobieren, da sind es dann schon wieder anders aus, weil das Laden länger dauert. Dasselbe Problem hatte ich auch bei Nordstern, wo ich das Wetter umschalten wollte, was wohl aber auch nicht geht, wenn noch kein Wetter da ist (sonst hat man das alte Wetter, also immerhin kein Absturz). Meine Lösung war, einen recht großzügigen Wert einzustellen, also alles andere als optimal. Aber vielleicht ist das bei deinem Problem ja anders :dnuhr:

Neok
03.04.2012, 09:30
Ich habs jetzt dreckig gelöst und zwar feuert das Ding 100 mal im 20ms Takt :D
dadurch dürfte keine Verzögerung zu spüren sein und da die Kamera nicht animiert ist, sollte das retriggern nicht auffallen.

Was mich verwundert ist, das es vor dem Update problemlos funktionierte.
Evtl. versucht ja noch jemand das Problem zu reproduzieren.

Gottfried
03.04.2012, 18:59
1. Cursor verwendet jetzt offenbar eine andere Textur, die fehlt aber.Es gibt eine Userkonstante (http://gottfried.milgo.de/LeGo/?Userkonstanten) für die Cursortextur. Diese hat sich siet der letzten Version nicht geändert, es ist nach wie vor die Cursor.tga. (Sie ist auch in den Resources enthalten.)

2. PrintScreen zentriert jetzt??? Meine Zeitanzeige, die früher immer in der rechten oberen Ecke war, ist jetzt in der oberen Mitte.Sieht ganz so aus als hätte Lehona sich da verrechnet. In der eben hochgeladenen 2.2.1 ist das behoben.

3. Meine Formel für die Koordinatenberechnung in meinem kleinen Minispiel in XR funktioniert nicht mehr, aber da weiß ich noch nicht mehr, muss ich mal, wenn ich irgendwann mal wirklich wieder Zeit hab, gucken, woran das liegt.Welche LeGo-Funktionen benutzt die denn?


After solving stack owerflow , Gothic started freezing just at the end of loading . I had to fix it turning all FF_apply functions off... Did something changed in this function ?Yes. The FrameFunctions are based on foreachHndl (http://gottfried.milgo.de/LeGo/?PermMem#foreachHndl) now. Do you have any trouble using this function?
(foreachHndl itself uses a while-loop. It should work with the latest version of Ikarus.)


LeGo 2.2 ist jetzt identisch mit 2.2.1.
In 2.2.1 wurde der sinnlose "Scherz" entfernt, sowieso das PrintScreen-Problem behoben. Frohen April :)

MfG Gottfried

Bonne6
03.04.2012, 19:07
Es gibt eine Userkonstante (http://gottfried.milgo.de/LeGo/?Userkonstanten) für die Cursortextur. Diese hat sich siet der letzten Version nicht geändert, es ist nach wie vor die Cursor.tga. (Sie ist auch in den Resources enthalten.)

Bisher war das immer das A von dem Font ;) Und den Resources-Ordner gibt's im aktuellen Paket ja nicht mehr, jetzt muss ich das mühsam raussuchen ...

EDIT: Ok, der Teil hat sich ja erledigt :D


Sieht ganz so aus als hätte Lehona sich da verrechnet. In der eben hochgeladenen 2.2.1 ist das behoben.

Ok :D


Welche LeGo-Funktionen benutzt die denn?

Ähm, hab da rumgerechnet mit der Bildschirmgröße und so, muss ich mir mal anschauen, ist jetzt auch schon wieder ein paar Monate her, falls ich nicht weiter weiß, poste ich die Scripte hier dann mal ;)

Gottfried
03.04.2012, 19:13
Bisher war das immer das A von dem Font ;) Und den Resources-Ordner gibt's im aktuellen Paket ja nicht mehr, jetzt muss ich das mühsam raussuchen ...Die im Einleitungspost verlinkte 2.2 (oder 2.2.1) hat doch einen Resources-Ordner? :p Hast du vielleicht versehentlich die LeGo.zip heruntergeladen?
Die Font gibt es nicht mehr, weil der Cursor jetzt einen View benutzt.

Edit: Okay, hat sich ja erledigt :)

MfG Gottfried

Bonne6
03.04.2012, 19:13
Hab's grad editiert, weil ich's gesehen hab :D

Roshi
05.04.2012, 21:44
Hi §wink
Since the quickslots script was released with LeGo_dump I have been always thinking that there is some bug which makes item rendering not working, however i just finished talking to friend of mine who has it fully working and he claims he did not change anything in your scripts. He even send me his script and I checked it on my PC it didn't change anything quickslots were not rendering any items.
I have checked with few other friends and for none of them it worked, except for the one I mentioned before.
Any ideas why it might work in some cases and in other don't? :dnuhr:
The only difference between me and my friend is that he has Gold Edition whereas I got Gothic 2 and Gothic 2 Night of the Raven installed separately. Could that be the reason why?

Lehona
05.04.2012, 22:48
That shouldn't be the reason, as long as you're using the report-version, there should be virtually no difference, at least none that effects our scripts. It was working for both of us, but that was a couple of revisions ago, at least for me.

Roshi
05.04.2012, 22:54
I have been thinking the same, and now I'm getting a little bit mad with it, I just spend like two hours trying to see what might be the cause of this, and I couldn't find a decent explanation.

I am using QS_Init to init quickslots, is it possible that I am missing something out? Besides this I have the newest LeGo installed and applied in game.

Milky-Way
06.04.2012, 09:14
I have been thinking the same, and now I'm getting a little bit mad with it, I just spend like two hours trying to see what might be the cause of this, and I couldn't find a decent explanation.

I am using QS_Init to init quickslots, is it possible that I am missing something out? Besides this I have the newest LeGo installed and applied in game.

is it necessary to initialize Ikarus separately before using the quickslots?
You do have the report version installed?

Roshi
07.04.2012, 11:20
Yes and I have fixed it already, the problem was a little bit bugged _QS_RenderItem function which makes me wander how come could that be working for other if it was bugged? I am not posting the fixed version of script (which wasn't changed much) because I am still looking to see if there is any bugs or anything like that.

Lehona
07.04.2012, 13:55
Yes and I have fixed it already, the problem was a little bit bugged _QS_RenderItem function which makes me wander how come could that be working for other if it was bugged? I am not posting the fixed version of script (which wasn't changed much) because I am still looking to see if there is any bugs or anything like that.

Thanks for your effort! If you're trying to get it to work feel free to contact me (see my profile), maybe we can eventually add it to LeGo once again (crediting you, of course) :)

Roshi
07.04.2012, 18:11
I didn't put much effort in it, since it was only a very small change. As I said when I am fully finished with it I am going to post fixed script here so everyone can use it if you wish to distribute it together with LeGo I don't see any reason why you shouldn't afterall it's your script which I only edited.

I am working now on getting it to work with runes and scrolls, hte only problem I have is that spells can be assigned to key even if there is some other item assigned to it already since they saved in different arrays. Once I am done with that there shouldn't be much to fix.

Lehona
07.04.2012, 18:35
I am working now on getting it to work with runes and scrolls, hte only problem I have is that spells can be assigned to key even if there is some other item assigned to it already since they saved in different arrays. Once I am done with that there shouldn't be much to fix.

That is why we disabled the oCMag_Book, so that doesn't happen. But I think there should be a less-destructive way of making the player unable to equip magic... I will do some more research in IDA.

Edit: With some hooking with previous overriding the machine code I should be able to deactivate the oCMag_Book under any arbitrary conditions. This will allow us to equip magic items when necessary, but we have to deactivate the event of drawing the magic as well, then (unless we want to equip/unequip the magic whenever it is drawn... Apparently we probably still got a problem then). I will do more investigation :p

Roshi
07.04.2012, 23:27
Thank you for even bothering to check it.
I have been thinking of finding a way of comparing the two arrays and whenever its necessary removing the one which has been equiped first, however I am not too sure how to access array of prepared runes. If my understanding of the way things actually work is correct then each NPC has its own mag_book with unique instance, but I am not sure of it.



And I have another problem bothering me. I have recently found that I can not either delete or hide a bar I have created. What could be the cause of it? Is it some bug or I am not using it correctly?

Lehona
08.04.2012, 00:18
Thank you for even bothering to check it.
I have been thinking of finding a way of comparing the two arrays and whenever its necessary removing the one which has been equiped first, however I am not too sure how to access array of prepared runes. If my understanding of the way things actually work is correct then each NPC has its own mag_book with unique instance, but I am not sure of it.



And I have another problem bothering me. I have recently found that I can not either delete or hide a bar I have created. What could be the cause of it? Is it some bug or I am not using it correctly?

Yes, ever NPC owns its own oCMag_Book (oCNpc.magbook or so)..

Can you show me the code?

Roshi
08.04.2012, 01:48
Can you show me the code?

For the hiding bars? No problem:

func void hide_bars()
{
Bar_Hide(stamina_bar);
Bar_Hide(expirience);
Bar_Delete(stamina_bar);
Bar_Delete(expirience);
FF_Remove(create_exp_bar);
FF_Remove(create_stamina_bar);
};
As you see I am trying to hide both bars, trying to delete them and I am stopping creating them. So what can be the problem?

Lehona
08.04.2012, 01:51
Show me your FrameFunctions. From what you're telling me I think I know the problem :)

Roshi
08.04.2012, 16:11
I am using the newest FrameFunctions (just yesterday downloaded from SVN) and I am triggering it in startup_global if this will be of any use.

I noticed I have been triggering initialization of FrameFunction, which was creating the bar, every frame, after fixing it, it was still the same, I mean my function was not hiding/destroying the bars.

Lehona
08.04.2012, 17:05
I mean: Can you show me the code of your FrameFunction, i.e. create_exp_bar() and create_stamina_bar() :)

Roshi
08.04.2012, 17:58
So that's what you meant! I've been thinking if i am giving you what you are asking for, well nevermind, here it goes:
func void create_stamina_bar()

{
var int staminabar;
if(!Hlp_IsValidHandle(staminabar))
{
staminabar = Bar_Create(stamina_bar);
};
Bar_SetMax(staminabar, stamina_max);
Bar_SetValue(staminabar, stamina);
};

Lehona
08.04.2012, 18:29
Okay, that is completely correct. Apparently, Bar_Delete() might be not working correctly, though (Which has nothing to do with bars but with View_Delete()). Bar_Hide() should be completely functional, did you try just using Bar_Hide()? If that doesn't work, I'll later on try to find the error (Gottfried is on vaccation or at least not online for the next few days, so it may take some time).

Bonne6
09.04.2012, 20:15
Ist es so gewollt, das beim Struct für neue Klassen ein "int string int int int" beim Speichern crasht und ein "auto auto auto|3" geht? Sollte das nicht gleich sein? Also ich hatte vorher ersteres und mit der neuen LeGo-Version ist das gecrasht, bin deswegen umgestiegen, weil's ja auch so im Respawn-Tutorial stand, nur wurde das so damals noch nicht unterstützt in der offiziellen Version :D

Lehona
09.04.2012, 20:34
Du kannst auch einfach "auto|5" angeben. Aber ja, das ist uns (Gottfried) durchaus bewusst. Theoretisch hätte er da wohl 'ne Ausnahme einbauen können, der Himmel weiß, warum er das nicht gemacht hat :p

Bonne6
09.04.2012, 20:43
Gut zu wissen, da war ich mir nicht sicher, weil ja in deinem Tut was stand "vom gleichen Typ" und int und string sind ja unterschiedlich. Hatte auch noch keine Lust das auszuprobieren, aber dann kann ich's ja umstellen, ist das noch ein wenig kürzer :)

Lehona
09.04.2012, 20:47
Gut zu wissen, da war ich mir nicht sicher, weil ja in deinem Tut was stand "vom gleichen Typ" und int und string sind ja unterschiedlich. Hatte auch noch keine Lust das auszuprobieren, aber dann kann ich's ja umstellen, ist das noch ein wenig kürzer :)

Alle primitiven Typen lassen sich zu "auto" abkürzen. Allerdings kann es sinnvoll sein, eine Funktion mit PM_SaveFuncID() zu speichern, um eine höhere Kompatibilität zu Patches zu gewährleisten (Die Frage ist bloß, wie sinnvoll das denn ist, ich weiß nicht genau, wann ein Patch kaputt geht und wann nicht). Außerdem ist es besser zum Debuggen, weil der Name der Funktion (bzw. des Symbols) gespeichert wird und nicht nur der Index.

Umfi
10.04.2012, 12:10
Hi, da ich mir mal PermMem näher anschauen wollte, hab ich einen Pflanzenrespawn mit Hilfe von PermMem realisiert.
An der Stelle möcht ich mich gleich nochmal bei Lehona und Gottfried für LeGo bedanken, wenn ich denke das man früher für etwas in der Art mit 100terten von Waypoints und Abfragen kämpfen musste....


Als erstes muss man die Pflanzenitems ergänzen mit einer Zeile, und zwar mit der ungenutzen Varible nutrition der Klasse C_Item/oCItem.

So könnte es dann z.B. aussehen:


INSTANCE ItPl_Survival_Plant_2 (C_Item)
{
name = "Plant 2";

mainflag = ITEM_KAT_FOOD;
flags = ITEM_MULTI;

value = Value_Plant_1;

visual = "SURVIVAL_ITEMPLANT_02.3DS";
material = MAT_LEATHER;
on_state[0] = Use_Plant_2;
scemeName = "FOOD";

description = name;

nutrition = 1; //nur Pflanzen
TEXT[5] = NAME_EFFEKT;
};

func void Use_Plant_2 ()
{
Npc_ChangeAttribute (self, ATR_HITPOINTS, HP_Plant_2);
};

Als nächstes müssen wir die Stelle hooken, an der der Spieler die Items aufhebt.
Dazu muss folgendes in die InitGlobals der Startup.d


if (!Hlp_StrCmp(GOTHIC_RESTART, "Y"))
{
Hook_oCNpc__DoTakeVob();
GOTHIC_RESTART = "Y";
};


So jetzt zum eigentlichen Hook.



///////////////////////////////////////////////////////////////////////////////
// Hook: Item aufheben
//////////////////////////////////////////////////////////////////////////////

func void Hook_oCNpc__DoTakeVob() {
const int oCNpc__DoTakeVob = 7621056; //0x7449C0
HookEngine(oCNpc__DoTakeVob, 6, "EVT_NPCTAKEVOB");
};

func void EVT_NpcTakeVob()
{
// ----- an den NPC und das item kommen -----
var c_npc slf; slf = MEM_PtrToInst(ECX); // der NPC, der das Item einsammelt
var oCItem itm; itm = MEM_PtrToInst(MEM_ReadInt(ESP + 4)); // Pointer auf das Item
// ----- an den NPC und das item kommen -----

// ----- stimmt das item? -----
if (!Hlp_IsValidItem (itm))
{
return;
}
else
{
if ((itm.nutrition == 1) && ((itm.flags & ITEM_DROPPED) != ITEM_DROPPED))
{
CreateRespawnObject(itm);
};
};
};



Jetzt zum eigentlich Teil, nähmlich den RespawnObjekt.




/*****************************************
* RespawnObject
* Verantwortlich für den Pflanzen respawn
*****************************************/


class RespawnObject {
var int inst;
var int spawnPosition[16];
var int respawnDay;
var string WorldName;
};

instance RespawnObject@(RespawnObject);


//*************************************
// Erzeuge ein RespawnObject
//*************************************

func void CreateRespawnObject(var oCItem slf) {
var int hndl; hndl = new(RespawnObject@);
var RespawnObject myRespawnObject; myRespawnObject = get(hndl);
myRespawnObject.inst = Hlp_GetInstanceID(slf);
MEM_CopyWords(_@(slf._zCVob_trafoObjToWorld), _@(myRespawnObject.spawnPosition), 16);
myRespawnObject.respawnDay = Wld_GetDay() + 2; // Irgendeine Formel z.b: Wld_GetDay() + (slf.value/20)+2;
myRespawnObject.WorldName = MEM_World.worldName;
};

//*************************************
// Entferne ein RespawnObject
//*************************************

func void RemoveRespawnObject(var int hndl) {
delete(hndl);
};

//************************************************
// Iteminstance an Koordinaten einfügen
//************************************************
func void MEM_InsertItemInstance (var int inst, var int fX, var int fY, var int fZ) {
var zCWaynet wayNet; wayNet = MEM_PtrToInst(MEM_World.wayNet);
var zCWaypoint wp; wp = MEM_PtrToInst(MEM_ReadInt(wayNet.wplist_next+4));
var int x; x = wp.pos[0];
var int y; y = wp.pos[1];
var int z; z = wp.pos[2];
wp.pos[0] = fX;
wp.pos[1] = fY;
wp.pos[2] = fZ;
Wld_InsertItem(inst, wp.name);
wp.pos[0] = x;
wp.pos[1] = y;
wp.pos[2] = z;
};

/* Wer die Funktionen von Sektenspinner noch nicht hat....
//************************************************
// Set Position of Vob
//************************************************

func void GetPositionWorldVec(var int vobPtr, var int vecPtr) {
var zCVob vob; vob = MEM_PtrToInst(vobPtr);
MEM_WriteIntArray(vecPtr, 0, vob.trafoObjToWorld[3]);
MEM_WriteIntArray(vecPtr, 1, vob.trafoObjToWorld[7]);
MEM_WriteIntArray(vecPtr, 2, vob.trafoObjToWorld[11]);
};

func void SetPositionWorldVec(var int vobPtr, var int vecPtr) {
const int zCVob_SetPositionWorld = 6404976; //0x61BB70

CALL_PtrParam(vecPtr);
CALL__thiscall(vobPtr, zCVob_SetPositionWorld);
};

//Wenn manuell an der Position rumgeschmiert wird, werden Bounding Box usw. nicht angepasst.
//Vobs flackern oder haben Fokusnamen an der falschen Stelle etc.
func void VobPositionUpdated(var int vobPtr) {
var int pos[3];
GetPositionWorldVec(vobPtr, _@(pos));
SetPositionWorldVec(vobPtr, _@(pos));
};
*/

//***************************************
// Überprüfe ob gespawned werden darf
//***************************************
func void CheckRespawns() {
foreachHndl (RespawnObject@, _CheckRespawns);
};

func int _CheckRespawns(var int hndl) {
var RespawnObject myRespawnObject; myRespawnObject = get(hndl);

if (myRespawnObject.respawnDay <= Wld_GetDay() && (Hlp_StrCmp (myRespawnObject.WorldName, MEM_World.worldName))) {
MEM_InsertItemInstance(myRespawnObject.inst, myRespawnObject.spawnPosition[3], myRespawnObject.spawnPosition[7], myRespawnObject.spawnPosition[11]);
var zCPar_Symbol a; a = _^(MEM_ReadIntArray (currSymbolTableAddress, myRespawnObject.inst));
var oCItem itm; itm = _^(a.offset);
var int itmPtr; itmPtr = MEM_InstToPtr (itm);
MEM_CopyWords(_@(myRespawnObject.spawnPosition),_@(itm._zCVob_trafoObjToWorld), 16);
VobPositionUpdated(itmPtr);
RemoveRespawnObject(hndl);
};
return rContinue;
};



Zum Schluss muss die Funktion CheckRespawns(); noch aufgerufen werden, dass kann z.B.: in der SleepABit.d in der Funktion PC_Sleep() gemacht werden.


func void PC_Sleep (var int t)
{
AI_StopProcessInfos(self);

PLAYER_MOBSI_PRODUCTION = MOBSI_NONE;
self.aivar[AIV_INVINCIBLE]=FALSE;
if (Wld_IsTime(00,00,t,00))
{
Wld_SetTime (t,00);
}
else
{
t = t + 24;
Wld_SetTime (t,00);
};

CheckRespawns();

[...]
};

Und das wars schon 70 Zeilen Code (ohne Hooks usw.) reichen um ein funktionierendes Pflanzenrespawnsystem zu implementieren. §wink
Kommentiert hab ich den Code jetzt nicht, aber das könnt ihr ja in Lehonas Tutorial (http://forum.worldofplayers.de/forum/threads/1023720-Skriptpaket-LeGo/page18?p=18317833&viewfull=1#post18317833) nachlesen.

Bonne6
10.04.2012, 12:23
Wollte ich auch schon machen, aber weil ich's nicht in XR einbauen durfte, hab ich's gelassen :D

Aber das tolle ist, dass ich es jetzt nicht mehr machen muss, wenn ich es doch mal irgendwo einbauen will.

Was man berücksichtigen sollte in Mods mit mehreren Leveln (also Ladezonen), ist, dass die Pflanzen im richtigen Level respawnt werden, das gilt aber ja auch schon für Lehonas Monsterrespawn.

Braucht es das Struct zum Speichern nicht unbedingt oder hast du es vergessen?

Lehona
10.04.2012, 12:25
Wollte ich auch schon machen, aber weil ich's nicht in XR einbauen durfte, hab ich's gelassen :D

Aber das tolle ist, dass ich es jetzt nicht mehr machen muss, wenn ich es doch mal irgendwo einbauen will.

Was man berücksichtigen sollte in Mods mit mehreren Leveln (also Ladezonen), ist, dass die Pflanzen im richtigen Level respawnt werden, das gilt aber ja auch schon für Lehonas Monsterrespawn.

Braucht es das Struct zum Speichern nicht unbedingt oder hast du es vergessen?

Warum durftest du das denn nicht einbauen? Balancing? :(

Solange sich eine Klasse durch "auto|x" zusammenfassen lässt, ist eine Strukturbeschreibung unnötig ;)

Sektenspinner
10.04.2012, 13:41
Schwächen (zum Teil schon genannt):
Die Respawn Objekte müssen die Welt kennen für die sie gelten.
256 Objekte ist ein künstliche und unnötige Beschränkung (und viel zu klein). Nutze zCArray, LeGo kann damit umgehen (hat Archiver und Unarchiver) und Ikarus bietet Funktionen zum einfügen und entfernen. Also new(zCArray@) und ab gehts.
Vielleicht kannst du dir sogar das Array sparen und etwas wie foreachHndl(RespawnObject@, CheckPlant) machen, allerdings ist da die Dokumentation etwas dünn.
Die Positionswerte zu speichern ist nicht immer ausreichend. Man bedenke, dass moos- und pilzartige Pflanzen auch gedreht an Steinen wachsen können. Ich würde empfehlen die gesammte Transformationsmatrix zu kopieren:

MEM_CopyWords(_@(vob._zCVob_trafoObjToWorld), _@(myRespawnObject.spawnPosition), 16);die gespeicherten Werte dann beim Einfügen des Vobs in die Tranformationsmatrix zu kopieren und VobPositionUpdated (http://forum.worldofplayers.de/forum/threads/969446-Skriptpaket-Ikarus-3/page14?p=18428179&viewfull=1#post18428179) oder vergleichbares aufzurufen.
Wenn du die Schleifenbedingung direkt ins while packst, sieht das etwas besser aus und du brauchst den Spezialfall nextRespawnIndex == 0 nicht. ;)
Du solltest auf das flag ITEM_DROPPED prüfen, aus naheliegenden Gründen.

Lehona
10.04.2012, 13:50
...

ForEachHndl() (http://gottfried.milgo.de/LeGo/?PermMem#foreachHndl) ist vermutlich in der Tat die schönere Lösung und meiner Meinung nach ist die Dokumentation vollkommen ausreichend, aber ich kenn es ja quasi auch :p Bei konkreten Fragen könnte ich eher was dazu beitragen, die Funktion wird einfach für jedes Handle ausgeführt, das mit der Instanz x (erster Parameter) erzeugt wurde (also new(x)).
Das Drop-Flag ist vermutlich keine schlechte Idee :D

Sektenspinner
10.04.2012, 14:07
ForEachHndl() (http://gottfried.milgo.de/LeGo/?PermMem#foreachHndl) ist vermutlich in der Tat die schönere Lösung und meiner Meinung nach ist die Dokumentation vollkommen ausreichend, aber ich kenn es ja quasi auch :pNun, ist wohl etwas unfair von mir, der Dokumentation vorzuwerfen sie sei dünn, ohne das zu konkretisieren. Zunächst sei festgehalten, dass in der Doku nicht steht, dass die behandelnde Funktion einen Rückgabewert haben muss (rBreak bzw. rContinue).

Bedenken hatte ich zudem, weil die Doku kein Wort darüber verliert, inwiefern es zulässig ist Objekte zu zerstören während iteriert wird. Zumindest, falls ein Handle freigegeben wird über das eigentlich gleich noch iteriert werden wird, wird bei der Funktion ein ungültiges Handle ankommen. Der vorliegene Fall scheint allerdings unkritisch zu sein und es scheint zulässig das Handle über das gerade iteriert wird freizugeben.

Lehona
10.04.2012, 14:15
Nun, ist wohl etwas unfair von mir, der Dokumentation vorzuwerfen sie sei dünn, ohne das zu konkretisieren. Zunächst sei festgehalten, dass in der Doku nicht steht, dass die behandelnde Funktion einen Rückgabewert haben muss (rBreak bzw. rContinue).

Bedenken hatte ich zudem, weil die Doku kein Wort darüber verliert, inwiefern es zulässig ist Objekte zu zerstören während iteriert wird. Zumindest, falls ein Handle freigegeben wird über das eigentlich gleich noch iteriert werden wird, wird bei der Funktion ein ungültiges Handle ankommen. Der vorliegene Fall scheint allerdings unkritisch zu sein und es scheint zulässig das Handle über das gerade iteriert wird freizugeben.

Ersteres war mir selber nicht mal bewusst (Gottfried hatte das mal erwähnt, war aber eher eine flüchtige Erinnerung :p) und das gerade benutzte Objekt darf man löschen, da hat sich Gottfried drum gekümmert (Hatte er erst selber mit Probleme). Zukünftige Handles zu löschen wird wohl nicht funktionieren, da hast du Recht... Die Frage ist, wann das mal vorkommt und wie gut es lösbar ist? Aber das ist in der Tat sinnvolle Kritik, das besser ich entweder selber aus oder hau Gottfried mal an (Er hat die Funktion schließlich geschrieben), der sollte heute eh aus dem Urlaub kommen.

Umfi
10.04.2012, 14:28
Schwächen (zum Teil schon genannt):

Die Respawn Objekte müssen die Welt kennen für die sie gelten.
256 Objekte ist ein künstliche und unnötige Beschränkung (und viel zu klein). Nutze zCArray, LeGo kann damit umgehen (hat Archiver und Unarchiver) und Ikarus bietet Funktionen zum einfügen und entfernen. Also new(zCArray@) und ab gehts.
Vielleicht kannst du dir sogar das Array sparen und etwas wie foreachHndl(RespawnObject@, CheckPlant) machen, allerdings ist da die Dokumentation etwas dünn.
Die Positionswerte zu speichern ist nicht immer ausreichend. Man bedenke, dass moos- und pilzartige Pflanzen auch gedreht an Steinen wachsen können. Ich würde empfehlen die gesammte Transformationsmatrix zu kopieren:

MEM_CopyWords(_@(vob._zCVob_trafoObjToWorld), _@(myRespawnObject.spawnPosition), 16);die gespeicherten Werte dann beim Einfügen des Vobs in die Tranformationsmatrix zu kopieren und VobPositionUpdated (http://forum.worldofplayers.de/forum/threads/969446-Skriptpaket-Ikarus-3/page14?p=18428179&viewfull=1#post18428179) oder vergleichbares aufzurufen.
Wenn du die Schleifenbedingung direkt ins while packst, sieht das etwas besser aus und du brauchst den Spezialfall nextRespawnIndex == 0 nicht. ;)
Du solltest auf das flag ITEM_DROPPED prüfen, aus naheliegenden Gründen.




Danke, ich werd's versuchen gleich um/einzubauen und dann den Code oben zu aktualisieren.

@ flag ITEM_DROPPED

Stimmt, dass ich das vergessen habe. :D
(das hab ich gleich mal ausgebessert.)

Umfi
11.04.2012, 15:17
Okay, oben findet ihr jetzt die aktuellste Version des Skriptes. Danke noch mal an Lehona, der mir bei (aus meiner Sicht unlösbaren Problemen) geholfen hat.

Das Skript arbeitet jetzt mit den foreachhandles, sie sind wirklich einfach zubedienen, im Vergleich zu den Daedalus Arrays. :D

mfg Umfi §wink

Bonne6
11.04.2012, 15:23
Wird die Rotation da jetzt auch berücksichtigt?

Und ich finde das sollte dann wie im Ikarus-Thread im ersten Beitrag verlinkt werden, ist ja doch was Nützliches und dann muss man nicht immer wieder suchen, wenn man mal gucken will :)

Lehona
11.04.2012, 15:37
Wird die Rotation da jetzt auch berücksichtigt?

Und ich finde das sollte dann wie im Ikarus-Thread im ersten Beitrag verlinkt werden, ist ja doch was Nützliches und dann muss man nicht immer wieder suchen, wenn man mal gucken will :)
Die komplette Transformationsmatrix wird überschrieben.

Ich werde Gottfried sofort dazu zwingen, sobald er wieder da ist. Eigentlich sollte ich die Threads einfach eröffnen, als Mod kann er meinen Beitrag eh editieren.

Übrigens sollte ich mein Tutorial zu PM auch auf ForEachHndl() aktualisieren - das hat vieles einfacher gemacht.

Gottfried
11.04.2012, 17:37
Nun, ist wohl etwas unfair von mir, der Dokumentation vorzuwerfen sie sei dünn, ohne das zu konkretisieren. Zunächst sei festgehalten, dass in der Doku nicht steht, dass die behandelnde Funktion einen Rückgabewert haben muss (rBreak bzw. rContinue).

Bedenken hatte ich zudem, weil die Doku kein Wort darüber verliert, inwiefern es zulässig ist Objekte zu zerstören während iteriert wird. Zumindest, falls ein Handle freigegeben wird über das eigentlich gleich noch iteriert werden wird, wird bei der Funktion ein ungültiges Handle ankommen. Der vorliegene Fall scheint allerdings unkritisch zu sein und es scheint zulässig das Handle über das gerade iteriert wird freizugeben.Eigentlich wollte ich zum Thema foreachHndl auch noch ein Beispiel beisteuern, das ist offensichtlich untergegangen. Ich werde das in den folgenden Tagen nachholen.
(Achso. Ich sehe gerade.. Die Beispiele zu PermMem wurden noch gar nicht übertragen. Ich mache das so bald wie möglich.)

Dann verliere ich mal ein paar Worte zur Funktionalität der Funktion:
Wenn ein handle über "new" erzeugt wird (und auch wirklich nur bei new), landet es direkt in der foreachTable. Die kann man sich ungefähr so vorstellen: Für jede Instanz-ID existiert ein zCArray in dem alle Handles ebendieser gespeichert sind.
Ruft der Nutzer also new(1205) auf, wird der Rückgabewert in das zCArray foreachTable[1205] geschrieben. Sinngemäß.
Angenommen new(1205) wird fünf Male hintereinander gecallt, so ist foreachTable[1205]->numInArray (die Anzahl der Elemente des zCArrays) mindestens fünf.

Was genau passiert nun beim Aufruf foreachHndl(1205, myFunc)?
Zuerst wird der gesamte Inhalt des zCArrays foreachTable[1205], sprich foreachTable[1205]->array, in einen neu alloziierten Pointer kopiert. Da dieser eigene Speicherbereich von new und delete absolut unabhängig ist, ist es möglich aus einer Funktion die von foreachHndl gecallt wurde heraus, das übergebene Handle zu löschen. Die Kopie wird nach Abschließen des Vorganges wieder freigegeben.

Folgendes ist also denkbar:

func void deleteAll(var int inst) {
foreachHndl(inst, deleteAll_sub);
};

func void deleteAll_sub(var int handle) {
delete(handle);
};Was passiert? Alle handles dieser Instanz werden gelöscht. Beispiel: deleteAll(FFItem@); um sämtliche FrameFunctions zu stoppen.

Aber war da nicht etwas mit Rückgabewert? Ja. Im Prinzip ist der eben gezeigte Code nicht ganz korrekt. Richtig wäre es so:

func void deleteAll(var int inst) {
foreachHndl(inst, deleteAll_sub);
};

func int deleteAll_sub(var int handle) {
delete(handle);
return rContinue;
};Wie Sektenspinner bereits erwähnt hat, gibt es die beiden Symbole rContinue und rBreak. Einigen dürfte das bekannt vorkommen. Wird rContinue zurückgegeben passiert "nichts" und alle folgenden Handles werden ebenfalls durchgegangen. Eine Rückgabe von rBreak hingegen stoppt die Schleife.

Beispiel: Ich möchte nur das erste Handle in der Liste löschen.

func void deleteFirst(var int inst) {
foreachHndl(inst, deleteFirst_sub);
};

func int deleteFirst_sub(var int handle) {
delete(handle);
return rBreak;
};


Warum es in obigem Beispiel trotz "func void" funktioniert ist einfach: Es wird nur der Sonderfall rBreak behandelt, rContinue ist nur eine symbolische Variable.
Was foreachHndl macht ist den Rückgabewert vom Stack zu popen. In dieser Hinsicht kommt uns das Verhalten des Parsers zugute: Wird von einem leeren Stack gepopt kommt einfach eine null zurück, und da 0 != rBreak ergibt sich aus keinem Rückgabewert vergleichsweise ein Rückgabewert von rContinue.
Trotzdem hat Sektenspinner natürlich Recht. Liegt zB. noch etwas Müll auf dem Stack der zufällig den Wert von rBreak beinhaltet, kann das zu unerwünschten Nebeneffekten führen. Sicher ist sicher.

Doch zurück zu der anderen Problematik.
Bedenken hatte ich zudem, weil die Doku kein Wort darüber verliert, inwiefern es zulässig ist Objekte zu zerstören während iteriert wird. Zumindest, falls ein Handle freigegeben wird über das eigentlich gleich noch iteriert werden wird, wird bei der Funktion ein ungültiges Handle ankommen.
Der erste Fall ist klar. Es ist problemlos möglich das aktuelle Objekt zu zerstören, da durch die Kopie des Arrays nichts verrutschen kann.
Der zweite Fall ist schon etwas verzwickter. foreachHndl prüft trotz der Kopie vor jedem Handle erneut ob es gültig ist, damit ist auf jeden Fall gewährleistet, dass keine ungültigen Handles in der Schleife landen können. So weit so gut. Wenn eine Schleife also lustig herumlöscht sollte das im Prinzip keine Probleme machen, da die handles dadurch automatisch ungültig werden.
Jetzt gibt es aber ein Problem. Ich glaube das lässt sich mit einem Beispiel wieder am besten erläutern:

1. Handle 1 und 2 werden mit der Instanz A erzeugt.
2. Für die Instanz A wird foreachHndl ausgeführt.
3. Während Handle 1 abgearbeitet wird, löscht es sich selbst und Handle 2.
4. Handle 2 ist ungültig und wird übersprungen.Perfekt. Wo ist da das Problem? Noch keines. Das ist der Fall der in der Regel funktionieren sollte. Was passiert nun wenn ich Punkt 3 etwas abändere? So vielleicht:

3. Während Handle 1 abgearbeitet wird, löscht es sich selbst und Handle 2. Danach erzeugt es ein neues Handle der Instanz B.Und schon ist das Problem da: Handle 2 ist nach dem Löschvorgang natürlich frei, kann also wenn es schlecht läuft direkt danach wieder befüllt werden, dummerweise mit einer Instanz B.
Wie geht es weiter?

4. Handle 2 ist nicht ungültig und wird als nächstes aufgerufen.


Ich hoffe das war alles weitestgehend verständlich. (Bin etwas müde.)
Bis zur nächsten Version wird ein Check auf die Instanz mit drin sein, damit dürfte man bunt rumlöschen können :)


Achja.. Sektenspinner hat mich letztens auf eine nette Funktion des Renderers aufmerksam gemacht. Es ist nun möglich zweidimensionale Bildchen dreh- und zoombar auf dem Bildschirm darzustellen, sogar mit frei einstellbaren UV-Koordinaten der zugewiesenen Textur. Wer will kann es sich bereits vom SVN runterziehen. Das Paket ist die "Sprite.d". :gratz
In den folgenden Tagen (Ich glaube ich sollte diese Phrase nicht all zu oft nutzen?) werde ich dazu zwei/drei Tutorials schreiben, die Möglichkeiten sind da ja beinahe endlos :)
(Kompass, Minimap, Sektenspinner hat ein Minispiel für das Schlösserknacken vorgeschlagen..)

MfG Gottfried

Lehona
11.04.2012, 18:12
Zu der Problematik mit ForEachHndl(): Es steht momentan im Raum (Von Sektenspinner angesprochen), mit Hashtabellen (http://de.wikipedia.org/wiki/Hashtabelle) zu arbeiten. Das würde dann a) Hlp_IsValidHandle() "sicher" machen, würde also besser funktionieren und b) dieses Problem mit ForEachHndl() beheben (Was sich aber eh auf Hlp_IsValidHandle() zurückführen lässt). Desweiteren hat new() dann eine Laufzeit von O(1), also konstant, wobei das auch ohne Hashtabelle möglich wäre.

waldhoppser
14.04.2012, 10:43
Moin Moin,
Wenn eine Funktion in die AI_Queue geschoben wird, ist dann innerhalb der Funktion "self" schon der Queuenbesitzer?
edit: Mir Idiot ist natürlich nicht eingefallen, das eben selbst auszuprobieren... §ugly
Die Antwort ist nein.

Lehona
14.04.2012, 13:38
Moin Moin,
Wenn eine Funktion in die AI_Queue geschoben wird, ist dann innerhalb der Funktion "self" schon der Queuenbesitzer?
edit: Mir Idiot ist natürlich nicht eingefallen, das eben selbst auszuprobieren... §ugly
Die Antwort ist nein.

Das ist allerdings keine dumme Frage. Self sollte über einen Register ansprechbar sein, ich such das eben raus.
Edit:
var oCNpc slf; slf = _^(ECX);
Das tut's :)

Roshi
14.04.2012, 15:56
Hello again, today I am not writhing to you to trouble you with some bugs I have found, but to ask for your permission to make a polish wiki about LeGo. The idea was mine and i have been thinking about it for a while now. Edeksumo offered his help so whole process shouldn't take long, but before we start we would like to know if you don't have any problem with that.

Lehona
14.04.2012, 16:11
Hello again, today I am not writhing to you to trouble you with some bugs I have found, but to ask for your permission to make a polish wiki about LeGo. The idea was mine and i have been thinking about it for a while now. Edeksumo offered his help so whole process shouldn't take long, but before we start we would like to know if you don't have any problem with that.

We obviously don't have a problem with that, but what about some kind of cooperation and hosting the wiki at http://gottfried.milgo.de/LeGo/pl/? So you just have to care about the wiki (it's done mostly in MediaWiki-Syntax), everything else will be taken care of :)

Do you have any sort of Instant Messenger where we can discuss things further?

Roshi
14.04.2012, 16:23
Here is my ICQ number 634401572, we can sort all of the things when we start talking, just when you will find some time to talk to me? I am not very often on ICQ so I would need to know that.

Dada
25.04.2012, 14:30
Ich habe mal eine Frage zu den Focusnames...
Wann werden die Farbzuordnungen geupdatet?

Folgende Situation: Der Held hat zu Spielbeginn die GIL_NONE. Im Laufe des Spiels erhält er nun die GIL_MIL. Theoretisch (laut Scripten) müssten jetzt ja alle Milizen freundlich sein, also grün angezeigt werden. Doch sie bleiben weiß.

Nun also meine Frage, zu welchem Zeitpunkt werden die Focusnames geupdatet?

Gottfried
25.04.2012, 18:42
Es wird jeden Frame aktualisiert.
Vermutlich aktualisiert Gothic die Gildenattitüden nicht zuverlässig. Wie genau weist du die Gilde denn zu?

MfG Gottfried

Dada
25.04.2012, 21:54
Mit

hero.guild = GIL_*

Probehalber habe ich auch mal probiert, weit weg zu gehen, mich zurückzuteleportieren, etc...

Bonne6
25.04.2012, 22:05
Versuch auch mal ein Npc_SetTrueGuild (hero, GIL_*);

Vielleicht liegt's ja nur daran.

Dada
26.04.2012, 11:32
Tatsache, funktioniert, ich sollte mich mal durch die Externals durchwühlen... :scared:

Danke :gratz

Teron Gorefiend
20.05.2012, 11:13
hört sich ja Prima an dieses LeGo, Die Schadensberechnung von Lehona klappt auf jeden Fall.

Mal eine frage habe gerade mal im wiki etwas nachgelesen
http://gottfried.milgo.de/LeGo/?Focusnames

wäre es irgendwie möglich auch Items/gegenstände eine Farbe zu geben?. Zum Beispiel Wolfsfell = grün, Schattenläuferfell = blau, schwarzes Treollfell = lila

Lehona
20.05.2012, 11:36
Schau dir mal die Datei Focusnames.d im LeGo-Ordner an. In der Funktion _Focusnames() gibt es einen Abschnitt, in dem Items behandelt werden. Du musst in der passenden If-Abfrage bloß die Variable 'col' auf den entsprechenden Farbwert setzen. Dazu baust du dir einfach deine Farbe mit der Funktion RGBA() zusammen (Steht für Rot/Grün/Blau/Alpha) wie in den Funktionen Focusnames_Color_Friendly() etc. auch. Desweiteren gibt es in der Userconst.d ein paar vorgefertigte Farben, wenn ein Item gelb sein soll, könntest du z.B. einfach 'col = COL_Yellow;' benutzen. Nicht vergessen, LeGo mindestens mit 'LeGo_Init(LeGo_Focusnames);' in der Init_Global() zu intialisieren.

Teron Gorefiend
26.05.2012, 13:58
hi also das klappte noch nicht so ganz bei mir.

Frage1) die items sind ja dann leider nur farbig wenn sie offen in der Welt rumliegen, aber nicht wenn sie im Inventar sind. Gibts da irgend eine Möglich die Schrift auch farbig zu machen wenn man sie im Inventar des Helden betrachtet?

Frage2)
Wie genau mache ich nochmal eine Abfrage für Gegenstände. Habs so gemacht


...
else if(Hlp_Is_oCItem(her.focus_vob))
{

var c_item itm;
itm = MEM_PtrToInst(her.focus_vob);

// Setze col = RGBA(.., .., .., ..); um die Farbe einzustellen
col = Focusnames_Color_common();

}

else ///Gegenstände
{


if (Hlp_GetInstanceID(ItAt_WolfFur) == Hlp_GetInstanceID(item))
{
col = Focusnames_Color_uncommon();
}
else ///normal
{
col = Focusnames_Color_common();
};



};///ende gegenstände
...

Nur sind alel Gegenstände Weiß
Weiß nicht wirklich wie die genaue Abfrage für Gegenstände ist. Wenn ich da scon frage fällt mir gleich ein, dass ich dies dann für meine Müllfunktion nutzen kann. wenn ein NPC stirbt wird diese ausgeführt und entfernt ALLE Waffen aus der Spielwelt.



instance clrItm(oCItem);

func void DeleteItems() {
PrintDebug("BOTK: MUELLMANN: Start");

var int activeVobList; activeVobList = MEM_World.activeVobList_array;
var int activeVobList_max; activeVobList_max = MEM_World.activeVobList_numInArray;

var int i; i = 0;
var int ptr;

var int pos;
pos = MEM_StackPos.position;
ptr = MEM_ReadInt(activeVobList+4*i);

MEM_AssignInst(clrItm, ptr);
if (clrItm.mainflag & ITEM_KAT_NF)||(clrItm.mainflag & ITEM_KAT_FF)/*||(clrItm.mainflag & ITEM_KAT_MUN)*/ {
if Hlp_IsValidItem(clrItm) {
Wld_RemoveItem(clrItm);
};
};

i += 1;
if(i < activeVobList_max) {
MEM_StackPos.position = pos; };

PrintDebug("BOTK: MUELLMANN: Finished");
};



Ich würde dies gerne einmal bei Spielstart ausführen und Sachen wie Schwarze Perlen, Trollfell und alle anderen seltenen Sachen aus der Spielwelt zu entfernen, aber wie frage ich das nochmal ab?

Gottfried
26.05.2012, 14:19
Frage1) die items sind ja dann leider nur farbig wenn sie offen in der Welt rumliegen, aber nicht wenn sie im Inventar sind. Gibts da irgend eine Möglich die Schrift auch farbig zu machen wenn man sie im Inventar des Helden betrachtet?Schwierige Sache. Man müsste einen Hook finden, der dort ansetzt wo der Text im Inventar eingestellt wird. Vielleicht schaue ich demnächst mal danach.


Frage2)
Wie genau mache ich nochmal eine Abfrage für Gegenstände.In deinem Fall prüfst du zuerst ob es ein Item ist (Hlp_Is_oCItem(her.focus_vob)), willst aber erst im nächsten Block (also wenn es kein Item ist) prüfen ob es ein Wolfsfell ist. Das kann so nicht funktionieren. (Eine ordentliche Einrückung hilft so etwas zu erkennen ;))
Außerdem vergleichst du das Wolfsfell mit der globalen Instanz 'item', die wird aber gar nicht befüllt. Du musst 'itm' verwenden, welchem du davor das Ziel des Helden zuweist.

Probiere es so:

[...]
else if(Hlp_Is_oCItem(her.focus_vob))
{
var c_item itm; itm = MEM_PtrToInst(her.focus_vob);
if (Hlp_GetInstanceID(ItAt_WolfFur) == Hlp_GetInstanceID(itm)) {
col = Focusnames_Color_uncommon();
}
else {
col = Focusnames_Color_common();
};
}
[...]


Ich würde dies gerne einmal bei Spielstart ausführen und Sachen wie Schwarze Perlen, Trollfell und alle anderen seltenen Sachen aus der Spielwelt zu entfernen, aber wie frage ich das nochmal ab?Diese Funktion wird so ohnehin nicht funktionieren, da sie nur in der activeVobList nachsieht. Dort sind nur Items enthalten auf die gerade die Physik wirkt.

Ich weiß gerade nicht aus dem Kopf wo alle Items gelagert werden. (MEM_World.voblist_item oder so ähnlich?)
Die müsstest du durchsuchen und die entsprechenden Items daraus entfernen.

MfG Gottfried

Teron Gorefiend
26.05.2012, 16:22
Schwierige Sache. Man müsste einen Hook finden, der dort ansetzt wo der Text im Inventar eingestellt wird. Vielleicht schaue ich demnächst mal danach.

Wäre super denn normalerweise sind fast alle Items ja im Inventar und mich hat das schon immer genervt, dass die alle weiß waren, Optimal wäre es wenn Name und Beschreibung andere Farben hätte aber nur der Name würde auch reichen. Damit würdest du mir einen riesen Gefallen tun.



Diese Funktion wird so ohnehin nicht funktionieren, da sie nur in der activeVobList nachsieht. Dort sind nur Items enthalten auf die gerade die Physik wirkt.

Ich weiß gerade nicht aus dem Kopf wo alle Items gelagert werden. (MEM_World.voblist_item oder so ähnlich?)
Die müsstest du durchsuchen und die entsprechenden Items daraus entfernen.

MfG Gottfried

Ähm konntest diesen Schritt evtl. nochmal genauer erklären.

Edit: Ich könnte das Problem auch anders lösen. Ich wandle einfach alle seltenen Sachen die es in der Welt gibt gegen Müll aus. Aus Schattenläufer oder Trollfell wird beschädigtes Fell. Und erstelle neue Iteminstanzen die es in der Welt nicht gibt. In der Give_DeathINV gebe ich den toten Monster dann einfach neue Beute und bei Bosper ändere ich bei Fellabgabe einfach den Instanznamen. Zwar ein bisschen Aufwand aber was solls.

Edit:
LeGo hört sich so toll an da muss ich einfach nochmal was fragen. Gibt es die Möglichkeit neue Itemsslots zu erstellen. In Gothic gibts ja nur Rüstung, 2 Ringe, Amulett, Nah und Fernkampfwaffe und in G2 noch Gürtel. So ein paar Sachen mehr wie Handschuhe, Schuhe etc. wären toll. Wäre sowas möglich bzw. gibt es dazu ein Tutorial ?

Lehona
26.05.2012, 16:30
Items vom Typ "ITEM_SHIELD" (oder so ähnlich) kann man in unbegrenzter Menge anlegen. Darauf aufbauend kannst du dir deine anderen Items bauen.

Die Itemsanzeige einzufärben ist eventuell nicht so simpel wie es scheint, kann mir gut vorstellen, dass eine Menge von anderem Text da auch mitgefärbt wird. Wird man ausprobieren müssen.

Lehona
27.05.2012, 18:51
Ups, war doch einfacher als gedacht :p


func void ColorItemName() {
var zCViewText txt; txt = _^(EAX);
var int col; col = -1;
var C_Item itm; itm = _^(MEM_ReadInt(ESP+324+4));




txt.color = col;
txt.colored = 1;
};

// Zum initialisieren einmalig pro Session folgendes aufrufen:

HookEngineF(7369071/*0x70716F*/, 6, ColorItemName);


Damit wird bloß der angezeigte Name gemäß 'col' eingefärbt :)
Die Beschreibung inzufärben wäre aus diversen Gründen ein wenig komplizierter (aber auch möglich). Wenn du es unbedingt brauchst, kann ich mir das vielleicht nochmal anschauen.

Teron Gorefiend
27.05.2012, 22:57
ähm ja ich kann mal wieder mit dem script nichts anfangen, wohin genau kommt ColorItemName()

einmalig pro Session folgendes aufrufen:
HookEngineF(7369071/*0x70716F*/, 6, ColorItemName);
heißt das, einmal beim Spielstart ausführen also z.b. in die Startup.d kopieren

bzw. wo müsste ich das jetzt einfügen das mein Wolfsfell grün ist


///fokusnamen

func int Focusnames_Color_Friendly()
{

return RGBA(0, 255, 0, 255); // Grün

};



func int Focusnames_Color_Neutral()
{

return RGBA(255, 255, 255, 255); // Weiß

};



func int Focusnames_Color_Angry()
{

return RGBA(255, 180, 0, 255); // Orange

};



func int Focusnames_Color_Hostile()
{

return RGBA(255, 0, 0, 255); // Rot

};




///items
func int Focusnames_Color_legendary() ///legendär orange
{

return RGBA(255, 127, 0, 255); // orange
};



func int Focusnames_Color_epic() ///lila
{

return RGBA(255, 0, 255, 255); // lila
};



func int Focusnames_Color_rar() ///blau
{

return RGBA(0, 0, 255, 255); // Grün

};



func int Focusnames_Color_uncommon() ///grün
{

return RGBA(0, 255, 0, 255); // Grün

};



func int Focusnames_Color_common() ///weiß
{

return RGBA(255, 255, 255, 255); // Weiß

};



func int Focusnames_Color_bad() ///grau
{

return RGBA(0, 255, 0, 255); // Grün

};




//========================================
// [intern] Färben der Namen
//========================================

func void _Focusnames()
{

var int itemid;
itemid = Hlp_GetInstanceID (item);



var int col;

var oCNpc her;
her = Hlp_GetNpc(hero);



if(Hlp_Is_oCNpc(her.focus_vob))
{

var c_npc oth;
oth = MEM_PtrToInst(her.focus_vob);

var int att;
att = Npc_GetPermAttitude(hero, oth);


if (att == ATT_FRIENDLY)
{
col = Focusnames_Color_Friendly();
}

else if(att == ATT_NEUTRAL)
{
col = Focusnames_Color_Neutral();
}

else if(att == ATT_ANGRY)
{
col = Focusnames_Color_Angry();
}

else if(att == ATT_HOSTILE)
{
col = Focusnames_Color_Hostile();
};



}

else if(Hlp_Is_oCItem(her.focus_vob))
{

var c_item itm;
itm = MEM_PtrToInst(her.focus_vob);

// Setze col = RGBA(.., .., .., ..); um die Farbe einzustellen
col = Focusnames_Color_common();


if (Hlp_GetInstanceID(ItMw_2h_legendary_firehammer) == Hlp_GetInstanceID(itm))
{
col = Focusnames_Color_legendary(); ///episch = lila
}



else if ((Hlp_GetInstanceID(ItAt_TrollBlackFur) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_FireGolemHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_IceGolemHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_DemonHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_DragonScale2) == Hlp_GetInstanceID(itm)))


{
col = Focusnames_Color_epic(); ///episch = lila
}


else if ((Hlp_GetInstanceID(ItAt_CrawlerMandibles) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_Sting) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_CrawlerPlate) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_ShadowFur) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_SharkSkin) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_TrollFur) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_WaranFiretongue) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_ShadowHorn) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_SharkTeeth) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_icewolfTeeth) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_TrollTooth) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_StoneGolemHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_SwampgolemHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_DragonBlood) == Hlp_GetInstanceID(itm)))

{
col = Focusnames_Color_rar(); ///blau = rar
}

else if ((Hlp_GetInstanceID(ItAt_WolfFur) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_Addon_BCKopf) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_Meatbugflesh) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_SheepFur) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_BugMandibles) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_Claw) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_LurkerClaw) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_Teeth) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_Wing) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(itat_LurkerSkin) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_WargFur) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_Addon_KeilerFur) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_DrgSnapperHorn) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_GoblinBone) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_UndeadDragonSoulStone) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_IcedragonHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_RockdragonHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_SwampdragonHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_FiredragonHeart) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_DragonScale) == Hlp_GetInstanceID(itm))
|| (Hlp_GetInstanceID(ItAt_SkeletonBone) == Hlp_GetInstanceID(itm)))
{
col = Focusnames_Color_uncommon(); ///grün
}
else
{
col = Focusnames_Color_common();
};


}

else ///Gegenstände
{

/*

var c_item itm; itm = MEM_PtrToInst(her.focus_vob);

if (Hlp_GetInstanceID(ItAt_WolfFur) == Hlp_GetInstanceID(itm))
{
col = Focusnames_Color_uncommon();
}
else {
col = Focusnames_Color_common();
};


*/

};

///ende gegenstände


var int ptr;
ptr = MEM_Alloc(4);

MEM_WriteInt(ptr, col);

CALL_IntParam(ptr);

CALL__thiscall(MEM_ReadInt(screen_offset), zCView__SetFontColor);
MEM_Free(ptr);



};

Lehona
28.05.2012, 14:02
Kurz was zur Terminologie: Eine Session meint (zumindest benutze ich es so) den Zeitraum, indem der selbe Prozess läuft. Wenn ich also Gothic2 starte (über den GothicStarter z.B.), fängt eine Session an. Wenn ich jetzt das Programm beende, indem ich auf "Gothic 2 beenden" im Menü drücke, ist die Session vorrüber.

Du musst also sicherstellen, dass die Zeile nur einmal pro Session aufgerufen wird. Mittlerweile führt ein Verletzen dieser Regel nicht mehr zum Crash sondern nurnoch dafür, dass die Funktion zweimal ausgeführt wird - sollte in diesem Fall "nur" zu einem Performanzkiller führen.

Das kannst du machen, indem du folgenden Code in der Init_Global() einfügst:


const int oncePerSession = 1;
if (oncePerSession) {
oncePerSession = 0;
/* Tu, was du einmal pro Session tun solltest */
};

Ansonsten zu deinem Code: Bitte, bitte gewöhne dir einen vernünftigen Stil an. Ich erwarte nicht, dass du meinen Stil kopierst, aber gewöhne dir an richtig einzurücken und nicht so viele unnötige Leerzeilen einzubauen. Es ist eine Graus, deinen Code zu lesen und er ist unnötig schwierig zu verstehen.

Außerdem musst du aufpassen: Dieser Teil des Codes wird sehr frequent (jeden Frame) aufgerufen. Es ist sinnvoll, ihn nicht zu performanzlastig zu schreiben. Es ist daher viel sinnvoller, den Typ des Items in einer ungenutzten Eigenschaft zu speichern, da würden sich C_Item.weight, C_Item.nutrition, C_Item.hp oder C_Item.hp_max anbieten, dieser Wert kann dann einfach im Konstruktor (Die Instanz) gesetzt werden.

Umfi
31.05.2012, 12:40
Hallo, ich hab ein kleines Problem.

Ich bin jetzt ein paar Tage dabei gesessen, damit es so funktioniert und aussieht wie ich es will, allerdings ist es momentan nur auf eine Auflösung optimiert und skaliert nicht ordentlich mit. Ich hab zwar zuvor immer getestet (Auflösung verändert -> hat immer gepasst; Aber kein Neues Spiel mit der neuen Auflösung gestartet und heut hab ich's mal gemacht und da hab ich bemerkt das garnichts mehr passt.)

Nun zu meiener Frage, wie kann ich das anpassen, das es für alle Auflösungen gleich ausschaut, bzw. sich mitskalliert?

Hier mal ein Ausschnitt:



Print_GetScreenSize();
SUR_BM_X = (Print_Screen[PS_X] / 2) - 256;
SUR_BM_Y = Print_Screen[PS_Y] / 4;

bm_v = View_Create(Print_ToVirtual(SUR_BM_X, PS_X), Print_ToVirtual(SUR_BM_Y, PS_Y), Print_ToVirtual(SUR_BM_X, PS_X) + Print_ToVirtual(512, PS_X), Print_ToVirtual(SUR_BM_Y, PS_Y) + Print_ToVirtual(512, PS_Y));
View_SetTexture(bm_v, "SURVIVAL_BAUMENU_MAIN.TGA");

//Buttons - Hauptmenü
Button_Building = Button_Create(Print_ToVirtual(SUR_BM_X + 39, PS_X), Print_ToVirtual(SUR_BM_Y + 132, PS_Y), Print_ToVirtual(148, PS_X), Print_ToVirtual(119, PS_Y), "SURVIVAL_BAUMENU_MAIN_SLOT_BUILDING.TGA", Button_Building_onEnter, Button_Building_onLeave, Button_Building_onClick);

//usw....



mfg Umfi

Lehona
31.05.2012, 12:52
Niemals gar nicht nie reale Pixel benutzen sondern (fast immer) virtuelle Koordinaten :)
Eine Beispiellösung gibt es wenn ich wieder an meinem Laptop bin und damit ins Forum kann :)

Umfi
01.06.2012, 13:10
Ich bin jetzt auf die virtuellen Pixel umgestiegen und jetzt scheint es zu passen. Allerding hab ich noch keine System gefunden un das genau zu positionieren, nur durch raten und probieren. Da gibt es doch bestimmt ein System dafür oder?

Milky-Way
01.06.2012, 13:25
Wenn ich jetzt nicht vollkommen danebenliege:
0,0 links oben - 8192,8192 unten rechts.
Werte dazwischen sind Positionen dazwischen,
4096,4096 wäre dann die Mitte.
Je nach Auflösung haben kleine Veränderungen natürlich keine Wirkung.
Die angegebenen Koordinaten sind z.B. dann der Anfangspunkt einer Textur. Zeigst du also eine Textur bei 4096,4096 an, so ist die linke obere Ecke der Textur in der Bildmitte. Gibt es eigentlich direkt mitgeliefert eine Funktion, die die Texturmitte auf die angegebenen Koordinaten setzt?
Gibt es eine Funktion, die die Größe einer Textur bestimmt?

War es das, was du wissen wolltest?

Lehona
01.06.2012, 14:04
Die Größe eines View stellt man ja selber ein. Aber es gibt View_CreateCenter() :)

Umfi
01.06.2012, 15:44
Ich dachte eher an sowas. Ich hab mal schnell eine kleine Grafik gemacht.

http://upload.worldofplayers.de/files8/EQErl2Unbenannt_1.jpg



Wie komm ich jetztzu den X/Y Koardinaten des blauen Rechteckes?
Bei der Pixelmethode ging das ja leicht.


Print_ToVirtual(linker oberer Punkt + abstand zu blauen rechteck, PS_X), Print_ToVirtual(linker oberer Punkt + abstand zu blauen rechteck, PS_Y), länge, breite, ...



Aber hier muss ich immer raten und lange anpassen bis ich die richtie Stelle habe.

Ich hoffe das ist so verständlich.

mfg

Milky-Way
01.06.2012, 15:59
Ich verstehe nicht ganz, was das Problem ist?

Wenn du weißt, dass es bei deiner Auflösung der 135. von 1024 Pixeln ist, dann musst du nur die Gleichung 135/1024 = x/8192 lösen, x ist dann deine virtuelle Koordinate (bzw. der erste Teil davon).

Oder wie bekommst du bei der alten Methode die Position heraus?

Umfi
01.06.2012, 16:10
So einfach... und ich stell da wieder ganz neue Theorien udn Formeln auf.

Naja jedenfalls danke, für den Denkanstoß. §wink

ukur
09.06.2012, 22:25
I make ​​a new status menu on the Gothic.dat scripts with use LeGo (buttons, cursor ... http://www.youtube.com/watch?v=6ptLoAgYsWg), which is now called instead of playing map from player_hotkey_screen_map ()
Is it possible to reassign the default key that opens the original status menu from menu.dat to my new status menu script from Gothic.dat?

Lehona
10.06.2012, 01:18
I make ​​a new status menu on the Gothic.dat scripts with use LeGo (buttons, cursor ... http://www.youtube.com/watch?v=6ptLoAgYsWg), which is now called instead of playing map from player_hotkey_screen_map ()
Is it possible to reassign the default key that opens the original status menu from menu.dat to my new status menu script from Gothic.dat?

First of all: I'm impressed by your work, this is exactly why we developed LeGo: to give Gothic2 a new touch :gratz

The easiest way to override the original status menu is probably to hook void __thiscall oCNpc::OpenScreen_Status(void) at address 73D982h and length 5. This will give you access to when the player opened the status screen. Then we don't want the original status screen to open, so we return from the function (there used to be an easy way for this but it never got released in LeGo because we thought it didn't work - even though it did). To accomplish this, we want to insert a return-statement and pop some integers from the stack. Looking at IDA we know that there will be 8 Byte on the local stack, so we want a retn 8 instruction, resulting in the following code:


MemoryProtectionOverride(7592327, 4);
MEM_WriteByte(7592327, 194);
MEM_WriteByte(7592328, 8);
MEM_WriteByte(7592329, 0);


This code has just been created on the fly, so it might not work - if you can't get it to work, I will investigate further in the next couple of days.



On a slightly unrelated note: Is there any way to see the scripts of your mod? I'm quite interested and amazed by what you have done :)

MyFreshP
10.06.2012, 23:11
On a slightly unrelated note: Is there any way to see the scripts of your mod? I'm quite interested and amazed by what you have done :)I think you're not the only one who is interested and amazed! That's really good work.

König Rhobar123
11.06.2012, 14:06
Hallo Lehona/Gottfried .


Seid der letzten Gothic II Neuinstallation funktioniert der Befehl LeGo_Init (LeGo_ALL); leider nicht mehr. Kurz nachdem ich auf den Button "Spiel Starten" klicke erscheint nur der klassische schwarze Bildschrim und ein CallStack (Access Violation) . Dabei sei erwähnt das ich Win 7 64 - Bit Nutzer bin (seid neustem) und daher keinen Plan habe was nun zu tun ist , da es vorher auf dem 32 - Bit System astrein lief (Scripte sind unverändert).


Bitte um Hilfe :o


Grüße ,

Rhobar

Milky-Way
11.06.2012, 14:14
Die GothicStarter_mod.exe musst du "Als Administrator ausführen...". Hast du das gemacht?

König Rhobar123
11.06.2012, 14:25
Habe ich , der Kompatiblitätsmodus (zb Windows XP) hat auch nichts gebracht .


Edit: Hier die Zusammenfassung von Zspy (http://upload.worldofplayers.de/files8/CallStack.d)

Gottfried
11.06.2012, 16:28
An LeGo liegt es nicht, sonst hättest du ein
LeGo 2.2.1 wird initialisiert.
in deinem zSpy Log.

Entweder liegt es an Ikarus (das wird noch vor dieser Ausgabe initialisiert) oder du hast ein anderes Problem.
Ich für meinen Teil benutze auch Windows 7 in der 64bit Version, hatte aber nie Probleme damit in Bezug auf Gothic.

Achja.. Lade doch das nächste mal den Text direkt als .txt hoch oder poste ihn mit
-Tags. (Opera will .d nicht anzeigen ;))

MfG Gottfried

Lehona
11.06.2012, 16:52
Du solltest überprüfen ob du die Report-Version installiert hast (auch wenn Ikarus da eigentlich meckern sollte), den zSpy-Level auf 10 stellen wenn er das noch nicht ist und überprüfen, dass die DEP Gothic nicht betrifft (sollte sie standardmäßig aber eh nicht). Wenn es dann noch nicht klappt, stelle bitte erneut den zSpy Log hier rein und hänge einen Screenshot der AV an, da dort einige Informationen drauf sind die nicht im zSpy landen.

König Rhobar123
11.06.2012, 17:17
Sry Gottfried ^^ Aufgrund dieser Tatsache (und weiteren) kommt mir Opera nicht aufs System :D


Hier die Access Violation. (http://s7.directupload.net/images/120611/unyta26t.png)

und hier die Zspy auf Stufe 10 (http://www62.zippyshare.com/v/37488505/file.html) (Report Fix und aktuellster Graka Treiber usw ist installiert)


Edit:

ich sollte noch erwähnen das es sich bei der Ikarus Version natürlich um die neuste Alpha Version handelt.

Gruß Rhobar

Edit Nr2:

Sobald LeGo_Init entfernt wird funktioniert es ._.

Lehona
11.06.2012, 22:30
Hast du die DEP kontrolliert?

Auf den Screens ist nichts zu erkennen. Interessant ist, dass Gothic nichtmal weiß, warum es gecrasht ist - weder einen Callstack noch wird die Art der Zugriffsverletzung erkannt. Im zSpy landet nichtmal die Meldung, dass LeGo jetzt initialisiert wird - komisch.

Sektenspinner
11.06.2012, 23:24
Geht denn
MEM_InitAll();
ohne LeGo_Init?

Falls Ikarus nicht läuft, schau mal ob ein Waypoint "TOT" existiert. Weiß grad nicht auswendig, ob es Probleme gibt, wenn der fehlt. Sonst gibt es eigentlich nichts was man bei der Benutzung von Ikarus falsch machen kann. Merkwürdig.

König Rhobar123
12.06.2012, 06:18
@ Sektenspinner:

Mit Ikarus gibt es keine Probleme und ich habe mittels einem Print("......"); überprüft ob MEM_InitAll(); aufgerufen wird. => Wurde es.


@ Lehona:

Ich weiß auch nicht warum Gothic II auf einmal meckert , schließlich sind es exakt dieselben Scripte wie auf der vorherigen 32 Bit Win 7 Installation. Mir fällt gerade noch ein das LilaLauneBär auch mal ein Problem hatte direkt nach dem Starten des Spiels mit LeGo . Eventuell bringt ja die Lösung die bei dieser Sache angewandt wurde Erfolg ?


Grüße Rhobar

ukur
12.06.2012, 12:01
On a slightly unrelated note: Is there any way to see the scripts of your mod? I'm quite interested and amazed by what you have done :)
Two days ago (10.06.12) I sent in PM, received?

Sektenspinner
12.06.2012, 19:48
Mit Ikarus gibt es keine Probleme und ich habe mittels einem Print("......"); überprüft ob MEM_InitAll(); aufgerufen wird. => Wurde es.Da ein paar Informationen (MEM_Info) nicht ausgegeben werden, die eigentlich in MEM_InitAll erscheinen sollten, vermute ich mal, dass du etwas anderes eingestellt hast (Ikarus_Const_G2.d) als:

const int zERR_ReportToZSpy = zERR_TYPE_INFO; //alles ab zERR_TYPE_INFO
und somit ein paar Infomeldungen unterdrückst.

Falls ich recht habe, ändere mal die Konstante und zeige nochmal deinen Spy-Log. Und nutze am besten
-Tags, das ist am einfachsten. Die Konstanten stehen bei mir auf
[code]const int zERR_ReportToZSpy = zERR_TYPE_INFO; //alles ab zERR_TYPE_INFO
const int zERR_ShowErrorBox = zERR_TYPE_FAULT; //Messageboxen nur für Errors
const int zERR_PrintStackTrace = zERR_TYPE_WARN; //Tracktrace printen für Warnings.

const int zERR_ErrorBoxOnlyForFirst = 1; /* nie mehr als eine Error-Box anzeigen */
const int zERR_StackTraceOnlyForFirst = 0; /* nur für den ersten Error Stack Trace anzeigen */

Wenn wirklich LeGo_Init das Problem ist, wäre der nächste logische Schritt herauszufinden an welchem LeGo Paket es liegt in dem du nach und nach weniger von LeGo initialisierst. Kannst ja mal mit LeGo_Init(0) anfangen und dann immer mehr flags dazunehmen, bis es schief geht.

Lehona
12.06.2012, 22:06
Ein wenig mehr Informationen wo genau es crasht wäre sehr angenehm. Ansonsten: LilaLauneBär hatte glaube ich eine "falsch" eingestellt DEP (Data Execution Prevention - Datenausführungsverhinderung), die unsere Arbeitsweise wohl nicht mochte :p Vielleicht war es aber wer anderes - hast du das denn nun überprüft?



Two days ago (10.06.12) I sent in PM, received?

I've got your PM, sorry that I didn't answer.

König Rhobar123
14.06.2012, 18:20
Sry das ich mich erst jetzt melde . Es lag wirklich an der DEP :mad:Problem ist also gelöst :)


Grüße Rhobar


Edit: Nur für den Fall das nochmal jemand das gleiche Problem hat , hier (http://www.winfaq.de/faq_html/Content/tip2000/onlinefaq.php?h=tip2323.htm) ist alles genaustens beschrieben.

Lehona
19.06.2012, 12:23
Ich habe ein Problem mit PrintScreen() behoben. Der Fehler führte dazu, dass nach einem Neuen Spiel oder einem geladenen Spielstand PrintScreen() nicht mehr reagierte.
Der SVN ist aktualisiert und hier ist der Fix für diejenigen, die nur die Releaseversion benutzen: http://pastebin.com/4v42FfmN
Einfach die LeGo überschreiben.

Teron Gorefiend
27.06.2012, 19:21
hallo mal eine frage ich wollte eine funktion einbauen, dass meine Pfeile mehr Schaden anrichten wenn ich sie länger spanne.

ist schon lange her deswegen habe ich es fast vergessen. Hat bei mir auch nicht so gut geklappt. Habe per Schleife einfach abgefragt ob der held eine gezückte Fernkampfwaffe hat und dann die anzahl der Munition abgefragt. Wenn die Anzahl noch gleich war hieß das, dass kein Pfeil abgefeuert wurde und der timer wurde erhöht. Klappte mehr oder weniger nur hatte das 2 Probleme a)lief der timer schon wenn man den Bogen raus hatte aber noch nichts eingespannt hatte und b) lief meine Schleife nur im Sekunden takt, hier würde ich schon gerne eine zehnerpotenz runtergehen (wenn das möglich wäre)

ukur´s video hat mich dazu wieder motiviert. Irgendjemand eine Idee?

Milky-Way
27.06.2012, 19:35
Ohne jetzt eine tolle Idee liefern zu können, kann ich dir zumindest sagen, dass du bei Triggern im Spacer auch kleinere FireDelays als 1 angeben kannst.

Sektenspinner
27.06.2012, 21:07
Und um rauszufinden ob der Spieler zielt würde ich mal folgendes probieren:


func int SpielerZielt() {
if (Npc_GetTarget(hero)) {
if (Npc_IsAiming(hero, other)) {
return true;
};
};
return false;
};Hab aber nicht ausprobiert, ob die Funktion wirklich das tut, was man erwartet.
Und die Funktion ist nutzlos, wenn das System auch dann funktionieren soll, wenn man ohne Fokus zielt und schießt.

ukur
28.06.2012, 01:46
Teron Gorefiend
Not all understand from your questions (in English it would be better, or Russian :) ), but here is slice of my script.

Previously, I used Trigger-Script, but then hung up on FF_Apply (B_GlobalLoop);


var int PC_AimingLost; \\ var for delay before target decrease
var int PC_AIM_PERCENT; \\ MAX 100% used for aimbar, and calculate damage in B_PC_AimingTarget

func void B_GlobalLoop()
{

\\\\\\\
\\\\\\\
if(Npc_IsInFightMode(hero,FMODE_FAR)) //Hero in far mode (draw bow)
{
if(Npc_GetTarget(hero)) //Hero has target (victim in focus)
{
if(Npc_IsAiming(hero,other)) //Hero is aiming (pulls bow)
{
PC_AimingLost = 100; //for loop frame per second ~ 60
B_PC_AimingTarget(TRUE); //Func for calculate...
else
{
PC_AimingLost -= 1; //Decrease delay every cycle if hero not aiming
if(PC_AimingLost < 1)
{
B_PC_AimingTarget(FALSE); //Func for calculate... FALSE - Reset
PC_AimingLost = FALSE;
};
};
B_InitFightSkills(hero); //Func for calculate...
}
else
{
PC_AIM_PERCENT = FALSE; //Reset aim
};
\\\\\\
\\\\\\
};

Teron Gorefiend
28.06.2012, 18:34
hi ukur, thaught you wont look again in this post so I used my language.

however something doesnt work. I can load the game without crashing. but one sec before the game starts the game crashes and i get this message

X: XD3D_Init_PerDX_ Cant Initialize with 32 bit depth buffer, trying 24bit...
i click on ok
X: XD3D_Init_PerDX_ Cant Initialize with 32 bit depth buffer, trying default
Q: Exception handler was involked. Ikarus tried to print a Daedlus-Stacktrace to zpy. Gothic will now crash
2* Application error.

The game worked before.
Ok I know the error. I used a very big bar and a very small max_value. I changed that and know it works perfectly thanks ukur.

Ok another question to the LeGo tean. Does LeGo works with g1? Today i tried G1 and it didnt work. Just made everything like G2 except other Ikarus scripts. Errors I didnt get when working with G2 (or already forgot that errors)
for example: U:PAR: Not a valid class or prototype name: cGamemanager (line 3736). After replaced ikarus.d with a newer version. ok sehe gerade das ikarus 1.2 nur für g2 funzt, das erklärt einiges.

FrancyTheKing
07.07.2012, 23:10
Hi there. I have some problems with this mod. First of all, I added the Ikarus files and the LeGo files in the Gothic.src:
_Intern\Ikarus_Const_G2.d
_Intern\EngineClasses_G2\Misc.d
_Intern\EngineClasses_G2\oCAiHuman.d
_Intern\EngineClasses_G2\oCGame.d
_Intern\EngineClasses_G2\oCInfoManager.d
_Intern\EngineClasses_G2\oCItem.d
_Intern\EngineClasses_G2\oCMob.d
_Intern\EngineClasses_G2\oCNpc.d
_Intern\EngineClasses_G2\oCZoneMusic.d
_Intern\EngineClasses_G2\zCCamera.d
_Intern\EngineClasses_G2\zCConsole.d
_Intern\EngineClasses_G2\zCConsole.d
_Intern\EngineClasses_G2\zCMenu.d
_Intern\EngineClasses_G2\zCOption.d
_Intern\EngineClasses_G2\zCParser.d
_Intern\EngineClasses_G2\zCSkyController.d
_Intern\EngineClasses_G2\zCTrigger.d
_Intern\EngineClasses_G2\zCWaynet.d
_Intern\EngineClasses_G2\zCWorld.d
_Intern\EngineClasses_G2\zCZoneZFog.d
_Intern\Ikarus.d
LeGo\Header.src

Then, I tried to compile the GOTHIC.DAT with Gothic Sourcer but it gives me a LOT of errors (115 of them).
What I have to do in order to fix the errors? Do you think that in GothicStarter it would work?

Lehona
08.07.2012, 00:03
The GothicSourcer is flawed and can't cope with Ikarus/LeGo. Use the GothicStarter.

FrancyTheKing
08.07.2012, 14:41
So, I've tried to compile with GothicStarter, but it gives me an error like this:
LeGo\Locals.d(90): Error: Undefined function: _@S

what the hell?

Gottfried
08.07.2012, 14:49
You will need the latest version of Ikarus. (1.2a (http://exodus.worldofgothic.com/team/Sektenspinner/Ikarus_1.2_alpha.zip))
And don't forget to install the float package too.

WfG Gottfried

FrancyTheKing
08.07.2012, 15:10
Where can I download that "Float package"?
New error: After downloading the newest Ikarus and LeGo, an another error appears:

LeGo\Timer.d(47): Error: Undefined function: MKF

Lehona
08.07.2012, 15:15
Copy the script from this topic: http://forum.worldofplayers.de/forum/threads/500080-Instrumentarium-Floats
The error will vanish when you use that script :)

FrancyTheKing
08.07.2012, 15:36
Thank you all. It works. :D

Lehona
20.07.2012, 14:22
LeGo 2.2.2 (https://subversion.assembla.com/svn/lego2/Release/LeGo_2_2_2.7z) HookEngine Der Register edi wird jetzt gemäß der Variable EDI aktualisiert



Dieses Update soll bloß die Benutzung der eigenen Schadensberechnung (http://forum.worldofplayers.de/forum/threads/1149697-Script-Eigene-Schadensberechnung) vereinfachen.

Bonne6
27.07.2012, 18:12
Hat die Beschränkung auf 256 Buttons irgendeinen Sinn oder kann ich da beliebig dran rumschrauben?

Gottfried
27.07.2012, 18:17
"Wer mehr Buttons hat, hat doch 'nen Rad ab :) Kann aber auch gerne erweitert werden."
Um es mit den behutsamen Worten Lehonas auszudrücken. (So steht es zumindest im Code als Kommentar ;))

Die Beschränkung existiert nur weil Lehona zu faul war da ne dynamische Collection zu nutzen schätze ich :p

MfG Gottfried

Bonne6
27.07.2012, 21:02
Ok, steht ja in der Zeile drunter :D

Muss die Anzahl hochsetzen, weil ich für die EW-Maussteuerung auch eine 2D-Map einbaue und die Magierfelder da Buttons werden, damit ich's leichter hab.

Lehona
27.07.2012, 22:02
Dann hast du offiziell ein Rad ab :A
Nein, Konstanten sind dazu da, um verändert zu werden. Zumindest manchmal :p
Ich kann das aber auch umbauen, der Code der Buttons ist noch von vor ForEachHndl().

Bonne6
27.07.2012, 23:00
Weil ich jetzt eben erstmal die Kommentarfunktion soweit fertig eingebaut hab, ist mir aufgefallen, dass beim automatischen Zeilenumbruch beim View mit dem Seperator die neue Zeile zu hoch angefangen wird, die zwei Zeilen sich also überlagern, sieht nicht so gut aus :(

Als Font hab ich übrigens Font_ScreenSmall genommen ;)

Lehona
28.07.2012, 00:13
Das sollte nicht passieren. Es kann sein, dass du die Funktion mit einem falschen Parameter aufgerufen hast (Ich kann dir das aber nicht 100% garantieren, vielleicht habe ich auch tatsächlich einen Fehler gemacht, der mir beim Testen nicht aufgefallen ist) - würdest du mir deinen Code zeigen? Entweder hier oder per ICQ :)

Bonne6
28.07.2012, 09:31
Klick (https://github.com/Bonne6/Elemental-War/blob/develop/_work/data/Scripts/Content/FUNKTIONEN/Specialfunc.d) (Zeile 1149 geht's los), der Text selbst gesetzt wird in Zeile 1183. CommentTextEingabe ist einfach eine Zeichenkette und alle 50 Zeichen kommt ein ~ für den Zeilenumbruch.

Lehona
28.07.2012, 13:49
In der View.d in Zeile 228 gab es einen Fehler in der Berechnung der Höhe (Es war v.pposy+v.psizey anstatt nur v.psizey). Das ist mir beim Testen nicht aufgefallen, weil das unter bestimmten Bedingungen (View sehr nahe am oberen Bildschirmrand) nahezu keine Auswirkung auf das Ergebnis hat und sich im Bereich von einigen wenigen realen Pixel aufhält. Im nächsten Release wird das behoben sein.

Lehona
30.08.2012, 21:35
Ich habe das PermMem-Tutorial mal ein wenig aktualisiert - und zwar mit ForEachHndl() (http://gottfried.milgo.de/LeGo/de/?PermMem#foreachHndl).

Da vor kurzem jemand nach einer Möglichkeit zum Respawn gefragt hat und ich fanatisch LeGo angepriesen habe, dache ich mir, dass das ein geeignetes praktisches Beispiel sei, um den Umgeang mit PermMem ein wenig näher zu beleuchten. Aber Vorsicht, es folgt ein ziemlich langer Post. Wer also PermMem beherrscht oder einfach nicht so viel lesen will, sollte wohl gar nicht erst anfangen...

Als erstes müssen wir uns ein klares Ziel definieren bzw. aufschreiben, in unserem Fall das Respawn System:
"Unser System soll jedes Monster, das bestimmte Bedingungen erfüllt, nach einer bestimmten Zeit respawnen. Die Respawn-Zeit ist linear abhängig vom Level des Monsters und wird täglich (bzw. nächtlich in der SleepABit.d) geprüft."
Das hätten wir also. Da wir verzögert respawnen (Alles andere wäre für den Spieler ja eh frustrierend) müssen wir uns die relevanten Informationen merken. Daher sollten wir uns genau ansehen, was wir brauchen:


Monster Typ oder Instanz (Wir wollen ja keinen Ork an Stelle eines Wolfes spawnen)
Waypoint um zu wissen, wo der Respawn vollzogen werden soll
Zeitpunkt, an dem der Respawn erfolgen soll


Der Übersicht halber nochmal in Daedalus formuliert:

class RespawnObject {
var int inst; //Die Monsterinstanz
var string wp; //Der Wegpunkt
var int respawnDay; // Der Tag des Respawns, wobei der erste Tag den Wert 0 hat... Genau wie Gothic.
};
Ich habe unserer Informationsstruktur (Im folgenden "Klasse"... Wer noch gar nichts über Klassen weiß, sollte sich mal in der Ikarus-Dokumentation umsehen) einfach mal den Namen RespawnObject gegeben, Englisch ist schließlich hip.

In einem Objekt (einer Instanz) dieser Klasse können wir also alle nötigen Daten speichern.

Wenn jetzt ein Monster stirbt (und es unsere Bedingungen, z.B. kein Mensch, erfüllt), wollen wir ein Objekt erzeugen und es mit den entsprechenden Informationen füllen.

Wenn man sich jetzt fragt, warum es dazu PermMem braucht, ist die Frage völlig gerechtfertigt.
Ikarus bietet die Möglichkeit, Speicher zu allozieren und auch, den Speicher (bzw. einen Zeiger auf den Speicher) einer Instanz zuzuweisen. Aber (Und das ist ein großes Aber) Ikarus garantiert keinen sicheren Speicher, er ist bloß einen Frame sicher gültig. Anders formuliert: Wenn der Spieler lädt oder ähnliche Aktionen durchführt, führt das sehr oft dazu, dass der Speicher nicht mehr da steht, wo er soll (oder sogar ganz weg ist).
Genau das übernimmt aber PermMem: Es merkt sich den Speicherblock und "zwingt" den User im Gegenzug eine eindeutige Zahl ("Handle" genannt) zu benutzen, die PM immer einem Zeiger zuordnen kann. Wenn gespeichert wird, schreibt PM den Inhalt all dieser Speicherblöcke nach bestimmten Regeln (s. weiter unten oder in den Beispielen (http://lego.origo.ethz.ch/wiki/beispiele_permmem)) in eine eigene Speicherdatei; beim Laden wird diese Datei ausgelesen, interpretiert und die Daten werden wieder in den Speicher geschrieben.
Des Weiteren kann PM noch ein paar andere tolle Sachen, z.B. werden Objekte an Hand einer Instanz-Funktion initialisiert, Instanz-Funktionen meint sowas:

instance myNpc(C_NPC) {
Print("Ich bin eine Instanz-Funktion!");
};
Später erlaubt das, die Objekte nicht nur auf Grund ihrer Klasse zu unterscheiden sondern auch an Hand der Instanz, mit der sie erzeugt wurden, somit kann man sie unterschiedlich löschen oder speichern.

Wie auch immer, zurück zu unserem Problem: Das Respawn-System.
An geeigneter Stelle sollten wir so ein Objekt erzeugen - wir brauchen uns nichteinmal eine Referenz merken, weil wir alle wichtigen Objekte ja an ihrer Ursprungsinstanz identifizieren können (Wird später noch klar). Ab jetzt geht das Scripten wirklich los:
Wir erzeugen als erstes ein Respawn-Objekt mit dem Befehl new(). Aber was erwartet new() für Parameter? Ein Blick ins Wiki (http://lego.origo.ethz.ch/wiki/permmem#new) hilft:

int new(instance inst)
Gut, new() will also eine Instanz... Aber wir haben ja gar keine Instanz? Unser Code sieht ja bisher so aus:

class RespawnObject {
var int inst; //Die Monsterinstanz
var string wp; //Der Wegpunkt
var int respawnDay; // Der Tag des Respawns, wobei der erste Tag den Wert 0 hat... Genau wie Gothic.
};

New() möchte eine Instanz als Parameter, da damit das Objekt initialisiert wird (werden kann). Eigentlich wird einfach die Instanz-Funktion (s.o.) ausgeführt. Da wir die Instanz-Funktion nicht allzu sinnvoll parametrisieren können, nehmen wir einfach eine leere:

instance RespawnObject@(RespawnObject);
// oder
instance RespawnObject@(RespawnObject){};




func void AddToRespawnArray(var c_npc slf) {
var int hndl; hndl = new(RespawnObject@);};


Nun, das ist noch nicht vollständig und das könnt ihr euch vermutlich denken. Wir müssen noch die Informationen in unser Objekt schreiben. Dafür brauchen wir die Funktionen get() (http://lego.origo.ethz.ch/wiki/permmem#get) oder getPtr() (http://lego.origo.ethz.ch/wiki/permmem#getPtr). Es ist einfacher, direkt ein Objekt zu nutzen anstatt erst den Zeiger in ein Objekt zu verwandeln, daher werden wir get() benutzen. Wir definieren also eine Variable des Typs RespawnObject, das geht wie mit Integern und Strings:

var RespawnObject myRespawnObject;
Dieser Variable weisen wir dann einfach unser Handle zu (korrekt: get(hndl);) und können ohne Probleme die Informationen in das Objekt schreiben. Also:


func void AddToRespawnArray(var c_npc slf) {
var int hndl; hndl = new(RespawnObject@);
var RespawnObject myRespawnObject; myRespawnObject = get(hndl);
myRespawnObject.inst = Hlp_GetInstanceID(slf);
myRespawnObject.wp = slf.spawnPoint;
myRespawnObject.respawnDay = Wld_GetDay() + (slf.level/10)+2; // Irgendeine Formel
};

Und das war es eigentlich auch schon, damit sind alle wichtigen Informationen verstaut. Jetzt müssen wir die Funktion nur noch an einem sinnvollen Ort aufrufen - und was eignet sich da besser als die ZS_Dead()? Richtig, nichts.

Es ist eigentlich völlig egal, wo wir unsere Funktion in der ZS_Dead() aufrufen, aber der Übersicht halber machen wir es ganz am Anfang. Da wir nicht alle Monster wiederbeleben wollen, packen wir das Ganze auch noch in eine Abfrage:


func int MeetsRespawnCondition(var c_npc slf) {
return (slf.guild > GIL_SEPERATOR_HUM); // Überprüft bisher bloß, ob 'slf' nicht menschlich ist
};


func void ZS_Dead ()
{
if (MeetsRespawnCondition(self)) {
AddToRespawnArray(self);
};
[...]
};

Die Abfrage ist noch nicht so toll und euch fallen bestimmt noch andere wichtige Sachen rein, aber ich will ja bloß ein Konzept vorstellen.

Okay... Ein kleiner Rückblick: Wir haben uns die wichtigen Informationen erfolgreich gemerkt... Und mehr nicht. 'Ne ganze Menge Arbeit für so eine kleine Aufgabe, nicht?
Wenn wir zurück schauen, sehen wir aber: Das waren eigentlich bloß ein paar Zeilen, kaum eine zweistellige Anzahl. Sobald man PM verstanden habt (Und ich bin mir sicher das werdet ihr nach diesem Tutorial), kann man das sehr schnell tippen. Machen wir uns aber nun an den eigentlichen Teil unseres Systems: Das Respawnen. Um einen geeigneten Zeitpunkt zum Auslösen des Respawns kümmern wir uns später. Wir wollen jetzt also eine Funktion, die testet, ob der aktuelle Tag größer gleich dem "Respawn-Tag" ist und gegebenfalls das Monster in die Welt einfügen, das ist auch gar nicht so schwierig, der Code erklärt sich, mitsamt Kommentaren, eigentlich von selbst:


func void CheckRespawns() {
ForEachHndl(RespawnObject@, _CheckRespawns);/* Dieser Part bedarf vielleicht einer kurzen Erklärung:
Mit ForEachHndl() führe ich eine angegebene Funktion (2. Parameter) für alle Objekte/Handles
einer angegebenen Ursprungsinstanz (1. Parameter) aus. So kann ich ganz einfach
alle RespawnObjects überprüfen :) */
};


func int _CheckRespawns(var int hndl) { // In diesem Parameter steht, für welches Handle die Funktion gerade ausgeführt wird
var RespawnObject myRespawnObject; myRespawnObject = get(hndl);
//Jetzt haben wir unser Objekt!

if (myRespawnObject.respawnDay <= Wld_GetDay()) { // Der Tag des Respawns ist gekommen! \o/
Wld_InsertNpc(myRespawnObject.inst, myRespawnObject.wp); // Daher fügen wir einfach den NPC an seinem WP ein :)
// Allerdings müssen wir nun unser Objekt auch entfernen, sonst würde es ja beim nächsten Mal wieder eingefügt!
// Ich werde daher einfach mal die Funktion RemoveRespawnObject() aufrufen - wie die aussehen muss, schauen wir später.
RemoveRespawnObject(hndl);
return rContinue; // Wir wollen schließlich weiterhin alle Handles durchlaufen - bis wir alle haben
};
So weit, so gut, das war nicht so kompliziert, jetzt müssen wir uns aber um die RemoveRespawnObject() kümmern. Die ist aber eigentlich ganz simpel: Wir müssen bloß unser RespawnObject löschen (Und damit den Speicher wieder freigeben), darum kümmert sich PM aber fast ganz von alleine:


func void RemoveRespawnObject(var int hndl) {
delete(hndl); // Alles weitere macht PM dann selber. Unter anderem wird versucht, Respawn_Object_Delete() aufzurufen
};
Wir hätten auch direkt bloß delete(hndl) aufrufen können, das macht keinen Unterschied.

Das rufen wir jetzt noch in der PC_Sleep() (Datei: Scripts\Content\Story\Dialog_Mobsis\SleepABit.d) auf, optimalerweise nachdem die Zeit geändert wurde:



func void PC_Sleep (var int t)
{
AI_StopProcessInfos(self); // [SK] ->muss hier stehen um das update zu gewährleisten

PLAYER_MOBSI_PRODUCTION = MOBSI_NONE;
self.aivar[AIV_INVINCIBLE]=FALSE;
if (Wld_IsTime(00,00,t,00))
{
Wld_SetTime (t,00);
}
else
{
t = t + 24;
Wld_SetTime (t,00);
};

CheckRespawns();

[...]
};

Der Kern unseres Systems ist damit geschaffen und wir näherns uns (rapide!) dem Ende, eigentlich möchte ich bloß noch eine (in diesem Fall unnötige) Sache aufzeigen:
Klassen in Gothic haben leider nicht genug Informationen, um sie (immer) vernünftig speichern zu können, Zeiger unterscheiden sich z.B. nicht von normalen Ganzzahlwerten. Daher bietet LeGo sog. structs an. Das ist dem eigentlichen Begriff aus anderen Programmiersprachen ein wenig entfremdet, in unserem Fall ist das bloß ein String, der den Aufbau der Klasse beschreibt. Dabei wird einfach Stück für Stück der "Typ" einer Objekt-Eigenschaft angegeben, wobei einfache Werte (Func, float, int, string) einfach als 'auto' (für 'automatisch') referenziert werden. Man kann auch eine Anzahl angeben, wenn mehrere Eigenschaften des selben Typs aufeinander folgen. In unserem Fall sähe das so aus:

const string RespawnObject_Struct = "auto|3";
// oder
const string RespawnObject_Struct = "auto auto auto";
Hätten wir in unserer RespawnObject-Klasse am Ende noch einen Zeiger auf ein weiteres Respawn-Object, sähe das so aus:

const string RespawnObject_Struct = "auto|3 RespawnObject*";
Der Sternchen-Operator zeigt, wie aus anderen Programmiersprachen gewohnt, einen Zeiger an.

Es ist auch möglich, die Speicherregeln komplett von Hand vorzugeben, aber das werde ich in diesem Tutorial nicht behandeln und sollte aus der Dokumentation im Wiki auch ersichtlich werden.


Und damit sind wir endlich am Ende angekommen! Was dem ein oder anderen wie ein Haufen Arbeit erscheint haben mag, war letztendlich ganz wenig - ca. 75 Zeilen, wobei davon einige Leerzeilen oder Kommentare waren.


Abschließende Worte: Ich habe nicht großartig gegengelesen, wenn also jemand noch Fehler findet (Syntaxfehler in Script oder auch Sprache), behebe ich das gerne. Semantisch sollte das im Groben und Ganzen eigentlich korrekt sein, ich gebe allerdings zu, es nichtmal durch den Parser gejagt zu haben. Wenn es nicht funktioniert, seht es einfach als zusätzliche Aufgabe, es zu beheben ;)

Bisasam
24.12.2012, 21:04
ich hab wahrscheinlich eine dumme frage zu AI-function:

ich möchte, dass items erst der reihe nach übergeben werden (beispiel: npc sagt "Hallo", dann "Hier ist deine Waffe" und DANN erst soll geprintet werden, dass man ne waffe gekriegt hat!) und dachte, dazu könnte man AI-function wohl benutzen. aber ich weiß nicht, welche ich für B_GiveInvItems am besten nehme. kann mir da jemand weiterhelfen?

OldCoin
24.12.2012, 21:21
Warum machst du es nicht einfach über

CreateInvItems und B_GiveInvItems?

Also:

Hier ist deine Waffe

CreateInvItems (self,Waffe, 1);
B_GiveInvItems (self, other, Waffe, 1);

Und hier deine Kekse

CreateInvItems (self,Kekse, 1);
B_GiveInvItems (self, other, Kekse_L, 1);

Bisasam
24.12.2012, 21:42
das problem ist, dass prints immer am dialoganfang kommen und das ist unästhetisch, wenn man viele items kriegt.

geht hierdrum (http://forum.worldofplayers.de/forum/threads/1046839-H-Die-Herausforderung?p=17085888&viewfull=1#post17085888), da grenze ich ja auch ab, was man wann kriegt und es ist vor allem bei M unschön

OldCoin
24.12.2012, 22:00
das problem ist, dass prints immer am dialoganfang kommen und das ist unästhetisch, wenn man viele items kriegt.

Bin mir gerade nicht wirklich sicher. Aber ich meine mich zu erinnern, dass wird nach der jeweiligen Übergabe geprintet.


hierdrum (http://forum.worldofplayers.de/forum/threads/1046839-H-Die-Herausforderung?p=17085888&viewfull=1#post17085888)

Der Link ist etwas blöd für diejenigen, die keinen Zugang zu unserem Internen haben. :p Den bitte wieder entfernen.

Bisasam
24.12.2012, 22:10
Bin mir gerade nicht wirklich sicher. Aber ich meine mich zu erinnern, dass wird nach der jeweiligen Übergabe geprintet.



Der Link ist etwas blöd für diejenigen, die keinen Zugang zu unserem Internen haben. :p Den bitte wieder entfernen.

nein, ich habe es ja getestet, dachte nämlich auch, das kommt nicht direkt. liegt in erster linie daran, dass B_GiveInvItems sich nicht in die AI-Queue einreiht und deshalb sofort kommt. will das aber einreihen

der war in erster linie für dich gedacht

Der Ahnungslose
24.12.2012, 22:44
Schon mal nach den LeGo AI_Functions geschaut?

Edit: Damit lassen sich verzögert Funktionen aufrufen. Sollte machbar sein, was du damit vorhast, hab kurz drüber geschaut.

Gottfried
25.12.2012, 18:42
Du redest von Gothic II nehme ich an, da hat OldCoin schon recht - der Print kommt verzögert. B_GiveInvItems wird freilich direkt aufgerufen wenn der Dialog startet, intern wird aber nicht PrintScreen benutzt sondern AI_PrintScreen, welches sich in die letzte AI-Queue einreiht.

Wenn du trotzdem aus irgendeinem Grund die AI_Functions benutzen möchtest wirst du dir eine abgekapselte Funktion schreiben müssen. AI_Functions unterstützen maximal zwei Parameter, B_GiveInvItems erwartet aber vier.

MfG Gottfried

Frank-95
26.12.2012, 10:03
Excuse me a question.

How is that possible that lego is using while cycles if deadalus don't support them?

Sektenspinner
26.12.2012, 15:54
Excuse me a question.

How is that possible that lego is using while cycles if deadalus don't support them?Ikarus supports them.

Note that
while(1 < 6);
is a valid function call in Daedalus if there is a function defined as:

func void while(var int condition);
Also, a single variable name is a valid statement, i.e, you can write:

var int end;
end;
therefore end; is a valid (but arguably pointless) statement.

The function while is now defined in Daedalus to restructure the Bytecode at the position where it was called from, changing the call to while to a conditional jump to the end of the loop and the end; to a unconditional jump back before the start of the loop.

This was the furthest I could go with Daedalus Syntax. It would have been preferable to have proper while sytax (while(condition) { }), but the parser cannot process this.

Bisasam
07.01.2013, 23:43
AI_Function_II hat mein gothic frontal abstürzen lassen.

verwendung:


AI_Function_II (other, Npc_SetTalentSkill, NPC_TALENT_ACROBAT, 1);

im dialog. parsfehlermeldung gabs keine, ist erst bei dialogstart abgestürzt

Sektenspinner
08.01.2013, 02:01
AI_Function_II hat mein gothic frontal abstürzen lassen.

verwendung:


AI_Function_II (other, Npc_SetTalentSkill, NPC_TALENT_ACROBAT, 1);

im dialog. parsfehlermeldung gabs keine, ist erst bei dialogstart abgestürzt
Du vergisst den ersten Parameter von Npc_SetTalentSkill.
AI_Function_II ist für Funktionen die zwei Integer Parameter nehmen. Definiere eine Hilfsfunktion die selbst keine Parameter nimmt und tut was du willst und nutze diese in AI_Function.

Bisasam
09.01.2013, 17:41
funktioniert auch nicht so recht.

oben definiert:


func void springen ()
{
Npc_SetTalentSkill (other, Npc_Talent_Acrobat, 1);
};

Aufgerufen so:


AI_Function (other, springen);


gleiches ergebnis

Lehona
09.01.2013, 17:42
Fehlermeldungen sind auch weiterhin hilfreich, die sind ja nicht umsonst da.

Bisasam
09.01.2013, 18:03
gibt nur nen access-violation den ich nicht ganz ins fenster kriege:

http://upload.worldofplayers.de/files8/ac_ida.png

die aussagekraft ist mmn eher gering, hab versucht, irgendwie zu skrollen, aber geht nicht.

Lehona
09.01.2013, 18:24
Was aussagekräftig oder nicht ist, überlass mal ruhig mir. Ich vermute, dass da irgendein Symbolindex als Zeiger interpretiert wird. Merkwürdig, aber ich schau's mir mal an.
Gibt's keinen Callstack von Ikarus?

Lehona
09.01.2013, 18:49
Ich kann den Fehler nicht reproduzieren, aber benutz mal bitte 'hero' anstatt 'other' (v.a. in Springen())... Ansonsten bin ich erstmal verwirrt, bei mir funktioniert's.

Bisasam
09.01.2013, 19:28
fehlende initialisierung wars. nicht zu fassen... muss es in der startup vergessen haben.

problem jetzt: hero springt herum, aber lernt akrobatik nicht obwohl es so drin steht.

hast du es so übernommen und bei dir getestet oder wie hast du das gemacht?
ich habs in ne AI_PlayAni-Reihe eingefädelt. erst zweimal jumpen, dann einmal mit akrobatik. klappt nicht so recht.
das steht konkret hinter einem AI_TurnToNpc (hero, self); innerhalb eines dialoges

Lehona
09.01.2013, 19:40
Wenn du die normale Springanimation ausführst, wirst du das doch auch tun, wenn der Held Akrobatik beherrscht? Lass ihn doch einfach die Akrobatik-Animation ausführen?

Und ich habe dem Helden beim Testen Akrobatik beigebracht, das ist also nicht das Problem.

Bisasam
09.01.2013, 19:46
die springanimation ändert sich, aber der name bleibt gleich. ich hab nen anderen npc der akrobatik beherrscht und der in einem dia mit genau demselben befehl einen akrobatikssprung ausführt statt des normalen. mein hero springt immer normal.

edit: hab mal ne printmeldung in die aufzurufende funktion gesetzt: sie wird nicht aufgerufen

König Rhobar123
09.01.2013, 19:51
Ich hatte mal ein ähnliches Problem da in nem Dialog die AI-Queue von dem Hero durcheinander war. Komischer Weise konnte ich das Problem damals mit ner AI_Function lösen. Eventuell hilfts dir ja auch ...



var C_Npc LearnAcrobatics;
var int GetAcrobaticStatus;

func void LearnAcrobatics ()
{
if (GetAcrobaticStatus >= 1)
{
Mdl_ApplyOverlayMds (LearnAcrobatics, "Humans_Acrobatic.mds");
}
else
{
Mdl_RemoveOverlayMDS (LearnAcrobatics, "Humans_Acrobatic.mds")
};
};


func void AI_LearnAcrobatics (var C_NPC slf , var int Nr)
{
LearnAcrobatics = Hlp_GetNpc(slf);
AI_Function(slf , LearnAcrobatics);
GetAcrobaticStatus = Nr;
};



Oder aber eine einfache Npc_ClearAiQueue würde reichen mit anschließendem Akrobatik beibringen.

Lehona
09.01.2013, 21:00
Dann zeig doch einfach mal den kompletten Dialog und nicht immer nur kleine Fragmente...

Bisasam
09.01.2013, 21:25
endlich geht das inet auf meinem haupt-pc wieder...



// ************************************************************
// springen
// ************************************************************

func void springenlernen_test ()
{
//Npc_SetTalentSkill (hero, NPC_TALENT_ACROBAT, 1);

Mdl_ApplyOverlayMds (hero, "HUMANS_ACROBATIC.mds");
print ("jetzt!");
};


Instance DIA_Raika_springen (C_INFO)
{
npc = AMZ_4422_Raika;
nr = 1;
condition = DIA_Raika_springen_Condition;
information = DIA_Raika_springen_Info;
description = "Springdialog testen";
};

Func int DIA_Raika_springen_Condition()
{
return TRUE;
};

Func void DIA_Raika_springen_Info()
{
AI_PlayAni (other, "T_STAND_2_JUMP");
AI_TurnToNpc (other, self);
AI_PlayAni (other, "T_STAND_2_JUMP");
AI_TurnToNpc (other, self);
AI_Function (hero, springenlernen_test);
AI_PlayAni (other, "T_STAND_2_JUMP");
AI_TurnToNpc (other, self);
};

ist ein testdialog

Lehona
09.01.2013, 21:32
Ich habe deinen Code jetzt genau so kopiert und bei mir funktioniert es bestens. Der Fehler scheint irgendwo anders zu sein. Funktionen AI_Functions unter anderen Bedingungen?

Bisasam
09.01.2013, 21:40
inwiefern "andere bedingungen"?

edit: achja ich initialisiere lego in einem dialog vorher mit lego_init (Lego_All); (o.ä. gedächtniszitat, ist als beispiel in der lego.d aufgeführt oben) und kriege eine fehlermeldung von wegen invalid adress (print ingame, zu kurz, um komplett gelesen zu werden)

Lehona
09.01.2013, 21:41
inwiefern "andere bedingungen"?

Umständen, Zeitpunkten, was auch immer. Wenn du sie (wo) anders benutzt.

Edit: Gut, dass du die Fehlermeldung so liberal ignoriert hast, die war nur da, um Leute zu ärgen.
Sorry, dass ich ein *wenig* genervt klinge, aber erwartet doch nicht, dass alles vernünftig funktionieren (muss), wenn es Fehlermeldungen gibt...

Milky-Way
09.01.2013, 21:47
inwiefern "andere bedingungen"?

edit: achja ich initialisiere lego in einem dialog vorher mit lego_init (Lego_All); (o.ä. gedächtniszitat, ist als beispiel in der lego.d aufgeführt oben) und kriege eine fehlermeldung von wegen invalid adress (print ingame, zu kurz, um komplett gelesen zu werden)

Ja wenn es gar nicht richtig initialisiert wird...

Wieso nimmst du nicht die Init_Global?

Ikarus initialisierst du?

Bisasam
10.01.2013, 12:18
meine init_global:


func void INIT_GLOBAL()
{
// wird fuer jede Welt aufgerufen (vor INIT_<LevelName>)
Game_InitGerman();
MEM_InitAll ();
LeGo_Init (LeGo_All);
};

keine fehlermeldung mehr als ingameprint aufgerufen wird meine funktion aber trotzdem irgendwie noch nicht. abstürze keine

Frank-95
10.01.2013, 14:28
Since I installed LeGo everytime I save the game there's a quite fastidous bug:


saves_/savegame5/scrptsave.sav/Datei Konnte nicht erstellt werden. Fehlercode3

I hope I reported it well in german :)

The game minimizes, yields this error, load a bit, and then re-opens again. I initialiazed only bars, focusnames and AI_Function

Lehona
10.01.2013, 15:03
@Assasine91: Dann kann ich dir so auch nicht direkt weiterhelfen. Sollte sich das Problem nicht plötzlich von alleine lösen (wovon ich nicht ausgehe), melde dich am besten bei mir direkt per IM (In ICQ solltest du mich als Kontakt noch haben, ansonsten empfehle ich mein WoP-Profil), dann kann ich mit dir passenden Debug-Code entwickeln.


Since I installed LeGo everytime I save the game there's a quite fastidous bug:

I hope I reported it well in german :)

The game minimizes, yields this error, load a bit, and then re-opens again. I initialiazed only bars, focusnames and AI_Function

Why the bug occurs (if you just want to fix it, skip this):

LeGo's inner core is mostly based upon PermMem, which allows us to allocate memory that is persistent even when the player restarts the game (ie has saved/loaded the savegame). To achieve this we obviously need to save the information (memory) somewhere and we chose an additional save-file similar to the ones Gothic is already using (ie same folder, same extension). However, since it's quite likely to have 2 mods installed at once that both use LeGo, we don't only have to track the save-number (ie which slot it is in) but also the mod so we can put the file in the correct folder. How that is derived is irrelevant, but Gothic uses the .ini as an indicator (strips the extension and that's it basically).

How I think the error you have is occuring:
You play with the GothicGame.ini, ie you have not created your own .ini-file for testing purposes (which is fine in itself). However, this means LeGo will try to save the file in the wrong folder (\saves_\ instead of \saves\), because we derive the folder by concatenating the string "saves_" with the mod name, whereas Gothic has a special case concerning the non-modded game, using only "saves" as the folder name.

How to fix it: Name your .ini something else and use that (internally the Gothic2.exe has to be started with the parameter -game:name.ini, but the GothicStarter does that on its own).

Frank-95
10.01.2013, 16:27
Ahh, okay thanks for explanation.

In fact I was testing my mod with lego without using gothic starter.. Thanks!

edit: I didn't test, but can I load saves during the which that error occured normally and without no more errors?

Lehona
10.01.2013, 16:45
Ahh, okay thanks for explanation.

In fact I was testing my mod with lego without using gothic starter.. Thanks!

edit: I didn't test, but can I load saves during the which that error occured normally and without no more errors?

Yes, but that could technically cause some issues with LeGo (because there is no save-file). However, there is no way to fix this because there never was a save-file created.

Milky-Way
10.01.2013, 17:33
I guess that is something you could fix fairly easily within LeGo? (checking whether a mod-ini is used, ...)

Lehona
10.01.2013, 17:42
I guess that is something you could fix fairly easily within LeGo? (checking whether a mod-ini is used, ...)

Yeah sure, just an exception if the modname is "" (empty string). I will put it up on the SVN, but technically that should never happen anyway, because it works if you use the GothicStarter (even with the standard .ini) :)

Frank-95
11.01.2013, 13:00
Yes but I think that anyone should have the possibility to choose whether choosing to start it normally or via gothicstarter

Lehona
11.01.2013, 13:31
Yes but I think that anyone should have the possibility to choose whether choosing to start it normally or via gothicstarter

Well you can start it normally, but you need to call the Gothic2.exe with certain parametes (-game:name.ini that is), which is a must if you want to play a mod anyway, so as long as you play mods and/or use the GothicStarter, you're safe.


However, I have implemented an exception, so use the Saves.d on the SVN if you want to use it (not really tested though, but it was half a line :D), otherwise just add "-game:GothicGame.ini" to your starting parameters of your shortcut to the Gothic2.exe, which will trigger the exception already in place.

Bonne6
03.02.2013, 11:44
Ich hab mal wieder ein kleines Problem, bei dem ich Hilfestellung brauche.

Und zwar ist es so, dass die Kampfsteuerung in GoMoN jetzt nahezu komplett auf die Maus umgebaut wurde und dann eben mit den LeGo-Buttons funktioniert. Alles soweit kein Problem, klappt wunderbar. Wenn ich aber einen Spielstand lade, dann reagieren die Buttons erst nach einer ganzen Weile, je nach Spieldauer offenbar immer länger. Hab mal nachgeschaut, dabei kam raus, dass die Buttons_Do-Funktion nicht gleich gestartet wird.

Woran kann das denn liegen und wie beheb ich das? Ist halt unpraktisch, wenn man nach dem Laden eines Spielstandes dann erst fünf Minuten warten muss, bis man kämpfen kann ;)

BiesterKiller
03.02.2013, 12:52
Ich hab mal wieder ein kleines Problem, bei dem ich Hilfestellung brauche.

Und zwar ist es so, dass die Kampfsteuerung in GoMoN jetzt nahezu komplett auf die Maus umgebaut wurde und dann eben mit den LeGo-Buttons funktioniert. Alles soweit kein Problem, klappt wunderbar. Wenn ich aber einen Spielstand lade, dann reagieren die Buttons erst nach einer ganzen Weile, je nach Spieldauer offenbar immer länger. Hab mal nachgeschaut, dabei kam raus, dass die Buttons_Do-Funktion nicht gleich gestartet wird.

Woran kann das denn liegen und wie beheb ich das? Ist halt unpraktisch, wenn man nach dem Laden eines Spielstandes dann erst fünf Minuten warten muss, bis man kämpfen kann ;)

Das hört sich so an wie das Problem, das ich mit den Triggern hatte. Vielleicht hilft dir ja die geänderte LeGo.d am Ende. http://forum.worldofplayers.de/forum/threads/1228353-Problem-mit-FF_ApplyOnceExt?p=20527332&viewfull=1#post20527332

Bonne6
03.02.2013, 14:14
Scheint auf den ersten Blick zu funktionieren, danke :)

Oparilames
10.03.2013, 22:17
Grüßt euch.

Ich habe gerade mal versucht LeGo mit Gothic zu starten, aber beim Initialisieren stürzt er ab.

Vorgenommene Änderungen:

Userconst.d


//========================================
// Names
//========================================
// !G1 Bereich
//const int AIV_Name = 89; // Genutzte AI-Var
const int AIV_Name = 42+1;// Erste ungenutzte AI-Var

Trialoge.d

func void EquipWeapon (var C_NPC slf, var int ItemInst) {

if (!Npc_HasItems (slf, ItemInst)) {
CreateInvItems (slf, ItemInst, 1);
};

if (!Npc_GetInvItem(slf, ItemInst)) {
MEM_AssertFail("Unexpected behaviour in EquipWeapon.");
return;
};

if ((item.mainflag == ITEM_KAT_NF) && (Npc_HasReadiedMeleeWeapon(slf)))
|| ((item.mainflag == ITEM_KAT_FF) && (Npc_HasReadiedRangedWeapon(slf))) {
MEM_Warn ("EquipWeapon: Caller wants to equip a weapon while weapon of the same type is readied. Ignoring request.");
return;
};
// !G1 var
//if (item.flags & ITEM_ACTIVE)
if (item.flags)
&& (!EquipWeapon_TogglesEquip) {
/* calling EquipWeapon would unequip the weapon. */
MEM_Info ("EquipWeapon: This weapon is already equipped. Ignoring request.");
return;
};

CALL_PtrParam(MEM_InstToPtr(item));
CALL__thiscall(MEM_InstToPtr(slf), oCNpc__EquipWeapon);
};

Names.d

/***********************************\
NAMES
\***********************************/

//========================================
// Namen setzen
//========================================
func void SetName(var int npc, var string nname) {
var oCNpc slf; slf = Hlp_GetNpc(npc);
if(slf.aiscriptvars[AIV_Name]) {
slf.name = nname;
};
slf.name1 = nname;
};

//========================================
// Namen anzeigen
//========================================
func void ShowName(var int npc) {
var oCNpc slf; slf = Hlp_GetNpc(npc);
slf.aiscriptvars[AIV_Name] = 1;
// !G1 Var
//slf.name = slf.name1;
// replacement for G1
slf.name = slf.name1;
};
Bloodsplats.d


func void _B_HeroDamage() {
var int currDam; currDam = Hero_LastHP - hero.attribute[ATR_Hitpoints];
if(currDam) {
Bloodsplat(currDam);
// !G1 Func
//Wld_StopEffect("HERO_HURT");
Wld_PlayEffect("HERO_HURT", hero, hero, 0, 0, 0, 0);
};
};
View.d


func void zCView_Archiver(var zCView this) {
PM_SaveInt("_vtbl", this._vtbl);
PM_SaveInt("_zCInputCallBack_vtbl", this._zCInputCallBack_vtbl);

// !G1 Var
//PM_SaveInt("m_bFillZ", this.m_bFillZ);
PM_SaveInt("next", this.next);
// ...
};
// ...

func void zCView_Unarchiver(var zCView this) {
var int vx1; vx1 = PM_Load("vposx");
var int vy1; vy1 = PM_Load("vposy");
var int vx2; vx2 = vx1 + PM_Load("vsizex");
var int vy2; vy2 = vy1 + PM_Load("vsizey");

_View_Create(MEM_InstToPtr(this), vx1, vy1, vx2, vy2);

this._vtbl = PM_LoadInt("_vtbl");
this._zCInputCallBack_vtbl = PM_LoadInt("_zCInputCallBack_vtbl");

// !G1 Var
//this.m_bFillZ = PM_LoadInt("m_bFillZ");
// this.next = PM_LoadInt("next"); // Darf ich nicht überschreiben, habs der Übersicht halber aber hier gelassen
// ...

Ich vermute es liegt am letztgenannter Änderung.
Startup.d


FUNC VOID INIT_MODWORLD ()
{
B_InitMonsterAttitudes ();
B_InitGuildAttitudes();
MEM_InitAll();
LeGo_Init(LeGo_All);
FF_ApplyOnceExt(EnforceSavingPolicy,1,-1); // jede Sekunde, unendlich oft
FF_ApplyOnceExt(MOD_CheckSaving_Print, 30,-1);
};

Die Bild der Fehlermeldung:
http://upload.worldofplayers.de/files9/Error.png

Lässt sich da etwas machen?

Lehona
10.03.2013, 22:41
a) Ändere bitte nicht die internen LeGo-Dateien ohne zu wissen, was genau du da tust :p
b) LeGo funktioniert nicht mit Gothic 1. Um LeGo mit Gothic 1 funktionsfähig zu machen wirst du ohne mind. rudimentäre Kenntnisse von Disassemblern (z.B. IDA) bzw. Maschinensprache nicht herumkommen.


Ich würde vorschlagen, einfach G2 zu verwenden ;)

Und bzgl. der Fehlermeldung: Es wird eine Funktion aufgerufen, deren Adresse aus der Gothic2.exe entstammt. Die Funktion liegt in Gothic 1 vermutlich an einer anderen Adresse.

Oparilames
10.03.2013, 22:51
Ok danke Lehona dann muss ich warten, bis ich meine dNdR-CD wiederbekomme. (Eigentlich war Samstag abgemacht ...)

Lehona
10.03.2013, 22:54
Ok danke Lehona dann muss ich warten, bis ich meine dNdR-CD wiederbekomme. (Eigentlich war Samstag abgemacht ...)

Übrigens noch eine Sache: Wie auch hier (http://gottfried.milgo.de/LeGo/de/?FrameFunctions#FF_ApplyExt) nachzulesen, werden bei den FrameFunctions Milisekunden als Parameter angegeben, nicht Sekunden. Wenn ein Delay dauerhaft/auf längere Sicht kleiner ist als die Dauer eines Frames kann es ebenfalls zu Abstürzen kommen (endlose Rekursion).

Oparilames
24.03.2013, 11:46
Grüßt euch. Ich habe mit den FrameFunctions ein Problem.
Ich versuche bereits seit Tagen einen alten, ziemlichen Spaghetti-Code zu entwirren. Er regelte das Intro zu RatotS und lief über Triggerscript-Events. (Genauergesagt ein riesiges)

Nun bin ich an einer Stelle wo ich mich wirklich frage, ob ich bei den FFs irgendetwas nicht verstanden habe.
In einem Auswahldialog wählt man den Schwierigkeitsgrad (mache ich evtl. noch über ein Menü, mal sehen.)



// Nachdem der Monolog beendet ist, soll das Intro beginnen.
FUNC VOID PC_MOD_IntroMonolog_End_Info()
{
PrintS("PC_MOD_IntroMonolog_End_Info"); // wird nicht angezeigt
B_ENDMONODIALOG (); // äquivalent zu B_ENDMOBSIDIALOG
if (MOD_In_DialogOption_Number==MOD_IntroGucken)
|| (MOD_In_DialogOption_Number==MOD_IntroSpielen)
{
Print("Gothic"); // Wird aufgerufen
MOD_INTRO_Act1();
//Wld_SendTrigger ("MOD_INTRO_TRIGGER"); // alter Aufruf
//AI_Function(PC_HERO,MOD_INTRO_Act1); // Funktioniert nicht
//FF_ApplyOnceExt(MOD_INTRO_Act1,150,-1); // Geht ebensowenig
};
};

Dann das eigentliche Intro:


func void MOD_INTRO_Act1()
{
CreateInvItems(PC_HERO, Itmi_Gold,10);
if (MOD_INTRO_ORKS_GESPAWNT == 0)
{
MOD_INTRO_ORKS_GESPAWNT += 1;
Wld_SendTrigger ("MOD_INTRO_CAMERA1");// wird ausgeführt, aber ab hier wird alles ignoriert
AI_PlayAni (INTRO_ORK, "T_PERCEPTION");
Npc_ExchangeRoutine (INTRO_Ork, "Start");
AI_ContinueRoutine (INTRO_Ork);
AI_GotoWP (INTRO_ORK2, "MOD_INTRO_ORKS_STEHEN_VOR_HUETTE_2");

//2 Sekunden warten
FF_ApplyOnceExt(MOD_INTRO_Act1,200,-1);
}else
if (MOD_INTRO_ORKS_GESPAWNT == 1)
&& (Npc_GetDistToWp (INTRO_ORK, "MOD_INTRO_ORKS_STEHEN_VOR_HUETTE") <= 550)
&& C_BodyStateContains(INTRO_ORK,BS_STAND)
{
MOD_INTRO_ORKS_GESPAWNT += 1;
AI_PlayAni (INTRO_ORK, "R_ROAM2");
AI_PlayAni (INTRO_ORK, "T_WARN");

//3 Sekunden warten
FF_ApplyOnceExt(MOD_INTRO_Act1,300,1);
} else
if(MOD_INTRO_ORKS_GESPAWNT == 2)
{
MOD_INTRO_ORKS_GESPAWNT += 1;
Wld_SendTrigger ("MOD_INTRO_CAMERA2"); //MOD: Fahrt zum Stuhl
AI_PlayAni (INTRO_Ork2, "T_DIALOGGESTURE_02");
AI_Output (BAU_000_Ehefrau,BAU_000_Ehefrau,"SVM_17_WhatWasThat"); //Was war das?!
Wld_SendTrigger ("MOD_INTRO_TRIGGER_FUER_PHASE1_VON_ERSTEM_GESCHOSS");
Npc_ExchangeRoutine (INTRO_Ork2, "Start");
AI_ContinueRoutine (INTRO_Ork2);

//1 Sekunde warten
FF_ApplyOnceExt(MOD_INTRO_Act1,75,1);
} else
// und so weiter

//FFs mit einer -1-Dauer dürfen nicht entfernt werden!
if (MOD_INTRO_ORKS_GESPAWNT!=1)
//&& (!Npc_IsInState(PC_HERO,ZS_Talk))
{
FF_Remove(MOD_INTRO_Act1);
};

Edit:-->
HookEngine-Befehle werden zu diesem Zeitpunkt bereits akzeptiert.

Der Startup-Ausschnitt:

// *********
// GLOBAL
// *********

func void STARTUP_GLOBAL()
{
// wird fuer jede Welt aufgerufen (vor STARTUP_<LevelName>)
Game_InitGerman();
};

func void INIT_GLOBAL()
{
// wird fuer jede Welt aufgerufen (vor INIT_<LevelName>)
Game_InitGerman();
LeGo_Init(LeGo_All);
if(HooksPlaced==0) //Gothic ist neu gestartet worden
{
HooksPlaced = 1;
};
};

// *********
// MOD Welt
// *********

FUNC VOID INIT_MOD_STARTGEBIET ()
{
HookEngine(oCNpc__SetAsPlayer, 6, "MOD_AfterStartup");
Set_MainSubtitleCondition(false,false);
Wld_SetTime (19,47);
};

FUNC VOID STARTUP_MODWORLD()
{
// ------ StartUps der Unter-Parts ------
STARTUP_NewWorld_Part_City_01();
Wld_InsertNpc (INTRO_ORK, "MOD_INTRO_ORKS_TAUCHEN_AUF");
Wld_InsertNpc (INTRO_ORK2, "MOD_INTRO_ORKS_TAUCHEN_AUF_2");
Wld_InsertNpc (BAU_000_EHEFRAU, "NW_TROLLAREA_TROLLLAKECAVE_03A"); //Irgendwohin, ist ja egal wohin.
};

FUNC VOID INIT_MODWORLD()
{
B_InitMonsterAttitudes ();
B_InitGuildAttitudes();
B_InitNpcGlobals ();

B_ENTER_NEWWORLD ();

// ------ INITS der Unter-Parts ------
INIT_SUB_NewWorld_Part_City_01();
INIT_MOD_STARTGEBIET();
};


const int MOD_OldStartMethod=true; // statt Menü ein Monolog
func void MOD_AfterStartup()
{
if(MOD_StartupHook>=1)
{
return;
};
MOD_StartupHook=1;
MEM_SendToSpy(zERR_TYPE_WARN, "MOD_AfterStartup()");
if(MOD_OldStartMethod)
{
PC_Hero.aivar[AIV_INVINCIBLE]=TRUE;
PLAYER_MOBSI_PRODUCTION = MOBSI_MOD_IntroMonolog;
Ai_ProcessInfos (PC_Hero);
}; //Anderer Fall noch nicht implementiert
//UnHookEngine möglich? Anscheinend nicht /:
//HookEngine(oCNpc__SetAsPlayer, 6, "");
};

Gottfried
26.03.2013, 18:15
Ich kann deinem Script nicht so ganz folgen. Wozu überhaupt dieser Hook? Du könntest einmalig eine FF benutzen um den Monolog in Gang zu bringen, das sollte reichen.

Was mir noch spontan auffällt ist dass du beim ersten If in MOD_INTRO_Act1

//2 Sekunden warten
FF_ApplyOnceExt(MOD_INTRO_Act1,200,-1);Stehen hast. Die -1 könnte das ganze etwas durcheinander bringen.

Ich an deiner Stelle würde das alles in separate Funktionen packen, so kannst du den ganzen Prozess wesentlich besser verfolgen.

Achja.. Und das sind Milisekunden die du angeben musst. Zwei Sekunden == 2000ms.

MfG Gottfried

Umfi
26.03.2013, 18:52
Ich hätte da einen Fehler zu verkünden, laut meinem Teamkollegen gibt es ein Problem, wenn ein Trialogteilnehmer ein "Geist" (NPC_FLAG_GHOST) ist. Dann werden die Trialogteilnehmer abwechselnd zum Geist. Ansich sollte das kein großes Problem sein, das zu beheben oder?

Gottfried
28.03.2013, 13:18
Ansich sollte das kein großes Problem sein, das zu beheben oder?Jain. Ich kann bei Gelegenheit einmal einen Blick darauf werfen, kann aber nicht garantieren dass ich das beheben kann.
Npc_Flag_Ghost ist eine etwas kritische Angelegenheit wenn ich das richtig in Erinnerung habe.

MfG Gottfried

Oparilames
28.03.2013, 19:51
@Gottfried die ganze Kamerafahrten und Moveraktionen, werden erst nach
dem Monolog gestartet.

Der Hook soll eine Triggerschleife ersetzen, die damals das Intro ingame
ablaufen ließ. Jedes Event musste zeitlich abgepasst und erst dann abgefeuert
werden, damit z.B. ein Stein eine Seitenwand eines Hauses einreißen konnte.

Das mit den einzelnen Funktionen könnte ich mal versuchen.
Bei dem ms-Fehler habe ich ausprobieren wollen, ob man 200 Millisekunden
ausreichen. Ich habe in der TriggerScript-Version mittels RefuseTalk
die Zeit eingegrenzt und das ging damals nur Sekundengenau.

Gottfried
28.03.2013, 20:13
Der Hook soll eine Triggerschleife ersetzen, die damals das Intro ingame
ablaufen ließ. Jedes Event musste zeitlich abgepasst und erst dann abgefeuert
werden, damit z.B. ein Stein eine Seitenwand eines Hauses einreißen konnte.Warum benutzt du dann keine FF dafür die nur einmalig feuert? Du kannst bereits in der Startup einer Map eine FF eintragen, das sollte keine Probleme machen.

Hooken würde ich immer nur dann wenn es sich wirklich nicht vermeiden lässt - in dem Fall gehts einfacher ohne.

MfG Gottfried

Oparilames
28.03.2013, 20:30
Hmm das ließe sich machen. Aber ich frage mich dennoch, weshalb
MOD_INTRO_Act1 abbricht. Liegt das am internen Aufbau der FFs?
Andererseits könnte man auch eine Klasse für FFs schreiben mit
einer Pause/Wait-Funktion. (Also damit meine ich nicht euch,
soetwas ist denke ich schnell erledigt)

Gottfried
28.03.2013, 20:50
Ich denke das Problem dürfte hierbei liegen:

FF_Remove(MOD_INTRO_Act1);

Da du gleichzeitig FF_ApplyOnce benutzt. FF_ApplyOnce legt fest dass die gegebene Funktion nur einmalig in der FF-Liste stehen darf.

Bei der ersten Abfrage setzt du MOD_INTRO_Act1 mit -1 (= unendlich) Wiederholungen ein - jeder weitere Aufruf an FF_ApplyOnce wird nun abgebrochen weil die Funktion bereits in der Liste steht und noch läuft. Wenn darauf dann FF_Remove aufgerufen wird wird die Funktion vollständig getötet.

Verstehst du die Problematik?

MfG Gottfried

König Rhobar123
01.04.2013, 18:45
Hi,

ich hab da ein kleines Problem mit den Trialogen. Offenbar werden beim Wechsel des Gesprächspartners die Flags von self gespeichert. Npc 1 ist in meinem Dialog ein Geist mit dem Flag NPC_FLAG_GHOST , wenn ich nun mit Npc 2 reden möchte bekommt er auch den ghost Flag.

Gottfried
01.04.2013, 19:27
Hi,

ich hab da ein kleines Problem mit den Trialogen. Offenbar werden beim Wechsel des Gesprächspartners die Flags von self gespeichert. Npc 1 ist in meinem Dialog ein Geist mit dem Flag NPC_FLAG_GHOST , wenn ich nun mit Npc 2 reden möchte bekommt er auch den ghost Flag.Schau mal zwei, drei Posts weiter nach oben und sieh dir meine Antwort dazu an ;)

MfG Gottfried

König Rhobar123
01.04.2013, 20:32
Hatte ich übersehn , sry. @Post: Das heißt nun soviel wie "Ist nicht möglich" oder aber Zeit und Lust fehlt dazu :D ?

Lehona
01.04.2013, 20:57
Hatte ich übersehn , sry. @Post: Das heißt nun soviel wie "Ist nicht möglich" oder aber Zeit und Lust fehlt dazu :D ?

Ich habe mich vor einiger Zeit mal ganz kurz mit dem Flag auseinandergesetzt (Ich wollte einfach NPCs halbtransparent rendern lassen), aber die Engine ist da ein wenig... merkwürdig, vielleicht waren meine Tests aber auch fehlerhaft. Auf jedenfall hat das Flag selber afaik keine Auswirkung, das ist wohl bloß während der Erzeugung relevant, dementsprechend müssen wir dafür eine Sonderbehandlung einführen. Prinzipiell nicht kompliziert, wenn man weiß, was genau durch das Flag geändert wird... Weiß aber keiner (von uns) :p

Sektenspinner
01.04.2013, 22:33
Um das Ghost-Flag zu übernehmen genügt es npc.visualAlpha und npc.visualAlphaEnabled zu setzen. Der Wert für npc.visualAlpha steht in der ini unter INTERNAL.GhostAlpha.

Teleport zu sich selbst tuts auch (beim Helden: AI_Teleport(hero, "PC_HERO");), aber das ist vielleicht nicht seiteneffektfrei für eure Anwendung.

Ich schätze mal ihr werden wohl zusätzlich zum Visual einfach noch die beiden Alpha Attribute mit swappen wollen.

König Rhobar123
01.04.2013, 23:12
Um das Ghost-Flag zu übernehmen genügt es npc.visualAlpha und npc.visualAlphaEnabled zu setzen.


Da bin ich irritiert. Wie & Wo nutze ich das denn jetzt um meinem Npc nicht den Ghost flag geben zu müssen?



Gar nicht, die Antwort war an Gottfried und mich gerichtet

:o


erstmal

Hoffentlich ^^

Lehona
01.04.2013, 23:18
Da bin ich irritiert. Wie & Wo nutze ich das denn jetzt um meinem Npc nicht den Ghost flag geben zu müssen?

Gar nicht, die Antwort war an Gottfried und mich gerichtet :) Für dich gibt es erstmal keine direkte Lösung.

Sektenspinner
05.04.2013, 13:11
Ich lade das mal hier ab, für Interessierte.
Nach Aufruf von PreventArrowTriggerCollision können Pfeile nicht mehr mit zCTrigger und zCTriggerScript Objekten kollidieren die respondToObject auf FALSE gesetzt haben.

Das erlaubt es Triggerzonen aufzustellen die auf Berührung reagieren, die Spieler und Npcs beim Bogenschießen aber nicht behindern (die Pfeile rattern da gerne mal lautstark zu Boden).

Zonen die auf Pfeile reagieren sind weiterhin möglich (Tempelschalter), bei diesen muss respondToObject auf TRUE gelassen werden.


//##############################################################
// Call this in INIT_GLOBAL after LeGo_Init.
//##############################################################

func void PreventArrowTriggerCollision() {
const int done = false;
if(!done) {
//6A1490: virtual int __thiscall oCAIArrow::CanThisCollideWith(class zCVob *)
HookEngineF(6952080, 7, CanThisCollideHook);

done = true;
};
};
//##############################################################
// The Handler
//##############################################################
func void CanThisCollideHook() {
var int vtbl; vtbl = MEM_ReadInt(MEM_ReadInt(ESP + 4));

const int zCTrigger_vtbl = 8627196;
const int zCTriggerScript_vtbl = 8582148;

if(vtbl != zCTrigger_vtbl)
&&(vtbl != zCTriggerScript_vtbl) {
//It is no Trigger
return;
};

var int arg_0; arg_0 = ESP + 4;
var zCTrigger trigger; trigger = _^(MEM_ReadInt(arg_0));

if(trigger.bitfield & zCTrigger_bitfield_respondToObject) {
//It is supposed to collide with arrows
return;
};

//I think this should not collide.
//The Engine inself excludes the shooter, so lets make it look like
//the arrow collides with the shooter

// vob = this.owner
MEM_WriteInt(arg_0, MEM_ReadInt(ECX + 92));
};

Lehona
05.04.2013, 13:14
D.h. wenn ein Trigger ohne RespondToObject potentiell mit einem Pfeil kollidiert, gibst du der Engine einfach vor dass momentan auf Pfeil kollidiert mit dem Schützen geprüft wird?

Sektenspinner
05.04.2013, 13:22
D.h. wenn ein Trigger ohne RespondToObject potentiell mit einem Pfeil kollidiert, gibst du der Engine einfach vor dass momentan auf Pfeil kollidiert mit dem Schützen geprüft wird?Exakt. Habe auf die schnell keine bessere Möglichkeit gesehen die Funktion false zurückgeben zu lassen.

Das ganze müsste auch sicher sein, denn der Schütze existiert immer (wenn nicht stürzt die Funktion auch ohne mein Eingreifen bereits ab).

In Returning scheint das Problem recht oft aufzutreten, mal schauen ob sich jetzt einer erbarmt, den Code nutzt und die respondToObject flags setzt.

Lehona
05.04.2013, 13:25
Exakt. Habe auf die schnell keine bessere Möglichkeit gesehen die Funktion false zurückgeben zu lassen.

Das ganze müsste auch sicher sein, denn der Schütze existiert immer (wenn nicht stürzt die Funktion auch ohne mein Eingreifen bereits ab).

Performanter wäre wohl einfach eine Manipulation des Bytecodes, aber ich denke nicht, dass die Funktion so viel Rechenleistung kostet. Andererseits weiß ich auch nicht, wie oft sie aufgerufen wird.

Sektenspinner
05.04.2013, 13:33
Performanter wäre wohl einfach eine Manipulation des Bytecodes, aber ich denke nicht, dass die Funktion so viel Rechenleistung kostet. Andererseits weiß ich auch nicht, wie oft sie aufgerufen wird.Das dürfte pro Frame und Pfeil und mit dem Pfeil kollidierenden unerwünschtem Ziel nicht mehr als ein Aufruf sein.
Unerwünschte Ziele sind zum einen Triggerzonen zum anderen (nur bei Npc-geschossenen Pfeilen) nicht-Target Npcs (ein Bandit schießt durch den anderen durch).
Diese unerwünschten Zeile dürften also hinreichend selten sein, wenn man nicht gerade 20 Triggerzonen aufeinanderstapelt oder in engen Korridoren mit Banditenhorden kämpft.

Beispiel: Wenn ich durch eine ein paar Meter Breite Triggerzone durchschieße kriegt ich so 20 Aufrufe während der Pfeil innerhalb der Zone fliegt.

Die andere Fälle (wo tatsächlich eine Kollision mit einem Vob stattfindet) halte ich für vernachlässigbar, das passiert ja pro Pfeil im wesentlichen nur einmal.

Habt ihr eigentlich mal gemessen wie teuer ein Hook ist?

Lehona
05.04.2013, 13:41
Naja, es ist ein Aufruf pro potentieller Kollision, nicht pro ungewünschter Kollision, die macht bloß ca. 50% des Daedalus-Codes aus, allerdings scheint es sich ja trotzdem in Grenzen zu halten.

Die Hook selber kostet nur minimal mehr als zCParser::CallFunc sowie der dazugehörige Daedalus-Code. Wie zCParser::CallFunc ist, sollte man wohl testen (mit einer leeren Daedalus-Funktion), da muss ich wohl ein wenig Bytecode zusammenschustern.

Sektenspinner
05.04.2013, 13:55
Du hast recht, es ist ein Problem. Bei so ca. 20 Banditen macht es den Unterschied zwischen 30 und 15 Frames (Welt: Newworld/Xardas).
Das habe ich wohl falsch eingeschätzt.

Edt: Update. Hm, so schlimm ist es vielleicht doch nicht.
Ich habe nochmal mit (etwas) besserem Code getestet und habe jetzt gar keinen Unterschied mehr festgestellt. O_o

Bei der ersten Messung sind aber auch merkwürdige Dinge passiert: Die Pfeile sind in der Luft zusammengestoßen und haben dort einen dicken Klumpen gebildet. Vielleicht waren meine Testbedingungen da doch etwas unrealistisch (20 Banditen sind schon verdammt viel).

Lehona
05.04.2013, 14:10
Du hast recht, es ist ein Problem. Bei so ca. 20 Banditen macht es den Unterschied zwischen 30 und 15 Frames (Welt: Newworld/Xardas).
Das habe ich wohl falsch eingeschätzt.

Dann wird man die Bedingungen etc. wohl in Bytecode formulieren müssen, das ist aber ein wenig aufwändiger. Falls jemand wirklich den Performance-Schub braucht, kann man das ja machen. Ansonsten sollte man wohl nicht in Khorinis mit dem Bogen schießen (oder keine Triggerzonen verwenden).

Teron Gorefiend
07.04.2013, 14:42
hey, war lange nicht mehr im Eding. Wie auch immer habe gerade Semesterferien und eine richtig schwere Klausur erfolgreich hinter mehr, also eben 2 Fragen.

1. Ist Lego inzwischen verfügbar für G1? Meine G1 als G2 Mod klappt nicht so wirklich, außer man findet unzählige Fehlermeldung beim Laden und anschließend einen schwarzen Bildschirm ansprechend.

2. Wie kann man nochmal neue Untertitel von Dialoge bzw. die OU´s erstellen, da gabs mal so nen nettes Tool, glaube von Sektenspinner, aber ich weiß gerade den Namen nicht mehr.

Lehona
07.04.2013, 15:45
1. Nein
2. Redefix

Sektenspinner
07.04.2013, 17:13
Folgender Code hilft Information im Charaktermenü darzustellen. Mögliche Anwendungen:

Anzeige von Script-verwalteten Talenten, zum Beispiel Goldhacken.
Anzeige der Goldmünzen im Spielerinventar
Anzeige von Stärke als Zahl (z.B. 100) anstatt als Bruch (z.B. 100/100)
Allgemeiner: Anzeige beliebiger Strings in beliebigen Menu Items im Charaktermenü deren Werte nicht Engine-verwaltet sind.

Idee: Jedes mal wenn das Charaktermenü geöffnet wird, wird die Funktion Update_Character_Menu aufgerufen in der es DEINE Aufgabe ist deine Menu Items anhand deiner Vorstellungen mit Werten zu füllen. Dazu liegt eine Funktion Update_Menu_Item bei. Ein Beispiel liegt bereit, in dem die Überschrift ("Charakterprofil") ersetzt wird durch einen String der die Zahl der Münzen im Spieler Inventar anzeigt.

Ein ausführlicher Kommentar am Anfang des Skripts beantwortet hoffentlich weitere Fragen.


/*##############################################################
Idea:
This code is useful if you want to display information
in the character menu that you cannot or do not want to
link to an Npc-Talent or Attribute.

Traditionally, the Engine fills in values itself, for example
initialising the menu Item MENU_ITEM_LEVEL with hero.level,
or retrieving the string in MENU_ITEM_PLAYERGUILD according to
hero.guild and the table TXT_GUILDS (see Text.d).

Because the way in which the engine retrieves these values
is hardcoded, you have only limited controll on what is
displayed in the character menu.

The following code is aimed to give you more control,
allowing you to implement additional talents (more
than NPC_TALENT_MAX) or statistical information
(like number of monsters killed) that are not represented
in attributes or talents.
You also have more controll on how the information is
displayed, for example as a value (100), a fraction (30/100)
with a unit (32 Coins), as a percentage (42%) or in
any other way you fancy.

Usage:
1.) Call Install_Character_Menu_Hook() in INIT_GLOBAL
after having called LeGo_Init.
2.) For each piece of information you want to display,
create a menu item in Scripts\System\Menu\Menu_Status.d
You need to specify the position of the menu item there.
Use e.g. MENU_ITEM_STATUS_HEADING as a reference.
Lets say your new menu item is called MENU_ITEM_GOLD.
3.) At the top of Menu_Status.d, update MENU_STATUS
such that your new menu item is listed as well.
4.) In the function Update_Character_Menu (see below)
you need to "calculate" the value that should be
displayed within the menu item (calculating might
be as easy as specifying a variable).
Use the function Update_Menu_Item.
This may look like this:
var int gold;
gold = Npc_HasItems(hero, ItMi_Gold);
var string s;
s = ConcatStrings(IntToString(gold), " Coins");
Update_Menu_Item("MENU_ITEM_GOLD", s);
5.) If you need additional labels or headings,
create additional menu items in Menu_Status.d for it.
For example a label "Gold:".
You can use MENU_ITEM_STATUS_HEADING as a reference.
Don't forget to list all new items in MENU_STATUS.
5.) Do not call Update_Character_Menu yourself.
This is automatically done for you each time
the character menu is opened.
6.) Do not try to manage menu items that the engine
manages itself. For example you will not be able
to change the value in MENU_ITEM_LEARN, because
the engine will always display the number of learn points there, negating your changes.
If, for example, you want to display the player strength,
create a new menu item or rename the old menu item
instead of just using MENU_ITEM_ATTRIBUTE_1.

The function Update_Character_Menu currently contains
code for replacing the heading "CHARAKTERPROFIL" in the
status menu with a string displaying number of gold coins
in the hero's inventory.
This is supposed to serve as an example.
After following only step 1 above this should already work.
##############################################################*/

// [INTERAL]
func void Update_Menu_Item(var string name, var string val) {
var int itPtr;
itPtr = MEM_GetMenuItemByString(name);

if (!itPtr) {
MEM_Error(ConcatStrings("Update_Menu_Item: Invalid Menu Item: ", name));
return;
};

//void __thiscall zCMenuItem::SetText(val = val, line = 0, drawNow = true)
const int SetText = 5114800;

CALL_IntParam(true);
CALL_IntParam(0);
CALL_zStringPtrParam(val);
CALL__thiscall(itPtr, SetText);
};

//Call this is INIT_GLOBAL after LeGo_Init.
func void Install_Character_Menu_Hook() {
//at oCMenu_Status::SetLearnPoints
const int done = false;
if(!done) {
HookEngineF(4707920, 6, Update_Character_Menu);
done = true;
};
};
// [/INTERNAL]

// Fill in this function according to your needs:
func void Update_Character_Menu() {
/* Usage:
Update_Menu_Item([Name of the Menu Item],
[new String value]);
*/

//Replace heading with number of coins
var int gold;
gold = Npc_HasItems(hero, ItMi_Gold);
var string s;
s = ConcatStrings(IntToString(gold), " Coins");
Update_Menu_Item("MENU_ITEM_STATUS_HEADING", s);
};

Danke an Varus fürs testen.

redleha
09.05.2013, 10:34
Hello! I would like to share the information that I found yesterday. I do not know if this was already known before.

Game console has command: ZPROGMESHLOD (apply global strength value to all pm LOD rendering, -1 (default), 0 .. 1 .. x)

I found a memory address. With Ikarus changed it to 0. After that was gone LOD mesh morphing head of the protagonist "Dark Saga" Alastair all within sight.

Prior to this change in his head, which has more than 1,300 polygons greatly distorted even at a distance of two steps.

Here it is:
008A5334 - LOD address parameter / / = 9065268

const int LODparametr = 9065268, / / this is the number of type float.
MEM_WriteInt (LODparametr, 0);

As I see it, it's maybe not the correct implementation, so I hope that the authors will be able to add LeGo correct function. For example Set_LODfactor (var float lodfactor).

I would be glad if I get any response to my message.

Milky-Way
09.05.2013, 12:22
Could you maybe make two screenshots that show before / after?

redleha
09.05.2013, 13:26
Could you maybe make two screenshots that show before / after?
1. Default (lodfactor = -1)
http://i.imgur.com/2rbIdJB.jpg?1 (http://imgur.com/2rbIdJB)

2. Lodfactor = 0
http://i.imgur.com/H1J0XOC.jpg (http://imgur.com/H1J0XOC)

3. + zhighqualityrender
http://i.imgur.com/rjtnKIL.jpg (http://imgur.com/rjtnKIL)

redleha
10.05.2013, 12:48
Also empirically found a pointer to a memory location that stores a value set by the command SET CLIPPINGFACTOR.
Well, that just turned out that there is already in use "Dynamic Memory Allocation".

Pointer: (0099AC8C // 10071180) / / offset = 1436;
Description of the command SET CLIPPINGFACTOR: Setting the clipping-factor. Default is 1. Usually check 0.1 ... 2.0

I exhibited a value of 3. Range of detailed drawing really increased. A higher value has little effect.

Golden Age
11.05.2013, 13:04
Der Link im Startpost zum Wiki für die neuen Funktionen funktioniert nicht mehr.
Da ich jetzt auch mit Ikarus und LeGo anfangen will/muss, wäre das sehr hilfreich:)

Ich scheitere im Moment schon daran, dass ich erfolgreiche Tagebucheinträge grün ausgeben will. Wie genau funktioniert das?

Und 2.
Ich habe ein Mob, Kisten die man auseinanderschieben muss. Danach kann man in eine Höhle gehen, ähnlich wie in Sarkeras. Da der Endzustand eines Mobs nicht gespeichert wird, wollte ich das Mob beim Laden löschen und stattdessen eine 3ds an der Stelle einfügen, welche so aussieht, dass die Kisten bereits auseinandergeschoben sind.
Könnt ihr mit bitte sagen, wie das funktioniert? Ich finds toll, dass es jetzt dafür Möglichkeiten gibt, aber ich möchte mich selbst nicht unbedingt so lang damit aufhalten.

Und warum bringt mir dieser Code ne Fehlermeldung(Division by zero)

DIAG_SetAni("GreetCool");
AI_Output (self, other, "DIA_NONE_3503_Vater_nachfrage_14_01");//Na mein Sohn. Danke, mir geht es gut.
DIAG_Reset();

Danke!§wink

Lehona
12.05.2013, 13:01
Es gab ein paar Probleme mit der Datenbank, das Wiki sollte jetzt wieder erreichbar sein.

Gottfried
12.05.2013, 13:05
Das LeGo-Wiki (http://gottfried.milgo.de/LeGo/de/?) funktioniert jetzt wieder :)

Wenn du einen Tagebucheintrag grün ausgeben willst kannst du PrintS dafür verwenden:

PrintS(ConcatStrings("Quest abgeschlossen: ", quest_title), COL_Green);

COL_Green ist eine der Farbkonstanten (http://gottfried.milgo.de/LeGo/de/?Userkonstanten#Interface). Alternativ kann man dafür natürlich auch die RGBA-Funktion (http://gottfried.milgo.de/LeGo/de/?Interface#RGBA) verwenden.


Bei deinem Mob-Problem brauchst du LeGo gar nicht. Du kannst die beiden Funktionen MEM_DeleteVob und MEM_InsertVob aus Ikarus dafür verwenden.


Die Dialoggestures haben vor einiger Zeit ein sehr großes Update erhalten, weil das alte System zu unschön war. Die Funktion DIAG_SetAni solltest du gar nicht benutzen - mein Fehler dass die Funktion überhaupt noch mit diesem Namen vorhanden ist.

Um die Dialoggestures mit dem neuen LeGo zu verwenden musst du die Funktion DIAG (http://gottfried.milgo.de/LeGo/de/?Dialoggestures) nehmen. Die Anwendung ist etwas schwieriger zu verstehen, dafür insgesamt komfortabler wenn man mal weiß wie.
Wenn du die Funktionalität nicht so recht durchschaust kannst du mir gerne ne PN schreiben. Ich sehe gerade dass es für dieses Paket gar keine Beispiele gibt. Das ist natürlich blöd, mal schauen ob ich da in nächster Zeit was schreiben kann.


MfG Gottfried

PsyonikerAusmSumpf
15.05.2013, 12:33
ich trau mich kaum zu fragen, aber wie benutzt man euer wundertool?
ich möchte zum beispiel einen perk implementieren der 1% maxMp/Sek regeneriert. (das problem liegt beim platzieren und starten der schleife)

auf die wikiseite komme ich leider nicht drauf. ich bekomme immer nen timeout, liegt das an mir?

ich würd mich über jede hilfe freuen

Lehona
15.05.2013, 12:51
Also das Wiki funktioniert momentan bei mir. Wir benutzen seit kurzem eine Gratis Datenbank, kann sein, dass dort die Uptime nicht so toll ist... Aber es sollte jetzt wieder funktionieren.


Eigentlich musst du bloß die Scripte einpflegen (d.h. irgendwo in den Scripts-Ordner kopieren und LeGo\Header.src in die Gothic.src eintragen, nach Ikarus und den Floats) und entsprechend initialisieren. Wenn du nur Schleifen brauchst, ist LeGo_Init(LeGo_FrameFunctions); in der Init_Global() (in Startup.d) völlig ausreichend.

Danach kannst du eine ein-sekündige Schleife mit FF_ApplyExtOnce(myFunc, -1, 1000); hinzufügen (einfach direkt nach LeGo_Init() aufrufen). Näheres zu den FrameFunctions findest du hier (http://gottfried.milgo.de/LeGo/de/?FrameFunctions).

mobpapst
18.05.2013, 18:47
Wenn du einen Tagebucheintrag grün ausgeben willst kannst du PrintS dafür verwenden:

PrintS(ConcatStrings("Quest abgeschlossen: ", quest_title), COL_Green);

MfG Gottfried


Das habe ich probiert. Aber ich bekommen beim reparsen den Fehler, das eine Klammer nicht stimmt. Aber ich habe da eine generelle Frage:

Nehmen wir mal an das sei mein Tagebucheintrag:

1.


Log_CreateTopic (TOPIC_WOOD_FENCE, LOG_MISSION);
Log_SetTopicStatus(TOPIC_WOOD_FENCE, LOG_RUNNING);
B_LogEntry (TOPIC_WOOD_FENCE, "xxx.");


2.

Könnte ich dann das einfach so machen, damit er Grün ausgegeben wird? :


Log_CreateTopic (TOPIC_WOOD_FENCE, LOG_MISSION);
Log_SetTopicStatus(TOPIC_WOOD_FENCE, LOG_RUNNING);
B_LogEntry (TOPIC_WOOD_FENCE, "xxx.");
PrintS(ConcatStrings("Quest abgeschlossen: ", WOOD_FENCE), COL_Green)



Mfg

Lehona
18.05.2013, 18:57
Ich glaube du brauchst TOPIC_WOOD_FENCE, nicht WOOD_FENCE, ansonsten dürfte es aber stimmen. In B_LogEntry() wird glaube ich noch ein Print ausgeführt, den solltest du ggf. entfernen oder einfach ersetzen.

mobpapst
18.05.2013, 19:50
Ok danke. Hab ich nun abgeändert wie du gesagt hast, aber bekomme beim PrintS-Befehl folgenden Fehler:



PrintS(ConcatStrings("Quest abgeschlossen: ", TOPIC_WOOD_FENCE), COL_Green)


U:PAR Expected ')
'(line xxx)

Lehona
18.05.2013, 19:53
PrintS() nimmt nur einen Text, wenn du Farbe möchtest, benutze PrintS_Ext(). Dafür kann man auch eben im Wiki (http://gottfried.milgo.de/LeGo/de/?Interface#PrintS) schauen.

mobpapst
18.05.2013, 20:00
Alles klar und vielen Dank! :gratz

mobpapst
19.05.2013, 10:50
Ich habe eine weitere Frage zum Ausgeben eines PrintScreen_Ext. Da zur Zeit leider die Seite down ist habe ich mir in der Interface-Datei folgendes angesehen:



PrintScreen_Ext(var string txt, var int x, var int y, var string font, var int timeSec)


Und dann daraus das gemacht:




Log_CreateTopic (TOPIC_WOOD_Task, LOG_MISSION);
Log_SetTopicStatus(TOPIC_WOOD_Task, LOG_RUNNING);
B_LogEntry TOPIC_WOOD_Task, "xxx.");
PrintScreen_Ext(ConcatStrings("Quest angenommen:, " TOPIC_WOOD_Task), -1, 2, FONT_ScreenSmall, 3000)


Ich möchte damit erreichen, das mein Tagebucheintrag mittig plaziert wird. Beim reparsen bekomme ich aber Zeichensetzungsfehler. Ich hab noch xx-Dinge versucht, komme aber leider auf keine passende Lösung.

Mfg

Lehona
19.05.2013, 11:04
Das mit dem Wiki ist doof, der Gratis-Hoster unser DB taugt wohl nicht sonderlich viel §gnah Wir werden nach einer anderen Lösung suchen.


PrintScreen_Ext() ist eigentlich nicht unbedingt zur Verwendung gedacht, es macht auch nichts anderes als PrintScreen() ;)
Gewöhn dir einfach mal an, immer die genaue Fehlermeldung zu posten (und stell sicher, dass sie sich auch genau darauf bezieht), so direkt sieht es erstmal korrekt aus.
Edit: Oder auch nicht, du hast das Semikolon am Ende vergessen.

mobpapst
19.05.2013, 11:15
Hat geklappt, danke. Aber es lang an etwas anderem.

redleha
20.05.2013, 11:32
Maybe my question seems silly, but still ask.

What instrument can overwrite the value of the constant (int, string, float)?
I understand I first need to get the address by a symbolic name. And then rewrite using the MEM_WriteXXX. Could you show an example of a few lines, or specify where to look (maybe enough to look in Ikarus.d)?

And another question. When I change the value of a constant (cost of item) with the package G2ext, the changes appear in your inventory when you save the game. Is it possible to directly produce this reinitialization after the constant changes?

I hope I have correctly written thought. :D

Lehona
20.05.2013, 11:39
var zCPar_Symbol symb; symb = MEM_GetParserSymbol("SYMBNAME");
symb.content = newValue;

If it's a string, newValue must be of type zString*, ie a pointer to the string.
If you want to change the address of an instance, you will have to change symb.offset.

Sektenspinner
20.05.2013, 18:24
What instrument can overwrite the value of the constant (int, string, float)? I'd suggest using _@, _@s and _@f to get the addresses of ints, strings and floats and use MEM_WriteInt and MEM_WriteString to change the values at these addresses.


And another question. When I change the value of a constant (cost of item) with the package G2ext, the changes appear in your inventory when you save the game. Is it possible to directly produce this reinitialization after the constant changes?The easiest way I know of would be to destroy and recreate the items or to call the intialiser Funktion for each relevant item (MEM_CallByID(ITMI_MYITEM) after setting the Instance ITMI_MYITEM appropriately and consistently specifying the instance in assignments within the initialiser function (ITMI_MYITEM.name = "My Item"; instead of name = "My Item";)

In short, no, its not possible to have changes to constants affect the items that use these constants directly unless you take care of it manually.

redleha
20.05.2013, 19:51
Thank you, comrades. :gratz
(I corrected the example of Lehona. It was a little bit wrong. ;))

And another question. After changing the value of a constant effect lasts only until you restart the game. If you turn off and turn on the game, the value of constant returns. How to avoid this?
Also I will be glad if you give an example or specify the search direction.

Lehona
20.05.2013, 20:27
Thank you, comrades. :gratz
(I corrected the example of Lehona. It was a little bit wrong. ;))

And another question. After changing the value of a constant effect lasts only until you restart the game. If you turn off and turn on the game, the value of constant returns. How to avoid this?
Also I will be glad if you give an example or specify the search direction.

Woops, I forgot a _^() :p

Constants are loaded from the .dat file and are not stored in the savegame, with pure scripts there's no way around that.

redleha
21.05.2013, 05:11
Thank you, Lehona! I expected this answer to my question. But hope springs eternal. :D

redleha
24.05.2013, 09:12
Hello again. I ask this question.
Is it possible to intercept the time of transfer of the goods from NPC to NPC during trading. The subject of trade, how much money for the product, the type of currency.
That is, when we click "Ctrl" or the "left mouse button" when trading.
For example:


function tradeItem(C_ITEM item)
{
var int x; x=item.value
var int y; y= Hlp_GetInsanceID(${type_of_currency});
CreateInvItems(hero, y, item.value * TRADE_VALUE_MULTIPLIER);
};

I think it is clear why these manipulations.
The player will be able to sell expensive weapons - to arms dealer. The player will be able to sell more expensive animal trophies - to the hunter.

Lehona
24.05.2013, 12:51
This is definitely possible, but I'll have to analyse the assembly first. I'll try to dig something up (Found the correct address already, just gotta figure out how I can access the item + the NPC at this position) :)

Lehona
24.05.2013, 14:57
Alas, I've found a way to get what you need.

func void onTradeLeft() {
value = MEM_ReadInt(ESP+20); // itm.value * multiplier
MEM_WriteInt(ESP+20, 123); // set new value
var oCItem itm; itm = _^(EBX); //Get the item
var oCNpc npc; npc = _^(MEM_InformationMan.npc); // Get the NPC
};

const int oCViewDialogTrade__OnTransferLeftX = 6863312; //0x68B9D0
HookEngineF(oCViewDialogTrade__OnTransferLeftX, 6, onTradeLeft);

This should only trigger when the hero sells something, buying is a completely different (well, similar, but different) thing.
The code should be self-explaining to you, if you have questions how to use it, go ahead an ask :)

Edit: The value seems to be capped at about 16k (I assume around 214 but didn't check it as I thought that wouldn't matter much to you).

redleha
24.05.2013, 15:41
Thank you so much! I'll try. It's better to learn new things.

PS Today I have manipulated the script by building the function that I wanted at a time when there was no Ikarus, no LeGo. But it could not be implemented.

Lehona
24.05.2013, 15:45
So is your script working or is it not? I can't quite figure out what it's supposed to do, because that symbTable stuff looks a bit shady to me :)
Edit: And it's gone. Guess you don't need help.

ukur
26.05.2013, 21:44
Lehona
With PermMem.d (Revision 61 from SVN) in my mod stop work buttons, do not respond to cursor. At previous revisions work normal.

Lehona
26.05.2013, 23:21
Thanks for your bug report, I will investigate tomorrow :)

redleha
28.05.2013, 12:19
This question yet. How can I get the symbolic name (a variable, a constant)?
And also, how to get a symbolic name in a function when the variable or constant is passed as a parameter.
Example:


const string AAA = "BBB"; //symbolic name = "AAA". right?
???func string GetSymbolicName_()

func string examp_1(var string x)
{
???
return symbolic_name; //must be "AAA"
};
exapm_1(AAA) = "AAA";

I kind of already know the work of memory, pointers, but sometimes difficult. :(

Lehona
28.05.2013, 14:39
zCPar_Symbol has the attribute zCPar_Symbol.name, that is what you want.

The problem with your second question is that after a parameter has been pushed by the caller (ie in foo(var1) var1 will be pushed onto the stack), the callee (ie the function that is called) will pop that value from the stack into its own parameter-variables, e.g. foo(var int par1), so when the function is entered, par1 will have the value of var1. To circumvent this, you have to manipulate the bytecode in the Gothic.dat (which is entirely possible by scripts, not even too hard).

Do you have any experience with Daedalus Bytecode (zCParser.d is kind of all you need)? Don't wanna write a whole novel if you know most of the basics already anyway.

redleha
28.05.2013, 15:29
I know about zCPar_Symbol.name .


To circumvent this, you have to manipulate the bytecode in the Gothic.dat (which is entirely possible by scripts, not even too hard).

Do you have any experience with Daedalus Bytecode (zCParser.d is kind of all you need)? Don't wanna write a whole novel if you know most of the basics already anyway.

But in these phrases I do not understand what you mean. :dnuhr:

In Gothic script I'm working well (5 years experience). Programming is also not alien to me. I recently started working with Ikarus and LeGo. A ASM-like scripting a bit complicated for me to start understanding. So I gradually master.

Isacz
28.05.2013, 15:54
Kann es sein, dass das Wiki seit einiger Zeit nicht mehr erreichbar ist? Ich bekomme die letzten Tage immer die Meldung
"Konnte nicht mit der Datenbank verbinden. Bitte versuche es später noch einmal."

Ist eine neue Version von LeGo geplant? Und könnte man, der Übersicht zu liebe, die diversen Werke von Usern wie Umfis Pflanzenrespawn im Ep verlinken?

Lehona
28.05.2013, 16:13
Well then you know the answer to your first question ;)

To track back the symbolic name of a given parameter (ie you do not want the name of the parameter ("par1") but the variable it was filled with ("var1")), you have to change the compiled code, because once the "normal" code inside a function is executed, this information is gone. You could do it like this though:


func string _getVarName() {
MEM_PopInst();
MEM_PushInst(zPAR_TOK_PUSHINT);
var int ptr; ptr = MEM_PopInt() - zCParSymbol_content_offset;
var zCPar_Symbol symb; symb = _^(ptr);
return symb.name;
};

func string getVarName(var int par) {
MEM_Error("This function should have never been entered.");
return "";
};

func void initVarName() {
MEM_ReplaceFunc(getVarName, _getVarName);
};

@Isacz: Ja, wir versuchen gerade unsere Datenbank mit dem WoG zu hosten, dann sollte die Seite wieder vernünftig stabil sein.

Edit: Verbessert.

Sektenspinner
28.05.2013, 19:10
@Lehona: If I am not mistaken, a Pointer to the value is pushed not a pointer to the symbol containing the value.
Therefore your code is missing the subtraction of zCParSymbol_content_offset from ptr before following it.

Lehona
28.05.2013, 19:28
@Lehona: If I am not mistaken, a Pointer to the value is pushed not a pointer to the symbol containing the value.
Therefore your code is missing the subtraction of zCParSymbol_content_offset from ptr before following it.

I'm sure you've had more experience dealing with that nasty stuff :p I was typing that from my mind to give an idea of what it's about.

redleha
29.05.2013, 14:48
That was the question. How to intercept keyboard input commands. I am aware of only two possibilities: either the "Marvin" console (F2), either in the player menu - invisible symbols (where input code "Marvin").
The best way - through the console (F2). Let it swears that the input text is nonsense, but it will still run. The main thing - to get the string "[command] [parameters]"

For a start - possible or not? :gratz
P.S.
In our mod "Dark Saga" we have own console (G2Ext) and own commands. I would like to have this or a similar mechanism, made in the gothic scripts.

Lehona
29.05.2013, 15:19
Now that's an entirely different question. You can create your own console commands, although parsing them is a bitch (Sektenspinner wrote a some kind of lexer for it, it's still really inconvenient and there isn't much you can do about it (http://forum.worldofplayers.de/forum/showthread.php?p=15287907&#post15287907)). You can also create your own console, but if you only need it for testing purposes, it's a bit over the top. If you genuinely want the player to input text, go ask Bonne6, he implemented a way to give feedback for his mod ingame.

redleha
30.05.2013, 13:36
I hope I have not bored you with my questions. :gratz

How to make a reinitialization of topics that appear at the beginning of the dialogue.
In fact, you can break off and start a dialogue.
If you create a condition for a line of dialogue to appear, for example, in one outer loop - this line will appear, but will not be displayed. (I tested this by pasting the code into ZS_Talk)


var int LeftShift; LeftShift = MEM_KeyState(KEY_LEFTARROW);
var int RightShift; RightShift = MEM_KeyState(KEY_RIGHTARROW);
if((LeftShift == KEY_PRESSED) && !GLOBAL_DSG_KEY_DIALOG)
{
GLOBAL_DSG_KEY_DIALOG = TRUE; //this is condition.
//At this moment the line is created, but not displayed.
//If I press Enter, the dialog will work.
};
if((RightShift == KEY_PRESSED) && GLOBAL_DSG_KEY_DIALOG)
{
GLOBAL_DSG_KEY_DIALOG = FALSE;
Print("RIGHTARROW");
};

I've been thinking that I can just hit the right place. (CallByPtr?)

Lehona
30.05.2013, 15:03
I'm not quite sure what you mean, maybe you should try explaining it in a different way.
However, bear in mind that all AI_Output()s are called at the beginning of a dialogue. If you want to have a conditional output, the condition must be set when the player selects said dialogue.

Sektenspinner
30.05.2013, 15:20
I am also not sure what you mean.

When starting the Dialogue Manager, the list of available C_INFOs is built according to the conditions of the C_INFOs.
If the condition functions evaluate differently at the point when the Info is chosen by the player, unexpected behaviour may occur:
If the player picks the i-th entry in the list of infos displayed to him, then its not necessarily the i-th info in that list that will be triggered, instead the list will be built anew (without displaying it) and the i-th info in that updated list will be triggered.

Is that what you are talking about?

redleha
30.05.2013, 16:03
Sektenspinner - Yes, that's what I mean.
You are well understood my question. Also you have correctly described the problem.
The condition for the topic Run outside (external program or cycle) -> list of objects С_INFO in dialog_manager reconstructed, but there was no visual rebuild. And if you now click on the topic "End", functionality is executed according to another topic, the rules of which have now done.

I need to rebuild list C_INFOs.
How I can do it without leaving the dialog manager (by the reaction of the button, as I've tried it)?