# HG changeset patch # User darius # Date 881383024 0 # Node ID 8c6d5731234dae86c8f67f48e6d1841832465bfd # Parent 0542759991943d98a5581666dccfc5a4eeb82841 First entry of Paradise Server 2.9 patch 10 Beta diff -r 054275999194 -r 8c6d5731234d src/pl_gen6.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pl_gen6.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,419 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include + +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" +#include "planets.h" + +#define SYSWIDTH (GWIDTH/4.5) /* 5.9 width of a system */ + +#define SYSTEMS 6 /* 9 number of planetary systems */ + +/* atmosphere chances form a cascade win rand()%100 */ +#define PATMOS1 40 /* chance for normal atmosphere */ +#define PATMOS2 70 /* chance for thin atmosphere */ +#define PATMOS3 90 /* chance for slightly toxic stmos */ +#define PPOISON 100 /* chance for poison atmos */ + +/* defines that deal with planets resources and types */ +#define NMETAL 13 /* number of metal deposits */ +#define NDILYTH 10 /* number of dilythium deposits */ +#define NARABLE 15 /* number of arable land planets */ +/* defines that deal with star placement */ + +#define GW ((float)GWIDTH) /* size of galaxy in floating point */ +#define STARBORD (GW*0.27) +#define TEAMBORD (GW*0.32) +#define STARMIN (GW/5.6)/* min dist between stars */ +#define STARMAX GW +#define TEAMMIN (GW/2.8)/* min dist between team stars */ +#define TEAMMAX (GW/1.8)/* max dist between team stars */ + +/* defines that deal with systems and their planets */ +#define SYSADD 2 /* number possible above min number */ +#define SYSBORD (7000.0 + (float)GWIDTH/200) /* min distance from + * border wall */ +#define INDBORD (GW*0.23) +#define SYSMIN (5500.0 + (float)GWIDTH/200) /* min distance between + * objects */ +#define SYSMIN2 (SYSMIN*SYSMIN) /* square of sysmin distance */ +#define SYSPLMIN 9 /* 5 min number of planets for system */ +#define SYSPLADD 0 /* number of possible extra planets */ +#define MINARMY 5 /* 8 /* min numer of armies on a + * planet */ +#define MAXARMY 6 /* 15 /* max number of armies on a + * planet */ + +/* other defines */ +#define HOMEARMIES 30 /* number of armies on home planets */ +#define COLONYARMIES 10 /* number of armies for colony planet */ + + +/* defines dealing with growth timers */ +#define PLGFUEL configvals->plgrow.fuel /* time for growth of fuel + * depot */ +#define PLGAGRI configvals->plgrow.agri /* time for growth of agri */ +#define PLGREPAIR configvals->plgrow.repair /* time for growth of + * repair */ +#define PLGSHIP configvals->plgrow.shipyard /* time for growth of + * shipyard */ + + +/*-----------------------------PLACESYSTEMS------------------------------*/ +/* + * This function places the planets in each star's system. The function will + * return the index of the first planet that was not placed in a system. The + * coordinates of the planets are placed in the space grid. + */ + +static int +placesystems() +{ + int i, j, k; /* looping vars */ + double x, y; /* to hold star coordinates */ + int done; /* flag to indicate done */ + double dx, dy; /* delta x and y's */ + int n; /* number of planet to place */ + int np; /* number of planets in system */ + int attempts; + + n = SYSTEMS; /* first planet to place */ + for (i = 0; i < SYSTEMS; i++) + { /* planets for each system */ + np = SYSPLMIN + lrand48() % (SYSPLADD + 1); /* how many planets */ + for (k = 0; k < np; k++) + { /* go place the planets */ + attempts = 0; + do + { /* do until location found */ + attempts++; + done = 0; /* not done yet */ + dx = (drand48() * SYSWIDTH - SYSWIDTH / 2.0); + dy = (drand48() * SYSWIDTH - SYSWIDTH / 2.0); + if (dx * dx + dy * dy > (SYSWIDTH / 2.0) * (SYSWIDTH / 2.0)) + continue; /* might orbit its way out of the galaxy */ + x = planets[i].pl_x + dx; + y = planets[i].pl_y + dy; + if ((x > GW - SYSBORD) || (x < SYSBORD) + || (y < SYSBORD) || (y > GW - SYSBORD)) + continue; /* too close to border? */ + + done = 1; /* assume valid coord found */ + for (j = 0; j < n; j++) + { /* go through previous planets */ + dx = fabs(x - (double) planets[j].pl_x); + dy = fabs(y - (double) planets[j].pl_y); + if (dx * dx + dy * dy < SYSMIN2) + { /* if too close to another star */ + done = 0; /* we must get another coord */ + } + } + } while (!done && attempts < 200); /* do until location found */ + + if (!done) + return 0; /* universe too crowded, try again */ + + move_planet(n, (int) x, (int) y, 0); + planets[n].pl_system = i + 1; /* mark the sytem number */ + planets[n].pl_armies = MINARMY + lrand48() % (MAXARMY - MINARMY); + n++; /* go to next planet */ + } + } + return (n); /* return index of next planet */ +} + + + + +/*-----------------------------PLACEINDEP------------------------------*/ +/* + * This function places idependent planets that are not in a system. They can + * appear anywhere in the galaxy as long as they are not too close to another + * planet. The coords are put in the space grid. + */ + +static int +placeindep(n) + int n; +/* number of planet to start with */ +{ + int i, j; /* looping vars */ + double x, y; /* to hold star coordinates */ + int done; /* flag to indicate done */ + double dx, dy; /* delta x and y's */ + int attempts; + + for (i = n; i < (NUMPLANETS - (WORMPAIRS * 2)); i++) + { /* go through rest of planets */ + x = drand48() * (GW - 2 * INDBORD) + INDBORD; /* pick initial coords */ + y = drand48() * (GW - 2 * INDBORD) + INDBORD; + attempts = 0; + do + { /* do until location found */ + attempts++; + done = 0; /* not done yet */ + x = INDBORD + fmod(x + (3574.0 - INDBORD), GW - 2 * INDBORD); /* offset coords a + * little */ + y = INDBORD + fmod(y + (1034.0 - INDBORD), GW - 2 * INDBORD); /* every loop */ +#if 0 + if ((x > GW - INDBORD) || (x < INDBORD) + || (y < INDBORD) || (y > GW - INDBORD)) + continue; /* too close to border? */ +#endif + done = 1; /* assume valid coord */ + for (j = 0; j < n; j++) + { /* go through previous planets */ + dx = fabs(x - (double) planets[j].pl_x); + dy = fabs(y - (double) planets[j].pl_y); + if (dx * dx + dy * dy < SYSMIN2) + { /* if planet to close */ + done = 0; /* we must get another coord */ + } + } + } while (!done && attempts < 200); /* do until location found */ + + if (!done) + return 0; + + move_planet(n, (int) x, (int) y, 0); + planets[n].pl_system = 0; /* mark the no sytem */ + planets[n].pl_armies = MINARMY + lrand48() % (MAXARMY - MINARMY); + n++; /* go to next planet */ + } + for (i = n; i < NUMPLANETS; i++) /* now place wormholes */ + { + x = drand48() * GW; /* pick intial coords */ + y = drand48() * GW; + attempts = 0; + do + { /* do until location found */ + attempts++; + done = 0; /* not done yet */ + x = fmod(x + 3574.0, GW); /* offset coords a little */ + y = fmod(y + 1034.0, GW); /* every loop */ +#if 0 + if ((x > GW) || (y > GW)) + continue; /* too close to border? */ +#endif + done = 1; /* assume valid coord */ + for (j = 0; j < n; j++) + { /* go through previous planets */ + dx = fabs(x - (double) planets[j].pl_x); + dy = fabs(y - (double) planets[j].pl_y); + if (dx * dx + dy * dy < SYSMIN2) + { /* if planet to close */ + done = 0; /* we must get another coord */ + } + } + } while (!done && attempts < 200); /* do until location found */ + + if (!done) + return 0; + + move_planet(n, (int) x, (int) y, 0); + planets[n].pl_system = 0; /* mark the no system */ + planets[n].pl_flags |= PLWHOLE; /* mark the planet as a wormhole */ + /* the armies in a wormhole is the other wormhole's x coord */ + /* the radius is the other wormhole's y coord */ + if (NUMPLANETS % 2) + { + if (!(n % 2)) + { + planets[n].pl_armies = planets[n - 1].pl_x; + planets[n].pl_radius = planets[n - 1].pl_y; + planets[n - 1].pl_armies = planets[n].pl_x; + planets[n - 1].pl_radius = planets[n].pl_y; + } + } + else + { + if (n % 2) + { + planets[n].pl_armies = planets[n - 1].pl_x; + planets[n].pl_radius = planets[n - 1].pl_y; + planets[n - 1].pl_armies = planets[n].pl_x; + planets[n - 1].pl_radius = planets[n].pl_y; + } + } + planets[i].pl_owner = NOBODY; /* no team owns a star */ + planets[i].pl_hinfo = ALLTEAM; /* all teams know its a star */ + for (j = 0; j < MAXTEAM + 1; j++) + { /* go put in info for teams */ + planets[i].pl_tinfo[j].owner = NOBODY; /* nobody owns it */ + planets[i].pl_tinfo[j].armies = 0; + planets[i].pl_tinfo[j].flags = planets[i].pl_flags; + } + n++; /* go to next planet */ + } + return 1; +} + + + + +/*---------------------------------PLACERACES------------------------------*/ +/* + * This function places the races in the galaxy. Each race is placed in a + * different system. The race is given a home world with an Agri and Ship- + * yard on it and HOMEARMIES. They are also given a conoly planet with + * dilythium deposits and COLONYARMIES on it. + */ + +static void +placeraces() +{ + int i, j, k, x; /* looping vars */ + int p; /* to hold planet for race */ + int r[4], t; + + r[0] = r[1] = lrand48() % 4; /* pick two races at random. They will be */ + while (r[0] == r[1]) /* the races whose systems are 'optimally' */ + r[1] = lrand48() % 4; /* placed. */ + i = 0; + while (i == r[0] || i == r[1]) + i++; + r[2] = i++; + while (i == r[0] || i == r[1]) + i++; + r[3] = i; + + /* only allow these teams */ + status2->nontteamlock = (1 << r[0]) | (1 << r[1]); + + for (i = 0; i < 4; i++) + { /* go through races */ + t = r[i]; /* which team */ + p = lrand48() % NUMPLANETS; /* pick random planet */ + /* for (x=0; x <= 1; x++) { /* loop twice for 2 systems */ + while ((planets[p].pl_system != i + 1) + || (PL_TYPE(planets[p]) == PLSTAR) + || (planets[p].pl_owner != NOBODY)) + p = (p + 1) % NUMPLANETS; /* go on to next planet */ + + planets[p].pl_flags &= ~PLSURMASK; /* make sure no dilithium */ + planets[p].pl_flags |= (PLMETAL | PLARABLE); /* metal and arable */ + planets[p].pl_flags |= PLATYPE1; /* good atmosphere */ + planets[p].pl_flags |= (PLAGRI | PLSHIPYARD | PLREPAIR); + planets[p].pl_tagri = PLGAGRI; /* set timers for resources */ + planets[p].pl_tshiprepair = PLGSHIP; + planets[p].pl_owner = 1 << t; /* make race the owner */ + planets[p].pl_armies = HOMEARMIES; /* set the armies */ + planets[p].pl_hinfo = 1 << t; /* race has info on planet */ + planets[p].pl_tinfo[1 << t].owner = 1 << t; /* know about owner */ + planets[p].pl_tinfo[1 << t].armies = planets[p].pl_armies; + planets[p].pl_tinfo[1 << t].flags = planets[p].pl_flags; + + /* find colony planet */ + p = lrand48() % NUMPLANETS; /* pick random planet */ + while ((planets[p].pl_system != i + 1) + || (PL_TYPE(planets[p]) == PLSTAR) + || (planets[p].pl_owner != NOBODY)) + p = (p + 1) % NUMPLANETS; /* go on to next planet */ + planets[p].pl_flags |= PLFUEL; /* make fuel depot */ + planets[p].pl_tfuel = PLGFUEL; /* set timer for fuel depot */ + planets[p].pl_flags &= ~PLATMASK; /* take off previous atmos */ + planets[p].pl_flags |= PLPOISON; /* poison atmosphere */ + planets[p].pl_flags |= PLDILYTH; /* dilythium deposits */ + planets[p].pl_owner = 1 << t; /* make race the owner */ + planets[p].pl_armies = COLONYARMIES; /* set the armies */ + planets[p].pl_hinfo = 1 << t; /* race knows about */ + planets[p].pl_tinfo[1 << t].owner = 1 << t; /* know about owner */ + planets[p].pl_tinfo[1 << t].armies = planets[p].pl_armies; + planets[p].pl_tinfo[1 << t].flags = planets[p].pl_flags; + for (j = 0; j < NUMPLANETS; j++) + { + if ((planets[j].pl_system == i + 1) + && (PL_TYPE(planets[j]) != PLSTAR)) + { +#ifdef LEAGUE_SUPPORT + for (k = (status2->league ? 0 : t); + k < (status2->league ? 4 : t + 1); + k++) +#else + k = t; +#endif + { + planets[j].pl_owner = 1 << t; + planets[j].pl_hinfo = +#ifdef LEAGUE_SUPPORT + status2->league ? (1 << 4) - 1 : +#endif + (1 << t); + planets[j].pl_tinfo[1 << k].owner = 1 << t; + planets[j].pl_tinfo[1 << k].armies = planets[j].pl_armies; + planets[j].pl_tinfo[1 << k].flags = planets[j].pl_flags; + } + } + } + } +} + +/* + * Generate a complete galaxy. This variation is similar to gen_galaxy_1; + * except that it tries to place the races at consistent distances from one + * another. + */ + +void +gen_galaxy_6() +{ + int t; + + NUMPLANETS = 60; /* planets + wormholes */ + GWIDTH = 200000; + + while (1) + { + initplanets(); /* initialize planet structures */ + + /* place the resources */ + zero_plflags(planets, NUMPLANETS); + randomize_atmospheres(planets + SYSTEMS, NUMPLANETS - SYSTEMS, + PATMOS1, PATMOS2, PATMOS3, PPOISON); + randomize_resources(planets + SYSTEMS, NUMPLANETS - SYSTEMS, + NMETAL, NDILYTH, NARABLE); + + /* place system centers */ + t = place_stars(planets, 2, + (int) TEAMBORD, (int) TEAMMIN, (int) TEAMMAX, + (struct planet *) 0, 0) + && place_stars(planets + 2, 2, + (int) (STARBORD * 0.8), (int) TEAMMIN, (int) STARMAX, + planets, 2) + && place_stars(planets + 4, SYSTEMS - 4, + (int) STARBORD, (int) STARMIN, (int) STARMAX, + planets, 4); + + if (!t) + continue; + t = placesystems(); /* place planets in systems */ + if (!t) + continue; + t = placeindep(t); /* place independent planets */ + if (t) + break; /* success */ + } + if (configvals->justify_galaxy) + justify_galaxy(SYSTEMS); + placeraces(); /* place home planets for races */ +} diff -r 054275999194 -r 8c6d5731234d src/pl_gen7.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pl_gen7.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,547 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ +#include "config.h" +#include + +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" +#include "planets.h" + +#define SYSWIDTH (GWIDTH/5.9) /* width of a system */ + +#define SYSTEMS 7 /* number of planetary systems */ + +/* atmosphere chances form a cascade win rand()%100 */ +#define PATMOS1 40 /* chance for normal atmosphere */ +#define PATMOS2 70 /* chance for thin atmosphere */ +#define PATMOS3 90 /* chance for slightly toxic stmos */ +#define PPOISON 100 /* chance for poison atmos */ + +/* defines that deal with planets resources and types */ +#define NMETAL 10 /* number of metal deposits */ +#define NDILYTH 8 /* number of dilythium deposits */ +#define NARABLE 12 /* number of arable land planets */ +/* defines that deal with star placement */ + +#define GW ((float)GWIDTH) /* size of galaxy in floating point */ +#define STARBORD ((GW/5.2)*1.3) +#define TEAMBORD ((GW/5.2)/1.1) +#define STARMIN (GW/5.0)/* min dist between stars */ +#define STARMIN2 (STARMIN*STARMIN) /* min star dist squared */ +#define STARMAX GW +#define STARMAX2 (GW*GW) +#define TEAMMIN (GW/2.8)/* min dist between team stars */ +#define TEAMMIN2 (TEAMMIN*TEAMMIN) +#define TEAMMAX (GW/1.4)/* max dist between team stars */ +#define TEAMMAX2 (TEAMMAX*TEAMMAX) + +/* defines that deal with systems and their planets */ +#define SYSADD 2 /* number possible above min number */ +#define SYSBORD (4000.0 + (float)GWIDTH/200) /* min distance from + * border wall */ +#define INDBORD (GW * 0.1) +#define SYSMIN (6000.0 + (float)GWIDTH/200) /* min distance between + * objects */ +#define SYSMIN2 (SYSMIN*SYSMIN) /* square of sysmin distance */ +#define SYSPLMIN 5 /* min number of planets for system */ +#define SYSPLADD 0 /* number of possible extra planets */ +#define MINARMY 8 /* min numer of armies on a planet */ +#define MAXARMY 15 /* max number of armies on a planet */ + +/* other defines */ +#define HOMEARMIES 30 /* number of armies on home planets */ +#define COLONYARMIES 10 /* number of armies for colony planet */ + + +/* defines dealing with growth timers */ +#define PLGFUEL configvals->plgrow.fuel /* time for growth of fuel + * depot */ +#define PLGAGRI configvals->plgrow.agri /* time for growth of agri */ +#define PLGREPAIR configvals->plgrow.repair /* time for growth of + * repair */ +#define PLGSHIP configvals->plgrow.shipyard /* time for growth of + * shipyard */ + + +#if 0 +/*-------------------------------GENRESOURCES----------------------------*/ +/* + * This function goes through the planets structure and determines what kind + * of atmosphere and what kind of surface the planets have. It generates the + * stars that will be used as system centers ans then places atmospheres on + * the other planets. It then distributes the resources on the planet + * surfaces. + */ + +static void +genresources() +{ + int i; /* looping vars */ + int t; /* temp var */ + + for (i = 0; i < SYSTEMS; i++) /* first planets are stars */ + planets[i].pl_flags |= PLSTAR; /* or in star flag */ + for (i = SYSTEMS; i < NUMPLANETS; i++) + { /* generate atmospheres */ + t = lrand48() % 100; /* random # 0-99 */ + if (t < PATMOS1) /* is it atmosphere type 1 */ + planets[i].pl_flags |= PLATYPE1; + else if (t < PATMOS2) /* is it atmosphere type 2 */ + planets[i].pl_flags |= PLATYPE2; + else if (t < PATMOS3) /* is it atmosphere type 3 */ + planets[i].pl_flags |= PLATYPE3; + else if (t < PPOISON) /* is it poison atmosphere */ + planets[i].pl_flags |= PLPOISON; + } + for (i = 0; i < NMETAL; i++) + { /* place the metal deposits */ + t = lrand48() % (NUMPLANETS - SYSTEMS) + SYSTEMS; /* random planet */ + planets[t].pl_flags |= PLMETAL; /* OR in the metal flag */ + if (!configvals->resource_bombing) + planets[t].pl_flags |= PLREPAIR; + } + for (i = 0; i < NDILYTH; i++) + { /* place the metal deposits */ + t = lrand48() % (NUMPLANETS - SYSTEMS) + SYSTEMS; /* random planet */ + planets[t].pl_flags |= PLDILYTH; /* OR in the dilyth flag */ + planets[t].pl_flags &= ~(PLATMASK | PLARABLE); /* zero off previous + * atmos */ + planets[t].pl_flags |= PLPOISON; /* dilyth poisons atmosphere */ + if (!configvals->resource_bombing) + planets[t].pl_flags |= PLFUEL; + } + for (i = 0; i < NARABLE; i++) + { /* place the metal deposits */ + t = lrand48() % (NUMPLANETS - SYSTEMS) + SYSTEMS; /* random planet */ + planets[t].pl_flags |= PLARABLE | PLATYPE1; /* OR in the arable flag */ + if (!configvals->resource_bombing) + planets[t].pl_flags |= PLAGRI; + } +} +#endif + + +#if 0 + +/*--------------------------------PLACESTARS------------------------------*/ +/* + * This function places each system's star. The stars are expected to be in + * the first SYSTEMS number of planets. The coordinates of the stars are + * placed in the space grid. + */ + +static int +placestars() +{ + int i, j; /* looping vars */ + double x, y; /* to hold star coordinates */ + int done; /* flag to indicate done */ + double dx, dy; /* delta x and y's */ + int attempts; + double min, max, dist, bord, nbwidth; + double xoff, yoff; + + for (i = 0; i < SYSTEMS; i++) + { /* star for each system */ + if (i < 4) + { + min = TEAMMIN2; + max = TEAMMAX2; + bord = TEAMBORD; + } + else + { + min = STARMIN2; + max = STARMAX2; + bord = STARBORD; + } + nbwidth = GW - 2 * bord; + x = drand48() * nbwidth + bord; /* pick intial coords */ + y = drand48() * nbwidth + bord; + xoff = 3574.0 - bord; + yoff = 1034.0 - bord; + attempts = 0; + do + { /* do until location found */ + attempts++; + done = 0; /* not done yet */ + x = bord + fmod(x + xoff, nbwidth); /* offset coords a little */ + y = bord + fmod(y + yoff, nbwidth); /* every loop */ +#if 0 + if ((x > GW - bord) || (x < bord) + || (y < bord) || (y > GW - bord)) + continue; /* too close to border? */ +#endif + done = 1; /* assume valid cord found */ + for (j = 0; j < i; j++) + { /* go through previous stars */ + dx = fabs(x - (double) planets[j].pl_x); + dy = fabs(y - (double) planets[j].pl_y); + dist = dx * dx + dy * dy; + if (dist < min || dist > max) /* if too close or too far then */ + done = 0; /* we must get another coord */ + } + } while (!done && attempts < 1000); /* do until location found */ + + if (!done) + return 0; + + planets[i].pl_owner = NOBODY; /* no team owns a star */ + planets[i].pl_flags |= PLSTAR; /* mark planet as a star */ + move_planet(i, (int) x, (int) y, 0); + planets[i].pl_system = i + 1; /* mark the sytem number */ + planets[i].pl_hinfo = ALLTEAM; /* all teams know its a star */ + for (j = 0; j < MAXTEAM + 1; j++) + { /* go put in info for teams */ + planets[i].pl_tinfo[j].owner = NOBODY; /* nobody owns it */ + planets[i].pl_tinfo[j].armies = 0; + planets[i].pl_tinfo[j].flags = planets[i].pl_flags; + } + } + return 1; +} + +#endif + + +/*-----------------------------PLACESYSTEMS------------------------------*/ +/* + * This function places the planets in each star's system. The function will + * return the index of the first planet that was not placed in a system. The + * coordinates of the planets are placed in the space grid. + */ + +static int +placesystems() +{ + int i, j, k; /* looping vars */ + double x, y; /* to hold star coordinates */ + int done; /* flag to indicate done */ + double dx, dy; /* delta x and y's */ + int n; /* number of planet to place */ + int np; /* number of planets in system */ + int attempts; + + n = SYSTEMS; /* first planet to place */ + for (i = 0; i < SYSTEMS; i++) + { /* planets for each system */ + np = SYSPLMIN + lrand48() % (SYSPLADD + 1); /* how many planets */ + for (k = 0; k < np; k++) + { /* go place the planets */ + attempts = 0; + do + { /* do until location found */ + attempts++; + done = 0; /* not done yet */ + dx = (drand48() * SYSWIDTH - SYSWIDTH / 2.0); + dy = (drand48() * SYSWIDTH - SYSWIDTH / 2.0); + if (dx * dx + dy * dy > (SYSWIDTH / 2.0) * (SYSWIDTH / 2.0)) + continue; /* might orbit its way out of the galaxy */ + x = planets[i].pl_x + dx; + y = planets[i].pl_y + dy; + if ((x > GW - SYSBORD) || (x < SYSBORD) + || (y < SYSBORD) || (y > GW - SYSBORD)) + continue; /* too close to border? */ + + done = 1; /* assume valid coord found */ + for (j = 0; j < n; j++) + { /* go through previous planets */ + dx = fabs(x - (double) planets[j].pl_x); + dy = fabs(y - (double) planets[j].pl_y); + if (dx * dx + dy * dy < SYSMIN2) + { /* if too close to another star */ + done = 0; /* we must get another coord */ + } + if (ihypot((int) dx, (int) dy) < 3000) + done = 0; + } + } while (!done && attempts < 200); /* do until location found */ + + if (!done) + return 0; /* universe too crowded, try again */ + + move_planet(n, (int) x, (int) y, 0); + planets[n].pl_system = i + 1; /* mark the sytem number */ + planets[n].pl_armies = MINARMY + lrand48() % (MAXARMY - MINARMY); + n++; /* go to next planet */ + } + } + return (n); /* return index of next planet */ +} + + + + +/*-----------------------------PLACEINDEP------------------------------*/ +/* + * This function places idependent planets that are not in a system. They can + * appear anywhere in the galaxy as long as they are not too close to another + * planet. The coords are put in the space grid. + */ + +static int +placeindep(n) + int n; +/* number of planet to start with */ +{ + int i, j; /* looping vars */ + double x, y; /* to hold star coordinates */ + int done; /* flag to indicate done */ + double dx, dy; /* delta x and y's */ + int attempts; + + for (i = n; i < (NUMPLANETS - (WORMPAIRS * 2)); i++) + { + /* go through rest of planets */ + x = drand48() * (GW - 2 * INDBORD) + INDBORD; /* pick intial coords */ + y = drand48() * (GW - 2 * INDBORD) + INDBORD; + attempts = 0; + do + { /* do until location found */ + attempts++; + done = 0; /* not done yet */ + x = INDBORD + fmod(x + (3574.0 - INDBORD), GW - 2 * INDBORD); /* offset coords a + * little */ + y = INDBORD + fmod(y + (1034.0 - INDBORD), GW - 2 * INDBORD); /* every loop */ +#if 0 + if ((x > GW - INDBORD) || (x < INDBORD) + || (y < INDBORD) || (y > GW - INDBORD)) + continue; /* too close to border? */ +#endif + done = 1; /* assume valid coord */ + for (j = 0; j < n; j++) + { /* go through previous planets */ + dx = fabs(x - (double) planets[j].pl_x); + dy = fabs(y - (double) planets[j].pl_y); + if (dx * dx + dy * dy < SYSMIN2) + { /* if planet to close */ + done = 0; /* we must get another coord */ + } + } + } while (!done && attempts < 200); /* do until location found */ + + if (!done) + return 0; + + move_planet(n, (int) x, (int) y, 0); + planets[n].pl_system = 0; /* mark the no sytem */ + planets[n].pl_armies = MINARMY + lrand48() % (MAXARMY - MINARMY); + n++; /* go to next planet */ + } + for (i = n; i < NUMPLANETS; i++) /* now place wormholes */ + { + x = drand48() * GW; /* pick intial coords */ + y = drand48() * GW; + attempts = 0; + do + { /* do until location found */ + attempts++; + done = 0; /* not done yet */ + x = fmod(x + 3574.0, GW); /* offset coords a little */ + y = fmod(y + 1034.0, GW); /* every loop */ +#if 0 + if ((x > GW) || (y > GW)) + continue; /* too close to border? */ +#endif + done = 1; /* assume valid coord */ + for (j = 0; j < n; j++) + { /* go through previous planets */ + dx = fabs(x - (double) planets[j].pl_x); + dy = fabs(y - (double) planets[j].pl_y); + if (dx * dx + dy * dy < SYSMIN2) + { /* if planet to close */ + done = 0; /* we must get another coord */ + } + } + } while (!done && attempts < 200); /* do until location found */ + + if (!done) + return 0; + + move_planet(n, (int) x, (int) y, 0); + planets[n].pl_system = 0; /* mark the no system */ + planets[n].pl_flags |= PLWHOLE; /* mark the planet as a wormhole */ + /* the armies in a wormhole is the other wormhole's x coord */ + /* the radius is the other wormhole's y coord */ + if (NUMPLANETS % 2) + { + if (!(n % 2)) + { + planets[n].pl_armies = planets[n - 1].pl_x; + planets[n].pl_radius = planets[n - 1].pl_y; + planets[n - 1].pl_armies = planets[n].pl_x; + planets[n - 1].pl_radius = planets[n].pl_y; + } + } + else + { + if (n % 2) + { + planets[n].pl_armies = planets[n - 1].pl_x; + planets[n].pl_radius = planets[n - 1].pl_y; + planets[n - 1].pl_armies = planets[n].pl_x; + planets[n - 1].pl_radius = planets[n].pl_y; + } + } + planets[i].pl_owner = NOBODY; /* no team owns a star */ + planets[i].pl_hinfo = ALLTEAM; /* all teams know its a star */ + for (j = 0; j < MAXTEAM + 1; j++) + { /* go put in info for teams */ + planets[i].pl_tinfo[j].owner = NOBODY; /* nobody owns it */ + planets[i].pl_tinfo[j].armies = 0; + planets[i].pl_tinfo[j].flags = planets[i].pl_flags; + } + n++; /* go to next planet */ + } + return 1; +} + + + + +/*---------------------------------PLACERACES------------------------------*/ +/* + * This function places the races in the galaxy. Each race is placed in a + * different system. The race is given a home world with an Agri and Ship- + * yard on it and HOMEARMIES. They are also given a conoly planet with + * dilythium deposits and COLONYARMIES on it. + */ + +static void +placeraces() +{ + int i, j, k; /* looping vars */ + int p; /* to hold planet for race */ + + for (i = 0; i < 4; i++) + { /* go through races */ + /* find home planet */ + p = lrand48() % NUMPLANETS; /* pick random planet */ + while ((planets[p].pl_system != i + 1) + || (PL_TYPE(planets[p]) == PLSTAR) + || (planets[p].pl_owner != NOBODY)) + p = (p + 1) % NUMPLANETS; /* go on to next planet */ + planets[p].pl_flags &= ~PLSURMASK; /* make sure no dilithium */ + planets[p].pl_flags |= (PLMETAL | PLARABLE); /* metal and arable */ + planets[p].pl_flags |= PLATYPE1; /* good atmosphere */ + planets[p].pl_flags |= (PLAGRI | PLSHIPYARD | PLREPAIR); + planets[p].pl_tagri = PLGAGRI; /* set timers for resources */ + planets[p].pl_tshiprepair = PLGSHIP; + planets[p].pl_owner = 1 << i; /* make race the owner */ +#if 0 /* home planets do not have traditional names */ + strcpy(planets[p].pl_name, homenames[1 << i]); /* set name and length */ + planets[p].pl_namelen = strlen(homenames[1 << i]); +#endif + planets[p].pl_armies = HOMEARMIES; /* set the armies */ + planets[p].pl_hinfo = 1 << i; /* race has info on planet */ + planets[p].pl_tinfo[1 << i].owner = 1 << i; /* know about owner */ + planets[p].pl_tinfo[1 << i].armies = planets[p].pl_armies; + planets[p].pl_tinfo[1 << i].flags = planets[p].pl_flags; + /* find colony planet */ + p = lrand48() % NUMPLANETS; /* pick random planet */ + while ((planets[p].pl_system != i + 1) + || (PL_TYPE(planets[p]) == PLSTAR) + || (planets[p].pl_owner != NOBODY)) + p = (p + 1) % NUMPLANETS; /* go on to next planet */ + planets[p].pl_flags |= PLFUEL; /* make fuel depot */ + planets[p].pl_tfuel = PLGFUEL; /* set timer for fuel depot */ + planets[p].pl_flags &= ~PLATMASK; /* take off previous atmos */ + planets[p].pl_flags |= PLPOISON; /* poison atmosphere */ + planets[p].pl_flags |= PLDILYTH; /* dilythium deposits */ + planets[p].pl_owner = 1 << i; /* make race the owner */ + planets[p].pl_armies = COLONYARMIES; /* set the armies */ + planets[p].pl_hinfo = 1 << i; /* race knows about */ + planets[p].pl_tinfo[1 << i].owner = 1 << i; /* know about owner */ + planets[p].pl_tinfo[1 << i].armies = planets[p].pl_armies; + planets[p].pl_tinfo[1 << i].flags = planets[p].pl_flags; + for (j = 0; j < NUMPLANETS; j++) + { + if ((planets[j].pl_system == i + 1) && (PL_TYPE(planets[j]) != PLSTAR)) + { +#ifdef LEAGUE_SUPPORT + for (k = (status2->league ? 0 : i); + k < (status2->league ? 4 : i + 1); + k++) +#else + k = i; +#endif + { + planets[j].pl_owner = 1 << i; + planets[j].pl_hinfo = +#ifdef LEAGUE_SUPPORT + status2->league ? (1 << 4) - 1 : +#endif + (1 << i); + planets[j].pl_tinfo[1 << k].owner = 1 << i; + planets[j].pl_tinfo[1 << k].armies = planets[j].pl_armies; + planets[j].pl_tinfo[1 << k].flags = planets[j].pl_flags; + } + } + } + } +} + +/* + * Generate a complete galaxy, deepspace style. We use a 125k^2 grid with + * lots of planets for lots of fun. We're assuming a no-warp environment. + */ + +void +gen_galaxy_7() +{ + int t; + + GWIDTH = 125000; + NUMPLANETS = 60 - WORMPAIRS * 2; + configvals->warpdrive = 0; + + while (1) + { + initplanets(); /* initialize planet structures */ + + /* place the resources */ + zero_plflags(planets, NUMPLANETS); + randomize_atmospheres(planets + SYSTEMS, NUMPLANETS - SYSTEMS, + PATMOS1, PATMOS2, PATMOS3, PPOISON); + randomize_resources(planets + SYSTEMS, NUMPLANETS - SYSTEMS, + NMETAL, NDILYTH, NARABLE); + + /* place system centers */ + t = place_stars(planets, 4, + (int) TEAMBORD, (int) TEAMMIN, (int) TEAMMAX, + (struct planet *) 0, 0) + && place_stars(planets + 4, SYSTEMS - 4, + (int) STARBORD, (int) STARMIN, (int) STARMAX, + planets, 4); + + if (!t) + continue; + t = placesystems(); /* place planets in systems */ + if (!t) + continue; + t = placeindep(t); /* place independent planets */ + if (t) + break; /* success */ + } + if (configvals->justify_galaxy) + justify_galaxy(SYSTEMS); + placeraces(); /* place home planets for races */ + +} diff -r 054275999194 -r 8c6d5731234d src/planets.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/planets.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,1497 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + + +#define PLANETS 1 +#define GRID 0 /* for space grid */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "struct.h" +#include "data.h" +#include "daemonII.h" +#include "planets.h" +#include "misc.h" +#include "conquer.h" +#include "player.h" +#include "grid.h" +#include "shmem.h" +#include "terrain.h" + + +/* define this if you want the experimental dragging-into-star-counts mod */ +#define GIVESTARKILLS + +#define friendly(fred, bart) \ + (!(fred->p_team & (bart->p_swar|bart->p_hostile)) && \ + !(bart->p_team & (fred->p_swar|fred->p_hostile))) + + +/* defines dealing with growth timers */ +#define PLGFUEL configvals->plgrow.fuel /* time for growth of fuel + * depot */ +#define PLGAGRI configvals->plgrow.agri /* time for growth of agri */ +#define PLGREPAIR configvals->plgrow.repair /* time for growth of + * repair */ +#define PLGSHIP configvals->plgrow.shipyard /* time for growth of + * shipyard */ + +/* other defines */ +#define UCVISIBLE 40000 /* dist for uncloaked visibility */ +#define CVISMIN 12000 /* cloakers always visible distance */ +#define CVISSPEED 2000 /* cloak dist added per warp point */ +#define CVISIBLE 25000 /* dist for cloaked visibility */ +#define PLFIREDIST 1500 /* distance planets fire at players */ +#define PLVISDIST 5000 /* dist planets sense enemy players */ +#define REVOLT 200 /* chance out of 1000 of revolt start */ +#define STARTREV 8 /* for revolt timer */ +/*-------------------------------------------------------------------------*/ + + + + + + +/*-----------------------------MODULE VARIABLES----------------------------*/ + +/* the list of all possible planet names */ +char *pnames[] = +{ + /* Federation planets */ + "Rigel", "Canopus", "Beta Crucis", "Organia", "Deneb", + "Ceti Alpha V", "Altair", "Vega", "Alpha Centauri", + /* Romulan worlds */ + "Eridani", "Aldeberan", "Regulus", "Capella", "Tauri", + "Draconis", "Sirius", "Indi", "Hydrae", + /* Klingon worlds */ + "Pleiades V", "Andromeda", "Lalande", "Pollux", "Lyrae", + "Scorpii", "Mira", "Cygni", "Castor", + /* Orion worlds */ + "Cassiopia", "El Nath", "Spica", "Procyon", "Polaris", + "Arcturus", "Ursae Majoris", "Herculis", "Antares", + + /* new worlds */ + "Planet 10", "Bezier", "Sequent", "Ophiuchi", "Lacaille", + "Luyten", "Pavonis", "Wolf 424", "Ross 882", "Cephei", + "Kruger", "Groombridge", "Maanen's Star", "Heinlein", + "Pixel", "Lazarus", "Mycroft", "Asimov", "Varley", + "Clarke's Star", "Ren", "Stimpy", "Foo", "Jolt Cola", + "Kelly Bundy", "Tyrell", "Roy", "Deckard", "Vangelis", + "Orpheus", "Xanth", "Tatooine", "Ludicrous", "Ogg", + "Scum", "Twink", "Chiapucci", "Bugno", "Hampsten", "Fignon", + "Paradise", "Azriel", "Gargamel", "Smurf Village", + "Praxis", "Acherner", "Arrakis", "Caladan", "Giedi Prime", + "Clue", "Paulina", "Sith", "Salusa", "Ahrain", "Cerranos", + "Darkurthe", "Dagobah", "Phaze", "Chatsubu", "Lemond", + "Bronco", "Vulcan", "Eden", "Klein", "Merckx", "Tarot", + "Mottet", "Roche", "Doorstop", "Shaedron", "Fondriest", + + /* Bob's fave worlds */ + "Wayne's World", "DanjerHaus", "Anvil", /* B-52s */ "Claire", + "Planet Reebok", "Sony Corp.", "SEGA!", "McWorld", + "Tokyo", "New York", "D.C.", "Atlanta", /* places I've never been */ + /* Tony */ "Levin", + "Planet Woogie", "Nancy", "Wilson", /* real people */ + "Beavis", "Butthead", + "Memolo", /* Matt Memolo was murdered in Miami in July + * of '93. He was a really swell guy. "...he + * would go far out of his way to give you + * the shirt off his back." - ajc */ + /* names from the T.V. shows */ + "New Berlin", + /* + * "Bejor", "Cardassia" I'm not including these till I can spell them - RF + */ + + /* Mike's fave worlds */ + "Melmac", "Order", "Yosemite", "New Chicago", "Ceptus", "Ork", + "Levi 501", "Toughskin", "Wonka", + + /* book names */ + "Terminus", "Magrathea", "Trantor", "Synnax", "Coruscant", + + /* Moons, names, etc. */ + "Io ", "Titan", "Europa", "Ganymede", "Charon", + "Tholia", "Gor", "Kzin", "Aerth", + "Proxima", "Cellust", "Calamar", "Icarus", + "New Prague", + + /* How about the solar system? */ + "Mercury", "Venus", "Mars", "Jupiter", "Saturn", "Neptune", + "Uranus", "Pluto", /* are Neptune and Uranus in order? */ + +#if 0 + /* Player's names */ + "Claypigeon", "Maxout", "Fungus", "Lynx", + "Bubbles", "KnightRaven", "Bolo", "Vladimir", + "Gajah Mada", "Trippix", "Shrew", "Bob Dobbs", "Wibble", + "Rogue" +#endif +}; + +#define MAXNAMES (sizeof(pnames)/sizeof(char *)) /* # of planet names */ + +char *homenames[] = /* names of the race's home worlds */ +{ + " ", "Earth", "Romulus", " ", "Klingus", " ", " ", " ", + "Orion" +}; + + +/* + * This table is used to turn the four bits of resources flags into a three + * bit number. The shipyard and the repair are ORed together. All the non + * resource bits need to be masked off with PLRESMASK before this table is + * used + */ +int restores[16] = {0, 1, 2, 3, 4, 5, 6, 7, 1, 1, 3, 3, 5, 5, 7, 7}; + + +/* + * This is a matrix that determines the chance a planet has of popping. The + * chance is expressed as a chance out of 100. The matrix is accessed with + * the planet's atmosphere type and the resource bits after they have been + * converted to 3 bits with the table above. + */ +int popchance[4][8] = { + /* + * 000 00Z 0f0 0fZ a00 a0Z af0 afZ--the resources flags, + * Z=r|s + */ + {2, 3, 2, 2, 5, 7, 4, 8}, /* poison */ + {3, 5, 2, 4, 9, 11, 7, 12}, /* atmos #3 */ + {5, 7, 4, 6, 12, 14, 10, 15}, /* atmos #2 */ + {8, 12, 7, 10, 20, 24, 18, 23}/* atmos #1 */ +}; + + +/* + * This is a matrix that determines the multiplier for popping. When popping + * the armies on a planet will be multiplied by this multiplier to get the + * number of extra armies that grow. A negative number indicates negative + * growth. + */ +float popmult[4][8] = { + /* 000 00Z 0f0 0fZ a00 a0Z af0 afZ */ + {-0.08, 0.00, -0.10, -0.03, 0.00, 0.05, -0.05, 0.05}, /* poison */ + {0.03, 0.05, 0.02, 0.04, 0.06, 0.07, 0.06, 0.07}, /* atmos #3 */ + {0.05, 0.07, 0.05, 0.06, 0.10, 0.11, 0.08, 0.10}, /* atmos #2 */ + {0.09, 0.12, 0.08, 0.10, 0.17, 0.19, 0.15, 0.18} /* atmos #1 */ +}; + + +/* + * This is a matrix that determines the maximum army capacity of a planet. + * Once this capacity is reached, no other armies can grow there. + */ +float popcap[4][8] = { + /* + * 000 00Z 0f0 0fZ a00 a0Z af0 afZ--the resources flags, + * Z=r|s + */ + {5, 10, 7, 10, 15, 15, 10, 18}, /* poison */ + {9, 14, 11, 14, 20, 20, 14, 22}, /* atmos #3 */ + {12, 18, 15, 18, 25, 25, 19, 27}, /* atmos #2 */ + {15, 22, 18, 25, 40, 35, 27, 40} /* atmos #1 */ +}; + +/*-------------------------------------------------------------------------*/ + + + + + + + + +#ifdef LEAGUE_SUPPORT +extern void tlog_res(); +extern void tlog_bomb(); +extern void tlog_bres(); +extern void tlog_plankill(); +extern void tlog_revolt(); +extern void tlog_pop(); +#else +#define tlog_res(a,b) +#define tlog_bomb(a,b,c) +#define tlog_bres(a,b,c) +#define tlog_plankill(a,b,c) +#define tlog_revolt(a) +#define tlog_pop(a,b) +#endif +extern void scout_planet(); +extern int inflict_damage(); +extern void killmess(); +extern int enemy_admiral(); +extern off_t lseek(); +extern int write(); + +/*------------------------------INTERNAL FUNCTIONS-------------------------*/ + +void fill_planets(); + + +#ifndef NO_QSORT +/* used by the qsort() in sortnames() below */ +static int +comp_pl_name(a, b) + void *a, *b; +{ + return strcasecmp(((struct planet *) a)->pl_name, + ((struct planet *) b)->pl_name); +} +#endif + +/*--------------------------------SORTNAMES---------------------------------*/ +/* + * This function sorts the planet into a alphabeticly increasing list. It + * operates on the global planets structure. This uses a simple bubble sort + * because I was too lazy to write anything more sophisticated. + */ + +/* + * Bubble sorts suck. Let's use the qsort library function instead, if + * available (HK) + */ + +void +sortnames() +{ +#ifdef NO_QSORT + struct planet ptemp; /* temporary space to hold planet */ + int exchange; /* flag for exchange made in pass */ + int i; /* looping var */ + int t; /* temp var */ + + exchange = 1; /* no exchanges done yet */ + while (exchange) + { /* do until no exchanges */ + exchange = 0; /* no exchanges for this pass yet */ + for (i = 0; i < NUMPLANETS - 1; i++) + { /* go through list */ + if (strcmp(planets[i].pl_name, planets[i + 1].pl_name) > 0) + { + t = planets[i].pl_no; /* exchange planet numbers */ + planets[i].pl_no = planets[i + 1].pl_no; + planets[i + 1].pl_no = t; + memcpy(&ptemp, &(planets[i]), sizeof(struct planet)); + memcpy(&(planets[i]), &(planets[i + 1]), sizeof(struct planet)); + memcpy(&(planets[i + 1]), &ptemp, sizeof(struct planet)); + exchange++; /* we made an exchange this pass */ + } + } + } +#else + int i; + + qsort(planets, NUMPLANETS, sizeof(struct planet), comp_pl_name); + for (i = 0; i < NUMPLANETS; i++) /* go through the planets */ + planets[i].pl_no = i; /* and fix their pl_no value */ +#endif +} + + +/*--------------------------------INITPLANETS-------------------------------*/ +/* + * This function generates the names and initializes the fields in the + * planets structure. The planet names need to be sorted afterthe planets + * have been placed. + */ + +void +initplanets() +{ + int i, j; /* looping vars */ + int nused[MAXNAMES]; /* to mark which names are used */ + + for (i = 0; i < MAXNAMES; i++)/* go through all possible names */ + nused[i] = 0; /* mark name is not used yet */ + for (i = 0; i < NUMPLANETS; i++) + { + planets[i].pl_no = i; /* set planet number */ + planets[i].pl_flags = PLPARADISE; /* Paradise planet */ + planets[i].pl_owner = NOBODY; /* no owner yet */ + planets[i].pl_x = 0; /* just to intialize x and y */ + planets[i].pl_y = 0; + j = lrand48() % MAXNAMES; /* get a random name */ + do + { /* do until unused name found */ + j = (j + 1) % MAXNAMES; /* go on to next name in list */ + } while (nused[j]); /* until unused name found */ + nused[j] = 1; /* mark name as used */ + strcpy(planets[i].pl_name, pnames[j]); /* copy into planet struct */ + planets[i].pl_namelen = strlen(pnames[j]); /* set name's length */ +#if 1 + planets[i].pl_hostile = 0; /* planet doesn't hate anyone yet */ +#else + planets[i].pl_torbit = 0; /* no teams orbiting */ +#endif + planets[i].pl_tshiprepair = 0; /* zero the repair growth timer */ + planets[i].pl_tagri = 0; /* zero the agri growth timer */ + planets[i].pl_tfuel = 0; /* zero the fuel growth timer */ + planets[i].pl_armies = 0; /* no armies yet */ + planets[i].pl_warning = 0; /* no warning being counted down for */ + planets[i].pl_system = 0; /* not in a system yet */ + planets[i].pl_hinfo = NOBODY; /* no race has info on planet */ + for (j = 0; j < MAXTEAM + 1; j++) + { /* go through four races */ + planets[i].pl_tinfo[j].owner = NOBODY; /* do not know who owns it */ + planets[i].pl_tinfo[j].armies = 0; /* no armies on planet */ + planets[i].pl_tinfo[j].flags = PLPARADISE; /* know nothing about + * flags */ + planets[i].pl_tinfo[j].timestamp = 0; /* set the timestamp */ + } + planets[i].pl_trevolt = 0; /* revolt timer not counting down */ +#if GRID + planets[i].pl_next = NULL; /* set fields related to space grid */ + planets[i].pl_previous = NULL; + planets[i].pl_gridnum = 0; +#endif + } +} + + + + +/*-------------------------------GROWPLANETS------------------------------*/ +/* + * This function grows resources on planets. It goes through all planets and + * updates the growth timers and checks for growth. Independent planets do + * not grow. This function also checks to see if any player in a starbase is + * orbiting a planet and adjusts the planet's growth rate if so. + */ + +void +growplanets() +{ + int i; /* looping var */ + struct planet *p; /* to point within planets */ + int add; /* number to add to timers */ + + if (!status->tourn) + return; + + if (!configvals->resource_bombing) + return; + + for (i = 0; i < MAXPLAYER; i++) + { /* go through all players */ + struct player *py = &players[i]; /* and look for orbiting */ + if ((py->p_status != PALIVE) || /* starbases */ + (py->p_ship.s_type != STARBASE) || + !(py->p_flags & PFORBIT)) + continue; + p = &planets[py->p_planet]; /* found one, get planet */ + p->pl_tfuel += 20; /* give growth rate a boost */ + p->pl_tagri += 30; /* NOTE: change these if PLG consts */ + p->pl_tshiprepair += 50; /* change */ + } + p = &planets[0]; /* start with first planet */ + for (i = 0; i < NUMPLANETS; i++, p++) + { /* through all planets */ + if (p->pl_owner == NOBODY) /* if independent then */ + continue; /* no growth */ + add = p->pl_armies / 2; /* rate based on armies */ + p->pl_tfuel += add; /* add to fuel timer */ + p->pl_tfuel = (p->pl_tfuel > PLGFUEL) ? PLGFUEL : p->pl_tfuel; + if ((!(p->pl_flags & PLFUEL)) /* if no fuel */ + && (p->pl_flags & PLDILYTH) /* and dilythium deposits */ + && (p->pl_tfuel >= PLGFUEL)) + { /* and timer high enough */ + p->pl_flags |= (PLFUEL | PLREDRAW); /* create fuel depot */ + p->pl_tinfo[p->pl_owner].flags = p->pl_flags; + p->pl_tinfo[p->pl_owner].timestamp = status->clock; + tlog_res(p, "FUEL"); + } + p->pl_tagri += add; /* add to agri timer */ + p->pl_tagri = (p->pl_tagri > PLGAGRI) ? PLGAGRI : p->pl_tagri; + if ((!(p->pl_flags & PLAGRI)) /* if no agri on planet */ + && (p->pl_flags & PLARABLE) /* and arable */ + && (p->pl_tagri >= PLGAGRI)) + { /* and timer high enough */ + p->pl_flags |= (PLAGRI | PLREDRAW); /* create agri planet */ + p->pl_tinfo[p->pl_owner].flags = p->pl_flags; + p->pl_tinfo[p->pl_owner].timestamp = status->clock; + tlog_res(p, "AGRI"); + } + p->pl_tshiprepair += add; /* add to ship/repair timer */ + if ((!(p->pl_flags & PLREPAIR)) /* if not repair */ + && (p->pl_flags & PLMETAL) /* and metal deposits */ + && (p->pl_tshiprepair >= PLGREPAIR)) + { /* and timer high enough */ + p->pl_flags |= (PLREPAIR | PLREDRAW); /* create repair station */ + p->pl_tinfo[p->pl_owner].flags = p->pl_flags; + p->pl_tinfo[p->pl_owner].timestamp = status->clock; + tlog_res(p, "REPAIR"); + } + p->pl_tshiprepair = (p->pl_tshiprepair > PLGSHIP) ? PLGSHIP : + p->pl_tshiprepair; /* clamp value to max */ + if ((!(p->pl_flags & PLSHIPYARD)) /* if not repair */ + && (p->pl_flags & PLMETAL) /* and metal deposits */ + && (p->pl_tshiprepair >= PLGSHIP)) + { /* and timer high enough */ + p->pl_flags |= (PLSHIPYARD | PLREDRAW); /* create repair station */ + p->pl_tinfo[p->pl_owner].flags = p->pl_flags; + p->pl_tinfo[p->pl_owner].timestamp = status->clock; + tlog_res(p, "SHIPYARD"); + } + } +} + + + + +/*----------------------------------PVISIBLE------------------------------*/ +/* + * This function goes through the players and checks the other playes to see + * if an enemy is close enough to see him. THIS FUNCTION SHOULD EVENTUALLY + * USE THE SPACE GRID. + */ + +void +pvisible() +{ + struct player *p; /* to point to a player */ + int i; /* looping var */ + int h; /* looping var */ + struct player *pl2; /* to point to other players */ + int dx, dy; /* delta coords */ + int dist; /* to hold distance */ + + for (i = 0, p = &players[0]; i < MAXPLAYER; i++, p++) + p->p_flags &= ~PFSEEN; /* clear all players' the seen flags */ + for (i = 0, p = &players[i]; i < MAXPLAYER - 1; i++, p++) + { + if (p->p_status != PFREE && /* only do if player alive */ + p->p_status != POBSERVE) + { /* observers can't augment team scanning */ + for (h = i + 1, pl2 = &players[h]; h < MAXPLAYER; h++, pl2++) + { + if ((pl2->p_status == PFREE) || (pl2->p_status == POBSERVE) + || (pl2->p_flags & PFROBOT) /* if not alive or robot or */ + || (pl2->p_team == p->p_team)) /* same team then continue */ + continue; + dx = ABS(pl2->p_x - p->p_x); /* calc delta coords */ + dy = ABS(pl2->p_y - p->p_y); + if ((dx > UCVISIBLE) || (dy > UCVISIBLE)) /* if obviously too far + * away */ + continue; /* then don't bother further */ + dist = ihypot(dx, dy); + if (dist > UCVISIBLE) /* out of range */ + continue; /* on to next ship */ + if ((dist < CVISMIN + CVISSPEED * pl2->p_speed) || + (!(pl2->p_flags & PFCLOAK))) + pl2->p_flags |= PFSEEN; /* if close then visible */ + if ((dist < CVISMIN + CVISSPEED * p->p_speed) || + (!(p->p_flags & PFCLOAK))) + p->p_flags |= PFSEEN; /* second player */ + } + } + } +} + + + +void +blast_resource(p, l, res, dival) + struct player *p; + struct planet *l; + int res; + double dival; +{ + if (status->tourn) + { + p->p_stats.st_di += dival; + p->p_stats.st_tresbomb++; + p->p_resbomb++; + status->resbomb++; + } + l->pl_flags &= ~res; + l->pl_tinfo[l->pl_owner].flags = l->pl_flags; + l->pl_tinfo[l->pl_owner].timestamp = status->clock; + l->pl_tinfo[p->p_team].flags = l->pl_flags; + l->pl_tinfo[p->p_team].timestamp = status->clock; + l->pl_flags |= PLREDRAW; /* slate for redraw */ +} + +/*-----------------------------------PBOMB---------------------------------*/ +/* + * This function goes through the players and does the bombing if any player + * is bombing. This will knock resources off of planets. If a player is + * bombing a planet that another team owns, then that team will see the + * player by having the PFSEEN flag set. + */ + +void +pbomb() +{ + struct player *p; /* to point to a player */ + int i; /* looping var */ + struct planet *l; /* to point to planet being bombed */ + char buf[90]; /* to sprintf messages into */ + char buf1[80]; + int rnd; /* to hold armies to knock off */ + + for (i = 0, p = &players[0]; i < MAXPLAYER; i++, p++) + { /* go through playrs */ + if ((p->p_status == PALIVE) /* only do if player is alive */ + && (p->p_flags & PFORBIT) /* and he is orbiting */ + && (p->p_flags & PFBOMB)) + { /* and he is bombing */ + + l = &planets[p->p_planet];/* get planet being bombed */ + + if ((!((p->p_swar | p->p_hostile) & l->pl_owner)) + && (l->pl_owner != NOBODY)) + { + /* if he's non-hostile, quit bombing */ + p->p_flags &= ~PFBOMB; + continue; + } + if ((l->pl_warning <= 0) && (l->pl_owner != NOBODY)) + { /* warning? */ + l->pl_warning = 50 / PLFIGHTFUSE; /* reset warning timer */ + sprintf(buf, "We are being attacked by %s %s who is %d%% damaged.", + p->p_name, twoletters(p), + (100 * p->p_damage) / (p->p_ship.s_maxdamage)); + sprintf(buf1, "%-3s->%-3s", l->pl_name, teams[l->pl_owner].shortname); + pmessage(buf, l->pl_owner, MTEAM | MBOMB, buf1); /* send message */ + + /* CRD feature: shipyard guardians - MAK, 2-Jun-93 */ + if ((l->pl_flags & PLSHIPYARD) && (!status->tourn)) + { + rescue(l->pl_owner, 0, l->pl_no); + } + } + p->p_swar |= l->pl_owner; /* set player at war w/ owner */ + rnd = (lrand48() % 50) + p->p_ship.s_bomb; /* pick random number */ + rnd = (int) ((float) rnd / 33.0 + 0.5); /* calc armies bombed */ + if (rnd <= 0) + continue; /* can't bomb negative armies */ + if (l->pl_armies > 4) + { /* if armies to bomb then */ + l->pl_armies -= rnd; /* kill off armies */ + tlog_bomb(l, p, rnd); + l->pl_armies = (l->pl_armies < 1) ? 1 : l->pl_armies; + l->pl_tinfo[l->pl_owner].armies = l->pl_armies; + l->pl_tinfo[l->pl_owner].timestamp = status->clock; + l->pl_tinfo[p->p_team].armies = l->pl_armies; + l->pl_tinfo[p->p_team].timestamp = status->clock; + if (l->pl_armies < 5) /* if planet needs to be redrawn */ + l->pl_flags |= PLREDRAW; /* schedule planet for redraw */ + if (l->pl_owner != NOBODY) + { + credit_armiesbombed(p, rnd, l); + } + } /* now do the resource bombing */ + if ((l->pl_armies > 4) || + (!configvals->resource_bombing)) /* no bombing resources if + * armies */ + continue; /* on planet or in bronco-mode */ +#if defined(AEDILE) || defined(SLOW_BOMB) + l->pl_tfuel -= rnd * 5; /* knock fuel timer down */ +#else + l->pl_tfuel -= rnd * 8; /* knock fuel timer down */ +#endif + l->pl_tfuel = (l->pl_tfuel < 0) ? 0 : l->pl_tfuel; + if ((l->pl_tfuel == 0) && (l->pl_flags & PLFUEL)) + { + blast_resource(p, l, PLFUEL, 0.10); + tlog_bres(l, p, "FUEL"); + } +#if defined(AEDILE) || defined(SLOW_BOMB) + l->pl_tagri -= rnd * 4; /* attack the agri timer */ +#else + l->pl_tagri -= rnd * 6; /* attack the agri timer */ +#endif + l->pl_tagri = (l->pl_tagri < 0) ? 0 : l->pl_tagri; + if ((l->pl_tagri == 0) && (l->pl_flags & PLAGRI)) + { + blast_resource(p, l, PLAGRI, 0.25); + tlog_bres(l, p, "AGRI"); + } +#if defined(AEDILE) || defined(SLOW_BOMB) + l->pl_tshiprepair -= rnd * 5; /* knock ship/repr down */ +#else + l->pl_tshiprepair -= rnd * 8; /* knock ship/repr down */ +#endif + l->pl_tshiprepair = (l->pl_tshiprepair < 0) ? 0 : + l->pl_tshiprepair; + if ((l->pl_tshiprepair < PLGREPAIR) && (l->pl_flags & PLSHIPYARD)) + { + blast_resource(p, l, PLSHIPYARD, 0.10); + tlog_bres(l, p, "SHIPYARD"); + } + if ((l->pl_tshiprepair == 0) && (l->pl_flags & PLREPAIR)) + { + blast_resource(p, l, PLREPAIR, 0.20); + tlog_bres(l, p, "REPAIR"); + } + } + } +} + + + + +/*---------------------------------PFIRE-----------------------------------*/ +/* + * This function goes through the planets and sees if any enemy players are + * close enough to be fired upon by the planet. It also checks to see if + * players are close enough to the planet so that the planet should be + * redrawn. Enemy planets will 'see' players that are very close to them. + * THIS FUNCTION SHOULD EVENTUALLY USE THE SPACE GRID. + */ + +void +pfire() +{ + struct player *p; /* to point to a player */ + int i, j; /* looping vars */ + struct planet *l; /* to point to the planets */ + int dx, dy; /* to hold delta coords */ + int dist; /* to hold distance */ + int dam; /* to hold damage */ + int boost; /* for warp zones, total boost [BDyess] */ + + for (j = 0, p = &players[0]; j < MAXPLAYER; j++, p++) + { + if (p->p_status != PALIVE) + continue; + boost = 0; /* default no bonus or penalty [BDyess] */ + for (i = 0, l = &planets[0]; i < NUMPLANETS; i++, l++) + { + if ((p->p_team == l->pl_owner) && (PL_TYPE(*l) != PLSTAR) + && !configvals->warpzone) + continue; /* no, then continue */ + dx = ABS(l->pl_x - p->p_x); /* calc delta coorda between */ + dy = ABS(l->pl_y - p->p_y); /* planet and player */ + dist = ihypot(dx, dy); + + if (dist < configvals->warpzone) + { + /* within warp boost/block range [BDyess] */ + if (p->p_team == l->pl_owner) + boost += configvals->warpzone - dist; + else if (l->pl_owner != NOBODY && + ((p->p_swar | p->p_hostile) & l->pl_owner)) + boost -= configvals->warpzone - dist; + } + + if (dx < 6 * PLFIREDIST && dy < 6 * PLFIREDIST) /* redraw planet */ + l->pl_flags |= PLREDRAW;/* if player is very close */ + + if (dist <= p->p_ship.s_scanrange) + { /* check for scanners */ + scout_planet(p->p_no, l->pl_no); +#if 0 + handled in scout_planet now. + l->pl_hinfo |= p->p_team; + l->pl_tinfo[p->p_team].armies = l->pl_armies; + l->pl_tinfo[p->p_team].flags = l->pl_flags; + l->pl_tinfo[p->p_team].owner = l->pl_owner; + l->pl_tinfo[p->p_team].timestamp = status->clock; +#endif + } + + if (dist > PLVISDIST) + continue; + if ((dist < PLVISDIST) && (l->pl_owner != NOBODY) /* enemy planet */ + && ((p->p_swar | p->p_hostile) & l->pl_owner)) /* see players */ + p->p_flags |= PFSEEN; /* let team see enemy */ + if ((dist > PFIREDIST) || + ((dist > PFIREDIST / 2) && + (PL_TYPE(*l) == PLWHOLE))) /* if not within range */ + continue; /* go on to next playert */ + if (((p->p_swar | p->p_hostile) & l->pl_owner) + || ((l->pl_owner == NOBODY) +#if 1 + && (l->pl_hostile & p->p_team) +#else + && (l->pl_torbit & (p->p_team << 4)) +#endif + && (l->pl_armies != 0)) + || (PL_TYPE(*l) == PLWHOLE) || (PL_TYPE(*l) == PLSTAR)) + { + dam = l->pl_armies / 7 + 2; /* calc the damage */ + if (PL_TYPE(*l) == PLWHOLE) + { /* if a wormhole... */ + /* ...place outside the new wormhole's radius. */ + if ((wh_effect[SS_WARP] && !(p->p_flags & PFWARP)) + || (!wh_effect[SS_WARP])) + { + p->p_x = l->pl_armies + + (((PLFIREDIST / 2) + 50) * Cos[p->p_dir]); + p->p_y = l->pl_radius + + (((PLFIREDIST / 2) + 50) * Sin[p->p_dir]); + } + if ((p->p_speed > (p->p_ship.s_imp.maxspeed / 2)) && + (wh_effect[SS_IMPULSE])) + { + dam = ((p->p_ship.s_mass / 100) * (p->p_speed - + p->p_ship.s_imp.maxspeed / 2)); + } + else + dam = 0; + + } + else if (PL_TYPE(*l) == PLSTAR) /* if planet is a star */ + dam = 150; /* do massive damage */ + /* + * this needs to be reworked and most of it jammed into + * inflict_damage + */ + p->p_whodead = i; /* which planet is shooting */ + if (dam > 0 && inflict_damage(0, 0, p, dam, KPLANET)) + { + struct player *killer = 0; + p->p_whydead = KPLANET; /* set killed by a planet */ + if (PL_TYPE(*l) == PLSTAR) + { /* killed by star? */ +#ifdef GIVESTARKILLS + int pln; + for (pln = 0, killer = &players[0]; + pln < MAXPLAYER; + pln++, killer++) + { + if (killer->p_status != PALIVE) + continue; + if (!friendly(killer, p) && killer->p_tractor == p->p_no + && killer->p_flags & (PFTRACT | PFPRESS)) + { + + killer->p_kills += 1 + (p->p_armies + p->p_kills) / 10; + killerstats(killer->p_no, p); + checkmaxkills(killer->p_no); + break; + } + } + if (pln >= MAXPLAYER) + killer = 0; +#endif + } + killmess(p, killer); + tlog_plankill(p, l, killer); + } + } + } + /* found the boost for this player, make adjustments if in warp [BDyess] */ + if (configvals->warpzone && p->p_flags & PFWARP) + { + if (boost == 0 && p->p_zone > 0) + { /* did get warp bonus, lost it */ + if (p->p_desspeed > p->p_ship.s_warp.maxspeed) + p->p_desspeed = p->p_ship.s_warp.maxspeed; + } + else if (boost < 0 && p->p_zone >= 0) + { /* warp no longer allowed */ + p->p_desspeed = p->p_ship.s_imp.maxspeed; + if (!configvals->warpdecel) + p->p_flags &= ~PFWARP; + } + } + p->p_zone = boost; + } +} + + + + +/*---------------------------------REVOLT---------------------------------*/ +/* + * This function does the revolt of a planet. It updates the revolt timer + * and prints the messages that warn the team. + */ + +void +revolt(l) + struct planet *l; /* the planet to check */ +{ + if (!configvals->revolts) + return; + + if (l->pl_trevolt > 0) + { /* revolt timer running? */ + char buf[80]; /* to sprintf into */ + + { + int i; + for (i = 0; i < MAXPLAYER; i++) + { + if (players[i].p_status == PALIVE + && (players[i].p_flags & (PFORBIT | PFDOCK)) == PFORBIT + && players[i].p_planet == l->pl_no + && players[i].p_team == l->pl_owner) + return; /* orbiting ship delays revolt */ + } + } + + l->pl_trevolt--; /* dec the timer */ + if ((l->pl_trevolt == 0) && (l->pl_armies > 2)) + { + l->pl_trevolt = 0; /* turn off revolt timer */ + sprintf(buf, "The revolution on %s has been put down.", + l->pl_name); /* get message to display */ + pmessage(buf, l->pl_owner, MTEAM | MCONQ, "PREFECT->"); + } + else if ((l->pl_trevolt == 0) && (l->pl_armies == 2)) + { + l->pl_trevolt = STARTREV; /* more time til last army */ + l->pl_armies--; /* kill one army */ + l->pl_tinfo[l->pl_owner].armies = l->pl_armies; + l->pl_tinfo[l->pl_owner].timestamp = status->clock; + sprintf(buf, "We cannot hold out much longer on %s", + l->pl_name); /* get message to display */ + pmessage(buf, l->pl_owner, MTEAM | MCONQ, "PREFECT->"); + } + else if (l->pl_trevolt == 0) + { + l->pl_trevolt = 0; /* revolution succeeded */ + sprintf(buf, "The planet %s has been lost to revolutionaries", + l->pl_name); /* get message to display */ + pmessage(buf, l->pl_owner, MTEAM | MCONQ, "PREFECT->"); + + tlog_revolt(l); + + l->pl_tinfo[l->pl_owner].timestamp = status->clock; + l->pl_tinfo[l->pl_owner].owner = NOBODY; + l->pl_owner = NOBODY; + l->pl_flags |= PLREDRAW; /* slate for redraw */ + checkwin(enemy_admiral(-1)); /* check for game end */ + + } + } + else + { /* no revolt timer--check for start */ + if ((l->pl_armies <= 2) && (!(l->pl_armies == 0)) + && ((lrand48() % 1000) <= REVOLT)) + { + char buf[80]; /* to sprintf message into */ + + sprintf(buf, "There is civil unrest on %s", l->pl_name); + pmessage(buf, l->pl_owner, MTEAM | MCONQ, "PREFECT>>"); + l->pl_trevolt = STARTREV; /* time before revolution */ + } + } +} + +void +check_revolt() +{ + static int planetlist[MAXPLANETS]; + static int count = 0; + int idx; + struct planet *l; + + if (!status->tourn) + return; + + if (count < 1) + fill_planets(planetlist, &count, -1); + + idx = planetlist[--count]; + l = &planets[idx]; + + if (l->pl_armies > 0 && l->pl_owner != NOBODY) + revolt(l); +} + +/*-------------------------------------------------------------------------*/ + + + + + + +/* struct planet *stars[NUMPLANETS + 1]; */ + +static void +build_stars_array() +{ + int i; + struct planet *pl; + + for (i = 0; i < NUMPLANETS; i++) + { + pl = &planets[i]; + if (PL_TYPE(*pl) == PLSTAR) + stars[pl->pl_system] = i; + } +} + +/*------------------------------VISIBLE FUNCTIONS-------------------------*/ + +/*-------------------------------GEN_PLANETS-------------------------------*/ +/* + * This function generates a number of random planets. The planets are + * arranged in systems and are also placed so that they are not too close to + * any other planets. The races are then given home planets. + */ + +void +gen_planets() +{ + int i; + struct planet *pl; + + status->clock = 0; /* reset the timestamp clock */ + + switch (configvals->galaxygenerator) + { + case 2: + gen_galaxy_2(); /* Bob Forsman's compact galaxy generator */ + break; + case 3: + gen_galaxy_3(); /* Heath's better race placement galaxy + * generator */ + break; + case 4: + gen_galaxy_4(); /* Mike's Bronco emulator */ + break; + case 5: + gen_galaxy_5(); /* Mike's small-galaxy generator */ + break; + case 6: + gen_galaxy_6(); /* Brandon's hack on Heath's to give 2 */ + break; /* systems to each race */ + case 7: + gen_galaxy_7(); /* Eric Dormans deepspace galaxy gen, rooted + * in galaxy gen 6. */ + break; + case 1: + default: + gen_galaxy_1(); /* original paradiseII galaxy generator */ + break; + } + + if (configvals->galaxygenerator != 4) + { + /* gotta do this before they are sorted */ + for (i = 0; i < NUMPLANETS; i++) + { + pl = &planets[i]; + if (PL_TYPE(*pl) == PLSTAR || + ((pl->pl_system == 0) && (PL_TYPE(*pl) != PLWHOLE))) + { + pl->pl_radius = 0; + pl->pl_angle = 0; + } + else if (PL_TYPE(*pl) != PLWHOLE) + { + int dx, dy; + dx = pl->pl_x - planets[pl->pl_system - 1].pl_x; + dy = pl->pl_y - planets[pl->pl_system - 1].pl_y; + pl->pl_radius = ihypot(dx, dy); + pl->pl_angle = atan2((double) dy, (double) dx); + } + } + sortnames(); /* sort the names of planets */ + build_stars_array(); + if (configvals->neworbits) + pl_neworbit(); + generate_terrain(); + } +} + +void +pl_neworbit() +/* + * rearranges a pre-existing galaxy setup such that planets orbit at more + * "unique" distances from their star. Asteroids look and probably play bad + * when all the planets are approx. the same dist from the star, so I'd + * suggest turning this on if you plan to have asteroids or orbiting planets + * on your server. I'd suggest turning it on even if you don't. :) -MDM + */ +{ + register int i, j; + register struct planet *p; + register int numStars = 0, planetsThisStar = 0; +#ifndef IRIX + int planetList[NUMPLANETS]; +#else + int planetList[70]; +#endif + + /* find the number of stars */ + for (i = 0; i < MAXPLANETS; i++) + if (PL_TYPE(planets[i]) == PLSTAR) + numStars++; + + /* for each star, find the number of planets, and the average distance */ + + for (i = 1; i <= numStars; i++) + { + planetsThisStar = 0; + for (j = 0; j < MAXPLANETS; j++) + if (planets[j].pl_system == i) + planetList[planetsThisStar++] = j; + + /* + * now move the planets such that each planet we came across gets its + * previous distance from it's star, times (it's position in the + * planetList array)/(planetsThisStar/1.6). also make sure that new + * radius isin't so close to star ship can't orbit it. Heh. Separate + * the men from the boyz, eh? + */ + + for (j = 0; j < planetsThisStar; j++) + { + planets[planetList[j]].pl_radius = + (int) ((float) planets[planetList[j]].pl_radius * + ((float) (j + 1) / (float) (planetsThisStar / 1.6))) + 1500; + planets[planetList[j]].pl_x = + planets[stars[i]].pl_x + + (int) ((float) cos(planets[planetList[j]].pl_angle) * + (float) planets[planetList[j]].pl_radius); + planets[planetList[j]].pl_y = + planets[stars[i]].pl_y + + (int) ((float) sin(planets[planetList[j]].pl_angle) * + (float) planets[planetList[j]].pl_radius); + } + } +} + +void +moveplanets() +{ + register int i; /* for looping */ + register struct planet *l; /* to point to individual plaent */ + + if (stars[1] < 0) + build_stars_array(); + + /* totally experimental planet moving stuff */ + for (i = 0; i < NUMPLANETS; i++) + { + int x, y; + double r; + l = &planets[i]; + if (PL_TYPE(*l) == PLSTAR || l->pl_system == 0) + continue; /* write code for them another time */ + + r = l->pl_radius; + l->pl_angle += configvals->planupdspd * 1e2 / sqrt(r * r * r); + if (l->pl_angle > 2 * M_PI) + l->pl_angle -= 2 * M_PI; + x = planets[stars[l->pl_system]].pl_x + cos(l->pl_angle) * l->pl_radius; + y = planets[stars[l->pl_system]].pl_y + sin(l->pl_angle) * l->pl_radius; + move_planet(i, x, y, 1); + } +} + + +/* + * This function pops the armies on planets. It now uses the tables that are + * in this module. Negative growth is supported. + */ + +static void +pop_one_planet1(l) + struct planet *l; +{ + int r; /* to hold resource index */ + int a; /* to hold atmosphere index */ + int t; /* temp var */ + float ft; /* another temp */ + + r = (l->pl_flags & PLRESMASK) >> PLRESSHIFT; /* get resource bits */ + r = restores[r]; /* convert to 3 bits */ + a = l->pl_flags & PLATMASK; /* get atmosphere bits */ + a = a >> PLATSHIFT; /* shift to lower two bits of int */ + +#ifdef UFL + t = status2->league ? popchance[a][r] : 8; +#else + t = popchance[a][r]; /* get pop chance */ +#endif + if (t < lrand48() % 100) /* if planet misses chance */ + return; /* then on to next planet */ + ft = popmult[a][r]; /* get pop multiplier */ + if (ft >= 0) + { /* positive multiplier */ + int incr; + + if (l->pl_armies >= popcap[a][r]) + return; + + if (l->pl_armies < 4) /* chance of going over four */ + l->pl_flags |= PLREDRAW; /* slate planet for redraw */ + if (configvals->new_army_growth) +#ifdef AEDILE + incr = 0.5 + ft * 2.0 * (float) (lrand48() % 6 + 3); +#else + incr = 1 + 0.5 + ft * (float) (l->pl_armies); +#endif + else + /* what about agri? */ + incr = 1 + lrand48() % 3; /* bronco is always 1-3 armies/pop */ + tlog_pop(l, incr); + l->pl_armies += incr; /* add on multiplier armies */ + l->pl_tinfo[l->pl_owner].armies = l->pl_armies; + l->pl_tinfo[l->pl_owner].timestamp = status->clock; + } + else + { /* negative multiplier */ + int decr; + if (l->pl_armies < 4) /* no killing all the armies on */ + return; /* a planet */ + l->pl_flags |= PLREDRAW; /* slate planet for redraw */ + decr = 1 + 0.5 - ft * (float) (l->pl_armies); + tlog_pop(l, -decr); + l->pl_armies -= decr; /* subtract armies */ + l->pl_armies = (l->pl_armies < 0) ? 0 : l->pl_armies; + if (l->pl_armies <= 0) + { /* if all died then */ + l->pl_armies = 0; /* no negative armies */ + l->pl_tinfo[l->pl_owner].armies = 0; /* old owner knows */ + l->pl_tinfo[l->pl_owner].timestamp = status->clock; + l->pl_tinfo[l->pl_owner].owner = NOBODY; + l->pl_owner = NOBODY; /* planet is neutral */ + } + l->pl_tinfo[l->pl_owner].armies = l->pl_armies; + l->pl_tinfo[l->pl_owner].timestamp = status->clock; + if (l->pl_armies == 0) /* if all armies died */ + checkwin(enemy_admiral(-1)); /* check if game over */ + } +} +/* + * */ + +static void +pop_one_planet2(l) + struct planet *l; +{ + int delta = 0; + int atmosphere = (l->pl_flags & PLATMASK) >> PLATSHIFT; + int surface = (l->pl_flags & PLSURMASK) >> PLSURSHIFT; + + if (l->pl_armies < 4 && (l->pl_flags & PLAGRI)) + delta++; + + if (atmosphere == 0) + { + if (l->pl_armies >= 4 && drand48() < 0.5) + { + delta--; + } + } + else if (atmosphere < 3) + { + if (drand48() < + ((atmosphere == 1) + ? (l->pl_armies < 4 ? 0.2 : 0.1) + : (l->pl_armies < 4 ? 0.5 : 0.2))) + { + delta++; + } + } + else + { + if (drand48() < (l->pl_armies < 4 ? 0.3 : 0.2)) + { + static int table[] = {2, 2, 2, 3, 3, 3, 4, 4}; + int max = table[surface]; + delta++; + if (l->pl_flags & PLAGRI && l->pl_armies >= 4) + max++; /* armies<4 handled at top */ + delta += lrand48() % max; + } + } + + if (l->pl_armies == 0 && delta > 1) + delta = 1; /* training that first army is tough */ + + tlog_pop(l, delta); + + if (delta > 0 && + l->pl_armies > popcap[atmosphere] + [restores[(l->pl_flags & PLRESMASK) >> PLRESSHIFT]]) + delta = 0; + l->pl_armies += delta; + + /* + * I doubt this if statement will ever get executed unless someone's + * frobbing shmem + */ + if (l->pl_armies <= 0) + { /* if all died then */ + l->pl_armies = 0; /* no negative armies */ + + tlog_revolt(l); /* well, not exactly. */ + + l->pl_tinfo[l->pl_owner].armies = 0; /* old owner knows */ + l->pl_tinfo[l->pl_owner].timestamp = status->clock; + l->pl_tinfo[l->pl_owner].owner = NOBODY; + l->pl_owner = NOBODY; /* planet is neutral */ + checkwin(enemy_admiral(-1));/* check if game over */ + } + + l->pl_tinfo[l->pl_owner].armies = l->pl_armies; + l->pl_tinfo[l->pl_owner].timestamp = status->clock; +} + +void +pop_one_planet(l) + struct planet *l; +{ +#if 0 + printf("popping planet #%d %x\n", l->pl_no, l->pl_owner); + fflush(stdout); +#endif + + switch (configvals->popscheme) + { + case 1: + pop_one_planet2(l); + break; + default: + case 0: + pop_one_planet1(l); + break; + } +} + + +/*-------------------------------UDPLANETS----------------------------------*/ + +void +fill_planets(plist, count, owner) + int *plist; /* array */ + int *count; /* scalar */ + int owner; +{ + int i; + *count = 0; + for (i = 0; i < configvals->numplanets; i++) + { + if (owner < 0 || planets[i].pl_owner == owner) + plist[(*count)++] = i; + } + + for (i = *count - 1; i > 0; i--) + { + int idx = lrand48() % (i + 1); + int temp = plist[idx]; + plist[idx] = plist[i]; + plist[i] = temp; + } +} + +int +find_other_team(teammask) + int teammask; +{ + int counts[NUMTEAM]; + int i; + for (i = 0; i < NUMTEAM; i++) + counts[i] = 0; + for (i = 0; i < MAXPLAYER; i++) + { + int teamidx = mask_to_idx(players[i].p_team); + if (teamidx >= 0 && teamidx < NUMTEAM && !(teammask & (1 << teamidx))) + counts[teamidx]++; + } + + { + int max = -1; + int rval = 0; + for (i = 0; i < NUMTEAM; i++) + { + if (counts[i] > max && !(teammask & (1 << i))) + { + max = counts[i]; + rval = 1 << i; + } + } + return rval; + } +} + +void +popplanets() +{ + register int i; /* for looping */ + register struct planet *l; /* to point to individual plaent */ + + if (!status->tourn) /* check t-mode */ + return; /* do not pop planets */ + + switch (configvals->popchoice) + { + case 0: + { + static int fuse = 0; + if (++fuse < PLANETFUSE) + return; /* nothing to do */ + fuse = 0; + for (i = 0, l = &planets[i]; i < NUMPLANETS; i++, l++) + { + if ((l->pl_armies == 0) || + (PL_TYPE(*l) == PLSTAR) || + (PL_TYPE(*l) == PLWHOLE)) /* if no armies to pop */ + continue; /* go to next planet */ +#if 0 + if (l->pl_owner != NOBODY) /* only team planets can revolt */ + revolt(l); /* check for revolt */ +#endif + pop_one_planet(l); + } + } break; + case 1: + { +#if 0 + static int indplanets[MAXPLANETS]; + static int indcount = 0; +#endif + static int Aplanets[MAXPLANETS]; + static int Acount = 0, Amask = 0; + static int Bplanets[MAXPLANETS]; + static int Bcount = 0, Bmask = 0; + + int INDchance; + float Achance, Bchance; + float f; + + /* make sure there's planets in the lists */ +#if 0 + if (indcount < 1) + fill_planets(indplanets, &indcount, NOBODY); +#endif + if (Acount < 1) + { + Amask = find_other_team(Bmask); + fill_planets(Aplanets, &Acount, Amask); + } + if (Bcount < 1) + { + Bmask = find_other_team(Amask); + fill_planets(Bplanets, &Bcount, Bmask); + } + + /* figure out the probabilities */ + INDchance = Achance = Bchance = 0; + for (i = 0; i < configvals->numplanets; i++) + { + if (planets[i].pl_owner == Amask) + Achance += 1.0; + else if (planets[i].pl_owner == Bmask) + Bchance += 1.0; + else if (!((PL_TYPE(planets[i]) == PLSTAR) || + (PL_TYPE(planets[i]) == PLWHOLE))) + /* if (planets[i].pl_owner == NOBODY) */ + INDchance += 1.0; + } + +#ifdef LOOSING_ADVANTAGE + { + double la = LOOSING_ADVANTAGE; + if (Achance < Bchance) + Achance *= (la - (la - 1) * Achance / Bchance); + else + Bchance *= (la - (la - 1) * Bchance / Achance); + } +#endif + + f = drand48() * (INDchance + Achance + Bchance); + if (f < INDchance) + { +#if 0 /* 3rd-race planets and INDs don't pop */ + pop_one_planet(&planets[indplanets[--indcount]]); +#endif + } + else if (f - INDchance < Achance) + { + pop_one_planet(&planets[Aplanets[--Acount]]); + } + else + { + pop_one_planet(&planets[Bplanets[--Bcount]]); + } + + } break; + } +} + + + + + +/*----------------------------------PLFIGHT--------------------------------*/ +/* + * This function does the fighting for a planet. It decs the warning timer + * and clears the REDRAW flag. It then handles the bombing for the players. + * It then goes on to see if a player is visible to the other team by + * checking the closeness of other players. The planets are then checked to + * see if they are close enough to fire on enemy players. + */ + +void +plfight() +{ + register int h; /* looping vars */ + register struct planet *l; /* for looping through planets */ + + for (h = 0, l = &planets[h]; h < NUMPLANETS; h++, l++) + { + l->pl_flags &= ~PLREDRAW; /* clear the PLDRAW flag */ + if (l->pl_warning > 0) /* check if timer needs dec */ + l->pl_warning--; /* dec the warning timer */ + } + pbomb(); /* go do bombing for players */ + pvisible(); /* check visibility w/ other players */ + pfire(); /* let planets fire on other players */ +} + + + + +/*-------------------------------SAVE_PLANETS-----------------------------*/ +/* + * This function saves the planets structure to disk. The plfd variable is a + * handle on the previously opened .planets file. The function also saves + * the status to the glfd file. + */ + +void +save_planets() +{ + if (plfd >= 0) + { /* if plfd file open */ + (void) lseek(plfd, (long) 0, 0); /* save the planets */ + (void) write(plfd, (char *) planets, sizeof(struct planet) * MAXPLANETS); + } + if (glfd >= 0) + { /* if glfd file open then */ + (void) lseek(glfd, (long) 0, 0); /* save the status */ + (void) write(glfd, (char *) status, sizeof(struct status)); + } +} + +/*-------------------------------------------------------------------------*/ + + + +/*----------END OF FILE--------*/ diff -r 054275999194 -r 8c6d5731234d src/planets.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/planets.h Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,61 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "defs.h" /* for GWIDTH */ + + +/*--------------------------------NUMBER DEFINES-------------------------*/ + +/*-----------------------------------------------------------------------*/ + + + +/*------------------------PLANETS FUNCTION PROTOTYPES----------------------*/ +void gen_planets(); /* generate planets positions */ +void popplanets(); /* update planets pop */ +void growplanets(); /* grow planets facilities */ +void plfight(); /* do fighting for planets */ +void save_planets(); /* save the planets to '.planets' file */ +/*-------------------------------------------------------------------------*/ + +/*--------------------------PLANET UTILITY FUNCTIONS-----------------------*/ +#ifdef __STDC__ +extern int +place_stars(struct planet * first, int count, int border, + int minpad, int maxpad, struct planet * othercheck, + int ocount); +extern void zero_plflags(struct planet * first, int count); +extern void +randomize_atmospheres(struct planet * first, int count, + int p1, int p2, int p3, int p4); +extern void +randomize_resources(struct planet * first, int count, + int nm, int nd, int na); +extern void justify_galaxy(int numsystems); +#else +extern int place_stars(); +extern void zero_plflags(); +extern void randomize_atmospheres(); +extern void randomize_resources(); +extern void justify_galaxy(); +#endif +void pl_neworbit(); +/*-------------------------------------------------------------------------*/ + + +/*----------END OF FILE-------*/ diff -r 054275999194 -r 8c6d5731234d src/plasma.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plasma.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,130 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include +#include +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" + + + + + +/*-----------------------------VISIBLE FUNCTIONS---------------------------*/ + +/*--------------------------------NPLASMATORP------------------------------*/ +/* + * This function fires a plasma torp. It checks a number of conditions to + * see if it is allowable to fire a plasma torp. If so the the plasma if + * fire. The two styles of plasma torp are ones that fire in the direction + * the ship is going and ones that can fire independent of the ships + * direction. + */ + +void +nplasmatorp(course, type) + unsigned char course; /* direction plasma should go */ + int type; /* type of plasma */ +{ + register int i; /* looping var */ + register struct plasmatorp *k;/* to point to plasma torp */ + + if (weaponsallowed[WP_PLASMA] == 0) + { /* are plasmas enabled */ + warning("Plasmas haven't been invented yet."); + return; + } + if (me->p_ship.s_plasma.cost <= 0) + { /* ship can have plasma */ + warning("Weapon's Officer: Captain, this ship can't carry plasma torpedoes!"); + return; + } + if (!(me->p_specweap & SFNPLASMAARMED)) + { /* ship equiped with plasma */ + warning("Weapon's Officer: Captain, this ship is not armed with plasma torpedoes!"); + return; + } + if (me->p_flags & PFWEP) + { /* ship not w-temped */ + warning("Plasma torpedo launch tube has exceeded the maximum safe temperature!"); + return; + } + if (me->p_nplasmatorp == MAXPLASMA) + { + warning("Our fire control system limits us to 1 live torpedo at a time captain!"); + return; + } + if (me->p_fuel < myship->s_plasma.cost) + { /* have enough fuel? */ + warning("We don't have enough fuel to fire a plasma torpedo!"); + return; + } + if (me->p_flags & PFREPAIR) + { /* not while in repair mode */ + warning("We cannot fire while our vessel is undergoing repairs."); + return; + } + if ((me->p_cloakphase) && (me->p_ship.s_type != ATT)) + { + warning("We are unable to fire while in cloak, captain!"); + return; /* not while cloaked */ + } + + if (!check_fire_warp() + || !check_fire_warpprep() + || !check_fire_docked()) + return; + me->p_nplasmatorp++; /* inc plasma torps fired */ + me->p_fuel -= myship->s_plasma.cost; /* take off the fuel */ + me->p_wtemp += myship->s_plasma.wtemp; /* do the w-temp */ + for (i = me->p_no * MAXPLASMA, k = &plasmatorps[i]; + i < (me->p_no + 1) * MAXPLASMA; i++, k++) + { + if (k->pt_status == PTFREE) /* find a free plasma to fire */ + break; + } + + k->pt_no = i; /* set plasmas number */ + k->pt_status = type; /* set what type plasma is */ + k->pt_owner = me->p_no; /* set the owner */ + k->pt_team = me->p_team; /* set the team */ + k->pt_x = me->p_x; /* set starting coords */ + k->pt_y = me->p_y; + if (myship->s_nflags & SFNPLASMASTYLE) /* depending on type set */ + k->pt_dir = course; /* any direction */ + else + k->pt_dir = me->p_dir; /* or straight ahead of ship */ + k->pt_damage = myship->s_plasma.damage; /* set the damage it will do */ + k->pt_speed = myship->s_plasma.speed; /* set its speed */ + k->pt_war = me->p_hostile | me->p_swar; /* who it doesn't like */ + k->pt_fuse = myship->s_plasma.fuse; /* how long it will live */ + k->pt_turns = myship->s_plasma.aux; /* how much will it track */ +} + +/*-------------------------------------------------------------------------*/ + + + + + +/*------END OF FILE-----*/ diff -r 054275999194 -r 8c6d5731234d src/player.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/player.h Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,39 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + + + + + +/*----------------------------FUNCTION PROTOTYPES-------------------------*/ +void fractbomb(); /* do fractional bombing */ +void loserstats(); /* inc a killed player's losses */ +void killerstats(); /* inc killers kills */ +void checkmaxkills(); /* adjust player's maxkills if need be */ +void blowup(); /* inflict damage on nearby players */ +void beam(); /* beam up and down for players */ +void udcloak(); /* inc/dec the cloakphases for players */ +void udplayers(); /* update the players */ +/*-----------------------------------------------------------------------*/ + + + + + + +/*----------END OF FILE--------*/ diff -r 054275999194 -r 8c6d5731234d src/plutil.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plutil.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,272 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include + +#include "plutil.h" +#include "data.h" +#include "shmem.h" + +int +idx_to_mask(i) + int i; +{ + if (i >= 0) + return 1 << i; + else + return 0; +} + +int +mask_to_idx(m) + int m; +{ + int i; + if (!m) + return -1; + for (i = 0; m > 1; i++, m >>= 1); + return i; +} + +/* + */ + +int +in_warp(pl) + struct player *pl; +{ + if (pl->p_flags & PFDOCK) + { + /* if we are docked, then we have the same state as our base */ + return in_warp(&players[pl->p_docked]); + } + return (pl->p_flags & PFWARP) || pl->p_warptime; +} + + +int +undock_player(pl) + struct player *pl; +{ + struct player *base; + + if (!(pl->p_flags & PFDOCK)) + return 0; + + base = &players[pl->p_docked]; + base->p_docked--; /* base no longer has as many docked */ + base->p_port[pl->p_port[0]] = VACANT; /* the port is vacant */ + + /* what if the player is being undocked because he died? */ + if (base->p_ship.s_type == JUMPSHIP) + { + pl->p_jsdock = 1; + pl->p_lastjs = pl->p_docked; + } + pl->p_flags &= ~PFDOCK; + pl->p_docked = -1; + pl->p_port[0] = VACANT; + + return 1; +} + +int +base_undock(base, port_id) + struct player *base; + int port_id; +{ + struct player *pl; + + if (base->p_port[port_id] < 0) + return 0; + + pl = &players[base->p_port[port_id]]; + + base->p_docked--; + base->p_port[port_id] = VACANT; + + /* if the jumpship kicks you off, he doesn't get credited. -RF */ + + pl->p_flags &= ~PFDOCK; + pl->p_docked = -1; + pl->p_port[0] = VACANT; + return 1; +} + +void +enforce_dock_position(pl) + struct player *pl; +{ + struct player *base; + unsigned char angle; + int port_id; + + if (!(pl->p_flags & PFDOCK)) + return; + + base = &players[pl->p_docked]; + port_id = pl->p_port[0]; + + if ((base->p_ship.s_type == STARBASE) || (base->p_ship.s_type == WARBASE) || + (base->p_ship.s_type == JUMPSHIP)) + angle = (port_id * 2 + 1) * 128 / base->p_ship.s_numports; + else + angle = base->p_dir + 64 + (128 * port_id); /* max of two ports, really */ + move_player(pl->p_no, (int) (base->p_x + DOCKDIST * Cos[angle]), + (int) (base->p_y + DOCKDIST * Sin[angle]), 1); + + pl->p_speed = pl->p_desspeed = 0; + if ((base->p_ship.s_type == STARBASE) || (base->p_ship.s_type == WARBASE) || + (base->p_ship.s_type == JUMPSHIP)) + pl->p_dir = pl->p_desdir = angle + 64; + else + pl->p_dir = pl->p_desdir = base->p_dir; +} + +void +dock_to(pl, base_num, port_id) + struct player *pl; + int base_num, port_id; +{ + struct player *base = &players[base_num]; + + undock_player(pl); + + base->p_docked++; + base->p_port[port_id] = pl->p_no; + + pl->p_flags |= PFDOCK; /* we are docked */ + pl->p_docked = base_num; /* to this base */ + pl->p_port[0] = port_id; /* in this docking bay */ + + enforce_dock_position(pl); +} + +void +scout_planet(p_no, pl_no) + int p_no; + int pl_no; +{ + struct player *fred = &players[p_no]; + struct planet *mars = &planets[pl_no]; + int oldness = status->clock - mars->pl_tinfo[fred->p_team].timestamp; + + if (!status->tourn) + return; + + if ((mars->pl_owner != fred->p_team) && + (oldness > 2)) + { +#define LOG2OFe 1.442695 + double scoutdi = log((double) oldness) * LOG2OFe / 100; + if (scoutdi > 0.1) + scoutdi = 0.1; + fred->p_stats.st_di += scoutdi; + } + mars->pl_hinfo |= fred->p_team; + if (mars->pl_owner != fred->p_team) + { + mars->pl_tinfo[fred->p_team].flags = mars->pl_flags; + mars->pl_tinfo[fred->p_team].armies = mars->pl_armies; + mars->pl_tinfo[fred->p_team].owner = mars->pl_owner; + mars->pl_tinfo[fred->p_team].timestamp = status->clock; + } +} + +/* + * */ + +void +evaporate(pl) + struct player *pl; +{ + /* put someone on the outfit screen with no ill effects */ + + undock_player(pl); /* if docked then undock me */ + + if (allows_docking(pl->p_ship)) + { /* if ships can dock */ + int k; + for (k = 0; k < pl->p_ship.s_numports; k++) + base_undock(pl, k); /* remove all docked ships */ + pl->p_docked = 0; /* no ships docked anymore */ + } + if (pl->p_flags & PFORBIT) + { /* if orbiting then */ + pl->p_flags &= ~PFORBIT; /* eject from orbit */ + } + + pl->p_status = POUTFIT; + pl->p_whydead = KPROVIDENCE; +} + +void +explode_everyone(whydead, minlive) + int whydead; + int minlive; +{ + int i; + for (i = 0; i < MAXPLAYER; i++) + { + if (players[i].p_status != PALIVE + && players[i].p_status != POBSERVE) + continue; + + if (players[i].p_updates < minlive) + continue; + + players[i].p_whydead = whydead; + players[i].p_whodead = 0; + players[i].p_status = PEXPLODE; + players[i].p_explode = 10; + players[i].p_ntorp = 0; /* no torps shot */ + players[i].p_nplasmatorp = 0; /* no plasmas shot */ + } +} + + +/* round randomly, but weighted by the fractional part */ + +int +random_round(d) + double d; +{ + int rval = floor(d); + if (drand48() < d - rval) + rval++; + return rval; +} + + +char * +twoletters(pl) + struct player *pl; +/* calculate the two letters that form the players designation (e.g. R4) */ +{ +#define RINGSIZE MAXPLAYER+3 + static char buf[RINGSIZE][3]; /* ring of buffers so that this */ + static int idx; /* proc can be called several times before + * the results are used */ + if (idx >= RINGSIZE) + idx = 0; + buf[idx][0] = teams[pl->p_team].letter; + buf[idx][1] = shipnos[pl->p_no]; + buf[idx][2] = 0; + return buf[idx++]; +} diff -r 054275999194 -r 8c6d5731234d src/plutil.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plutil.h Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,40 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + + +#ifndef plutil_h_ +#define plutil_h_ + +/* is the player in warp? */ +int in_warp( /* struct player * */ ); + + +/* + * remove the player from his base. Returns 1 if the player was really + * docked, 0 otherwise + */ +int undock_player( /* struct player * */ ); + +/* make sure the player has the proper coordinates */ +void enforce_dock_position( /* struct player * */ ); + +/* dock a player onto a base at a certain port */ +void + dock_to( /* struct player *, int base_num, int port_id */ ); + +#endif diff -r 054275999194 -r 8c6d5731234d src/rcslog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rcslog Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,190 @@ +daemonII.c +---------------------------- +revision 1.3 +date: 1996/10/11 01:39:48; author: edorman; state: Exp; lines: +2 -2 +old vsn would wipe out loadcheck data if PARAVERS was too long (doh!) +we only care about 1st number anyway so print that. +---------------------------- +revision 1.2 +date: 1996/10/11 01:17:22; author: edorman; state: Exp; lines: +2 -0 +FreeBSD doesn't need lseek decl conflicts with POSIXness +---------------------------- + +data.c +---------------------------- +revision 1.2 locked by: edorman; +date: 1996/10/11 01:34:13; author: edorman; state: Exp; lines: +1 -1 +Experimental notation. +---------------------------- + +feature.c +---------------------------- +revision 1.3 +date: 1996/10/18 23:54:33; author: edorman; state: Exp; lines: +5 -1 +make sure we tell the client what features the server supports. +---------------------------- +revision 1.2 +date: 1996/10/16 00:22:38; author: edorman; state: Exp; lines: +4 -0 +no change +---------------------------- + +getship.c +---------------------------- +revision 1.2 +date: 1996/10/12 02:10:01; author: edorman; state: Exp; lines: +7 -0 +check and see if WARPDRIVE got unset later and +fix it when we give a ship to a player. +---------------------------- + +listen.c +---------------------------- +revision 1.3 +date: 1996/10/11 02:26:59; author: edorman; state: Exp; lines: +1 -1 +bad syntax causes bad inetaddr in cases where dns won't resolve to a name +---------------------------- +revision 1.2 +date: 1996/10/11 01:21:09; author: edorman; state: Exp; lines: +2 -0 +FreeBSD doesn't want sys_errlist defined this way; use system proto +---------------------------- + +main.c +---------------------------- +revision 1.3 +date: 1996/10/16 00:27:41; author: edorman; state: Exp; lines: +3 -0 +added player default to RCD off +---------------------------- +revision 1.2 +date: 1996/10/15 23:50:12; author: edorman; state: Exp; lines: +3 -3 +added rtt, sdv, pckloss to logging +,. +---------------------------- + +pl_gen7.c +---------------------------- +revision 1.2 +date: 1996/10/24 21:27:57; author: edorman; state: Exp; lines: +1 -2 +include wormholes +---------------------------- + +planets.c +---------------------------- +revision 1.5 +date: 1996/10/12 03:29:12; author: edorman; state: Exp; lines: +2 -2 +hope i fixed it this time. +---------------------------- +revision 1.4 +date: 1996/10/12 03:22:22; author: edorman; state: Exp; lines: +1 -1 +not quite far enuf +---------------------------- +revision 1.3 +date: 1996/10/12 02:50:05; author: edorman; state: Exp; lines: +4 -2 +fix so no planet is so close to star that can't orbit. maybe +should leave it that way, eh? pisser to have SY that way tho. +---------------------------- +revision 1.2 +date: 1996/10/12 02:10:58; author: edorman; state: Exp; lines: +4 -0 +planets.c +---------------------------- + +player.c +---------------------------- +revision 1.4 +date: 1996/10/12 03:22:28; author: edorman; state: Exp; lines: +22 -4 +fixed ship operation at empty fuel +---------------------------- +revision 1.3 +date: 1996/10/12 02:42:28; author: edorman; state: Exp; lines: +2 -3 +old etemp code too good :) fixed now 2x rate for helpfulplanets +---------------------------- +revision 1.2 +date: 1996/10/12 02:32:57; author: edorman; state: Exp; lines: +20 -6 +added helpfulplanets configvals +---------------------------- + +shmem.c +---------------------------- +revision 1.3 +date: 1996/10/24 21:28:04; author: edorman; state: Exp; lines: +1 -1 +fixed so planet generator can set numplanets. +---------------------------- +revision 1.2 +date: 1996/10/11 01:59:56; author: edorman; state: Exp; lines: +1 -1 +fix for galaxy gen setup +---------------------------- + +socket.c +---------------------------- +revision 1.3 locked by: edorman; +date: 1996/10/12 02:10:58; author: edorman; state: Exp; lines: +4 -4 +planets.c +---------------------------- +revision 1.2 +date: 1996/10/12 01:07:28; author: edorman; state: Exp; lines: +1 -1 +must update ship _first_ when using shortpackets +elsewise client gets confused; nonshort sends abs addr anyway. +---------------------------- + +sysdefaults.c +---------------------------- +revision 1.3 +date: 1996/11/01 22:09:10; author: edorman; state: Exp; lines: +0 -1 +deleted unused debugging code +---------------------------- +revision 1.2 +date: 1996/10/12 02:10:58; author: edorman; state: Exp; lines: +2 -0 +planets.c +---------------------------- +config.h +---------------------------- +revision 1.3 +date: 1996/10/16 00:23:21; author: edorman; state: Exp; lines: +5 -0 +added RC_DISTRESS stuff +---------------------------- +revision 1.2 +date: 1996/10/15 23:36:12; author: edorman; state: Exp; lines: +5 -0 +added LOG_LONG_INFO for more info. +---------------------------- + +defs.h +---------------------------- +revision 1.2 +date: 1996/10/11 01:41:01; author: edorman; state: Exp; lines: +1 -1 +metaserver..ecst > metaserver..ecst asthetic change. +---------------------------- + +shmem.h +---------------------------- +revision 1.2 +date: 1996/10/11 02:08:31; author: edorman; state: Exp; lines: +1 -0 +helpfulplanets for fuel/etemp recovery +---------------------------- + +struct.h +---------------------------- +revision 1.5 +date: 1996/10/16 00:32:38; author: edorman; state: Exp; lines: +1 -0 +added MDISTR message type +---------------------------- +revision 1.4 +date: 1996/10/16 00:24:47; author: edorman; state: Exp; lines: +7 -7 +changed u_char to 'unsigned char' +---------------------------- +revision 1.3 +date: 1996/10/16 00:20:49; author: edorman; state: Exp; lines: +2 -2 +changed #ifdef RCD to #ifdef RC_DISTRESS to reflect paradise usage +---------------------------- +revision 1.2 +date: 1996/10/16 00:16:37; author: edorman; state: Exp; lines: +122 -0 +Added RCD definitions +---------------------------- + +Makefile.in +---------------------------- +revision 1.3 +date: 1996/10/12 02:18:01; author: edorman; state: Exp; lines: +1 -1 +fixed pl_gen6/7 +---------------------------- +revision 1.2 +date: 1996/10/11 01:49:35; author: edorman; state: Exp; lines: +2 -1 +added pl_gen7.c +---------------------------- diff -r 054275999194 -r 8c6d5731234d src/redraw.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/redraw.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,689 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include +#include +#include /* change 4/14/91 TC */ +#include +#include + +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "packets.h" +#include "shmem.h" + +extern char start_login[], start_name[]; /* change 4/14/91 TC */ +extern int goAway; /* change 4/14/91 TC */ +extern jmp_buf env; /* change 4/14/91 TC */ + + +#ifdef AUTHORIZE +extern int makeReservedPacket(); +#endif +extern int sendClientPacket(); +#ifndef IRIX +extern int fprintf(); +#endif +extern void death(); +void auto_features(); +extern int set_speed(); +extern int orbit(); +extern int set_course(); +int newcourse(); +extern void imm_warning(); + +#ifdef AUTHORIZE +void +check_authentication() +{ + /* if (!configvals->binconfirm) testtime=0; */ + if (testtime == -1) + { + struct reserved_spacket sp; + +#ifdef RSA_EXEMPTION_FILE + if (site_rsa_exempt()) + { + printf("site exempt from RSA authentication\n"); + strcpy(RSA_client_type, "site/player is RSA exempt"); + testtime = 0; + } + else +#endif /* RSA_EXEMPTION_FILE */ + { + /* + * Give reasonable period of time to respond to query (and test code if + * they need to) + */ + + testtime = 200; + makeReservedPacket(&sp); + memcpy(testdata, sp.data, KEY_SIZE); + sendClientPacket((struct player_spacket *) & sp); + } /* RSA EXEMPTION */ + } + else if (testtime != 0) + { + testtime--; + if (testtime == 0) + { + /* User failed to respond to verification query. Bye! */ + if (!configvals->binconfirm) + me->p_stats.st_flags |= ST_CYBORG; /* mark for reference 7/27/91 + * TC */ + else + { + me->p_explode = 10; + me->p_whydead = KQUIT; + me->p_status = PEXPLODE; + fprintf(stderr, "User binary failed to verify\n"); + if (RSA_Client == 1) + warning("No customized binaries. Please use a blessed one."); + else if (RSA_Client == 2) + warning("Wrong Client Version Number!"); + else + warning("You need a spiffy new RSA client for this server!"); + } + } + } +} +#endif /* AUTHORIZE */ + +void +intrupt() +{ +#ifdef AUTHORIZE + check_authentication(); +#endif + + if (me->p_status == PFREE) + { + me->p_ghostbuster = 0; + me->p_status = PDEAD; + } + /* Change 4/14/91 TC: fixing 2 players/1 slot bug here, since this is */ + /* where the ghostbust check is */ + +#if 0 + if ((strcmp(me->p_login, start_login) != 0) || + (strcmp(me->p_name, start_name) != 0)) + { + struct pstatus_spacket pstatus; + goAway = 1; /* get rid of this client! */ + warning("Sorry, your slot has been taken by another player."); + pstatus.type = SP_PSTATUS; + pstatus.pnum = 0; + pstatus.status = PDEAD; + sendClientPacket(&pstatus); + longjmp(env, 0); + } +#endif + + if (me->p_status == PEXPLODE || me->p_status == PDEAD) + { + inputMask = 0; + } + if (((me->p_status == PDEAD) || (me->p_status == POUTFIT)) + && (me->p_ntorp <= 0) && (me->p_nplasmatorp <= 0)) + { + death(); + } + auto_features(); + updateClient(); +} + + +static void +selfdestruct_countdown() +{ + char buf[180]; + if (!(me->p_flags & PFSELFDEST)) + return; + + if ((me->p_updates >= selfdest) || + ((me->p_flags & PFGREEN) && (me->p_damage == 0) + && (me->p_shield == me->p_ship.s_maxshield))) + { + me->p_flags &= ~PFSELFDEST; + me->p_explode = 10; + me->p_whydead = KQUIT; + me->p_status = PEXPLODE; + } + else + { + switch ((selfdest - me->p_updates) / 10) + { + case 5: + case 4: + imm_warning("You notice everyone on the bridge is staring at you."); + break; + default: + sprintf(buf, "Stand by ... Self destruct in %d seconds", + (selfdest - me->p_updates) / 10); + imm_warning(buf); + break; + } + } +} + +static void +warp_powerup() +{ + static int sequence = 0; + int time = myship->s_warpinittime; + + if (me->p_warptime <= 0 && sequence == 0) + return; + + if (me->p_speed > myship->s_warpprepspeed && !(me->p_flags & PFWARP)) + { + if (sequence < 1) + { + warning("Prepping for warp jump"); + sequence = 1; + } + } + else if (me->p_warptime >= time * 9 / 10 /* 37 */ ) + { + if (sequence < 2) + { + warning("Starting power buildup for warp"); + sequence = 2; + } + } + else if (me->p_warptime >= time * 3 / 4 /* 30 */ ) + { + if (sequence < 3) + { + imm_warning("Warp power buildup at 30%"); + sequence = 3; + } + } + else if (me->p_warptime >= time * 3 / 5 /* 23 */ ) + { + if (sequence < 4) + { + imm_warning("Warp power buildup at 60%"); + sequence = 4; + } + } + else if (me->p_warptime >= time * 2 / 5 /* 16 */ ) + { + if (sequence < 5) + { + imm_warning("Warp power buildup at 90%"); + sequence = 5; + } + } + else if (me->p_warptime >= time * 1 / 5 /* 8 */ ) + { + if (sequence < 6) + { + imm_warning("Commander Hoek: `Prepare to surge to sub-light speed'"); + sequence = 6; + } + } + else if (me->p_warptime == 0) + { + warning((me->p_flags & PFWARP) ? "Engage" : "Warp drive aborted"); + sequence = 0; + } +} + +static void +refit_countdown() +{ + char buf[120]; + static int lastRefitValue = 0;/* for smooth display */ + + if (!(me->p_flags & PFREFITTING)) + return; + + if (lastRefitValue != (rdelay - me->p_updates) / 10) + { + lastRefitValue = (rdelay - me->p_updates) / 10; /* CSE to the rescue? */ + switch (lastRefitValue) + { + case 3: + case 2: + sprintf(buf, "Engineering: Energizing transporters in %d seconds", lastRefitValue); + warning(buf); + break; + case 1: + warning("Engineering: Energize. [ SFX: chimes ]"); + break; + case 0: + switch (lrand48() % 5) + { + case 0: + warning("Wait, you forgot your toothbrush!"); + break; + case 1: + warning("Nothing like turning in a used ship for a new one."); + break; + case 2: + warning("First officer: Oh no, not you again... we're doomed!"); + break; + case 3: + warning("First officer: Uh, I'd better run diagnostics on the escape pods."); + break; + case 4: + warning("Shipyard controller: `This time, *please* be more careful, okay?'"); + break; + } + break; + } + } +} + +static void +backstab_countdown() +{ + static int lastWarValue = 0; + + if (!(me->p_flags & PFWAR)) + return; + + if (lastWarValue != (delay - me->p_updates) / 10) + { + char *str = 0; + lastWarValue = (delay - me->p_updates) / 10; /* CSE to the rescue? */ + if (lastWarValue == 0) + { + static char buf[1024]; + static char *msgs[7] = { + "tires on the ether", + "Klingon bitmaps are ugly", + "Federation bitmaps are gay", + "all admirals have scummed", + "Mucus Pig exists", + "guests advance 5x faster", + "Iggy has infinite fuel", + }; + sprintf(buf, "First Officer: laws of the universe, like '%s'.", + msgs[lrand48() % 7]); + str = buf; + } + else if (lastWarValue <= 9) + { + static char *msgs[10] = { + "First Officer: Easy, big guy... it's just one of those mysterious", + "Weapons officer: Bah! [ bangs fist on inoperative console ]", + "Weapons officer: Just to twiddle a few bits of the ship's memory?", + "Weapons officer: ...the whole ship's computer is down?", + "Weapons officer: Not again! This is absurd...", + }; + str = msgs[(lastWarValue - 1) / 2]; + } + else + { + str = "urk"; + } + if (str) + { + warning(str); + } + } +} + +static void +bombing_info() +{ + char buf[120]; + + if (!(me->p_flags & PFBOMB)) + return; + + if (planets[me->p_planet].pl_armies < 5) + { + if (configvals->facilitygrowth) + imm_warning("Weapons Officer: Bombing resources off planet, sir."); + else + { + sprintf(buf, "Weapons Officer: Bombing is ineffective. Sensor read %d armies left.", + planets[me->p_planet].pl_armies); + imm_warning(buf); + } + } + else + { + sprintf(buf, "Weapons Officer: Bombarding %s... Sensors read %d armies left.", + planets[me->p_planet].pl_name, + planets[me->p_planet].pl_armies); + imm_warning(buf); + } +} + + +static void +operate_transporters() +{ + char buf[120]; + int troop_capacity = 0; + + if ((me->p_ship.s_nflags & SFNARMYNEEDKILL) && + (me->p_kills * myship->s_armyperkill) < myship->s_maxarmies) + { + troop_capacity = (int) (me->p_kills * myship->s_armyperkill); + } + else + troop_capacity = me->p_ship.s_maxarmies; + + if (me->p_flags & PFBEAMUP) + { + if (me->p_flags & PFORBIT) + { + if (planets[me->p_planet].pl_armies < 1) + { + sprintf(buf, "%s: Too few armies to beam up", + planets[me->p_planet].pl_name); + warning(buf); + me->p_flags &= ~PFBEAMUP; + } + else if ((planets[me->p_planet].pl_armies <= 4) && + (me->p_lastman != 2)) + { + strcpy(buf, "Hit beam again to beam up all armies."); + warning(buf); + me->p_flags &= ~PFBEAMUP; + } + else if (me->p_armies == troop_capacity) + { + sprintf(buf, "No more room on board for armies"); + warning(buf); + me->p_flags &= ~PFBEAMUP; + } + else + { + sprintf(buf, "Beaming up. (%d/%d)", me->p_armies, troop_capacity); + imm_warning(buf); + } + } + else if (me->p_flags & PFDOCK) + { + if (players[me->p_docked].p_armies == 0) + { + sprintf(buf, "Starbase %s: Too few armies to beam up", + players[me->p_docked].p_name); + warning(buf); + me->p_flags &= ~PFBEAMUP; + } + else if (me->p_armies >= troop_capacity) + { + sprintf(buf, "No more room on board for armies"); + warning(buf); + me->p_flags &= ~PFBEAMUP; + } + else + { + sprintf(buf, "Beaming up. (%d/%d)", me->p_armies, troop_capacity); + imm_warning(buf); + } + } + } + if (me->p_flags & PFBEAMDOWN) + { + if (me->p_armies == 0) + { + if (me->p_flags & PFDOCK) + { + sprintf(buf, "No more armies to beam down to Starbase %s.", + players[me->p_docked].p_name); + warning(buf); + } + else + { + sprintf(buf, "No more armies to beam down to %s.", + planets[me->p_planet].pl_name); + warning(buf); + } + me->p_flags &= ~PFBEAMDOWN; + } + else if (me->p_flags & PFORBIT) + { + sprintf(buf, "Beaming down. (%d/%d) %s has %d armies left", + me->p_armies, + troop_capacity, + planets[me->p_planet].pl_name, + planets[me->p_planet].pl_armies); + imm_warning(buf); + } + else if (me->p_flags & PFDOCK) + { + if (players[me->p_docked].p_armies == + players[me->p_docked].p_ship.s_maxarmies) + { + sprintf(buf, "Transporter Room: Starbase %s reports all troop bunkers are full!", + players[me->p_docked].p_name); + warning(buf); + me->p_flags &= ~PFBEAMDOWN; + } + else + { + sprintf(buf, "Transfering ground units. (%d/%d) Starbase %s has %d armies left", + me->p_armies, + troop_capacity, + players[me->p_docked].p_name, + players[me->p_docked].p_armies); + imm_warning(buf); + } + } + } +} + +#if 0 +static void +reduce_speed() +{ + if (me->p_desspeed > myship->s_imp.maxspeed) + { + /* drop out of warp */ + me->p_desspeed = myship->s_imp.maxspeed + 1; + me->p_flags &= ~(PFWARP | PFAFTER); + warning("Approaching planet, dropping out of warp"); + } + set_speed(me->p_desspeed - 1, 0); +} +#endif + +static void +decelerate_at_range(dist) + int dist; +{ + int speed; + int maximp = myship->s_imp.maxspeed; + +#define FUDGEFACT 1.15 + + if (me->p_flags & PFWARP) + { + if (configvals->warpdecel) + { + /* + * int impdist = 1000*(maximp*10*WARP1*maximp*10*WARP1)/ (2 * + * myship->s_imp.dec*10*10*warp1); + */ + + int impdist = FUDGEFACT * (maximp * maximp - 2 * 2) * 500 * WARP1 / myship->s_imp.dec; + + for (speed = maximp; + speed < me->p_desspeed && speed < me->p_speed; + speed++) + { + int decdist; + decdist = FUDGEFACT * 500 * ((speed * speed) - (maximp * maximp)) * WARP1 / + myship->s_warp.dec; + if (dist - impdist - ENTORBDIST < decdist) + break; + } + if (speed == maximp && speed < me->p_speed) + warning("Approaching planet, dropping out of warp"); + if (speed < me->p_desspeed && + speed < me->p_speed) + { + /* printf("(W) curr: %d, ideal %d\n", me->p_speed, speed); */ + me->p_desspeed = speed; + } + } + else + { + int impdist; + maximp = (3 * maximp + myship->s_warp.maxspeed) / 4; + impdist = FUDGEFACT * ((maximp) * (maximp) - 2 * 2) * + 500 * WARP1 / myship->s_imp.dec; + if (dist - impdist - ENTORBDIST < 0) + me->p_flags &= ~PFWARP; + } + } + else + { + for (speed = 2; speed < me->p_desspeed && speed < me->p_speed; speed++) + { + int decdist; + decdist = FUDGEFACT * 500 * (speed * speed - 2 * 2) * WARP1 / myship->s_imp.dec; + if (dist - ENTORBDIST < decdist) + break; + } + if (speed < me->p_desspeed && + speed < me->p_speed) + { + /* printf("(I) curr: %d, ideal %d\n", me->p_speed, speed); */ + me->p_desspeed = speed; + } + } +} + +static void +follow_player() +{ + struct player *pl; + int dist; + + if (!(me->p_flags & PFPLOCK)) + return; + + /* set course to player x */ + + pl = &players[me->p_playerl]; + if (pl->p_status != PALIVE) + me->p_flags &= ~PFPLOCK; + if (allows_docking(pl->p_ship)) + { + dist = ihypot(me->p_x - pl->p_x, me->p_y - pl->p_y); + + decelerate_at_range(dist); + + if ((dist < DOCKDIST) && (me->p_speed <= 2)) + { + orbit(); + me->p_flags &= ~PFPLOCK; + } + } + if (me->p_flags & PFPLOCK) + set_course(newcourse(pl->p_x, pl->p_y)); + +} + +static void +follow_planet() +{ /* follow a planet? How silly. Will it + * perhaps outmaneuver you? */ + struct planet *pln; + int dist; + /* int speed = me->p_speed; */ + + if (!(me->p_flags & PFPLLOCK)) + return; + + /* set course to planet x */ + + pln = &planets[me->p_planet]; + dist = ihypot(me->p_x - pln->pl_x, me->p_y - pln->pl_y); + + decelerate_at_range(dist); + + if ((dist < ENTORBDIST) && (me->p_speed <= 2)) + { + orbit(); + me->p_flags &= ~PFPLLOCK; + } + else + { + int course = newcourse(pln->pl_x, pln->pl_y); + set_course(course); + } +} + +/* + * These are routines that need to be done on interrupts but don't belong in + * the redraw routine and particularly don't belong in the daemon. + */ + +void +auto_features() +{ + selfdestruct_countdown(); + + warp_powerup(); + + /* provide a refit countdown 4/6/92 TC */ + refit_countdown(); + + /* provide a war declaration countdown 4/6/92 TC */ + backstab_countdown(); + + /* give certain information about bombing or beaming */ + bombing_info(); + + operate_transporters(); + + if (me->p_flags & PFREPAIR) + { + if ((me->p_damage == 0) && (me->p_shield == me->p_ship.s_maxshield)) + me->p_flags &= ~PFREPAIR; + } + if (me->p_status != POBSERVE) + { + /* these mess up the observer mode */ + follow_player(); + follow_planet(); + } + +#if defined(CLUECHECK1) || defined(CLUECHECK2) + if ( +#ifdef LEAGUE_SUPPORT + !status2->league && +#endif + configvals->cluecheck) + countdown_clue(); +#endif +} + +int +newcourse(x, y) + int x, y; +{ + if (x == me->p_x && y == me->p_y) + return 0; + + return (int) (atan2((double) (x - me->p_x), + (double) (me->p_y - y)) / 3.14159 * 128.); +} diff -r 054275999194 -r 8c6d5731234d src/rmove.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rmove.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,1539 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "weapons.h" +#include "shmem.h" + +#define SIZEOF(s) (sizeof (s) / sizeof (*(s))) +#define AVOID_TIME 4 +#define AVOID_CLICKS 200 + +#define BOREDOM_TIME 1200 /* 10 minutes since last torp fired + * => become hostile to all 4/13/92 + * TC */ + +#define AVOID_STAR 8000 /* Distance from star within which collision + * avoidance is invoked. - MAK, 16-Jun-93 */ +#define AVOID_MELT 2000 /* Distance from star within which collision + * prevention is invoked. - MAK, 16-Jun-93 */ + +#define NORMALIZE(d) (((d) + 256) % 256) + +#define E_INTRUDER 0x01 +#define E_TSHOT 0x02 +#define E_PSHOT 0x04 +#define E_TRACT 0x08 +#define NOENEMY (struct Enemy *) -1 + +struct Enemy +{ + int e_info; + int e_dist; + unsigned char e_course; /* course to enemy */ + unsigned char e_edir; /* enemy's current heading */ + unsigned char e_tcourse; /* torpedo intercept course to enemy */ + unsigned int e_flags; + int e_tractor; /* who he's tractoring/pressoring */ + int e_phrange; /* his phaser range */ + unsigned int e_hisflags; /* his pflags. bug fix: 6/24/92 TC */ +}; + +static int avoidTime; + +#define MESSFUSEVAL 200 /* maint: removed trailing ';' 6/22/92 TC */ +static int messfuse = MESSFUSEVAL; +static char rmessage[110]; +static char tmessage[110]; +static char *rmessages[] = { + /* I got bored and actually made it say something: 'DIE SCUM' */ + "1000100 1001001 1000101 100000 1010011 1000011 1010101 1001101 !" + "Crush, Kill, DESTROY!!", + "Run coward!", + "Hey! Come on you Hoser! I dare you!", + "Resistance is useless!", + "Dry up and blow away you weenie!", + "Go ahead, MAKE MY DAY!", + "Just hit ' Q' ... and spare both of us the trouble", + "Is that REALLY you Kurt?", + "I have you now!", + "By the way, any last requests?", + "Dropping your shields is considered a peaceful act.", + "Drop your shields, and I MAY let you live ...", + "Don't you have midterms coming up or something?", + "Ya wanna Tango baby?", + "Hey! Outta my turf you filthy $t!", + "I seeeee you...", + "I claim this space for the $f.", + "Give up fool ... you're meat.", + "And another one bites the dust ...", + "Surrender ... NOW!", + "Hey! Have you heard about the clever $t? No?.. Me neither.", + "You have been registered for termination.", + "This'll teach you to mind your own business!", + "Man, you stupid $ts never learn!", + "ALL RIGHT, enough goofing off ... you're toast buster!", + "You pesky humans just NEVER give up, do you?", + "You're actually paying money so you can play this game?", + "My job is to put over-zealous newbies like you out of your misery.", + "How can you stand to be $T?!? What a hideous life!", + "All $ts are losers!", + "$ts all suck. Come join the $f!", + "The $f shall crush all filthy $ts like you!", + "TWINK", + "How can your friends stand to let you live?", + "Happy, Happy, Joy, Joy." +}; + +char *termie_messages[] = { + "$n: Hasta la vista, Baby.", + "Come quietly, or there will be trouble. [thump] [thump]", + "Make your peace with GOD.", + "$n: Say your prayers", + "This galaxy isn't big enough for the two of us, $n.", + "$n, I have a warrant for your arrest.", + "$n, self-destruct now.", + "Coming through. Out of my way.", + "You feel lucky, punk?", + "Killing is our business. Business is good.", + "$n, Die. You have 10 seconds to comply.", + "You can run $n, but you can't hide!", + "Sorry, I am out of cool quotes. Just die.", + "$n: duck." +}; + +extern int debug; +extern int hostile; +extern int sticky; +extern int practice; +extern int polymorphic; + +extern int startplanet; /* CRD feature - MAK, 2-Jun-93 */ + +extern int target; /* robotII.c 7/27/91 TC */ +extern int phrange; /* robotII.c 7/31/91 TC */ +extern int trrange; /* robotII.c 8/2/91 TC */ + +extern int dogslow; /* robotII.c 8/9/91 TC */ +extern int dogfast; +extern int runslow; +extern int runfast; +extern int closeslow; +extern int closefast; + +unsigned char getcourse(); +char *robo_message(); +char *termie_message(); /* added 8/2/91 TC */ + + +extern void (*r_signal()) (); +#ifndef IRIX +extern int fprintf(); +#endif +extern unsigned int sleep(); +void exitRobot(); +extern void move_player(); +void messAll(); +int phaser_plasmas(); +void pmessage2(); +int do_repair(); +void go_home(); +extern int ntorp(); +extern int repair_off(); +extern int cloak_off(); +extern int phaser(); +extern int angdist(); +int isTractoringMe(); +extern int pressor_player(); +extern int tractor_player(); +int projectDamage(); +extern int set_course(); +extern int cloak_on(); +extern int shield_up(); +extern void detothers(); +extern int shield_down(); +extern int set_speed(); +extern int lock_planet(); +extern int orbit(); +extern int repair(); +#ifdef ROBOTSTATS +extern void save_robot(); +#endif + +void +rmove() +{ + register struct player *j; + register struct planet *l; + register int i; + register int burst; + register int numHits, tDir; + int avDir; + extern struct Enemy *get_nearest(); + struct Enemy *enemy_buf; + struct player *enemy; + static int clock = 0; + static int avoid[2] = {-32, 32}; + int no_cloak; + char towhom[80]; + int timer; + static int lastTorpped = 0; /* when we last fired a torp 4/13/92 TC */ + + clock++; + /* Check that I'm alive */ + if (me->p_status == PEXPLODE) + { + r_signal(SIGALRM, SIG_IGN); + if (debug) + fprintf(stderr, "Robot: Augh! exploding.\n"); + + + /* hack: get rid of robot processes! */ + + if (1) + { + sleep(3); + } + else + { + while (me->p_status == PEXPLODE); + } + if (debug) + fprintf(stderr, "Robot: done exploding.\n"); + if (1) + { + sleep(3); + } + else + { + while (me->p_ntorp > 0); + } + if (debug) + fprintf(stderr, "Robot: torps are gone.\n"); + exitRobot(); + } + if (me->p_status == PDEAD) + { + r_signal(SIGALRM, SIG_IGN); + /* + * me->p_status = PFREE; move_player(me->p_no, -1,-1, 1); exit(0); + */ + exitRobot(); + } + /* keep ghostbuster away */ + me->p_ghostbuster = 0; + + timer = 0; + for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) + { + if ((j->p_status != PFREE) && !(j->p_flags & PFROBOT)) + timer = 1; + } + if (!timer && !sticky) + { + r_signal(SIGALRM, SIG_IGN); + me->p_status = PFREE; + move_player(me->p_no, -1, -1, 1); + exit(0); + } + /* if I'm a Terminator, quit if he quits, and quit if he dies and */ + /* I'm not "sticky" (-s) */ + + if (target >= 0) + { + if (players[target].p_status == PFREE) + { /* he went away */ + me->p_status = PEXPLODE; + return; + } + if ((!sticky) && (players[target].p_status != PALIVE)) + { /* he died */ + me->p_status = PEXPLODE; + return; + } + } + /* + * If it's been BOREDOM_TIME updates since we fired a torp, become hostile + * to all races, if we aren't already, and if we're not a practice robot + * (intended for guardian bots). 4/13/92 TC + */ + + if ((clock - lastTorpped > BOREDOM_TIME) && (!practice) && (!hostile) && + (me->p_team != 0)) + { + messAll("Bored, Bored, Bored."); + hostile++; + declare_war(ALLTEAM); + } + /* Our first priority is to phaser plasma torps in nearby vicinity... */ + /* If we fire, we aren't allowed to cloak... */ + no_cloak = phaser_plasmas(); + + /* Find an enemy */ + + enemy_buf = get_nearest(); + + if ((enemy_buf != NULL) && (enemy_buf != NOENEMY)) + { /* Someone to kill */ + enemy = &players[enemy_buf->e_info]; + if (((lrand48() % messfuse) == 0) && + (ihypot(me->p_x - enemy->p_x, me->p_y - enemy->p_y) < 20000)) + { + /* change 5/10/21 TC ...neut robots don't message */ + messfuse = MESSFUSEVAL; + if (me->p_team != 0) + { + sprintf(towhom, " %s->%s", + twoletters(&players[me->p_no]), + twoletters(&players[enemy->p_no])); + pmessage2(robo_message(enemy), enemy->p_no, + MINDIV, towhom, me->p_no); + } + else if (target >= 0) + { + /* + * MAK, 28-Apr-92 - send termie messages only to target + * messAll(termie_message(enemy)); + */ + sprintf(towhom, " %s->%s", + twoletters(&players[me->p_no]), + twoletters(&players[enemy->p_no])); + pmessage2(termie_message(enemy), enemy->p_no, + MINDIV, towhom, me->p_no); + } + } + else if (--messfuse == 0) + messfuse = 1; + timer = 0; + if (debug) + fprintf(stderr, "%d) noticed %d\n", me->p_no, enemy_buf->e_info); + } + else if (enemy_buf == NOENEMY) + { /* no more players. wait 1 minute. */ + if (do_repair()) + { + return; + } + go_home(0); + /* + * if (debug) fprintf(stderr, "%d) No players in game.\n", me->p_no); + */ + return; + } + else if (enemy_buf == 0) + { /* no one hostile */ + /* + * if (debug) fprintf(stderr, "%d) No hostile players in game.\n", + * me->p_no); + */ + if (do_repair()) + { + return; + } + go_home(0); + timer = 0; + return; + } + /* + * Note a bug in this algorithm: * Once someone dies, he is forgotten. + * This makes robots particularly easy * to kill on a suicide run, where + * you aim to where you think he will turn * as you die. Once dead, the + * robot will ignore you and all of your * active torpedoes! + */ + + /* + * Algorithm: * We have an enemy. * First priority: shoot at target in + * range. * Second: Dodge stars, torps, and plasma torps. * Third: Get away + * if we are damaged. * Fourth: repair. * Fifth: attack. + */ + + /* + * * If we are a practice robot, we will do all but the second. One * will + * be modified to shoot poorly and not use phasers. + */ + /* Fire weapons!!! */ + /* + * get_nearest() has already determined if torpedoes and phasers * will + * hit. It has also determined the courses which torps and * phasers + * should be fired. If so we will go ahead and shoot here. * We will lose + * repair and cloaking for the rest of this interrupt. * if we fire here. + */ + + if (practice) + { + no_cloak = 1; + if (enemy_buf->e_flags & E_TSHOT) + { + /* + * if (debug) fprintf(stderr, "%d) firing torps\n", me->p_no); + */ + for (burst = 0; (burst < 3) && (me->p_ntorp < MAXTORP); burst++) + { + ntorp(enemy_buf->e_tcourse, TMOVE); + } + } + } + else + { + if (enemy_buf->e_flags & E_TSHOT) + { + /* + * if (debug) fprintf(stderr, "%d) firing torps\n", me->p_no); + */ + for (burst = 0; (burst < 2) && (me->p_ntorp < MAXTORP); burst++) + { + repair_off(); + cloak_off(); + ntorp(enemy_buf->e_tcourse, TMOVE); /* was TSTRAIGHT 8/9/91 TC */ + no_cloak++; + lastTorpped = clock; /* record time of firing 4/13/92 TC */ + } + } + if (enemy_buf->e_flags & E_PSHOT) + { + /* + * if (debug) fprintf(stderr, "%d) phaser firing\n", me->p_no); + */ + no_cloak++; + repair_off(); + cloak_off(); + phaser(enemy_buf->e_course); + } + } + + /* auto pressor 7/27/91 TC */ + /* tractor/pressor rewritten on 5/1/92... glitches galore :-| TC */ + + /* + * whoa, too close for comfort, or he's tractoring me, or headed in for me, + * or I'm hurt + */ + + /* a little tuning -- 0.8 on phrange and +/- 90 degrees in for pressor */ + + /* + * pressor_player(-1); this didn't do anything before, so we'll let the + * pressors disengage by themselves 5/1/92 TC + */ + if (enemy_buf->e_flags & E_TRACT) + { /* if pressorable */ + if (((enemy_buf->e_dist < 0.8 * enemy_buf->e_phrange) && + (angdist(enemy_buf->e_edir, enemy_buf->e_course) > 64)) || + (isTractoringMe(enemy_buf)) || + (me->p_damage > 0)) + { + if (!(enemy->p_flags & PFCLOAK)) + { + if (debug) + fprintf(stderr, "%d) pressoring %d\n", me->p_no, + enemy_buf->e_info); + pressor_player(enemy->p_no); + no_cloak++; + repair_off(); + cloak_off(); + } + } + } + /* auto tractor 7/31/91 TC */ + + /* tractor if not pressoring and... */ + + /* tractor if: in range, not too close, and not headed +/- 90 degrees */ + /* of me, and I'm not hurt */ + + if ((!(me->p_flags & PFPRESS)) && + (enemy_buf->e_flags & E_TRACT) && + (angdist(enemy_buf->e_edir, enemy_buf->e_course) < 64) && + (enemy_buf->e_dist > 0.7 * enemy_buf->e_phrange)) + { + if (!(me->p_flags & PFTRACT)) + { + if (debug) + fprintf(stderr, "%d) tractoring %d\n", me->p_no, + enemy_buf->e_info); + tractor_player(enemy->p_no); + no_cloak++; + } + } + else + tractor_player(-1); /* otherwise don't tractor */ + + /* Avoid stars - MAK, 16-Jun-93 */ + /* + * This section of code allows robots to avoid crashing into stars. Within + * a specific range (AVOID_STAR), they will check to see if their current + * course will take them close to the star. If so, course will be adjusted + * to avoid the star. Within a smaller range (AVOID_MELT), course is + * adjusted directly away from the star. Collision avoidance is all they + * will do for this round, other than shooting. + */ + for (i = 0, l = &planets[0]; i < NUMPLANETS; i++, l++) + { + if (PL_TYPE(*l) == PLSTAR) + { + int dx, dy, stardir, newcourse = -1; + dx = ABS(l->pl_x - me->p_x); + dy = ABS(l->pl_y - me->p_y); + /* Avoid over box rather than circle to speed calculations */ + if (dx < AVOID_STAR && dy < AVOID_STAR) + { + stardir = getcourse(l->pl_x, l->pl_y); + + if (dx < AVOID_MELT && dy < AVOID_MELT) + { + /* Emergency! Way too close! */ + newcourse = NORMALIZE(stardir - 128); + if (debug) + { + fprintf(stderr, "Steering away from star %s, dir = %d\n", + l->pl_name, newcourse); + } + } + else if (angdist(me->p_dir, stardir) < 16) + { + /* Heading towards star, so adjust course. */ + newcourse = + NORMALIZE((me->p_dir < stardir) ? stardir - 32 : stardir + 32); + if (debug) + { + fprintf(stderr, "Adjusting course away from star %s, dir = %d\n", + l->pl_name, newcourse); + } + } + if (newcourse != -1) + { /* Change course and speed */ + me->p_desdir = newcourse; + if (angdist(me->p_desdir, me->p_dir) > 64) + me->p_desspeed = dogslow; + else + me->p_desspeed = dogfast; + return; + } + } + } + } + + /* Avoid torps */ + /* + * This section of code allows robots to avoid torps. * Within a specific + * range they will check to see if * any of the 'closest' enemies torps + * will hit them. * If so, they will evade for four updates. * Evading is + * all they will do for this round, other than shooting. + */ + + if (!practice) + { + if ((enemy->p_ntorp < 5)) + { + if ((enemy_buf->e_dist < 15000) || (avoidTime > 0)) + { + numHits = projectDamage(enemy->p_no, &avDir); + if (debug) + { + /* + * fprintf(stderr, "%d hits expected from %d from dir = %d\n", + * numHits, enemy->p_no, avDir); + */ + } + if (numHits == 0) + { + if (--avoidTime > 0) + { /* we may still be avoiding */ + if (angdist(me->p_desdir, me->p_dir) > 64) + me->p_desspeed = dogslow; + else + me->p_desspeed = dogfast; + return; + } + } + else + { + /* Actually avoid Torps */ + avoidTime = AVOID_TIME; + tDir = avDir - me->p_dir; + /* put into 0->255 range */ + tDir = NORMALIZE(tDir); + if (debug) + fprintf(stderr, "mydir = %d avDir = %d tDir = %d q = %d\n", + me->p_dir, avDir, tDir, tDir / 64); + switch (tDir / 64) + { + case 0: + case 1: + set_course(NORMALIZE(avDir + 64)); + break; + case 2: + case 3: + set_course(NORMALIZE(avDir - 64)); + break; + } + if (!no_cloak) + cloak_on(); + + if (angdist(me->p_desdir, me->p_dir) > 64) + me->p_desspeed = dogslow; + else + me->p_desspeed = dogfast; + + shield_up(); + detothers(); /* hmm */ + if (debug) + fprintf(stderr, "evading to dir = %d\n", me->p_desdir); + return; + } + } + } + /* + * Trying another scheme. * Robot will keep track of the number of torps + * a player has * launched. If they are greater than say four, the robot + * will * veer off immediately. Seems more humanlike to me. + */ + + else if (enemy_buf->e_dist < 15000) + { + if (--avoidTime > 0) + { /* we may still be avoiding */ + if (angdist(me->p_desdir, me->p_dir) > 64) + me->p_desspeed = dogslow; + else + me->p_desspeed = dogfast; + return; + } + if (lrand48() % 2) + { + me->p_desdir = NORMALIZE(enemy_buf->e_course - 64); + avoidTime = AVOID_TIME; + } + else + { + me->p_desdir = NORMALIZE(enemy_buf->e_course + 64); + avoidTime = AVOID_TIME; + } + if (angdist(me->p_desdir, me->p_dir) > 64) + me->p_desspeed = dogslow; + else + me->p_desspeed = dogfast; + shield_up(); + return; + } + } + /* Run away */ + /* + * The robot has taken damage. He will now attempt to run away from * the + * closest player. This obviously won't do him any good if there * is + * another player in the direction he wants to go. * Note that the robot + * will not run away if he dodged torps, above. * The robot will lower his + * shields in hopes of repairing some damage. + */ + +#define STARTDELTA 5000 /* ships appear +/- delta of home planet */ + + if (me->p_damage > 0 && enemy_buf->e_dist < 13000) + { + if (me->p_etemp > 900) /* 90% of 1000 */ + me->p_desspeed = runslow; + else + me->p_desspeed = runfast; + if (!no_cloak) + cloak_on(); + repair_off(); + shield_down(); + set_course(enemy_buf->e_course - 128); + if (debug) + fprintf(stderr, "%d(%d)(%d/%d) running from %s %16s damage (%d/%d) dist %d\n", + me->p_no, + (int) me->p_kills, + me->p_damage, + me->p_shield, + twoletters(enemy), + enemy->p_login, + enemy->p_damage, + enemy->p_shield, + enemy_buf->e_dist); + return; + } + /* Repair if necessary (we are safe) */ + /* + * The robot is safely away from players. It can now repair in peace. * It + * will try to do so now. + */ + + if (do_repair()) + { + return; + } + /* Attack. */ + /* + * The robot has nothing to do. It will check and see if the nearest * + * enemy fits any of its criterion for attack. If it does, the robot * + * will speed in and deliver a punishing blow. (Well, maybe) + */ + + if ((enemy_buf->e_flags & E_INTRUDER) || (enemy_buf->e_dist < 15000) + || (hostile)) + { + if ((!no_cloak) && (enemy_buf->e_dist < 10000)) + cloak_on(); + shield_up(); + if (debug) + fprintf(stderr, "%d(%d)(%d/%d) attacking %s %16s damage (%d/%d) dist %d\n", + me->p_no, + (int) me->p_kills, + me->p_damage, + me->p_shield, + twoletters(enemy), + enemy->p_login, + enemy->p_damage, + enemy->p_shield, + enemy_buf->e_dist); + + if (enemy_buf->e_dist < 15000) + { + set_course(enemy_buf->e_course + + avoid[(clock / AVOID_CLICKS) % SIZEOF(avoid)]); + if (angdist(me->p_desdir, me->p_dir) > 64) + set_speed(closeslow, 1); + else + set_speed(closefast, 1); + } + else + { + me->p_desdir = enemy_buf->e_course; + if (angdist(me->p_desdir, me->p_dir) > 64) + set_speed(closeslow, 1); + if (target >= 0) /* 7/27/91 TC */ + set_speed(12, 1); + else if (me->p_etemp > 900) /* 90% of 1000 */ + set_speed(runslow, 1); + else + set_speed(runfast, 1); + } + } + else + { + go_home(enemy_buf); + } +} + +unsigned char +getcourse(x, y) + int x, y; +{ + return ((unsigned char) (int) (atan2((double) (x - me->p_x), + (double) (me->p_y - y)) / 3.14159 * 128.)); +} + +/* the 100000's here were once GWIDTHs... */ +struct +{ + int x; + int y; +} center[] = +{ + { + + 100000 / 2, 100000 / 2 + }, /* change 5/20/91 TC was {0,0} */ + { + 100000 / 4, 100000 * 3 / 4 + }, /* Fed */ + { + 100000 / 4, 100000 / 4 + }, /* Rom */ + { + 0, 0 + }, + { + 100000 *3 / 4, 100000 / 4 + } , /* Kli */ + { + 0, 0 + } , + { + 0, 0 + } , + { + 0, 0 + } , + { + 100000 *3 / 4, 100000 * 3 / 4 + } +}; /* Ori */ + +/* + * This function means that the robot has nothing better to do. If there are + * hostile players in the game, it will try to get as close to them as it + * can, while staying in its own space. Otherwise, it will head to the center + * of its own space. + */ +/* CRD feature: robots now hover near their start planet - MAK, 2-Jun-93 */ + +#define GUARDDIST 8000 + +void +go_home(ebuf) + struct Enemy *ebuf; +{ + int x, y; + double dx, dy; + struct player *j; + + if (ebuf == 0) + { /* No enemies */ + /* + * if (debug) fprintf(stderr, "%d) No enemies\n", me->p_no); + */ + if (target >= 0) + { + /* First priority, current target (if any) */ + j = &players[target]; + x = j->p_x; + y = j->p_y; + } + else if (startplanet == -1) + { + /* No start planet, so go to center of galaxy */ + x = (GWIDTH / 2); + y = (GWIDTH / 2); + } + else + { + /* Return to start planet */ + x = planets[startplanet].pl_x + (lrand48() % 2000) - 1000; + y = planets[startplanet].pl_y + (lrand48() % 2000) - 1000; + } + } + else + { /* Let's get near him */ + j = &players[ebuf->e_info]; + x = j->p_x; + y = j->p_y; + + if (startplanet != -1) + { + /* Get between enemy and planet */ + int px, py; + double theta; + + px = planets[startplanet].pl_x; + py = planets[startplanet].pl_y; + theta = atan2((double) (y - py), (double) (x - px)); + x = px + GUARDDIST * cos(theta); + y = py + GUARDDIST * sin(theta); + } + } + /* + * if (debug) fprintf(stderr, "%d) moving towards (%d/%d)\n", me->p_no, x, + * y); + */ + + /* + * Note that I've decided that robots should never stop moving. * It makes + * them too easy to kill + */ + + me->p_desdir = getcourse(x, y); + if (angdist(me->p_desdir, me->p_dir) > 64) + set_speed(dogslow, 1); + else if (me->p_etemp > 900) /* 90% of 1000 */ + set_speed(runslow, 1); + else + { + dx = x - me->p_x; + dy = y - me->p_y; + set_speed((ihypot((int) dx, (int) dy) / 5000) + 3, 1); + } + cloak_off(); +} + +int +phaser_plasmas() +{ + register struct plasmatorp *pt; + register int i; + int myphrange; + + myphrange = phrange; /* PHASEDIST * me->p_ship.s_phaserdamage / + * 100; */ + for (i = 0, pt = &plasmatorps[0]; i < MAXPLASMA * MAXPLAYER; i++, pt++) + { + if (pt->pt_status != PTMOVE) + continue; + if (i == me->p_no) + continue; + if (!(pt->pt_war & me->p_team) && !(me->p_hostile & pt->pt_team)) + continue; + if (abs(pt->pt_x - me->p_x) > myphrange) + continue; + if (abs(pt->pt_y - me->p_y) > myphrange) + continue; + if (ihypot(pt->pt_x - me->p_x, pt->pt_y - me->p_y) > myphrange) + continue; + repair_off(); + cloak_off(); + phaser(getcourse(pt->pt_x, pt->pt_y)); + return 1; /* was this missing? 3/25/92 TC */ + break; + } + return 0; /* was this missing? 3/25/92 TC */ +} + +int +projectDamage(eNum, dirP) + int eNum; + int *dirP; +{ + register int i, j, numHits = 0, mx, my, tx, ty, dx, dy; + double tdx, tdy, mdx, mdy; + register struct torp *t; + + *dirP = 0; + for (i = 0, t = &torps[eNum * MAXTORP]; i < MAXTORP; i++, t++) + { + if (t->t_status == TFREE) + continue; + tx = t->t_x; + ty = t->t_y; + mx = me->p_x; + my = me->p_y; + tdx = (double) t->t_speed * Cos[t->t_dir] * WARP1; + tdy = (double) t->t_speed * Sin[t->t_dir] * WARP1; + mdx = (double) me->p_speed * Cos[me->p_dir] * WARP1; + mdy = (double) me->p_speed * Sin[me->p_dir] * WARP1; + for (j = t->t_fuse; j > 0; j--) + { + tx += tdx; + ty += tdy; + mx += mdx; + my += mdy; + dx = tx - mx; + dy = ty - my; + if (ABS(dx) < EXPDIST && ABS(dy) < EXPDIST) + { + numHits++; + *dirP += t->t_dir; + break; + } + } + } + if (numHits > 0) + *dirP /= numHits; + return (numHits); +} + +int +isTractoringMe(enemy_buf) + struct Enemy *enemy_buf; +{ + return ((enemy_buf->e_hisflags & PFTRACT) && /* bug fix: was using */ + !(enemy_buf->e_hisflags & PFPRESS) && /* e_flags 6/24/92 TC */ + (enemy_buf->e_tractor == me->p_no)); +} + +struct Enemy ebuf; + +struct Enemy * +get_nearest() +{ + int pcount = 0; + register int i; + register struct player *j; + int intruder = 0; + int tdist; + double dx, dy; + double vxa, vya, l; /* Used for trap shooting */ + double vxt, vyt; + double vxs, vys; + double dp; + + /* Find an enemy */ + ebuf.e_info = me->p_no; + ebuf.e_dist = GWIDTH + 1; + + pcount = 0; /* number of human players in game */ + + if (target >= 0) + { + j = &players[target]; + if (!((me->p_swar | me->p_hostile) & j->p_team)) + declare_war(players[target].p_team); /* make sure we're at war + * 7/31/91 TC */ + + /* We have an enemy */ + /* Get his range */ + dx = j->p_x - me->p_x; + dy = j->p_y - me->p_y; + tdist = ihypot((int) dx, (int) dy); + + if (j->p_status != POUTFIT) + { /* ignore target if outfitting */ + ebuf.e_info = target; + ebuf.e_dist = tdist; + ebuf.e_flags &= ~(E_INTRUDER); + } + /* need a loop to find hostile ships */ + /* within tactical range */ + + for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) + { + if ((j->p_status != PALIVE) || (j == me) || + ((j->p_flags & PFROBOT) && (!hostile))) + continue; + else + pcount++; /* Other players in the game */ + if (((j->p_swar | j->p_hostile) & me->p_team) + || ((me->p_swar | me->p_hostile) & j->p_team)) + { + /* We have an enemy */ + /* Get his range */ + dx = j->p_x - me->p_x; + dy = j->p_y - me->p_y; + tdist = ihypot((int) dx, (int) dy); + + /* if target's teammate is too close, mark as nearest */ + + if ((tdist < ebuf.e_dist) && (tdist < 15000)) + { + ebuf.e_info = i; + ebuf.e_dist = tdist; + ebuf.e_flags &= ~(E_INTRUDER); + } + } /* end if */ + } /* end for */ + } + else + { /* no target */ + /* avoid dead slots, me, other robots (which aren't hostile) */ + for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) + { + if ((j->p_status != PALIVE) || (j == me) || + ((j->p_flags & PFROBOT) && (!hostile))) + continue; + else + pcount++; /* Other players in the game */ + if (((j->p_swar | j->p_hostile) & me->p_team) + || ((me->p_swar | me->p_hostile) & j->p_team)) + { + /* We have an enemy */ + /* Get his range */ + dx = j->p_x - me->p_x; + dy = j->p_y - me->p_y; + tdist = ihypot((int) dx, (int) dy); + + /* Check to see if ship is near our planet. */ + if (startplanet != -1) + { + int px, py; + px = planets[startplanet].pl_x; + py = planets[startplanet].pl_y; + + intruder = (ihypot(j->p_x - px, j->p_y - py) + < GUARDDIST); + } + if (tdist < ebuf.e_dist) + { + ebuf.e_info = i; + ebuf.e_dist = tdist; + if (intruder) + ebuf.e_flags |= E_INTRUDER; + else + ebuf.e_flags &= ~(E_INTRUDER); + } + } /* end if */ + } /* end for */ + } /* end else */ + if (pcount == 0) + { + return (NOENEMY); /* no players in game */ + } + else if (ebuf.e_info == me->p_no) + { + return (0); /* no hostile players in the game */ + } + else + { + j = &players[ebuf.e_info]; + + /* Get torpedo course to nearest enemy */ + ebuf.e_flags &= ~(E_TSHOT); + + vxa = (j->p_x - me->p_x); + vya = (j->p_y - me->p_y); + l = ihypot((int) vxa, (int) vya); /* Normalize va */ + if (l != 0) + { + vxa /= l; + vya /= l; + } + vxs = (Cos[j->p_dir] * j->p_speed) * WARP1; + vys = (Sin[j->p_dir] * j->p_speed) * WARP1; + dp = vxs * vxa + vys * vya; /* Dot product of (va vs) */ + dx = vxs - dp * vxa; + dy = vys - dp * vya; + l = hypot(dx, dy); /* Determine how much speed is required */ + dp = (float) (me->p_ship.s_torp.speed * WARP1); + l = (dp * dp - l * l); + if (l > 0) + { + double he_x, he_y, area; + + /* Only shoot if within distance */ + he_x = j->p_x + Cos[j->p_dir] * j->p_speed * 50 * WARP1; + he_y = j->p_y + Sin[j->p_dir] * j->p_speed * 50 * WARP1; + area = 50 * me->p_ship.s_torp.speed * WARP1; + if (ihypot(he_x - me->p_x, he_y - me->p_y) < area) + { + l = sqrt(l); + vxt = l * vxa + dx; + vyt = l * vya + dy; + ebuf.e_flags |= E_TSHOT; + ebuf.e_tcourse = getcourse((int) vxt + me->p_x, (int) vyt + me->p_y); + } + } + /* Get phaser shot status */ + if (ebuf.e_dist < 0.8 * phrange) + ebuf.e_flags |= E_PSHOT; + else + ebuf.e_flags &= ~(E_PSHOT); + + /* Get tractor/pressor status */ + if (ebuf.e_dist < trrange) + ebuf.e_flags |= E_TRACT; + else + ebuf.e_flags &= ~(E_TRACT); + + + /* get his phaser range */ + ebuf.e_phrange = PHASEDIST * j->p_ship.s_phaser.damage / 100; + + /* get course info */ + ebuf.e_course = getcourse(j->p_x, j->p_y); + ebuf.e_edir = j->p_dir; + ebuf.e_hisflags = j->p_flags; + ebuf.e_tractor = j->p_tractor; + /* + * if (debug) fprintf(stderr, "Set course to enemy is %d (%d)\n", + * (int)ebuf.e_course, (int) ebuf.e_course * 360 / 256); + */ + + /* check to polymorph */ + + if ((polymorphic) && (j->p_ship.s_type != me->p_ship.s_type) && + (j->p_ship.s_type != ATT)) + { /* don't polymorph to ATT 4/8/92 TC */ + extern int config(); + extern int getship(); + int old_shield; + int old_damage; + old_shield = me->p_ship.s_maxshield; + old_damage = me->p_ship.s_maxdamage; + + getship(&(me->p_ship), j->p_ship.s_type); + config(); + if (me->p_speed > me->p_ship.s_imp.maxspeed) + me->p_speed = me->p_ship.s_imp.maxspeed; + me->p_shield = (me->p_shield * (float) me->p_ship.s_maxshield) + / (float) old_shield; + me->p_damage = (me->p_damage * (float) me->p_ship.s_maxdamage) + / (float) old_damage; + } + return (&ebuf); + } +} + +struct planet * +get_nearest_planet() +{ + register int i; + register struct planet *l; + register struct planet *nearest; + int dist = GWIDTH; /* Manhattan distance to nearest planet */ + int ldist; + + nearest = &planets[0]; + for (i = 0, l = &planets[i]; i < NUMPLANETS; i++, l++) + { + if ((ldist = (abs(me->p_x - l->pl_x) + abs(me->p_y - l->pl_y))) < + dist) + { + dist = ldist; + nearest = l; + } + } + return nearest; +} + +int +do_repair() +{ + /* Repair if necessary (we are safe) */ + + register struct planet *l; + int dx, dy; + int dist; + + l = get_nearest_planet(); + dx = abs(me->p_x - l->pl_x); + dy = abs(me->p_y - l->pl_y); + + if (me->p_damage > 0) + { + if ((me->p_swar | me->p_hostile) & l->pl_owner) + { + if (l->pl_armies > 0) + { + if ((dx < PFIREDIST) && (dy < PFIREDIST)) + { + if (debug) + fprintf(stderr, "%d) on top of hostile planet (%s)\n", me->p_no, l->pl_name); + return (0); /* can't repair on top of hostile planets */ + } + if (ihypot((int) dx, (int) dy) < PFIREDIST) + { + if (debug) + fprintf(stderr, "%d) on top of hostile planet (%s)\n", me->p_no, l->pl_name); + return (0); + } + } + me->p_desspeed = 0; + } + else + { /* if friendly */ + if ((l->pl_flags & PLREPAIR) && + !(me->p_flags & PFORBIT)) + { /* oh, repair! */ + dist = ihypot((int) dx, (int) dy); + + if (debug) + fprintf(stderr, "%d) locking on to planet %d\n", + me->p_no, l->pl_no); + cloak_off(); + shield_down(); + me->p_desdir = getcourse(l->pl_x, l->pl_y); + lock_planet(l->pl_no); + me->p_desspeed = 4; + if (dist - (ORBDIST / 2) < (11500 * me->p_speed * me->p_speed) / + me->p_ship.s_imp.dec) + { + if (me->p_desspeed > 2) + { + set_speed(2, 1); + } + } + if ((dist < ENTORBDIST) && (me->p_speed <= 2)) + { + me->p_flags &= ~PFPLLOCK; + orbit(); + } + return (1); + } + else + { /* not repair, so ignore it */ + me->p_desspeed = 0; + } + } + shield_down(); + if (me->p_speed == 0) + repair(); + if (debug) + fprintf(stderr, "%d) repairing damage at %d\n", + me->p_no, + me->p_damage); + return (1); + } + else + { + return (0); + } +} + + +void +pmessage(str, recip, group, address) + char *str; + int recip; + int group; + char *address; +{ + pmessage2(str, recip, group, address, 255); +} + + +void +pmessage2(str, recip, group, address, from) + char *str; + int recip; + int group; + char *address; + unsigned char from; +{ + struct message *cur; + int mesgnum; + + if ((mesgnum = ++(mctl->mc_current)) >= MAXMESSAGE) + { + mctl->mc_current = 0; + mesgnum = 0; + } + cur = &messages[mesgnum]; + cur->m_no = mesgnum; + cur->m_flags = group; + cur->m_recpt = recip; + cur->m_from = from; + (void) sprintf(cur->m_data, "%-9s %s", address, str); + cur->m_flags |= MVALID; +} + + +char * +robo_message(enemy) + struct player *enemy; +{ + int i; + char *s, *t; + + i = (lrand48() % (sizeof(rmessages) / sizeof(rmessages[0]))); + + for (t = rmessages[i], s = rmessage; *t != '\0'; s++, t++) + { + switch (*t) + { + case '$': + switch (*(++t)) + { + case '$': + *s = *t; + break; + case 'T': /* "a Fed" or "a Klingon" ... */ + if (enemy->p_team != me->p_team && + enemy->p_team == ORI) + { + strcpy(s, "an "); + } + else + { + strcpy(s, "a "); + } + s = s + strlen(s); + case 't': /* "Fed" or "Orion" */ + if (enemy->p_team != me->p_team) + { + switch (enemy->p_team) + { + case FED: + strcpy(s, "Fed"); + break; + case ROM: + strcpy(s, "Romulan"); + break; + case KLI: + strcpy(s, "Klingon"); + break; + case ORI: + strcpy(s, "Orion"); + break; + } + } + else + { + strcpy(s, "TRAITOR"); + } + s = s + strlen(s) - 1; + break; + case 'f': + switch (me->p_team) + { + case FED: + strcpy(s, "Federation"); + break; + case ROM: + strcpy(s, "Romulan empire"); + break; + case KLI: + strcpy(s, "Klingon empire"); + break; + case ORI: + strcpy(s, "Orion empire"); + break; + } + s = s + strlen(s) - 1; + break; + default: + *s = *t; + } + break; + default: + *s = *t; + break; + } + } + *s = '\0'; + return (rmessage); +} + +char * +termie_message(enemy) + struct player *enemy; +{ + int i; + char *s, *t; + + i = (lrand48() % (sizeof(termie_messages) / sizeof(termie_messages[0]))); + + for (t = termie_messages[i], s = tmessage; *t != '\0'; s++, t++) + { + switch (*t) + { + case '$': + switch (*(++t)) + { + case '$': + *s = *t; + break; + case 'T': /* "a Fed" or "a Klingon" ... */ + if (enemy->p_team != me->p_team && + enemy->p_team == ORI) + { + strcpy(s, "an "); + } + else + { + strcpy(s, "a "); + } + s = s + strlen(s); + case 't': /* "Fed" or "Orion" */ + if (enemy->p_team != me->p_team) + { + switch (enemy->p_team) + { + case FED: + strcpy(s, "Fed"); + break; + case ROM: + strcpy(s, "Romulan"); + break; + case KLI: + strcpy(s, "Klingon"); + break; + case ORI: + strcpy(s, "Orion"); + break; + } + } + else + { + strcpy(s, "TRAITOR"); + } + s = s + strlen(s) - 1; + break; + case 'f': + switch (me->p_team) + { + case FED: + strcpy(s, "Federation"); + break; + case ROM: + strcpy(s, "Romulan empire"); + break; + case KLI: + strcpy(s, "Klingon empire"); + break; + case ORI: + strcpy(s, "Orion empire"); + break; + } + s = s + strlen(s) - 1; + break; + case 'n': /* name 8/2/91 TC */ + strcpy(s, enemy->p_name); + s = s + strlen(s) - 1; + break; + default: + *s = *t; + } + break; + default: + *s = *t; + break; + } + } + *s = '\0'; + return (tmessage); + +} + +void +exitRobot() +{ + static char buf[80]; + + r_signal(SIGALRM, SIG_IGN); + if (me != NULL && me->p_team != ALLTEAM) + { + if (target >= 0) + { + strcpy(buf, "I'll be back."); + messAll(buf); + } + else + { + /* + * sprintf(buf, "%s %s (%s) leaving the game (%.16s@%.16s)", + * ranks[me->p_stats.st_rank].name, me->p_name, me->p_mapchars, + * me->p_login, me->p_monitor); messAll(buf); + */ + } + } +#ifdef ROBOTSTATS + save_robot(); +#endif + + strcpy(buf, me->p_name); + /* something about Terminators hangs up the slot when a human */ + /* tries to log in on that slot, so... */ + memset(me, 0, sizeof(struct player)); /* confusion 8/5/91 TC */ + strcpy(me->p_name, buf); + + /* + * me->p_status = PFREE; move_player(me->p_no, -1,-1, 1); + */ + + /* + * all right, so zeroing out p_stats.st_tticks has undesireable side + * effects when the client tries to compute ratings... + */ + + me->p_stats.st_tticks = 1; /* quick fix 3/15/92 TC */ + exit(0); +} + +void +messAll(buf) + char *buf; /* wasn't K&R before...oops 5/1/92 TC */ +{ + static char addrbuf[20]; + + sprintf(addrbuf, " %s->ALL", twoletters(me)); + pmessage2(buf, 0, MALL, addrbuf, me->p_no); +} diff -r 054275999194 -r 8c6d5731234d src/robotII.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/robotII.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,622 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +char binary[] = "@(#)robotII"; + +#include "config.h" + +#include +#include +#include +#include +#include +#ifndef ULTRIX +#include +#endif +#include +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" + +extern void (*r_signal()) (); + +void config(); + +struct itimerval udt; +extern int redrawall; /* maint: missing "extern" 6/22/92 TC */ +extern int lastm; /* maint: missing "extern" 6/22/92 TC */ + +/* This lets you specify which ships a robot is allowed to choose */ +int robotships[NUM_TYPES] = { + 1, /* SCOUT */ + 1, /* DESTROYER */ + 1, /* CRUISER */ + 1, /* BATTLESHIP */ + 1, /* ASSAULT */ + 0, /* STARBASE */ + 0, /* ATT */ + 0, /* JUMPSHIP */ + 1, /* FRIGATE */ + 0, /* WARBASE */ + 1, /* LIGHTCRUISER */ + 0, /* CARRIER */ + 0, /* UTILITY */ + 1 /* PATROL */ +}; + +/* lots of neat flags */ +int hostile; +int debug; +int level; +int fleet; +int sticky; +int berserk; +int practice; +int nofuel; + +int polymorphic; /* match opponent's ship class 8/15/91 TC */ +int target; /* Terminator's target 7/27/91 TC */ +int phrange; /* phaser range 7/31/91 TC */ +int trrange; /* tractor range 8/2/91 TC */ + +int startplanet = -1; /* CRD feature - MAK, 2-Jun-93 */ + +/* velocities 8/9/91 TC */ + +int dogslow; /* dodge speed (hard turn) */ +int dogfast; /* dodge speed (soft turn) */ +int runslow; /* run speed (flat etemp) */ +int runfast; /* run speed (gain etemp) */ +int closeslow; /* approach speed (hard turn) */ +int closefast; /* approach speed (soft turn) */ + +char *rnames[6] = {"M5", "Colossus", "Guardian", "HAL", "DreadPirate Bob", +"TERMINATOR"}; + +#ifdef ROBOTSTATS +void +do_robot_login() +{ + int plfd, position, entries, i; + char *path; + struct statentry player; + struct stat buf; + + path = build_path(PLAYERFILE); + plfd = open(path, O_RDONLY, 0); + if (plfd < 0) + { + fprintf(stderr, "%s: I cannot open the player file! (errno: %d)\n", + argv0, errno); + me->p_pos = -1; + return; + } + position = 0; + while (read(plfd, (char *) &player, sizeof(struct statentry)) == + sizeof(struct statentry)) + { + if (!strcmp(pseudo, player.name)) + { + close(plfd); + me->p_pos = position; + memcpy(&(me->p_stats), &player.stats, sizeof(struct stats)); + return; + } + position++; + } + /* Not in there, so create it */ + strcpy(player.name, pseudo); + strcpy(player.password, "*"); /* an invalid password to prevent logins */ + memset(&player.stats, 0, sizeof(struct stats)); + player.stats.st_tticks = 1; + player.stats.st_flags = ST_INITIAL; + + plfd = open(path, O_RDWR | O_CREAT, 0644); + if (plfd < 0) + { + fprintf(stderr, "%s: I cannot open the player file! (errno: %d)\n", + argv0, errno); + me->p_pos = -1; + return; + } + else + { + fstat(plfd, &buf); + entries = buf.st_size / sizeof(struct statentry); + lseek(plfd, entries * sizeof(struct statentry), 0); + write(plfd, (char *) &player, sizeof(struct statentry)); + close(plfd); + me->p_pos = entries; + memcpy(&(me->p_stats), &player.stats, sizeof(struct stats)); + } +} + +void +save_robot() +{ + int fd; + char *path; + + if (me->p_pos < 0) + return; + path = build_path(PLAYERFILE); + fd = open(path, O_WRONLY, 0644); + if (fd >= 0) + { + me->p_stats.st_lastlogin = time(NULL); + lseek(fd, 32 + me->p_pos * sizeof(struct statentry), 0); + write(fd, (char *) &me->p_stats, sizeof(struct stats)); + close(fd); + } +} +#endif + +int +main(argc, argv) + int argc; + char **argv; +{ + register int i; + int rmove(); + int team = -1; + int bteam; + int pno; + int class; /* ship class 8/9/91 TC */ + + argv0 = argv[0]; + srand48(time(NULL) + getpid()); + + openmem(0, 0); + + for (;;) + { + class = lrand48() % NUM_TYPES; /* pick a ship type */ + if (robotships[class] && shipsallowed[class]) + break; + } + + target = -1; /* no target 7/27/91 TC */ + for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) + { + switch (argv[1][1]) + { + case 'S': + startplanet = atoi(&argv[1][2]); + if (startplanet >= configvals->numplanets) + { + printf("startplanet insane: %d\n", startplanet); + startplanet = -1; + } + break; + case 'F': + nofuel++; + break; + case 'P': + polymorphic++; + break; + case 'f': + fleet++; + break; + case 's': + sticky++; + break; + case 'd': + debug++; + break; + case 'h': + hostile++; + break; + case 'p': + practice++; + break; + case 'b': + berserk++; + break; + case 'l': + if (argv[1][2] != '\0') + level = atoi(&argv[1][2]); + else + level = 100; + break; + case 'c': /* ship class */ + { + char cstr[NUM_TYPES + 1]; + + for (class = 0; class <= NUM_TYPES; class++) + { + if (class == NUM_TYPES) + { + cstr[NUM_TYPES] = 0; + fprintf(stderr, "Unknown ship class, must be one of [%s].\n", cstr); + exit(1); + } + if (argv[1][2] == shipvals[class].s_letter) + break; + cstr[class] = shipvals[class].s_letter; + } + } + break; + case 'T': /* team */ + switch (argv[1][2]) + { + case 'f': + team = 0; + bteam = FED; + break; + case 'r': + team = 1; + bteam = ROM; + break; + case 'k': + team = 2; + bteam = KLI; + break; + case 'o': + team = 3; + bteam = ORI; + break; + case 'n': /* change 5/10/91 TC neutral */ + case 'i': + team = 4; + bteam = FED | ROM | KLI | ORI; /* don't like anybody */ + break; + case 't': + { + char c; + c = argv[1][3]; + + team = 5; + bteam = FED | ROM | KLI | ORI; /* don't like anybody */ + target = -1; + if (c == '\0') + { + fprintf(stderr, "Must specify target. e.g. -Tt3.\n"); + exit(1); + } + if ((c >= '0') && (c <= '9')) + target = c - '0'; + else if ((c >= 'a') && (c <= 'v')) + target = c - 'a' + 10; + else + { + fprintf(stderr, "Must specify target. e.g. -Tt3.\n"); + exit(1); + } + } /* end case 't' */ + break; + default: + fprintf(stderr, "Unknown team type. Usage -Tx where x is [frko]\n"); + exit(1); + } /* end switch argv */ + break; + default: + fprintf(stderr, "Unknown option '%c' (must be one of: bcdfpsFPT)\n", argv[1][1]); + exit(1); + } /* end switch argv[1][1] */ + + + } /* end for */ + + if (team < 0 || team >= 6) + { /* change 7/27/91 TC was 4 now 6 */ + if (debug) + fprintf(stderr, "Choosing random team.\n"); + team = lrand48() % 4; + } + + pno = findrslot(); /* Robots are entitled to tester's slots. */ + me = &players[pno]; + me->p_no = pno; + myship = &me->p_ship; + mystats = &me->p_stats; + lastm = mctl->mc_current; + + /* + * At this point we have memory set up. If we aren't a fleet, we don't + * want to replace any other robots on this team, so we'll check the other + * players and get out if there are any on our team. + */ + + if (practice) + { + strcpy(pseudo, "Hozer"); + } + else + { + strcpy(pseudo, rnames[team]); + } + strcpy(login, "Robot"); + + (void) strncpy(me->p_login, login, sizeof(me->p_login)); + me->p_login[sizeof(me->p_login) - 1] = '\0'; + (void) strncpy(me->p_monitor, "Nowhere", sizeof(me->p_monitor)); + me->p_monitor[sizeof(me->p_monitor) - 1] = '\0'; + + /* repeat "Nowhere" for completeness 4/13/92 TC */ + (void) strncpy(me->p_full_hostname, "Nowhere", sizeof(me->p_full_hostname)); + me->p_full_hostname[sizeof(me->p_full_hostname) - 1] = '\0'; + + if (target >= 0) + { /* hack 7/27/91 TC */ + enter(team, target, pno, class, startplanet); + startplanet = -1; /* Termies should forget about startplanet */ + } + else + startplanet = enter(team, 0, pno, class, startplanet); + +#ifdef ROBOTSTATS + do_robot_login(); +#else + me->p_pos = -1; /* So robot stats don't get saved */ +#endif + + me->p_flags |= PFROBOT; /* Mark as a robot */ + if ((berserk) || (team == 4)) /* indeps are hostile */ + me->p_hostile = (FED | ROM | KLI | ORI); /* unless they are berserk */ + else if (team == 5) + me->p_hostile = 0; /* Termies declare war later */ + else if (practice) + me->p_hostile = bteam; /* or practice */ + else + me->p_hostile = 0; /* robots are peaceful */ + + if (practice) + me->p_flags |= PFPRACTR; /* Mark as a practice robot */ + r_signal(SIGALRM, rmove); + + config(); + if (practice) + { + udt.it_interval.tv_sec = 1; /* Robots get to move 1/sec */ + udt.it_interval.tv_usec = 000000; + } + else + { + udt.it_interval.tv_sec = 0; /* Robots get to move 2/sec */ + udt.it_interval.tv_usec = 500000; + } + udt.it_value.tv_sec = 1; + udt.it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, &udt, 0) < 0) + { + perror("setitimer"); + me->p_status = PFREE; /* Put robot in game */ + move_player(me->p_no, -1, -1, 1); + exit(1); + } + /* allows robots to be forked by the daemon -- Evil ultrix bullshit */ +#ifndef SVR4 + sigsetmask(0); +#endif /* SVR4 */ + + if (team == 4) + { + int count = 0; + for (i = 0; i < MAXPLAYER; i++) + { + if (players[i].p_status == PALIVE) + count++; + } + if (((count <= 1) && (!fleet)) || + ((count < 1) && (fleet))) + { /* if one or less players, don't show */ + if (debug) + fprintf(stderr, "No one to hoze.\n"); + players[pno].p_status = PFREE; + move_player(me->p_no, -1, -1, 1); + exit(1); + } + } + if (!fleet) + { + for (i = 0; i < MAXPLAYER; i++) + { + if ((players[i].p_status == PALIVE) && (players[i].p_team == bteam)) + { + if (debug) + fprintf(stderr, "Galaxy already defended\n"); + players[pno].p_status = PFREE; + move_player(me->p_no, -1, -1, 1); + exit(1); + } + } + } + me->p_status = PALIVE; /* Put robot in game */ + while (1) + { + pause(); + } + return 0; +} + +int +findrslot() +{ + register int i; + +#if 0 + for (i = 0; i < MAXPLAYER; i++) +#else + for (i = MAXPLAYER - 1; i >= 0; i--) +#endif + { + /* reverse entry..let's be trendy 4/6/92 TC */ + if (players[i].p_status == PFREE) + { /* We have a free slot */ + players[i].p_status = POUTFIT; /* possible race code */ + break; + } + } + if ((i == MAXPLAYER) || (i == -1)) + { + if (debug) + { + fprintf(stderr, "No more room in game\n"); + } + exit(0); + } + memset(&players[i].p_stats, 0, sizeof(struct stats)); + players[i].p_stats.st_tticks = 1; + return (i); +} + +void +warning(mess) + char *mess; +{ + if (debug) + fprintf(stderr, "warning: %s\n", mess); +} + +void +config() +{ + /* calc class-specific stuff */ + + phrange = PHASEDIST * me->p_ship.s_phaser.damage / 100; + trrange = TRACTDIST * me->p_ship.s_tractrng; + + switch (myship->s_type) + { + case SCOUT: + dogslow = 5; + dogfast = 7; + runslow = 8; + runfast = 9; + closeslow = 5; + closefast = 7; + break; + case DESTROYER: + dogslow = 4; + dogfast = 6; + runslow = 6; + runfast = 8; + closeslow = 4; + closefast = 6; + break; + case CRUISER: + dogslow = 4; + dogfast = 6; + runslow = 6; + runfast = 7; + closeslow = 4; + closefast = 6; + break; + case BATTLESHIP: + dogslow = 3; + dogfast = 5; + runslow = 5; + runfast = 6; + closeslow = 3; + closefast = 4; + break; + case FRIGATE: + dogslow = 3; + dogfast = 5; + runslow = 5; + runfast = 6; + closeslow = 3; + closefast = 4; + break; + case ASSAULT: + dogslow = 3; + dogfast = 5; + runslow = 6; + runfast = 7; + closeslow = 3; + closefast = 4; + break; + case JUMPSHIP: + dogslow = 2; + dogfast = 3; + runslow = 2; + runfast = 3; + closeslow = 2; + closefast = 3; + break; + case STARBASE: + dogslow = 2; + dogfast = 2; + runslow = 2; + runfast = 2; + closeslow = 2; + closefast = 2; + break; + case WARBASE: + dogslow = 2; + dogfast = 2; + runslow = 2; + runfast = 2; + closeslow = 2; + closefast = 2; + break; + case LIGHTCRUISER: + dogslow = 5; + dogfast = 6; + runslow = 6; + runfast = 7; + closeslow = 5; + closefast = 7; + break; + case CARRIER: + dogslow = 3; + dogfast = 4; + runslow = 5; + runfast = 6; + closeslow = 4; + closefast = 6; + break; + case UTILITY: + dogslow = 3; + dogfast = 4; + runslow = 5; + runfast = 6; + closeslow = 4; + closefast = 5; + break; + case PATROL: + dogslow = 7; + dogfast = 8; + runslow = 9; + runfast = 10; + closeslow = 8; + closefast = 9; + break; + } + + if (debug) + printf("My phaser range: %d.\n", phrange); + if (debug) + printf("My tractor range: %d.\n", trrange); + + if (!nofuel) + { + myship->s_phaser.cost = 0; + myship->s_torp.cost = 0; + myship->s_cloakcost = 0; + } + if (target >= 0) + { /* 7/27/91 TC */ + myship->s_imp.maxspeed = 20;/* was 10, so you can't run */ + myship->s_imp.cost = 1; + myship->s_egncoolrate = 100; + } +} diff -r 054275999194 -r 8c6d5731234d src/shipvals.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shipvals.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,1794 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include +#include +#include +#include +#include + +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" + + +/* This defines the core flags for a normal ship */ +#define SFNCORE \ + /*SFNCANDOCK|*/SFNCANORBIT | SFNARMYNEEDKILL|SFNCANWARP|SFNHASPHASERS|SFNARMYNEEDKILL + + + + + + +/*-------------------------------INTERNAL FUNCTONS------------------------*/ + +/*---------------------------------GETSHIPDEFAULTS------------------------*/ +/* + * This function loads the shipvals array with the default values for the + * ships. They can later be changed with the sysdefaults. + */ + + +void +getshipdefaults() +{ + int i; + + for (i = 0; i < NUM_TYPES; i++) + shipvals[i].s_type = i; + + /* comprehensive definition of SCOUT */ + shipvals[SCOUT].s_alttype = 0; + strcpy(shipvals[SCOUT].s_name, "Scout"); + shipvals[SCOUT].s_turns = 570000; + shipvals[SCOUT].s_imp.acc = 200; + shipvals[SCOUT].s_imp.dec = 300; /* was: 270; (BG) */ + shipvals[SCOUT].s_imp.cost = 2; + shipvals[SCOUT].s_imp.maxspeed = 12; + shipvals[SCOUT].s_imp.etemp = 1000; + shipvals[SCOUT].s_after.acc = 700; + shipvals[SCOUT].s_after.dec = 270; + shipvals[SCOUT].s_after.cost = 40; + shipvals[SCOUT].s_after.maxspeed = 14; + shipvals[SCOUT].s_after.etemp = 35000; + if (configvals->bronco_shipvals) + { + shipvals[SCOUT].s_warp.acc = 10000; + shipvals[SCOUT].s_warp.dec = 200; + shipvals[SCOUT].s_warp.cost = 14; + shipvals[SCOUT].s_warp.maxspeed = 19; + shipvals[SCOUT].s_warp.etemp = 9000; + shipvals[SCOUT].s_warpinitcost = 909; + shipvals[SCOUT].s_warpinittime = 30; + shipvals[SCOUT].s_warpprepspeed = 2; + } + else + { + shipvals[SCOUT].s_warp.acc = 10000; + shipvals[SCOUT].s_warp.dec = 200; + shipvals[SCOUT].s_warp.cost = 13; /* was: 14; (BG) */ + shipvals[SCOUT].s_warp.maxspeed = 32; /* was: 27; (BG) */ + shipvals[SCOUT].s_warp.etemp = 9000; + shipvals[SCOUT].s_warpinitcost = 909; + shipvals[SCOUT].s_warpinittime = 30; + shipvals[SCOUT].s_warpprepspeed = 3; + } + shipvals[SCOUT].s_mass = 1500; + shipvals[SCOUT].s_tractstr = 2000; + shipvals[SCOUT].s_tractrng = 0.7; + shipvals[SCOUT].s_tractcost = 3; + shipvals[SCOUT].s_tractetemp = 1000; + shipvals[SCOUT].s_torp.damage = 25; + shipvals[SCOUT].s_torp.speed = 16; + shipvals[SCOUT].s_torp.cost = 175; +#ifndef OLDSHIPVALS + shipvals[SCOUT].s_torp.fuse = 16; +#else + shipvals[SCOUT].s_torp.fuse = 15; +#endif + shipvals[SCOUT].s_torp.wtemp = 7; + shipvals[SCOUT].s_torp.wtemp_halfarc = 32; + shipvals[SCOUT].s_torp.wtemp_factor = 9; + shipvals[SCOUT].s_torp.aux = 0; + shipvals[SCOUT].s_phaser.damage = 75; + shipvals[SCOUT].s_phaser.speed = 4500; + shipvals[SCOUT].s_phaser.cost = 525; + shipvals[SCOUT].s_phaser.fuse = 10; +#ifndef OLDSHIPVALS + shipvals[SCOUT].s_phaser.wtemp = 52; +#else + shipvals[SCOUT].s_phaser.wtemp = 50; +#endif + shipvals[SCOUT].s_missile.damage = 0; + shipvals[SCOUT].s_missile.speed = 0; + shipvals[SCOUT].s_missile.cost = 0; + shipvals[SCOUT].s_missile.fuse = 0; + shipvals[SCOUT].s_missile.wtemp = 0; + shipvals[SCOUT].s_missile.count = 0; + shipvals[SCOUT].s_missile.aux = 0; + shipvals[SCOUT].s_missilestored = 0; + shipvals[SCOUT].s_plasma.damage = -1; + shipvals[SCOUT].s_plasma.speed = 0; + shipvals[SCOUT].s_plasma.cost = 0; + shipvals[SCOUT].s_plasma.fuse = 0; + shipvals[SCOUT].s_plasma.wtemp = 50; + shipvals[SCOUT].s_plasma.aux = 0; + shipvals[SCOUT].s_maxwpntemp = 1000; + shipvals[SCOUT].s_wpncoolrate = 3; + if (configvals->bronco_shipvals) + shipvals[SCOUT].s_maxegntemp = 1000; + else + shipvals[SCOUT].s_maxegntemp = 1500; + shipvals[SCOUT].s_egncoolrate = 8; + shipvals[SCOUT].s_maxfuel = 5000; + shipvals[SCOUT].s_recharge = 16; + shipvals[SCOUT].s_mingivefuel = 0; + shipvals[SCOUT].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[SCOUT].s_expldam = 35; /* was: 40; (BG) */ + shipvals[SCOUT].s_fueldam = 50; /* was: 45; (BG) */ + } + else + { + shipvals[SCOUT].s_expldam = 75; + shipvals[SCOUT].s_fueldam = 0; + } + shipvals[SCOUT].s_armyperkill = 2; + shipvals[SCOUT].s_maxarmies = 2; + if (configvals->bronco_shipvals) + shipvals[SCOUT].s_bomb = 10; + else + shipvals[SCOUT].s_bomb = 0; + shipvals[SCOUT].s_repair = 80; + shipvals[SCOUT].s_maxdamage = 75; + shipvals[SCOUT].s_maxshield = 75; + shipvals[SCOUT].s_shieldcost = 2; + shipvals[SCOUT].s_detcost = 100; + shipvals[SCOUT].s_detdist = 1750; + if (configvals->bronco_shipvals) + { + shipvals[SCOUT].s_cloakcost = 85; + shipvals[SCOUT].s_scanrange = -1; + } + else + { + shipvals[SCOUT].s_cloakcost = 50; +#ifdef LONG_SCANRANGE + shipvals[SCOUT].s_scanrange = 8000; +#else + shipvals[SCOUT].s_scanrange = 5000; +#endif + } + shipvals[SCOUT].s_numports = 0; + shipvals[SCOUT].s_letter = 's'; + shipvals[SCOUT].s_desig1 = 'S'; + shipvals[SCOUT].s_desig2 = 'C'; + shipvals[SCOUT].s_bitmap = 0; + shipvals[SCOUT].s_width = 20; + shipvals[SCOUT].s_height = 20; + shipvals[SCOUT].s_timer = 0; + shipvals[SCOUT].s_maxnum = 32; + shipvals[SCOUT].s_rank = 0; + shipvals[SCOUT].s_numdefn = 0; + shipvals[SCOUT].s_numplan = 0; + if (configvals->warpdrive) + shipvals[SCOUT].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNHASPHASERS; + else + shipvals[SCOUT].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNHASPHASERS; + + + /* comprehensive definition of DESTROYER */ + shipvals[DESTROYER].s_alttype = 1; + strcpy(shipvals[DESTROYER].s_name, "Destroyer"); + shipvals[DESTROYER].s_turns = 310000; + shipvals[DESTROYER].s_imp.acc = 200; + shipvals[DESTROYER].s_imp.dec = 300; + shipvals[DESTROYER].s_imp.cost = 3; + shipvals[DESTROYER].s_imp.maxspeed = 10; + shipvals[DESTROYER].s_imp.etemp = 1000; + shipvals[DESTROYER].s_after.acc = 700; + shipvals[DESTROYER].s_after.dec = 270; + shipvals[DESTROYER].s_after.cost = 100; + shipvals[DESTROYER].s_after.maxspeed = 12; + shipvals[DESTROYER].s_after.etemp = 40000; + if (configvals->bronco_shipvals) + { + shipvals[DESTROYER].s_warp.acc = 10000; + shipvals[DESTROYER].s_warp.dec = 300; + shipvals[DESTROYER].s_warp.cost = 22; + shipvals[DESTROYER].s_warp.maxspeed = 15; + shipvals[DESTROYER].s_warp.etemp = 8000; + shipvals[DESTROYER].s_warpinitcost = 1272; + shipvals[DESTROYER].s_warpinittime = 50; + shipvals[DESTROYER].s_warpprepspeed = 2; + } + else + { + shipvals[DESTROYER].s_warp.acc = 10000; + shipvals[DESTROYER].s_warp.dec = 300; + shipvals[DESTROYER].s_warp.cost = 21; /* was: 22; (BG) */ + shipvals[DESTROYER].s_warp.maxspeed = 27; /* was: 22; (BG) */ + shipvals[DESTROYER].s_warp.etemp = 8000; + shipvals[DESTROYER].s_warpinitcost = 1272; + shipvals[DESTROYER].s_warpinittime = 50; + shipvals[DESTROYER].s_warpprepspeed = 3; + } + shipvals[DESTROYER].s_mass = 1800; + shipvals[DESTROYER].s_tractstr = 2500; + shipvals[DESTROYER].s_tractrng = 0.9; + shipvals[DESTROYER].s_tractcost = 4; + shipvals[DESTROYER].s_tractetemp = 1000; + shipvals[DESTROYER].s_torp.damage = 30; + shipvals[DESTROYER].s_torp.speed = 14; + shipvals[DESTROYER].s_torp.cost = 210; + shipvals[DESTROYER].s_torp.fuse = 30; + shipvals[DESTROYER].s_torp.wtemp = 11; + shipvals[DESTROYER].s_torp.wtemp_halfarc = 32; + shipvals[DESTROYER].s_torp.wtemp_factor = 9; + shipvals[DESTROYER].s_torp.aux = 0; + shipvals[DESTROYER].s_phaser.damage = 85; + shipvals[DESTROYER].s_phaser.speed = 5100; + shipvals[DESTROYER].s_phaser.cost = 595; + shipvals[DESTROYER].s_phaser.fuse = 10; + shipvals[DESTROYER].s_phaser.wtemp = 59; + shipvals[DESTROYER].s_missile.damage = 20; + shipvals[DESTROYER].s_missile.speed = 8; + shipvals[DESTROYER].s_missile.cost = 900; + shipvals[DESTROYER].s_missile.fuse = 100; + shipvals[DESTROYER].s_missile.wtemp = 100; + shipvals[DESTROYER].s_missile.count = 2; + shipvals[DESTROYER].s_missile.aux = 2; + shipvals[DESTROYER].s_missilestored = 8; + shipvals[DESTROYER].s_plasma.damage = 75; + shipvals[DESTROYER].s_plasma.speed = 15; + shipvals[DESTROYER].s_plasma.cost = 2250; + shipvals[DESTROYER].s_plasma.fuse = 30; + shipvals[DESTROYER].s_plasma.wtemp = 217; + shipvals[DESTROYER].s_plasma.aux = 1; + shipvals[DESTROYER].s_maxwpntemp = 1000; + shipvals[DESTROYER].s_wpncoolrate = 2; + if (configvals->bronco_shipvals) + shipvals[DESTROYER].s_maxegntemp = 1000; + else + shipvals[DESTROYER].s_maxegntemp = 1500; + shipvals[DESTROYER].s_egncoolrate = 7; + shipvals[DESTROYER].s_maxfuel = 7000; + shipvals[DESTROYER].s_recharge = 22; + shipvals[DESTROYER].s_mingivefuel = 0; + shipvals[DESTROYER].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[DESTROYER].s_expldam = 65; /* was: 50; (BG) */ + shipvals[DESTROYER].s_fueldam = 45; /* was: 50; (BG) */ + } + else + { + shipvals[DESTROYER].s_expldam = 100; + shipvals[DESTROYER].s_fueldam = 0; + } + shipvals[DESTROYER].s_armyperkill = 2; +#ifndef OLDSHIPVALS + shipvals[DESTROYER].s_maxarmies = 4; +#else + shipvals[DESTROYER].s_maxarmies = 5; +#endif + if (configvals->bronco_shipvals) + shipvals[DESTROYER].s_bomb = 10; + else + shipvals[DESTROYER].s_bomb = 5; + shipvals[DESTROYER].s_repair = 100; + shipvals[DESTROYER].s_maxdamage = 85; + shipvals[DESTROYER].s_maxshield = 85; + shipvals[DESTROYER].s_shieldcost = 3; + shipvals[DESTROYER].s_detcost = 100; + shipvals[DESTROYER].s_detdist = 1750; + if (configvals->bronco_shipvals) + { + shipvals[DESTROYER].s_cloakcost = 105; + shipvals[DESTROYER].s_scanrange = -1; + } + else + { + shipvals[DESTROYER].s_cloakcost = 75; + shipvals[DESTROYER].s_scanrange = 1000; + } + shipvals[DESTROYER].s_numports = 0; + shipvals[DESTROYER].s_letter = 'd'; + shipvals[DESTROYER].s_desig1 = 'D'; + shipvals[DESTROYER].s_desig2 = 'D'; + shipvals[DESTROYER].s_bitmap = 1; + shipvals[DESTROYER].s_width = 20; + shipvals[DESTROYER].s_height = 20; + shipvals[DESTROYER].s_timer = 0; + shipvals[DESTROYER].s_maxnum = 32; + shipvals[DESTROYER].s_rank = 0; + shipvals[DESTROYER].s_numdefn = 0; + shipvals[DESTROYER].s_numplan = 0; + if (configvals->warpdrive) + shipvals[DESTROYER].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNHASPHASERS; + else + shipvals[DESTROYER].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNHASPHASERS; + + /* comprehensive definition of CRUISER */ + shipvals[CRUISER].s_alttype = 2; + strcpy(shipvals[CRUISER].s_name, "Cruiser"); + shipvals[CRUISER].s_turns = 170000; + shipvals[CRUISER].s_imp.acc = 150; + shipvals[CRUISER].s_imp.dec = 200; + shipvals[CRUISER].s_imp.cost = 4; + shipvals[CRUISER].s_imp.maxspeed = 9; + shipvals[CRUISER].s_imp.etemp = 1000; + shipvals[CRUISER].s_after.acc = 550; + shipvals[CRUISER].s_after.dec = 270; + shipvals[CRUISER].s_after.cost = 200; + shipvals[CRUISER].s_after.maxspeed = 11; + shipvals[CRUISER].s_after.etemp = 50000; + if (configvals->bronco_shipvals) + { + shipvals[CRUISER].s_warp.acc = 10000; + shipvals[CRUISER].s_warp.dec = 500; + shipvals[CRUISER].s_warp.cost = 25; + shipvals[CRUISER].s_warp.maxspeed = 13; + shipvals[CRUISER].s_warp.etemp = 7000; + shipvals[CRUISER].s_warpinitcost = 1818; + shipvals[CRUISER].s_warpinittime = 60; + shipvals[CRUISER].s_warpprepspeed = 1; + } + else + { + shipvals[CRUISER].s_warp.acc = 10000; + shipvals[CRUISER].s_warp.dec = 500; + shipvals[CRUISER].s_warp.cost = 24; /* was: 25; (BG) */ + shipvals[CRUISER].s_warp.maxspeed = 24; /* was: 19; (BG) */ + shipvals[CRUISER].s_warp.etemp = 7000; + shipvals[CRUISER].s_warpinitcost = 1818; + shipvals[CRUISER].s_warpinittime = 60; + shipvals[CRUISER].s_warpprepspeed = 2; + } + shipvals[CRUISER].s_mass = 2000; + shipvals[CRUISER].s_tractstr = 3000; + shipvals[CRUISER].s_tractrng = 1.0; + shipvals[CRUISER].s_tractcost = 4; + shipvals[CRUISER].s_tractetemp = 1000; + shipvals[CRUISER].s_torp.damage = 40; + shipvals[CRUISER].s_torp.speed = 12; + shipvals[CRUISER].s_torp.cost = 280; + shipvals[CRUISER].s_torp.fuse = 40; + shipvals[CRUISER].s_torp.wtemp = 18; + shipvals[CRUISER].s_torp.wtemp_halfarc = 32; + shipvals[CRUISER].s_torp.wtemp_factor = 9; + shipvals[CRUISER].s_torp.aux = 0; + shipvals[CRUISER].s_phaser.damage = 100; +#ifndef OLDSHIPVALS + shipvals[CRUISER].s_phaser.speed = 6000; +#else + shipvals[CRUISER].s_phaser.speed = 5500; +#endif + shipvals[CRUISER].s_phaser.cost = 700; + shipvals[CRUISER].s_phaser.fuse = 10; + shipvals[CRUISER].s_phaser.wtemp = 70; + shipvals[CRUISER].s_missile.damage = 25; + shipvals[CRUISER].s_missile.speed = 7; + shipvals[CRUISER].s_missile.cost = 900; + shipvals[CRUISER].s_missile.fuse = 100; + shipvals[CRUISER].s_missile.wtemp = 105; + shipvals[CRUISER].s_missile.count = 3; + shipvals[CRUISER].s_missile.aux = 2; + shipvals[CRUISER].s_missilestored = 10; + shipvals[CRUISER].s_plasma.damage = 100; + shipvals[CRUISER].s_plasma.speed = 15; + shipvals[CRUISER].s_plasma.cost = 3000; + shipvals[CRUISER].s_plasma.fuse = 35; + shipvals[CRUISER].s_plasma.wtemp = 292; + shipvals[CRUISER].s_plasma.aux = 1; + shipvals[CRUISER].s_maxwpntemp = 1000; + shipvals[CRUISER].s_wpncoolrate = 2; + if (configvals->bronco_shipvals) + shipvals[CRUISER].s_maxegntemp = 1000; + else + shipvals[CRUISER].s_maxegntemp = 1500; + shipvals[CRUISER].s_egncoolrate = 6; + shipvals[CRUISER].s_maxfuel = 10000; + shipvals[CRUISER].s_recharge = 24; + shipvals[CRUISER].s_mingivefuel = 0; + shipvals[CRUISER].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[CRUISER].s_expldam = 75; /* was: 50; (BG) */ + shipvals[CRUISER].s_fueldam = 40; /* was: 65; (BG) */ + } + else + { + shipvals[CRUISER].s_expldam = 100; + shipvals[CRUISER].s_fueldam = 0; + } + shipvals[CRUISER].s_armyperkill = 2; +#ifndef OLDSHIPVALS + shipvals[CRUISER].s_maxarmies = 6; +#else + shipvals[CRUISER].s_maxarmies = 10; +#endif + shipvals[CRUISER].s_bomb = 10; + shipvals[CRUISER].s_repair = 110; + shipvals[CRUISER].s_maxdamage = 100; + shipvals[CRUISER].s_maxshield = 100; + shipvals[CRUISER].s_shieldcost = 4; + shipvals[CRUISER].s_detcost = 100; + shipvals[CRUISER].s_detdist = 1750; + if (configvals->bronco_shipvals) + shipvals[CRUISER].s_cloakcost = 130; + else + shipvals[CRUISER].s_cloakcost = 100; +#ifdef LONG_SCANRANGE + shipvals[CRUISER].s_scanrange = 1000; +#else + shipvals[CRUISER].s_scanrange = -1; +#endif + shipvals[CRUISER].s_numports = 0; + shipvals[CRUISER].s_letter = 'c'; + shipvals[CRUISER].s_desig1 = 'C'; + shipvals[CRUISER].s_desig2 = 'A'; + shipvals[CRUISER].s_bitmap = 2; + shipvals[CRUISER].s_width = 20; + shipvals[CRUISER].s_height = 20; + shipvals[CRUISER].s_timer = 0; + shipvals[CRUISER].s_maxnum = 32; + shipvals[CRUISER].s_rank = 0; + shipvals[CRUISER].s_numdefn = 0; + shipvals[CRUISER].s_numplan = 0; + if (configvals->warpdrive) + shipvals[CRUISER].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNHASPHASERS; + else + shipvals[CRUISER].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNHASPHASERS; + + /* comprehensive definition of BATTLESHIP */ + shipvals[BATTLESHIP].s_alttype = 3; + strcpy(shipvals[BATTLESHIP].s_name, "Battleship"); + shipvals[BATTLESHIP].s_turns = 75000; + shipvals[BATTLESHIP].s_imp.acc = 80; + shipvals[BATTLESHIP].s_imp.dec = 180; + shipvals[BATTLESHIP].s_imp.cost = 6; + shipvals[BATTLESHIP].s_imp.maxspeed = 8; + shipvals[BATTLESHIP].s_imp.etemp = 1000; + shipvals[BATTLESHIP].s_after.acc = 500; + shipvals[BATTLESHIP].s_after.dec = 270; + shipvals[BATTLESHIP].s_after.cost = 100; + shipvals[BATTLESHIP].s_after.maxspeed = 10; + shipvals[BATTLESHIP].s_after.etemp = 50000; + if (configvals->bronco_shipvals) + { + shipvals[BATTLESHIP].s_warp.acc = 10000; + shipvals[BATTLESHIP].s_warp.dec = 500; + shipvals[BATTLESHIP].s_warp.cost = 37; + shipvals[BATTLESHIP].s_warp.maxspeed = 11; + shipvals[BATTLESHIP].s_warp.etemp = 7000; + shipvals[BATTLESHIP].s_warpinitcost = 2545; + shipvals[BATTLESHIP].s_warpinittime = 70; + shipvals[BATTLESHIP].s_warpprepspeed = 0; + } + else + { + shipvals[BATTLESHIP].s_warp.acc = 10000; + shipvals[BATTLESHIP].s_warp.dec = 500; + shipvals[BATTLESHIP].s_warp.cost = 35; /* was: 37; (BG) */ + shipvals[BATTLESHIP].s_warp.maxspeed = 21; /* was: 16; (BG) */ + shipvals[BATTLESHIP].s_warp.etemp = 7000; + shipvals[BATTLESHIP].s_warpinitcost = 2545; + shipvals[BATTLESHIP].s_warpinittime = 70; + shipvals[BATTLESHIP].s_warpprepspeed = 1; + } + shipvals[BATTLESHIP].s_mass = 2300; + shipvals[BATTLESHIP].s_tractstr = 3700; + shipvals[BATTLESHIP].s_tractrng = 1.2; + shipvals[BATTLESHIP].s_tractcost = 4; + shipvals[BATTLESHIP].s_tractetemp = 1000; + shipvals[BATTLESHIP].s_torp.damage = 40; + shipvals[BATTLESHIP].s_torp.speed = 12; + shipvals[BATTLESHIP].s_torp.cost = 300; + shipvals[BATTLESHIP].s_torp.fuse = 40; + shipvals[BATTLESHIP].s_torp.wtemp = 20; + shipvals[BATTLESHIP].s_torp.wtemp_halfarc = 32; + shipvals[BATTLESHIP].s_torp.wtemp_factor = 9; + shipvals[BATTLESHIP].s_torp.aux = 0; + shipvals[BATTLESHIP].s_phaser.damage = 105; +#ifndef OLDSHIPVALS + shipvals[BATTLESHIP].s_phaser.speed = 6300; + shipvals[BATTLESHIP].s_phaser.cost = 945; +#else + shipvals[BATTLESHIP].s_phaser.speed = 6000; + shipvals[BATTLESHIP].s_phaser.cost = 900; +#endif + shipvals[BATTLESHIP].s_phaser.fuse = 10; + shipvals[BATTLESHIP].s_phaser.wtemp = 94; + shipvals[BATTLESHIP].s_missile.damage = 30; + shipvals[BATTLESHIP].s_missile.speed = 5; + shipvals[BATTLESHIP].s_missile.cost = 900; + shipvals[BATTLESHIP].s_missile.fuse = 100; + shipvals[BATTLESHIP].s_missile.wtemp = 100; + shipvals[BATTLESHIP].s_missile.count = 4; + shipvals[BATTLESHIP].s_missile.aux = 3; + shipvals[BATTLESHIP].s_missilestored = 12; + shipvals[BATTLESHIP].s_plasma.damage = 130; + shipvals[BATTLESHIP].s_plasma.speed = 15; + shipvals[BATTLESHIP].s_plasma.cost = 3900; + shipvals[BATTLESHIP].s_plasma.fuse = 35; + shipvals[BATTLESHIP].s_plasma.wtemp = 382; + shipvals[BATTLESHIP].s_plasma.aux = 1; + shipvals[BATTLESHIP].s_maxwpntemp = 1000; + shipvals[BATTLESHIP].s_wpncoolrate = 3; + if (configvals->bronco_shipvals) + shipvals[BATTLESHIP].s_maxegntemp = 1000; + else + shipvals[BATTLESHIP].s_maxegntemp = 1500; + shipvals[BATTLESHIP].s_egncoolrate = 6; + shipvals[BATTLESHIP].s_maxfuel = 14000; + shipvals[BATTLESHIP].s_recharge = 28; + shipvals[BATTLESHIP].s_mingivefuel = 0; + shipvals[BATTLESHIP].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[BATTLESHIP].s_expldam = 85; /* was: 50; (BG) */ + shipvals[BATTLESHIP].s_fueldam = 35; /* was: 85; (BG) */ + } + else + { + shipvals[BATTLESHIP].s_expldam = 10; + shipvals[BATTLESHIP].s_fueldam = 0; + } + shipvals[BATTLESHIP].s_armyperkill = 2; + shipvals[BATTLESHIP].s_maxarmies = 6; + shipvals[BATTLESHIP].s_bomb = 20; + shipvals[BATTLESHIP].s_repair = 125; + shipvals[BATTLESHIP].s_maxdamage = 130; + shipvals[BATTLESHIP].s_maxshield = 130; + shipvals[BATTLESHIP].s_shieldcost = 5; + shipvals[BATTLESHIP].s_detcost = 100; + shipvals[BATTLESHIP].s_detdist = 1750; + shipvals[BATTLESHIP].s_cloakcost = 150; +#ifdef LONG_SCANRANGE + shipvals[BATTLESHIP].s_scanrange = 1000; +#else + shipvals[BATTLESHIP].s_scanrange = -1; +#endif + shipvals[BATTLESHIP].s_numports = 0; + shipvals[BATTLESHIP].s_letter = 'b'; + shipvals[BATTLESHIP].s_desig1 = 'B'; + shipvals[BATTLESHIP].s_desig2 = 'B'; + shipvals[BATTLESHIP].s_bitmap = 3; + shipvals[BATTLESHIP].s_width = 20; + shipvals[BATTLESHIP].s_height = 20; + shipvals[BATTLESHIP].s_timer = 0; + shipvals[BATTLESHIP].s_maxnum = 32; + shipvals[BATTLESHIP].s_rank = 0; + shipvals[BATTLESHIP].s_numdefn = 0; + shipvals[BATTLESHIP].s_numplan = 0; + shipvals[BATTLESHIP].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNHASPHASERS; + + /* comprehensive definition of ASSAULT */ + shipvals[ASSAULT].s_alttype = 4; + strcpy(shipvals[ASSAULT].s_name, "Assault"); + shipvals[ASSAULT].s_turns = 120000; + shipvals[ASSAULT].s_imp.acc = 100; + shipvals[ASSAULT].s_imp.dec = 200; + if (configvals->bronco_shipvals) + shipvals[ASSAULT].s_imp.cost = 3; + else + shipvals[ASSAULT].s_imp.cost = 4; + shipvals[ASSAULT].s_imp.maxspeed = 8; + shipvals[ASSAULT].s_imp.etemp = 1000; + shipvals[ASSAULT].s_after.acc = 550; + shipvals[ASSAULT].s_after.dec = 270; + shipvals[ASSAULT].s_after.cost = 25; + shipvals[ASSAULT].s_after.maxspeed = 10; + shipvals[ASSAULT].s_after.etemp = 50000; + if (configvals->bronco_shipvals) + { + shipvals[ASSAULT].s_warp.acc = 10000; + shipvals[ASSAULT].s_warp.dec = 5000; + shipvals[ASSAULT].s_warp.cost = 20; + shipvals[ASSAULT].s_warp.maxspeed = 12; + shipvals[ASSAULT].s_warp.etemp = 6500; + shipvals[ASSAULT].s_warpinitcost = 1000; + shipvals[ASSAULT].s_warpinittime = 80; + shipvals[ASSAULT].s_warpprepspeed = 0; + } + else + { + shipvals[ASSAULT].s_warp.acc = 10000; + shipvals[ASSAULT].s_warp.dec = 5000; + shipvals[ASSAULT].s_warp.cost = 20; + shipvals[ASSAULT].s_warp.maxspeed = 23; /* was: 18; (BG) */ + shipvals[ASSAULT].s_warp.etemp = 6500; + shipvals[ASSAULT].s_warpinitcost = 1000; + shipvals[ASSAULT].s_warpinittime = 80; + shipvals[ASSAULT].s_warpprepspeed = 1; + } + shipvals[ASSAULT].s_mass = 2300; + shipvals[ASSAULT].s_tractstr = 2500; + shipvals[ASSAULT].s_tractrng = 0.7; + shipvals[ASSAULT].s_tractcost = 3; + shipvals[ASSAULT].s_tractetemp = 1000; + shipvals[ASSAULT].s_torp.damage = 30; + shipvals[ASSAULT].s_torp.speed = 16; + shipvals[ASSAULT].s_torp.cost = 270; + shipvals[ASSAULT].s_torp.fuse = 30; + shipvals[ASSAULT].s_torp.wtemp = 17; + shipvals[ASSAULT].s_torp.wtemp_halfarc = 32; + shipvals[ASSAULT].s_torp.wtemp_factor = 9; + shipvals[ASSAULT].s_torp.aux = 0; + shipvals[ASSAULT].s_phaser.damage = 80; + shipvals[ASSAULT].s_phaser.speed = 4800; + shipvals[ASSAULT].s_phaser.cost = 560; + shipvals[ASSAULT].s_phaser.fuse = 10; + shipvals[ASSAULT].s_phaser.wtemp = 56; + shipvals[ASSAULT].s_missile.damage = 0; + shipvals[ASSAULT].s_missile.speed = 0; + shipvals[ASSAULT].s_missile.cost = 0; + shipvals[ASSAULT].s_missile.fuse = 0; + shipvals[ASSAULT].s_missile.wtemp = 0; + shipvals[ASSAULT].s_missile.count = 0; + shipvals[ASSAULT].s_missile.aux = 0; + shipvals[ASSAULT].s_missilestored = 0; + shipvals[ASSAULT].s_plasma.damage = -1; + shipvals[ASSAULT].s_plasma.speed = 0; + shipvals[ASSAULT].s_plasma.cost = 0; + shipvals[ASSAULT].s_plasma.fuse = 0; + shipvals[ASSAULT].s_plasma.wtemp = 5; + shipvals[ASSAULT].s_plasma.aux = 0; + shipvals[ASSAULT].s_maxwpntemp = 1000; + shipvals[ASSAULT].s_wpncoolrate = 2; + if (configvals->bronco_shipvals) + shipvals[ASSAULT].s_maxegntemp = 1000; + else + shipvals[ASSAULT].s_maxegntemp = 1700; + shipvals[ASSAULT].s_egncoolrate = 6; + shipvals[ASSAULT].s_maxfuel = 6000; + if (configvals->bronco_shipvals) + shipvals[ASSAULT].s_recharge = 20; + else + shipvals[ASSAULT].s_recharge = 24; + shipvals[ASSAULT].s_mingivefuel = 0; + shipvals[ASSAULT].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[ASSAULT].s_expldam = 70; /* was: 50; (BG) */ + shipvals[ASSAULT].s_fueldam = 40; /* was: 45; (BG) */ + } + else + { + shipvals[ASSAULT].s_expldam = 100; + shipvals[ASSAULT].s_fueldam = 0; + } + shipvals[ASSAULT].s_armyperkill = 3; + shipvals[ASSAULT].s_maxarmies = 20; + if (configvals->bronco_shipvals) + shipvals[ASSAULT].s_bomb = 25; + else + shipvals[ASSAULT].s_bomb = 50; + shipvals[ASSAULT].s_repair = 120; + shipvals[ASSAULT].s_maxdamage = 200; + shipvals[ASSAULT].s_maxshield = 80; + shipvals[ASSAULT].s_shieldcost = 3; + shipvals[ASSAULT].s_detcost = 100; + shipvals[ASSAULT].s_detdist = 1750; + if (configvals->bronco_shipvals) + shipvals[ASSAULT].s_cloakcost = 85; + else + shipvals[ASSAULT].s_cloakcost = 80; +#ifdef LONG_SCANRANGE + shipvals[ASSAULT].s_scanrange = 1000; +#else + shipvals[ASSAULT].s_scanrange = -1; +#endif + shipvals[ASSAULT].s_numports = 0; + shipvals[ASSAULT].s_letter = 'a'; + shipvals[ASSAULT].s_desig1 = 'A'; + shipvals[ASSAULT].s_desig2 = 'S'; + shipvals[ASSAULT].s_bitmap = 4; + shipvals[ASSAULT].s_width = 20; + shipvals[ASSAULT].s_height = 20; + shipvals[ASSAULT].s_timer = 0; + shipvals[ASSAULT].s_maxnum = 32; + shipvals[ASSAULT].s_rank = 0; + shipvals[ASSAULT].s_numdefn = 0; + shipvals[ASSAULT].s_numplan = 0; + if (configvals->warpdrive) + shipvals[ASSAULT].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNHASPHASERS; + else + shipvals[ASSAULT].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNHASPHASERS; + + /* comprehensive definition of STARBASE */ + shipvals[STARBASE].s_alttype = 5; + strcpy(shipvals[STARBASE].s_name, "Starbase"); + shipvals[STARBASE].s_turns = 50000; + shipvals[STARBASE].s_imp.acc = 100; + shipvals[STARBASE].s_imp.dec = 200; + if (configvals->bronco_shipvals) + shipvals[STARBASE].s_imp.cost = 10; + else + shipvals[STARBASE].s_imp.cost = 4; +#ifdef BEEFY_BASES + shipvals[STARBASE].s_imp.maxspeed = 3; +#else + shipvals[STARBASE].s_imp.maxspeed = 2; +#endif + shipvals[STARBASE].s_imp.etemp = 1000; + shipvals[STARBASE].s_after.acc = 100; + shipvals[STARBASE].s_after.dec = 100; + shipvals[STARBASE].s_after.cost = 40; + shipvals[STARBASE].s_after.maxspeed = 5; + shipvals[STARBASE].s_after.etemp = 30000; + if (configvals->bronco_shipvals) + { + shipvals[STARBASE].s_warp.acc = 100; + shipvals[STARBASE].s_warp.dec = 100; + shipvals[STARBASE].s_warp.cost = 20; + shipvals[STARBASE].s_warp.maxspeed = 4; + shipvals[STARBASE].s_warp.etemp = 1500; + shipvals[STARBASE].s_warpinitcost = 10909; + shipvals[STARBASE].s_warpinittime = 100; + shipvals[STARBASE].s_warpprepspeed = 1; + } + else + { + shipvals[STARBASE].s_warp.acc = 100; + shipvals[STARBASE].s_warp.dec = 100; + shipvals[STARBASE].s_warp.cost = 20; + shipvals[STARBASE].s_warp.maxspeed = 6; + shipvals[STARBASE].s_warp.etemp = 1500; + shipvals[STARBASE].s_warpinitcost = 10909; + shipvals[STARBASE].s_warpinittime = 100; + shipvals[STARBASE].s_warpprepspeed = 2; + } + shipvals[STARBASE].s_mass = 5000; + shipvals[STARBASE].s_tractstr = 8000; + shipvals[STARBASE].s_tractrng = 1.5; + shipvals[STARBASE].s_tractcost = 10; + shipvals[STARBASE].s_tractetemp = 3000; + shipvals[STARBASE].s_torp.damage = 30; + shipvals[STARBASE].s_torp.speed = 14; + shipvals[STARBASE].s_torp.cost = 300; + if (configvals->bronco_shipvals) + shipvals[STARBASE].s_torp.fuse = 30; + else + shipvals[STARBASE].s_torp.fuse = 45; + shipvals[STARBASE].s_torp.wtemp = 20; + shipvals[STARBASE].s_torp.wtemp_halfarc = 0; + shipvals[STARBASE].s_torp.wtemp_factor = 0; + shipvals[STARBASE].s_torp.aux = 0; + shipvals[STARBASE].s_phaser.damage = 120; +#ifndef OLDSHIPVALS + shipvals[STARBASE].s_phaser.speed = 7200; + shipvals[STARBASE].s_phaser.wtemp = 96; +#else + shipvals[STARBASE].s_phaser.speed = 6500; + shipvals[STARBASE].s_phaser.wtemp = 66; +#endif + shipvals[STARBASE].s_phaser.cost = 960; + shipvals[STARBASE].s_phaser.fuse = 4; + shipvals[STARBASE].s_missile.damage = 40; + shipvals[STARBASE].s_missile.speed = 14; + shipvals[STARBASE].s_missile.cost = 2000; + shipvals[STARBASE].s_missile.fuse = 100; + shipvals[STARBASE].s_missile.wtemp = 120; + shipvals[STARBASE].s_missile.count = 4; + shipvals[STARBASE].s_missile.aux = 2; + shipvals[STARBASE].s_missilestored = -1; + shipvals[STARBASE].s_plasma.damage = 150; + shipvals[STARBASE].s_plasma.speed = 15; + shipvals[STARBASE].s_plasma.cost = 3750; + if (configvals->bronco_shipvals) + shipvals[STARBASE].s_plasma.fuse = 25; + else + shipvals[STARBASE].s_plasma.fuse = 40; + shipvals[STARBASE].s_plasma.wtemp = 367; + shipvals[STARBASE].s_plasma.aux = 1; + shipvals[STARBASE].s_maxwpntemp = 1300; +#ifdef BEEFY_BASES + shipvals[STARBASE].s_wpncoolrate = 7; +#else + shipvals[STARBASE].s_wpncoolrate = 4; +#endif + if (configvals->bronco_shipvals) + shipvals[STARBASE].s_maxegntemp = 1000; + else + shipvals[STARBASE].s_maxegntemp = 1300; + shipvals[STARBASE].s_egncoolrate = 10; + shipvals[STARBASE].s_maxfuel = 60000; +#ifdef BEEFY_BASES + shipvals[STARBASE].s_recharge = 90; +#else + shipvals[STARBASE].s_recharge = 70; +#endif + shipvals[STARBASE].s_mingivefuel = 10000; + shipvals[STARBASE].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[STARBASE].s_expldam = 150; /* was: 100; (BG) */ + shipvals[STARBASE].s_fueldam = 100; + } + else + { + shipvals[STARBASE].s_expldam = 200; + shipvals[STARBASE].s_fueldam = 0; + } + shipvals[STARBASE].s_armyperkill = 5; + shipvals[STARBASE].s_maxarmies = 25; + shipvals[STARBASE].s_bomb = 50; + shipvals[STARBASE].s_repair = 170; /* was: 140; (BG) */ + shipvals[STARBASE].s_maxdamage = 600; + shipvals[STARBASE].s_maxshield = 500; + shipvals[STARBASE].s_shieldcost = 10; + shipvals[STARBASE].s_detcost = 100; + shipvals[STARBASE].s_detdist = 1800; + if (configvals->bronco_shipvals) + { + shipvals[STARBASE].s_cloakcost = 375; + shipvals[STARBASE].s_scanrange = -1; + shipvals[STARBASE].s_numports = 4; + } + else + { + shipvals[STARBASE].s_cloakcost = 750; +#ifdef LONG_SCANRANGE + shipvals[STARBASE].s_scanrange = 10000; +#else + shipvals[STARBASE].s_scanrange = 5000; +#endif + shipvals[STARBASE].s_numports = 6; + } + shipvals[STARBASE].s_letter = 'o'; + shipvals[STARBASE].s_desig1 = 'S'; + shipvals[STARBASE].s_desig2 = 'B'; + shipvals[STARBASE].s_bitmap = 5; + shipvals[STARBASE].s_width = 20; + shipvals[STARBASE].s_height = 20; + shipvals[STARBASE].s_timer = 30; + shipvals[STARBASE].s_maxnum = 1; + shipvals[STARBASE].s_rank = 4; + shipvals[STARBASE].s_numdefn = 4; + if (configvals->bronco_shipvals) + shipvals[STARBASE].s_numplan = 5; + else + shipvals[STARBASE].s_numplan = 7; + if (configvals->warpdrive) + shipvals[STARBASE].s_nflags = SFNCANWARP | SFNCANFUEL | SFNCANREPAIR | SFNCANREFIT | SFNHASPHASERS | SFNPLASMASTYLE | SFNPLASMAARMED | SFNHASMISSILE; + else + shipvals[STARBASE].s_nflags = SFNCANFUEL | SFNCANREPAIR | SFNCANREFIT | SFNHASPHASERS | SFNPLASMASTYLE | SFNPLASMAARMED | SFNHASMISSILE; + /* comprehensive definition of ATT */ + shipvals[ATT].s_alttype = 6; + strcpy(shipvals[ATT].s_name, "AT&T"); + shipvals[ATT].s_turns = 1000000; + shipvals[ATT].s_imp.acc = 10000; + shipvals[ATT].s_imp.dec = 9000; + shipvals[ATT].s_imp.cost = 1; + shipvals[ATT].s_imp.maxspeed = 90; + shipvals[ATT].s_imp.etemp = 0; + shipvals[ATT].s_after.acc = 550; + shipvals[ATT].s_after.dec = 270; + shipvals[ATT].s_after.cost = 1; + shipvals[ATT].s_after.maxspeed = 99; + shipvals[ATT].s_after.etemp = 5; + shipvals[ATT].s_warp.acc = 32000; + shipvals[ATT].s_warp.dec = 32000; + shipvals[ATT].s_warp.cost = 1; + shipvals[ATT].s_warp.maxspeed = 99; + shipvals[ATT].s_warp.etemp = 1; + shipvals[ATT].s_warpinitcost = 1; + shipvals[ATT].s_warpinittime = 1; + shipvals[ATT].s_warpprepspeed = 0; + shipvals[ATT].s_mass = 6000; + shipvals[ATT].s_tractstr = 32000; + shipvals[ATT].s_tractrng = 3; + shipvals[ATT].s_tractcost = 1; + shipvals[ATT].s_tractetemp = 3; + shipvals[ATT].s_torp.damage = 40; + shipvals[ATT].s_torp.speed = 20; + shipvals[ATT].s_torp.cost = 1; + shipvals[ATT].s_torp.fuse = 20; + shipvals[ATT].s_torp.wtemp = 1; + shipvals[ATT].s_torp.wtemp_halfarc = 0; + shipvals[ATT].s_torp.wtemp_factor = 0; + shipvals[ATT].s_torp.aux = 1; + shipvals[ATT].s_phaser.damage = 110; + shipvals[ATT].s_phaser.speed = 32000; + shipvals[ATT].s_phaser.cost = 1; + shipvals[ATT].s_phaser.fuse = 5; + shipvals[ATT].s_phaser.wtemp = 5; + shipvals[ATT].s_missile.damage = 0; + shipvals[ATT].s_missile.speed = 0; + shipvals[ATT].s_missile.cost = 0; + shipvals[ATT].s_missile.fuse = 0; + shipvals[ATT].s_missile.wtemp = 0; + shipvals[ATT].s_missile.count = 0; + shipvals[ATT].s_missile.aux = 0; + shipvals[ATT].s_missilestored = 0; + shipvals[ATT].s_plasma.damage = 150; + shipvals[ATT].s_plasma.speed = 15; + shipvals[ATT].s_plasma.cost = 1; + shipvals[ATT].s_plasma.fuse = 20; + shipvals[ATT].s_plasma.wtemp = 5; + shipvals[ATT].s_plasma.aux = 2; + shipvals[ATT].s_maxwpntemp = 10000; + shipvals[ATT].s_wpncoolrate = 100; + shipvals[ATT].s_maxegntemp = 10000; + shipvals[ATT].s_egncoolrate = 100; + shipvals[ATT].s_maxfuel = 60000; + shipvals[ATT].s_recharge = 1000; + shipvals[ATT].s_mingivefuel = 0; + shipvals[ATT].s_takeonfuel = 150; + shipvals[ATT].s_expldam = 500; + shipvals[ATT].s_fueldam = 500; + shipvals[ATT].s_armyperkill = 1.5; + shipvals[ATT].s_maxarmies = 1000; + shipvals[ATT].s_bomb = -2100; + shipvals[ATT].s_repair = 30000; + shipvals[ATT].s_maxdamage = 30000; + shipvals[ATT].s_maxshield = 30000; + shipvals[ATT].s_shieldcost = 1; + shipvals[ATT].s_detcost = 1; + shipvals[ATT].s_detdist = 3000; + shipvals[ATT].s_cloakcost = 1; + shipvals[ATT].s_scanrange = 10000; + shipvals[ATT].s_numports = 0; + shipvals[ATT].s_letter = '.'; + shipvals[ATT].s_desig1 = 'A'; + shipvals[ATT].s_desig2 = 'T'; + shipvals[ATT].s_bitmap = 6; + shipvals[ATT].s_width = 28; + shipvals[ATT].s_height = 28; + shipvals[ATT].s_timer = 5; + shipvals[ATT].s_maxnum = 32; + shipvals[ATT].s_rank = 0; + shipvals[ATT].s_numdefn = 0; + shipvals[ATT].s_numplan = 0; + shipvals[ATT].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNHASPHASERS | SFNPLASMASTYLE | SFNPLASMAARMED; + + /* comprehensive definition of JUMPSHIP */ + shipvals[JUMPSHIP].s_alttype = 5; + strcpy(shipvals[JUMPSHIP].s_name, "Jumpship"); + shipvals[JUMPSHIP].s_turns = 700000; + if (configvals->bronco_shipvals) + { + shipvals[JUMPSHIP].s_imp.acc = 1000; + shipvals[JUMPSHIP].s_imp.dec = 500; + } + else + { + shipvals[JUMPSHIP].s_imp.acc = 2000; + shipvals[JUMPSHIP].s_imp.dec = 1000; + } + shipvals[JUMPSHIP].s_imp.cost = 1; + shipvals[JUMPSHIP].s_imp.maxspeed = 20; + shipvals[JUMPSHIP].s_imp.etemp = 1000; + shipvals[JUMPSHIP].s_after.acc = 2000; + shipvals[JUMPSHIP].s_after.dec = 2000; +#ifndef OLDSHIPVALS + shipvals[JUMPSHIP].s_after.maxspeed = 30; + shipvals[JUMPSHIP].s_after.etemp = 200000; + shipvals[JUMPSHIP].s_after.cost = 1000; + shipvals[JUMPSHIP].s_warp.cost = 200; +#else + shipvals[JUMPSHIP].s_after.maxspeed = 60; + shipvals[JUMPSHIP].s_after.etemp = 90000; + shipvals[JUMPSHIP].s_after.cost = 15; + shipvals[JUMPSHIP].s_warp.cost = 2; +#endif + shipvals[JUMPSHIP].s_warp.acc = 2000; + shipvals[JUMPSHIP].s_warp.dec = 3000; + if (configvals->bronco_shipvals) + shipvals[JUMPSHIP].s_warp.maxspeed = 32; + else + shipvals[JUMPSHIP].s_warp.maxspeed = 45; + shipvals[JUMPSHIP].s_warp.etemp = 500; + shipvals[JUMPSHIP].s_warpinitcost = 1; + shipvals[JUMPSHIP].s_warpinittime = 7; + shipvals[JUMPSHIP].s_warpprepspeed = 2; + shipvals[JUMPSHIP].s_mass = 10000; + shipvals[JUMPSHIP].s_tractstr = 5000; + shipvals[JUMPSHIP].s_tractrng = 1.5; +#ifndef OLDSHIPVALS + shipvals[JUMPSHIP].s_tractcost = 8; +#else + shipvals[JUMPSHIP].s_tractcost = 3; +#endif + shipvals[JUMPSHIP].s_tractetemp = 5000; + shipvals[JUMPSHIP].s_torp.damage = 5; + shipvals[JUMPSHIP].s_torp.speed = 18; + shipvals[JUMPSHIP].s_torp.cost = 1000; + shipvals[JUMPSHIP].s_torp.fuse = 10; + shipvals[JUMPSHIP].s_torp.wtemp = 99; + shipvals[JUMPSHIP].s_torp.wtemp_halfarc = 32; + shipvals[JUMPSHIP].s_torp.wtemp_factor = 9; + shipvals[JUMPSHIP].s_torp.aux = 0; + shipvals[JUMPSHIP].s_phaser.damage = 25; + shipvals[JUMPSHIP].s_phaser.speed = 3000; + shipvals[JUMPSHIP].s_phaser.cost = 500; + shipvals[JUMPSHIP].s_phaser.fuse = 4; + shipvals[JUMPSHIP].s_phaser.wtemp = 5; + shipvals[JUMPSHIP].s_missile.damage = 0; + shipvals[JUMPSHIP].s_missile.speed = 0; + shipvals[JUMPSHIP].s_missile.cost = 0; + shipvals[JUMPSHIP].s_missile.fuse = 0; + shipvals[JUMPSHIP].s_missile.wtemp = 0; + shipvals[JUMPSHIP].s_missile.count = 0; + shipvals[JUMPSHIP].s_missile.aux = 0; + shipvals[JUMPSHIP].s_missilestored = 0; + shipvals[JUMPSHIP].s_plasma.damage = -1; + shipvals[JUMPSHIP].s_plasma.speed = 15; + shipvals[JUMPSHIP].s_plasma.cost = 0; + shipvals[JUMPSHIP].s_plasma.fuse = 25; + shipvals[JUMPSHIP].s_plasma.wtemp = 5; + shipvals[JUMPSHIP].s_plasma.aux = 1; + shipvals[JUMPSHIP].s_maxwpntemp = 1300; + shipvals[JUMPSHIP].s_wpncoolrate = 4; + shipvals[JUMPSHIP].s_maxegntemp = 5000; + shipvals[JUMPSHIP].s_egncoolrate = 34; + shipvals[JUMPSHIP].s_maxfuel = 50000; + shipvals[JUMPSHIP].s_recharge = 200; + shipvals[JUMPSHIP].s_mingivefuel = 10000; + shipvals[JUMPSHIP].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[JUMPSHIP].s_expldam = 25; /* was: 30; */ + shipvals[JUMPSHIP].s_fueldam = 175; /* was: 160; */ + } + else + { + shipvals[JUMPSHIP].s_expldam = 150; + shipvals[JUMPSHIP].s_fueldam = 0; + } + shipvals[JUMPSHIP].s_armyperkill = 0; + shipvals[JUMPSHIP].s_maxarmies = 0; + shipvals[JUMPSHIP].s_bomb = 30; + shipvals[JUMPSHIP].s_repair = 200; + shipvals[JUMPSHIP].s_maxdamage = 60; + shipvals[JUMPSHIP].s_maxshield = 5; + shipvals[JUMPSHIP].s_shieldcost = 5; + shipvals[JUMPSHIP].s_detcost = 100; + shipvals[JUMPSHIP].s_detdist = 1750; + shipvals[JUMPSHIP].s_cloakcost = 1000; + shipvals[JUMPSHIP].s_scanrange = -1; + shipvals[JUMPSHIP].s_numports = 4; + shipvals[JUMPSHIP].s_letter = 'j'; + shipvals[JUMPSHIP].s_desig1 = 'J'; + shipvals[JUMPSHIP].s_desig2 = 'S'; + shipvals[JUMPSHIP].s_bitmap = 7; + shipvals[JUMPSHIP].s_width = 20; + shipvals[JUMPSHIP].s_height = 20; + shipvals[JUMPSHIP].s_timer = 5; + shipvals[JUMPSHIP].s_maxnum = 1; + shipvals[JUMPSHIP].s_rank = 3; + shipvals[JUMPSHIP].s_numdefn = 3; + shipvals[JUMPSHIP].s_numplan = 0; + /* UFL says jumpships shouldn't refit. */ + if (configvals->warpdrive) + shipvals[JUMPSHIP].s_nflags = SFNCANWARP | SFNCANFUEL | SFNHASPHASERS | SFNCANREFIT; + else + shipvals[JUMPSHIP].s_nflags = SFNCANFUEL | SFNHASPHASERS | SFNCANREFIT; + + /* comprehensive definition of FRIGATE */ + shipvals[FRIGATE].s_alttype = 4; + strcpy(shipvals[FRIGATE].s_name, "Frigate"); + shipvals[FRIGATE].s_turns = 122500; + shipvals[FRIGATE].s_imp.acc = 115; + shipvals[FRIGATE].s_imp.dec = 190; + shipvals[FRIGATE].s_imp.cost = 5; + shipvals[FRIGATE].s_imp.maxspeed = 9; + shipvals[FRIGATE].s_imp.etemp = 1000; + shipvals[FRIGATE].s_after.acc = 525; + shipvals[FRIGATE].s_after.dec = 270; + shipvals[FRIGATE].s_after.cost = 150; + shipvals[FRIGATE].s_after.maxspeed = 10; + shipvals[FRIGATE].s_after.etemp = 50000; + shipvals[FRIGATE].s_warp.acc = 10000; + shipvals[FRIGATE].s_warp.dec = 500; + shipvals[FRIGATE].s_warp.cost = 30; + if (configvals->bronco_shipvals) + shipvals[FRIGATE].s_warp.maxspeed = 12; + else + shipvals[FRIGATE].s_warp.maxspeed = 23; + shipvals[FRIGATE].s_warp.etemp = 7000; + shipvals[FRIGATE].s_warpinitcost = 2272; + shipvals[FRIGATE].s_warpinittime = 65; + if (configvals->bronco_shipvals) + shipvals[FRIGATE].s_warpprepspeed = 1; + else + shipvals[FRIGATE].s_warpprepspeed = 2; + shipvals[FRIGATE].s_mass = 2150; + shipvals[FRIGATE].s_tractstr = 3400; + shipvals[FRIGATE].s_tractrng = 1.1; + shipvals[FRIGATE].s_tractcost = 4; + shipvals[FRIGATE].s_tractetemp = 1000; + shipvals[FRIGATE].s_torp.damage = 40; + shipvals[FRIGATE].s_torp.speed = 12; + shipvals[FRIGATE].s_torp.cost = 290; + shipvals[FRIGATE].s_torp.fuse = 40; + shipvals[FRIGATE].s_torp.wtemp = 19; + shipvals[FRIGATE].s_torp.wtemp_halfarc = 32; + shipvals[FRIGATE].s_torp.wtemp_factor = 9; + shipvals[FRIGATE].s_torp.aux = 0; +#ifndef OLDSHIPVALS + shipvals[FRIGATE].s_phaser.damage = 102; + shipvals[FRIGATE].s_phaser.speed = 6150; + shipvals[FRIGATE].s_phaser.cost = 816; +#else + shipvals[FRIGATE].s_phaser.damage = 100; + shipvals[FRIGATE].s_phaser.speed = 5750; + shipvals[FRIGATE].s_phaser.cost = 800; +#endif + shipvals[FRIGATE].s_phaser.fuse = 10; + shipvals[FRIGATE].s_phaser.wtemp = 80; + shipvals[FRIGATE].s_missile.damage = 23; + shipvals[FRIGATE].s_missile.speed = 6; + shipvals[FRIGATE].s_missile.cost = 850; + shipvals[FRIGATE].s_missile.fuse = 100; + shipvals[FRIGATE].s_missile.wtemp = 100; + shipvals[FRIGATE].s_missile.count = 3; + shipvals[FRIGATE].s_missile.aux = 2; + shipvals[FRIGATE].s_missilestored = 11; + shipvals[FRIGATE].s_plasma.damage = 115; + shipvals[FRIGATE].s_plasma.speed = 15; + shipvals[FRIGATE].s_plasma.cost = 3450; + shipvals[FRIGATE].s_plasma.fuse = 35; + shipvals[FRIGATE].s_plasma.wtemp = 337; + shipvals[FRIGATE].s_plasma.aux = 1; + shipvals[FRIGATE].s_maxwpntemp = 1000; + shipvals[FRIGATE].s_wpncoolrate = 3; + shipvals[FRIGATE].s_maxegntemp = 1500; + shipvals[FRIGATE].s_egncoolrate = 6; + shipvals[FRIGATE].s_maxfuel = 12500; + shipvals[FRIGATE].s_recharge = 26; + shipvals[FRIGATE].s_mingivefuel = 0; + shipvals[FRIGATE].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[FRIGATE].s_expldam = 77; /* was: 50; (BG) */ + shipvals[FRIGATE].s_fueldam = 40; /* was: 72; (BG) */ + } + else + { + shipvals[FRIGATE].s_expldam = 100; + shipvals[FRIGATE].s_fueldam = 0; + } + shipvals[FRIGATE].s_armyperkill = 2; +#ifndef OLDSHIPVALS + shipvals[FRIGATE].s_maxarmies = 6; +#else + shipvals[FRIGATE].s_maxarmies = 8; +#endif + shipvals[FRIGATE].s_bomb = 15; + shipvals[FRIGATE].s_repair = 118; + shipvals[FRIGATE].s_maxdamage = 115; + shipvals[FRIGATE].s_maxshield = 115; + shipvals[FRIGATE].s_shieldcost = 5; + shipvals[FRIGATE].s_detcost = 100; + shipvals[FRIGATE].s_detdist = 1750; + if (configvals->bronco_shipvals) + shipvals[FRIGATE].s_cloakcost = 140; + else + shipvals[FRIGATE].s_cloakcost = 125; +#ifdef LONG_SCANRANGE + shipvals[FRIGATE].s_scanrange = 1000; +#else + shipvals[FRIGATE].s_scanrange = -1; +#endif + shipvals[FRIGATE].s_numports = 0; + shipvals[FRIGATE].s_letter = 'f'; + shipvals[FRIGATE].s_desig1 = 'F'; + shipvals[FRIGATE].s_desig2 = 'R'; + shipvals[FRIGATE].s_bitmap = 8; + shipvals[FRIGATE].s_width = 20; + shipvals[FRIGATE].s_height = 20; + shipvals[FRIGATE].s_timer = 0; + shipvals[FRIGATE].s_maxnum = 32; + shipvals[FRIGATE].s_rank = 0; + shipvals[FRIGATE].s_numdefn = 0; + shipvals[FRIGATE].s_numplan = 0; + if (configvals->warpdrive) + shipvals[FRIGATE].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNHASPHASERS; + else + shipvals[FRIGATE].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNHASPHASERS; + + /* comprehensive definition of WARBASE */ + shipvals[WARBASE].s_alttype = 5; + strcpy(shipvals[WARBASE].s_name, "Warbase"); + shipvals[WARBASE].s_turns = 90000; + shipvals[WARBASE].s_imp.acc = 100; + shipvals[WARBASE].s_imp.dec = 200; + shipvals[WARBASE].s_imp.cost = 4; +#ifdef BEEFY_BASES + shipvals[WARBASE].s_imp.maxspeed = 3; +#else + shipvals[WARBASE].s_imp.maxspeed = 2; +#endif + shipvals[WARBASE].s_imp.etemp = 1000; + shipvals[WARBASE].s_after.acc = 250; + shipvals[WARBASE].s_after.dec = 100; + shipvals[WARBASE].s_after.cost = 40; + shipvals[WARBASE].s_after.maxspeed = 5; + shipvals[WARBASE].s_after.etemp = 30000; + shipvals[WARBASE].s_warp.acc = 80; + shipvals[WARBASE].s_warp.dec = 80; + shipvals[WARBASE].s_warp.cost = 6; + if (configvals->bronco_shipvals) + { + shipvals[WARBASE].s_warp.maxspeed = 4; + shipvals[WARBASE].s_warpprepspeed = 1; + } + else + { + shipvals[WARBASE].s_warp.maxspeed = 6; + shipvals[WARBASE].s_warpprepspeed = 2; + } + shipvals[WARBASE].s_warp.etemp = 1500; + shipvals[WARBASE].s_warpinitcost = 9090; + shipvals[WARBASE].s_warpinittime = 100; + shipvals[WARBASE].s_mass = 4000; + shipvals[WARBASE].s_tractstr = 8000; + shipvals[WARBASE].s_tractrng = 1.5; + shipvals[WARBASE].s_tractcost = 10; + shipvals[WARBASE].s_tractetemp = 3000; + shipvals[WARBASE].s_torp.damage = 45; + shipvals[WARBASE].s_torp.speed = 15; + shipvals[WARBASE].s_torp.cost = 450; +#ifndef OLDSHIPVALS + shipvals[WARBASE].s_torp.fuse = 20; +#else + shipvals[WARBASE].s_torp.fuse = 18; +#endif + shipvals[WARBASE].s_torp.wtemp = 35; + shipvals[WARBASE].s_torp.wtemp_halfarc = 32; + shipvals[WARBASE].s_torp.wtemp_factor = 9; + shipvals[WARBASE].s_torp.aux = 0; +#ifndef OLDSHIPVALS + shipvals[WARBASE].s_phaser.damage = 125; + shipvals[WARBASE].s_phaser.speed = 7500; + shipvals[WARBASE].s_phaser.cost = 1000; +#else + shipvals[WARBASE].s_phaser.damage = 135; + shipvals[WARBASE].s_phaser.speed = 6000; + shipvals[WARBASE].s_phaser.cost = 1150; +#endif + shipvals[WARBASE].s_phaser.fuse = 5; + shipvals[WARBASE].s_phaser.wtemp = 90; + shipvals[WARBASE].s_missile.damage = 40; + shipvals[WARBASE].s_missile.speed = 14; + shipvals[WARBASE].s_missile.cost = 2000; + shipvals[WARBASE].s_missile.fuse = 100; + shipvals[WARBASE].s_missile.wtemp = 120; + shipvals[WARBASE].s_missile.count = 3; + shipvals[WARBASE].s_missile.aux = 2; + shipvals[WARBASE].s_missilestored = -1; + shipvals[WARBASE].s_plasma.damage = 150; + shipvals[WARBASE].s_plasma.speed = 15; + shipvals[WARBASE].s_plasma.cost = 3750; + shipvals[WARBASE].s_plasma.fuse = 40; + shipvals[WARBASE].s_plasma.wtemp = 360; + shipvals[WARBASE].s_plasma.aux = 1; + shipvals[WARBASE].s_maxwpntemp = 1500; + shipvals[WARBASE].s_wpncoolrate = 5; + shipvals[WARBASE].s_maxegntemp = 1000; + shipvals[WARBASE].s_egncoolrate = 10; + shipvals[WARBASE].s_maxfuel = 50000; + if (configvals->bronco_shipvals) + shipvals[WARBASE].s_recharge = 70; + else + shipvals[WARBASE].s_recharge = 80; + shipvals[WARBASE].s_mingivefuel = 10000; + shipvals[WARBASE].s_takeonfuel = 150; + shipvals[WARBASE].s_expldam = 100; + shipvals[WARBASE].s_fueldam = 100; + shipvals[WARBASE].s_armyperkill = 0; + shipvals[WARBASE].s_maxarmies = 0; + shipvals[WARBASE].s_bomb = 90; + shipvals[WARBASE].s_repair = 170; /* was: 150; (BG) */ + shipvals[WARBASE].s_maxdamage = 500; + shipvals[WARBASE].s_maxshield = 250; + shipvals[WARBASE].s_shieldcost = 10; + shipvals[WARBASE].s_detcost = 100; + shipvals[WARBASE].s_detdist = 1800; + shipvals[WARBASE].s_cloakcost = 1000; + shipvals[WARBASE].s_scanrange = 5000; + shipvals[WARBASE].s_numports = 2; + shipvals[WARBASE].s_letter = 'w'; + shipvals[WARBASE].s_desig1 = 'W'; + shipvals[WARBASE].s_desig2 = 'B'; + shipvals[WARBASE].s_bitmap = 9; + shipvals[WARBASE].s_width = 20; + shipvals[WARBASE].s_height = 20; + shipvals[WARBASE].s_timer = 15; + shipvals[WARBASE].s_maxnum = 1; + shipvals[WARBASE].s_rank = 3; + shipvals[WARBASE].s_numdefn = 3; + shipvals[WARBASE].s_numplan = 3; + if (configvals->warpdrive) + shipvals[WARBASE].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNCANFUEL | SFNCANREPAIR | SFNHASPHASERS | SFNPLASMASTYLE | SFNPLASMAARMED | SFNHASMISSILE; + else + shipvals[WARBASE].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANFUEL | SFNCANREPAIR | SFNHASPHASERS | SFNPLASMASTYLE | SFNPLASMAARMED | SFNHASMISSILE; + + /* comprehensive definition of LIGHTCRUISER */ + shipvals[LIGHTCRUISER].s_alttype = 2; + strcpy(shipvals[LIGHTCRUISER].s_name, "Light"); + shipvals[LIGHTCRUISER].s_turns = 220000; /* was 225000 */ + shipvals[LIGHTCRUISER].s_imp.acc = 190; + shipvals[LIGHTCRUISER].s_imp.dec = 250; + shipvals[LIGHTCRUISER].s_imp.cost = 3; + shipvals[LIGHTCRUISER].s_imp.maxspeed = 10; + shipvals[LIGHTCRUISER].s_imp.etemp = 1000; + shipvals[LIGHTCRUISER].s_after.acc = 720; + shipvals[LIGHTCRUISER].s_after.dec = 280; + shipvals[LIGHTCRUISER].s_after.cost = 80; + shipvals[LIGHTCRUISER].s_after.maxspeed = 12; + shipvals[LIGHTCRUISER].s_after.etemp = 35000; + shipvals[LIGHTCRUISER].s_warp.acc = 10000; + shipvals[LIGHTCRUISER].s_warp.dec = 400; + shipvals[LIGHTCRUISER].s_warp.cost = 24; + if (configvals->bronco_shipvals) + { + shipvals[LIGHTCRUISER].s_warp.maxspeed = 16; + shipvals[LIGHTCRUISER].s_warpprepspeed = 1; + } + else + { + shipvals[LIGHTCRUISER].s_warp.maxspeed = 27; /* was: 24; (BG) */ + shipvals[LIGHTCRUISER].s_warpprepspeed = 2; + } + shipvals[LIGHTCRUISER].s_warp.etemp = 7000; + shipvals[LIGHTCRUISER].s_warpinitcost = 1550; + shipvals[LIGHTCRUISER].s_warpinittime = 45; + shipvals[LIGHTCRUISER].s_mass = 1900; + shipvals[LIGHTCRUISER].s_tractstr = 2700; + shipvals[LIGHTCRUISER].s_tractrng = 0.9; + shipvals[LIGHTCRUISER].s_tractcost = 3; + shipvals[LIGHTCRUISER].s_tractetemp = 1000; + shipvals[LIGHTCRUISER].s_torp.damage = 35; + shipvals[LIGHTCRUISER].s_torp.speed = 13; +#ifndef OLDSHIPVALS + shipvals[LIGHTCRUISER].s_torp.cost = 245; +#else + shipvals[LIGHTCRUISER].s_torp.cost = 240; +#endif + shipvals[LIGHTCRUISER].s_torp.fuse = 35; + shipvals[LIGHTCRUISER].s_torp.wtemp = 16; + shipvals[LIGHTCRUISER].s_torp.wtemp_halfarc = 32; + shipvals[LIGHTCRUISER].s_torp.wtemp_factor = 9; + shipvals[LIGHTCRUISER].s_torp.aux = 0; + shipvals[LIGHTCRUISER].s_phaser.damage = 90; +#ifndef OLDSHIPVALS + shipvals[LIGHTCRUISER].s_phaser.speed = 5400; + shipvals[LIGHTCRUISER].s_phaser.cost = 630; +#else + shipvals[LIGHTCRUISER].s_phaser.speed = 5000; + shipvals[LIGHTCRUISER].s_phaser.cost = 600; +#endif + shipvals[LIGHTCRUISER].s_phaser.fuse = 10; + shipvals[LIGHTCRUISER].s_phaser.wtemp = 60; + shipvals[LIGHTCRUISER].s_missile.damage = 22; + shipvals[LIGHTCRUISER].s_missile.speed = 7; + shipvals[LIGHTCRUISER].s_missile.cost = 800; + shipvals[LIGHTCRUISER].s_missile.fuse = 100; + shipvals[LIGHTCRUISER].s_missile.wtemp = 100; + shipvals[LIGHTCRUISER].s_missile.count = 3; + shipvals[LIGHTCRUISER].s_missile.aux = 2; + shipvals[LIGHTCRUISER].s_missilestored = 9; + shipvals[LIGHTCRUISER].s_plasma.damage = 90; + shipvals[LIGHTCRUISER].s_plasma.speed = 15; + shipvals[LIGHTCRUISER].s_plasma.cost = 2500; + shipvals[LIGHTCRUISER].s_plasma.fuse = 30; + shipvals[LIGHTCRUISER].s_plasma.wtemp = 242; + shipvals[LIGHTCRUISER].s_plasma.aux = 1; + shipvals[LIGHTCRUISER].s_maxwpntemp = 1000; + shipvals[LIGHTCRUISER].s_wpncoolrate = 3; + shipvals[LIGHTCRUISER].s_maxegntemp = 1500; + shipvals[LIGHTCRUISER].s_egncoolrate = 6; + shipvals[LIGHTCRUISER].s_maxfuel = 8500; + shipvals[LIGHTCRUISER].s_recharge = 23; + shipvals[LIGHTCRUISER].s_mingivefuel = 0; + shipvals[LIGHTCRUISER].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[LIGHTCRUISER].s_expldam = 67; /* was: 50; (BG) */ + shipvals[LIGHTCRUISER].s_fueldam = 45; /* was: 58; (BG) */ + } + else + { + shipvals[LIGHTCRUISER].s_expldam = 100; + shipvals[LIGHTCRUISER].s_fueldam = 0; + } + shipvals[LIGHTCRUISER].s_armyperkill = 2; + shipvals[LIGHTCRUISER].s_maxarmies = 3; /* was 4 */ + shipvals[LIGHTCRUISER].s_bomb = 6; + shipvals[LIGHTCRUISER].s_repair = 80; /* was 90 */ + shipvals[LIGHTCRUISER].s_maxdamage = 90; + shipvals[LIGHTCRUISER].s_maxshield = 95; + shipvals[LIGHTCRUISER].s_shieldcost = 4; + shipvals[LIGHTCRUISER].s_detcost = 100; + shipvals[LIGHTCRUISER].s_detdist = 1750; + if (configvals->bronco_shipvals) + shipvals[LIGHTCRUISER].s_cloakcost = 115; + else + shipvals[LIGHTCRUISER].s_cloakcost = 75; +#ifdef LONG_SCANRANGE + shipvals[LIGHTCRUISER].s_scanrange = 1000; +#else + shipvals[LIGHTCRUISER].s_scanrange = 500; +#endif + shipvals[LIGHTCRUISER].s_numports = 0; + shipvals[LIGHTCRUISER].s_letter = 'l'; + shipvals[LIGHTCRUISER].s_desig1 = 'C'; + shipvals[LIGHTCRUISER].s_desig2 = 'L'; + shipvals[LIGHTCRUISER].s_bitmap = 10; + shipvals[LIGHTCRUISER].s_width = 20; + shipvals[LIGHTCRUISER].s_height = 20; + shipvals[LIGHTCRUISER].s_timer = 0; + shipvals[LIGHTCRUISER].s_maxnum = 32; + shipvals[LIGHTCRUISER].s_rank = 0; + shipvals[LIGHTCRUISER].s_numdefn = 0; + shipvals[LIGHTCRUISER].s_numplan = 0; + if (configvals->warpdrive) + shipvals[LIGHTCRUISER].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNCANWARP | SFNHASPHASERS; + else + shipvals[LIGHTCRUISER].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNHASPHASERS; + + /* comprehensive definition of CARRIER */ + shipvals[CARRIER].s_alttype = 3; + strcpy(shipvals[CARRIER].s_name, "Carrier"); + shipvals[CARRIER].s_turns = 60000; + shipvals[CARRIER].s_imp.acc = 100; + shipvals[CARRIER].s_imp.dec = 200; + shipvals[CARRIER].s_imp.cost = 4; + shipvals[CARRIER].s_imp.maxspeed = 9; + shipvals[CARRIER].s_imp.etemp = 1000; + shipvals[CARRIER].s_after.acc = 500; + shipvals[CARRIER].s_after.dec = 250; + shipvals[CARRIER].s_after.cost = 100; + shipvals[CARRIER].s_after.maxspeed = 11; + shipvals[CARRIER].s_after.etemp = 50000; + shipvals[CARRIER].s_warp.acc = 10000; + shipvals[CARRIER].s_warp.dec = 300; + shipvals[CARRIER].s_warp.cost = 28; + if (configvals->bronco_shipvals) + { + shipvals[CARRIER].s_warp.maxspeed = 14; + shipvals[CARRIER].s_warpprepspeed = 0; + } + else + { + shipvals[CARRIER].s_warp.maxspeed = 25; /* was: 20; (BG) */ + shipvals[CARRIER].s_warpprepspeed = 1; + } + shipvals[CARRIER].s_warp.etemp = 7000; + shipvals[CARRIER].s_warpinitcost = 2800; + shipvals[CARRIER].s_warpinittime = 75; + shipvals[CARRIER].s_mass = 2500; + shipvals[CARRIER].s_tractstr = 4000; /* was 3200 (MDM) */ + shipvals[CARRIER].s_tractrng = 1.3; /* was 1.1 (MDM) */ + shipvals[CARRIER].s_tractcost = 5; + shipvals[CARRIER].s_tractetemp = 1000; + shipvals[CARRIER].s_torp.damage = 30; /* these are the CVs own torps */ + shipvals[CARRIER].s_torp.speed = 13; /* fighter-torps are now constant */ + shipvals[CARRIER].s_torp.cost = 210; /* still used when fighters fire! */ + shipvals[CARRIER].s_torp.fuse = 35; + shipvals[CARRIER].s_torp.wtemp = 20; /* still used when fighters fire! */ + shipvals[CARRIER].s_torp.wtemp_halfarc = 32; + shipvals[CARRIER].s_torp.wtemp_factor = 9; + shipvals[CARRIER].s_torp.aux = 0; + shipvals[CARRIER].s_phaser.damage = 95; + shipvals[CARRIER].s_phaser.speed = 6500; + shipvals[CARRIER].s_phaser.cost = 570; + shipvals[CARRIER].s_phaser.fuse = 6; + shipvals[CARRIER].s_phaser.wtemp = 45; + shipvals[CARRIER].s_missile.damage = 20; + shipvals[CARRIER].s_missile.speed = 14; + shipvals[CARRIER].s_missile.cost = 380; /* no longer includes + * torpcost */ + shipvals[CARRIER].s_missile.fuse = 300; + shipvals[CARRIER].s_missile.wtemp = 35; /* no longer includes torp + * wtemp */ + shipvals[CARRIER].s_missile.count = 8; + shipvals[CARRIER].s_missile.aux = 3; + shipvals[CARRIER].s_missilestored = 0; + shipvals[CARRIER].s_plasma.damage = 80; + shipvals[CARRIER].s_plasma.speed = 15; + shipvals[CARRIER].s_plasma.cost = 3000; + shipvals[CARRIER].s_plasma.fuse = 35; + shipvals[CARRIER].s_plasma.wtemp = 270; + shipvals[CARRIER].s_plasma.aux = 2; + shipvals[CARRIER].s_maxwpntemp = 1000; + shipvals[CARRIER].s_wpncoolrate = 2; + shipvals[CARRIER].s_maxegntemp = 1500; + shipvals[CARRIER].s_egncoolrate = 5; + shipvals[CARRIER].s_maxfuel = 15000; + shipvals[CARRIER].s_recharge = 25; + shipvals[CARRIER].s_mingivefuel = 0; + shipvals[CARRIER].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[CARRIER].s_expldam = 80; /* was: 55; (BG) */ + shipvals[CARRIER].s_fueldam = 70; /* was: 80; (BG) */ + } + else + { + shipvals[CARRIER].s_expldam = 100; + shipvals[CARRIER].s_fueldam = 0; + } + shipvals[CARRIER].s_armyperkill = 25; + shipvals[CARRIER].s_maxarmies = 3; + shipvals[CARRIER].s_bomb = 20; + shipvals[CARRIER].s_repair = 105; + shipvals[CARRIER].s_maxdamage = 150; + shipvals[CARRIER].s_maxshield = 120; + shipvals[CARRIER].s_shieldcost = 5; + shipvals[CARRIER].s_detcost = 50; + shipvals[CARRIER].s_detdist = 1900; + if (configvals->bronco_shipvals) + shipvals[CARRIER].s_cloakcost = 135; + else + shipvals[CARRIER].s_cloakcost = 100; +#ifdef LONG_SCANRANGE + shipvals[CARRIER].s_scanrange = 1000; +#else + shipvals[CARRIER].s_scanrange = -1; +#endif + shipvals[CARRIER].s_numports = 0; + shipvals[CARRIER].s_letter = 'v'; + shipvals[CARRIER].s_desig1 = 'C'; + shipvals[CARRIER].s_desig2 = 'V'; + shipvals[CARRIER].s_bitmap = 11; + shipvals[CARRIER].s_width = 20; + shipvals[CARRIER].s_height = 20; + shipvals[CARRIER].s_timer = 12; + shipvals[CARRIER].s_maxnum = 1; + shipvals[CARRIER].s_rank = 3; + shipvals[CARRIER].s_numdefn = 5; + shipvals[CARRIER].s_numplan = 3; + if (configvals->warpdrive) + shipvals[CARRIER].s_nflags = SFNCANWARP | SFNHASPHASERS | SFNHASMISSILE | SFNHASFIGHTERS; + else + shipvals[CARRIER].s_nflags = SFNHASPHASERS | SFNHASMISSILE | SFNHASFIGHTERS; + + /* comprehensive definition of UTILITY */ + shipvals[UTILITY].s_alttype = 4; + strcpy(shipvals[UTILITY].s_name, "Utility"); + shipvals[UTILITY].s_turns = 80000; + shipvals[UTILITY].s_imp.acc = 100; + shipvals[UTILITY].s_imp.dec = 200; + shipvals[UTILITY].s_imp.cost = 4; + shipvals[UTILITY].s_imp.maxspeed = 7; + shipvals[UTILITY].s_imp.etemp = 1000; + shipvals[UTILITY].s_after.acc = 500; + shipvals[UTILITY].s_after.dec = 250; + shipvals[UTILITY].s_after.cost = 40; + shipvals[UTILITY].s_after.maxspeed = 8; + shipvals[UTILITY].s_after.etemp = 40000; + shipvals[UTILITY].s_warp.acc = 10000; + shipvals[UTILITY].s_warp.dec = 5000; + shipvals[UTILITY].s_warp.cost = 20; + if (configvals->bronco_shipvals) + { + shipvals[UTILITY].s_warp.maxspeed = 10; + shipvals[UTILITY].s_warpprepspeed = 0; + } + else + { + shipvals[UTILITY].s_warp.maxspeed = 20; /* was: 15; (BG) */ + shipvals[UTILITY].s_warpprepspeed = 1; + } + shipvals[UTILITY].s_warp.etemp = 5500; + shipvals[UTILITY].s_warpinitcost = 1200; + shipvals[UTILITY].s_warpinittime = 50; + shipvals[UTILITY].s_mass = 2400; + shipvals[UTILITY].s_tractstr = 3500; + shipvals[UTILITY].s_tractrng = 1.1; + shipvals[UTILITY].s_tractcost = 4; + shipvals[UTILITY].s_tractetemp = 1000; + shipvals[UTILITY].s_torp.damage = 20; + shipvals[UTILITY].s_torp.speed = 15; + shipvals[UTILITY].s_torp.cost = 250; + shipvals[UTILITY].s_torp.fuse = 25; + shipvals[UTILITY].s_torp.wtemp = 18; + shipvals[UTILITY].s_torp.wtemp_halfarc = 16; + shipvals[UTILITY].s_torp.wtemp_factor = 4; + shipvals[UTILITY].s_torp.aux = 0; + shipvals[UTILITY].s_phaser.damage = 80; + shipvals[UTILITY].s_phaser.speed = 5600; + shipvals[UTILITY].s_phaser.cost = 640; + shipvals[UTILITY].s_phaser.fuse = 8; + shipvals[UTILITY].s_phaser.wtemp = 85; + shipvals[UTILITY].s_missile.damage = 30; + shipvals[UTILITY].s_missile.speed = 8; + shipvals[UTILITY].s_missile.cost = 800; + shipvals[UTILITY].s_missile.fuse = 80; + shipvals[UTILITY].s_missile.wtemp = 60; + shipvals[UTILITY].s_missile.count = 3; + shipvals[UTILITY].s_missile.aux = 2; + shipvals[UTILITY].s_missilestored = 18; + shipvals[UTILITY].s_plasma.damage = -1; + shipvals[UTILITY].s_plasma.speed = 0; + shipvals[UTILITY].s_plasma.cost = 0; + shipvals[UTILITY].s_plasma.fuse = 0; + shipvals[UTILITY].s_plasma.wtemp = 0; + shipvals[UTILITY].s_plasma.aux = 0; + shipvals[UTILITY].s_maxwpntemp = 1000; + shipvals[UTILITY].s_wpncoolrate = 2; + shipvals[UTILITY].s_maxegntemp = 1800; + shipvals[UTILITY].s_egncoolrate = 5; + shipvals[UTILITY].s_maxfuel = 16000; + shipvals[UTILITY].s_recharge = 38; + shipvals[UTILITY].s_mingivefuel = 4000; + shipvals[UTILITY].s_takeonfuel = 150; + if (configvals->fuel_explosions) + { + shipvals[UTILITY].s_expldam = 60; + shipvals[UTILITY].s_fueldam = 80; + } + else + { + shipvals[UTILITY].s_expldam = 100; + shipvals[UTILITY].s_fueldam = 0; + } + shipvals[UTILITY].s_armyperkill = 12; + shipvals[UTILITY].s_maxarmies = 12; + shipvals[UTILITY].s_bomb = 0; + shipvals[UTILITY].s_repair = 120; + shipvals[UTILITY].s_maxdamage = 220; + shipvals[UTILITY].s_maxshield = 120; + shipvals[UTILITY].s_shieldcost = 4; + shipvals[UTILITY].s_detcost = 50; + shipvals[UTILITY].s_detdist = 1900; + if (configvals->bronco_shipvals) + shipvals[UTILITY].s_cloakcost = 180; + else + shipvals[UTILITY].s_cloakcost = 130; /* was 90 (MDM) */ + shipvals[UTILITY].s_scanrange = 2000; + shipvals[UTILITY].s_numports = 2; + shipvals[UTILITY].s_letter = 'u'; + shipvals[UTILITY].s_desig1 = 'U'; + shipvals[UTILITY].s_desig2 = 'T'; + shipvals[UTILITY].s_bitmap = 12; + shipvals[UTILITY].s_width = 20; + shipvals[UTILITY].s_height = 20; + shipvals[UTILITY].s_timer = 7; + shipvals[UTILITY].s_maxnum = 1; + shipvals[UTILITY].s_rank = 2; + shipvals[UTILITY].s_numdefn = 2; + shipvals[UTILITY].s_numplan = 1; + if (configvals->warpdrive) + shipvals[UTILITY].s_nflags = SFNCANWARP | SFNHASPHASERS | SFNCANREPAIR | SFNCANFUEL; + else + shipvals[UTILITY].s_nflags = SFNHASPHASERS | SFNCANREPAIR | SFNCANFUEL; + + /* Comprehensive definition of Gunboat */ + shipvals[PATROL].s_alttype = 0; + strcpy(shipvals[PATROL].s_name, "Patrol Ship"); + shipvals[PATROL].s_turns = 1500000; + shipvals[PATROL].s_imp.acc = 350; + shipvals[PATROL].s_imp.dec = 400; + shipvals[PATROL].s_imp.cost = 1; + shipvals[PATROL].s_imp.maxspeed = 13; + shipvals[PATROL].s_imp.etemp = 1000; + shipvals[PATROL].s_after.acc = 800; + shipvals[PATROL].s_after.dec = 350; + shipvals[PATROL].s_after.cost = 18; + shipvals[PATROL].s_after.maxspeed = 15; + shipvals[PATROL].s_after.etemp = 30000; + shipvals[PATROL].s_warp.acc = 10000; + shipvals[PATROL].s_warp.dec = 500; + if (configvals->bronco_shipvals) + { + shipvals[PATROL].s_warp.maxspeed = 21; + shipvals[PATROL].s_warpprepspeed = 2; + } + else + { + shipvals[PATROL].s_warp.maxspeed = 35; /* was: 30; (BG) */ + shipvals[PATROL].s_warpprepspeed = 3; + } + shipvals[PATROL].s_warp.cost = 22; + shipvals[PATROL].s_warp.etemp = 35000; + shipvals[PATROL].s_warpinitcost = 800; + shipvals[PATROL].s_warpinittime = 20; + shipvals[PATROL].s_mass = 1000; + shipvals[PATROL].s_tractstr = 1500; + shipvals[PATROL].s_tractrng = 0.75; + shipvals[PATROL].s_tractcost = 2; + shipvals[PATROL].s_tractetemp = 1000; + shipvals[PATROL].s_torp.damage = 30; + shipvals[PATROL].s_torp.speed = 15; + shipvals[PATROL].s_torp.cost = 180; + shipvals[PATROL].s_torp.fuse = 18; + shipvals[PATROL].s_torp.wtemp = 10; + shipvals[PATROL].s_torp.wtemp_halfarc = 32; + shipvals[PATROL].s_torp.wtemp_factor = 9; + shipvals[PATROL].s_torp.aux = 0; + shipvals[PATROL].s_phaser.damage = 50; + shipvals[PATROL].s_phaser.speed = 5000; + shipvals[PATROL].s_phaser.cost = 300; + shipvals[PATROL].s_phaser.fuse = 8; + shipvals[PATROL].s_phaser.wtemp = 45; + shipvals[PATROL].s_missile.damage = 50; + shipvals[PATROL].s_missile.speed = 17; + shipvals[PATROL].s_missile.cost = 450; + shipvals[PATROL].s_missile.fuse = 50; + shipvals[PATROL].s_missile.wtemp = 50; + shipvals[PATROL].s_missile.count = 6; + shipvals[PATROL].s_missile.aux = 1; + shipvals[PATROL].s_missilestored = 6; + shipvals[PATROL].s_plasma.damage = -1; + shipvals[PATROL].s_plasma.speed = 0; + shipvals[PATROL].s_plasma.cost = 0; + shipvals[PATROL].s_plasma.fuse = 0; + shipvals[PATROL].s_plasma.wtemp = 0; + shipvals[PATROL].s_plasma.aux = 0; + shipvals[PATROL].s_maxwpntemp = 1000; + shipvals[PATROL].s_wpncoolrate = 3; + shipvals[PATROL].s_maxegntemp = 1500; + shipvals[PATROL].s_egncoolrate = 8; + shipvals[PATROL].s_maxfuel = 4000; + shipvals[PATROL].s_recharge = 10; + shipvals[PATROL].s_mingivefuel = 0; + shipvals[PATROL].s_takeonfuel = 120; + if (configvals->fuel_explosions) + { + shipvals[PATROL].s_expldam = 35; + shipvals[PATROL].s_fueldam = 30; + } + else + { + shipvals[PATROL].s_expldam = 60; + shipvals[PATROL].s_fueldam = 0; + } + shipvals[PATROL].s_armyperkill = 1; + shipvals[PATROL].s_maxarmies = 1; + shipvals[PATROL].s_bomb = 0; + shipvals[PATROL].s_repair = 50; + shipvals[PATROL].s_maxdamage = 40; + shipvals[PATROL].s_maxshield = 50; + shipvals[PATROL].s_shieldcost = 2; + shipvals[PATROL].s_detcost = 100; + shipvals[PATROL].s_detdist = 1750; + if (configvals->bronco_shipvals) + shipvals[PATROL].s_cloakcost = 40; + else + shipvals[PATROL].s_cloakcost = 30; + shipvals[PATROL].s_scanrange = -1; + shipvals[PATROL].s_numports = 0; + shipvals[PATROL].s_letter = 'p'; + shipvals[PATROL].s_desig1 = 'P'; + shipvals[PATROL].s_desig2 = 'T'; + shipvals[PATROL].s_bitmap = 13; + shipvals[PATROL].s_width = 20; + shipvals[PATROL].s_height = 20; + shipvals[PATROL].s_timer = 0; + shipvals[PATROL].s_maxnum = 32; + shipvals[PATROL].s_rank = 0; + shipvals[PATROL].s_numdefn = 0; + shipvals[PATROL].s_numplan = 0; /* 1; was 1 but everybody bitched + * (BG) */ + if (configvals->warpdrive) + shipvals[PATROL].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNHASPHASERS | SFNHASMISSILE | SFNMASSPRODUCED | SFNCANWARP; + else + shipvals[PATROL].s_nflags = SFNCANORBIT | SFNARMYNEEDKILL | SFNHASPHASERS | SFNHASMISSILE | SFNMASSPRODUCED; +} + +/*----------END OF FILE-----*/ diff -r 054275999194 -r 8c6d5731234d src/shmem.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shmem.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,286 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "shmem.h" +#include "path.h" +#include "data.h" + +/*---------------------------SHARED MEMORY STRUCTURE----------------------*/ + +#include "shmemP.h" + +/*-------------------------------------------------------------------------*/ + +struct player *players; +struct torp *torps; +struct missile *missiles; +struct thingy *thingies; +struct plasmatorp *plasmatorps; +struct status *status; +struct status2 *status2; +struct planet *planets; +struct t_unit *terrain_grid; +struct phaser *phasers; +int *stars; +struct mctl *mctl; +struct message *messages; +struct team *teams; + +struct ship *shipvals; +struct configuration *configvals; +int *shipsallowed; /* points inside configvals */ +int *weaponsallowed; /* ditto */ +int *sun_effect; +int *ast_effect; +int *neb_effect; +int *wh_effect; +int *num_nebula; +int *nebula_density; +int *nebula_subclouds; +int *num_asteroid; +float *asteroid_thickness; +int *asteroid_density; +int *asteroid_radius; +float *asteroid_thick_variance; +int *asteroid_dens_variance; +int *asteroid_rad_variance; +int *improved_tracking; +int *tstart; +int *newgalaxy; +int *nontteamlock; +char *cluephrase_storage; + +static int PKEY = 128; + +/*------------------------------STARTDAEMON---------------------------------*/ +/* + * This function starts the daemon. It get the path to where the daemon + * resides, then tries to start it up. + */ + + +#ifndef SYSV /* HP/UX hates this */ +extern int fprintf(); +#endif +extern pid_t fork(); +extern int execl(); +extern void perror(); +extern int shmget(); +#ifndef IRIX +extern int shmctl(); +#endif +extern unsigned int sleep(); +extern uid_t geteuid(); + +void +startdaemon(leagueflag, restart) + int leagueflag, restart; +{ + int i; /* temp var */ + char *hell; /* to hold path to daemon */ + + if (restart) + { + fprintf(stderr, "RE-"); + kill(status->nukegame, SIGKILL); /* daemon is killed without giving it + * a chance to blast the shmem */ + sleep(2); + } + fprintf(stderr, "Starting daemon...\n"); /* record that deaemon is */ + i = fork(); /* starting */ + if (i == 0) + { /* if successful */ + char *nargv[10]; + int argc = 0; + hell = build_path(DAEMON); + nargv[argc++] = "daemon"; + if (leagueflag) + nargv[argc++] = "-l"; + if (restart) + nargv[argc++] = "-a"; + nargv[argc] = 0; + execv(hell, nargv); + + perror(hell); /* did it work */ + fprintf(stderr, "Couldn't start daemon!!!\n"); + _exit(1); /* let's get out of here */ + } +} + + + +static int shmid = -1; /* ID number of shared mem */ + + +/*--------------------------------OPENMEM----------------------------------*/ +/* + * if code is 0, openmem will exit(1) upon finding the memory gone. if code + * is 1, openmem will fork a netrek daemon and retry. if code is 2, openmem + * will blast any already existing shared memory. + */ + +void +openmem(code, leagueflag) + int code; + int leagueflag; /* only used if code==1 */ +{ + extern int errno; /* to get error number */ + key_t shmemKey = PKEY; /* shared memory's key */ + struct memory *sharedMemory; /* to point to shared memory */ + char *k; + + k = getenv("TREKSHMKEY"); /* grab shared mem id environment variable */ + if (k) + { /* if it's set... */ + int i; + if (sscanf(k, "%d", &i) > 0 && i > 0) /* ...grab its value... */ + shmemKey = i; /* ...and use it */ + } + + errno = 0; /* clear error number */ + shmid = shmget(shmemKey, 0, 0); /* get id of shared mem */ + if (code == 2) + { + if (shmid >= 0) + { + /* If we're in daemon mode and we opened the memory */ + /* "There can be only one". */ + fprintf(stderr, "Killing existing segment\n"); + shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0); + /* create a new one */ + } + shmid = shmget(shmemKey, sizeof(struct memory), IPC_CREAT | 0666); + } + if (shmid < 0) + { /* if shared mem does not exist */ + switch (code) + { + case 0: + if (errno != ENOENT) + { /* catastrophic, sell all your stock */ + perror("shmget"); /* and leave the country type of */ + exit(1); /* error--suicide */ + } + fprintf(stderr, "Daemon not running (err:%d)\n", errno); + exit(1); + case 1: + if (errno != ENOENT) + { /* catastrophic, sell all your stock */ + perror("shmget"); /* and leave the country type of */ + exit(1); /* error--suicide */ + } + startdaemon(leagueflag, 0); /* try to start the daemon */ + sleep(2); /* wait for a sec for deamon to start */ + shmid = shmget(shmemKey, 0, 0); /* try again to get shared mem */ + if (shmid < 0) + { /* failure again then get out of here */ + fprintf(stderr, "Daemon not running (err:%d)\n", errno); + exit(1); + } + break; + case 2: + perror("daemon: can't open shared memory"); + exit(1); + } + } + if (code == 2) + { + struct shmid_ds smbuf; + + shmctl(shmid, IPC_STAT, &smbuf); /* Hose Ed's robots */ + smbuf.shm_perm.uid = geteuid(); + smbuf.shm_perm.mode = 0666; + shmctl(shmid, IPC_SET, &smbuf); + } + sharedMemory = (struct memory *) shmat(shmid, (char *) 0, 0); + if (sharedMemory == (struct memory *) - 1) + { + perror("shared memory"); + exit(1); + } + if (code == 2) + { + /* set the magic number */ + sharedMemory->shmem_size = sizeof(struct memory); + } + else + { + if (sharedMemory->shmem_size != sizeof(struct memory)) + { + fprintf(stderr, "shared memory segment magic number mismatch!\ + (%d != %ld)\n aborting to prevent corruption of game data\n", + sharedMemory->shmem_size, (long) sizeof(struct memory)); + exit(1); + } + } + players = sharedMemory->players; /* set pointer to fields */ + torps = sharedMemory->torps; /* in shared memory structure */ + missiles = sharedMemory->missiles; /* for easy access */ + thingies = sharedMemory->thingies; + plasmatorps = sharedMemory->plasmatorps; + status = &sharedMemory->status; + status2 = &sharedMemory->status2; + planets = sharedMemory->planets; + terrain_grid = sharedMemory->terrain_grid; + phasers = sharedMemory->phasers; + stars = sharedMemory->stars; + mctl = &sharedMemory->mctl; + messages = sharedMemory->messages; + teams = sharedMemory->teams; + shipvals = sharedMemory->shipvals; + configvals = &sharedMemory->configvals; + galaxyValid = &sharedMemory->galaxyValid; + /* configvals->gwidth = 200000; *//* pick up from galaxy generator later */ + /* configvals->numplanets = 60; *//* this too */ + + shipsallowed = configvals->shipsallowed; + weaponsallowed = configvals->weaponsallowed; + sun_effect = configvals->sun_effect; + ast_effect = configvals->ast_effect; + neb_effect = configvals->neb_effect; + wh_effect = configvals->wh_effect; + num_nebula = &(configvals->num_nebula); + nebula_density = &(configvals->nebula_density); + nebula_subclouds = &(configvals->nebula_subclouds); + num_asteroid = &(configvals->num_asteroid); + asteroid_thickness = &(configvals->asteroid_thickness); + asteroid_density = &(configvals->asteroid_density); + asteroid_radius = &(configvals->asteroid_radius); + asteroid_thick_variance = &(configvals->asteroid_thick_variance); + asteroid_dens_variance = &(configvals->asteroid_dens_variance); + asteroid_rad_variance = &(configvals->asteroid_rad_variance); + improved_tracking = configvals->improved_tracking; + + cluephrase_storage = sharedMemory->cluephrase_storage; + + stars[1] = -1; +} + +void +blast_shmem() +{ + shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0); +} diff -r 054275999194 -r 8c6d5731234d src/shmem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shmem.h Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,244 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#ifndef shmem_h_ +#define shmem_h_ + +#include "struct.h" + +enum spec_weapons_e +{ + WP_PLASMA, + WP_TRACTOR, + WP_MISSILE, + WP_FIGHTER, + WP_MAX +}; + +enum ships_systems +{ + /* Terrain could, I suppose, affect any of these */ + /* I may have forgotten a couple, feel free to add.. */ + SS_PLASMA, + SS_TRACTOR, + SS_MISSILE, + SS_FIGHTER, + SS_PHOTON, + SS_PHASER, + SS_SHIELD, + SS_REPAIR, + SS_CLOAK, + SS_SCANNER, + SS_SENSOR, + SS_WARP, + SS_IMPULSE, + SS_DOCK, + SS_NAVIGATION, + SS_COMMUNICATION, + SHIPS_SYSTEMS +}; + +struct configuration +{ + int tournplayers; /* how many players necessary for T-mode */ + int ntesters; /* number of slots reserved for robots */ + + char binconfirm; /* binary confirmation */ + float maxload; /* maximum load */ + char udpAllowed; /* is UDP allowed */ + int min_upd_delay; /* minimum update delay */ + int min_observer_upd_delay; /* minimum observer update delay */ + + /* planet things */ + int galaxygenerator; /* which method to generate the galaxy with */ + int numplanets; /* number of planets */ + float planupdspd; /* planet movement speed */ + char resource_bombing; /* have growable and bombable resources? */ + char revolts; /* are revolts allowed? */ + unsigned char popscheme; /* individual planet popping scheme */ + unsigned char popchoice; /* how to choose a planet for popping */ + int popspeed; /* 100 is normal speed */ + char evacuation; /* allow beaming up below 5 armies? */ + char new_army_growth; /* base army growth on current pop? */ + int planetsinplay; /* Max # of planets in play */ + int planetlimittype; /* how planet taking is limited */ + char beamlastarmies; /* if you can, or cannot beam up the last + * armies. */ + char justify_galaxy; /* Do we want to ensure that the galaxy is + * "fair"? */ + int num_wormpairs; /* The number of wormhole pairs -- DON'T SET + * ABOVE (NUMPLANETS/2) */ + int num_nebula; /* the number of nebulas in the galaxy. */ + int nebula_density; /* not yet used. Will be used for + * funky-shaped nebs */ + int nebula_subclouds; /* the number of nebulous subclouds */ + int num_asteroid; /* number of asteroid belts in the galaxy */ + float asteroid_thickness; /* the thickness of an asteroid belt. */ + int asteroid_density; /* the density (% chance) of an asteroid + * field */ + int asteroid_radius; /* distance of a belt from its star */ + float asteroid_thick_variance;/* float value -- useful range 0.0 - 10.0 or + * so */ + int asteroid_dens_variance; /* int value -- useful range 0 - 200 */ + int asteroid_rad_variance; /* int value -- useful range 0 - 255 */ + + float plkills; /* how many kills to allow plasmas */ + float mskills; /* how many kills to allow missiles */ + float erosion; /* hull erosion factor */ + float penetration; /* shield penetration factor */ + int newturn; /* TC's new style turns */ + int hiddenenemy; /* enemies hidden in T-mode */ + int gwidth; /* galactic width */ + char bronco_shipvals; /* use bronco ship values? */ + char afterburners; /* can people use afterburners? */ + char warpdrive; /* is warping allowed? */ + char fuel_explosions; /* are explosions based on gas? */ + char newcloak; /* use new cloaking? */ + char bronco_ranks; /* use bronco ranking? NYI, kinda */ + + char warpdecel; /* non-instant deceleration from warp */ + char affect_shiptimers_outside_T; /* should ship destruction outside of + * T-mode affect the team ship + * timers? */ + /* NYTested */ + char durablescouting; /* if 0, then you have to keep scouting + * planets to get up-to-date info. If 1, + * then you only need to scout it once. */ + + /* NYI */ + char facilitygrowth; /* if 0, then you can't bomb or grow + * facilities. if 1, then you can. */ + char fireduringwarpprep; /* can you fire during warp prep? */ + char fireduringwarp; /* can you fire while warping? */ + char firewhiledocked; /* can you fire while docked? */ + +#define WPS_NOTRACT 0 /* tractors do not affect warp prep */ +#define WPS_TABORT 1 /* tractors cause an abort at the end */ +#define WPS_TPREVENT 2 /* tractors prevent entering warp */ +#define WPS_TABORTNOW 3 /* tractors immediately abort warp prep */ +#define WPS_TSUSPEND 4 /* tractors suspend countdown */ + char warpprepstyle; + + char baserankstyle; /* if nobody on the team has enough rank */ + /* to get a special ship; and this is set */ + /* to 1, then the player with the highest */ + /* rank on the team may get the spec. ship */ + + char cloakduringwarpprep; + char cloakwhilewarping; + char tractabortwarp; /* this many tractors will abort warp */ + + float orbitdirprob; /* probability that the player will orbit + * clockwise */ + char neworbits; /* New, incremental planet distances from the + * parent star -- important for games with + * terrain. */ + + int sun_effect[SHIPS_SYSTEMS];/* suns affect these systems */ + int ast_effect[SHIPS_SYSTEMS];/* asteroids affect these systems */ + int neb_effect[SHIPS_SYSTEMS];/* a nebula affects these */ + int wh_effect[SHIPS_SYSTEMS]; /* wormhole effects */ + int improved_tracking[SHIPS_SYSTEMS]; /* which weapons use IT */ + int shipsallowed[NUM_TYPES]; /* which ships are allowed */ + int weaponsallowed[WP_MAX]; /* which special weapons are allowed */ +#ifdef LEAGUE_SUPPORT + /* league configuration stuff */ + int timeouts; /* timeouts per team in league play */ + int regulation_minutes; /* minutes in regulation play */ + int overtime_minutes; /* minutes in overtime play */ + int playersperteam; /* maximum number of players per team */ +#endif + /* ping stuff */ + int ping_period; /* ping period in seconds */ + int ping_iloss_interval; /* in terms of ping_period */ + int ping_allow_ghostbust; /* allow ghostbust detection from + * ping_ghostbust (cheating possible) */ + int ping_ghostbust_interval; /* in terms of ping_period, when to ghostbust + * (if allowed) */ + + char cluecheck; /* should we check clue? */ + int cluedelay; /* maximum time between clue checks */ + int cluetime; /* time player has to respond to a clue check */ + int cluesource; /* source of clue phrase */ +#define CC_COMPILED_IN_PHRASE_LIST 0 +#define CC_MOTD 1 +#define CC_PHRASE_LIST_FILE 2 + + int variable_warp; /* allow variable warp or not [BDyess] */ + int warpprep_suspendable; /* allow warp prep to be suspended [BDyess] */ + int warpzone; /* radius of warp zone [BDyess] */ + + /* tmode stuff */ + int nopregamebeamup; /* whether to disallow beamup before a game */ + int gamestartnuke; /* whether everyone is nuked at game start */ + int nottimeout; /* # minutes after loss of tmode before */ + /* galaxy resets (0 disables) */ + + /* put planet growth timer constants here */ + struct plgrow_ + { + int fuel, agri, repair, shipyard; + } plgrow; + int helpfulplanets; /* planets help fuel/etmep */ +}; + +extern struct player *players; +extern struct torp *torps; +extern struct missile *missiles; +extern struct thingy *thingies; +extern struct plasmatorp *plasmatorps; +extern struct status *status; +extern struct status2 *status2; +extern struct planet *planets; +extern struct t_unit *terrain_grid; +extern struct phaser *phasers; +extern int *stars; +extern struct mctl *mctl; +extern struct message *messages; +extern struct team *teams; + +#define NUMPLANETS configvals->numplanets +#define GWIDTH configvals->gwidth +#define WORMPAIRS configvals->num_wormpairs + +extern struct ship *shipvals; +extern struct configuration *configvals; +extern int *shipsallowed; /* points inside configvals */ +extern int *weaponsallowed; /* ditto */ +extern int *sun_effect; /* how do suns affect ship systems? */ +extern int *ast_effect; /* asteroids */ +extern int *neb_effect; /* nebulae */ +extern int *wh_effect; /* wormholes */ +extern int *num_nebula; /* number of nebulae */ +extern int *nebula_density; /* funkyness of nebulae -- NYI */ +extern int *nebula_subclouds; /* number of subclouds per nebula */ +extern int *num_asteroid; /* number of asteroid fields */ +extern float *asteroid_thickness; /* thickness of an asteroid belt */ +extern int *asteroid_density; /* density of asteroid belts */ +extern int *asteroid_radius; /* distance from owning star */ +extern float *asteroid_thick_variance; +extern int *asteroid_dens_variance; +extern int *asteroid_rad_variance; +extern int *improved_tracking; /* smarter tracking algorithm */ +extern char *galaxyValid; /* does galaxy go invalid? 0 if so */ +#define CLUEPHRASE_SIZE 1024 +extern char *cluephrase_storage; +void openmem( /* 0=or die, 1=fork daemon, 2=are daemon */ ); +void blast_shmem(); + +#endif diff -r 054275999194 -r 8c6d5731234d src/shmemP.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/shmemP.h Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,51 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + + +#ifndef _shmemP_h +#define _shmemP_h + +struct memory +{ + int shmem_size; /* sizeof(struct memory) sort of a magic + * number so that we don't connect an + * obsolete program to the shmem. */ + struct player players[MAXPLAYER]; + struct torp torps[MAXPLAYER * MAXTORP]; + struct missile missiles[MAXPLAYER * NPTHINGIES]; + struct thingy thingies[NGTHINGIES]; + struct plasmatorp plasmatorps[MAXPLAYER * MAXPLASMA]; + struct status status; + struct status2 status2; + struct planet planets[MAXPLANETS]; + struct t_unit terrain_grid[(MAX_GWIDTH / TGRID_GRANULARITY) * + (MAX_GWIDTH / TGRID_GRANULARITY)]; + struct phaser phasers[MAXPLAYER]; + int stars[MAXPLANETS + 1]; /* indices of the stars in the game, indexed + * on system number */ + struct mctl mctl; + struct message messages[MAXMESSAGE]; + struct team teams[MAXTEAM + 1]; + + struct ship shipvals[NUM_TYPES]; + struct configuration configvals; + char cluephrase_storage[CLUEPHRASE_SIZE]; + char galaxyValid[MAXPLAYER]; +}; + +#endif /* _shmemP_h */ diff -r 054275999194 -r 8c6d5731234d src/sintab.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sintab.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,546 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +/*---------------------------------DATA------------------------------------*/ +/* The sine table so we do not have to calculate this on the fly. */ + +double Sin[] = { + -1.0000, + -0.9997, + -0.9988, + -0.9973, + -0.9952, + -0.9925, + -0.9892, + -0.9853, + -0.9808, + -0.9757, + -0.9701, + -0.9638, + -0.9570, + -0.9496, + -0.9416, + -0.9330, + -0.9239, + -0.9143, + -0.9040, + -0.8933, + -0.8820, + -0.8701, + -0.8578, + -0.8449, + -0.8315, + -0.8176, + -0.8033, + -0.7884, + -0.7731, + -0.7573, + -0.7410, + -0.7243, + -0.7072, + -0.6896, + -0.6716, + -0.6533, + -0.6345, + -0.6153, + -0.5958, + -0.5759, + -0.5557, + -0.5351, + -0.5142, + -0.4930, + -0.4715, + -0.4497, + -0.4277, + -0.4054, + -0.3828, + -0.3600, + -0.3370, + -0.3138, + -0.2904, + -0.2668, + -0.2431, + -0.2192, + -0.1952, + -0.1711, + -0.1469, + -0.1225, + -0.0982, + -0.0737, + -0.0492, + -0.0247, + -0.0001, + 0.0244, + 0.0489, + 0.0734, + 0.0979, + 0.1223, + 0.1466, + 0.1708, + 0.1949, + 0.2190, + 0.2428, + 0.2666, + 0.2901, + 0.3135, + 0.3367, + 0.3598, + 0.3825, + 0.4051, + 0.4274, + 0.4495, + 0.4713, + 0.4928, + 0.5140, + 0.5349, + 0.5554, + 0.5757, + 0.5956, + 0.6151, + 0.6343, + 0.6531, + 0.6714, + 0.6894, + 0.7070, + 0.7241, + 0.7408, + 0.7571, + 0.7729, + 0.7882, + 0.8031, + 0.8175, + 0.8314, + 0.8448, + 0.8576, + 0.8700, + 0.8818, + 0.8931, + 0.9039, + 0.9141, + 0.9238, + 0.9329, + 0.9415, + 0.9495, + 0.9569, + 0.9637, + 0.9700, + 0.9757, + 0.9808, + 0.9852, + 0.9891, + 0.9925, + 0.9952, + 0.9973, + 0.9988, + 0.9997, + 1.0000, + 0.9997, + 0.9988, + 0.9973, + 0.9952, + 0.9925, + 0.9892, + 0.9853, + 0.9808, + 0.9757, + 0.9700, + 0.9638, + 0.9569, + 0.9495, + 0.9415, + 0.9330, + 0.9239, + 0.9142, + 0.9040, + 0.8932, + 0.8819, + 0.8701, + 0.8577, + 0.8449, + 0.8315, + 0.8176, + 0.8032, + 0.7884, + 0.7730, + 0.7572, + 0.7410, + 0.7243, + 0.7071, + 0.6896, + 0.6716, + 0.6532, + 0.6344, + 0.6153, + 0.5957, + 0.5758, + 0.5556, + 0.5350, + 0.5141, + 0.4929, + 0.4714, + 0.4496, + 0.4276, + 0.4053, + 0.3827, + 0.3599, + 0.3369, + 0.3137, + 0.2903, + 0.2667, + 0.2430, + 0.2191, + 0.1951, + 0.1710, + 0.1468, + 0.1225, + 0.0981, + 0.0736, + 0.0491, + 0.0246, + 0.0000, + -0.0245, + -0.0490, + -0.0735, + -0.0980, + -0.1224, + -0.1467, + -0.1709, + -0.1950, + -0.2190, + -0.2429, + -0.2667, + -0.2902, + -0.3136, + -0.3368, + -0.3598, + -0.3826, + -0.4052, + -0.4275, + -0.4496, + -0.4713, + -0.4928, + -0.5140, + -0.5349, + -0.5555, + -0.5758, + -0.5956, + -0.6152, + -0.6343, + -0.6531, + -0.6715, + -0.6895, + -0.7071, + -0.7242, + -0.7409, + -0.7572, + -0.7730, + -0.7883, + -0.8032, + -0.8175, + -0.8314, + -0.8448, + -0.8577, + -0.8700, + -0.8819, + -0.8932, + -0.9040, + -0.9142, + -0.9238, + -0.9330, + -0.9415, + -0.9495, + -0.9569, + -0.9638, + -0.9700, + -0.9757, + -0.9808, + -0.9853, + -0.9892, + -0.9925, + -0.9952, + -0.9973, + -0.9988, + -0.9997 +}; +double Cos[] = { + 0.0000, + 0.0245, + 0.0491, + 0.0736, + 0.0980, + 0.1224, + 0.1467, + 0.1710, + 0.1951, + 0.2191, + 0.2430, + 0.2667, + 0.2903, + 0.3137, + 0.3369, + 0.3599, + 0.3827, + 0.4052, + 0.4275, + 0.4496, + 0.4714, + 0.4929, + 0.5141, + 0.5350, + 0.5556, + 0.5758, + 0.5957, + 0.6152, + 0.6344, + 0.6532, + 0.6715, + 0.6895, + 0.7071, + 0.7242, + 0.7409, + 0.7572, + 0.7730, + 0.7883, + 0.8032, + 0.8176, + 0.8315, + 0.8448, + 0.8577, + 0.8701, + 0.8819, + 0.8932, + 0.9040, + 0.9142, + 0.9239, + 0.9330, + 0.9415, + 0.9495, + 0.9569, + 0.9638, + 0.9700, + 0.9757, + 0.9808, + 0.9853, + 0.9892, + 0.9925, + 0.9952, + 0.9973, + 0.9988, + 0.9997, + 1.0000, + 0.9997, + 0.9988, + 0.9973, + 0.9952, + 0.9925, + 0.9892, + 0.9853, + 0.9808, + 0.9757, + 0.9700, + 0.9638, + 0.9570, + 0.9495, + 0.9416, + 0.9330, + 0.9239, + 0.9142, + 0.9040, + 0.8933, + 0.8819, + 0.8701, + 0.8578, + 0.8449, + 0.8315, + 0.8176, + 0.8032, + 0.7884, + 0.7731, + 0.7573, + 0.7410, + 0.7243, + 0.7072, + 0.6896, + 0.6716, + 0.6532, + 0.6344, + 0.6153, + 0.5958, + 0.5759, + 0.5556, + 0.5351, + 0.5142, + 0.4930, + 0.4715, + 0.4497, + 0.4276, + 0.4053, + 0.3828, + 0.3600, + 0.3370, + 0.3138, + 0.2904, + 0.2668, + 0.2431, + 0.2192, + 0.1952, + 0.1710, + 0.1468, + 0.1225, + 0.0981, + 0.0737, + 0.0492, + 0.0246, + 0.0001, + -0.0244, + -0.0490, + -0.0735, + -0.0979, + -0.1223, + -0.1466, + -0.1709, + -0.1950, + -0.2190, + -0.2429, + -0.2666, + -0.2902, + -0.3136, + -0.3368, + -0.3598, + -0.3826, + -0.4051, + -0.4275, + -0.4495, + -0.4713, + -0.4928, + -0.5140, + -0.5349, + -0.5555, + -0.5757, + -0.5956, + -0.6151, + -0.6343, + -0.6531, + -0.6715, + -0.6895, + -0.7070, + -0.7242, + -0.7409, + -0.7571, + -0.7729, + -0.7883, + -0.8031, + -0.8175, + -0.8314, + -0.8448, + -0.8577, + -0.8700, + -0.8819, + -0.8932, + -0.9039, + -0.9142, + -0.9238, + -0.9329, + -0.9415, + -0.9495, + -0.9569, + -0.9637, + -0.9700, + -0.9757, + -0.9808, + -0.9853, + -0.9892, + -0.9925, + -0.9952, + -0.9973, + -0.9988, + -0.9997, + -1.0000, + -0.9997, + -0.9988, + -0.9973, + -0.9952, + -0.9925, + -0.9892, + -0.9853, + -0.9808, + -0.9757, + -0.9701, + -0.9638, + -0.9570, + -0.9496, + -0.9416, + -0.9330, + -0.9239, + -0.9143, + -0.9041, + -0.8933, + -0.8820, + -0.8702, + -0.8578, + -0.8449, + -0.8316, + -0.8177, + -0.8033, + -0.7884, + -0.7731, + -0.7573, + -0.7411, + -0.7244, + -0.7072, + -0.6897, + -0.6717, + -0.6533, + -0.6345, + -0.6154, + -0.5958, + -0.5759, + -0.5557, + -0.5351, + -0.5142, + -0.4930, + -0.4715, + -0.4498, + -0.4277, + -0.4054, + -0.3828, + -0.3601, + -0.3371, + -0.3138, + -0.2905, + -0.2669, + -0.2432, + -0.2193, + -0.1953, + -0.1711, + -0.1469, + -0.1226, + -0.0982, + -0.0737, + -0.0493, + -0.0247 +}; + +/*-------------------------------------------------------------------------*/ + + + + + + +/*-------END OF FILE--------*/ diff -r 054275999194 -r 8c6d5731234d src/smessage.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/smessage.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,95 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" + +#include +#include +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" + +/* int parse_control_mess(); */ + + +/*-----------------------------VISIBLE FUNCTIONS--------------------------*/ + +/*---------------------------------PMESSAGE-------------------------------*/ +/* + * This function sends a message. It marks a message as being sent from God. + */ + + +void pmessage2(); + +void +pmessage(str, recip, group, address) + char *str; /* the message */ + int recip; /* who will receive it */ + int group; /* the group (type of recipient) */ + char *address; /* attached to front of message */ +{ + pmessage2(str, recip, group, address, 255); +} + + + + +/*--------------------------------PMESSAGE2--------------------------------*/ +/* + * This function sends a message. It places the message in the array of + * messages. + */ + +void +pmessage2(str, recip, group, address, from) + char *str; /* the message */ + int recip; /* who will receive it */ + int group; /* the group (type of recipient) */ + char *address; /* attached to front of message */ + unsigned char from; /* who the message is from */ +{ + struct message *cur; /* to point to where to put message */ + int mesgnum; /* to hold index number in message array */ + + if ((mesgnum = ++(mctl->mc_current)) >= MAXMESSAGE) + { + mctl->mc_current = 0; /* get index of where to put the message */ + mesgnum = 0; /* roll it index number over if need be */ + } + cur = &messages[mesgnum]; /* get address of message structure in array */ + cur->m_no = mesgnum; /* set the message number */ + cur->m_flags = group; /* set group or type of recipient */ + cur->m_recpt = recip; /* set the recipient */ + cur->m_from = from; /* set who it was from */ + (void) sprintf(cur->m_data, "%-9s ", address); + strncat(cur->m_data, str, sizeof(cur->m_data) - strlen(cur->m_data)); + cur->m_flags |= MVALID; /* set messages status as valid */ +} + +/*-------------------------------------------------------------------------*/ + + + +/*----------------------------INVISIBLE FUNCTIONS-------------------------*/ + + +/*-------END OF FILE--------*/ diff -r 054275999194 -r 8c6d5731234d src/snake.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/snake.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,395 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + + +char binary[] = "@(#)snake"; + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" + +#ifndef linux +double atof(); +#endif +extern void (*r_signal()) (); + +struct player *perfs[2]; +int printsnakeUsage(); +int num_perfs = 2; +int debug = 0; +int target = -1; +int berserk = 0; +int patrol = 0; +int noSmush = 0; +int plan_guard = 0; /* KAO */ +int planet1, planet2; /* KAO */ +int team1 = 0, team2 = 0; +int length = MAXTORP; /* how many pairs of torps in the snake */ + +struct itimerval udt; /* derived from frequency RF */ +int lastm; +int tno = 0; + +int +choose_team(team) +{ + if (tno < 0) + tno = team; + if (!team1) + team1 = 1 << team; + else if (!team2) + team2 = 1 << team; +} + +main(argc, argv) + int argc; + char **argv; +{ + register int i; + int snakemove(), exitSnake(); + int pno; + char str[80], tlet; + int pc = 0; + int usage = 0; + double frequency = 10; /* default of 10 updates per second */ + + argv0 = argv[0]; + tno = -1; + + srand48(getpid() + time((time_t *) 0)); + memset(perfs, 0, sizeof(perfs)); + + for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) + { + switch (argv[1][1]) + { + case 'p': + patrol++; + break; + case 'n': + noSmush = 1; + break; + case 's': + noSmush = -1; + break; + case 'g': /* KAO */ + plan_guard++; /* KAO */ + argv++; /* KAO */ + argc--; + planet1 = atoi(argv[1]); /* KAO */ + argc--; + argv++; /* KAO */ + planet2 = atoi(argv[1]); /* KAO */ + break; /* KAO */ + case 'b': + berserk++; + break; + case 'd': + debug++; + break; + case 't': + { /* target */ + char c; + c = argv[1][2]; + target = -1; + if (c == '\0') + { + fprintf(stderr, "Must specify target. e.g. -t3.\n"); + exit(1); + } + if ((c >= '0') && (c <= '9')) + target = c - '0'; + else if ((c >= 'a') && (c <= 'z')) + target = c - 'a' + 10; + else + { + fprintf(stderr, "Must specify target. e.g. -t3.\n"); + exit(1); + } + } + break; + + case 'T': /* team */ + tlet = argv[1][2]; + if (isupper(tlet)) + tlet = tolower(tlet); + switch (tlet) + { + case 'f': + choose_team(0); + break; + case 'r': + choose_team(1); + break; + case 'k': + choose_team(2); + break; + case 'o': + choose_team(3); + break; + case 'i': + tno = 4; + break; + default: + fprintf(stderr, "Unknown team type. Usage -Tx where x is [frkoi]\n"); + exit(1); + } /* end switch argv */ + break; + + case 'l': + length = atoi(argv[1] + 2); + if (length < 1) + { + length = 1; + } + else if (length > MAXTORP) + { + length = MAXTORP; + } + break; + case 'f': + frequency = atof(argv[1] + 2); + if (frequency < 0) + { + frequency = 1; + } + break; + default: + fprintf(stderr, "Unknown option '%c'\n", argv[1][1]); + usage++; + exit(1); + } /* end switch argv[1][1] */ + } /* end for */ + + if (usage) + { + printsnakeUsage(); + exit(1); + } + + /* if -T wasn't specified default to FED */ + if (tno < 0) + tno = lrand48() % 4; + + /* XX -- teams imply patrol */ + if (team1 && team2) + patrol++; + +#ifdef nodef + /* debug */ + if (patrol) + { + printf("snake (%s): patrolling %s,%s\n", teamshort[1 << tno], + teamshort[team1], + teamshort[team2]); + } + fflush(stdout); +#endif + + /* readsysdefaults(); */ + + (void) r_signal(SIGHUP, exitSnake); + (void) r_signal(SIGINT, exitSnake); + (void) r_signal(SIGBUS, exitSnake); + (void) r_signal(SIGSEGV, exitSnake); + openmem(0, 0); + + lastm = mctl->mc_current; + + for (i = 0; i < 2; i++) + { /* two players per snake */ + pno = findrslot(); + if (pno < 0) + { + fprintf(stderr, "snake: no room in game\n"); + if (i > 0) + perfs[0]->p_status = PFREE; + exit(1); + } + me = &players[pno]; + + perfs[i] = me; + + me->p_no = pno; + myship = &me->p_ship; + mystats = &me->p_stats; + + strcpy(pseudo, "The Snake"); + strcpy(login, "SnkeChrmr"); + + strcpy(me->p_name, pseudo); + me->p_name[sizeof(me->p_name) - 1] = '\0'; + + (void) strncpy(me->p_login, login, sizeof(me->p_login)); + me->p_login[sizeof(me->p_login) - 1] = '\0'; + (void) strncpy(me->p_monitor, "Server", sizeof(me->p_monitor)); + me->p_monitor[sizeof(me->p_monitor) - 1] = '\0'; + /* enter(tno, 0, pno, class, -1); */ + + me->p_team = (tno < 4) ? (1 << tno) : 0; + config(); + + me->p_pos = -1; + me->p_flags |= PFROBOT; /* Mark as a robot */ + me->p_flags |= PFSNAKE; /* Mark as snake */ + if (berserk) + me->p_hostile = FED | ROM | ORI | KLI; + } + + r_signal(SIGALRM, snakemove); + + { + double period = 1 / frequency; + udt.it_interval.tv_sec = period; /* get the whole part */ + period -= udt.it_interval.tv_sec; /* get the fractional part */ + udt.it_interval.tv_usec = 1e6 * period; + udt.it_value.tv_sec = 1; + udt.it_value.tv_usec = 0; + } + + if (setitimer(ITIMER_REAL, &udt, 0) < 0) + { + perror("setitimer"); + for (i = 0; i < num_perfs; i++) + { + if (perfs[i]) + perfs[i]->p_status = PFREE; + } + exit(1); + } +#ifndef SVR4 + /* allows robots to be forked by the daemon -- Evil ultrix bullshit */ + sigsetmask(0); +#endif /* SVR4 */ + + /* NOTE: snakes do not become alive. */ + + while (1) + { + pause(); + } +} + +findtestslot() +{ + register int i; + + for (i = MAXPLAYER - configvals->ntesters; i < MAXPLAYER; i++) + { + if (players[i].p_status == PFREE) + { /* We have a free slot */ + players[i].p_status = POUTFIT; /* possible race code */ + break; + } + } + if (i == MAXPLAYER) + { + return -1; /* no room in tester slots */ + } + memset(&players[i].p_stats, 0, sizeof(struct stats)); + players[i].p_stats.st_tticks = 1; + return (i); +} + +findrslot() +{ + register int i; + + /* look for tester slot first */ + i = findtestslot(); + if (i > -1) + return i; + + for (i = 0; i < MAXPLAYER; i++) + { + if (players[i].p_status == PFREE) + { /* We have a free slot */ + players[i].p_status = POUTFIT; /* possible race code */ + break; + } + } + if ((i == MAXPLAYER) || (i == -1)) + { + if (debug) + { + fprintf(stderr, "No more room in game\n"); + } + return -1; + } + memset(&players[i].p_stats, 0, sizeof(struct stats)); + players[i].p_stats.st_tticks = 1; + return (i); +} + +void +warning(mess) + char *mess; +{ + if (debug) + fprintf(stderr, "warning: %s\n", mess); +} + +config() +{ + /* mostly not used */ +#if 0 + /* what the heck is this procedure for ? */ + myship->s_phasercost = 0; + myship->s_torpcost = 0; + myship->s_cloakcost = 0; + myship->s_torpfuse = 1000000; + myship->s_torpdamage = 10; + myship->s_plasmadamage = 50; + myship->s_plasmacost = 0; + myship->s_plasmaturns = 0; + myship->s_plasmaspeed = 10; + myship->s_plasmafuse = 1000000; + myship->s_wpncoolrate = 100; + myship->s_egncoolrate = 100; +#endif +} + +/*---------------------[ prints the usage of snake ]---------------------*/ + +printsnakeUsage() +{ + printf("Usage: snake [options]\n"); + printf("Options:\n\ + -u -- this usage message\n\ + -p -- patrol\n\ + -s -- noSmush (?)\n\ + -b -- berserk\n\ + -d -- debug\n\ + -t -- target \n\ + -T -- team [frkoi]\n\ + -l -- length (in torps)\n\ + -f -- frequency\n\ + -g -- guardian: -g (must be 2 planets listed,\n\ + by number).\n"); +} + +/*--------------------------[ printsnakeUsage ]--------------------------*/ diff -r 054275999194 -r 8c6d5731234d src/snakemove.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/snakemove.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,1080 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + +#include "config.h" +#include +#include + +#ifdef apollo +#include +#define MAXINT INT_MAX +#else +#include +#endif + +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "planets.h" +#include "shmem.h" + +#define SYSWIDTH (GWIDTH/5)/* width of a system */ + +/* distance on either side of center */ +#define EYEWIDTH 100 /* 100 */ +/* which torp the eyes are positioned alongside */ +#define EYETORP 0 /* 0 */ +/* angle from EYETORP */ +#define EYEANGLE 64 /* 64 */ +#define TORPSEP WARP1*12 +#define PLANRAD 900 +#define PLANRATE 16 + +/* threshold to avoid galactic boundaries */ +#define MD 4500 +/* overlap threshold on team boundaries */ +#define TMD 2250 + +/* how often to check for bombers in cyles (1/10th second) */ +#define BOMBCHECK 20 + +/* how often to check for players in the game in cyles (1/10th second) */ +#define PLAYERCHECK 100 + +#define WARHOSTILE(p) ((((p)->p_swar | (p)->p_hostile)& \ + perfs[0]->p_team) || ((perfs[0]->p_swar | \ + perfs[0]->p_hostile) & (p)->p_team)) + +#define SNAKETORPDAMAGE 30 +#define SNAKEPLASMADAMAGE 100 + +static struct torp *thead, *eyet, *eyetp; +static int lx, ly; +static struct plasmatorp *fl, *fr; +static int explode, explodetorps, tfuse; + +extern struct player *perfs[2]; +extern int num_perfs; +extern int debug; +extern int lastm; +extern int tno; +extern int target; +extern int berserk; +extern int patrol; +extern int noSmush; +extern int plan_guard; /* KAO */ +extern int planet1, planet2; /* KAO */ +extern int team1, team2; +extern int length; + +static int plan_count = 0; +static int s_clock; +static _move(); +static int defenders[ALLTEAM]; + +struct player *whokilledme(); +struct planet *homeworld = 0; +struct planet *homestar = 0; + +unsigned char getacourse(); +extern void (*r_signal()) (); + + +struct planet * +star_of(pl) + struct planet *pl; +{ + int i; + if (pl->pl_system < 1) + return 0; + + for (i = 0; i < NUMPLANETS; i++) + { + if (!(planets[i].pl_flags & PLSTAR)) + continue; + if (planets[i].pl_system == pl->pl_system) + return &planets[i]; + } + + return 0; +} + + + +snakemove() +{ + s_clock++; + + _move(); +} + +static +_move() +{ + if (!perfs[0] || !perfs[1]) + exitSnake(); + + /* keep ghostbuster away */ + perfs[0]->p_ghostbuster = 0; + perfs[1]->p_ghostbuster = 0; + + if (s_clock == 5) + startsnake(); + else if (s_clock > 5) + { + check_explode(); + if (!explode) + { + movesnake(); + } + else if ((perfs[0]->p_ntorp == 0 && perfs[1]->p_ntorp == 0 && + perfs[0]->p_nplasmatorp == 0 && perfs[1]->p_nplasmatorp == 0) || + /* xx -- sometimes above doesn't work? */ + s_clock - explode > 56) + exitSnake(); + } + return 1; +} + +startsnake() +{ + register i, l; + register struct player *j; + register struct torp *k; + struct player *p1 = perfs[0], *p2 = perfs[1]; + int first = 1; + int px, py; + + for (i = 0; i < NUMPLANETS; i++) + { + if (planets[i].pl_flags & PLHOME && planets[i].pl_owner == 1 << tno) + { + homeworld = &planets[i]; + break; + } + if (!homeworld && planets[i].pl_owner == 1 << tno) + homeworld = &planets[i]; + } + + if (!homeworld) + { + /* ouch */ + homeworld = &planets[lrand48() % NUMPLANETS]; + fprintf(stderr, "snake: My race (%d) has no planets. Picking one at random: %s\n", tno, homeworld->pl_name); + } + homestar = star_of(homeworld); + if (!homestar) + homestar = homeworld; + + px = (lrand48() % 10000) - 5000; + py = (lrand48() % 10000) - 5000; + + p1->p_ntorp = p2->p_ntorp = 0; + p1->p_nplasmatorp = p2->p_nplasmatorp = 0; + + /* body */ + + for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1])) + { + + for (l = 0, i = j->p_no * MAXTORP, k = &torps[i]; + i < j->p_no * MAXTORP + length; i++, k++, l++) + { + + if (l == EYETORP && j == perfs[0]) + { + /* eye location */ + eyet = k; + } + if (l == ((EYETORP == 0) ? 1 : (EYETORP - 1)) && j == perfs[0]) + { + /* perpendicular torp offset */ + eyetp = k; + } + /* torps are free here */ + snake_torp(k, i, j); + /* note: have to be same team for this to work */ + k->t_x = homeworld->pl_x + px; + k->t_y = homeworld->pl_y + py - (l + (j == perfs[1] ? length : 0)) * TORPSEP; + /* + * if(debug) fprintf(stderr, "k->t_x %d, k->t_y %d\n", k->t_x, k->t_y); + */ + if (first) + { + thead = k; + first = 0; + } + } + } + + /* eyes */ + fl = &plasmatorps[perfs[0]->p_no * MAXPLASMA]; + fl->pt_no = perfs[0]->p_no * MAXPLASMA; + fl->pt_status = PTMOVE; + fl->pt_owner = perfs[0]->p_no; + fl->pt_team = perfs[0]->p_team; + fl->pt_x = eyet->t_x - EYEWIDTH; + fl->pt_y = eyet->t_y; + if (plan_guard == 0) + fl->pt_damage = SNAKEPLASMADAMAGE; + else + fl->pt_damage = SNAKEPLASMADAMAGE * 10; + fl->pt_speed = 0; + fl->pt_war = 0; + fl->pt_fuse = MAXINT; + fl->pt_turns = 0; + + perfs[0]->p_nplasmatorp++; + + fr = &plasmatorps[perfs[1]->p_no * MAXPLASMA]; + fr->pt_no = perfs[1]->p_no * MAXPLASMA; + fr->pt_status = PTMOVE; + fr->pt_owner = perfs[1]->p_no; + fr->pt_team = perfs[1]->p_team; /* doesn't work */ + fr->pt_x = eyet->t_x + EYEWIDTH; + fr->pt_y = eyet->t_y; + fr->pt_damage = SNAKEPLASMADAMAGE; + fr->pt_speed = 0; + fr->pt_war = 0; + fr->pt_fuse = MAXINT; + fr->pt_turns = 0; + + perfs[1]->p_nplasmatorp++; + + if (debug) + fprintf(stderr, "started\n"); +} + +restore_eye() +{ + if (fl->pt_status != PTMOVE) + { + /* eyes */ + fl = &plasmatorps[perfs[0]->p_no * MAXPLASMA]; + fl->pt_no = perfs[0]->p_no * MAXPLASMA; + fl->pt_status = PTMOVE; + fl->pt_owner = perfs[0]->p_no; + fl->pt_team = perfs[0]->p_team; + fl->pt_x = eyet->t_x - EYEWIDTH; + fl->pt_y = eyet->t_y; + if (plan_guard == 0) + fl->pt_damage = SNAKEPLASMADAMAGE; + else + fl->pt_damage = SNAKEPLASMADAMAGE * 10; + fl->pt_speed = 0; + fl->pt_war = 0; + fl->pt_fuse = MAXINT; + fl->pt_turns = 0; + perfs[0]->p_nplasmatorp++; + } + if (fr->pt_status != PTMOVE) + { + fr = &plasmatorps[perfs[1]->p_no * MAXPLASMA]; + fr->pt_no = perfs[1]->p_no * MAXPLASMA; + fr->pt_status = PTMOVE; + fr->pt_owner = perfs[1]->p_no; + fr->pt_team = perfs[1]->p_team; /* doesn't work */ + fr->pt_x = eyet->t_x + EYEWIDTH; + fr->pt_y = eyet->t_y; + fr->pt_damage = SNAKEPLASMADAMAGE; + fr->pt_speed = 0; + fr->pt_war = 0; + fr->pt_fuse = MAXINT; + fr->pt_turns = 0; + perfs[1]->p_nplasmatorp++; + } +} + +movesnake() +{ + register i, px, py; + register struct player *j; + register struct torp *k /* , *prev = thead */ ; + unsigned char tc; + struct player *tr; + static + int dir = 8; + int ok; + + if ((s_clock % PLAYERCHECK) == 0) + { + /* every x seconds make sure there's people in the game */ + ok = 0; + defenders[FED] = defenders[ROM] = defenders[KLI] = defenders[ORI] = 0; + for (i = 0, j = players; i < MAXPLAYER; i++, j++) + { + if ((j->p_status != PFREE) && !(j->p_flags & PFROBOT)) + { + ok = 1; + defenders[j->p_team]++; + } + } + if (!ok) + exitSnake(); + } + if (patrol && (target == -1) && (s_clock % BOMBCHECK) == 0) + { + target = bombcheck(team1, team2); + } + if ((s_clock % (4 + (lrand48() % 4))) == 0) + dir = -dir; + + thead->t_dir += dir + rrnd(8); + + if (target > -1) + { + tr = &players[target]; + if (tr->p_status == PALIVE) + { + int nd, td; + tc = getacourse(tr->p_x, tr->p_y, thead->t_x, thead->t_y); + nd = angdist(thead->t_dir, tc); + if (nd > 8) + { + td = tc + nd; + if (td == thead->t_dir) + thead->t_dir -= 8; + else + thead->t_dir += 8; + } + } + } + if (target == -1) + { + if (!patrol) + check_tboundary(ALLTEAM, &thead->t_dir, 8, thead->t_x, thead->t_y); + else + check_tboundary(team1 | team2, &thead->t_dir, 8, thead->t_x, thead->t_y); + } + lx = thead->t_x; + ly = thead->t_y; + + if (!plan_guard) + { + /* NOTE: we aren't letting the daemon move the torp head */ + thead->t_x += (double) TORPSEP *Cos[thead->t_dir]; + thead->t_y += (double) TORPSEP *Sin[thead->t_dir]; + } + for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1])) + { + if (plan_guard) + { + int temp; + thead = &torps[j->p_no * MAXTORP]; + if (j == perfs[0]) + temp = planet1; + else + temp = planet2; + lx = thead->t_x; + ly = thead->t_y; + thead->t_x = planets[temp].pl_x + Cos[255 - plan_count] * PLANRAD; + thead->t_y = planets[temp].pl_y + Sin[255 - plan_count] * PLANRAD; + } + for (i = j->p_no * MAXTORP, k = &torps[i]; + i < j->p_no * MAXTORP + length; i++, k++) + { + + if (k->t_status == TFREE) + /* got exploded. x & y location will remain however */ + snake_torp(k, i, j); + + if (k == thead) + continue; + + px = k->t_x; + py = k->t_y; + + k->t_x = lx; + k->t_y = ly; + + lx = px; + ly = py; + } + } + if (plan_guard) + { + thead = &torps[perfs[0]->p_no * MAXTORP]; + plan_count = (plan_count + PLANRATE) % 256; + } + lx = thead->t_x; + ly = thead->t_y; + doeyes(); +} + +check_explode() +{ + register int i, l; + register struct player *j; + register struct torp *k; + static struct player *killer; + + if (fl->pt_status == PTDET || fr->pt_status == PTDET || + fl->pt_status == PTEXPLODE || fr->pt_status == PTEXPLODE || explode) + { + if (plan_guard) + { + restore_eye(); + return; + } /* KAO */ + if (debug) + fprintf(stderr, "snake exploding\n"); + if (!explode) + { + /* do once */ + explode = s_clock; + tfuse = 0; + if (fl->pt_status == PTDET || fl->pt_status == PTEXPLODE) + { + killer = whokilledme(fl); + if (killer) + award(killer); + } + if (fr->pt_status == PTDET || fr->pt_status == PTEXPLODE) + { + killer = whokilledme(fr); + if (killer) + award(killer); + } + } + if (fl->pt_status != PTFREE && fl->pt_status != PTEXPLODE) + { + fl->pt_war = FED | ROM | KLI | ORI; /* make sure its at war when + * it explodes */ + fl->pt_status = PTEXPLODE; + fl->pt_fuse = 10; + } + if (fl->pt_status != PTFREE && fr->pt_status != PTEXPLODE) + { + fl->pt_war = FED | ROM | KLI | ORI; + fr->pt_status = PTEXPLODE; + fr->pt_fuse = 10; + } + /* + * now for some fancy stuff. If killer is our target and is hostile or at + * war with our team then snake torp head makes a beeline for him. This + * lasts until killer dies or torps have been chasing killer for 40 + * cycles + */ + + if (killer && WARHOSTILE(killer) && (noSmush < 1) && (killer->p_status == PALIVE) && + tfuse < 40 && (killer->p_no == target || noSmush < 0)) + { + crash_killer(killer); + } + else + { + /* explode all torps in sequence, 1 per cycle until all gone */ + for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1])) + { + for (l = (j == perfs[0]) ? 0 : length, i = j->p_no * MAXTORP, k = &torps[i]; + i < j->p_no * MAXTORP + length; i++, k++, l++) + { + if (l == explodetorps && k->t_status != TEXPLODE && + k->t_status != TFREE) + { + k->t_status = TEXPLODE; + k->t_fuse = 10; + explodetorps++; + return; + } + else if (l == explodetorps) + explodetorps++; + } + } + } + } +} + +crash_killer(p) + struct player *p; +{ + register int i, px, py; + register struct player *j; + register struct torp *k; + unsigned char tc; + int active = 0; + + tfuse++; + + tc = getacourse(p->p_x, p->p_y, thead->t_x, thead->t_y); + thead->t_dir = tc; + + lx = thead->t_x; + ly = thead->t_y; + + thead->t_x += (double) (12 * WARP1) * Cos[thead->t_dir]; + thead->t_y += (double) (12 * WARP1) * Sin[thead->t_dir]; + + for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1])) + { + for (i = j->p_no * MAXTORP, k = &torps[i]; + i < j->p_no * MAXTORP + length; i++, k++) + { + + /* move the head up if it exploded */ + if (k != thead && thead->t_status == TFREE) + thead = k; + else if (k == thead) + continue; + + if (k->t_status != TFREE) + active++; + + px = k->t_x; + py = k->t_y; + + k->t_x = lx; + k->t_y = ly; + + lx = px; + ly = py; + } + } + return active; +} + + +doeyes() +{ + unsigned char c = getacourse(eyetp->t_x, eyetp->t_y, eyet->t_x, + eyet->t_y); + int ew = EYEWIDTH, war_ok; + + /* c + 64 -- fl c - 64 -- fr */ + + if (plan_guard) + { + fl->pt_x = planets[planet1].pl_x + Cos[255 - plan_count] * PLANRAD; + fl->pt_y = planets[planet1].pl_y + Sin[255 - plan_count] * PLANRAD; + fr->pt_x = planets[planet2].pl_x + Cos[255 - plan_count] * PLANRAD; + fr->pt_y = planets[planet2].pl_y + Sin[255 - plan_count] * PLANRAD; + return; + } + if (fl->pt_war) + ew += 15; + + fl->pt_x = eyet->t_x + (double) (ew) * Cos[(unsigned char) (c - EYEANGLE)]; + fl->pt_y = eyet->t_y + (double) (ew) * Sin[(unsigned char) (c - EYEANGLE)]; + +#ifdef nodef + if (fl->pt_x < 0) + fl->pt_x = 0; + else if (fl->pt_x > GWIDTH) + fl->pt_x = GWIDTH; + + if (fl->pt_y < 0) + fl->pt_y = 0; + else if (fl->pt_y > GWIDTH) + fl->pt_y = GWIDTH; +#endif + + if (fr->pt_war) + ew += 15; + + fr->pt_x = eyet->t_x + (double) (ew) * Cos[(unsigned char) (c + EYEANGLE)]; + fr->pt_y = eyet->t_y + (double) (ew) * Sin[(unsigned char) (c + EYEANGLE)]; + +#ifdef nodef + if (fr->pt_x < 0) + fr->pt_x = 0; + else if (fl->pt_x > GWIDTH) + fr->pt_x = GWIDTH; + + if (fr->pt_y < 0) + fr->pt_y = 0; + else if (fl->pt_y > GWIDTH) + fr->pt_y = GWIDTH; +#endif + + /* toggle war */ + if ((s_clock % 6) == 0) + { + /* + * your home planet and shipyards are always safe from your own snake + * unless you are a target. + */ + war_ok = !sp_area(thead->t_x, thead->t_y); + + if (!fr->pt_war && war_ok) + fr->pt_war = (FED | ROM | KLI | ORI) & ~(war_ok ? 0 : (1 << tno)); + else + fr->pt_war = 0; + + if (!fl->pt_war && war_ok) + fl->pt_war = (FED | ROM | KLI | ORI) & ~(war_ok ? 0 : (1 << tno)); + else + fl->pt_war = 0; + } +} + +exitSnake(sig) + int sig; +{ + register int i; + register struct player *j; + register struct torp *k; + register struct plasmatorp *f; + + r_signal(SIGALRM, SIG_DFL); + + if (debug) + fprintf(stderr, "snake exiting\n"); + + for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1])) + { + for (i = j->p_no * MAXTORP, k = &torps[i]; + i < j->p_no * MAXTORP + length; i++, k++) + { + /* torps are free here */ + if (k->t_status != TFREE) + k->t_status = TOFF; + } + f = &plasmatorps[j->p_no * MAXPLASMA]; + f->pt_status = PTFREE; + /* plasma */ + } + + memset(perfs[0], 0, sizeof(struct player)); + memset(perfs[1], 0, sizeof(struct player)); + perfs[0]->p_stats.st_tticks = 1; + perfs[1]->p_stats.st_tticks = 1; + + /* + * note: if we had a segmentation violation or bus error we want a core + * file to debug + */ + if (sig == SIGBUS || sig == SIGSEGV) + abort(); + else + exit(0); +} + +pmessage(str, recip, group, address) + char *str; + int recip; + int group; + char *address; +{ + pmessage2(str, recip, group, address, 255); +} + +pmessage2(str, recip, group, address, from) + char *str; + int recip; + int group; + char *address; + unsigned char from; +{ + struct message *cur; + int mesgnum; + + if ((mesgnum = ++(mctl->mc_current)) >= MAXMESSAGE) + { + mctl->mc_current = 0; + mesgnum = 0; + } + cur = &messages[mesgnum]; + cur->m_no = mesgnum; + cur->m_flags = group; + cur->m_recpt = recip; + cur->m_from = from; + (void) sprintf(cur->m_data, "%-9s %s", address, str); + cur->m_flags |= MVALID; +} + +/* get course from (mx,my) to (x,y) */ +unsigned char +getacourse(x, y, mx, my) + int x, y, mx, my; +{ + if (x == mx && y == my) + return 0; + + return (unsigned char) (int) (atan2((double) (x - mx), + (double) (my - y)) / 3.14159 * 128.); +} + +/* + * FED 1 ROM 2 KLI 4 ORI 8 + */ + +/* + * 256/0 192 + 64 128 */ + +check_tboundary(teams, mycrs, range, x, y) + int teams; + int x, y; + unsigned char *mycrs; + int range; +{ + int lx = homestar->pl_x - SYSWIDTH / 2, rx = homestar->pl_x + SYSWIDTH / 2, + ty = homestar->pl_y - SYSWIDTH / 2, by = homestar->pl_y + SYSWIDTH / 2; + int r = 0, l = 0; + unsigned char crs = *mycrs; + + if (x < lx && crs >= 128) + { + if (crs >= 192) + *mycrs += range; + else + *mycrs -= range; + l = 1; + } + else if (x > rx && crs < 128) + { + if (crs > 64) + *mycrs += range; + else + *mycrs -= range; + r = 1; + } + if (y < ty && (crs >= 192 || crs < 64)) + { + if (crs >= 192 && !l) + *mycrs -= range; + else + *mycrs += range; + } + else if (y > by && (crs < 192 && crs >= 64)) + { + if (crs < 128 && !r) + *mycrs -= range; + else + *mycrs += range; + } +} + +/* return rnd between -range & range */ +rrnd(range) + int range; +{ + return lrand48() % (2 * range) - range; +} + +#ifdef nodef +/* NOTUSED */ +contrast(t) + int t; +{ + return ROM; /* experiment */ + switch (t) + { + case FED: + return ORI; + case ORI: + return FED; + case KLI: + return ROM; + case ROM: + return KLI; + default: + return FED; + } +} + +#endif + +snake_torp(t, n, p) + struct torp *t; + int n; + struct player *p; +{ + t->t_no = n; + t->t_status = TMOVE; + t->t_owner = p->p_no; + t->t_team = p->p_team; + t->t_dir = 128; + if (plan_guard == 0) + t->t_damage = SNAKETORPDAMAGE; + else + t->t_damage = SNAKETORPDAMAGE * 10; + t->t_speed = 0; + if (berserk) + t->t_war = FED | ROM | ORI | KLI; + else if (target == -1) + t->t_war = 0; + else + t->t_war = perfs[0]->p_swar | perfs[0]->p_hostile; + t->t_fuse = MAXINT; + t->t_turns = 0; + p->p_ntorp++; +} + +struct player * +whokilledme(pt) + struct plasmatorp *pt; +{ + register i; + register struct phaser *j; + + for (i = 0, j = &phasers[i]; i < MAXPLAYER; i++, j++) + { + if (j->ph_status == PHHIT2) + { + if (debug) + { + fprintf(stderr, "found PHHIT2 from %d at %d,%d\n", players[i].p_no, + j->ph_x, j->ph_y); + fprintf(stderr, "plasma is at %d,%d\n", pt->pt_x, pt->pt_y); + fprintf(stderr, "fl is at %d,%d\n", fl->pt_x, fl->pt_y); + fprintf(stderr, "fr is at %d,%d\n", fr->pt_x, fr->pt_y); + } + if (j->ph_x == pt->pt_x && j->ph_y == pt->pt_y) + { + return &players[i]; + } + } + } + return NULL; +} + +/* + * NOTE: the procedure could be writing shared memory variables at the same + * time as the daemon. This may produce unpredicatable results. A better + * implementation would mark the "snake plasma" and have the daemon do the + * awarding. + */ + +award(win) + struct player *win; +{ + char buf[80]; + char addrbuf[10]; + + if (!win) + return; + + if (target == -1 && !(win->p_flags & PFROBOT) && !WARHOSTILE(win)) + { + strcpy(buf, "Snake eyes!"); + + /* what do we have for our big winner today, fred? */ + + if (((100 * win->p_damage) / win->p_ship.s_maxdamage) > 50 || + ((100 * win->p_shield) / win->p_ship.s_maxshield) < 50) + { + win->p_damage = 0; + win->p_shield = win->p_ship.s_maxshield; + strcat(buf, " You win free repairs!"); + } + else if (((100 * win->p_fuel) / win->p_ship.s_maxfuel) < 50) + { + win->p_fuel = win->p_ship.s_maxfuel; + strcat(buf, " You win free fuel!"); + } + else if (((100 * win->p_etemp) / win->p_ship.s_maxegntemp) > 60) + { + win->p_etemp = 0; + strcat(buf, " You win free engine cooling!"); + } + else if (((100 * win->p_wtemp) / win->p_ship.s_maxwpntemp) > 60) + { + win->p_wtemp = 0; + strcat(buf, " You win free weapons cooling!"); + } + else + { + win->p_damage = 0; + win->p_shield = win->p_ship.s_maxshield; + win->p_fuel = win->p_ship.s_maxfuel; + win->p_etemp = 0; + win->p_wtemp = 0; + strcat(buf, " You feel healthy!"); + } + + /* ... */ + + sprintf(addrbuf, "%s->%c%c", SERVNAME, + teams[win->p_team].letter, shipnos[win->p_no]); + pmessage2(buf, win->p_no, MINDIV, addrbuf, 255); + } + sprintf(buf, "%s (%c%c) slew the vile space serpent!", + win->p_name, teams[win->p_team].letter, shipnos[win->p_no]); + pmessage(buf, 0, MALL | MKILLA, MSERVA, 255); + + /* and get .5 kills */ + + win->p_kills += 0.5; + if (win->p_ship.s_type == STARBASE) + { + if (win->p_stats.st_sbmaxkills < win->p_kills) + { + win->p_stats.st_sbmaxkills = win->p_kills; + } + } + else if (win->p_stats.st_tmaxkills < win->p_kills) + { + win->p_stats.st_tmaxkills = win->p_kills; + } +} + +bombcheck(team1, team2) + int team1, team2; +{ + register i; + register struct player *j; + struct planet *p; + + for (i = 0, j = players; i < MAXPLAYER; i++, j++) + { + if (j->p_status == PALIVE) + { + if ((j->p_flags & PFBOMB) && (j->p_flags & PFORBIT)) + { + p = &planets[j->p_planet]; + if (!((j->p_swar | j->p_hostile) & p->pl_owner)) + continue; + + if (defenders[p->pl_owner] >= configvals->tournplayers) + continue; + +#if 0 + /* ignore planets that aren't within team boundaries */ + if (p->pl_x > boundaries[p->pl_owner].rx || + p->pl_x < boundaries[p->pl_owner].lx || + p->pl_y > boundaries[p->pl_owner].by || + p->pl_y < boundaries[p->pl_owner].ty) + continue; +#endif + + if (!team1 && !team2) + { + /* any planet */ + printf("snake found bomber: targeting %c%c\n", + teams[j->p_team].letter, shipnos[j->p_no]); + fflush(stdout); + make_war(j, p->pl_owner); + return j->p_no; + } + else + { + if (team1) + { + if (p->pl_owner == team1) + { + printf("found bomber: targeting %c%c\n", + teams[j->p_team].letter, shipnos[j->p_no]); + fflush(stdout); + make_war(j, p->pl_owner); + return j->p_no; + } + } + if (team2) + { + if (p->pl_owner == team2) + { + printf("found bomber: targeting %c%c\n", + teams[j->p_team].letter, shipnos[j->p_no]); + fflush(stdout); + make_war(j, p->pl_owner); + return j->p_no; + } + } + } + } + } + } + return -1; +} + +make_war(p, plteam) + struct player *p; + int plteam; +{ + register int i; + register struct player *j; + register struct torp *k; + + perfs[0]->p_team = plteam; + perfs[0]->p_swar = 0; + perfs[0]->p_hostile = 0; + perfs[1]->p_team = plteam; + perfs[1]->p_swar = 0; + perfs[1]->p_hostile = 0; + + perfs[0]->p_swar |= p->p_team; + perfs[0]->p_hostile |= p->p_team; + perfs[1]->p_swar |= p->p_team; + perfs[1]->p_hostile |= p->p_team; + + /* update our torps war status */ + for (j = perfs[0]; j; j = (j == perfs[1] ? NULL : perfs[1])) + { + for (i = j->p_no * MAXTORP, k = &torps[i]; + i < j->p_no * MAXTORP + length; i++, k++) + { + + k->t_war = perfs[0]->p_swar | perfs[0]->p_hostile; + } + } +} + + + +/* + * start planet areas are places where people will likely enter the game + * (only considers 1 start planet at this time) + */ + +sp_area(x, y) + int x, y; +{ + register i, j, px, py; + +#if 0 + /* check for proximity to a shipyard? */ + return 0; +#else + + for (i = 0; i < NUMPLANETS; i++) + { + struct planet *pl = &planets[i]; + if (!(pl->pl_flags & (PLSHIPYARD | PLHOME))) + continue; + px = pl->pl_x; + py = pl->pl_y; + /* printf("checking %s (%d,%d)\n", pl->pl_name, i*10,j); */ + + if (!(x < px - 5300 || x > px + 5300 || + y < py - 5300 || y > py + 5300)) + { +#ifdef maybe /* not used. */ + if (target != -1) + { + struct player *p = &players[target]; + /* + * if target is also in same home area, he should at least be able to + * phaser the snake since the torps are already deadly + */ + if (!(p->p_x < px - 5300 || p->p_x > px + 5300 || + p->p_y < py - 5300 || p->p_y > py + 5300)) + return 0; + else + return 1; + } +#endif + return 1; + } + } + + return 0; + +#endif +} diff -r 054275999194 -r 8c6d5731234d src/socket.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/socket.c Sat Dec 06 04:37:04 1997 +0000 @@ -0,0 +1,4607 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation, or any derivative works thereof, for any NON-COMMERCIAL +purpose and without fee is hereby granted, provided that this copyright +notice appear in all copies. No representations are made about the +suitability of this software for any purpose. This software is provided +"as is" without express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie +--------------------------------------------------------------------------*/ + + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "packets.h" +#include "shmem.h" +#include "path.h" +#include "gppackets.h" + +#ifdef OOPS +#ifdef MIPSEL +#ifndef htonl + +#define htonl(x) ((u_long) (((u_long) x << 24) | (((u_long) x & 0xff00) << 8) | \ + (((u_long) x & 0xff0000) >> 8) | ((u_long) x >> 24))) +#define ntohl(x) htonl(x) +#define htons(x) ((u_short) (((u_short) x << 8) | ((u_short) x >> 8))) +#define ntohs(x) htons(x) + +#endif /* htonl */ +#endif /* MIPSEL */ +#endif /* OOPS */ + +extern void (*r_signal()) (); + +/* #define DOUBLE_UDP /* comment this out to disable it */ + +/* #define BROKEN /* for local stress testing; drops 20% of packets */ +/* #define HOSED /* combine with BROKEN; drops 90% of packets */ + +void handleTorpReq(), handlePhasReq(), handleSpeedReq(); +void handleDirReq(), handleShieldReq(), handleRepairReq(), handleOrbitReq(); +void handlePractrReq(), handleBombReq(), handleBeamReq(), handleCloakReq(); +void handleDetTReq(), handleCopilotReq(); +void handleOutfit(), handleLoginReq(); +void handlePlasmaReq(), handleWarReq(), handlePlanlockReq(); +void handlePlaylockReq(), handleDetMReq(); +void handleTractorReq(), handleRepressReq(); +void handleCoupReq(), handleRefitReq(), handleMessageReq(); +void handleQuitReq(), handleOptionsPacket(); +void handleSocketReq(), handleByeReq(); +void handleDockingReq(), handleReset(); +void handleUpdatesReq(), handleReserved(); +void handleScan(); +void handleUdpReq(), handleSequence(); +void handleAskMOTD(); +void handleRSAKey(); +void handlePingResponse(); +#ifdef SHORT_PACKETS +void handleShortReq(), handleThresh(), handleSMessageReq(); +#endif +#ifdef FEATURE +void handleFeature(), sendFeature(); /* in feature.c */ +#endif + +static int remoteaddr = -1; /* inet address in net format */ +extern int errno; + +struct packet_handler handlers[] = { + {0}, /* record 0 */ + {handleMessageReq}, /* CP_MESSAGE */ + {handleSpeedReq}, /* CP_SPEED */ + {handleDirReq}, /* CP_DIRECTION */ + {handlePhasReq}, /* CP_PHASER */ + {handlePlasmaReq}, /* CP_PLASMA */ + {handleTorpReq}, /* CP_TORP */ + {handleQuitReq}, /* CP_QUIT */ + {handleLoginReq}, /* CP_LOGIN */ + {handleOutfit}, /* CP_OUTFIT */ + {handleWarReq}, /* CP_WAR */ + {handlePractrReq}, /* CP_PRACTR */ + {handleShieldReq}, /* CP_SHIELD */ + {handleRepairReq}, /* CP_REPAIR */ + {handleOrbitReq}, /* CP_ORBIT */ + {handlePlanlockReq}, /* CP_PLANLOCK */ + {handlePlaylockReq}, /* CP_PLAYLOCK */ + {handleBombReq}, /* CP_BOMB */ + {handleBeamReq}, /* CP_BEAM */ + {handleCloakReq}, /* CP_CLOAK */ + {handleDetTReq}, /* CP_DET_TORPS */ + {handleDetMReq}, /* CP_DET_MYTORP */ + {handleCopilotReq}, /* CP_COPLIOT */ + {handleRefitReq}, /* CP_REFIT */ + {handleTractorReq}, /* CP_TRACTOR */ + {handleRepressReq}, /* CP_REPRESS */ + {handleCoupReq}, /* CP_COUP */ + {handleSocketReq}, /* CP_SOCKET */ + {handleOptionsPacket}, /* CP_OPTIONS */ + {handleByeReq}, /* CP_BYE */ + {handleDockingReq}, /* CP_DOCKPERM */ + {handleUpdatesReq}, /* CP_UPDATES */ + {handleReset}, /* CP_RESETSTATS */ + {handleReserved}, /* CP_RESERVED */ + {handleScan}, /* CP_SCAN (ATM) */ + {handleUdpReq}, /* CP_UDP_REQ */ + {handleSequence}, /* CP_SEQUENCE */ + {handleRSAKey}, /* CP_RSA_KEY */ + {handleAskMOTD}, /* CP_ASK_MOTD */ + {0}, + {0}, + {0}, + {handlePingResponse}, /* CP_PING_RESPONSE */ +#ifdef SHORT_PACKETS + {handleShortReq}, /* CP_S_REQ */ + {handleThresh}, /* CP_S_THRS */ + {handleSMessageReq}, /* CP_S_MESSAGE */ + {0}, /* CP_S_RESERVED */ + {0}, /* CP_S_DUMMY */ +#else + {0}, + {0}, + {0}, + {0}, + {0}, +#endif + {0}, /* 48 */ + {0}, /* 49 */ + {0}, /* 50 */ + {0}, /* 51 */ + {0}, /* 52 */ + {0}, /* 53 */ + {0}, /* 54 */ + {0}, /* 55 */ + {0}, /* 56 */ + {0}, /* 57 */ + {0}, /* 58 */ + {0}, /* 59 */ + {handleFeature}, /* CP_FEATURE */ + {0} +}; +#define NUM_PACKETS (sizeof(handlers) / sizeof(*handlers) - 1) + +int size_of_spacket(); +int size_of_cpacket(); + +int packetsReceived[256] = {0}; +int packetsSent[256] = {0}; + +int clientDead = 0; + +static int udpLocalPort = 0; +static int udpClientPort = 0; +int udpMode = MODE_SIMPLE; /* what kind of UDP trans we want */ + +/* this stuff is used for Fat UDP */ +typedef void *PTR; /* adjust this if you lack (void *) */ +typedef struct fat_node_t +{ + PTR packet; + int pkt_size; + struct fat_node_t *prev; + struct fat_node_t *next; +} FAT_NODE; + +/* needed for fast lookup of semi-critical fat nodes */ +extern FAT_NODE fat_kills[MAXPLAYER]; +extern FAT_NODE fat_torp_info[MAXPLAYER * MAXTORP]; +extern FAT_NODE fat_thingy_info[TOTALTHINGIES]; +extern FAT_NODE fat_phaser[MAXPLAYER]; +extern FAT_NODE fat_plasma_info[MAXPLAYER * MAXPLASMA]; +extern FAT_NODE fat_you; +#if 0 +extern FAT_NODE fat_status; +extern FAT_NODE fat_planet[MAXPLANETS]; +#else +extern FAT_NODE fat_status2; +extern FAT_NODE fat_planet2[MAXPLANETS]; +#endif +extern FAT_NODE fat_flags[MAXPLAYER]; +extern FAT_NODE fat_hostile[MAXPLAYER]; + +struct plyr_info_spacket clientPlayersInfo[MAXPLAYER]; +struct plyr_login_spacket clientLogin[MAXPLAYER]; +struct hostile_spacket clientHostile[MAXPLAYER]; +struct stats_spacket clientStats[MAXPLAYER]; +struct player_spacket clientPlayers[MAXPLAYER]; +struct kills_spacket clientKills[MAXPLAYER]; +struct flags_spacket clientFlags[MAXPLAYER]; +struct pstatus_spacket clientPStatus[MAXPLAYER]; +int msgCurrent; +struct torp_info_spacket clientTorpsInfo[MAXPLAYER * MAXTORP]; +struct torp_spacket clientTorps[MAXPLAYER * MAXTORP]; +struct thingy_info_spacket clientThingysInfo[TOTALTHINGIES]; +struct thingy_spacket clientThingys[TOTALTHINGIES]; +int clientThingyStatus[TOTALTHINGIES]; +struct phaser_spacket clientPhasers[MAXPLAYER]; +struct you_spacket clientSelf; +struct pe1_num_missiles_spacket clientMissiles; +#if 0 +struct status_spacket clientStatus; +struct planet_spacket clientPlanets[MAXPLANETS]; +#endif +struct planet_loc_spacket clientPlanetLocs[MAXPLANETS]; +struct plasma_info_spacket clientPlasmasInfo[MAXPLAYER * MAXPLASMA]; +struct plasma_spacket clientPlasmas[MAXPLAYER * MAXPLASMA]; +int mustUpdate[MAXPLAYER]; +struct status_spacket2 clientStatus2; /* new stats packets */ +struct stats_spacket2 clientStats2[MAXPLAYER]; +struct planet_spacket2 clientPlanets2[MAXPLANETS]; + +#ifdef SHORT_PACKETS + +struct youss_spacket clientSelfShip; +struct youshort_spacket clientSelfShort; + +/* HW */ +static unsigned char clientVPlanets[MAXPLANETS * sizeof(struct planet_s_spacket) + 2 + 6]; +static int clientVPlanetCount; +static int vtsize[9] = {4, 8, 8, 12, 12, 16, 20, 20, 24}; /* How big is the + * SP_S_TORP packet */ +static int vtdata[9] = {0, 3, 5, 7, 9, 12, 14, 16, 18}; /* How big is Torpdata */ +static int mustsend; /* Flag to remind me that i must send + * SP_S_TORP */ + +static unsigned char clientVTorps[40]; + +static unsigned char clientVTorpsInfo[16]; + +static unsigned char clientVPlayers[MAXPLAYER * VPLAYER_SIZE + 16]; +#if MAXPLAYER > 32 +static unsigned char clientVXPlayers[33 * 4]; +#endif +static int clientVPlayerCount; +static int clientVXPlayerCount; +static int big, small; + +static int send_threshold = 0; /* infinity */ +static int send_short = 0; +static int send_mesg = 1; +static int send_kmesg = 1; +static int send_warn = 1; +static int numupdates = 5; /* For threshold */ +static int actual_threshold = 0;/* == send_threshold / numupdates */ +static int spk_update_sall = 0; /* Small Update: Only weapons, Kills and + * Planets */ +static int spk_update_all = 0; /* Full Update minus SP_STATS */ + +#define SPK_VOFF 0 /* variable packets off */ +#define SPK_VON 1 /* variable packets on */ +#define SPK_MOFF 2 /* message packets off */ +#define SPK_MON 3 /* message packets on */ +#define SPK_M_KILLS 4 +#define SPK_M_NOKILLS 5 +#define SPK_THRESHOLD 6 +#define SPK_M_WARN 7 +#define SPK_M_NOWARN 8 +#define SPK_SALL 9 /* only planets,kills and weapons */ +#define SPK_ALL 10 /* Full Update - SP_STATS */ + +#endif + + +extern long unsigned int inet_addr( /* ??? */ ); +void initClientData(); +void updateTorpInfos(); +void short_updateTorps(), updateTorps(); +void updateMissiles(); +void updateThingies(); +void updatePlasmas(); +void updateStatus(); +void updateSelf(); +void updatePhasers(); +void updateShips(); +void updatePlanets(); +void updateTerrain(); +void updateMessages(); +void sendMissileNum(); +extern void updateWarnings(); /* warning.c */ +void sendClientSizedPacket(); +void sendClientPacket(); +void flushSockBuf(); +void updateMOTD(); +int parseQuery(); +void bounce(); +int gwrite(); +void printUdpInfo(); +int closeUdpConn(); +void updateFat(); +int fatten(); +void fatMerge(); +int doRead(); +extern int read(); +extern void perror(); +void logmessage(); +extern int ntorp(); +extern int phaser(); +extern int set_speed(); +extern int set_course(); +extern int shield_up(); +extern int shield_down(); +extern int repair(); +extern int orbit(); +extern pid_t fork(); +extern int execl(); +extern int bomb_planet(); +extern int beam_up(); +extern int beam_down(); +extern int cloak_on(); +extern int cloak_off(); +extern void detothers(); +extern void fire_missile_dir(); +extern int nplasmatorp(); +extern int lock_planet(); +extern int lock_player(); +extern int do_refit(); +extern int pmessage2(); +extern int parse_command_mess(); +extern int write(); +extern int setitimer(); +extern int gethostname(); +extern int decryptRSAPacket(); +extern int makeRSAPacket(); +extern int encryptReservedPacket(); +void forceUpdate(); +int connUdpConn(); +extern int sendMotd(); +void dequeue(); +void enqueue(); +extern int pmessage(); + +int +connectToClient(machine, port) + char *machine; + int port; +{ + int ns; + struct sockaddr_in addr; + struct hostent *hp; + /* int len,cc; */ + /* char buf[BUFSIZ]; */ + /* int i; */ + + if (sock != -1) + { + shutdown(sock, 2); + sock = -1; + } + /* printf("Connecting to %s through %d\n", machine, port); */ + + if ((ns = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + printf("I cannot create a socket\n"); + exit(2); + } + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + if (remoteaddr != -1) + { + addr.sin_addr.s_addr = remoteaddr; + } + else if ((addr.sin_addr.s_addr = inet_addr(machine)) == -1) + { + if ((hp = gethostbyname(machine)) == NULL) + { + printf("I cannot get host name\n"); + close(ns); + exit(1); + } + else + { +#if 1 + memcpy((char *) &addr.sin_addr, hp->h_addr, hp->h_length); +#else + addr.sin_addr.s_addr = *(long *) hp->h_addr; +#endif + } + } + remoteaddr = addr.sin_addr.s_addr; + + if (connect(ns, (struct sockaddr *) & addr, sizeof(addr)) < 0) + { + /* printf("I cannot connect through port %d\n", port); */ + close(ns); + return (0); + } + sock = ns; + initClientData(); + testtime = -1; + return (1); +} + +/* + * Check the socket to read it's inet addr for possible future use. + */ +void +checkSocket() +{ + struct sockaddr_in sin; + int length; + + length = sizeof(sin); + if (getpeername(sock, (struct sockaddr *) & sin, &length) < 0) + { + /* A bad thing. */ + return; + } + remoteaddr = sin.sin_addr.s_addr; +} + +void +initClientData() +/* invalidates all data, so it is all sent to the client */ +{ + int i; + + clientDead = 0; + clientMissiles.num = 0; + for (i = 0; i < MAXPLAYER; i++) + { + clientHostile[i].hostile = -1; + clientStats[i].losses = -1; + clientLogin[i].rank = -1; + clientPlayersInfo[i].shiptype = -1; + clientPStatus[i].status = -1; + clientPlayers[i].x = htonl(-1); + clientPhasers[i].status = -1; + clientKills[i].kills = htonl(-1); + clientFlags[i].flags = htonl(-1); + mustUpdate[i] = 0; + + fat_hostile[i].packet = (PTR) & clientHostile[i]; + fat_hostile[i].pkt_size = sizeof(struct hostile_spacket); + fat_hostile[i].prev = fat_hostile[i].next = (FAT_NODE *) NULL; + fat_phaser[i].packet = (PTR) & clientPhasers[i]; + fat_phaser[i].pkt_size = sizeof(struct phaser_spacket); + fat_phaser[i].prev = fat_phaser[i].next = (FAT_NODE *) NULL; + fat_kills[i].packet = (PTR) & clientKills[i]; + fat_kills[i].pkt_size = sizeof(struct kills_spacket); + fat_kills[i].prev = fat_kills[i].next = (FAT_NODE *) NULL; + fat_flags[i].packet = (PTR) & clientFlags[i]; + fat_flags[i].pkt_size = sizeof(struct flags_spacket); + fat_flags[i].prev = fat_flags[i].next = (FAT_NODE *) NULL; + } + for (i = 0; i < MAXPLAYER * MAXTORP; i++) + { + clientTorpsInfo[i].status = -1; + clientTorps[i].x = -1; + + fat_torp_info[i].packet = (PTR) & clientTorpsInfo[i]; + fat_torp_info[i].pkt_size = sizeof(struct torp_info_spacket); + fat_torp_info[i].prev = fat_torp_info[i].next = (FAT_NODE *) NULL; + } + for (i = 0; i < TOTALTHINGIES; i++) + { + clientThingysInfo[i].shape = htons(-1); + clientThingysInfo[i].owner = htons(i / NPTHINGIES); + clientThingys[i].x = htonl(-1); + + fat_thingy_info[i].packet = (PTR) & clientThingysInfo[i]; + fat_thingy_info[i].pkt_size = sizeof(struct torp_info_spacket); + fat_thingy_info[i].prev = fat_thingy_info[i].next = (FAT_NODE *) NULL; + } + for (i = 0; i < MAXPLAYER * MAXPLASMA; i++) + { + clientPlasmasInfo[i].status = -1; + clientPlasmas[i].x = -1; + + fat_plasma_info[i].packet = (PTR) & clientPlasmasInfo[i]; + fat_plasma_info[i].pkt_size = sizeof(struct plasma_info_spacket); + fat_plasma_info[i].prev = fat_plasma_info[i].next = (FAT_NODE *) NULL; + } + for (i = 0; i < MAXPLANETS; i++) + { + clientPlanets2[i].armies = htonl(-1); + clientPlanetLocs[i].x = htonl(-1); + +#if 0 + fat_planet[i].packet = (PTR) & clientPlanets[i]; + fat_planet[i].pkt_size = sizeof(struct planet_spacket); + fat_planet[i].prev = fat_planet[i].next = (FAT_NODE *) NULL; +#else + fat_planet2[i].packet = (PTR) & clientPlanets2[i]; + fat_planet2[i].pkt_size = sizeof(struct planet_spacket2); + fat_planet2[i].prev = fat_planet2[i].next = (FAT_NODE *) 0; +#endif + } + msgCurrent = (mctl->mc_current + 1) % MAXMESSAGE; + clientSelf.pnum = -1; + + fat_you.packet = (PTR) & clientSelf; + fat_you.pkt_size = sizeof(struct you_spacket); + fat_you.prev = fat_you.next = (FAT_NODE *) NULL; +#if 0 + fat_status.packet = (PTR) & clientStatus; + fat_status.pkt_size = sizeof(struct status_spacket); + fat_status.prev = fat_status.next = (FAT_NODE *) NULL; +#else + fat_status2.packet = (PTR) & clientStatus2; + fat_status2.pkt_size = sizeof(struct status_spacket2); + fat_status2.prev = fat_status2.next = (FAT_NODE *) 0; +#endif + + reset_fat_list(); +} + +int +isClientDead() +{ + return (clientDead); +} + +void +updateClient() +{ + int i; + + for (i = 0; i < MAXPLAYER; i++) + { + mustUpdate[i] = 0; + } + updateShips(); +#ifdef SHORT_PACKETS + if (send_short) + { + short_updateTorps(); + } + else +#endif + { + updateTorps(); + updateTorpInfos(); + } + + if (weaponsallowed[WP_MISSILE] || + weaponsallowed[WP_FIGHTER]) + updateMissiles(); + updateThingies(); + sendMissileNum(me->p_ship.s_missilestored); + updatePlasmas(); + updateStatus(); + updateSelf(); + updatePhasers(); + updatePlanets(); + updateTerrain(); /* for galaxy reset */ + updateMessages(); + updateWarnings(); /* warning.c */ + + /* + * these checks are here to make sure we don't ping from the updateClient + * call in death(). The reason is that savestats() can take > 100ms, + * invalidating the next ping lag calc + */ + /* Also, don't ping while in verification stage */ + + if (ping + && (repCount % efticks(5 * configvals->ping_period) == 0) + && me->p_status != PDEAD + && me->p_status != POUTFIT + /* && me->p_status != PTQUEUE */ +#ifdef AUTHORIZE + && testtime <= 0 +#endif + ) + sendClientPing(); /* ping.c */ + + if (buffersEmpty()) + { + /* We sent nothing! We better send something to wake him */ + sendClientPacket((struct player_spacket *) & clientSelf); + } + flushSockBuf(); + repCount++; +} + +void +briefUpdateClient() +{ + updateMessages(); + updateMOTD(); + updateWarnings(); + + flushSockBuf(); + repCount++; +} + +void +updateStatus() +{ + if (repCount % efticks(75) == 0 && + ((ntohl(clientStatus2.timeprod) != status->timeprod) || + (clientStatus2.tourn != status->tourn))) + { + clientStatus2.type = SP_STATUS2; + clientStatus2.tourn = status->tourn; + clientStatus2.dooshes = htonl(status->dooshes); + clientStatus2.armsbomb = htonl(status->armsbomb); + clientStatus2.resbomb = htonl(status->resbomb); + clientStatus2.planets = htonl(status->planets); + clientStatus2.kills = htonl(status->kills); + clientStatus2.losses = htonl(status->losses); + clientStatus2.sbkills = htonl(status->sbkills); + clientStatus2.sblosses = htonl(status->sblosses); + clientStatus2.sbtime = htonl(status->sbtime); + clientStatus2.wbkills = htonl(status->wbkills); + clientStatus2.wblosses = htonl(status->wblosses); + clientStatus2.wbtime = htonl(status->wbtime); + clientStatus2.jsplanets = htonl(status->jsplanets); + clientStatus2.jstime = htonl(status->jstime); + clientStatus2.time = htonl(status->time); + clientStatus2.timeprod = htonl(status->timeprod); + sendClientPacket((struct player_spacket *) & clientStatus2); + } +} + +struct player * +maybe_watching(p) + struct player *p; +{ + struct player *tg = &players[me->p_playerl]; + return (p == me + && me->p_status == POBSERVE + && (me->p_flags & PFPLOCK) + && (me->p_teamspy & tg->p_team) + && tg->p_spyable) ? + tg : p; +} + +struct planet * +maybe_watching_planet() +{ + return (me->p_status == POBSERVE && (me->p_flags & PFPLLOCK)) ? + &planets[me->p_planet] : 0; +} + +void +updateSelf() +{ + struct player *watched = maybe_watching(me); + int armies = maybe_watching_planet() + ? maybe_watching_planet()->pl_armies + : watched->p_armies; + int damage; + + damage = watched->p_damage + + shipvals[watched->p_ship.s_type].s_maxdamage + - watched->p_ship.s_maxdamage; + + if (ntohl(clientSelf.fuel) != watched->p_fuel || + ntohl(clientSelf.shield) != watched->p_shield || + ntohl(clientSelf.damage) != damage || + ntohs(clientSelf.etemp) != watched->p_etemp || + ntohs(clientSelf.wtemp) != watched->p_wtemp || + ntohl(clientSelf.flags) != watched->p_flags || + clientSelf.armies != armies || + clientSelf.swar != watched->p_swar || + ntohs(clientSelf.whydead) != watched->p_whydead || + ntohs(clientSelf.whodead) != watched->p_whodead || + clientSelf.pnum != me->p_no) + { + + /* we want to send it, but how? */ + clientSelf.type = SP_YOU; + + if (commMode == COMM_UDP) + { + if (ntohl(clientSelf.flags) != watched->p_flags || + clientSelf.armies != armies || + clientSelf.swar != watched->p_swar) + { + clientSelf.type = SP_YOU | 0x40; /* mark as semi-critical */ + } + if (ntohs(clientSelf.whydead) != watched->p_whydead || + ntohs(clientSelf.whodead) != watched->p_whodead || + clientSelf.pnum != me->p_no) + { + clientSelf.type = SP_YOU | 0x80; /* mark as critical */ + } + } + clientSelf.pnum = me->p_no; + clientSelf.flags = htonl(watched->p_flags); + clientSelf.swar = watched->p_swar; + clientSelf.hostile = watched->p_hostile; + clientSelf.armies = armies; + clientSelf.shield = htonl(watched->p_shield); + clientSelf.fuel = htonl(watched->p_fuel); + clientSelf.etemp = htons(watched->p_etemp); + clientSelf.wtemp = htons(watched->p_wtemp); + clientSelf.whydead = htons(watched->p_whydead); + clientSelf.whodead = htons(watched->p_whodead); + clientSelf.damage = htonl(damage); + /* ATM - visible tractor */ + clientSelf.tractor = (char) watched->p_tractor | 0x40; + + clientSelf.pad2 = (unsigned char) (status->clock & 0xFF); + clientSelf.pad3 = (unsigned char) ((status->clock & 0xFF00) >> 8); + sendClientPacket((struct player_spacket *) & clientSelf); + } +} + +extern int ignored[]; + +void +updateShips() +{ + register int i; + register struct player *pl; + register struct plyr_info_spacket *cpli; + register struct player_spacket *cpl; + register struct kills_spacket *kills; + register struct flags_spacket *flags; + register struct pstatus_spacket *pstatus; + register struct plyr_login_spacket *login; + register struct hostile_spacket *hostile; +#if 0 + struct stats_spacket ms_stats; +#endif + register struct stats_spacket2 *stats; + int update; + int x, y; + /* + * #define FLAGMASK + * (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFBEAMUP|PFBEAMDOWN|PFPRACTR|PFD + * OCK|PFTRACT|PFPRESS|PFDOCKOK) atm mask + */ + + /* + * #define FLAGMASK + * (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFBEAMUP|PFBEAMDOWN|PFPRACTR|PFD + * OCK|PFTRACT|PFPRESS|PFDOCKOK) aieee, too much. 7/27/91 TC + */ + +#define FLAGMASK (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFPRACTR|PFDOCK|PFTRACT|PFPRESS|PFDOCKOK) +#define INVISOMASK (PFCLOAK|PFROBOT|PFPRACTR|PFDOCKOK) + + /* Please excuse the ugliness of this loop declaration */ + for (i = 0, pl = players, cpli = clientPlayersInfo, cpl = clientPlayers, kills = clientKills, flags = clientFlags, pstatus = clientPStatus, login = clientLogin, hostile = clientHostile, stats = clientStats2; + i < MAXPLAYER; + i++, pl++, cpli++, cpl++, kills++, flags++, pstatus++, login++, hostile++, stats++) + { + update = 0; + if (strcmp(pl->p_name, login->name) != 0 || + pl->p_stats.st_rank != login->rank || + strcmp(pl->p_monitor, login->monitor) != 0) + { + strncpy(login->name, pl->p_name, 15); + strncpy(login->monitor, pl->p_monitor, 15); + strncpy(login->login, pl->p_login, 15); + login->name[15] = 0; + login->monitor[15] = 0; + login->login[15] = 0; + login->type = SP_PL_LOGIN; + login->pnum = i; + login->rank = pl->p_stats.st_rank; + sendClientPacket((struct player_spacket *) login); + } + if ((pl != me && (pl->p_swar & me->p_team) != hostile->war) || + (pl != me && (pl->p_hostile & me->p_team) != hostile->hostile) || + (pl == me && pl->p_swar != hostile->war) || + (pl == me && pl->p_hostile != hostile->hostile)) + { + hostile->type = SP_HOSTILE; + if (pl == me) + { + hostile->war = pl->p_swar; + hostile->hostile = pl->p_hostile; + } + else + { + hostile->war = (pl->p_swar & me->p_team); + hostile->hostile = (pl->p_hostile & me->p_team); + } + hostile->pnum = i; + sendClientPacket((struct player_spacket *) hostile); + } + /* + * Send stat packets once per five updates. But, only send one. We will + * cycle through them all eventually. + */ + /* + * Also, update if status chages (i.e., entered game, died, tq'ed, etc) + */ + + if (pl->p_status != pstatus->status || + (repCount % (MAXPLAYER * efticks(5)) == i * efticks(5) && + (stats->di != htonl(pl->p_stats.st_di) || + stats->kills != htonl(pl->p_stats.st_tkills) || + stats->losses != htonl(pl->p_stats.st_tlosses) || + stats->armsbomb != htonl(pl->p_stats.st_tarmsbomb) || + stats->resbomb != htonl(pl->p_stats.st_tresbomb) || + stats->dooshes != htonl(pl->p_stats.st_tdooshes) || + stats->planets != htonl(pl->p_stats.st_tplanets) || + stats->sbkills != htonl(pl->p_stats.st_sbkills) || + stats->sblosses != htonl(pl->p_stats.st_sblosses) || + stats->wbkills != htonl(pl->p_stats.st_wbkills) || + stats->wblosses != htonl(pl->p_stats.st_wblosses) || + stats->jsplanets != htonl(pl->p_stats.st_jsplanets) || + stats->rank != htonl(pl->p_stats.st_rank) || + stats->royal != htonl(pl->p_stats.st_royal)))) + { + + stats->genocides = htonl(pl->p_stats.st_genocides); + stats->maxkills = htonl((int) (pl->p_stats.st_tmaxkills * 100)); + stats->di = htonl((int) (pl->p_stats.st_di * 100)); + stats->kills = htonl(pl->p_stats.st_tkills); + stats->losses = htonl(pl->p_stats.st_tlosses); + stats->armsbomb = htonl(pl->p_stats.st_tarmsbomb); + stats->resbomb = htonl(pl->p_stats.st_tresbomb); + stats->dooshes = htonl(pl->p_stats.st_tdooshes); + stats->planets = htonl(pl->p_stats.st_tplanets); + stats->tticks = htonl(pl->p_stats.st_tticks); + stats->sbkills = htonl(pl->p_stats.st_sbkills); + stats->sblosses = htonl(pl->p_stats.st_sblosses); + stats->sbticks = htonl(pl->p_stats.st_sbticks); + stats->sbmaxkills = htonl((int) (pl->p_stats.st_sbmaxkills * 100)); + stats->wbkills = htonl(pl->p_stats.st_wbkills); + stats->wblosses = htonl(pl->p_stats.st_wblosses); + stats->wbticks = htonl(pl->p_stats.st_wbticks); + stats->wbmaxkills = htonl((int) (pl->p_stats.st_wbmaxkills * 100)); + stats->jsplanets = htonl(pl->p_stats.st_jsplanets); + stats->jsticks = htonl(pl->p_stats.st_jsticks); + stats->rank = htonl(pl->p_stats.st_rank); + stats->royal = htonl(pl->p_stats.st_royal); + stats->type = SP_STATS2; + stats->pnum = i; + /* if (blk_metaserver == 0) */ + sendClientPacket((struct player_spacket *) stats); +#if 0 + else + { + ms_stats.type = SP_STATS; + ms_stats.pnum = i; + ms_stats.tkills = htonl(pl->p_stats.st_tkills); + ms_stats.tlosses = htonl(pl->p_stats.st_tlosses); + ms_stats.kills = htonl(1); + ms_stats.losses = htonl(1); + ms_stats.tticks = htonl(pl->p_stats.st_tticks); + ms_stats.tplanets = htonl(pl->p_stats.st_tplanets); + ms_stats.tarmies = htonl(pl->p_stats.st_tarmsbomb); + ms_stats.sbkills = htonl(pl->p_stats.st_sbkills); + ms_stats.sblosses = htonl(pl->p_stats.st_sblosses); + ms_stats.armies = htonl(1); + ms_stats.planets = htonl(1); + ms_stats.maxkills = htonl((long) (pl->p_stats.st_tmaxkills * 100)); + ms_stats.sbmaxkills = htonl((long) (pl->p_stats.st_sbmaxkills * 100)); + sendClientPacket((struct player_spacket *) & ms_stats); + } +#endif + } + if (maybe_watching(pl)->p_ship.s_type != cpli->shiptype || + pl->p_team != cpli->team) + { + cpli->type = SP_PLAYER_INFO; + cpli->pnum = i; + cpli->shiptype = maybe_watching(pl)->p_ship.s_type; + cpli->team = pl->p_team; + sendClientPacket((struct player_spacket *) cpli); + /* + * if (!blk_flag) cpli->shiptype=pl->p_ship.s_type; + */ + } + if (kills->kills != htonl((int) (maybe_watching(pl)->p_kills * 100))) + { + kills->type = SP_KILLS; + kills->pnum = i; + kills->kills = htonl((int) (maybe_watching(pl)->p_kills * 100)); + sendClientPacket((struct player_spacket *) kills); + } + { + int plstat = pl->p_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused && pl->p_team != me->p_team) + plstat = PFREE; /* enemies are invisible when the game is + * paused */ +#endif + + if (pstatus->status != plstat) + { + /* + * We update the location of people whose status has changed. (like + * if they just re-entered...) + */ + update = 1; + pstatus->type = SP_PSTATUS; + pstatus->pnum = i; + pstatus->status = plstat; + if (pl->p_status == PFREE) + { + /* + * I think this will turn off ignores for players that leave. + * 7/24/91 TC + */ + ignored[i] = 0; + } + sendClientPacket((struct player_spacket *) pstatus); + } + } + + /* Used to send flags here, see below 8/7/91 TC */ + + if (!configvals->hiddenenemy || pl->p_team == me->p_team || + (maybe_watching(pl)->p_flags & PFSEEN) || (status->tourn == 0) || + (maybe_watching(pl)->p_flags & PFROBOT)) + { /* a bot never has its PFSEEN bit set */ + + x = maybe_watching(pl)->p_x; + y = maybe_watching(pl)->p_y; + if (me != pl && flags->flags != + htonl(FLAGMASK & maybe_watching(pl)->p_flags)) + { + flags->type = SP_FLAGS; + flags->pnum = i; + flags->flags = htonl(FLAGMASK & maybe_watching(pl)->p_flags); + flags->tractor = (char) maybe_watching(pl)->p_tractor | 0x40; /* ATM - visible tractor */ + sendClientPacket((struct player_spacket *) flags); + } + } + else + { + /* A hack to make him inviso */ + x = -100000; + y = -100000; + + /* reduce flag info if he's inviso 8/7/91 TC */ + + if (me != pl && flags->flags != htonl(INVISOMASK & pl->p_flags)) + { + flags->type = SP_FLAGS; + flags->pnum = i; + flags->flags = htonl(INVISOMASK & pl->p_flags); + sendClientPacket((struct player_spacket *) flags); + } + } + if (x != ntohl(cpl->x) || y != ntohl(cpl->y) || + maybe_watching(pl)->p_dir != cpl->dir || + maybe_watching(pl)->p_speed != cpl->speed) + { + /* + * We update the player if: 1) haven't updated him for 9 intervals. 2) + * he is on the screen 3) he was on the screen recently. + */ + if (!update && repCount % efticks(9) != 0 && + (ntohl(cpl->x) < me->p_x - SCALE * WINSIDE / 2 || + ntohl(cpl->x) > me->p_x + SCALE * WINSIDE / 2 || + ntohl(cpl->y) > me->p_y + SCALE * WINSIDE / 2 || + ntohl(cpl->y) < me->p_y - SCALE * WINSIDE / 2) && + (y > me->p_y + SCALE * WINSIDE / 2 || + x > me->p_x + SCALE * WINSIDE / 2 || + x < me->p_x - SCALE * WINSIDE / 2 || + y < me->p_y - SCALE * WINSIDE / 2)) + continue; + /* + * If the guy is cloaked, give information only occasionally, and make + * it slightly inaccurate. Also, we don't give a direction. The client + * has no reason to know. + */ + if ((pl->p_flags & PFCLOAK) && + (pl->p_cloakphase == (CLOAK_PHASES - 1)) && + (maybe_watching(me) != pl) && !mustUpdate[i]) + { + if (repCount % efticks(9) != 0) + continue; + cpl->type = SP_PLAYER; + cpl->pnum = i; + cpl->x = htonl(x + (lrand48() % 2000) - 1000); + cpl->y = htonl(y + (lrand48() % 2000) - 1000); + sendClientPacket(cpl); + continue; + } + cpl->type = SP_PLAYER; + cpl->pnum = i; + cpl->x = htonl(x); + cpl->y = htonl(y); + cpl->speed = maybe_watching(pl)->p_speed; + cpl->dir = maybe_watching(pl)->p_dir; + sendClientPacket(cpl); + } + } +} + +void +updateTorpInfos() +{ + register struct torp *torp; + register int i; + register struct torp_info_spacket *tpi; + + for (i = 0, torp = torps, tpi = clientTorpsInfo; + i < MAXPLAYER * MAXTORP; + i++, torp++, tpi++) + { + if (torp->t_owner == me->p_no) + { + if (torp->t_war != tpi->war || + torp->t_status != tpi->status) + { + tpi->type = SP_TORP_INFO; + tpi->war = torp->t_war; + tpi->status = torp->t_status; + tpi->tnum = htons(i); + sendClientPacket((struct player_spacket *) tpi); + } + } + else + { /* Someone else's torp... */ + if (torp->t_y > me->p_y + SCALE * WINSIDE / 2 || + torp->t_x > me->p_x + SCALE * WINSIDE / 2 || + torp->t_x < me->p_x - SCALE * WINSIDE / 2 || + torp->t_y < me->p_y - SCALE * WINSIDE / 2 || + torp->t_status == TFREE) + { + if (torp->t_status == TFREE && tpi->status == TEXPLODE) + { + tpi->status = TFREE; + continue; + } + if (tpi->status != TFREE) + { + tpi->status = TFREE; + tpi->tnum = htons(i); + tpi->type = SP_TORP_INFO; + sendClientPacket((struct player_spacket *) tpi); + } + } + else + { /* in view */ + enum torp_status_e tstatus = torp->t_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused + && players[torp->t_owner].p_team != me->p_team) + tstatus = TFREE; /* enemy torps are invisible during game + * pause */ +#endif + + if (tstatus != tpi->status || + (torp->t_war & me->p_team) != tpi->war) + { + /* Let the client fade away the explosion on its own */ + tpi->war = torp->t_war & me->p_team; + tpi->type = SP_TORP_INFO; + tpi->tnum = htons(i); + tpi->status = tstatus; + sendClientPacket((struct player_spacket *) tpi); + } + } + } + } +} + + + +void +updateTorps() +{ + register struct torp *torp; + register int i; + register struct torp_spacket *tp; + + for (i = 0, torp = torps, tp = clientTorps; + i < MAXPLAYER * MAXTORP; + i++, torp++, tp++) + { + if (torp->t_owner == me->p_no) + { + + if (tp->x != htonl(torp->t_x) || + tp->y != htonl(torp->t_y)) + { + tp->type = SP_TORP; + tp->x = htonl(torp->t_x); + tp->y = htonl(torp->t_y); + tp->dir = torp->t_dir; + tp->tnum = htons(i); + sendClientPacket((struct player_spacket *) tp); + } + } + else + { /* Someone else's torp... */ + if (torp->t_y > me->p_y + SCALE * WINSIDE / 2 || + torp->t_x > me->p_x + SCALE * WINSIDE / 2 || + torp->t_x < me->p_x - SCALE * WINSIDE / 2 || + torp->t_y < me->p_y - SCALE * WINSIDE / 2 || + torp->t_status == TFREE) + { + /* do nothing */ + } + else + { /* in view */ + enum torp_status_e tstatus = torp->t_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused + && players[torp->t_owner].p_team != me->p_team) + tstatus = TFREE; /* enemy torps are invisible during game + * pause */ +#endif + + if (tstatus == TFREE) + continue; /* no need to transmit position */ + + if (tp->x != htonl(torp->t_x) || + tp->y != htonl(torp->t_y)) + { + tp->x = htonl(torp->t_x); + tp->y = htonl(torp->t_y); + tp->dir = torp->t_dir; + tp->tnum = htons(i); + tp->type = SP_TORP; + sendClientPacket((struct player_spacket *) tp); + } + } + } + } +} + +#ifdef SHORT_PACKETS + +#define NIBBLE() *(*data)++ = (torp->t_war & 0xf) | (torp->t_status << 4) + +int +encode_torp_status(torp, pnum, data, tpi, tp, mustsend) + struct torp *torp; + int pnum; + char **data; + struct torp_info_spacket *tpi; + struct torp_spacket *tp; + int *mustsend; +{ + if (pnum != me->p_no) + { + int dx, dy; + int i = SCALE * WINSIDE / 2; + dx = me->p_x - torp->t_x; + dy = me->p_y - torp->t_y; + if (dx < -i || dx > i || dy < -i || dy > i || torp->t_status == TFREE) + { + if (torp->t_status == TFREE && tpi->status == TEXPLODE) + tpi->status = TFREE; + else if (tpi->status != TFREE) + { + tpi->status = TFREE; + *mustsend = 1; + } + return 0; + } + } + + if (torp->t_war != tpi->war) + { + tpi->war = torp->t_war; + tpi->status = torp->t_status; + NIBBLE(); + return 1; + } + else if (torp->t_status != tpi->status) + { + switch (torp->t_status) + { + case TFREE: + { + int rval = 0; + if (tpi->status == TEXPLODE) + { + NIBBLE(); + rval = 1; + } + else + *mustsend = 1; + tpi->status = torp->t_status; + tp->x = htonl(torp->t_x); + tp->y = htonl(torp->t_y); + return rval; + } + break; + case TMOVE: + case TSTRAIGHT: + tpi->status = torp->t_status; + break; + default: + NIBBLE(); + tpi->status = torp->t_status; + return 1; + break; + } + } + return 0; +} + +#define TORP_INVISIBLE(tstatus) ( \ + (tstatus)== TFREE || \ + (tstatus) == TOFF || \ + (tstatus) == TLAND) + +int +encode_torp_position(torp, pnum, data, shift, cache) + struct torp *torp; + int pnum; + char **data; + int *shift; + struct torp_spacket *cache; +{ + int x, y; + + if (htonl(torp->t_x) == cache->x && + htonl(torp->t_y) == cache->y) + return 0; + + cache->x = htonl(torp->t_x); + cache->y = htonl(torp->t_y); + + if (TORP_INVISIBLE(torp->t_status) +#ifdef LEAGUE_SUPPORT + || (status2->paused && + players[pnum].p_team != me->p_team) +#endif + ) + return 0; + + x = torp->t_x / SCALE - me->p_x / SCALE + WINSIDE / 2; + y = torp->t_y / SCALE - me->p_y / SCALE + WINSIDE / 2; + + if (x < 0 || x >= WINSIDE || + y < 0 || y >= WINSIDE) + { + if (pnum != me->p_no) + return 0; + x = y = 501; + } + + **data |= x << *shift; + *(++(*data)) = (0x1ff & x) >> (8 - *shift); + (*shift)++; + **data |= y << *shift; + *(++(*data)) = (0x1ff & y) >> (8 - *shift); + (*shift)++; + if (*shift == 8) + { + *shift = 0; + *(++(*data)) = 0; + } + return 1; +} + +void +short_updateTorps() +{ + register int i; + + for (i = 0; i <= (MAXPLAYER * MAXTORP - 1) / 8; i++) + { + struct torp *torp = &torps[i * 8]; + int j; + char packet[2 /* packet type and player number */ + + 1 /* torp mask */ + + 1 /* torp info mask */ + + 18 /* 2*8 9-bit numbers */ + + 8 /* 8 torp info bytes */ + ]; + char *data = packet + 4; + char info[8]; + char *ip = info; + int shift = 0; + int torppos_mask = 0; + int torpinfo_mask = 0; + int mustsend; + + /* encode screen x and y coords */ + data[0] = 0; +#define TIDX (j+i*8) +#define PNUM ((int)((j+i*8)/MAXTORP)) + for (j = 0; j < 8 && TIDX < MAXPLAYER * MAXTORP; j++) + { + torpinfo_mask |= encode_torp_status + (&torp[j], PNUM, &ip, &clientTorpsInfo[TIDX], &clientTorps[TIDX], &mustsend) << j; + torppos_mask |= encode_torp_position + (&torp[j], PNUM, &data, &shift, &clientTorps[TIDX]) << j; + } + + /* + * if (!torppos_mask) continue; + */ + + if (torpinfo_mask) + { + if (shift) + data++; + for (j = 0; j < 8 && &info[j] < ip; j++) + data[j] = info[j]; + packet[0] = SP_S_TORP_INFO; + packet[1] = torppos_mask; + packet[2] = i; + packet[3] = torpinfo_mask; + sendClientSizedPacket(packet, (data - packet + j)); + } + else if (torppos_mask == 0xff) + { + /* what a disgusting hack */ + packet[2] = SP_S_8_TORP; + packet[3] = i; + sendClientSizedPacket(packet + 2, 20); + } + else if (mustsend || torppos_mask != 0) + { + packet[1] = SP_S_TORP; + packet[2] = torppos_mask & 0xff; + packet[3] = i; + sendClientSizedPacket(packet + 1, (data - (packet + 1) + (shift != 0))); + } + } +#undef PNUM +#undef TIDX +} + + +#endif + + +void +updateMissiles() +{ + register struct missile *missile; + register int i; + register struct thingy_info_spacket *dpi; + register struct thingy_spacket *dp; + + for (i = 0, missile = missiles, dpi = clientThingysInfo, dp = clientThingys; + i < MAXPLAYER * NPTHINGIES; + i++, missile++, dpi++, dp++) + { + enum torp_status_e msstatus = missile->ms_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused && + players[missile->ms_owner].p_team != me->p_team) + msstatus = TFREE; /* enemy torps are invisible during game + * pause */ +#endif + + switch (msstatus) + { + case TFREE: + case TLAND: + case TOFF: + dpi->shape = htons(SHP_BLANK); + break; + case TMOVE: + case TRETURN: + case TSTRAIGHT: + dpi->shape = htons((missile->ms_type == FIGHTERTHINGY) + ? SHP_FIGHTER + : SHP_MISSILE); + break; + case TEXPLODE: + case TDET: + dpi->shape = htons(SHP_PBOOM); + break; + } + + dpi->type = SP_THINGY_INFO; + dpi->tnum = htons(i); + + dp->type = SP_THINGY; + dp->tnum = htons(i); + dp->dir = missile->ms_dir; + + if (missile->ms_owner == me->p_no) + { + if (missile->ms_war != dpi->war || + msstatus != clientThingyStatus[i]) + { + dpi->war = missile->ms_war; + clientThingyStatus[i] = msstatus; + sendClientPacket((struct player_spacket *) dpi); + } + if (dp->x != htonl(missile->ms_x) || + dp->y != htonl(missile->ms_y)) + { + dp->x = htonl(missile->ms_x); + dp->y = htonl(missile->ms_y); + /* printf("missile at %d,%d\n", dp->x, dp->y); */ + sendClientPacket((struct player_spacket *) dp); + } + } + else + { /* Someone else's missile... */ + if (msstatus == TFREE || + missile->ms_y > me->p_y + SCALE * WINSIDE / 2 || + missile->ms_x > me->p_x + SCALE * WINSIDE / 2 || + missile->ms_x < me->p_x - SCALE * WINSIDE / 2 || + missile->ms_y < me->p_y - SCALE * WINSIDE / 2) + { + if (msstatus == TFREE && clientThingyStatus[i] == TEXPLODE) + { + clientThingyStatus[i] = TFREE; + continue; + } + if (clientThingyStatus[i] != TFREE) + { + clientThingyStatus[i] = TFREE; + dpi->shape = htons(SHP_BLANK); + sendClientPacket((struct player_spacket *) dpi); + } + } + else + { /* in view */ + if (dp->x != htonl(missile->ms_x) || + dp->y != htonl(missile->ms_y)) + { + dp->x = htonl(missile->ms_x); + dp->y = htonl(missile->ms_y); + sendClientPacket((struct player_spacket *) dp); + } + if (msstatus != clientThingyStatus[i] || + (missile->ms_war & me->p_team) != dpi->war) + { + /* Let the client fade away the explosion on its own */ + dpi->war = missile->ms_war & me->p_team; + clientThingyStatus[i] = msstatus; + sendClientPacket((struct player_spacket *) dpi); + } + } + } + } +} + +static void +fill_thingy_info_packet(thing, packet) + struct thingy *thing; + struct thingy_info_spacket *packet; +{ + switch (thing->type) + { + case TT_NONE: + packet->war = 0; + packet->shape = htons(SHP_BLANK); + packet->owner = 0; + break; + case TT_WARP_BEACON: + packet->war = 0; + if (thing->u.wbeacon.owner == me->p_team) + { + packet->shape = htons(SHP_WARP_BEACON); + packet->owner = htons(thing->u.wbeacon.owner); + } + else + { + packet->shape = htons(SHP_BLANK); + packet->owner = 0; + } + break; + default: + printf("Unknown thingy type: %d\n", (int) thing->type); + break; + } +} + +static void +fill_thingy_packet(thing, packet) + struct thingy *thing; + struct thingy_spacket *packet; +{ + switch (thing->type) + { + case TT_NONE: + packet->dir = 0; + packet->x = packet->y = htonl(0); + break; + case TT_WARP_BEACON: + packet->dir = 0; + if (thing->u.wbeacon.owner == me->p_team) + { + packet->x = htonl(thing->u.wbeacon.x); + packet->y = htonl(thing->u.wbeacon.y); + } + else + { + packet->x = packet->y = htonl(0); + } + break; + default: + printf("Unknown thingy type: %d\n", (int) thing->type); + break; + } +} + +void +updateThingies() +{ + struct thingy *thing; + struct thingy_info_spacket *tip; + struct thingy_spacket *tp; + int i; + + for (i = 0; i < NGTHINGIES; i++) + { + struct thingy_info_spacket ti1; + struct thingy_spacket t2; + + thing = &thingies[i]; + tip = &clientThingysInfo[i + MAXPLAYER * NPTHINGIES]; + tp = &clientThingys[i + MAXPLAYER * NPTHINGIES]; + + ti1.type = SP_THINGY_INFO; + ti1.tnum = htons(i + MAXPLAYER * NPTHINGIES); + fill_thingy_info_packet(thing, &ti1); + + if (0 != memcmp((char *) tip, (char *) &ti1, sizeof(ti1))) + { + memcpy(tip, &ti1, sizeof(ti1)); + sendClientPacket((struct player_spacket *) tip); + } + + if (tip->shape != htons(SHP_BLANK)) + { + t2.type = SP_THINGY; + t2.tnum = htons(i + MAXPLAYER * NPTHINGIES); + fill_thingy_packet(thing, &t2); + + if (0 != memcmp(tp, &t2, sizeof(t2))) + { + memcpy(tp, &t2, sizeof(t2)); + sendClientPacket((struct player_spacket *) tp); + } + } + } + +} + +void +updatePlasmas() +{ + register struct plasmatorp *torp; + register int i; + register struct plasma_info_spacket *tpi; + register struct plasma_spacket *tp; + + for (i = 0, torp = plasmatorps, tpi = clientPlasmasInfo, tp = clientPlasmas; + i < MAXPLAYER * MAXPLASMA; + i++, torp++, tpi++, tp++) + { + if (torp->pt_owner == me->p_no) + { + if (torp->pt_war != tpi->war || + torp->pt_status != tpi->status) + { + tpi->type = SP_PLASMA_INFO; + tpi->war = torp->pt_war; + tpi->status = torp->pt_status; + tpi->pnum = htons(i); + sendClientPacket((struct player_spacket *) tpi); + } + if (tp->x != htonl(torp->pt_x) || + tp->y != htonl(torp->pt_y)) + { + tp->type = SP_PLASMA; + tp->x = htonl(torp->pt_x); + tp->y = htonl(torp->pt_y); + tp->pnum = htons(i); + sendClientPacket((struct player_spacket *) tp); + } + } + else + { /* Someone else's torp... */ + enum torp_status_e ptstatus = torp->pt_status; + +#ifdef LEAGUE_SUPPORT + if (status2->paused && + players[torp->pt_owner].p_team != me->p_team) + ptstatus = TFREE; /* enemy torps are invisible during game + * pause */ +#endif + if (torp->pt_y > me->p_y + SCALE * WINSIDE / 2 || + torp->pt_x > me->p_x + SCALE * WINSIDE / 2 || + torp->pt_x < me->p_x - SCALE * WINSIDE / 2 || + torp->pt_y < me->p_y - SCALE * WINSIDE / 2 || + ptstatus == PTFREE) + { + if (ptstatus == PTFREE && tpi->status == PTEXPLODE) + { + tpi->status = PTFREE; + continue; + } + if (tpi->status != PTFREE) + { + tpi->status = PTFREE; + tpi->pnum = htons(i); + tpi->type = SP_PLASMA_INFO; + sendClientPacket((struct player_spacket *) tpi); + } + } + else + { /* in view */ + /* Send torp (we assume it moved) */ + tp->x = htonl(torp->pt_x); + tp->y = htonl(torp->pt_y); + tp->pnum = htons(i); + tp->type = SP_PLASMA; + sendClientPacket((struct player_spacket *) tp); + if (ptstatus != tpi->status || + (torp->pt_war & me->p_team) != tpi->war) + { + tpi->war = torp->pt_war & me->p_team; + tpi->type = SP_PLASMA_INFO; + tpi->pnum = htons(i); + tpi->status = ptstatus; + sendClientPacket((struct player_spacket *) tpi); + } + } + } + } +} + +void +updatePhasers() +{ + register int i; + register struct phaser_spacket *ph; + register struct phaser *phase; + register struct player *pl; + + for (i = 0, ph = clientPhasers, phase = phasers, pl = players; + i < MAXPLAYER; i++, ph++, phase++, pl++) + { + if (pl->p_y > me->p_y + SCALE * WINSIDE / 2 || + pl->p_x > me->p_x + SCALE * WINSIDE / 2 || + pl->p_x < me->p_x - SCALE * WINSIDE / 2 || + pl->p_y < me->p_y - SCALE * WINSIDE / 2) + { + if (ph->status != PHFREE) + { + ph->pnum = i; + ph->type = SP_PHASER; + ph->status = PHFREE; + sendClientPacket((struct player_spacket *) ph); + } + } + else + { + if (phase->ph_status == PHHIT) + { + mustUpdate[phase->ph_target] = 1; + } + if (ph->status != phase->ph_status || + ph->dir != phase->ph_dir || + ph->target != htonl(phase->ph_target)) + { + ph->pnum = i; + ph->type = SP_PHASER; + ph->status = phase->ph_status; + ph->dir = phase->ph_dir; + ph->x = htonl(phase->ph_x); + ph->y = htonl(phase->ph_y); + ph->target = htonl(phase->ph_target); + sendClientPacket((struct player_spacket *) ph); + } + } + } +} + + +#define PLFLAGMASK (PLRESMASK|PLATMASK|PLSURMASK|PLPARADISE|PLTYPEMASK) + +void +updatePlanets() +{ + register int i; + register struct planet *plan; + register struct planet_loc_spacket *pll; +#if 0 + register struct planet_spacket *mspl; +#endif + register struct planet_spacket2 *pl; + int dx, dy; + int d2x, d2y; + char *name; + + for (i = 0, pl = clientPlanets2, plan = planets, pll = clientPlanetLocs; + i < MAXPLANETS; + i++, pl++, plan++, pll++) + { + /* + * Send him info about him not having info if he doesn't but thinks he + * does. Also send him info on every fifth cycle if the planet needs to + * be redrawn. + */ + if (((plan->pl_hinfo & me->p_team) == 0) && (pl->info & me->p_team)) + { + pl->type = SP_PLANET2; + pl->pnum = i; + pl->info = 0; + pl->flags = PLPARADISE; + sendClientPacket((struct player_spacket *) pl); + } + else + { + struct teaminfo temp, *ptr; + if (configvals->durablescouting) + { + temp.owner = plan->pl_owner; + temp.armies = plan->pl_armies; + temp.flags = plan->pl_flags; + temp.timestamp = status->clock; + ptr = &temp; + } + else + ptr = &plan->pl_tinfo[me->p_team]; + + if (pl->info != plan->pl_hinfo || + pl->armies != htonl(ptr->armies) || + pl->owner != ptr->owner || + pl->flags != htonl(ptr->flags & PLFLAGMASK) + || ((pl->timestamp != htonl(ptr->timestamp)) + && (me->p_team != plan->pl_owner))) + { + pl->type = SP_PLANET2; + pl->pnum = (char) i; + pl->info = (char) plan->pl_hinfo; + pl->flags = htonl(ptr->flags & PLFLAGMASK); + pl->armies = htonl(ptr->armies); + pl->owner = (char) ptr->owner; + pl->timestamp = htonl(ptr->timestamp); + sendClientPacket((struct player_spacket *) pl); + } + } + /* Assume that the planet only needs to be updated once... */ + + /* Odd, changes in pl_y not supported. 5/31/92 TC */ + + dx = ntohl(pll->x) - plan->pl_x; + if (dx < 0) + dx = -dx; + dy = ntohl(pll->y) - plan->pl_y; + if (dy < 0) + dy = -dy; + + d2x = plan->pl_x - me->p_x; + d2y = plan->pl_y - me->p_y; + if (d2x < 0) + d2x = -d2x; + if (d2y < 0) + d2y = -d2y; + + if (1 || plan->pl_hinfo & me->p_team) + name = plan->pl_name; + else + name = " "; + /* + * if ((pll->x != htonl(plan->pl_x)) || (pll->y != htonl(plan->pl_y))) { + */ + if (strcmp(pll->name, name) || + ((dx > 400 || dy > 400) || + ((dx >= 20 || dy >= 20) && (d2x < 10000 && d2y < 10000)))) + { + pll->x = htonl(plan->pl_x); + pll->y = htonl(plan->pl_y); + pll->pnum = i; + if (plan->pl_system == 0) + pll->pad2 = 255; + else + pll->pad2 = (char) stars[plan->pl_system]; + strcpy(pll->name, name); + pll->type = SP_PLANET_LOC; + sendClientPacket((struct player_spacket *) pll); + } + } +} + +void +updateMessages() +{ + int i; + struct message *cur; + struct mesg_spacket msg; + + for (i = msgCurrent; i != (mctl->mc_current + 1) % MAXMESSAGE; i = (i + 1) % MAXMESSAGE) + { + if (i == MAXMESSAGE) + i = 0; + cur = &messages[i]; + + if (cur->m_flags & MVALID && + (cur->m_flags & MALL || + (cur->m_flags & MTEAM && cur->m_recpt == me->p_team) || + (cur->m_flags & MINDIV && cur->m_recpt == me->p_no) || + (cur->m_flags & MGOD && cur->m_from == me->p_no))) + { + msg.type = SP_MESSAGE; + strncpy(msg.mesg, cur->m_data, 80); + msg.mesg[79] = '\0'; + msg.m_flags = cur->m_flags; + msg.m_recpt = cur->m_recpt; + msg.m_from = cur->m_from; + + if ((cur->m_from < 0) + || (cur->m_from > MAXPLAYER) + || (cur->m_flags & MGOD && cur->m_from == me->p_no) + || (cur->m_flags & MALL && !(ignored[cur->m_from] & MALL)) + || (cur->m_flags & MTEAM && !(ignored[cur->m_from] & MTEAM))) + sendClientPacket((struct player_spacket *) & msg); + else if (cur->m_flags & MINDIV) + { + + /* session stats now parsed here. parseQuery == true */ + /* means eat message 4/17/92 TC */ + + if (!parseQuery(&msg)) + if (ignored[cur->m_from] & MINDIV) + bounce("That player is currently ignoring you.", + cur->m_from); + else + sendClientPacket((struct player_spacket *) & msg); + } + } + msgCurrent = (msgCurrent + 1) % MAXMESSAGE; + } +} + +/* Asteroid/Nebulae socket code (5/16/95 rpg) */ + +#define DIM (MAX_GWIDTH/TGRID_GRANULARITY) + +void +updateTerrain() +{ + int i; + int j, maxfor; + int status; + int npkts; + struct terrain_packet2 tpkt; + struct terrain_info_packet2 tinfo_pkt; + unsigned long olen = DIM * DIM, dlen = DIM * DIM / 1000 + DIM * DIM + 13; +#if defined(T_DIAG) || defined(T_DIAG2) + char buf[80]; +#endif + unsigned char origBuf[DIM * DIM]; + unsigned char gzipBuf[DIM * DIM / 1000 + + DIM * DIM + 13]; + /* + * Don't ask me. The compression libs need (original size + 0.1% + 12 + * bytes). + */ + /* + * Note - this will have to be RADICALLY changed if alt1/alt2 are sent as + * well. + */ + + /* check to see if client can handle the terrain data first */ + if (F_terrain) + { + if (galaxyValid[me->p_no]) + return; + +#if defined(T_DIAG) || defined(T_DIAG2) + { + char buf[80]; + sprintf(buf, "pno: %d gIsense: %d", me->p_no, galaxyValid[me->p_no]); + pmessage(buf, 0, MALL, MSERVA); + } +#endif + galaxyValid[me->p_no] = 1; + /* Send initial packet. */ + tinfo_pkt.type = SP_TERRAIN_INFO2; + tinfo_pkt.xdim = htons(DIM); + tinfo_pkt.ydim = htons(DIM); + sendClientPacket((struct player_spacket *) & tinfo_pkt); + for (i = 0; i < DIM * DIM; i++) + { + origBuf[i] = terrain_grid[i].types; /* pack types field into + * array */ + } +#if defined(T_DIAG) || defined(T_DIAG2) + status = compress(gzipBuf, &dlen, origBuf, olen); + if (status != Z_OK) + { + pmessage("TERRAIN: Cannot gzip terrain grid.", 0, MALL, MSERVA); + return; + } + else + { + sprintf(buf, "TERRAIN: Original length %d, compressed length %d", DIM * DIM, dlen); + pmessage(buf, 0, MALL, MSERVA); + } +#else + compress(gzipBuf, &dlen, origBuf, olen); +#endif + npkts = (dlen >> LOG2NTERRAIN); + if (dlen & TERRAIN_MASK) + { + npkts++; /* require a partial packet */ + } + for (i = 1; i <= npkts; i++) + { + tpkt.type = SP_TERRAIN2; + tpkt.sequence = (unsigned char) i; + tpkt.total_pkts = (unsigned char) npkts; + if (i < npkts) + { + maxfor = tpkt.length = NTERRAIN; + } + else + { + maxfor = tpkt.length = (dlen & TERRAIN_MASK); + } + for (j = 0; j < maxfor; j++) + { + tpkt.terrain_type[j] = gzipBuf[((i - 1) << LOG2NTERRAIN) + j]; + } + /* ok, packet is filled in, send it */ +#ifdef T_DIAG2 + sprintf(buf, "Sending terrain packet %d of %d", tpkt.sequence, tpkt.total_pkts); + pmessage(buf, 0, MALL, MSERVA); +#endif + sendClientPacket((struct player_spacket *) & tpkt); + } + } +#ifdef FEATURE_DIAG + else + { + pmessage("Mis-timed terrain data (F_terrain = 0)!", 0, MALL, MSERVA); + } +#endif +} + +void +updateMOTD() +{ + static int spinner = 0; + + if (--spinner < 0) + { + static struct stat oldstat; + static int firsttime = 1; + + char *path; + struct stat newstat; + struct obvious_packet pkt; + + spinner = 10; + + if (!firsttime) + { + path = build_path(MOTD); + stat(path, &newstat); + if (newstat.st_ino == oldstat.st_ino && + newstat.st_mtime == oldstat.st_mtime) + return; + oldstat.st_ino = newstat.st_ino; + oldstat.st_mtime = newstat.st_mtime; + + pkt.type = SP_NEW_MOTD; + sendClientPacket((struct player_spacket *) & pkt); + } + else + { + sendMotd(); /* can't build_path before this */ + path = build_path(MOTD); + stat(path, &oldstat); + /* printf("%s: %d, %d\n", path, oldstat.st_ino, oldstat.st_mtime); */ + firsttime = 0; + } + } +} + +void +sendQueuePacket(pos) + short int pos; +{ + struct queue_spacket qPacket; + + qPacket.type = SP_QUEUE; + qPacket.pos = htons(pos); + sendClientPacket((struct player_spacket *) & qPacket); + flushSockBuf(); +} + +void +sendClientPacket(packet) + struct player_spacket *packet; +{ + sendClientSizedPacket(packet, -1); +} + +void +sendClientSizedPacket(packet, size) +/* Pick a random type for the packet */ + struct player_spacket *packet; + int size; +{ + int orig_type; + int issc; + static int oldStatus = POUTFIT; + +#if 0 + if (blk_metaserver) +#endif +#ifdef SHOW_PACKETS + { + FILE *logfile; + char *paths; + paths = build_path("logs/metaserver.log"); + logfile = fopen(paths, "a"); + if (logfile) + { + fprintf(logfile, "Sending packet type %d\n", (int) packet->type); + fclose(logfile); + } + + } +#endif + +#ifdef T_DIAG2 + if ((packet->type == SP_TERRAIN2) || (packet->type == SP_TERRAIN_INFO2)) + { + pmessage("Sending TERRAIN packet\n", 0, MALL, MSERVA); + } +#endif + + orig_type = packet->type; +#if 0 + packet->type &= ~(0x40 | 0x80); /* clear special flags */ +#else + packet->type &= (char) 0x3f; /* above doesn't work? 4/18/92 TC */ +#endif +#ifdef MAYBE + /* + * If we're dead, dying, or just born, we definitely want the transmission + * to get through (otherwise we can get stuck). I don't think this will be + * a problem for anybody, though it might hang for a bit if the TCP + * connection is bad. + */ + /* Okay, now I'm not so sure. Whatever. */ + if (oldStatus != PALIVE || (me != NULL && me->p_status != PALIVE)) + orig_type = packet->type | 0x80; /* pretend it's critical */ +#endif + + /* if we're not given the size, calculate it */ + if (size < 0) + { + if (size_of_spacket(packet) == 0) + { + printf("Attempt to send strange packet %d\n", packet->type); + return; + } + size = size_of_spacket(packet); + } + else + { + /* pad to 32-bits */ + size = ((size - 1) / 4 + 1) * 4; + } + + packetsSent[packet->type]++; + + + if (commMode == COMM_TCP + || (commMode == COMM_UDP && udpMode == MODE_TCP)) + { + switch (orig_type) + { + case SP_MOTD: + case SP_MOTD_PIC: + /* these can afford to be delayed */ + sendTCPdeferred((void *) packet, size); + break; + + default: + /* business as usual, TCP */ + sendTCPbuffered((void *) packet, size); + break; + } + } + else + { + /* + * do UDP stuff unless it's a "critical" packet (note that both kinds get + * a sequence number appended) (FIX) + */ + issc = 0; + switch (orig_type) + { + case SP_KILLS: + case SP_TORP_INFO: + case SP_THINGY_INFO: + case SP_PHASER: + case SP_PLASMA_INFO: + case SP_YOU | 0x40: /* ??? what is this? */ + case SP_STATUS: + case SP_STATUS2: + case SP_PLANET: + case SP_PLANET2: + case SP_FLAGS: + case SP_HOSTILE: + /* + * these are semi-critical; flag as semi-critical and fall through + */ + issc = 1; + + case SP_PLAYER: + case SP_TORP: +#ifdef SHORT_PACKETS + case SP_S_TORP: + case SP_S_8_TORP: +#endif + case SP_THINGY: + case SP_YOU: + case SP_PLASMA: + case SP_STATS: + case SP_STATS2: + /* case SP_SCAN: */ + case SP_PING: + case SP_UDP_REPLY: /* only reply when COMM_UDP is SWITCH_VERIFY */ + /* these are non-critical updates; send them via UDP */ + V_UDPDIAG(("Sending type %d\n", packet->type)); + packets_sent++; + sendUDPbuffered(issc, (void *) packet, size); + break; + + case SP_MOTD: + case SP_MOTD_PIC: + sendTCPdeferred((void *) packet, size); + break; + + default: + sendTCPbuffered((void *) packet, size); + break; + } + } + + if (me != NULL) + oldStatus = me->p_status; +} + +/* + * flushSockBuf, socketPause, socketWait were here + */ + +/* Find out if client has any requests */ +int +readFromClient() +{ + struct timeval timeout; + fd_set readfds, writefds; + int retval = 0; + + if (clientDead) + return (0); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + build_select_masks(&readfds, &writefds); + + if (select(32, &readfds, &writefds, (fd_set *) 0, &timeout) != 0) + { + /* Read info from the xtrek client */ + if (FD_ISSET(sock, &readfds)) + { + retval += doRead(sock); + } + if (udpSock >= 0 && FD_ISSET(udpSock, &readfds)) + { + V_UDPDIAG(("Activity on UDP socket\n")); + retval += doRead(udpSock); + } + if (retval == 0 && /* no other traffic */ + FD_ISSET(sock, &writefds)) + { + flushDeferred(); /* we have an eye in the packet hurricane */ + } + } + return (retval != 0); /* convert to 1/0 */ +} + +static int +input_allowed(packettype) + int packettype; +{ + switch (packettype) + { + case CP_MESSAGE: + case CP_SOCKET: + case CP_OPTIONS: + case CP_BYE: + case CP_UPDATES: + case CP_RESETSTATS: + case CP_RESERVED: + case CP_RSA_KEY: + case CP_ASK_MOTD: + case CP_PING_RESPONSE: + case CP_UDP_REQ: +#ifdef FEATURE + case CP_FEATURE: +#endif +#ifdef SHORT_PACKETS + case CP_S_MESSAGE: +#endif + return 1; + default: + if (!me) + return; + + if (me->p_status == PTQUEUE) + return (packettype == CP_OUTFIT + ); + else if (me->p_status == POBSERVE) + return (packettype == CP_QUIT + || packettype == CP_PLANLOCK + || packettype == CP_PLAYLOCK + || packettype == CP_SCAN + || packettype == CP_SEQUENCE /* whatever this is */ + ); + + if (inputMask >= 0 && inputMask != packettype) + return 0; + if (me == NULL) + return 1; + if (!(me->p_flags & (PFWAR | PFREFITTING))) + return 1; + + return 0; + } +} + +static int rsock; /* ping stuff */ + +/* ripped out of above routine */ +int +doRead(asock) + int asock; +{ + struct timeval timeout; + /* int readfds; */ + fd_set readfds; + char buf[BUFSIZ * 2]; + char *bufptr; + int size; + int count; + int temp; + + rsock = asock; /* need the socket in the ping handler + * routine */ + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + /* readfds = 1< NUM_PACKETS || + size_of_cpacket((void *) bufptr) == 0) + { + printf("Unknown packet type: %d, aborting...\n", *bufptr); + return (0); + } + size = size_of_cpacket(bufptr); + while (size > count + (buf - bufptr)) + { + /* + * We wait for up to twenty seconds for rest of packet. If we don't get + * it, we assume the client died. + */ + timeout.tv_sec = 20; + timeout.tv_usec = 0; + /* readfds=1<p_flags & PFSELFDEST + && *bufptr != CP_PING_RESPONSE) + { + me->p_flags &= ~PFSELFDEST; + warning("Self Destruct has been canceled"); + } + (*(handlers[(unsigned char) *bufptr].handler)) (bufptr); + } + /* Otherwise we ignore the request */ + } + else + { + printf("Handler for packet %d not installed...\n", *bufptr); + } + bufptr += size; + if (bufptr > buf + BUFSIZ) + { + memcpy(buf, buf + BUFSIZ, BUFSIZ); + if (count == BUFSIZ * 2) + { + /* readfds = 1<dir, (int) TMOVE); +} + +void +handlePhasReq(packet) + struct phaser_cpacket *packet; +{ + phaser(packet->dir); +} + +void +handleSpeedReq(packet) + struct speed_cpacket *packet; +{ + set_speed(packet->speed, 1); +} + +void +handleDirReq(packet) + struct dir_cpacket *packet; +{ + me->p_flags &= ~(PFPLOCK | PFPLLOCK); + set_course(packet->dir); +} + +void +handleShieldReq(packet) + struct shield_cpacket *packet; +{ + if (packet->state) + { + shield_up(); + } + else + { + shield_down(); + } +} + +void +handleRepairReq(packet) + struct repair_cpacket *packet; +{ + if (packet->state) + { + repair(); + } + else + { + me->p_flags &= ~(PFREPAIR); + } +} + +void +handleOrbitReq(packet) + struct orbit_cpacket *packet; +{ + if (packet->state) + { + orbit(); + } + else + { + me->p_flags &= ~PFORBIT; +#if 0 + planets[me->p_planet].pl_torbit &= ~me->p_team; +#endif + if (me->p_flags & PFDOCK) + { + if (players[me->p_docked].p_speed > 4) + { + warning("It's unsafe to disengage from bases while over warp 4."); + return; + } + else + undock_player(me); + } + } +} + +/*-----------------------------PRACTICE_ROBOT-----------------------------*/ +/* + * Send in a practice robot. You can only bring i a practice robot if no + * other players are in the game. + */ + +static void +practice_robo() +{ + char *paths; /* to hold dot dir path */ + char *arg1; + register int i; /* looping var */ + register struct player *j; /* to point to players */ + static struct timeval space = {0, 0}; + + if (!temporally_spaced(&space, 1000000)) /* damn auto-repeating... */ + return; + + for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) + { + if (j->p_status != PALIVE) /* if payer not alive, that's ok */ + continue; + if (j == me) /* ignore myself */ + continue; + warning("Can't send in practice robot with other players in the game."); + return; /* another player discovered--out of here */ + } + + if (fork() == 0) + { /* do if fork successful */ + (void) r_signal(SIGALRM, SIG_DFL); + (void) close(0); + (void) close(1); + (void) close(2); + switch (me->p_team) + { /* decide which teaem robot is on */ + case FED: + arg1 = "-Tf"; /* fed option */ + break; + case ROM: + arg1 = "-Tr"; /* rom option */ + break; + case KLI: + arg1 = "-Tk"; /* klingon option */ + break; + case ORI: + arg1 = "-To"; /* orion option */ + break; + default: + arg1 = "-Ti"; /* in case something screwy happens */ + break; + } + + paths = build_path(ROBOT); + + execl(paths, "robot", arg1, "-p", "-f", "-h", 0); + _exit(1); /* failure :( died at birth */ + } +} + +/*--------------------------------------------------------------------------*/ + +/* ARGSUSED */ +void +handlePractrReq(packet) + struct practr_cpacket *packet; +{ + practice_robo(); +} + +void +handleBombReq(packet) + struct bomb_cpacket *packet; +{ + if (packet->state) + { + bomb_planet(); + } + else + { + me->p_flags &= ~(PFBOMB); + } +} + +void +handleBeamReq(packet) + struct beam_cpacket *packet; +{ + if (packet->state == 1) + { + beam_up(); + } + else if (packet->state) + { + beam_down(); + } + else + { + me->p_flags &= ~(PFBEAMUP | PFBEAMDOWN); + } +} + +void +handleCloakReq(packet) + struct cloak_cpacket *packet; +{ + if (packet->state) + { + cloak_on(); + } + else + { + cloak_off(); + } +} + +/* ARGSUSED */ +void +handleDetTReq(packet) + struct det_torps_cpacket *packet; +{ + detothers(); +} + +/* ARGSUSED */ +void +handleCopilotReq(packet) + struct copilot_cpacket *packet; +{ + /* + * Unsupported... if (packet->state) { me->p_flags |= PFCOPILOT; } else { + * me->p_flags &= ~PFCOPILOT; } + */ +} + +void +handleOutfit(packet) + struct outfit_cpacket *packet; +{ + shipPick = packet->ship; + teamPick = packet->team; +} + +void +sendPickokPacket(state) + int state; +{ + struct pickok_spacket pickPack; + + pickPack.type = SP_PICKOK; + pickPack.state = state; + sendClientPacket((struct player_spacket *) & pickPack); +} + +void +handleLoginReq(packet) + struct login_cpacket *packet; +{ + if (packet->pad2 == 0x69) + { + if (packet->pad3 == 0x42) + blk_flag = 1; /* added 1/19/93 KAO */ + if (packet->pad3 == 0x43) + blk_flag = 2; + } + strncpy(namePick, packet->name, 16); + namePick[15] = 0; + strncpy(passPick, packet->password, 16); + passPick[15] = 0; + /* Is this a name query or a login? */ + if (packet->query) + { + passPick[15] = 1; + } + strncpy(login, packet->login, 16); + login[15] = 0; +} + +void +sendClientLogin(stats) + struct stats *stats; +{ + struct login_spacket logPacket; + logPacket.pad2 = 69; + if (configvals->galaxygenerator == 4) + logPacket.pad3 = 88; + else + logPacket.pad3 = 42; + logPacket.type = SP_LOGIN; + if (stats == NULL) + { + logPacket.accept = 0; + } + else + { + logPacket.accept = 1; + logPacket.flags = htonl(stats->st_flags); + } + sendClientPacket((struct player_spacket *) & logPacket); +} + +void +handlePlasmaReq(packet) + struct plasma_cpacket *packet; +{ + if (me->p_specweap & SFNHASMISSILE) + { + fire_missile_dir(packet->dir); + } + else if (me->p_specweap & SFNPLASMAARMED) + { + nplasmatorp(packet->dir, PTMOVE); + } + else + { + warning("This ship is armed with no special weapons"); + } +} + +void +handleWarReq(packet) + struct war_cpacket *packet; +{ + declare_war(packet->newmask); +} + +void +handlePlanlockReq(packet) + struct planlock_cpacket *packet; +{ + lock_planet(packet->pnum); +} + +void +handlePlaylockReq(packet) + struct playlock_cpacket *packet; +{ + lock_player(packet->pnum); +} + +void +handleDetMReq(packet) + struct det_mytorp_cpacket *packet; +{ + struct torp *atorp; + short t; + + /* you can det individual torps */ + t = ntohs(packet->tnum); + if (t < 0) + { + struct missile *dr; + int i, any; + + any = 0; + + for (i = 0; i < MAXTORP; i++) + { + atorp = &torps[me->p_no * MAXTORP + i]; + if (atorp->t_status == TMOVE || atorp->t_status == TSTRAIGHT) + { + atorp->t_status = TOFF; + any = 1; + } + } + + if (any) + return; + + for (i = 0; i < NPTHINGIES; i++) + { + dr = &missiles[me->p_no * NPTHINGIES + i]; + if (dr->ms_status == TMOVE || dr->ms_status == TSTRAIGHT) + { + switch (dr->ms_type) + { + case MISSILETHINGY: + dr->ms_status = TOFF; + break; + case FIGHTERTHINGY: + dr->ms_status = TRETURN; + break; + } + any = 1; + } + } + + /* any ? */ + } + else + { + + if (t < 0 || t >= MAXPLAYER * MAXTORP) + return; + atorp = &torps[t]; + + if (atorp->t_owner != me->p_no) + return; + if (atorp->t_status == TMOVE || atorp->t_status == TSTRAIGHT) + { + atorp->t_status = TOFF; + } + } +} + +void +handleTractorReq(packet) + struct tractor_cpacket *packet; +{ + int target; + struct player *player; + + if (weaponsallowed[WP_TRACTOR] == 0) + { + warning("Tractor beams haven't been invented yet."); + return; + } + target = packet->pnum; + if (packet->state == 0) + { + me->p_flags &= ~(PFTRACT | PFPRESS); + return; + } + if (me->p_flags & PFCLOAK) + { + warning("Weapons's Officer: Cannot tractor while cloaked, sir!"); + return; + } + if (target < 0 || target >= MAXPLAYER || target == me->p_no) + return; + player = &players[target]; + if (player->p_flags & PFCLOAK) + return; + if (me->p_flags & PFDOCK && players[me->p_docked].p_speed > 4) + { + warning("It's unsafe to tractor while docked and moving at a warp greater then 4."); + return; + } + if (ihypot(me->p_x - player->p_x, me->p_y - player->p_y) < + (TRACTDIST) * me->p_ship.s_tractrng) + { + undock_player(me); + me->p_flags &= ~PFORBIT; +#if 0 + undock_player(player); /* harmless if they're not docked */ + +#if 0 + if (player->p_flags & PFORBIT) + planets[player->p_planet].pl_torbit &= ~player->p_team; + if (me->p_flags & PFORBIT) + planets[me->p_planet].pl_torbit &= ~me->p_team; +#endif + player->p_flags &= ~(PFORBIT | PFDOCK); + me->p_flags &= ~(PFORBIT | PFDOCK); +#endif + me->p_tractor = target; + me->p_flags |= PFTRACT; + + } + else + { + warning("Weapon's Officer: Vessel is out of range of our tractor beam."); + } +} + +void +handleRepressReq(packet) + struct repress_cpacket *packet; +{ + int target; + struct player *player; + + if (weaponsallowed[WP_TRACTOR] == 0) + { + warning("Pressor beams haven't been invented yet."); + return; + } + target = packet->pnum; + if (packet->state == 0) + { + me->p_flags &= ~(PFTRACT | PFPRESS); + return; + } + if (me->p_flags & PFCLOAK) + { + warning("Weapons's Officer: Cannot pressor while cloaked, sir!"); + return; + } + if (target < 0 || target >= MAXPLAYER || target == me->p_no) + return; + player = &players[target]; + if (player->p_flags & PFCLOAK) + return; + if (me->p_flags & PFDOCK && players[me->p_docked].p_speed > 4) + { + warning("It's unsafe to pressor while docked and moving at a warp greater then 4."); + return; + } + if (ihypot(me->p_x - player->p_x, me->p_y - player->p_y) < + (TRACTDIST) * me->p_ship.s_tractrng) + { + undock_player(me); + me->p_flags &= ~PFORBIT; +#if 0 + undock_player(player); + +#if 0 + if (player->p_flags & PFORBIT) + planets[player->p_planet].pl_torbit &= ~player->p_team; + if (me->p_flags & PFORBIT) + planets[me->p_planet].pl_torbit &= ~me->p_team; +#endif + player->p_flags &= ~(PFORBIT | PFDOCK); + me->p_flags &= ~(PFORBIT | PFDOCK); +#endif + me->p_tractor = target; + me->p_flags |= (PFTRACT | PFPRESS); + } + else + { + warning("Weapon's Officer: Vessel is out of range of our pressor beam."); + } +} + +void +sendMotdLine(line) + char *line; +{ + struct motd_spacket motdPacket; + + motdPacket.type = SP_MOTD; + strncpy(motdPacket.line, line, 80); + motdPacket.line[79] = '\0'; + sendClientPacket((struct player_spacket *) & motdPacket); +} + +/* ARGSUSED */ +void +handleCoupReq(packet) + struct coup_cpacket *packet; +{ + switch_special_weapon(); +} + +void +handleRefitReq(packet) + struct refit_cpacket *packet; +{ + do_refit(packet->ship); +} + +void +handleMessageReq(packet) + struct mesg_cpacket *packet; +{ + char addrbuf[9]; + static long lasttime = 0 /* , time() */ ; + static int balance = 0; /* make sure he doesn't get carried away */ + long thistime; + + int isCensured(); /* "shut up and play" code 7/21/91 TC */ + int parseIgnore(); /* still more code, 7/24/91 TC */ + + /* + * Some random code to make sure the player doesn't get carried away about + * the number of messages he sends. After all, he could try to jam peoples + * communications if we let him. + */ + + thistime = time(NULL); + if (lasttime != 0) + { + balance = balance - (thistime - lasttime); + if (balance < 0) + balance = 0; + } + lasttime = thistime; + if (balance >= 15) + { + warning("Be quiet"); + balance += 3; + if (balance > time(NULL) + 60) + { + balance = time(NULL) + 60; + } + return; + } + balance += 3; + /* packet->mesg[69] = '\0'; */ + sprintf(addrbuf, " %s->", twoletters(me)); + if (parseIgnore(packet)) + return; /* moved this up 4/6/92 TC */ + if (packet->group & MGOD) + { + strcpy(addrbuf + 5, "GOD"); + } + else if (packet->group & MALL) + { + sprintf(addrbuf + 5, "ALL"); + if (isCensured(me->p_login)) + { + warning("You are censured. Message was not sent."); + return; + } + } + else if (packet->group & MTEAM) + { + if (packet->indiv != FED && packet->indiv != ROM && + packet->indiv != KLI && packet->indiv != ORI) + return; + if (isCensured(me->p_login) && (packet->indiv != me->p_team)) + { + warning("You are censured. Message was not sent."); + return; + } + sprintf(addrbuf + 5, teams[packet->indiv].shortname); + } + else if (packet->group & MINDIV) + { + if (packet->indiv < 0 || packet->indiv >= MAXPLAYER) + return; + if (players[packet->indiv].p_status == PFREE) + return; + if (isCensured(me->p_login) && (players[packet->indiv].p_team != me->p_team)) + { + warning("You are censured. Message was not sent."); + return; + } + if (ignored[packet->indiv] & MINDIV) + { + warning("You are ignoring that player. Message was not sent."); + return; + } + if ((me->p_team != players[packet->indiv].p_team) && + (isCensured(players[packet->indiv].p_login))) + { + warning("That player is censured. Message was not sent."); + return; + } + sprintf(addrbuf + 5, "%s ", twoletters(&players[packet->indiv])); + } + else + { + return; + } +#if 0 + if ((packet->group == MGOD + || me->p_no == packet->indiv && packet->group == MINDIV) + && parse_command_mess(packet->mesg, me->p_no)) + { + /* message parsed. Eat it */ + } + else + { + pmessage2(packet->mesg, packet->indiv, packet->group, addrbuf, me->p_no); + } +#else + /* don't eat the parsed messages */ + pmessage2(packet->mesg, packet->indiv, packet->group, addrbuf, me->p_no); + if (me->p_no == packet->indiv && packet->group == MINDIV) + { + char tmpbuf[sizeof(packet->mesg) + 1]; + strncpy(tmpbuf, packet->mesg, sizeof(packet->mesg)); + tmpbuf[sizeof(packet->mesg)] = 0; + parse_command_mess(tmpbuf, me->p_no); + } +#endif + + /* + * Blech !!! + * + * Don't do this: + * + * if (me->p_no == packet->indiv && packet->mesg[0] == '_') me = &players[0]; + */ +} + +/* ARGSUSED */ +void +handleQuitReq(packet) + struct quit_cpacket *packet; +{ + if (me->p_status == POBSERVE) + { + me->p_status = PTQUEUE; + return; + } + me->p_flags |= PFSELFDEST; + + switch (me->p_ship.s_type) + { + case STARBASE: + case WARBASE: + selfdest = 60; + break; + default: + selfdest = 10; + } + + selfdest = me->p_updates + selfdest * 10; + + warning("Self destruct initiated"); +} + +void +sendMaskPacket(mask) + int mask; +{ + struct mask_spacket maskPacket; + + maskPacket.type = SP_MASK; + maskPacket.mask = mask; + sendClientPacket((struct player_spacket *) & maskPacket); +} + +void +handleOptionsPacket(packet) + struct options_cpacket *packet; +{ + mystats->st_flags = ntohl(packet->flags) | + (mystats->st_flags & ST_CYBORG); /* hacked fix 8/24/91 TC */ + keeppeace = (mystats->st_flags / ST_KEEPPEACE) & 1; +} + +void +handleSocketReq(packet) + struct socket_cpacket *packet; +{ + nextSocket = ntohl(packet->socket); + userVersion = packet->version; + userUdpVersion = packet->udp_version; +} + +/* ARGSUSED */ +void +handleByeReq(packet) + struct bye_cpacket *packet; +{ + noressurect = 1; +} + +int +checkVersion() +{ + struct badversion_spacket packet; + + if (userVersion != SOCKVERSION) + { + packet.type = SP_BADVERSION; + packet.why = 0; + sendClientPacket((struct player_spacket *) & packet); + flushSockBuf(); + return (0); + } + return (1); +} + +void +logEntry() +{ + FILE *logfile; + int curtime; + char *paths; + + paths = build_path(LOGFILENAME); + logfile = fopen(paths, "a"); + if (!logfile) + return; + curtime = time(NULL); + +#ifdef LOG_LONG_INFO /*-[ prints out long info to the log files ]-*/ + + fprintf(logfile, "Joining: %s, (%c) <%s@%s> %s", me->p_name, + shipnos[me->p_no], + me->p_login, /* debug 2/21/92 TMC */ + +#else + + fprintf(logfile, "Joining: %s <%s@%s> %s", me->p_name, me->p_login, + +#endif /*-[ LOG_LONG_INFO ]-*/ + + me->p_full_hostname, + ctime((time_t *) & curtime)); + + fclose(logfile); +} + +/* gwrite was here */ + +void +handleDockingReq(packet) + struct dockperm_cpacket *packet; +{ + int i; + + if (allows_docking(me->p_ship)) + { + if (me->p_speed > 4 && me->p_docked) + { + warning("It's unsafe to disengage other ships while over warp 4."); + return; + } + else + { + for (i = 0; i < me->p_ship.s_numports; i++) + base_undock(me, i); + me->p_docked = 0; + + if (packet->state) + me->p_flags |= PFDOCKOK; + else + me->p_flags &= ~PFDOCKOK; + } + } +} + +void +handleReset(packet) + struct resetstats_cpacket *packet; +{ + extern int startTkills, startTlosses, startTarms, startTplanets, startTticks; + + if (packet->verify != 'Y') + return; + + /* Gee, they seem to want to reset their stats! Here goes... */ +#if 0 + mystats->st_maxkills = 0.0; + mystats->st_kills = 0; + mystats->st_losses = 0; + mystats->st_armsbomb = 0; + mystats->st_planets = 0; + mystats->st_ticks = 0; + mystats->st_tkills = 0; + mystats->st_tlosses = 0; + mystats->st_tarmsbomb = 0; + mystats->st_tplanets = 0; + mystats->st_tticks = 1; + mystats->st_rank = 0; + mystats->st_sbkills = 0; + mystats->st_sblosses = 0; + mystats->st_sbticks = 0; + mystats->st_sbmaxkills = 0.0; + + startTkills = mystats->st_tkills; + startTlosses = mystats->st_tlosses; + startTarms = mystats->st_tarmsbomb; + startTplanets = mystats->st_tplanets; + startTticks = mystats->st_tticks; +#endif + + mystats->st_genocides = 0; + mystats->st_tmaxkills = 0.0; + mystats->st_di = 0.0; + mystats->st_tkills = 0; + mystats->st_tlosses = 0; + mystats->st_tarmsbomb = 0; + mystats->st_tresbomb = 0; + mystats->st_tdooshes = 0; + mystats->st_tplanets = 0; + mystats->st_tticks = 1; + mystats->st_sbkills = 0; + mystats->st_sblosses = 0; + mystats->st_sbmaxkills = 0.0; + mystats->st_sbticks = 1; + mystats->st_wbkills = 0; + mystats->st_wblosses = 0; + mystats->st_wbmaxkills = 0.0; + mystats->st_wbticks = 1; + mystats->st_jsplanets = 0; + mystats->st_jsticks = 1; + mystats->st_rank = 0; + mystats->st_royal = 0; + + startTkills = mystats->st_tkills; + startTlosses = mystats->st_tlosses; + startTarms = mystats->st_tarmsbomb; + startTplanets = mystats->st_tplanets; + startTticks = mystats->st_tticks; +} + +void +handleUpdatesReq(packet) + struct updates_cpacket *packet; +{ + struct itimerval udt; + extern int interrupting; /* main.c */ + int min_delay = me->p_observer + ? configvals->min_observer_upd_delay + : configvals->min_upd_delay; + + timerDelay = ntohl(packet->usecs); + if (timerDelay < min_delay) + timerDelay = min_delay; + if (timerDelay >= 1000000) + timerDelay = 999999; + + if (interrupting) + { /* only setitimer if the ntserv is configured + * to handle it. It's NOT configured to + * handle it in the outfit loop... */ + udt.it_interval.tv_sec = 0; + udt.it_interval.tv_usec = timerDelay; + udt.it_value.tv_sec = 0; + udt.it_value.tv_usec = timerDelay; + setitimer(ITIMER_REAL, &udt, 0); + } + +} + +void +logmessage(string) + char *string; +{ + FILE *fp; + char *paths; + + paths = build_path(LOGFILENAME); + + fp = fopen(paths, "a"); + if (fp) + { + fprintf(fp, "%s\n", string); + fclose(fp); + } +} + +#if 0 +handleReserved(packet) + struct reserved_cpacket *packet; +{ + /* char temp[20]; */ + struct reserved_cpacket mycp; + struct reserved_spacket mysp; + char serverName[64]; /* now get serverName from system 8/2/92 TC */ + + if (testtime == 1) + return; + if (memcmp(packet->data, testdata, 16) != 0) + { + testtime = 1; + return; + } + memcpy(mysp.data, testdata, 16); + if (gethostname(serverName, 64)) + fprintf(stderr, "gethostname() error\n"); /* 8/2/92 TC */ + encryptReservedPacket(&mysp, &mycp, serverName, me->p_no); + if (memcmp(packet->resp, mycp.resp, 16) != 0) + { + fprintf(stderr, "User verified incorrectly.\n"); + testtime = 1; + return; + } + testtime = 0; +} + +#ifdef ATM_STUFF +void +dummy_() +{ + if ((configvals->binconfirm == 2) && + !strcmp(packet->resp, "Cyborg")) + { + testtime = 0; /* accept */ + cyborg = 1; + if (me->p_name[0] != '+') + { + temp[0] = '+'; /* indicate cyborg */ + strcpy(temp + 1, me->p_name); /* this happens AFTER entry, */ + temp[15] = '\0'; /* so changing enter() isn't */ + strcpy(me->p_name, temp); /* sufficient */ + } + return; + } + + if (memcmp(packet->resp, mycp.resp, 16) != 0) + { + fprintf(stderr, "User verified incorrectly.\n"); + testtime = 1; + return; + } + + testtime = 0; +} + +#endif +#else + +void +handleRSAKey(packet) + struct rsa_key_cpacket *packet; +{ +#ifdef AUTHORIZE + struct rsa_key_spacket mysp; + char serverName[64]; + + if (testtime == 1) + return; + if (RSA_Client != 1) + return; + memcpy(mysp.data, testdata, KEY_SIZE); + if (gethostname(serverName, 64)) + fprintf(stderr, "gethostname() error\n"); + if (decryptRSAPacket(&mysp, packet, serverName)) + { + fprintf(stderr, "User verified incorrectly.\n"); + testtime = 1; + return; + } + testtime = 0; +#endif /* AUTHORIZE */ +} + +void +handleReserved(packet) + struct reserved_cpacket *packet; +{ +#ifdef AUTHORIZE + struct reserved_cpacket mycp; + struct reserved_spacket mysp; + struct rsa_key_spacket rsp; + char serverName[64]; /* now get serverName from system 8/2/92 TC */ + + if (testtime == 1) + return; + if (memcmp(packet->data, testdata, RESERVED_SIZE) != 0) + { + testtime = 1; + return; + } + if (!strncmp(packet->resp, RSA_VERSION, 3)) + { + /* This is an RSA type client */ + RSA_Client = 2; + warning(RSA_VERSION); + if (!strncmp(packet->resp, RSA_VERSION, strlen("RSA v??"))) + { + /* This is the right major version */ + RSA_Client = 1; + makeRSAPacket(&rsp); + memcpy(testdata, rsp.data, KEY_SIZE); + sendClientPacket((struct player_spacket *) & rsp); + return; + } + testtime = 1; + return; + } + memcpy(mysp.data, testdata, RESERVED_SIZE); + if (gethostname(serverName, 64)) + fprintf(stderr, "gethostname() error\n"); /* 8/2/92 TC */ + encryptReservedPacket(&mysp, &mycp, serverName, me->p_no); + if (memcmp(packet->resp, mycp.resp, RESERVED_SIZE) != 0) + { + fprintf(stderr, "User verified incorrectly.\n"); + testtime = 1; + return; + } + /* Use .sysdef CONFIRM flag to allow old style clients. */ + if (configvals->binconfirm == 2) + testtime = 0; + else + testtime = 1; + +#endif /* AUTHORIZE */ +} + +#endif + +void +handleScan(packet) /* ATM */ + struct scan_cpacket *packet; +{ +#if 0 + struct scan_spacket response; + struct player *pp; + + memset(&response, 0, sizeof(struct scan_spacket)); + response.type = SP_SCAN; + response.pnum = packet->pnum; + if (!weaponsallowed[WP_SCANNER]) + { + warning("Scanners haven't been invented yet"); + response.success = 0; + } + else + { + response.success = scan(packet->pnum); + + if (response.success) + { + /fill in all the goodies / + pp = &players[packet->pnum]; + response.p_fuel = htonl(pp->p_fuel); + response.p_armies = htonl(pp->p_armies); + response.p_shield = htonl(pp->p_shield); + response.p_damage = htonl(pp->p_damage); + response.p_etemp = htonl(pp->p_etemp); + response.p_wtemp = htonl(pp->p_wtemp); + } + } + sendClientPacket((struct player_spacket *) & response); +#endif +} + + +void +handlePingResponse(packet) + struct ping_cpacket *packet; +{ + char buf[80]; + /* client requests pings by sending pingme == 1 on TCP socket */ + + if (rsock == sock) + { + if (!ping && packet->pingme == 1) + { + ping = 1; + sprintf(buf, "Server sending ping packets at %d second intervals", + configvals->ping_period); + warning(buf); + return; + } + /* client says stop */ + else if (ping && !packet->pingme) + { + ping = 0; + warning("Server no longer sending ping packets."); + return; + } + } + pingResponse(packet); /* ping.c */ +} + +#ifdef SHORT_PACKETS + +void +handleShortReq(packet) + struct shortreq_cpacket *packet; +{ + struct shortreply_spacket resp; + + switch (packet->req) + { + case SPK_VOFF: + send_short = 0; + warning("Not sending variable and short packets. Back to default."); + if (udpSock >= 0 && udpMode == MODE_FAT) + forceUpdate(); + break; + + case SPK_VON: + if (packet->version != (char) SHORTVERSION) + { + warning("Your SHORT Protocol Version is not right!"); + packet->req = SPK_VOFF; + break; + } + if (!send_short) + warning("Sending variable and short packets. "); /* send only firsttime */ + send_short = 1; + resp.winside = ntohs(WINSIDE); + resp.gwidth = ntohl(GWIDTH); + break; + + case SPK_MOFF: + send_mesg = 1; + warning("Obsolete!"); + packet->req = SPK_MON; + break; + + case SPK_MON: + send_mesg = 1; + warning("All messages sent."); + break; + + case SPK_M_KILLS: + send_kmesg = 1; + warning("Kill messages sent"); + break; + + case SPK_M_NOKILLS: + send_kmesg = 1; + warning("Obsolete!"); + packet->req = SPK_M_KILLS; + break; + + case SPK_M_WARN: + send_warn = 1; + warning("Warn messages sent"); + break; + + case SPK_M_NOWARN: + send_warn = 1; + warning("Obsolete!"); + packet->req = SPK_M_WARN; + break; + + case SPK_SALL: + if (send_short) + { + spk_update_sall = 1; + spk_update_all = 0; + forceUpdate(); + } + else + warning("Activate SHORT Packets first!"); + return; + + case SPK_ALL: + if (send_short) + { + spk_update_sall = 0; + spk_update_all = 1; + forceUpdate(); + } + else + warning("Activate SHORT Packets first!"); + return; + + default: + warning("Unknown short packet code"); + return; + } + + resp.type = SP_S_REPLY; + resp.repl = (char) packet->req; + + sendClientPacket((struct player_spacket *) & resp); +} + +void +handleThresh(packet) + struct threshold_cpacket *packet; +{ + send_threshold = packet->thresh; +#ifdef SHORT_THRESHOLD + if (send_threshold == 0) + { + actual_threshold = 0; + warning("Threshold test deactivated."); + } + else + { + actual_threshold = send_threshold / numupdates; + if (actual_threshold < 60) + { /* my low value */ + actual_threshold = 60; /* means: 1 SP_S_PLAYER+SP_S_YOU + 16 bytes */ + sprintf(buf, "Threshold set to %d . %d / Update(Server limit!)", + numupdates * 60, 60); + warning(buf); + } + else + { + sprintf(buf, "Threshold set to %d . %d / Update", send_threshold, actual_threshold); + warning(buf); + } + } +#else + warning("Server is compiled without Thresholdtesting!"); +#endif +} + +void +handleSMessageReq(packet) + struct mesg_s_cpacket *packet; +{ + /* If someone would delete the hardcoded things in handleMessageReq */ + /* like packet->mesg[69]='\0'; */ + /* we could give handleMessageReq the packet without copying */ + /* But i have no time HW 04/6/93 */ + + struct mesg_cpacket mesPacket; + mesPacket.type = CP_MESSAGE; + mesPacket.group = packet->group; + mesPacket.indiv = packet->indiv; + strcpy(mesPacket.mesg, packet->mesg); + handleMessageReq(&mesPacket); + /* I hope this was it */ +} + + +#endif + +/* + * + * --------------------------------------------------------------------------- + * Strictly UDP from here on + * --------------------------------------------------------------------------- + * */ + +void +handleUdpReq(packet) + struct udp_req_cpacket *packet; +{ + struct udp_reply_spacket response; + int mode; + + response.type = SP_UDP_REPLY; + + if (packet->request == COMM_VERIFY) + { + /* this request should ONLY come through the UDP connection */ + if (commMode == COMM_UDP) + { + UDPDIAG(("Got second verify from %s; resending server verify\n", + me->p_name)); + response.reply = SWITCH_VERIFY; + goto send; + } + UDPDIAG(("Receieved UDP verify from %s\n", me->p_name)); + UDPDIAG(("--- UDP connection established to %s\n", me->p_name)); +#ifdef BROKEN + warning("WARNING: BROKEN mode is enabled"); +#endif + + resetUDPsequence(); /* reset sequence numbers */ + commMode = COMM_UDP; /* at last */ + udpMode = MODE_SIMPLE; /* just send one at a time */ + + /* note that we don't NEED to send a SWITCH_VERIFY packet; the client */ + /* + * will change state when it receives ANY packet on the UDP connection + */ + /* (this just makes sure that it gets one) */ + /* (update: recvfrom() currently tosses the first packet it gets...) */ + response.reply = SWITCH_VERIFY; + goto send; + /* return; */ + } + if (packet->request == COMM_MODE) + { + /* wants to switch modes; mode is in "conmode" */ + mode = packet->connmode; + if (mode < MODE_TCP || mode > MODE_DOUBLE) + { + warning("Server can't do that UDP mode"); + UDPDIAG(("Got bogus request for UDP mode %d from %s\n", + mode, me->p_name)); + } + else + { + /* I don't bother with a reply, though it can mess up the opt win */ + switch (mode) + { + case MODE_TCP: + warning("Server will send with TCP only"); + break; + case MODE_SIMPLE: + warning("Server will send with simple UDP"); + break; + case MODE_FAT: + warning("Server will send with fat UDP; sent full update"); + V_UDPDIAG(("Sending full update to %s\n", me->p_name)); + forceUpdate(); + break; +#ifdef DOUBLE_UDP + case MODE_DOUBLE: + warning("Server will send with double UDP"); + scbufptr = scbuf + sizeof(struct sc_sequence_spacket); + break; +#else + case MODE_DOUBLE: + warning("Request for double UDP DENIED (set to simple)"); + mode = MODE_SIMPLE; + break; +#endif /* DOUBLE_UDP */ + } + + udpMode = mode; + UDPDIAG(("Switching %s to UDP mode %d\n", me->p_name, mode)); + } + return; + } + if (packet->request == COMM_UPDATE) + { + /* client wants a FULL update */ + V_UDPDIAG(("Sending full update to %s\n", me->p_name)); + forceUpdate(); + + return; + } + UDPDIAG(("Received request for %s mode from %s\n", + (packet->request == COMM_TCP) ? "TCP" : "UDP", me->p_name)); + if (packet->request == commMode) + { + /* client asking to switch to current mode */ + if (commMode == COMM_UDP) + { + /* + * client must be confused... whatever the cause, he obviously isn't + * connected to us, so we better drop out end and retry. + */ + UDPDIAG(("Rcvd UDP req from %s while in UDP mode; dropping old\n", + me->p_name)); + closeUdpConn(); + commMode = COMM_TCP; + /* ...and fall thru to the UDP request handler */ + } + else + { + /* + * Again, client is confused. This time there's no damage though. Just + * tell him that he succeeded. Could also happen if the client tried + * to connect to our UDP socket but failed, and decided to back off. + */ + UDPDIAG(("Rcvd TCP req from %s while in TCP mode\n", me->p_name)); + + response.reply = SWITCH_TCP_OK; + sendClientPacket((struct player_spacket *) & response); + + if (udpSock >= 0) + { + closeUdpConn(); + UDPDIAG(("Closed UDP socket\n")); + } + return; + } + } + /* okay, we have a request to change modes */ + if (packet->request == COMM_UDP) + { + udpClientPort = ntohl(packet->port); /* where to connect to */ + if (!configvals->udpAllowed) + { + UDPDIAG(("Rejected UDP request from %s\n", me->p_name)); + response.reply = SWITCH_DENIED; + response.port = htons(0); + goto send; + } + else + { + if (userUdpVersion != UDPVERSION) + { + char buf[80]; + sprintf(buf, "Server UDP is v%.1f, client is v%.1f", + (float) UDPVERSION / 10.0, + (float) userUdpVersion / 10.0); + warning(buf); + UDPDIAG(("%s (rejected %s)\n", buf, me->p_name)); + response.reply = SWITCH_DENIED; + response.port = htons(1); + goto send; + } + if (udpSock >= 0) + { + /* we have a socket open, but the client doesn't seem aware */ + /* (probably because our UDP verify got lost down the line) */ + UDPDIAG(("Receieved second request from %s, reconnecting\n", + me->p_name)); + closeUdpConn(); + } + /* (note no openUdpConn(); we go straight to connect) */ + if (connUdpConn() < 0) + { + response.reply = SWITCH_DENIED; + response.port = 0; + goto send; + } + UDPDIAG(("Connected UDP socket (%d:%d) for %s\n", udpSock, + udpLocalPort, me->p_name)); + + /* we are now connected to the client, but he's merely bound */ + /* don't switch to UDP mode yet; wait until client connects */ + response.reply = SWITCH_UDP_OK; + response.port = htonl(udpLocalPort); + + UDPDIAG(("packet->connmode = %d\n", packet->connmode)); + if (packet->connmode == CONNMODE_PORT) + { + /* send him our port # so he can connect to us */ + goto send; + } + else + { /* send him a packet; he'll get port from + * recvfrom() */ + int t = sizeof(response); + if (gwrite(udpSock, (char *) &response, sizeof(response)) != t) + { + UDPDIAG(("Attempt to send UDP packet failed; using alt\n")); + } + goto send; + } + + } + } + else if (packet->request == COMM_TCP) + { + closeUdpConn(); + commMode = COMM_TCP; + response.reply = SWITCH_TCP_OK; + response.port = 0; + UDPDIAG(("Closed UDP socket for %s\n", me->p_name)); + goto send; + } + else + { + fprintf(stderr, "ntserv: got weird UDP request (%d)\n", + packet->request); + return; + } +send: + sendClientPacket((struct player_spacket *) & response); +} + + +int +connUdpConn() +{ + struct sockaddr_in addr; + int len; + + if (udpSock > 0) + { + fprintf(stderr, "ntserv: tried to open udpSock twice\n"); + return (0); /* pretend we succeeded (this could be bad) */ + } + resetUDPbuffer(); + if ((udpSock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + perror("ntserv: unable to create DGRAM socket"); + return (-1); + } + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = remoteaddr; /* addr of our client */ + addr.sin_port = htons(udpClientPort); /* client's port */ + + if (connect(udpSock, (struct sockaddr *) & addr, sizeof(addr)) < 0) + { + perror("ntserv: connect to client UDP port"); + UDPDIAG(("Unable to connect() to %s on port %d\n", me->p_name, + udpClientPort)); + close(udpSock); + udpSock = -1; + return (-1); + } + UDPDIAG(("connect to %s's port %d on 0x%x succeded\n", + me->p_name, udpClientPort, remoteaddr)); + + /* determine what our port is */ + len = sizeof(addr); + if (getsockname(udpSock, (struct sockaddr *) & addr, &len) < 0) + { + perror("netrek: unable to getsockname(UDP)"); + UDPDIAG(("Can't get our own socket; connection failed\n")); + close(udpSock); + udpSock = -1; + return (-1); + } + udpLocalPort = (int) ntohs(addr.sin_port); + + if (configvals->udpAllowed > 2) /* verbose debug mode? */ + printUdpInfo(); + + return (0); +} + +int +closeUdpConn() +{ + V_UDPDIAG(("Closing UDP socket\n")); + if (udpSock < 0) + { + fprintf(stderr, "ntserv: tried to close a closed UDP socket\n"); + return (-1); + } + shutdown(udpSock, 2); /* wham */ + close(udpSock); /* bam */ + udpSock = -1; /* (nah) */ + + return (0); +} + +/* used for debugging */ +void +printUdpInfo() +{ + struct sockaddr_in addr; + int len; + + len = sizeof(addr); + if (getsockname(udpSock, (struct sockaddr *) & addr, &len) < 0) + { + perror("printUdpInfo: getsockname"); + return; + } + UDPDIAG(("LOCAL: addr=0x%lx, family=%d, port=%d\n", + (u_long) addr.sin_addr.s_addr, + addr.sin_family, ntohs(addr.sin_port))); + + if (getpeername(udpSock, (struct sockaddr *) & addr, &len) < 0) + { + perror("printUdpInfo: getpeername"); + return; + } + UDPDIAG(("PEER : addr=0x%lx, family=%d, port=%d\n", + (u_long) addr.sin_addr.s_addr, + addr.sin_family, ntohs(addr.sin_port))); +} + +void +handleSequence() +{ + /* we don't currently deal with sequence numbers from clients */ +} + +void +handleAskMOTD() +{ + sendMotd(); +} + + +#ifdef DOUBLE_UDP +/* + * If we're in double-UDP mode, then we need to send a separate semi-critical + * transmission over UDP. We need to give it the same sequence number as the + * previous transmission, but the sequence packet will have type + * SP_CP_SEQUENCE instead of SP_SEQUENCE. + */ +void +sendSC() +{ + struct sequence_spacket *ssp; + struct sc_sequence_spacket *sc_sp; + int cc; + + if (commMode != COMM_UDP || udpMode != MODE_DOUBLE) + { + /* mode not active, keep buffer clear */ + scbufptr = scbuf; + return; + } + if (scbufptr - scbuf <= sizeof(struct sc_sequence_spacket)) + { + /* nothing to send */ + return; + } + /* copy sequence #, send what we got, then reset buffer */ + sc_sp = (struct sc_sequence_spacket *) scbuf; + ssp = (struct sequence_spacket *) udpbuf; + sc_sp->type = SP_SC_SEQUENCE; + sc_sp->sequence = ssp->sequence; + if ((cc = gwrite(udpSock, scbuf, scbufptr - scbuf)) != scbufptr - scbuf) + { + fprintf(stderr, "UDP sc gwrite failed (%d, error %d)\n", cc, errno); + UDPDIAG(("*** UDP diSConnected for %s\n", me->p_name)); + printUdpInfo(); + closeUdpConn(); + commMode = COMM_TCP; + return; + } + scbufptr = scbuf + sizeof(struct sc_sequence_spacket); +} + +#endif + +/* + * This is a truncated version of initClientData(). Note that it doesn't + * explicitly reset all the fat UDP stuff; sendClientData will take care of + * that by itself eventually. + * + * Only semi-critical data is sent, with a few exceptions for non-critical data + * which would be nice to update (stats, kills, player posn, etc). The + * critical stuff can't be lost, so there's no point in resending it. + * + * (Since the fat data begins in an unqueued state, forceUpdate() should be + * called immediately after switching to fat mode. This guarantees that + * every packet will end up on a queue. The only real reason for doing this + * is so that switching to fat mode will clear up your display and keep it + * cleared; otherwise you could have torps floating around forever because + * the packet for them isn't on a queue. Will it reduce the effectiveness of + * fat UDP? No, because as soon as the player hits the "update all" key it's + * gonna happen anyway...) + */ +void +forceUpdate() +{ + static time_t lastone = 0; + time_t now; + int i; + + now = time(0); + if (now - lastone < UDP_UPDATE_WAIT) + { + warning("Update request DENIED (chill out!)"); + return; + } + lastone = now; + + /* clientDead=0; */ + for (i = 0; i < MAXPLAYER; i++) + { + clientHostile[i].hostile = -1; + clientStats[i].losses = -1; /* (non-critical, but nice) */ + /* clientLogin[i].rank= -1; (critical) */ + /* clientPlayersInfo[i].shiptype= -1; (critical) */ + /* clientPStatus[i].status= -1; (critical) */ + clientPlayers[i].x = htonl(-1); /* (non-critical, but nice) */ + clientPhasers[i].status = -1; + clientKills[i].kills = htonl(-1); /* (non-critical, but nice) */ + clientFlags[i].flags = htonl(-1); + mustUpdate[i] = 0; + } + for (i = 0; i < MAXPLAYER * MAXTORP; i++) + { + clientTorpsInfo[i].status = -1; + /* clientTorps[i].x= -1; (non-critical) */ + } + for (i = 0; i < MAXPLAYER * MAXPLASMA; i++) + { + clientPlasmasInfo[i].status = -1; + /* clientPlasmas[i].x= -1; (non-critical) */ + } + for (i = 0; i < TOTALTHINGIES; i++) + { + + clientThingysInfo[i].shape = htons(-1); + /* clientThingys[i].x= -1; (non-critical) */ + } + for (i = 0; i < MAXPLANETS; i++) + { + clientPlanets2[i].armies = htonl(-2); + /* clientPlanetLocs[i].x= htonl(-1); (critical) */ + } + /* msgCurrent=(mctl->mc_current+1) % MAXMESSAGE; */ + clientSelf.pnum = -1; +} + +int +isCensured(s) /* return true if cannot message opponents */ + char *s; +{ + return ( +#if 0 + (strncmp(s, "am4m", 4) == 0) || /* 7/21/91 TC */ + (strncmp(s, "dm3e", 4) == 0) || /* 7/21/91 TC */ + (strncmp(s, "gusciora", 8) == 0) || /* 7/25/91 TC */ + (strncmp(s, "flan", 4) == 0) || /* 4/2/91 TC */ + (strncmp(s, "kc3b", 4) == 0) || /* 4/4/91 TC */ + (strncmp(s, "windom", 6) == 0) || /* 7/20/92 TC */ +#endif + 0 + ); +} + +/* return true if you should eat message */ + +int +parseIgnore(packet) + struct mesg_cpacket *packet; +{ + char *s; + int who; + int what; + char buf[80]; + int noneflag; + + /* if (packet->indiv != me->p_no) return 0; */ + + s = packet->mesg; + + who = packet->indiv; + if ((*s != ':') && (strncmp(s, " ", 5) != 0)) + return 0; + if ((who == me->p_no) || (*s == ' ')) + { /* check for borg call 4/6/92 TC */ + if (configvals->binconfirm) + warning("No cyborgs allowed in the game at this time."); + else + { + char buf[80]; + char buf2[5]; + int i; + int cybflag = 0; + + strcpy(buf, "Possible cyborgs: "); + for (i = 0; i < MAXPLAYER; i++) + if ((players[i].p_status != PFREE) && + (players[i].p_stats.st_flags & ST_CYBORG)) + { + sprintf(buf2, "%s ", twoletters(&players[i])); + strcat(buf, buf2); + cybflag = 1; + } + if (!cybflag) + strcat(buf, "None"); + warning(buf); + } + if (*s != ' ') /* if not a borg call, eat msg 4/6/92 TC */ + return 1; + else + return 0; /* otherwise, send it 4/6/92 TC */ + } + if (packet->group != MINDIV) + return 0; /* below is for indiv only */ + + do + { + what = 0; + switch (*(++s)) + { + case 'a': + case 'A': + what = MALL; + break; + case 't': + case 'T': + what = MTEAM; + break; + case 'i': + case 'I': + what = MINDIV; + break; + case '\0': + what = 0; + break; + default: + what = 0; + break; + } + ignored[who] ^= what; + } while (what != 0); + + strcpy(buf, "Ignore status for this player: "); + noneflag = 1; + if (ignored[who] & MALL) + { + strcat(buf, "All "); + noneflag = 0; + } + if (ignored[who] & MTEAM) + { + strcat(buf, "Team "); + noneflag = 0; + } + if (ignored[who] & MINDIV) + { + strcat(buf, "Indiv "); + noneflag = 0; + } + if (noneflag) + strcat(buf, "None"); + warning(buf); + return 1; +} + +/* give session stats if you send yourself a '?' 2/27/92 TC */ +/* or '!' for ping stats (HAK) */ +/* merged RSA query '#' here, too (HAK) */ +/* return true if you should eat message */ + +int +parseQuery(packet) + struct mesg_spacket *packet; /* was cpacket 4/17/92 TC */ +{ + char buf[80]; + float sessionBombing, sessionPlanets, sessionOffense, sessionDefense; + int deltaArmies, deltaPlanets, deltaKills, deltaLosses, deltaTicks; + + extern int startTkills, startTlosses, startTarms, startTplanets, startTticks; + + /* 0-8 for address, 9 is space */ + + if (packet->mesg[11] != '\0') /* one character only */ + return 0; + + switch (packet->mesg[10]) + { + case '!': + return bouncePingStats(packet); + case '#': + sprintf(buf, "Client: %s", RSA_client_type); + bounce(buf, packet->m_from); + return 1; + case '?': + deltaPlanets = me->p_stats.st_tplanets - startTplanets; + deltaArmies = me->p_stats.st_tarmsbomb - startTarms; + deltaKills = me->p_stats.st_tkills - startTkills; + deltaLosses = me->p_stats.st_tlosses - startTlosses; + deltaTicks = me->p_stats.st_tticks - startTticks; + + if (deltaTicks == 0) + return 1; /* can happen if no tmode */ + + sessionPlanets = (float) deltaPlanets *status->timeprod / + ((float) deltaTicks * status->planets); + + sessionBombing = (float) deltaArmies *status->timeprod / + ((float) deltaTicks * status->armsbomb); + + sessionOffense = (float) deltaKills *status->timeprod / + ((float) deltaTicks * status->kills); + + sessionDefense = (float) deltaTicks *status->losses / + (deltaLosses != 0 ? + ((float) deltaLosses * status->timeprod) : + (status->timeprod)); + + sprintf(buf, "%2s stats: %d planets and %d armies. %d wins/%d losses. %5.2f hours.", + twoletters(me), + deltaPlanets, + deltaArmies, + deltaKills, + deltaLosses, + (float) deltaTicks / 36000.0); + bounce(buf, packet->m_from); + sprintf(buf, "Ratings: Pla: %5.2f Bom: %5.2f Off: %5.2f Def: %5.2f Ratio: %4.2f", + sessionPlanets, + sessionBombing, + sessionOffense, + sessionDefense, + (float) deltaKills / + (float) ((deltaLosses == 0) ? 1 : deltaLosses)); + bounce(buf, packet->m_from); + return 1; + default: + return 0; + } + /* NOTREACHED */ +} + +int +bouncePingStats(packet) + struct mesg_spacket *packet; +{ + char buf[80]; + + if (me->p_avrt == -1) + { + /* client doesn't support it or server not pinging */ + sprintf(buf, "No ping stats available for %s", + twoletters(me)); + } + else + { + sprintf(buf, "%s ping stats: Average: %d ms, Stdv: %d ms, Loss: %d%%", + twoletters(me), + me->p_avrt, + me->p_stdv, + me->p_pkls); + } + bounce(buf, packet->m_from); + + return 1; +} + +/* new code, sends bouncemsg to bounceto from GOD 4/17/92 TC */ +void +bounce(bouncemsg, bounceto) + char *bouncemsg; + int bounceto; +{ + char buf[10]; + + sprintf(buf, "GOD->%s", twoletters(&players[bounceto])); + pmessage(bouncemsg, bounceto, MINDIV, buf); +} + + +/* + */ + +void +sendShipCap() +{ + struct ship_cap_spacket temppack; + struct ship ship; + int i; + + if (!blk_flag) + return; + for (i = 0; i < NUM_TYPES; i++) + { + getship(&ship, i); + temppack.type = SP_SHIP_CAP; + temppack.operation = 0; + temppack.s_type = htons(ship.s_type); + temppack.s_torpspeed = htons(ship.s_torp.speed); +#if 1 + temppack.s_phaserrange = htons(ship.s_phaser.speed); +#else + temppack.s_phaserrange = htons(ship.s_phaser.damage); +#endif + temppack.s_maxspeed = htonl(ship.s_imp.maxspeed); + temppack.s_maxfuel = htonl(ship.s_maxfuel); + temppack.s_maxshield = htonl(ship.s_maxshield); + temppack.s_maxdamage = htonl(ship.s_maxdamage); + temppack.s_maxwpntemp = htonl(ship.s_maxwpntemp); + temppack.s_maxegntemp = htonl(ship.s_maxegntemp); + temppack.s_width = htons(ship.s_width); + temppack.s_height = htons(ship.s_height); + temppack.s_maxarmies = htons(ship.s_maxarmies); + temppack.s_letter = ship.s_letter; + temppack.s_desig1 = ship.s_desig1; + temppack.s_desig2 = ship.s_desig2; + if (blk_flag == 1) + temppack.s_bitmap = htons(ship.s_alttype); + else + temppack.s_bitmap = htons(ship.s_bitmap); + sendClientPacket((struct player_spacket *) & temppack); + } +} + +void +sendMotdPic(x, y, bits, page, width, height) + int x; + int y; + char *bits; + int page; + int width; + int height; +{ + struct motd_pic_spacket temppack; + short sx, sy, sp, sw, sh; + int size; + + size = (width / 8 + (width % 8 != 0)) * height; + sx = x; + sy = y; + sp = page; + sw = width; + sh = height; + temppack.type = SP_MOTD_PIC; + temppack.x = htons(sx); + temppack.y = htons(sy); + temppack.width = htons(sw); + temppack.height = htons(sh); + temppack.page = htons(sp); + memcpy(temppack.bits, bits, size); + + sendClientPacket((struct player_spacket *) & temppack); +} + + +void +sendMotdNopic(x, y, page, width, height) + int x; + int y; + int page; + int width; + int height; +{ + struct pe1_missing_bitmap_spacket temppack; + + temppack.type = SP_PARADISE_EXT1; + temppack.subtype = SP_PE1_MISSING_BITMAP; + temppack.page = htons((short) page); + temppack.x = htons((short) x); + temppack.y = htons((short) y); + temppack.width = htons((short) width); + temppack.height = htons((short) height); + + sendClientPacket((struct player_spacket *) & temppack); +} + +/* tells the client how many missiles carried [BDyess] */ +void +sendMissileNum(num) + int num; +{ + + /* remove the 1 || to enable missile updates [BDyess] */ + if (clientMissiles.num == htons(num)) + return; + + clientMissiles.type = SP_PARADISE_EXT1; + clientMissiles.subtype = SP_PE1_NUM_MISSILES; + clientMissiles.num = htons(num); + + sendClientPacket((struct player_spacket *) & clientMissiles); +} + +#ifdef RSA_EXEMPTION_FILE + +/* + * this code was copied from + * + * portname.c, part of faucet and hose: network pipe utilities Copyright (C) + * 1992 Robert Forsman + * + * He has granted the Paradise project permission to use this code for + * non-profit purposes. + * + */ + +int +convert_hostname(char *name, struct in_addr * addr) +{ + struct hostent *hp; + int len; + + hp = gethostbyname(name); + if (hp != NULL) + memcpy(addr, hp->h_addr, hp->h_length); + else + { + int count; + unsigned int a1, a2, a3, a4; + + count = sscanf(name, "%i.%i.%i.%i%n", &a1, &a2, &a3, &a4, &len); + + if (4 != count || 0 != name[len]) + return 0; + + addr->s_addr = (((((a1 << 8) | a2) << 8) | a3) << 8) | a4; + } + return 1; +} + +/* + * figure out if our client is exempt from RSA authentication. + * + * The host name resolution above doesn't handle gateways, which can have more + * than one internet address :/ + */ + +int +site_rsa_exempt() +{ + FILE *fp; + char buf[256]; + + if (remoteaddr == -1) + { + printf("remote address is not yet available?!\n"); + return 0; /* weird */ + } + + /* hopefully we've got the remote address at this point */ + + fp = fopen(build_path(RSA_EXEMPTION_FILE), "r"); + + if (!fp) + return 0; /* nobody is exempt */ + + while (fgets(buf, sizeof(buf), fp)) + { + char hostname[256]; + char *playername; + int len; + int i; + struct in_addr addr; + + len = strlen(buf); + + if (buf[len - 1] == '\n') + buf[len - 1] = 0; + + for (i = 0; buf[i] && !isspace(buf[i]); i++) + hostname[i] = buf[i]; + + hostname[i] = 0; /* hostname is copied to buffer */ + + while (buf[i] && isspace(buf[i])) + i++; + + playername = buf + i; /* player name is stuff after hostname */ + + if (!(*playername == 0 || strcmp(playername, me->p_name) == 0)) + continue; /* name didn't match */ + + /* + * shit, I gotta parse this crap myself. I'll steal this code from hose + * - RF + */ + if (!convert_hostname(hostname, &addr)) + { + printf("address in %s unparseable `%s'\n", + RSA_EXEMPTION_FILE, hostname); + continue; + } + + if (addr.s_addr == remoteaddr) + return 1; + } /* while (line in rsa-exempt file) */ + + fclose(fp); + + return 0; +} + +#endif /* RSA_EXEMPTION_FILE */