Themabewertung:
  • 5 Bewertung(en) - 5 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Reverse Engineering der NLT
(26.01.2017, 13:28)Rabenaas schrieb: Mein Lieblingsscaler ist hq3x. Die Ergebnisse sind erstaunlich.

Im Allgemeinen oder für SCHICK im Speziellen?
(25.01.2017, 23:31)HenneNWH schrieb: Hallo Alrik,

(25.01.2017, 19:05)Alrik Alrikson schrieb:
(25.01.2017, 16:16)HenneNWH schrieb: [...]
Die Ausgabe auf den Framebuffer muss neu geschrieben werden + sinnvolle Skalierungsmöglichkeiten, da eine Auflösung von 320x200 nicht mehr tragbar ist.
[...]

Welche Auflösung wird das fertige Spiel denn dann haben, oder ist es noch zu früh darüber etwas sagen zu können?

das ist schwer zu sagen. Prinzipiell kann man das fertige Bild mit OpenGL auf jede beliebige Größe skalieren,
aber ob das immer schön aussieht ist fraglich. Das Seitenverhältnis der Bilder muss schon beibehalten werden.
Bis jetzt hatte ich mal einige Scaler aus der DOSBox probiert, aber bin bei normal2x geblieben.
Der Grund ist folgender: In Schick muss viel Text gelesen werden und alle Scaler die etwas cleverer sind
versuchen die weiße Schrift mit dem grünen Hintergrund zu verschmelzen.
Die Folge ist eine unscharfe Schrift.
Für die Bilder finde ich die Scaler in Ordnung.

Fazit: Ich denke im Moment, dass die Bilder gezeichnet,
mit einem guten Scaler skaliert und anschließend der Text auf das Resultat geschrieben werden sollte.
Welcher Scaler für Schick am geeignetsten ist, weiß ich auch noch nicht.


Hallo Henne,

danke für Deine Erklärungen.

Dann bleibe ich weiterhin gespannt, wie das fertige Produkt aussehen wird. :)
"Alrik war durstig und hat getrunken."
(26.01.2017, 14:33)HenneNWH schrieb: Im Allgemeinen oder für SCHICK im Speziellen?
Für weitgehend statische, comichafte Grafiken mit viel Text wie bei schrittweisen Dungeoncrawlern. Bei Jump&Runs mag ich den z.B. nicht so.

[Bild: Test_nn.png] [Bild: Test_hq3x.png]
Wo findet man die Texte, die von get_tx() usw. ausgegeben werden? In der EXE?
Ah, zu get_tx usw kann ich etwas sagen. Die Texte stammen sämtlich aus der SCHICK.DAT - je nach Spielsituation aus unterschiedlichen Dateien (mit Endungen *.DTX odr *.LTX). In meinem neulich hier vorgestellten Tool sind diese Dateien gelb eingefärbt.

get_ttx bezieht sich immer auf die TEXT.LTX. Die ist nämlich ständig geladen. get_tx und get_tx2 beziehen sich auf wechselnde Text-Dateien aus der SCHICK.DAT, die in den Variablen TX_INDEX und TX2_INDEX indiziert sind und mit load_tx bzw. load_tx2 nachgeladen werden.

Die Hex-Angaben im Argument von get_tx(...) beziehen sich auf die Offsets in den Index-Tabellen TX_INDEX, TX2_INDEX usw. und können in mein Python-Tool bei den jeweiligen Dateien direkt eingegeben werden.
Ich wollte die Offsets durch geeignete Label ersetzen. Meinst Du, so eine Liste kann man auch automatisiert erstellen?
Meinst du echt, das ist nötig? Das ist echt viel Zeug und man müsste wahnsinnig lange Bezeichner verwenden um damit überhaupt etwas anfangen zu können. Wie wäre es stattdessen, an den jeweiligen Stellen im Code die entscheidenden Strings in Kommentaren anzuführen?
Ich mag keine physikalischen Konstanten im Code. Das ist barbarisch. Hinterher wollen wir vielleicht mal Unicode oder sonstwas. Meine ursprüngliche Idee war z.B. #define TX_A1 0xa1, und dann nach und nach A1 etc. von Hand durch etwas sinnvolles zu ersetzen. Und schon haben wir kostenlos eine Stufe Indirektion. Sowas wie der %S-%s-Fehler würde dann im Header und nicht mehr im eigentlichen Code erledigt.
Ihr gebt dann Bescheid, wenn ihr mit eurem Dekompilier- und Datensegment-Variablenbennennungs-Gedöns so weit seid, dass ich die Programmcode-Änderungen aus meinem umfassenden Patch einpflegen kann? :wave:
(26.01.2017, 22:14)Rabenaas schrieb: Ich mag keine physikalischen Konstanten im Code.
Physikalische Konstanten sind das nicht. Da sind einfach alle Strings durchnummeriert. Das gleiche Problem hat man übrigens auch bei moderner internationaler Software, die sowas wie GNU gettext verwendet, siehe beispielsweise die Diskussion hier: https://stackoverflow.com/questions/2164...glish-text Da scheiden sich die Geister, ob man die (englischen) Strings direkt im Code verwendet, ob man die Strings durchnummeriert (wofür man sich bei der Schicksalsklinge vermutlich entschieden hatte) oder ob man irgendwelche abkürzenden Bezeichnungen verwendet.

Als ersten Schritt könnte man vielleicht die Hexzahlen durch Dezimalzahlen ersetzen. Statt get_tx(0x0c) sollte man get_tx(3) (Faktor 4 kann man immer rauskürzen, der ist immer drin) verwenden. Das würde dann demnächst zu tx_index[3]. Dann könnte man noch sowas machen wie tx_index[msg0273] oder tx_index[tx_ottarje_003] oder tx_index[TX_thorgun_the_strong] (weil der vierte String in der OTTARJE.LTX eben "THORGUN DER STARKE" ist).

Oder was schwebt dir aktuell konkret vor, wie es am Ende aussehen könnte?

Nachtrag: Wenn du eindeutige Identifikatoren definieren willst, die nicht einfach nur durchnummerieren, dann hier ein Vorgeschmack, welche Art von Strings du da voneinander unterscheiden musst (direkt aufeinanderfolgend in FEATURE4.LTX):
Code:
SCHRITT FÜR SCHRITT SCHAUFELT IHR EUCH VORWÄRTS. ES IST BITTERKALT. DER ATEM
GEFRIERT EUCH AUF DER KLEIDUNG, UND GELEGENTLICH HABT IHR DAS GEFÜHL, DASS
EURE ZEHEN GEFÜHLLOS WERDEN. IHR MÜSST EINE PAUSE EINLEGEN UND EIN FEUER
ENTZÜNDEN, WENN IHR NICHT ERFRIEREN WOLLT.
Code:
STUNDE UM STUNDE MARSCHIERT IHR, EURE AUGEN GEBLENDET VON DER ENDLOSEN
SCHNEEWÜSTE, BIS IHR ENDLICH AUF DEN GEWÜNSCHTEN WEG ZURÜCKFINDET.
Code:
STUNDE UM STUNDE MARSCHIERT IHR DURCH DIE ENDLOSE SCHNEEWÜSTE, EURE AUGEN
GEBLENDET, EURE FÜSSE HALB ERFROREN UND EURE KLEIDER STEIFGEFROREN VON
SCHWEISS UND ATEM. IHR WISST NICHT, WIEVIEL ZEIT VERGANGEN IST, ABER
IRGENDWANN KÖNNT IHR NICHT MEHR FESTSTELLEN, WO IHR SEID UND WO IHR
HINWOLLT. ZUDEM MÜSST IHR EINE PAUSE EINLEGEN UND EUCH AUFWÄRMEN, WENN IHR
NICHT ERFRIEREN WOLLT...
Außerdem gibt es solche Strings wie "UMKEHREN UND EUREN WEG FORTSETZEN?" gleich zigfach an unterschiedlichen Stellen in unterschiedlichen LTX-Dateien (teilweise auch mehrmals innerhalb derselben Datei). Werden die dann durchnummeriert?
Na, tx_ottarje_003 wäre doch schon ziemlich aufgeräumt. Man könnte auch gleich das ganze get_tx(0x..) durch je so ein Makro zu ersetzen.

Es wäre schön, wenn wir von so etwas wie
Code:
strcat((char*)Real2Host(ds_readd(DTP2)),
                                (char*)get_tx(0x74));
zu etwas wie
Code:
strcat(STR_AT(DTP2), TX_029);
kämen.
(26.01.2017, 23:24)Rabenaas schrieb: Es wäre schön, wenn wir [...]
Woran wir momentan arbeiten, ist die Wiederherstellung dessen, was vermutlich im Original-Code stand. Und das ist in diesem Fall sehr wahrscheinlich eine dieser Varianten:
Code:
strcat(&dtp2, tx_index[29]);
strcat(&dtp2, tx_index[TX_spelltxt_029]);
strcat(&dtp2, tx_index[TX_spelltxt_and]);
Bis dahin dauert's wirklich nicht mehr lange!

Natürlich kannst du auch das get_tx(...) in die Definition der Makros hineinnehmen, sodass da steht
Code:
strcat(&dtp2, TX_spelltxt_029);
Aber was machst du dann mit sowas?
Code:
get_tx(random_schick(4) + 19)

Nebenbei: Wenn du wirklich die LTX-Datei (also OTTARJE.LTX oder SPELLTXT.LTX usw.) in den Variablennamen hineinnehmen willst, wirst du eine Menge Arbeit vor dir haben. Du müsstest bei jedem der 2500 Aufrufe von get_tx bzw. get_tx2 herausfinden, auf welche Datei sich der Offset jeweils bezieht.

Die kryptischen Hex-Werte der INDEX-Offsets habe ich jetzt durch die etwas brauchbareren Dezimalwerte der String-Nummern ersetzt. Also ein get_tx(0x0c) wird zu get_tx(3) usw. Hier der pull request dazu: https://github.com/Henne/Bright-Eyes/pull/37 Wenn du also etwas in der Richtung machen willst, Rabenaas, schließt du vielleicht am besten daran an.

Edit: Beitrag nochmal umgeschrieben und Infos ergänzt.
Ach, dann verstehe ich jetzt auch das hier.

(25.01.2017, 16:16)HenneNWH schrieb: Phase 2 ist folgendermaßen untergliedert:
  • Mit dem BCC eine SCHICKM.EXE erstellen, in welcher sich der Code aus Phase 1 an genau den richtigen Stellen befindet.
  • Ersetzen der Variablen aus dem Datensegment, welches bis jetzt nur ein großes Feld mit Daten ist, durch Variablen, welche in C deklariert und ggf. definiert sind.

Im Moment arbeite ich an Punkt 1, gaor an Punkt 2.
Ich bin schon bis zu Segment seg014 vorgedrungen, an welchem es noch kleine Unterschiede gibt, anschließend kommen die Stub-Segmente, das Datensegment und schließlich der Code (seg024-seg122) welche aus der SCHICKM.EXE bei Bedarf nachgeladen werden. Die Stub-Segmente und der nachladbare Code sollten schon soweit identisch sein, das Datensegment ist vorerst nur ein
großes Feld mit lauter Nullen.
Diese Nullen werden durch die Arbeit von gaor durch _richtige_ Daten ersetzt, wodurch der Code wesentlich lesbarer werden wird.

Wie gehst Du vor? Variablen deklarieren und hoffen, dass es passt?
Ich bin momentan noch nicht so ganz sicher, an welcher Stelle im Code ich globale Variablen am Ende deklarieren muss, damit auch die Reihenfolge passt. Aber prinzipiell ist die Idee, bei den Einträgen in symbols.h einen Eintrag der Form...
Code:
#define HERBS_TOXIC                     (0x08e7)    /* signed short[5]; { SHURINKNOLLE (0x7a), ALRAUNE (0x7e), LOTUSBLUTE (0x84), EITRIGER KROTENSCHEMEL (0x3e), 0xff } */
... in eine Deklaration der folgenden Art zu verwandeln:
Code:
signed short herbs_toxic[5] = { ITEM_SHURINKNOLLE, ITEM_ALRAUNE, ITEM_LOTUSBLUTE, ITEM_EITRIGER_KROTENSCHEMEL, 0xff };
Momentan schiebe ich das auf, bis ich wirklich alle Einträge in der symbols.h entschlüsselt habe. Das wäre aber eigentlich gar nicht nötig. Man könnte auch die bisher unbekannten Einträge durch Bezeichnungen wie SYM_UNKNOWN_01 ersetzen und direkt loslegen. Wenn mir jemand sagt, wo im Code die Deklarationen hinmüssen, damit sie am Ende in der EXE an der richtigen Stelle erscheinen, dann lege ich sofort damit los.
Wäre es ggf. eine Möglichkeit, die Variablen als extern zu deklarieren, in einer eigenen c-Datei zu definieren? Diese c-Datei müsste man per pragma in ein beliebiges Segment einordnen lassen können.
(27.01.2017, 12:27)Rabenaas schrieb: Ach, dann verstehe ich jetzt auch das hier.

(25.01.2017, 16:16)HenneNWH schrieb: Phase 2 ist folgendermaßen untergliedert:
  • Mit dem BCC eine SCHICKM.EXE erstellen, in welcher sich der Code aus Phase 1 an genau den richtigen Stellen befindet.
  • Ersetzen der Variablen aus dem Datensegment, welches bis jetzt nur ein großes Feld mit Daten ist, durch Variablen, welche in C deklariert und ggf. definiert sind.

Im Moment arbeite ich an Punkt 1, gaor an Punkt 2.
Ich bin schon bis zu Segment seg014 vorgedrungen, an welchem es noch kleine Unterschiede gibt, anschließend kommen die Stub-Segmente, das Datensegment und schließlich der Code (seg024-seg122) welche aus der SCHICKM.EXE bei Bedarf nachgeladen werden. Die Stub-Segmente und der nachladbare Code sollten schon soweit identisch sein, das Datensegment ist vorerst nur ein
großes Feld mit lauter Nullen.
Diese Nullen werden durch die Arbeit von gaor durch _richtige_ Daten ersetzt, wodurch der Code wesentlich lesbarer werden wird.

Wie gehst Du vor? Variablen deklarieren und hoffen, dass es passt?

Im Wesentlichen ja. Das kann ich allerdings erst machen wenn der komplette Code an der richtigen Stelle ist.
Wie der Linker (TLINK) von BCC die Daten anordnet habe ich schon herausgefunden,
bzw. kann man sich beim Linken eine MAP-Datei erstellen, in welcher alle Positionen der globalen Variablen stehen.
Zuerst kommen die initialisierten Variablen in der Reihenfolge, in der die Objektdateien an den Linker übergeben werden.
Also erst die CLIB, dann seg001, seg002,...,seg122.
Typisierte Konstanten (const) sind initialisierte Daten.
Danach kommen die uninitialisierten Daten (BSS) in derselben Reihenfolge.

Wie es aber am realisiert werden soll, weiß ich noch nicht.
Ich glaube aber, dass eine große C-Datei mit Daten erstmal am besten funktioniert.

Im Original sind die Daten teilweise auf die C-Dateien verteilt worden,
die Beschreibungen der Schatztruhen in den Dungeons, in denen sie vorkommen,
Tabellen für Händler bei den Händlern, etc.
Bei dem Speicherbereich für den Spielstand und den Tabellen würde ich vielleicht eine Ausnahme (eigene Datei) machen.
So, die symbols.h ist jetzt im Wesentlichen vollständig und die globalen Variablen könnten also deklariert werden: https://github.com/Henne/Bright-Eyes/pull/41

Übrigens habe ich noch ein bisschen mit meinem Tool herumgespielt. Man kann jetzt auch die Karten von Dungeons und Städten anschauen - inkl. Kämpfen, Türen, Treppen und Gebäuden:

[Bild: screenshot4.png]
Ich könnte jetzt das Datensegment über die datseg.cpp füllen. Der Code ist hier: http://pastebin.com/sSgNjd13 Es fehlen nur noch etwa 270 Zeilen - das wäre schnell durchgecheckt. Aber der BCC beschwert sich:

Code:
Error datseg.cpp 1595: Group overflowed maximum size: DGROUP

Jemand eine Ahnung, was man dagegen macht?
Wäre es eigentlich möglich, den Download auf github auszulagern? Dafür müsste für jeden Download releases festgelegt werden und jemand (ich) könnte dann die binaries beisteuern. Habe ich schon bei mehreren Softwareprojekten gesehen.

https://github.com/blog/1547-release-your-software

Ein Vorteil wäre, dass ich hier nicht mehr mit den Anhängen hantieren müsste. Außerdem würde das Forum/Crystal aus dem Fokus genommen, was vor allem aus rechtlicher Sicht so langsam immer bedenkenswerter wird. Das Download-Thema würde ich weiterhin pflegen, aber mit externem Download. Viel wird das Binary eh nicht heruntergeladen....
--------
Warnung! Geschichte kann zu Einsichten führen und verursacht Bewusstsein!
Avatar by: Keven Law (CC BY-SA 2.0)
(12.02.2017, 17:30)gaor schrieb: Ich könnte jetzt das Datensegment über die datseg.cpp füllen. Der Code ist hier: http://pastebin.com/sSgNjd13 Es fehlen nur noch etwa 270 Zeilen - das wäre schnell durchgecheckt. Aber der BCC beschwert sich:

Code:
Error datseg.cpp 1595: Group overflowed maximum size: DGROUP

Jemand eine Ahnung, was man dagegen macht?

Der Fehler kommt wenn dein Segment > 64k ist

laut https://github.com/Henne/Bright-Eyes/blo...e/datseg.h
ist das Datensegment (0xf7af - 0x936 - 2) = 0xEE77 = 61047 Bytes - also noch unter 64k

ich würde aber (wenn nicht 100% klar ist wo was liegt) vorsichtig vorgehen:

1. einen Struct mit den ds-Variablen definieren - und mit static_assert/offsetof dauerhaft Offset und komplette Größe prüfen

2. gehörig auf das Alignment achten (könnte sich bei BCC zu gcc usw. unterscheiden - was tödlich wäre)
siehe #pragma pack(1) (https://msdn.microsoft.com/de-de/library/2e70t5y1.aspx)

Code:
#pragma pack(push,1)
struct ds_structur
{
  char dummy1[4];
  char g_str_borland_cpp[43]; // ds:0x0004
  char g_str_divide_error[45]; // ds:0x002f  
  //...
  char dummy_filler[61047-94];
};
#pragma pack(pop)
//wenn gcc oder VS2010
static_assert(sizeof(ds_structur) == 61047, "wrong ds size");
//...
static_assert(offsetof(ds_structur, g_str_borland_cpp) == 0x0004);
static_assert(offsetof(ds_structur, g_str_divide_error) == 0x002f);
//...

3. die ds-Variable auf den Struct-casten - und damit arbeiten - dann bleiben die Initalwerte erstmal wo sie sind

...

4. eine weitere instanz von ds_structur erzeugen - die members einzeln fuellen und pruefen ob das
dem Inhalt von ds entspricht - dauerhaft

Code:
ds_structur fuell_test;
assert(sizeof(ds) == sizeof(fuell_test));
::memset(fuell_test.dummy1, 0, sizeof(fuell_test.dummy1));
const char fix1[] = "Borland C++ - Copyright 1991 Borland Intl.";
::memcpy(fuell_test.g_str_borland_cpp, fix1, sizeof(fix1)-1);
const char fix2[] = "Divide error\r\nAbnormal program termination\r\n";
fuell_test.g_str_divide_error, fix2, sizeof(fix2)-1);
//...
assert(::memcmp(fuell_test, ds, sizeof(fuell_test)) == 0);

und wenn alles passt kannst du die char ds[...] durch ds_structur ds; ersetzen

am einfachsten ist es wohl wenn du eine Liste der Variablen, Typen und Offsets hast dann kannst du dir
den ganzen Code mit Python oder sonstwas einfach generieren




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