/* Hovertank 3-D Source Code * Copyright (C) 1993-2014 Flat Rock Software * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "IDLIB.H" #pragma hdrstop /* ============================================================================= Library, C section ============================================================================= */ #define BLANKCHAR 9 char ch,str[80]; // scratch space inputtype playermode[3]; int JoyXlow [3], JoyXhigh [3], JoyYlow [3], JoyYhigh [3], buttonflip; char key[8],keyB1,keyB2; //////////////////// // // prototypes // //////////////////// void CalibrateJoy (int joynum); void Printscan (int sc); void calibratekeys (void); //========================================================================= //////////////// // // CalibrateJoy // Brings up a dialog and has the user calibrate // either joystick1 or joystick2 // //////////////// void CalibrateJoy (int joynum) { int stage,dx,dy,xl,yl,xh,yh; ControlStruct ctr; ExpWin (34,11); fontcolor=13; CPPrint("Joystick Configuration\n"); py+=6; fontcolor=15; PPrint("Hold the joystick in the UPPER LEFT\n"); PPrint("corner and press a button:"); stage=15; sx=(px+7)/8; do // wait for a button press { DrawChar (sx,py,stage); WaitVBL (3); if (++stage==23) stage=15; ReadJoystick (joynum,&xl,&yl); ctr = ControlJoystick(joynum); if (keydown[1]) return; } while (ctr.button1!= 1 && ctr.button2!=1); DrawChar(sx,py,BLANKCHAR); do // wait for the button release { ctr = ControlJoystick(joynum); } while (ctr.button1); WaitVBL (4); // so the button can't bounce py+=6; PPrint("\nHold the joystick in the LOWER RIGHT\n"); PPrint("corner and press a button:"); do // wait for a button press { DrawChar (sx,py,stage); WaitVBL (3); if (++stage==23) stage=15; ReadJoystick (joynum,&xh,&yh); ctr = ControlJoystick(joynum); if (keydown[1]) return; } while (ctr.button1!= 1 && ctr.button2!=1); DrawChar (sx,py,BLANKCHAR); do // wait for the button release { ctr = ControlJoystick(joynum); } while (ctr.button1); // // figure out good boundaries // dx=(xh-xl) / 6; dy=(yh-yl) / 6; JoyXlow[joynum]=xl+dx; JoyXhigh[joynum]=xh-dx; JoyYlow[joynum]=yl+dy; JoyYhigh[joynum]=yh-dy; if (joynum==1) playermode[1]=joystick1; else playermode[1]=joystick2; py+=6; PPrint ("\n(F)ire or (A)fterburn with B1 ?"); ch = PGet(); if ( ch == 'A' || ch == 'a') buttonflip = 1; else buttonflip = 0; } ///////////////////////////// // // print a representation of the scan code key // //////////////////////////// void printscan (int sc) { char static chartable[128] = {'?','?','1','2','3','4','5','6','7','8','9','0','-','+','?','?', 'Q','W','E','R','T','Y','U','I','O','P','[',']','|','?','A','S', 'D','F','G','H','J','K','L',';','"','?','?','?','Z','X','C','V', 'B','N','M',',','.','/','?','?','?','?','?','?','?','?','?','?', '?','?','?','?','?','?','?','?', 15,'?','-', 21,'5', 17,'+','?', 19,'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?', '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?', '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?'}; sc = sc & 0x7f; if (sc==1) PPrint ("ESC"); else if (sc==0xe) PPrint ("BKSP"); else if (sc==0xf) PPrint ("TAB"); else if (sc==0x1d) PPrint ("CTRL"); else if (sc==0x2A) PPrint ("LSHIFT"); else if (sc==0x39) PPrint ("SPACE"); else if (sc==0x3A) PPrint ("CAPSLK"); else if (sc>=0x3b && sc<=0x44) { char str[3]; PPrint ("F"); itoa (sc-0x3a,str,10); PPrint (str); } else if (sc==0x57) PPrint ("F11"); else if (sc==0x59) PPrint ("F12"); else if (sc==0x46) PPrint ("SCRLLK"); else if (sc==0x1c) PPrint ("ENTER"); else if (sc==0x36) PPrint ("RSHIFT"); else if (sc==0x37) PPrint ("PRTSC"); else if (sc==0x38) PPrint ("ALT"); else if (sc==0x47) PPrint ("HOME"); else if (sc==0x49) PPrint ("PGUP"); else if (sc==0x4f) PPrint ("END"); else if (sc==0x51) PPrint ("PGDN"); else if (sc==0x52) PPrint ("INS"); else if (sc==0x53) PPrint ("DEL"); else if (sc==0x45) PPrint ("NUMLK"); else if (sc==0x48) PPrint ("UP"); else if (sc==0x50) PPrint ("DOWN"); else if (sc==0x4b) PPrint ("LEFT"); else if (sc==0x4d) PPrint ("RIGHT"); else { str[0]=chartable[sc]; str[1]=0; PPrint (str); } } ///////////////////////////// // // calibratekeys // //////////////////////////// void calibratekeys (void) { char ch; int hx,hy,i,select,new; ExpWin (22,12); fontcolor=13; CPPrint ("Keyboard Configuration"); fontcolor=15; PPrint ("\n1 north"); PPrint ("\n2 east"); PPrint ("\n3 south"); PPrint ("\n4 west"); PPrint ("\n5 button1"); PPrint ("\n6 button2"); PPrint ("\nModify which action:"); hx=(px+7)/8; hy=py; for (i=0;i<4;i++) { px=pxl+8*12; py=pyl+10*(1+i); PPrint(":"); printscan (key[i*2]); } px=pxl+8*12; py=pyl+10*5; PPrint(":"); printscan (keyB1); px=pxl+8*12; py=pyl+10*6; PPrint(":"); printscan (keyB2); do { px=hx*8; py=hy; DrawChar (hx,hy,BLANKCHAR); ch=PGet() % 256; if (ch<'1' || ch>'6') continue; select = ch - '1'; DrawPchar (ch); PPrint ("\nPress the new key:"); ClearKeys (); new=-1; while (!keydown[++new]) if (new==0x79) new=-1; else if (new==0x29) new++; // skip STUPID left shifts! Bar(leftedge,py,22,10,0xff); if (select<4) key[select*2]=new; if (select==4) keyB1=new; if (select==5) keyB2=new; px=pxl+8*12; py=pyl+(select+1)*10; Bar(px/8,py,9,10,0xff); PPrint (":"); printscan (new); ClearKeys (); ch='0'; // so the loop continues } while (ch>='0' && ch<='9'); playermode[1]=keyboard; } //========================================================================= /* =========================== = = ControlKBD = =========================== */ ControlStruct ControlKBD () { int xmove=0, ymove=0; ControlStruct action; if (keydown [key[north]]) ymove=-1; if (keydown [key[east]]) xmove=1; if (keydown [key[south]]) ymove=1; if (keydown [key[west]]) xmove=-1; if (keydown [key[northeast]]) { ymove=-1; xmove=1; } if (keydown [key[northwest]]) { ymove=-1; xmove=-1; } if (keydown [key[southeast]]) { ymove=1; xmove=1; } if (keydown [key[southwest]]) { ymove=1; xmove=-1; } switch (ymove*3+xmove) { case -4: action.dir = northwest; break; case -3: action.dir = north; break; case -2: action.dir = northeast; break; case -1: action.dir = west; break; case 0: action.dir = nodir; break; case 1: action.dir = east; break; case 2: action.dir = southwest; break; case 3: action.dir = south; break; case 4: action.dir = southeast; break; } action.button1 = keydown [keyB1]; action.button2 = keydown [keyB2]; return (action); } /* =============================== = = ReadJoystick = Just return the resistance count of the joystick = =============================== */ void ReadJoystick (int joynum,int *xcount,int *ycount) { int portval,a1,a2,xbit,ybit; if (joynum==1) { xbit=1; ybit=2; } else { xbit=4; ybit=8; } *xcount = 0; *ycount = 0; outportb (0x201,inportb (0x201)); /* start the signal pulse */ asm cli; do { portval = inportb (0x201); a1 = (portval & xbit) != 0; a2 = (portval & ybit) != 0; *xcount+=a1; *ycount+=a2; } while ((a1+a2!=0) && (*xcount<500) && (*ycount<500)); asm sti; } /* ============================= = = JoyButton = = Returns the joystick button pressed, or 0 = ============================= */ int JoyButton (void) { int buttons = inportb (0x201); /* Get all four button status */ if ((buttons & 0x10) == 0) return 1; if ((buttons & 0x20) == 0) return 2; return 0; } /* ============================= = = ControlJoystick (joy# = 1 / 2) = ============================= */ ControlStruct ControlJoystick (int joynum) { int joyx = 0,joyy = 0, /* resistance in joystick */ xmove = 0, ymove = 0, buttons; ControlStruct action; ReadJoystick (joynum,&joyx,&joyy); if ( (joyx>500) | (joyy>500) ) { joyx=JoyXlow [joynum] + 1; /* no joystick connected, do nothing */ joyy=JoyYlow [joynum] + 1; } if (joyx > JoyXhigh [joynum]) xmove = 1; else if (joyx < JoyXlow [joynum]) xmove = -1; if (joyy > JoyYhigh [joynum]) ymove = 1; else if (joyy < JoyYlow [joynum]) ymove = -1; switch (ymove*3+xmove) { case -4: action.dir = northwest; break; case -3: action.dir = north; break; case -2: action.dir = northeast; break; case -1: action.dir = west; break; case 0: action.dir = nodir; break; case 1: action.dir = east; break; case 2: action.dir = southwest; break; case 3: action.dir = south; break; case 4: action.dir = southeast; break; } buttons = inportb (0x201); /* Get all four button status */ if (joynum == 1) { action.button1 = ((buttons & 0x10) == 0); action.button2 = ((buttons & 0x20) == 0); } else { action.button1 = ((buttons & 0x40) == 0); action.button2 = ((buttons & 0x80) == 0); } if (buttonflip) { buttons = action.button1; action.button1 = action.button2; action.button2 = buttons; } return (action); } /* ============================= = = ControlPlayer = = Expects a 1 or a 2 = ============================= */ ControlStruct ControlPlayer (int player) { ControlStruct ret; switch (playermode[player]) { case keyboard : return ControlKBD (); case joystick1: return ControlJoystick(1); case joystick2: return ControlJoystick(2); } return ControlKBD(); } #define DRAWCHAR(x,y,n) DrawChar(x,(y)*8,n) /* ============================================================================= ** ** Miscellaneous library routines ** ============================================================================= */ /////////////////////////////// // // ClearKeys // Clears out the bios buffer and zeros out the keydown array // /////////////////////////////// void ClearKeys (void) { int i; NBKscan=NBKascii=0; memset (keydown,0,sizeof(keydown)); } /* =============== = = Ack = = Waits for a keypress or putton press = =============== */ void Ack(void) { ControlStruct c; ClearKeys(); while (1) { if (NBKscan>127) { NBKscan&=0x7f; return; } c = ControlPlayer(1); if (c.button1 || c.button2) return; } } //========================================================================== ///////////////////////////////////////////////////////// // // Load a LARGE file into a FAR buffer! // ///////////////////////////////////////////////////////// unsigned long LoadFile(char *filename,char huge *buffer) { unsigned handle,flength1=0,flength2=0,buf1,buf2,foff1,foff2, len1,len2; buf1=FP_OFF(buffer); buf2=FP_SEG(buffer); asm mov WORD PTR foff1,0 // file offset = 0 (start) asm mov WORD PTR foff2,0 asm mov dx,filename asm mov ax,3d00h // OPEN w/handle (read only) asm int 21h asm jc out asm mov handle,ax asm mov bx,ax asm xor cx,cx asm xor dx,dx asm mov ax,4202h asm int 21h // SEEK (find file length) asm jc out asm mov flength1,ax asm mov len1,ax asm mov flength2,dx asm mov len2,dx asm mov bx,handle asm xor cx,cx asm xor dx,dx asm mov ax,4200h asm int 21h // SEEK (to file start) asm jc out asm cmp WORD PTR len2,0 // MULTI-SEGMENTAL? asm je L_2 L_1: asm push ds asm mov bx,handle asm mov cx,8000h // read 32K chunks asm mov dx,buf1 asm mov ax,buf2 asm mov ds,ax asm mov ah,3fh // READ w/handle asm int 21h asm pop ds asm jc out asm add buf2,800h asm sub len1,8000h asm sbb WORD PTR len2,0 asm cmp WORD PTR len2,0 asm ja L_1 asm cmp len1,8000h asm jae L_1 L_2: asm push ds asm mov bx,handle asm mov cx,len1 asm mov dx,buf1 asm mov ax,buf2 asm mov ds,ax asm mov ah,3fh // READ w/handle asm int 21h asm pop ds out: asm mov bx,handle // CLOSE w/handle asm mov ah,3eh asm int 21h return (flength2*0x10000+flength1); } //=========================================================================== /* ============================================== = = Save a *LARGE* file far a FAR buffer! = by John Romero (C) 1990 PCRcade = ============================================== */ void SaveFile(char *filename,char huge *buffer, long size) { unsigned int handle,buf1,buf2,foff1,foff2; buf1=FP_OFF(buffer); buf2=FP_SEG(buffer); asm mov WORD PTR foff1,0 // file offset = 0 (start) asm mov WORD PTR foff2,0 asm mov dx,filename asm mov ax,3c00h // CREATE w/handle (read only) asm xor cx,cx asm int 21h asm jc out asm mov handle,ax asm cmp word ptr size+2,0 // larger than 1 segment? asm je L2 L1: asm push ds asm mov bx,handle asm mov cx,8000h asm mov dx,buf1 asm mov ax,buf2 asm mov ds,ax asm mov ah,40h // WRITE w/handle asm int 21h asm pop ds asm add buf2,800h // bump ptr up 1/2 segment asm sub WORD PTR size,8000h // done yet? asm sbb WORD PTR size+2,0 asm cmp WORD PTR size+2,0 asm ja L1 asm cmp WORD PTR size,8000h asm jae L1 L2: asm push ds asm mov bx,handle asm mov cx,WORD PTR size asm mov dx,buf1 asm mov ax,buf2 asm mov ds,ax asm mov ah,40h // WRITE w/handle asm int 21h asm pop ds asm jmp out out: asm mov bx,handle // CLOSE w/handle asm mov ah,3eh asm int 21h } //========================================================================== /* ==================================== = = BloadinMM = ==================================== */ void BloadinMM (char *filename,memptr *spot) { int handle; long length; char huge *location; char error[80]; if ( (handle = open (filename,O_BINARY)) != -1 ) { length = filelength (handle); MMGetPtr (spot,length); close (handle); LoadFile (filename,*spot); } else { strcpy (error,"BloadinMM: Can't find file "); strcat (error,filename); Quit (error); } } /* ======================================== = = BloadinRLEMM = Returns a paraligned pointer to a file that has been unpacked off disk = ======================================== */ void BloadinRLEMM (char *filename,memptr *spot) { long length; memptr org; BloadinMM (filename,&org); length = *(long _seg *)org; // rleb compressed length MMGetPtr (spot,length); RLEBExpand ((unsigned char far *)org,(unsigned char far *)*spot); MMFreePtr (&org); } /* ======================================== = = BloadinHUFFMM = Returns a paraligned pointer to a file that has been unpacked off disk = ======================================== */ int useegamem; void BloadinHUFFMM (char *filename,memptr *spot) { long length; memptr org; if (useegamem) { org = (memptr)(0xa000+(linewidth*200)/16); LoadFile (filename,MK_FP(org,0)); } else BloadinMM (filename,&org); length = *(((long _seg *)org)+1); // huff compressed length MMGetPtr (spot,length); HuffExpandFile ((unsigned char far *)org,(unsigned char far *)*spot); if (!useegamem) MMFreePtr (&org); } //////////////////////////////////////////////////////////////////// // // Verify a file's existence // //////////////////////////////////////////////////////////////////// long Verify(char *filename) { int handle; long size; if ((handle=open(filename,O_BINARY))==-1) return 0; size=filelength(handle); close(handle); return size; } /* ==================== = = StopDrive = = Stop a floppy drive after sounds have been started = ==================== */ void StopDrive (void) { int i; for (i=0;i<100;i++) CallTimer(); } /* ============================================================================ COMPRESSION routines, see JHUFF.C for more ============================================================================ */ huffnode nodearray[256]; // 256 nodes is worst case void OptimizeNodes (huffnode *table); /* ================== = = HuffExpandFile = = Expands a file with all needed header info = ================== */ void HuffExpandFile (unsigned char huge *infile, unsigned char huge *outfile) { char header[4]; unsigned tag; long length; header[0] = *infile; header[1] = *(infile+1); header[2] = *(infile+2); header[3] = *(infile+3); if (strncmp (header,"HUFF",4)) Quit ("Tried to expand a file that isn't HUFF!"); length = *(long huge *)(infile+4); movedata(FP_SEG(infile+8),FP_OFF(infile+8),_DS,(unsigned)&nodearray,1020); OptimizeNodes (nodearray); HuffExpand (infile+1028,outfile,length,nodearray); } /* =============== = = OptimizeNodes = = Goes through a huffman table and changes the 256-511 node numbers to the = actular address of the node. Must be called before HuffExpand = =============== */ void OptimizeNodes (huffnode *table) { huffnode *node; int i; node = table; for (i=0;i<255;i++) { if (node->bit0 >= 256) node->bit0 = (unsigned)(table+(node->bit0-256)); if (node->bit1 >= 256) node->bit1 = (unsigned)(table+(node->bit1-256)); node++; } } /* ====================== = = HuffExpand = ====================== */ void HuffExpand (unsigned char huge *source, unsigned char huge *dest, long length,huffnode *hufftable) { unsigned bit,byte,node,code; unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff; huffnode *nodeon,*headptr; headptr = hufftable+254; // head node is allways node 254 #if0 bit = 1; byte = *source++; while (length) { if (byte&bit) code = nodeon->bit1; else code = nodeon->bit0; bit<<=1; if (bit==256) { bit=1; byte = *source++; } if (code<256) { *dest++=code; nodeon=headptr; length--; } else nodeon = (huffnode *)code; } #endif source++; // normalize source--; dest++; dest--; sourceseg = FP_SEG(source); sourceoff = FP_OFF(source); destseg = FP_SEG(dest); destoff = FP_OFF(dest); length--; // // al = source byte // cl = bit in source (1,2,4,8,...) // dx = code // // ds:si source // es:di dest // ss:bx node pointer // asm mov bx,[headptr] asm mov cl,1 asm mov si,[sourceoff] asm mov di,[destoff] asm mov es,[destseg] asm mov ds,[sourceseg] asm lodsb // load first byte expand: asm test al,cl // bit set? asm jnz bit1 asm mov dx,[ss:bx] // take bit0 path from node asm jmp gotcode bit1: asm mov dx,[ss:bx+2] // take bit1 path gotcode: asm shl cl,1 // advance to next bit position asm jnc sourceup asm lodsb asm cmp si,0x10 // normalize ds:si asm jb sinorm asm mov cx,ds asm inc cx asm mov ds,cx asm xor si,si sinorm: asm mov cl,1 // back to first bit sourceup: asm or dh,dh // if dx<256 its a byte, else move node asm jz storebyte asm mov bx,dx // next node = (huffnode *)code asm jmp expand storebyte: asm mov [es:di],dl asm inc di // write a decopmpressed byte out asm mov bx,[headptr] // back to the head node for next bit asm cmp di,0x10 // normalize es:di asm jb dinorm asm mov dx,es asm inc dx asm mov es,dx asm xor di,di dinorm: asm sub [WORD PTR ss:length],1 asm jnc expand asm dec [WORD PTR ss:length+2] asm jns expand // when length = ffff ffff, done asm mov ax,ss asm mov ds,ax } /*========================================================================*/ /* ====================== = = RLEWexpand = ====================== */ #define RLETAG 0xFEFE void RLEWExpand (unsigned far *source, unsigned far *dest) { long length; unsigned value,count,i; unsigned far *start,far *end; length = *(long far *)source; end = dest + (length)/2; source+=2; // skip length words // // expand it // do { value = *source++; if (value != RLETAG) // // uncompressed // *dest++=value; else { // // compressed string // count = *source++; value = *source++; if (dest+count>end) Quit("RLEWExpand error!"); for (i=1;i<=count;i++) *dest++ = value; } } while (dest2;i--) { colors[i][16] = bordercolor; _ES=FP_SEG(&colors[i]); _DX=FP_OFF(&colors[i]); _AX=0x1002; geninterrupt(0x10); WaitVBL(6); } } void SetNormalPalette(void) { int i; colors[3][16] = bordercolor; _ES=FP_SEG(&colors[3]); _DX=FP_OFF(&colors[3]); _AX=0x1002; geninterrupt(0x10); } //////////////////////////////////////////////////////////////////// // // Fade EGA screen out // //////////////////////////////////////////////////////////////////// void FadeOut(void) { int i; for (i=3;i>=0;i--) { colors[i][16] = bordercolor; _ES=FP_SEG(&colors[i]); _DX=FP_OFF(&colors[i]); _AX=0x1002; geninterrupt(0x10); WaitVBL(6); } } /* ==================== = = SetLineWidth = ==================== */ void SetLineWidth (int width) { EGAVirtualScreen(width); linewidth = width; GenYlookup(); } /* ============================================================================ IGRAB STUFF ============================================================================ */ memptr grsegs[NUMCHUNKS]; char needgr[NUMCHUNKS]; // for caching #if NUMPICS>0 pictype pictable[NUMPICS]; #endif #if NUMPICM>0 pictype picmtable[NUMPICS]; unsigned picmsize[NUMPICS]; // plane size for drawing #endif #if NUMSPRITES>0 spritetype image, spritetable[NUMSPRITES]; unsigned spritesize[NUMSPRITES]; // plane size for drawing #endif #if NUMFONTS+NUMFONTSM>0 unsigned fontcolor,pdrawmode; unsigned px,py; unsigned pxl,pxh,pyl,pyh; fontstruct _seg * fontseg; // used by drawpchar and drawmpchar #endif #if NUMSPRITES /* ============ = = DrawSprite = ============ */ void DrawSprite (int xcoord, int ycoord, int spritenum) { int shapenum; unsigned dest; shapenum = spritenum; switch (spritetable[spritenum].shifts) { case 2: shapenum += (xcoord&7)/4; break; case 4: shapenum += (xcoord&7)/2; break; case 8: shapenum += (xcoord&7); break; } xcoord = (xcoord+64)/8-8; dest = ycoord*linewidth+xcoord+screenofs; EGAWRITEMODE(0); DrawSpriteT (spritetable[shapenum].width,spritetable[shapenum].height, (unsigned)grsegs[shapenum+STARTSPRITES],dest,spritesize[shapenum]); } #endif /* ============================================================================ MID LEVEL GRAPHIC ROUTINES ============================================================================ */ int win_xl,win_yl,win_xh,win_yh; int sx,sy,leftedge; int screencenterx = 20,screencentery = 11; ////////////////////////// // // DrawWindow // draws a bordered window and homes the cursor // ////////////////////////// void DrawWindow (int xl, int yl, int xh, int yh) { int x,y; win_xl=xl; pxl = xl*8+8; win_yl=yl; win_xh=xh; pxh = xh*8; win_yh=yh; // so the window can be erased DRAWCHAR (xl,yl,1); for (x=xl+1;x 2) { if (height >2) ExpWin (width-2,height-2); else ExpWinH (width-2,height); } else if (height >2) ExpWinV (width,height-2); WaitVBL (1); CenterWindow (width,height); } void ExpWinH (int width, int height) { if (width > 2) ExpWinH (width-2,height); WaitVBL (1); CenterWindow (width,height); } void ExpWinV (int width, int height) { if (height >2) ExpWinV (width,height-2); WaitVBL (1); CenterWindow (width,height); } ////////////////////////////////////////////////// // // Draw Frame 0/1 (for flashing) // ////////////////////////////////////////////////// void DrawFrame(int x1,int y1,int x2,int y2,int type) { int loop; type=type*22+1; for (loop=x1+1;loop>(1-loop)*4)&15]; Print(str); } } //////////////////////////////////////////////////////////////////// // // Print hex // //////////////////////////////////////////////////////////////////// void PrintHex(unsigned value) { Print("$"); PrintHexB(value>>8); PrintHexB(value&0xff); } //////////////////////////////////////////////////////////////////// // // Print bin // //////////////////////////////////////////////////////////////////// void PrintBin(unsigned value) { int loop; Print("%"); for (loop=0;loop<16;loop++) if ((value>>15-loop)&1) Print("1"); else Print("0"); } //////////////////////////////////////////////////////////////////// // // center Print // //////////////////////////////////////////////////////////////////// void PrintC(char *string) { sx=1+screencenterx-(strlen(string)/2); Print(string); } //////////////////////////////////////////////////////////////////// // // Input unsigned // //////////////////////////////////////////////////////////////////// unsigned InputInt(void) { char string[18]="",digit,hexstr[16]="0123456789ABCDEF"; unsigned value,loop,loop1; Input(string,2); if (string[0]=='$') { int digits; digits=strlen(string)-2; if (digits<0) return 0; for (value=0,loop1=0;loop1<=digits;loop1++) { digit=toupper(string[loop1+1]); for (loop=0;loop<16;loop++) if (digit==hexstr[loop]) { value|=(loop<<(digits-loop1)*4); break; } } } else if (string[0]=='%') { int digits; digits=strlen(string)-2; if (digits<0) return 0; for (value=0,loop1=0;loop1<=digits;loop1++) { if (string[loop1+1]<'0' || string[loop1+1]>'1') return 0; value|=(string[loop1+1]-'0')<<(digits-loop1); } } else value=atoi(string); return value; } //////////////////////////////////////////////////////////////////// // // line Input routine (PROPORTIONAL) // //////////////////////////////////////////////////////////////////// int Input(char *string,int max) { char key; int count=0,loop; int pxt[90]; pxt[0]=px; do { key=toupper(PGet()&0xff); if ((key==127 || key==8)&&count>0) { count--; px=pxt[count]; DrawPchar(string[count]); px=pxt[count]; } if (key>=' ' && key<='z' && countwidth[ch]; } return length; } ///////////////////////// // // CPPrint // Centers the string between pxl/pxh // ///////////////////////// void CPPrint (const char *str) { int width; width = PSize(str); px=pxl+(int)(pxh-pxl-width)/2; PPrint (str); } ///////////////////////// // // PWarap // Prints a string at px,py, word wrapping to pxl/pxh // ///////////////////////// void PWrap (const char *str) { unsigned char ch; while ((ch=*str++) != 0) if (ch == '\n') { py+=10; px=leftedge; } else if (ch == '\r') px=leftedge; else DrawPchar (ch); } void PPrintInt (int val) { itoa(val,str,10); PPrint (str); } void PPrintUnsigned (unsigned val) { ltoa((long)val,str,10); PPrint (str); } void PPrintLong (long val) { ltoa((long)val,str,10); PPrint (str); } //////////////////////////////////////////////////////////////////// // // line Input routine with default string // //////////////////////////////////////////////////////////////////// int PInput(char *string,int max) { char key; int count,loop,oldx; count = strlen(string); PPrint (str); do { key=toupper(PGet()&0xff); if ((key==127 || key==8)&&count>0) { px-= ((fontstruct _seg *)fontseg)->width[ch]; oldx=px; count--; DrawPchar(string[count]); px=oldx; } if (key>=' ' && key<='z' && count>(1-loop)*4)&15]; PPrint(str); } } //////////////////////////////////////////////////////////////////// // // Print hex // //////////////////////////////////////////////////////////////////// void PPrintHex(unsigned value) { PPrint("$"); PPrintHexB(value>>8); PPrintHexB(value&0xff); } /* =========================================================================== GAME ROUTINES =========================================================================== */ long score,highscore; int level,bestlevel; char far *maprle; LevelDef far *levelheader; unsigned far *mapplane[4]; // points into map int mapbwide,mapwwide,mapwidthextra,mapheight; //////////////////////// // // loadctrls // Tries to load the control panel settings // creates a default if not present // //////////////////////// void LoadCtrls (void) { int handle; if ((handle = open("CTLPANEL."EXTENSION, O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1) // // set up default control panel settings // { key[0] = 0x48; key[1] = 0x49; key[2] = 0x4d; key[3] = 0x51; key[4] = 0x50; key[5] = 0x4f; key[6] = 0x4b; key[7] = 0x47; keyB1 = 0x1d; keyB2 = 0x38; } else { read(handle, &key, sizeof(key)); read(handle, &keyB1, sizeof(keyB1)); read(handle, &keyB2, sizeof(keyB2)); read(handle, &highscore, sizeof(highscore)); read(handle, &bestlevel, sizeof(bestlevel)); close(handle); } } void SaveCtrls (void) { int handle; if ((handle = open("CTLPANEL."EXTENSION, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE)) == -1) return; write(handle, &key, sizeof(key)); write(handle, &keyB1, sizeof(keyB1)); write(handle, &keyB2, sizeof(keyB2)); write(handle, &highscore, sizeof(highscore)); write(handle, &bestlevel, sizeof(bestlevel)); close(handle); }