1 /* Catacomb Armageddon Source Code
\r
2 * Copyright (C) 1993-2014 Flat Rock Software
\r
4 * This program is free software; you can redistribute it and/or modify
\r
5 * it under the terms of the GNU General Public License as published by
\r
6 * the Free Software Foundation; either version 2 of the License, or
\r
7 * (at your option) any later version.
\r
9 * This program is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 * GNU General Public License for more details.
\r
14 * You should have received a copy of the GNU General Public License along
\r
15 * with this program; if not, write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
31 #include "sl_file.h"
\r
34 #define MAX_GAMELIST_NAMES 20
\r
37 ////////////////////////////////////////////////////////////////////////////
\r
41 boolean InLoadSaveGame = false;
\r
42 //AudioDeviceType ge_DigiMode;
\r
43 boolean ConserveMemory = false;
\r
44 char GameListNames[MAX_GAMELIST_NAMES+1][FNAME_LEN],current_disk=1;
\r
46 short PPT_LeftEdge=0,PPT_RightEdge=320;
\r
47 boolean LeaveDriveOn=false,ge_textmode=true;
\r
48 char Filename[FILENAME_LEN+1], ID[sizeof(GAMENAME)], VER[sizeof(SAVEVER_DATA)];
\r
49 short wall_anim_delay,wall_anim_time = 7;
\r
56 ////////////////////////////////////////////////////////////////////////////
\r
58 // CalibrateJoystick()
\r
60 void CalibrateJoystick(short joynum)
\r
69 VW_FixRefreshBuffer();
\r
73 US_CPrintLine("Move joystick to the upper-left");
\r
74 US_CPrintLine("and press one of the buttons.");
\r
77 while ((LastScan != sc_Escape) && !IN_GetJoyButtonsDB(joynum));
\r
78 if (LastScan == sc_Escape)
\r
81 IN_GetJoyAbs(joynum,&minx,&miny);
\r
82 while (IN_GetJoyButtonsDB(joynum));
\r
85 US_CPrintLine("Move joystick to the lower-right");
\r
86 US_CPrintLine("and press one of the buttons.");
\r
89 while ((LastScan != sc_Escape) && !IN_GetJoyButtonsDB(joynum));
\r
90 if (LastScan == sc_Escape)
\r
93 IN_GetJoyAbs(joynum,&maxx,&maxy);
\r
94 if ((minx == maxx) && (miny == maxy))
\r
97 IN_SetupJoy(joynum,minx,maxx,miny,maxy);
\r
99 while (IN_GetJoyButtonsDB(joynum));
\r
101 IN_ClearKeysDown();
\r
103 JoystickCalibrated = true;
\r
106 ////////////////////////////////////////////////////////////////////////////
\r
110 void WaitKeyVBL(short key, short vbls)
\r
115 IN_ReadControl(0,&control);
\r
116 if ((control.button0|control.button1)||(Keyboard[key]))
\r
121 ////////////////////////////////////////////////////////////////////////////
\r
125 // panadjust must be saved and restored if MoveScreen is being called from
\r
128 void MoveScreen(short x, short y)
\r
132 address = (y*linewidth)+(x/8);
\r
133 VW_SetScreen(address,0);
\r
134 bufferofs = displayofs = address;
\r
138 ////////////////////////////////////////////////////////////////////////////
\r
142 void MoveGfxDst(short x, short y)
\r
146 address = (y*linewidth)+(x/8);
\r
147 bufferofs = displayofs = address;
\r
154 ///////////////////////////////////////////////////////////////////////////
\r
156 // DoPiracy() - Graphics piracy code...
\r
160 struct Shape Pirate1Shp;
\r
161 struct Shape Pirate2Shp;
\r
163 VW_SetScreenMode (EGA320GR);
\r
164 VW_ClearVideo(BLACK);
\r
168 if (LoadShape("PIRATE1E."EXT,&Pirate1Shp))
\r
169 TrashProg("Can't load PIRATE1E.BIO");
\r
171 if (LoadShape("PIRATE2E."EXT,&Pirate2Shp))
\r
172 TrashProg("Can't load PIRATE2E.BIO");
\r
174 // Deal with shapes...
\r
176 VW_SetLineWidth(40);
\r
181 UnpackEGAShapeToScreen(&Pirate1Shp,(linewidth-Pirate1Shp.BPR)<<2,0);
\r
184 UnpackEGAShapeToScreen(&Pirate2Shp,(linewidth-Pirate2Shp.BPR)<<2,0);
\r
188 WaitKeyVBL(57,200);
\r
189 while (Keyboard[57]);
\r
191 SD_PlaySound(GOOD_PICKSND);
\r
194 WaitKeyVBL(57,300);
\r
195 while (Keyboard[57]);
\r
198 FreeShape(&Pirate1Shp);
\r
199 FreeShape(&Pirate2Shp);
\r
204 ///////////////////////////////////////////////////////////////////////////
\r
206 // DoPiracy() - Text-based piracy code...
\r
215 //--------------------------------------------------------------------------
\r
217 //--------------------------------------------------------------------------
\r
218 void BlackPalette()
\r
220 extern char colors[7][17];
\r
222 _ES=FP_SEG(&colors[0]);
\r
223 _DX=FP_OFF(&colors[0]);
\r
225 geninterrupt(0x10);
\r
226 screenfaded = true;
\r
229 //--------------------------------------------------------------------------
\r
230 // ColoredPalette()
\r
231 //--------------------------------------------------------------------------
\r
232 void ColoredPalette()
\r
234 extern char colors[7][17];
\r
236 _ES=FP_SEG(&colors[3]);
\r
237 _DX=FP_OFF(&colors[3]);
\r
239 geninterrupt(0x10);
\r
240 screenfaded = false;
\r
243 ////////////////////////////////////////////////////////////////////////////
\r
247 long Verify(char *filename)
\r
252 if ((handle=open(filename,O_BINARY))==-1)
\r
254 size=filelength(handle);
\r
259 ///////////////////////////////////////////////////////////////////////////
\r
263 // Handles user i/o for saving a game
\r
265 ///////////////////////////////////////////////////////////////////////////
\r
269 boolean GettingFilename=true;
\r
270 // char Filename[FILENAME_LEN+1]; //, ID[sizeof(GAMENAME)], VER[sizeof(SAVEVER_DATA)];
\r
272 struct dfree dfree;
\r
275 VW_FixRefreshBuffer();
\r
277 while (GettingFilename)
\r
279 DisplayGameList(2,7,3,10);
\r
280 US_DrawWindow(5,1,30,3);
\r
281 memset(Filename,0,sizeof(Filename));
\r
282 US_CPrint("Enter name to SAVE this game:");
\r
286 if (!US_LineInput((linewidth<<2)-32,20,Filename,"",true,8,0))
\r
288 if (!strlen(Filename))
\r
290 getdfree(getdisk()+1,&dfree);
\r
291 davail = (long)dfree.df_avail*(long)dfree.df_bsec*(long)dfree.df_sclus;
\r
292 if (davail < 10000)
\r
294 US_CenterWindow(22,4);
\r
296 US_CPrintLine("Disk Full: Can't save game.");
\r
297 US_CPrintLine("Try inserting another disk.");
\r
304 strcat(Filename,".SAV");
\r
305 GettingFilename = false;
\r
306 if (Verify(Filename)) // FILE EXISTS
\r
308 US_CenterWindow(22,4);
\r
309 US_CPrintLine("That file already exists...");
\r
310 US_CPrintLine("Overwrite it ????");
\r
311 US_CPrintLine("(Y)es or (N)o?");
\r
314 while((!Keyboard[21]) && (!Keyboard[49]) && !Keyboard[27]);
\r
320 GettingFilename = true;
\r
327 handle = open(Filename,O_RDWR|O_CREAT|O_BINARY,S_IREAD|S_IWRITE);
\r
331 if ((!CA_FarWrite(handle,(void far *)GAMENAME,sizeof(GAMENAME))) || (!CA_FarWrite(handle,(void far *)SAVEVER_DATA,sizeof(SAVEVER_DATA))))
\r
339 if (!USL_SaveGame(handle))
\r
340 Quit("Save game error");
\r
352 US_CenterWindow(22,6);
\r
353 US_CPrintLine("DISK ERROR");
\r
354 US_CPrintLine("Check: Write protect...");
\r
355 US_CPrintLine("File name...");
\r
356 US_CPrintLine("Bytes free on disk...");
\r
357 US_CPrintLine("Press SPACE to continue.");
\r
359 while (!Keyboard[57]);
\r
360 while (Keyboard[57]);
\r
363 while (Keyboard[1]);
\r
370 ///////////////////////////////////////////////////////////////////////////
\r
374 // Handles user i/o for loading a game
\r
376 ///////////////////////////////////////////////////////////////////////////
\r
378 boolean GE_LoadGame()
\r
380 boolean GettingFilename=true,rt_code=false;
\r
383 IN_ClearKeysDown();
\r
384 memset(ID,0,sizeof(ID));
\r
385 memset(VER,0,sizeof(VER));
\r
386 VW_FixRefreshBuffer();
\r
388 while (GettingFilename)
\r
390 DisplayGameList(2,7,3,10);
\r
391 US_DrawWindow(5,1,30,3);
\r
392 memset(Filename,0,sizeof(Filename));
\r
393 US_CPrint("Enter name of game to RESTORE:");
\r
397 if (!US_LineInput((linewidth<<2)-32,20,Filename,"",true,8,0))
\r
399 strcat(Filename,".SAV");
\r
400 GettingFilename = false;
\r
402 if (!Verify(Filename)) // FILE DOESN'T EXIST
\r
404 US_CenterWindow(22,3);
\r
405 US_CPrintLine(" That file doesn't exist....");
\r
406 US_CPrintLine("Press SPACE to try again.");
\r
409 while (!Keyboard[57]);
\r
410 while (Keyboard[57]);
\r
411 GettingFilename = true;
\r
415 handle = open(Filename,O_RDWR|O_BINARY);
\r
419 if ((!CA_FarRead(handle,(void far *)&ID,sizeof(ID))) || (!CA_FarRead(handle,(void far *)&VER,sizeof(VER))))
\r
422 if ((strcmp(ID,GAMENAME)) || (strcmp(VER,SAVEVER_DATA)))
\r
424 US_CenterWindow(32,4);
\r
425 US_CPrintLine("That isn't a "GAMENAME);
\r
426 US_CPrintLine(".SAV file.");
\r
427 US_CPrintLine("Press SPACE to continue.");
\r
429 while (!Keyboard[57]);
\r
430 while (Keyboard[57]);
\r
438 if (!USL_LoadGame(handle))
\r
439 Quit("Load game error.");
\r
447 US_CenterWindow(22,3);
\r
448 US_CPrintLine("DISK ERROR ** LOAD **");
\r
449 US_CPrintLine("Press SPACE to continue.");
\r
450 while (!Keyboard[57]);
\r
451 while (Keyboard[57]);
\r
462 ///////////////////////////////////////////////////////////////////////////
\r
464 // GE_HardError() - Handles the Abort/Retry/Fail sort of errors passed
\r
465 // from DOS. Hard coded to ignore if during Load/Save Game.
\r
467 ///////////////////////////////////////////////////////////////////////////
\r
470 int GE_HardError(word errval,int ax,int bp,int si)
\r
475 extern void ShutdownId(void);
\r
477 static char buf[32];
\r
478 static WindowRec wr;
\r
479 static boolean oldleavedriveon;
\r
482 boolean holdscreenfaded;
\r
484 if (InLoadSaveGame)
\r
485 hardresume(IGNORE);
\r
490 oldleavedriveon = LeaveDriveOn;
\r
491 LeaveDriveOn = false;
\r
494 s = "Device Error";
\r
497 if ((di & 0x00ff) == 0)
\r
498 s = "Drive ~ is Write Protected";
\r
500 s = "Error on Drive ~";
\r
501 for (t = buf;*s;s++,t++) // Can't use sprintf()
\r
502 if ((*t = *s) == '~')
\r
503 *t = (ax & 0x00ff) + 'A';
\r
508 c = peekb(0x40,0x49); // Get the current screen mode
\r
509 if ((c < 4) || (c == 7))
\r
512 // DEBUG - handle screen cleanup
\r
513 holdscreenfaded=screenfaded;
\r
515 US_SaveWindow(&wr);
\r
516 VW_ClearVideo(0); ////////////// added for exiting
\r
517 US_CenterWindow(30,3);
\r
519 US_CPrint("(R)etry or (A)bort?");
\r
521 if (holdscreenfaded)
\r
523 IN_ClearKeysDown();
\r
525 asm sti // Let the keyboard interrupts come through
\r
529 switch (IN_WaitForASCII())
\r
540 if (holdscreenfaded)
\r
544 US_RestoreWindow(&wr);
\r
545 LeaveDriveOn = oldleavedriveon;
\r
553 TrashProg("Terminal Error: %s\n",s);
\r
555 // fprintf(stderr,"You launched from TED. I suggest that you reboot...\n");
\r
565 //--------------------------------------------------------------------------
\r
571 //--------------------------------------------------------------------------
\r
577 ////////////////////////////////////////////////////////////////////////////
\r
579 // UpdateBOBList() - Adds a sprite to an objects BOBlist. The BOB List
\r
580 // must already be allocated and have an available slot.
\r
582 // RETURNS : true = Success adding Sprite / false = Failure.
\r
584 // NOTE : This also sets the users 'needtoreact' flag to true.
\r
586 boolean UpdateBOBList(objtype *obj,struct Simple_Shape *Shape,shapeclass Class, short priority, spriteflags sprflags)
\r
588 struct BOB_Shape *CurBOBShape = NULL;
\r
592 if (CurBOBShape = obj->nextshape)
\r
594 // Treverse down BOBList looking for a sprite with the same class
\r
595 // OR an empty shape struct to store the new shape.
\r
597 while ((CurBOBShape->class != Class) && (CurBOBShape->class) && CurBOBShape)
\r
599 CurBOBShape = CurBOBShape->nextshape;
\r
604 RF_RemoveSprite(&CurBOBShape->sprite);
\r
605 CurBOBShape->shapenum = Shape->shapenum;
\r
606 CurBOBShape->x_offset = Shape->x_offset;
\r
607 CurBOBShape->y_offset = Shape->y_offset;
\r
608 CurBOBShape->priority = priority;
\r
609 CurBOBShape->sprflags = sprflags;
\r
610 CurBOBShape->class = Class;
\r
620 /////////////////////////////////////////////////////////////////////////////
\r
622 // RemoveBOBShape() - Removes a sprite from a BOBList.
\r
624 // RETURNS : true = Success / false = Failure (shape not found)
\r
626 boolean RemoveBOBShape(objtype *obj, shapeclass Class)
\r
628 struct BOB_Shape *CurBOBShape = NULL;
\r
632 if (CurBOBShape = obj->nextshape)
\r
634 while ((CurBOBShape->class != Class) && (!CurBOBShape->class) && CurBOBShape)
\r
636 CurBOBShape = CurBOBShape->nextshape;
\r
641 CurBOBShape->class = noshape;
\r
652 /////////////////////////////////////////////////////////////////////////////
\r
654 // RemoveBOBList() - Removes an entire BOBList attached to an object.
\r
657 void RemoveBOBList(objtype *obj)
\r
659 struct BOB_Shape *CurBOBShape;
\r
663 if (CurBOBShape = obj->nextshape)
\r
665 // Treverse down BOBList looking for a sprite with the same class
\r
666 // OR an empty shape struct to store the new shape.
\r
668 while (CurBOBShape)
\r
670 if (CurBOBShape->class)
\r
672 CurBOBShape->class = noshape;
\r
673 RF_RemoveSprite (&CurBOBShape->sprite);
\r
675 CurBOBShape = CurBOBShape->nextshape;
\r
685 /////////////////////////////////////////////////////////////////////////////
\r
687 // InitBOBList() -- This initializes a BOB list for all the possible shapes
\r
688 // attached at one time. This is done with an array of
\r
689 // BOB_Shape structs and links the 'nextshape' pointer to
\r
690 // to the next element.
\r
693 void InitBOBList(objtype *obj, struct BOB_Shape *BOB_Shape, short NumElements)
\r
695 struct BOB_Shape *CurShape;
\r
698 obj->nextshape = BOB_Shape;
\r
700 for (loop=1;loop<NumElements;loop++)
\r
702 CurShape = BOB_Shape++;
\r
703 CurShape->nextshape = BOB_Shape;
\r
706 BOB_Shape->nextshape = NULL;
\r
710 ////////////////////////////////////////////////////////////////////////////
\r
712 // RefreshBOBList() -- This routine updates all sprites attached to the
\r
713 // BOBList and refreshes there position in the sprite
\r
716 void RefreshBOBList(objtype *obj)
\r
718 struct BOB_Shape *Shape;
\r
720 Shape = obj->nextshape;
\r
725 RF_PlaceSprite(&Shape->sprite,obj->x+Shape->x_offset,obj->y+Shape->y_offset, Shape->shapenum, spritedraw,Shape->priority,Shape->sprflags);
\r
726 Shape = Shape->nextshape;
\r
733 //--------------------------------------------------------------------------
\r
734 // InitBufferedIO()
\r
735 //--------------------------------------------------------------------------
\r
736 memptr InitBufferedIO(int handle, BufferedIO *bio)
\r
738 bio->handle = handle;
\r
739 bio->offset = BIO_BUFFER_LEN;
\r
741 MM_GetPtr(&bio->buffer,BIO_BUFFER_LEN);
\r
743 return(bio->buffer);
\r
746 //--------------------------------------------------------------------------
\r
747 // FreeBufferedIO()
\r
748 //--------------------------------------------------------------------------
\r
749 void FreeBufferedIO(BufferedIO *bio)
\r
752 MM_FreePtr(&bio->buffer);
\r
755 //--------------------------------------------------------------------------
\r
757 //--------------------------------------------------------------------------
\r
758 byte bio_readch(BufferedIO *bio)
\r
762 if (bio->offset == BIO_BUFFER_LEN)
\r
765 bio_fillbuffer(bio);
\r
768 buffer = MK_FP(bio->buffer,bio->offset++);
\r
773 //--------------------------------------------------------------------------
\r
774 // bio_fillbuffer()
\r
776 // BUGS (Not really bugs... More like RULES!)
\r
778 // 1) This code assumes BIO_BUFFER_LEN is no smaller than
\r
779 // NEAR_BUFFER_LEN!!
\r
781 // 2) BufferedIO.status should be altered by this code to report
\r
782 // read errors, end of file, etc... If you know how big the file
\r
783 // is you're reading, determining EOF should be no problem.
\r
785 //--------------------------------------------------------------------------
\r
786 void bio_fillbuffer(BufferedIO *bio)
\r
788 #define NEAR_BUFFER_LEN (64)
\r
789 byte near_buffer[NEAR_BUFFER_LEN];
\r
790 short bio_length,bytes_read,bytes_requested;
\r
793 bio_length = BIO_BUFFER_LEN;
\r
796 if (bio_length > NEAR_BUFFER_LEN-1)
\r
797 bytes_requested = NEAR_BUFFER_LEN;
\r
799 bytes_requested = bio_length;
\r
801 read(bio->handle,near_buffer,bytes_requested);
\r
802 _fmemcpy(MK_FP(bio->buffer,bytes_read),near_buffer,bytes_requested);
\r
804 bio_length -= bytes_requested;
\r
805 bytes_read += bytes_requested;
\r
809 ///////////////////////////////////////////////////////////////////////////
\r
813 void SwapLong(long far *Var)
\r
818 asm xchg ax,[es:bx+2]
\r
823 ///////////////////////////////////////////////////////////////////////////
\r
827 void SwapWord(unsigned int far *Var)
\r
838 ////////////////////////////////////////////////////////////////////////////
\r
842 int LoadShape(char *Filename,struct Shape *SHP)
\r
844 #define CHUNK(Name) (*ptr == *Name) && \
\r
845 (*(ptr+1) == *(Name+1)) && \
\r
846 (*(ptr+2) == *(Name+2)) && \
\r
847 (*(ptr+3) == *(Name+3))
\r
851 // struct ffblk ffblk;
\r
855 memptr IFFfile = NULL;
\r
856 unsigned long FileLen, size, ChunkLen;
\r
862 // Decompress to ram and return ptr to data and return len of data in
\r
863 // passed variable...
\r
865 if (!(FileLen = BLoad(Filename,&IFFfile)))
\r
866 TrashProg("Can't load Compressed Shape - Possibly corrupt file!");
\r
868 // Evaluate the file
\r
870 ptr = MK_FP(IFFfile,0);
\r
871 if (!CHUNK("FORM"))
\r
875 FileLen = *(long far *)ptr;
\r
876 SwapLong((long far *)&FileLen);
\r
879 if (!CHUNK("ILBM"))
\r
886 ChunkLen = *(long far *)(ptr+4);
\r
887 SwapLong((long far *)&ChunkLen);
\r
888 ChunkLen = (ChunkLen+1) & 0xFFFFFFFE;
\r
893 SHP->bmHdr.w = ((struct BitMapHeader far *)ptr)->w;
\r
894 SHP->bmHdr.h = ((struct BitMapHeader far *)ptr)->h;
\r
895 SHP->bmHdr.x = ((struct BitMapHeader far *)ptr)->x;
\r
896 SHP->bmHdr.y = ((struct BitMapHeader far *)ptr)->y;
\r
897 SHP->bmHdr.d = ((struct BitMapHeader far *)ptr)->d;
\r
898 SHP->bmHdr.trans = ((struct BitMapHeader far *)ptr)->trans;
\r
899 SHP->bmHdr.comp = ((struct BitMapHeader far *)ptr)->comp;
\r
900 SHP->bmHdr.pad = ((struct BitMapHeader far *)ptr)->pad;
\r
901 SwapWord(&SHP->bmHdr.w);
\r
902 SwapWord(&SHP->bmHdr.h);
\r
903 SwapWord(&SHP->bmHdr.x);
\r
904 SwapWord(&SHP->bmHdr.y);
\r
911 size = *((long far *)ptr);
\r
913 SwapLong((long far *)&size);
\r
914 SHP->BPR = (SHP->bmHdr.w+7) >> 3;
\r
915 MM_GetPtr(&SHP->Data,size);
\r
918 movedata(FP_SEG(ptr),FP_OFF(ptr),FP_SEG(SHP->Data),0,size);
\r
926 FileLen -= ChunkLen+8;
\r
934 // segptr = (memptr)FP_SEG(IFFfile);
\r
935 MM_FreePtr(&IFFfile);
\r
943 ////////////////////////////////////////////////////////////////////////////
\r
947 void FreeShape(struct Shape *shape)
\r
950 MM_FreePtr(&shape->Data);
\r
953 ////////////////////////////////////////////////////////////////////////////
\r
955 // UnpackEGAShapeToScreen()
\r
957 int UnpackEGAShapeToScreen(struct Shape *SHP,int startx,int starty)
\r
960 signed char n, Rep, far *Src, far *Dst[8], loop, Plane;
\r
961 unsigned int BPR, Height;
\r
962 boolean NotWordAligned;
\r
964 NotWordAligned = SHP->BPR & 1;
\r
966 Src = MK_FP(SHP->Data,0);
\r
969 Height = SHP->bmHdr.h;
\r
972 Dst[0] = (MK_FP(0xA000,displayofs));
\r
973 Dst[0] += ylookup[currenty];
\r
975 for (loop=1; loop<SHP->bmHdr.d; loop++)
\r
976 Dst[loop] = Dst[0];
\r
979 for (Plane=0; Plane<SHP->bmHdr.d; Plane++)
\r
981 outport(0x3c4,((1<<Plane)<<8)|2);
\r
983 BPR = ((SHP->BPR+1) >> 1) << 1; // IGNORE WORD ALIGN
\r
986 if (SHP->bmHdr.comp)
\r
998 if ((!BPR) && (NotWordAligned)) // IGNORE WORD ALIGN
\r
1002 *Dst[Plane]++ = Rep;
\r
1011 if ((!BPR) && (NotWordAligned)) // IGNORE WORD ALIGN
\r
1015 *Dst[Plane]++ = *Src++;
\r
1017 if ((!BPR) && (NotWordAligned)) // IGNORE WORD ALIGN
\r
1028 ////////////////////////////////////////////////////////////////////////////
\r
1032 char GetKeyChoice(char *choices,boolean clear)
\r
1034 extern void DoEvents(void);
\r
1039 IN_ClearKeysDown();
\r
1047 if (Keyboard[*s++])
\r
1055 IN_ClearKeysDown();
\r
1062 ////////////////////////////////////////////////////////////////////////////
\r
1066 boolean AnimateObj(objtype *obj)
\r
1072 if (obj->animtype == at_NONE) // Animation finished?
\r
1073 return(true); // YEP!
\r
1075 if (obj->animdelay) // Check animation delay.
\r
1077 obj->animdelay -= tics;
\r
1078 if (obj->animdelay < 0)
\r
1079 obj->animdelay = 0;
\r
1083 switch (obj->animtype) // Animate this object!
\r
1087 switch (obj->animdir)
\r
1090 if (obj->curframe < obj->maxframe)
\r
1091 AdvanceAnimFWD(obj);
\r
1093 if (obj->animtype == at_CYCLE)
\r
1095 obj->curframe = 0; // RESET CYCLE ANIMATION
\r
1100 obj->animtype = at_NONE; // TERMINATE ONCE ANIM
\r
1106 if (obj->curframe > 0)
\r
1107 AdvanceAnimREV(obj);
\r
1109 if (obj->animtype == at_CYCLE)
\r
1111 obj->curframe = obj->maxframe; // RESET CYCLE ANIMATION
\r
1112 obj->animdelay = 1;
\r
1116 obj->animtype = at_NONE; // TERMINATE ONCE ANIM
\r
1124 switch (obj->animdir)
\r
1127 if (obj->curframe < obj->maxframe)
\r
1128 AdvanceAnimFWD(obj);
\r
1131 obj->animdir = at_REV;
\r
1132 obj->animdelay = 1;
\r
1137 if (obj->curframe > 0)
\r
1138 AdvanceAnimREV(obj);
\r
1141 obj->animdir = at_FWD;
\r
1142 obj->animdelay = 1;
\r
1147 break; /* REBOUND */
\r
1157 void AdvanceAnimFWD(objtype *obj) // Advances a Frame of ANIM for ONCE,CYCLE, REBOUND
\r
1159 obj->curframe++; // INC frames
\r
1160 obj->animdelay = obj->maxdelay; // Init Delay Counter.
\r
1161 obj->needtoreact = true;
\r
1165 void AdvanceAnimREV(objtype *obj) // Advances a Frame of ANIM for ONCE,CYCLE, REBOUND
\r
1167 obj->curframe--; // DEC frames
\r
1168 obj->animdelay = obj->maxdelay; // Init Delay Counter.
\r
1169 obj->needtoreact = true;
\r
1174 ///////////////////////////////////////////////////////////////////////////
\r
1176 // LoadASArray() - Load an array of audio samples in FAR memory.
\r
1178 void LoadASArray(struct Sample *ASArray)
\r
1182 while (ASArray[loop].filename)
\r
1184 if (!BLoad(ASArray[loop].filename,(memptr *)&ASArray[loop].data))
\r
1185 TrashProg("Unable to load sample in LoadASArray()");
\r
1192 ////////////////////////////////////////////////////////////////////////////
\r
1194 // FreeASArray() - Frees an ASArray from memory that has been loaded with
\r
1197 void FreeASArray(struct Sample *ASArray)
\r
1199 unsigned loop = 0;
\r
1201 while (ASArray[loop].data)
\r
1203 MM_SetPurge((memptr *)&ASArray[loop++].data,3);
\r
1204 MM_FreePtr((memptr *)&ASArray[loop++].data);
\r
1208 ///////////////////////////////////////////////////////////////////////////
\r
1210 // GE_LoadAllDigiSounds() - This is a hook that CA_LoadAllSounds()
\r
1211 // calls to load all of the Digitized sounds for
\r
1212 // Sound Blaster & Sound Source.
\r
1214 // NOTE : This stub would do any other necessary routines for DigiSounds
\r
1215 // specific to GAMERS EDGE code. (Keeping seperate from ID's)
\r
1217 void GE_LoadAllDigiSounds()
\r
1219 LoadASArray(DigiSounds);
\r
1224 /////////////////////////////////////////////////////////////////////////
\r
1226 // GE_FreeAllDigiSounds() -- This is a hook that CA_LoadAllSounds()
\r
1227 // calls to free all digitized sounds for
\r
1228 // which ever hardware and allow for any necessary
\r
1232 // NOTE : This stub would do any other necessary routines for DigiSounds
\r
1233 // specific to GAMERS EDGE code. (Keeping seperate from ID's)
\r
1235 void GE_FreeAllDigiSounds()
\r
1237 FreeASArray(DigiSounds);
\r
1242 ///////////////////////////////////////////////////////////////////////////
\r
1244 // GE_LoadAllSounds() - Loads ALL sounds needed for detected hardware.
\r
1246 void GE_LoadAllSounds()
\r
1250 start = STARTPCSOUNDS;
\r
1251 for (i=0;i<NUMSOUNDS;i++,start++)
\r
1252 CA_CacheAudioChunk (start);
\r
1256 start = STARTADLIBSOUNDS;
\r
1257 for (i=0;i<NUMSOUNDS;i++,start++)
\r
1258 CA_CacheAudioChunk (start);
\r
1261 if (SoundBlasterPresent)
\r
1262 LoadASArray(DigiSounds);
\r
1266 //////////////////////////////////////////////////////////////////////////
\r
1268 // GE_PurgeAllSounds() - Frees all sounds that were loaded.
\r
1270 void GE_PurgeAllSounds()
\r
1274 start = STARTPCSOUNDS;
\r
1275 for (i=0;i<NUMSOUNDS;i++,start++)
\r
1276 if (audiosegs[start])
\r
1277 MM_SetPurge (&(memptr)audiosegs[start],3); // make purgable
\r
1282 start = STARTADLIBSOUNDS;
\r
1283 for (i=0;i<NUMSOUNDS;i++,start++)
\r
1284 if (audiosegs[start])
\r
1285 MM_SetPurge (&(memptr)audiosegs[start],3); // make purgable
\r
1288 if (SoundBlasterPresent)
\r
1289 GE_FreeAllDigiSounds();
\r
1293 /////////////////////////////////////////////////////////////////////////////
\r
1295 // PlaySample() -- Plays a DIGITIZED sample using SoundBlaster OR SoundSource
\r
1297 // PARAMETERS : Sample Number (Corresponding to ASArray "DigiSounds[]".
\r
1299 void PlaySample(unsigned SampleNum)
\r
1302 if (!DigiSounds[SampleNum].data)
\r
1303 TrashProg("PlaySample - Trying to play an unloaded digi sound!");
\r
1306 switch (SoundMode) // external variable in ID_SD for sound mode..
\r
1308 case sdm_SoundBlaster:
\r
1309 case sdm_SoundBlasterAdLib:
\r
1310 SDL_SBPlaySample(MK_FP(DigiSounds[SampleNum].data,0));
\r
1314 TrashProg("PlaySample() - incorrect SoundMode for PlaySample()");
\r
1320 /////////////////////////////////////////////////////////////////////////////
\r
1322 // SelectDigiAudio() -- This routine intergrates multi sound hardware with
\r
1325 void SelectDigiAudio(AudioDeviceType Device)
\r
1329 case ged_SoundSource:
\r
1330 case ged_SoundBlaster:
\r
1336 ///////////////////////////////////////////////////////////////////////////
\r
1338 // DisplayGameList()
\r
1340 void DisplayGameList(short winx, short winy, short list_width, short list_height)
\r
1344 short width,col,row,orgcol,games_printed=0,h;
\r
1346 // Possibly shrink window.
\r
1348 h = (NumGames / list_width) + ((NumGames % list_width) > 0);
\r
1349 if (h < list_height)
\r
1352 // Open window and print header...
\r
1354 US_DrawWindow(winx,winy,list_width*(8+SPACES*2),list_height+3);
\r
1355 US_CPrintLine("LIST OF SAVED GAMES");
\r
1358 col = orgcol = PrintX;
\r
1361 // Display as many 'save game' files as can fit in the window.
\r
1363 width = list_width;
\r
1364 while ((games_printed<NumGames) && (list_height))
\r
1366 // Print filename and padding spaces.
\r
1368 US_Printxy(col+(SPACES*8),row,GameListNames[games_printed]);
\r
1369 col += 8*((SPACES*2)+8);
\r
1371 // Check for end-of-line or end-of-window.
\r
1378 width = list_width;
\r
1387 ////////////////////////////////////////////////////////////////////////////
\r
1391 void ReadGameList()
\r
1393 struct ffblk ffblk;
\r
1397 done = findfirst("*.sav",&ffblk,0);
\r
1401 if (NumGames == MAX_GAMELIST_NAMES)
\r
1402 memcpy(GameListNames,GameListNames[1],MAX_GAMELIST_NAMES*sizeof(GameListNames[0]));
\r
1406 fnsplit(ffblk.ff_name,NULL,NULL,GameListNames[NumGames],NULL);
\r
1408 done=findnext(&ffblk);
\r
1415 ////////////////////////////////////////////////////////////////////////////
\r
1419 void CenterObj(objtype *obj, unsigned x, unsigned y)
\r
1421 spritetabletype far *sprite;
\r
1422 unsigned width, height;
\r
1424 sprite=&spritetable[obj->baseshape+obj->curframe-STARTSPRITES];
\r
1426 width = (sprite->xh-sprite->xl+(1<<G_P_SHIFT)) >> 1;
\r
1427 if (obj->sprflags&sf_vertflip)
\r
1429 height = (sprite->yl-(sprite->height<<G_P_SHIFT) + sprite->yh+(1<<G_P_SHIFT)) >> 1;
\r
1432 height = (sprite->yh-sprite->yl+(1<<G_P_SHIFT)) >> 1;
\r
1435 obj->y = y-height;
\r
1440 //-------------------------------------------------------------------------
\r
1442 //-------------------------------------------------------------------------
\r
1443 void cacheout(short s,short e)
\r
1447 for(i=(s);i<=(e);i++)
\r
1449 grneeded[i]&=~ca_levelbit;
\r
1451 MM_SetPurge(&grsegs[i],3);
\r
1456 //-------------------------------------------------------------------------
\r
1458 //-------------------------------------------------------------------------
\r
1459 void cachein(short s,short e)
\r
1463 for(i=(s);i<=(e);i++)
\r
1465 CA_MarkGrChunk(i);
\r
1467 MM_SetPurge(&grsegs[i],0);
\r
1473 ////////////////////////////////////////////////////////////////////////////
\r
1475 // SetUpdateBlock()
\r
1477 void SetUpdateBlock(unsigned x,unsigned y,unsigned width,unsigned height,char refresh)
\r
1479 eraseblocktype *erase;
\r
1481 #if 0 //SP unsure if this is needed
\r
1482 x = (x+((MAPBORDER+MAPXLEFTOFFSET)<<4))>>3;
\r
1483 y += ((MAPBORDER+MAPYTOPOFFSET)<<4);
\r
1485 x = (x+(MAPBORDER<<4))>>3;
\r
1486 y += (MAPBORDER<<4);
\r
1492 erase = eraselistptr[0]++;
\r
1495 erase->width=width;
\r
1496 erase->height=height;
\r
1501 erase = eraselistptr[1]++;
\r
1504 erase->width=width;
\r
1505 erase->height=height;
\r
1510 ////////////////////////////////////////////////////////////////////////////
\r
1514 unsigned ObjHeight(objtype *obj)
\r
1516 spritetabletype far *sprite;
\r
1518 sprite=&spritetable[obj->baseshape+obj->curframe-STARTSPRITES];
\r
1520 if (obj->sprflags&sf_vertflip)
\r
1522 return((sprite->yl-(sprite->height<<G_P_SHIFT) + sprite->yh+(1<<G_P_SHIFT)) >> 1);
\r
1525 return((sprite->yh-sprite->yl+(1<<G_P_SHIFT)) >> 1);
\r
1529 ////////////////////////////////////////////////////////////////////////////
\r
1533 unsigned ObjWidth(objtype *obj)
\r
1535 spritetabletype far *sprite;
\r
1537 sprite=&spritetable[obj->baseshape+obj->curframe-STARTSPRITES];
\r
1539 return((sprite->xh-sprite->xl+(1<<G_P_SHIFT)) >> 1);
\r
1544 //--------------------------------------------------------------------------
\r
1546 //--------------------------------------------------------------------------
\r
1547 boolean visible_on(objtype *obj)
\r
1549 if (!(obj->flags & of_visible))
\r
1551 obj->needtoreact=true;
\r
1552 obj->flags |= of_visible;
\r
1559 //--------------------------------------------------------------------------
\r
1561 //--------------------------------------------------------------------------
\r
1562 boolean visible_off(objtype *obj)
\r
1564 if (obj->flags & of_visible)
\r
1566 obj->needtoreact=true;
\r
1567 obj->flags &= ~of_visible;
\r
1577 ===================
\r
1581 ===================
\r
1584 #define PIXPERFRAME 10000
\r
1586 void FizzleFade (unsigned source, unsigned dest,
\r
1587 unsigned width,unsigned height, boolean abortable)
\r
1589 unsigned drawofs,pagedelta;
\r
1590 unsigned char maskb[8] = {1,2,4,8,16,32,64,128};
\r
1591 unsigned x,y,p,frame;
\r
1593 ScanCode lastLastScan=LastScan=0;
\r
1598 pagedelta = dest-source;
\r
1599 // VW_SetScreen (dest,0);
\r
1603 asm mov es,[screenseg]
\r
1604 asm mov dx,SC_INDEX
\r
1605 asm mov al,SC_MAPMASK
\r
1608 TimeCount=frame=0;
\r
1611 if ((abortable) || (Flags & FL_QUICK))
\r
1613 IN_ReadControl(0,&control);
\r
1614 if (control.button0 || control.button1 || (lastLastScan != LastScan)
\r
1615 || Keyboard[sc_Escape] || (Flags & FL_QUICK))
\r
1617 VW_ScreenToScreen (source,dest,(width+1)/8,height+1);
\r
1622 for (p=0;p<PIXPERFRAME;p++)
\r
1625 // seperate random value into x/y pair
\r
1627 asm mov ax,[WORD PTR rndval]
\r
1628 asm mov dx,[WORD PTR rndval+2]
\r
1631 asm mov [BYTE PTR y],bl // low 8 bits - 1 = y xoordinate
\r
1643 asm mov [x],bx // next 9 bits = x xoordinate
\r
1645 // advance to next random element
\r
1653 asm mov [WORD PTR rndval],ax
\r
1654 asm mov [WORD PTR rndval+2],dx
\r
1656 if (x>width || y>height)
\r
1658 drawofs = source+ylookup[y];
\r
1663 asm mov dx,GC_INDEX
\r
1664 asm mov al,GC_BITMASK
\r
1665 asm mov ah,BYTE PTR [maskb+si]
\r
1668 asm mov si,[drawofs]
\r
1674 asm add di,[pagedelta]
\r
1676 asm mov dx,GC_INDEX
\r
1677 asm mov al,GC_READMAP // leave GC_INDEX set to READMAP
\r
1680 asm mov dx,SC_INDEX+1
\r
1683 asm mov dx,GC_INDEX+1
\r
1687 asm mov bl,[es:si]
\r
1688 asm xchg [es:di],bl
\r
1690 asm mov dx,SC_INDEX+1
\r
1693 asm mov dx,GC_INDEX+1
\r
1697 asm mov bl,[es:si]
\r
1698 asm xchg [es:di],bl
\r
1700 asm mov dx,SC_INDEX+1
\r
1703 asm mov dx,GC_INDEX+1
\r
1707 asm mov bl,[es:si]
\r
1708 asm xchg [es:di],bl
\r
1710 asm mov dx,SC_INDEX+1
\r
1713 asm mov dx,GC_INDEX+1
\r
1717 asm mov bl,[es:si]
\r
1718 asm xchg [es:di],bl
\r
1720 if (rndval == 1) // entire sequence has been completed
\r
1724 // while (TimeCount<frame); // don't go too fast
\r
1735 //-------------------------------------------------------------------------
\r
1737 //-------------------------------------------------------------------------
\r
1738 void mprintf(char *msg, ...)
\r
1742 static char far *video = MK_FP(0xb000,0x0000);
\r
1743 char buffer[100],*ptr;
\r
1749 vsprintf(buffer,msg,ap);
\r
1760 _fmemcpy(MK_FP(0xb000,0x0000),MK_FP(0xb000,0x00a0),3840);
\r
1765 video += ((80-x)<<1);
\r
1786 //--------------------------------------------------------------------------
\r
1787 // FULL SCREEN REFRESH/ANIM MANAGERS
\r
1788 //--------------------------------------------------------------------------
\r
1790 ///////////////////////////////////////////////////////////////////////////
\r
1792 // InitLatchRefresh() -- Loads an ILBM (JAMPAK'd) into the Master Latch
\r
1793 // to be used as the background refresh screen...
\r
1795 void InitLatchRefresh(char *filename)
\r
1797 struct Shape RefreshShp;
\r
1802 if (LoadShape(filename,&RefreshShp))
\r
1803 TrashProg("Can't load %s",filename);
\r
1805 VW_SetLineWidth(RefreshShp.BPR);
\r
1807 yofs = masterswap/SCREENWIDTH;
\r
1808 MoveGfxDst(0,yofs); // Handle title screen
\r
1809 UnpackEGAShapeToScreen(&RefreshShp,0,0);
\r
1810 FreeShape(&RefreshShp);
\r
1813 VW_InitDoubleBuffer();
\r
1815 RF_NewPosition(0,0);
\r
1819 SetUpdateBlock(0,0,RefreshShp.bmHdr.w,RefreshShp.bmHdr.h,3);
\r
1823 ////////////////////////////////////////////////////////////////////////////
\r
1825 // InitFullScreenAnim() -- Initialize ALL necessary functions for full screen
\r
1826 // animation types.
\r
1828 // filename - filename for background lbm.
\r
1829 // SpawnAll - spawn function to call to spawn all inital objects..
\r
1831 void InitFullScreenAnim(char *filename, void (*SpawnAll)())
\r
1833 unsigned old_flags;
\r
1835 old_flags = GE_SystemFlags.flags;
\r
1836 GE_SystemFlags.flags &= ~(GEsf_Tiles | GEsf_Panning | GEsf_RefreshVec);
\r
1840 RFL_InitSpriteList();
\r
1846 CA_CacheMarks(NULL);
\r
1851 InitLatchRefresh(filename);
\r
1853 RF_ForceRefresh();
\r
1854 RF_ForceRefresh();
\r
1856 GE_SystemFlags.flags = old_flags;
\r
1861 ///////////////////////////////////////////////////////////////////////////
\r
1863 // DoFullScreenAnim() -- a General "Do-Every-Thing" function that
\r
1864 // displays a full screen animation...
\r
1866 // filename - Filename of background lbm
\r
1867 // SpawnAll - Function to call to spawn all inital objects (REQUIRED)
\r
1868 // CheckKey - Function to call every cycle - The function called must
\r
1869 // return a value of greater than zero (0) to terminate the
\r
1870 // animation cycle. (REQUIRED)
\r
1871 // CleanUp - Function to call upon exiting the animation. (OPTIONAL)
\r
1873 void DoFullScreenAnim(char *filename, void (*SpawnAll)(), short (*CheckKey)(),void (*CleanUp)())
\r
1875 unsigned old_flags;
\r
1876 boolean ExitAnim = false;
\r
1878 // Save off the current system flags....
\r
1880 old_flags = GE_SystemFlags.flags;
\r
1881 GE_SystemFlags.flags &= ~(GEsf_Tiles | GEsf_Panning);
\r
1885 // Init refresh latch screen, initalize all object, and setup video mode.
\r
1887 InitFullScreenAnim(filename,SpawnAll);
\r
1897 ExitAnim = (boolean)CheckKey();
\r
1900 // RemoveBOBList(player);
\r
1901 // CalcInactivate();
\r
1906 // Restore old system flags...
\r
1908 GE_SystemFlags.flags = old_flags;
\r
1913 //--------------------------------------------------------------------------
\r
1915 //--------------------------------------------------------------------------
\r
1916 boolean FindFile(char *filename,char *disktext,char disknum)
\r
1918 extern boolean splitscreen;
\r
1920 char command[100];
\r
1921 char choices[]={sc_Escape,sc_Space,0},drive[2];
\r
1922 boolean fadeitout=false,rt_code=2;
\r
1925 disktext = GAMENAME;
\r
1926 drive[0] = getdisk() + 'A';
\r
1928 while (rt_code == 2)
\r
1930 if (Verify(filename))
\r
1938 printf("\nInsert %s disk %d into drive %s.\n",disktext,disknum,drive);
\r
1939 printf("Press SPACE to continue, ESC to abort.\n");
\r
1945 bufferofs = displayofs = screenloc[screenpage];
\r
1946 CenterWindow(38,5);
\r
1950 bufferofs = displayofs = 0;
\r
1951 US_CenterWindow(38,5);
\r
1954 strcpy(command,"\nInsert ");
\r
1955 strcat(command,disktext);
\r
1956 strcat(command," disk");
\r
1957 if (disknum != -1)
\r
1959 strcat(command," ");
\r
1960 itoa(disknum,command+strlen(command),10);
\r
1962 strcat(command," into drive ");
\r
1963 strcat(command,drive);
\r
1964 strcat(command,".");
\r
1965 US_CPrint(command);
\r
1966 US_CPrint("Press SPACE to continue, ESC to abort.");
\r
1981 if (GetKeyChoice(choices,true) == sc_Escape)
\r
1994 //--------------------------------------------------------------------------
\r
1996 //--------------------------------------------------------------------------
\r
1997 void CacheAV(char *title)
\r
1999 if (Verify("EGAGRAPH."EXT))
\r
2001 CA_CacheMarks(title);
\r
2002 if (!FindFile("EGAGRAPH."EXT,AUDIO_DISK))
\r
2003 TrashProg("Can't find graphics files.");
\r
2007 current_disk = AUDIO_DISK;
\r
2014 if (!FindFile("EGAGRAPH."EXT,VIDEO_DISK))
\r
2015 TrashProg("Can't find audio files.");
\r
2016 CA_CacheMarks(title);
\r
2018 current_disk = VIDEO_DISK;
\r
2023 #ifdef TEXT_PRESENTER
\r
2024 //--------------------------------------------------------------------------
\r
2026 // TEXT PRESENTER CODE
\r
2028 //--------------------------------------------------------------------------
\r
2030 typedef enum pi_stype {pis_pic2x,pis_latch_pic} pi_stype;
\r
2033 typedef struct { // 4 bytes
\r
2034 unsigned shapenum;
\r
2035 pi_stype shape_type;
\r
2038 #define pia_active 0x01
\r
2040 typedef struct { // 10 bytes
\r
2049 #define PI_CASE_SENSITIVE
\r
2051 #define PI_RETURN_CHAR '\n'
\r
2052 #define PI_CONTROL_CHAR '^'
\r
2054 #define PI_CNVT_CODE(c1,c2) ((c1)|(c2<<8))
\r
2056 // shape table provides a way for the presenter to access and
\r
2057 // display any shape.
\r
2059 pi_shape_info far pi_shape_table[] = {
\r
2061 {BOLTOBJPIC,pis_pic2x}, // 0
\r
2062 {NUKEOBJPIC,pis_pic2x},
\r
2063 {SKELETON_1PIC,pis_pic2x},
\r
2064 {EYE_WALK1PIC,pis_pic2x},
\r
2065 {ZOMB_WALK1PIC,pis_pic2x},
\r
2067 {TIMEOBJ1PIC,pis_pic2x}, // 5
\r
2068 {POTIONOBJPIC,pis_pic2x},
\r
2069 {RKEYOBJPIC,pis_pic2x},
\r
2070 {YKEYOBJPIC,pis_pic2x},
\r
2071 {GKEYOBJPIC,pis_pic2x},
\r
2073 {BKEYOBJPIC,pis_pic2x}, // 10
\r
2074 {RGEM1PIC,pis_pic2x},
\r
2075 {GGEM1PIC,pis_pic2x},
\r
2076 {BGEM1PIC,pis_pic2x},
\r
2077 {YGEM1PIC,pis_pic2x},
\r
2079 {PGEM1PIC,pis_pic2x}, // 15
\r
2080 {CHESTOBJPIC,pis_pic2x},
\r
2081 {PSHOT1PIC,pis_pic2x},
\r
2082 {RED_DEMON1PIC,pis_pic2x},
\r
2083 {MAGE1PIC,pis_pic2x},
\r
2085 {BAT1PIC,pis_pic2x}, // 20
\r
2086 {GREL1PIC,pis_pic2x},
\r
2087 {GODESS_WALK1PIC,pis_pic2x},
\r
2088 {ANT_WALK1PIC,pis_pic2x},
\r
2089 {FATDEMON_WALK1PIC,pis_pic2x},
\r
2091 {SUCCUBUS_WALK1PIC,pis_pic2x}, //25
\r
2092 {TREE_WALK1PIC,pis_pic2x},
\r
2093 {DRAGON_WALK1PIC,pis_pic2x},
\r
2094 {BUNNY_LEFT1PIC,pis_pic2x},
\r
2098 // anim table holds info about each different animation.
\r
2100 pi_anim_info far pi_anim_table[] = {{0,0,3,0,10}, // 0 BOLT
\r
2101 {1,0,3,0,10}, // NUKE
\r
2102 {2,0,4,0,10}, // SKELETON
\r
2103 {3,0,3,0,10}, // EYE
\r
2104 {4,0,3,0,10}, // ZOMBIE
\r
2106 {5,0,2,0,10}, // 5 FREEZE TIME
\r
2107 {11,0,2,0,10}, // RED GEM
\r
2108 {12,0,2,0,10}, // GREEN GEM
\r
2109 {13,0,2,0,10}, // BLUE GEM
\r
2110 {14,0,2,0,10}, // YELLOW GEM
\r
2112 {15,0,2,0,10}, // 10 PURPLE GEM
\r
2113 {17,0,2,0,10}, // PLAYER'S SHOT
\r
2114 {18,0,3,0,10}, // RED DEMON
\r
2115 {19,0,2,0,10}, // MAGE
\r
2116 {20,0,4,0,10}, // BAT
\r
2118 {21,0,2,0,10}, // 15 GRELMINAR
\r
2119 {22,0,3,0,10}, // GODESS
\r
2120 {23,0,3,0,10}, // ANT
\r
2121 {24,0,4,0,10}, // FAT DEMON
\r
2122 {25,0,4,0,10}, // SUCCUBUS
\r
2124 {26,0,2,0,10}, // 20 TREE
\r
2125 {27,0,3,0,10}, // DRAGON
\r
2126 {28,0,2,0,10}, // BUNNY
\r
2129 // anim list is created on the fly from the anim table...
\r
2130 // this allows a single animation to be display in more than
\r
2133 pi_anim_info far pi_anim_list[PI_MAX_ANIMS];
\r
2134 boolean pi_recursing=false;
\r
2136 //--------------------------------------------------------------------------
\r
2137 // Presenter() - DANGEROUS DAVE "Presenter()" is more up-to-date than this.
\r
2140 // Active control codes:
\r
2142 // ^CE - center text between 'left margin' and 'right margin'
\r
2143 // ^FCn - set font color
\r
2144 // ^LMnnn - set left margin (if 'nnn' == "fff" uses current x)
\r
2145 // ^RMnnn - set right margin (if 'nnn' == "fff" uses current x)
\r
2146 // ^EP - end of page (waits for up/down arrow)
\r
2147 // ^PXnnn - move x to coordinate 'n'
\r
2148 // ^PYnnn - move y to coordinate 'n'
\r
2149 // ^XX - exit presenter
\r
2150 // ^LJ - left justify --\ ^RJ doesn't handle imbedded control
\r
2151 // ^RJ - right justify --/ codes properly. Use with caution.
\r
2152 // ^BGn - set background color
\r
2153 // ^ANnn - define animation
\r
2154 // ^SHnnn - display shape 'n' at current x,y
\r
2157 // Future control codes:
\r
2159 // ^OBnnn - activate object 'n'
\r
2160 // ^FL - flush to edges (whatever it's called)
\r
2165 // All 'n' values are hex numbers (0 - f), case insensitive.
\r
2166 // The number of N's listed is the number of digits REQUIRED by that control
\r
2167 // code. (IE: ^LMnnn MUST have 3 values! --> 003, 1a2, 01f, etc...)
\r
2169 // If a line consists only of control codes, the cursor is NOT advanced
\r
2170 // to the next line (the ending <CR><LF> is skipped). If just ONE non-control
\r
2171 // code is added, the number "8" for example, then the "8" is displayed
\r
2172 // and the cursor is advanced to the next line.
\r
2174 // ^CE must be on the same line as the text it should center!
\r
2176 //--------------------------------------------------------------------------
\r
2177 void Presenter(PresenterInfo *pi)
\r
2180 XBitMap **font = pi->font;
\r
2182 #define ch_width(ch) font[ch]->pad
\r
2183 char font_height = font[0]->Rows;
\r
2185 fontstruct _seg *font = (fontstruct _seg *)grsegs[STARTFONT];
\r
2187 #define MAX_PB 150
\r
2188 #define ch_width(ch) font->width[ch]
\r
2189 char font_height = font->height-1; // "-1" squeezes font vertically
\r
2194 enum {jm_left,jm_right,jm_flush};
\r
2195 char justify_mode = jm_left;
\r
2196 boolean centering=false;
\r
2198 short bgcolor = pi->bgcolor;
\r
2199 short xl=pi->xl,yl=pi->yl,xh=pi->xh,yh=pi->yh;
\r
2200 short cur_x = xl, cur_y = yl;
\r
2201 char far *first_ch = pi->script[0];
\r
2203 char far *scan_ch,temp;
\r
2204 short scan_x,PageNum=0,numanims=0;
\r
2205 boolean up_released=true,dn_released=true;
\r
2206 boolean presenting=true,start_of_line=true;
\r
2208 // if set background is first thing in file, make sure initial screen
\r
2209 // clear uses this color.
\r
2211 if (!_fstrncmp(first_ch,"^BG",3))
\r
2212 bgcolor = PI_VALUE(first_ch+3,1);
\r
2214 if (!pi_recursing)
\r
2217 CachePage(first_ch);
\r
2219 VW_Bar(xl,yl,xh-xl+1,yh-yl+1,bgcolor);
\r
2221 while (presenting)
\r
2224 // HANDLE WORD-WRAPPING TEXT
\r
2226 if (*first_ch != PI_CONTROL_CHAR)
\r
2228 start_of_line = false;
\r
2230 // Parse script until one of the following:
\r
2232 // 1) text extends beyond right margin
\r
2233 // 2) NULL termination is reached
\r
2234 // 3) PI_RETURN_CHAR is reached
\r
2235 // 4) PI_CONTROL_CHAR is reached
\r
2238 scan_ch = first_ch;
\r
2239 while ((scan_x+ch_width(*scan_ch) <= xh) && (*scan_ch) &&
\r
2240 (*scan_ch != PI_RETURN_CHAR) && (*scan_ch != PI_CONTROL_CHAR))
\r
2241 scan_x += ch_width(*scan_ch++);
\r
2243 // if 'text extends beyond right margin', scan backwards for
\r
2246 if (scan_x+ch_width(*scan_ch) > xh)
\r
2248 short last_x = scan_x;
\r
2249 char far *last_ch = scan_ch;
\r
2251 while ((scan_ch != first_ch) && (*scan_ch != ' ') && (*scan_ch != PI_RETURN_CHAR))
\r
2252 scan_x -= ch_width(*scan_ch--);
\r
2254 if (scan_ch == first_ch)
\r
2255 scan_ch = last_ch, scan_x = last_x;
\r
2258 // print current line
\r
2261 while (first_ch < scan_ch)
\r
2263 qBlit(font[*first_ch++],pi->dst,cur_x,cur_y);
\r
2264 // qBlit(font[*first_ch],pi->dst,cur_x,cur_y);
\r
2265 // cur_x += ch_width(*first_ch++);
\r
2271 if ((justify_mode == jm_right)&&(!centering))
\r
2273 unsigned width,height;
\r
2275 VWL_MeasureString(first_ch,&width,&height,font);
\r
2284 length = scan_ch-first_ch+1; // USL_DrawString only works with
\r
2285 if (length > MAX_PB)
\r
2286 Quit("Presenter(): Print buffer string too long!");
\r
2287 _fmemcpy(pb,first_ch,length); // near pointers...
\r
2289 if (*first_ch != '\n')
\r
2290 USL_DrawString(pb);
\r
2293 first_ch = scan_ch;
\r
2296 centering = false;
\r
2298 // skip SPACES / RETURNS at end of line
\r
2300 if ((*first_ch==' ') || (*first_ch==PI_RETURN_CHAR))
\r
2303 // PI_CONTROL_CHARs don't advance to next character line
\r
2305 if (*scan_ch != PI_CONTROL_CHAR)
\r
2308 cur_y += font_height;
\r
2313 // HANDLE CONTROL CODES
\r
2316 PresenterInfo endmsg;
\r
2317 pi_anim_info far *anim;
\r
2318 pi_shape_info far *shape_info;
\r
2319 unsigned shapenum;
\r
2323 if (first_ch[-1] == '\n')
\r
2324 start_of_line = true;
\r
2327 #ifndef PI_CASE_SENSITIVE
\r
2328 *first_ch=toupper(*first_ch);
\r
2329 *(first_ch+1)=toupper(*(first_ch+1));
\r
2331 switch (*((unsigned far *)first_ch)++)
\r
2333 // CENTER TEXT ------------------------------------------------------
\r
2335 case PI_CNVT_CODE('C','E'):
\r
2338 while (*s && (*s != PI_RETURN_CHAR))
\r
2342 case PI_CONTROL_CHAR:
\r
2344 switch (*((unsigned *)s)++)
\r
2347 case PI_CNVT_CODE('F','C'):
\r
2348 case PI_CNVT_CODE('B','G'):
\r
2353 case PI_CNVT_CODE('L','M'):
\r
2354 case PI_CNVT_CODE('R','M'):
\r
2355 case PI_CNVT_CODE('S','H'):
\r
2356 case PI_CNVT_CODE('P','X'):
\r
2357 case PI_CNVT_CODE('P','Y'):
\r
2361 case PI_CNVT_CODE('L','J'):
\r
2362 case PI_CNVT_CODE('R','J'):
\r
2363 // No parameters to pass over!
\r
2369 length += ch_width(*s++);
\r
2373 cur_x = ((xh-xl+1)-length)/2;
\r
2377 // DRAW SHAPE -------------------------------------------------------
\r
2379 case PI_CNVT_CODE('S','H'):
\r
2380 shapenum = PI_VALUE(first_ch,3);
\r
2382 shape_info = &pi_shape_table[shapenum];
\r
2383 switch (shape_info->shape_type)
\r
2388 cur_x = ((cur_x+2) + 7) & 0xFFF8;
\r
2389 width=BoxAroundPic(cur_x-2,cur_y-1,shape_info->shapenum,pi);
\r
2390 VW_DrawPic2x(cur_x>>3,cur_y,shape_info->shapenum);
\r
2396 // INIT ANIMATION ---------------------------------------------------
\r
2398 case PI_CNVT_CODE('A','N'):
\r
2399 shapenum = PI_VALUE(first_ch,2);
\r
2401 _fmemcpy(&pi_anim_list[numanims],&pi_anim_table[shapenum],sizeof(pi_anim_info));
\r
2402 anim = &pi_anim_list[numanims++];
\r
2403 shape_info = &pi_shape_table[anim->baseshape+anim->frame];
\r
2404 switch (shape_info->shape_type)
\r
2409 cur_x = ((cur_x+2) + 7) & 0xFFF8;
\r
2410 width=BoxAroundPic(cur_x-2,cur_y-1,shape_info->shapenum,pi);
\r
2411 VW_DrawPic2x(cur_x>>3,cur_y,shape_info->shapenum);
\r
2412 anim->x = cur_x>>3;
\r
2420 // FONT COLOR -------------------------------------------------------
\r
2422 case PI_CNVT_CODE('F','C'):
\r
2423 fontcolor = bgcolor ^ PI_VALUE(first_ch++,1);
\r
2427 // BACKGROUND COLOR -------------------------------------------------
\r
2429 case PI_CNVT_CODE('B','G'):
\r
2430 bgcolor = PI_VALUE(first_ch++,1);
\r
2433 // LEFT MARGIN ------------------------------------------------------
\r
2435 case PI_CNVT_CODE('L','M'):
\r
2436 shapenum = PI_VALUE(first_ch,3);
\r
2438 if (shapenum == 0xfff)
\r
2444 // RIGHT MARGIN -----------------------------------------------------
\r
2446 case PI_CNVT_CODE('R','M'):
\r
2447 shapenum = PI_VALUE(first_ch,3);
\r
2449 if (shapenum == 0xfff)
\r
2455 // SET X COORDINATE -------------------------------------------------
\r
2457 case PI_CNVT_CODE('P','X'):
\r
2458 cur_x = PI_VALUE(first_ch,3);
\r
2462 // SET Y COORDINATE -------------------------------------------------
\r
2464 case PI_CNVT_CODE('P','Y'):
\r
2465 cur_y = PI_VALUE(first_ch,3);
\r
2469 // LEFT JUSTIFY -----------------------------------------------------
\r
2471 case PI_CNVT_CODE('L','J'):
\r
2472 justify_mode = jm_left;
\r
2475 // RIGHT JUSTIFY ----------------------------------------------------
\r
2477 case PI_CNVT_CODE('R','J'):
\r
2478 justify_mode = jm_right;
\r
2481 // END OF PAGE ------------------------------------------------------
\r
2483 case PI_CNVT_CODE('E','P'):
\r
2485 Quit("Presenter(): Can't use ^EP when recursing!");
\r
2487 endmsg.xl = cur_x;
\r
2488 endmsg.yl = yh-(font_height+2);
\r
2491 endmsg.bgcolor = bgcolor;
\r
2492 endmsg.ltcolor = pi->ltcolor;
\r
2493 endmsg.dkcolor = pi->dkcolor;
\r
2494 endmsg.script[0] = (char far *)"^CE^FC8- ^FC0ESC ^FC8to return to play, or ^FC0ARROW KEYS ^FC8to page through more Help -^XX";
\r
2496 pi_recursing = true;
\r
2497 Presenter(&endmsg);
\r
2498 pi_recursing = false;
\r
2503 VW_ColorBorder(8 | 56);
\r
2512 newtime = TimeCount;
\r
2513 realtics = tics = newtime-lasttimecount;
\r
2514 lasttimecount = newtime;
\r
2519 AnimatePage(numanims);
\r
2520 IN_ReadControl(0,&control);
\r
2522 if (control.button1 || Keyboard[1])
\r
2529 if (ControlTypeUsed != ctrl_Keyboard)
\r
2530 control.dir = dir_None;
\r
2532 if (((control.dir == dir_North) || (control.dir == dir_West)) && (PageNum))
\r
2537 up_released = false;
\r
2543 up_released = true;
\r
2544 if (((control.dir == dir_South) || (control.dir == dir_East)) && (PageNum < pi->numpages-1))
\r
2549 dn_released = false;
\r
2554 dn_released = true;
\r
2561 if (cur_y+font_height > yh)
\r
2562 cur_y = yh-font_height;
\r
2563 first_ch = pi->script[PageNum];
\r
2567 CachePage(first_ch);
\r
2569 VW_Bar(xl,yl,xh-xl+1,yh-yl+1,bgcolor);
\r
2572 // EXIT PRESENTER ---------------------------------------------------
\r
2574 case PI_CNVT_CODE('X','X'):
\r
2579 if ((first_ch[0] == ' ') && (first_ch[1] == '\n') && start_of_line)
\r
2585 //--------------------------------------------------------------------------
\r
2587 //--------------------------------------------------------------------------
\r
2590 pi_anim_list[0].baseshape = -1;
\r
2593 //--------------------------------------------------------------------------
\r
2595 //--------------------------------------------------------------------------
\r
2596 void AnimatePage(short numanims)
\r
2598 pi_anim_info far *anim=pi_anim_list;
\r
2599 pi_shape_info far *shape_info;
\r
2601 while (numanims--)
\r
2603 anim->delay += tics;
\r
2604 if (anim->delay >= anim->maxdelay)
\r
2608 if (anim->frame == anim->maxframes)
\r
2611 #if ANIM_USES_SHAPETABLE
\r
2612 shape_info = &pi_shape_table[anim->baseshape+anim->frame];
\r
2614 shape_info = &pi_shape_table[anim->baseshape];
\r
2616 switch (shape_info->shape_type)
\r
2619 #if ANIM_USES_SHAPETABLE
\r
2620 VW_DrawPic2x(anim->x,anim->y,shape_info->shapenum);
\r
2622 VW_DrawPic2x(anim->x,anim->y,shape_info->shapenum+anim->frame);
\r
2631 //--------------------------------------------------------------------------
\r
2633 //--------------------------------------------------------------------------
\r
2634 short BoxAroundPic(short x1, short y1, unsigned picnum, PresenterInfo *pi)
\r
2638 x2 = x1+(pictable[picnum-STARTPICS].width<<4)+2;
\r
2639 y2 = y1+(pictable[picnum-STARTPICS].height)+1;
\r
2640 VWB_Hlin(x1,x2,y1,pi->ltcolor);
\r
2641 VWB_Hlin(x1,x2,y2,pi->dkcolor);
\r
2642 VWB_Vlin(y1,y2,x1,pi->ltcolor);
\r
2643 VWB_Vlin(y1,y2,x1+1,pi->ltcolor);
\r
2644 VWB_Vlin(y1,y2,x2,pi->dkcolor);
\r
2645 VWB_Vlin(y1,y2,x2+1,pi->dkcolor);
\r
2650 //--------------------------------------------------------------------------
\r
2652 //--------------------------------------------------------------------------
\r
2653 void PurgeAllGfx()
\r
2659 //--------------------------------------------------------------------------
\r
2661 //--------------------------------------------------------------------------
\r
2662 void CachePage(char far *script)
\r
2664 pi_anim_info far *anim;
\r
2666 unsigned shapenum;
\r
2667 boolean end_of_page=false;
\r
2670 while (!end_of_page)
\r
2672 switch (*script++)
\r
2674 case PI_CONTROL_CHAR:
\r
2675 #ifndef PI_CASE_SENSITIVE
\r
2676 *script=toupper(*script);
\r
2677 *(script+1)=toupper(*(script+1));
\r
2679 switch (*((unsigned far *)script)++)
\r
2681 case PI_CNVT_CODE('S','H'):
\r
2682 shapenum = PI_VALUE(script,3);
\r
2684 CA_MarkGrChunk(pi_shape_table[shapenum].shapenum);
\r
2687 case PI_CNVT_CODE('A','N'):
\r
2688 shapenum = PI_VALUE(script,2);
\r
2691 if (numanims++ == PI_MAX_ANIMS)
\r
2692 Quit("CachePage(): Too many anims on one page.");
\r
2694 anim = &pi_anim_table[shapenum];
\r
2695 #if ANIM_USES_SHAPETABLE
\r
2696 for (loop=anim->baseshape;loop < anim->baseshape+anim->maxframes; loop++)
\r
2697 CA_MarkGrChunk(pi_shape_table[loop].shapenum);
\r
2699 shapenum = pi_shape_table[anim->baseshape].shapenum;
\r
2700 for (loop=0; loop<anim->maxframes; loop++)
\r
2701 CA_MarkGrChunk(shapenum+loop);
\r
2705 case PI_CNVT_CODE('X','X'):
\r
2706 case PI_CNVT_CODE('E','P'):
\r
2707 end_of_page = true;
\r
2714 CA_CacheMarks(NULL);
\r
2717 //--------------------------------------------------------------------------
\r
2719 //--------------------------------------------------------------------------
\r
2720 unsigned PI_VALUE(char far *ptr,char num_nybbles)
\r
2722 char ch,nybble,shift;
\r
2725 for (nybble=0; nybble<num_nybbles; nybble++)
\r
2727 shift = 4*(num_nybbles-nybble-1);
\r
2732 value |= (toupper(ch)-'A'+10)<<shift;
\r
2734 value |= (ch-'0')<<shift;
\r
2740 //--------------------------------------------------------------------------
\r
2741 // LoadPresenterScript()
\r
2742 //--------------------------------------------------------------------------
\r
2743 long LoadPresenterScript(char *filename,PresenterInfo *pi)
\r
2748 if (!(size=BLoad(filename,&pi->scriptstart)))
\r
2750 pi->script[0] = MK_FP(pi->scriptstart,0);
\r
2751 pi->script[0][size-1] = 0; // Last byte is trashed!
\r
2752 InitPresenterScript(pi);
\r
2758 //-------------------------------------------------------------------------
\r
2759 // FreePresenterScript()
\r
2760 //-------------------------------------------------------------------------
\r
2761 void FreePresenterScript(PresenterInfo *pi)
\r
2764 MM_FreePtr(&pi->scriptstart);
\r
2767 //-------------------------------------------------------------------------
\r
2768 // InitPresenterScript()
\r
2769 //-------------------------------------------------------------------------
\r
2770 void InitPresenterScript(PresenterInfo *pi)
\r
2772 char far *script = pi->script[0];
\r
2774 pi->numpages = 1; // Assume at least 1 page
\r
2777 switch (*script++)
\r
2779 case PI_CONTROL_CHAR:
\r
2780 #ifndef PI_CASE_SENSITIVE
\r
2781 *script=toupper(*script);
\r
2782 *(script+1)=toupper(*(script+1));
\r
2784 switch (*((unsigned far *)script)++)
\r
2786 case PI_CNVT_CODE('E','P'):
\r
2787 if (pi->numpages < PI_MAX_PAGES)
\r
2788 pi->script[pi->numpages++] = script;
\r
2790 TrashProg("GE ERROR: Too many Presenter() pages. --> %d",pi->numpages);
\r
2796 if (*script == '\n')
\r
2798 *(script-1) = ' ';
\r
2805 pi->numpages--; // Last page defined is not a real page.
\r
2810 //-------------------------------------------------------------------------
\r
2811 // AnimateWallList()
\r
2812 //-------------------------------------------------------------------------
\r
2813 void AnimateWallList(void)
\r
2815 walltype *wall, *check;
\r
2817 int tile,org_tile;
\r
2819 if (wall_anim_delay>0)
\r
2821 wall_anim_delay-=realtics;
\r
2826 // Re-Init our counter...
\r
2829 wall_anim_delay = wall_anim_time;
\r
2832 // Clear all previous flags marking animation being DONE.
\r
2835 for (i=0;i<NUMFLOORS;i++)
\r
2836 TILE_FLAGS(i) &= ~tf_MARKED;
\r
2840 // Run though wall list updating only then needed animations
\r
2843 for (wall=&walls[1];wall<rightwall;wall++)
\r
2845 org_tile = tile = wall->color + wall_anim_pos[wall->color];
\r
2847 if (ANIM_FLAGS(tile))
\r
2851 if (!(TILE_FLAGS(tile) & tf_MARKED))
\r
2854 // update our offset table (0-NUMANIMS)
\r
2857 wall_anim_pos[tile] += (char signed)ANIM_FLAGS(tile+(char signed)wall_anim_pos[tile]);
\r
2860 // Mark tile as being already updated..
\r
2863 TILE_FLAGS(tile) |= tf_MARKED;
\r
2867 // Check rest of tiles in this animation string...
\r
2870 tile += (char signed)ANIM_FLAGS(tile);
\r
2872 } while (tile != org_tile);
\r