home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / spy.vs.bob / svs.c < prev   
Encoding:
C/C++ Source or Header  |  1995-05-03  |  25.0 KB  |  1,032 lines

  1. /*
  2.  * Spy vs "Bob"
  3.  *
  4.  * Based on the Apple ][ game "Spy vs Spy", and 'dodger' by Bert Nelson
  5.  */
  6.  
  7. /*
  8.  * Copyright 1992 David Lemke and Network Computing Devices
  9.  *
  10.  * Permission to use, copy, modify, distribute, and sell this software and its
  11.  * documentation for any purpose is hereby granted without fee, provided that
  12.  * the above copyright notice appear in all copies and that both that
  13.  * copyright notice and this permission notice appear in supporting
  14.  * documentation, and that the name of Network Computing Devices not be
  15.  * used in advertising or publicity pertaining to distribution of the
  16.  * software without specific, written prior permission.  Network Computing
  17.  * Devices makes no representations about the suitability of this software
  18.  * for any purpose.  It is provided "as is" without express or implied
  19.  * warranty.
  20.  *
  21.  * NETWORK COMPUTING DEVICES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
  22.  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  23.  * IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE FOR ANY SPECIAL,
  24.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  25.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  26.  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  27.  * OR PERFORMANCE OF THIS SOFTWARE.
  28.  *
  29.  * Author:
  30.  *        Dave Lemke
  31.  *        lemke@ncd.com
  32.  *
  33.  *        Network Computing Devices, Inc
  34.  *        350 North Bernardo Ave
  35.  *        Mountain View, CA 94043
  36.  *
  37.  *    @(#)svs.c    1.9    92/02/10
  38.  *
  39.  */
  40.  
  41. #include    <stdio.h>
  42. #include    <X11/Xos.h>
  43. #include     <sys/types.h>
  44. //#include     <sys/time.h>
  45. #include    <errno.h>
  46. #include    <X11/Xlib.h>
  47. #include    <X11/Xutil.h>
  48. #include    <math.h>
  49.  
  50. extern char *getenv();
  51.  
  52. extern int  errno;
  53. char       *progname;
  54. char        user_name[40];
  55. Bool        debug = False;
  56.  
  57. #define    rnd(x)    (random() % (x))
  58.  
  59. /* game stuff */
  60. //#define    NUM_LEDGES        10
  61. #define    NUM_LEDGES        6
  62. #define    NUM_VATORS        4
  63.  
  64. #define    MIN_LEDGE        3    /* tightest it will get */
  65.  
  66. #define    NUM_LIVES        5
  67. #define    START_LEDGE        (NUM_LEDGES - 1)
  68. #define    START_TIME        100
  69. #define    DELAY_TIME        20000
  70. #define    ROUNDS_PER_UPDATE    8
  71.  
  72. #define    GIFT_SCORE        500
  73. #define    GIFT_NOTYET        1
  74. #define    GIFT_OUT        2
  75. #define    GIFT_TAKEN        3
  76.  
  77.  
  78. extern void update_scores();
  79. extern void show_scores();
  80.  
  81. int         score = 0;
  82. int         highscore = 0;
  83. int         time_left;
  84. int         time_interval = ROUNDS_PER_UPDATE;
  85. int         lives = 0;
  86. int         ledge_num;
  87. int         ledge_side;
  88. int         level;
  89. int        ledge;
  90. int         vator_loc[NUM_VATORS];
  91. int         vator_speed[NUM_VATORS];
  92. int         vator_run;
  93. int         man_x,
  94.             man_y;
  95. int         man_speed;
  96. int         man_delta;
  97.  
  98. int         gift_x,
  99.             gift_y;
  100. int         gift_state;
  101. Bool        refresh_gift;
  102. int         gift_time;
  103.  
  104. /* increase with each level */
  105. double      level_factor = 1.0;
  106.  
  107. /* speeds */
  108. #define    MIN_VATOR_SPEED        5
  109. #define    VATOR_SPEED_RANGE    10
  110.  
  111. #ifdef fast
  112. #define    LEVEL_INCREASE        (0.2)
  113. #else
  114. #define    LEVEL_INCREASE        (0.0)
  115. #endif
  116.  
  117. /* X stuff */
  118.  
  119. Display    *dpy;
  120. Window      game_win;
  121. Colormap    cmap;
  122. GC          text_gc;
  123. GC          vator_gc;
  124. GC          draw_gc;
  125. unsigned long man_color,
  126.             vator_color,
  127.             vator_bg_color,
  128.             timer_color,
  129.             gift_color,
  130.             splat_color,
  131.             ledge_color;
  132. unsigned long text_color;
  133. unsigned long bg_color;
  134. Bool        paused = False;
  135. Pixmap      man_left,
  136.             man_right,
  137.             man_stand,
  138.             splat_map,
  139.             slack_map,
  140.             vator_map;
  141.  
  142. #define    MAN        0
  143. #define    VATOR        1
  144. #define    TIMER        2
  145. #define    LEDGE        3
  146. #define    TEXT        4
  147. #define    BACKGROUND    5
  148. #define    GIFT        6
  149. #define    VATOR_BG    7
  150. #define    SPLAT        8
  151.  
  152. static char *game_colors[] = {
  153.     "pink",            /* MAN */
  154.     "blue",            /* VATOR */
  155.     "yellow",            /* TIMER */
  156.     "brown",            /* LEDGE */
  157.     "white",            /* TEXT */
  158.     "black",            /* BACKGROUND */
  159.     "green",            /* GIFT */
  160.     "white",            /* VATOR_BG */
  161.     "pink",            /* SPLAT */
  162. };
  163.  
  164.  
  165. static char bob_vator_bits[] = {
  166.     0xff, 0x01, 0x50, 0x25, 0x00, 0xfe, 0x03, 0x07, 0x00, 0xfc, 0xff, 0x03,
  167.     0x80, 0x03, 0x03, 0x00, 0xff, 0x5e, 0x06, 0x00, 0x03, 0x03, 0xc0, 0x97,
  168.     0x44, 0x0a, 0x00, 0x03, 0x03, 0xc0, 0x17, 0xa9, 0x1d, 0x00, 0x03, 0x03,
  169.     0xe0, 0x7f, 0xdd, 0x7f, 0x00, 0x03, 0x03, 0xf0, 0xff, 0xff, 0xf3, 0x00,
  170.     0x03, 0x03, 0xf0, 0xff, 0xdf, 0xf0, 0x00, 0x03, 0x03, 0xf0, 0xa5, 0x17,
  171.     0xf0, 0x01, 0x03, 0x03, 0xf0, 0x00, 0x00, 0xf0, 0x00, 0x03, 0x03, 0xf8,
  172.     0x00, 0x00, 0xe8, 0x00, 0x03, 0x03, 0xf0, 0x01, 0x00, 0xe8, 0x00, 0x03,
  173.     0x03, 0xf0, 0x00, 0x00, 0xe4, 0x00, 0x03, 0x03, 0xf8, 0x00, 0x00, 0xe8,
  174.     0x00, 0x03, 0x03, 0xf0, 0x09, 0x80, 0xfb, 0x00, 0x03, 0x03, 0xe8, 0x3e,
  175.     0xe0, 0xee, 0x00, 0x03, 0x03, 0xf8, 0x68, 0x70, 0xfd, 0x00, 0x03, 0x03,
  176.     0x30, 0xee, 0x78, 0xe3, 0x00, 0x03, 0x03, 0x30, 0xf2, 0xa8, 0x60, 0x00,
  177.     0x03, 0x03, 0x30, 0xb4, 0xc0, 0x63, 0x00, 0x03, 0x03, 0x30, 0x98, 0x00,
  178.     0x40, 0x00, 0x03, 0x03, 0x20, 0x80, 0x00, 0xa0, 0x00, 0x03, 0x03, 0xb0,
  179.     0x40, 0x00, 0x60, 0x00, 0x03, 0x03, 0x80, 0xd1, 0x70, 0x18, 0x00, 0x03,
  180.     0x03, 0xc0, 0xe9, 0x8e, 0x0d, 0x00, 0x03, 0x03, 0x80, 0xf7, 0x87, 0x3f,
  181.     0x00, 0x03, 0x03, 0x80, 0xfa, 0xea, 0x0c, 0x00, 0x03, 0x03, 0x80, 0x32,
  182.     0x49, 0x0c, 0x00, 0x03, 0x03, 0x00, 0x35, 0x35, 0x0c, 0x00, 0x03, 0x03,
  183.     0x00, 0xf1, 0x0f, 0x06, 0x00, 0x03, 0x03, 0x00, 0xf6, 0x15, 0x02, 0x00,
  184.     0x03, 0x03, 0x10, 0xda, 0x0b, 0x03, 0x00, 0x03, 0x03, 0x48, 0x4e, 0x00,
  185.     0x01, 0x00, 0x03, 0x03, 0x58, 0x77, 0x80, 0x00, 0x00, 0x03, 0x03, 0xe2,
  186.     0xf3, 0xc0, 0x00, 0x00, 0x03, 0x03, 0xcc, 0x41, 0x3f, 0x00, 0x00, 0x03,
  187.     0x03, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0xdc, 0x00, 0x00, 0x00,
  188.     0x00, 0x03, 0x07, 0x70, 0x00, 0x00, 0x00, 0x80, 0x03, 0xff, 0x01, 0x00,
  189. 0x00, 0x00, 0xfe, 0x03};
  190.  
  191. static char man_left_bits[] = {
  192.     0x18, 0x01, 0x00, 0xf8, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfe, 0x00, 0x00,
  193.     0xfc, 0x01, 0x00, 0xfa, 0x03, 0x00, 0xf1, 0xff, 0x01, 0x20, 0xff, 0x01,
  194.     0x84, 0x1f, 0x01, 0x86, 0x3f, 0x01, 0xce, 0xff, 0x01, 0x78, 0xff, 0x03,
  195.     0x20, 0xff, 0x01, 0x00, 0xff, 0x00, 0x80, 0x7f, 0x04, 0xc0, 0xfe, 0x0e,
  196. 0xc0, 0x9c, 0x0b, 0x80, 0x09, 0x09, 0x00, 0x03, 0x00, 0xc0, 0x01, 0x00};
  197.  
  198. static char man_right_bits[] = {
  199.     0x00, 0x88, 0x01, 0x00, 0xf0, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xf0, 0x07,
  200.     0x00, 0xf8, 0x03, 0x00, 0xfc, 0x05, 0xf8, 0xff, 0x08, 0xf8, 0x4f, 0x00,
  201.     0x88, 0x1f, 0x02, 0xc8, 0x1f, 0x06, 0xf8, 0x3f, 0x07, 0xfc, 0xef, 0x01,
  202.     0xf8, 0x4f, 0x00, 0xf0, 0x0f, 0x00, 0xe2, 0x1f, 0x00, 0xf7, 0x37, 0x00,
  203. 0x9d, 0x33, 0x00, 0x09, 0x19, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x38, 0x00};
  204.  
  205. static char man_stand_bits[] = {
  206.     0x80, 0x03, 0x00, 0xc0, 0x07, 0x00, 0xf0, 0x1f, 0x00, 0xc0, 0x07, 0x00,
  207.     0x80, 0x03, 0x00, 0x00, 0x01, 0x00, 0x80, 0x03, 0x00, 0xf0, 0x0f, 0x00,
  208.     0xfc, 0x1f, 0x00, 0xfe, 0xbf, 0x0f, 0xf3, 0x7f, 0x01, 0xf3, 0xff, 0x01,
  209.     0xfe, 0x1f, 0x01, 0xfc, 0x1f, 0x00, 0xf8, 0x3f, 0x00, 0xf0, 0x3f, 0x00,
  210. 0xf0, 0x7f, 0x00, 0xc0, 0x0c, 0x00, 0xc0, 0x0c, 0x00, 0xf0, 0x3c, 0x00};
  211.  
  212.  
  213. static char slack_bits[] = {
  214. 0xeb, 0x56, 0xa9, 0x32, 0xeb, 0x32, 0xaa, 0x52, 0xbb, 0x56};
  215.  
  216. static char splatter_bits[] = {
  217.     0x68, 0x20, 0x02, 0x00, 0x2b, 0x49, 0x31, 0x1e, 0x3e, 0x92, 0x88, 0x11,
  218.     0x26, 0x22, 0x45, 0x1e, 0x6e, 0xec, 0xe3, 0x07, 0xf8, 0xff, 0xff, 0x00,
  219.     0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  220. 0x00, 0x00, 0x00, 0x00};
  221.  
  222. #define    MAN_WIDTH    20
  223. #define    MAN_HEIGHT    20
  224. #define    MAN_DELTA    6    /* motion per step */
  225. #define    MIN_MAN_DELTA    4
  226.  
  227. #define SPLAT_WIDTH    30
  228. #define SPLAT_HEIGHT    10
  229.  
  230. #define    VATOR_WIDTH    50
  231. #define    VATOR_HEIGHT    40
  232. #define    VATOR_GAP    40    /* space between them */
  233.  
  234. #define    GIFT_WIDTH    15
  235. #define    GIFT_HEIGHT    5
  236.  
  237. #define    LEDGE_WIDTH    30
  238. #define    LEDGE_HEIGHT    4
  239.  
  240. #define    LEDGE_GAP    ((int)(VATOR_HEIGHT * 1.2 + LEDGE_HEIGHT))
  241.  
  242. #define    TIMER_HEIGHT    25
  243. #define    TIMER_SLICE    1    /* visual size of each tick */
  244.  
  245. #define    INFO_HEIGHT    100    /* size of timer, score, etc */
  246.  
  247. #define    DELIM_HEIGHT    10    /* bar between game and info */
  248.  
  249. #define    WIN_WIDTH    (NUM_VATORS * VATOR_WIDTH + (NUM_VATORS - 1) * VATOR_GAP + 2 * LEDGE_WIDTH)
  250. #define    WIN_HEIGHT    (NUM_LEDGES * LEDGE_GAP + INFO_HEIGHT + DELIM_HEIGHT)
  251.  
  252. /* range of y locs for elevators */
  253. #define    VATOR_RUN    (WIN_HEIGHT - (INFO_HEIGHT + DELIM_HEIGHT) - VATOR_HEIGHT)
  254.  
  255. /* range of man */
  256. #define    MAN_MAX_X    (WIN_WIDTH - MAN_DELTA - MAN_WIDTH)
  257.  
  258. #define    TIMER_Y        (WIN_HEIGHT - ((INFO_HEIGHT * 2) / 3))
  259. #define    EXTRA_MAN_X    (WIN_WIDTH - 2 * MAN_WIDTH)
  260. #define    STATUS_Y    (TIMER_Y + 15)
  261. #define    STATUS_X    (2 * TIMER_SLICE)
  262.  
  263. #define    FONTNAME    "fixed"
  264.  
  265. #define    COLLISION_FUDGE    4
  266.  
  267. #define    vator_pos(i) (LEDGE_WIDTH + (i) * (VATOR_GAP + VATOR_WIDTH))
  268. #define    man_start_pos(i)    (MAN_DELTA + (i) * (WIN_WIDTH - MAN_WIDTH - (2 * MAN_DELTA)))
  269. #define    man_y_pos(l)    ((LEDGE_GAP * ((l) + 1)) - (LEDGE_HEIGHT + MAN_HEIGHT))
  270.  
  271. #define    min(a, b)    (((a) < (b)) ? (a) : (b))
  272. #define    max(a, b)    (((a) > (b)) ? (a) : (b))
  273.  
  274. static void wait_for_start();
  275. static void run();
  276. static void finish_up();
  277.  
  278. static void draw_ledges();
  279. static void draw_init_screen();
  280. static void draw_scores();
  281. static void draw_obj();
  282. static void draw_timer();
  283. static void draw_status();
  284. static void draw_message();
  285. static void draw_message2();
  286. static void erase_obj();
  287. static void new_man();
  288. static void new_gift();
  289. static void flush_keyboard();
  290.  
  291. static void
  292. usage()
  293. {
  294.     fprintf(stderr, "Usage: %s [-display displayname]\n", progname);
  295.     exit(0);
  296. }
  297.  
  298. static unsigned long
  299. get_color(cname)
  300.     char       *cname;
  301. {
  302.     XColor      col;
  303.  
  304.     XParseColor(dpy, cmap, cname, &col);
  305.     XAllocColor(dpy, cmap, &col);
  306.     return col.pixel;
  307. }
  308.  
  309. static void
  310. init_display(ac, av, dname)
  311.     int         ac;
  312.     char      **av;
  313.     char       *dname;
  314. {
  315.     Bool        is_color = False;
  316.     int         screen;
  317.     unsigned long wmask,
  318.                 gcmask;
  319.     XSetWindowAttributes wattr;
  320.     XGCValues   gcv;
  321.     XFontStruct *pfont;
  322.     int         x,
  323.                 y;
  324.     XSizeHints  xsh;
  325.     XWMHints    wmhints;
  326.  
  327.     dpy = XOpenDisplay(dname);
  328.     if (!dpy) {
  329.     fprintf(stderr, "%s: Couldn't open display \"%s\"\n", progname, dname);
  330.     exit(-1);
  331.     }
  332.     screen = DefaultScreen(dpy);
  333.  
  334.     if (debug)
  335.     XSynchronize(dpy, 1);
  336.  
  337.     if (DisplayCells(dpy, screen) > 2)
  338.     is_color = True;
  339.     cmap = DefaultColormap(dpy, screen);
  340.  
  341.     /* set up colors */
  342.     if (is_color) {
  343.     man_color = get_color(game_colors[MAN]);
  344.     splat_color = get_color(game_colors[SPLAT]);
  345.     vator_color = get_color(game_colors[VATOR]);
  346.     vator_bg_color = get_color(game_colors[VATOR_BG]);
  347.     ledge_color = get_color(game_colors[LEDGE]);
  348.     timer_color = get_color(game_colors[TIMER]);
  349.     text_color = get_color(game_colors[TEXT]);
  350.     gift_color = get_color(game_colors[GIFT]);
  351.     bg_color = get_color(game_colors[BACKGROUND]);
  352.     } else {
  353.     man_color = WhitePixel(dpy, screen);
  354.     splat_color = WhitePixel(dpy, screen);
  355.     vator_color = BlackPixel(dpy, screen);
  356.     vator_bg_color = WhitePixel(dpy, screen);
  357.     ledge_color = WhitePixel(dpy, screen);
  358.     timer_color = WhitePixel(dpy, screen);
  359.     text_color = WhitePixel(dpy, screen);
  360.     gift_color = WhitePixel(dpy, screen);
  361.     bg_color = BlackPixel(dpy, screen);
  362.     }
  363.  
  364.     x = 100;
  365.     y = 100;
  366.  
  367.     wattr.background_pixel = bg_color;
  368.     wattr.event_mask = ExposureMask | KeyPressMask |
  369.     ButtonPressMask | ButtonReleaseMask;
  370.  
  371.     wmask = CWEventMask | CWBackPixel;
  372.  
  373.     game_win = XCreateWindow(dpy, RootWindow(dpy, screen), x, y, WIN_WIDTH,
  374.            WIN_HEIGHT, 0, CopyFromParent, CopyFromParent, CopyFromParent,
  375.                  wmask, &wattr);
  376.  
  377.     xsh.flags = PSize | PMinSize | PMaxSize;
  378.     xsh.width = xsh.min_width = xsh.max_width = WIN_WIDTH;
  379.     xsh.height = xsh.min_height = xsh.max_height = WIN_HEIGHT;
  380.     XSetStandardProperties(dpy, game_win, "Spy vs \"Bob\"", "SvB", None,
  381.                av, ac, &xsh);
  382.  
  383.     wmhints.input = True;
  384.     wmhints.flags = InputHint;
  385.     XSetWMHints(dpy, game_win, &wmhints);
  386.  
  387.     pfont = XLoadQueryFont(dpy, FONTNAME);
  388.  
  389.     gcmask = GCForeground | GCBackground;
  390.     gcv.foreground = text_color;
  391.     gcv.background = bg_color;
  392.     if (pfont) {
  393.     gcv.font = pfont->fid;
  394.     gcmask |= GCFont;
  395.     }
  396.     text_gc = XCreateGC(dpy, game_win, gcmask, &gcv);
  397.  
  398.     gcmask = GCForeground | GCBackground | GCGraphicsExposures;
  399.     gcv.foreground = man_color;
  400.     gcv.background = bg_color;
  401.     gcv.graphics_exposures = False;
  402.     draw_gc = XCreateGC(dpy, game_win, gcmask, &gcv);
  403.  
  404.     gcmask = GCForeground | GCBackground | GCGraphicsExposures;
  405.     gcv.foreground = vator_color;
  406.     gcv.background = vator_bg_color;
  407.     gcv.graphics_exposures = False;
  408.     vator_gc = XCreateGC(dpy, game_win, gcmask, &gcv);
  409.  
  410.     /* make bitmaps */
  411.     vator_map = XCreateBitmapFromData(dpy, game_win, bob_vator_bits,
  412.                       VATOR_WIDTH, VATOR_HEIGHT);
  413.     man_left = XCreateBitmapFromData(dpy, game_win, man_left_bits,
  414.                      MAN_WIDTH, MAN_HEIGHT);
  415.     man_right = XCreateBitmapFromData(dpy, game_win, man_right_bits,
  416.                       MAN_WIDTH, MAN_HEIGHT);
  417.     man_stand = XCreateBitmapFromData(dpy, game_win, man_stand_bits,
  418.                       MAN_WIDTH, MAN_HEIGHT);
  419.     slack_map = XCreateBitmapFromData(dpy, game_win, slack_bits,
  420.                       GIFT_WIDTH, GIFT_HEIGHT);
  421.     splat_map = XCreateBitmapFromData(dpy, game_win, splatter_bits,
  422.                       SPLAT_WIDTH, SPLAT_HEIGHT);
  423.  
  424.     XMapWindow(dpy, game_win);
  425. }
  426.  
  427. main(argc, argv)
  428.     int         argc;
  429.     char      **argv;
  430. {
  431.     int         i;
  432.     char       *dname = NULL;
  433.  
  434.     progname = argv[0];
  435.     for (i = 1; i < argc; i++) {
  436.     if (!strncmp(argv[i], "-d", 2)) {
  437.         if (argv[++i])
  438.         dname = argv[i];
  439.         else
  440.         usage();
  441.     }
  442.     }
  443.     strcpy(user_name, "Unknown");
  444.     if (getenv("USER"))
  445.     strcpy(user_name, getenv("USER"));
  446.     srandom(getpid());
  447.     init_display(argc, argv, dname);
  448.     update_scores();
  449.     draw_init_screen();
  450.     while (1) {
  451.     wait_for_start();
  452.     run();
  453.     finish_up();
  454.     }
  455. }
  456.  
  457. static void
  458. refresh_screen()
  459. {
  460.     int         i;
  461.  
  462.     XClearWindow(dpy, game_win);
  463.  
  464.     draw_ledges();
  465.  
  466.     /* delimiter */
  467.     XFillRectangle(dpy, game_win, text_gc, 0, WIN_HEIGHT - INFO_HEIGHT,
  468.            WIN_WIDTH, DELIM_HEIGHT);
  469.  
  470.     for (i = 0; i < NUM_VATORS; i++) {
  471.     draw_obj(vator_pos(i), vator_loc[i], VATOR);
  472.     }
  473.     draw_obj(man_x, man_y, MAN);
  474.     if (gift_state == GIFT_OUT)
  475.     draw_obj(gift_x, gift_y, GIFT);
  476.     draw_scores();
  477.     draw_message(NULL);
  478.     draw_message2(NULL);
  479. }
  480.  
  481. static void
  482. draw_init_screen()
  483. {
  484.     int         i;
  485.  
  486.     XClearWindow(dpy, game_win);
  487.  
  488.     /* place some random elevators */
  489.     for (i = 0; i < NUM_VATORS; i++) {
  490.     vator_loc[i] = rnd(VATOR_RUN);
  491.     }
  492.  
  493.     /* and the man */
  494.     man_x = man_start_pos(rnd(2));
  495.     man_y = man_y_pos(rnd(NUM_LEDGES));
  496.  
  497.     gift_state = GIFT_NOTYET;
  498.     new_gift();
  499.  
  500.     draw_message("     Spy Vs \"Bob\"     Hit 's' to Start, 'q' to Quit, 'h' for Hi Scores");
  501.     draw_message2("    Use 'j', 'k', SPACE or Mouse buttons to move, 'p' to Pause");
  502.  
  503.     refresh_screen();
  504. }
  505.  
  506. char
  507. get_key(kev)
  508.     XKeyPressedEvent *kev;
  509. {
  510.     char        buffer[10];
  511.     int         len;
  512.  
  513.     len = XLookupString(kev, buffer, 10, NULL, NULL);
  514.     if (len)
  515.     return buffer[0];
  516.     else
  517.     return (char) -1;
  518. }
  519.  
  520. /*
  521.  * draws instructions, waits for 'q' or 's'
  522.  */
  523. static void
  524. wait_for_start()
  525. {
  526.     XEvent      ev;
  527.     Bool        done = False;
  528.     char        c;
  529.  
  530.     while (!done) {
  531.     XNextEvent(dpy, &ev);
  532.     switch (ev.type) {
  533.     case Expose:
  534.         if (ev.xexpose.count == 0)
  535.         refresh_screen();
  536.         break;
  537.     case KeyPress:
  538.         c = get_key((XKeyPressedEvent *) & ev);
  539.         switch (c) {
  540.         case 'q':
  541.         exit(0);
  542.         break;
  543.         case 's':
  544.         done = True;
  545.         break;
  546.         case 'h':
  547.         show_scores();
  548.                 refresh_screen();
  549.         break;
  550.         default:
  551.         break;
  552.         }
  553.     }
  554.     }
  555.     score = 0;
  556.     draw_message("");
  557.     draw_message2("");
  558. }
  559.  
  560. static void
  561. init_vators()
  562. {
  563.     int         i;
  564.  
  565.     for (i = 0; i < NUM_VATORS; i++) {
  566.     vator_loc[i] = rnd(vator_run);
  567.     vator_speed[i] = rnd(VATOR_SPEED_RANGE) + MIN_VATOR_SPEED;
  568.     }
  569. }
  570.  
  571. static void
  572. got_across()
  573. {
  574.     if (gift_state == GIFT_OUT)
  575.     erase_obj(gift_x, gift_y, GIFT);
  576.     man_speed = 0;
  577.     ledge_num--;
  578.     score += 200 + (time_left * 5);
  579.     ledge++;
  580.     if (ledge_num < 0) {    /* finished level */
  581.     /* shrink the game board */
  582.     if (level < (START_LEDGE - MIN_LEDGE)) {
  583.         /* don't drop it to 0, in case anyone's that good */
  584.         ledge_num = START_LEDGE - level;
  585.         vator_run -= LEDGE_GAP;
  586.     } else {
  587.         ledge_num = MIN_LEDGE;
  588.     }
  589.     lives++;
  590.     ledge_side = 0;
  591.     new_man();
  592.     level_factor += LEVEL_INCREASE;
  593.     level++;
  594.     time_interval--;    /* speed it up too */
  595.     if (time_interval < 1)
  596.         time_interval = 1;
  597.     man_delta--;
  598.     if (man_delta <= MIN_MAN_DELTA)
  599.         man_delta = MIN_MAN_DELTA;
  600.     }
  601.     man_y = man_y_pos(ledge_num);
  602.     time_left = START_TIME;
  603.     gift_time = START_TIME - rnd(START_TIME / 2);
  604.     gift_state = GIFT_NOTYET;
  605.     flush_keyboard();
  606.     draw_scores();
  607. }
  608.  
  609. static void
  610. move_man()
  611. {
  612.     erase_obj(man_x, man_y, MAN);
  613.     man_x += man_speed;
  614.     if (man_x < man_start_pos(0)) {
  615.     man_x = man_start_pos(0);
  616.     if (ledge_side == 1) {    /* made it across */
  617.         ledge_side = 0;
  618.         got_across();
  619.     }
  620.     }
  621.     if (man_x > man_start_pos(1)) {
  622.     man_x = man_start_pos(1);
  623.     if (ledge_side == 0) {
  624.         ledge_side = 1;
  625.         got_across();
  626.     }
  627.     }
  628.     draw_obj(man_x, man_y, MAN);
  629. }
  630.  
  631. static void
  632. move_vators()
  633. {
  634.     int         i;
  635.  
  636.     for (i = 0; i < NUM_VATORS; i++) {
  637.     erase_obj(vator_pos(i), vator_loc[i], VATOR);
  638.     vator_loc[i] += vator_speed[i];
  639.     if (vator_loc[i] <= 0) {
  640.         vator_loc[i] = 0;
  641.         vator_speed[i] = level_factor *
  642.         (rnd(VATOR_SPEED_RANGE) + MIN_VATOR_SPEED);
  643.     } else if (vator_loc[i] >= vator_run) {
  644.         vator_loc[i] = vator_run;
  645.         vator_speed[i] = -level_factor *
  646.         (rnd(VATOR_SPEED_RANGE) + MIN_VATOR_SPEED);
  647.     }
  648.     draw_obj(vator_pos(i), vator_loc[i], VATOR);
  649.     }
  650. }
  651.  
  652. static void
  653. new_man()
  654. {
  655.     int         i;
  656.  
  657.     erase_obj(man_x, man_y, MAN);
  658.     if (gift_state == GIFT_OUT)
  659.     erase_obj(gift_x, gift_y, GIFT);
  660.     for (i = 0; i < NUM_VATORS; i++)
  661.     erase_obj(vator_pos(i), vator_loc[i], VATOR);
  662.     time_left = START_TIME;
  663.     gift_time = START_TIME - rnd(START_TIME / 2);
  664.     init_vators();
  665.     man_speed = 0;
  666.     man_x = man_start_pos(ledge_side);
  667.     man_y = man_y_pos(ledge_num);
  668.     draw_obj(man_x, man_y, MAN);
  669.     draw_status();
  670.     flush_keyboard();
  671. }
  672.  
  673. static void
  674. check_collision()
  675. {
  676.     int         i;
  677.  
  678.     for (i = 0; i < NUM_VATORS; i++) {
  679.     if (((man_x + MAN_WIDTH - COLLISION_FUDGE) > vator_pos(i)) &&
  680.         (man_x < (vator_pos(i) + VATOR_WIDTH - COLLISION_FUDGE))) {
  681.         if ((man_y > vator_loc[i]) &&
  682.             (man_y < vator_loc[i] + VATOR_HEIGHT)) {
  683.         lives--;
  684.         draw_message("SPLAT!!!");
  685.         erase_obj(man_x, man_y, MAN);
  686.         draw_obj(vator_pos(i), vator_loc[i], VATOR);
  687.         draw_obj(man_x - 5, man_y + 10, SPLAT);
  688.         XSync(dpy, 0);
  689.         sleep(1);
  690.         refresh_screen();
  691.         new_man();
  692.         return;
  693.         }
  694.     }
  695.     }
  696.  
  697.     if (gift_state == GIFT_OUT) {
  698.     if (((man_x + MAN_WIDTH) > gift_x) &&
  699.         (man_x < (gift_x + GIFT_WIDTH))) {
  700.         score += GIFT_SCORE;
  701.         gift_state = GIFT_TAKEN;
  702.         draw_scores();
  703.         return;
  704.     }
  705.     }
  706. }
  707.  
  708. static void
  709. flush_keyboard()
  710. {
  711.     XEvent      ev;
  712.  
  713.     while (XCheckTypedEvent(dpy, KeyPress, &ev));
  714.     while (XCheckTypedEvent(dpy, ButtonPress, &ev));
  715.     while (XCheckTypedEvent(dpy, ButtonRelease, &ev));
  716. }
  717.  
  718. static void
  719. new_gift()
  720. {
  721.     if (gift_state == GIFT_NOTYET) {
  722.     gift_y = man_y + GIFT_HEIGHT;
  723.     gift_x = rnd(WIN_WIDTH - 2 * LEDGE_WIDTH) + LEDGE_WIDTH;
  724.     draw_obj(gift_x, gift_y, GIFT);
  725.     gift_state = GIFT_OUT;
  726.     }
  727. }
  728.  
  729. static Bool
  730. handle_event()
  731. {
  732.     char        c = '\0';
  733.     XEvent      ev;
  734.     int         button;
  735.  
  736.     XNextEvent(dpy, &ev);
  737.     switch (ev.type) {
  738.     case KeyPress:
  739.     c = get_key((XKeyPressedEvent *) & ev);
  740.     switch (c) {
  741.     case 'q':
  742.         return False;
  743.     case 'j':
  744.         man_speed = -man_delta;
  745.         break;
  746.     case 'k':
  747.         man_speed = man_delta;
  748.         break;
  749.     case ' ':
  750.         man_speed = 0;
  751.         break;
  752.     case 'p':
  753.         paused = !paused;
  754.         draw_status();
  755.         break;
  756.     default:
  757.         break;
  758.     }
  759.     break;
  760.     case Expose:
  761.     refresh_screen();
  762.     break;
  763.     case ButtonPress:
  764.     button = ev.xbutton.button;
  765.     if (button == 1) {
  766.         man_speed = -man_delta;
  767.     } else {
  768.         man_speed = man_delta;
  769.     }
  770.     break;
  771.     case ButtonRelease:
  772.     button = ev.xbutton.button;
  773.     man_speed = 0;
  774.     break;
  775.     }
  776.     return True;
  777. }
  778.  
  779. static void
  780. init_parms()
  781. {
  782.     ledge_num = START_LEDGE;
  783.     ledge_side = 0;
  784.     level = 1;
  785.     ledge = 0;
  786.     lives = NUM_LIVES;
  787.     man_delta = MAN_DELTA;
  788.     vator_run = VATOR_RUN;
  789.     erase_obj(gift_x, gift_y, GIFT);
  790.     gift_state = GIFT_NOTYET;
  791.     level_factor = 1.0;
  792.     time_interval = ROUNDS_PER_UPDATE;
  793. }
  794.  
  795. /*
  796.  * plays the game
  797.  */
  798. static void
  799. run()
  800. {
  801.     int         time = 0;
  802.     int         ret;
  803.     int         serverfd = XConnectionNumber(dpy);
  804.     fd_set      read_fds,
  805.                 base;
  806.     struct timeval tval,
  807.                *tm;
  808.  
  809.     FD_ZERO(&base);
  810.     FD_SET(serverfd, &base);
  811.     init_parms();
  812.     new_man();
  813.  
  814.     tval.tv_sec = 0;
  815.     tval.tv_usec = DELAY_TIME;
  816.     while (1) {
  817.     if (XPending(dpy)) {
  818.         if (!handle_event())
  819.         return;
  820.         continue;
  821.     }
  822.     if (!paused)
  823.         tm = &tval;
  824.     else
  825.         tm = (struct timeval *) 0;
  826.     read_fds = base;
  827.     ret = select(serverfd + 1, &read_fds, (fd_set *) 0, (fd_set *) 0, tm);
  828.     if (ret == -1)
  829.         if (errno == EINTR)
  830.         continue;
  831.     if (ret == 1) {
  832.         if (!handle_event())
  833.         return;
  834.         continue;
  835.     }
  836.     if (paused)
  837.         continue;
  838.     if (time_left == 0) {
  839.         lives--;
  840.         draw_message("Time's Up");
  841.         XSync(dpy, 0);
  842.         sleep(1);
  843.         new_man();
  844.         time = 0;
  845.     }
  846.     if (lives == 0)
  847.         return;
  848.  
  849.     time++;
  850.     if (time >= time_interval) {
  851.         time = 0;
  852.         time_left--;
  853.         if (gift_time <= time_left) {
  854.         new_gift();
  855.         gift_time = -1;
  856.         }
  857.         draw_timer();
  858.             /* XXX this shouldn't really be necessray, but on a slow display,
  859.              * output can get queueed enough that the action gets delayed
  860.              */
  861.         XSync(dpy, 0);
  862.     }
  863.     move_vators();
  864.     move_man();
  865.     check_collision();
  866.     if (gift_state == GIFT_OUT)
  867.         draw_obj(gift_x, gift_y, GIFT);
  868.     }
  869. }
  870.  
  871. /*
  872.  * cleans up screen, shows score
  873.  */
  874. static void
  875. finish_up()
  876. {
  877.     draw_message("     Spy Vs \"Bob\"     Hit 's' to Start, 'q' to Quit, 'h' for Hi Scores");
  878.     draw_message2("    Use 'j', 'k', SPACE or Mouse buttons to move, 'p' to Pause");
  879.     add_score(score, ledge);
  880.     draw_scores();
  881.     refresh_screen();
  882. }
  883.  
  884. static void
  885. erase_obj(x, y, type)
  886.     int         x,
  887.                 y,
  888.                 type;
  889. {
  890.     switch (type) {
  891.     case VATOR:
  892.     XClearArea(dpy, game_win, x, y, VATOR_WIDTH, VATOR_HEIGHT, False);
  893.     break;
  894.     case GIFT:
  895.     XClearArea(dpy, game_win, x, y, GIFT_WIDTH, GIFT_HEIGHT, False);
  896.     break;
  897.     case MAN:
  898.     XClearArea(dpy, game_win, x, y, MAN_WIDTH, MAN_HEIGHT, False);
  899.     break;
  900.     }
  901. }
  902.  
  903. static void
  904. draw_obj(x, y, type)
  905.     int         x,
  906.                 y,
  907.                 type;
  908. {
  909.     Pixmap      mmap;
  910.  
  911.     switch (type) {
  912.     case VATOR:
  913.     XCopyPlane(dpy, vator_map, game_win, vator_gc,
  914.            0, 0, VATOR_WIDTH, VATOR_HEIGHT, x, y, 1);
  915.     break;
  916.     case GIFT:
  917.     XSetForeground(dpy, draw_gc, gift_color);
  918.     XCopyPlane(dpy, slack_map, game_win, draw_gc,
  919.            0, 0, GIFT_WIDTH, GIFT_HEIGHT, x, y, 1);
  920.     break;
  921.     case MAN:
  922.     XSetForeground(dpy, draw_gc, man_color);
  923.     if (man_speed == 0)
  924.         mmap = man_stand;
  925.     else if (man_speed < 0)
  926.         mmap = man_left;
  927.     else
  928.         mmap = man_right;
  929.     XCopyPlane(dpy, mmap, game_win, draw_gc,
  930.            0, 0, MAN_WIDTH, MAN_HEIGHT, x, y, 1);
  931.     break;
  932.     case SPLAT:
  933.     XSetForeground(dpy, draw_gc, splat_color);
  934.     XCopyPlane(dpy, splat_map, game_win, draw_gc,
  935.            0, 0, SPLAT_WIDTH, SPLAT_HEIGHT, x, y, 1);
  936.     break;
  937.     case LEDGE:
  938.     XSetForeground(dpy, draw_gc, ledge_color);
  939.     XFillRectangle(dpy, game_win, draw_gc, x, y, LEDGE_WIDTH, LEDGE_HEIGHT);
  940.     break;
  941.     }
  942. }
  943.  
  944. static void
  945. draw_ledges()
  946. {
  947.     int         i;
  948.     int         y;
  949.  
  950.     for (i = 0; i < NUM_LEDGES; i++) {
  951.     y = (i + 1) * LEDGE_GAP;
  952.     draw_obj(0, y, LEDGE);
  953.     draw_obj(WIN_WIDTH - LEDGE_WIDTH, y, LEDGE);
  954.     }
  955. }
  956.  
  957. static void
  958. draw_scores()
  959. {
  960.     char        score_buffer[256];
  961.  
  962.     sprintf(score_buffer, "Time Left      Level %2d Best %7d Score %7d Lives %2d",
  963.         level, highscore, score, lives);
  964.     XDrawImageString(dpy, game_win, text_gc, STATUS_X, WIN_HEIGHT - 5,
  965.              score_buffer, strlen(score_buffer));
  966. }
  967.  
  968. static void
  969. draw_timer()
  970. {
  971.     if (paused) {
  972.     draw_message("PAUSED");
  973.     } else {
  974.     XClearArea(dpy, game_win, TIMER_SLICE,
  975.            TIMER_Y, TIMER_SLICE * START_TIME, TIMER_HEIGHT, False);
  976.     XSetForeground(dpy, draw_gc, timer_color);
  977.     XFillRectangle(dpy, game_win, draw_gc, TIMER_SLICE,
  978.                TIMER_Y, TIMER_SLICE * time_left, TIMER_HEIGHT);
  979.     }
  980. }
  981.  
  982. static void
  983. draw_status()
  984. {
  985.     int         i,
  986.                 x,
  987.                 y;
  988.     int         old_sp;
  989.  
  990.     XClearArea(dpy, game_win, TIMER_SLICE * (START_TIME + 1), TIMER_Y,
  991.            10000, MAN_HEIGHT, False);
  992.     y = TIMER_Y;
  993.     x = EXTRA_MAN_X;
  994.     old_sp = man_speed;
  995.     man_speed = 0;        /* make sure they're standing */
  996.     for (i = 0; i < min(lives - 1, 7); i++) {
  997.     draw_obj(x, y, MAN);
  998.     x -= (int) (MAN_WIDTH * 1.5);
  999.     }
  1000.     man_speed = old_sp;
  1001.     draw_timer();
  1002.     draw_scores();
  1003. }
  1004.  
  1005. static void
  1006. draw_message(str)
  1007.     char       *str;
  1008. {
  1009.     static char msgbuf[256];
  1010.  
  1011.     if (str)
  1012.     strcpy(msgbuf, str);
  1013.     XClearArea(dpy, game_win, TIMER_SLICE,
  1014.            TIMER_Y, TIMER_SLICE * START_TIME, TIMER_HEIGHT, False);
  1015.     XDrawImageString(dpy, game_win, text_gc, STATUS_X, STATUS_Y,
  1016.              msgbuf, strlen(msgbuf));
  1017. }
  1018.  
  1019. static void
  1020. draw_message2(str)
  1021.     char       *str;
  1022. {
  1023.     static char msgbuf2[256];
  1024.  
  1025.     if (str)
  1026.     strcpy(msgbuf2, str);
  1027.     XClearArea(dpy, game_win, STATUS_X,
  1028.            STATUS_Y + 10, 1000, 15, False);
  1029.     XDrawImageString(dpy, game_win, text_gc, STATUS_X, STATUS_Y + 20,
  1030.              msgbuf2, strlen(msgbuf2));
  1031. }
  1032.