Themabewertung:
  • 1 Bewertung(en) - 5 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Schicksalsklinge: Umfassender Bugfix-Patch
Jetzt noch ein Bugfix, der die "unsichtbaren Sperren" behebt.

Die Situation ist so:
  • Die Hinterteile von toten zweifeldrigen Monstern sind unsichtbar. Aber es gibt sie.
  • Es gibt sie sogar öfter als man denkt, denn anscheinend können auch geflohene Gegner solche am Spielfeld hinterlassen.
  • Die toten Hinterteile können zwar betreten, aber nicht überschritten werden. Für Gegner sind die toten Hinterteile komplett unbetretbar.
Technische Erklärung:
  • In der Wegfinde-Routine FIG_find_path_to_target(...) (vormals seg038(...))in seg038.cpp werden Felder mit toten Monstern begehbar gemacht, allerdings nicht die Hinterteile von toten zweifeldrigen Monstern. Aus diesem Grund können diese Felder nicht überquert und von Gegnern auch nicht betreten werden.
  • In der Routine, die für die Helden-Bewegung zuständig ist, sind Felder mit toten Gegnern erlaubt, wobei explizit auch tote Hinterteile mit einbezogen werden. Somit können diese als Zielfeld ausgewählt werden. Der Weg zum Zielfeld wird wieder von FIG_find_path_to_target berechnet. Vor dem Aufruf wird aber der Inhalt des Zielfelds mit einem Marker (Zahl 124) überschrieben. Somit kriegt FIG_find_path_to_target in diesem Fall nichts mehr von dem toten Hinterteil mit.
  • Der Bugfix besteht nun darin, die toten Hinterteile auch in FIG_find_path_to_target begehbar zu machen. Ich habe es mit BrightEyes ausprobiert und mir scheint, dass das Problem behoben ist. Vorher wollte ja nach kürzester Zeit kein Hund mehr nachkommen, weil -- wie ich jetzt weiß -- die toten Hinterteile alles verstopft haben. Mit dem Bugfix kommen brav alle nach und nach angelaufen.
Zitieren
Da muss man ja komplett was Neues einfügen. Na, das wird ein Spaß auf Binärcode-Ebene.
Zitieren
Du meinst den "unsichtbare Sperren"-Bug, richtig? Ja, da ist wohl leider eine kleine Verlängerung des Binärcodes nötig. Zumindest ist die Bedingung der zusätzlich erforderlichen Verzweigung sehr ähnlich zu der davor. Man kann die also übernehmen und muss nur 3 Zahlen anpassen: 10->30, 30->50 und nochmal 10->30.

Beim "99BP-Bug" müssen zwei verschachtelte Bedingungen "flach" gemacht werden. Einerseits fallen zwei 'if'-Konstrukte weg, aber andererseits muss an einer Stelle noch die zusätzliche Bedingung 'cb_entry_bug < 10' eingeflochten werden. Meine Hoffnung ist, dass sich das für die Anzahl der Bytes im Maschinencode die Waage hält.
Zitieren
Die "unsichtbare Sperre" war nur die Spitze des Eisbergs...Jetzt, wo die Katze aus dem Sack ist und wir wissen, dass die Hinterteile von toten zweifeldrigen Monstern manchmal unsichtbar weiterexistieren, sind der Phantasie keine Grenzen gesetzt.

Ich habe ein wenig probiert: Man kann auf so ein unsichtbares Phantom-Hinterteil einen Skelettarius sprechen. Damit entsteht ein Zombie, und zwar auf dem Feld, wo zuvor der Kopf war. Wenn auf dem Feld schon etwas anderes steht, also ein anderer Gegner oder ein Held, dann wird der Zombie einfach auf dasselbe Feld gesetzt. Das Phantom-Hinterteil zählt danach als das entkoppelte Hinterteil des Zombies, so dass das Feld blockiert ist und man den Zombie auch auf diesem Feld angreifen kann. Das sieht mitunter sehr seltsam aus: Der Held knüppelt auf ein leeres Feld ein, und am anderen Ende der Kampfkarte dreht sich der Zombie als Reaktion auf den Angriff. Und wenn der Zombie den Heldentot gestorben ist (kann ein Untoter sterben?), dann kann man ihn erneut am Hinterteil wiederbeleben.

Fast noch besser wird es, wenn man den Skelettarius auf das Phantom-Hinterteil eines geflohenen Gegners spricht. Dann entsteht laut Textfenster auch ein Zombi. In einem Fall war aber kein Zombi zu sehen, und im anderen Fall war tatsächlich ein paar Felder weiter am Spielfeldrand (aber noch im Spielfeld) eine Art Fata Morgana eines Zombis. D.h. abgesehen davon, dass man den Zombi dort sah, war er Luft. Man kann durchlaufen und ihn nicht angreifen. Der Kampf war nur dadurch zu beenden, dass die beiden Zombis durch Angriff auf das zugehörige Phantom-Hinterteil besiegt werden.

Der einzig vernünftige Bugfix wäre, die Hinterteile im Fall eines getöteten oder geflohenen zweifeldrigen Monsters komplett zu entfernen. Eigentlich sollte das nicht so schwierig sein. Aber trotz einiger Sucherei konnte ich bisher nicht finden, welcher Code bei einem getöteten Gegner bzw. bei Flucht ausgeführt wird.
Zitieren
Also soll ich noch warten, bevor ich Deine beiden Korrekturvorschläge umsetze? Oder sind die davon unabhängig?
Zitieren
Der erste Fix (99BP-Bug) ist definitiv unabhängig. Der zweite Fix ("unsichtbare Sperren") wäre evtl. nicht mehr nötig, streng genommen. Von der Logik her ist es aber ein Bug, dass die Hinterteile uneinheitlich behandelt werden, womit es definitiv gut wäre den Fix "auf Nummer sicher" drinzuhaben.

Weißt du zufällig, wo der Programmcode steht, der bei Tod oder Flucht eines Gegners ausgeführt wird?
Zitieren
Nein, das müsste ich auch noch recherchieren.

Bezüglich Skelettarius hatte ich aber schon im Patch was gemacht, was ich hier beschrieben hatte.
Zitieren
wow, die von dir verlinkte Skelettarius-Sache klingt unangenehm. Das war bestimmt nicht leicht herauszufinden.

Nachdem ich ja jetzt mit BrightEyes rumteste, wäre es gut, wenn dieser alte Bug nicht auch noch die Dinge verkompliziert. Kannst du mir sagen, was ich am Skelettarius ändern muss, um den Bug zu beheben?
Zitieren
Vorher:
Code:
void spell_skelettarius(void)
{
        Bit8u *enemy;
        signed short x;
        signed short y;
        signed char unk;

        /* Set pointer to enemy target */
        ds_writed(SPELLTARGET_E,
                (Bit32u)RealMake(datseg, host_readbs(get_spelluser() + HERO_ENEMY_ID) * SIZEOF_ENEMY_SHEET + (ENEMY_SHEETS - 10*SIZEOF_ENEMY_SHEET)));

        /* check if the enemy is dead */
        if (!enemy_dead(get_spelltarget_e())) {

                /* prepare message */
                sprintf((char*)Real2Host(ds_readd(DTP2)),
                        (char*)get_tx(15),
                        Real2Host(GUI_names_grammar((signed short)0x8000,
                                host_readbs(get_spelltarget_e() + ENEMY_SHEET_MON_ID), 1)));

                /* set ae costs */
                ds_writew(SPELL_SPECIAL_AECOST, 0);
        } else {

                /* prepare message */
                sprintf((char*)Real2Host(ds_readd(DTP2)),
                        (char*)get_tx(16),
                        Real2Host(GUI_names_grammar((signed short)0x8000,
                                host_readbs(get_spelltarget_e() + ENEMY_SHEET_MON_ID), 1)));

                enemy = Real2Host(FIG_get_ptr(host_readbs(get_spelltarget_e() + ENEMY_SHEET_FIGHTER_ID)));

                x = host_readbs(enemy + FIGHTER_CBX);
                y = host_readbs(enemy + FIGHTER_CBY);

                if (host_readbs(enemy + FIGHTER_TWOFIELDED) != -1) {
                        FIG_remove_from_list(ds_readbs(FIG_TWOFIELDED_TABLE + host_readbs(enemy + FIGHTER_TWOFIELDED)), 0);
                }

                FIG_remove_from_list(host_readbs(get_spelltarget_e() + ENEMY_SHEET_FIGHTER_ID), 0);

                unk = host_readbs(get_spelltarget_e() + ENEMY_SHEET_DUMMY2);

                fill_enemy_sheet(host_readbs(get_spelluser() + HERO_ENEMY_ID) - 10, 0x10, 0);

                FIG_load_enemy_sprites(get_spelltarget_e() + ENEMY_SHEET_MON_ID, x, y);

                or_ptr_bs(get_spelltarget_e() + ENEMY_SHEET_STATUS2, 2);
                host_writebs(get_spelltarget_e() + ENEMY_SHEET_DUMMY2, unk);
        }
}
Nachher:
Code:
void spell_skelettarius(void)
{
        Bit8u *enemy;
        signed short x;
        signed short y;
        signed char unk;

        /* Set pointer to enemy target */
        ds_writed(SPELLTARGET_E,
                (Bit32u)RealMake(datseg, host_readbs(get_spelluser() + HERO_ENEMY_ID) * SIZEOF_ENEMY_SHEET + (ENEMY_SHEETS - 10*SIZEOF_ENEMY_SHEET)));

        /* check if the enemy is dead */
        if (!enemy_dead(get_spelltarget_e())) {

                /* prepare message */
                sprintf((char*)Real2Host(ds_readd(DTP2)),
                        (char*)get_tx(15),
                        Real2Host(GUI_names_grammar((signed short)0x8000,
                                host_readbs(get_spelltarget_e() + ENEMY_SHEET_MON_ID), 1)));

                /* set ae costs */
                ds_writew(SPELL_SPECIAL_AECOST, 0);
        } else {

                /* prepare message */
                sprintf((char*)Real2Host(ds_readd(DTP2)),
                        (char*)get_tx(16),
                        Real2Host(GUI_names_grammar((signed short)0x8000,
                                host_readbs(get_spelltarget_e() + ENEMY_SHEET_MON_ID), 1)));

                enemy = Real2Host(FIG_get_ptr(host_readbs(get_spelltarget_e() + ENEMY_SHEET_FIGHTER_ID)));

                x = host_readbs(enemy + FIGHTER_CBX);
                y = host_readbs(enemy + FIGHTER_CBY);
                RealPt temp1 =datseg[FIGHTOBJ_BUF_SEEK_PTR];
                RealPt temp2 =datseg[FIGHTOBJ_BUF_FREESPACE];
                datseg[FIGHTOBJ_BUF_SEEK_PTR] =*(enemy +FIGHTER_GFXBUF);

                if (host_readbs(enemy + FIGHTER_TWOFIELDED) != -1) {
                        FIG_remove_from_list(ds_readbs(FIG_TWOFIELDED_TABLE + host_readbs(enemy + FIGHTER_TWOFIELDED)), 0);
                }

                FIG_remove_from_list(host_readbs(get_spelltarget_e() + ENEMY_SHEET_FIGHTER_ID), 0);

                unk = host_readbs(get_spelltarget_e() + ENEMY_SHEET_DUMMY2);

                fill_enemy_sheet(host_readbs(get_spelluser() + HERO_ENEMY_ID) - 10, 0x10, 0);

                FIG_load_enemy_sprites(get_spelltarget_e() + ENEMY_SHEET_MON_ID, x, y);

                or_ptr_bs(get_spelltarget_e() + ENEMY_SHEET_STATUS2, 2);
                datseg[FIGHTOBJ_BUF_SEEK_PTR] =temp1;
                datseg[FIGHTOBJ_BUF_FREESPACE] =temp2;
                host_writebs(get_spelltarget_e() + ENEMY_SHEET_DUMMY2, unk);
        }
}
Das ist jetzt einfach die auf Maschinencode-Ebene vorgenomme Änderung nach C übersetzt. Ich hoffe, Du siehst, was gemeint ist; ich bin bei diesem dämlichen host_readbs-Zeug nie durchgestiegen, für mich liest sich das wie "host read bullshit". ;) Die Konstantenbeschriftungen in BrightEyes sind übrigens falsch, es geht bei "enemy" nicht um ENEMY_SHEET_*, sondern um FIGHTER_*.

Frag mich nicht nach inhaltlichen Details, die habe ich nach vier Jahren vergessen.
Zitieren
vielen Dank! Idee verstanden und eingebaut, funktioniert offenbar. Auch Danke für den Hinweis enemy vs. fighter. Ich hatte mich schon gefragt, was ENEMY_SHEET_LE da soll.

(21.01.2021, 09:34)NRS schrieb: Frag mich nicht nach inhaltlichen Details, die habe ich nach vier Jahren vergessen.
Bei mir reichen oft schon 4 Tage. Das ist auch mit der Grund, warum ich versuche die Sachen gut kommentiert in BrightEyes reinzubekommen, bevor alles wieder weg ist.
Zitieren
Ich habe beim Skelettarius gleich noch einen anderen Bug gefunden und repariert: Objekte, die unter der Leiche liegen, sind nach dem Skelettarius verschwunden (obwohl sie noch angezeigt werden). Damit ist es jetzt möglich, ganze Stapel von übereinanderliegenden Leichen nach und nach in Skelette zu verwandeln. Leider ist der Bugfix wieder mit einer Verlängerung des Codes verbunden.

In diesem Zusammenhang eine Frage:
Wurde eigentlich dieser Bug damals in deinem Patch behoben? Wenn ja, wie? Wenn nein, würde ich mich auch daran mal versuchen, weil es ja ziemlich nahe an den Dingen ist, mit denen ich mich bisher beschäftigt habe.
Zitieren
Nein. Ich hatte eigentlich gehofft, dass bis auf den 99-BP-Bug und die (nunmehr zwei) Skelettarius-Geschichten sich alles andere in Wohlgefallen auflösen würde, wenn "Der einzig vernünftige Bugfix wäre, die Hinterteile im Fall eines getöteten oder geflohenen zweifeldrigen Monsters komplett zu entfernen." implementiert ist.
Zitieren
Ich fürchte ein wenig, dass das nochmal ein separater Bug sein könnte. Denn ich bringe das Fehlerbild nicht mit den herumliegenden Phantom-Hinterteilen zusammen.

Ja, das Entfernen der Hinterteile steht noch aus. Ich bin aber tatsächlich schon etwas schlauer. An dieser Code-Stelle wird tatsächlich ein Hinterteil korrekt entfernt. Sie kommt meines Erachtens immer dann zur Ausführung, wenn der zweifeldrige Gegner "regulär", also mit Waffe, Zauberspruch etc. von einem Helden getötet wurde.

Nicht davon erfasst sind jedoch Situationen, wo der zweifeldrige Gegner geflohen ist oder sich durch einen Attacke-Patzer selber umgebracht hat. Die Phantom-Hinterteile dürften aus diesen Situationen stammen.
Zitieren
(27.03.2016, 11:13)NRS schrieb: Admin-EDIT: Der Patch ist im NLT-Wiki erhältlich -> http://nlt-wiki.crystals-dsa-foren.de/do.../downloads (Umfangreicher Schicksalsklinge-Fanpatch)

Entschuldigt, wenn ich hier so unverblümt nachfrage...
Ist der im NLT-Wiki unter Patches verlinkte "Umfangreiche Schicksalsklinge-Fanpatch" der richtige wenn ich Schick Heldenedition spiele?[url=http://nlt-wiki.crystals-dsa-foren.de/lib/exe/fetch.php/downloads/patches/dsa1pat_2018-12-27.zip][/url] Und wenn ja, wie muss ich dann genau vorgehen, um den Patch richtig anzuwenden?
Let's play *interaktiv - Die Schicksalsklinge (1992)
---------------------------------------------------------
Let's play *interaktiv - Sternenschweif (1994)
---------------------------------------------------------
Let's play *interaktiv - Schatten über Riva (1996)
Zitieren
Ja, das ist die aktuelle Datei des NRS-Patches. Wichtig ist wohl, dass Du mit der CD-Version 3.02 spielst. Ansonsten wüsste ich nicht, dass die Edition von Relevanz wäre.

Hier (https://www.crystals-dsa-foren.de/showth...#pid148653) erklärt NRS, wie der Patch anzuwenden ist. Der Link in diesem älteren Beitrag auf die Patch-Datei ist ungültig, der von Dir genannte Link bzw. die Datei is korrekt.

EDIT: Du kannst bequemer in der DOS-Box die "applyfix.bat" ausführen, dann musst Du nichts mounten, das kommt auf's Selbe raus. Wichtig ist nur, innerhalb der DOS-Umgebung und nicht von Windows aus auszuführen, das funktioniert dann nicht.
"Alrik war durstig und hat getrunken."
Zitieren
(28.01.2021, 17:40)Alrik Alrikson schrieb: EDIT: Du kannst bequemer in der DOS-Box die "applyfix.bat" ausführen, dann musst Du nichts mounten, das kommt auf's Selbe raus. Wichtig ist nur, innerhalb der DOS-Umgebung und nicht von Windows aus auszuführen, das funktioniert dann nicht.

Danke für den Tipp! Habe die Schicksalsklinge nun erfolgreich gepatched! Was bedeutet eigentlich, wenn da steht SPIELSTANDXY.GAM erfolgreich aktualisiert? Ist die komplette Spielwelt des Spielstands somit auch gepatched? Ich hatte den Spielstand nämlich extra noch woanders gesichert...
Viele Grüße
Let's play *interaktiv - Die Schicksalsklinge (1992)
---------------------------------------------------------
Let's play *interaktiv - Sternenschweif (1994)
---------------------------------------------------------
Let's play *interaktiv - Schatten über Riva (1996)
Zitieren
(29.01.2021, 22:15)Walfänger schrieb:
(28.01.2021, 17:40)Alrik Alrikson schrieb: EDIT: Du kannst bequemer in der DOS-Box die "applyfix.bat" ausführen, dann musst Du nichts mounten, das kommt auf's Selbe raus. Wichtig ist nur, innerhalb der DOS-Umgebung und nicht von Windows aus auszuführen, das funktioniert dann nicht.

Danke für den Tipp! Habe die Schicksalsklinge nun erfolgreich gepatched! Was bedeutet eigentlich, wenn da steht SPIELSTANDXY.GAM erfolgreich aktualisiert? Ist die komplette Spielwelt des Spielstands somit auch gepatched? Ich hatte den Spielstand nämlich extra noch woanders gesichert...
Viele Grüße

Bitte!

Was genau in den Savegames gepatched wird, weiß ich nicht. Aber es soll wohl ermöglichen, ein vorhandenes Savegame weiter nutzen zu können ohne nach dem Patch ein neues Spiel beginnen zu müssen. Eventuell können aber nicht alle Änderungen des Patches rückwirkend auf ein Savegame übertragen werden. Das alles ist aber nur meine Vermutung.
"Alrik war durstig und hat getrunken."
Zitieren
Gespeicherte Spielstände beinhalten den kompletten Status sämtlicher Kämpfe, sobald ein Kampf stattgefunden hat. Da die Dungeon-Lagerkämpfe hinzugefügt werden, müssen sie in allen gespeicherten Spielständen ebenfalls hinzugefügt werden.
Zitieren
bedeutet das dass es jetzt wesentlich mehr differente Kämpfe gibt? die ZUfallskämpfe waren in der Tat etwas eintönig. Wenn ja dann hast du einen Jahrhundertpatch installiert!
Hacke Tau, Kumpels!

Ihr seid Freunde der alten NLT? Freunde des Mikromanagements? Ihr sucht eine neue Herausforderung, weil euch die NLT zu leicht war?

Dann spielt doch mal Schicksalsklinge HD 1.36 von Crafty Studios!
Zitieren
(30.01.2021, 15:19)Lippens die Ente schrieb: bedeutet das dass es jetzt wesentlich mehr differente Kämpfe gibt? die ZUfallskämpfe waren in der Tat etwas eintönig. Wenn ja dann hast du einen Jahrhundertpatch installiert!

Das wurde doch hier besprochen. ;)
"Alrik war durstig und hat getrunken."
Zitieren




Benutzer, die gerade dieses Thema anschauen: 2 Gast/Gäste