home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume11
/
bt
/
part01
/
client.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-12-11
|
17KB
|
700 lines
#include <stdio.h>
#include <curses.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stropts.h>
#include <errno.h>
#include "types.h"
#include "pack.h"
#define _MAPX 16
#define _MAPY 16
#define _HEXSTATUS 65
#define _PLAYERSTATUS 66
#define _PLAYERDEAD 67
#define _ACTION 68
#define _TEXT 69
#define _STARTUP 70
#define _END 71
#define _YOUARE 72
#define _MOVE 65
#define _RECRUIT 66
#define _QUIT 67
#define _PRIVATE 68
#define _TELLALL 69
#define _DISCONNECT 70
#define _CONSTRUCT 71
#define _DESTROY 72
#define _CURSORM1 1
#define _CURSORM2 2
#define _CURSORM3 3
#define _CURSORRECRUIT 4
#define _CURSORTELL 5
#define _CURSORCOMMAND 6
#define _CURSORCONSTRUCT 7
#define _CURSORDESTROY 8
#define SECONDSLIMIT 0L
#define MICROSECONDSLIMIT 1L
hex map[_MAPX][_MAPY];
player players[20];
int playernumber;
int totalplayers;
int currenttime;
int living;
int port;
int playerFd;
int promptoffset;
fd_set active;
int inputstate;
char* host;
int connectstream();
int inputwaiting();
void setupmap();
void displayhex();
void tellplayer();
void displayplayer();
void readnullterm();
void handlecommand();
void endprogram();
void inputfork();
void restorescreen();
int inrange();
void promptplayer();
int cursorx;
int cursory;
WINDOW* output;
WINDOW* mapw;
int getmessage();
int terrainimage[]= { ' ','.','T','M','F','C','S','^' };
char specificspace[256];
char outputline[256];
char* specific;
int inputfd;
int xsize;
/* Remember to call refresh() when changes need to be visible; right now
displayhex doesn't do so, in order to be efficient. */
main(argc,argv)
int argc;
char* argv[];
{
WINDOW* help;
struct strpeek checkio;
int inputchar;
int inputpos;
char inputline[200];
int done;
char messagetype;
location at;
location from,to;
int theplayer;
int x,y,roll;
int offset;
int count;
int gotmessage;
if (argc>1) {
host=argv[1];
if (argc>2)
port=atoi(argv[2]);
else
port=2727;
}
else {
printf("Usage: btclient hostaddress portnumber\n");
exit(1);
}
if (connectstream()==0) {
perror("Socket unopenable.\n");
exit(1);
}
initscr();
cbreak();
noecho();
inputstate=_CURSORCOMMAND;
xsize=COLS/(_MAPX+1);
promptoffset=0;
if (xsize<4) {
printf("The window is too narrow.");
exit(1);
}
output=newwin(LINES-_MAPY-4,COLS-1,20,0);
scrollok(output,1);
refresh();
setupmap();
signal(SIGTERM,endprogram);
signal(SIGCONT,restorescreen);
inputfd=fileno(stdin);
/* ioctl(fileno(stdin),I_SETSIG,S_INPUT);
signal(SIGPOLL,inputfork); */
fflush(stdin);
done=0;
inputpos=0;
specific=specificspace;
cursorx=-1;
cursory=-1;
while (!getmessage(&messagetype,specific));
playernumber=specific[0]-64;
sprintf(inputline,"We are player %c.\n",playernumber+64);
tellplayer(inputline);
while (!getmessage(&messagetype,specific));
totalplayers=specific[0]-64;
for (count=1; (count<=totalplayers); count++)
players[count].live=1;
while (done!=2) {
gotmessage=0;
while (getmessage(&messagetype,specific)) {
gotmessage=1;
offset=0;
switch ((int) messagetype) {
case _HEXSTATUS:
striplocation(&at,specific,&offset);
map[at.x][at.y].terrain=specific[offset]-64;
offset++;
stripint(&map[at.x][at.y].population,specific,&offset);
stripint(&map[at.x][at.y].lastuse,specific,&offset);
stripint(&map[at.x][at.y].troops,specific,&offset);
map[at.x][at.y].owner=specific[offset]-64;
offset++;
displayhex(at.x,at.y);
break;
case _PLAYERSTATUS:
theplayer=specific[offset]-64;
offset++;
stripint(&players[theplayer].action,specific,&offset);
stripint(&players[theplayer].hexes,specific,&offset);
stripint(&players[theplayer].troops,specific,&offset);
stripint(&players[theplayer].population,specific,&offset);
stripint(&players[theplayer].citadels,specific,&offset);
striplocation(&players[theplayer].start,specific,&offset);
displayplayer(theplayer);
if ((theplayer==playernumber) && (cursorx==-1)) {
cursorx=players[theplayer].start.x;
cursory=players[theplayer].start.y;
}
break;
case _PLAYERDEAD:
theplayer=specific[0]-64;
players[theplayer].live=0;
for (y=0; (y<_MAPY); y++) {
for (x=0; (x<_MAPX); x++) {
if (map[x][y].owner==theplayer) {
map[x][y].troops=0;
map[x][y].owner=0;
displayhex(x,y);
}
}
}
displayplayer(theplayer);
refresh();
if (theplayer==playernumber) {
tellplayer("We are out of the game.\n");
if (done==3)
done=2;
else {
done=1;
tellplayer("Press q to exit.\n");
}
}
break;
case _TEXT:
tellplayer(sprintf(inputline,"%s\n",specific));
case _ACTION:
for (theplayer=1; (theplayer<=totalplayers); theplayer++) {
if (players[theplayer].live==1) {
players[theplayer].action+=(2+players[theplayer].citadels);
displayplayer(theplayer);
}
}
break;
case _END:
tellplayer("The game is over.\n");
tellplayer("Press q to exit.\n");
done=1;
break;
}
}
if (done!=0) {
if (ioctl(inputfd,I_PEEK,&checkio)) {
inputchar=getch();
if (inputchar=='q')
done=2;
}
}
else {
checkio.flags=0;
while (ioctl(inputfd,I_PEEK,&checkio)) {
inputchar=getch();
switch (inputstate) {
case _CURSORM1:
case _CURSORM2:
case _CURSORRECRUIT:
case _CURSORCONSTRUCT:
case _CURSORDESTROY:
switch(inputchar) {
case 'h':
if (cursorx>0) {
cursorx--;
displayhex(cursorx+1,cursory);
displayhex(cursorx,cursory);
}
break;
case 'l':
if (cursorx<_MAPX-1) {
cursorx++;
displayhex(cursorx-1,cursory);
displayhex(cursorx,cursory);
}
break;
case 'k':
if (cursory>0) {
cursory--;
displayhex(cursorx,cursory+1);
displayhex(cursorx,cursory);
}
break;
case 'j':
if (cursory<_MAPY-1) {
cursory++;
displayhex(cursorx,cursory-1);
displayhex(cursorx,cursory);
}
break;
case ' ':
case '\n':
switch(inputstate) {
case _CURSORM1:
from.x=cursorx;
from.y=cursory;
promptplayer("To? ");
inputstate=_CURSORM2;
break;
case _CURSORM2:
to.x=cursorx;
to.y=cursory;
promptplayer("Troops?");
inputstate=_CURSORM3;
break;
case _CURSORRECRUIT:
case _CURSORCONSTRUCT:
case _CURSORDESTROY:
from.x=cursorx;
from.y=cursory;
outputline[1]=from.x+64;
outputline[2]=from.y+64;
outputline[3]=NULL;
switch (inputstate) {
case _CURSORRECRUIT:
outputline[0]=_RECRUIT;
break;
case _CURSORCONSTRUCT:
outputline[0]=_CONSTRUCT;
break;
case _CURSORDESTROY:
outputline[0]=_DESTROY;
break;
}
write(playerFd,outputline,strlen(outputline)+1);
inputstate=_CURSORCOMMAND;
break;
}
break;
}
break;
case _CURSORCOMMAND:
switch(inputchar) {
case 'h':
case '/':
case '?':
help=newwin(16,65,1,5);
werase(help);
box(help,'|','-');
wmove(help,0,0);
mvwprintw(help,1,1,"Broken Throne Help");
mvwprintw(help,2,1,"m: move troops (from) (to).");
mvwprintw(help,3,1," Attacking is accomplished by moving into enemy territory.");
mvwprintw(help,4,1,"r: recruit troops (location): location must be town or city");
mvwprintw(help,5,1,"c: construct city (location): location must be town");
mvwprintw(help,6,1,"d: destroy (location): location must be city or town");
mvwprintw(help,7,1,"q: quit game. Careful, there is no confirmation.");
mvwprintw(help,8,1,"Where parentheses appear above, you are expected to move");
mvwprintw(help,9,1,"the cursor with the standard hack/ vi/ moria movement keys:");
mvwprintw(help,10,1,"h left, l right, j down, k up.");
mvwprintw(help,11,1,"Select the location by pressing the space bar or RETURN.");
mvwprintw(help,12,1,"t: tell player (player letter): followed by message.");
mvwprintw(help,13,1,"Enter a '#' sign instead of a letter to tell all.");
mvwprintw(help,14,1,"Press any key now to continue play.");
wrefresh(help);
inputchar=getch();
delwin(help);
touchwin(mapw);
wrefresh(mapw);
break;
case 'm':
promptplayer("Move: From? ");
inputstate=_CURSORM1;
displayhex(cursorx,cursory);
break;
case 'r':
promptplayer("Recruit: at what location? ");
inputstate=_CURSORRECRUIT;
displayhex(cursorx,cursory);
break;
case 'c':
promptplayer("Construct city: at what location? ");
inputstate=_CURSORCONSTRUCT;
displayhex(cursorx,cursory);
break;
case 'd':
promptplayer("Destroy city or town: at what location? ");
inputstate=_CURSORDESTROY;
displayhex(cursorx,cursory);
break;
case 'q':
tellplayer("Quit\n");
outputline[0]=_QUIT;
outputline[1]=NULL;
done=3;
write(playerFd,outputline,strlen(outputline)+1);
break;
case 't':
promptplayer("Tell: whom and what? ");
inputstate=_CURSORTELL;
}
break;
case _CURSORM3:
case _CURSORTELL:
switch(inputchar) {
case '\b':
if (inputpos>0) {
inputpos--;
move(19,promptoffset+inputpos);
addch(' ');
move(19,promptoffset+inputpos);
refresh();
}
break;
case '\n':
inputline[inputpos]=NULL;
move(19,0);
inputpos=0;
refresh();
tellplayer("\n");
switch(inputstate) {
case _CURSORTELL:
if (inputline[0]=='#') {
outputline[0]=_TELLALL;
strcpy(&outputline[1],&inputline[1]);
write(playerFd,outputline,strlen(outputline)+1);
}
else {
outputline[0]=_PRIVATE;
if (inputline[0]>96)
inputline[0]-=32;
if (isalpha(inputline[0])) {
outputline[1]=inputline[0];
if (!inrange(outputline[1]-64,1,totalplayers)) {
tellplayer("Huh?\n");
}
else {
strcpy(&outputline[2],&inputline[1]);
write(playerFd,outputline,strlen(outputline)+1);
}
}
else
tellplayer("Huh?\n");
}
inputstate=_CURSORCOMMAND;
break;
case _CURSORM3:
outputline[0]=_MOVE;
outputline[1]=from.x+64;
outputline[2]=from.y+64;
outputline[3]=to.x+64;
outputline[4]=to.y+64;
packint(5,atoi(inputline));
outputline[8]=NULL;
write(playerFd,outputline,strlen(outputline)+1);
inputstate=_CURSORCOMMAND;
break;
}
default:
if ((inputpos+promptoffset<(COLS-1)) && (!iscntrl(inputchar))) {
inputline[inputpos]=inputchar;
move(19,promptoffset+inputpos);
if (inputpos==0)
clrtoeol();
addch(inputchar);
refresh();
inputpos++;
}
}
}
}
}
usleep(100000);
if (gotmessage==1) {
wrefresh(mapw);
refresh();
}
}
/* Terminating code - needs to be called on CTRLC also. */
endprogram();
}
void promptplayer(prompt)
char* prompt;
{
move(19,0);
clrtoeol();
addstr(prompt);
promptoffset=strlen(prompt)+1;
refresh();
}
void restorescreen() {
refresh();
}
void endprogram() {
outputline[0]=_DISCONNECT;
outputline[1]=NULL;
write(playerFd,outputline,strlen(outputline)+1);
wclear(output);
delwin(output);
clear();
refresh();
endwin();
echo();
nocbreak();
}
int inrange(x,low,high)
int x;
int low;
int high;
{
if (x<low || x>high)
return 0;
return 1;
}
int getmessage(messagetype,specific)
char* messagetype;
char* specific;
{
char in;
int pos;
*messagetype=0;
*specific=0;
if (!inputwaiting()) {
return 0;
}
read(playerFd,messagetype,1);
pos=0;
readnullterm(playerFd,specific);
if (*messagetype==0)
return 0;
else
return 1;
}
void readnullterm(fd,specific)
int fd;
char* specific;
{
int done;
char* current;
current=specific;
done=0;
while (done==0) {
while (!inputwaiting());
read(playerFd,current,1);
if (*current==0)
done=1;
current++;
}
}
void setupmap(x,y)
int x;
int y;
{
for (y=0; (y<_MAPY); y++) {
move(y+1,0);
addch(48+((y/10) % 10));
move(y+1,1);
addch(48+(y % 10));
}
for (x=0; (x<_MAPX); x++) {
move(0,x*xsize+5);
addch(65+x);
}
mapw=newwin(_MAPY,0,1,4);
for (y=0; (y<_MAPY); y++) {
for (x=0; (x<_MAPX); x++) {
map[x][y].terrain=7;
map[x][y].troops=0;
map[x][y].population=0;
map[x][y].owner=0;
map[x][y].lastuse=0;
displayhex(x,y);
}
}
refresh();
wrefresh(mapw);
}
void displayhex(x,y)
int x;
int y;
{
int redraw;
redraw=0;
if ((x==cursorx) && (y==cursory)) {
wstandout(mapw);
redraw=1;
}
else
wstandend(mapw);
wmove(mapw,y,x*xsize);
if (map[x][y].owner>0)
waddch(mapw,96+map[x][y].owner);
else
waddch(mapw,' ');
wmove(mapw,y,x*xsize+1);
waddch(mapw,terrainimage[map[x][y].terrain]);
if (((map[x][y].terrain!=4) || map[x][y].owner==playernumber)
&& (map[x][y].troops>0)) {
wmove(mapw,y,x*xsize+2);
waddch(mapw,48+((map[x][y].troops/10) % 10));
wmove(mapw,y,x*xsize+3);
waddch(mapw,48+(map[x][y].troops % 10));
}
else {
wmove(mapw,y,x*xsize+2);
waddstr(mapw," ");
}
wstandend(mapw);
if (redraw==1)
wrefresh(mapw);
wmove(mapw,y,x*xsize+1);
}
int connectstream()
{
int s;
struct sockaddr_in saddr;
struct in_addr host_address;
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket create");
return(0);
}
saddr.sin_family = AF_INET;
if (!get_host_address(host,&host_address)) {
printf("Bad or missing server address.\n");
exit(1);
}
bcopy(&host_address,&saddr.sin_addr,sizeof(struct in_addr));
/* saddr.sin_addr.s_addr = htonl(inet_addr(host)); Old method */
saddr.sin_port = htons(port);
if (connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) < 0) {
perror("connect");
return(0);
}
FD_SET(s,&active);
playerFd=s;
return(1);
}
int inputwaiting() {
int errrec;
fd_set readfds;
struct timeval waitTime;
waitTime.tv_sec=SECONDSLIMIT;
waitTime.tv_usec=MICROSECONDSLIMIT;
bcopy((char *) &active, (char *) &readfds,sizeof(active));
if (select(FD_SETSIZE,&readfds,NULL,NULL,&waitTime)<0) {
if (errno!=EINTR) {
perror("select");
}
return 0;
}
if (FD_ISSET(playerFd,&readfds))
return 1;
else
return 0;
}
void tellplayer(this)
char* this;
{
wprintw(output,this);
wrefresh(output);
}
void displayplayer(theplayer)
int theplayer;
{
static char outputline[100];
move(18,theplayer*10-9);
if (players[theplayer].live==1)
addstr(sprintf(outputline,"%c:%d ,%d ",theplayer+64,
players[theplayer].hexes,players[theplayer].action));
else addstr(sprintf(outputline,"%c: Dead",theplayer+64));
}
/* get_host_address: borrowed with appreciation from Tinytalk. Does a nice
job of getting around the various stupidities of the inetaddr routine,
et cetera. */
int get_host_address(name, addr) /* Get a host address. */
register char *name;
register struct in_addr *addr;
{
struct hostent *blob;
union { /* %#@!%!@%#!@ idiot who designed */
long signed_thingy; /* the inetaddr routine.... */
unsigned long unsigned_thingy;
} thingy;
if (*name == '\0') {
fprintf(stderr, "%% No host address specified.\n");
return (0);
}
if ((*name >= '0') && (*name <= '9')) { /* IP address. */
addr->s_addr = inet_addr(name);
thingy.unsigned_thingy = addr->s_addr;
if (thingy.signed_thingy == -1) {
fprintf(stderr, "%% Couldn't find host %s .\n", name);
return (0);
}
}
else { /* Host name. */
blob = gethostbyname(name);
if (blob == NULL) {
fprintf(stderr, "%% Couldn't find host %s .\n", name);
return (0);
}
bcopy(blob->h_addr, addr, sizeof(struct in_addr));
}
return (1); /* Success. */
}