home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume13 / x4war2 / part02 / x4war.c
C/C++ Source or Header  |  1992-08-03  |  45KB  |  1,819 lines

  1. #include <X11/Xlib.h>
  2. #include <X11/Xutil.h>
  3. #include <X11/X.h>
  4. #include <X11/Xos.h>
  5. #include <X11/Xatom.h>
  6. #include <X11/Intrinsic.h>
  7. #include <X11/keysym.h>
  8.  
  9. #include <stdio.h>
  10. #include "war.h"
  11.  
  12. #include "bitmaps/war_background.xbm"
  13. #include "bitmaps/war_logo.xbm"
  14.  
  15. #ifdef CHINESE
  16.  
  17. #include "bitmaps/chinese_piece/colours.xbm"
  18. #include "bitmaps/chinese_piece/marshal.xbm"
  19. #include "bitmaps/chinese_piece/general.xbm"
  20. #include "bitmaps/chinese_piece/m_general.xbm"
  21. #include "bitmaps/chinese_piece/brigadier.xbm"
  22. #include "bitmaps/chinese_piece/colonel.xbm"
  23. #include "bitmaps/chinese_piece/major.xbm"
  24. #include "bitmaps/chinese_piece/captain.xbm"
  25. #include "bitmaps/chinese_piece/f_lieutenant.xbm"
  26. #include "bitmaps/chinese_piece/sapper.xbm"
  27. #include "bitmaps/chinese_piece/mine.xbm"
  28. #include "bitmaps/chinese_piece/bomb.xbm"
  29.  
  30. #else
  31.  
  32. #include "bitmaps/image_piece/colours.xbm"
  33. #include "bitmaps/image_piece/marshal.xbm"
  34. #include "bitmaps/image_piece/general.xbm"
  35. #include "bitmaps/image_piece/m_general.xbm"
  36. #include "bitmaps/image_piece/brigadier.xbm"
  37. #include "bitmaps/image_piece/colonel.xbm"
  38. #include "bitmaps/image_piece/major.xbm"
  39. #include "bitmaps/image_piece/captain.xbm"
  40. #include "bitmaps/image_piece/f_lieutenant.xbm"
  41. #include "bitmaps/image_piece/sapper.xbm"
  42. #include "bitmaps/image_piece/mine.xbm"
  43. #include "bitmaps/image_piece/bomb.xbm"
  44.  
  45. #endif
  46.  
  47. #include "bitmaps/back0.xbm"
  48. #include "bitmaps/back1.xbm"
  49. #include "bitmaps/back2.xbm"
  50. #include "bitmaps/back3.xbm"
  51.  
  52. #include "bitmaps/cursor.xbm"
  53. #include "bitmaps/cursormask.xbm"
  54. #include "bitmaps/nodemask.xbm"
  55.  
  56. #include "bitmaps/go.xbm"
  57. #include "bitmaps/stop.xbm"
  58.  
  59. #include "bitmaps/pillar.xbm"
  60.  
  61. struct Player {
  62.     Display *dis;
  63.     int scr;        /* screen number of display *dis */
  64.     Window win, confirm;
  65.     Pixmap node[16];    /* 0-11 for faces of nodes, 12-15 for back and cursor */
  66.     Pixmap cursormask_pixmap,nodemask_pixmap,icon_pixmap,stop_pixmap,go_pixmap;
  67.     unsigned long fg[4];   /* foreground of nodes */
  68.     XColor fg_color, bg_color;
  69.     GC gc;
  70.     Cursor cursor, tmp_cursor;
  71.  
  72.     char *display_name;
  73.     char player_name[10];
  74.     char color_name[20];
  75.     int rip[5][5];
  76.     int rip_index;
  77.     int state;        /* 0--dead, 1--deploy, 2--play, 3--quit */
  78.     int num_movable;
  79.     int popup;        /* 0--no popup, 1--Peace Request, 2--Quit,
  80.                3--continue message*/
  81.             /* if confirm window is poped up, input is grabed */
  82.  
  83. /* this structure tells if a node is picked up by pressing a button, it
  84.    records the array and subscripts of the node.
  85. */
  86.     struct {
  87.     int arr;
  88.     int x, y;
  89.     int value;
  90.     Boolean picked;
  91.     } pick;
  92.     Boolean marshal_dead;
  93.     char talk_msg[3][30];
  94.     int talk_col;
  95.     int talk_x, talk_y;
  96. };
  97.  
  98. XtAppContext app_context;
  99.  
  100. Arr arr[4][6][5], mid[3][3];    /* array to remember the state of the
  101.                    war */
  102.  
  103. struct Player p[4];
  104.  
  105. Sapper_path sap[21];
  106.  
  107. Pixmap pillar[2];
  108. Boolean two;
  109.  
  110. unsigned int  global_argc;
  111. char ** global_argv;
  112. char *progname;
  113.  
  114. char msg1[30], msg2[30];
  115. char confirm_msg[30];
  116.  
  117. int mode;    /* game mode */
  118.         /* 0 -- new game and deploy phase */
  119.         /* 1 -- play phase    */
  120.         /* 2 -- peace request phase */
  121.         /* 3 -- one game finished */
  122.         /* 4 -- during a move */
  123.  
  124. int num_player; /* when one is defeated, this var decrease by 1 */
  125.  
  126. int count;    /* to calculate the flashing when node moved */
  127.         /* values and meanings
  128.            8--clear source;
  129.            7--show source;
  130.            6--clear source;
  131.            5--show source;
  132.            4--clear source;
  133.            3--show destination;
  134.            2--clear destination;
  135.            1--show destination;
  136.            0--clear destination;
  137.         */
  138. int turn;        /* 0-3, specifies who's turn to move */
  139.  
  140. int round;
  141.  
  142. int sf, si, sj, sw, sv, df, di, dj, dw, dv;    /* record one move */
  143.  
  144. Boolean debug;
  145.  
  146. static void refresh_board();
  147.  
  148.  
  149. /*******************************************************************
  150. *
  151. *   Synopsis
  152. *    parse_arguments(argc, argv)
  153. *        int argc;
  154. *        char **argv;
  155. *
  156. *   Description
  157. *    parses arguments in command line and set appropriate properties,
  158. *    exit if illegal argument present.
  159. *
  160. ********************************************************************/
  161.  
  162. static void
  163. parse_arguments(argc, argv)
  164. int argc;
  165. char **argv;
  166. {
  167.     int i;
  168.  
  169.     i = 1;
  170.     while (i<argc) {
  171.     if (!strcmp(argv[i], "-p0"))
  172.         strncpy(p[0].player_name, argv[++i], 9);
  173.     else if (!strcmp(argv[i], "-d0"))
  174.         p[0].display_name = argv[++i];
  175.     else if (!strcmp(argv[i], "-c0"))
  176.         strncpy(p[0].color_name, argv[++i], 19);
  177.     else if (!strcmp(argv[i], "-p1"))
  178.         strncpy(p[1].player_name, argv[++i], 9);
  179.     else if (!strcmp(argv[i], "-d1"))
  180.         p[1].display_name = argv[++i];
  181.     else if (!strcmp(argv[i], "-c1"))
  182.         strncpy(p[1].color_name, argv[++i], 19);
  183.     else if (!strcmp(argv[i], "-p2"))
  184.         strncpy(p[2].player_name, argv[++i], 9);
  185.     else if (!strcmp(argv[i], "-d2"))
  186.         p[2].display_name = argv[++i];
  187.     else if (!strcmp(argv[i], "-c2"))
  188.         strncpy(p[2].color_name, argv[++i], 19);
  189.     else if (!strcmp(argv[i], "-p3"))
  190.         strncpy(p[3].player_name, argv[++i], 9);
  191.     else if (!strcmp(argv[i], "-d3"))
  192.         p[3].display_name = argv[++i];
  193.     else if (!strcmp(argv[i], "-c3"))
  194.         strncpy(p[3].color_name, argv[++i], 19);
  195.     else if (!strcmp(argv[i], "-usage") || !strcmp(argv[i], "-help")) {
  196.         syntax(argv[0]);
  197.         exit(0);
  198.     }
  199.     else if (!strcmp(argv[i], "-two"))
  200.         two = True;
  201.     else if (!strcmp(argv[i], "-debug"))
  202.         debug = True;
  203.  
  204.     else {
  205.         syntax(argv[0]);
  206.         exit(-1);
  207.     }
  208.     i++;
  209.     }
  210. }
  211.  
  212.  
  213.  
  214.  
  215. /*****************************************************************************
  216.  *
  217.  *   Synopsis
  218.  *    Boolean LookUpColor(display, name, col, color_index)
  219.  *        Display *display;
  220.  *        char *name;
  221.  *        XColor *col;
  222.  *        unsigned long *color_index;    return
  223.  *
  224.  *   Arguments
  225.  *    display         specifies a connection to an X server;
  226.  *    name         a string for color;
  227.  *    col         returns XColor structure of the named color;
  228.  *    color_index  returns the pixel value representing the named color,
  229.  *             which is actually an index to the colormap;
  230.  *
  231.  *   Return values
  232.  *    True on success
  233.  *    False on failing to allocate the named color
  234.  *
  235.  ****************************************************************************/
  236.  
  237. Boolean LookUpColor(display, name, col, color_index)
  238. Display *display;
  239. char *name;
  240. XColor *col;
  241. unsigned long *color_index;
  242. {
  243.   XColor xcolor;
  244.  
  245.   if(XAllocNamedColor(display, DefaultColormap(display, DefaultScreen(display)),
  246.         name,  col, &xcolor) == 0) {
  247.     printf("LookUpColor: could not allocate %s.\n", name);
  248.     return(False);
  249.   } 
  250.   *color_index = col->pixel;
  251.   return(True);
  252. }
  253.  
  254.  
  255. /*********************************************************************
  256. *
  257. *   Synopsis
  258. *    connect_display()
  259. *
  260. *   Description
  261. *    connect to displays and create windows.
  262. *
  263. **********************************************************************/
  264.  
  265.  
  266. static void
  267. connect_display()
  268. {
  269.     Display *dpy;
  270.     Pixmap background;
  271.     int i, j;
  272.     char err_msg[100];
  273.     XSetWindowAttributes attr;
  274.     unsigned long fg, bg;
  275.     XSizeHints size_hints;
  276.     char *win_name, *icon_name;
  277.     XGCValues values;
  278.     XColor color;
  279.  
  280.     XtToolkitInitialize();
  281.     app_context = XtCreateApplicationContext();
  282.  
  283.     values.foreground = 0;
  284.     values.background = 1;
  285.  
  286.     win_name = (char *)malloc(40);
  287.  
  288.     for (i=0; i<4; i++) {
  289.     if (two && i%2 != 0) continue;    /*for two players, connect only twice*/
  290.  
  291.     if (!(p[i].dis=XtOpenDisplay(app_context, p[i].display_name, "x4war",
  292.         "x4war", 0, 0, &global_argc, global_argv))) {
  293.         sprintf(err_msg, "can not open display %s",
  294.             XDisplayName(p[i].display_name));
  295.         fatal_error(err_msg);
  296.     }
  297.     dpy = p[i].dis;
  298.     p[i].scr = DefaultScreen(dpy);
  299.  
  300.     attr.border_pixel = BlackPixel(dpy, p[i].scr);
  301.  
  302.     p[i].win = XCreateWindow(dpy, RootWindow(dpy,p[i].scr), 
  303.             i*40, 0, DIMENSION, DIMENSION, 4, CopyFromParent, 
  304.             InputOutput, CopyFromParent, CWBorderPixel, &attr);
  305.  
  306.     if (!LookUpColor(dpy, DEFAULT_BOARD_BG, &color, &bg))
  307.         bg = WhitePixel(dpy, p[i].scr);
  308.     if (!LookUpColor(dpy, DEFAULT_BOARD_FG, &color, &fg))
  309.         fg = BlackPixel(dpy, p[i].scr);
  310.     background = XCreatePixmapFromBitmapData(dpy, p[i].win,
  311.         war_background_bits, war_background_width,
  312.         war_background_height, fg, bg,
  313.         DefaultDepth(dpy, p[i].scr));
  314.  
  315.     XSetWindowBackgroundPixmap(dpy, p[i].win, background);
  316.  
  317.     XFreePixmap(dpy, background);
  318.  
  319.     sprintf(win_name, "x4war  player %s", p[i].player_name);
  320.     icon_name = p[i].player_name;
  321.     p[i].icon_pixmap = XCreateBitmapFromData(dpy, p[i].win, war_logo_bits,
  322.         war_logo_width, war_logo_height);
  323.  
  324.     size_hints.flags = PPosition | PSize | PMinSize;
  325.     size_hints.min_width = DIMENSION;
  326.     size_hints.min_height = DIMENSION;
  327.     {
  328.     XWMHints wm_hints;
  329.     XClassHint class_hints;
  330.  
  331.     XTextProperty windowName, iconName;
  332.  
  333.     if (XStringListToTextProperty(&win_name, 1, &windowName) == 0)
  334.         fatal_error("structure allocation for windowName failed.");
  335.     if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0)
  336.         fatal_error("structure allocation for iconName failed.");        
  337.  
  338.     wm_hints.initial_state = NormalState;
  339.     wm_hints.input = True;
  340.     wm_hints.icon_pixmap = p[i].icon_pixmap;
  341.     wm_hints.flags = StateHint | IconPixmapHint | InputHint;
  342.  
  343.     class_hints.res_name = progname;
  344.     class_hints.res_class = "X4war";
  345.  
  346.     XSetWMProperties(dpy, p[i].win, &windowName, &iconName, 
  347.             global_argv, global_argc, &size_hints, &wm_hints, 
  348.             &class_hints);
  349.     }
  350.  
  351.     XSelectInput(dpy, p[i].win, ExposureMask | KeyPressMask | 
  352.             ButtonPressMask | ButtonReleaseMask);
  353.  
  354.     if (!LookUpColor(dpy, p[i].color_name, &(p[i].fg_color), &(p[i].fg[i])))
  355.         p[i].fg[i] = BlackPixel(dpy, p[i].scr);
  356.  
  357.     for (j=0; j<4; j++) {
  358.         if ((two && j%2 != 0) || j==i) continue;
  359.         if (!LookUpColor(dpy, p[j].color_name, &color, &(p[i].fg[j])))
  360.         p[i].fg[j] = BlackPixel(dpy, p[i].scr);
  361.     }
  362.  
  363.     p[i].gc = XCreateGC(dpy, p[i].win, 0, NULL);
  364.     XSetBackground(dpy, p[i].gc, WhitePixel(dpy, p[i].scr));
  365.     XSetFont(dpy, p[i].gc, XLoadFont(dpy, "9x15bold"));
  366.     XSetLineAttributes(dpy, p[i].gc, 2, LineSolid, CapButt, JoinRound);
  367.  
  368.     p[i].node[0] = XCreateBitmapFromData(dpy, p[i].win, colours_bits,
  369.         colours_width, colours_height);
  370.     p[i].node[1] = XCreateBitmapFromData(dpy, p[i].win, sapper_bits,
  371.         sapper_width, sapper_height);
  372.     p[i].node[2] = XCreateBitmapFromData(dpy, p[i].win, f_lieutenant_bits,
  373.         f_lieutenant_width, f_lieutenant_height);
  374.     p[i].node[3] = XCreateBitmapFromData(dpy, p[i].win, captain_bits,
  375.         captain_width, captain_height);
  376.     p[i].node[4] = XCreateBitmapFromData(dpy, p[i].win, major_bits,
  377.         major_width, major_height);
  378.     p[i].node[5] = XCreateBitmapFromData(dpy, p[i].win, colonel_bits,
  379.         colonel_width, colonel_height);
  380.     p[i].node[6] = XCreateBitmapFromData(dpy, p[i].win, brigadier_bits,
  381.         brigadier_width, brigadier_height);
  382.     p[i].node[7] = XCreateBitmapFromData(dpy, p[i].win, m_general_bits,
  383.         m_general_width, m_general_height);
  384.     p[i].node[8] = XCreateBitmapFromData(dpy, p[i].win, general_bits,
  385.         general_width, general_height);
  386.     p[i].node[9] = XCreateBitmapFromData(dpy, p[i].win, marshal_bits,
  387.         marshal_width, marshal_height);
  388.     p[i].node[10] = XCreateBitmapFromData(dpy, p[i].win, mine_bits,
  389.         mine_width, mine_height);
  390.     p[i].node[11] = XCreateBitmapFromData(dpy, p[i].win, bomb_bits,
  391.         bomb_width, bomb_height);
  392.  
  393.     if (i != 0)
  394.         p[i].node[12] = XCreateBitmapFromData(dpy, p[i].win,
  395.             back0_bits, back0_width, back0_height);
  396.     if (i != 1)
  397.         p[i].node[13] = XCreateBitmapFromData(dpy, p[i].win,
  398.             back1_bits, back1_width, back1_height);
  399.     if (i != 2)
  400.         p[i].node[14] = XCreateBitmapFromData(dpy, p[i].win,
  401.             back2_bits, back2_width, back2_height);
  402.     if (i != 3)
  403.         p[i].node[15] = XCreateBitmapFromData(dpy, p[i].win,
  404.             back3_bits, back3_width, back3_height);
  405.  
  406.     p[i].node[12+i] = XCreateBitmapFromData(dpy, p[i].win,
  407.             cursor_bits, cursor_width, cursor_height);
  408.     p[i].cursormask_pixmap = XCreateBitmapFromData(dpy, p[i].win,
  409.             cursormask_bits, cursormask_width, cursormask_height);
  410.     LookUpColor(dpy, "White", &(p[i].bg_color), &bg);
  411.     p[i].cursor = XCreatePixmapCursor(dpy, p[i].node[i+12],
  412.         p[i].cursormask_pixmap, &(p[i].fg_color), &(p[i].bg_color),
  413.         cursor_x_hot, cursor_y_hot);
  414.     XDefineCursor(dpy, p[i].win, p[i].cursor);
  415.  
  416.     p[i].confirm = XCreateSimpleWindow(dpy, p[i].win, 400, 400, 300, 120, 4,
  417.         BlackPixel(dpy, p[i].scr), WhitePixel(dpy, p[i].scr));
  418.     XSelectInput(dpy, p[i].confirm, ExposureMask | ButtonPressMask);
  419.  
  420.     p[i].nodemask_pixmap = XCreateBitmapFromData(dpy, p[i].win,
  421.         nodemask_bits, nodemask_width, nodemask_height);
  422.     p[i].stop_pixmap = XCreateBitmapFromData(dpy, p[i].win, stop_bits,
  423.         stop_width, stop_height);
  424.     p[i].go_pixmap = XCreateBitmapFromData(dpy, p[i].win, go_bits,
  425.         go_width, go_height);
  426.     }
  427.  
  428.     if (two) {
  429.     pillar[0] = XCreateBitmapFromData(p[0].dis, p[0].win, pillar_bits,
  430.         pillar_width, pillar_height);
  431.     pillar[1] = XCreateBitmapFromData(p[2].dis, p[2].win, pillar_bits,
  432.         pillar_width, pillar_height);
  433.     }
  434. }
  435.  
  436.  
  437. /************************************************************************
  438. *
  439. *   Synopsis
  440. *    initial_board()
  441. *
  442. *   Description
  443. *    set for a new game
  444. *
  445. ************************************************************************/
  446. static void
  447. initial_board()
  448. {
  449.     int i, j, k;
  450.  
  451.  
  452.     for (i=0; i<4; i++)
  453.      for (j=0; j<6; j++)
  454.       for (k=0; k<5; k++) {
  455.     arr[i][j][k].value = EMPTY;
  456.     arr[i][j][k].id = i;
  457.     }
  458.  
  459.     for (i=0; i<3; i++)
  460.       for (j=0; j<3; j++)
  461.     mid[i][j].value = EMPTY;
  462.  
  463.  
  464.     for (i=0; i<4; i++) {
  465.     p[i].rip_index = 0;
  466.     p[i].state = 1;
  467.     p[i].num_movable = 21;
  468.     p[i].popup = 0;
  469.     p[i].pick.picked = False;
  470.     p[i].marshal_dead = False;
  471.     p[i].talk_msg[0][0] = p[i].talk_msg[1][0] = p[i].talk_msg[2][0] = '\0';
  472.     p[i].talk_col = 0;
  473.  
  474.     if (debug && (!two || i%2==0)) {
  475.         arr[i][0][0].value = MARSHAL;
  476.         arr[i][0][1].value = GENERAL;
  477.         arr[i][0][2].value = M_GENERAL;
  478.         arr[i][0][3].value = M_GENERAL;
  479.         arr[i][0][4].value = BRIGADIER;
  480.         arr[i][1][0].value = BRIGADIER;
  481.         arr[i][1][2].value = COLONEL;
  482.         arr[i][1][4].value = COLONEL;
  483.         arr[i][2][0].value = MAJOR;
  484.         arr[i][2][1].value = MAJOR;
  485.         arr[i][2][3].value = CAPTAIN;
  486.         arr[i][2][4].value = CAPTAIN;
  487.         arr[i][3][0].value = CAPTAIN;
  488.         arr[i][3][2].value = F_LIEUTENANT;
  489.         arr[i][3][4].value = F_LIEUTENANT;
  490.         arr[i][4][0].value = F_LIEUTENANT;
  491.         arr[i][4][1].value = SAPPER;
  492.         arr[i][4][2].value = SAPPER;
  493.         arr[i][4][3].value = SAPPER;
  494.         arr[i][4][4].value = BOMB;
  495.         arr[i][5][0].value = BOMB;
  496.         arr[i][5][1].value = COLOURS;
  497.         arr[i][5][2].value = MINE;
  498.         arr[i][5][3].value = MINE;
  499.         arr[i][5][4].value = MINE;
  500.  
  501.         for (j=0; j<5; j++)
  502.           for (k=0; k<5; k++)
  503.         p[i].rip[j][k] = EMPTY;
  504.     }
  505.  
  506.       else  {
  507.     p[i].rip[0][0] = COLOURS;
  508.     p[i].rip[0][1] = MARSHAL;
  509.     p[i].rip[0][2] = GENERAL;
  510.     p[i].rip[0][3] = M_GENERAL;
  511.     p[i].rip[0][4] = M_GENERAL;
  512.     p[i].rip[1][0] = BRIGADIER;
  513.     p[i].rip[1][1] = BRIGADIER;
  514.     p[i].rip[1][2] = COLONEL;
  515.     p[i].rip[1][3] = COLONEL;
  516.     p[i].rip[1][4] = MAJOR;
  517.     p[i].rip[2][0] = MAJOR;
  518.     p[i].rip[2][1] = CAPTAIN;
  519.     p[i].rip[2][2] = CAPTAIN;
  520.     p[i].rip[2][3] = CAPTAIN;
  521.     p[i].rip[2][4] = F_LIEUTENANT;
  522.     p[i].rip[3][0] = F_LIEUTENANT;
  523.     p[i].rip[3][1] = F_LIEUTENANT;
  524.     p[i].rip[3][2] = SAPPER;
  525.     p[i].rip[3][3] = SAPPER;
  526.     p[i].rip[3][4] = SAPPER;
  527.     p[i].rip[4][0] = MINE;
  528.     p[i].rip[4][1] = MINE;
  529.     p[i].rip[4][2] = MINE;
  530.     p[i].rip[4][3] = BOMB;
  531.     p[i].rip[4][4] = BOMB;
  532.       }
  533.  
  534.     }
  535.  
  536.     if (two) {
  537.     num_player = 2;
  538.     arr[1][0][0].value = arr[1][0][2].value = arr[1][0][4].value =
  539.     arr[3][0][0].value = arr[3][0][2].value = arr[3][0][4].value = PILLAR;
  540.     p[1].state = p[3].state = 3;
  541.     }
  542.     else  num_player = 4;
  543.     mode = 0;
  544. }
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551. /*********************************************************************
  552. *
  553. *   Synopsis
  554. *    int whichplayer(display)
  555. *        Display *display;
  556. *
  557. *   Return values
  558. *    0 - 4    according to whom the display belongs
  559. *    -1     if nobody
  560. *
  561. **********************************************************************/
  562.  
  563. int whichplayer(display)
  564. Display *display;
  565. {
  566.     int i;
  567.  
  568.     for (i=0; i<4; i++) {
  569.     if (two && i%2 != 0)  continue;
  570.     if (p[i].state != 3 && display == p[i].dis)  return(i);
  571.     }
  572.     return(-1);
  573. }
  574.  
  575.  
  576.  
  577. /**********************************************************************
  578. *
  579. *   Synopsis
  580. *    put_msg(s1, s2)
  581. *        char *s1, *s2;
  582. *
  583. *   Description
  584. *    put the two strings into the global msg1 and msg2, and draw them
  585. *    on the board.
  586. *
  587. ***********************************************************************/
  588.  
  589. static void
  590. put_msg(s1, s2)
  591. char *s1, *s2;
  592. {
  593.     int i;
  594.  
  595.     strncpy(msg1, s1, MAX_MSG);
  596.     strncpy(msg2, s2, MAX_MSG);
  597.  
  598.     for (i=0; i<4; i++)
  599.     if (p[i].state != 3) {
  600.         XClearArea(p[i].dis, p[i].win, MSG_BOX_X, MSG_BOX_Y,
  601.         MSG_WIDTH, MSG_HEIGHT, False);
  602.         XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
  603.         XDrawString(p[i].dis, p[i].win, p[i].gc, MSG_X, MSG_Y,
  604.         msg1, strlen(msg1));
  605.         XDrawString(p[i].dis, p[i].win, p[i].gc, MSG_X, MSG_Y+25,
  606.         msg2, strlen(msg2));
  607.     }
  608. }
  609.  
  610.  
  611.  
  612. /*********************************************************************
  613. *
  614. *   Synopsis
  615. *    send_expose_event()
  616. *
  617. *   Description
  618. *    send an expose event to all active players
  619. *
  620. *********************************************************************/
  621.  
  622. static void
  623. send_expose_event()
  624. {
  625.     XEvent event;
  626.     int n;
  627.  
  628.     event.xexpose.x = event.xexpose.y = 0;
  629.     event.xexpose.width = event.xexpose.height = DIMENSION;
  630.     for (n=0; n<4; n++)
  631.     if (p[n].state != 3)
  632.         refresh_board(n, &event);
  633. }
  634.  
  635.  
  636.  
  637.  
  638. /**********************************************************************
  639. *
  640. *   Synopsis
  641. *    redraw_confirm(i)
  642. *        int i;
  643. *
  644. *   Argument
  645. *    i    specifies which player;
  646. *
  647. *   Description
  648. *    redraws the confirmation window, with confirm_msg displayed.
  649. *
  650. ***********************************************************************/
  651.  
  652. static void
  653. redraw_confirm(i)
  654. int i;
  655. {
  656.     XSetForeground(p[i].dis, p[i].gc, BlackPixel(p[i].dis, p[i].scr));
  657.     XDrawRectangle(p[i].dis, p[i].confirm, p[i].gc, 3, 3, 293, 113);
  658.     if (p[i].popup == 3)
  659.     XDrawRectangle(p[i].dis, p[i].confirm, p[i].gc, 100, 75, 99, 19);
  660.     else {
  661.     XDrawRectangle(p[i].dis, p[i].confirm, p[i].gc, 80, 75, 39, 19);
  662.     XDrawRectangle(p[i].dis, p[i].confirm, p[i].gc, 180, 75, 39, 19);
  663.     }
  664.  
  665.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
  666.     if (p[i].popup == 3)
  667.     XDrawString(p[i].dis, p[i].confirm, p[i].gc, 110, 90, "CONTINUE", 8);
  668.     else {
  669.     XDrawString(p[i].dis, p[i].confirm, p[i].gc, 90, 90, "OK", 2);
  670.     XDrawString(p[i].dis, p[i].confirm, p[i].gc, 190, 90, "NO", 2);
  671.     }
  672.     XDrawString(p[i].dis, p[i].confirm, p[i].gc, 30, 40, confirm_msg,
  673.         strlen(confirm_msg));
  674. }
  675.  
  676.  
  677.  
  678.  
  679. /**********************************************************************
  680. *
  681. *   Synopsis
  682. *    Boolean valid_deploy(i)
  683. *        int i;
  684. *
  685. *   Description
  686. *    check if player i's initial deploy is valid.
  687. *
  688. ***********************************************************************/
  689.  
  690. Boolean valid_deploy(i)
  691. int i;
  692. {
  693.     int m, n, k;
  694.  
  695.     if (arr[i][5][1].value != COLOURS && arr[i][5][3].value != COLOURS)
  696.     return(False);
  697.     if (arr[i][1][1].value != EMPTY || arr[i][1][3].value != EMPTY ||
  698.     arr[i][2][2].value != EMPTY || arr[i][3][1].value != EMPTY ||
  699.     arr[i][3][3].value != EMPTY)
  700.       return(False);
  701.  
  702.     k = 0;
  703.     for (m=4; m<6; m++)
  704.       for (n=0; n<5; n++)
  705.     if (arr[i][m][n].value == MINE) k++;
  706.     if (k<3)  return(False);
  707.  
  708.     for (m=0; m<5; m++)
  709.       for (n=0; n<5; n++)
  710.     if (p[i].rip[m][n] != EMPTY)  return(False);
  711.  
  712.     if (arr[i][5][1].value != MINE && arr[i][5][3].value != MINE)
  713.     p[i].num_movable--; 
  714.     return(True);
  715. }
  716.  
  717.  
  718.  
  719.  
  720.  
  721. /***********************************************************************
  722. *
  723. *   Synopsis
  724. *    peace_request(i)
  725. *        int i;
  726. *
  727. *   Description
  728. *    player i request for peace, this can only happen in play mode 1.
  729. *
  730. ************************************************************************/
  731.  
  732. static void
  733. peace_request(i)
  734. int i;
  735. {
  736.     int n;
  737.  
  738.     mode = 2;
  739.  
  740.     for (n=0; n<4; n++)
  741.       if (n != i && p[n].state == 2) {
  742.     p[n].popup = 1;
  743.     sprintf(confirm_msg, "%s requesting peace", p[i].player_name);
  744.     XMapWindow(p[n].dis, p[n].confirm);
  745.       }
  746. }
  747.  
  748.  
  749.  
  750. /********************************************************************
  751. *
  752. *   Synopsis
  753. *    lost_war(i)
  754. *        int i;
  755. *
  756. *   Description
  757. *    player i lost the war, if he/she's partner has lost too, change
  758. *    mode to 3; else, just update the playing array and send an expose
  759. *    event.
  760. *
  761. **********************************************************************/
  762.  
  763. static void
  764. lost_war(i)
  765. int i;
  766. {
  767.     int n, j, k;
  768.  
  769.     p[i].state = 0;
  770.     num_player--;
  771.     if (two || p[(i+2)%4].state != 2) {
  772.     if (!two)
  773.         put_msg(p[i].player_name, "and my ally lost!");
  774.     if (two)
  775.         sprintf(confirm_msg, "%s lost the war", p[i].player_name);
  776.     else
  777.         sprintf(confirm_msg, "%s and %s lost!", p[i].player_name,
  778.             p[(i+2)%4].player_name);
  779.     for (n=0; n<4; n++)
  780.         if (p[n].state != 3) {
  781.         XBell(p[n].dis, 0);
  782.         p[n].popup = 3;
  783.         XMapWindow(p[n].dis, p[n].confirm);
  784.         p[n].state = 0;
  785.         }
  786.     mode = 3;
  787.     send_expose_event();
  788.     }
  789.     else {
  790.     for (n=0; n<4; n++)
  791.      for (j=0; j<6; j++)
  792.       for (k=0; k<5; k++)
  793.         if (arr[n][j][k].value != EMPTY  && arr[n][j][k].id == i) {
  794.         p[i].rip[p[i].rip_index/5][p[i].rip_index%5] =
  795.             arr[n][j][k].value;
  796.         p[i].rip_index++;
  797.         arr[n][j][k].value = EMPTY;
  798.         }
  799.     for (n=0; n<3; n++)
  800.       for (j=0; j<3; j++)
  801.         if (mid[n][j].value != EMPTY && mid[n][j].id == i) {
  802.         p[i].rip[p[i].rip_index/5][p[i].rip_index%5] = mid[n][j].value;
  803.         p[i].rip_index++;
  804.         mid[n][j].value = EMPTY;
  805.         }
  806.     send_expose_event();
  807.     }
  808. }
  809.  
  810.  
  811.  
  812.  
  813.  
  814. /***********************************************************************
  815. *
  816. *   Synopsis
  817. *    new_game()
  818. *
  819. *   Description
  820. *    it clears the board and starts a new game, or quit if someone has gone.
  821. *
  822. ************************************************************************/
  823.  
  824. static void
  825. new_game()
  826. {
  827.     int i, j, k;
  828.  
  829.     if (!two)
  830.       for (i=0; i<4; i++)
  831.     if (p[i].state == 3) {    /* someone has already quit */
  832.         for (k=0; k<4; k++) {
  833.         XFreeCursor(p[k].dis, p[k].cursor);
  834.         XFreeGC(p[k].dis, p[k].gc);
  835.         for (j=0; j<16; j++)
  836.             XFreePixmap(p[k].dis, p[k].node[j]);
  837.         XFreePixmap(p[k].dis, p[k].cursormask_pixmap);
  838.         XFreePixmap(p[k].dis, p[k].icon_pixmap);
  839.         XFreePixmap(p[k].dis, p[k].go_pixmap);
  840.         XFreePixmap(p[k].dis, p[k].stop_pixmap);
  841.         }
  842.         exit(0);
  843.     }
  844.  
  845.     for (i=0; i<4; i++) {
  846.     if (two && i%2 !=0)  continue;
  847.     if (p[i].popup != 0) {
  848.         p[i].popup = 0;
  849.         XUnmapWindow(p[i].dis, p[i].confirm);
  850.     }
  851.     XClearArea(p[i].dis, p[i].win, 0, 0, DIMENSION, DIMENSION, False);
  852.     }
  853.     initial_board();
  854.     put_msg("New War", "deploy first");
  855.     send_expose_event();
  856. }
  857.  
  858.  
  859.  
  860.  
  861.  
  862. /************************************************************************
  863. *
  864. *   Synopsis
  865. *    putsign(i, flag)
  866. *        int i, flag;
  867. *
  868. *   Arguments
  869. *    i    specifies which player's board;
  870. *    flag    0 or 1,  0 to put stop sign, and 1 to put go ahead sign
  871. *
  872. *   Description
  873. *    it puts stop or go-ahead signs in the sign box.
  874. *
  875. *************************************************************************/
  876.  
  877. static void
  878. putsign(i, flag)
  879. int i, flag;
  880. {
  881.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
  882.     if (flag)
  883.     XCopyPlane(p[i].dis, p[i].go_pixmap, p[i].win, p[i].gc, 0, 0,
  884.         SIGN_DIMENSION, SIGN_DIMENSION, P1+2, P1+2, 1);
  885.     else
  886.     XCopyPlane(p[i].dis, p[i].stop_pixmap, p[i].win, p[i].gc, 0, 0,
  887.         SIGN_DIMENSION, SIGN_DIMENSION, P1+2, P1+2, 1);
  888. }
  889.  
  890.  
  891.  
  892.  
  893. /***********************************************************************
  894. *
  895. *   Synopsis
  896. *    putnode(i, value, x, y)
  897. *        int i, value, x, y;
  898. *
  899. *   Arguments
  900. *    i    specifies player i's board;
  901. *    value    -2 -- 15, means clear or an index to the node image;
  902. *    x, y    coordinates of the center of the node on the board;
  903. *
  904. *   Description
  905. *    it draws the image indicated by value at position (x,y) on
  906. *    player i's board.
  907. *    if value is EMPTY, it clear the positioned area.
  908. *    the foreground of the gc should be set before hand.
  909. *    the image is drawn at (x-20, y-20) with width and height of
  910. *    both 40.
  911. *
  912. ************************************************************************/
  913.  
  914. static void
  915. putnode(i, value, x, y)
  916. int i, value, x, y;
  917. {
  918.     if (value == EMPTY)
  919.     XClearArea(p[i].dis, p[i].win, x-20, y-20, 40, 40, False);
  920.     else
  921.     if (value != PILLAR)
  922.         XCopyPlane(p[i].dis, p[i].node[value], p[i].win, p[i].gc, 0, 0,
  923.             40, 40, x-20, y-20, 1);
  924.     else
  925.         XCopyPlane(p[i].dis, pillar[i/2], p[i].win, p[i].gc, 0, 0,
  926.             40, 40, x-20, y-20, 1);
  927. }
  928.  
  929.  
  930.  
  931.  
  932. /************************************************************************
  933. *
  934. *   Synopsis
  935. *    putarea(i, x1, y1, x2, y2)
  936. *        int i, x1, y1, x2, y2)
  937. *
  938. *   Description
  939. *    redraw an area of (x1, y1), (x2, y2) on player i's board.
  940. *    the coordinates are for the board but within the area of F0-F3
  941. *    and MIDFIELD.
  942. *
  943. *************************************************************************/
  944.  
  945. putarea(i, x1, y1, x2, y2)
  946. int i, x1, y1, x2, y2;
  947. {
  948.     int f, k, l, m, n, a1, b1, a2, b2, c, d;
  949.  
  950.     boardtoarr(i, x1, y1, &a1, &b1);
  951.     f = boardtoarr(i, x2, y2, &a2, &b2);
  952.  
  953.     if (a1 > a2) {
  954.     k = a1;  a1 = a2;  a2 = k;
  955.     }
  956.     if (b1 > b2) {
  957.     k = b1;  b1 = b2;  b2 = k;
  958.     }
  959.  
  960.     for (m=a1; m<=a2; m++)
  961.       for (n=b1; n<=b2; n++) {
  962.     if (f == MIDFIELD) {
  963.         k = mid[m][n].value;
  964.         l = mid[m][n].id;
  965.     }
  966.     else {
  967.         k = arr[f][m][n].value;
  968.         l = arr[f][m][n].id;
  969.     }
  970.     if (k == PILLAR)
  971.         XSetForeground(p[i].dis, p[i].gc, BlackPixel(p[i].dis, p[i].scr));
  972.     else
  973.         XSetForeground(p[i].dis, p[i].gc, p[i].fg[l]);
  974.  
  975.     if (k > EMPTY && l != i && p[i].state != 0 &&
  976.         !(k==COLOURS && p[f].marshal_dead) )  k = l + 12;
  977.     arrtoboard(i, f, m, n, &c, &d);
  978.     putnode(i, k, c, d);
  979.       }
  980. }
  981.  
  982.  
  983.  
  984.  
  985. /************************************************************************
  986. *
  987. *   Synopsis
  988. *    refresh_board(i, event)
  989. *        int i;
  990. *        XEvent *event;
  991. *
  992. *   Description
  993. *    refresh player i's board according to the expose event.
  994. *
  995. **************************************************************************/
  996.  
  997. static void
  998. refresh_board(i, event)
  999. int i;
  1000. XEvent *event;
  1001. {
  1002.     int x1, y1, x2, y2;
  1003.     int a1, b1, a2, b2;
  1004.     int c1, d1, c2, d2;
  1005.     int flag, m, n;
  1006.     char s[35];
  1007.  
  1008.     x1 = event->xexpose.x;
  1009.     y1 = event->xexpose.y;
  1010.     x2 = x1 + event->xexpose.width;
  1011.     y2 = y1 + event->xexpose.height;
  1012.  
  1013.  
  1014.     flag = area_intersection(P1, P1, P2, P2, x1,y1, x2,y2, &a1, &b1, &a2, &b2);
  1015.     if (flag) {
  1016.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
  1017.     if (mode == 0 || mode == 3 || turn != i)
  1018.         putsign(i, 0);
  1019.     else putsign(i, 1);
  1020.  
  1021.     XClearArea(p[i].dis, p[i].win, TALK_L_X, TALK_Y, TALK_WIDTH, 150,False);
  1022.  
  1023.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[0]);
  1024.     sprintf(s, "PLAYER 0  (%s)", p[0].player_name);
  1025.     XDrawString(p[i].dis, p[i].win,p[i].gc, TALK0_X, TALK_Y-5, s,strlen(s));
  1026.     n = TALK0_Y;
  1027.     for (m=0; m<3; m++) {
  1028.         XDrawString(p[i].dis, p[i].win, p[i].gc, TALK0_X, n,
  1029.             p[0].talk_msg[m], strlen(p[0].talk_msg[m]));
  1030.         n += TALK_Y_INC;
  1031.     }
  1032.  
  1033.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[2]);
  1034.     sprintf(s, "PLAYER 2  (%s)", p[2].player_name);
  1035.     XDrawString(p[i].dis, p[i].win,p[i].gc, TALK2_X,TALK_Y+85, s,strlen(s));
  1036.     n = TALK2_Y;
  1037.     for (m=0; m<3; m++) {
  1038.         XDrawString(p[i].dis, p[i].win, p[i].gc, TALK2_X, n,
  1039.             p[2].talk_msg[m], strlen(p[2].talk_msg[m]));
  1040.         n += TALK_Y_INC;
  1041.     }
  1042.     }
  1043.  
  1044.     flag = area_intersection(P5, P1, P6, P2, x1,y1, x2,y2, &a1, &b1, &a2, &b2);
  1045.     if (flag) {
  1046.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
  1047.     XClearArea(p[i].dis, p[i].win, MSG_BOX_X, MSG_BOX_Y,
  1048.             MSG_WIDTH, MSG_HEIGHT, False);
  1049.     XDrawString(p[i].dis, p[i].win, p[i].gc, MSG_X, MSG_Y,
  1050.         msg1, strlen(msg1));
  1051.     XDrawString(p[i].dis, p[i].win, p[i].gc, MSG_X, MSG_Y+25,
  1052.         msg2, strlen(msg2));
  1053.  
  1054.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[1]);
  1055.     sprintf(s, "PLAYER 1  (%s)", p[1].player_name);
  1056.     XDrawString(p[i].dis, p[i].win,p[i].gc, TALK1_X, TALK_Y-5, s,strlen(s));
  1057.     n = TALK1_Y;
  1058.     for (m=0; m<3; m++) {
  1059.         XDrawString(p[i].dis, p[i].win, p[i].gc, TALK1_X, n,
  1060.             p[1].talk_msg[m], strlen(p[1].talk_msg[m]));
  1061.         n += TALK_Y_INC;
  1062.     }
  1063.  
  1064.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[3]);
  1065.     sprintf(s, "PLAYER 3  (%s)", p[3].player_name);
  1066.     XDrawString(p[i].dis, p[i].win,p[i].gc, TALK3_X,TALK_Y+85, s,strlen(s));
  1067.     n = TALK3_Y;
  1068.     for (m=0; m<3; m++) {
  1069.         XDrawString(p[i].dis, p[i].win, p[i].gc, TALK3_X, n,
  1070.             p[3].talk_msg[m], strlen(p[3].talk_msg[m]));
  1071.         n += TALK_Y_INC;
  1072.     }
  1073.     }
  1074.  
  1075.     flag = area_intersection(P1+5, RIP_Y+5, P1+RIP_DIMENSION-5,
  1076.     RIP_Y+RIP_DIMENSION-5, x1, y1, x2, y2, &a1, &b1, &a2, &b2);
  1077.     if (flag) {
  1078.     boardtofield(a1, b1, &c1, &d1);
  1079.     boardtofield(a2, b2, &c2, &d2);
  1080.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
  1081.     for (m=c1; m<=c2; m++)
  1082.       for (n=d1; n<=d2; n++) {
  1083.         fieldtoboard(RIP, m, n, &a1, &b1);
  1084.         putnode(i, p[i].rip[m][n], a1, b1);
  1085.       }
  1086.     }
  1087.  
  1088. /* refresh field 0 */
  1089.     flag = area_intersection(P3-20, P5-20, P4+20, P6+20,
  1090.         x1, y1, x2, y2, &a1, &b1, &a2, &b2);
  1091.     if (flag)
  1092.     putarea(i, a1, b1, a2, b2);
  1093.  
  1094.     if (mode > 0) {
  1095. /* refresh field 1 */
  1096.     flag = area_intersection(P5-20, P3-20, P6+20, P4+20,
  1097.         x1, y1, x2, y2, &a1, &b1, &a2, &b2);
  1098.     if (flag)
  1099.         putarea(i, a1, b1, a2, b2);
  1100.  
  1101. /* refresh field 2 */
  1102.         flag = area_intersection(P3-20, P1-20, P4+20, P2+20,
  1103.         x1, y1, x2, y2, &a1, &b1, &a2, &b2);
  1104.     if (flag)
  1105.         putarea(i, a1, b1, a2, b2);
  1106.  
  1107. /* refresh field 3 */
  1108.         flag = area_intersection(P1-20, P3-20, P2+20, P4+20,
  1109.         x1, y1, x2, y2, &a1, &b1, &a2, &b2);
  1110.     if (flag)
  1111.         putarea(i, a1, b1, a2, b2);
  1112.  
  1113. /* refresh midfield */
  1114.         flag = area_intersection(P3-20, P3-20, P4+20, P4+20,
  1115.         x1, y1, x2, y2, &a1, &b1, &a2, &b2);
  1116.     if (flag)
  1117.         putarea(i, a1, b1, a2, b2);
  1118.     }
  1119. }
  1120.  
  1121.  
  1122.  
  1123.  
  1124. /**********************************************************************
  1125. *
  1126. *   Synopsis
  1127. *    talk(i, flag, k)
  1128. *        int i, flag;
  1129. *        char k;
  1130. *
  1131. *   Arguments
  1132. *    i    player i pressed a key;
  1133. *    flag    0 - a printable key; 1 - a backspace; 2 - a Return key;
  1134. *    k    the char if printable;
  1135. *
  1136. *   Description
  1137. *    player i has pressed a key 'k', this function draws the character
  1138. *    in the corresponding talking box.
  1139. *
  1140. ************************************************************************/
  1141.  
  1142. static void
  1143. talk(i, flag, k)
  1144. int i, flag;
  1145. char k;
  1146. {
  1147.     int m;
  1148.     static char s[] = {' ', '\0'};
  1149.  
  1150.  
  1151.     if (flag == 1) {
  1152.     if (p[i].talk_col == 0)   return;
  1153.     s[0] = ' ';
  1154.     p[i].talk_msg[2][p[i].talk_col] = '\0';
  1155.     p[i].talk_col--;
  1156.     for (m=0; m<4; m++)
  1157.         if (p[m].state != 3)
  1158.         XDrawImageString(p[m].dis, p[m].win, p[m].gc,
  1159.             p[i].talk_x+p[i].talk_col*TALK_X_INC, p[i].talk_y,
  1160.             s, 1);
  1161.     return;
  1162.     }
  1163.  
  1164.     for (m=0; m<4; m++)
  1165.     if (p[m].state != 3)
  1166.         XSetForeground(p[m].dis, p[m].gc, p[m].fg[i]);
  1167.  
  1168.     if (flag == 2 || p[i].talk_col >= MAX_MSG) {
  1169.     strcpy(p[i].talk_msg[0], p[i].talk_msg[1]);
  1170.     strcpy(p[i].talk_msg[1], p[i].talk_msg[2]);
  1171.     p[i].talk_msg[2][0] = '\0';
  1172.     p[i].talk_col = 0;
  1173.     for (m=0; m<4; m++)
  1174.         if (p[m].state != 3) {
  1175.         XClearArea(p[m].dis, p[m].win, p[i].talk_x-5,
  1176.             p[i].talk_y-2*TALK_Y_INC-15, TALK_WIDTH, TALK_HEIGHT,
  1177.             False);
  1178.  
  1179.         XDrawImageString(p[m].dis, p[m].win, p[m].gc,
  1180.             p[i].talk_x, p[i].talk_y-2*TALK_Y_INC,
  1181.             p[i].talk_msg[0], strlen(p[i].talk_msg[0]));
  1182.         XDrawImageString(p[m].dis, p[m].win, p[m].gc,
  1183.             p[i].talk_x, p[i].talk_y-TALK_Y_INC,
  1184.             p[i].talk_msg[1], strlen(p[i].talk_msg[1]));
  1185.         }
  1186.     }
  1187.     if (flag == 0) {
  1188.     s[0] = k;
  1189.     for (m=0; m<4; m++)
  1190.         if (p[m].state != 3)
  1191.         XDrawImageString(p[m].dis, p[m].win, p[m].gc,
  1192.             p[i].talk_x+TALK_X_INC*p[i].talk_col,
  1193.             p[i].talk_y, s, 1);
  1194.     p[i].talk_msg[2][p[i].talk_col++] = k;
  1195.     p[i].talk_msg[2][p[i].talk_col] = '\0';
  1196.     }
  1197. }
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205. /**********************************************************************
  1206. *
  1207. *   Synopsis
  1208. *    int move(i, f, x, y)
  1209. *        int i, f, x, y;
  1210. *
  1211. *   Argument
  1212. *    i    0-3, specifies a move from p[i].pick;
  1213. *    f    F0 -- RIP, the destination array;
  1214. *    x, y    subscripts in the destination array;
  1215. *
  1216. *   Return values
  1217. *    0    invalid move;
  1218. *    1    no fight, just a move;
  1219. *    2    source loses;
  1220. *    3    tie;
  1221. *    4    source win;
  1222. *
  1223. ***********************************************************************/
  1224.  
  1225. int move(i, f, x, y)
  1226. int i, f, x, y;
  1227. {
  1228.     int m;
  1229.  
  1230.     if (f == RIP)  return(0);
  1231.     if (two && (f==1 || f==3)) return(0);
  1232.     if (f == MIDFIELD) {
  1233.     m = mid[x][y].value;
  1234.     if (m != EMPTY && (mid[x][y].id==i || (!two && mid[x][y].id==(i+2)%4)))
  1235.         return(0);
  1236.     }
  1237.     else {
  1238.     m = arr[f][x][y].value;
  1239.     if (m != EMPTY && (arr[f][x][y].id==i ||
  1240.                (!two && arr[f][x][y].id==(i+2)%4)))
  1241.         return(0);
  1242.     if (m != EMPTY && ((x==1 && y==1) || (x==1 && y==3) || (x==2 && y==2)
  1243.             || (x==3 && y==1) || (x==3 && y==3)))
  1244.         return(0);
  1245.     }
  1246.  
  1247.     if (!valid_move(p[i].pick.arr, p[i].pick.x, p[i].pick.y, f, x, y))
  1248.     return(0);
  1249.  
  1250.     if (x==5 && (y==1 || y==3))
  1251.      return ((m==COLOURS) ? 3 : 2);
  1252.     if (m == EMPTY)  return(1);
  1253.     return(fight(p[i].pick.value, m));
  1254. }
  1255.  
  1256.  
  1257.  
  1258.  
  1259. /************************************************************************
  1260. *
  1261. *   Synopsis
  1262. *    Boolean lose_check(i, v)
  1263. *        int i, v;
  1264. *
  1265. *   Return values
  1266. *    True    if defeated;
  1267. *    False    otherwise;
  1268. *
  1269. *   Description
  1270. *    player i has just lost a node valued v, this function checks if:
  1271. *        it is the COLOURS, then declares defeated;
  1272. *        it is the MARSHAL, then its COLOURS is showed face up on all
  1273. *        boards;
  1274. *        the player has no moving nodes avaliable, then declares defeated.
  1275. *    the last case is not implemented.
  1276. *
  1277. ***************************************************************************/
  1278.  
  1279. Boolean lose_check(i, v)
  1280. int i, v;
  1281. {
  1282.     int m, k, b, c;
  1283.  
  1284.     if (v == COLOURS)
  1285.     return(True);
  1286.     if (v == MARSHAL) {
  1287.     p[i].marshal_dead = True;
  1288.     m = (arr[i][5][1].value == COLOURS) ? 1 : 3;
  1289.     for (k=0; k<4; k++)
  1290.         if (p[k].state != 3) {
  1291.         XSetForeground(p[k].dis, p[k].gc, p[k].fg[i]);
  1292.         arrtoboard(k, i, 5, m, &b, &c);
  1293.         putnode(k, COLOURS, b, c);
  1294.         }
  1295.     }
  1296.     if ((--p[i].num_movable)==0)  return(True);
  1297.     return(False);
  1298. }
  1299.  
  1300.  
  1301.  
  1302.  
  1303.  
  1304. /***********************************************************************
  1305. *
  1306. *   Synopsis
  1307. *    return_rip(i, v)
  1308. *        int i, v;
  1309. *
  1310. *   Description
  1311. *    returns player i's node valued v to rip.
  1312. *
  1313. ************************************************************************/
  1314.  
  1315. static void
  1316. return_rip(i, v)
  1317. int i, v;
  1318. {
  1319.     int m, n, x, y;
  1320.  
  1321.     m = p[i].rip_index/5;
  1322.     n = p[i].rip_index%5;
  1323.     p[i].rip[m][n] = v;
  1324.     p[i].rip_index++;
  1325.     arrtoboard(i, RIP, m, n, &x, &y);
  1326.     XSetForeground(p[i].dis, p[i].gc, p[i].fg[i]);
  1327.     putnode(i, v, x, y);
  1328. }
  1329.  
  1330.  
  1331.  
  1332.  
  1333. /************************************************************************
  1334. *
  1335. *   Synopsis
  1336. *    show_move(m)
  1337. *        int m;
  1338. *
  1339. *   Argument
  1340. *    m    the moving result from move();
  1341. *
  1342. *   Description
  1343. *    it takes the values from the global arguments (sf,si,sj) and
  1344. *    (df,di,dj) and show the move on the board.
  1345. *    Then, it update the state to implement the move.
  1346. *
  1347. ************************************************************************/
  1348.  
  1349. static void
  1350. show_move(m)
  1351. int m;
  1352. {
  1353.     int a, b, c, v, w, x;
  1354.     char s1[40], s2[40];
  1355.  
  1356.     if (count >= 0) {
  1357.     for (c=0; c<4; c++)
  1358.         if (p[c].state != 3) {
  1359.         if (count>3)
  1360.             arrtoboard(c, sf, si, sj, &a, &b);
  1361.         else
  1362.             arrtoboard(c, df, di, dj, &a, &b);
  1363.         if (count%2 == 0)
  1364.             putnode(c, -1, a, b);
  1365.         else {
  1366.             XSetForeground(p[c].dis, p[c].gc, p[c].fg[sw]);
  1367.             x = sv;
  1368.             if (c!=sw && p[c].state!=0)
  1369.             x = 12 + sw;
  1370.             putnode(c, x, a, b);
  1371.         }
  1372.         }
  1373.     count--;
  1374.     XtAppAddTimeOut(app_context, 300, show_move, m);
  1375.     }
  1376.     else {
  1377.     sprintf(s1, "%s (%d,%d,%d)=>(%d,%d,%d)", p[sw].player_name,
  1378.         sf, si, sj, df, di, dj);
  1379.     if (m == 2)
  1380.         sprintf(s2, "%s lost to %s", p[sw].player_name, p[dw].player_name);
  1381.     else if (m == 3)
  1382.         sprintf(s2, "%s and %s tied", p[sw].player_name, p[dw].player_name);
  1383.     else
  1384.         sprintf(s2, "%s is marching on", p[sw].player_name);
  1385.     put_msg(s1, s2);
  1386.  
  1387.     if (m == 3)
  1388.         if (df == MIDFIELD) mid[di][dj].value = EMPTY;
  1389.         else arr[df][di][dj].value = EMPTY;
  1390.     if (m == 4 || m == 1)
  1391.         if (df == MIDFIELD) {
  1392.         mid[di][dj].value = sv;
  1393.         mid[di][dj].id = sw;
  1394.         }
  1395.         else {
  1396.         arr[df][di][dj].value = sv;
  1397.         arr[df][di][dj].id = sw;
  1398.         }
  1399.  
  1400.     if (df == MIDFIELD) {    
  1401.         w = mid[di][dj].id;
  1402.         v = mid[di][dj].value;
  1403.     }
  1404.     else {
  1405.         w = arr[df][di][dj].id;
  1406.         v = arr[df][di][dj].value;
  1407.     }
  1408.     for (c=0; c<4; c++)
  1409.         if (p[c].state != 3) {
  1410.         arrtoboard(c, df, di, dj, &a, &b);
  1411.         XSetForeground(p[c].dis, p[c].gc, p[c].fg[w]);
  1412.         x = v;
  1413.         if (c!=w && p[c].state!=0 && v!=EMPTY)
  1414.            x = 12 + w;
  1415.         putnode(c, x, a, b);
  1416.         }
  1417.  
  1418.     mode = 1;    /* because lost_war could change mode if lost */
  1419.     if (m == 3 || m == 4) {
  1420.         return_rip(dw, dv);
  1421.         if (lose_check(dw, dv)) lost_war(dw);
  1422.     }
  1423.     if ((mode==1) && (m==2 || m==3)) {
  1424.         return_rip(sw, sv);
  1425.         if (lose_check(sw, sv)) lost_war(sw);
  1426.     }
  1427.     if (mode == 1) {
  1428.         if (two)  turn = (turn + 2) % 4;
  1429.         else
  1430.         do {
  1431.             turn = (turn+1)%4;
  1432.         } while (p[turn].state != 2);
  1433.         putsign(sw, 0);
  1434.         putsign(turn, 1);
  1435.         XBell(p[turn].dis, 0);
  1436.     }
  1437.     }
  1438. }
  1439.  
  1440.  
  1441. main(argc, argv)
  1442. int argc;
  1443. char **argv;
  1444. {
  1445.     int i, j, who, x, y, f, m, n;
  1446.     int agree_to_peace;
  1447.     XEvent event;
  1448.     char buffer, s[40];
  1449.     KeySym keysym;
  1450.     XComposeStatus compose;
  1451.  
  1452.     progname = argv[0];
  1453.     global_argc = argc;
  1454.     global_argv = argv;
  1455.  
  1456.     for (i=0; i<4; i++) {
  1457.     p[i].display_name = NULL;
  1458.     sprintf(p[i].player_name, "PLAYER %d", i);
  1459.     }
  1460.     strcpy(p[0].color_name, PLAYER0_COLOR);
  1461.     strcpy(p[1].color_name, PLAYER1_COLOR);
  1462.     strcpy(p[2].color_name, PLAYER2_COLOR);
  1463.     strcpy(p[3].color_name, PLAYER3_COLOR);
  1464.     p[0].talk_x = p[2].talk_x = TALK0_X;
  1465.     p[1].talk_x = p[3].talk_x = TALK1_X;
  1466.     p[0].talk_y = p[1].talk_y = TALK0_Y+2*TALK_Y_INC;
  1467.     p[2].talk_y = p[3].talk_y = TALK2_Y+2*TALK_Y_INC;
  1468.  
  1469.     debug = False;
  1470.     two = False;
  1471.  
  1472.     parse_arguments(argc, argv);
  1473.  
  1474.     connect_display();
  1475.     initial_sapper();
  1476.     initial_board();
  1477.     turn = 0;
  1478.  
  1479.     for (i=0; i<4; i++) {
  1480.     if (two && i%2 != 0)  continue;
  1481.     XMapWindow(p[i].dis, p[i].win);
  1482.     }
  1483.  
  1484.     while (1) {
  1485.     XtAppNextEvent(app_context, &event);
  1486.     switch(event.type) {
  1487.       case Expose:
  1488.         who = whichplayer(event.xexpose.display);
  1489.         if (who == -1) break;
  1490.  
  1491.         if (p[who].confirm == event.xexpose.window)
  1492.         redraw_confirm(who);
  1493.         else refresh_board(who, &event);
  1494.         break;
  1495.  
  1496.       case ButtonPress:
  1497.         who = whichplayer(event.xbutton.display);
  1498.         if (who == -1) break;
  1499.  
  1500.         if (p[who].popup) {
  1501.         if (event.xbutton.window != p[who].confirm) {
  1502.             XBell(p[who].dis, 0);
  1503.             break;
  1504.         }
  1505.         x = event.xbutton.x;
  1506.         y = event.xbutton.y;
  1507.         if (p[who].popup != 3)
  1508.             if (x>80 && x<120 && y>75 && y<95)  f = 1;
  1509.             else if (x>180 && x<220 && y>75 && y<95)  f = 0;
  1510.             else {
  1511.             XBell(p[who].dis, 0);
  1512.             break;
  1513.             }
  1514.  
  1515.         XUnmapWindow(p[who].dis, p[who].confirm);
  1516.         if (p[who].popup == 3) {
  1517.             p[who].popup = 0;
  1518.             break;
  1519.         }
  1520.         if (p[who].popup == 2) {    /* QUIT popup */
  1521.             if (f) {        /* yes to quit */
  1522.             XUnmapWindow(p[who].dis, p[who].win);
  1523.             if (p[who].state || mode==3 || two) {
  1524.                 for (i=0; i<4; i++) {
  1525.                 if (two && i%2 != 0)  continue;
  1526.                 XFreeCursor(p[i].dis, p[i].cursor);
  1527.                 XFreeGC(p[i].dis, p[i].gc);
  1528.                 for (j=0; j<16; j++)
  1529.                     XFreePixmap(p[i].dis, p[i].node[j]);
  1530.                 XFreePixmap(p[i].dis, p[i].cursormask_pixmap);
  1531.                 XFreePixmap(p[i].dis, p[i].icon_pixmap);
  1532.                 XFreePixmap(p[i].dis, p[i].go_pixmap);
  1533.                 XFreePixmap(p[i].dis, p[i].stop_pixmap);
  1534.                 XFreePixmap(p[i].dis, p[i].nodemask_pixmap);
  1535.                 }
  1536.                 exit(0);
  1537.             }
  1538.             else p[who].state = 3;
  1539.             }
  1540.             p[who].popup = 0;
  1541.         }
  1542.         else    /* PEACE popup */
  1543.             if (f) {
  1544.             agree_to_peace++;
  1545.             p[who].popup = 0;
  1546.             if (agree_to_peace >= num_player) {
  1547.                 strcpy(confirm_msg, "peace arrived!");
  1548.                 for (i=0; i<4; i++)
  1549.                 if (p[i].state != 3) {
  1550.                     p[i].popup = 3;
  1551.                     XMapWindow(p[i].dis, p[i].confirm);
  1552.                 }
  1553.                 mode = 3;
  1554.             }
  1555.             }
  1556.             else {
  1557.             strcpy(confirm_msg, "Absolutely no peace!");
  1558.             for (i=0; i<4; i++)
  1559.                 if (p[i].state != 3) {
  1560.                 if (p[i].popup)
  1561.                     XUnmapWindow(p[i].dis, p[i].confirm);
  1562.                 p[i].popup = 3;
  1563.                 XMapWindow(p[i].dis, p[i].confirm);
  1564.                 }
  1565.             mode = 1;
  1566.             }
  1567.  
  1568.         break;
  1569.         }
  1570.  
  1571.         f = boardtofield(event.xbutton.x, event.xbutton.y, &x, &y);
  1572.         if (f == QUIT) {
  1573.         if (mode!=1 || p[who].state!=2 || who==turn) {
  1574.             strcpy(confirm_msg, "Confirm quit!");
  1575.             p[who].popup = 2;
  1576.             XMapWindow(p[who].dis, p[who].confirm);
  1577.         }
  1578.         else  XBell(p[who].dis, 0);
  1579.         break;
  1580.         }
  1581.  
  1582.         if (f == SURRENDER) {
  1583.         if (mode==1 && p[who].state==2 && turn==who) {
  1584.             put_msg(p[who].player_name, "I surrender, spare me!");
  1585.             if (two)  turn = (turn + 2) % 4;
  1586.             else
  1587.             do {
  1588.                 turn = (turn+1)%4;
  1589.             } while (p[turn].state != 2);
  1590.             XBell(p[turn].dis, 0);
  1591.             lost_war(who);
  1592.         }
  1593.  
  1594.         else XBell(p[who].dis, 0);
  1595.         break;
  1596.         }
  1597.  
  1598.         if (f == PEACE) {
  1599.         if (mode == 1 && p[who].state == 2 && turn == who) {
  1600.             for (i=0; i<4; i++)
  1601.             if (p[i].popup != 0) break;
  1602.             if (i == 4) {
  1603.             agree_to_peace = 1;
  1604.             peace_request(who);
  1605.             break;
  1606.             }
  1607.         }
  1608.         XBell(p[who].dis, 0);
  1609.         break;
  1610.         }
  1611.  
  1612.         if (f == REDEPLOY) {
  1613.         if (mode == 0)  p[who].state = 1;
  1614.         else XBell(p[who].dis, 0);
  1615.         break;
  1616.         }
  1617.  
  1618.         if (f == READY) {
  1619.         if (mode == 0)
  1620.             if (!valid_deploy(who)) {
  1621.             strcpy(confirm_msg,"Invalid deploy");
  1622.             p[who].popup = 3;
  1623.             XMapWindow(p[who].dis, p[who].confirm);
  1624.             XBell(p[who].dis, 0);
  1625.             }
  1626.             else {
  1627.             p[who].state = 2;
  1628.             if (two)
  1629.                 if (p[(who+2)%4].state == 2)  i = 4;
  1630.                 else  i = 0;
  1631.             else
  1632.                 for (i=0; i<4; i++)
  1633.                 if (p[i].state != 2) break;
  1634.  
  1635.             if (i == 4) {
  1636.                 mode = 1;
  1637.                 sprintf(s, "%s moves first", p[turn].player_name);
  1638.                 put_msg("WAR started", s);
  1639.                 send_expose_event();
  1640.                 XBell(p[turn].dis, 0);
  1641.             }
  1642.             }
  1643.         else XBell(p[who].dis, 0);
  1644.         break;
  1645.         }
  1646.  
  1647.         if (f == NEW) {
  1648.         if (mode == 3) new_game();
  1649.         else XBell(p[who].dis, 0);
  1650.         break;
  1651.         }
  1652.  
  1653. /*from now on the button event happened on the board for picking up a node */
  1654.  
  1655.         if (p[who].state==0 || mode>1) {
  1656.         XBell(p[who].dis, 0);
  1657.         break;
  1658.         }
  1659.  
  1660.         f = boardtoarr(who, event.xbutton.x, event.xbutton.y, &x, &y);
  1661.         if (f == -1) {
  1662.         XBell(p[who].dis, 0);
  1663.         break;
  1664.         }
  1665.         p[who].pick.arr = f;
  1666.         p[who].pick.x = x;
  1667.         p[who].pick.y = y;
  1668.         if (mode == 0)
  1669.         if (p[who].state == 1)
  1670.             if (f == RIP && p[who].rip[x][y] != EMPTY)
  1671.             p[who].pick.value = p[who].rip[x][y];
  1672.             else if (f == who && arr[f][x][y].value != EMPTY)
  1673.             p[who].pick.value = arr[f][x][y].value;
  1674.             else {
  1675.             XBell(p[who].dis, 0);
  1676.             break;
  1677.             }
  1678.         else {
  1679.             XBell(p[who].dis, 0);
  1680.             break;
  1681.         }
  1682.         else {
  1683.         if (turn != who) {
  1684.             XBell(p[who].dis, 0);
  1685.             break;
  1686.         }
  1687.         if (f==MIDFIELD && mid[x][y].id==who && mid[x][y].value!=EMPTY)
  1688.             p[who].pick.value = mid[x][y].value;
  1689.         else if (f>=F0 && f<=F3 && arr[f][x][y].id == who &&
  1690.             arr[f][x][y].value!=EMPTY && arr[f][x][y].value!=MINE &&
  1691.             (x!=5 || (y!=1 && y!=3)) )
  1692.             p[who].pick.value = arr[f][x][y].value;
  1693.         else {
  1694.             XBell(p[who].dis, 0);
  1695.             break;
  1696.         }
  1697.         }
  1698.         p[who].pick.picked = True;
  1699.         arrtoboard(who, f, x, y, &m, &n);
  1700.         putnode(who, -1, m, n);
  1701.  
  1702.         p[who].tmp_cursor = XCreatePixmapCursor(p[who].dis,
  1703.         p[who].node[p[who].pick.value], p[who].nodemask_pixmap,
  1704.         &(p[who].fg_color), &(p[who].bg_color),
  1705.         nodemask_x_hot, nodemask_y_hot);
  1706.         XDefineCursor(p[who].dis, p[who].win, p[who].tmp_cursor);
  1707.         break;
  1708.  
  1709.       case ButtonRelease:
  1710.         who = whichplayer(event.xbutton.display);
  1711.         if (who == -1)  break;
  1712.  
  1713.         if (p[who].pick.picked) {
  1714.         XSetForeground(p[who].dis, p[who].gc, p[who].fg[who]);
  1715.         p[who].pick.picked = False;
  1716.         XFreeCursor(p[who].dis, p[who].tmp_cursor);
  1717.         XDefineCursor(p[who].dis, p[who].win, p[who].cursor);
  1718.         f = boardtoarr(who, event.xbutton.x, event.xbutton.y, &x, &y);
  1719.         if (f != -1)
  1720.             if (mode == 0) {
  1721.             if (f == RIP && p[who].rip[x][y] == EMPTY)
  1722.                 p[who].rip[x][y] = p[who].pick.value;
  1723.             else if (f == who && arr[f][x][y].value == EMPTY)
  1724.                 arr[f][x][y].value = p[who].pick.value;
  1725.             else {
  1726.                 arrtoboard(who, p[who].pick.arr, p[who].pick.x,
  1727.                 p[who].pick.y, &m, &n);
  1728.                 putnode(who, p[who].pick.value, m, n);
  1729.                 XBell(p[who].dis, 0);
  1730.                 break;
  1731.             }
  1732.  
  1733.             m = p[who].pick.x;
  1734.             n = p[who].pick.y;
  1735.             if (p[who].pick.arr==RIP)
  1736.                 p[who].rip[m][n] = EMPTY;
  1737.             else  arr[who][m][n].value = EMPTY;
  1738.             arrtoboard(who, f, x, y, &m, &n);
  1739.             putnode(who, p[who].pick.value, m, n);
  1740.             }
  1741.             else {
  1742.             m = move(who, f, x, y);
  1743.             if (m == 0) {    /* invalid move */
  1744.                 arrtoboard(who, p[who].pick.arr, p[who].pick.x,
  1745.                 p[who].pick.y, &m, &n);
  1746.                 putnode(who, p[who].pick.value, m, n);
  1747.                 XBell(p[who].dis, 0);
  1748.             }
  1749.             else {
  1750.                 mode = 4;
  1751.                 sf = p[who].pick.arr;
  1752.                 si = p[who].pick.x;
  1753.                 sj = p[who].pick.y;
  1754.                 df = f;
  1755.                 di = x;
  1756.                 dj = y;
  1757.                 if (sf == MIDFIELD) {
  1758.                 sw = mid[si][sj].id;
  1759.                 sv = mid[si][sj].value;
  1760.                 mid[si][sj].value = EMPTY;
  1761.                 }
  1762.                 else {
  1763.                 sw = arr[sf][si][sj].id;
  1764.                 sv = arr[sf][si][sj].value;
  1765.                 arr[sf][si][sj].value = EMPTY;
  1766.                 }
  1767.                 if (df == MIDFIELD) {
  1768.                 dw = mid[di][dj].id;
  1769.                 dv = mid[di][dj].value;
  1770.                 }
  1771.                 else {
  1772.                 dw = arr[df][di][dj].id;
  1773.                 dv = arr[df][di][dj].value;
  1774.                 }
  1775.                 count = 8;
  1776.                 show_move(m);
  1777.             }
  1778.             }
  1779.         else {
  1780.             arrtoboard(who, p[who].pick.arr, p[who].pick.x,
  1781.                 p[who].pick.y, &m, &n);
  1782.             putnode(who, p[who].pick.value, m, n);
  1783.             XBell(p[who].dis, 0);
  1784.         }
  1785.         } /* if (picked == True) */
  1786.         break;
  1787.  
  1788.       case KeyPress:
  1789.         who = whichplayer(event.xkey.display);
  1790.         if (who == -1)  break;
  1791.  
  1792.         f = XLookupString(&event, &buffer, 1, &keysym, &compose);
  1793.         if (keysym==XK_Return || keysym==XK_Linefeed) {
  1794.         talk(who, 2, '_');
  1795.         break;
  1796.         }
  1797.         if (keysym==XK_BackSpace || keysym==XK_Delete) {
  1798.         talk(who, 1, '_');
  1799.         break;
  1800.         }
  1801.         if (keysym>=XK_space && keysym<=XK_asciitilde)
  1802.         talk(who, 0, buffer);
  1803.         break;
  1804.  
  1805.       case MappingNotify:
  1806.         XRefreshKeyboardMapping(&event);
  1807.         break;
  1808.  
  1809.       default:
  1810.         break;
  1811.     }  /* switch */
  1812.     } /* while(1) */
  1813. }
  1814.  
  1815.  
  1816.  
  1817.  
  1818.  
  1819.