home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume11 / bt / part01 / client.c < prev    next >
C/C++ Source or Header  |  1990-12-11  |  17KB  |  700 lines

  1. #include <stdio.h>
  2. #include <curses.h>
  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <netdb.h>
  7. #include <signal.h>
  8. #include <sys/time.h>
  9. #include <fcntl.h>
  10. #include <stropts.h>
  11. #include <errno.h>
  12.  
  13. #include "types.h"
  14. #include "pack.h"
  15. #define _MAPX 16
  16. #define _MAPY 16
  17.  
  18. #define _HEXSTATUS 65
  19. #define _PLAYERSTATUS 66
  20. #define _PLAYERDEAD 67
  21. #define _ACTION 68
  22. #define _TEXT 69
  23. #define _STARTUP 70
  24. #define _END 71
  25. #define _YOUARE 72
  26. #define _MOVE 65
  27. #define _RECRUIT 66
  28. #define _QUIT 67
  29. #define _PRIVATE 68
  30. #define _TELLALL 69
  31. #define _DISCONNECT 70
  32. #define _CONSTRUCT 71
  33. #define _DESTROY 72
  34.  
  35. #define _CURSORM1 1
  36. #define _CURSORM2 2
  37. #define _CURSORM3 3
  38. #define _CURSORRECRUIT 4
  39. #define _CURSORTELL 5
  40. #define _CURSORCOMMAND 6
  41. #define _CURSORCONSTRUCT 7
  42. #define _CURSORDESTROY 8
  43.  
  44. #define SECONDSLIMIT 0L
  45. #define MICROSECONDSLIMIT 1L
  46. hex map[_MAPX][_MAPY];
  47. player players[20];
  48. int playernumber;
  49. int totalplayers;
  50. int currenttime;
  51. int living;
  52. int port;
  53. int playerFd;
  54. int promptoffset;
  55. fd_set active;
  56. int inputstate;
  57. char* host;
  58. int connectstream();
  59. int inputwaiting();
  60. void setupmap();
  61. void displayhex();
  62. void tellplayer();
  63. void displayplayer();
  64. void readnullterm();
  65. void handlecommand();
  66. void endprogram();
  67. void inputfork();
  68. void restorescreen();
  69. int inrange();
  70. void promptplayer();
  71. int cursorx;
  72. int cursory;
  73. WINDOW* output;
  74. WINDOW* mapw;
  75. int getmessage();
  76. int terrainimage[]= { ' ','.','T','M','F','C','S','^' };
  77. char specificspace[256];
  78. char outputline[256];
  79. char* specific;
  80. int inputfd;
  81. int xsize;
  82.  
  83. /* Remember to call refresh() when changes need to be visible; right now
  84.    displayhex doesn't do so, in order to be efficient. */
  85. main(argc,argv)
  86.  int argc;
  87.  char* argv[];
  88.  {
  89.  WINDOW* help;
  90.  struct strpeek checkio;
  91.  int inputchar;
  92.  int inputpos;
  93.  char inputline[200];
  94.  int done;
  95.  char messagetype;
  96.  location at;
  97.  location from,to;
  98.  int theplayer;
  99.  int x,y,roll;
  100.  int offset;
  101.  int count;
  102.  int gotmessage;
  103.  if (argc>1) {
  104.    host=argv[1];
  105.    if (argc>2) 
  106.      port=atoi(argv[2]);
  107.    else
  108.      port=2727;
  109.  }
  110.  else {
  111.    printf("Usage: btclient hostaddress portnumber\n");
  112.    exit(1);
  113.  }
  114.  
  115.  if (connectstream()==0) {
  116.    perror("Socket unopenable.\n");
  117.    exit(1);
  118.  }
  119.  initscr();
  120.  cbreak();
  121.  noecho();
  122.  inputstate=_CURSORCOMMAND;
  123.  xsize=COLS/(_MAPX+1);
  124.  promptoffset=0;
  125.  if (xsize<4) {
  126.    printf("The window is too narrow.");
  127.    exit(1);
  128.  }
  129.  output=newwin(LINES-_MAPY-4,COLS-1,20,0);
  130.  scrollok(output,1);
  131.  refresh();
  132.  setupmap();
  133.  signal(SIGTERM,endprogram);
  134.  signal(SIGCONT,restorescreen);
  135.  inputfd=fileno(stdin);
  136.  /* ioctl(fileno(stdin),I_SETSIG,S_INPUT);
  137.  signal(SIGPOLL,inputfork); */
  138.  fflush(stdin);
  139.  done=0;
  140.  inputpos=0;
  141.  specific=specificspace;
  142.  cursorx=-1;
  143.  cursory=-1;
  144.  while (!getmessage(&messagetype,specific));
  145.  playernumber=specific[0]-64;
  146.  sprintf(inputline,"We are player %c.\n",playernumber+64);
  147.  tellplayer(inputline);
  148.  while (!getmessage(&messagetype,specific));
  149.  totalplayers=specific[0]-64;
  150.  for (count=1; (count<=totalplayers); count++) 
  151.    players[count].live=1;
  152.  
  153.  while (done!=2) {
  154.    gotmessage=0;
  155.    while (getmessage(&messagetype,specific)) {
  156.      gotmessage=1;
  157.      offset=0;
  158.      switch ((int) messagetype) {
  159.        case _HEXSTATUS:
  160.          striplocation(&at,specific,&offset);
  161.          map[at.x][at.y].terrain=specific[offset]-64;
  162.          offset++;
  163.          stripint(&map[at.x][at.y].population,specific,&offset);
  164.          stripint(&map[at.x][at.y].lastuse,specific,&offset);
  165.          stripint(&map[at.x][at.y].troops,specific,&offset);
  166.          map[at.x][at.y].owner=specific[offset]-64;
  167.          offset++;
  168.          displayhex(at.x,at.y);
  169.          break;
  170.        case _PLAYERSTATUS:
  171.          theplayer=specific[offset]-64;
  172.          offset++;
  173.          stripint(&players[theplayer].action,specific,&offset);
  174.          stripint(&players[theplayer].hexes,specific,&offset);
  175.          stripint(&players[theplayer].troops,specific,&offset);
  176.          stripint(&players[theplayer].population,specific,&offset);
  177.          stripint(&players[theplayer].citadels,specific,&offset);
  178.          striplocation(&players[theplayer].start,specific,&offset);
  179.          displayplayer(theplayer);
  180.          if ((theplayer==playernumber) && (cursorx==-1)) {
  181.            cursorx=players[theplayer].start.x;
  182.            cursory=players[theplayer].start.y;
  183.          }
  184.          break;
  185.        case _PLAYERDEAD:
  186.          theplayer=specific[0]-64;
  187.          players[theplayer].live=0;
  188.          for (y=0; (y<_MAPY); y++) {
  189.            for (x=0; (x<_MAPX); x++) {
  190.              if (map[x][y].owner==theplayer) {
  191.                map[x][y].troops=0;
  192.                map[x][y].owner=0;
  193.                displayhex(x,y);
  194.              }
  195.            }
  196.          }
  197.          displayplayer(theplayer);
  198.          refresh();
  199.          if (theplayer==playernumber) {
  200.            tellplayer("We are out of the game.\n");
  201.            if (done==3)
  202.              done=2;
  203.            else {
  204.              done=1;
  205.              tellplayer("Press q to exit.\n");
  206.            }
  207.          }
  208.          break;
  209.        case _TEXT:
  210.          tellplayer(sprintf(inputline,"%s\n",specific));
  211.        case _ACTION:
  212.          for (theplayer=1; (theplayer<=totalplayers); theplayer++) {
  213.            if (players[theplayer].live==1) {
  214.              players[theplayer].action+=(2+players[theplayer].citadels);
  215.              displayplayer(theplayer);
  216.            }
  217.          }
  218.          break;
  219.        case _END:
  220.          tellplayer("The game is over.\n");
  221.          tellplayer("Press q to exit.\n");
  222.          done=1;
  223.          break;
  224.      }
  225.    }
  226.   if (done!=0) {
  227.    if (ioctl(inputfd,I_PEEK,&checkio)) {
  228.      inputchar=getch();
  229.      if (inputchar=='q')
  230.        done=2;
  231.    }
  232.   }
  233.   else {
  234.    checkio.flags=0;
  235.    while (ioctl(inputfd,I_PEEK,&checkio)) {
  236.     inputchar=getch();
  237.     switch (inputstate) {
  238.     case _CURSORM1:
  239.     case _CURSORM2:
  240.     case _CURSORRECRUIT:
  241.     case _CURSORCONSTRUCT:
  242.     case _CURSORDESTROY:
  243.      switch(inputchar) {
  244.       case 'h':
  245.       if (cursorx>0) {
  246.         cursorx--;
  247.         displayhex(cursorx+1,cursory);
  248.         displayhex(cursorx,cursory);
  249.       }
  250.       break;
  251.       case 'l':
  252.       if (cursorx<_MAPX-1) {
  253.         cursorx++;
  254.         displayhex(cursorx-1,cursory);
  255.         displayhex(cursorx,cursory);
  256.       }
  257.       break;
  258.       case 'k':
  259.       if (cursory>0) {
  260.         cursory--;
  261.         displayhex(cursorx,cursory+1);
  262.         displayhex(cursorx,cursory);
  263.       }
  264.       break;
  265.       case 'j':
  266.       if (cursory<_MAPY-1) {
  267.         cursory++;
  268.         displayhex(cursorx,cursory-1);
  269.         displayhex(cursorx,cursory);
  270.       }
  271.       break;
  272.       case ' ':
  273.       case '\n':
  274.       switch(inputstate) {
  275.        case _CURSORM1:
  276.        from.x=cursorx;
  277.        from.y=cursory;
  278.        promptplayer("To? ");
  279.        inputstate=_CURSORM2;
  280.        break;
  281.        case _CURSORM2:
  282.        to.x=cursorx;
  283.        to.y=cursory;
  284.        promptplayer("Troops?");
  285.        inputstate=_CURSORM3; 
  286.        break;
  287.        case _CURSORRECRUIT:
  288.        case _CURSORCONSTRUCT:
  289.        case _CURSORDESTROY:
  290.        from.x=cursorx;
  291.        from.y=cursory;
  292.        outputline[1]=from.x+64;
  293.        outputline[2]=from.y+64;
  294.        outputline[3]=NULL;
  295.        switch (inputstate) {
  296.         case _CURSORRECRUIT:
  297.         outputline[0]=_RECRUIT;
  298.         break;
  299.         case _CURSORCONSTRUCT:
  300.         outputline[0]=_CONSTRUCT;
  301.         break;
  302.         case _CURSORDESTROY:
  303.         outputline[0]=_DESTROY;
  304.         break;
  305.        }
  306.        write(playerFd,outputline,strlen(outputline)+1);
  307.        inputstate=_CURSORCOMMAND;
  308.        break;
  309.       }
  310.       break;
  311.      }
  312.     break;
  313.     case _CURSORCOMMAND:
  314.      switch(inputchar) {
  315.       case 'h':
  316.       case '/':
  317.       case '?':
  318.       help=newwin(16,65,1,5);
  319.       werase(help);
  320.       box(help,'|','-');
  321.       wmove(help,0,0);
  322.       mvwprintw(help,1,1,"Broken Throne Help");
  323.       mvwprintw(help,2,1,"m: move troops (from) (to).");
  324.       mvwprintw(help,3,1," Attacking is accomplished by moving into enemy territory.");
  325.       mvwprintw(help,4,1,"r: recruit troops (location): location must be town or city");
  326.       mvwprintw(help,5,1,"c: construct city (location): location must be town");
  327.       mvwprintw(help,6,1,"d: destroy (location): location must be city or town");
  328.       mvwprintw(help,7,1,"q: quit game. Careful, there is no confirmation.");
  329.       mvwprintw(help,8,1,"Where parentheses appear above, you are expected to move");
  330.       mvwprintw(help,9,1,"the cursor with the standard hack/ vi/ moria movement keys:");
  331.       mvwprintw(help,10,1,"h left, l right, j down, k up.");
  332.       mvwprintw(help,11,1,"Select the location by pressing the space bar or RETURN.");
  333.       mvwprintw(help,12,1,"t: tell player (player letter): followed by message.");
  334.       mvwprintw(help,13,1,"Enter a '#' sign instead of a letter to tell all.");
  335.       mvwprintw(help,14,1,"Press any key now to continue play.");
  336.       wrefresh(help);
  337.       inputchar=getch();
  338.       delwin(help);
  339.       touchwin(mapw);
  340.       wrefresh(mapw);
  341.       break; 
  342.       case 'm':
  343.       promptplayer("Move: From? ");
  344.       inputstate=_CURSORM1;
  345.       displayhex(cursorx,cursory);
  346.       break;
  347.       case 'r':
  348.       promptplayer("Recruit: at what location? ");
  349.       inputstate=_CURSORRECRUIT;
  350.       displayhex(cursorx,cursory);
  351.       break;
  352.       case 'c':
  353.       promptplayer("Construct city: at what location? ");
  354.       inputstate=_CURSORCONSTRUCT;
  355.       displayhex(cursorx,cursory);
  356.       break;
  357.       case 'd':
  358.       promptplayer("Destroy city or town: at what location? ");
  359.       inputstate=_CURSORDESTROY;
  360.       displayhex(cursorx,cursory);
  361.       break;
  362.       case 'q':
  363.       tellplayer("Quit\n");
  364.       outputline[0]=_QUIT;
  365.       outputline[1]=NULL;
  366.       done=3;
  367.       write(playerFd,outputline,strlen(outputline)+1);
  368.       break;
  369.       case 't':
  370.       promptplayer("Tell: whom and what? ");
  371.       inputstate=_CURSORTELL;
  372.      }
  373.     break;
  374.     case _CURSORM3:
  375.     case _CURSORTELL:
  376.      switch(inputchar) { 
  377.       case '\b':
  378.         if (inputpos>0) {
  379.           inputpos--;
  380.           move(19,promptoffset+inputpos);
  381.           addch(' ');
  382.           move(19,promptoffset+inputpos);
  383.           refresh();
  384.         }
  385.         break;
  386.       case '\n':
  387.         inputline[inputpos]=NULL;
  388.         move(19,0);
  389.         inputpos=0;
  390.         refresh();
  391.         tellplayer("\n");
  392.         switch(inputstate) {
  393.          case _CURSORTELL:
  394.          if (inputline[0]=='#') {
  395.            outputline[0]=_TELLALL;
  396.            strcpy(&outputline[1],&inputline[1]);
  397.            write(playerFd,outputline,strlen(outputline)+1);
  398.          }
  399.          else {
  400.            outputline[0]=_PRIVATE;
  401.            if (inputline[0]>96)
  402.              inputline[0]-=32;
  403.            if (isalpha(inputline[0])) {
  404.              outputline[1]=inputline[0];
  405.              if (!inrange(outputline[1]-64,1,totalplayers)) {
  406.                tellplayer("Huh?\n");
  407.              }
  408.              else {
  409.                strcpy(&outputline[2],&inputline[1]);
  410.                write(playerFd,outputline,strlen(outputline)+1);
  411.              }
  412.            }
  413.            else
  414.              tellplayer("Huh?\n"); 
  415.          }
  416.          inputstate=_CURSORCOMMAND;
  417.          break;
  418.          case _CURSORM3:
  419.          outputline[0]=_MOVE;
  420.          outputline[1]=from.x+64;
  421.          outputline[2]=from.y+64;
  422.          outputline[3]=to.x+64;
  423.          outputline[4]=to.y+64;
  424.          packint(5,atoi(inputline)); 
  425.          outputline[8]=NULL;
  426.          write(playerFd,outputline,strlen(outputline)+1);
  427.          inputstate=_CURSORCOMMAND;
  428.          break;
  429.         }  
  430.       default:
  431.         if ((inputpos+promptoffset<(COLS-1)) && (!iscntrl(inputchar))) {
  432.           inputline[inputpos]=inputchar;
  433.           move(19,promptoffset+inputpos);
  434.           if (inputpos==0)
  435.             clrtoeol();
  436.           addch(inputchar);
  437.           refresh();
  438.           inputpos++;
  439.         }
  440.      }
  441.     }
  442.    }
  443.   }
  444.   usleep(100000);
  445.   if (gotmessage==1) {
  446.     wrefresh(mapw);
  447.     refresh();
  448.   }
  449.  } 
  450.  /* Terminating code - needs to be called on CTRLC also. */
  451.  endprogram();
  452. }
  453.  
  454. void promptplayer(prompt) 
  455.   char* prompt;
  456. {
  457.   move(19,0);
  458.   clrtoeol();
  459.   addstr(prompt);
  460.   promptoffset=strlen(prompt)+1;
  461.   refresh();
  462. }
  463.  
  464. void restorescreen() {
  465.   refresh();
  466. }
  467.  
  468. void endprogram() {
  469.   outputline[0]=_DISCONNECT;
  470.   outputline[1]=NULL;
  471.   write(playerFd,outputline,strlen(outputline)+1); 
  472.   wclear(output);
  473.   delwin(output);
  474.   clear();
  475.   refresh();
  476.   endwin();
  477.   echo();
  478.   nocbreak();
  479. }
  480.  
  481. int inrange(x,low,high)
  482.   int x;
  483.   int low;
  484.   int high;
  485. {
  486.   if (x<low || x>high)
  487.     return 0;
  488.   return 1;
  489. }
  490.        
  491. int getmessage(messagetype,specific)
  492.   char* messagetype;
  493.   char* specific;
  494. {
  495.   char in;
  496.   int pos;
  497.   *messagetype=0;
  498.   *specific=0;
  499.   if (!inputwaiting()) {
  500.     return 0;
  501.   }
  502.   read(playerFd,messagetype,1);
  503.   pos=0;
  504.   readnullterm(playerFd,specific);
  505.   if (*messagetype==0)
  506.     return 0;
  507.   else
  508.     return 1;
  509. }
  510.  
  511. void readnullterm(fd,specific)
  512.   int fd;
  513.   char* specific;
  514. {
  515.   int done;
  516.   char* current;
  517.   current=specific;
  518.   done=0;
  519.   while (done==0) {
  520.     while (!inputwaiting());
  521.     read(playerFd,current,1);
  522.     if (*current==0)
  523.       done=1;
  524.     current++;
  525.   }
  526.  
  527. void setupmap(x,y) 
  528.   int x;
  529.   int y;
  530. {
  531.   for (y=0; (y<_MAPY); y++) {
  532.     move(y+1,0);
  533.     addch(48+((y/10) % 10));
  534.     move(y+1,1);
  535.     addch(48+(y % 10));
  536.   }
  537.   for (x=0; (x<_MAPX); x++) {
  538.     move(0,x*xsize+5);
  539.     addch(65+x);
  540.   }
  541.   mapw=newwin(_MAPY,0,1,4);
  542.   for (y=0; (y<_MAPY); y++) {
  543.     for (x=0; (x<_MAPX); x++) {
  544.       map[x][y].terrain=7;
  545.       map[x][y].troops=0;
  546.       map[x][y].population=0;
  547.       map[x][y].owner=0;
  548.       map[x][y].lastuse=0;
  549.       displayhex(x,y);
  550.     }
  551.   }
  552.   refresh();
  553.   wrefresh(mapw);
  554. }
  555.  
  556. void displayhex(x,y)
  557.   int x;
  558.   int y;
  559. {
  560.   int redraw;
  561.   redraw=0;
  562.   if ((x==cursorx) && (y==cursory))  {
  563.     wstandout(mapw);
  564.     redraw=1;
  565.   }
  566.   else
  567.     wstandend(mapw);
  568.   wmove(mapw,y,x*xsize);
  569.   if (map[x][y].owner>0) 
  570.     waddch(mapw,96+map[x][y].owner);
  571.   else 
  572.     waddch(mapw,' ');
  573.   wmove(mapw,y,x*xsize+1);
  574.   waddch(mapw,terrainimage[map[x][y].terrain]);
  575.   if (((map[x][y].terrain!=4) || map[x][y].owner==playernumber)
  576.       && (map[x][y].troops>0)) {
  577.     wmove(mapw,y,x*xsize+2);
  578.     waddch(mapw,48+((map[x][y].troops/10) % 10));
  579.     wmove(mapw,y,x*xsize+3);
  580.     waddch(mapw,48+(map[x][y].troops % 10)); 
  581.   }
  582.   else {
  583.     wmove(mapw,y,x*xsize+2);
  584.     waddstr(mapw,"  ");
  585.   }
  586.   wstandend(mapw);
  587.   if (redraw==1)
  588.     wrefresh(mapw);
  589.   wmove(mapw,y,x*xsize+1);
  590. }
  591.   
  592. int connectstream()
  593. {
  594.   int s;
  595.   struct sockaddr_in saddr;
  596.   struct in_addr host_address;
  597.   if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  598.     perror("socket create");
  599.     return(0);
  600.   }
  601.  
  602.   saddr.sin_family = AF_INET;
  603.   if (!get_host_address(host,&host_address)) {
  604.     printf("Bad or missing server address.\n");
  605.     exit(1);
  606.   }
  607.   bcopy(&host_address,&saddr.sin_addr,sizeof(struct in_addr));
  608.   /* saddr.sin_addr.s_addr = htonl(inet_addr(host)); Old method */
  609.   saddr.sin_port = htons(port);
  610.  
  611.   if (connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) < 0) {
  612.     perror("connect");
  613.     return(0);
  614.   }
  615.   FD_SET(s,&active);
  616.   playerFd=s;
  617.   return(1);
  618. }
  619.  
  620. int inputwaiting() {
  621.   int errrec;
  622.   fd_set readfds;
  623.   struct timeval waitTime;
  624.   waitTime.tv_sec=SECONDSLIMIT;
  625.   waitTime.tv_usec=MICROSECONDSLIMIT;
  626.   bcopy((char *) &active, (char *) &readfds,sizeof(active));
  627.   if (select(FD_SETSIZE,&readfds,NULL,NULL,&waitTime)<0) {
  628.     if (errno!=EINTR) { 
  629.     perror("select");
  630.     }
  631.     return 0;
  632.   }
  633.   if (FD_ISSET(playerFd,&readfds))
  634.     return 1;
  635.   else
  636.     return 0;
  637. }
  638.  
  639. void tellplayer(this)
  640.   char* this;
  641. {
  642.   wprintw(output,this);
  643.   wrefresh(output);  
  644. }
  645.  
  646. void displayplayer(theplayer)
  647.   int theplayer;
  648. {
  649.   static char outputline[100];
  650.   move(18,theplayer*10-9);
  651.   if (players[theplayer].live==1) 
  652.     addstr(sprintf(outputline,"%c:%d ,%d ",theplayer+64,
  653.                    players[theplayer].hexes,players[theplayer].action));
  654.   else addstr(sprintf(outputline,"%c: Dead",theplayer+64));
  655. }
  656.  
  657. /* get_host_address: borrowed with appreciation from Tinytalk. Does a nice
  658.    job of getting around the various stupidities of the inetaddr routine,
  659.    et cetera. */
  660.  
  661. int get_host_address(name, addr)        /* Get a host address. */
  662.   register char *name;
  663.   register struct in_addr *addr;
  664. {
  665.   struct hostent *blob;
  666.   union {                               /* %#@!%!@%#!@ idiot who designed */
  667.     long signed_thingy;                 /* the inetaddr routine.... */
  668.     unsigned long unsigned_thingy;
  669.   } thingy;
  670.  
  671.   if (*name == '\0') {
  672.     fprintf(stderr, "%% No host address specified.\n");
  673.     return (0);
  674.   }
  675.  
  676.   if ((*name >= '0') && (*name <= '9')) {       /* IP address. */
  677.     addr->s_addr = inet_addr(name);
  678.     thingy.unsigned_thingy = addr->s_addr;
  679.     if (thingy.signed_thingy == -1) {
  680.       fprintf(stderr, "%% Couldn't find host %s .\n", name);
  681.       return (0);
  682.     }
  683.   }
  684.   else {                                /* Host name. */
  685.     blob = gethostbyname(name);
  686.  
  687.     if (blob == NULL) {
  688.       fprintf(stderr, "%% Couldn't find host %s .\n", name);
  689.       return (0);
  690.     }
  691.  
  692.     bcopy(blob->h_addr, addr, sizeof(struct in_addr));
  693.   }
  694.  
  695.   return (1);                           /* Success. */
  696. }
  697.  
  698.  
  699.