AGI/Specifications/Other/AGI256/Implementation Details
In the original PC AGI interpreter v2.936 the engine holds the color and priority/control line information for each pixel in a 160x200 byte buffer. The color data for each pixel is held in the byte's lower 4 bits and the priority/control line data is held in the upper 4 bits.
AGI256 extends this 160x200 byte buffer to a 320x200 byte buffer so that the 256-color data is held in the right 160x200 half of the buffer and the original style 16-color and priority/control line information is held in the left 160x200 half of the buffer.
Used external info
I used Nick Sonneveld's disassemblies of various PC AGI interpreter versions when trying to figure out AGI256. Those IDA databases were highly useful for understanding. Thanks Nick. You can check out the disassemblies if you're interested at the AGI Development Site.
Differences between AGI v2.936 and AGI256
Added files in AGI256:
- AGIGRAF.OVL
- AGIOBJS.OVL
Differences in the following files:
- AGI.EXE
- AGIDATA.OVL
Reverse engineered C version of AGI256's AGIOBJS.OVL
Things may be wrong, misleading etc. Caveat emptor.
This is the cel blitting routine from AGIOBJS.OVL.
struct blitStruct { uint8 b0; uint8 b1; uint8 notEgo; // Sort of a guess based on variable's usage, may also be dontUpdateEgoVisibility or something like that uint16 xPos; uint16 yPos; // Is this named correctly? uint8 b7; uint8 b8; uint8 b9; uint8 b10; uint8 b11; uint8 b12; uint8 b13; uint8 b14; uint8 b15; struct celStruct *celPtr; // Offset into segment DS really, 16 bits uint8 b18; uint8 b19; uint8 b20; uint8 b21; uint8 b22; uint8 b23; uint8 b24; uint8 b25; uint8 b26; uint8 b27; uint8 b28; uint8 b29; uint8 b30; uint8 b31; uint8 b32; uint8 b33; uint8 b34; uint8 b35; uint8 celPriority; }; struct celStruct { uint8 width; // This is a guess uint8 height; union { uint8 flags; // Uses values from enum flagsEnum uint8 transparentColor; // Only lower 4 bits }; uint8 rleData[?]; }; enum flagsEnum { F_MIRROR = 1 << 7; }; #define _WIDTH 160 #define _HEIGHT 168 uint16 screenOffset(uint8 x, uint8 y) { return y * (_WIDTH * 2) + x; } void agi256BlitCel(struct blitStruct *s) { uint8 *pic = &agi256PicSeg[0]; const uint16 endPos = (_WIDTH * 2) * (_HEIGHT - 1); // I would have put (((_WIDTH * 2) * (_HEIGHT - 1)) - _WIDTH) here bool celInvisible = true; uint8 height = s->celPtr->height; uint8 celPriority = s->celPriority; if (s->celPtr->flags & F_MIRROR) // Test for mirroring blitMirrorCell(); uint8 *rleData = s->celPtr->rleData; uint16 pos = screenOffset(s->xPos, s->yPos - height + 1); uint8 transparentColor = s->celPtr->transparentColor; do { uint16 oldPos = pos; while (uint8 rleByte = *(rleData++)) { // rleByte != 0 uint8 runColor = rleByte >> 4; uint8 runLength = rleByte & 0x0f; if (runColor == transparentColor) { // Check for transparency pos += runLength; } else do { uint8 pixelPriority = pic[pos] >> 4; // Read pixel's priority/control line info if (pixelPriority < 3) { pixelPriority = 0; for (uint16 ySearchPos = pos + _WIDTH * 2; ySearchPos < endPos && (pixelPriority = pic[ySearchPos] >> 4) < 3; ySearchPos += _WIDTH * 2); } if (celPriority >= pixelPriority) { pic[pos + _WIDTH] = runColor; celInvisible = false; } pos++; } while (--runLength > 0); } pos = oldPos + _WIDTH * 2; } while (--height > 0); if (!s->notEgo) setFlag(f1, celInvisible); }
Differences between AGI v2.936's AGIDATA.OVL and AGI256's AGIDATA.OVL
dseg:0x08C5: dw offset CmdUnknown170
Unknown170 command's subroutine's location has been changed from the original 0x2726 to hacked 0x9975. 0x9975 goes beyond what is in AGI.EXE so it goes to point to the AGIGRAF.OVL's functions. AGIGRAF.OVL is loaded into cseg:0x9800 so taking away the displacement we get 0x9975-0x9800 = 0x175. See the AGIGRAF.OVL disassembly for more details about the function that this points to.
Disassembly of AGIGRAF.OVL
codeseg:9800 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9800 codeseg:9800 ; AGIGRAF.OVL starts here at 0x9800 codeseg:9800 ; Attributes: thunk codeseg:9800 codeseg:9800 j_AG_setGrafMode proc near ; CODE XREF: sub_5528+14�p codeseg:9800 jmp AG_setGrafMode ; In Sonneveld's Agi2917.idb there was j_EGAGrafMode here. codeseg:9800 j_AG_setGrafMode endp ; codeseg:9800 ; Sets 320x200 256 color video mode (Mode 13h), codeseg:9800 ; sets ds:[videoOfs] to 0xA000 and codeseg:9800 ; clears first 64 KiB of video memory with zeroes. codeseg:9803 codeseg:9803 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9803 codeseg:9803 ; Attributes: thunk codeseg:9803 codeseg:9803 j_AG_setTextMode proc near ; CODE XREF: cmd_text_screen_106+1E�p codeseg:9803 jmp AG_setTextMode ; In Sonneveld's Agi2917.idb there was j_EGATextMode here. codeseg:9803 j_AG_setTextMode endp ; codeseg:9803 ; Sets 40x25 16 color text mode, codeseg:9803 ; enables background intensity (Colors 8-15), codeseg:9803 ; sets some cursor stuff and codeseg:9803 ; clears the text screen using ds:[textClrAttr] attribute. codeseg:9806 codeseg:9806 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9806 codeseg:9806 ; Attributes: thunk codeseg:9806 codeseg:9806 j_AG_agi256ShowPic proc near ; CODE XREF: sub_78CB+18�p codeseg:9806 jmp AG_agi256ShowPic ; In Sonneveld's Agi2917.idb there was j_EGAShowPic here. codeseg:9806 j_AG_agi256ShowPic endp ; codeseg:9806 ; Sets the 320x200 256 color video mode, codeseg:9806 ; clears screen etc (Look at setVideoMode) codeseg:9806 ; and calls an unknown function. codeseg:9809 codeseg:9809 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9809 codeseg:9809 ; Attributes: thunk codeseg:9809 codeseg:9809 j_AG_emptyFunc4 proc near codeseg:9809 jmp AG_emptyFunc4 ; In Sonneveld's Agi2917.idb there was an empty function here too. codeseg:9809 j_AG_emptyFunc4 endp ; codeseg:9809 ; Does nothing. Don't know what functionality codeseg:9809 ; would have been here in the original AGI interpreter. codeseg:9809 ; Maybe something to do with other than EGA graphics adapters? codeseg:980C codeseg:980C ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:980C codeseg:980C ; Attributes: thunk codeseg:980C codeseg:980C j_AG_agi256PutBlock proc near ; CODE XREF: _Pic_Show+40�p codeseg:980C ; sub_560C+E�p ... codeseg:980C jmp AG_agi256PutBlock ; In Sonneveld's Agi2917.idb there was j_EGAPutBlock here. codeseg:980C j_AG_agi256PutBlock endp ; codeseg:980C ; Shows an AGI 256 picture (Puts it into video memory). codeseg:980C ; Uses x2 horizontal stretching. codeseg:980F codeseg:980F ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:980F codeseg:980F ; Attributes: thunk codeseg:980F codeseg:980F j_AG_calcHeightLUT proc near ; CODE XREF: sub_5528+E�p codeseg:980F jmp AG_calcHeightLUT ; In Sonneveld's Agi2917.idb there was j_EGAInit here. codeseg:980F j_AG_calcHeightLUT endp ; codeseg:980F ; Precalculates table for Y*320 values (0 <= y < 200) codeseg:9812 codeseg:9812 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9812 codeseg:9812 ; Attributes: thunk codeseg:9812 codeseg:9812 j_AG_agi256FilledRect proc near ; CODE XREF: _BoxNBorder+11�p codeseg:9812 ; _BoxNBorder+28�p ... codeseg:9812 jmp AG_agi256FilledRect ; In Sonneveld's Agi2917.idb there was j_EGAFilledRect here. codeseg:9812 j_AG_agi256FilledRect endp ; codeseg:9812 ; Fills a solid rectangle in video memory with a given fill color. codeseg:9812 ; Inputs: codeseg:9812 ; DL = fill color codeseg:9812 ; AL = yPos ?? (More like last row) codeseg:9812 ; AH = xPos codeseg:9812 ; BH = yLen codeseg:9812 ; BL = xLen codeseg:9815 codeseg:9815 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9815 codeseg:9815 ; In Sonneveld's Agi2917.idb there was j_EGAGrafMode here. codeseg:9815 ; codeseg:9815 ; Sets 320x200 256 color video mode (Mode 13h), codeseg:9815 ; sets ds:[videoOfs] to 0xA000 and codeseg:9815 ; clears first 64 KiB of video memory with zeroes. codeseg:9815 codeseg:9815 AG_setGrafMode proc near ; CODE XREF: j_AG_setGrafMode�j codeseg:9815 ; AG_agi256ShowPic+8�p codeseg:9815 mov ax, 13h codeseg:9818 int 10h ; - VIDEO - SET VIDEO MODE codeseg:9818 ; AL = mode codeseg:981A mov bx, 0A000h codeseg:981D mov videoSeg, bx codeseg:9821 nop codeseg:9822 nop codeseg:9823 nop codeseg:9824 nop codeseg:9825 nop codeseg:9826 nop codeseg:9827 push es codeseg:9828 mov es, videoSeg codeseg:982C xor ax, ax codeseg:982E mov di, ax codeseg:9830 mov cx, 8000h codeseg:9833 repe stosw codeseg:9835 pop es codeseg:9836 retn codeseg:9836 AG_setGrafMode endp codeseg:9836 codeseg:9837 codeseg:9837 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9837 codeseg:9837 ; In Sonneveld's Agi2917.idb there was j_EGATextMode here. codeseg:9837 ; codeseg:9837 ; Sets 40x25 16 color text mode, codeseg:9837 ; enables background intensity (Colors 8-15), codeseg:9837 ; sets some cursor stuff and codeseg:9837 ; clears the text screen using ds:[textClrAttr] attribute. codeseg:9837 ; Attributes: bp-based frame codeseg:9837 codeseg:9837 AG_setTextMode proc near ; CODE XREF: j_AG_setTextMode�j codeseg:9837 push si codeseg:9838 push di codeseg:9839 push bp codeseg:983A mov bp, sp codeseg:983C sub sp, 2 codeseg:983F mov ax, 1 ; Set 40x25 16 color text (AH = 0, AL = 1) codeseg:9842 int 10h ; - VIDEO - SET VIDEO MODE codeseg:9842 ; AL = mode codeseg:9844 mov ax, 1003h codeseg:9847 xor bx, bx ; Disable blinking i.e. enable background intensity (Colors 8-15). codeseg:9849 int 10h ; - VIDEO - TOGGLE INTENSITY/BLINKING BIT (Jr, PS, TANDY 1000, EGA, VGA) codeseg:9849 ; BL = 00h enable background intensity codeseg:9849 ; = 01h enable blink codeseg:984B mov cx, 3000h codeseg:984E mov ah, 1 codeseg:9850 int 10h ; - VIDEO - SET CURSOR CHARACTERISTICS codeseg:9850 ; CH bits 0-4 = start line for cursor in character cell codeseg:9850 ; bits 5-6 = blink attribute codeseg:9850 ; CL bits 0-4 = end line for cursor in character cell codeseg:9852 xor bh, bh codeseg:9854 xor dx, dx codeseg:9856 mov ah, 2 codeseg:9858 int 10h ; - VIDEO - SET CURSOR POSITION codeseg:9858 ; DH,DL = row, column (0,0 = upper left) codeseg:9858 ; BH = page number codeseg:985A mov bh, byte ptr textClrAttr codeseg:985E xor al, al ; AL = 0 = blank whole window codeseg:9860 xor cx, cx ; CH = row 0 codeseg:9860 ; CL = column 0 codeseg:9862 mov dx, 1827h ; DH = row 24 codeseg:9862 ; DL = column 39 codeseg:9865 mov ah, 6 codeseg:9867 int 10h ; - VIDEO - SCROLL PAGE UP codeseg:9867 ; AL = number of lines to scroll window (0 = blank whole window) codeseg:9867 ; BH = attributes to be used on blanked lines codeseg:9867 ; CH,CL = row,column of upper left corner of window to scroll codeseg:9867 ; DH,DL = row,column of lower right corner of window codeseg:9869 add sp, 2 codeseg:986C pop bp codeseg:986D pop di codeseg:986E pop si codeseg:986F retn codeseg:986F AG_setTextMode endp codeseg:986F codeseg:9870 codeseg:9870 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9870 codeseg:9870 ; In Sonneveld's Agi2917.idb there was j_EGAShowPic here. codeseg:9870 ; codeseg:9870 ; Sets the 320x200 256 color video mode, codeseg:9870 ; clears screen etc (Look at setVideoMode) codeseg:9870 ; and calls an unknown function. codeseg:9870 ; Attributes: bp-based frame codeseg:9870 codeseg:9870 AG_agi256ShowPic proc near ; CODE XREF: j_AG_agi256ShowPic�j codeseg:9870 push si codeseg:9871 push di codeseg:9872 push bp codeseg:9873 mov bp, sp codeseg:9875 sub sp, 2 codeseg:9878 call AG_setGrafMode ; In Sonneveld's Agi2917.idb there was j_EGAGrafMode here. codeseg:9878 ; codeseg:9878 ; Sets 320x200 256 color video mode (Mode 13h), codeseg:9878 ; sets ds:[videoOfs] to 0xA000 and codeseg:9878 ; clears first 64 KiB of video memory with zeroes. codeseg:987B call _Pic_Show ; Was _Pic_Show in Agi2917.idb codeseg:987E add sp, 2 codeseg:9881 pop bp codeseg:9882 pop di codeseg:9883 pop si codeseg:9884 retn codeseg:9884 AG_agi256ShowPic endp codeseg:9884 codeseg:9885 codeseg:9885 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9885 codeseg:9885 ; In Sonneveld's Agi2917.idb there was an empty function here too. codeseg:9885 ; codeseg:9885 ; Does nothing. Don't know what functionality codeseg:9885 ; would have been here in the original AGI interpreter. codeseg:9885 ; Maybe something to do with other than EGA graphics adapters? codeseg:9885 codeseg:9885 AG_emptyFunc4 proc near ; CODE XREF: j_AG_emptyFunc4�j codeseg:9885 retn codeseg:9885 AG_emptyFunc4 endp codeseg:9885 codeseg:9886 codeseg:9886 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9886 codeseg:9886 ; In Sonneveld's Agi2917.idb there was j_EGAPutBlock here. codeseg:9886 ; codeseg:9886 ; Shows an AGI 256 picture (Puts it into video memory). codeseg:9886 ; Uses x2 horizontal stretching. codeseg:9886 codeseg:9886 AG_agi256PutBlock proc near ; CODE XREF: j_AG_agi256PutBlock�j codeseg:9886 codeseg:9886 xPos = ah ; Use case: 0 codeseg:9886 yPos = al ; Use case: 167 (Is this register named correctly??) codeseg:9886 xLen = bl ; Use case: 160 codeseg:9886 yLen = bh ; Use case: 168 codeseg:9886 codeseg:9886 test xPos, 1 codeseg:9889 jz xPosEven codeseg:988B dec xPos ; xPos wasn't even, so make it even by decreasing it by one codeseg:988D inc xLen codeseg:988F codeseg:988F xPosEven: ; CODE XREF: AG_agi256PutBlock+3�j codeseg:988F inc xLen codeseg:9891 and xLen, 11111110b ; Make xLen even codeseg:9894 mov cx, bx codeseg:9896 sub yPos, yLen codeseg:9898 codeseg:9898 loc_9898: ; CODE XREF: sub_5257+14�p codeseg:9898 ; _Pic_Show+35�p ... codeseg:9898 inc yPos ; Some Hercules code used to be at codeseg:0x9899 codeseg:9898 ; but isn't anymore. It's shouldn't be called in AGI256 at all. codeseg:989A codeseg:989A loc_989A: ; Calculates the screen offset for given coordinate? Video or AGI screen offset? codeseg:989A call screenOffset ; DI = AL * 320 + AH codeseg:989A ; (Destroys BX contents (Returns with BH = 0, BL = AH)) codeseg:989A ; codeseg:989A ; Maybe not named quite correctly? codeseg:989D mov si, di codeseg:989F call agiToScreenCoords ; Calculates (baseY+Y)*320 + X*2 codeseg:989F ; codeseg:989F ; Inputs: AL = Y, AH = X codeseg:989F ; Reads from DS:[byte_B389] = baseY codeseg:989F ; (Actually reads baseY as a word, but uses it like codeseg:989F ; it can't overflow to over 8 bits when adding Y to it) codeseg:989F ; Returns: DI = heightLUT[baseY+Y] + X*2 = (baseY+Y)*320 + X*2 codeseg:989F ; (Side-effects: BH = 0, BL = AH = X) codeseg:98A2 jmp AG_convCoord ; Input: CX codeseg:98A2 AG_agi256PutBlock endp ; BH = CH = Y codeseg:98A2 ; BL = CL/2 = X / 2 codeseg:98A2 ; SI += 160 (Go to right half of the 320x168 area) codeseg:98A2 ; goto AG_stretchToScreen codeseg:98A5 ; --------------------------------------------------------------------------- codeseg:98A5 nop codeseg:98A6 codeseg:98A6 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:98A6 codeseg:98A6 ; Copies data from agi256 picture segment to video memory with x2 horizontal stretching. codeseg:98A6 ; Both source and destination buffers use a stride/pitch of 320 bytes. codeseg:98A6 ; Inputs: codeseg:98A6 ; BL = xLen codeseg:98A6 ; BH = yLen codeseg:98A6 ; SI = srcOffset codeseg:98A6 ; DI = destOffset codeseg:98A6 codeseg:98A6 AG_stretchToScreen proc near ; CODE XREF: AG_convCoord+8�j codeseg:98A6 codeseg:98A6 xLen = bl codeseg:98A6 yLen = bh codeseg:98A6 xCounterHi = ch codeseg:98A6 xCounterLo = cl codeseg:98A6 codeseg:98A6 push ds codeseg:98A7 push es codeseg:98A8 mov es, videoSeg codeseg:98AC mov ds, agi256PicSeg codeseg:98B0 codeseg:98B0 yLoop: ; CODE XREF: AG_stretchToScreen+2E�j codeseg:98B0 xor xCounterHi, xCounterHi ; Stretches source AGI 256 picture into video memory codeseg:98B0 ; (Doubles the width of the picture, so 160 becomes 320 etc). codeseg:98B0 ; BL = source width (Probably 160)? codeseg:98B0 ; BH = source height (Probably 168)? codeseg:98B2 mov xCounterLo, xLen codeseg:98B4 push di codeseg:98B5 push si codeseg:98B6 codeseg:98B6 xLoop: ; CODE XREF: AG_stretchToScreen+1E�j codeseg:98B6 lodsw ; Read word from AGI 256 picture buffer codeseg:98B7 nop codeseg:98B8 nop codeseg:98B9 nop codeseg:98BA mov dl, ah codeseg:98BC mov ah, al codeseg:98BE stosw ; Put first read byte twice into video memory codeseg:98BF mov al, dl codeseg:98C1 mov ah, al codeseg:98C3 stosw ; Put second read byte twice into video memory codeseg:98C4 loop xLoop ; Loop xCounterLo times (xCounterHi is zero) codeseg:98C6 pop si codeseg:98C7 pop di codeseg:98C8 dec yLen codeseg:98CA jz end codeseg:98CC add si, 320 ; Figuring that source image width is 160 and still its pointer codeseg:98CC ; is added by 320 rather than 160 when going to the next line... codeseg:98CC ; it might make sense if the priorities are 160 wide per row as well codeseg:98CC ; and a row of picture data is always followed by a row of priority data. codeseg:98D0 add di, 320 codeseg:98D4 jmp short yLoop ; Stretches source AGI 256 picture into video memory codeseg:98D4 ; (Doubles the width of the picture, so 160 becomes 320 etc). codeseg:98D4 ; BL = source width (Probably 160)? codeseg:98D4 ; BH = source height (Probably 168)? codeseg:98D6 ; --------------------------------------------------------------------------- codeseg:98D6 codeseg:98D6 end: ; CODE XREF: AG_stretchToScreen+24�j codeseg:98D6 pop es codeseg:98D7 pop ds codeseg:98D8 retn codeseg:98D8 AG_stretchToScreen endp codeseg:98D8 codeseg:98D9 codeseg:98D9 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:98D9 codeseg:98D9 ; In Sonneveld's Agi2917.idb there was j_EGAFilledRect here. codeseg:98D9 ; codeseg:98D9 ; Fills a solid rectangle in video memory with a given fill color. codeseg:98D9 ; Inputs: codeseg:98D9 ; DL = fill color codeseg:98D9 ; AL = yPos ?? (More like last row) codeseg:98D9 ; AH = xPos codeseg:98D9 ; BH = yLen codeseg:98D9 ; BL = xLen codeseg:98D9 codeseg:98D9 AG_agi256FilledRect proc near ; CODE XREF: j_AG_agi256FilledRect�j codeseg:98D9 codeseg:98D9 yLen = bh codeseg:98D9 xLen = bl codeseg:98D9 codeseg:98D9 push es codeseg:98DA mov es, videoSeg codeseg:98DE mov dh, dl codeseg:98E0 sub al, yLen codeseg:98E2 inc al codeseg:98E4 mov cx, bx codeseg:98E6 call agiToScreenCoords ; Calculates (baseY+Y)*320 + X*2 codeseg:98E6 ; codeseg:98E6 ; Inputs: AL = Y, AH = X codeseg:98E6 ; Reads from DS:[byte_B389] = baseY codeseg:98E6 ; (Actually reads baseY as a word, but uses it like codeseg:98E6 ; it can't overflow to over 8 bits when adding Y to it) codeseg:98E6 ; Returns: DI = heightLUT[baseY+Y] + X*2 = (baseY+Y)*320 + X*2 codeseg:98E6 ; (Side-effects: BH = 0, BL = AH = X) codeseg:98E9 mov bx, cx codeseg:98EB mov ax, dx codeseg:98ED mov dx, 320 codeseg:98F0 xor ch, ch codeseg:98F2 sub dx, cx codeseg:98F4 sub dx, cx codeseg:98F6 codeseg:98F6 xLoop: ; CODE XREF: AG_agi256FilledRect+27�j codeseg:98F6 mov cl, xLen codeseg:98F8 repe stosw codeseg:98FA dec yLen codeseg:98FC jz end codeseg:98FE add di, dx codeseg:9900 jmp short xLoop codeseg:9902 ; --------------------------------------------------------------------------- codeseg:9902 codeseg:9902 end: ; CODE XREF: AG_agi256FilledRect+23�j codeseg:9902 pop es codeseg:9903 retn codeseg:9903 AG_agi256FilledRect endp codeseg:9903 codeseg:9904 codeseg:9904 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9904 codeseg:9904 ; In Sonneveld's Agi2917.idb there was j_EGAInit here. codeseg:9904 ; codeseg:9904 ; Precalculates table for Y*320 values (0 <= y < 200) codeseg:9904 codeseg:9904 AG_calcHeightLUT proc near ; CODE XREF: j_AG_calcHeightLUT�j codeseg:9904 lea di, ds:heightLUT codeseg:9908 mov ax, 0 codeseg:990B mov dx, 200 codeseg:990E codeseg:990E mulWidthLoop: ; CODE XREF: AG_calcHeightLUT+F�j codeseg:990E stosw codeseg:990F add ax, 320 codeseg:9912 dec dx codeseg:9913 jnz mulWidthLoop codeseg:9915 retn codeseg:9915 AG_calcHeightLUT endp codeseg:9915 codeseg:9916 codeseg:9916 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9916 codeseg:9916 ; To me this seems to blink the colors on the screen codeseg:9916 ; syncronized to some event. codeseg:9916 ; codeseg:9916 ; setPalette(uint16 cx) { codeseg:9916 ; read 16 colors from video card to ds:[palette] codeseg:9916 ; codeseg:9916 ; for (int z = 0; z < cx; z++) { codeseg:9916 ; for (int y = 0; y < 20; y++) { codeseg:9916 ; for (int i=0; i < 16*3; i++) { codeseg:9916 ; ds:palette[i] ^= 0xff; // Inverts palette codeseg:9916 ; } codeseg:9916 ; write 16 colors to video card from ds:[palette] codeseg:9916 ; wait for word_A139 to change (Loop until it does) codeseg:9916 ; } codeseg:9916 ; } codeseg:9916 ; } codeseg:9916 codeseg:9916 AG_blinkScreen proc near ; CODE XREF: cmd_shake_screen_110+2F�p codeseg:9916 push bx codeseg:9917 push si codeseg:9918 push di codeseg:9919 push es codeseg:991A push dx codeseg:991B mov ax, ds codeseg:991D mov es, ax codeseg:991F push cx codeseg:9920 mov dx, offset palette codeseg:9923 xor bx, bx codeseg:9925 mov cx, 16 ; Read first 16 colors from video card codeseg:9928 mov al, 17h codeseg:992A mov ah, 10h codeseg:992C int 10h ; - VIDEO - READ BLOCK OF DAC REGISTERS (EGA, VGA/MCGA) codeseg:992C ; BX = starting palette register, CX = number of palette registers to read codeseg:992C ; ES:DX -> buffer (3 * CX bytes in size) codeseg:992C ; Return: CX number of red, green and blue triples in buffer codeseg:992E pop cx codeseg:992F codeseg:992F outerLoop: ; CODE XREF: AG_blinkScreen+4C�j codeseg:992F push cx ; At first run, CX's value at function start is pushed codeseg:9930 mov cx, 20 codeseg:9933 codeseg:9933 loop20Times: ; CODE XREF: AG_blinkScreen+49�j codeseg:9933 push cx ; At first run, 20 is pushed codeseg:9934 mov bx, 47 ; 48/3 = 16 (Dealing with triples here) codeseg:9937 mov al, 0FFh codeseg:9939 codeseg:9939 invertPalette: ; CODE XREF: AG_blinkScreen+28�j codeseg:9939 xor palette[bx], al ; Inverts 16 colors in palette and writes them to video card DAC codeseg:993D dec bx codeseg:993E jns invertPalette ; Inverts 16 colors in palette and writes them to video card DAC codeseg:9940 mov dx, offset palette codeseg:9943 xor bx, bx codeseg:9945 mov cx, 16 codeseg:9948 mov al, 12h codeseg:994A mov ah, 10h codeseg:994C int 10h ; - VIDEO - SET BLOCK OF DAC REGISTERS (EGA, VGA/MCGA) codeseg:994C ; BX = starting color register, CX = number of registers to set codeseg:994C ; ES:DX -> table of 3*CX bytes where each 3 byte group represents one codeseg:994C ; byte each of red, green and blue (0-63) codeseg:994E mov cx, 1 codeseg:9951 codeseg:9951 neverLoopsHere: ; CODE XREF: AG_blinkScreen+46�j codeseg:9951 mov bx, word_A139 codeseg:9955 codeseg:9955 waitForChange: ; CODE XREF: AG_blinkScreen+43�j codeseg:9955 cmp bx, word_A139 codeseg:9959 jz waitForChange codeseg:995B dec cx codeseg:995C jnz neverLoopsHere ; This seems to never loop, so why is it here at all? codeseg:995E pop cx codeseg:995F loop loop20Times ; At first run, 20 is pushed codeseg:9961 pop cx codeseg:9962 loop outerLoop ; At first run, CX's value at function start is pushed codeseg:9964 pop dx codeseg:9965 pop es codeseg:9966 pop di codeseg:9967 pop si codeseg:9968 pop bx codeseg:9969 retn codeseg:9969 AG_blinkScreen endp codeseg:9969 codeseg:996A codeseg:996A ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:996A codeseg:996A ; Input: CX codeseg:996A ; BH = CH = Y codeseg:996A ; BL = CL/2 = X / 2 codeseg:996A ; SI += 160 (Go to right half of the 320x168 area) codeseg:996A ; goto AG_stretchToScreen codeseg:996A codeseg:996A AG_convCoord proc near ; CODE XREF: AG_agi256PutBlock+1C�j codeseg:996A mov bx, cx codeseg:996C shr bl, 1 codeseg:996E add si, 160 codeseg:9972 jmp AG_stretchToScreen ; Copies data from agi256 picture segment to video memory with x2 horizontal stretching. codeseg:9972 AG_convCoord endp ; Both source and destination buffers use a stride/pitch of 320 bytes. codeseg:9972 ; Inputs: codeseg:9972 ; BL = xLen codeseg:9972 ; BH = yLen codeseg:9972 ; SI = srcOffset codeseg:9972 ; DI = destOffset codeseg:9975 codeseg:9975 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9975 codeseg:9975 ; Command unknown 170 codeseg:9975 ; codeseg:9975 ; In AGIDATA.OVL at offset 0x08C5 there's codeseg:9975 ; dw offset CmdUnknown170 and now codeseg:9975 ; it's 0x9975 which points to 0x9800 + 0x175, codeseg:9975 ; so it's 0x175 in this file. So it points to this function. codeseg:9975 ; codeseg:9975 ; uint16 *cmdUnknown170(uint16 *varNum) { codeseg:9975 ; uint8 var = agiVar[*varNum]; codeseg:9975 ; AG_readAgi256Pic(var); codeseg:9975 ; return ++varNum; codeseg:9975 ; } codeseg:9975 ; Attributes: bp-based frame codeseg:9975 codeseg:9975 AG_cmd_set_simple_170 proc near ; DATA XREF: dataseg:08C5�o codeseg:9975 codeseg:9975 varNum = word ptr 8 codeseg:9975 codeseg:9975 push si codeseg:9976 push di codeseg:9977 push bp codeseg:9978 mov bp, sp codeseg:997A mov di, [bp+varNum] ; DI = varNum codeseg:997D inc [bp+varNum] ; varNum++ codeseg:9980 mov al, [di] ; AL = [DS:DI] = [old varNum] codeseg:9982 sub ah, ah ; AX = zero_extend(AL) codeseg:9984 mov di, ax ; DI = [old varNum] codeseg:9986 mov al, agiVar[di] ; AL = agiVar[[old varNum]] codeseg:998A sub ah, ah codeseg:998C push ax codeseg:998D call AG_readAgi256Pic ; Reads an AGI 256 picture with the given number to codeseg:998D ; agi256PicSeg so that the picture is a 160x168 picture in codeseg:998D ; a 320x168 area, but in the right half of it codeseg:998D ; (i.e. 168 <= x < 320 and 0 <= y < 168) codeseg:9990 add sp, 2 codeseg:9993 mov ax, [bp+varNum] codeseg:9996 pop bp codeseg:9997 pop di codeseg:9998 pop si codeseg:9999 retn codeseg:9999 AG_cmd_set_simple_170 endp codeseg:9999 codeseg:999A codeseg:999A ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:999A codeseg:999A ; Reads an AGI 256 picture with the given number to codeseg:999A ; agi256PicSeg so that the picture is a 160x168 picture in codeseg:999A ; a 320x168 area, but in the right half of it codeseg:999A ; (i.e. 168 <= x < 320 and 0 <= y < 168) codeseg:999A ; Attributes: bp-based frame codeseg:999A codeseg:999A AG_readAgi256Pic proc near ; CODE XREF: AG_cmd_set_simple_170+18�p codeseg:999A codeseg:999A picNum = word ptr 4 codeseg:999A codeseg:999A push bp codeseg:999B mov bp, sp codeseg:999D jmp jumpOverData codeseg:999D ; --------------------------------------------------------------------------- codeseg:99A0 aPicdir db 'PICDIR',0 codeseg:99A7 aVol_0 db 'VOL.0',0 codeseg:99AD tempBuf db 3 dup(0F0h) codeseg:99B0 ; --------------------------------------------------------------------------- codeseg:99B0 codeseg:99B0 jumpOverData: ; CODE XREF: AG_readAgi256Pic+3�j codeseg:99B0 push ds codeseg:99B1 mov cx, cs codeseg:99B3 mov ds, cx codeseg:99B5 assume ds:codeseg codeseg:99B5 call $+3 codeseg:99B8 codeseg:99B8 loc_99B8: ; CODE XREF: cmd_shake_screen_110+17�p codeseg:99B8 pop dx ; At first run, if called from 0x99B5 codeseg:99B8 ; DX = IP from the stack, which in turn is 0x99B8 codeseg:99B8 ; as it was the IP for the next instruction as call $+3 at 0x99B5 was made. codeseg:99B9 sub dx, 18h ; Subtract 0x18 from given value. codeseg:99B9 ; On first run it's 0x99B8 - 0x18 = 0x99A0 = offset "PICDIR" codeseg:99BC mov ax, 3D00h codeseg:99BF int 21h ; DOS - 2+ - OPEN DISK FILE WITH HANDLE codeseg:99BF ; DS:DX -> ASCIZ filename codeseg:99BF ; AL = access mode codeseg:99BF ; 0 - read codeseg:99C1 jnb fileOpenSuccess ; JNB = JNC codeseg:99C1 ; AX = file handle if CF not set, codeseg:99C1 ; AX = error code if CF is set codeseg:99C3 codeseg:99C3 error: ; CODE XREF: AG_readAgi256Pic+3D�j codeseg:99C3 ; AG_readAgi256Pic+4D�j ... codeseg:99C3 pop ds codeseg:99C4 assume ds:dataseg codeseg:99C4 retn codeseg:99C5 ; --------------------------------------------------------------------------- codeseg:99C5 codeseg:99C5 fileOpenSuccess: ; CODE XREF: AG_readAgi256Pic+27�j codeseg:99C5 mov bx, ax ; BX = AX = file handle of the picture directory file codeseg:99C7 mov dx, [bp+picNum] codeseg:99CA mov al, 3 codeseg:99CC mul dl ; AX = AL*DL = DL*3 = picNum*3 codeseg:99CE mov dx, ax ; DX = AX = picNum*3 codeseg:99D0 xor cx, cx ; Seek to position picNum*3 from beginning of file codeseg:99D2 mov ax, 4200h ; Inputs: BX = file handle, codeseg:99D2 ; CX = 16-bit MSB of bytes to move, codeseg:99D2 ; DX = 16-bit LSB of bytes to move codeseg:99D2 ; Returns: codeseg:99D2 ; DX:AX = new pointer location if CF not set codeseg:99D5 int 21h ; DOS - 2+ - MOVE FILE READ/WRITE POINTER (LSEEK) codeseg:99D5 ; AL = method: offset from beginning of file codeseg:99D7 jb error ; JC error codeseg:99D9 call $+3 codeseg:99DC pop dx codeseg:99DD sub dx, 2Fh ; '/' ; If called from 0x99D9 then after this subtraction codeseg:99DD ; DX will be 0x99DC - 0x2F = 0x99AD = offset tempBuf codeseg:99E0 mov cx, 3 ; Read three bytes from position picNum*3 codeseg:99E3 mov ah, 3Fh codeseg:99E5 int 21h ; DOS - 2+ - READ FROM FILE WITH HANDLE codeseg:99E5 ; BX = file handle, CX = number of bytes to read codeseg:99E5 ; DS:DX -> buffer codeseg:99E7 jb error codeseg:99E9 mov ah, 3Eh codeseg:99EB int 21h ; DOS - 2+ - CLOSE A FILE WITH HANDLE codeseg:99EB ; BX = file handle codeseg:99ED mov di, dx codeseg:99EF mov al, [di] codeseg:99F1 shr al, 4 ; AL = tempBuf[0]/16 codeseg:99F4 sub di, 2 codeseg:99F7 add [di], al ; Add tempBuf[0]/16 to "VOL.0" string's suffix (i.e. '0') codeseg:99F7 ; so that it may become "VOL.0" - "VOL.9". codeseg:99F9 sub dx, 6 ; DX = offset aVol_0 codeseg:99FC mov ax, 3D00h ; Open correct volume file (Some of "VOL.0" to "VOL.9") codeseg:99FF int 21h ; DOS - 2+ - OPEN DISK FILE WITH HANDLE codeseg:99FF ; DS:DX -> ASCIZ filename codeseg:99FF ; AL = access mode codeseg:99FF ; 0 - read codeseg:9A01 jb error codeseg:9A03 mov bx, ax ; BX = AX = file handle of the volume file codeseg:9A05 mov di, dx codeseg:9A07 add di, 6 ; DI = offset tempBuf codeseg:9A0A xor ch, ch codeseg:9A0C mov cl, [di] codeseg:9A0E and cl, 0Fh ; CL = tempBuf[0] % 16 codeseg:9A11 inc di codeseg:9A12 mov dh, [di] ; DH = tempBuf[1] codeseg:9A14 inc di codeseg:9A15 mov dl, [di] ; DL = tempBuf[2] codeseg:9A17 mov ax, 4200h ; Inputs: BX = file handle, codeseg:9A17 ; CX = 16-bit MSB of bytes to move, codeseg:9A17 ; DX = 16-bit LSB of bytes to move codeseg:9A17 ; Returns: codeseg:9A17 ; DX:AX = new pointer location if CF not set codeseg:9A1A int 21h ; DOS - 2+ - MOVE FILE READ/WRITE POINTER (LSEEK) codeseg:9A1A ; AL = method: offset from beginning of file codeseg:9A1C jb error codeseg:9A1E mov ax, 4201h codeseg:9A21 xor cx, cx codeseg:9A23 mov dx, 5 ; Move 5 bytes onwards from current seeking location codeseg:9A26 int 21h ; DOS - 2+ - MOVE FILE READ/WRITE POINTER (LSEEK) codeseg:9A26 ; AL = method: offset from present location codeseg:9A28 jb error codeseg:9A2A pop ds codeseg:9A2B push ds codeseg:9A2C mov dx, agi256PicSeg codeseg:9A30 mov ds, dx codeseg:9A32 mov dx, 160 ; Start reading to agi256PicSeg:[160] codeseg:9A35 mov cx, 168 codeseg:9A38 codeseg:9A38 readRow: ; CODE XREF: AG_readAgi256Pic+AB�j codeseg:9A38 push cx ; Read 168 rows of 160 bytes each. codeseg:9A39 mov cx, 160 codeseg:9A3C mov ah, 3Fh codeseg:9A3E int 21h ; DOS - 2+ - READ FROM FILE WITH HANDLE codeseg:9A3E ; BX = file handle, CX = number of bytes to read codeseg:9A3E ; DS:DX -> buffer codeseg:9A40 add dx, 320 ; Go to next row by adding 320 to destination pointer codeseg:9A44 pop cx codeseg:9A45 loop readRow ; Read 168 rows of 160 bytes each. codeseg:9A47 mov ah, 3Eh codeseg:9A49 int 21h ; DOS - 2+ - CLOSE A FILE WITH HANDLE codeseg:9A49 ; BX = file handle codeseg:9A4B pop ds codeseg:9A4C pop bp codeseg:9A4D retn codeseg:9A4D AG_readAgi256Pic endp codeseg:9A4D codeseg:9A4E ; --------------------------------------------------------------------------- codeseg:9A4E codeseg:9A4E loc_9A4E: codeseg:9A4E nop codeseg:9A4F codeseg:9A4F ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9A4F codeseg:9A4F ; Sets and/or clears current pixel bits codeseg:9A4F ; AL = ES:[DI] = PIXEL codeseg:9A4F ; (PIXEL |= BH) &= BL codeseg:9A4F codeseg:9A4F AG_setClrCurrPixel proc near ; CODE XREF: _SBuffXLine+2A�p codeseg:9A4F ; _SBuffYLine+3C�p ... codeseg:9A4F mov al, es:[di] codeseg:9A52 or al, bh codeseg:9A54 and al, bl codeseg:9A56 mov es:[di], al codeseg:9A59 retn codeseg:9A59 AG_setClrCurrPixel endp codeseg:9A59 codeseg:9A5A codeseg:9A5A ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9A5A codeseg:9A5A ; Was _WindowLineClr in Sonneveld's Agi2917.idb codeseg:9A5A ; codeseg:9A5A ; Clears first 8 rows (320*8 bytes) of video memory codeseg:9A5A ; with white pixels (Color 15). codeseg:9A5A codeseg:9A5A AG_setWhiteMenuBar proc near ; CODE XREF: _StatLineWrite+1A�p codeseg:9A5A ; sub_93D1+1C�p codeseg:9A5A push cx codeseg:9A5B push es codeseg:9A5C push di codeseg:9A5D push ax codeseg:9A5E mov ax, 0A000h codeseg:9A61 mov es, ax codeseg:9A63 assume es:nothing codeseg:9A63 xor di, di codeseg:9A65 mov ax, 0F0Fh codeseg:9A68 mov cx, (320*8)/2 codeseg:9A6B repe stosw codeseg:9A6D pop ax codeseg:9A6E pop di codeseg:9A6F pop es codeseg:9A70 assume es:dataseg codeseg:9A70 pop cx codeseg:9A71 retn codeseg:9A71 AG_setWhiteMenuBar endp codeseg:9A71 codeseg:9A71 ; --------------------------------------------------------------------------- codeseg:9A72 byte_9A72 db 33Eh dup(0)
Disassembly of AGIOBJS.OVL
codeseg:9DB0 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9DB0 codeseg:9DB0 ; AGIOBJS.OVL starts here at 0x9DB0 codeseg:9DB0 ; Attributes: thunk codeseg:9DB0 codeseg:9DB0 j_AO_agi256_saveArea proc near ; CODE XREF: sub_45E+15�p codeseg:9DB0 ; sub_5EDB+E4�p codeseg:9DB0 jmp AO_agi256_saveArea ; savearea(struct Sprite *s) { codeseg:9DB0 j_AO_agi256_saveArea endp ; int srcOffset = screenOffset(s->xPos, s->yPos); codeseg:9DB0 ; uint8 *src = agi256PicSeg[srcOffset + 160]; codeseg:9DB0 ; for (int y = 0; y < s->ySize; y++) codeseg:9DB0 ; memcpy(s->buffer + s->xSize * y, src + 320 * y, s->xSize); codeseg:9DB0 ; } codeseg:9DB3 codeseg:9DB3 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9DB3 codeseg:9DB3 ; Attributes: thunk codeseg:9DB3 codeseg:9DB3 j_AO_agi256_restoreArea proc near ; CODE XREF: sub_307+13�p codeseg:9DB3 ; sub_5EDB+121�p codeseg:9DB3 jmp AO_agi256_restoreArea ; restoreArea(struct Sprite *s) { codeseg:9DB3 j_AO_agi256_restoreArea endp ; int destOffset = screenOffset(s->xPos, s->yPos); codeseg:9DB3 ; uint8 *dest = &agi256PicSeg[destOffset + 160]; codeseg:9DB3 ; for (int y = 0; y < s->ySize; y++) codeseg:9DB3 ; memcpy(dest + 320 * y, s->buffer + s->xSize * y, s->xSize); codeseg:9DB3 ; } codeseg:9DB6 codeseg:9DB6 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9DB6 codeseg:9DB6 ; Attributes: thunk codeseg:9DB6 codeseg:9DB6 j_AO_agi256_blit proc near ; CODE XREF: sub_45E+1E�p codeseg:9DB6 ; sub_57CF+22�p ... codeseg:9DB6 jmp AO_agi256_blit codeseg:9DB6 j_AO_agi256_blit endp codeseg:9DB6 codeseg:9DB9 codeseg:9DB9 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9DB9 codeseg:9DB9 ; savearea(struct Sprite *s) { codeseg:9DB9 ; int srcOffset = screenOffset(s->xPos, s->yPos); codeseg:9DB9 ; uint8 *src = agi256PicSeg[srcOffset + 160]; codeseg:9DB9 ; for (int y = 0; y < s->ySize; y++) codeseg:9DB9 ; memcpy(s->buffer + s->xSize * y, src + 320 * y, s->xSize); codeseg:9DB9 ; } codeseg:9DB9 ; Attributes: bp-based frame codeseg:9DB9 codeseg:9DB9 AO_agi256_saveArea proc near ; CODE XREF: j_AO_agi256_saveArea�j codeseg:9DB9 codeseg:9DB9 spritePtr = word ptr 8 codeseg:9DB9 codeseg:9DB9 push si codeseg:9DBA push di codeseg:9DBB push bp codeseg:9DBC mov bp, sp codeseg:9DBE sub sp, 2 codeseg:9DC1 mov bp, [bp+spritePtr] codeseg:9DC4 mov al, byte ptr [bp+Sprite.yPos] ; At some places only lowest 8 bits are used codeseg:9DC7 mov ah, byte ptr [bp+Sprite.xPos] ; At some places only lowest 8 bits are used codeseg:9DCA call screenOffset ; Calculates the screen offset for given coordinate? Video or AGI screen offset? codeseg:9DCA ; DI = AL * 320 + AH codeseg:9DCA ; (Destroys BX contents (Returns with BH = 0, BL = AH)) codeseg:9DCA ; codeseg:9DCA ; Maybe not named quite correctly? codeseg:9DCD mov si, di codeseg:9DCF mov ah, byte ptr [bp+Sprite.ySize] ; At some places only lowest 8 bits are used codeseg:9DD2 mov al, byte ptr [bp+Sprite.xSize] ; At some places only lowest 8 bits are used codeseg:9DD5 mov di, [bp+Sprite.buffer] codeseg:9DD8 push ds codeseg:9DD9 mov ds, agi256PicSeg codeseg:9DDD xor dx, dx codeseg:9DDF mov cx, dx codeseg:9DE1 jmp AO_agi256_saveArea_loop_init ; DX = 320 - Sprite.xSize (AL) codeseg:9DE1 AO_agi256_saveArea endp ; SI += 160 (This is done in part 2 of the loop init, actually) codeseg:9DE1 ; This is elsewhere than directly inside AO_agi256_saveArea codeseg:9DE1 ; probably because it didn't fit otherwise. Returns to AO_agi256_saveArea_loop codeseg:9DE1 ; (Although calls AO_agi256_saveArea_loop_init_part2 first) codeseg:9DE4 ; --------------------------------------------------------------------------- codeseg:9DE4 nop codeseg:9DE5 nop codeseg:9DE6 codeseg:9DE6 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9DE6 codeseg:9DE6 ; Loop in pseudo C: codeseg:9DE6 ; for (int y = 0; y < Sprite.ySize; y++) { codeseg:9DE6 ; memcpy(ES:DI, DS:SI, Sprite.xSize); codeseg:9DE6 ; SI += 320; codeseg:9DE6 ; DI += Sprite.xSize; codeseg:9DE6 ; } codeseg:9DE6 codeseg:9DE6 AO_agi256_saveArea_loop proc near ; CODE XREF: AO_agi256_saveArea_loop+8�j codeseg:9DE6 ; AO_agi256_saveArea_loop_init_part2+4�j codeseg:9DE6 mov cl, al ; Move Sprite.xSize bytes per row codeseg:9DE8 repe movsb ; Move the bytes from DS:SI to ES:DI codeseg:9DEA add si, dx ; Move to the next row codeseg:9DEA ; repe movsb added Sprite.xSize to SI codeseg:9DEA ; add si,dx adds (320 - Sprite.xSize) to SI codeseg:9DEA ; so the addition is Sprite.xSize + (320 - Sprite.xSize) = 320 codeseg:9DEC dec ah ; Loop Sprite.ySize times codeseg:9DEE jnz AO_agi256_saveArea_loop ; Loop in pseudo C: codeseg:9DEE ; for (int y = 0; y < Sprite.ySize; y++) { codeseg:9DEE ; memcpy(ES:DI, DS:SI, Sprite.xSize); codeseg:9DEE ; SI += 320; codeseg:9DEE ; DI += Sprite.xSize; codeseg:9DEE ; } codeseg:9DF0 pop ds codeseg:9DF1 add sp, 2 codeseg:9DF4 pop bp codeseg:9DF5 pop di codeseg:9DF6 pop si codeseg:9DF7 retn codeseg:9DF7 AO_agi256_saveArea_loop endp ; sp = 0Ah codeseg:9DF7 codeseg:9DF8 codeseg:9DF8 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9DF8 codeseg:9DF8 ; restoreArea(struct Sprite *s) { codeseg:9DF8 ; int destOffset = screenOffset(s->xPos, s->yPos); codeseg:9DF8 ; uint8 *dest = &agi256PicSeg[destOffset + 160]; codeseg:9DF8 ; for (int y = 0; y < s->ySize; y++) codeseg:9DF8 ; memcpy(dest + 320 * y, s->buffer + s->xSize * y, s->xSize); codeseg:9DF8 ; } codeseg:9DF8 ; Attributes: bp-based frame codeseg:9DF8 codeseg:9DF8 AO_agi256_restoreArea proc near ; CODE XREF: j_AO_agi256_restoreArea�j codeseg:9DF8 codeseg:9DF8 spritePtr = word ptr 8 codeseg:9DF8 codeseg:9DF8 push si codeseg:9DF9 push di codeseg:9DFA push bp codeseg:9DFB mov bp, sp codeseg:9DFD sub sp, 2 codeseg:9E00 mov bp, [bp+spritePtr] codeseg:9E03 mov al, byte ptr [bp+Sprite.yPos] ; At some places only lowest 8 bits are used codeseg:9E06 mov ah, byte ptr [bp+Sprite.xPos] ; At some places only lowest 8 bits are used codeseg:9E09 call screenOffset ; Calculates the screen offset for given coordinate? Video or AGI screen offset? codeseg:9E09 ; DI = AL * 320 + AH codeseg:9E09 ; (Destroys BX contents (Returns with BH = 0, BL = AH)) codeseg:9E09 ; codeseg:9E09 ; Maybe not named quite correctly? codeseg:9E0C mov si, [bp+Sprite.buffer] codeseg:9E0F mov ah, byte ptr [bp+Sprite.ySize] ; At some places only lowest 8 bits are used codeseg:9E12 mov al, byte ptr [bp+Sprite.xSize] ; At some places only lowest 8 bits are used codeseg:9E15 push es codeseg:9E16 mov es, agi256PicSeg codeseg:9E1A xor dx, dx codeseg:9E1C mov cx, dx codeseg:9E1E jmp AO_agi256_restoreArea_loop_init ; DX = 320 - Sprite.xSize (AL) codeseg:9E1E AO_agi256_restoreArea endp ; DI += 160 codeseg:9E1E ; This is elsewhere than directly inside AO_agi256_restoreArea codeseg:9E1E ; probably because it didn't fit otherwise. Returns to AO_agi256_restoreArea_loop codeseg:9E21 ; --------------------------------------------------------------------------- codeseg:9E21 nop codeseg:9E22 nop codeseg:9E23 codeseg:9E23 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9E23 codeseg:9E23 ; Loop in pseudo C: codeseg:9E23 ; for (int y = 0; y < Sprite.ySize; y++) { codeseg:9E23 ; memcpy(ES:DI, DS:SI, Sprite.xSize); codeseg:9E23 ; DI += 320; codeseg:9E23 ; SI += Sprite.xSize; codeseg:9E23 ; } codeseg:9E23 codeseg:9E23 AO_agi256_restoreArea_loop proc near ; CODE XREF: AO_agi256_restoreArea_loop+8�j codeseg:9E23 ; AO_agi256_restoreArea_loop_init+D�j codeseg:9E23 mov cl, al ; Move Sprite.xSize bytes per row codeseg:9E25 repe movsb ; Move the bytes from DS:SI to ES:DI codeseg:9E27 add di, dx ; Move to the next row codeseg:9E27 ; repe movsb added Sprite.xSize to DI codeseg:9E27 ; add di,dx adds (320 - Sprite.xSize) to DI codeseg:9E27 ; so the addition is Sprite.xSize + (320 - Sprite.xSize) = 320 codeseg:9E29 dec ah codeseg:9E2B jnz AO_agi256_restoreArea_loop ; Loop in pseudo C: codeseg:9E2B ; for (int y = 0; y < Sprite.ySize; y++) { codeseg:9E2B ; memcpy(ES:DI, DS:SI, Sprite.xSize); codeseg:9E2B ; DI += 320; codeseg:9E2B ; SI += Sprite.xSize; codeseg:9E2B ; } codeseg:9E2D pop es codeseg:9E2E add sp, 2 codeseg:9E31 pop bp codeseg:9E32 pop di codeseg:9E33 pop si codeseg:9E34 retn codeseg:9E34 AO_agi256_restoreArea_loop endp ; sp = 0Ah codeseg:9E34 codeseg:9E35 codeseg:9E35 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9E35 codeseg:9E35 ; Attributes: bp-based frame codeseg:9E35 codeseg:9E35 AO_agi256_blit proc near ; CODE XREF: j_AO_agi256_blit�j codeseg:9E35 codeseg:9E35 structPtr = word ptr 8 codeseg:9E35 arg_1C = byte ptr 24h codeseg:9E35 codeseg:9E35 push si codeseg:9E36 push di codeseg:9E37 push bp codeseg:9E38 mov bp, sp codeseg:9E3A sub sp, 2 codeseg:9E3D mov bp, [bp+structPtr] codeseg:9E40 mov al, [bp+2] codeseg:9E43 push ax codeseg:9E44 mov si, [bp+10h] codeseg:9E47 test byte ptr [si+2], 80h codeseg:9E4B jz dontMirror codeseg:9E4D push bp codeseg:9E4E call _BlitMirrorCell codeseg:9E51 pop bp codeseg:9E52 mov si, [bp+10h] codeseg:9E55 codeseg:9E55 dontMirror: ; CODE XREF: AO_agi256_blit+16�j codeseg:9E55 inc si codeseg:9E56 lodsw codeseg:9E57 mov dx, ax codeseg:9E59 mov ah, byte ptr [bp+blitStruc.xPos] codeseg:9E5C mov al, byte ptr [bp+blitStruc.yPos] codeseg:9E5F sub al, dl codeseg:9E61 inc al codeseg:9E63 call screenOffset ; Calculates the screen offset for given coordinate? Video or AGI screen offset? codeseg:9E63 ; DI = AL * 320 + AH codeseg:9E63 ; (Destroys BX contents (Returns with BH = 0, BL = AH)) codeseg:9E63 ; codeseg:9E63 ; Maybe not named quite correctly? codeseg:9E66 shl dh, 1 codeseg:9E68 shl dh, 1 codeseg:9E6A shl dh, 1 codeseg:9E6C shl dh, 1 ; DH *= 16 codeseg:9E6E push es codeseg:9E6F mov es, agi256PicSeg codeseg:9E73 mov bl, 1 codeseg:9E75 mov bh, [bp+arg_1C] codeseg:9E78 shl bh, 1 codeseg:9E7A shl bh, 1 codeseg:9E7C shl bh, 1 codeseg:9E7E shl bh, 1 ; BH *= 16 codeseg:9E80 mov bp, di codeseg:9E82 xor cx, cx codeseg:9E84 jmp short startBlit ; Read byte from DS:[SI++] codeseg:9E86 ; --------------------------------------------------------------------------- codeseg:9E86 nop codeseg:9E87 codeseg:9E87 ah_eq_dh: ; CODE XREF: AO_agi256_blit+61�j codeseg:9E87 cbw ; Sign extend AL to AX (0 <= AL <= 0x0F, so AH = 0) codeseg:9E88 add di, ax ; DI += AX codeseg:9E8A codeseg:9E8A startBlit: ; CODE XREF: AO_agi256_blit+4F�j codeseg:9E8A ; AO_agi256_blit+83�j ... codeseg:9E8A lodsb ; Read byte from DS:[SI++] codeseg:9E8B or al, al codeseg:9E8D jz zeroByte ; Jump if it's zero codeseg:9E8F mov ah, al ; Double the pixel codeseg:9E91 and ax, 0F00Fh ; Make lower nibble of AL contain pixel's color info and codeseg:9E91 ; upper nibble of AH contain pixel's priority/control info codeseg:9E94 cmp ah, dh codeseg:9E96 jz ah_eq_dh ; Sign extend AL to AX (0 <= AL <= 0x0F, so AH = 0) codeseg:9E98 mov cl, al codeseg:9E9A shr ah, 1 codeseg:9E9C shr ah, 1 codeseg:9E9E shr ah, 1 codeseg:9EA0 shr ah, 1 ; Bring priority/control info to lower nibble of AH codeseg:9EA2 codeseg:9EA2 xLoop: ; CODE XREF: AO_agi256_blit+81�j codeseg:9EA2 ; AO_agi256_blit+B1�j codeseg:9EA2 mov al, es:[di] ; Read pixel codeseg:9EA5 and al, 0F0h ; Leave only the priority/control info codeseg:9EA7 cmp al, 2 shl 4 codeseg:9EA9 jbe controlByte012 ; Jump if pixel's control info is 0, 1 or 2 codeseg:9EAB cmp al, bh codeseg:9EAD ja priGreaterThanBH codeseg:9EAF mov al, bh ; AL <= BH so codeseg:9EAF ; AL = BH <=> AL = MAX(AL, BH) codeseg:9EB1 codeseg:9EB1 loc_9EB1: ; CODE XREF: AO_agi256_blit+AE�j codeseg:9EB1 or al, ah ; AL |= AH codeseg:9EB3 jmp AO_agi256_blit_sub ; ES:[160 + DI++] = AL & 0x0F; codeseg:9EB3 ; BL = 0; codeseg:9EB6 ; --------------------------------------------------------------------------- codeseg:9EB6 codeseg:9EB6 afterBlitSubCall: ; CODE XREF: AO_agi256_blit_sub+D�j codeseg:9EB6 loop xLoop ; Read pixel codeseg:9EB8 jmp short startBlit ; Read byte from DS:[SI++] codeseg:9EBA ; --------------------------------------------------------------------------- codeseg:9EBA codeseg:9EBA zeroByte: ; CODE XREF: AO_agi256_blit+58�j codeseg:9EBA dec dl ; DL-- codeseg:9EBC jz zeroDL codeseg:9EBE add bp, 320 codeseg:9EC2 mov di, bp codeseg:9EC4 jmp short startBlit ; Read byte from DS:[SI++] codeseg:9EC6 ; --------------------------------------------------------------------------- codeseg:9EC6 codeseg:9EC6 controlByte012: ; CODE XREF: AO_agi256_blit+74�j codeseg:9EC6 push di codeseg:9EC7 xor ch, ch codeseg:9EC9 codeseg:9EC9 loc_9EC9: ; CODE XREF: AO_agi256_blit+A7�j codeseg:9EC9 cmp di, 0D0C0h codeseg:9ECD jnb loc_9EDE codeseg:9ECF add di, 320 codeseg:9ED3 mov ch, es:[di] codeseg:9ED6 and ch, 0F0h codeseg:9ED9 cmp ch, 20h ; ' ' codeseg:9EDC jbe loc_9EC9 codeseg:9EDE codeseg:9EDE loc_9EDE: ; CODE XREF: AO_agi256_blit+98�j codeseg:9EDE pop di codeseg:9EDF cmp ch, bh codeseg:9EE1 mov ch, 0 codeseg:9EE3 jbe loc_9EB1 ; AL |= AH codeseg:9EE5 codeseg:9EE5 priGreaterThanBH: ; CODE XREF: AO_agi256_blit+78�j codeseg:9EE5 inc di codeseg:9EE6 loop xLoop ; Read pixel codeseg:9EE8 jmp short startBlit ; Read byte from DS:[SI++] codeseg:9EEA ; --------------------------------------------------------------------------- codeseg:9EEA codeseg:9EEA zeroDL: ; CODE XREF: AO_agi256_blit+87�j codeseg:9EEA pop es codeseg:9EEB pop ax codeseg:9EEC or al, al codeseg:9EEE jnz zeroDL_notZeroAL codeseg:9EF0 mov al, 1 ; f1 = Ego is invisible on the screen (Completely obscured by another object) codeseg:9EF2 test bl, bl codeseg:9EF4 jnz notZeroBL ; Hide ego (Set ego as invisible) codeseg:9EF6 call _ResetFlagAL ; Show ego (Set ego as visible i.e. not invisible) codeseg:9EF9 jmp short zeroDL_notZeroAL codeseg:9EFB ; --------------------------------------------------------------------------- codeseg:9EFB codeseg:9EFB notZeroBL: ; CODE XREF: AO_agi256_blit+BF�j codeseg:9EFB call _SetFlagAL ; Hide ego (Set ego as invisible) codeseg:9EFE codeseg:9EFE zeroDL_notZeroAL: ; CODE XREF: AO_agi256_blit+B9�j codeseg:9EFE ; AO_agi256_blit+C4�j codeseg:9EFE add sp, 2 codeseg:9F01 pop bp codeseg:9F02 pop di codeseg:9F03 pop si codeseg:9F04 retn codeseg:9F04 AO_agi256_blit endp codeseg:9F04 codeseg:9F05 codeseg:9F05 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9F05 codeseg:9F05 ; DX = 320 - Sprite.xSize (AL) codeseg:9F05 ; SI += 160 (This is done in part 2 of the loop init, actually) codeseg:9F05 ; This is elsewhere than directly inside AO_agi256_saveArea codeseg:9F05 ; probably because it didn't fit otherwise. Returns to AO_agi256_saveArea_loop codeseg:9F05 ; (Although calls AO_agi256_saveArea_loop_init_part2 first) codeseg:9F05 codeseg:9F05 AO_agi256_saveArea_loop_init proc near ; CODE XREF: AO_agi256_saveArea+28�j codeseg:9F05 mov dx, 320 codeseg:9F08 push ax codeseg:9F09 xor ah, ah codeseg:9F0B sub dx, ax ; DX = 320 - Sprite.xSize codeseg:9F0D pop ax codeseg:9F0E jmp AO_agi256_saveArea_loop_init_part2 ; This is elsewhere than directly inside AO_agi256_saveArea_loop_init codeseg:9F0E AO_agi256_saveArea_loop_init endp ; probably because it didn't fit otherwise. Returns to AO_agi256_saveArea_loop codeseg:9F0E codeseg:9F11 codeseg:9F11 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9F11 codeseg:9F11 ; DX = 320 - Sprite.xSize (AL) codeseg:9F11 ; DI += 160 codeseg:9F11 ; This is elsewhere than directly inside AO_agi256_restoreArea codeseg:9F11 ; probably because it didn't fit otherwise. Returns to AO_agi256_restoreArea_loop codeseg:9F11 codeseg:9F11 AO_agi256_restoreArea_loop_init proc near codeseg:9F11 ; CODE XREF: AO_agi256_restoreArea+26�j codeseg:9F11 mov dx, 320 codeseg:9F14 push ax codeseg:9F15 xor ah, ah codeseg:9F17 sub dx, ax codeseg:9F19 pop ax codeseg:9F1A add di, 160 codeseg:9F1E jmp AO_agi256_restoreArea_loop ; Loop in pseudo C: codeseg:9F1E AO_agi256_restoreArea_loop_init endp ; for (int y = 0; y < Sprite.ySize; y++) { codeseg:9F1E ; memcpy(ES:DI, DS:SI, Sprite.xSize); codeseg:9F1E ; DI += 320; codeseg:9F1E ; SI += Sprite.xSize; codeseg:9F1E ; } codeseg:9F21 codeseg:9F21 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9F21 codeseg:9F21 ; This is elsewhere than directly inside AO_agi256_saveArea_loop_init codeseg:9F21 ; probably because it didn't fit otherwise. Returns to AO_agi256_saveArea_loop codeseg:9F21 codeseg:9F21 AO_agi256_saveArea_loop_init_part2 proc near codeseg:9F21 ; CODE XREF: AO_agi256_saveArea_loop_init+9�j codeseg:9F21 add si, 160 codeseg:9F25 jmp AO_agi256_saveArea_loop ; Loop in pseudo C: codeseg:9F25 AO_agi256_saveArea_loop_init_part2 endp ; for (int y = 0; y < Sprite.ySize; y++) { codeseg:9F25 ; memcpy(ES:DI, DS:SI, Sprite.xSize); codeseg:9F25 ; SI += 320; codeseg:9F25 ; DI += Sprite.xSize; codeseg:9F25 ; } codeseg:9F28 codeseg:9F28 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ codeseg:9F28 codeseg:9F28 ; ES:[160 + DI++] = AL & 0x0F; codeseg:9F28 ; BL = 0; codeseg:9F28 codeseg:9F28 AO_agi256_blit_sub proc near ; CODE XREF: AO_agi256_blit+7E�j codeseg:9F28 add di, 160 codeseg:9F2C and al, 0Fh codeseg:9F2E stosb codeseg:9F2F sub di, 160 codeseg:9F33 xor bl, bl codeseg:9F35 jmp afterBlitSubCall codeseg:9F35 AO_agi256_blit_sub endp codeseg:9F35 codeseg:9F35 ; --------------------------------------------------------------------------- codeseg:9F38 db 0D8h dup(0) codeseg:9F38 codeseg ends codeseg:9F38
Differences between AGI v2.936's AGI.EXE and AGI256's hacked AGI.EXE
Disclaimer
This is a raw info dump from a personal file so things may be funny, wrong, weird or <insert your favorite adjective here> but there are details to be sure:
The raw info dump
Differences between original Sierra On-Line's AGI interpreter version 2.936 and the hacked AGI256's AGI.EXE: ///////////////////////////////////////////////////////////////////////////// Copyright string changed and some other bytes... not 100% sure if they are used or not... let's see. If changed bytes from seg000:0065 to seg000:0077 to all zeroes and to all semirandomly typed in numbers and all it did was that it made the AGI256 demo have some white color pixels where they shouldn't be in the Larry's bar screen. So... it may very well be that they're used. NOTE THAT: E8 49 00 = call sub_C4 = db 'FI',0 AND there's a real subroutine starting at seg000:00C4 so it might be used as code! - ORIGINAL 2.936 INTERPRETER: seg000:0000 aAdventureGameI db 'Adventure Game Interpreter',0Dh,0Ah seg000:0000 ; DATA XREF: seg001:0000�o seg000:0000 ; sub_401D+59�r ... seg000:0000 db 'Copyright (C) 1984, 1985, 1986 Sierra On-Line, Inc.',0Dh,0Ah seg000:0000 db 'Authors: Jeff Stephenson & Chris Iden',0Dh,0Ah seg000:0000 db 'FI',0 -> AGI256 INTERPRETER: seg000:0000 aAgi256ColorsCS db 'AGI 256 colors ',0Dh,0Ah ; DATA XREF: seg001:0000�o seg000:0000 ; sub_401D+59�r ... seg000:0000 db '(C) Sierra On-Line - by Jeff Stephenson and Chris Iden',0Dh,0Ah seg000:0000 db 'Hacked by Dark Minister',0Dh,0Ah seg000:0000 db 'FI',0 seg000:0065 db 87h ; Unknown data from 0x0065 to 0x0077 seg000:0066 db 49h ; I seg000:0067 db 29h ; ) seg000:0068 db 23h ; # ; DATA XREF: sub_4125+12�r seg000:0068 ; sub_4125+27�r ... seg000:0069 db 92h seg000:006A db 99h seg000:006B db 99h seg000:006C db 11h seg000:006D db 11h ; seg000:006E db 11h seg000:006F db 19h ; seg000:0070 db 88h seg000:0071 db 37h ; 7 seg000:0072 db 83h seg000:0073 db 83h ; â seg000:0074 db 73h ; s seg000:0075 db 87h ; ç seg000:0076 db 38h ; 8 seg000:0077 db 83h ; â ///////////////////////////////////////////////////////////////////////////// In function _StatLineWrite (Function name taken from Agi2917.idb): Changes _WindowLineClr call to setWhiteMenuBar call which clears first 8 rows of video memory with white. So changes the code that clears the status line before writing to it. Rationale: Probably because of wanting VGA support. - ORIGINAL 2.936 INTERPRETER: seg000:34D7 E8 CC F6 call sub_2BA6 ; _WindowLineClr in Agi2917.idb -> AGI256 INTERPRETER: seg000:34D7 E8 80 65 call near ptr 9A5Ah 0x9A5A - 0x9800 = 0x025A in the AGIGRAF.OVL: seg000:025A ; Clears first 8 rows (320*8 bytes) of video memory seg000:025A ; with white pixels (Color 15). seg000:025A seg000:025A setWhiteMenuBar proc near seg000:025A push cx seg000:025B push es seg000:025C push di seg000:025D push ax seg000:025E mov ax, 0A000h seg000:0261 mov es, ax seg000:0263 assume es:nothing seg000:0263 xor di, di seg000:0265 mov ax, 0F0Fh seg000:0268 mov cx, 500h seg000:026B repe stosw seg000:026D pop ax seg000:026E pop di seg000:026F pop es seg000:0270 assume es:nothing seg000:0270 pop cx seg000:0271 retn seg000:0271 setWhiteMenuBar endp ///////////////////////////////////////////////////////////////////////////// In _ArrangeMem (Name from Agi2917.idb): Changed to allocating twice the memory than with the original interpreter. Saves the allocated memory's segment to SBuff_Seg in Agi2917.idb and to agi256PicSeg in AGI256's disassembly. Rationale: Need another screen besides the 16 color & control line & priority info screen for 256 color info so that doubles the memory need. 0x690 in paragraphs (16 bytes) is 160*168 bytes. 0xD20 is twice that. - ORIGINAL 2.936 INTERPRETER: seg000:4240 mov bx, 690h -> AGI256 INTERPRETER: seg000:4240 mov bx, 0D20h ///////////////////////////////////////////////////////////////////////////// In _ArrangeMem (Name from Agi2917.idb): Changed to allocating twice the memory than with the original interpreter. Saves the allocated memory's segment to wHGCFontData in Agi2917.idb. Rationale: Don't really know. Maybe not needed at all? Or it's also possible that the wHGCFontData is not a correct name for the variable and/or the allocate area is used for something else and Hercules font data. 0x690 in paragraphs (16 bytes) is 160*168 bytes. 0xD20 is twice that. - ORIGINAL 2.936 INTERPRETER: seg000:4259 add ax, 690h -> AGI256 INTERPRETER: seg000:4259 add ax, 0D20h ///////////////////////////////////////////////////////////////////////////// In an AGI screen buffer filling function (_SBuffClear in Agi2917.idb): Fills the AGI screen buffer with AX contents. Filling space doubled in AGI256. (There's some obsolete Hercules code in this function, but it's not used so it doesn't matter). Use cases: AX = 0x4040 (Fill with lowest priority i.e. 4 and black color i.e. 0). AX = 0x4F4F (Fill with lowest priority i.e. 4 and white color i.e. 15). Rationale: Needed because the 256 color screen and the normal 16 color screen are horizontally adjacent. Probably only needed for clearing the 16 color screen because the 256 color screen is always fully filled when loading an AGI256 picture resource into it. 160*168 = 0x3480 * 2 160*168*2 = 0x6900 * 2 There's a repe stosw using cx after this instruction. - ORIGINAL 2.936 INTERPRETER: seg000:525E mov cx, 3480h -> AGI256 INTERPRETER: seg000:525E mov cx, 6900h ///////////////////////////////////////////////////////////////////////////// In _SBuffXLine (Name from Agi2917.idb): Changes direct pixel manipulation code to a function call. Functionally changes nothing as the called function is functionally identical to the code that was replaced. Rationale: Maybe not needed at all? Maybe some leftover modification that wasn't used after all? 0x9A4F must be pointing to: seg000:024E ; Sets and/or clears current pixel bits seg000:024E ; AL = ES:[DI] = PIXEL seg000:024E ; (PIXEL |= BH) &= BL seg000:024E seg000:024E setClrCurrPixel proc near seg000:024E nop seg000:024F mov al, es:[di] seg000:0252 or al, bh seg000:0254 and al, bl seg000:0256 mov es:[di], al seg000:0259 retn seg000:0259 setClrCurrPixel endp in AGIGRAF.OVL! So that makes their relocation value 0x9A4F - 0x24E = 0x9801... wait... that's not even... let's see, there's a nop in setClrCurrPixel's start. Let's throw that away so we'd jump right into 0x24F so the relocation value would be 0x9A4F - 0x24E = 0x9800... now that's better :-). - ORIGINAL 2.936 INTERPRETER: seg000:5298 loc_5298: ; CODE XREF: sub_526F+34�j seg000:5298 inc di seg000:5299 mov al, es:[di] ; CHANGED seg000:529C or al, bh ; CHANGED seg000:529E and al, bl ; CHANGED seg000:52A0 mov es:[di], al ; CHANGED seg000:52A3 loop loc_5298 -> AGI256 INTERPRETER: seg000:5298 loc_5298: ; CODE XREF: sub_526F+34�j seg000:5298 inc di seg000:5299 call near ptr 9A4Fh ; CHANGED seg000:52A3 loop loc_5298 ///////////////////////////////////////////////////////////////////////////// In _SBuffYLine (Name from Agi2917.idb): This converts the vertical drawing loop to use 320 rather than 160 as the offset between rows. Also changes direct pixel manipulation code to a function call with functionally identical code in it. Rationale: As there are now two AGI screens horizontally adjacent to each other (Left 160x168 one is the normal 16 color screen and the right 160x168 one is the new 256 color screen) the vertical line drawing loop has to use 320 as the offset between rows rather than 160. The pixel manipulation code replacement with a function call is probably not needed as it doesn't functionally change anything. - ORIGINAL 2.936 INTERPRETER: seg000:52E3 loc_52E3: ; CODE XREF: sub_52AB+34�j seg000:52E3 add di, 0A0h ; 'á' seg000:52E7 mov al, es:[di] seg000:52EA or al, bh seg000:52EC and al, bl seg000:52EE mov es:[di], al seg000:52F1 loop loc_52E1 -> AGI256 INTERPRETER: seg000:52E3 loc_52E3: ; CODE XREF: sub_52AB+34�j seg000:52E3 add di, 140h seg000:52E7 call near ptr 9A4Fh seg000:52F1 loop loc_52E1 which is effectively the same as: seg000:52E3 loc_52E3: ; CODE XREF: sub_52AB+34�j seg000:52E3 add di, 140h seg000:024F mov al, es:[di] seg000:0252 or al, bh seg000:0254 and al, bl seg000:0256 mov es:[di], al seg000:52F1 loop loc_52E1 ///////////////////////////////////////////////////////////////////////////// In _SBuffPlotPixel (Name from Agi2917.idb): Changes multiplication from 160 to 320 in calculation x + y * 320. (16 to 32 really but they're multiplied by 10 before these changes). Rationale: As there are now two AGI screens horizontally adjacent to each other (Left 160x168 one is the normal 16 color screen and the right 160x168 one is the new 256 color screen) the pixel plotting code has to use 320 as the offset between rows rather than 160. - ORIGINAL 2.936 INTERPRETER: seg000:5311 shl di, 1 seg000:5313 shl di, 1 seg000:5315 shl di, 1 seg000:5317 shl di, 1 -> AGI256 INTERPRETER: seg000:5311 shl di, 4 seg000:5314 shl di, 1 ///////////////////////////////////////////////////////////////////////////// In _SBuffPlotPixel (Name from Agi2917.idb): Changes direct pixel manipulation code to a function call. Functionally changes nothing as the called function is functionally identical to the code that was replaced. Rationale: Maybe not needed at all? Maybe some leftover modification that wasn't used after all? - ORIGINAL 2.936 INTERPRETER: seg000:532F mov al, es:[di] seg000:5332 or al, bh seg000:5334 and al, bl seg000:5336 mov es:[di], al -> AGI256 INTERPRETER: seg000:532F call near ptr 9A4Fh ///////////////////////////////////////////////////////////////////////////// In _SBuffPicFill (Name from Agi2917.idb): Changes multiplication from 160 to 320 in calculation x + y * 320. (16 to 32 really but they're multiplied by 10 before these changes). Rationale: As there are now two AGI screens horizontally adjacent to each other (Left 160x168 one is the normal 16 color screen and the right 160x168 one is the new 256 color screen) the pixel plotting code has to use 320 as the offset between rows rather than 160. - ORIGINAL 2.936 INTERPRETER: seg000:5483 shl di, 1 seg000:5485 shl di, 1 seg000:5487 shl di, 1 seg000:5489 shl di, 1 -> AGI256 INTERPRETER: seg000:5483 shl di, 4 seg000:5486 shl di, 1 ///////////////////////////////////////////////////////////////////////////// In _Pic_Show (Name from Agi2917.idb): Before calling j_EGAPutBlock (Name from Agi2917.idb) or j_AG_agi256PutBlock (Name from AGI256's disassembly) rotate the AGI screen buffers' pixels right by four in place (Writes the rotated values back to the buffer, that is) if a certain variable is one (rotate_sbuff). Probably exchanges the places of color and priority information. Rationale: As there are now two AGI screens horizontally adjacent to each other (Left 160x168 one is the normal 16 color screen and the right 160x168 one is the new 256 color screen) priority screen showing code needs to use 320 as the offset between rows rather than 160. But because the code is just a single loop for rotating the whole screen and rotating the 256 color values (If they aren't shown) doesn't matter (As presumably they are rotated back to their normal values afterwards) it is easier to just rotate both screens. 160*168 = 0x6900 160*168*2 = 0xD200 - ORIGINAL 2.936 INTERPRETER: seg000:5563 mov cx, 6900h -> AGI256 INTERPRETER: seg000:5563 mov cx, 0D200h ///////////////////////////////////////////////////////////////////////////// In _FBuffOffset (Agi2917.idb), agiToScreenCoords (AGI256 disassembly): Changes graphics driver dependent (CGA, EGA, Hercules etc) specific switches to a single VGA specific code. Rationale: AGI256 requires VGA so there's no need for the other switches. // The original 2.936 interpreter's part in pseudo C: { uint16 display = *(ds:0x1130); // enum {CGA, Tandy, HGC, EGA, VGA?}; uint16 computer = *(ds:0x112e); // enum { IBM_PC?, PCJr?, Tandy?, ...?} if (display == VGA) x *= 2; if (computer == IBM_PC) { x /= 2; if (display == EGA) x /= 2; } if (computer == Tandy) { if (display == EGA) x /= 4; } offset += x; retn; } // AGI256 interpreter's part in pseudo C: di += bx * 2; retn; - ORIGINAL 2.936 INTERPRETER: seg000:5636 cmp word ptr ds:1130h, 4 seg000:563B jnz loc_563F seg000:563D shl bx, 1 seg000:563F seg000:563F loc_563F: ; CODE XREF: seg000:563B�j seg000:563F cmp word ptr ds:112Eh, 0 seg000:5644 jnz loc_5651 seg000:5646 shr bx, 1 seg000:5648 cmp word ptr ds:1130h, 3 seg000:564D jnz loc_5651 seg000:564F shr bx, 1 seg000:5651 seg000:5651 loc_5651: ; CODE XREF: seg000:5644�j seg000:5651 ; seg000:564D�j seg000:5651 cmp word ptr ds:112Eh, 2 seg000:5656 jnz loc_5663 seg000:5658 cmp word ptr ds:1130h, 3 seg000:565D jnz loc_5663 seg000:565F shr bx, 1 seg000:5661 shr bx, 1 seg000:5663 seg000:5663 loc_5663: ; CODE XREF: seg000:5656�j seg000:5663 ; seg000:565D�j seg000:5663 add di, bx seg000:5665 retn -> AGI256 INTERPRETER: seg000:5636 shl bx, 1 seg000:5638 add di, bx seg000:563A retn ///////////////////////////////////////////////////////////////////////////// In _PicBuffOffset (Agi2917.idb), screenOffset (AGI256 disassembly): Changes multiplication from 160 to 320 in calculation x + y * 320. (16 to 32 really but they're multiplied by 10 before these changes). Rationale: As there are now two AGI screens horizontally adjacent to each other (Left 160x168 one is the normal 16 color screen and the right 160x168 one is the new 256 color screen) the AGI screen pixel position calculation has to use 320 as the offset between rows rather than 160. - ORIGINAL 2.936 INTERPRETER: seg000:5676 shl di, 1 seg000:5678 shl di, 1 seg000:567A shl di, 1 seg000:567C shl di, 1 -> AGI256 INTERPRETER: seg000:5676 shl di, 4 seg000:5679 shl di, 1 seg000:567B nop seg000:567C nop seg000:567D nop ///////////////////////////////////////////////////////////////////////////// Function that is called near the _EnablePicDraw's beginning in Agi2917.idb: If the relocation value 0x9800 works here too (Why wouldn't it?) then we're changing jump from ???GRAF.OVL's first subroutine (Not from the jump table in its head but after that at 0x0015 is the first subroutine) to a straight return. The first subroutine the the ???GRAF.OVL is the video mode setting routine. At least in AGIGRAF.OVL it sets 320x200 256 color video mode (Mode 13h), sets ds:[videoOfs] to 0xA000 and clears first 64 KiB of video memory with zeroes. Rationale: So this basically throws away some video mode specific stuff and replaces it with a VGA specific "nothing needed here" code :). // The original 2.936 interpreter's part in pseudo C: { uint16 display = *(ds:0x1130); // enum {CGA, Tandy, HGC, EGA, VGA?}; uint16 computer = *(ds:0x112e); // enum { IBM_PC?, PCJr?, Tandy?, ...?} if (computer == IBM_PC && display != HGC && display != EGA) setVideoMode(); // goto near ptr 0x9815; else retn; } // AGI256 interpreter's part in pseudo C (Eh :)): retn; - ORIGINAL 2.936 INTERPRETER: seg000:569F jmp near ptr 9815h -> AGI256 INTERPRETER: seg000:569F retn ///////////////////////////////////////////////////////////////////////////// If the relocation value 0x9800 works here too (Why wouldn't it?) then we're changing jump from ???GRAF.OVL's second subroutine (Not from the jump table in its head but after that at 0x0037 is the second subroutine) to a straight return. The second subroutine the the ???GRAF.OVL is the text mode setting routine. At least in AGIGRAF.OVL it sets 40x25 16 color text mode, enables background intensity (Colors 8-15), sets some cursor stuff and clears the text screen using some attribute. So this basically throws away some video mode specific stuff and replaces it with a VGA specific "nothing needed here" code :). // The original 2.936 interpreter's part in pseudo C: { uint16 display = *(ds:0x1130); // enum {CGA, Tandy, HGC, EGA, VGA?}; uint16 computer = *(ds:0x112e); // enum { IBM_PC?, PCJr?, Tandy?, ...?} if (computer == IBM_PC && display != HGC && display != EGA) setTextMode(); // goto near ptr 0x9837; else retn; } // AGI256 interpreter's part in pseudo C (Eh :)): retn; - ORIGINAL 2.936 INTERPRETER: seg000:5937 jmp near ptr 9837h -> AGI256 INTERPRETER: seg000:5937 retn ///////////////////////////////////////////////////////////////////////////// 'GAMEID' -string's (No trailing zero btw) start is turned into 'DM', 0 Rationale: DM is probably short for "Dark Minister" who was the hacker who made the AGI256 hack. Is this modification needed? Is this checked as the game ID or something? Don't know... - ORIGINAL 2.936 INTERPRETER: seg000:5B6C 'GAMEID' (A string without the trailing zero) -> AGI256 INTERPRETER: seg000:5B6C 'DM', 0 (, 'eID') ///////////////////////////////////////////////////////////////////////////// In _MenuInput (Agi2917.idb): Changes _WindowLineClr (Agi2917.idb) call near the function's beginning to AGIGRAF.OVL's setWhiteMenuBar which clears first 8 rows (320*8 bytes) of video memory with white pixels (Color 15). Rationale: Probably needed for VGA support when handling the menu/status line. - ORIGINAL 2.936 INTERPRETER: seg000:93ED call sub_2BA6 -> AGI256 INTERPRETER: seg000:93ED call near ptr 9A5Ah ///////////////////////////////////////////////////////////////////////////// - ORIGINAL 2.936 INTERPRETER & AGI256 INTERPRETER -info combined: seg001:0000 dd 0 ; seg001:0004 db 0 ; seg001:0005 db 0 ; seg001:0006 dd unk_9800 seg001:000A dw seg seg006 seg001:000C db 86h ; å seg001:000D db 0 ; seg001:000E db 0 ; seg001:000F db 0 ; seg001:0010 db 0 ; seg001:0011 db 0 ; seg001:0012 db 2Bh ; + seg001:0013 db 0 ; seg001:0014 db 0 ; seg001:0015 db 0 ; seg001:0016 dd unk_9800 seg001:001A dw seg seg004 seg001:001C db 93h ; ô seg001:001D db 0 ; seg001:001E db 0 ; seg001:001F db 0 ; seg001:0020 db 0 ; seg001:0021 db 0 ; seg001:0022 db 1Eh ; seg001:0023 db 0 ; seg001:0024 db 0 ; seg001:0025 db 0 ; seg001:0026 dd unk_9800 seg001:002A dw seg seg005 seg001:002C db 159 seg001:002D db 0 ; seg001:002E db 0 ; seg001:002F db 0 ; seg001:0030 db 0 ; seg001:0031 db 0 ; seg001:0032 db 37 ; Changed 0x25 (37) -> 0x28 (40) in AGI256 hack, size in paragraphs seg001:0033 db 0 ; seg001:0034 db 0 ; seg001:0035 db 0 ; seg001:0036 dd unk_9800 seg001:003A dw seg seg007 seg001:003C db 172 seg001:003D db 0 ; seg001:003E db 0 ; seg001:003F db 0 ; seg001:0040 db 0 ; seg001:0041 db 0 ; seg001:0042 db 91 seg001:0043 db 0 ; seg001:0044 db 0 ; seg001:0045 db 0 ; seg001:0046 dd unk_9800 seg001:004A dw seg seg003 seg001:004C db 185 seg001:004D db 0 ; seg001:004E db 0 ; seg001:004F db 0 ; seg001:0050 db 0 ; seg001:0051 db 0 ; seg001:0052 db 23 ; Changed 0x17 (23) -> 0x28 (40) in AGI256 hack, size in paragraphs seg001:0053 db 0 ; seg001:0054 db 0 ; seg001:0055 db 0 ; seg001:0056 dd unk_9DB0 seg001:005A dw seg seg008 seg001:005C db 197 seg001:005D db 0 ; seg001:005E db 0 ; seg001:005F db 0 ; seg001:0060 db 0 ; seg001:0061 db 0 ; seg001:0062 db 22 ; Changed 0x16 (22) -> 0x19 (25) in AGI256 hack, size in paragraphs seg001:0063 db 0 ; seg001:0064 db 0 ; seg001:0065 db 0 ; seg001:0066 dd unk_9DB0 seg001:006A dw seg seg009 seg001:006C dw 210 seg001:006E db 0 ; seg001:006F db 0 ; seg001:0070 db 0 ; seg001:0071 db 0 ; seg001:0072 dw 38 seg001:0074 db 0 ; seg001:0075 db 40h seg001:0076 db 0 ; seg001:0077 db 0 ; seg001:0078 dd seg seg009+0BF10000h seg001:007C dw 0DFh seg001:007E db 0 ; seg001:007F db 0 ; seg001:0080 db 0 ; seg001:0081 db 0 ; seg001:0082 db 0E8h ; F seg001:0083 db 1 ; seg001:0084 db 0FFh ; seg001:0085 db 0FFh ; seg001:0086 aCga_graf_ovl db 'CGA_GRAF.OVL',0 ; Changed to an empty string in AGI256 hack seg001:0093 aJr_graf_ovl db 'JR_GRAF.OVL',0 ; Changed to an empty string in AGI256 hack seg001:009F aEga_graf_ovl db 'EGA_GRAF.OVL',0 ; Changed to 'AGIGRAF.OVL',0 in AGI256 hack seg001:00AC aHgc_graf_ovl db 'HGC_GRAF.OVL',0 ; Changed to an empty string in AGI256 hack seg001:00B9 aVg_graf_ovl db 'VG_GRAF.OVL',0 ; Changed to an empty string in AGI256 hack seg001:00C5 aIbm_objs_ovl db 'IBM_OBJS.OVL',0 ; Changed to 'AGIOBJS.OVL',0 in AGI256 hack seg001:00D2 aHgc_objs_ovl db 'HGC_OBJS.OVL',0 ; Changed to an empty string in AGI256 hack seg001:00DF aAgidata_ovl db 'AGIDATA.OVL',0 seg001:00EB aAgi_exe db 'AGI.EXE',0 /////////////////////////////////////////////////////////////////////////////