home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 Mobile / Chip_Mobile_2001.iso / palm / spiele / argon / argon.exe / src / argonv.c next >
Encoding:
C/C++ Source or Header  |  2000-01-26  |  27.9 KB  |  1,172 lines

  1. /*
  2.  
  3.   argonv.c - (c) 1999 by Till Harbaum
  4.  
  5.   ArgonV, the ultimate space blaster
  6.  
  7.   T.Harbaum@tu-bs.de - http://www.ibr.cs.tu-bs.de/~harbaum/pilot
  8.  
  9.   This program is distributed in the hope that it will be useful,
  10.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.   GNU General Public License for more details.
  13.  
  14. */
  15.  
  16. #include <Pilot.h>
  17. #include <KeyMgr.h>
  18. #include <System/DLServer.h>
  19.  
  20. #include "video.h"
  21. #include "argonv.h"
  22. #include "argonvRsc.h"
  23.  
  24. static Boolean StartApplication(void);
  25. static Boolean MainFormHandleEvent(EventPtr event);
  26. static void    EventLoop(void);
  27.  
  28. #define noFORCE_PREFS  // force regeneration of preferences 
  29. #define MAX_Y  176     // sprites max y postition
  30.  
  31. /* preference stuff */
  32. #define MAX_SCORES    6  /* save and display the six top scores */
  33. #define MAX_NAMELEN  10
  34.  
  35. unsigned long score;
  36.  
  37. struct score {
  38.   char name[MAX_NAMELEN+1];
  39.   unsigned long  value;
  40. };
  41.  
  42. struct {
  43.   struct score score[MAX_SCORES];
  44.   int last_name_index;
  45.   Boolean sound;
  46. } prefs;
  47.  
  48. /* some globals for overall control */
  49. int game_state  = STATE_TITLE;
  50. int sub_state   = 0;
  51.  
  52. /* save hard key state */
  53. DWord last_state=0;
  54.  
  55. /************************************************************/
  56. /* players ship position handling                           */
  57.  
  58. #define SHIP_START_Y 155
  59.  
  60. unsigned int scroll_y;
  61. int ship_x_pos, ship_y_pos;
  62.  
  63. unsigned int ship_save_scroll;
  64. int ship_save_x, ship_save_y;
  65.  
  66. /* save position for restore */
  67. void ship_save_position(void) {
  68.   ship_save_x = ship_x_pos;
  69.   ship_save_y = ship_y_pos;
  70.   ship_save_scroll = scroll_y;
  71. }
  72.  
  73. /* save position for restore */
  74. void ship_restore_position(void) {
  75.   ship_x_pos = ship_save_x; 
  76.   ship_y_pos = ship_save_y;
  77.   scroll_y = ship_save_scroll;
  78. }
  79.  
  80. /************************************************************/
  81. /* player name input                                        */
  82. char    current_name[MAX_NAMELEN+1];
  83. Boolean name_init;
  84. int     name_pos;
  85.  
  86. /* get hotsync user name */
  87. void set_default_name(void) {
  88.   char name[dlkUserNameBufSize];
  89.   int i;
  90.  
  91.   DlkGetSyncInfo(0, 0, 0, name, 0, 0);
  92.  
  93.   /* remove weird characters */
  94.   for(name_pos=0,i=0;(name[i]!=0)&&
  95.     (name_pos<MAX_NAMELEN)&&(name[i]!=' ');i++) {
  96.  
  97.     /* convert lowercase to uppercase */
  98.     if((name[i]>='a')&&(name[i]<='z'))
  99.       current_name[name_pos++] = name[i] - 'a' + 'A'; 
  100.     else if((name[i]>='A')&&(name[i]<='Z'))
  101.       current_name[name_pos++] = name[i];
  102.   }
  103.  
  104.   /* last char */
  105.   current_name[name_pos]=0;
  106.  
  107.   if(name_pos>=MAX_NAMELEN) name_pos--;
  108. }
  109.  
  110. void init_name_input(void) {
  111.   name_init       = true;
  112. }
  113.  
  114. /* compare function to sort hiscores */
  115. Int name_compare(VoidPtr a, VoidPtr b, Long nix) {
  116.   return ((struct score*)b)->value - ((struct score*)a)->value;
  117. }
  118.  
  119. void name_add_char(char chr) {
  120.   int i;
  121.  
  122.   switch(chr) {
  123.  
  124.     /* END */
  125.   case 3:
  126.     /* switch to title display */
  127.     game_state = STATE_TITLE;
  128.     sub_state  = 0;
  129.  
  130.     /* add hi score to prefs */
  131.     StrCopy(prefs.score[MAX_SCORES-1].name, current_name);
  132.     prefs.score[MAX_SCORES-1].value = score;
  133.     SysQSort(prefs.score, MAX_SCORES, sizeof(struct score), name_compare, 0);
  134.  
  135.     /* remember that this was the last name entered */
  136.     for(i=0;i<MAX_SCORES;i++) 
  137.       if(StrCompare(prefs.score[i].name, current_name) == 0)
  138.     prefs.last_name_index = i;
  139.  
  140.     break;
  141.  
  142.     /* RUB */
  143.   case 2:
  144.     if(name_pos>0) current_name[--name_pos] = '\0';
  145.     break;
  146.  
  147.     /* CLR */
  148.   case 1:
  149.     name_pos = 0;
  150.     current_name[name_pos] = '\0';
  151.     break;
  152.  
  153.     /* SPC */
  154.   case 0:
  155.     chr = ' ';
  156.   default:
  157.     current_name[name_pos++] = chr;
  158.     current_name[name_pos]   = '\0';    
  159.   }
  160.   if(name_pos>=MAX_NAMELEN) name_pos--;
  161. }
  162.  
  163. void main_name_input(void) {
  164.   DWord hardKeyState;
  165.   static int cur_x, cur_y;
  166.  
  167.   hardKeyState = KeyCurrentState();
  168.   if(name_init) {
  169.     name_init  = false;
  170.  
  171.     /* default cursor position is 'END' */
  172.     cur_x = 6;
  173.     cur_y = 3;
  174.   }
  175.  
  176.   /* draw scrolling background */
  177.   VideoDrawTitleBg();
  178.   VideoDrawSprite(53 + 8*name_pos, 57, SPR_CURSOR);
  179.  
  180.   if(cur_x <= 5) {
  181.     /* cursor on characters */
  182.     VideoDrawSprite(29 + 16*cur_x, 77 + 12*cur_y, SPR_CURSOR);
  183.   } else {
  184.     /* cursor on special entries */
  185.     VideoDrawSprite(29 + 120, 77 + 12*cur_y, SPR_CURSOR);
  186.     VideoDrawSprite(29 + 112, 77 + 12*cur_y, SPR_CUREXT);
  187.     VideoDrawSprite(29 + 104, 77 + 12*cur_y, SPR_CUREXT);
  188.   }
  189.  
  190.   VideoDrawText(2,  30, "New High Score!");
  191.   VideoDrawText(2,  40, "Enter your name:");
  192.  
  193.   VideoDrawText(5,  60, current_name);
  194.   VideoDrawText(5,  65, "----------");
  195.   
  196.   VideoDrawText(2,  80, "A B C D E F  SPC");
  197.   VideoDrawText(2,  92, "G H I J K L  CLR");
  198.   VideoDrawText(2, 104, "M N O P Q R  RUB");
  199.   VideoDrawText(2, 116, "S T U V W X  END");
  200.   VideoDrawText(2, 128, "Y Z");
  201.  
  202.   /* is currently a key pressed? */
  203.   if((hardKeyState != 0) &&
  204.      ((hardKeyState & last_state) != hardKeyState)) {
  205.  
  206.     /* cursor movement key */
  207.     if((hardKeyState & keyBitPageUp)   != 0) cur_y -= 1;
  208.     if((hardKeyState & keyBitPageDown) != 0) cur_y += 1;
  209.     if((hardKeyState & keyBitHard3)    != 0) cur_x -= 1;
  210.     if((hardKeyState & keyBitHard4)    != 0) cur_x += 1;    
  211.  
  212.     /* 'enter' key */ 
  213.     if((hardKeyState & keyBitHard1)    != 0) {
  214.       if(cur_x<6) name_add_char('A'+cur_x+cur_y*6);
  215.       else        name_add_char(cur_y);
  216.     }
  217.  
  218.     if((hardKeyState & keyBitHard2)    != 0) {
  219.       /* switch to title display */
  220.       game_state = STATE_TITLE;
  221.       sub_state  = 0;
  222.     }
  223.  
  224.     /* check limits */
  225.     if(cur_x<0) cur_x=0;
  226.     if(cur_x>6) cur_x=6;
  227.     if(cur_y<0) cur_y=0;
  228.     if(cur_y>4) cur_y=4;
  229.     if((cur_y==4)&&(cur_x>1)) cur_y=3;
  230.   }
  231.  
  232.   /* save last keystate */
  233.   last_state = hardKeyState;
  234. }
  235.  
  236. /************************************************************/
  237. /** preference stuff                                        */
  238.  
  239. void get_preferences(void) {
  240.   Word size, result;
  241.   int i;
  242.  
  243.   SystemPreferencesType sysPrefs;
  244.  
  245.   size   = sizeof(prefs);
  246.   result = PrefGetAppPreferences( CREATOR, 0, &prefs, &size, true);
  247.  
  248.   /* initialize default settings */
  249. #ifndef FORCE_PREFS
  250.   if(result == noPreferenceFound)
  251. #endif
  252.   {
  253.     prefs.sound = true;
  254.     prefs.last_name_index = -1;
  255.  
  256.     for(i=0;i<MAX_SCORES;i++) {
  257.       StrCopy(prefs.score[i].name, "- empty -");
  258.       prefs.score[i].value=0;
  259.     }
  260.   }
  261.  
  262.   /* preference is fine, get last entered name */
  263.   if(prefs.last_name_index>=0) {
  264.     StrCopy(current_name, prefs.score[prefs.last_name_index].name);
  265.     name_pos = StrLen(current_name);
  266.     if(name_pos>=MAX_NAMELEN) name_pos--;
  267.   } else
  268.     set_default_name();
  269.  
  270.   /* get system preferences for sound */
  271.   PrefGetPreferences(&sysPrefs);
  272.   if(sysPrefs.gameSoundLevelV20 == slOff) 
  273.     prefs.sound = false;
  274. }
  275.  
  276. void save_preferences(void) {
  277.   PrefSetAppPreferences( CREATOR, 0, 1, &prefs, sizeof(prefs), true);
  278. }
  279.  
  280. /************************************************************/
  281. /* routie to handle messages during the game                */
  282. unsigned char message_buffer[21];   /* at most 20 chars */
  283. int msg_state, msg_offset,msg_len;
  284. #define MSG_RELOAD 50
  285.  
  286. void init_message(void) {
  287.   msg_state=0;    /* no message */
  288. }
  289.  
  290. void new_message(char *str) {
  291.   int i=0;
  292.  
  293.   msg_state = MSG_RELOAD;
  294.  
  295.   /* copy string */
  296.   while(message_buffer[i++] = *str++);
  297.  
  298.   /* center message horizontally */
  299.   msg_offset = (21-i)/2;
  300.   msg_len = i-1;
  301. }
  302.  
  303. void handle_message(void) {
  304.   int i;
  305.  
  306.   if(msg_state>0) {
  307.     if(msg_state>(MSG_RELOAD-8)) {
  308.       i = MSG_RELOAD-msg_state;
  309.       VideoDrawPartialText(msg_offset, 32, message_buffer, 
  310.                  0, 20, (7-i)/2, (8+i)/2);
  311.     } else if(msg_state<msg_len) {
  312.       i = (msg_len-msg_state)/2;
  313.       VideoDrawPartialText(msg_offset, 32, message_buffer, 
  314.                  i, msg_len-i-1, 0, 7);
  315.     } else
  316.       VideoDrawText(msg_offset, 32, message_buffer);
  317.  
  318.     msg_state--;
  319.   }
  320. }
  321.  
  322. /************************************************************/
  323. /* routines to update status line                           */
  324. char score_str[21]="00000  \002\010\010\010\010\003  \001\001\001\001\001";
  325.  
  326. void score_inc(int amount) {
  327.   unsigned int s;
  328.   int i;
  329.  
  330.   score += amount;
  331.   s = score;
  332.  
  333.   i=4;
  334.   while(i>=0) {
  335.     score_str[i--] = '0' + s%10;
  336.     s/=10;
  337.   }
  338. }
  339.  
  340. /************************************************************/
  341. /* shield and damage stuff                                  */
  342.  
  343. #define SHIP_EXPLODE_TIMER 50
  344.  
  345. #define SHIELD_MUL  (8)   /* shield muliplier */
  346. #define MAX_SHIELDS (SHIELD_MUL*4*4)
  347. #define MAX_LIFES   (5)
  348. int shields, lifes;
  349.  
  350. void damage(int amount) {
  351.   int i,k,p;
  352.  
  353.   /* game currently running */
  354.   if(sub_state == 0) {
  355.  
  356.     /* total destruction */
  357.     if(amount == DAMAGE_DESTROY) {
  358.       shields = -1;
  359.       amount  = 0;
  360.     }
  361.  
  362.     /* reload/init shields */
  363.     if(amount == DAMAGE_RELOAD) {
  364.       shields = MAX_SHIELDS;
  365.       amount  = 0;
  366.     }
  367.  
  368.     /* shields are down -> explode ship */
  369.     shields -= amount;
  370.  
  371.     /* shields just got below warning level */
  372.     if((shields<(4*SHIELD_MUL))&&(shields+amount>=(4*SHIELD_MUL)))
  373.       new_message("SHIELDS LOW!");
  374.  
  375.     if(shields < 0) {
  376.       lifes--;
  377.       shields = 0;
  378.       sub_state = SHIP_EXPLODE_TIMER + 2*(SPR_EXP_L - SPR_EXP_F + 1);
  379.     }
  380.     
  381.     /* draw shield bar */
  382.     for(p = shields/SHIELD_MUL, k=11;k!=7;k--, p-=4) {
  383.       if(p>4)       score_str[k] = 8;   /* 100%    */
  384.       else if(p<0)  score_str[k] = 4;   /* 0%      */
  385.       else          score_str[k] = 4+p; /* 25%-75% */
  386.     }
  387.     
  388.     /* draw lifes */
  389.     for(p = lifes, k=19; k!=19-MAX_LIFES; k--, p--)
  390.       if(p>0) score_str[k]=1;
  391.       else    score_str[k]=' ';
  392.   }
  393. }
  394.  
  395. /************************************************************/
  396. /** explosion                                               */
  397.  
  398. #define MAX_EXP    8
  399.  
  400. struct explosion {
  401.   int x, y;    /* position */
  402.   int state;   /* timer */
  403. };
  404.  
  405. struct explosion explosion[MAX_EXP];  /* current explosion position/state */
  406.  
  407. void init_exp(void) {
  408.   int i;
  409.   for(i=0;i<MAX_EXP;i++) explosion[i].y = -1;
  410. }
  411.  
  412. void new_exp(int x, int y) {
  413.   int i;
  414.  
  415.   /* find an empty explosion slot and use it */
  416.   for(i=0;i<MAX_EXP;i++) {
  417.     if(explosion[i].y < 0) {
  418.       explosion[i].state = SPR_EXP_F;  /* first explosion sprite */
  419.       explosion[i].x = x;
  420.       explosion[i].y = y;
  421.       return;
  422.     }
  423.   }
  424. }
  425.  
  426. void handle_exp(void) {
  427.   static reload=0;
  428.   Boolean f;
  429.   int i;
  430.  
  431.   /* draw explosions */
  432.   for(i=0;i<MAX_EXP;i++) {
  433.     if(explosion[i].y >= 0) {
  434.       VideoDrawSprite(explosion[i].x, explosion[i].y, explosion[i].state);
  435.       explosion[i].state += 1;
  436.       if(explosion[i].state == (SPR_EXP_L+1))
  437.     explosion[i].y = -1;
  438.     }
  439.   }
  440. }
  441.  
  442. /************************************************************/
  443. /** players shot                                            */
  444.  
  445. int shot_sprite[]={SPR_SHOT1, SPR_SHOT2, SPR_SHOT3 };
  446.  
  447. #define MAX_SHOTS   8
  448. #define SHOT_STEP   3
  449.  
  450. const shot_reload_time[]={12,8,6};
  451.  
  452. int shot_mode, shot_reload;
  453.  
  454. struct shot {
  455.   int x,y;  /* current shot position */
  456.   int spr;  /* type of shot (single, double, tripple) */
  457. };
  458.  
  459. struct shot shot[MAX_SHOTS];
  460.  
  461. void init_shot(void) {
  462.   int i;
  463.  
  464.   shot_mode = SHOT_SINGLE;
  465.   shot_reload = 0;
  466.  
  467.   for(i=0;i<MAX_SHOTS;i++) shot[i].y = -1;
  468. }
  469.  
  470. void handle_shot(Boolean fire, int mode, int x, int y) {
  471.   static reload=0;
  472.   Boolean f;
  473.   int i;
  474.  
  475.   /* it's time for a new shot */
  476.   if((fire)&&(reload==0)) {
  477.  
  478.     /* find an empty shot slot and use it */
  479.     for(f=false,i=0;(i<MAX_SHOTS)&&(!f);i++) {
  480.       if(shot[i].y < 0) {
  481.     shot[i].x   = x;
  482.     shot[i].y   = y;
  483.     shot[i].spr = shot_sprite[mode];
  484.     f = true;
  485.       }
  486.     }
  487.  
  488.     if(f) reload = shot_reload_time[shot_reload];
  489.   }
  490.  
  491.   if(reload>0) reload--;
  492.  
  493.   /* draw shots */
  494.   for(i=0;i<MAX_SHOTS;i++) {
  495.     if(shot[i].y >= 0) {
  496.       VideoDrawSprite(shot[i].x, shot[i].y, shot[i].spr);
  497.       shot[i].y -= SHOT_STEP;
  498.  
  499.       /* shot automatically disappears at pos < 0 */
  500.     }
  501.   }
  502. }
  503.  
  504. /************************************************************/
  505. /** enemies bomb                                            */
  506.  
  507. #define MAX_BOMBS  8
  508. #define BOMB_STEP  2
  509.  
  510. /* all things we need to know about one bomb */
  511. struct bomb {
  512.   int x,y;     /* bomb position */
  513. };
  514.  
  515. struct bomb bomb[MAX_BOMBS];  /* current bomb position */
  516. int bomb_freq;
  517.  
  518. void init_bomb(void) {
  519.   int i;
  520.   for(i=0;i<MAX_BOMBS;i++) bomb[i].y=-1;
  521.   bomb_freq = 10;
  522. }
  523.  
  524. void new_bomb(int x, int y) {
  525.   Boolean f;
  526.   int i;
  527.  
  528.   /* find an empty bomb slot and use it */
  529.   for(f=false,i=0;(i<MAX_BOMBS)&&(!f);i++) {
  530.     if(bomb[i].y < 0) {
  531.       bomb[i].x = x;
  532.       bomb[i].y = y;
  533.       f = true;
  534.     }
  535.   }
  536. }
  537.   
  538. void handle_bomb(int x, int y) {
  539.   int i;
  540.  
  541.   /* draw bombs */
  542.   for(i=0;i<MAX_BOMBS;i++) {
  543.     if(bomb[i].y >= 0) {
  544.       VideoDrawSprite(bomb[i].x, bomb[i].y, SPR_EBOMB);
  545.       bomb[i].y += BOMB_STEP;
  546.  
  547.       /* game still running? */
  548.       if(sub_state == 0) {
  549.     /* is our ship hit? */
  550.     if(VideoSpriteCollide(x, y, SPR_SHIP, 
  551.                   bomb[i].x, bomb[i].y, SPR_EBOMB)) {
  552.       damage(DAMAGE_BOMB);  /* cause damage to ship */
  553.       bomb[i].y = -1;       /* remove bomb */
  554.     }
  555.       }
  556.  
  557.       /* bomb disappears at pos > 176 (160+16) */
  558.       if(bomb[i].y >= MAX_Y) bomb[i].y = -1;
  559.     }
  560.   }
  561. }
  562.  
  563. /************************************************************/
  564. /** extra (bonus score etc) stuff                           */
  565.  
  566. #define EXTRA_DURATION    20
  567. #define MAX_EXTRA          8
  568. #define EXTRA_STEP         1
  569.  
  570. struct extra {
  571.   int x,y;      /* screen position */
  572.   int spr;      /* sprite type     */
  573.   int ttl;      /* time to live    */ 
  574. };
  575.  
  576. struct extra extra[MAX_EXTRA];  /* current extra position/time/sprite */
  577.  
  578. void init_extra(void) {
  579.   int i;
  580.   for(i=0;i<MAX_EXTRA;i++) extra[i].y=-1;
  581. }
  582.  
  583. void new_extra(int x, int y, int sprite) {
  584.   int i, max=0;
  585.  
  586.   /* do score handling */
  587.   if(sprite == SPR_SCORE10)       score_inc(SCORE_10);
  588.   else if(sprite == SPR_SCORE100) score_inc(SCORE_100);
  589.  
  590.   /* find an empty extra slot and use it */
  591.   for(i=0;i<MAX_EXTRA;i++) {
  592.     if(extra[i].y < 0) {
  593.       extra[i].x   = x;
  594.       extra[i].y   = y;
  595.       extra[i].spr = sprite;
  596.       extra[i].ttl = EXTRA_DURATION;
  597.       return;
  598.     }
  599.   }
  600.  
  601.   /* no empty slot? empty one! */
  602.   /* ... */
  603. }
  604.  
  605. void handle_extra(void) {
  606.   int i;
  607.  
  608.   for(i=0;i<MAX_EXTRA;i++) {
  609.     if(extra[i].y >= 0) {
  610.       VideoDrawSprite(extra[i].x, extra[i].y, extra[i].spr);
  611.  
  612.       extra[i].y += EXTRA_STEP;
  613.  
  614.       /* timeout? */
  615.       if((--extra[i].ttl==0)||(extra[i].y>=MAX_Y)) {
  616.     /* remove sprite */
  617.     extra[i].y = -1;
  618.       }
  619.     }
  620.   }
  621. }
  622.  
  623. /************************************************************/
  624. /** enemy wave                                              */
  625.  
  626. #define PI2 6   /* this is precise enough */
  627.  
  628. /* horiz. center of display area */
  629. #define CENTER  88
  630. #define CENTER2 (2*CENTER)
  631.  
  632. /* wave states */
  633. struct wave {
  634.   char mode;       /* type of wave             */
  635.   char len;        /* number of enemies        */
  636.   unsigned char y; /* wave parameter (y-pos)   */
  637.   char rad;        /* wave parameter (radius)  */
  638.   char flip;       /* vertical flip            */
  639.   char rev;        /* reverse wave             */
  640.   char dist;       /* distance between enemies */
  641.   char sprite;     /* enemy sprite             */
  642.   char speed;      /* speed of sprites         */
  643. };
  644.  
  645. #define WTYPE_PAUSE 0
  646. #define WTYPE_LOOP  1
  647. #define WTYPE_SLOOP 2
  648.  
  649. /* all waves ... */
  650. struct wave wave[]={
  651.   {  WTYPE_LOOP, 5, 120, 50,    -1,    -1, 30, SPR_BALL, 3 },
  652.   { WTYPE_SLOOP, 5,  30, 25,    -1,    -1, 30, SPR_BALL, 3 },
  653.   {          -1, 0,   0,  0,     0,     0,  0,        0, 0 }
  654. };
  655.  
  656. int wave_state;  /* state of current wave */
  657. int wave_wait, wave_type;
  658. int wave_bits;
  659.   
  660. int wave_rad2;
  661. struct wave wave_cur;
  662.  
  663. void init_wave(int type, int wait) {
  664.   int r;
  665.  
  666.   if(wave[type].mode == -1) type = 0;
  667.  
  668.   /* waiting for next wave */
  669.   wave_type = type;
  670.  
  671.   wave_wait  = wait;
  672.   wave_state = 0;
  673.   MemMove(&wave_cur, &wave[type], sizeof(struct wave));
  674.   wave_bits  = 0xffff>>(16-wave_cur.len);  // all enemies alive 
  675.  
  676.   /* init some constants */
  677.   switch(wave_cur.mode) {
  678.   case WTYPE_LOOP:
  679.   case WTYPE_SLOOP:
  680.     r = SysRandom(0);
  681.     if(wave_cur.rev  == -1) wave_cur.rev  = r&1;
  682.     if(wave_cur.flip == -1) wave_cur.flip = r&2;
  683.     
  684.     wave_rad2 = PI2 * wave_cur.rad;
  685.     break;
  686.   }
  687. }
  688.  
  689. void handle_wave(int sx, int sy) {
  690.   int x, y, l, enemy, epos, i, bomb_r, bomb_e;
  691.  
  692.   if(wave_wait == 0) {
  693.  
  694.     /* bomb randomizer */
  695.     bomb_r = SysRandom(0);
  696.     bomb_e = bomb_r%wave_cur.len;   // enemy to drop bomb
  697.     bomb_r >>= 4;                   // remaining random value
  698.     
  699.     /* draw all enemies */
  700.     for(enemy=0;enemy<wave_cur.len;enemy++) {
  701.  
  702.       /* enemy still alive?? */
  703.       if(wave_bits & (1<<enemy)) {
  704.  
  705.     epos = wave_state - (enemy * wave_cur.dist);
  706.     
  707.     x = y = 0;   /* default position (invisible) */
  708.     
  709.     switch(wave_cur.mode) {
  710.  
  711.       /* here is the quite ugly wave form calculation stuff */
  712.       
  713.       /* loop wave */
  714.     case WTYPE_LOOP:
  715.       /* reverse flight */
  716.       if(wave_cur.rev)  epos = (CENTER2 + wave_rad2) - epos;
  717.       
  718.       if((epos>0)&&(epos<CENTER)) {
  719.         /* flight to the center */
  720.         x = epos;
  721.         y = wave_cur.y;
  722.       } else if((epos >= CENTER)&&(epos < (CENTER + wave_rad2))) {
  723.         /* full circle */
  724.         l = (((long)epos - CENTER) * 256)/(wave_rad2);
  725.         x = CENTER + (VideoSin[l] * wave_cur.rad) / 128;
  726.         y = wave_cur.y - wave_cur.rad + 
  727.           (VideoCos[l] * wave_cur.rad) / 128;
  728.       } else if((epos >= (CENTER  + wave_rad2))&&
  729.             (epos <  (CENTER2 + wave_rad2))) {
  730.         /* leave from center */
  731.         x = epos - wave_rad2;
  732.         y = wave_cur.y;
  733.       }
  734.       
  735.       /* flip */
  736.       if((x!=0)&&(wave_cur.flip)) x = 176 - x;
  737. //      if((y!=0)&&(wave_cur.flip)) y = ((wave_cur.y - wave_cur.rad)<<1) - y;
  738.       
  739.       break;
  740.       
  741.       /* s wave */
  742.     case WTYPE_SLOOP:
  743.       /* reverse flight */
  744.       if(wave_cur.rev)  epos = (CENTER2 + wave_rad2) - epos;
  745.       
  746.       if((epos>0)&&(epos<CENTER)) {
  747.         /* enter screen and fly to the middle */
  748.         x = epos;
  749.         y = wave_cur.y;
  750.       } else if((epos >= CENTER)&&(epos < (CENTER + (wave_rad2/2)))) {
  751.         /* half circle */
  752.         l = (((long)epos - CENTER) * 256)/(wave_rad2);
  753.         x = CENTER + (VideoSin[l] * wave_cur.rad) / 128;
  754.         y = wave_cur.y + wave_cur.rad - 
  755.           (VideoCos[l] * wave_cur.rad) / 128;
  756.       } else if((epos >= CENTER+(wave_rad2/2))&&
  757.             (epos < (CENTER + wave_rad2))) {
  758.         /* another half circle */
  759.         l = (((long)epos - CENTER - (wave_rad2/2)) * 256)/(wave_rad2);
  760.         x = CENTER - (VideoSin[l] * wave_cur.rad) / 128;
  761.         y = wave_cur.y + 3*wave_cur.rad - 
  762.           (VideoCos[l] * wave_cur.rad) / 128;
  763.       } else if((epos >= (CENTER  + wave_rad2))&&
  764.             (epos <  (CENTER2 + wave_rad2))) {
  765.         /* leave screen */
  766.         x = epos - wave_rad2;
  767.         y = wave_cur.y + 4*wave_cur.rad;
  768.       }
  769.  
  770.       /* flip */
  771.       if((x!=0)&&(wave_cur.flip)) x = 176 - x;
  772.       
  773.       break;
  774.     }
  775.     
  776.     /* draw alien */
  777.     VideoDrawSprite(x, y, wave_cur.sprite);
  778.  
  779.     if(sub_state == 0) {
  780.       /* did alien collide with our ship? */
  781.       if(VideoSpriteCollide(x, y, wave_cur.sprite,
  782.                 sx, sy, SPR_SHIP)) {
  783.  
  784.         /* get score, anyway */
  785.         score_inc(SCORE_ALIEN);
  786.         
  787.         /* draw explosion */
  788.         new_exp(x, y);
  789.         
  790.         /* remove alien */
  791.         wave_bits &= ~(1<<enemy);
  792.         
  793.         /* add damage to ship */
  794.         damage(DAMAGE_ALIEN);
  795.         
  796.         /* whole wave removed? */
  797.         if(wave_bits == 0)
  798.           new_extra(x, y, SPR_SCORE10);
  799.       }
  800.     }
  801.  
  802.     /* is this enemy to drop a bomb? */
  803.     if((bomb_e == enemy)&&((bomb_r % bomb_freq) == 1))
  804.       new_bomb(x, y);
  805.     
  806.     /* check if enemy is hit */
  807.     for(i=0;i<MAX_SHOTS;i++) {
  808.       if(shot[i].y >= 0) {
  809.         if(VideoSpriteCollide(x, y, wave_cur.sprite, 
  810.                   shot[i].x, shot[i].y, shot[i].spr)) {
  811.  
  812.           /* yupp, we got em */
  813.           score_inc(SCORE_ALIEN);
  814.           new_exp(x, y);
  815.  
  816.           shot[i].y = -1;  /* remove shot */
  817.           wave_bits &= ~(1<<enemy);
  818.  
  819.           /* whole wave removed */
  820.           if(wave_bits == 0)
  821.         new_extra(x, y, SPR_SCORE10);
  822.         }        
  823.       }
  824.     }
  825.       }
  826.     }
  827.  
  828.     if(wave_state >= (CENTER2 + wave_rad2 + (wave_cur.len-1) * wave_cur.dist))
  829.       wave_wait = WAVE_PAUSE;
  830.  
  831.     wave_state += wave_cur.speed;
  832.   } else {
  833.     /* still in wait state */
  834.     wave_wait--;
  835.  
  836.     /* next wave is coming ... */
  837.     if(wave_wait == 0) {
  838.       init_wave(wave_type+1, 0);
  839.     }
  840.   }
  841. }
  842.  
  843. #define OFFSET 65
  844. void draw_Argon(int y) {
  845.   VideoDrawSprite(OFFSET+0,  y,   SPR_A);
  846.   VideoDrawSprite(OFFSET+13, y,   SPR_r);
  847.   VideoDrawSprite(OFFSET+21, y+4, SPR_g);
  848.   VideoDrawSprite(OFFSET+33, y,   SPR_o);
  849.   VideoDrawSprite(OFFSET+45, y,   SPR_n);
  850.   VideoDrawSprite(OFFSET+60, y,   SPR_V);
  851. }  
  852.  
  853. /************************************************************/
  854. /* main title animation routine                             */
  855. void main_title(void) {
  856.   unsigned int i;
  857.   DWord hardKeyState;
  858.   char str[6];
  859.  
  860.   /* draw scrolling background */
  861.   VideoDrawTitleBg();
  862.  
  863.   /* draw messages */
  864.   switch(game_state) {
  865.  
  866.     /* first title page */
  867.   case STATE_TITLE:
  868.     if(sub_state<28)
  869.       draw_Argon(sub_state);
  870.     else {
  871.       draw_Argon(28);
  872.       
  873.       /*                                         ------------------ */
  874.       if(sub_state>40)    VideoDrawText(5,50,       "Version 1.0");
  875.       if(sub_state>60) {  VideoDrawText(5,70,       "\011 1999-2000");
  876.                           VideoDrawText(3,80,    "by Till Harbaum"); }
  877.       if(sub_state>80) {  VideoDrawText(2,100,   "www.cs.tu-bs.de/");
  878.                           VideoDrawText(3,110,    "~harbaum/pilot"); }
  879.       if(sub_state>100)   VideoDrawText(1,130,  "T.Harbaum@tu-bs.de");
  880.       /*                                         ------------------ */
  881.     }
  882.     break;
  883.     
  884.   case STATE_HISCORE:
  885.     /*                                           ------------------ */
  886.                           VideoDrawText(5,40,       "High Scores");
  887.                           VideoDrawText(5,42,       "___________");
  888.  
  889.     for(i=0;i<MAX_SCORES;i++) {
  890.       if(sub_state>(20+20*i)) {
  891.     StrIToA(str, (long)prefs.score[i].value);
  892.     VideoDrawText(2,60+12*i, prefs.score[i].name);
  893.     VideoDrawText(18-StrLen(str),60+12*i, str);
  894.       }
  895.       /*                                         ------------------ */
  896.     }
  897.     break;
  898.     
  899.   case STATE_HELP:
  900.     /*                                         ------------------ */
  901.                         VideoDrawText(4,40,      "We Want You!");
  902.                         VideoDrawText(3,42,     "______________");
  903.     if(sub_state>20)    VideoDrawText(2,60,    "ArgonV is a work");
  904.     if(sub_state>40)    VideoDrawText(2,70,    "in progress. If");
  905.     if(sub_state>60)    VideoDrawText(2,80,    "you want to par-");
  906.     if(sub_state>80)    VideoDrawText(2,90,    "ticipate in this");
  907.     if(sub_state>100)   VideoDrawText(2,100,   "project, read the");
  908.     if(sub_state>120)   VideoDrawText(2,110,   "file 'readme.txt'");
  909.     if(sub_state>140)   VideoDrawText(2,120,   "that came with");
  910.     if(sub_state>160)   VideoDrawText(2,130,   "this archive.");
  911.     /*                                         ------------------ */
  912.     break;
  913.   }
  914.   
  915.   /* message printed on all pages */
  916.   VideoDrawText(1,160, "Press key to start");
  917.  
  918.   /* animate titles */
  919.   if(++sub_state == 300) {
  920.     sub_state = 0;
  921.     
  922.     if(++game_state == STATE_WRAP)
  923.       game_state = STATE_TITLE;
  924.   }
  925.   
  926.   hardKeyState = KeyCurrentState() & 
  927.     (keyBitPageUp | keyBitPageDown | 
  928.      keyBitHard1  | keyBitHard2 | 
  929.      keyBitHard3  | keyBitHard4);
  930.   
  931.   /* is currently a key pressed? */
  932.   if((hardKeyState != 0) &&
  933.      ((hardKeyState & last_state) != hardKeyState)) {
  934.  
  935.     /* initialize level */
  936.     VideoInitLevel();
  937.     
  938.     /* start game engine */
  939.     game_state = STATE_RUNNING;
  940.     sub_state  = 0;
  941.     
  942.     /* init game parameteters */
  943.     ship_x_pos = CENTER;
  944.     ship_y_pos = SHIP_START_Y;
  945.     scroll_y   = 0;
  946.  
  947.     ship_save_position();
  948.  
  949.     /* clear score */
  950.     score = 0;
  951.     
  952.     /* re-init game elements */
  953.     init_shot();
  954.     init_exp();
  955.     init_bomb();
  956.     init_wave(0, WAVE_INIT);
  957.     init_extra();
  958.     init_message();
  959.     
  960.     /* recharge shields/lifes */
  961.     lifes   = MAX_LIFES;
  962.     damage(DAMAGE_RELOAD);
  963.   }
  964.   
  965.   /* save last keystate */
  966.   last_state = hardKeyState;
  967. }
  968.  
  969. /////////////////////////
  970. // EventLoop
  971. /////////////////////////
  972.  
  973. static void EventLoop(void) {
  974.   EventType event;
  975.   Word      error;
  976.   DWord hardKeyState;
  977.   int new_x, new_y, i;
  978.  
  979.   do {
  980.     EvtGetEvent(&event, 1);
  981.     if (SysHandleEvent(&event))
  982.       continue;
  983.  
  984.     FrmDispatchEvent(&event);
  985.  
  986.     /* currently running a game? */
  987.     if(game_state == STATE_RUNNING) {
  988.  
  989.       hardKeyState = KeyCurrentState();
  990.  
  991.       /* draw background (both layers) */
  992.       VideoDrawBackground(scroll_y++);
  993.  
  994.       /* ship isn't exploding */
  995.       if(sub_state == 0) {
  996.     /* push ship if hit by background */
  997.     if(VideoSpriteBgCollide(scroll_y, ship_x_pos, ship_y_pos, SPR_SHIP)) {
  998.       damage(DAMAGE_WALL);  /* some little damage to the ship */
  999.  
  1000.       /* push it */
  1001.       ship_y_pos += 2;
  1002.       
  1003.       /* ship pushed out of the screen */
  1004.       if(ship_y_pos > 160) {
  1005.         damage(DAMAGE_DESTROY);  /* destroy ship */
  1006.         
  1007.         /* xxxx */
  1008.         ship_y_pos = SHIP_START_Y; /* restore demo position */
  1009.       }
  1010.     }
  1011.     
  1012.     new_x = ship_x_pos;
  1013.     new_y = ship_y_pos;
  1014.     
  1015.     /* hard keys */
  1016.     if((hardKeyState & keyBitPageUp)   != 0) new_y -= 2;
  1017.     if((hardKeyState & keyBitPageDown) != 0) new_y += 2;
  1018.  
  1019.     if((hardKeyState & keyBitHard3)    != 0) new_x -= 2;
  1020.     if((hardKeyState & keyBitHard4)    != 0) new_x += 2;
  1021.     
  1022.     /* limit movement to screen area */
  1023.     if(new_x < 16)  new_x = 16;
  1024.     if(new_x > 160) new_x = 160;
  1025.     if(new_y < 16)  new_y = 16;
  1026.     if(new_y > 160) new_y = 160;
  1027.     
  1028.     if((new_x != ship_x_pos)||(new_y != ship_y_pos)) {
  1029.       if(VideoSpriteBgCollide(scroll_y, new_x, new_y, SPR_SHIP)) {
  1030.         /* we hit the wall */
  1031.         damage(DAMAGE_WALL);
  1032.         
  1033.         /* let's try a small step */
  1034.         new_x = (new_x + ship_x_pos)/2;
  1035.         new_y = (new_y + ship_y_pos)/2;
  1036.         
  1037.         if(!VideoSpriteBgCollide(scroll_y, new_x, new_y, SPR_SHIP)) {
  1038.           /* accept new ship position */
  1039.           ship_x_pos = new_x;
  1040.           ship_y_pos = new_y;
  1041.         }
  1042.       } else {
  1043.         /* ok, accept new ship position */
  1044.         ship_x_pos = new_x;
  1045.         ship_y_pos = new_y;
  1046.       }
  1047.     }
  1048.     
  1049.     /* finally draw ship */
  1050.     VideoDrawSprite(ship_x_pos, ship_y_pos, SPR_SHIP);
  1051.       } else {
  1052.  
  1053.     /* ship is currently exploding */
  1054.     if(sub_state>1) {
  1055.  
  1056.       if(sub_state>SHIP_EXPLODE_TIMER) {
  1057.  
  1058.         /* ship is currently exploding */
  1059.         VideoDrawSprite(ship_x_pos, ship_y_pos, 
  1060.                 SPR_EXP_L - (sub_state - SHIP_EXPLODE_TIMER)/2);
  1061.       } else {
  1062.         #define MSG_Y  140
  1063.  
  1064.         if(sub_state>SHIP_EXPLODE_TIMER-(MAX_Y-MSG_Y))
  1065.           i = MSG_Y+(sub_state-(SHIP_EXPLODE_TIMER-(MAX_Y-MSG_Y)));
  1066.         else
  1067.           i = MSG_Y;
  1068.  
  1069.         if(lifes==0) VideoDrawText(5,i,"GAME OVER!");
  1070.       }
  1071.  
  1072.       sub_state--;
  1073.     } else 
  1074.       {
  1075.       /* ship explosion finished, show title */
  1076.  
  1077.       /* still lifes left? */
  1078.       if(lifes==0) {
  1079.         /* new hi score? */
  1080.         if(score > prefs.score[MAX_SCORES-1].value) {
  1081.           init_name_input();
  1082.           game_state  = STATE_NAME;
  1083.         } else
  1084.           game_state  = STATE_TITLE;
  1085.  
  1086.         sub_state   = 0;
  1087.       } else {
  1088.  
  1089.         /* explosion finished and still lifes left */
  1090.  
  1091.         /* reinitialize ship */
  1092.         init_shot();
  1093.         init_exp();
  1094.         init_bomb();
  1095.         init_wave(0, WAVE_INIT);
  1096.         init_extra();
  1097.  
  1098.         /* restart ... */
  1099.         new_message("GET READY");
  1100.         sub_state = 0;
  1101.  
  1102.         /* reload damage indicator */
  1103.         damage(DAMAGE_RELOAD);
  1104.  
  1105.         /* restore last saved ship position */
  1106.         ship_restore_position();
  1107.       }
  1108.     }
  1109.       }
  1110.  
  1111.       /* process different game objects */
  1112.       handle_shot(hardKeyState & keyBitHard1, 
  1113.           shot_mode, ship_x_pos, ship_y_pos);
  1114.  
  1115.       handle_exp();
  1116.       handle_bomb(ship_x_pos, ship_y_pos);
  1117.       handle_wave(ship_x_pos, ship_y_pos);
  1118.       handle_extra();
  1119.       handle_message();
  1120.  
  1121.       /* finally update screen */
  1122.       VideoDrawText(0, 16, score_str);
  1123.     } else if(game_state == STATE_NAME) {
  1124.       /* user is currently entering a name */
  1125.       main_name_input();
  1126.     } else {
  1127.       /* title/hiscore etc are currently shown */
  1128.       main_title();
  1129.     }
  1130.     VideoFlip();
  1131.   }
  1132.   while (event.eType != appStopEvent);
  1133. }
  1134.  
  1135. /************************************************************/
  1136. /** global init and cleanup                                 */
  1137. static Boolean StartApplication(void) {
  1138.  
  1139.   if(!VideoGreyscaleOn()) return false;
  1140.  
  1141.   /* Mask hardware keys */
  1142.   KeySetMask(~(keyBitPageUp | keyBitPageDown | 
  1143.            keyBitHard1  | keyBitHard2 | 
  1144.            keyBitHard3  | keyBitHard4 ));
  1145.  
  1146.   SysRandom(TimGetTicks());
  1147.  
  1148.   get_preferences();
  1149.  
  1150.   return true;
  1151. }
  1152.  
  1153. static void StopApplication(void) {
  1154.   save_preferences();
  1155.  
  1156.   VideoGreyscaleOff();
  1157. }
  1158.  
  1159. /////////////////////////
  1160. // PilotMain
  1161. /////////////////////////
  1162.  
  1163. DWord PilotMain(Word cmd, Ptr cmdBPB, Word launchFlags) {
  1164.   if (cmd == sysAppLaunchCmdNormalLaunch) {
  1165.     if(StartApplication()) {
  1166.       EventLoop();
  1167.       StopApplication();
  1168.     }
  1169.   }
  1170.   return(0);
  1171. }
  1172.