[comp.sources.games] v11i076: bt - Broken Throne, multiplayer realtime conquest game, Part02/02

billr@saab.CNA.TEK.COM (Bill Randle) (11/22/90)

Submitted-by: Tom Boutell <boutell@freezer.it.udel.edu>
Posting-number: Volume 11, Issue 76
Archive-name: bt/Part02
Environment: INET sockets, curses

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  Makefile interface.c types.h
# Wrapped by billr@saab on Wed Nov 21 12:13:26 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(306 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
Xbtclient: client.o pack.o
X	cc client.o pack.o -o btclient -ltermcap -lcurses -ltermlib
X
Xbtserver: bt.o pack.o interface.o
X	cc bt.o pack.o interface.o -o btserver
X
Xclient.o: client.c
X	cc -c -g client.c
Xpack.o: pack.c
X	cc -c -g pack.c
Xinterface.o: interface.c
X	cc -c -g interface.c
Xbt.o: bt.c
X	cc -c -g bt.c
END_OF_FILE
if test 306 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'interface.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'interface.c'\"
else
echo shar: Extracting \"'interface.c'\" \(8905 characters\)
sed "s/^X//" >'interface.c' <<'END_OF_FILE'
X
X/* interface.c: Socket communications support& medium- level message
X * passing functions. Copyright (C) 1990 Tom Boutell on original portions.
X * All low- level socket code drawn with appreciation from:
X * SOCK.C
X * Copyright (C)1989 Dr Evil Laboratories
X * This code written by Ray Moody, Roy Riggs, Mitch Adler,
X * Bill Burdick, and Steven Grady
X * No one makes any guarantees about anything.  This file maybe 
X * freely distributed and modified as long as this header remains intact.  
X */
X 
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <string.h>
X#include <ctype.h>
X#include <signal.h>
X#include <netdb.h>
X#include <varargs.h>
X
X#include "types.h"
X#include "pack.h"
X#include "bt.h"
X#include "interface.h"
X
X#define DEBUG
X#undef DEBUG
X#ifdef DEBUG
X#define debug printf
X#else
X#define debug 0+
X#define perror 0+
X#endif
X
X#define SECONDSLIMIT 0L
X#define MICROSECONDSLIMIT 1L
X
X#define LINE_LEN 1024
X#define LOST_CARRIER_MSG "F"
X
X#define NONE (fd_set *) NULL
X#define NEVER (struct timeval *) NULL
X#define IGNORE (struct sockaddr *) NULL
X
Xfd_set active;
Xstruct sockaddr_in sc_in;
Xint s;
Xchar cur_input[LINE_LEN];
Xchar *curhostname = "";
Xint playerids[20];
Xchar outputline[256];
Xvoid setupinterface() {
X  int current;
X  init_socket(2727);
X  playertext=(outputline+1);
X  for (current=1; (current<=totalplayers); current++) {
X    playerids[current]=new_player(0);
X    players[current].live=1;
X    printf("Player %d has joined.\n",current);
X    outputline[0]=_YOUARE;
X    outputline[1]=64+current;
X    outputline[2]=0;
X    w_p(playerids[current],outputline,strlen(&outputline[0])+1);
X    }
X} 
X
Xvoid tellplayer(player)
X  int player;
X{
X  outputline[0]=_TEXT;
X  w_p(playerids[player],outputline,strlen(&outputline[0])+1);
X} 
X
Xvoid broadcast(messagetype,details)
X  char messagetype;
X  void* details;
X{
X  location where;
X  int thisplayer;
X  int current;
X  outputline[0]=messagetype;
X  switch (messagetype) {
X   
X    case _HEXSTATUS:
X      where=*(location*)details;
X      outputline[1]=64+where.x;
X      outputline[2]=64+where.y;
X      outputline[3]=64+map[where.x][where.y].terrain;
X      packint(4,map[where.x][where.y].population);
X      packint(7,map[where.x][where.y].lastuse);
X      packint(10,map[where.x][where.y].troops);
X      outputline[13]=map[where.x][where.y].owner+64;
X      outputline[14]=NULL;
X      break;
X    case _PLAYERSTATUS:
X      thisplayer=*(int*)details;
X      outputline[1]=thisplayer+64;
X      packint(2,players[thisplayer].action);
X      packint(5,players[thisplayer].hexes);
X      packint(8,players[thisplayer].troops);
X      packint(11,players[thisplayer].population);
X      packint(14,players[thisplayer].citadels);
X      outputline[17]=players[thisplayer].start.x+64;
X      outputline[18]=players[thisplayer].start.y+64;
X      outputline[19]=NULL;
X      break;
X    case _PLAYERDEAD:
X      thisplayer=*(int*)details;
X      outputline[1]=thisplayer+64;
X      outputline[2]=NULL;
X      break;
X    case _ACTION:
X      outputline[1]=NULL;	
X      break;
X    case _STARTUP:
X      outputline[1]=totalplayers+64;
X      outputline[2]=NULL;
X      break;
X    case _TEXT:
X      strcpy(&outputline[1],(char*) details);
X      break;
X    case _END:
X      outputline[1]=NULL;
X  }
X  for (current=0; (current<=totalplayers); current++) {
X    if (outputline[0]==_END) {
X    }
X    if (players[current].live) {
X      w_p(playerids[current],outputline,strlen(outputline)+1); 
X    }   
X  }
X}    
X
Xint getrequest(thisplayer,requesttype,specific)
X  int* thisplayer;
X  char* requesttype;
X  char* specific;
X{
X  char* received;
X  static int sweep;
X  int oldsweep;
X  sweep++;
X  if ((sweep>totalplayers) || (sweep<=0))
X    sweep=1;
X  oldsweep=sweep;
X  while (players[sweep].live==0) {
X    sweep++;
X    if (sweep>totalplayers)
X      sweep=1;
X    if (sweep==oldsweep)
X      return 0;
X  }
X  received=read_player(playerids[sweep]);
X  *thisplayer=sweep;
X  if (*received==NULL)
X    return 0;
X  *requesttype=received[0];
X  strcpy(specific,(received+=1));
X  return 1;
X  }           
X
X
Xvoid shutdowninterface() {
X  disconnect_all();
X}
X  
X
X/* - PD Socket code begins here.
X * init_socket() - intialize our socket, port is the port number to use
X *                 call this once at the beginning of your code
X */
X
Xint init_socket(port)
X	int port;
X{
X	setbuf(stdout, (char *)0);
X	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
X		perror("socket");
X		return 0;
X	}
X	sc_in.sin_family = AF_INET;
X	sc_in.sin_addr.s_addr = INADDR_ANY;
X	sc_in.sin_port = htons((u_short) port);
X	if (bind(s, (struct sockaddr *) &sc_in, sizeof(sc_in)) < 0) {
X		perror("bind");
X		return 0;
X	}
X	if (listen(s, 5) < 0) {
X		perror("listen");
X		return 0;
X	}
X
X	FD_ZERO(&active);
X
X	return 1;
X}
X
X
X/*
X * disconnect_all() - throws everyone off
X */
X
Xint disconnect_all()
X{
X	register int i;
X	
X	for (i = 0; i < FD_SETSIZE; i++) {
X		if (FD_ISSET(i, &active))
X			(void) disconnect(i);
X	}
X	return 1;
X}
X
X
X/*
X * shut-down -- kills all connections and exits the pgm
X */
X
Xint shut_down()
X{
X	(void) disconnect_all();
X	exit(0);
X}
X
X
X/* hostfrom() - returns a string containing an ascii name for the host
X *              that the passed socket s is connected to.  Note that the
X *              string is in static space.  If you want to munge with it,
X *              make a copy.
X */
X
Xchar *hostfrom(i)
X	int i;
X{
X	struct sockaddr_in from;
X	int fromlen = sizeof(from);
X	struct hostent *host;
X	struct in_addr addr;
X
X	if (getpeername(i, &from, &fromlen) < 0) {
X		perror("getpeername");
X		return NULL;
X	}
X	
X	addr = from.sin_addr;
X	if ((host = gethostbyaddr(&addr, sizeof(addr), AF_INET)) == NULL) {
X		debug("gethostbyaddr failed");
X		return NULL;
X	}
X	    
X	return curhostname = host->h_name;
X}
X
X
X/*
X * hostname() - returns curhostname
X */
X
Xchar *hostname()
X{
X	return curhostname;
X}
X
X
X/*
X * new_player() - call this routine in your main loop to allow new
X *                players to join.  returns a playerId or -1 if no one
X *                wants to join.
X *                if wait == 0, then put your process to sleep until
X *                someone new tries to connect.
X */
X
Xint new_player(wait)
X	int wait;   /* 0 - wait for activity, else don't wait */
X{
X	fd_set readfds;
X	int j;
X	struct timeval *pWaitTime, waitTime;
X
X	pWaitTime = &waitTime;
X	
X	if (0 == wait) {
X		pWaitTime = NEVER;
X	} else {
X		pWaitTime->tv_sec = SECONDSLIMIT;
X		pWaitTime->tv_usec = MICROSECONDSLIMIT;
X	}
X
X	bcopy((char *) &active, (char *) &readfds, sizeof(active));
X
X	FD_SET(s, &readfds);
X
X	if (select(FD_SETSIZE, &readfds, NONE, NONE, pWaitTime) < 0) {
X		perror("select");
X		return -1;
X	}
X	if (FD_ISSET(s, &readfds)) {
X		if ((j = accept(s, IGNORE, (int *) 0)) < 0) {
X			return -1;
X		}
X		FD_SET(j, &active);
X		curhostname = hostfrom(j);
X		debug("Test Host=%s\n", curhostname);
X		return j;
X	} else {
X		return -1;
X	}
X}
X
X
X/*
X * disconnect() - drop the player with the given id
X */
X
Xint disconnect(id)
X	int id;
X{
X	if (FD_ISSET(id, &active)) {
X		debug("** Just dropped %d\n", id);
X		FD_CLR(id, &active);
X		if (close(id) < 0) {
X			perror("close");
X			return 0;
X		}
X	} else {
X		debug("** Just tried to drop someone not connected\n");
X		return 0;
X	}
X	return 1;
X}
X
X
X/*
X * read_player() - This routine returns the next string from the player
X *                 connected to descriptor playerFd. If there is no
X *                 input it returns the empty string. If the connection
X *                 is lost the string LOST_CARRIER_MSG is returned.
X *                 NOTE: control characters are replaced by spaces
X *                       and it is null terminated at the first nl/cr
X */
X
Xchar *read_player(playerFd)
X	int playerFd;
X{
X	fd_set readfds;
X	struct timeval waitTime;
X	
X	waitTime.tv_sec = SECONDSLIMIT;
X	waitTime.tv_usec = MICROSECONDSLIMIT;
X
X	bcopy((char *) &active, (char *) &readfds, sizeof(active));
X
X	if (select(FD_SETSIZE, &readfds, NONE, NONE, &waitTime) < 0) {
X		perror("select");
X		return("");
X	}
X
X	if (FD_ISSET(playerFd, &readfds)) {
X		int nbytes, i;
X		
X		nbytes = read(playerFd, cur_input, LINE_LEN);
X		if (nbytes < 0) {
X			perror("read");
X			disconnect(playerFd);
X			return(LOST_CARRIER_MSG);
X		} else if (nbytes == 0) {
X			disconnect(playerFd);
X			return(LOST_CARRIER_MSG);
X		} else {
X/* Don't need control editing	for(i=0; i<nbytes; ++i) {
X				if (iscntrl(cur_input[i])) {
X					if (cur_input[i]=='\n' ||
X					    cur_input[i]=='\r')
X						cur_input[i] = '\n';
X					else
X						cur_input[i] = ' ';
X				}
X			}
X*/
X			if (nbytes != LINE_LEN) {
X				cur_input[nbytes] = '\0';
X			} else {
X				cur_input[LINE_LEN - 1] = '\0';
X			}
X
X			return((char *) cur_input);
X		}
X	}
X	return("");
X}
X
X
X/*
X * write_player() - write to id, a string with the given length
X */
X
Xint w_p(id, str, len)
X	int id, len;
X	char *str;
X{
X	if (id > -1) {
X		if (!FD_ISSET(id, &active)) {
X			debug("** Tried to write to closed id #%d.\n", id);
X			return 0;
X		} else if (write(id, str, len) < 0) {
X			perror("Write");
X			return 0;
X		}
X	}
X	return 1;
X}
X
X
X
X
END_OF_FILE
if test 8905 -ne `wc -c <'interface.c'`; then
    echo shar: \"'interface.c'\" unpacked with wrong size!
fi
# end of 'interface.c'
fi
if test -f 'types.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'types.h'\"
else
echo shar: Extracting \"'types.h'\" \(282 characters\)
sed "s/^X//" >'types.h' <<'END_OF_FILE'
Xtypedef struct {
X  char terrain;
X  int population;
X  int lastuse;
X  int troops;
X  int owner;
X} hex;
X
Xtypedef struct {
X  int x;
X  int y;
X} location;
X
Xtypedef struct {
X  int action;
X  int hexes;
X  int troops;
X  int population;
X  int citadels;
X  int live;
X  location start;
X} player;
X
END_OF_FILE
if test 282 -ne `wc -c <'types.h'`; then
    echo shar: \"'types.h'\" unpacked with wrong size!
fi
# end of 'types.h'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0