Ich schlage vor, du lässt XMScopy die tatsächlich empfangenen Werte anzeigen, damit du drüber schauen kannst, ob sich irgendwo irgendwas verrechnet.
Statt unsigned int könntest du auch einen extra zu dem Zweck definierten uint16 Typ verwenden, um deutlicher zu machen, was wo übergeben wird.
XMScopy könnte statt ZWEI 16-bit Werten (entweder Segment und Offset im DOS Speicher oder obere und untere 16 Bit des XMS-Offsets) auch EINEN 32-bit Wert annehmen. Far Pointer sind sowieso 32 Bit und der 32 Bit Offset auch. Dann sparst du dir in beiden Fällen die Umrechnung. Noch eleganter wäre eine union, die die gleichen 4 Bytes einmal als 16 Bit DOS Segment und 16 Bit DOS Offset und einmal als einen 32 Bit Offset interpretiert, für bessere Lesbarkeit.
unsigned int XMSbl=XMSb;
unsigned int XMSbh=XMSb>>16;
Das ist eine eher unleserliche Methode, 32 Bit "XMSb" zu zerstückeln. Lass das lieber an einem 32 Bit Stück. Ich vermisse auch ein XMSbl = XMSb & 0xffff um zumindest explizit zu machen, dass die oberen 16 Bit der 32 Bit Variable bewusst verworfen werden, wenn du die unteren in eine 16 Bit Variable rüberkopierst.
Es ist natürlich auch ein wenig eine Glaubensfrage, aber willst du dir wirklich den Schmerz mit den vielen 16-Bit Stücken von 32-Bit Variablen antun, damit dein Spiel auf 286 lauffähig bleibt? Wenn du einen 386 als Mindestanforderung nimmst, kannst du bequem 32 Bit am Stück in einem Register wie EAX transportieren. Und auf älteren als 286 PC läuft das Spiel sowieso nicht, weil es dort kein XMS geben kann. Mal ganz abgesehen von der Geschwindigkeit
... (DCa<<16)>>16,DCa>>16, ...
Auch hier würde ich wieder sagen: Übergib lieber 32 Bit am Stück, statt den DCa (seltsamer Name für "Quelloffset der gewünschten Textur im XMS Block") auf seltsame Weise in zwei 16-Bit Teile zu zerlegen. Und wieso machst du diesmal "32 Bit Variable um 16 Bit nach links schieben, dann wieder 16 Bit nach rechts, dann in 16 Bit Argument kopieren", während du bei XMSbl überhaupt nicht geschoben hast? Anders gesagt, du könntest es so machen:
... DCa & 0xffff, DCa >> 16, ...
oder eben noch besser mit weniger, aber dafür 32 Bit Argumenten:
// Typ-Definitionen gerne als Header verwenden, hat Borland evtl. auch schon irgendwo fertig vorbereitet:
typedef unsigned char uint8;
typedef unsigned int uint16; // falls 32 Bit Compiler: unsigned short
typedef unsigned long int uint32; // falls 32 Bit Compiler: unsigned int
// Ausschnitt aus getsprite:
uint32 TexturOffset = TNr;
TexturOffset *= 1026;
if (!XMScopy(XMShandle, TexturOffset ,(uint32)&MXsprite[55][0], 1026)) { // if returned value is 0, false, not okay:
... Fehlermeldung mit Fehlercode XMSfehler anzeigen
}
// Variante von XMScopy mit 32-Bit Quellen- und Ziel-Offset und Laenge:
// int XMScopy(unsigned int XMSqh, unsigned int XMSqo, unsigned int XMSqs, unsigned int XMSzh, unsigned int XMSzo, unsigned int XMSzs, unsigned long XMSb )
uint16 XMScopy(uint16 XmsSourceHandle, uint32 XmsSourceOffset, uint16 XmsDestHandle, uint32 XmsDestOffset, uint32 CopySize)
{
if ((CopySize & 1) != 0) {
... prueft zwar der XMS Treiber auch selbst, aber selber pruefen kann interessant sein?
XMSfehler = 0xa7; // invalid length
return 0;
}
if (XmsSourceHandle == 0 && XmsDestHandle == 0) {
... evtl. Warnung ausgeben, dass Kopie sowohl vom als auch zum DOS Speicher stattfinden wird?
}
... evtl. Sicherheitsabfrage einbauen, ob FP_SEG bei Handles die 0 sind im plausiblen Bereich liegt?
... wie oben: XMS Treiber prueft zwar selbst, ob Offset und (Offset + CopySize) bei XMS Handles zur Laenge passen, aber das selbst pruefen kann auch wieder interessant sein.
asm {
... left as an exercise to the reader ;-)
}
return XMStest; // woher kommt die Variable eigentlich, ist die global? Oder erzeugt die Erwaehnung im ASM Block sie lokal?
}
Alles anzeigen
Dass dein XMS Handle den festgelegten Wert 1 genau in dem Moment bekommt, zu dem getsprite ihn wissen will, kann eigentlich auch nicht sein. Der Handle sollte vom Treiber beantragt werden, Handle 1 kann wer weiss was sein. Wenn du den Eindruck hast, dass der Handle Wert manchmal verloren geht, mach lieber was in der Richtung von "if XMShandle < 1 then gibt Fehlermeldung aus, dass XMS Handle auf einmal auf DOS Speicher zeigt, und bricht das Programm an der Stelle ganz ab, oder brich wenigstens getsprite ab".
Wegen diesem "Buche den Handle bevor die Borland IDE startet und gib ihn dann wieder frei, damit das Spiel ihn verwenden kann", kannst du ja trotzdem deine "Besorge dir einen 4 MB XMS Handle" Funktion zu Testzwecken immer 1 returnen lassen, aber die 1 (oder besser ein einstellbarer Wert, evtl. per Command Line Argument deines Spiels einstellbar) sollte nur an dieser einen einzigen Stelle im Quelltext vorkommen und nicht erst mitten in getsprite auftauchen.
Wie ist in dem Zusammenhang das hier gemeint?
if (XMShandle!=1) Xprint(28,10,14,"XMSHANDLE");//Speicherbedarf am Anfang anzeigen
if (XMShandle!=1) Xprint(28,30,12,TNr);//Speicherbedarf am Anfang anzeigen
Es scheint in die Richtung von "wenn XMShandle noch nicht gebucht ist, gib irgendwas aus" zu gehen, aber das ist wie gesagt gar nicht die richtige Stelle, um den Handle zu buchen. Ausserdem ist es seltsam, dass Xprint sowohl Strings als auch Integers wie TNr ausgeben kann, wie macht es das?