[comp.sources.games] v12i053: bt3 - Broken Throne, multiplayer realtime conquest game

billr@saab.CNA.TEK.COM (Bill Randle) (04/24/91)

Submitted-by: Tom Boutell <boutell@freezer.it.udel.edu>
Posting-number: Volume 12, Issue 53
Archive-name: bt3/Part02
Supersedes: bt2: Volume 12, Issue 22-23
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 bt.doc bt.h btclient.h btserver.h changes
#   interface.c interface.h map.txt msleep.c msleep.h pack.c robot.c
#   ultrix_cpt.h xbt
# Wrapped by billr@saab on Tue Apr 23 13:33:09 1991
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'\" \(765 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# define NO_FDSET if the full set of FD_SET macros are not available
X# (BSD 4.2, SunOS 3.x and Ultrix 2.x)
X#
XCFLAGS = #-DNO_FDSET
X
Xall: btclient btserver btrobot
X
Xbtclient: btclient.o pack.o msleep.o
X	cc btclient.o pack.o msleep.o -o btclient -ltermcap -lcurses -ltermlib
X
Xbtserver: btserver.o pack.o interface.o msleep.o
X	cc btserver.o pack.o interface.o msleep.o -o btserver 
X
Xbtrobot: robot.o pack.o
X	cc robot.o pack.o -o btrobot
X
Xrobot.o: robot.c bt.h
X	cc -c $(CFLAGS) robot.c
X
Xbtclient.o: btclient.c btclient.h bt.h
X	cc -c $(CFLAGS) btclient.c
Xpack.o: pack.c pack.h
X	cc -c pack.c
Xinterface.o: interface.c interface.h
X	cc -c $(CFLAGS) interface.c 
Xbtserver.o: btserver.c btserver.h bt.h
X	cc -c btserver.c 
Xmsleep.o: msleep.c msleep.h
X	cc -c $(CFLAGS) msleep.c
X
END_OF_FILE
if test 765 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'bt.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bt.doc'\"
else
echo shar: Extracting \"'bt.doc'\" \(16973 characters\)
sed "s/^X//" >'bt.doc' <<'END_OF_FILE'
XThe Broken Throne
X
XA multiplayer, realtime game of conquest for the Unix operating system
X
XBy Tom Boutell (boutell@freezer.acs.udel.edu), 11/14/90
XLatest Revision (1.13) 4/22/91
X
XPermission granted to freely copy and alter the code, provided that new
Xversions are cleared through me before release. I will be acting as a
Xsource of information, and would appreciate copies of all changes.
X
XFIRST
X
XSee the readme file for instructions on building the game! This file (bt.doc)
Xcovers the rules of the game, not installation. The readme file also
Xcovers new features of each version and tips on getting it to compile
Xif you don't seem to be having any luck.
X
XTHE STORY
X
XEmperor Lettuce Prei of Squaria has died, leaving no heir. The nobles
Xof the land scramble to reunite the pieces of the Broken Throne; do it
Xfirst and become the next Emperor!
X
XABOUT THE GAME
X
XBroken Throne is a strategic wargame which runs in "real time." Every
Xfew seconds, "action points" are transmitted to the players, which allow
Xthem to do things- recruiting troops, moving troops, attacking, and
Xconstructing and destroying cities. The object is to seize control of
Xall of your opponents' cities; when a player controls no cities, that
Xplayer is out of the game. Gameplay is quite rapid, and the map is
Xcontinuously updated on the screen. All that is required to play is
Xan ordinary terminal with curses screen control; any terminal that can
Xrun a visual editor (like vi or emacs) will do fine. If the terminal
Xis especially large, the game will take advantage of this, displaying
Xmore space between locations and adding extra lines to the output window.
XThis is handy if you are running Xwindows.
X
XThe map of Broken Throne is 16x16, consisting of square "hexes." Each
Xhex may contain one of several types of terrain:
X
X.      Plains
XT      Town         
XM      Mountains (passable) 
XF      Forest
XC      City
XS      Swamp
X^      Crags (impassable mountains)
X
XOn the screen, a hex is displayed like this:
X
XaC05
X
XWhere the lowercase letter is the letter of the player who controls the
Xhex, the capital letter (or . or ^ ) is the terrain type, and the number
Xfollowing is the number of troops. Unowned territories have no lowercase
Xletter, and territories without troops have no following number.
X
XSTARTING OUT
X
XTo launch the game, someone must launch the server program. This is done
Xby typing btserver #ofplayers &, where #ofplayers is replaced by the
Xactual number of combatants and the & sign puts the server in the background.
XPutting the server in the background is important because it allows the
Xplayer who runs the server to play in the game as well.
X
XThen, the individual players each need to launch the client program. This
Xis done by typing btclient addressOfServer, where addressOfServer is the
XInternet address of the machine on which the server is being run.
X
XFor instance, in our local network, bt resides in a subdirectory of my
Xown directory, so a player types:
X
Xcd ~boutell/bt    <-- Of course this should be replaced by the path of your
X                      *own* Broken Throne directory. 
Xbtserver 2 &      ... To launch the game for two players, then each
X                  player moves to the bt directory and types:
Xbtclient toffee   <-- Where "toffee" is the name of the machine the game
X                  is running on. EVEN IF YOU ARE ALL ON THE SAME MACHINE
X                  IT IS STILL NECESSARY TO SPECIFY THE NAME OF THE MACHINE.
X                  ONLY ONE PLAYER LAUNCHES THE SERVER.
X
XThe player who is running the server should start up his client last, in
Xorder to keep his screen from being "munged" as the server announces
Xplayers.
X
XOTHER PORT NUMBERS
X
XIf you do not want to use the default port (2727), or if there is another
XBT game in progress on the same machine, you will need to specify a port
Xnumber. Port numbers should be between 1000 and 9999, the same on both
Xclient and server. Enter the port number after the number of players
Xor machine address, and before the & in the case of the server.
X
XROBOT PLAYERS
X
XIf you can't find opponents or want an added challenge, use the robot
Xplayer! It's launched just like the client, but plays by itself, so
Xput it in background so you can launch your own client and take it on.
XFor example:
X
Xbtrobot toffee &
X
XIt also accepts port numbers if needed. You can launch as many robots
Xas you wish; include them in the player count. The server can't tell them
Xfrom human players.
X
XIMPORTANT NOTE ON USING ROBOTS: If all human players leave a game in which
Xrobots are still playing, they'll keep going, and they never quit! So
Xthe person who launched them should type "jobs" to list the programs
Xrunning, and kill each robot: "kill %n" where n was the listed job
Xnumber of the robot. When all the robots are dead, the server will say
X"Ending," letting you know that the game is completely over.
X
XThe source is in the file robot.c. Have fun modifying it; it plays well
Xearly on but has a rotten endgame, or rather, *no* real endgame. It's
Xintended to be a jumping- off point for other programmers.
X
XONCE THE GAME STARTS:
X
XOnce the client is launched, a blank map will be displayed. Within a moment
Xor two it should be replaced by the full map; be patient if there are
Xseveral players.
X
XWhen the game first begins, the player is told which lowercase letter
Xrepresents them. Initially the player controls one city and no troops.
XIn order to acquire troops, the r (recruit) command should be used
Ximmediately. A cursor will appear at the city's location. This cursor
Xcan be moved with the standard vi/ moria/ hack movement keys:
X
X          k
X          |
X        h-*-l
X          |
X          j
X
XThe space bar is used to actually select a location at which to
Xrecruit. Since the cursor starts out at the first city, the player should
Xjust tap the space bar after pressing r to recruit. Several troops should
Xappear in the city.
X
XIt is then possible to fan out and claim control of towns. The m (move)
Xcommand is used to do this. The player should press m, then move the cursor
Xto the source of the troops, initially the first city, and press the space
Xbar. Then the cursor should be moved to the destination of the troops,
Xwhich can be no more than one hex away; diagonal moves are acceptable.
XWhen the space bar is pressed again, the troops will be moved.
XOnce a new town is reached, the player can use the r command here to recruit
Xmore troops.
X
XRecruitment can only take place every twenty ticks in any given town or city.
XFound in btserver.h is the constant _SPEED, which determines how often a "tick"
Xtakes place, awarding action points and bringing the next recruitment closer.
XThe number of ticks between recruitments can be changed from the default
Xvalue of 20 in the file bt.h.
X
XThe player can attempt to recruit early, but runs the risk of failure, and
Xwill be forced to wait the full time again if recruitment does not succeed.
XThe number of troops recruited is a function of population, not including
Xother towns' population, so towns and cities surrounded by farmland will
Xtend to recruit the most troops, towns surrounded by swamp, very few.
X
XIn order to help keep the player on track, an "R" will appear in the
Xlower right corner of the screen and disappear in a few seconds, each time
Xthe necessary wait between recruitments goes by. The player need not recruit
Xin sync with this message, and it DOES NOT guarantee that you can recruit
Xin a particular town that you've recruited in somewhere in the middle of the
Xlast period. It's just a warning.  
X
XAction points are required to move troops! The player will soon find
Xthemselves running low on them while exploring the area. This is because
Xmovement in unfamiliar territory costs 4 action points per army moved.
XMovement in the player's own territory costs only 2 action points per
Xarmy moved. When each tick takes place, the player will receive 2 action
Xpoints, plus 1 action point for each city under the player's control.
X
XAction points are displayed for each player at the bottom of the screen:
X
XA: 6,13
X
XThis denotes that player A has six hexes (territories) and thirteen
Xaction points.
X
XThe cursor can be moved freely while considering what command to enter
Xnext. The only time you cannot move the cursor is during the entry of a
Xnumber of troops, or a text message to another player.
X
XCOMBAT
X
XCombat in the Broken Throne is simple; the player simply moves troops into
Xenemy territory, and the game resolves the conflict. Each round of battle,
Xthere is a 50% chance the attacker will lose an army, and a 50% chance
Xthe defender will; this continues until one side has no more troops.
XUsually, however, the odds of combat are modified by the terrain of the
Xtwo hexes, as detailed below. If the attacker seizes an opponent's last
Xcity, that opponent is out of the game!
X
XArmies are broken down into units in battle, three units representing
Xeach army. This makes the odds of battle somewhat more realistic while
Xstill allowing for occasional freak outcomes.
X
XTERRAIN
X
XThe different terrain types have different roles in the game. Plains
Xhexes (' . ') have no effect on combat, but provide substantial population.
XThe number of troops a town or city can recruit depends on the surrounding
Xpopulation either controlled by the player or not controlled.
X
XTown hexes (' T ') are the basic source of troops in the game, since
Xrecruitment can only take place here and in cities. They have a strong
Xdefensive advantage, 10%, but no offensive advantage.
X
XMountain hexes (' M ') are difficult to move through. When moving troops
Xinto them, some troops will usually be balked by conditions in the passes,
Xand the action points will still be spent. However, a player in the mountains
Xenjoys a 10% advantage, both defending against attack and when striking
Xdown out of the mountains.
X
XForest hexes (' F ') hide enemy troops from view. A player can only tell
Xwho the forest is controlled by; the exact numbers of troops are hidden.
XForces in a forest enjoy a 5% advantage when attacking out of the forest.
XForces in the forest have a 10% defensive advantage as well.
X
XCity hexes (' C ') are the strongest hexes in the game, with a 15% defensive
Xadvantage, though only a 5% offensive advantage. The player can recruit
Xtroops at cities, and cities also provide an extra action point per tick;
Xthe more cities the player controls, the more resources they have, and
Xthe more quickly they can move armies. Cities can be constructed out of
Xtowns, at a cost of typically 90 action points! This value can be set
Xin the file btserver.h, and is the constant _CONSTRUCTCOST. If a player loses
Xcontrol of all cities, that player is out of the game, and their existing
Xtroops disband, leaving their territory free for the taking! Although
Xbuilding cities is expensive, the action points they provide can quickly
Xmake up for the cost. It is very inexpensive to destroy a city, however,
Xso they should be built in safe areas.
X
XSwamp hexes (' S ') are the armpit of Broken Throne! Troops are very
Xunhappy here; the swamp will often gobble one army of the advancing
Xforce. Swamps have no population, and unless in the player's way, aren't
Xworth slogging through. Troops in a swamp are at a 10% DISadvantage,
Xboth attacking and defending!
X
XCrag hexes (' ^ ') are impassable mountains. It is not possible to
Xenter these hexes, and so they do not affect combat.
X
XCOMMAND REFERENCE& SOME NEW COMMANDS
X
Xc (location): construct a city. This requires, usually, 90 action points,
X  unless the value has been changed in btserver.h before compiling.
X  Can only be used in towns.
Xd (location): destroy a city or town. Usually costs 10 action points.
Xq: quit the game. You must confirm this.
Xt (player letter) (message): Tell a player something. Type their player
X  letter (case is not important) after striking t, then your message to
X  them (one line). The message will appear in their output window. 
Xt # (message): If you type a '#' sign instead of a letter, the message
X  will go to all players, including yourself.
Xm (location) (location) (# of troops): move troops. The game will prompt
X  for the locations from which and to which troops are to be moved, then
X  for the number of troops.
Xr (location): recruit troops. See notes above on the rules of recruitment.
XM (capitalized): redraw a Messy screen. This is useful after a talk
X  request messes up your display.
XESC (Escape key): Cancels *whatever* you are in the process of doing.
X  Very useful for retaining your sanity.
X
XWINNING& LOSING
X
XYou win the game when no other players remain. You lose the game if you
Xcontrol no cities. If your last city is taken (towns don't count), it
Xdoesn't matter how many troops you still have, so be careful to defend
Xthem! When a player is eliminated, any remaining troops and territories
Xare dissolved and available to the first taker.
X
XIf you have lost the game, you can continue to watch the game for as long
Xas you like, before striking 'q' to actually leave the program.
X
XIf you win, the game will not automatically halt itself. You need to type
X'q' to quit the game as the last player. This allows the game to be launched
Xby one person on one terminal to test it out.
X
XThe player who launched the server should see the message "Ending" after
Xthe last player quits. If not, that player should do a ps -aux command
Xand look for a lingering copy of the server, then kill that copy of the
Xserver. (There have been no problems of this sort in the latest release
Xto my knowledge.)
X
XIF YOU ABORT THE PROGRAM
X
XIf you control-c a client, the other players can continue, but you will be
Xout of the game. You will not be able to see what you type unless you quit
Xproperly with the 'q' command. Type 'tset' to repair this.
X
XCUSTOMIZED MAPS
X
XIf you get tired of playing on random maps, try designing your own map!
XAll you have to do is create a file arranged like this:
X
X << 16 across>>
XMMMMFMMFMFMMMMTT
XMMFF....TMMMFFMM ^
XMMMMMMMM.6..MTMM ^
XMMMM..T..MMMMMMM
XMMFFFM..T..TMMMM 1
XMMMMMMMTMMMMMMTM 6
XMMM..1....5...MM
XMMMMMMTMMMMMMMMM d
XMMMMMM...MTMMMMM o
XMMMTMMMMT4MMM3TM w
XMM.....MMMMMMMMM n
XMMMMMMTMTMTMMFFM
XMT..T..MMMMMMMMM v
XMMMMMMMMFFFMTMMM v
XMMMTMMMMTMM.2.MM
XMMMMMMMMMMMMMMMM
X
X(Don't put in the text "16 across" and "16 down," of course.)
X
XThe same terrain letters you see during the game should be used here in
Xthe map file, but with no spaces in between. In addition, in the locations
Xat which players should enter the game, place the numbers one through
Xsix. You should designate a location for all six possible players. If
Xyou play with fewer players, the unused starting locations will become
Xfarmland ('.'); otherwise, they become citadels, and the designated
Xplayers enter the game there. 
X
XTo load the map, give its filename last on the command line when starting
Xthe server:
X
Xbtserver 4 map.txt &
X
XStarts a four- player game, using the file map.txt.
X
Xbtserver 4 2000 map.txt &
X
XStarts a four- player game on port 2000, using the file map.txt.
X
XA sample map, map.txt, is provided to help you get the hang of the map
Xfile system; you can edit it to produce a new map if you wish.
X
XIF YOU'VE DESIGNED GOOD MAPS...
X
XMail them to me at boutell@freezer.acs.udel.edu! I may include a selection
Xof good ones in a future release, and they'll go out to the player- contact
Xmailing list, too.
X
XRUNNING ON LARGE TERMINALS& UNDER X-WINDOWS
X
XUnder X- Windows and on other systems providing large terminals, the game
Xwill take advantage of the terminal's size to provide more spacing and
Xmore room for output messages. The wider and deeper, the better. The game
Xwill *not* take notice if you resize the window while it is running, however.
XYou probably don't want a window wider than about 120 characters, though,
Xsince it becomes difficult to see which locations are next to each other.
X
XA file titled xbt is provided in the distribution. If you chmod this
Xfile to make it executable, you can use it in place of btclient when
Xrunning Xwindows, in order to automatically launch btclient in a
Xnew window using a larger font. I find this file convenient, but it
Xdoesn't make BT a true X program by any stretch of the imagination.
XAn example of its use:
X
Xxbt maplenut
X
X... To connect to a game on the machine "maplenut," exactly as one would
Xby entering "btclient maplenut."
X
XSUNVIEW
X
XPerformance under Sunview is a mixed thing, apparently. On our somewhat
Xolder Sunview, there are problems with Curses that prevent it from running
Xproperly, but under Sunview 3.0 I'm told it works fine.
X
XFINDING OPPONENTS
X
XI've started a Broken Throne contact service! If you want to find opponents,
Xwrite me at boutell@freezer.acs.udel.edu. The game can be played over the
XInternet; I've played decent games against European players. I'll be
Xin touch with folks who write me. Bug reports should also go to the above
Xaddress. And remember, I'm usually up for a game! (I'm not the best player,
Xeither; the best I'm aware of is a friend of mine here who's been playing
Xsince the beginning. HE'S the one you should worry about.)
X 
X
X
END_OF_FILE
if test 16973 -ne `wc -c <'bt.doc'`; then
    echo shar: \"'bt.doc'\" unpacked with wrong size!
fi
# end of 'bt.doc'
fi
if test -f 'bt.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bt.h'\"
else
echo shar: Extracting \"'bt.h'\" \(1378 characters\)
sed "s/^X//" >'bt.h' <<'END_OF_FILE'
X/* Main Include File for Broken Throne
X   By Tom Boutell
X   Do As Thou Wilt, But Give Me The Source!
X
X   If your compiler complains, uncomment
X   the line below (remove the surrounding characters).
X   Thanks to Marcus Ranum: */
X
X/* #define COMPILER_HATES_VOIDSTAR 1 */
X
X#ifdef COMPILER_HATES_VOIDSTAR
Xtypedef char *pointer;
X#else
Xtypedef void *pointer;
X#endif
X
X#ifdef NO_FDSET
X#include "ultrix_cpt.h"
X#endif
X
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
X/* Dimensions of Map
X   Can be changed if your display hardware permits. Make sure you
X   recompile *EVERYTHING.* */ 
X
X#define _MAPX 16
X#define _MAPY 16
X
X/* Messages from server to clients: */
X#define _HEXSTATUS 65
X#define _PLAYERSTATUS 66
X#define _PLAYERDEAD 67
X#define _ACTION 68
X#define _TEXT 69
X#define _STARTUP 70
X#define _END 71
X#define _YOUARE 72
X#define _LOOK 73
X
X/* From clients to server: */
X#define _MOVE 65
X#define _RECRUIT 66
X#define _QUIT 67
X#define _PRIVATE 68
X#define _TELLALL 69
X#define _DISCONNECT 70
X#define _CONSTRUCT 71
X#define _DESTROY 72
X
X/* Number of ticks between safe recruitments: */
X#define _RTICKS 20
X
X/* Maximum number of players: */
X#define _MAXPLAYERS 6
X
END_OF_FILE
if test 1378 -ne `wc -c <'bt.h'`; then
    echo shar: \"'bt.h'\" unpacked with wrong size!
fi
# end of 'bt.h'
fi
if test -f 'btclient.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'btclient.h'\"
else
echo shar: Extracting \"'btclient.h'\" \(1509 characters\)
sed "s/^X//" >'btclient.h' <<'END_OF_FILE'
X/* btclient.h: function declarations for the Broken Throne Client
X   By Tom Boutell, 11/90- 2/91. Do As Thou Wilt, Only Please Send
X   Me Copies!
X
X   The three constants below can be changed if necessary to support
X   unusal codes or non- ASCII machines.
X   Both mdelete and mbackspace are accepted as a backspace key in an
X   effort to improve compatibility with brain- dead Cursi. (Well,
X   what ELSE is the plural of Curses? Cursesi?)
X*/
X
X#define mbackspace 8
X#define mdelete 127
X#define mescape 27
X
X#define _CURSORM1 1
X#define _CURSORM2 2
X#define _CURSORM3 3
X#define _CURSORRECRUIT 4
X#define _CURSORTELL 5
X#define _CURSORCOMMAND 6
X#define _CURSORCONSTRUCT 7
X#define _CURSORDESTROY 8
X
X#define SECONDSLIMIT 0L
X#define MICROSECONDSLIMIT 100000L
X
Xhex map[_MAPX][_MAPY];
Xplayer players[20];
Xint playernumber;
Xint totalplayers;
Xint currenttime;
Xint living;
Xint port;
Xint playerFd;
Xint promptoffset;
Xfd_set events;
Xfd_set realevents;
Xint inputstate;
Xchar* host;
X
Xint connectstream();
Xint inputwaiting();
Xvoid waitevent();
Xint waitshort();
Xvoid setupmap();
Xvoid displayhex();
Xvoid flashhex();
Xvoid tellplayer();
Xvoid displayplayer();
Xvoid readnullterm();
Xvoid handlecommand();
Xvoid endprogram();
Xvoid inputfork();
Xvoid restorescreen();
Xvoid displaysignal();
Xint inrange();
Xvoid promptplayer();
Xint cursorx;
Xint cursory;
XWINDOW* output;
XWINDOW* mapw;
Xint getmessage();
Xint terrainimage[]= { ' ','.','T','M','F','C','S','^' };
Xchar specificspace[256];
Xchar outputline[256];
Xchar* specific;
Xint inputfd;
Xint xsize;
X
END_OF_FILE
if test 1509 -ne `wc -c <'btclient.h'`; then
    echo shar: \"'btclient.h'\" unpacked with wrong size!
fi
# end of 'btclient.h'
fi
if test -f 'btserver.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'btserver.h'\"
else
echo shar: Extracting \"'btserver.h'\" \(1161 characters\)
sed "s/^X//" >'btserver.h' <<'END_OF_FILE'
X/* btserver.h- declarations and controlling constants for Broken Throne.
X   Copyright 1990 by Tom Boutell. */
X
X#define _MAPX 16
X#define _MAPY 16
X#define _SPEED 5
X#define _CITYCOST 90
X#define _DESTROYCOST 10
X
X#define _HEXSTATUS 65
X#define _PLAYERSTATUS 66
X#define _PLAYERDEAD 67
X#define _ACTION 68
X#define _TEXT 69
X#define _STARTUP 70
X#define _END 71
X#define _YOUARE 72
X
X#define _MOVE 65
X#define _RECRUIT 66
X#define _QUIT 67
X#define _PRIVATE 68
X#define _TELLALL 69
X#define _DISCONNECT 70
X#define _CONSTRUCT 71
X#define _DESTROY 72
X
Xhex map[_MAPX][_MAPY];
Xplayer players[20];
Xint currentplayer;
Xint totalplayers;
Xint currenttime;
Xint living;
X
X/* Beware terrain type zero... existing to keep C happy. */
X
Xvoid move(); /* location from,location to,int number */
Xvoid tellcurrentplayer(); /* char* fmt, variable args */
Xvoid setupmap();
Xvoid recruit(); /* location at */
Xint legal(); /* int x,int y */
Xvoid killplayer(); /* int player */
Xchar* namelocation(); /* location at */
Xchar* nameplayer(); /* int player */
Xint cost(); /* int x,y */
Xvoid destroy(); /* location at */
Xvoid construct(); /* location at */
Xvoid endprogram();
Xvoid stopgame(); /* char* message */
END_OF_FILE
if test 1161 -ne `wc -c <'btserver.h'`; then
    echo shar: \"'btserver.h'\" unpacked with wrong size!
fi
# end of 'btserver.h'
fi
if test -f 'changes' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'changes'\"
else
echo shar: Extracting \"'changes'\" \(67 characters\)
sed "s/^X//" >'changes' <<'END_OF_FILE'
XSee the readme file for a description of changes in version 1.13.
X
END_OF_FILE
if test 67 -ne `wc -c <'changes'`; then
    echo shar: \"'changes'\" unpacked with wrong size!
fi
# end of 'changes'
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'\" \(9255 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
X#ifdef sequent
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
X#include <ctype.h>
X#include <signal.h>
X#include <netdb.h>
X#include <varargs.h>
X
X#include "pack.h"
X#include "bt.h"
X#include "btserver.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
Xint currplayer;
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(portnumber)
X  int portnumber;
X{
X  int current;
X  init_socket(portnumber);
X  playertext=(outputline+1);
X  signal(SIGPIPE,broken);
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(theplayer)
X  int theplayer;
X{
X  outputline[0]=_TEXT;
X  w_p(playerids[theplayer],outputline,strlen(&outputline[0])+1);
X} 
X
Xvoid broadcast(messagetype,details)
X  char messagetype;
X  pointer details;
X{
X  location where;
X  location* wherep;
X  int thisplayer;
X  int current;
X  outputline[0]=messagetype;
X  switch (messagetype) {
X   
X    case _HEXSTATUS:
X      wherep=(location*) details;
X      where=(*wherep);
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 _LOOK:
X      where=(*(location*)details);
X      outputline[1]=64+where.x;
X      outputline[2]=64+where.y;
X      outputline[3]=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  
Xvoid broken() {
X  int count;
X  for (count=1; (count<=totalplayers); count++) {
X    if (playerids[count]==currplayer) {
X      killplayer(count);
X      players[currplayer].live=0;
X      break;
X    }
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			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                currplayer=id;
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 9255 -ne `wc -c <'interface.c'`; then
    echo shar: \"'interface.c'\" unpacked with wrong size!
fi
# end of 'interface.c'
fi
if test -f 'interface.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'interface.h'\"
else
echo shar: Extracting \"'interface.h'\" \(601 characters\)
sed "s/^X//" >'interface.h' <<'END_OF_FILE'
Xvoid setupinterface(); /* int portnumber */
Xvoid shutdowninterface();
Xint getrequest();
X     /* int* player,char* requesttype,char* specific */
Xvoid broadcast(); /* char messagetype,void* details */
Xvoid tellplayer(); /* int player */
Xint init_socket(); /* int port */
Xint disconnect_all();
Xint shutdown();
Xchar *hostfrom(); /* int i */
Xchar *hostname();
Xint new_player(); /* int wait */
Xint disconnect(); /* int id */
Xchar *read_player(); /* int playerFd */
Xint w_p(); /* int id, char* str, int len */
Xchar* playertext; /* String to sprinted by tellplayer */
Xvoid broken(); /* Broken pipe handler */
END_OF_FILE
if test 601 -ne `wc -c <'interface.h'`; then
    echo shar: \"'interface.h'\" unpacked with wrong size!
fi
# end of 'interface.h'
fi
if test -f 'map.txt' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'map.txt'\"
else
echo shar: Extracting \"'map.txt'\" \(273 characters\)
sed "s/^X//" >'map.txt' <<'END_OF_FILE'
XMMMMFMMFMFMMMMTT
XMMFF....TMMMFFMM
XMMMMMMMM.6..MTMM
XMMMM..T..MMMMMMM
XMMFFFM..T..TMMMM
XMMMMMMMTMMMMMMTM
XMMM..1....5...MM
XMMMMMMTMMMMMMMMM
XMMMMMM...MTMMMMM
XMMMTMMMMT4MMM3TM
XMM.....MMMMMMMMM
XMMMMMMTMTMTMMFFM
XMT..T..MMMMMMMMM
XMMMMMMMMFFFMTMMM
XMMMTMMMMTMM.2.MM
XMMMMMMMMMMMMMMMM
X
END_OF_FILE
if test 273 -ne `wc -c <'map.txt'`; then
    echo shar: \"'map.txt'\" unpacked with wrong size!
fi
# end of 'map.txt'
fi
if test -f 'msleep.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'msleep.c'\"
else
echo shar: Extracting \"'msleep.c'\" \(250 characters\)
sed "s/^X//" >'msleep.c' <<'END_OF_FILE'
X
X#include "bt.h"
X#include <sys/types.h>
X#include <sys/time.h>
X
X#ifndef NULL
X#define NULL 0
X#endif /* NULL */
X
Xvoid msleep(n)
X  long n;
X{
X  struct timeval sleept;
X  sleept.tv_sec=0;
X  sleept.tv_usec=n;
X  select(FD_SETSIZE,NULL,NULL,NULL,&sleept);
X}
X 
END_OF_FILE
if test 250 -ne `wc -c <'msleep.c'`; then
    echo shar: \"'msleep.c'\" unpacked with wrong size!
fi
# end of 'msleep.c'
fi
if test -f 'msleep.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'msleep.h'\"
else
echo shar: Extracting \"'msleep.h'\" \(224 characters\)
sed "s/^X//" >'msleep.h' <<'END_OF_FILE'
X/* msleep: A portable routine to sleep for n microseconds.
X   By Tom Boutell 2/2/91, from various suggestions from netfolk.
X   (One fellow sent me such a routine earlier, which I have lost.)
X*/
X
Xvoid msleep(/* int n */);   
END_OF_FILE
if test 224 -ne `wc -c <'msleep.h'`; then
    echo shar: \"'msleep.h'\" unpacked with wrong size!
fi
# end of 'msleep.h'
fi
if test -f 'pack.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pack.c'\"
else
echo shar: Extracting \"'pack.c'\" \(757 characters\)
sed "s/^X//" >'pack.c' <<'END_OF_FILE'
X/* pack.c: Functions for packing of Broken Throne data for transmission
X   via sockets. Copyright 1990, Tom Boutell. */
X
X#include "bt.h"
X#include "pack.h"
X
Xvoid packint(offset,contents)
X  int offset;
X  int contents; 
X{
X  outputline[offset]=(contents % 32)+32;
X  contents/=32;
X  outputline[offset+1]=(contents % 32)+32;
X  contents/=32;
X  outputline[offset+2]=(contents % 32)+32;
X}
X
Xvoid striplocation(at,specific,offset)
X  location* at;
X  char* specific;
X  int* offset;
X{
X  at->x=specific[*offset]-64;
X  at->y=specific[*offset+1]-64;
X  *offset+=2;
X}
X
Xvoid stripint(number,specific,offset)
X  int* number;
X  char* specific;
X  int* offset;
X{
X  *number=specific[*offset]-32+(specific[*offset+1]-32)*32+
X          (specific[*offset+2]-32)*1024;
X  *offset+=3;
X}
X
X
END_OF_FILE
if test 757 -ne `wc -c <'pack.c'`; then
    echo shar: \"'pack.c'\" unpacked with wrong size!
fi
# end of 'pack.c'
fi
if test -f 'robot.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'robot.c'\"
else
echo shar: Extracting \"'robot.c'\" \(9828 characters\)
sed "s/^X//" >'robot.c' <<'END_OF_FILE'
X/* Robot player for Broken Throne- 12/90 by Tom Boutell
X   This robot is basically a hacked client. You can use it as a 
X   starting point for robots of your own! */
X
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X#include <signal.h>
X#include <sys/time.h>
X#include <fcntl.h>
X#include <errno.h>
X#include "bt.h"
X#include "pack.h"
X#include <ctype.h>
X#include <math.h>
X#define _MAPX 16
X#define _MAPY 16
X
X#define _HEXSTATUS 65
X#define _PLAYERSTATUS 66
X#define _PLAYERDEAD 67
X#define _ACTION 68
X#define _TEXT 69
X#define _STARTUP 70
X#define _END 71
X#define _YOUARE 72
X#define _MOVE 65
X#define _RECRUIT 66
X#define _QUIT 67
X#define _PRIVATE 68
X#define _TELLALL 69
X#define _DISCONNECT 70
X#define _CONSTRUCT 71
X#define _DESTROY 72
X
X#define SECONDSLIMIT 0L
X#define MICROSECONDSLIMIT 1L
Xhex map[_MAPX][_MAPY];
Xint lastrecruit[_MAPX][_MAPY];
Xplayer players[20];
Xint playernumber;
Xplayer* me;
Xint totalplayers;
Xint currenttime;
Xint living;
Xint port;
Xint playerFd;
Xint promptoffset;
Xfd_set server;
Xint inputstate;
Xchar* host;
Xint connectstream();
Xint inputwaiting();
Xvoid setupmap();
Xvoid readnullterm();
Xvoid endprogram();
Xint inrange();
Xint legal();
Xvoid recruit();
Xvoid move();
Xint getmessage();
Xchar specificspace[256];
Xchar outputline[256];
Xchar* specific;
X
Xmain(argc,argv)
X int argc;
X char* argv[];
X {
X int done;
X char messagetype;
X location at;
X location from,to;
X int theplayer;
X int x,y,roll;
X int xexp,yexp,xnew,ynew;
X int xbest,ybest,sbest,sthis;
X int tried;
X int offset;
X int count;
X if (argc>1) {
X   host=argv[1];
X   if (argc>2) 
X     port=atoi(argv[2]);
X   else
X     port=2727;
X }
X else {
X   printf("Usage: btrobot hostaddress portnumber\n");
X   exit(1);
X }
X
X if (connectstream()==0) {
X   perror("Socket unopenable.\n");
X   exit(1);
X }
X setupmap();
X done=0;
X currenttime=0;
X specific=specificspace;
X while (!getmessage(&messagetype,specific));
X playernumber=specific[0]-64;
X me=(&players[playernumber]);
X xexp=0;
X yexp=0;
X while (!getmessage(&messagetype,specific));
X totalplayers=specific[0]-64;
X for (count=1; (count<=totalplayers); count++) 
X   players[count].live=1;
X
X while (done!=2) {
X   while (getmessage(&messagetype,specific)) {
X     offset=0;
X     switch ((int) messagetype) {
X       case _HEXSTATUS:
X         striplocation(&at,specific,&offset);
X         map[at.x][at.y].terrain=specific[offset]-64;
X         offset++;
X         stripint(&map[at.x][at.y].population,specific,&offset);
X         stripint(&map[at.x][at.y].lastuse,specific,&offset);
X         stripint(&map[at.x][at.y].troops,specific,&offset);
X         map[at.x][at.y].owner=specific[offset]-64;
X         offset++;
X         break;
X       case _PLAYERSTATUS:
X         theplayer=specific[offset]-64;
X         offset++;
X         stripint(&players[theplayer].action,specific,&offset);
X         stripint(&players[theplayer].hexes,specific,&offset);
X         stripint(&players[theplayer].troops,specific,&offset);
X         stripint(&players[theplayer].population,specific,&offset);
X         stripint(&players[theplayer].citadels,specific,&offset);
X         striplocation(&players[theplayer].start,specific,&offset);
X         break;
X       case _PLAYERDEAD:
X         theplayer=specific[0]-64;
X         players[theplayer].live=0;
X         for (y=0; (y<_MAPY); y++) {
X           for (x=0; (x<_MAPX); x++) {
X             if (map[x][y].owner==theplayer) {
X               map[x][y].troops=0;
X               map[x][y].owner=0;
X             }
X           }
X         }
X         if (theplayer==playernumber) {
X           done=2;
X         }
X         break;
X       case _TEXT:
X         break;
X       case _ACTION:
X         for (theplayer=1; (theplayer<=totalplayers); theplayer++) {
X           if (players[theplayer].live==1) {
X             players[theplayer].action+=(2+players[theplayer].citadels);
X           }
X         }
X         currenttime++;
X         break;
X       case _END:
X         done=2;
X         break;
X     }
X   }
X  sleep(1);
X  /* Now it's time to think. */
X  /* Sweep our towns and do useful things: */
X  for (y=0; (y<_MAPY); y++) {
X    for (x=0; (x<_MAPX); x++) {
X      if (map[x][y].owner==playernumber) {
X        if ((map[x][y].terrain==2) || (map[x][y].terrain==5)) {
X          if ((currenttime-lastrecruit[x][y])>20) {
X            recruit(x,y);
X          }
X        }
X      }  
X    }
X  }
X  /* osmose troops around the board. */
X  if ((me->action)>5) {
X    tried=0;
X    while (tried==0) {
X      xexp++;
X      if (xexp==_MAPX) {
X        xexp=0;
X        yexp++;
X        if (yexp==_MAPY) {
X          yexp=0;
X          tried=1;
X        }
X      }
X      if ((map[xexp][yexp].owner==playernumber) && (map[xexp][yexp].troops>0)) {
X        xbest=(-1);
X        ybest=(-1);
X        sbest=(-9999);
X        for (y=(-1); (y<=1); y++) {
X          for (x=(-1); (x<=1); x++) {
X            sthis=0;
X            if (legal(xexp+x,yexp+y)) {
X             if (map[xexp+x][yexp+y].terrain==6)
X               sthis=sthis-50;
X             if (map[xexp+x][yexp+y].owner!=playernumber)
X               sthis=sthis+30;
X             if (map[xexp+x][yexp+y].terrain==2)
X               sthis=sthis+20;
X             if (map[xexp+x][yexp+y].terrain==5)
X               sthis=sthis+25;
X             if ((sthis>sbest) ||
X                 ((sthis==sbest) && (((rand()*512) % 2)==0))) {
X               xbest=xexp+x;
X               ybest=yexp+y;
X               sbest=sthis;
X             }
X            }
X          }
X        } 
X        xnew=xbest;
X        ynew=ybest;              
X        if ((xnew!=xexp) || (ynew!=yexp)) {
X         if ((map[xexp][yexp].terrain!=6) || (((rand()*512) % 10)>7)) {
X           move(xexp,yexp,xnew,ynew,1);
X           tried=1;
X         }
X        }
X      } 
X    }
X  } 
X } 
X /* Terminating code - needs to be called on CTRLC also. */
X endprogram();
X}
X
Xvoid recruit(x,y)
Xint x,y;
X{
X  outputline[0]=_RECRUIT;
X  outputline[1]=x+64;
X  outputline[2]=y+64;
X  outputline[3]=NULL;
X  write(playerFd,outputline,strlen(outputline)+1);
X  lastrecruit[x][y]=currenttime;
X}
X
Xvoid move (x1,y1,x2,y2,troops)
Xint x1,y1,x2,y2,troops;
X{
X  outputline[0]=_MOVE;
X  outputline[1]=x1+64;
X  outputline[2]=y1+64;
X  outputline[3]=x2+64;
X  outputline[4]=y2+64;
X  packint(5,troops);
X  outputline[8]=0;
X  write(playerFd,outputline,strlen(outputline)+1);
X}
X
Xvoid endprogram() {
X  outputline[0]=_DISCONNECT;
X  outputline[1]=NULL;
X  write(playerFd,outputline,strlen(outputline)+1);
X  close(playerFd); 
X}
X
Xint legal(x,y)
Xint x,y;
X{
X  if (inrange(x,0,_MAPX-1) && inrange(y,0,_MAPY-1))
X    return 1;
X  else
X    return 0;
X}
X
Xint inrange(x,low,high)
X  int x;
X  int low;
X  int high;
X{
X  if (x<low || x>high)
X    return 0;
X  return 1;
X}
X       
Xint getmessage(messagetype,specific)
X  char* messagetype;
X  char* specific;
X{
X  char in;
X  int pos;
X  *messagetype=0;
X  *specific=0;
X  if (!inputwaiting(&server,playerFd)) {
X    return 0;
X  }
X  read(playerFd,messagetype,1);
X  pos=0;
X  readnullterm(playerFd,specific);
X  if (*messagetype==0)
X    return 0;
X  else
X    return 1;
X}
X
Xvoid readnullterm(fd,specific)
X  int fd;
X  char* specific;
X{
X  int done;
X  char* current;
X  current=specific;
X  done=0;
X  while (done==0) {
X    while (!inputwaiting(&server,playerFd));
X    read(playerFd,current,1);
X    if (*current==0)
X      done=1;
X    current++;
X  }
X} 
X
Xvoid setupmap(x,y) 
X  int x;
X  int y;
X{
X  for (y=0; (y<_MAPY); y++) {
X    for (x=0; (x<_MAPX); x++) {
X      lastrecruit[x][y]=(-100);
X      map[x][y].terrain=7;
X      map[x][y].troops=0;
X      map[x][y].population=0;
X      map[x][y].owner=0;
X      map[x][y].lastuse=0;
X    }
X  }
X}
X
Xint connectstream()
X{
X  int s;
X  struct sockaddr_in saddr;
X  struct in_addr host_address;
X  if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
X    perror("socket create");
X    return(0);
X  }
X
X  saddr.sin_family = AF_INET;
X  if (!get_host_address(host,&host_address)) {
X    printf("Bad or missing server address.\n");
X    exit(1);
X  }
X  bcopy(&host_address,&saddr.sin_addr,sizeof(struct in_addr));
X  /* saddr.sin_addr.s_addr = htonl(inet_addr(host)); Old method */
X  saddr.sin_port = htons(port);
X
X  if (connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) < 0) {
X    perror("connect");
X    return(0);
X  }
X  FD_SET(s,&server);
X  playerFd=s;
X  return(1);
X}
X
Xint inputwaiting(sfdset,sfd) 
X  fd_set* sfdset;
X  int sfd;
X{
X  int errrec;
X  fd_set readfds;
X  struct timeval waitTime;
X  waitTime.tv_sec=SECONDSLIMIT;
X  waitTime.tv_usec=MICROSECONDSLIMIT;
X  bcopy((char *) sfdset, (char *) &readfds,sizeof(*sfdset));
X  if (select(FD_SETSIZE,&readfds,NULL,NULL,&waitTime)<0) {
X    if (errno!=EINTR) { 
X    perror("select");
X    }
X    return 0;
X  }
X  if (FD_ISSET(sfd,&readfds))
X    return 1;
X  else
X    return 0;
X}
X
X
X/* get_host_address: borrowed with appreciation from Tinytalk. Does a nice
X   job of getting around the various stupidities of the inetaddr routine,
X   et cetera. */
X
Xint get_host_address(name, addr)        /* Get a host address. */
X  register char *name;
X  register struct in_addr *addr;
X{
X  struct hostent *blob;
X  union {                               /* %#@!%!@%#!@ idiot who designed */
X    long signed_thingy;                 /* the inetaddr routine.... */
X    unsigned long unsigned_thingy;
X  } thingy;
X
X  if (*name == '\0') {
X    fprintf(stderr, "%% No host address specified.\n");
X    return (0);
X  }
X
X  if ((*name >= '0') && (*name <= '9')) {       /* IP address. */
X    addr->s_addr = inet_addr(name);
X    thingy.unsigned_thingy = addr->s_addr;
X    if (thingy.signed_thingy == -1) {
X      fprintf(stderr, "%% Couldn't find host %s .\n", name);
X      return (0);
X    }
X  }
X  else {                                /* Host name. */
X    blob = gethostbyname(name);
X
X    if (blob == NULL) {
X      fprintf(stderr, "%% Couldn't find host %s .\n", name);
X      return (0);
X    }
X
X    bcopy(blob->h_addr, addr, sizeof(struct in_addr));
X  }
X
X  return (1);                           /* Success. */
X}
X
X
END_OF_FILE
if test 9828 -ne `wc -c <'robot.c'`; then
    echo shar: \"'robot.c'\" unpacked with wrong size!
fi
# end of 'robot.c'
fi
if test -f 'ultrix_cpt.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ultrix_cpt.h'\"
else
echo shar: Extracting \"'ultrix_cpt.h'\" \(1530 characters\)
sed "s/^X//" >'ultrix_cpt.h' <<'END_OF_FILE'
X/*	@(#)ultrix_cpt.h 1.7 89/09/14 SMI	*/
X
X/* From the XView source distribution */
X/*
X * Ultrix 2.X, SunOS 3.X, BSD 4.2 Compatibility Header File
X *
X * This file provides a limited compatibility with older BSD variants
X * that do not provide macros for dealing with fd sets.
X *
X * BIG NOTE!!! This will only allow fd_sets of N bits , where N is
X * the size of an int.
X *
X */
X
X#ifndef xview_ultrix_compat_DEFINED
X#define xview_ultrix_compat_DEFINED
X
X
X#ifndef NBBY
X#define NBBY    8               /* number of bits in a byte */
X#endif
X
X#ifndef NFDBITS
X#define	NFDBITS	(sizeof(int) * NBBY)
X#define I_DEFINED_NFDBITS	/* register the fact that I defined this */
X#endif
X
X#ifndef FD_SETSIZE
X#define FD_SETSIZE	NFDBITS
X#define I_DEFINED_FDSETSIZE	/* register the fact that I defined this */
X#endif
X
X/*
X *	Here we assume that the only use of howmany(x, y) is 
X *	howmany(FD_SETSIZE, NFDBITS). If we defined both FD_SETSIZE and
X * 	NFDBITS, then we already know what howmany(x, y) will be: 1.
X *	If we did not define FD_SETSIZE and NFDBITS, then we'll have
X *	to calculate the value of howmany(x, y).
X */
X
X#if defined(I_DEFINED_FDSETSIZE) && defined(I_DEFINED_NFDBITS)
X#define howmany(x, y)	1
X#else
X#define howmany(x, y)	(((x)+((y)-1))/(y))
X#endif
X
X#define FD_SET(n, p)    ((p)->fds_bits[0] |= (1 << ((n) % NFDBITS)))
X#define FD_CLR(n, p)    ((p)->fds_bits[0] &= ~(1 << ((n) % NFDBITS)))
X#define FD_ISSET(n, p)  ((p)->fds_bits[0] & (1 << ((n) % NFDBITS)))
X#define FD_ZERO(p)      ((p)->fds_bits[0] = 0)
X
X
X#endif ~xview_ultrix_compat_DEFINED
END_OF_FILE
if test 1530 -ne `wc -c <'ultrix_cpt.h'`; then
    echo shar: \"'ultrix_cpt.h'\" unpacked with wrong size!
fi
# end of 'ultrix_cpt.h'
fi
if test -f 'xbt' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xbt'\"
else
echo shar: Extracting \"'xbt'\" \(83 characters\)
sed "s/^X//" >'xbt' <<'END_OF_FILE'
X#!/bin/sh 
X
Xexec `xterm -fn "-*-fixed-*-*-*-*-*-200-*-*-*-*-*-*" -e btclient $*` &
END_OF_FILE
if test 83 -ne `wc -c <'xbt'`; then
    echo shar: \"'xbt'\" unpacked with wrong size!
fi
chmod +x 'xbt'
# end of 'xbt'
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