home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XGAMES / SPIDER.TAR / spider / events.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-28  |  11.7 KB  |  615 lines

  1. /*
  2.  *    Spider
  3.  *
  4.  *    (c) Copyright 1989, Donald R. Woods and Sun Microsystems, Inc.
  5.  *    (c) Copyright 1990, David Lemke and Network Computing Devices Inc.
  6.  *
  7.  *    See copyright.h for the terms of the copyright.
  8.  *
  9.  *    @(#)events.c    2.6    91/05/09
  10.  *
  11.  */
  12.  
  13. /*
  14.  * Spider event handlers
  15.  */
  16.  
  17. #include    "defs.h"
  18. #include    "globals.h"
  19.  
  20. extern int    cheat_count;
  21.  
  22. static    CardPtr        current_card = CARDNULL;
  23. static    CardList    current_list = CARDLISTNULL;
  24.  
  25. static CardList        coords_to_list();
  26. static CardPtr        coords_to_card();
  27. static Bool        hit_deck();
  28. Bool            write_confirmer();
  29. Bool            newgame_confirmer();
  30. #ifdef XVIEW
  31. extern void        show_play();
  32. #else
  33. extern Bool        show_play_events();
  34. #endif
  35. #ifdef    KITLESS
  36. static void        handle_table_event();
  37. static void        redraw_table();
  38. static void        button_press();
  39. static void        button_release();
  40. static void        key_press();
  41. static void        resize_event();
  42. static void        do_expand();
  43. static void        handle_message_event();
  44. #endif /* KITLESS */
  45.  
  46. Bool    usebell = False;
  47.  
  48. #ifdef KITLESS
  49. /*
  50.  * main event handling loop
  51.  */
  52. event_loop()
  53. {
  54. XEvent    xev;
  55.  
  56.     while (1)    {
  57.         XNextEvent(dpy, &xev);
  58.         if (xev.xany.window == table)    {
  59.             handle_table_event(&xev);
  60.         } else if (xev.xany.window == message_win)    {
  61.             handle_message_event(&xev);
  62.         }
  63.         if (restart)    {
  64.             shuffle_cards();
  65.         }
  66.     }
  67. }
  68.  
  69. /*
  70.  * event on table
  71.  */
  72. static void
  73. handle_table_event(xev)
  74. XEvent    *xev;
  75. {
  76.     if (xev->xany.type == Expose)    {
  77.         redraw_table((XExposeEvent *)xev);
  78.     } else if (xev->xany.type == ButtonPress)    {
  79.         button_press((XButtonPressedEvent *)xev);
  80.     } else if (xev->xany.type == ButtonRelease)    {
  81.         button_release((XButtonReleasedEvent *)xev);
  82.         current_list = CARDLISTNULL;
  83.     } else if (xev->xany.type == KeyPress)    {
  84.         key_press((XKeyPressedEvent *)xev);
  85.     } else if (xev->xany.type == ConfigureNotify)    {
  86.         resize_event((XConfigureEvent *)xev);
  87.     }
  88. }
  89.  
  90. static void
  91. handle_message_event(xev)
  92. XEvent    *xev;
  93. {
  94.     if (xev->xany.type == Expose)    {
  95.         show_message(NULL);
  96.     }
  97. }
  98.  
  99. /* KITLESS doesn't bother to check -- just clobbers existing file */
  100. Bool
  101. write_confirmer()
  102. {
  103.     return True;
  104. }
  105.  
  106. Bool
  107. newgame_confirmer()
  108. {
  109.     return True;
  110. }
  111. #endif /* KITLESS */
  112.  
  113.  
  114. #ifndef KITLESS
  115. void
  116. #else /* KITLESS */
  117. static void
  118. #endif /* KITLESS */
  119. redraw_table(xev)
  120. XExposeEvent    *xev;
  121. {
  122. static Bool    last_was_zero = True;    /* so at init time it paints */
  123.  
  124.     /*
  125.      * this mess is to optimize the painting.   a complex exposure
  126.      * area could cause a card to have several damage areas.  since
  127.      * the entire card is painted when damaged, the following keeps
  128.      * track of whether its been painted in the latest flurry of
  129.      * exposures, and prevents it being painted multiple times.
  130.      */
  131.     if (last_was_zero)    {
  132.         draw_count++;
  133.         last_was_zero = False;
  134.     }
  135.     if (xev->count == 0)
  136.         last_was_zero = True;
  137.  
  138.     redraw_deck(xev->x, xev->y, xev->width, xev->height);
  139.     redraw_card_piles(xev->x, xev->y, xev->width, xev->height);
  140.     redraw_card_stacks(xev->x, xev->y, xev->width, xev->height);
  141. }
  142.  
  143. /* 
  144.  * ignore y when getting list
  145.  */
  146. static CardList
  147. coords_to_list(x, y)
  148. int    x, y;
  149. {
  150. int    i;
  151.  
  152.     if (y < STACK_LOC_Y)    {
  153.         for (i = 0; i < NUM_PILES; i++)    {
  154.             if ((x >= PILE_LOC_X(piles[i]->place)) &&
  155.                 (x <= (PILE_LOC_X(piles[i]->place) + CARD_WIDTH)))
  156.                 return (piles[i]);
  157.         }
  158.         return (CARDLISTNULL);
  159.     } else    {
  160.         for (i = 0; i < NUM_STACKS; i++)    {
  161.             if ((x >= STACK_LOC_X(stack[i]->place)) &&
  162.                 (x <= (STACK_LOC_X(stack[i]->place) + CARD_WIDTH)))
  163.                 return (stack[i]);
  164.         }
  165.         return (CARDLISTNULL);
  166.     }
  167. }
  168.  
  169. static CardPtr
  170. coords_to_card(x, y)
  171. int    x, y;
  172. {
  173. CardList    list;
  174. CardPtr    tmp;
  175.  
  176.     list = coords_to_list(x, y);
  177.     if (list == CARDLISTNULL || IS_PILE(list))
  178.         return (CARDNULL);
  179.     tmp = list->cards;
  180.     if (tmp == CARDNULL)
  181.         return CARDNULL;
  182.     while (tmp)    {
  183.         if (tmp->next)    {
  184.             if ((y <= tmp->next->y) && (y >= tmp->y))    {
  185.                 return (tmp);
  186.             }
  187.         } else    {
  188.             if ((y <= (tmp->y + CARD_HEIGHT)) &&
  189.                 (y >= tmp->y))    {
  190.                 return (tmp);
  191.             }
  192.         }
  193.         tmp = tmp->next;
  194.     }
  195.     return CARDNULL;
  196. }
  197.  
  198. static Bool
  199. hit_deck(x, y)
  200. int    x, y;
  201. {
  202.     return ((x <= (deck->x + CARD_WIDTH)) && (x >= deck->x) &&
  203.         (y <= (deck->y + CARD_HEIGHT)) && (y >= deck->y));
  204. }
  205.  
  206. #ifndef KITLESS
  207. void
  208. #else    /* KITLESS */
  209. static void
  210. #endif    /* KITLESS */
  211. button_press(xev)
  212. XButtonPressedEvent    *xev;
  213. {
  214.  
  215.     if (hit_deck(xev->x, xev->y))    {
  216.         current_list = deck;
  217.         return;
  218.     }
  219.     current_card = coords_to_card(xev->x, xev->y);
  220.     if (xev->button == Button2)    {
  221.         if (current_card == CARDNULL)
  222.             return;
  223.         /* ignore facedown cards */
  224.         if (current_card->type != Faceup)    {
  225.             current_card = CARDNULL;
  226.             current_list = coords_to_list(xev->x, xev->y);
  227.             return;
  228.         }
  229. #ifdef DEBUG
  230.         if (xev->state & ShiftMask)    {
  231.             current_list = coords_to_list(xev->x, xev->y);
  232.             return;
  233.         }
  234. #endif    /* DEBUG */
  235.         if (!can_move(current_card))    {
  236.             card_message("Can't move", current_card);
  237.             spider_bell(dpy, 0);
  238.             current_card = CARDNULL;
  239.         }
  240.     } else    {
  241.         current_card = CARDNULL;
  242.     }
  243.     current_list = coords_to_list(xev->x, xev->y);
  244.     if (IS_PILE(current_list))    {
  245.         if (current_list->cards)    {
  246.             show_message("Can't move removed cards.");
  247.             spider_bell(dpy, 0);
  248.         } else    {
  249.             show_full_suits();
  250.         }
  251.         current_list = CARDLISTNULL;
  252.     } else if (current_list && current_list->cards == CARDNULL)    {
  253.         show_message("No cards to move.");
  254.         current_list = CARDLISTNULL;
  255.     }
  256. }
  257.  
  258. #ifndef KITLESS
  259. void
  260. #else    /* KITLESS */
  261. static void
  262. #endif     /* KITLESS */
  263. button_release(xev)
  264. XButtonReleasedEvent    *xev;
  265. {
  266. CardList    list_hit;
  267. CardPtr        tmp;
  268.  
  269.     if (current_list == CARDLISTNULL)
  270.         return;
  271.  
  272.     if (hit_deck(xev->x, xev->y))    {
  273.         if (current_list == deck)    {
  274.             if (deal_number == 0)    {
  275.                 deal_cards();
  276.             } else    {
  277.                 deal_next_hand(True);
  278.             }
  279.         } else    {    /* no dropping on deck */
  280.             show_message("Can't move cards to deck");
  281.             spider_bell(dpy, 0);
  282.         }
  283.         return;
  284.     }
  285.  
  286.     list_hit = coords_to_list(xev->x, xev->y);
  287.     if (list_hit == CARDLISTNULL)
  288.         return;
  289.  
  290.     if (current_card)    {
  291. #ifdef DEBUG
  292.         if (xev->state & ShiftMask)    {
  293.             move_to_list(current_card, list_hit, True);
  294.             current_card = CARDNULL;
  295.             return;
  296.         }
  297. #endif
  298.         if (list_hit == current_list)    {
  299.             best_list_move(list_hit, current_card);
  300.             return;
  301.         }
  302.         if ((IS_PILE(list_hit)))    {
  303.             if((current_card->rank == King) && 
  304.                 (can_move(current_card)) &&
  305.                 (last_card(current_card->list)->rank == Ace)) {
  306.                 move_to_pile(current_card);
  307.             } else    {
  308.                 card_message("Can't remove", current_card);
  309.                 spider_bell(dpy, 0);
  310.             }
  311.             current_card = CARDNULL;
  312.             return;
  313.         }
  314.         if (can_move_to(current_card, list_hit))    {
  315.             move_to_list(current_card, list_hit, True);
  316.         } else    {
  317.             card2_message("Can't move", current_card, "to",
  318.                 last_card(list_hit));
  319.             spider_bell(dpy, 0);
  320.         }
  321.         current_card = CARDNULL;
  322.     /* try best move if the mouse wasn't moved */
  323.     } else if (list_hit == current_list)    {
  324.         best_list_move(list_hit, CARDNULL);
  325.     } else    {
  326.         if (IS_PILE(list_hit))    {
  327.             tmp = last_card(current_list);
  328.             if (tmp->rank == Ace)    {
  329.                 while (tmp && can_move(tmp))    {
  330.                     if (tmp->rank == King)    {
  331.                         move_to_pile(tmp);
  332.                         return;
  333.                     }
  334.                     tmp = tmp->prev;
  335.                 }
  336.             }
  337.             card_message("Can't remove", tmp);
  338.             spider_bell(dpy, 0);
  339.             return;
  340.         }
  341.         tmp = current_list->cards;
  342.         while (tmp)    {
  343.             if (can_move(tmp))    {
  344.                 if (can_move_to(tmp, list_hit))    {
  345.                     move_to_list(tmp, list_hit, True);
  346.                     return;
  347.                 }
  348.             }
  349.             tmp = tmp->next;
  350.         }
  351.         if (tmp)
  352.             card_message("Can't move", tmp);
  353.         else
  354.             show_message("No movable cards");
  355.         spider_bell(dpy, 0);
  356.     }
  357. }
  358.  
  359. #ifndef KITLESS
  360. void
  361. #else    /* KITLESS */
  362. static void
  363. #endif    /* KITLESS */
  364. key_press(xev)
  365. XKeyPressedEvent    *xev;
  366. {
  367. char    str[32];
  368. char    buf[512];
  369. char    *fname;
  370. int    num;
  371. #ifdef KITLESS
  372. #define    get_name_field(x)    get_selection(x)
  373. #else
  374. extern char    *get_name_field();
  375. #endif /* KITLESS */
  376.  
  377.     num = XLookupString(xev, str, 32, NULL, NULL);
  378.     if (num == 0)
  379.         return;
  380.     switch (str[0])    {
  381.     case    'f':        /* find card */
  382.     case    'F':
  383.         fname = get_name_field();
  384.         if (fname == NULL || strlen(fname) == 0) {
  385.             show_message("Selection is unusable or unobtainable.");
  386.         } else    {
  387.             locate(fname);
  388.         }
  389.         break;
  390.     case    'l':
  391.     case    'L':
  392.         if ((fname = get_name_field()) == NULL)    {
  393.             show_message("Selection is unusable or unobtainable.");
  394.         } else    {
  395.             read_file_or_selection(fname);
  396.         }
  397.         /* force everything to redraw */
  398.         force_redraw();
  399.         break;
  400.     case    'w':
  401.     case    'W':
  402.         /* write to selection */
  403.         if ((fname = get_name_field()) == NULL)    {
  404.             show_message("Selection is unusable or unobtainable.");
  405.         } else    {
  406.             write_file(fname, write_confirmer);
  407.         }
  408.         break;
  409.     case    's':
  410.     case    'S':
  411.         /* score */
  412.         (void)sprintf(buf, "Current position scores %d out of 1000.", 
  413.             compute_score());
  414.         show_message(buf);
  415.         break;
  416.     case    'a':
  417.     case    'A':
  418.         /* play again */
  419.         (void)replay();
  420.         init_cache();    /* reset move cache */
  421.         break;
  422.     case    'r':
  423.     case    'R':
  424.         /* show move log */
  425. #ifdef XVIEW
  426.         show_play();
  427. #else
  428.         show_play(0, 0, show_play_events, delay);
  429. #endif
  430.         break;
  431.     case    'n':
  432.     case    'N':
  433.         /* start over */
  434.         if (newgame_confirmer())    {
  435.             restart = True;
  436.             clear_message();
  437.         }
  438.         break;
  439.     case    'e':
  440.     case    'E':
  441.         do_expand();
  442.         break;
  443.     case    'd':
  444.     case    'D':
  445.         if (deal_number == 0)    {
  446.             deal_cards();
  447.         } else    {
  448.             deal_next_hand(True);
  449.         }
  450.         /* deal next hand */
  451.         break;
  452.     case    'u':
  453.     case    'U':
  454.         undo();
  455.         break;
  456.     case    'v':
  457.     case    'V':
  458.         print_version();
  459.         break;
  460.     case    'Q':
  461.         /* quit */
  462.         exit(0);
  463.     case    '#':
  464.         if (deal_number == 0)    {
  465.             show_message("Haven't dealt yet.");
  466.         } else if (deal_number == 1)    {
  467.             sprintf(buf, "Initial deal; cheat count: %d",
  468.                     cheat_count);
  469.             show_message(buf);
  470.         } else    {
  471.             sprintf(buf, "Deal number %d of 5; cheat count: %d",
  472.                 deal_number - 1, cheat_count);
  473.             show_message(buf);
  474.         }
  475.         break;
  476.     case    '?':
  477.         if (deal_number == 0)    {
  478.             show_message("Haven't dealt yet.");
  479.         } else    {
  480.             advise_best_move();
  481.         }
  482.         break;
  483.     default:
  484.         str[num] = '\0';    /* NULL terminate it */
  485.         (void) sprintf(buf, "Unknown command: '%s'", str);
  486.         show_message(buf);
  487.         break;
  488.     }
  489. }
  490.  
  491. #ifdef KITLESS
  492. static void
  493. resize_event(xev)
  494. XConfigureEvent    *xev;
  495. {
  496. int    i;
  497.  
  498.     table_height = xev->height;
  499.     table_width = xev->width;
  500.  
  501.     /* adjust message window */
  502.     XMoveResizeWindow(dpy, message_win, 0, (table_height - 2 * TABLE_BW - 
  503.         (message_font->ascent + message_font->descent)),
  504.         (table_width - 2 * TABLE_BW),
  505.         (message_font->ascent + message_font->descent));
  506.  
  507.     /* fix stacks */
  508.     for (i = 0; i < NUM_STACKS; i++)    {
  509.         if (stack[i])
  510.             recompute_list_deltas(stack[i]);
  511.     }
  512.     /* exposure will repaint them */
  513. }
  514. #endif    /* KITLESS */
  515.  
  516. void
  517. print_version()
  518. {
  519. char    buf[256];
  520.  
  521.     (void)sprintf(buf, "Spider version %s, last built: %s", version,
  522.                             build_date);
  523.     show_message(buf);
  524. }
  525.  
  526.  
  527. static CardList
  528. get_list()
  529. {
  530. XEvent    event;
  531. CardList    list = CARDLISTNULL;
  532.  
  533.     if (XGrabPointer(dpy, table, False, 
  534.             ButtonPressMask | ButtonReleaseMask,
  535.             GrabModeAsync, GrabModeAsync, table, None,
  536.             CurrentTime) != GrabSuccess)    {
  537.         show_message("Unable to grab pointer.");
  538.         return CARDLISTNULL;
  539.     }
  540.     while (1)    {
  541.         XNextEvent(dpy, &event);
  542.  
  543.         switch (event.type)    {
  544.         case    ButtonRelease:
  545.             if (event.xbutton.window == table)    {
  546.                 list = coords_to_list(event.xbutton.x,
  547.                     event.xbutton.y);
  548.             }
  549.             XUngrabPointer(dpy, CurrentTime);
  550.             return list;
  551.         default:
  552.             break;
  553.         }
  554.     }
  555. }
  556.  
  557. #ifdef KITLESS
  558. static void
  559. #else    /* KITLESS */
  560. void
  561. #endif    /* KITLESS */
  562. do_expand()
  563. {
  564. CardList    list;
  565.  
  566.     show_message("Click over the column whose contents you want to see.");
  567. #ifdef    XAW
  568.     flush_message();
  569. #endif    /* XAW */
  570.     list = get_list();
  571.     if (list && !IS_PILE(list))    {
  572.         expand(list);
  573.     } else    {
  574.         show_message("That wasn't over a column!");
  575.     }
  576. }
  577.  
  578. #ifdef KITLESS
  579. Bool
  580. show_play_events()
  581. {
  582. XEvent    xev;
  583.  
  584.     while (XPending(dpy))    {
  585.         XNextEvent(dpy, &xev);
  586.  
  587.         /* any key or button will stop it */
  588.         switch(xev.type)    {
  589.             default:
  590.                 if (xev.xany.window == table)   {
  591.                     handle_table_event(&xev);
  592.                 } else if (xev.xany.window == message_win) {
  593.                     handle_message_event(&xev);
  594.                 }
  595.                 break;
  596.  
  597.             case    KeyPress:
  598.             case    KeyRelease:
  599.             case    ButtonPress:
  600.             case    ButtonRelease:
  601.                 return False;
  602.         }
  603.     }
  604.     return True;
  605. }
  606. #endif    /* KITLESS */
  607.  
  608. spider_bell(d, level)
  609. Display    *d;
  610. int    level;
  611. {
  612.     if (usebell)
  613.         XBell(d, level);
  614. }
  615.