home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume15 / bt4 / part01 < prev    next >
Encoding:
Text File  |  1993-01-26  |  54.2 KB  |  2,076 lines

  1. Path: uunet!charon.amdahl.com!pacbell.com!iggy.GW.Vitalink.COM!cs.widener.edu!eff!sol.ctr.columbia.edu!destroyer!gatech!emory!ogicse!zephyr.ens.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v15i015:  bt4 - Broken Throne, multiplayer realtime conquest game (V2.03), Part01/03
  5. Message-ID: <3826@master.CNA.TEK.COM>
  6. Date: 29 Oct 92 01:41:54 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2064
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1514
  11.  
  12. Submitted-by: boutell@isis.cshl.org (Tom Boutell)
  13. Posting-number: Volume 15, Issue 15
  14. Archive-name: bt4/Part01
  15. Supersedes: bt3: Volume 12, Issue 52-53
  16. Environment: INET sockets, curses
  17.  
  18.     [This is the latest version of Broken Throne. It includes internal
  19.      restructuring, new features and AIX support. -br]
  20.  
  21. #! /bin/sh
  22. # This is a shell archive.  Remove anything before this line, then unpack
  23. # it by saving it into a file and typing "sh file".  To overwrite existing
  24. # files, type "sh file -c".  You can also feed this as standard input via
  25. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  26. # will see the following message at the end:
  27. #        "End of archive 1 (of 3)."
  28. # Contents:  MANIFEST btrobot.c btserver.c
  29. # Wrapped by billr@saab on Wed Oct 28 17:38:00 1992
  30. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  31. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  32.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  33. else
  34. echo shar: Extracting \"'MANIFEST'\" \(765 characters\)
  35. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  36. X   File Name        Archive #    Description
  37. X-----------------------------------------------------------
  38. X INSTALL                    3    
  39. X MANIFEST                   1    This shipping list
  40. X Makefile                   3    
  41. X bt.doc                     2    
  42. X bt.h                       3    
  43. X btclient.c                 2    
  44. X btclient.h                 2    
  45. X btinterface.c              3    
  46. X btinterface.h              3    
  47. X btpack.c                   3    
  48. X btpack.h                   3    
  49. X btrobot.c                  1    
  50. X btserver.c                 1    
  51. X btserver.h                 2    
  52. X btserverrc                 2    
  53. X changes                    2    
  54. X map.txt                    3    
  55. X msleep.c                   3    
  56. X msleep.h                   3    
  57. X readme                     3    
  58. X xbt                        3    
  59. END_OF_FILE
  60. if test 765 -ne `wc -c <'MANIFEST'`; then
  61.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  62. fi
  63. # end of 'MANIFEST'
  64. fi
  65. if test -f 'btrobot.c' -a "${1}" != "-c" ; then 
  66.   echo shar: Will not clobber existing file \"'btrobot.c'\"
  67. else
  68. echo shar: Extracting \"'btrobot.c'\" \(10429 characters\)
  69. sed "s/^X//" >'btrobot.c' <<'END_OF_FILE'
  70. X/*
  71. X * Robot player for Broken Throne- 12/90 by Tom Boutell This robot is
  72. X * basically a hacked client. You can use it as a starting point for robots
  73. X * of your own!
  74. X */
  75. X
  76. X
  77. X#include <stdio.h>
  78. X#include <sys/types.h>
  79. X#include <sys/socket.h>
  80. X#include <netinet/in.h>
  81. X#include <netdb.h>
  82. X#include <signal.h>
  83. X#include <sys/time.h>
  84. X#include <fcntl.h>
  85. X#include <errno.h>
  86. X#include <ctype.h>
  87. X#include <math.h>
  88. X
  89. X#include "bt.h"
  90. X#include "btpack.h"
  91. X
  92. X#define SECONDSLIMIT 0L
  93. X#define MICROSECONDSLIMIT 1L
  94. Xhex           **map;
  95. Xint             gamemapsizex;
  96. Xint             gamemapsizey;
  97. Xplayer          players[20];
  98. Xint             playernumber;
  99. Xplayer         *me;
  100. Xint             totalplayers;
  101. Xint             currenttime;
  102. Xint             living;
  103. Xint             port;
  104. Xint             playerFd;
  105. Xint             promptoffset;
  106. Xfd_set          server;
  107. Xint             inputstate;
  108. Xchar           *host;
  109. Xint             connectstream();
  110. Xint             inputwaiting();
  111. Xvoid            setupmap();
  112. Xvoid            readnullterm();
  113. Xvoid            endprogram();
  114. Xint             inrange();
  115. Xint             legal();
  116. Xvoid            move();
  117. Xint             getmessage();
  118. Xchar            specificspace[256];
  119. Xchar            outputline[256];
  120. Xchar           *specific;
  121. X
  122. Xmain(argc, argv)
  123. X    int             argc;
  124. X    char           *argv[];
  125. X{
  126. X    char            hostname[81];
  127. X    int             done;
  128. X    char            messagetype;
  129. X    location        at;
  130. X    location        from, to;
  131. X    int             theplayer;
  132. X    int             x, y, roll;
  133. X    int             xexp, yexp, xnew, ynew;
  134. X    int             xbest, ybest, sbest, sthis;
  135. X    int             tried;
  136. X    int             offset;
  137. X    int             count;
  138. X    int             i;
  139. X    port = 2727;
  140. X    gethostname(hostname, 80);
  141. X    host = hostname;
  142. X    for (i = 1; (i < argc); i++) {
  143. X        if (strcmp(argv[i], "-h") == 0) {
  144. X            if ((i + 1) < argc) {
  145. X                host = argv[++i];
  146. X            } else {
  147. X                fprintf(stderr, "btrobot: hostname missing for -h option.\n");
  148. X                exit(-1);
  149. X            }
  150. X        } else if (strcmp(argv[i], "-p") == 0) {
  151. X            if ((i + 1) < argc) {
  152. X                port = atoi(argv[++i]);
  153. X            } else {
  154. X                fprintf(stderr, "btrobot: port # missing for -p option.\n");
  155. X                exit(-1);
  156. X            }
  157. X        } else {
  158. X            fprintf(stderr, "Unknown option.\n");
  159. X            fprintf(stderr, "Usage: btrobot -h hostname [-p port#]\n");
  160. X            exit(-1);
  161. X        }
  162. X    }
  163. X
  164. X    if (connectstream() == 0) {
  165. X        perror("Socket unopenable.\n");
  166. X        exit(1);
  167. X    }
  168. X    signal(SIGPIPE, endprogram);
  169. X    signal(SIGTERM, endprogram);
  170. X    signal(SIGQUIT, endprogram);
  171. X    signal(SIGINT, endprogram);
  172. X    done = 0;
  173. X    currenttime = 0;
  174. X    specific = specificspace;
  175. X    /* Get YOUARE message */
  176. X    do {
  177. X        getmessage(&messagetype, specific);
  178. X        if (messagetype == _END) {
  179. X            endprogram();
  180. X        }
  181. X    } while (messagetype != _YOUARE);
  182. X    playernumber = specific[0] - 64;
  183. X    me = &players[playernumber];
  184. X    /* Get STARTUP message */
  185. X    do {
  186. X        getmessage(&messagetype, specific);
  187. X        if (messagetype == _END) {
  188. X            endprogram();
  189. X        }
  190. X    } while (messagetype != _STARTUP);
  191. X    totalplayers = specific[0] - 64;
  192. X    gamemapsizex = specific[1] - 64;
  193. X    gamemapsizey = specific[2] - 64;
  194. X    setupmap();
  195. X    for (count = 1; (count <= totalplayers); count++)
  196. X        players[count].live = 1;
  197. X
  198. X    while (done != 2) {
  199. X        while (getmessage(&messagetype, specific)) {
  200. X            offset = 0;
  201. X            switch ((int) messagetype) {
  202. X            case _HEXSTATUS:
  203. X                striplocation(&at, specific, &offset);
  204. X                map[at.x][at.y].terrain = specific[offset] - 64;
  205. X                offset++;
  206. X                stripint(&map[at.x][at.y].population, specific, &offset);
  207. X                stripint(&map[at.x][at.y].lastuse, specific, &offset);
  208. X                stripint(&map[at.x][at.y].troops, specific, &offset);
  209. X                map[at.x][at.y].owner = specific[offset] - 64;
  210. X                offset++;
  211. X                break;
  212. X            case _PLAYERSTATUS:
  213. X                theplayer = specific[offset] - 64;
  214. X                offset++;
  215. X                stripint(&players[theplayer].action, specific, &offset);
  216. X                stripint(&players[theplayer].hexes, specific, &offset);
  217. X                stripint(&players[theplayer].troops, specific, &offset);
  218. X                stripint(&players[theplayer].population, specific, &offset);
  219. X                stripint(&players[theplayer].citadels, specific, &offset);
  220. X                striplocation(&players[theplayer].start, specific, &offset);
  221. X                break;
  222. X            case _PLAYERDEAD:
  223. X                theplayer = specific[0] - 64;
  224. X                players[theplayer].live = 0;
  225. X                for (y = 0; (y < gamemapsizey); y++) {
  226. X                    for (x = 0; (x < gamemapsizex); x++) {
  227. X                        if (map[x][y].owner == theplayer) {
  228. X                            map[x][y].troops = 0;
  229. X                            map[x][y].owner = 0;
  230. X                        }
  231. X                    }
  232. X                }
  233. X                if (theplayer == playernumber) {
  234. X                    done = 2;
  235. X                }
  236. X                break;
  237. X            case _TEXT:
  238. X                break;
  239. X            case _ACTION:
  240. X                for (theplayer = 1; (theplayer <= totalplayers); theplayer++) {
  241. X                    if (players[theplayer].live == 1) {
  242. X                        players[theplayer].action += (2 + players[theplayer].citadels);
  243. X                    }
  244. X                }
  245. X                currenttime++;
  246. X                break;
  247. X            case _END:
  248. X                done = 2;
  249. X                break;
  250. X            }
  251. X        }
  252. X        sleep(1);
  253. X        /* Now it's time to think. */
  254. X        /* Sweep our towns and do useful things: */
  255. X        /* osmose troops around the board. */
  256. X        if ((me->action) > 5) {
  257. X            tried = 0;
  258. X            while (tried == 0) {
  259. X                xexp++;
  260. X                if (xexp == gamemapsizex) {
  261. X                    xexp = 0;
  262. X                    yexp++;
  263. X                    if (yexp == gamemapsizey) {
  264. X                        yexp = 0;
  265. X                        tried = 1;
  266. X                    }
  267. X                }
  268. X                if ((map[xexp][yexp].owner == playernumber) && (map[xexp][yexp].troops > 0)) {
  269. X                    xbest = (-1);
  270. X                    ybest = (-1);
  271. X                    sbest = (-9999);
  272. X                    for (y = (-1); (y <= 1); y++) {
  273. X                        for (x = (-1); (x <= 1); x++) {
  274. X                            sthis = 0;
  275. X                            if (legal(xexp + x, yexp + y)) {
  276. X                                if (map[xexp + x][yexp + y].terrain == 6)
  277. X                                    sthis = sthis - 50;
  278. X                                if (map[xexp + x][yexp + y].owner != playernumber)
  279. X                                    sthis = sthis + 30;
  280. X                                if (map[xexp + x][yexp + y].terrain == 2)
  281. X                                    sthis = sthis + 20;
  282. X                                if (map[xexp + x][yexp + y].terrain == 5)
  283. X                                    sthis = sthis + 25;
  284. X                                if ((sthis > sbest) ||
  285. X                                    ((sthis == sbest) && (((rand() * 512) % 2) == 0))) {
  286. X                                    xbest = xexp + x;
  287. X                                    ybest = yexp + y;
  288. X                                    sbest = sthis;
  289. X                                }
  290. X                            }
  291. X                        }
  292. X                    }
  293. X                    xnew = xbest;
  294. X                    ynew = ybest;
  295. X                    if ((xnew != xexp) || (ynew != yexp)) {
  296. X                        if ((map[xexp][yexp].terrain != 6) || (((rand() * 512) % 10) > 7)) {
  297. X                            move(xexp, yexp, xnew, ynew, 1);
  298. X                            tried = 1;
  299. X                        }
  300. X                    }
  301. X                }
  302. X            }
  303. X        }
  304. X    }
  305. X    /* Terminating code - needs to be called on CTRLC also. */
  306. X    endprogram();
  307. X}
  308. X
  309. Xvoid
  310. Xmove(x1, y1, x2, y2, troops)
  311. X    int             x1, y1, x2, y2, troops;
  312. X{
  313. X    outputline[0] = _MOVE;
  314. X    outputline[1] = x1 + 64;
  315. X    outputline[2] = y1 + 64;
  316. X    outputline[3] = x2 + 64;
  317. X    outputline[4] = y2 + 64;
  318. X    packint(5, troops);
  319. X    outputline[8] = 0;
  320. X    write(playerFd, outputline, strlen(outputline) + 1);
  321. X}
  322. X
  323. Xvoid
  324. Xendprogram()
  325. X{
  326. X    outputline[0] = _DISCONNECT;
  327. X    outputline[1] = NULL;
  328. X    write(playerFd, outputline, strlen(outputline) + 1);
  329. X    /*
  330. X     * Give server a chance to send any messages about our death without
  331. X     * a SIGPIPE
  332. X     */
  333. X    sleep(2);
  334. X    /* Now close connection */
  335. X    close(playerFd);
  336. X    exit(-1);
  337. X}
  338. X
  339. Xint
  340. Xlegal(x, y)
  341. X    int             x, y;
  342. X{
  343. X    if (inrange(x, 0, gamemapsizex - 1) && inrange(y, 0, gamemapsizey - 1))
  344. X        return 1;
  345. X    else
  346. X        return 0;
  347. X}
  348. X
  349. Xint
  350. Xinrange(x, low, high)
  351. X    int             x;
  352. X    int             low;
  353. X    int             high;
  354. X{
  355. X    if (x < low || x > high)
  356. X        return 0;
  357. X    return 1;
  358. X}
  359. X
  360. Xint
  361. Xgetmessage(messagetype, specific)
  362. X    char           *messagetype;
  363. X    char           *specific;
  364. X{
  365. X    char            in;
  366. X    int             pos;
  367. X    *messagetype = 0;
  368. X    *specific = 0;
  369. X    if (!inputwaiting(&server, playerFd)) {
  370. X        return 0;
  371. X    }
  372. X    read(playerFd, messagetype, 1);
  373. X    pos = 0;
  374. X    readnullterm(playerFd, specific);
  375. X    if (*messagetype == 0)
  376. X        return 0;
  377. X    else
  378. X        return 1;
  379. X}
  380. X
  381. Xvoid
  382. Xreadnullterm(fd, specific)
  383. X    int             fd;
  384. X    char           *specific;
  385. X{
  386. X    int             done;
  387. X    char           *current;
  388. X    current = specific;
  389. X    done = 0;
  390. X    while (done == 0) {
  391. X        while (!inputwaiting(&server, playerFd));
  392. X        read(playerFd, current, 1);
  393. X        if (*current == 0)
  394. X            done = 1;
  395. X        current++;
  396. X    }
  397. X}
  398. X
  399. Xvoid
  400. Xsetupmap(x, y)
  401. X    int             x;
  402. X    int             y;
  403. X{
  404. X    map = (hex **) malloc(sizeof(hex *) * gamemapsizex);
  405. X    for (x = 0; (x < gamemapsizex); x++) {
  406. X        map[x] = (hex *) malloc(sizeof(hex) * gamemapsizey);
  407. X    }
  408. X    for (y = 0; (y < gamemapsizey); y++) {
  409. X        for (x = 0; (x < gamemapsizex); x++) {
  410. X            map[x][y].terrain = 7;
  411. X            map[x][y].troops = 0;
  412. X            map[x][y].population = 0;
  413. X            map[x][y].owner = 0;
  414. X            map[x][y].lastuse = 0;
  415. X        }
  416. X    }
  417. X}
  418. X
  419. Xint
  420. Xconnectstream()
  421. X{
  422. X    int             s;
  423. X    struct sockaddr_in saddr;
  424. X    struct in_addr  host_address;
  425. X    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  426. X        perror("socket create");
  427. X        return (0);
  428. X    }
  429. X    saddr.sin_family = AF_INET;
  430. X    if (!get_host_address(host, &host_address)) {
  431. X        printf("Bad or missing server address.\n");
  432. X        exit(1);
  433. X    }
  434. X    bcopy(&host_address, &saddr.sin_addr, sizeof(struct in_addr));
  435. X    /* saddr.sin_addr.s_addr = htonl(inet_addr(host)); Old method */
  436. X    saddr.sin_port = htons(port);
  437. X
  438. X    if (connect(s, (struct sockaddr *) & saddr, sizeof(struct sockaddr_in)) < 0) {
  439. X        perror("connect");
  440. X        return (0);
  441. X    }
  442. X    FD_SET(s, &server);
  443. X    playerFd = s;
  444. X    return (1);
  445. X}
  446. X
  447. Xint
  448. Xinputwaiting(sfdset, sfd)
  449. X    fd_set         *sfdset;
  450. X    int             sfd;
  451. X{
  452. X    int             errrec;
  453. X    fd_set          readfds;
  454. X    struct timeval  waitTime;
  455. X    waitTime.tv_sec = SECONDSLIMIT;
  456. X    waitTime.tv_usec = MICROSECONDSLIMIT;
  457. X    bcopy((char *) sfdset, (char *) &readfds, sizeof(*sfdset));
  458. X    if (select(FD_SETSIZE, &readfds, NULL, NULL, &waitTime) < 0) {
  459. X        if (errno != EINTR) {
  460. X            perror("select");
  461. X        }
  462. X        return 0;
  463. X    }
  464. X    if (FD_ISSET(sfd, &readfds))
  465. X        return 1;
  466. X    else
  467. X        return 0;
  468. X}
  469. X
  470. X
  471. X/*
  472. X * get_host_address: borrowed with appreciation from Tinytalk. Does a nice
  473. X * job of getting around the various stupidities of the inetaddr routine, et
  474. X * cetera.
  475. X */
  476. X
  477. Xint
  478. Xget_host_address(name, addr)    /* Get a host address. */
  479. X    register char  *name;
  480. X    register struct in_addr *addr;
  481. X{
  482. X    struct hostent *blob;
  483. X    union {            /* %#@!%!@%#!@ idiot who designed */
  484. X        long            signed_thingy;    /* the inetaddr routine.... */
  485. X        unsigned long   unsigned_thingy;
  486. X    }               thingy;
  487. X
  488. X    if (*name == '\0') {
  489. X        fprintf(stderr, "%% No host address specified.\n");
  490. X        return (0);
  491. X    }
  492. X    if ((*name >= '0') && (*name <= '9')) {    /* IP address. */
  493. X        addr->s_addr = inet_addr(name);
  494. X        thingy.unsigned_thingy = addr->s_addr;
  495. X        if (thingy.signed_thingy == -1) {
  496. X            fprintf(stderr, "%% Couldn't find host %s .\n", name);
  497. X            return (0);
  498. X        }
  499. X    } else {        /* Host name. */
  500. X        blob = gethostbyname(name);
  501. X
  502. X        if (blob == NULL) {
  503. X            fprintf(stderr, "%% Couldn't find host %s .\n", name);
  504. X            return (0);
  505. X        }
  506. X        bcopy(blob->h_addr, addr, sizeof(struct in_addr));
  507. X    }
  508. X
  509. X    return (1);        /* Success. */
  510. X}
  511. END_OF_FILE
  512. if test 10429 -ne `wc -c <'btrobot.c'`; then
  513.     echo shar: \"'btrobot.c'\" unpacked with wrong size!
  514. fi
  515. # end of 'btrobot.c'
  516. fi
  517. if test -f 'btserver.c' -a "${1}" != "-c" ; then 
  518.   echo shar: Will not clobber existing file \"'btserver.c'\"
  519. else
  520. echo shar: Extracting \"'btserver.c'\" \(39546 characters\)
  521. sed "s/^X//" >'btserver.c' <<'END_OF_FILE'
  522. X#include <math.h>
  523. X#include <stdio.h>
  524. X#include <varargs.h>
  525. X#include <string.h>
  526. X#include <sys/types.h>
  527. X#include <sys/time.h>
  528. X#include <signal.h>
  529. X#include <stdlib.h>
  530. X#include "bt.h"
  531. X#include "btserver.h"
  532. X#include "btinterface.h"
  533. X#include "btpack.h"
  534. X#include "msleep.h"
  535. X
  536. Xhex           **map;
  537. Xplayer          players[_MAXPLAYERS];
  538. X
  539. Xint             gamemapsizey;
  540. Xint             gamemapsizex;
  541. Xint             gamespeed;
  542. Xint             gamecitycost;
  543. Xint             gamedestroycost;
  544. Xint             gamerecruittime;
  545. Xint             portnumber;
  546. Xint             gamecontinuous;
  547. X
  548. Xint             currentplayer;
  549. Xint             totalplayers;
  550. Xint             currenttime;
  551. Xint             ismap;
  552. Xint             living;
  553. Xint             memoryalloced;
  554. Xchar            gamemapfile[81];
  555. X
  556. Xint             terrainfrom[] = {0, 0, 10, 10, 5, 5, -10, 0};
  557. Xint             terrainto[] = {0, 0, -10, -10, -10, -15, 10, 0};
  558. Xint             terrainpopulation[] = {0, 100, 300, 50, 75, 400, 10, 0};
  559. X
  560. X#define QUEUESIZE (gamemapsizex*gamemapsizey)
  561. Xstatic location *recruitqueue;
  562. Xstatic int      queuefront;
  563. Xstatic int      queueback;
  564. X
  565. X
  566. X/* And enough space for half that many regions */
  567. X
  568. X/*
  569. X * Track population and # of troops, and remember one hex that's in the
  570. X * region from which to seek others when needed
  571. X */
  572. X
  573. Xstatic int     *regionspop;
  574. Xstatic location *regionshex;
  575. Xstatic int     *regionstroops;
  576. Xstatic int      regionnext;
  577. X
  578. X#define STREQ(a, b) (strcmp(a,b)==0)
  579. X#define SAFEARG ((i+1)<argc)
  580. X
  581. Xvoid
  582. Xreadbtserverrc(argc, argv)
  583. X    int             argc;
  584. X    char           *argv[];
  585. X{
  586. X    int             i;
  587. X    char            defaultfile[81];
  588. X    char           *path;
  589. X    FILE           *f;
  590. X    int             found;
  591. X    path = getenv("HOME");
  592. X    sprintf(defaultfile, ".btserverrc");
  593. X    if (!(f = fopen(defaultfile, "r"))) {
  594. X        sprintf(defaultfile, "%s/btserverrc", path);
  595. X        if (!(f = fopen(defaultfile, "r"))) {
  596. X            found = 0;
  597. X        } else {
  598. X            found = 1;
  599. X        }
  600. X    } else {
  601. X        found = 1;
  602. X    }
  603. X    for (i = 1; (i < argc); i++) {
  604. X        if (STREQ(argv[i], "-d")) {
  605. X            if (SAFEARG) {
  606. X                sprintf(defaultfile, "%s", argv[i + 1]);
  607. X                if (!(f = fopen(defaultfile, "r"))) {
  608. X                    found = 0;
  609. X                    fprintf(stderr, "btserver: default file specified not found.\n");
  610. X                    exiterror();
  611. X                } else {
  612. X                    found = 1;
  613. X                }
  614. X            } else {
  615. X                fprintf(stderr, "btserver: filename missing for -d option.\n");
  616. X                exiterror();
  617. X            }
  618. X        }
  619. X    }
  620. X    if (!found) {
  621. X        return;        /* no .btserverrc */
  622. X    }
  623. X    /* Now process file */
  624. X    while (!feof(f)) {
  625. X        char            sbuf[81];
  626. X        char           *item;
  627. X        char           *valuestr;
  628. X        char           *sp;
  629. X        int             value;
  630. X        if (!(fgets(sbuf, 81, f)))
  631. X            break;
  632. X        if ((sbuf[0] == ';') || (sbuf[0] == '#'))
  633. X            continue;    /* Comment */
  634. X        sp = strchr(sbuf, ' ');
  635. X        if (!sp)
  636. X            continue;    /* Blank or comment line */
  637. X        *sp = '\0';
  638. X        item = sbuf;
  639. X        valuestr = sp + 1;
  640. X        /* Stomp CR */
  641. X        valuestr[strlen(valuestr) - 1] = '\0';
  642. X        value = atoi(valuestr);
  643. X
  644. X        if (STREQ(item, "players")) {
  645. X            totalplayers = value;
  646. X            if (totalplayers > _MAXPLAYERS) {
  647. X                fprintf(stderr, "Error in default file: max of %d players.\n",
  648. X                    _MAXPLAYERS);
  649. X                fclose(f);
  650. X                exiterror();
  651. X            }
  652. X        } else if (STREQ(item, "sizex")) {
  653. X            gamemapsizex = value;
  654. X        } else if (STREQ(item, "sizey")) {
  655. X            gamemapsizey = value;
  656. X        } else if (STREQ(item, "size")) {
  657. X            if (sscanf(valuestr, "%dx%d", &gamemapsizex, &gamemapsizey) < 2) {
  658. X                fprintf(stderr,
  659. X                    "Error in default file: dimension(s) missing for size option.\n");
  660. X                fprintf(stderr, "(example syntax: size 5x5 - note the x)\n");
  661. X                exiterror();
  662. X            }
  663. X        } else if (STREQ(item, "speed")) {
  664. X            gamespeed = value;
  665. X        } else if (STREQ(item, "citycost")) {
  666. X            gamecitycost = value;
  667. X        } else if (STREQ(item, "destroycost")) {
  668. X            gamedestroycost = value;
  669. X        } else if (STREQ(item, "recruittime")) {
  670. X            gamerecruittime = value;
  671. X        } else if (STREQ(item, "mapfile")) {
  672. X            ismap = 1;
  673. X            strcpy(gamemapfile, valuestr);
  674. X        } else if (STREQ(item, "continuous")) {
  675. X            if (STREQ(valuestr, "on")) {
  676. X                gamecontinuous = 1;
  677. X            } else {
  678. X                gamecontinuous = 0;
  679. X            }
  680. X        } else if (STREQ(item, "port")) {
  681. X            portnumber = value;
  682. X            if (value < 1000 || value > 9999) {
  683. X                fprintf(stderr, "Error in default file: port number must be\n");
  684. X                fprintf(stderr, "between 1000 and 9999.\n");
  685. X                exiterror();
  686. X            }
  687. X        }
  688. X    }
  689. X    fclose(f);
  690. X}
  691. X
  692. Xvoid
  693. Xusage()
  694. X{
  695. X    fprintf(stderr,
  696. X      "Usage: btserver -n [# of players] -p [port # (default 2727)]\n");
  697. X    fprintf(stderr,
  698. X        "-m [map filename; -r creates random map] -d [defaults file; default\n");
  699. X    fprintf(stderr, "~/.btserverrc] -s [widthxheight; default %dx%d]\n",
  700. X        _DEFAULTMAPSIZEX, _DEFAULTMAPSIZEY);
  701. X}
  702. X
  703. Xvoid
  704. Xreadargs(argc, argv)
  705. X    int             argc;
  706. X    char           *argv[];
  707. X{
  708. X    int             i;
  709. X    for (i = 1; (i < argc); i++) {
  710. X        if (STREQ(argv[i], "-d")) {
  711. X            i++;    /* Ignore (and ignore argument) */
  712. X        } else if (STREQ(argv[i], "-n")) {
  713. X            if (SAFEARG) {
  714. X                totalplayers = atoi(argv[++i]);
  715. X                if (totalplayers > _MAXPLAYERS) {
  716. X                    fprintf(stderr, "btserver: maximum of %d players.\n",
  717. X                        _MAXPLAYERS);
  718. X                    exiterror();
  719. X                }
  720. X            } else {
  721. X                fprintf(stderr, "btserver: # of players missing for -n option.\n");
  722. X                exiterror();
  723. X            }
  724. X        } else if (STREQ(argv[i], "-p")) {
  725. X            if (SAFEARG) {
  726. X                portnumber = atoi(argv[++i]);
  727. X                if (portnumber < 1000 || portnumber > 9999) {
  728. X                    fprintf(stderr, "btserver: port # must be between 1000 and 9999.\n");
  729. X                    exiterror();
  730. X                }
  731. X            } else {
  732. X                fprintf(stderr, "btserver: port # missing for -p option.\n");
  733. X                exiterror();
  734. X            }
  735. X        } else if (STREQ(argv[i], "-m")) {
  736. X            if (SAFEARG) {
  737. X                strcpy(gamemapfile, argv[++i]);
  738. X                ismap = 1;
  739. X            } else {
  740. X                fprintf(stderr, "btserver: filename missing for -m option.\n");
  741. X                exiterror();
  742. X            }
  743. X        } else if (STREQ(argv[i], "-r")) {
  744. X            ismap = 0;
  745. X        } else if (STREQ(argv[i], "-s")) {
  746. X            if (SAFEARG) {
  747. X                if (sscanf(argv[++i], "%dx%d", &gamemapsizex, &gamemapsizey) < 2) {
  748. X                    fprintf(stderr, "btserver: dimension(s) missing for -s option.\n");
  749. X                    fprintf(stderr, "(example syntax: -s 5x5 - note the x)\n");
  750. X                    exiterror();
  751. X                }
  752. X            } else {
  753. X                fprintf(stderr, "btserver: dimension(s) missing for -s option.\n");
  754. X                fprintf(stderr, "(example syntax: -s 5x5 - note the x)\n");
  755. X                exiterror();
  756. X            }
  757. X        } else if (STREQ(argv[i], "-?") || STREQ(argv[i], "-h")) {
  758. X            usage();
  759. X            exiterror();
  760. X        } else {
  761. X            fprintf(stderr, "Unknown option.\n");
  762. X            usage();
  763. X            exiterror();
  764. X        }
  765. X    }
  766. X}
  767. X
  768. Xint
  769. Xmain(argc, argv)
  770. X    int             argc;
  771. X    char           *argv[];
  772. X{
  773. X    char            requesttype;
  774. X    location        from, to;
  775. X    int             number;
  776. X    long            lasttime;
  777. X    long            newtime;
  778. X    char            specificspace[256];
  779. X    char           *specific;
  780. X    int             offset;
  781. X    location        size;
  782. X    printf("Broken Throne server program launching...\n");
  783. X    ismap = 0;
  784. X    totalplayers = 0;
  785. X    portnumber = 2727;
  786. X    memoryalloced = 0;
  787. X    gamemapsizex = _DEFAULTMAPSIZEX;
  788. X    gamemapsizey = _DEFAULTMAPSIZEY;
  789. X    gamespeed = _DEFAULTSPEED;
  790. X    gamecitycost = _DEFAULTCITYCOST;
  791. X    gamedestroycost = _DEFAULTDESTROYCOST;
  792. X    gamerecruittime = _DEFAULTRECRUITTIME;
  793. X    gamecontinuous = 0;    /* Not continuous by default */
  794. X    ismap = 0;
  795. X    readbtserverrc(argc, argv);
  796. X    if (argc > 1) {
  797. X        readargs(argc, argv);
  798. X    }
  799. X    if (ismap) {
  800. X        FILE           *f;
  801. X        if (!(f = fopen(gamemapfile, "r"))) {
  802. X            fprintf(stderr, "btserver: unable to open map file %s.\n", gamemapfile);
  803. X            exiterror();
  804. X        }
  805. X        if (fscanf(f, "%dx%d", &gamemapsizex, &gamemapsizey) < 2) {
  806. X            fprintf(stderr, "btserver: dimensions missing from map file %s.\n",
  807. X                gamemapfile);
  808. X            fclose(f);
  809. X            exiterror();
  810. X        }
  811. X        fclose(f);
  812. X    }
  813. X    if ((gamemapsizex > _MAXMAPSIZEX) || (gamemapsizey > _MAXMAPSIZEY)) {
  814. X        fprintf(stderr, "Maximum map dimensions: %dx%d.\n",
  815. X            _MAXMAPSIZEX, _MAXMAPSIZEY);
  816. X        exiterror();
  817. X    }
  818. X    if (!totalplayers) {
  819. X        fprintf(stderr, "Error: a number of players must be specified.\n");
  820. X        usage();
  821. X        exiterror();
  822. X    }
  823. X    setupinterface(portnumber);
  824. X    do {
  825. X        fetchplayers();
  826. X        living = totalplayers;
  827. X        specific = specificspace;
  828. X        time(&lasttime);
  829. X        srand(lasttime % 1024);    /* Get a new random # seed */
  830. X        signal(SIGTERM, endtrap);
  831. X        signal(SIGQUIT, endtrap);
  832. X        signal(SIGINT, endtrap);
  833. X        size.x = gamemapsizex;
  834. X        size.y = gamemapsizey;
  835. X        currenttime = 100;
  836. X        broadcast(_STARTUP, (pointer) & size);
  837. X        setupmap(ismap, gamemapfile);
  838. X        while (living > 0) {
  839. X            msleep(100000);
  840. X            while (getrequest(¤tplayer, &requesttype, specific)) {
  841. X                offset = 0;
  842. X                switch ((int) requesttype) {
  843. X                case _DISCONNECT:
  844. X                    if (players[currentplayer].live != 0) {
  845. X                        players[currentplayer].live = 0;
  846. X                        killplayer(currentplayer);
  847. X                    }
  848. X                    disconnect_player(currentplayer);
  849. X                    break;
  850. X                case _MOVE:
  851. X                    striplocation(&from, specific, &offset);
  852. X                    striplocation(&to, specific, &offset);
  853. X                    stripint(&number, specific, &offset);
  854. X                    move(from, to, number);
  855. X                    break;
  856. X                case _RECRUIT:
  857. X                    striplocation(&from, specific, &offset);
  858. X                    recruitqueueremove(from.x, from.y);
  859. X                    recruit(from);
  860. X                    recruitenqueue(from.x, from.y);
  861. X                    break;
  862. X                case _CONSTRUCT:
  863. X                    striplocation(&from, specific, &offset);
  864. X                    construct(from);
  865. X                    break;
  866. X                case _DESTROY:
  867. X                    striplocation(&from, specific, &offset);
  868. X                    destroy(from);
  869. X                    break;
  870. X                case _QUIT:
  871. X                    killplayer(currentplayer);
  872. X                    break;
  873. X                case _PRIVATE:
  874. X                    sprintf(playertext, "%c: %s", currentplayer + 64, &specific[1]);
  875. X                    tellplayer(specific[0] - 64);
  876. X                    break;
  877. X                case _TELLALL:
  878. X                    sprintf(playertext, "%c to ALL: %s", currentplayer + 64, specific);
  879. X                    broadcast(_TEXT, (pointer) playertext);
  880. X                }
  881. X            }
  882. X            time(&newtime);
  883. X            if (newtime - lasttime >= gamespeed) {
  884. X                currenttime++;
  885. X                broadcast(_ACTION, (pointer) NULL);
  886. X                recruitall();
  887. X                support();
  888. X                for (number = 1; (number <= totalplayers); number++)
  889. X                    players[number].action += (2 + players[number].citadels);
  890. X                lasttime = newtime;
  891. X            }
  892. X        }
  893. X        freememory();
  894. X    } while (gamecontinuous);
  895. X    fprintf(stderr, "Server Shutdown\n");
  896. X    endprogram();
  897. X    exit(0);
  898. X}
  899. X
  900. Xvoid
  901. Xendtrap()
  902. X{
  903. X    broadcast(_TEXT, (pointer) "Server died");
  904. X    broadcastwaitqueue(_TEXT, (pointer) "Server died");
  905. X    endprogram();
  906. X}
  907. X
  908. Xvoid
  909. Xendprogram()
  910. X{
  911. X    broadcast(_END, (pointer) NULL);
  912. X    broadcastwaitqueue(_END, (pointer) NULL);
  913. X    shutdowninterface();
  914. X    freememory();
  915. X    exit(0);
  916. X}
  917. X
  918. Xvoid
  919. Xexiterror()
  920. X{
  921. X    freememory();
  922. X    exit(-1);
  923. X}
  924. X
  925. Xvoid
  926. Xfreememory()
  927. X{
  928. X    int             i;
  929. X    if (memoryalloced) {
  930. X        free(regionshex);
  931. X        free(regionspop);
  932. X        free(regionstroops);
  933. X        for (i = 0; (i < gamemapsizex); i++) {
  934. X            free(map[i]);
  935. X        }
  936. X        free(map);
  937. X        memoryalloced = 0;
  938. X    }
  939. X}
  940. X
  941. Xvoid
  942. Xrecruitdequeue()
  943. X{
  944. X    if (queuefront == queueback)
  945. X        return;
  946. X    queuefront++;
  947. X    if (queuefront >= QUEUESIZE)
  948. X        queuefront = 0;
  949. X}
  950. X
  951. Xvoid
  952. Xrecruitenqueue(x, y)
  953. X    int             x, y;
  954. X{
  955. X    recruitqueue[queueback].x = x;
  956. X    recruitqueue[queueback].y = y;
  957. X    queueback++;
  958. X    if (queueback >= QUEUESIZE)
  959. X        queueback = 0;
  960. X}
  961. X
  962. Xvoid
  963. Xrecruitqueueremove(x, y)
  964. X    int             x, y;
  965. X{
  966. X    int             i;
  967. X    i = queuefront;
  968. X    while (i != queueback) {
  969. X        if ((recruitqueue[i].x == x) && (recruitqueue[i].y == y)) {
  970. X            recruitqueue[i].x = -1;    /* Mark as invalid */
  971. X            return;
  972. X        }
  973. X        i++;
  974. X        if (i >= QUEUESIZE)
  975. X            i = 0;
  976. X    }
  977. X}
  978. X
  979. Xvoid
  980. Xsupport()
  981. X{
  982. X    location       *hexes;
  983. X    int             total;
  984. X    int             i;
  985. X    hexes = (location *) malloc(sizeof(location) * gamemapsizex * gamemapsizey);
  986. X    for (i = 1; (i < regionnext); i++) {
  987. X        int             supportable;
  988. X        int             deficit;
  989. X        if (regionspop[i] == 0)
  990. X            continue;    /* No territory - defunct */
  991. X        supportable = regionspop[i] / 100;
  992. X        if (supportable < regionstroops[i]) {
  993. X            int             where;
  994. X            int             origwhere;
  995. X            location        at;
  996. X            deficit = regionstroops[i] - supportable;
  997. X            /* Have a starvation event somewhere */
  998. X            regionget(regionshex[i], hexes, &total);
  999. X            /* If the survey didn't fix it, it's real */
  1000. X            if (supportable < regionstroops[i]) {
  1001. X                where = (rand() % total);
  1002. X                origwhere = where;
  1003. X                do {
  1004. X                    at = hexes[where];
  1005. X                    if (map[at.x][at.y].troops) {
  1006. X                        int             owner;
  1007. X                        owner = map[at.x][at.y].owner;
  1008. X                        map[at.x][at.y].troops--;
  1009. X                        players[owner].troops--;
  1010. X                        regionstroops[i]--;
  1011. X                        sprintf(playertext, "Starvation at %s.", namelocation(at));
  1012. X                        tellplayer(owner);
  1013. X                        broadcast(_HEXSTATUS, (pointer) & at);
  1014. X                        broadcast(_PLAYERSTATUS, (pointer) & owner);
  1015. X                        break;
  1016. X                    }
  1017. X                    where++;
  1018. X                    if (where >= total) {
  1019. X                        where = 0;
  1020. X                    }
  1021. X                } while (where != origwhere);
  1022. X            }
  1023. X        }
  1024. X    }
  1025. X    free(hexes);
  1026. X}
  1027. X
  1028. Xvoid
  1029. Xrecruitall()
  1030. X{
  1031. X    int             x, y;
  1032. X    while (queuefront != queueback) {
  1033. X        x = recruitqueue[queuefront].x;
  1034. X        y = recruitqueue[queuefront].y;
  1035. X        if (x < 0) {    /* Destroyed */
  1036. X            recruitdequeue();
  1037. X            continue;
  1038. X        }
  1039. X        if (map[x][y].lastuse <= (currenttime - gamerecruittime)) {
  1040. X            currentplayer = map[x][y].owner;
  1041. X            recruit(recruitqueue[queuefront]);
  1042. X            recruitdequeue();
  1043. X            recruitenqueue(x, y);
  1044. X        } else {    /* This is at the front and not ready, so
  1045. X                 * none are ready */
  1046. X            return;
  1047. X        }
  1048. X    }
  1049. X}
  1050. X
  1051. Xvoid
  1052. Xstopgame(message)
  1053. X    char           *message;
  1054. X{
  1055. X    broadcast(_TEXT, (pointer) message);
  1056. X    endprogram();
  1057. X}
  1058. X
  1059. Xint
  1060. Xcost(x, y)
  1061. X    int             x;
  1062. X    int             y;
  1063. X{
  1064. X    if (map[x][y].owner == currentplayer)
  1065. X        return 2;
  1066. X    else
  1067. X        return 4;
  1068. X}
  1069. X
  1070. Xvoid
  1071. Xregionupdate(at, new, newowner)
  1072. X    location        at;
  1073. X    int             new;
  1074. X    int             newowner;
  1075. X{
  1076. X    int             old;
  1077. X    int             dpop;
  1078. X    int             oldtotal = 0;
  1079. X    int             newtotal = 0;
  1080. X    int             x, y;
  1081. X    int             i;
  1082. X    location        oldnbrs[8];
  1083. X    location        newnbrs[8];
  1084. X    old = map[at.x][at.y].region;
  1085. X    map[at.x][at.y].owner = newowner;
  1086. X    map[at.x][at.y].region = new;
  1087. X    dpop = map[at.x][at.y].population;
  1088. X    regionspop[old] -= dpop;
  1089. X    regionspop[new] += dpop;
  1090. X    /*
  1091. X     * If previously unowned, no split is possible; if previously owned,
  1092. X     * pay attention
  1093. X     */
  1094. X    if (old) {
  1095. X        for (x = at.x - 1; (x <= at.x + 1); x++) {
  1096. X            for (y = at.y - 1; (y <= at.y + 1); y++) {
  1097. X                if ((!(legal(x, y))) || ((x == at.x) && (y == at.y)))
  1098. X                    continue;
  1099. X                if (map[x][y].region == old) {
  1100. X                    location        l;
  1101. X                    l.x = x;
  1102. X                    l.y = y;
  1103. X                    oldnbrs[oldtotal++] = l;
  1104. X                } else if (map[x][y].owner == newowner) {
  1105. X                    location        l;
  1106. X                    l.x = x;
  1107. X                    l.y = y;
  1108. X                    newnbrs[newtotal++] = l;
  1109. X                }
  1110. X            }
  1111. X        }
  1112. X        if (oldtotal) {
  1113. X            /*
  1114. X             * Check each neighbor; if a path doesn't exist to
  1115. X             * the first, then make a new region including that
  1116. X             * neighbor. First make sure the region hasn't
  1117. X             * already been changed (because it's adjacent to an
  1118. X             * already - broken - off neighbor).
  1119. X             */
  1120. X
  1121. X            /*
  1122. X             * First, set the seed hex of the first neighbors'
  1123. X             * region to be the first neighbors' location, since
  1124. X             * it might otherwise fall in a broken - off region.
  1125. X             */
  1126. X
  1127. X            regionshex[map[oldnbrs[0].x][oldnbrs[0].y].region] = oldnbrs[0];
  1128. X
  1129. X            for (i = 1; (i < oldtotal); i++) {
  1130. X                if (map[oldnbrs[i].x][oldnbrs[i].y].region == old) {
  1131. X                    if (!(regionpath(oldnbrs[0], oldnbrs[i]))) {
  1132. X                        regionnew(oldnbrs[i]);
  1133. X                    }
  1134. X                }
  1135. X            }
  1136. X        }
  1137. X    }
  1138. X    /* Now see if regions belonging to the new owner have been joined */
  1139. X    if (newtotal) {
  1140. X        for (i = 0; (i < newtotal); i++) {
  1141. X            if (map[newnbrs[i].x][newnbrs[i].y].region != new) {
  1142. X                regionchange(newnbrs[i], new);
  1143. X            }
  1144. X        }
  1145. X    }
  1146. X    /* Dump map */
  1147. X#ifdef DUMPMAP
  1148. X    for (x = 0; (x < regionnext); x++) {
  1149. X        printf("%d:%d,%d ", x, regionspop[x], regionstroops[x]);
  1150. X    }
  1151. X
  1152. X    printf("\n");
  1153. X    for (y = 0; (y < gamemapsizey); y++) {
  1154. X        for (x = 0; (x < gamemapsizex); x++) {
  1155. X            printf("%d ", map[x][y].region);
  1156. X        }
  1157. X        printf("\n");
  1158. X    }
  1159. X    printf("\n");
  1160. X#endif
  1161. X}
  1162. X
  1163. X/* The x and y components of the 8 directions */
  1164. X
  1165. Xstatic int      dirx[] = {-1, 0, 1, -1, 1, -1, 0, 1};
  1166. Xstatic int      diry[] = {-1, -1, -1, 0, 0, 1, 1, 1};
  1167. X
  1168. Xint
  1169. Xregionpath(from, to)
  1170. X    location        from, to;
  1171. X{
  1172. X    location       *locs;
  1173. X    int            *dirs;
  1174. X    int           **been;
  1175. X    int             hloc = 0;
  1176. X    int             r;
  1177. X    int             x, y;
  1178. X    int             result = 0;
  1179. X    locs = (location *) malloc(sizeof(location) * gamemapsizex * gamemapsizey);
  1180. X    dirs = (int *) malloc(sizeof(int) * gamemapsizex * gamemapsizey);
  1181. X    been = (int **) malloc(sizeof(int *) * gamemapsizex);
  1182. X    locs[hloc] = from;
  1183. X    dirs[hloc] = 0;
  1184. X    for (x = 0; (x < gamemapsizex); x++) {
  1185. X        been[x] = (int *) malloc(sizeof(int) * gamemapsizey);
  1186. X    }
  1187. X    r = map[from.x][from.y].region;
  1188. X    for (y = 0; (y < gamemapsizey); y++) {
  1189. X        for (x = 0; (x < gamemapsizex); x++) {
  1190. X            been[x][y] = 0;
  1191. X        }
  1192. X    }
  1193. X    while (1) {
  1194. X        int             d;
  1195. X        location        l;
  1196. X        location        next;
  1197. X        d = dirs[hloc];
  1198. X        l = locs[hloc];
  1199. X        been[l.x][l.y] = 1;
  1200. X        while (1) {
  1201. X            if (l.x == to.x && l.y == to.y) {
  1202. X                result = 1;
  1203. X                goto freemem;
  1204. X            }
  1205. X            next.x = l.x + dirx[d];
  1206. X            next.y = l.y + diry[d];
  1207. X            if (legal(next.x, next.y) &&
  1208. X                (map[next.x][next.y].region == r) &&
  1209. X                ((!been[next.x][next.y]))) {
  1210. X                hloc++;
  1211. X                locs[hloc] = next;
  1212. X                dirs[hloc] = 0;
  1213. X                break;
  1214. X            } else {
  1215. X                d++;
  1216. X                if (d > 7) {
  1217. X                    hloc--;
  1218. X                    if (hloc < 0) {
  1219. X                        result = 0;
  1220. X                        goto freemem;
  1221. X                    } else {
  1222. X                        break;
  1223. X                    }
  1224. X                }
  1225. X            }
  1226. X        }
  1227. X    }
  1228. Xfreemem:
  1229. X    free(locs);
  1230. X    free(dirs);
  1231. X    for (x = 0; (x < gamemapsizex); x++) {
  1232. X        free(been[x]);
  1233. X    }
  1234. X    free(been);
  1235. X    return result;
  1236. X}
  1237. X
  1238. Xvoid
  1239. Xregionchange(at, new)
  1240. X    location        at;
  1241. X    int             new;
  1242. X{
  1243. X    location       *hexes;
  1244. X    int             total;
  1245. X    int             i;
  1246. X    int             old;
  1247. X    hexes = (location *) malloc(sizeof(hex) * gamemapsizex * gamemapsizey);
  1248. X    regionget(at, hexes, &total);
  1249. X    old = map[at.x][at.y].region;
  1250. X    for (i = 0; (i < total); i++) {
  1251. X        hex            *h;
  1252. X        h = &map[hexes[i].x][hexes[i].y];
  1253. X        h->region = new;
  1254. X        regionspop[old] -= h->population;
  1255. X        regionspop[new] += h->population;
  1256. X        regionstroops[old] -= h->troops;
  1257. X        regionstroops[new] += h->troops;
  1258. X    }
  1259. X    free(hexes);
  1260. X}
  1261. X
  1262. Xvoid
  1263. Xregionget(at, hexes, total)
  1264. X    location        at;
  1265. X    location       *hexes;
  1266. X    int            *total;
  1267. X{
  1268. X    /* My favorite organic floodfill */
  1269. X    int             r;
  1270. X    int           **been;
  1271. X    int             cseed = 0;
  1272. X    int             hseed = 1;
  1273. X    int             x, y;
  1274. X    been = (int **) malloc(sizeof(int *) * gamemapsizex);
  1275. X    for (x = 0; (x < gamemapsizex); x++) {
  1276. X        been[x] = (int *) malloc(sizeof(int) * gamemapsizey);
  1277. X    }
  1278. X    for (y = 0; (y < gamemapsizey); y++) {
  1279. X        for (x = 0; (x < gamemapsizex); x++) {
  1280. X            been[x][y] = 0;
  1281. X        }
  1282. X    }
  1283. X    hexes[0] = at;
  1284. X    been[at.x][at.y] = 1;
  1285. X    r = map[at.x][at.y].region;
  1286. X    /*
  1287. X     * While we're here, may as well fix these values in case I've
  1288. X     * managed to break them
  1289. X     */
  1290. X    regionspop[r] = 0;
  1291. X    regionstroops[r] = 0;
  1292. X    regionspop[r] += map[at.x][at.y].population;
  1293. X    regionstroops[r] += map[at.x][at.y].troops;
  1294. X    do {
  1295. X        int             i;
  1296. X        location        c;
  1297. X        c = hexes[cseed];
  1298. X        cseed++;
  1299. X        for (i = 0; (i < 8); i++) {
  1300. X            location        l;
  1301. X            l.x = c.x + dirx[i];
  1302. X            l.y = c.y + diry[i];
  1303. X            if (legal(l.x, l.y) &&
  1304. X             (map[l.x][l.y].region == r) && (!been[l.x][l.y])) {
  1305. X                hexes[hseed] = l;
  1306. X                hseed++;
  1307. X                been[l.x][l.y] = 1;
  1308. X                regionspop[r] += map[l.x][l.y].population;
  1309. X                regionstroops[r] += map[l.x][l.y].troops;
  1310. X            }
  1311. X        }
  1312. X    } while (cseed < hseed);
  1313. X    *total = hseed;
  1314. X    for (x = 0; (x < gamemapsizex); x++) {
  1315. X        free(been[x]);
  1316. X    }
  1317. X    free(been);
  1318. X}
  1319. X
  1320. Xvoid
  1321. Xregionnew(at)
  1322. X    location        at;
  1323. X{
  1324. X    int             i;
  1325. X    for (i = 1; (i < regionnext); i++) {
  1326. X        if (regionspop[i] == 0) {
  1327. X            regionstroops[i] = 0;
  1328. X            regionchange(at, i);
  1329. X            regionshex[i] = at;
  1330. X            return;
  1331. X        }
  1332. X    }
  1333. X    regionshex[regionnext] = at;
  1334. X    regionchange(at, regionnext++);
  1335. X}
  1336. X
  1337. Xvoid
  1338. Xmove(from, to, number)
  1339. X    location        from;
  1340. X    location        to;
  1341. X    int             number;
  1342. X{
  1343. X    int             owner;
  1344. X    int             enemystrength;
  1345. X    int             unitsa;
  1346. X    int             unitsb;
  1347. X    int             numberold;
  1348. X    int             enemyold;
  1349. X    int             stragglers;
  1350. X    int             marchers;
  1351. X    int             weight;
  1352. X    if (number == 0) {
  1353. X        sprintf(playertext, "Ignored (no troops moved).");
  1354. X        tellcurrentplayer();
  1355. X        return;
  1356. X    }
  1357. X    if (abs(from.x - to.x) > 1 || abs(from.y - to.y) > 1) {
  1358. X        sprintf(playertext, "That destination is out of range.\n");
  1359. X        tellcurrentplayer();
  1360. X        return;
  1361. X    }
  1362. X    if (map[from.x][from.y].owner == currentplayer)
  1363. X        if (players[currentplayer].action >= number * cost(to.x, to.y))
  1364. X            if (map[from.x][from.y].troops >= number)
  1365. X                map[from.x][from.y].troops -= number;
  1366. X            else {
  1367. X                sprintf(playertext, "You do not have enough troops in that hex.\n");
  1368. X                tellcurrentplayer();
  1369. X                return;
  1370. X            }
  1371. X        else {
  1372. X            sprintf(playertext, "You don't have enough action points.\n");
  1373. X            tellcurrentplayer();
  1374. X            return;
  1375. X        }
  1376. X    else {
  1377. X        sprintf(playertext, "You don't control that hex!\n");
  1378. X        tellcurrentplayer();
  1379. X        return;
  1380. X    }
  1381. X    players[currentplayer].action -= number * cost(to.x, to.y);
  1382. X    switch (map[to.x][to.y].terrain) {
  1383. X    case 1:
  1384. X        break;
  1385. X    case 2:
  1386. X        break;
  1387. X    case 3:
  1388. X        stragglers = 0;
  1389. X        for (marchers = 1; (marchers <= number); marchers++) {
  1390. X            if ((rand() & 512) == 0)
  1391. X                stragglers++;
  1392. X        }
  1393. X        map[from.x][from.y].troops += stragglers;
  1394. X        if (stragglers == number) {
  1395. X            sprintf(playertext, "No troops made it through the mountains.");
  1396. X            tellcurrentplayer();
  1397. X            broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1398. X            return;
  1399. X        } else if (stragglers >= 0) {
  1400. X            sprintf(playertext, "%d of your armies have not crossed.", stragglers);
  1401. X            tellcurrentplayer();
  1402. X            number -= stragglers;
  1403. X        }
  1404. X        break;
  1405. X    case 4:
  1406. X        break;
  1407. X    case 5:
  1408. X        break;
  1409. X    case 6:
  1410. X        if ((rand() & 512) == 0) {
  1411. X            players[currentplayer].troops--;
  1412. X            regionstroops[map[from.x][from.y].region]--;
  1413. X            if (number == 1) {
  1414. X                sprintf(playertext, "Your army was sucked into the swamp.");
  1415. X                tellcurrentplayer();
  1416. X                number = 0;
  1417. X                break;
  1418. X            } else {
  1419. X                sprintf(playertext, "One of your units was lost in the swamp.");
  1420. X                tellcurrentplayer();
  1421. X                number--;
  1422. X                break;
  1423. X            }
  1424. X        }
  1425. X        break;
  1426. X    case 7:
  1427. X        sprintf(playertext, "Crags are impassable.");
  1428. X        tellcurrentplayer();
  1429. X        map[from.x][from.y].troops += number;
  1430. X        players[currentplayer].action += number * cost(to.x, to.y);
  1431. X        return;
  1432. X    }
  1433. X    owner = map[to.x][to.y].owner;
  1434. X    if (owner != currentplayer) {
  1435. X        if (owner != 0)
  1436. X            broadcast(_LOOK, (pointer) & to);
  1437. X        enemystrength = map[to.x][to.y].troops;
  1438. X        if (enemystrength == 0) {
  1439. X            sprintf(playertext, "%s was overrun.", namelocation(to));
  1440. X            tellcurrentplayer();
  1441. X            if (map[to.x][to.y].terrain == 5) {
  1442. X                players[owner].citadels--;
  1443. X                if (players[owner].citadels == 0) {
  1444. X                    sprintf(playertext, "Your last citadel was seized!");
  1445. X                    tellplayer(owner);
  1446. X                    killplayer(owner);
  1447. X                }
  1448. X                players[currentplayer].citadels++;
  1449. X            }
  1450. X            regionupdate(to, map[from.x][from.y].region, currentplayer);
  1451. X            map[to.x][to.y].troops = number;
  1452. X            if (map[to.x][to.y].terrain == 2 || map[to.x][to.y].terrain == 5) {
  1453. X                map[to.x][to.y].lastuse = currenttime;
  1454. X                recruitqueueremove(to.x, to.y);
  1455. X                recruitenqueue(to.x, to.y);
  1456. X            }
  1457. X            players[currentplayer].population += map[to.x][to.y].population;
  1458. X            players[currentplayer].hexes++;
  1459. X            if (owner > 0) {
  1460. X                players[owner].hexes--;
  1461. X                broadcast(_PLAYERSTATUS, (pointer) & owner);
  1462. X            }
  1463. X            broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1464. X            broadcast(_HEXSTATUS, (pointer) & to);
  1465. X            broadcast(_HEXSTATUS, (pointer) & from);
  1466. X        } else {
  1467. X            sprintf(playertext, "You have been attacked by %s at %s with %d troops.",
  1468. X                nameplayer(currentplayer),
  1469. X                namelocation(to), number);
  1470. X            tellplayer(owner);
  1471. X            weight = 50;
  1472. X            weight += terrainfrom[map[from.x][from.y].terrain];
  1473. X            weight += terrainto[map[to.x][to.y].terrain];
  1474. X            unitsa = number * 3;
  1475. X            unitsb = enemystrength * 3;
  1476. X            while ((unitsa > 0) && (unitsb > 0)) {
  1477. X                if (weight > ((rand() >> 5) % 100)) {    /* In search of good
  1478. X                                     * random #s! */
  1479. X                    unitsb--;
  1480. X                } else {
  1481. X                    unitsa--;
  1482. X                }
  1483. X            }
  1484. X            numberold = number;
  1485. X            enemyold = enemystrength;
  1486. X            number = ((unitsa + 2) / 3);
  1487. X            enemystrength = ((unitsb + 2) / 3);
  1488. X            players[currentplayer].troops -= (numberold - number);
  1489. X            regionstroops[map[from.x][from.y].region] -= (numberold - number);
  1490. X            players[owner].troops -= (enemyold - enemystrength);
  1491. X            regionstroops[map[to.x][to.y].region] -= (enemyold - enemystrength);
  1492. X            if (unitsa == 0) {
  1493. X                sprintf(playertext, "Your forces were destroyed.");
  1494. X                tellcurrentplayer();
  1495. X                sprintf(playertext,
  1496. X                    "You destroyed the enemy forces. %d of your armies survived.",
  1497. X                    enemystrength);
  1498. X                tellplayer(owner);
  1499. X                map[to.x][to.y].troops = enemystrength;
  1500. X                broadcast(_HEXSTATUS, (pointer) & from);
  1501. X                broadcast(_HEXSTATUS, (pointer) & to);
  1502. X                broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1503. X                broadcast(_PLAYERSTATUS, (pointer) & owner);
  1504. X            } else {
  1505. X                sprintf(playertext, "You liberated the territory.");
  1506. X                tellcurrentplayer();
  1507. X                if (owner != 0) {
  1508. X                    sprintf(playertext, "The territory was seized. %d armies occupied the territory.", number);
  1509. X                    tellplayer(owner);
  1510. X                    players[owner].population -=
  1511. X                        map[to.x][to.y].population;
  1512. X                    if (map[to.x][to.y].terrain == 5) {
  1513. X                        players[owner].citadels--;
  1514. X                        if (players[owner].citadels == 0) {
  1515. X                            sprintf(playertext, "Your last citadel has been eliminated!");
  1516. X                            tellplayer(owner);
  1517. X                            killplayer(owner);
  1518. X                        }
  1519. X                        players[currentplayer].citadels++;
  1520. X                    }
  1521. X                    map[to.x][to.y].troops = number;
  1522. X                    regionupdate(to, map[from.x][from.y].region, currentplayer);
  1523. X                    if (map[to.x][to.y].terrain == 2 || map[to.x][to.y].terrain == 5) {
  1524. X                        map[to.x][to.y].lastuse = currenttime;
  1525. X                        recruitenqueue(to.x, to.y);
  1526. X                    }
  1527. X                    players[currentplayer].hexes++;
  1528. X                    players[owner].hexes--;
  1529. X                    players[currentplayer].population += map[to.x][to.y].population;
  1530. X                    broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1531. X                    broadcast(_PLAYERSTATUS, (pointer) & owner);
  1532. X                    broadcast(_HEXSTATUS, (pointer) & from);
  1533. X                    broadcast(_HEXSTATUS, (pointer) & to);
  1534. X                }
  1535. X            }
  1536. X        }
  1537. X    } else {
  1538. X        marchers = number + map[to.x][to.y].troops;
  1539. X        if (marchers > 99) {
  1540. X            sprintf(playertext, "Up to 99 troops per territory.");
  1541. X            tellcurrentplayer();
  1542. X            map[to.x][to.y].troops = 99;
  1543. X            players[currentplayer].action += (marchers - 99);
  1544. X            map[from.x][from.y].troops += (marchers - 99);
  1545. X            broadcast(_HEXSTATUS, (pointer) & from);
  1546. X            broadcast(_HEXSTATUS, (pointer) & to);
  1547. X            broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1548. X            return;
  1549. X        } else {
  1550. X            map[to.x][to.y].troops = marchers;
  1551. X            broadcast(_HEXSTATUS, (pointer) & from);
  1552. X            broadcast(_HEXSTATUS, (pointer) & to);
  1553. X            broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1554. X            return;
  1555. X        }
  1556. X    }
  1557. X}
  1558. X
  1559. Xint
  1560. Xlegal(x, y)
  1561. X    int             x;
  1562. X    int             y;
  1563. X{
  1564. X    if (x >= 0 && x < gamemapsizex && y >= 0 && y < gamemapsizey)
  1565. X        return 1;
  1566. X    else
  1567. X        return 0;
  1568. X}
  1569. X
  1570. Xvoid
  1571. Xconstruct(at)
  1572. X    location        at;
  1573. X{
  1574. X    if (map[at.x][at.y].owner != currentplayer) {
  1575. X        sprintf(playertext, "You don't own that territory!");
  1576. X        tellcurrentplayer();
  1577. X        return;
  1578. X    }
  1579. X    if (map[at.x][at.y].terrain != 2) {
  1580. X        sprintf(playertext, "That territory is not a town.");
  1581. X        tellcurrentplayer();
  1582. X        return;
  1583. X    }
  1584. X    if (players[currentplayer].action < gamecitycost) {
  1585. X        sprintf(playertext, "You don't have enough action points!");
  1586. X        tellcurrentplayer();
  1587. X        return;
  1588. X    }
  1589. X    map[at.x][at.y].terrain = 5;
  1590. X    players[currentplayer].citadels++;
  1591. X    players[currentplayer].action -= gamecitycost;
  1592. X    players[currentplayer].population -= terrainpopulation[2];
  1593. X    players[currentplayer].population += terrainpopulation[5];
  1594. X    broadcast(_HEXSTATUS, (pointer) & at);
  1595. X    broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1596. X    sprintf(playertext, "You have constructed a new city.");
  1597. X    tellcurrentplayer();
  1598. X}
  1599. X
  1600. Xvoid
  1601. Xdestroy(at)
  1602. X    location        at;
  1603. X{
  1604. X    if ((players[currentplayer].citadels == 1) && (map[at.x][at.y].terrain == 5)) {
  1605. X        sprintf(playertext, "You cannot destroy your last city.");
  1606. X        tellcurrentplayer();
  1607. X        return;
  1608. X    }
  1609. X    if (map[at.x][at.y].owner != currentplayer) {
  1610. X        sprintf(playertext, "You don't control that territory!");
  1611. X        tellcurrentplayer();
  1612. X        return;
  1613. X    }
  1614. X    if ((map[at.x][at.y].terrain != 2) && (map[at.x][at.y].terrain != 5)) {
  1615. X        sprintf(playertext, "That territory is not a town or city!");
  1616. X        tellcurrentplayer();
  1617. X        return;
  1618. X    }
  1619. X    if (map[at.x][at.y].troops == 0) {
  1620. X        sprintf(playertext, "You must have forces in the territory!");
  1621. X        tellcurrentplayer();
  1622. X        return;
  1623. X    }
  1624. X    if (players[currentplayer].action < gamedestroycost) {
  1625. X        sprintf(playertext, "You need at least %d action points.", gamedestroycost);
  1626. X        tellcurrentplayer();
  1627. X        return;
  1628. X    }
  1629. X    players[currentplayer].action -= gamedestroycost;
  1630. X    if (map[at.x][at.y].terrain == 5)
  1631. X        players[currentplayer].citadels--;
  1632. X    players[currentplayer].population -= map[at.x][at.y].population;
  1633. X    map[at.x][at.y].terrain = 1;
  1634. X    recruitqueueremove(at.x, at.y);
  1635. X    players[currentplayer].population += terrainpopulation[1];
  1636. X    broadcast(_HEXSTATUS, (pointer) & at);
  1637. X    broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1638. X    sprintf(playertext, "You have destroyed the territory.");
  1639. X    tellcurrentplayer();
  1640. X}
  1641. X
  1642. Xvoid
  1643. Xrecruit(at)
  1644. X    location        at;
  1645. X{
  1646. X    int             chance;
  1647. X    int             population;
  1648. X    int             x, y;
  1649. X    int             recruits;
  1650. X    int             supportable;
  1651. X    int             total;
  1652. X    if (map[at.x][at.y].owner != currentplayer) {
  1653. X        sprintf(playertext, "You don't own that territory!");
  1654. X        tellcurrentplayer();
  1655. X        return;
  1656. X    }
  1657. X    if ((map[at.x][at.y].terrain != 2) && (map[at.x][at.y].terrain != 5)) {
  1658. X        sprintf(playertext, "That territory is not a town or citadel.");
  1659. X        tellcurrentplayer();
  1660. X        return;
  1661. X    }
  1662. X    chance = currenttime - map[at.x][at.y].lastuse;
  1663. X    map[at.x][at.y].lastuse = currenttime;
  1664. X    population = 0;
  1665. X    if (chance >= ((rand() / 100) % gamerecruittime)) {
  1666. X        for (y = (-1); (y <= 1); y++) {
  1667. X            for (x = (-1); (x <= 1); x++) {
  1668. X                if (legal(at.x + x, at.y + y)) {
  1669. X                    if ((((map[at.x + x][at.y + y].terrain != 2) &&
  1670. X                          (map[at.x + x][at.y + y].terrain != 5)) ||
  1671. X                         ((x == 0) && (y == 0))) &&
  1672. X                        (map[at.x][at.y].owner == currentplayer))
  1673. X                        population += map[at.x + x][at.y + y].population;
  1674. X                }
  1675. X            }
  1676. X        }
  1677. X        recruits = population / (100 * ((rand() / 100) % 5 + 2)) + 1;
  1678. X        total = regionstroops[map[at.x][at.y].region];
  1679. X        if (regionspop[map[at.x][at.y].region] < 0) {
  1680. X            regionspop[map[at.x][at.y].region] = 1;
  1681. X        }
  1682. X        supportable = regionspop[map[at.x][at.y].region] / 100;
  1683. X        if (total + recruits > supportable) {
  1684. X            recruits = supportable - total;
  1685. X            if (recruits <= 0) {
  1686. X                return;
  1687. X            }
  1688. X        }
  1689. X        if (map[at.x][at.y].troops == 99) {
  1690. X            return;
  1691. X        }
  1692. X        map[at.x][at.y].troops += recruits;
  1693. X        if (map[at.x][at.y].troops > 99) {
  1694. X            recruits -= (map[at.x][at.y].troops - 99);
  1695. X            map[at.x][at.y].troops = 99;
  1696. X        }
  1697. X        players[currentplayer].troops += recruits;
  1698. X        regionstroops[map[at.x][at.y].region] += recruits;
  1699. X        sprintf(playertext, "You recruited %d troops at %s.", recruits,
  1700. X            namelocation(at));
  1701. X        tellcurrentplayer();
  1702. X        broadcast(_PLAYERSTATUS, (pointer) & currentplayer);
  1703. X        broadcast(_HEXSTATUS, (pointer) & at);
  1704. X        return;
  1705. X    } else {
  1706. X        sprintf(playertext, "Recruitment failed; the territory is under too much stress.");
  1707. X        tellcurrentplayer();
  1708. X        return;
  1709. X    }
  1710. X}
  1711. X
  1712. Xvoid
  1713. Xsetupmap(ismap, mapfile)
  1714. X    int             ismap;
  1715. X    char           *mapfile;
  1716. X{
  1717. X    FILE           *mf;
  1718. X    int           **altitude;
  1719. X    int           **newaltitude;
  1720. X    int             x, y, subx, suby;
  1721. X    int             seed;
  1722. X    int             seedcomp;
  1723. X    int             acceptable;
  1724. X    int             full;
  1725. X    int             totalaltitude;
  1726. X    location        newhex;
  1727. X    int             placement;
  1728. X    int             typ;
  1729. X    int             i;
  1730. X    static char     dummy[81];
  1731. X    char            buf[2];
  1732. X    full = 0;
  1733. X    if (ismap) {
  1734. X        broadcast(_TEXT, "Loading the map...");
  1735. X    } else {
  1736. X        broadcast(_TEXT, "Generating the map...");
  1737. X    }
  1738. X    /* Allocate space for map, et cetera */
  1739. X    map = (hex **) malloc(sizeof(hex *) * gamemapsizex);
  1740. X    for (i = 0; (i < gamemapsizex); i++) {
  1741. X        map[i] = (hex *) malloc(sizeof(hex) * gamemapsizey);
  1742. X    }
  1743. X    queuefront = 0;
  1744. X    queueback = 0;
  1745. X    regionnext = 1;
  1746. X    memoryalloced = 1;
  1747. X    /* Now the simple vectors */
  1748. X    recruitqueue = (location *) malloc(sizeof(location) * gamemapsizex * gamemapsizey);
  1749. X    regionspop = (int *) malloc(sizeof(int) * gamemapsizex * gamemapsizey / 2);
  1750. X    regionstroops = (int *) malloc(sizeof(int) * gamemapsizex * gamemapsizey / 2);
  1751. X    regionshex = (location *) malloc(sizeof(location) * gamemapsizex * gamemapsizey / 2);
  1752. X    regionspop[0] = 0;
  1753. X    if (ismap) {
  1754. X        mf = fopen(mapfile, "r");
  1755. X        fgets(dummy, 80, mf);    /* Throw away dimensions (already
  1756. X                     * read) */
  1757. X        if (!mf) {
  1758. X            stopgame("Btserver: map file specified not found.\n");
  1759. X        }
  1760. X        for (y = 0; (y < gamemapsizey); y++) {
  1761. X            x = 0;
  1762. X            while (x < gamemapsizex) {
  1763. X                /* Throw away spaces */
  1764. X                while ((placement = getc(mf)) == ' ');
  1765. X                if (isdigit(placement)) {
  1766. X                    buf[0] = placement;
  1767. X                    buf[1] = 0;
  1768. X                    seed = atoi(buf);
  1769. X                    if (seed <= totalplayers) {
  1770. X                        location        l;
  1771. X                        map[x][y].terrain = 5;
  1772. X                        map[x][y].owner = seed;
  1773. X                        map[x][y].population = terrainpopulation[5];
  1774. X                        regionspop[regionnext] = map[x][y].population;
  1775. X                        regionstroops[regionnext] = 0;
  1776. X                        l.x = x;
  1777. X                        l.y = y;
  1778. X                        regionshex[0] = l;
  1779. X                        map[x][y].region = regionnext++;
  1780. X                        players[seed].start.x = x;
  1781. X                        players[seed].start.y = y;
  1782. X                        players[seed].population = terrainpopulation[5];
  1783. X                        players[seed].live = 1;
  1784. X                        players[seed].hexes = 1;
  1785. X                        players[seed].citadels = 1;
  1786. X                        map[x][y].lastuse = 0;
  1787. X                        recruitenqueue(x, y);
  1788. X                        broadcast(_HEXSTATUS, (pointer) & players[seed].start);
  1789. X                        broadcast(_PLAYERSTATUS, (pointer) & seed);
  1790. X                    } else {
  1791. X                        map[x][y].terrain = 1;
  1792. X                        map[x][y].population = terrainpopulation[1];
  1793. X                        regionspop[0] += map[x][y].population;
  1794. X                        map[x][y].owner = 0;
  1795. X                        map[x][y].troops = 0;
  1796. X                        map[x][y].region = 0;
  1797. X                        newhex.x = x;
  1798. X                        newhex.y = y;
  1799. X                        broadcast(_HEXSTATUS, (pointer) & newhex);
  1800. X                    }
  1801. X                    x++;
  1802. X                } else {
  1803. X                    switch (placement) {
  1804. X                    case '.':
  1805. X                        typ = 1;
  1806. X                        break;
  1807. X                    case 'T':
  1808. X                        typ = 2;
  1809. X                        break;
  1810. X                    case 'M':
  1811. X                        typ = 3;
  1812. X                        break;
  1813. X                    case 'F':
  1814. X                        typ = 4;
  1815. X                        break;
  1816. X                    case 'C':
  1817. X                        typ = 5;
  1818. X                        break;
  1819. X                    case 'S':
  1820. X                        typ = 6;
  1821. X                        break;
  1822. X                    default:
  1823. X                        typ = 0;
  1824. X                        break;
  1825. X                    }
  1826. X                    if (typ) {
  1827. X                        map[x][y].terrain = typ;
  1828. X                        map[x][y].population = terrainpopulation[typ];
  1829. X                        regionspop[0] += map[x][y].population;
  1830. X                        map[x][y].owner = 0;
  1831. X                        map[x][y].troops = 0;
  1832. X                        map[x][y].lastuse = 0;
  1833. X                        map[x][y].region = 0;
  1834. X                        newhex.x = x;
  1835. X                        newhex.y = y;
  1836. X                        broadcast(_HEXSTATUS, (pointer) & newhex);
  1837. X                        x++;
  1838. X                    }
  1839. X                }
  1840. X            }
  1841. X        }
  1842. X        return;
  1843. X    }
  1844. X    /* Generate random map */
  1845. X    altitude = (int **) malloc(sizeof(int *) * gamemapsizex);
  1846. X    newaltitude = (int **) malloc(sizeof(int *) * gamemapsizex);
  1847. X    for (i = 0; (i < gamemapsizex); i++) {
  1848. X        altitude[i] = (int *) malloc(sizeof(int) * gamemapsizey);
  1849. X        newaltitude[i] = (int *) malloc(sizeof(int) * gamemapsizey);
  1850. X    }
  1851. X    /* Now we can finally get started with map generation */
  1852. X    for (y = 0; (y < gamemapsizey); y++) {
  1853. X        for (x = 0; (x < gamemapsizex); x++) {
  1854. X            map[x][y].terrain = 0;
  1855. X            altitude[x][y] = 0;
  1856. X        }
  1857. X    }
  1858. X    for (seed = 1; (seed <= totalplayers); seed++) {
  1859. X        location        l;
  1860. X        int             initx, inity;
  1861. X        x = ((rand() / 32) % (gamemapsizex - 4)) + 2;
  1862. X        y = ((rand() / 32) % (gamemapsizey - 4)) + 2;
  1863. X        initx = x;
  1864. X        inity = y;
  1865. X        while (1) {
  1866. X            acceptable = 1;
  1867. X            x++;
  1868. X            if (x > gamemapsizex - 2) {
  1869. X                x = 3;
  1870. X                y++;
  1871. X                if (y > gamemapsizey - 2) {
  1872. X                    y = 1;
  1873. X                }
  1874. X            }
  1875. X            if ((x == initx) && (y == inity)) {
  1876. X                fprintf(stderr, "btserver: unable to fit %d players on the map.\n",
  1877. X                    totalplayers);
  1878. X                fprintf(stderr, "Try fewer players or a larger map.\n");
  1879. X                exiterror();
  1880. X            }
  1881. X            for (seedcomp = 1; (seedcomp < seed); seedcomp++) {
  1882. X                if (abs(x - players[seedcomp].start.x) +
  1883. X                    abs(y - players[seedcomp].start.y) < 5)
  1884. X                    acceptable = 0;
  1885. X            }
  1886. X            if (acceptable == 1)
  1887. X                break;
  1888. X        }
  1889. X        map[x][y].terrain = 5;
  1890. X        map[x][y].lastuse = 0;
  1891. X        altitude[x][y] = 100;
  1892. X        map[x][y].population = terrainpopulation[5];
  1893. X        map[x][y].owner = seed;
  1894. X        map[x][y].troops = 0;
  1895. X        players[seed].start.x = x;
  1896. X        players[seed].start.y = y;
  1897. X        players[seed].population = terrainpopulation[5];
  1898. X        players[seed].live = 1;
  1899. X        players[seed].hexes++;
  1900. X        players[seed].citadels = 1;
  1901. X        regionspop[regionnext] = map[x][y].population;
  1902. X        regionstroops[regionnext] = 0;
  1903. X        l.x = x;
  1904. X        l.y = y;
  1905. X        regionshex[regionnext] = l;
  1906. X        map[x][y].region = regionnext++;
  1907. X        recruitenqueue(x, y);
  1908. X        broadcast(_HEXSTATUS, (pointer) & players[seed].start);
  1909. X        broadcast(_PLAYERSTATUS, (pointer) & seed);
  1910. X        full++;
  1911. X    }
  1912. X    /*
  1913. X     * Now sweep, dropping altitudes of new hexes based on adjacents.
  1914. X     * Don't let altitude drop to zero; increment full as each hex is
  1915. X     * filled. At 90% full or so, call it quits.
  1916. X     */
  1917. X
  1918. X    acceptable = (gamemapsizey * gamemapsizex) * 9 / 10;
  1919. X    while (full < acceptable) {
  1920. X        for (y = 0; (y < gamemapsizey); y++) {
  1921. X            for (x = 0; (x < gamemapsizex); x++) {
  1922. X                newaltitude[x][y] = altitude[x][y];
  1923. X                if (altitude[x][y] == 0) {
  1924. X                    totalaltitude = 0;
  1925. X                    for (suby = (-1); (suby <= 1); suby++) {
  1926. X                        for (subx = (-1); (subx <= 1); subx++) {
  1927. X                            if (legal(x + subx, y + suby))
  1928. X                                totalaltitude += altitude[x + subx][y + suby];
  1929. X                        }
  1930. X                    }
  1931. X                    if (totalaltitude > 0) {
  1932. X                        newaltitude[x][y] = totalaltitude / 2 + ((rand() / 100) % 20);
  1933. X                        map[x][y].lastuse = 0;
  1934. X                        map[x][y].troops = 0;
  1935. X                        map[x][y].owner = 0;
  1936. X                        map[x][y].region = 0;
  1937. X                        placement = ((rand() / 100) % 100) * (newaltitude[x][y]) / 100;
  1938. X                        if (placement > 90) {
  1939. X                            map[x][y].terrain = 7;
  1940. X                        } else if (placement > 70) {
  1941. X                            map[x][y].terrain = 3;
  1942. X                        } else if (placement > 50) {
  1943. X                            map[x][y].terrain = 4;
  1944. X                        } else if (placement > 40) {
  1945. X                            map[x][y].terrain = 2;
  1946. X                        } else if (placement > 20) {
  1947. X                            map[x][y].terrain = 1;
  1948. X                        } else {
  1949. X                            map[x][y].terrain = 6;
  1950. X                        }
  1951. X                        map[x][y].population = terrainpopulation[map[x][y].terrain];
  1952. X                        regionspop[0] += map[x][y].population;
  1953. X                        newhex.x = x;
  1954. X                        newhex.y = y;
  1955. X                        broadcast(_HEXSTATUS, (pointer) & newhex);
  1956. X                        full++;
  1957. X                    }
  1958. X                }
  1959. X            }
  1960. X        }
  1961. X        for (y = 0; (y < gamemapsizey); y++) {
  1962. X            for (x = 0; (x < gamemapsizex); x++) {
  1963. X                altitude[x][y] = newaltitude[x][y];
  1964. X            }
  1965. X        }
  1966. X    }
  1967. X    for (y = 0; (y < gamemapsizey); y++) {
  1968. X        for (x = 0; (x < gamemapsizex); x++) {
  1969. X            if (!map[x][y].terrain) {
  1970. X                map[x][y].terrain = 7;
  1971. X                map[x][y].population = terrainpopulation[7];
  1972. X                regionspop[0] += map[x][y].population;
  1973. X                map[x][y].owner = 0;
  1974. X                map[x][y].lastuse = 0;
  1975. X                map[x][y].troops = 0;
  1976. X                map[x][y].region = 0;
  1977. X                newhex.x = x;
  1978. X                newhex.y = y;
  1979. X                broadcast(_HEXSTATUS, (pointer) & newhex);
  1980. X            }
  1981. X        }
  1982. X    }
  1983. X    for (i = 0; (i < gamemapsizex); i++) {
  1984. X        free(altitude[i]);
  1985. X        free(newaltitude[i]);
  1986. X    }
  1987. X    free(altitude);
  1988. X    free(newaltitude);
  1989. X}
  1990. X
  1991. Xvoid
  1992. Xtellcurrentplayer()
  1993. X{
  1994. X    tellplayer(currentplayer);
  1995. X}
  1996. X
  1997. Xvoid
  1998. Xkillplayer(owner)
  1999. X    int             owner;
  2000. X{
  2001. X    int             x, y;
  2002. X    int             i;
  2003. X    broadcast(_PLAYERDEAD, (pointer) & owner);
  2004. X    for (y = 0; (y < gamemapsizey); y++) {
  2005. X        for (x = 0; (x < gamemapsizex); x++) {
  2006. X            if (map[x][y].owner == owner) {
  2007. X                map[x][y].owner = 0;
  2008. X                map[x][y].troops = 0;
  2009. X                regionspop[map[x][y].region] = 0;
  2010. X                regionstroops[map[x][y].troops] = 0;
  2011. X                map[x][y].region = 0;
  2012. X                if ((map[x][y].terrain == 2) || (map[x][y].terrain == 5)) {
  2013. X                    recruitqueueremove(x, y);
  2014. X                }
  2015. X            }
  2016. X        }
  2017. X    }
  2018. X    players[owner].population = 0;
  2019. X    players[owner].troops = 0;
  2020. X    if (players[owner].live) {
  2021. X        players[owner].live = 2;
  2022. X    }
  2023. X    living = 0;
  2024. X    for (i = 1; (i <= totalplayers); i++) {
  2025. X        if (players[i].live == 1) {
  2026. X            living++;
  2027. X        }
  2028. X    }
  2029. X    sprintf(playertext, "%d players left in current game.", living);
  2030. X    broadcastwaitqueue(_TEXT, playertext);
  2031. X}
  2032. X
  2033. Xchar           *
  2034. Xnamelocation(at)
  2035. X    location        at;
  2036. X{
  2037. X    static char     namespace[20];
  2038. X    sprintf(namespace, "[%c%d]", 65 + at.x, at.y);
  2039. X    return &namespace[0];
  2040. X}
  2041. X
  2042. Xchar           *
  2043. Xnameplayer(thisid)
  2044. X    int             thisid;
  2045. X{
  2046. X    static char     namespace[20];
  2047. X    namespace[0] = ' ';
  2048. X    namespace[1] = 64 + thisid;
  2049. X    namespace[2] = ' ';
  2050. X    namespace[3] = NULL;
  2051. X    return &namespace[0];
  2052. X}
  2053. END_OF_FILE
  2054. if test 39546 -ne `wc -c <'btserver.c'`; then
  2055.     echo shar: \"'btserver.c'\" unpacked with wrong size!
  2056. fi
  2057. # end of 'btserver.c'
  2058. fi
  2059. echo shar: End of archive 1 \(of 3\).
  2060. cp /dev/null ark1isdone
  2061. MISSING=""
  2062. for I in 1 2 3 ; do
  2063.     if test ! -f ark${I}isdone ; then
  2064.     MISSING="${MISSING} ${I}"
  2065.     fi
  2066. done
  2067. if test "${MISSING}" = "" ; then
  2068.     echo You have unpacked all 3 archives.
  2069.     rm -f ark[1-9]isdone
  2070. else
  2071.     echo You still need to unpack the following archives:
  2072.     echo "        " ${MISSING}
  2073. fi
  2074. ##  End of shell archive.
  2075. exit 0
  2076.