home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / apilot.lha / APilot / APilot_Opt / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-12  |  25.6 KB  |  853 lines

  1. /**************************************************************************
  2.  *
  3.  * main.c -- APilot, an xpilot like game for the Amiga.
  4.  *
  5.  *-------------------------------------------------------------------------
  6.  * Authors: Casper Gripenberg  (casper@alpha.hut.fi)
  7.  *          Kjetil Jacobsen  (kjetilja@stud.cs.uit.no)
  8.  *
  9.  */
  10.  
  11. /*------------------------------------------------------------------------*/
  12.  
  13. #include <math.h> 
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdarg.h>
  17. #include <string.h>
  18. #include <exec/types.h>             /* The Amiga data types file.         */
  19. #include <exec/memory.h>
  20. #include <devices/input.h>
  21. #include <devices/timer.h>
  22. #include <intuition/intuition.h>    /* Intuition data strucutres, etc.    */
  23. #include <graphics/displayinfo.h>   /* Release 2 Amiga display mode ID's  */
  24. #include <libraries/dos.h>          /* Official return codes defined here */
  25.  
  26. #include <proto/exec.h>
  27. #include <proto/input.h>
  28. #include <proto/intuition.h>
  29. #include <proto/graphics.h>
  30. #include <proto/diskfont.h>
  31. #include <proto/timer.h>
  32. #include <proto/dos.h>
  33.  
  34. #include <libraries/asl.h>
  35. #include <proto/asl.h>
  36.  
  37. /*------------------------------------------------------------------------*/
  38.  
  39. #include "map_protos.h"
  40. #include "points_protos.h"
  41. #include "ships_protos.h"
  42. #include "lists_protos.h"
  43. #include "cannon_protos.h"
  44. #include "collision_protos.h"
  45. #include "fuelpod_protos.h"
  46. #include "misc_protos.h"
  47. #include "vertb_protos.h"
  48. #include "main_protos.h"
  49.  
  50. #include "common.h"
  51. #include "vertb.h"
  52. #include "map.h"
  53. #include "prefs.h"
  54.  
  55. /*------------------------------------------------------------------------*/
  56.  
  57. /* Disable ctrl-c handling */
  58. void __regargs __chkabort(void);
  59. void __regargs __chkabort(void) { return; }
  60.  
  61. /*------------------------------------------------------------------------*/
  62.  
  63. char *version = "$VER: APilot_Opt is still beta (22.03.94)";
  64.  
  65. /*------------------------------------------------------------------------*/
  66.  
  67. /*
  68.  * This is where all the action is
  69.  */
  70. AWorld World;
  71.  
  72. /*
  73.  * For rawkey interpreting.
  74.  */
  75. #define RAWKEY_KP_MINUS 74
  76. #define RAWKEY_KP_PLUS  94
  77. #define RAWKEY_KP_STAR  93
  78. #define RAWKEY_F        35
  79. #define RAWKEY_T        20
  80. #define RAWKEY_Q        16
  81. #define RAWKEY_A        32
  82. #define RAWKEY_S        33
  83. #define RAWKEY_ENTER    68
  84. #define RAWKEY_SPACE    64
  85.  
  86. /* This one is for the screenmode, sizes, etc. */
  87. UserPrefs prefs;
  88.  
  89. #ifdef CPU_USAGE
  90. static BOOL   cpu_meter   = FALSE;
  91. struct Library *TimerBase = NULL;
  92. static struct timerequest tr;
  93. #endif
  94.  
  95. /*
  96.  * Global structures and variables needed in this file
  97.  */
  98. static BYTE   deviceopen  = 1;
  99. static UWORD  w_framerate = APILOT_NFR;  /* Wanted framerate */
  100. static UWORD  oldrptdelay;
  101. static struct TextFont    *hudFont  = 0;
  102. static struct Screen      *myScreen = NULL;
  103. static struct Window      *myWindow = NULL;
  104. static struct BitMap      *myBitMap[MY_BUFFERS];
  105. static struct RastPort    myRP[MY_BUFFERS];
  106. static struct DBufInfo    *myDBI    = NULL;
  107. static struct MsgPort     *inputPort = NULL;
  108. static struct MsgPort     *dbufport = NULL;
  109. static struct timerequest *inputReqBlk = NULL;
  110.  
  111. /*------------------------------------------------------------------------*/
  112.  
  113. /*
  114.  * init_world -- Initializes all data in the World structure.
  115.  *
  116.  */
  117. void
  118. init_world( void )
  119. {
  120.   APTR *dummy;
  121.  
  122.   World.Height = 0;
  123.   World.Width  = 0;
  124.  
  125.   World.gravity = DEF_GRAVITY * PRECS;
  126.  
  127.   if ( (World.players = (AShip *) malloc(sizeof(AShip))) == NULL )
  128.     cleanExit( RETURN_WARN, "** Unable to get memory for players.\n" );
  129.   if ( (dummy =  malloc(sizeof(AShip))) == NULL )
  130.     cleanExit( RETURN_WARN, "** Unable to get memory for players.\n" );
  131.   ((AShip *)dummy)->next = (AShip *)dummy;
  132.   World.players->next = (AShip *)dummy;
  133.  
  134.   if ( (World.fuelpods = (AFuelPod *) malloc(sizeof(AFuelPod))) == NULL )
  135.     cleanExit( RETURN_WARN, "** Unable to get memory for fuelpods.\n" );
  136.   if ( (dummy =  malloc(sizeof(AFuelPod))) == NULL )
  137.     cleanExit( RETURN_WARN, "** Unable to get memory for fuelpods.\n" );
  138.   ((AFuelPod *)dummy)->next = (AFuelPod *)dummy;
  139.   World.fuelpods->next = (AFuelPod *)dummy;
  140.  
  141.   if ( (World.cannons = (ACannon *) malloc(sizeof(ACannon))) == NULL )
  142.     cleanExit( RETURN_WARN, "** Unable to get memory for cannons.\n" );
  143.   if ( (dummy = malloc(sizeof(ACannon))) == NULL )
  144.     cleanExit( RETURN_WARN, "** Unable to get memory for cannons.\n" );
  145.   ((ACannon *)dummy)->next = (ACannon *)dummy;
  146.   World.cannons->next = (ACannon *)dummy;
  147.  
  148.   if ( (World.bases = (ABase *) malloc(sizeof(ABase))) == NULL )
  149.     cleanExit( RETURN_WARN, "** Unable to get memory for bases.\n" );
  150.   if ( (dummy = malloc(sizeof(ABase))) == NULL )
  151.     cleanExit( RETURN_WARN, "** Unable to get memory for bases.\n" );
  152.   ((ABase *)dummy)->next = (ABase *)dummy;
  153.   World.bases->next = (ABase *)dummy;
  154.  
  155.   if ( (World.players = (AShip *) malloc(sizeof(AShip))) == NULL )
  156.     cleanExit( RETURN_WARN, "** Unable to get memory for players.\n" );
  157.   if ( (dummy = malloc(sizeof(AShip))) == NULL )
  158.     cleanExit( RETURN_WARN, "** Unable to get memory for players.\n" );
  159.   ((AShip *)dummy)->next = (AShip *)dummy;
  160.   World.players->next = (AShip *)dummy;
  161.   
  162.   World.points  = NULL;
  163.  
  164.   /* Local stuff */
  165.   World.framerate = APILOT_NFR;
  166.   World.hudon     = TRUE;
  167.   World.shld_bm   = NULL;
  168. }
  169.  
  170. /*------------------------------------------------------------------------*/
  171.  
  172. /*
  173.  * init_display -- Opens a screen with a backdrop window.
  174.  *             
  175.  */
  176. void
  177. init_display( int native )
  178. {
  179.   int    h, i, j;
  180. #ifndef DYN_SCR
  181.   int    myScreenLEdge;
  182.   struct Screen wbScreen;
  183. #endif
  184.   struct RastPort rp;
  185.   UWORD  pens[] = { (UWORD)~0 };
  186.   
  187.   struct ScreenModeRequester *req;
  188.   char *Postext = "Play";
  189.   char *Toptext = "Select APilot ScreenMode";
  190.   
  191.   /* The first white will be faded to black later for a nice effect :) */
  192.   struct ColorSpec mycolors[] = { { 0, 15, 15, 15 },        /* White */
  193.                                   { 1, 13,  4,  4 },        /* Red   */
  194.                                   { 2,  5,  5, 14 },        /* Blue  */
  195.                                   { 3, 13, 13, 13 },        /* White */
  196.                                   {-1,  0,  0,  0 } };
  197.  
  198.   /***************************************************************
  199.    * SAS Handles auto-opening and closing of all needed librarys *
  200.    ***************************************************************/ 
  201.  
  202.   if (!native) {
  203.     /* Allocate requester, seems like  the player want another screenmode  */
  204.     if ((req = AllocAslRequestTags(ASL_ScreenModeRequest,
  205.                                    ASLSM_DoOverscanType, 1,
  206.                                    ASLSM_MinWidth,     MINResX,
  207.                                    ASLSM_MaxWidth,     MAXResX,
  208.                                    ASLSM_MinHeight,    MINResY,
  209.                                    ASLSM_MaxHeight,    MAXResY,
  210.                                    ASLSM_TitleText,    Toptext,
  211.                                    ASLSM_PositiveText, Postext,
  212.                                    TAG_DONE)) == NULL)
  213.       cleanExit( RETURN_WARN, "** Unable to allocate screenmode-requester.\n" );
  214.     
  215.     /* Prompt user */
  216.     if (!AslRequestTags(req,
  217.                         ASLSM_DoOverscanType,1,
  218.                         ASLSM_MinWidth, MINResX,
  219.                         ASLSM_MaxWidth, MAXResX,
  220.                         ASLSM_MinHeight,MINResY,
  221.                         ASLSM_MaxHeight,MAXResY,
  222.                         ASLSM_TitleText,   Toptext,
  223.                         ASLSM_PositiveText,Postext,
  224.                         TAG_DONE))
  225.       cleanExit( RETURN_WARN, "** Unable to get screenmode.\n" ); 
  226.     
  227.     /* Requester turned out successfully, store values */
  228.     prefs.dpy_oscan  = req->sm_OverscanType;
  229.     prefs.dpy_width  = (int) (req->sm_DisplayWidth-1) | 1;  /* Ensure odd values */
  230.     prefs.dpy_height = (int) (req->sm_DisplayHeight-1) | 1;
  231.     prefs.dpy_modeid = req->sm_DisplayID;
  232.   
  233.     /* Now free requester memory */
  234.     FreeAslRequest(req);
  235.   }
  236.   
  237.   /* Allocate all bitmaps needed for display buffering. */
  238.   for( i = 0; i < MY_BUFFERS; i++ ) {
  239.     myBitMap[i] = AllocBitMap( SCR_WIDTH  + MAP_BLOCKSIZE*2,
  240.                                SCR_HEIGHT + MAP_BLOCKSIZE*2,
  241.                                SCR_DEPTH, 
  242.                                BMF_CLEAR|BMF_DISPLAYABLE, NULL );
  243.     
  244.     if( myBitMap[i] == NULL )
  245.       cleanExit( RETURN_WARN, "** Unable to allocate bitmaps.\n" );
  246.     
  247.     /* Init the rastport and attach the corresponding bitmap */
  248.     InitRastPort( &myRP[i] );
  249.     myRP[i].BitMap = myBitMap[i];
  250.   }
  251.   
  252.   /*
  253.    * Make a temporatry bitmap which we will use to draw the
  254.    * ship shield images into. The bitmap will then later be used for 
  255.    * blitting the shield images to display memory.
  256.    */
  257.   World.shld_bm = AllocBitMap( (SHL_SIZE*2+1)*SHL_ANIM, 
  258.                                 SHL_SIZE*2+1,
  259.                                 SCR_DEPTH, 
  260.                                 BMF_CLEAR|BMF_DISPLAYABLE, 
  261.                                 myBitMap[0] );
  262.   if ( World.shld_bm == NULL )
  263.     cleanExit( RETURN_WARN, "** Unable to allocate bitmaps.\n" );
  264.   
  265.   InitRastPort( &rp );
  266.   rp.BitMap = World.shld_bm;
  267.   
  268.   /* Draw some shield images for animation. */
  269.   for (i = 0; i < SHL_ANIM; i++)
  270.     DrawEllipse(&rp, SHL_SIZE+((SHL_SIZE*2+1)*i), SHL_SIZE, SHL_SIZE, SHL_SIZE);
  271.  
  272.   /*
  273.    * Draw some 'holes' into the circles so they look nicer. Last image is
  274.    * kept from being changed, as it is used for clearing.
  275.    */
  276.   SetAPen(&rp, 0);
  277.  
  278.   for (h = 0; h < SHL_ANIM-1; h++)
  279.     for (i = 0, j = h; i < 360; i++,j++) { 
  280.       if (j > 15)
  281.         WritePixel(&rp, (long)(SHL_SIZE+0.5 + 
  282.                                SHL_SIZE * sin((double)PI/180*i)) + ((SHL_SIZE*2+1)*h),
  283.                         (long)(SHL_SIZE+0.5 + 
  284.                                SHL_SIZE * cos((double)PI/180*i)));
  285.       if (j >= 20) j = 0;
  286.     }
  287.  
  288. #ifndef DYN_SCR
  289.   /*
  290.    * Get info about the wb screen so we can nicely center our own
  291.    * screen in the 'middle' of the wbscreen. We don't need this for
  292.    * dynamic screens, as they use standard clip-regions.
  293.    */
  294.   GetScreenData(&wbScreen, sizeof(struct Screen), WBENCHSCREEN, NULL);
  295.   myScreenLEdge = (wbScreen.Width-SCR_WIDTH)/2 + wbScreen.LeftEdge;
  296.   if (myScreenLEdge < 0) myScreenLEdge = 0;
  297. #endif
  298.   
  299.   /* Open the screen */
  300.   myScreen = OpenScreenTags(NULL,
  301. #ifndef DYN_SCR
  302.                             SA_Left,      myScreenLEdge,
  303. #endif
  304.                             SA_Width,     SCR_WIDTH,
  305.                             SA_Height,    SCR_HEIGHT, 
  306.                             SA_BitMap,    myBitMap[0],
  307.                             SA_Pens,      (ULONG)pens, 
  308.                             SA_Colors,    mycolors,
  309.                             SA_DisplayID, prefs.dpy_modeid,
  310.                             SA_AutoScroll,0,
  311.                             SA_Overscan,  prefs.dpy_oscan,
  312.                             SA_Quiet,     1,
  313.                             SA_Type,      CUSTOMSCREEN | CUSTOMBITMAP,
  314.                             SA_Depth,     SCR_DEPTH,
  315.                             SA_Title,     (ULONG)"APilot",
  316.                             TAG_DONE);
  317.   
  318.   if (myScreen != NULL) {
  319.  
  320.     /* 
  321.      * Now set the bitmap offsets so that part of the bitmap is outside
  322.      * the visible screen. This way we don't have to do line clipping
  323.      * on map-blocks and ships.
  324.      */
  325.     myScreen->ViewPort.RasInfo->RxOffset = MAP_BLOCKSIZE; 
  326.     myScreen->ViewPort.RasInfo->RyOffset = MAP_BLOCKSIZE;
  327.     ScrollVPort(&myScreen->ViewPort);
  328.  
  329.     /* Make the screen titlebar go behind the Backdrop window */
  330.     ShowTitle(myScreen, FALSE);
  331.  
  332.     /* ... and open the window */
  333.     myWindow = OpenWindowTags(NULL,
  334.                               /* Specify window dimensions and limits */
  335.                               WA_Left,         0,
  336.                               WA_Top,          0,
  337.                               WA_Width,        SCR_WIDTH,
  338.                               WA_Height,       SCR_HEIGHT,
  339.                               WA_MaxWidth,     ~0,
  340.                               WA_MaxHeight,    ~0,
  341.                               /* Specify the system gadgets we want */
  342.                               WA_CloseGadget,  FALSE,
  343.                               WA_SizeGadget,   FALSE,
  344.                               WA_DepthGadget,  FALSE,
  345.                               WA_DragBar,      FALSE,
  346.                               WA_Borderless,   TRUE,
  347.                               /* Specify other attributes           */
  348.                               WA_RMBTrap,      TRUE,
  349.                               WA_RptQueue,     0,
  350.                               WA_Backdrop,     FALSE,
  351.                               WA_Activate,     TRUE,
  352.                               WA_NoCareRefresh,TRUE,
  353.                               /* Specify the events we want to know about */
  354.                               WA_IDCMP,        IDCMP_RAWKEY |
  355.                                                IDCMP_INACTIVEWINDOW |
  356.                                                IDCMP_ACTIVEWINDOW,
  357.                               /* Attach the window to the open screen ...*/
  358.                               WA_CustomScreen, myScreen,
  359.                               WA_Title,        NULL,
  360.                               WA_ScreenTitle,  NULL,
  361.                               TAG_DONE);
  362.     if (myWindow != NULL) {
  363.       do_fade();
  364.       return;
  365.     }
  366.   }
  367.   cleanExit( RETURN_WARN, "** Unable to initialize screen\n" );  
  368. }
  369.  
  370. /*------------------------------------------------------------------------*/
  371.  
  372. /*
  373.  * init_font -- Opens a font from disk for the HUD display.
  374.  *
  375.  */
  376. void
  377. init_font(void)
  378. {
  379.   int i;
  380.   struct TextAttr  hudtextAttr;
  381.  
  382.   hudtextAttr.ta_Name  = "SystemThin.font";
  383.   hudtextAttr.ta_YSize = 8;
  384.   hudtextAttr.ta_Style = FS_NORMAL;
  385.   hudtextAttr.ta_Flags = FPF_DISKFONT | FPF_DESIGNED;
  386.  
  387.   if ((hudFont = OpenDiskFont(&hudtextAttr)) == 0)
  388.     cleanExit( RETURN_WARN, "** Unable to open font 'SystemThin'." );
  389.   
  390.   for (i = 0; i < MY_BUFFERS; i++) {
  391.     SetFont(&myRP[i], hudFont);
  392.   }
  393. }  
  394.  
  395. /*------------------------------------------------------------------------*/
  396.  
  397. /*
  398.  * do_fade -- Smoothly fades the screen from white to black
  399.  *
  400.  */
  401. void
  402. do_fade(void)
  403. {
  404.   int i, r, g;
  405.   UWORD color[] = { 0x0fff };
  406.  
  407.   r = g = 15;
  408.  
  409.   for (i = 0; i < 15; i++) {
  410.     /* Red */
  411.     color[0] = ( (color[0] & 0x00ff) | ((--r) << 8) );
  412.     WaitTOF();
  413.     WaitTOF();
  414.     LoadRGB4(&myScreen->ViewPort, color, 1);
  415.     /* Green */
  416.     color[0] = ( (color[0] & 0x0f0f) | ((--g) << 4) );
  417.     WaitTOF();
  418.     LoadRGB4(&myScreen->ViewPort, color, 1);
  419.     /* Blue */
  420.     color[0]--;
  421.     WaitTOF();    
  422.     LoadRGB4(&myScreen->ViewPort, color, 1);
  423.   }
  424. }    
  425.  
  426.  
  427. /*------------------------------------------------------------------------*/
  428.  
  429. /*
  430.  * init_kbdrepeat -- Sets up structures for keyboard repeat modifying.
  431.  *                   Repeats are modified because keyboard repeating
  432.  *                   creates lag. Should perhaps read keys directly
  433.  *                   from keyboard.device..Shrug. This is still the
  434.  *                   easiest way I think.
  435.  */
  436. void
  437. init_kbdrepeat(void)
  438. {
  439.   struct shortprefs {
  440.     BYTE dummy1;
  441.     UBYTE dummy2;
  442.     UWORD dummy3;
  443.     struct timeval dummy4;
  444.     struct timeval keyRptDelay;
  445.   } myPrefs;
  446.  
  447.   GetPrefs( (struct Preferences *) &myPrefs, sizeof(struct shortprefs) );
  448.   oldrptdelay = myPrefs.keyRptDelay.tv_secs;
  449.  
  450.   if (!(inputPort = CreatePort( NULL, NULL )))
  451.     cleanExit( RETURN_WARN, "** Unable to create message port\n" );
  452.   if (!(inputReqBlk = (struct timerequest *) 
  453.        CreateExtIO(inputPort, sizeof(struct timerequest))))
  454.     cleanExit( RETURN_WARN, "** Unable to CreateExtIO()\n" ); 
  455.   if ((deviceopen = OpenDevice("input.device", NULL, 
  456.                                (struct IORequest *)inputReqBlk, NULL)))
  457.     cleanExit( RETURN_WARN, "** Unable to open input.device\n" );
  458.  
  459.   inputReqBlk->tr_node.io_Command = IND_SETTHRESH;
  460.   inputReqBlk->tr_time.tv_secs  = 0;
  461.   inputReqBlk->tr_time.tv_micro = myPrefs.keyRptDelay.tv_micro;
  462. }
  463.  
  464. /*------------------------------------------------------------------------*/
  465.  
  466. /*
  467.  * Main...
  468.  */
  469. void
  470. main(int argc, char *argv[])
  471. {
  472.   int   over = 0;
  473.   int   frameinfo[4] = { 0, 0, 0, 0 };
  474.   UWORD a_framerate;                   /* Actual framerate */
  475.  
  476. #ifdef CPU_USAGE
  477.   int    cpu_usage;
  478.   int    avg_cpu_usage  = 0;
  479.   int    topcounter     = 75;
  480.   int    top_cpu_usage  = 0;
  481.   int    top_cpu_usage2 = 0;
  482.   int    min_cpu_usage  = 100;
  483.   ULONG  e_freq, time1, time2; 
  484.   struct EClockVal eclock;
  485. #endif
  486.  
  487.   AShip           myShip, dummyShip;
  488.   BOOL            done = FALSE;
  489.   UWORD           CurBuffer;
  490.   ULONG           vb_signal;
  491.   extern UWORD    vb_counter;         /* This comes from our vblank server */
  492.   struct ViewPort *scrnVP;
  493.   struct Task     *my_task;
  494.  
  495.   /*
  496.    * Parse commandline for eventual options, and set default prefs.
  497.    */
  498.   prefs.mapname = MAPFILE;
  499.   prefs.dpy_modeid = HIRES|LACE;
  500.   prefs.dpy_autoscroll = 0;
  501.   prefs.dpy_oscan = OSCAN_STANDARD;    
  502.   prefs.dpy_width = 639;    /* Default values (could really be anything) */
  503.   prefs.dpy_height = 511;
  504.   prefs.native_mode = 1;
  505.  
  506.   cmdline(argc, argv);
  507.  
  508.   /*
  509.    * Init everything..
  510.    */
  511.   CurBuffer = 1;
  512.   my_task   = FindTask(NULL);
  513.   vb_signal = init_VertBServer();
  514.   init_world();
  515.   init_map();
  516.   init_sctables();
  517.   init_points();
  518.   init_explosion();
  519.   init_display(prefs.native_mode);
  520.   init_font();
  521.   init_kbdrepeat();
  522. #ifndef PURE_OS
  523.   init_writepixel(myBitMap[0]->BytesPerRow);
  524. #endif
  525.   init_ship(&myShip);
  526.  
  527.   /* This is just here for testing */
  528.   init_ship(&dummyShip);
  529.   dummyShip.shields = FALSE;
  530.   dummyShip.local   = FALSE;
  531.   dummyShip.next = World.players->next;
  532.   World.players->next = &dummyShip;
  533.   myShip.next = World.players->next;
  534.   World.players->next = &myShip;
  535.  
  536.   World.local_ship = &myShip;
  537.  
  538. #ifdef CPU_USAGE
  539.     if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) &tr, 0))
  540.       cleanExit( RETURN_WARN, "** Failed to open timer.device.\n");
  541.  
  542.     TimerBase = (struct Library *)tr.tr_node.io_Device;
  543.     /* Count how many e-ticks per screen update (50Hz) */
  544.     e_freq = (ReadEClock(&eclock) / 100) * APILOT_NFR;
  545. #endif    
  546.  
  547.   /*
  548.    * Set up needed structures for double-buffering..
  549.    */
  550.   if ((dbufport = CreateMsgPort()) == NULL)
  551.     cleanExit( RETURN_WARN, "** Unable to create message port\n" );
  552.  
  553.   scrnVP = &myScreen->ViewPort;
  554.   if ((myDBI = AllocDBufInfo( scrnVP )) == NULL)
  555.     cleanExit( RETURN_WARN, "** Unable to allocate DBufInfo\n" );
  556.  
  557.   myDBI->dbi_SafeMessage.mn_ReplyPort = dbufport;
  558.   myDBI->dbi_DispMessage.mn_ReplyPort = NULL;
  559.  
  560.   vb_counter = 0;
  561.  
  562.   /*
  563.    * Main loop...
  564.    */
  565.   while (!done) {
  566.  
  567.     a_framerate = vb_counter+1;
  568.     if (a_framerate < 5 ) 
  569.       frameinfo[a_framerate-1]++;
  570.  
  571. /*----------------------------------------------------*/
  572. /* This part is run on a higher priority to eliminate */
  573. /* flicker. This has VERY little impact on overall    */
  574. /* system performace but is needed because for some   */
  575. /* reason WaitTOF() isn't always very accurate on     */
  576. /* lower priorities.                                  */
  577. /*----------------------------------------------------*/
  578.     SetTaskPri(my_task, 30);
  579.     if (a_framerate > APILOT_NFR) {
  580.       over++;
  581.       WaitTOF();
  582.     }
  583.     Wait(vb_signal); 
  584.  
  585. #ifdef CPU_USAGE
  586.     ReadEClock(&eclock);
  587.     time1 = eclock.ev_lo;
  588. #endif
  589.  
  590.     WaitBlit();
  591.     ChangeVPBitMap(scrnVP, myBitMap[CurBuffer], myDBI);
  592.     SetTaskPri(my_task,0);
  593. /*---------------------------------------------------*/
  594.  
  595.     CurBuffer ^= 1; 
  596.     vb_counter = 0;
  597.  
  598.     /*
  599.      * Update everything...
  600.      */
  601.     move_points(CurBuffer, w_framerate); 
  602.     update_ship(&myShip, CurBuffer, w_framerate);
  603.     
  604.     /* Only for testing */
  605.     update_ship(&dummyShip, CurBuffer, w_framerate);
  606.  
  607.     update_cannons(&myShip, w_framerate);
  608.     update_fuelpods(w_framerate);
  609.     check_collisions();
  610.  
  611.     /* 
  612.      * Wait for the 'safe to write' message 
  613.      */
  614.     while (!GetMsg(dbufport)) Wait(1l<<(dbufport->mp_SigBit));
  615.  
  616.     /*
  617.      * Draw everything...
  618.      */
  619.     draw_ship(&myShip, &myRP[CurBuffer], CurBuffer);
  620.  
  621.     /* And testing again */
  622.     draw_ship(&dummyShip, &myRP[CurBuffer], CurBuffer);
  623.  
  624. #ifdef PURE_OS
  625.     draw_points(&myShip, &myRP[CurBuffer], CurBuffer, w_framerate); 
  626. #else
  627.     draw_points(&myShip, myBitMap[CurBuffer], CurBuffer, w_framerate); 
  628. #endif
  629.  
  630.     /* draw_map calls draw_hud */
  631.     draw_map(&myRP[CurBuffer], &myShip, CurBuffer, w_framerate);
  632.  
  633.  
  634. #ifdef CPU_USAGE
  635.     ReadEClock(&eclock);
  636.     time2 = eclock.ev_lo;
  637.  
  638.     cpu_usage = (abs(time2-time1)*(200/w_framerate))/e_freq % 300;
  639.     /* Average of 2 just to smooth it a little. */
  640.     avg_cpu_usage = (cpu_usage + avg_cpu_usage) / 2;
  641.  
  642.     if (cpu_usage > top_cpu_usage)
  643.       top_cpu_usage = cpu_usage;
  644.     if (cpu_usage > top_cpu_usage2)
  645.       top_cpu_usage2 = cpu_usage;
  646.     if (cpu_usage < min_cpu_usage)
  647.       min_cpu_usage = cpu_usage;
  648.     if (topcounter-- <= 0) {
  649.       topcounter    = 75;
  650.       top_cpu_usage = 0;
  651.     }
  652.  
  653.     if (cpu_meter) {
  654.       SetAPen(&myRP[CurBuffer], 0);
  655.       SetWriteMask(&myRP[CurBuffer], 1l);
  656.       RectFill( &myRP[CurBuffer], 70, 70,
  657.                                   370, 78 );
  658.       SetAPen(&myRP[CurBuffer], 1);
  659.       Move(&myRP[CurBuffer], 70 + top_cpu_usage, 70);
  660.       Draw(&myRP[CurBuffer], 70 + top_cpu_usage, 78);
  661.       RectFill( &myRP[CurBuffer], 70, 70,
  662.                                 70 + avg_cpu_usage, 78 );
  663.       Move(&myRP[CurBuffer], 70, 66);
  664.       Draw(&myRP[CurBuffer], 70, 82);
  665.       Move(&myRP[CurBuffer], 170, 66);
  666.       Draw(&myRP[CurBuffer], 170, 82);
  667.       Move(&myRP[CurBuffer], 270, 66);
  668.       Draw(&myRP[CurBuffer], 270, 82);
  669.     }
  670. #endif
  671.  
  672.     done = handleIDCMP(&myShip);
  673.   }
  674.  
  675.   printf("Over wanted framerate: %d frames.\n", over);
  676.   printf("50 fps : %d\n25 fps : %d\n16.7 fps : %d\n12.5fps : %d\n", 
  677.           frameinfo[0], frameinfo[1], frameinfo[2], frameinfo[3]);
  678.  
  679. #ifdef CPU_USAGE
  680.   printf("Max cpu usage during game: %d percent.\n", top_cpu_usage2 / 2);
  681.   printf("Min cpu usage during game: %d percent.\n", min_cpu_usage  / 2);
  682. #endif
  683.  
  684.   WaitBlit();
  685.   cleanExit( RETURN_OK, "" );
  686. }
  687.  
  688. /*------------------------------------------------------------------------*/
  689.  
  690. /*
  691.  * handleIDCMP -- Reads keyboard events and does what the user tells it
  692.  *                to do.
  693.  */
  694. BOOL 
  695. handleIDCMP(AShip *aShip)
  696. {
  697.   BOOL done = FALSE;
  698.   BOOL keyup;
  699.   ULONG class;
  700.   USHORT code;
  701.   USHORT qual;
  702.  
  703.   struct IntuiMessage *message;    
  704.   extern struct VertBData vertbdata;  /* From vertb.c */
  705.  
  706.  
  707.   /* Examine pending messages */
  708.   while( message = (struct IntuiMessage *)GetMsg(myWindow->UserPort) )
  709.   {
  710.     class = message->Class;  /* get all data we need from message */
  711.     code  = message->Code;
  712.     qual  = message->Qualifier;
  713.  
  714.     /* When we're through with a message, reply */
  715.     ReplyMsg( (struct Message *)message);
  716.  
  717.     /* See what events occurred */
  718.     keyup = (code & 0x80);
  719.  
  720.     switch( class ) {
  721.       case IDCMP_RAWKEY:
  722.         if(qual & IEQUALIFIER_RSHIFT)
  723.           aShip->thrusting = TRUE;
  724.         else
  725.           aShip->thrusting = FALSE;
  726.  
  727.         switch( 0x7F & code )
  728.         {
  729.           case RAWKEY_ENTER:
  730.             if (!keyup)
  731.               aShip->fireing = TRUE;
  732.             break;
  733.           case RAWKEY_A:
  734.             if (keyup)
  735.               aShip->turning = NO;
  736.             else
  737.               aShip->turning = LEFT;
  738.             break;
  739.           case RAWKEY_S:
  740.             if (keyup)
  741.               aShip->turning = NO;
  742.             else
  743.               aShip->turning = RIGHT;
  744.             break;
  745.           case RAWKEY_Q:  
  746.             inputReqBlk->tr_time.tv_secs = oldrptdelay;
  747.             DoIO((struct IORequest *) inputReqBlk);
  748.             done = TRUE;
  749.             break;
  750.           case RAWKEY_SPACE:
  751.             if (keyup)
  752.               aShip->shields = FALSE;
  753.             else
  754.               aShip->shields = TRUE;
  755.             break;
  756.           case RAWKEY_F:
  757.             if (keyup) {
  758.               aShip->fueling = FALSE;
  759.             } else {
  760.               World.hudon    = TRUE;
  761.               aShip->fueling = TRUE;
  762.               aShip->fpod    = NULL;
  763.             }
  764.             break;
  765. #ifdef CPU_USAGE
  766.           case RAWKEY_KP_STAR:
  767.             if (keyup)
  768.               cpu_meter ^= 1;
  769.             break;
  770. #endif
  771.           case RAWKEY_KP_MINUS:
  772.             if (keyup) {
  773.               if (w_framerate > 1) {
  774.                 World.framerate = --w_framerate;
  775.                 vertbdata.sigframe--;
  776.               }
  777.             }
  778.             break;
  779.           case RAWKEY_KP_PLUS:
  780.             if (keyup) {
  781.               if (w_framerate < 4) {
  782.                 World.framerate = ++w_framerate;
  783.                 vertbdata.sigframe++;
  784.               }
  785.             }
  786.             break;
  787.           default:
  788.             break;
  789.         }
  790.         break;
  791.       case IDCMP_ACTIVEWINDOW:
  792.         /* 1000 Should be enough to prevent repeat. */
  793.         inputReqBlk->tr_time.tv_secs = 1000;
  794.         DoIO((struct IORequest *) inputReqBlk);
  795.         break;
  796.       case IDCMP_INACTIVEWINDOW:
  797.         inputReqBlk->tr_time.tv_secs = oldrptdelay;
  798.         DoIO((struct IORequest *) inputReqBlk);
  799.         break;
  800.       default:
  801.         break;
  802.     }
  803.   }
  804.   return(done);
  805. }
  806.  
  807. /*------------------------------------------------------------------------*/
  808.  
  809. /*
  810.  * cleanExit -- Closes windows, screens etc. and tries to exit
  811.  *              gracefully.
  812.  */
  813. void 
  814. cleanExit( LONG returnValue, char *fmt, ... )
  815. {
  816.   int i;
  817.   va_list argp;
  818.  
  819.   va_start(argp, fmt);
  820.   vfprintf (stderr, fmt, argp);
  821.   va_end(argp);
  822.  
  823.   remove_VertBServer();
  824.   if (deviceopen == 0) CloseDevice((struct IORequest *) inputReqBlk);
  825.   if (inputReqBlk)     DeleteExtIO((struct IORequest *) inputReqBlk);
  826.   if (inputPort)       DeletePort( inputPort );
  827.   if (myDBI)           FreeDBufInfo( myDBI );
  828.   if (myWindow)        CloseWindow( myWindow );
  829.   if (myScreen)        CloseScreen( myScreen );
  830.   if (hudFont)         CloseFont(hudFont);
  831.  
  832. #ifdef CPU_USAGE
  833.   if (TimerBase)       CloseDevice((struct IORequest *) &tr);
  834. #endif
  835.  
  836.   if (dbufport) {
  837.     /* Cleanup any pending messages */
  838.     while (GetMsg(dbufport));
  839.     DeleteMsgPort(dbufport);
  840.   }
  841.  
  842.   if (World.shld_bm != NULL)
  843.     FreeBitMap( World.shld_bm );
  844.  
  845.   for (i = 0; i < MY_BUFFERS; i++) {
  846.     if (myBitMap[i] != NULL)
  847.       FreeBitMap( myBitMap[i] );
  848.   }
  849.   exit(returnValue);
  850. }
  851.  
  852. /*------------------------------------------------------------------------*/
  853.