# HG changeset patch # User darius # Date 881383023 0 # Node ID aa38447a4b2122b2eef31acc2f60e9352805ec97 # Parent cafa94d86546709c3ac453ee0e276f0256ce8273 First entry of Paradise Server 2.9 patch 10 Beta diff -r cafa94d86546 -r aa38447a4b21 src/fatudp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fatudp.c Sat Dec 06 04:37:03 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 +#include + +#include "defs.h" +#include "data.h" +#include "packets.h" +#include "shmem.h" + +/* #define FATDIAG /* define to get LOTS of fat UDP debugging messages */ + + +/* 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; + +FAT_NODE fat_kills[MAXPLAYER]; +FAT_NODE fat_torp_info[MAXPLAYER * MAXTORP]; +FAT_NODE fat_thingy_info[TOTALTHINGIES]; +FAT_NODE fat_phaser[MAXPLAYER]; +FAT_NODE fat_plasma_info[MAXPLAYER * MAXPLASMA]; +FAT_NODE fat_you; +#if 0 +FAT_NODE fat_status; +FAT_NODE fat_planet[MAXPLANETS]; +#else +FAT_NODE fat_status2; +FAT_NODE fat_planet2[MAXPLANETS]; +#endif +FAT_NODE fat_flags[MAXPLAYER]; +FAT_NODE fat_hostile[MAXPLAYER]; + +/* define the lists */ +#define MAX_FAT_LIST 5 /* tweakable; should be > 1 */ +typedef struct +{ + FAT_NODE *head; + FAT_NODE *tail; +} FAT_LIST; +FAT_LIST fatlist[MAX_FAT_LIST], tmplist[MAX_FAT_LIST]; +/* tweakable parameters; compare with UDPBUFSIZE */ +/* NOTE: FAT_THRESH + MAX_FAT_DATA must be < UDPBUFSIZE */ +/* MAX_FAT_DATA must be larger than biggest semi-critical packet */ +#define MAX_FAT_DATA 100 /* add at most this many bytes */ +#define MAX_NONFAT 10 /* if we have this much left, stop */ + + +void +reset_fat_list() +{ + int i; + for (i = 0; i < MAX_FAT_LIST; i++) + fatlist[i].head = fatlist[i].tail = (FAT_NODE *) NULL; +} +/* + * + * --------------------------------------------------------------------------- + * Fat City + * --------------------------------------------------------------------------- + * */ + +/* + * Remove a FAT_NODE from a queue. If it's at the head or the tail of a + * list, then we need to figure out which list it's in and update the head or + * tail pointer. It's easier to go searching than to maintain a queue number + * in every FAT_NODE. + * + * This routine looks too complex... there must be a simpler way to do this. + */ +void +dequeue(fatp) + FAT_NODE *fatp; +{ + int i; + +#ifdef V_FATDIAG + for (i = 0; i < MAX_FAT_LIST; i++) + { + printf("fatlist[i].head = 0x%.8lx tail = 0x%.8lx\n", + fatlist[i].head, fatlist[i].tail); + if ((fatlist[i].head == NULL && fatlist[i].tail != NULL) || + (fatlist[i].head != NULL && fatlist[i].tail == NULL)) + { + printf("before!\n"); + kill(getpid(), 15); + } + } +#endif + + + if (fatp->next == NULL) + { + /* it's at the head or not in a queue */ + for (i = 0; i < MAX_FAT_LIST; i++) + { + if (fatlist[i].head == fatp) + { + fatlist[i].head = fatp->prev; /* move head back */ + if (fatlist[i].head != NULL) + (fatlist[i].head)->next = NULL; /* amputate */ + break; + } + } + } + else + { + /* it's not at the head */ + if (fatp->prev != NULL) + fatp->prev->next = fatp->next; + } + + if (fatp->prev == NULL) + { + /* it's at the tail or not in a queue */ + for (i = 0; i < MAX_FAT_LIST; i++) + { + if (fatlist[i].tail == fatp) + { + fatlist[i].tail = fatp->next; /* move head fwd */ + if (fatlist[i].tail != NULL) + (fatlist[i].tail)->prev = NULL; /* amputate */ + break; + } + } + } + else + { + /* it's not at the tail */ + if (fatp->next != NULL) + fatp->next->prev = fatp->prev; + } + +#ifdef FATDIAG + printf("Removed 0x%.8lx...", fatp); /* FATDIAG */ + for (i = 0; i < MAX_FAT_LIST; i++) + { + if ((fatlist[i].head == NULL && fatlist[i].tail != NULL) || + (fatlist[i].head != NULL && fatlist[i].tail == NULL)) + { + printf("after: %d %.8lx %.8lx\n", i, fatlist[i].head, fatlist[i].tail); + kill(getpid(), 15); + } + } +#endif + fatp->prev = NULL; + fatp->next = NULL; +} + +/* + * Add a FAT_NODE to the tail of a temporary queue. The merge() routine + * merges the temporary queues with the fatlists once the transmission is + * sent. + */ +void +enqueue(fatp, list) + FAT_NODE *fatp; + int list; +{ +#ifdef FATDIAG + printf("added to tmplist %d\n", list); /* FATDIAG */ +#endif + + if (tmplist[list].tail == NULL) + { + /* list was empty */ + tmplist[list].tail = tmplist[list].head = fatp; + } + else + { + /* list wasn't empty */ + fatp->next = tmplist[list].tail; + fatp->next->prev = fatp; + tmplist[list].tail = fatp; + } +} + +/* + * This updates the "fat" tables; it's called from sendClientData(). + */ +void +updateFat(packet) +/* Pick a random type for the packet */ + struct player_spacket *packet; +{ + FAT_NODE *fatp; + struct kills_spacket *kp; + struct torp_info_spacket *tip; + struct thingy_info_spacket *thip; + struct phaser_spacket *php; + struct plasma_info_spacket *pip; + /* struct you_spacket *yp; */ + /* struct status_spacket2 *sp2; */ + /* struct planet_spacket *plp; */ + struct planet_spacket2 *plp2; + struct flags_spacket *fp; + struct hostile_spacket *hp; + int idx; + + /* step 1 : find the FAT_NODE for this packet */ + switch (packet->type) + { + case SP_KILLS: + kp = (struct kills_spacket *) packet; + idx = (int) kp->pnum; + fatp = &fat_kills[idx]; + break; + case SP_TORP_INFO: + tip = (struct torp_info_spacket *) packet; + idx = (int) ntohs(tip->tnum); + fatp = &fat_torp_info[idx]; + break; + case SP_THINGY_INFO: + thip = (struct thingy_info_spacket *) packet; + idx = (int) ntohs(thip->tnum); + fatp = &fat_thingy_info[idx]; + break; + case SP_PHASER: + php = (struct phaser_spacket *) packet; + idx = (int) php->pnum; + fatp = &fat_phaser[idx]; + break; + case SP_PLASMA_INFO: + pip = (struct plasma_info_spacket *) packet; + idx = (int) ntohs(pip->pnum); + fatp = &fat_plasma_info[idx]; + break; + case SP_YOU: + /* yp = (struct you_spacket *) packet; */ + fatp = &fat_you; + break; +#if 0 + case SP_STATUS: + /* sp = (struct status_spacket *) packet; */ + fatp = &fat_status; + break; + case SP_PLANET: + plp = (struct planet_spacket *) packet; + idx = plp->pnum; + fatp = &fat_planet[idx]; + break; +#else + case SP_STATUS2: + /* sp = (struct status_spacket *) packet; */ + fatp = &fat_status2; + break; + case SP_PLANET2: + plp2 = (struct planet_spacket2 *) packet; + idx = plp2->pnum; + fatp = &fat_planet2[idx]; + break; +#endif + case SP_FLAGS: + fp = (struct flags_spacket *) packet; + idx = (int) fp->pnum; + fatp = &fat_flags[idx]; + break; + case SP_HOSTILE: + hp = (struct hostile_spacket *) packet; + idx = (int) hp->pnum; + fatp = &fat_hostile[idx]; + break; + default: + fprintf(stderr, "Fat error: bad semi-critical type (%d) in updateFat\n", (CARD8) packet->type); + return; + } + + if (fatp->packet != (PTR) packet) + { + fprintf(stderr, "Fat error: fatp->packet=0x%.8lx, packet=0x%.8lx\n", + (unsigned long) fatp->packet, (unsigned long) packet); + return; + } + /* step 2 : move this dude to temporary list 0 */ + dequeue(fatp); + enqueue(fatp, 0); +} + +/* + * This fattens up the transmission, adding up to MAX_FAT_DATA bytes. The + * packets which get added will be moved to a higher queue, giving them less + * priority for next time. Note that they are added to a parallel temporary + * list (otherwise they'd could be sent several times in the same + * transmission as the algorithm steps through the queues), and merged later + * on. + * + * Packets are assigned from head to tail, on a first-fit basis. If a + * semi-critical packet is larger than MAX_FAT_DATA, this routine will never + * send it, but it will skip around it. + * + * This routine is called from flushSockBuf, before the transmission is sent. + * + * A possible improvement is to have certain packets "expire", never to be seen + * again. This way we don't keep resending torp packets for players who are + * long dead. This raises the possibility that the dead player's torps will + * never go away though. + */ +int +fatten() +{ + int bytesleft; + FAT_NODE *fatp, *nextfatp; + int list; + +#ifdef FATDIAG + printf("--- fattening\n"); +#endif + bytesleft = MAX_FAT_DATA; + for (list = 0; list < MAX_FAT_LIST; list++) + { + fatp = fatlist[list].head; + while (fatp != NULL) + { + nextfatp = fatp->prev; /* move toward tail */ +#ifdef FATDIAG + if (nextfatp == fatp) + { + printf("Hey! nextfatp == fatp!\n"); + kill(getpid(), 15); + } +#endif + if (fatp->pkt_size < bytesleft) + { + /* got one! */ + sendUDPbuffered(0, fatp->packet, fatp->pkt_size); + bytesleft -= fatp->pkt_size; + + packets_sent++; /* counts as a udp packet sent */ + + /* move the packet to a higher queue (if there is one) */ + dequeue(fatp); + if (list + 1 == MAX_FAT_LIST) + { + /* enqueue(fatp, list); *//* keep packets on high queue? */ + } + else + { + enqueue(fatp, list + 1); + } + + /* done yet? */ + if (bytesleft < MAX_NONFAT) + goto done; /* don't waste time searching anymore */ + } + fatp = nextfatp; + } + } + +done: + /* at this point, we either filled with fat or ran out of queued packets */ +#ifdef FATDIAG + printf("--- done\n"); +#endif + V_UDPDIAG(("- Added %d grams of fat\n", MAX_FAT_DATA - bytesleft)); + return (0); /* some compilers need something after a goto */ +} + + +/* + * This gets called from flushSockBuf after the transmission is sent. It + * appends all the packets sitting in temporary queues to the corresponding + * fat queues, where they will be eligible for fattening next transmission. + */ +void +fatMerge() +{ + int i; + + for (i = 0; i < MAX_FAT_LIST; i++) + { + if (tmplist[i].head == NULL) + continue; /* temp list is empty, nothing to do */ + + if (fatlist[i].head == NULL) + { + /* fatlist is empty; just copy pointers */ + fatlist[i].head = tmplist[i].head; + fatlist[i].tail = tmplist[i].tail; + + } + else + { + /* stuff in both */ + (tmplist[i].head)->next = fatlist[i].tail; /* fwd pointer */ + (fatlist[i].tail)->prev = tmplist[i].head; /* back pointer */ + fatlist[i].tail = tmplist[i].tail; /* move tail back */ + tmplist[i].head = tmplist[i].tail = NULL; /* clear the tmp list */ + } + tmplist[i].head = tmplist[i].tail = NULL; +#ifdef FATDIAG + printf("merged list %d: %.8lx %.8lx\n", i, fatlist[i].head, + fatlist[i].tail); +#endif + } +} diff -r cafa94d86546 -r aa38447a4b21 src/feature.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/feature.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,228 @@ +/*-------------------------------------------------------------------------- +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" +#ifdef FEATURE +#ifdef HPUX +#include +#include +#endif +#include "defs.h" +#include "data.h" +#include "struct.h" +#include "packets.h" + +void sendClientPacket(); + +#ifdef UNIXWARE /* can you BELIEVE it doesn't have strcmpi?? */ +#if 0 /* just use strcmp for now */ +int +strcmpi(char *a, char *b) +{ + + char ta, tb; + + while ((*a) && (*b)) + { + ta = ((*a) >= 'a') && ((*b) <= 'z')) ? (*a) & 223 : (*a); + tb = ((*b) >= 'a') && ((*b) <= 'z')) ? (*b) & 223 : (*b); + if (ta < tb) + return (-1); + if (ta > tb) + return (1); + a++; + b++; + } + if (!(*a) && (*b)) + return (1); + if (!(*b) && (*a)) + return (-1); + return (0); +} +#endif +#endif + +/* + * Feature.c + * + * March, 1994. Joe Rumsey, Tedd Hadley + * + * most of the functions needed to handle SP_FEATURE/CP_FEATURE packets. fill + * in the features list below for your client, and add a call to + * reportFeatures just before the RSA response is sent. handleFeature should + * just call checkFeature, which will search the list and set the appropriate + * variable. features unknown to the server are set to the desired value for + * client features, and off for server/client features. + * + * feature packets look like: struct feature_cpacket { char + * type; char feature_type; char arg1, arg2; + * int value; char name[80]; }; + * + * type is CP_FEATURE, which is 60. feature_spacket is identical. + * + * Code lifted July 1995 by Bob Glamm - enabled into server code. + * + */ + +void handleFeature(struct feature_cpacket *); +void +sendFeature(char *name, int feature_type, + int value, int arg1, int arg2); + +/* not the actual packets: this holds a list of features to report for */ +/* this client. */ +struct feature +{ + char *name; + int *var; /* holds allowed/enabled status */ + char feature_type; /* 'S' or 'C' for server/client */ + int value; /* desired status */ + char *arg1, *arg2; /* where to copy args, if non-null */ +} features[] = +{ + /* + * also sent seperately, put here for checking later. should be ok that + * it's sent twice. + */ + { + "FEATURE_PACKETS", &F_feature_packets, 'S', 1, 0, 0 + }, + + { + "VIEW_BOX", &F_allowViewBox, 'C', 1, 0, 0 + }, + { + "SHOW_ALL_TRACTORS", &F_allowShowAllTractorPressor, 'S', 1, 0, 0 + }, +#ifdef CONTINUOUS_MOUSE + { + "CONTINUOUS_MOUSE", &F_allowContinuousMouse, 'C', 1, 0, 0 + }, +#endif + { + "NEWMACRO", &F_UseNewMacro, 'C', 1, 0, 0 + }, + /* {"SMARTMACRO",&F_UseSmartMacro, 'C', 1, 0, 0}, */ + { + "MULTIMACROS", &F_multiline_enabled, 'S', 1, 0, 0 + }, + { + "WHY_DEAD", &F_why_dead, 'S', 1, 0, 0 + }, + { + "CLOAK_MAXWARP", &F_cloakerMaxWarp, 'S', 1, 0, 0 + }, + /* {"DEAD_WARP", &F_dead_warp, 'S', 1, 0, 0}, */ +#ifdef RC_DISTRESS + { + "RC_DISTRESS", &F_gen_distress, 'S', 1, 0, 0 + }, +#ifdef BEEPLITE + { + "BEEPLITE", &F_allow_beeplite, 'C', 1, (char *) &F_beeplite_flags, 0 + }, +#endif +#endif + /* terrain features */ + { + "TERRAIN", &F_terrain, 'S', 1, (char *) &F_terrain_major, (char *) &F_terrain_minor + }, + /* Gzipped MOTD */ + { + "GZ_MOTD", &F_gz_motd, 'S', 1, (char *) &F_gz_motd_major, (char *) &F_gz_motd_minor + }, + { + 0, 0, 0, 0, 0, 0 + } +}; + +void +handleFeature(packet) + struct feature_cpacket *packet; +{ + int feature = 0; + int value = ntohl(packet->value); + +#ifdef FEATURE_DIAG + pmessage("Whoohoo! Getting a feature packet.", 0, MALL, MSERVA); +#endif + while (features[feature].name) + { + if (!strcmp(features[feature].name, packet->name)) + { +#ifdef FEATURE_DIAG + { + char buf[80]; + sprintf(buf, "BEANS! Matched feature %s", packet->name); + pmessage(buf, 0, MALL, MSERVA); + } +#endif + /* A match was found. */ + if (features[feature].var) + *features[feature].var = packet->value; + if (features[feature].arg1) + *features[feature].arg1 = packet->arg1; + if (features[feature].arg2) + *features[feature].arg2 = packet->arg2; + + /* + * tell the client that the server handles all of the above server + * features. + */ + if (features[feature].feature_type == 'S') + { +#ifdef FEATURE_DIAG + pmessage("Sending FEATURE_PACKETS right back at ya!", 0, MALL, MSERVA); +#endif + sendFeature(features[feature].name, + features[feature].feature_type, + features[feature].value, + (features[feature].arg1 ? *features[feature].arg1 : 0), + (features[feature].arg2 ? *features[feature].arg2 : 0)); + } + } + feature++; + } +} + +void +sendFeature(name, feature_type, value, arg1, arg2) + char *name; + int feature_type; + int value; + int arg1, arg2; +{ + struct feature_cpacket packet; +#ifdef FEATURE_DIAG + char buf[80]; + + sprintf(buf, "Sending packet %d, name %s", SP_FEATURE, name); + pmessage(buf, 0, MALL, MSERVA); +#endif + + strncpy(packet.name, name, sizeof(packet.name)); + packet.type = SP_FEATURE; + packet.name[sizeof(packet.name) - 1] = 0; + packet.feature_type = feature_type; + packet.value = htonl(value); + packet.arg1 = arg1; + packet.arg2 = arg2; + sendClientPacket((struct player_spacket *) & packet); +} + +#endif /* FEATURE */ diff -r cafa94d86546 -r aa38447a4b21 src/findslot.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/findslot.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,491 @@ +/*-------------------------------------------------------------------------- +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 "defs.h" +#include "struct.h" +#include "data.h" +#include "packets.h" +#include "shmem.h" + +int grabslot( /* int */ ); +void mapWaitCount( /* int */ ); + + +extern int isClientDead(); +extern unsigned int sleep(); +extern int sendQueuePacket(); +extern int flushSockBuf(); + +int +findslot(overload, homeaway) + int overload; + enum HomeAway homeaway; +{ + int i; + + i = grabslot(overload, homeaway); + players[i].p_pos = -1; + memset(&players[i].p_stats, 0, sizeof(struct stats)); + players[i].p_stats.st_tticks = 1; +#if 0 + for (j = 0; j < 95; j++) + { + players[i].p_stats.st_keymap[j] = j + 32; + } + players[i].p_stats.st_keymap[95] = 0; +#endif + players[i].p_stats.st_flags = ST_INITIAL; + return (i); +} + +static int +allocate_slot(homeaway, overload, allocate) + enum HomeAway homeaway; + int overload; + int allocate; +{ + int i; + if (overload) + { + for (i = MAXPLAYER - 1; i >= 0; i--) + { + if (players[i].p_status == PFREE) + { + if (allocate) + { + players[i].p_status = POUTFIT; + players[i].p_team = NOBODY; + } + return i; + } + } + } + else + { +#ifdef LEAGUE_SUPPORT + if (status2->league) + { + /* + * for league play, make sure one team doesn't crowd out the other. + */ + int count = 0; + for (i = 0; i < MAXPLAYER; i++) + { + if (players[i].p_status == PFREE) + continue; + if (players[i].p_homeaway == homeaway) + count++; + } + if (count * 2 >= MAXPLAYER - configvals->ntesters) + return -1; /* our team is full */ + } +#endif + for (i = 0; i < MAXPLAYER - configvals->ntesters; i++) + { + if (players[i].p_status == PFREE) + { + if (allocate) + { + players[i].p_status = POUTFIT; + players[i].p_team = NOBODY; + } + return i; + } + } + } + return -1; +} +#if 0 +static int +ImAllowed(slotnum, homeaway) + int slotnum; + enum HomeAway homeaway; +{ +#ifdef LEAGUE_SUPPORT + int half; + if (!status2->league) + return 1; + + half = (MAXPLAYER - configvals->ntesters) / 2; + return (homeaway == AWAY) ? (slotnum < half) : + (slotnum >= half); +#else + return 1; +#endif +} +#endif +/* + * The following code for grabslot() is really bizarre, and needs an + * explaination. + * + * Basically, the queue works like this: Each process that needs to wait takes + * a number, and when that number comes up, the process enters the game. + * status->count is the next number to take for a new process, and + * status->wait is the current process being served. + * + * However, this is not enough to determine exactly how many people are waiting, + * because people may drop out. So, 3 more variables are added, + * status->request posts a request of some sort to all of the other + * processes, and status->number is the process posting the request. Also, + * status->answer is available for any kind of response needed from the other + * processes. (Needless to say, only one process can make a request at any + * one time). + * + * Every process will wait for a second (sleep(1)), and then check the queue + * status, do what is appropriate, and repeat. + * + * Above and beyond this, processes may die, and not report it (for whatever + * reason, and every process waiting on the queue watches the behavior of + * every other supposed process to make sure it is still alive). + * + * When a space opens up, and the person who holds the number currently being + * served does not respond, then the processes argue over who deserves to get + * in next. The first process to decide that no one is going to take the + * free slot says that his number is the next on to be served. He waits for + * anyone to disagree with him. Any other processes which notice that their + * number is lower than the number being served claim that their number is + * the next one to be served. They also wait for anyone to disagree with + * them. Eventually, everyone is done waiting, and the process with the + * lowest count will be served. + * + * Variables: status->wait: Number being served. status->count: Next + * number to take. + * + * status->request: Process request. (status->number) (status->answer) + * REQFREE: No requests pending. REQWHO: How many people are + * before me? In this case, every process in from of this process (whose + * position is recorded in status->number) increments status->answer. + * REQDEAD: I am leaving the queue (Either to quit, or enter game). Any + * process whose position is higher than this process will note that they are + * closer to the top of the queue. + * + * (Local) waitWin: The window. qwin: The quit half of waitWin. + * countWin: The count half of waitWin. count: My number (Position + * in queue). pseudocount: Number of people in front of me (-1 means I don't + * know). myRequest: This keeps track of requests I've made. If it is non + * zero, then this is the number of times I will leave it there before I get + * my answer (if there is one), and reset status->request. idie: This + * is set to one if I need to leave the queue. When I get a chance, I will + * submit my request, and leave. wearein: This is the slot we grabbed + * to enter the game. If it is -1, then we haven't got a slot yet. If we + * can grab a slot, then wearein is set to the slot #, and idie is set to 1. + * + * Because we need to monitor other processes, the following variables also + * exist: + * + * oldcount: The number that was being served last time I looked. waits: + * Number of times I've seen oldcount as the number being served. If a + * position opens in the game, and no one takes it for a while, we assume + * that someone died. lastRequest: The last request I have seen. + * lastNumber: The process making this request. reqCount: Number of + * times I've seen this request. If I see this request 9 times, I assume it + * is obsolete, and I reset it. + */ + +int +grabslot(overload, homeaway) + int overload; /* Indicates a request for a tester's slot. */ + enum HomeAway homeaway; +{ + int count; /* My number */ + int oldcount; /* Number that was being served last check */ + int i; + int waits; /* # times I have waited for someone else to + * act */ + int oldwait; /* Number being served last check */ + int pseudocount = -1; /* Count on queue for sake of person waiting */ + int myRequest = 0; /* To keep track of any request I'm making */ + int lastRequest = 0; /* Last request I've seen */ + int lastNumber = 0; /* Last person making request */ + int reqCount = 0; /* Number of times I've seen this */ + int idie = 0; /* Do I want to die? */ + int wearein = -1; /* Slot we got in the game */ + int rep = 0; + + /* If other players waiting, we get in line behind them */ + if (!overload && status->wait != status->count) + { + count = status->count++; + } + else + { + /* Get in game if posible */ +#if 1 + i = allocate_slot(homeaway, overload, 1); + if (i >= 0) + return i; +#else + if (overload) + for (i = MAXPLAYER - 1; i >= 0; i--) + { + if (players[i].p_status == PFREE) + { /* We have a free slot */ + players[i].p_status = POUTFIT; /* possible race code */ + players[i].p_team = NOBODY; + return (i); + } + } + else + for (i = 0; i < MAXPLAYER - configvals->ntesters; i++) + { + if (ImAllowed(i, homeaway) + && players[i].p_status == PFREE) + { /* We have a free slot */ + players[i].p_status = POUTFIT; /* possible race code */ + players[i].p_team = NOBODY; + return (i); + } + } +#endif + /* Game full. We will wait. */ + count = status->count++; + } + waits = 0; + oldwait = -1; + oldcount = status->wait; + + /* For count = 0,1,2 I know that it is right */ + if (count - status->wait < 1) + { + pseudocount = count - status->wait; + } + for (;;) + { + /* Send packets occasionally to see if he is accepting... */ + if (rep++ % 10 == 0) + { + mapWaitCount(pseudocount); + } + if (isClientDead()) + { + if (count == status->count - 1) + { + status->count--; + exit(0); + } + /* If we are at top, decrease it */ + if (count == status->wait) + { + status->wait++; + } + idie = 1; + /* break; warning, function has return e and return */ + exit(0); + } + if (status->wait != oldcount) + { + mapWaitCount(pseudocount); + oldcount = status->wait; + } + /* To mimize process overhead and aid synchronization */ + sleep(1); + /* Message from daemon that it died */ + if (status->count == 0) + exit(0); + /* I have a completed request? */ + if (myRequest != 0 && --myRequest == 0) + { + if (idie && status->request == REQDEAD) + { + status->request = REQFREE; + /* Out of queue, into game */ + if (wearein != -1) + { + return (wearein); + } + exit(0); + } + pseudocount = status->answer; + status->request = REQFREE; + if (pseudocount > 18) + idie = 1; + mapWaitCount(pseudocount); + } + /* Tell the world I am going bye bye */ + if (idie && status->request == REQFREE) + { + status->request = REQDEAD; + status->number = count; + myRequest = 4; + } + /* Should I request a count for # of people waiting? */ + if (pseudocount == -1 && status->request == REQFREE) + { + status->request = REQWHO; + status->number = count; + status->answer = 0; + myRequest = 4; + /* I give people 4 seconds to respond */ + } + /* Is someone else making a request? */ + if (status->request != REQFREE && myRequest == 0) + { + if (status->request == lastRequest && + status->number == lastNumber) + { + reqCount++; + /* 9 occurances of the same request implies that the process */ + /* died. I will reset request. */ + if (reqCount > 8) + { + status->request = REQFREE; + } + } + else + { + lastRequest = status->request; + lastNumber = status->number; + reqCount = 1; + if (lastRequest == REQWHO) + { + if (count < lastNumber) + { + status->answer++; + } + } + else if (lastRequest == REQDEAD) + { + if (count > lastNumber && pseudocount != -1) + { + pseudocount--; + mapWaitCount(pseudocount); + } + } + } + } + /* If someone raised wait too high, I claim that I * am next in line */ + if (status->wait > count && !idie) + { + status->wait = count; + /* Give people a chance to correct me */ + sleep(2); + } +#if 1 + if (idie) + continue; + if (count == status->wait) + { + i = allocate_slot(homeaway, overload, 1); + if (i < 0) + continue; + status->wait++; + wearein = i; + idie = 1; + } + else + { + i = allocate_slot(homeaway, overload, 0); + if (i < 0) + continue; + if (oldwait == status->wait) + { + waits++; + } + else + { + oldwait = status->wait; + waits = 1; + } + /* If this is our fifth wait (5 sec), then something is */ + /* wrong. We assume someone died, and fix this problem */ + if (waits == 5 && !idie) + { + /* I want to be next in line, so I say so. */ + status->wait = count; + /* And I allow someone to correct me if I'm wrong */ + sleep(2); + waits = 0; + } + + } +#else + for (i = 0; i < MAXPLAYER - configvals->ntesters; i++) + { + /* If we want to die anyway, we have no right looking for */ + /* a free slot */ + if (idie) + break; + if (ImAllowed(i, homeaway) && players[i].p_status == PFREE) + { + /* If I am next in line... */ + if (count == status->wait) + { + players[i].p_status = POUTFIT; + players[i].p_team = NOBODY; + /* Increase count for next player */ + status->wait++; + /* I should check idie, but maybe he wants in, eh? */ + wearein = i; + idie = 1; + break; + } + else + { + if (oldwait == status->wait) + { + waits++; + } + else + { + oldwait = status->wait; + waits = 1; + } + /* If this is our fifth wait (5 sec), then something is */ + /* wrong. We assume someone died, and fix this problem */ + if (waits == 5 && !idie) + { + /* I want to be next in line, so I say so. */ + status->wait = count; + /* And I allow someone to correct me if I'm wrong */ + sleep(2); + waits = 0; + } + break; + } + } + } +#endif + /* this location is skipped if we didn't find a slot */ + } +} + +void +mapWaitCount(count) + unsigned int count; +{ + if (count == -1) + return; + + sendQueuePacket((short) count); + blk_flag = 1; + updateMOTD(); + blk_flag = 0; + + undeferDeferred(); /* send the MOTD through the TCP buffers */ + flushSockBuf(); +} diff -r cafa94d86546 -r aa38447a4b21 src/gameconf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gameconf.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,343 @@ +/*-------------------------------------------------------------------------- +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 "gppackets.h" +#include "shmem.h" +#include "data.h" + +/* some game params packet stuff */ +/* status experimental */ + +void +updateGPrank() +{ + int i; + struct gp_rank_spacket pkt; + + pkt.type = SP_GPARAM; + pkt.subtype = 5; + + for (i = 0; i < NUMRANKS; i++) + { + pkt.rankn = i; + pkt.genocides = htonl(ranks[i].genocides); +#ifndef BAD_SVR4_HACKS + pkt.milliDI = htonl(1000 * ranks[i].di); + pkt.millibattle = htonl(1000 * ranks[i].battle); + pkt.millistrat = htonl(1000 * ranks[i].strategy); + pkt.millispec = htonl(1000 * ranks[i].specship); +#else /* Unixware/IRIX requires explicit casts */ + /* this next define will make the next more readable */ +#define BAD_SVR4_HACKS_CAST(a,b) (unsigned long)( (long double)a * (long double)b ) + pkt.milliDI = htonl(BAD_SVR4_HACKS_CAST(1000, ranks[i].di)); + pkt.millibattle = htonl(BAD_SVR4_HACKS_CAST(1000, ranks[i].battle)); + pkt.millistrat = htonl(BAD_SVR4_HACKS_CAST(1000, ranks[i].strategy)); + pkt.millispec = htonl(BAD_SVR4_HACKS_CAST(1000, ranks[i].specship)); +#endif /* BAD_SVR4_HACKS */ + strcpy(pkt.name, ranks[i].name); + + sendClientPacket((struct player_spacket *) & pkt); + } +} + +void +updateGProyal() +{ + int i; + struct gp_royal_spacket pkt; + + pkt.type = SP_GPARAM; + pkt.subtype = 6; + + for (i = 0; i < NUMROYALRANKS; i++) + { + pkt.rankn = i; + strcpy(pkt.name, royal[i].name); + sendClientPacket((struct player_spacket *) & pkt); + } +} + +void +updateGPteams() +{ + struct gp_team_spacket pkt; + int i; + + for (i = 0; i < NUMTEAM; i++) + { + pkt.type = SP_GPARAM; + pkt.subtype = 1; + + pkt.index = i; + pkt.letter = teams[idx_to_mask(i)].letter; + strncpy(pkt.shortname, teams[idx_to_mask(i)].shortname, + sizeof(pkt.shortname)); + strncpy(pkt.teamname, teams[idx_to_mask(i)].name, sizeof(pkt.teamname)); + + sendClientPacket((struct player_spacket *) & pkt); + } +} + +static void +send_one_teamlogo(teamidx, data, width, height) + int teamidx; + unsigned char *data; + int width, height; +{ + struct gp_teamlogo_spacket pkt; + int pwidth; + + if (width > 99 || height > 99) + { + printf("logo too big: %dx%d\n", width, height); + return; + } + + pkt.type = SP_GPARAM; + pkt.subtype = 2; + + pkt.logowidth = width; + pkt.logoheight = height; + pkt.teamindex = teamidx; + + pwidth = (width - 1) / 8 + 1; + pkt.thisheight = sizeof(pkt.data) / pwidth; + + for (pkt.y = 0; pkt.y < height; pkt.y += pkt.thisheight) + { + + if (pkt.y + pkt.thisheight > height) + pkt.thisheight = height - pkt.y; + + memcpy(pkt.data, data + pkt.y * pwidth, pkt.thisheight * pwidth); + sendClientPacket((struct player_spacket *) & pkt); + } +} + +void +updateGPteamlogos() +{ + char buf[40]; + char *data; + int width, height; + int i; + + for (i = 0; i < NUMTEAM; i++) + { + sprintf(buf, "artwork/%d/logo", i); +#ifdef LEAGUE_SUPPORT + if (status2->league == 1) + { + if (i == 0) + sprintf(buf, "artwork/%s/logo", status2->home.name); + else if (i == 1) + sprintf(buf, "artwork/%s/logo", status2->away.name); + } + else if (status2->league) + { + if (i == status2->home.index) + sprintf(buf, "artwork/%s/logo", status2->home.name); + else if (i == status2->away.index) + sprintf(buf, "artwork/%s/logo", status2->away.name); + } +#endif + { + FILE *fp; + fp = fopen(build_path(buf), "r"); + if (!fp) + continue; /* no image to transmit */ + ParseXbmFile(fp, &width, &height, &data); + fclose(fp); + } + if (!data) + { + continue; + } + send_one_teamlogo(i, data, width, height); + free(data); + } +} + +/* #include "borgcube.bm" */ + +void +updateGPshipshapes() +{ +#if 0 + { + struct gp_shipshape_spacket pkt; + + pkt.type = SP_GPARAM; + pkt.subtype = 3; + + pkt.shipno = ATT; + pkt.race = -1; + pkt.nviews = 1; + pkt.width = borgcube_width; + pkt.height = borgcube_height; + + sendClientPacket((struct player_spacket *) & pkt); + } + + { + struct gp_shipbitmap_spacket pkt; + + pkt.type = SP_GPARAM; + pkt.subtype = 4; + + pkt.shipno = ATT; + pkt.race = -1; + pkt.thisview = 0; + + memcpy(pkt.bitmapdata, borgcube_bits, sizeof(borgcube_bits)); + + sendClientPacket((struct player_spacket *) & pkt); + } +#endif +} + +void +updateGPplanetbitmaps() +{ + struct gp_teamplanet_spacket pkt; + char buf[40]; + char *data; + int width, height; + int i; + + for (i = 0; i < NUMTEAM; i++) + { + + pkt.type = SP_GPARAM; + pkt.subtype = 7; + + pkt.teamn = i; + + sprintf(buf, "artwork/%d/tplanet", i); +#ifdef LEAGUE_SUPPORT + if (status2->league == 1) + { + if (i == 0) + sprintf(buf, "artwork/%s/tplanet", status2->home.name); + else if (i == 1) + sprintf(buf, "artwork/%s/tplanet", status2->away.name); + } + else if (status2->league) + { + if (i == status2->home.index) + sprintf(buf, "artwork/%s/tplanet", status2->home.name); + else if (i == status2->away.index) + sprintf(buf, "artwork/%s/tplanet", status2->away.name); + } +#endif + { + FILE *fp; + fp = fopen(build_path(buf), "r"); + if (!fp) + continue; /* no image to transmit */ + ParseXbmFile(fp, &width, &height, &data); + fclose(fp); + } + if (!data) + { + continue; + } + memcpy(pkt.tactical, data, 120); + memcpy(pkt.tacticalM, data, 120); + free(data); + + sprintf(buf, "artwork/%d/gplanet", i); +#ifdef LEAGUE_SUPPORT + if (status2->league == 1) + { + if (i == 0) + sprintf(buf, "artwork/%s/gplanet", status2->home.name); + else if (i == 1) + sprintf(buf, "artwork/%s/gplanet", status2->away.name); + } + else if (status2->league) + { + if (i == status2->home.index) + sprintf(buf, "artwork/%s/gplanet", status2->home.name); + else if (i == status2->away.index) + sprintf(buf, "artwork/%s/gplanet", status2->away.name); + } +#endif + { + FILE *fp; + fp = fopen(build_path(buf), "r"); + if (!fp) + continue; /* no image to transmit */ + ParseXbmFile(fp, &width, &height, &data); + fclose(fp); + } + if (!data) + { + continue; + } + memcpy(pkt.galactic, data, 32); + memcpy(pkt.galacticM, data, 32); + free(data); + + sendClientPacket((struct player_spacket *) & pkt); + } + +} + +void +updateGameparams() +{ + struct gp_sizes_spacket pkt; + + memset((char *) &pkt, 0, sizeof(pkt)); + + pkt.type = SP_GPARAM; + pkt.subtype = 0; + + pkt.nplayers = MAXPLAYER; + pkt.nteams = 4; + pkt.nshiptypes = NUM_TYPES; + pkt.nranks = NUMRANKS; + pkt.nroyal = NUMROYALRANKS; + pkt.nphasers = 1; + pkt.ntorps = MAXTORP; + pkt.nplasmas = MAXPLASMA; + pkt.nthingies = NPTHINGIES; + pkt.gthingies = NGTHINGIES; + pkt.gwidth = GWIDTH; + pkt.flags = 0; + pkt.nplanets = configvals->numplanets; + sendClientPacket((struct player_spacket *) & pkt); + + updateGPteams(); + if (me == 0 || !(me->p_stats.st_flags & ST_NOBITMAPS)) + { + updateGPteamlogos(); + updateGPshipshapes(); + updateGPplanetbitmaps(); + } + updateGPrank(); + updateGProyal(); +} + +/* end game params stuff */ diff -r cafa94d86546 -r aa38447a4b21 src/getentry.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/getentry.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,421 @@ +/*-------------------------------------------------------------------------- +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 "packets.h" +#include "shmem.h" + +extern int overload; /* 7/31/91 TC let overloaded join any team */ + +extern int updateShips(); +extern int sendMaskPacket(); +int tournamentMask(); +extern int briefUpdateClient(); +extern int flushSockBuf(); +extern int socketPause(); +extern int readFromClient(); +extern int isClientDead(); +extern int exitGame(); +#ifndef IRIX +extern int printf(); +#endif +extern int closeUdpConn(); +extern unsigned int sleep(); +extern int connectToClient(); +extern int updateSelf(); +extern int sendPickokPacket(); +extern int allowed_ship(); +extern int time_access(); +int deadTeam(); +int realNumShips(); + +#if 1 + +void +detourneyqueue() +{ + me->p_status = POUTFIT; + me->p_whydead = KPROVIDENCE; +} + +#endif + + +void +getEntry(team, stype) + int *team; + int *stype; +{ + + + int switching = -1; /* confirm switches 7/27/91 TC */ + inputMask = CP_OUTFIT; + for (;;) + { + /* updateShips so he knows how many players on each team */ + if (blk_flag) + updateShips(); + sendMaskPacket(tournamentMask(me->p_team)); + if (blk_flag) + briefUpdateClient(); + flushSockBuf(); + /* Have we been busted? */ + if (me->p_status == PFREE) + { + me->p_status = PDEAD; + me->p_explode = 600; + } + socketPause(); + readFromClient(); + if (isClientDead()) + { + int i; + + if (noressurect) + exitGame(); + printf("Ack! The client went away!\n"); + printf("I will attempt to resurrect him!\n"); + + /* UDP fail-safe */ + commMode = COMM_TCP; + if (udpSock >= 0) + closeUdpConn(); + + /* For next two minutes, we try to restore connection */ + shutdown(sock, 2); + sock = -1; + for (i = 0;; i++) + { + switch (me->p_status) + { + case PFREE: + me->p_status = PDEAD; + me->p_explode = 600; + break; + case PALIVE: + case POBSERVE: + me->p_ghostbuster = 0; + break; + case PDEAD: + me->p_explode = 600; + break; + default: + me->p_explode = 600; + me->p_ghostbuster = 0; + break; + } + sleep(5); + if (connectToClient(host, nextSocket)) + break; + if (i == 23) + { + printf("Oh well, maybe I'm getting rusty!\n"); + switch (me->p_status) + { + case PFREE: + break; + case PALIVE: + case POBSERVE: + me->p_ghostbuster = 100000; + break; + case PDEAD: + me->p_explode = 0; + break; + default: + me->p_explode = 0; + me->p_ghostbuster = 100000; + break; + } + exitGame(); + } + } + printf("A miracle! He's alive!\n"); + teamPick = -1; + updateSelf(); + updateShips(); + flushSockBuf(); + } + if (teamPick != -1) + { + if (teamPick < 0 || teamPick > 3) + { + warning("Get real!"); + sendPickokPacket(0); + teamPick = -1; + continue; + } +#if 1 + if (!(tournamentMask(me->p_team) & (1 << teamPick))) + { + warning("I cannot allow that. Pick another team"); + sendPickokPacket(0); + teamPick = -1; + continue; + } +#endif + + if (((1 << teamPick) != me->p_team) && + (me->p_team != ALLTEAM)) /* switching teams 7/27/91 TC */ + if ((switching != teamPick) + && (me->p_whydead != KGENOCIDE) +#ifdef LEAGUE_SUPPORT + && !status2->league +#endif + ) + { + switching = teamPick; + warning("Please confirm change of teams. Select the new team again."); + sendPickokPacket(0); + teamPick = -1; + continue; + } + /* His team choice is ok. */ + if (shipPick < 0 || shipPick >= NUM_TYPES) + { + warning("That is an illegal ship type. Try again."); + sendPickokPacket(0); + teamPick = -1; + continue; + } + if (!allowed_ship(1 << teamPick, mystats->st_rank, mystats->st_royal, shipPick)) + { + sendPickokPacket(0); + teamPick = -1; + continue; + } + if (shipvals[shipPick].s_nflags & SFNMASSPRODUCED) + { + warning("o)utpost, u)tility, or s)tandard?"); + sendPickokPacket(0); + tmpPick = shipPick; + continue; + } + break; + } +#if 1 + if (me->p_status == PTQUEUE) + { + if (status->tourn) + detourneyqueue(); + /* You don't time out on the tourney queue */ + me->p_ghostbuster = 0; + } +#endif + } + *team = teamPick; + if ((shipvals[tmpPick].s_nflags & SFNMASSPRODUCED) && + ((shipvals[shipPick].s_numports) || (shipPick == SCOUT))) + { + + *stype = tmpPick; + tmpPick = CRUISER; + } + else + { + *stype = shipPick; + tmpPick = CRUISER; + } + sendPickokPacket(1); + flushSockBuf(); +} + + + + +/*------------------------------TOURNAMENTMASK----------------------------*/ +/* + * This function takes the players current team and returns a mask of the + * teams that the player can join. + */ + +int +leaguemask(ishome, idx) + int ishome; /* team index */ + int idx; +{ +#ifdef LEAGUE_SUPPORT + if (status2->league == 1) + return idx_to_mask(ishome); + else +#endif + return idx_to_mask(idx); +} + +int +tournamentMask(team) + int team; /* players current team */ +{ + int i; /* looping var */ + int team1, team2; /* for getting two possible teams */ + int num1, num2; /* to hold num players on teams */ + + if (!blk_flag) /* not a paradise client */ + return (0); + if (status->gameup == 0) /* if game over, can join no team */ + return (0); + if (overload) /* if tester slot then can join */ + return (ALLTEAM); /* any team */ + if (mustexit) /* should we force player out */ + return (0); + if (!time_access()) /* if server closed then can join */ + return (0); /* no team */ + +#ifdef LEAGUE_SUPPORT + /* league stuff */ + if (status2->league) + { + if (me->p_homeaway == AWAY) + return leaguemask(1, status2->away.index); + else if (me->p_homeaway == HOME) + return leaguemask(0, status2->home.index); + else + { + warning("You have connected to a league server but aren't on a side."); + me->p_homeaway = (lrand48() & 1) + 1; /* dangerous int->enum cast */ + return 0; + } + /* NOTREACHED */ + } +#endif + if (me->p_homeaway != NEITHER) + { + warning("You have connected to a non-league server with a league ntserv."); + me->p_homeaway = NEITHER; + } + + if (!status->tourn) + { + return status2->nontteamlock; + } + + if (team != ALLTEAM && deadTeam(team)) /* if former team dead */ + team = ALLTEAM; /* then check all others */ + for (i = 0; i < NUMTEAM; i++) + { /* go through all teams and eliminate */ + if ((team & (1 << i)) && (deadTeam(1 << i))) /* from team var all + * teams */ + team &= ~(1 << i); /* that are dead */ + } + team1 = 0; /* no team in team 1 */ + num1 = 0; /* 0 players on team 1 */ + team2 = 0; /* no team in team 2 */ + num2 = 0; /* 0 players on team 2 */ + for (i = 0; i < NUMTEAM; i++) + { /* go through all teams */ + if (deadTeam(1 << i)) /* if team is dead then */ + continue; /* disregard it */ + if (realNumShips(1 << i) >= configvals->tournplayers) + { /* enough players */ + if (!team1) /* if no team in team1 yet */ + team1 = (1 << i); /* then this will be team 1 */ + else + { /* otherwise its team2 */ + team2 = (1 << i); + num1 = realNumShips(team1); /* get num players on two teams */ + num2 = realNumShips(team2); + if (num1 == num2) + { /* if teams same size then */ + if (team & (team1 | team2)) /* if player on one team */ + return (team & (team1 | team2)); /* let him join same team */ + return (team1 | team2); /* otherwise, he can join either */ + } + else if ((num1 > num2) && (team != team1)) + return (team2); /* if slight imabalance */ + else if ((num1 < num2) && (team != team2)) + return (team1); /* if slight imbalance */ + else + { + if (ABS(num1 - num2) < 2 || (((num1 > num2) && (team == team2)) || + (num2 > num1 && team == team1))) + return (team); + else + return (team1 | team2); + } + } + } + } /* end of for loop */ + return (team); /* just in case */ +} + + + + +/*--------------------------------REALNUMSHIPS-----------------------------*/ +/* + * Count the real number of ships on a team. This function returns a count + * of all the ships on a team that are not PFREE. + */ + +int +realNumShips(owner) + int owner; /* the team to check for */ +{ + int i; /* looping var */ + int num; /* to hold ship count */ + struct player *p; /* to point to players */ + + num = 0; /* initialize count */ + for (i = 0, p = players; i < MAXPLAYER; i++, p++) + { + if ((p->p_status != PFREE) && + !(p->p_flags & (PFSNAKE | PFBIRD)) && + (p->p_team == owner)) + { + num++; /* if ship not free and on our team */ + } + } + return (num); /* retun number of ships */ +} + + + + +/*----------------------------------DEADTEAM-------------------------------*/ +/* + * This function counts the number of planets that a team owns. It returns a + * 1 if the team has no planets, and a 0 if they have at least one planet. + */ + +int +deadTeam(owner) + int owner; /* team to check for */ +{ + int i; /* looping var */ + struct planet *p; /* to point to a planets */ + + for (i = 0, p = planets; i < NUMPLANETS; i++, p++) + { + if (p->pl_owner & owner) /* if planet owned by team then */ + return (0); /* found one planet owned by team */ + } + return (1); /* no planets found, team is dead */ +} + +/*-------------------------------------------------------------------------*/ + + + + + +/*---------END OF FILE--------*/ diff -r cafa94d86546 -r aa38447a4b21 src/getname.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/getname.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,287 @@ +/*-------------------------------------------------------------------------- +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 +#ifndef ULTRIX +#include +#endif +#include +#include +#include +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "packets.h" +#include "path.h" +#include "shmem.h" + +#define crypt(a, b) (a) + +void handleLogin(); +extern int exitGame(); +extern int isClientDead(); +extern int socketPause(); +extern int readFromClient(); +int lockout(); +extern int sendClientLogin(); +extern int flushSockBuf(); +#ifdef BAD_SVR4_HACKS +int updateMOTD(); +#else +extern int updateMOTD(); +#endif +#ifndef IRIX +extern int printf(); +#endif +extern int read(); +extern int close(); +extern off_t lseek(); +extern int write(); +extern time_t time(); + +/* replace non-printable characters in string with spaces */ +static void +remove_ctl(str) + char *str; +{ + while (*str) + { + if (!isgraph(*str)) /* not a printable character */ + *str = ' '; /* replace it with space */ + str++; + } +} + +void +getname() +/* Let person identify themselves from w */ +{ + *(me->p_name) = 0; + while (*(me->p_name) == 0) + { + handleLogin(); + } +} + +void +handleLogin() +{ + static struct statentry player; + static int position = -1; + int plfd; + int entries; + struct stat buf; + char *paths; + + paths = build_path(PLAYERFILE); + *namePick = '\0'; + inputMask = CP_LOGIN; + while (*namePick == '\0') + { + /* Been ghostbusted? */ + if (me->p_status == PFREE) + exitGame(); + if (isClientDead()) + exitGame(); + socketPause(); + readFromClient(); + } +#ifdef REMOVE_CTL /* untested */ + /* Change those annoying control characters to spaces */ + remove_ctl(namePick); +#endif + if ((strcmp(namePick, "Guest") == 0 || strcmp(namePick, "guest") == 0) && + !lockout()) + { + hourratio = 5; + memset(&player.stats, 0, sizeof(struct stats)); + player.stats.st_tticks = 1; + player.stats.st_flags = ST_INITIAL; + /* + * If this is a query on Guest, the client is screwed, but I'll send him + * some crud anyway. + */ + if (passPick[15] != 0) + { + sendClientLogin(&player.stats); + flushSockBuf(); + return; + } + sendClientLogin(&player.stats); + + updateMOTD(); /* added here 1/19/93 KAO */ + + flushSockBuf(); + strcpy(me->p_name, namePick); + me->p_pos = -1; + memcpy(&(me->p_stats), &player.stats, sizeof(struct stats)); + return; + } + hourratio = 1; + /* We look for the guy in the stat file */ + if (strcmp(player.name, namePick) != 0) + { + for (;;) + { /* so I can use break; */ + plfd = open(paths, O_RDONLY, 0644); + if (plfd < 0) + { + printf("I cannot open the player file!\n"); + strcpy(player.name, namePick); + position = -1; + printf("Error number: %d\n", errno); + break; + } + position = 0; + while (read(plfd, (char *) &player, sizeof(struct statentry)) == + sizeof(struct statentry)) + { +#ifdef REMOVE_CTL /* untested */ + /* + * this is a temporary thing to remove control chars from existing + * entries in the player db + */ + remove_ctl(player.name); +#endif + if (strcmp(namePick, player.name) == 0) + { + close(plfd); + break; + } + position++; + } + if (strcmp(namePick, player.name) == 0) + break; + close(plfd); + position = -1; + strcpy(player.name, namePick); + break; + } + } + /* Was this just a query? */ + if (passPick[15] != 0) + { + if (position == -1) + { + sendClientLogin(NULL); + } + else + { + sendClientLogin(&player.stats); + } + flushSockBuf(); + return; + } + /* A new guy? */ + if ((position == -1) && !lockout()) + { + strcpy(player.name, namePick); + strcpy(player.password, crypt(passPick, namePick)); + memset(&player.stats, 0, sizeof(struct stats)); + player.stats.st_tticks = 1; + player.stats.st_flags = ST_INITIAL; + player.stats.st_royal = 0; + plfd = open(paths, O_RDWR | O_CREAT, 0644); + if (plfd < 0) + { + sendClientLogin(NULL); + } + 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)); + strcpy(me->p_name, namePick); + sendClientLogin(&player.stats); + updateMOTD(); /* added here 1/19/93 KAO */ + } + flushSockBuf(); + return; + } + /* An actual login attempt */ + if ((strcmp(player.password, crypt(passPick, player.password)) != 0) || + lockout()) + { + sendClientLogin(NULL); + } + else + { + strcpy(me->p_name, namePick); + me->p_pos = position; + memcpy(&(me->p_stats), &player.stats, sizeof(struct stats)); + + sendClientLogin(&player.stats); + + updateMOTD(); /* st_flags&ST_NOBITMAPS */ + } + flushSockBuf(); + +#if 1 + /* Try to make the first person in the player database an Emperor */ + if (position == 0) + me->p_stats.st_royal = NUMROYALRANKS - 1; +#endif + + return; +} + +void +savestats() +{ + int fd; + char *paths; + + if (me->p_pos < 0) + return; + + paths = build_path(PLAYERFILE); + + fd = open(paths, 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); + } +} + +/* return true if we want a lockout */ +int +lockout() +{ + return ( + /* + * (strncmp (login, "bozo", 4) == 0) || + */ + 0 + ); +} diff -r cafa94d86546 -r aa38447a4b21 src/getship.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/getship.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,114 @@ +/*-------------------------------------------------------------------------- +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" + + + + +/*-------------------------------INTERNAL FUNCTONS------------------------*/ + +/*----------------------------------GETSHIP--------------------------------*/ +/* + * This function gets the particular ship type the player wants. It takes + * the ship values from the shipvals array. + */ + +void +getship(shipp, s_type) + struct ship *shipp; /* the ship structure to load */ + int s_type; /* the type of ship to get */ +{ + memcpy((char *) shipp, (char *) &(shipvals[s_type]), sizeof(struct ship)); +} + + + +/*------------------------------------------------------------------------*/ + + + + + +void +get_ship_for_player(me, s_type) + struct player *me; + int s_type; +{ + getship(&me->p_ship, s_type); + + me->p_shield = me->p_ship.s_maxshield; /* shields are at max */ + me->p_damage = 0; /* no damage to ship */ + me->p_subdamage = 0; /* no fractional damage either */ + me->p_subshield = 0; /* no fractional damage to shield */ + + me->p_fuel = me->p_ship.s_maxfuel; /* fuel is at max */ + me->p_etemp = 0; /* engines are ice cold */ + me->p_etime = 0; /* not counting down for E-temp */ + me->p_warptime = 0; /* we are not preparing for warp */ + me->p_wtemp = 0; /* weapons cool too */ + me->p_wtime = 0; /* not counting down for W-temp */ + + if (allows_docking(me->p_ship)) + { /* if ship can be docked to */ + int i; + me->p_docked = 0; /* then set all ports as */ + for (i = 0; i < MAXPORTS; i++) /* vacant */ + me->p_port[i] = VACANT; + } + if (weaponsallowed[WP_MISSILE] && + (me->p_ship.s_missilestored > 0) && + (me->p_kills >= configvals->mskills)) + { + me->p_ship.s_nflags |= SFNHASMISSILE; /* arm ship with missile + * launcher */ + } + if (!(me->p_ship.s_nflags & SFNHASMISSILE)) + { + me->p_ship.s_missilestored = 0; /* no missiles if no launcher */ + } + if (weaponsallowed[WP_PLASMA] && + (me->p_ship.s_plasma.cost > 0) && + (me->p_kills >= configvals->plkills)) + { + me->p_ship.s_nflags |= SFNPLASMAARMED; /* arm ship with plasma + * launcher */ + } + me->p_specweap = 0; + + /* + * fix this now since we can't do it right in a conf.sysdef/default/pl_gen + * ordering... sigh. + */ + if (!configvals->warpdrive) + me->p_ship.s_nflags &= ~SFNCANWARP; +} + + +/*----------END OF FILE-----*/ diff -r cafa94d86546 -r aa38447a4b21 src/getship.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/getship.h Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,30 @@ +/*-------------------------------------------------------------------------- +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 initshipvals(); +int getship(); +/*------------------------------------------------------------------------*/ + + + + + +/*-------END OF FILE-------*/ diff -r cafa94d86546 -r aa38447a4b21 src/getstats.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/getstats.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,104 @@ +/*-------------------------------------------------------------------------- +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 + +struct stats +{ + int st_genocides; /* number of genocides participated in */ + float st_tmaxkills; /* max kills ever */ + float st_di; /* total destruction inflicted for all time */ + int st_tkills; /* Kills in tournament play */ + int st_tlosses; /* Losses in tournament play */ + int st_tarmsbomb; /* Tournament armies bombed */ + int st_tresbomb; /* resources bombed off */ + int st_tdooshes; /* armies killed while being carried */ + int st_tplanets; /* Tournament planets conquered */ + int st_tticks; /* Tournament ticks */ + /* SB/WB/JS stats are entirely separate */ + int st_sbkills; /* Kills as starbase */ + int st_sblosses; /* Losses as starbase */ + int st_sbticks; /* Time as starbase */ + float st_sbmaxkills; /* Max kills as starbase */ + int st_wbkills; /* Kills as warbase */ + int st_wblosses; /* Losses as warbase */ + int st_wbticks; /* Time as warbase */ + float st_wbmaxkills; /* Max kills as warbase */ + int st_jsplanets; /* planets assisted with in JS */ + int st_jsticks; /* ticks played as a JS */ + long st_lastlogin; /* Last time this player was played */ + int st_flags; /* Misc option flags */ + char st_keymap[96]; /* keymap for this player */ + int st_rank; /* Ranking of the player */ + int st_royal; /* royaly, specialty, rank */ +}; + +struct statentry +{ + char name[16]; /* player's name */ + char password[16]; /* player's password */ + struct stats stats; /* player's stats */ +}; + + +main(argn, argv) + int argn; + char **argv; +{ + FILE *f; + struct statentry s; + + f = fopen(argv[1], "r"); + if (f == NULL) + { + printf("Cannot open players file\n"); + exit(1); + } + while (fread(&s, sizeof(struct statentry), 1, f) == 1) + { + printf("\nPlayer: %s\n", s.name); + printf("Genocides: %d\n", s.stats.st_genocides); + printf("Maxkills: %f\n", s.stats.st_tmaxkills); + printf("DI: %f\n", s.stats.st_di); + printf("Kills: %d\n", s.stats.st_tkills); + printf("Losses: %d\n", s.stats.st_tlosses); + printf("Armies bombed: %d\n", s.stats.st_tarmsbomb); + printf("Resources bombed: %d\n", s.stats.st_tresbomb); + printf("Dooshes: %d\n", s.stats.st_tdooshes); + printf("Planets: %d\n", s.stats.st_tplanets); + printf("Time: %f\n", (float) s.stats.st_tticks / 36000.0); + printf("Rank: %d\n", s.stats.st_rank); + printf("Royalty: %d\n", s.stats.st_royal); + + printf("SB kills: %d\n", s.stats.st_sbkills); + printf("SB losses: %d\n", s.stats.st_sblosses); + printf("SB time: %f\n", (float) s.stats.st_sbticks / 36000.0); + printf("SB maxkills: %f\n", s.stats.st_sbmaxkills); + + printf("WB kills: %d\n", s.stats.st_wbkills); + printf("WB losses: %d\n", s.stats.st_wblosses); + printf("WB time: %f\n", (float) s.stats.st_wbticks / 36000.0); + printf("WB maxkills: %f\n", s.stats.st_wbmaxkills); + + printf("JS planets: %f\n", s.stats.st_jsplanets); + printf("JS time: %f\n", (float) s.stats.st_jsticks / 36000.0); + } + fclose(f); +} diff -r cafa94d86546 -r aa38447a4b21 src/gppackets.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gppackets.h Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,191 @@ +/*-------------------------------------------------------------------------- +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 gppackets_h_ +#define gppackets_h_ + +/* the definitions of {INT,CARD}{8,16,32} are in packets.h */ +#include "packets.h" + +struct gameparam_spacket +{ + INT8 type; + INT8 subtype; /* this packet is not real */ + /* generic game parameter packet */ + INT16 pad; +}; + +struct gp_sizes_spacket +{ + INT8 type; + INT8 subtype; /* =0 */ + + CARD8 nplayers; + CARD8 nteams; /* max of 8 */ + + CARD8 nshiptypes; + CARD8 nranks; /* number of ranks */ + CARD8 nroyal; /* number of royalties */ + CARD8 nphasers; + + CARD8 ntorps; + CARD8 nplasmas; + CARD8 nthingies; /* per-player */ + CARD8 gthingies; /* auxiliary thingies */ + + CARD32 gwidth; /* galaxy width */ + /* 16 bytes */ + CARD32 flags; /* some game parameter flags */ +#define GP_WRAPVERT (1<<0) +#define GP_WRAPHORIZ (1<<1) +#define GP_WRAPALL (GP_WRAPVERT|GP_WRAPHORIZ) + + /* + * The following bytes are room for growth. The size of this packet is + * unimportant because it only gets sent once. hopefully we've got plenty + * of room. + */ + CARD16 nplanets; + INT16 ext1; + + INT32 ext2; + INT32 ext3; + /* 32 bytes */ + + INT32 ext4; + INT32 ext5; + INT32 ext6; + INT32 ext7; + + INT32 ext8; + INT32 ext9; + INT32 ext10; + INT32 ext11; /* 16 ints, 64 bytes */ +}; + +struct gp_team_spacket +{ + INT8 type; + INT8 subtype; /* =1 */ + + CARD8 index; /* team index */ + CARD8 letter; /* team letter 'F' */ + + CARD8 shortname[3]; /* non-null-terminated 3-letter abbrev 'FED' */ + CARD8 pad; + /* 8 bytes */ + CARD8 teamname[56]; /* padding to 64 byte packet */ +}; + +struct gp_teamlogo_spacket +{ + /* + * This packet contains several adjacent rows of a team's logo bitmap Data + * is in raw XBM format (scanline-padded to 8 bits). Maximum bitmap size is + * 99x99, which takes 1287 (99x13) bytes. + */ + INT8 type; + INT8 subtype; /* =2 */ + + INT8 logowidth; /* <= 99 */ + INT8 logoheight; /* <= 99 */ + + INT8 y; /* y coord of the start of this packets info */ + INT8 thisheight; /* the height of this packet's info */ + INT8 teamindex; /* which team's logo this is */ + + CARD8 data[768 - 7]; /* pad packet to 768 bytes. */ +}; + +struct gp_shipshape_spacket +{ + INT8 type; + INT8 subtype; /* =3 */ + + CARD8 shipno; + INT8 race; /* -1 is independent */ + CARD8 nviews; /* typically 16 */ + + CARD8 width, height; + CARD8 pad1; +}; + +struct gp_shipbitmap_spacket +{ + INT8 type; + INT8 subtype; /* =4 */ + + CARD8 shipno; + INT8 race; /* -1 is independent */ + CARD8 thisview; /* 0..nviews-1 */ + + CARD8 bitmapdata[999]; +}; + +struct gp_rank_spacket +{ + INT8 type; + INT8 subtype; /* =5 */ + + INT8 rankn; /* rank number */ + + CARD8 name[-3 + 64 - 20]; /* name of the rank */ + + INT32 genocides; + INT32 milliDI; /* DI*1000 */ + INT32 millibattle; /* battle*1000 */ + INT32 millistrat; /* strategy*1000 */ + INT32 millispec; /* special ships*1000 */ +}; + +struct gp_royal_spacket +{ + INT8 type; + INT8 subtype; /* =6 */ + + CARD8 rankn; /* rank number */ + + CARD8 name[-3 + 64]; /* name of the rank */ +}; + +struct gp_teamplanet_spacket +{ + INT8 type; + INT8 subtype; /* =7 */ + + INT8 teamn; /* 0..7 */ + CARD8 pad1; + + INT32 ext1; /* extensions? */ + + /* + * Bitmaps of the team logo and masks. The bitmap of the planet will be + * constructed with (mask ? logo : planet), applied bitwise. This + * calculation is equivalent to (logo&mask)|(planet&~mask) + */ + + /* bitmap 30x30, X bitmap format (scanline padded to 8 bits) */ + CARD8 tactical[120]; + CARD8 tacticalM[120]; + + /* bitmap 16x16, X bitmap format (scanline padded to 8 bits) */ + CARD8 galactic[32]; + CARD8 galacticM[32]; +}; + +#endif diff -r cafa94d86546 -r aa38447a4b21 src/grid.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/grid.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,98 @@ +/*-------------------------------------------------------------------------- +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 "struct.h" +#include "shmem.h" + +/* + * This function should be called any time a planet is relocated. It is in + * charge of updating the space grid. + */ +void +move_planet(pno, x, y, isold) + int pno; /* planet number */ + int x, y; + int isold; /* 0 if the planet has not yet been entered + * into the grid */ +{ + struct planet *pl = &planets[pno]; + + if (isold) + { + /* remove from previous space grid position */ + } + pl->pl_x = x; + pl->pl_y = y; + + /* enter into space grid */ +} + +void +move_player(pno, x, y, isold) + int pno; /* player number */ + int x, y; + int isold; /* 0 if the player has not yet been entered + * into the grid */ +{ + struct player *pl = &players[pno]; + + if (isold) + { + } + pl->p_x = x; + pl->p_y = y; + + /* enter into space grid */ +} + +void +move_torp(tno, x, y, isold) + int tno; /* torp number */ + int x, y; + int isold; /* 0 if the torp has not yet been entered + * into the grid */ +{ + struct torp *t = &torps[tno]; + + if (isold) + { + } + t->t_x = x; + t->t_y = y; + + /* enter into space grid */ +} + +void +move_missile(dno, x, y, isold) + int dno; /* missile number */ + int x, y; + int isold; /* 0 if the missile has not yet been entered + * into the grid */ +{ + struct missile *d = &missiles[dno]; + + if (isold) + { + } + d->ms_x = x; + d->ms_y = y; + + /* enter into space grid */ +} diff -r cafa94d86546 -r aa38447a4b21 src/grid.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/grid.h Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,32 @@ +/*-------------------------------------------------------------------------- +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 grid_h_ +#define grid_h_ + +/* specifying an x,y of -1,-1 removes the item from the space grid */ + +/* the current coordinates of the object in question are not relevant */ + +void move_planet( /* pno, x, y, isold */ ); +void move_player( /* pno, x, y, isold */ ); + +void move_torp( /* tno, x, y, isold */ ); +void move_missile( /* dno, x, y, isold */ ); + +#endif diff -r cafa94d86546 -r aa38447a4b21 src/imath.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/imath.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,226 @@ +/*-------------------------------------------------------------------------- +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 +--------------------------------------------------------------------------*/ + +/* collection of integer math routines. [BDyess] */ + +/* + * Based on (n+1)^2 = n^2 + 2n + 1 given that 1^2 = 1, then 2^2 = 1 + (2 + + * 1) = 1 + 3 = 4 3^2 = 4 + (4 + 1) = 4 + 5 = 1 + 3 + 5 = 9 4^2 = 9 + (6 + 1) + * = 9 + 7 = 1 + 3 + 5 + 7 = 16 ... In other words, a square number can be + * express as the sum of the series n^2 = 1 + 3 + ... + (2n-1) + * + * Note that NO multiplication or floating point math is needed. [BDyess] + */ +int +isqrt(n) + int n; +{ + int result = 0, sum = 1, prev = 1; + + while (sum <= n) + { + prev += 2; + sum += prev; + ++result; + } + return result; +} + +/* + * Calculates the distance directly using a lookup table. Very fast, esp. + * compared to hypot(), but less accurate. + * + * Produces results exactly as (int) hypot( (double)x, (double)y) up to + * hypot(HYPOTMIN,HYPOTMIN), and then loses accuracy in the trailing digits. + * With HYPOTMIN = 1000, error is .01% at 200000,200000. + * + * Bill Dyess + */ + +#define HYPOTMIN 1000 +int hypotlookup[] = { + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1000, 1000, 1000, 1001, 1001, 1001, 1001, 1001, + 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, 1001, + 1001, 1001, 1001, 1001, 1002, 1002, 1002, 1002, 1002, 1002, + 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1003, 1003, + 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, + 1004, 1004, 1004, 1004, 1004, 1004, 1004, 1004, 1004, 1004, + 1004, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, + 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1006, 1007, + 1007, 1007, 1007, 1007, 1007, 1007, 1007, 1008, 1008, 1008, + 1008, 1008, 1008, 1008, 1008, 1009, 1009, 1009, 1009, 1009, + 1009, 1009, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1011, + 1011, 1011, 1011, 1011, 1011, 1011, 1012, 1012, 1012, 1012, + 1012, 1012, 1013, 1013, 1013, 1013, 1013, 1013, 1014, 1014, + 1014, 1014, 1014, 1014, 1015, 1015, 1015, 1015, 1015, 1015, + 1016, 1016, 1016, 1016, 1016, 1016, 1017, 1017, 1017, 1017, + 1017, 1018, 1018, 1018, 1018, 1018, 1019, 1019, 1019, 1019, + 1019, 1020, 1020, 1020, 1020, 1020, 1020, 1021, 1021, 1021, + 1021, 1022, 1022, 1022, 1022, 1022, 1023, 1023, 1023, 1023, + 1023, 1024, 1024, 1024, 1024, 1025, 1025, 1025, 1025, 1025, + 1026, 1026, 1026, 1026, 1027, 1027, 1027, 1027, 1027, 1028, + 1028, 1028, 1028, 1029, 1029, 1029, 1029, 1030, 1030, 1030, + 1030, 1031, 1031, 1031, 1031, 1032, 1032, 1032, 1032, 1032, + 1033, 1033, 1033, 1034, 1034, 1034, 1034, 1035, 1035, 1035, + 1035, 1036, 1036, 1036, 1036, 1037, 1037, 1037, 1037, 1038, + 1038, 1038, 1039, 1039, 1039, 1039, 1040, 1040, 1040, 1040, + 1041, 1041, 1041, 1042, 1042, 1042, 1042, 1043, 1043, 1043, + 1044, 1044, 1044, 1044, 1045, 1045, 1045, 1046, 1046, 1046, + 1046, 1047, 1047, 1047, 1048, 1048, 1048, 1049, 1049, 1049, + 1049, 1050, 1050, 1050, 1051, 1051, 1051, 1052, 1052, 1052, + 1053, 1053, 1053, 1053, 1054, 1054, 1054, 1055, 1055, 1055, + 1056, 1056, 1056, 1057, 1057, 1057, 1058, 1058, 1058, 1059, + 1059, 1059, 1060, 1060, 1060, 1061, 1061, 1061, 1062, 1062, + 1062, 1063, 1063, 1063, 1064, 1064, 1064, 1065, 1065, 1065, + 1066, 1066, 1066, 1067, 1067, 1068, 1068, 1068, 1069, 1069, + 1069, 1070, 1070, 1070, 1071, 1071, 1071, 1072, 1072, 1072, + 1073, 1073, 1074, 1074, 1074, 1075, 1075, 1075, 1076, 1076, + 1077, 1077, 1077, 1078, 1078, 1078, 1079, 1079, 1080, 1080, + 1080, 1081, 1081, 1081, 1082, 1082, 1083, 1083, 1083, 1084, + 1084, 1085, 1085, 1085, 1086, 1086, 1086, 1087, 1087, 1088, + 1088, 1088, 1089, 1089, 1090, 1090, 1090, 1091, 1091, 1092, + 1092, 1092, 1093, 1093, 1094, 1094, 1094, 1095, 1095, 1096, + 1096, 1096, 1097, 1097, 1098, 1098, 1099, 1099, 1099, 1100, + 1100, 1101, 1101, 1101, 1102, 1102, 1103, 1103, 1104, 1104, + 1104, 1105, 1105, 1106, 1106, 1107, 1107, 1107, 1108, 1108, + 1109, 1109, 1110, 1110, 1110, 1111, 1111, 1112, 1112, 1113, + 1113, 1114, 1114, 1114, 1115, 1115, 1116, 1116, 1117, 1117, + 1118, 1118, 1118, 1119, 1119, 1120, 1120, 1121, 1121, 1122, + 1122, 1122, 1123, 1123, 1124, 1124, 1125, 1125, 1126, 1126, + 1127, 1127, 1128, 1128, 1128, 1129, 1129, 1130, 1130, 1131, + 1131, 1132, 1132, 1133, 1133, 1134, 1134, 1135, 1135, 1136, + 1136, 1136, 1137, 1137, 1138, 1138, 1139, 1139, 1140, 1140, + 1141, 1141, 1142, 1142, 1143, 1143, 1144, 1144, 1145, 1145, + 1146, 1146, 1147, 1147, 1148, 1148, 1149, 1149, 1150, 1150, + 1151, 1151, 1152, 1152, 1153, 1153, 1154, 1154, 1155, 1155, + 1156, 1156, 1157, 1157, 1158, 1158, 1159, 1159, 1160, 1160, + 1161, 1161, 1162, 1162, 1163, 1163, 1164, 1164, 1165, 1165, + 1166, 1166, 1167, 1167, 1168, 1168, 1169, 1169, 1170, 1170, + 1171, 1171, 1172, 1172, 1173, 1173, 1174, 1175, 1175, 1176, + 1176, 1177, 1177, 1178, 1178, 1179, 1179, 1180, 1180, 1181, + 1181, 1182, 1182, 1183, 1184, 1184, 1185, 1185, 1186, 1186, + 1187, 1187, 1188, 1188, 1189, 1189, 1190, 1191, 1191, 1192, + 1192, 1193, 1193, 1194, 1194, 1195, 1195, 1196, 1197, 1197, + 1198, 1198, 1199, 1199, 1200, 1200, 1201, 1202, 1202, 1203, + 1203, 1204, 1204, 1205, 1205, 1206, 1207, 1207, 1208, 1208, + 1209, 1209, 1210, 1210, 1211, 1212, 1212, 1213, 1213, 1214, + 1214, 1215, 1216, 1216, 1217, 1217, 1218, 1218, 1219, 1220, + 1220, 1221, 1221, 1222, 1222, 1223, 1224, 1224, 1225, 1225, + 1226, 1226, 1227, 1228, 1228, 1229, 1229, 1230, 1231, 1231, + 1232, 1232, 1233, 1233, 1234, 1235, 1235, 1236, 1236, 1237, + 1238, 1238, 1239, 1239, 1240, 1241, 1241, 1242, 1242, 1243, + 1244, 1244, 1245, 1245, 1246, 1247, 1247, 1248, 1248, 1249, + 1250, 1250, 1251, 1251, 1252, 1253, 1253, 1254, 1254, 1255, + 1256, 1256, 1257, 1257, 1258, 1259, 1259, 1260, 1260, 1261, + 1262, 1262, 1263, 1263, 1264, 1265, 1265, 1266, 1266, 1267, + 1268, 1268, 1269, 1270, 1270, 1271, 1271, 1272, 1273, 1273, + 1274, 1275, 1275, 1276, 1276, 1277, 1278, 1278, 1279, 1280, + 1280, 1281, 1281, 1282, 1283, 1283, 1284, 1285, 1285, 1286, + 1286, 1287, 1288, 1288, 1289, 1290, 1290, 1291, 1291, 1292, + 1293, 1293, 1294, 1295, 1295, 1296, 1297, 1297, 1298, 1298, + 1299, 1300, 1300, 1301, 1302, 1302, 1303, 1304, 1304, 1305, + 1305, 1306, 1307, 1307, 1308, 1309, 1309, 1310, 1311, 1311, + 1312, 1313, 1313, 1314, 1315, 1315, 1316, 1316, 1317, 1318, + 1318, 1319, 1320, 1320, 1321, 1322, 1322, 1323, 1324, 1324, + 1325, 1326, 1326, 1327, 1328, 1328, 1329, 1330, 1330, 1331, + 1332, 1332, 1333, 1334, 1334, 1335, 1336, 1336, 1337, 1338, + 1338, 1339, 1340, 1340, 1341, 1342, 1342, 1343, 1344, 1344, + 1345, 1346, 1346, 1347, 1348, 1348, 1349, 1350, 1350, 1351, + 1352, 1352, 1353, 1354, 1354, 1355, 1356, 1356, 1357, 1358, + 1358, 1359, 1360, 1360, 1361, 1362, 1362, 1363, 1364, 1364, + 1365, 1366, 1366, 1367, 1368, 1369, 1369, 1370, 1371, 1371, + 1372, 1373, 1373, 1374, 1375, 1375, 1376, 1377, 1377, 1378, + 1379, 1380, 1380, 1381, 1382, 1382, 1383, 1384, 1384, 1385, + 1386, 1386, 1387, 1388, 1388, 1389, 1390, 1391, 1391, 1392, + 1393, 1393, 1394, 1395, 1395, 1396, 1397, 1398, 1398, 1399, + 1400, 1400, 1401, 1402, 1402, 1403, 1404, 1405, 1405, 1406, + 1407, 1407, 1408, 1409, 1409, 1410, 1411, 1412, 1412, 1413, + 1414 +}; + +int +ihypot(x, y) + int x, y; +{ + int max, min; + + x = (x < 0) ? -x : x; + y = (y < 0) ? -y : y; + if (x > y) + { + max = x; + min = y; + } + else + { + max = y; + min = x; + } + if (max == 0) + return 0; + /* if(max < 32768) return isqrt(max*max+min*min); */ + return hypotlookup[HYPOTMIN * min / max] * max / HYPOTMIN; +} + +#if 0 +/* code to calculate the lookup table. */ +#include + +int +main(int argc, char **argv) +{ + int i, j, max; + + if (argc != 2) + { + printf("Usage: %s \n", argv[0]); + return 0; + } + max = atoi(argv[1]); + printf("#define HYPOTMIN %d\nint hypotlookup[] = {\n %d", max, max); + for (i = 1, j = 1; i <= max; i++, j++) + { + if (j % 10 == 0) + printf(",\n "); + else + printf(", "); + printf("%d", (int) hypot((double) i, (double) max)); + } + printf("\n};\n"); + return 0; +} +#endif /* 0 */ + +#if 0 +/* code to test various routines */ +int +main(int argc, char **argv) +{ + if (argc != 3) + { + printf("Usage: %s \n", argv[0]); + return 0; + } + printf("hypot = %d\n", ihypot(atoi(argv[1]), atoi(argv[2]))); + return 0; +} +#endif /* 0 */ diff -r cafa94d86546 -r aa38447a4b21 src/input.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/input.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,163 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation for any NON-COMMERCIAL purpose (following the terms of +the GNU General Public License (read the file 'COPYING')) 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 + + Comprehensive credits are available in the file "CREDITS" +--------------------------------------------------------------------------*/ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" + +static int sendflag = 0; + +extern int intrupt(); +extern void start_interruptor(); +extern int isClientDead(); +int reconnect(); +extern int readFromClient(); +extern void stop_interruptor(); +extern int exitGame(); +extern int closeUdpConn(); +extern unsigned int sleep(); +extern int connectToClient(); +extern void (*r_signal()) (); + +void +setflag() +{ + sendflag = 1; +} + + +void +input() +{ + fd_set readfds; + + start_interruptor(); + + /* Idea: read from client often, send to client not so often */ + while (me->p_status == PALIVE || + me->p_status == PEXPLODE || + me->p_status == PDEAD || + me->p_status == POBSERVE) + { + if (isClientDead()) + { + if (!reconnect()) + exit(0); + } + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + if (udpSock >= 0) + FD_SET(udpSock, &readfds); + + /* + * blocks indefinitely unless client input or timerDelay SIGALRM causes + * EINTR + */ + + if (socketWait() > 0) + { + readFromClient(); + } + if (sendflag) + { + intrupt(); + sendflag = 0; + } + + /* statements below are executed once per timerDelay */ + if (me->p_updates > delay) + { + me->p_flags &= ~(PFWAR); + } + if (me->p_updates > rdelay) + { + me->p_flags &= ~(PFREFITTING); + } + + /* + * this will ghostbust a player if no ping has been received in + * ping_ghostbust_interval seconds + */ + + if (configvals->ping_allow_ghostbust + && (me->p_status == PALIVE || me->p_status == POBSERVE) + && ping_ghostbust > configvals->ping_ghostbust_interval) + me->p_ghostbuster = 100000; /* ghostbusted */ + else + /* Keep self from being nuked... */ + me->p_ghostbuster = 0; + } + stop_interruptor(); +} + +int +reconnect() +{ + int i; + + if (noressurect) + exitGame(); + stop_interruptor(); + + r_signal(SIGIO, SIG_IGN); +#ifdef DEBUG + printf("Ack! The client went away!\n"); + printf("I will attempt to resurrect him!\n"); + fflush(stdout); +#endif + commMode = COMM_TCP; + if (udpSock >= 0) + closeUdpConn(); + + /* For next two minutes, we try to restore connection */ + shutdown(sock, 2); + sock = -1; + for (i = 0;; i++) + { + me->p_ghostbuster = 0; + sleep(5); + if (connectToClient(host, nextSocket)) + break; + if (i == 23) + { +#ifdef DEBUG + printf("Oh well, maybe I'm getting rusty!\n"); + fflush(stdout); +#endif + return 0; + } + } + start_interruptor(); +#ifdef DEBUG + printf("A miracle! He's alive!\n"); + fflush(stdout); +#endif + return 1; +} diff -r cafa94d86546 -r aa38447a4b21 src/interface.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interface.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,1236 @@ +/*-------------------------------------------------------------------------- +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 "shmem.h" + +void cloak_off(); +void cloak_on(); +int numShips(); +void sendwarn(); +extern int pmessage2(); +int allowed_ship(); +int numPlanets(); +void suspendPrep(); +void unsuspendPrep(); + +/*-----------------------------VISIBLE FUNCTIONS---------------------------*/ + +/*--------------------------------SETSPEED---------------------------------*/ +/* + * This function takes the desired speed from the client and translates it + * into impulse, afterburners, or warp. 99 = warp. 98 = afterburners. 97 = + * suspend warp prep, 96 = resume warp prep, 0-x = impulse. This function is + * used for both requests to set a ships speed from the client and from the + * server. The client requests are requests that are received directly from + * the client. A speed of 99 is treated as a request for warp speed. A + * request of 98 is a request for afterburners. + */ + + + +void +set_speed(speed, type) + int speed; /* the desired speed */ + int type; /* type of request. 0=server 1=client */ +{ + if (me->p_flags & PFDOCK) + { /* if docked then */ + if (players[me->p_docked].p_speed > 4) + { /* you cannot get off >= 4 */ + warning("You are going too fast to disengage safely"); + return; + } + else + undock_player(me); + } + speed = (speed < 0) ? 0 : speed; /* no negative speeds */ + /* suspend warp [BDyess] */ + if (speed == 97 && configvals->warpprep_suspendable) + { /* suspend warp */ + suspendPrep(); + } + else if (speed == 96 && configvals->warpprep_suspendable) + { + /* unsuspend warp [BDyess] */ + unsuspendPrep(); + } + else if ((speed == 98) && (configvals->afterburners)) + { /* afterburners */ + /* turn off warp, warpprep, and warp suspended flags */ + me->p_flags &= ~(PFWARP | PFWARPPREP | PFWPSUSPENDED); + me->p_warptime = 0; + me->p_flags |= PFAFTER; /* turn on after burners */ + me->p_desspeed = me->p_ship.s_after.maxspeed; /* set speed of + * afterburn */ + /* + * go to warp if speed 99 is sent, OR if the speed sent is greater than + * max impulse and the VARIABLE_WARP sysdef is set, AND the ship can warp + * [BDyess] + */ + } + else if ((speed == 99 + || (configvals->variable_warp + && speed > me->p_ship.s_imp.maxspeed + && me->p_flags & (PFWARPPREP | PFWARP | PFWPSUSPENDED)) + ) + && (me->p_ship.s_nflags & SFNCANWARP)) + { + int maxspeed = me->p_ship.s_warp.maxspeed; + int preptime = myship->s_warpinittime; /* timer before warping */ + + if (configvals->warpzone) + { + if (me->p_zone < 0) + { + warning("The enemy is neutralizing our warp field, sir!"); + return; + } + else if (me->p_zone > 0) + { + maxspeed = maxspeed * 3 / 2; /* can go faster with boost [BDyess] */ + if (maxspeed > 99) + maxspeed = 99; + preptime /= 2; /* takes less time to build up when you have + * help */ + if (preptime == 0) + preptime = 1; + warning("warp boost!"); + } + } + + speed = (speed > maxspeed) + ? maxspeed + : speed; /* cap the request at max warp */ + + me->p_warpdesspeed = speed; /* remember how fast to warp for later + * [BDyess] */ + if (me->p_warptime > 0) + { + warning("Hold your horses, Speed Racer. These things take time."); + return; + } + if (me->p_flags & PFWARP) + { + me->p_desspeed = speed; + return; + } + if (me->p_damage > me->p_ship.s_maxdamage / 2) + { + warning("We are too damaged to risk warp speeds, Captain."); + return; + } + if (me->p_fuel < me->p_ship.s_warpinitcost) + { + warning("Not enough fuel for warp, Captain!"); + return; + } + me->p_desspeed = myship->s_warpprepspeed; /* slow ship down */ + me->p_flags |= PFWARPPREP; /* set warp prep flag [BDyess] */ + if (!configvals->cloakduringwarpprep) + cloak_off(); + + if (me->p_speed < me->p_desspeed) + me->p_speed = me->p_desspeed; + + /* turn off after burners and warpprep suspended flag [BDyess] */ + me->p_flags &= ~(PFAFTER | PFWPSUSPENDED); + me->p_warptime = preptime; /* timer before warping */ + me->p_fuel -= me->p_ship.s_warpinitcost; /* subtract off fuel */ + warning("Warp drive engaged!"); /* let him know its working */ + } + else if (type == 0) + { /* else if server request */ + me->p_desspeed = speed; /* grant speed request */ + } + else + { /* else client request for impulse */ + + if (!configvals->warpdecel) + me->p_flags &= ~(PFWARP | PFAFTER); + + me->p_warptime = 0; + me->p_flags &= ~(PFWARPPREP | PFWPSUSPENDED); /* turn off warpprep + * flag [BDyess] */ + speed = (speed > me->p_ship.s_imp.maxspeed) ? me->p_ship.s_imp.maxspeed : + speed; + me->p_desspeed = speed; /* set the speed */ + } +#if 0 + if (me->p_flags & PFORBIT) /* if we were orbiting */ + planets[me->p_planet].pl_torbit &= ~me->p_team; +#endif + me->p_flags &= ~(PFREPAIR | PFBOMB | PFORBIT | PFDOCK | PFBEAMUP | PFBEAMDOWN); + me->p_lastman = 0; +} + + + + +/*--------------------------------SET_COURSE-------------------------------*/ +/* + * Set the players course. This function takes a direction and sets the + * players direction to it. Certain flags are cleared. + */ + +void +set_course(dir) + unsigned char dir; +{ + me->p_desdir = dir; /* set the desired direction */ + if (me->p_flags & PFDOCK) + { /* if player is docked then he cannot */ + if (players[me->p_docked].p_speed > 4) + { /* undock if dockee going fast */ + warning("It's unsafe to disengage from bases while moving more that warp 4."); + return; + } + else + undock_player(me); + + } +#if 0 + if (me->p_flags & PFORBIT) /* if in orbit then take */ + planets[me->p_planet].pl_torbit &= ~me->p_team; /* team out of orbit */ +#endif + me->p_flags &= ~(PFBOMB | PFORBIT | PFDOCK | PFBEAMUP | PFBEAMDOWN); + me->p_lastman = 0; /* not beamin all armies up */ +} + + + + +/*----------------------------------SHIELD_UP-----------------------------*/ +/* This function raises the players shields. */ + +void +shield_up() +{ + me->p_flags |= PFSHIELD; /* some flags go up and some down */ + me->p_flags &= ~(PFBOMB | PFREPAIR | PFBEAMUP | PFBEAMDOWN); + me->p_lastman = 0; /* not beaming up all armies */ +} + + + + +/*---------------------------------SHIELD_DOWN----------------------------*/ +/* This function lowers the players shields. */ + +void +shield_down() +{ + me->p_flags &= ~PFSHIELD; /* shield flag clear */ +} + + + + +/*--------------------------------SHIELD_TOGGLE---------------------------*/ +/* This function toggles the players shields on and off. */ + +void +shield_tog() +{ + me->p_flags ^= PFSHIELD; /* toggle shield flag */ + me->p_flags &= ~(PFBOMB | PFREPAIR | PFBEAMUP | PFBEAMDOWN); + me->p_lastman = 0; +} + + + + +/*--------------------------------BOMB_PLANET------------------------------*/ +/* + * This function sets the bomb flag if certain conditions are met, such as + * you are bombing enemy planets. + */ + +void +bomb_planet() +{ + static int bombsOutOfTmode = 0; /* confirm bomb out of t-mode */ + int owner; /* owner of planet */ + + owner = planets[me->p_planet].pl_owner; /* get planet's owner */ + if (!(me->p_flags & PFORBIT)) + { /* can't bomb anything in */ + warning("Must be orbiting to bomb"); /* open space, now can you? */ + return; + } + if (me->p_team == planets[me->p_planet].pl_owner) + { + warning("Can't bomb your own armies. Have you been reading Catch-22 again?"); /* can't bomb own armies */ + return; + } + if (!((me->p_swar | me->p_hostile) & owner) && (owner != 0)) + { + warning("Must declare war first (no Pearl Harbor syndrome allowed here)."); + return; /* can't bomb friendlies */ + } + if ((!status->tourn) && (bombsOutOfTmode == 0)) + { + warning("Bomb out of T-mode? Please verify your order to bomb."); + bombsOutOfTmode++; /* warning about bombing out of T */ + return; + } + if ((!status->tourn) && (bombsOutOfTmode == 1)) + { + warning("Hoser!"); /* if he really wants to bomb, then */ + bombsOutOfTmode++; /* let him bomb out of T. Hoser */ + } /* warning */ + if (!numShips(planets[me->p_planet].pl_owner) + && (planets[me->p_planet].pl_owner != NOBODY)) + { + warning("You can't break the peace treaty, Captain"); + return; + } + if (status->tourn) /* reset the bombs out of t-mode */ + bombsOutOfTmode = 0; /* variable */ + me->p_flags |= PFBOMB; /* set the bomb flag */ +#if 1 + planets[me->p_planet].pl_hostile |= me->p_team; +#else + planets[me->p_planet].pl_torbit |= (me->p_team) << 4; +#endif + me->p_flags &= ~(PFSHIELD | PFREPAIR | PFBEAMUP | PFBEAMDOWN); +} + + + + +/*---------------------------------BEAM_UP---------------------------------*/ +/* This function set the beam up flag if it is allowable to beam men up. */ + +void +beam_up() +{ + if (!status2->starttourn && configvals->nopregamebeamup) + { + warning("You can't beam up armies before a game starts"); + return; + } + if (!(me->p_flags & (PFORBIT | PFDOCK))) + { + warning("Must be orbiting or docked to beam up."); + return; /* have to be orbiting or docked */ + } + if (me->p_flags & PFORBIT) + { /* if orbiting and not owner */ + if (me->p_team != planets[me->p_planet].pl_owner) + { + warning("Those aren't our men."); + return; + } + if (me->p_lastman == 0) /* if we have not signalled to pick */ + me->p_lastman = 1; /* up all armies */ + else if (planets[me->p_planet].pl_armies <= 4) + { /* else if less than 5 */ + if (numPlanets((int) me->p_team && configvals->beamlastarmies) == 1) + { + warning("You can't take those armies, they're on your only planet!"); + return; + } + me->p_lastman = 2; /* set status to beaming up all */ + } + } + else if (me->p_flags & PFDOCK) + { /* if docked must be to own team ship */ + if (me->p_team != players[me->p_docked].p_team) + { + warning("Comm Officer: Uhhh, they aren't our men!"); + return; + } + } + me->p_flags |= PFBEAMUP; /* set the beam up flag */ + me->p_flags &= ~(PFSHIELD | PFREPAIR | PFBOMB | PFBEAMDOWN); +} + + + + +/*--------------------------------BEAM_DOWN--------------------------------*/ +/* This function sets the beam up flag if certain conditions are met */ + +void +beam_down() +{ + int i; /* looping var */ + struct planet *pl; /* to access planets */ + int total; /* for total number of planets */ + char buf[80]; + + if (!(me->p_flags & (PFORBIT | PFDOCK))) + { + warning("Must be orbiting or docked to beam down."); + return; /* have to be docked or orbiting */ + } + if ((!((me->p_swar | me->p_hostile) & planets[me->p_planet].pl_owner)) + && (me->p_team != planets[me->p_planet].pl_owner) + && (planets[me->p_planet].pl_owner != NOBODY)) + { + warning("You can't beam down, you have not declared war"); + return; /* no beaming down if not hostile */ + } + if (!numShips(planets[me->p_planet].pl_owner) + && (planets[me->p_planet].pl_owner != NOBODY)) + { + warning("You can't break the peace treaty, Captain"); + return; + } + if (me->p_flags & PFDOCK) + { + if (me->p_team != players[me->p_docked].p_team) + { + warning("Comm Officer: Starbase refuses permission to beam our troops over."); /* no beaming to foreign + * bases */ + return; + } + } + + else if (configvals->planetlimittype) + { /* new planet limit */ + total = numPlanets(me->p_team); + + if (total >= configvals->planetsinplay + && planets[me->p_planet].pl_owner == NOBODY + && planets[me->p_planet].pl_armies) + { + sprintf(buf, "You may only take enemy planets when your team has %d or more planets.", + configvals->planetsinplay); + warning(buf); + me->p_flags &= ~(PFBOMB); + return; + } + } + else + { + int ns[MAXTEAM]; + for (i = 0; i < NUMTEAM; i++) + ns[1 << i] = numShips(1 << i); + + total = 0; + for (i = 0, pl = &planets[i]; i < NUMPLANETS; i++, pl++) + { + if (pl->pl_owner && ns[pl->pl_owner] > configvals->tournplayers - 1) + total++; + } + if ((total >= configvals->planetsinplay) + && (!(me->p_flags & PFDOCK)) + && (planets[me->p_planet].pl_owner == NOBODY)) + { + sprintf(buf, "Sorry, there are already %d planets in play.", + configvals->planetsinplay); + warning(buf); + me->p_flags &= ~(PFBOMB); + return; + } + } + me->p_flags |= PFBEAMDOWN; /* set beam down flag */ + me->p_flags &= ~(PFSHIELD | PFREPAIR | PFBOMB | PFBEAMUP); + me->p_lastman = 0; +} + + + + +/*---------------------------------REPAIR---------------------------------*/ +/* + * This function sets the reapair flag and turns off other flags. You cannot + * repair while in warp. + */ + +void +repair() +{ +#if !defined(AEDILE) || !defined(REPAIR_IN_WARP) + if (me->p_flags & PFWARP) + { /* no repairing in warp */ + warning("You cannot repair while in warp!"); + return; + } +#endif + me->p_desspeed = 0; /* speed goes to zero */ + me->p_warptime = 0; /* turn off warp prep */ + me->p_flags |= PFREPAIR; /* reair flag goes up */ + me->p_flags &= ~(PFSHIELD | PFBOMB | PFBEAMUP | PFBEAMDOWN | PFPLOCK | PFPLLOCK | PFWARP | PFAFTER | PFWARPPREP | PFWPSUSPENDED); + me->p_lastman = 0; /* not beaming all armies */ +} + + + + +/*--------------------------------REPAIR_OFF------------------------------*/ +/* This function takes the repair flag off. */ + +void +repair_off() +{ + me->p_flags &= ~PFREPAIR; +} + + + + +/*---------------------------------REPEAT---------------------------------*/ +/* This function repeats the last message. */ + +void +repeat_message() +{ + if (++lastm == MAXMESSAGE) /* go to next message */ + lastm = 0; /* account for rollover */ +} + + + + +/*---------------------------------CLOAK----------------------------------*/ +/* + * This function toggles the cloak flag. Tractors and pressor are turned + * off. + */ + +void +cloak() +{ + if (me->p_flags & PFCLOAK) + cloak_off(); + else + cloak_on(); +} + + + + +/*---------------------------------CLOAK_ON-------------------------------*/ +/* This function turns cloak on. Tractors and pressors are turned off. */ + +void +cloak_on() +{ + if (me->p_warptime && !configvals->cloakduringwarpprep) + { + warning("Can't cloak during warp preparation."); + return; + } + if (me->p_flags & PFWARP && !configvals->cloakwhilewarping) + { + warning("Can't cloak while warp engines are engaged."); + return; + } + me->p_flags |= PFCLOAK; + me->p_flags &= ~(PFTRACT | PFPRESS); +} + + + + +/*---------------------------------CLOAK_OFF------------------------------*/ +/* This function turns the cloak off. */ + +void +cloak_off() +{ + me->p_flags &= ~PFCLOAK; +} + + + + +/*-------------------------------LOCK_PLANET-----------------------------*/ +/* This function locks the player onto a planet. */ + +void +lock_planet(planet) + int planet; /* planet locking onto */ +{ + char buf[80]; /* to sprintf into */ + + if ((planet < 0) || (planet >= NUMPLANETS)) /* bad planet number? */ + return; + + if (me->p_status == POBSERVE) + { + if (planets[planet].pl_owner != me->p_team) + { + warning("Unable to observe enemy planets."); + me->p_flags &= ~(PFPLLOCK | PFPLOCK); + return; + } + else if (!(planets[planet].pl_owner & me->p_teamspy)) + { + warning("That team has barred you from observing."); + me->p_flags &= ~(PFPLLOCK | PFPLOCK); + return; + } + } + + me->p_flags |= PFPLLOCK; /* turn on the lock */ +#if 0 + if (me->p_flags & PFORBIT) /* if orbiting then leave torbit var */ + planets[me->p_planet].pl_torbit &= ~me->p_team; +#endif + me->p_flags &= ~(PFPLOCK | PFORBIT | PFBEAMUP | PFBEAMDOWN | PFBOMB); + me->p_lastman = 0; + me->p_planet = planet; /* set planet locked onto */ + sprintf(buf, "Locking onto %s", planets[planet].pl_name); + warning(buf); /* send message to player */ +} + + + + +/*-------------------------------LOCK_PLAYER-------------------------------*/ +/* This function locks the player onto another player. */ + +void +lock_player(player) + int player; /* player locking onto */ +{ + char buf[80]; + + if ((player < 0) || (player >= MAXPLAYER)) /* bad planet num? */ + return; + if (players[player].p_status != PALIVE) /* player not alive? */ + return; + if (players[player].p_flags & PFCLOAK) /* player is cloaked */ + return; + + if (me->p_status == POBSERVE && players[player].p_team != me->p_team) + { + sprintf(buf, "Unable to observe enemy players."); + warning(buf); + me->p_flags &= ~(PFPLLOCK | PFPLOCK); + return; + } + + me->p_flags |= PFPLOCK; /* set player lock flag */ +#if 0 + if (me->p_flags & PFORBIT) /* if in orbit take team out */ + planets[me->p_planet].pl_torbit &= ~me->p_team; /* of torbit */ +#endif + me->p_flags &= ~(PFPLLOCK | PFORBIT | PFBEAMUP | PFBEAMDOWN | PFBOMB); + me->p_lastman = 0; /* turn off taking all armies */ + me->p_playerl = player; /* set player loked oto */ + /* player locking onto own base */ + if ((players[player].p_team == me->p_team) && + allows_docking(players[player].p_ship)) + sprintf(buf, "Locking onto %s (%s) (docking is %s)", + players[player].p_name, twoletters(&players[player]), + (players[player].p_flags & PFDOCKOK) ? "enabled" : "disabled"); + else /* message for locking onto player */ + sprintf(buf, "Locking onto %s (%s)", players[player].p_name, + twoletters(&players[player])); + warning(buf); +} + + + + +/*-------------------------------TRACTOR_PLAYER----------------------------*/ +/* + * This function does the tractoring for the player. There are a few times + * when the tractor cannot be used. + */ + +void +tractor_player(player) + int player; +{ + struct player *victim; + + if (weaponsallowed[WP_TRACTOR] == 0) /* tractors allowed? */ + return; + if ((player < 0) || (player > MAXPLAYER)) + { /* out of bounds = cancel */ + me->p_flags &= ~(PFTRACT | PFPRESS); + return; + } + if (me->p_flags & PFCLOAK) /* no tractoring while */ + return; /* cloaked */ + if (player == me->p_no) /* can't tractor yourself */ + return; + victim = &players[player]; /* get player number */ + if (victim->p_flags & PFCLOAK) + return; + if (ihypot(me->p_x - victim->p_x, me->p_y - victim->p_y) < + (TRACTDIST) * me->p_ship.s_tractrng) + { + if (me->p_flags & PFDOCK && players[me->p_docked].p_speed > 4) + { + warning("It's unsafe to tractor while docked and base is moving more then warp 4."); + return; + } +#if 0 + undock_player(victim); /* harmless if not docked, handles js */ + undock_player(me); + +#if 0 + if (me->p_flags & PFORBIT) /* are we orbiting */ + planets[me->p_planet].pl_torbit &= ~me->p_team; + if (victim->p_flags & PFORBIT) /* is victim orbiting */ + planets[victim->p_planet].pl_torbit &= ~victim->p_team; + victim->p_flags &= ~(PFORBIT | PFDOCK); /* clear DOCK/ORBIT flags */ +#endif + me->p_flags &= ~(PFORBIT | PFDOCK); +#endif + me->p_tractor = player; /* set victim number */ + me->p_flags |= PFTRACT; /* set tractor flag */ + } +} + + + + +/*---------------------------------PRESSOR--------------------------------*/ +/* + * This function activates the tractors for the player. There are a number + * of conditions where tractors will not work. + */ + +void +pressor_player(player) + int player; /* the player to presoor */ +{ + int target; + struct player *victim; + + if (weaponsallowed[WP_TRACTOR] == 0) + { /* tractors allowed? */ + warning("Pressor beams haven't been invented yet."); + return; + } + target = player; /* save target */ + if ((target < 0) || (target > MAXPLAYER)) + { /* out of bounds = cancel */ + me->p_flags &= ~(PFTRACT | PFPRESS); + return; + } + if (me->p_flags & PFPRESS) /* already pressoring? */ + return; + if (me->p_flags & PFCLOAK) + { /* cloaked? */ + warning("Weapons's Officer: Cannot pressor while cloaked, sir!"); + return; + } + victim = &players[target]; /* get victim's struct */ + if (victim->p_flags & PFCLOAK)/* victim cloaked */ + return; + if (ihypot(me->p_x - victim->p_x, me->p_y - victim->p_y) < + (TRACTDIST) * me->p_ship.s_tractrng) + { + if (me->p_flags & PFDOCK && players[me->p_docked].p_speed > 4) + { + warning("It's unsafe to pressor while docked and base is moving more then warp 4."); + return; + } +#if 0 + undock_player(victim); + undock_player(me); + +#if 0 + if (me->p_flags & PFORBIT) /* are we orbiting */ + planets[me->p_planet].pl_torbit &= ~me->p_team; + if (victim->p_flags & PFORBIT) /* is victim orbiting */ + planets[victim->p_planet].pl_torbit &= ~victim->p_team; +#endif + victim->p_flags &= ~(PFORBIT | PFDOCK); /* clear orbit and dock flags */ + me->p_flags &= ~(PFORBIT | PFDOCK); +#endif + me->p_tractor = target; /* set the target */ + me->p_flags |= (PFTRACT | PFPRESS); /* set the tract and press */ + } + /* flags */ + else + warning("Weapon's Officer: Vessel is out of range of our pressor beam."); +} + + + + +/*-------------------------------DECLARE_WAR-----------------------------*/ +/* This function changes the war mask of a player. */ + +void +declare_war(mask) + int mask; /* who are we declaring war against */ +{ + int changes; /* to hold changes in war mask */ + int i; /* looping var */ + + mask &= ALLTEAM; /* mask off extraneous bits */ + mask &= ~me->p_team; /* mask out our team bit */ + mask |= me->p_swar; + changes = mask ^ me->p_hostile; /* determine changes */ + if (changes == 0) /* if no changes then we are done */ + return; + if (changes & FED) /* if Fed status changed then warn them */ + sendwarn("Federation", mask & FED, FED); + if (changes & ROM) /* if Rom status changed then warn them */ + sendwarn("Romulans", mask & ROM, ROM); + if (changes & KLI) /* if Kli status changed then warn them */ + sendwarn("Klingons", mask & KLI, KLI); + if (changes & ORI) /* if Orion status changed then warn them */ + sendwarn("Orions", mask & ORI, ORI); + if (me->p_flags & PFDOCK) + { /* if docked and now at war with */ + if (players[me->p_docked].p_team & mask) + { /* dockee then undock */ + undock_player(me); + } + } + else if (allows_docking(me->p_ship)) + { /* if ship is dockable then */ + if (me->p_docked > 0) + { /* go through ports and */ + for (i = 0; i < me->p_ship.s_numports; i++) + { /* kick off warring ships */ + if (me->p_port[i] >= 0 && + (mask & players[me->p_port[i]].p_team)) + { + base_undock(me, i); + } + } + } + } + if (mask & ~me->p_hostile) + { /* no sudden changing of */ + me->p_flags |= PFWAR; /* war status */ + delay = me->p_updates + 100; + warning("Pausing ten seconds to re-program battle computers."); + } + me->p_hostile = mask; /* new hostile mask */ +} + + + + +/*-----------------------------------SENDWARN------------------------------*/ +/* + * This function sends the warning message to the other players when a player + * switches his war status with that team. + */ + +void +sendwarn(string, atwar, team) + char *string; /* the name of the team changing status + * towards */ + int atwar; /* 1 if declarig war 0 if decalring peace */ + int team; /* name of team we are switching in regards + * to */ +{ + char buf[BUFSIZ]; /* to hold sprintfed message */ + char addrbuf[10]; /* to hold ship number and team letter */ + + if (atwar) + { /* if decalring war */ + (void) sprintf(buf, "%s (%s) declaring war on the %s", + me->p_name, twoletters(me), string); + } + else + { /* else decalring peace */ + (void) sprintf(buf, "%s (%s) declaring peace with the %s", + me->p_name, twoletters(me), string); + } + (void) sprintf(addrbuf, " %s->%-3s", twoletters(me), teams[team].shortname); + pmessage2(buf, team, MTEAM, addrbuf, me->p_no); +} + + +/* switches the special weapon of the player */ + +void +switch_special_weapon() +{ + int mask = 0; + int currflag; + int i, j; + + mask = me->p_ship.s_nflags & (SFNHASMISSILE | SFNPLASMAARMED); + + if (!mask) + { + warning("This ship is not armed with any special weapons"); + me->p_specweap = 0; + return; + } + for (i = 0; i < sizeof(int) * 8; i++) + { + currflag = 1 << i; + if (!mask & currflag) + continue; + if (me->p_specweap & currflag) + { + i++; + break; + } + } + + for (j = 0; j < sizeof(int) * 8; i++, j++) + { + if (i > sizeof(int) * 8) + i = 0; + currflag = 1 << i; + if (mask & currflag) + { + me->p_specweap = currflag; + break; + } + } + + if (me->p_specweap & SFNHASMISSILE) + { + if (me->p_ship.s_nflags & SFNHASFIGHTERS) + warning("Fighters ready"); + else + warning("Missiles armed"); + } + else if (me->p_specweap & SFNPLASMAARMED) + { + warning("Plasmas armed"); + } +} + +/*-------------------------------DO_REFIT---------------------------------*/ +/* + * This function will attempt to refit a player to another ship. There are + * all sorts of nasty reasons why it might fail. + */ + +void +do_refit(type) + int type; /* type of ship to refit to */ +{ + int i; /* looping var */ + + if (type < 0 || type >= NUM_TYPES) /* ship type select out of range */ + return; + if (me->p_flags & PFORBIT) + { /* if orbiting must be a shipyard */ + if (!(planets[me->p_planet].pl_flags & PLSHIPYARD)) + { + warning("You can change ships at a planet with a shipyard on it."); + return; + } +#if 0 + if (planets[me->p_planet].pl_owner != me->p_team) + { + warning("You can only refit on planets that your team owns."); + return; + } +#endif + } + else if (me->p_flags & PFDOCK) + { /* if docked then */ + if (allows_docking(shipvals[type])) + { /* cannot refit to a starbase */ + warning("Can only refit to a base in a shipyard"); + return; + } + if (players[me->p_docked].p_team != me->p_team) + { + warning("You must dock with YOUR base to apply for command reassignment!"); /* no refitting on enemy + * SB's */ + return; + } + if (!(players[me->p_docked].p_ship.s_nflags & SFNCANREFIT)) + { + warning("This base can not provide you with a new ship."); + return; + } + } + else + { /* planet does not have shipyard */ + warning("Must orbit a shipyard or dock with your base to apply for command reassignment!"); + return; + } + if ((me->p_damage > ((float) me->p_ship.s_maxdamage) * .75) || + (me->p_shield < ((float) me->p_ship.s_maxshield) * .75) || + (me->p_fuel < ((float) me->p_ship.s_maxfuel) * .75)) + { + warning("Central Command refuses to accept a ship in this condition!"); + return; /* ship must be in good condition */ + } + if ((me->p_armies > 0)) + { /* no refitting with armies on board */ + warning("You must beam your armies down before moving to your new ship"); + return; + } + + { + int oldt, oldd, oldp, allowed; + oldt = me->p_ship.s_type; + oldd = me->p_ship.s_numdefn; + oldp = me->p_ship.s_numplan; + me->p_ship.s_type = -1; + me->p_ship.s_numdefn = 0; + me->p_ship.s_numplan = 0; + allowed = allowed_ship(me->p_team, me->p_stats.st_rank, + me->p_stats.st_royal, type); + me->p_ship.s_type = oldt; + me->p_ship.s_numdefn = oldd; + me->p_ship.s_numplan = oldp; + if (!allowed) + return; + } + + if (me->p_ship.s_type == STARBASE || + me->p_ship.s_type == WARBASE || + me->p_ship.s_type == CARRIER) + me->p_kills = 0; /* reset kills to zero if coming */ + /* from a base */ + + if (allows_docking(me->p_ship)) + { /* if ship dockable then */ + for (i = 0; i < me->p_ship.s_numports; i++) + { /* dump all ship out of dock */ + base_undock(me, i); + } + } + get_ship_for_player(me, type);/* place ship in player strct */ + + switch_special_weapon(); + + if (me->p_flags & PFORBIT) + { + char buf[120]; + me->p_lastrefit = me->p_planet; + sprintf(buf, "%s is now your home port", planets[me->p_lastrefit].pl_name); + warning(buf); + } + + me->p_flags &= ~(PFREFIT); + me->p_flags |= PFREFITTING; + rdelay = me->p_updates + 50; + warning("You are being transported to your new vessel .... "); +} + + +/* + * Is a person with this rank on this team able to requisition a ship of this + * type? + */ +int +allowed_ship(team, rank, royal, type) + int team; + int rank; + int royal; + int type; +{ + struct ship *tempship; + int shipcount; + int used_teamstr; /* people required to support flying bases */ + int used_planstr; /* planets required to support flying bases */ + int i, maxrank = 0; + + if (!shipsallowed[type]) + { + warning("That ship hasn't been designed yet."); + return 0; + } + tempship = &shipvals[type]; + +#ifdef LEAGUE_SUPPORT + if (status2->league == 1) + return 1; + + if (!status2->league) + { +#endif + if (configvals->baserankstyle) + { + for (i = 0; i < MAXPLAYER; i++) + if ((players[i].p_status == PALIVE || + players[i].p_status == POUTFIT) + && players[i].p_team == team) + maxrank = MAX(rank, players[i].p_stats.st_rank); + } + else + maxrank = NUMRANKS; + + if ((rank < MIN(tempship->s_rank, maxrank) && !(royal > GODLIKE)) && + !(shipvals[tmpPick].s_nflags & SFNMASSPRODUCED)) + { + char buf[100]; + sprintf(buf, "Sorry %s, a rank of %s is required to command that ship.", + ranks[rank].name, ranks[tempship->s_rank].name); + warning(buf); + return 0; + } +#ifdef LEAGUE_SUPPORT + } +#endif + used_teamstr = used_planstr = 0; + shipcount = 0; /* How many ships of that type */ + /* are on our team already? */ + for (i = 0; i < MAXPLAYER; i++) + { + if (players[i].p_status == PALIVE && players[i].p_team == team) + { + if (players[i].p_ship.s_type == type) + shipcount++; + used_teamstr += players[i].p_ship.s_numdefn; + used_planstr += players[i].p_ship.s_numplan; + } + } + /* + * if you are in a base, and near the limits, you will sometimes have to + * switch into a normal ship before changing into another base + */ + + if ((shipcount >= tempship->s_maxnum) && !(shipvals[tmpPick].s_nflags & SFNMASSPRODUCED)) + { + char buf[100]; + sprintf(buf, "We already have %d %ss.", shipcount, tempship->s_name); + warning(buf); + return 0; + } + if ((teams[team].s_turns[type] > + (tempship->s_maxnum - shipcount - 1) * tempship->s_timer) && + !(shipvals[tmpPick].s_nflags & SFNMASSPRODUCED)) + { + char buf[100]; + int turnsleft = teams[team].s_turns[type] - + (tempship->s_maxnum - shipcount - 1) * tempship->s_timer; + if (teams[team].s_turns[type] > 1) + { + sprintf(buf, "We are still building that ship (%d minutes until finished.)", turnsleft); + warning(buf); + } + else + warning("We are still building that ship (1 minute until finished.)"); + return 0; + } + if ((tempship->s_numdefn && + numShips(team) < tempship->s_numdefn + used_teamstr) && + !(shipvals[tmpPick].s_nflags & SFNMASSPRODUCED)) + { + char buf[100]; + sprintf(buf, "Your team is not strong enough to defend a %s (%d+%d players needed).", + tempship->s_name, tempship->s_numdefn, used_teamstr); + warning(buf); + return 0; + } + if ((tempship->s_numplan && + numPlanets(team) < tempship->s_numplan + used_planstr) && + !(shipvals[tmpPick].s_nflags & SFNMASSPRODUCED)) + { + char buf[100]; + sprintf(buf, "Your team's struggling economy cannot support a %s (%d+%d planets needed).", tempship->s_name, tempship->s_numplan, used_planstr); + warning(buf); + return 0; /* have enough planets? */ + } + return 1; +} + + +/*----------------------------------NUMSHIPS------------------------------*/ +/* This function counts the number of players on a team. */ + +int +numShips(owner) + int owner; /* the team to count for */ +{ + int i; /* looping var */ + int num; /* to hold player count */ + struct player *p; /* to point to players */ + + num = 0; /* zero the count */ + for (i = 0, p = players; i < MAXPLAYER; i++, p++) + { /* go throgh players */ + if (p->p_status != PFREE && p->p_team == owner) /* if alive then */ + num++; /* inc player count */ + } + return (num); /* return number of ships */ +} + + + + +/*------------------------------NUMPLANETS--------------------------------*/ +/* This function counts the number of planets a team has. */ + +int +numPlanets(owner) + int owner; /* the team to check for */ +{ + int i; /* looping var */ + int num; /* to hold count */ + struct planet *p; /* to point to a planet */ + + num = 0; /* no planets found yet */ + for (i = 0, p = planets; i < MAXPLANETS; i++, p++) + { + if (p->pl_owner == owner) /* if planet owned by team then inc */ + num++; + } + return (num); /* return number of planets */ +} + +/*-------------------------------------------------------------------------*/ + +/* + * Suspends warp prep [BDyess] + */ +void +suspendPrep() +{ + /* check to see if the server allows warp prep to be suspended [BDyess] */ + if (!configvals->warpprep_suspendable) + return; + if (me->p_flags & PFWARPPREP) + { + me->p_flags |= PFWPSUSPENDED; /* turn on suspended flag */ + warning("Warp prep suspended."); + } + else + { + warning("Not in warp prep!"); + } +} + +/* + * Unsuspends warp prep [BDyess] + */ +void +unsuspendPrep() +{ + /* check to see if the server allows warp prep to be suspended [BDyess] */ + if (!configvals->warpprep_suspendable) + return; + if (me->p_flags & PFWARPPREP) + { + me->p_flags &= ~PFWPSUSPENDED; /* turn off suspended flag */ + warning("Warp prep continued."); + } + else + { + warning("Not in warp prep!"); + } +} + +/*-------END OF LINE----*/ diff -r cafa94d86546 -r aa38447a4b21 src/listen.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/listen.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,634 @@ +/*-------------------------------------------------------------------------- +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 +--------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------ +Startup program for netrek. Listens for connections, then forks off +servers. Based on code written by Brett McCoy, but heavily modified. + +Note that descriptor 2 is duped to descriptor 1, so that stdout and +stderr go to the same file. +--------------------------------------------------------------------------*/ + +#ifndef apollo +#include +#endif +#include +#include +#include +#include +#include +#include +#ifdef SVR4 +#include +#endif /* SVR4 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SYSV +#include +#endif +#ifdef hpux +#include +#endif +#include "defs.h" +#include "path.h" +#include "data.h" + +/* #define DEF_PORT 2592 /* port to listen on */ +/* + * #define NTSERV "bin/ntserv" + * + * #define METASERVER "metaserver.ecst.csuchico.edu" + */ +/* + * Since the metaserver address is a nameserver alias, we can't just compare + * the peer hostname with the setting of METASERVER. The peer hostname + * returned by gethostbyaddr() will be the machine's real name, which will be + * different (and could change). + * + * So, we'll do a gethostbyname() on METASERVER to get an IP address, then we + * can compare that with the connecting peer. + * + * It'd be overkill to get the metaserver's IP address with every connection; + * and it may be inadequate to get it just once at startup, since listen can + * exist for long periods of time, and the metaserver's IP address could be + * changed in that time. + * + * So, we'll grab the IP address at least every META_UPDATE_TIME seconds + */ +#define META_UPDATE_TIME (5*60*60) /* five hours */ + +void printlistenUsage(); +void set_env(); +int listenSock; +short port = PORT; +char *program; +int meta_addr; + +char *dateTime(); +void detach(); +void getConnections(); +void getListenSock(); +void multClose(); +void reaper(); +void terminate(); + +/* + * Error reporting functions ripped from my library. + */ +void syserr(); +void warnerr(); +void fatlerr(); +void err(); +char *lasterr(); +void print_pid(); + +struct hostent *gethostbyaddr(); +char *inet_ntoa(); +int metaserverflag; +char *leagueflag = 0; +char *observerflag = 0; + +#define NEA 10 +char *extraargs[NEA]; +int extraargc = 0; + +char *ntserv_binary = NTSERV; + +/* + * the System-V signal() function provides the older, unreliable signal + * semantics. So, this is an implementation of signal using sigaction. + */ + +void (* + r_signal(sig, func)) () + int sig; + void (*func) (); +{ + struct sigaction act, oact; + + act.sa_handler = func; + + sigemptyset(&act.sa_mask); + act.sa_flags = 0; +#ifdef SA_RESTART + act.sa_flags |= SA_RESTART; +#endif + + if (sigaction(sig, &act, &oact) < 0) + return (SIG_ERR); + + return (oact.sa_handler); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int i, key; + int nogo = 0; + struct hostent *he; + struct timeval tv; + time_t stamp, now; + + metaserverflag = 0; +#ifndef apollo + nice(-20); + nice(-20); + nice(-20); +#endif + + for (i = 1; i < argc; i++) + { + if (*argv[i] == '-') + { + switch (argv[i][1]) + { + case 'p': + port = atoi(argv[i + 1]); + break; + case 'k': + if (++i < argc && sscanf(argv[i], "%d", &key) > 0 && key > 0) + set_env("TREKSHMKEY", argv[i]); + else + nogo++; + break; + case 'b': + ntserv_binary = argv[++i]; + break; + case 'h': + case 'u': /* for old times sake, the others don't do + * this, but this one does so it doesn't pass + * to ntserv */ + case '-': /* same with this */ + nogo++; + break; + default: + /* all unknown arguments are passed through to ntserv. */ + extraargs[extraargc++] = argv[i]; + } + } + /* else just ignore non flags */ + } + + if ((program = strrchr(argv[0], '/'))) + ++program; + else + program = argv[0]; /* let err functions know our name */ + + if (nogo) + printlistenUsage(program); + + detach(); /* detach from terminal, close files, etc. */ + print_pid(); /* log the new PID */ + getListenSock(); + r_signal(SIGCHLD, reaper); + r_signal(SIGTERM, terminate); + r_signal(SIGHUP, SIG_IGN); + + meta_addr = 0; + stamp = 0; + tv.tv_sec = 1; + tv.tv_usec = 0; + + while (1) + { + now = time(0); + if (now - stamp > META_UPDATE_TIME) + { + he = gethostbyname(METASERVER); + if (he) + meta_addr = *((int *) he->h_addr); + stamp = now; + } + getConnections(); + select(0, 0, 0, 0, &tv); /* wait one sec between each connection */ + } +} + +/*********************************************************************** + * Detach process in various ways. + */ + +void +detach() +{ + int fd, rc, mode; + char *fname; + + mode = S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR; + /* fname = build_path("startup.log"); */ + fname = build_path("logs/startup.log"); + if ((fd = open(fname, O_WRONLY | O_CREAT | O_APPEND, mode)) == -1) + syserr(1, "detach", "couldn't open log file. [%s]", dateTime()); + dup2(fd, 2); + dup2(fd, 1); + multClose(1, 2, -1); /* close all other file descriptors */ + warnerr(0, "started at %s on port %d.", dateTime(), port); + + /* fork once to escape the shells job control */ + if ((rc = fork()) > 0) + exit(0); + else if (rc < 0) + syserr(1, "detach", "couldn't fork. [%s]", dateTime()); + + /* now detach from the controlling terminal */ + +#ifdef _SEQUENT_ + if ((fd = open("/dev/tty", O_RDWR | O_NOCTTY, 0)) >= 0) + { + (void) close(fd); + } +#else + if ((fd = open("/dev/tty", O_RDWR, 0)) == -1) + { + warnerr("detach", "couldn't open tty, assuming still okay. [%s]", + dateTime()); + return; + } +#if defined(SYSV) && defined(TIOCTTY) + { + int zero = 0; + ioctl(fd, TIOCTTY, &zero); + } +#else + ioctl(fd, TIOCNOTTY, 0); +#endif + close(fd); +#endif /* _SEQUENT_ */ + + setsid(); /* make us a new process group/session */ +} + +/*********************************************************************** + */ + +void +getListenSock() +{ + struct sockaddr_in addr; + + if ((listenSock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + syserr(1, "getListenSock", "can't create listen socket. [%s]", + dateTime()); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(port); + { + /* added this so we could handle nuking listen. KAO 3/26/93 */ + int foo = 1; + if (setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, (char *) &foo, + sizeof(foo)) == -1) + { + fprintf(stderr, "Error setting socket options in listen.\n"); + exit(1); + } + } + if (bind(listenSock, (struct sockaddr *) & addr, sizeof(addr)) < 0) + syserr(1, "getListenSock", "can't bind listen socket. [%s]", + dateTime()); + + if (listen(listenSock, 5) != 0) + syserr(1, "getListenSock", "can't listen to socket. [%s]", dateTime()); +} + +/*********************************************************************** + */ + +void +getConnections() +{ + int len, sock, pid, pa; + struct sockaddr_in addr; + struct hostent *he; + char host[100]; + + len = sizeof(addr); + while ((sock = accept(listenSock, (struct sockaddr *) & addr, &len)) < 0) + { + /* if we got interrupted by a dying child, just try again */ + if (errno == EINTR) + continue; + else + syserr(1, "getConnections", + "accept() on listen socket failed. [%s]", dateTime()); + } + + /* get the host name */ + he = gethostbyaddr((char *) &addr.sin_addr.s_addr, + sizeof(addr.sin_addr.s_addr), AF_INET); + if (he != 0) + { + strcpy(host, he->h_name); + pa = *((int *) he->h_addr); + } + else + { + strcpy(host, inet_ntoa(addr.sin_addr)); + pa = (int) addr.sin_addr.s_addr; + } + + if (pa == meta_addr) + metaserverflag = 1; + /* else */ + warnerr(0, "connect: %-33s[%s][%d]", host, dateTime(), metaserverflag); + + /* fork off a server */ + if ((pid = fork()) == 0) + { + char *newargv[10]; + int newargc = 0; + int i; + char *binname; + binname = build_path(ntserv_binary); + dup2(sock, 0); + multClose(0, 1, 2, -1); /* close everything else */ + + newargv[newargc++] = "ntserv"; + if (metaserverflag == 1) + newargv[newargc++] = "-M"; + for (i = 0; i < extraargc; i++) + newargv[newargc++] = extraargs[i]; + newargv[newargc++] = host; + newargv[newargc] = 0; + + execv(binname, newargv); + + syserr(1, "getConnections", + "couldn't execv %s as the server. [%s]", + binname, dateTime()); + exit(1); + } + else if (pid < 0) + syserr(1, "getConnections", "can't fork. [%s]", dateTime()); + + close(sock); + metaserverflag = 0; +} + +/*********************************************************************** + * Adds "var=value" to environment list + */ + +void +set_env(var, value) + char *var, *value; +{ + char *buf; +#if defined(SYSV) || defined(sparc) + buf = malloc(strlen(var) + strlen(value) + 2); + if (!buf) + syserr(1, "set_env", "malloc() failed. [%s]", dateTime()); + + strcpy(buf, var); + strcat(buf, "="); + strcat(buf, value); + + putenv(buf); +#else + /* don't need to malloc space, setenv() does it for us */ + setenv(var, value, 1); +#endif +} + + +/*********************************************************************** + * Returns a string containing the date and time. String area is static + * and reused. + */ + +char * +dateTime() +{ + time_t t; + char *s; + + time(&t); + s = ctime(&t); + s[24] = '\0'; /* wipe-out the newline */ + return s; +} + +/*********************************************************************** + * Handler for SIGTERM. Closes and shutdowns everything. + */ + +void +terminate() +{ + int s; + + fatlerr(1, "terminate", "killed. [%s]", dateTime()); +#ifdef SYSV + s = sysconf(_SC_OPEN_MAX); + if (s < 0) /* value for OPEN_MAX is indeterminate, */ + s = 32; /* so make a guess */ +#else + s = getdtablesize(); +#endif + /* shutdown and close everything */ + for (; s >= 0; s--) + { + shutdown(s, 2); + close(s); + } +} + +/*********************************************************************** + * Waits on zombie children. + */ + +void +reaper() +{ +#ifndef SVR4 + while (wait3(0, WNOHANG, 0) > 0); +#else + while (waitpid(0, 0, WNOHANG) > 0); +#endif /* SVR4 */ +} + +/*********************************************************************** + * Close all file descriptors except the ones specified in the argument list. + * The list of file descriptors is terminated with -1 as the last arg. + */ + +void +multClose(va_alist) va_dcl +{ + va_list args; + int fds[100], nfds, fd, ts, i, j; + + /* get all descriptors to be saved into the array fds */ + va_start(args); + for (nfds = 0; nfds < 99; nfds++) + { + if ((fd = va_arg(args, int)) == -1) + break; + else + fds[nfds] = fd; + } + +#ifdef SYSV + ts = sysconf(_SC_OPEN_MAX); + if (ts < 0) /* value for OPEN_MAX is indeterminate, */ + ts = 32; /* so make a guess */ +#else + ts = getdtablesize(); +#endif + + /* + * close all descriptors, but first check the fds array to see if this one + * is an exception + */ + for (i = 0; i < ts; i++) + { + for (j = 0; j < nfds; j++) + if (i == fds[j]) + break; + if (j == nfds) + close(i); + } +} + +/*********************************************************************** + * Error reporting functions taken from my library. + */ + +extern int sys_nerr; +#ifndef FreeBSD +extern char *sys_errlist[]; +#endif +extern int errno; + +void +syserr(va_alist) va_dcl +{ + va_list args; + int rc; + + va_start(args); + rc = va_arg(args, int); + err(args); + if (errno < sys_nerr) + fprintf(stderr, " system message: %s\n", sys_errlist[errno]); + + exit(rc); +} + +void +warnerr(va_alist) va_dcl +{ + va_list args; + + va_start(args); + err(args); +} + +void +fatlerr(va_alist) va_dcl +{ + va_list args; + int rc; + + va_start(args); + rc = va_arg(args, int); + err(args); + + exit(rc); +} + +void +err(args) + va_list args; +{ + + char *func, *fmt; + + if (program != 0) + fprintf(stderr, "%s", program); + func = va_arg(args, char *); + if (func != 0 && strcmp(func, "") != 0) + fprintf(stderr, "(%s)", func); + fprintf(stderr, ": "); + + fmt = va_arg(args, char *); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + fflush(stderr); +} + +char * +lasterr() +{ + if (errno < sys_nerr) + return sys_errlist[errno]; + else + return "No message text for this error."; +} + +/*---------------------[ prints the usage of listen ]---------------------*/ + +void +printlistenUsage(char name[]) +{ + int x; + char message[][255] = { + "\n\t'%s [options]'\n\n", + "Options:\n", + "\t-h help (this usage message)\n", + "\t-p port other than default port\n", + "\t-k n use n as shared memory key number\n\n", + "Any unrecognized options are passed through to ntserv. For an up\n", + "to date listing of available ntserv options check the binary.\n", + "\nNOTE: in league play you must start up two listen processes, ", + "one for each port.\n\n", + "\0" + }; + + fprintf(stderr, "-- NetrekII (Paradise), %s --\n", PARAVERS); + for (x = 0; *message[x] != '\0'; x++) + fprintf(stderr, message[x], name); + + exit(1); +} + +/*--------------------------[ printlistenUsage ]--------------------------*/ + +/* set the pid logfile (BG) */ +void +print_pid() +{ + char *fname; + FILE *fptr; + + fname = build_path("logs/listen.pid"); + fptr = fopen(fname, "w+"); + fprintf(fptr, "%d", getpid()); + fclose(fptr); +} diff -r cafa94d86546 -r aa38447a4b21 src/main.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,1211 @@ +/*-------------------------------------------------------------------------- +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[] = "@(#)ntserv"; + +#include "config.h" +#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" + +#if 0 +#define D(s) do { s } while(0) +#else +#define D(s) +#endif + + +#if 0 +jmp_buf env; +#endif + +int startTkills, startTlosses, startTarms, startTplanets, startTticks; +char start_login[16]; /* change 1/25/91 TC */ +char start_name[16]; /* change 1/25/91 TC */ +int goAway = 0; /* change 4/14/91 TC */ +int ignored[MAXPLAYER]; /* change 7/24/91 TC */ + +int overload = 0; /* global 7/31/91 TC */ +/* overload indicates a request for a reserved slot */ + +int indie = 0; /* always be indie 8/28/91 TC */ + + +extern void load_time_access(); +void printntservUsage(); +extern pid_t getpid(); +extern int connectToClient(); +extern int checkSocket(); +extern int initClientData(); +extern int socketPause(); +extern int readFromClient(); +extern int checkVersion(); +extern int findslot(); +extern void updateSelf(); +extern void updateShips(); +extern void updatePlanets(); +extern void updateTerrain(); +extern void flushSockBuf(); +extern int getname(); +extern int sendShipCap(); +extern int logEntry(); +extern int getEntry(); +void printStats(); +void exitGame(); +#if defined(sparc) && !defined(SVR4) +int atexitfunc( /* int, caddr_t */ ); +#else +void atexitfunc(); +#endif +extern void (*r_signal()) (); +extern int enter(); +extern int input(); +extern int setitimer(); +extern int pmessage2(); +extern int savestats(); +extern void move_player(); +extern int sendMotdLine(); +extern int time_access(); +void doMotdPics(); +extern int numPlanets(); +extern int sendMotdPic(); +extern int ParseXbmFile(); + +int +main(argc, argv) + int argc; + char **argv; +{ + int intrupt(); + char *getenv(); + int team, s_type; + int pno; + int usage = 0; /* Flag saying tell usage */ + int errorc = 0; /* Error count */ + char *errorv[5]; /* Error Vector (cannot have more than 5) */ + char *name, *ptr; + int reaper(); + int callHost = 0; + long starttime; + enum HomeAway homeaway = NEITHER; + int observer = 0; + + argv0 = argv[0]; + + pno = time(NULL); + + + /* load_time_acess - read in the hours file, Larry's. */ + + load_time_access(); + + name = *argv++; + argc--; + if ((ptr = strrchr(name, '/')) != NULL) + name = ptr + 1; + while (*argv) + { + if (**argv == '-') + ++* argv; + else + break; + + argc--; + ptr = *argv++; + while (*ptr) + { + switch (*ptr) + { + case 'u': /* for old times sake */ + case '-': /* this will help the --help people */ + case 'h': + usage++; + break; + case 'i': + indie++; + break; /* 8/28/91 TC */ + case 'R': + if (getuid() == geteuid()) + overload++; + break; + case 's': + xtrekPort = atoi(*argv); + callHost = 1; + argv++; + argc--; + break; + case 'M': + blk_metaserver = 1; + break; + case 'd': + host = *argv; + argc--; + argv++; + break; + /* netrek league stuff */ + case 'O': + observer = 1; + break; + case 'H': + homeaway = HOME; + break; + case 'A': + homeaway = AWAY; + break; + default: + { + char buffer[100]; + sprintf(buffer, "Unknown option '%c'\n", *ptr); + errorv[errorc++] = buffer; + break; + } + } + if (usage) + break; + ptr++; + } + } + + if (usage || errorc) + { + int x; + char message[][255] = { + "\n\t'%s [options] -s '\n\n", + "Options:\n", + "\t-h Help (this usage message)\n", + "\t-i Team independant\n", + "\t-R Reserved slot\n", + "\t-s Socket number\n", + "\t-M Metaserver\n", + "\t-d Display\n", + "\t-O Observer\n", + "\t-H Home (League Play)\n", + "\t-A Away (League Play)\n", + "\nNOTE: %s is designed to be launched by the startup process\n\n", + "\0" + }; + + fprintf(stderr, "-- NetrekII (Paradise), %s --\n", PARAVERS); + for (x = 0; x < errorc; x++) + fprintf(stderr, "\n%s: %s", argv0, errorv[x]); + for (x = 0; *message[x] != '\0'; x++) + fprintf(stderr, message[x], argv0); + + exit(1); + } + + openmem(1, homeaway != NEITHER); + + /* compatability */ + if (argc > 0) + host = argv[0]; + srand48(getpid() + time((time_t *) 0)); + /* this finds the shared memory information */ + +#if 0 + if (blk_metaserver) + { + FILE *ptr; + char *buf; + buf = build_path("logs/metaserver.log"); + ptr = fopen(buf, "a"); + fprintf(ptr, "Connection from meta-server\n"); + fclose(ptr); + } +#endif + + + me = NULL; /* UDP fix (?) */ + if (callHost) + { + if (!connectToClient(host, xtrekPort)) + { + exit(0); + } + } + else + { + sock = 0; /* Because we were forked by inetd! */ + checkSocket(); + initClientData(); /* "normally" called by connectToClient() */ + } + + starttime = time(NULL); + while (userVersion == 0) + { + /* + * Waiting for user to send his version number. We give him ten seconds + * to do so... + */ + if (starttime + 10 < time(NULL)) + { + exit(1); + } + socketPause(); + readFromClient(); + } + if (!checkVersion()) + exit(1); + + pno = findslot(overload, homeaway); + if (pno < 0) + { + /* print some appropriate message */ + exit(1); + } + +#if defined(sparc) && !defined(SVR4) + on_exit(atexitfunc, (caddr_t) 0); +#else + atexit(atexitfunc); /* register a function to execute at exit */ +#endif + + me = &players[pno]; + me->p_no = pno; + me->p_team = NOBODY; + me->p_stats.st_royal = 0; +#ifdef RC_DISTRESS + me->gen_distress = 0; /* default to RCD off */ +#endif + me->p_ntspid = getpid(); + myship = &me->p_ship; + mystats = &me->p_stats; + lastm = mctl->mc_current; + me->p_lastrefit = -1; + me->p_spyable = 1; + me->p_teamspy = ~0; +#if 0 + me->p_planfrac = 0; /* reset fractional parts */ + me->p_bombfrac = 0; /* reset fractional parts */ +#endif + + /* --------------------------[ CLUECHECK stuff ]-------------------------- */ +#ifdef CLUECHECK1 + me->p_cluedelay = 10; + me->p_cluecountdown = 0; +#endif + +#ifdef CLUECHECK2 + me->p_cluedelay = lrand48() % 1000; /* so it doesn't ask them immediately */ + me->p_cluecountdown = 0; +#endif + /* ----------------------------------------------------------------------- */ + +#ifndef AUTHORIZE + strcpy(RSA_client_type, "server doesn't support RSA"); +#endif + + (void) r_signal(SIGINT, SIG_IGN); + (void) r_signal(SIGCHLD, reaper); + + /* + * We set these so we won't bother updating him on the location of the + * other players in the galaxy which he is not near. There is no real harm + * to doing this, except that he would then get more information than he + * deserves. It is kind of a hack, but should be harmless. + */ + me->p_x = -100000; + me->p_y = -100000; + me->p_homeaway = homeaway; + me->p_observer = observer; + +#if 0 + updateGameparams(); +#endif + + updateSelf(); /* so he gets info on who he is */ + updateShips(); /* put this back so maybe something will work */ + /* with Andy's meta-server */ + + if (!blk_metaserver) + { + updateStatus(); + updatePlanets(); + updateTerrain(); + } +#if 1 + updateGameparams(); +#endif + + flushSockBuf(); + + /* Get login name */ + +#if 0 + if ((pwent = getpwuid(getuid())) != NULL) + (void) strncpy(login, pwent->pw_name, sizeof(login)); + else +#endif + (void) strncpy(login, "Bozo", sizeof(login)); + login[sizeof(login) - 1] = '\0'; + + strcpy(pseudo, "Guest"); + + strcpy(me->p_name, pseudo); + me->p_team = ALLTEAM; + getname(); + if (me->p_stats.st_rank >= NUMRANKS) + me->p_stats.st_rank = NUMRANKS - 1; + if (me->p_stats.st_royal >= NUMROYALRANKS) + me->p_stats.st_royal = NUMROYALRANKS - 1; + strcpy(pseudo, me->p_name); + strcpy(start_name, me->p_name); /* change 1/25/91 TC */ + + sendShipCap(); /* KAO 1/25/93 */ + + keeppeace = (me->p_stats.st_flags & ST_KEEPPEACE) == ST_KEEPPEACE; + + /* + * Set p_hostile to hostile, so if keeppeace is on, the guy starts off + * hating everyone (like a good fighter should) + */ + me->p_hostile = (FED | ROM | KLI | ORI); + s_type = CRUISER; + me->p_planets = 0; + me->p_armsbomb = 0; + me->p_dooshes = 0; + me->p_resbomb = 0; + /* Set up a reasonable default */ + me->p_whydead = KQUIT; + + (void) strncpy(me->p_login, login, sizeof(me->p_login)); + me->p_login[sizeof(me->p_login) - 1] = '\0'; + strcpy(start_login, login); /* change 1/25/91 TC */ + { + int i; + for (i = 0; i < MAXPLAYER; i++) + ignored[i] = 0; + } + + (void) strncpy(me->p_monitor, host, sizeof(me->p_monitor)); + me->p_monitor[sizeof(me->p_monitor) - 1] = '\0'; + + /* assume this is only place p_monitor is set, and mirror accordingly */ + /* 4/13/92 TC */ + (void) strncpy(me->p_full_hostname, host, sizeof(me->p_full_hostname)); + me->p_full_hostname[sizeof(me->p_full_hostname) - 1] = '\0'; + + logEntry(); /* moved down to get login/monitor 2/12/92 + * TMC */ + + me->p_avrt = -1; /* ping stats */ + me->p_stdv = -1; + me->p_pkls = -1; + + startTkills = me->p_stats.st_tkills; + startTlosses = me->p_stats.st_tlosses; + startTarms = me->p_stats.st_tarmsbomb; + startTplanets = me->p_stats.st_tplanets; + startTticks = me->p_stats.st_tticks; + + r_signal(SIGHUP, exitGame); /* allows use of HUP to force a clean exit */ + + + + me->p_status = POUTFIT; + repCount = 0; + + while (1) + { + switch (me->p_status) + { + case POUTFIT: + case PTQUEUE: + /* give the player the motd and find out which team he wants */ + if (me->p_status != PALIVE) + { + me->p_x = -100000; + me->p_y = -100000; + updateSelf(); + updateShips(); + teamPick = -1; + flushSockBuf(); + getEntry(&team, &s_type); + } + if (goAway) + { /* change 4/14/91 TC */ + printStats(); + exit(0); + } + if (team == -1) + { + exitGame(); + } + + if (indie) + team = 4; /* force to independent 8/28/91 TC */ + inputMask = -1; /* Allow all input now */ + enter(team, 0, pno, s_type, -1); + /* for (i = 0; i < NSIG; i++) { r_signal(i, SIG_IGN); } */ + + me->p_status = me->p_observer ? POBSERVE : PALIVE; /* Put player in game */ + me->p_ghostbuster = 0; + break; + case PALIVE: + case PEXPLODE: + case PDEAD: + case POBSERVE: + /* Get input until the player quits or dies */ + + + input(); + break; + default: + if (tmpPick != PATROL) + { + printf("player status = %d. exiting\n", me->p_status); + exitGame(); + } + } + } + + /* NOTREACHED */ + return 1; +} + +extern int setflag(); /* input.c */ + +int interrupting = 0; + +void +stop_interruptor() +{ + struct itimerval udt; + + if (!interrupting) + return; + + r_signal(SIGALRM, SIG_IGN); /* set up signals */ + udt.it_interval.tv_sec = 0; + udt.it_interval.tv_usec = 0; + udt.it_value.tv_sec = 0; + udt.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &udt, 0); + + interrupting = 0; +} + +void +start_interruptor() +{ + struct itimerval udt; + + if (interrupting) + return; + + { + int min_delay = me->p_observer + ? configvals->min_observer_upd_delay + : configvals->min_upd_delay; + + if (timerDelay < min_delay) + timerDelay = min_delay; + } + + r_signal(SIGALRM, SIG_IGN); /* set up signals */ + 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); + + r_signal(SIGALRM, setflag); + + interrupting = 1; +} + +#if 0 + +/* + * this is TOTALLY untested. It probably doesn't belong in this file, + * either. When I figure out all the mechanisms, this will replace the while + * loop in main(). RF + */ + +void +inputloop() +{ + static int switching = -1; /* is the player changing teams? */ + + int status = me->p_status; + + while (1) + { + switch (status) + { + case PFREE: + status = me->p_status = PDEAD; + me->p_explode = 600; + stop_interruptor(); + break; + + case POUTFIT: + case PTQUEUE: + updateSelf(); + updateShips(); + sendMaskPacket(tournamentMask(me->p_team)); + briefUpdateClient(); + teamPick = -1; + socketPause(); + break; + + case PEXPLODE: + case PDEAD: + inputMask = 0; + case PALIVE: + socketWait(); + delay_interrupt(); /* don't let client read be interrupted by + * the interval timer */ + /* + * ^-- won't work.. delay_interrupt doesn't stop ALRMs from happening + * (HAK 9/21) + */ + break; + } + + /* me->p_status could change in here. */ + readFromClient(); + + if (isClientDead()) + { + if (!reconnect()) + { + /* me->p_status=PFREE; should this be done? RF */ + exit(0); + } + } + switch (status) + { + case POUTFIT: + case PTQUEUE: + if (teamPick == -1) + break; + + if (teamPick < 0 || teamPick > 3 /* XXX */ ) + { + warning("That is not a valid team."); + sendPickokPacket(0); + } + else if (!(tournamentMask(me->p_team) & (1 << teamPick))) + { + warning("I cannot allow that. Pick another team"); + sendPickokPacket(0); + } + else if (((1 << teamPick) != me->p_team) && + (me->p_team != ALLTEAM) && + switching != teamPick && + me->p_whydead != KGENOCIDE) + { /* switching teams */ + switching = teamPick; + warning("Please confirm change of teams. Select the new team again."); + sendPickokPacket(0); + } + else if (shipPick < 0 || shipPick >= NUM_TYPES) + { + /* His team choice is ok. */ + warning("That is an illegal ship type. Try again."); + sendPickokPacket(0); + } + else if (!allowed_ship(1 << teamPick, mystats->st_rank, mystats->st_royal, shipPick)) + { + sendPickokPacket(0); + } + else + { + + if (goAway) + { /* what does this do ? */ + printStats(); + exit(0); + } + if (indie) + me->p_team = 4; + + inputMask = -1; + + enter(teamPick, 0, me->p_no, shipPick, -1); + + status = me->p_status = me->p_observer ? POBSERVER : PALIVE; + start_interruptor(); /* since we're alive, we need regular + * interrupts now */ + + me->p_ghostbuster = 0; + + repCount = 0; + + } + break; + case PALIVE: + case PEXPLODE: + case PDEAD: + if (0 /* sendflag */ ) + { /* this is still busted, ugh */ + check_authentication(); + if (me->p_status == PFREE) + { + me->p_ghostbuster = 0; + me->p_status = PDEAD; + } + if ((me->p_status == PDEAD || me->p_status == POUTFIT) + && (me->p_ntorp <= 0) + && (me->p_nplasmatorp <= 0)) + { + stop_interruptor(); + death(); + status = POUTFIT; + } + auto_features(); + updateClient(); + + /* sendflag=0; ugh, broke */ + } + reenable_interrupt(); + } + } +} + +#endif + + +void +exitGame() +{ + char buf[80]; + char addrbuf[20]; + + if (me != NULL && me->p_team != ALLTEAM) + { + sprintf(buf, "%s %s (%s) leaving game (%.16s@%.32s)", + ((me->p_stats.st_royal) ? royal[me->p_stats.st_royal].name + : ranks[me->p_stats.st_rank].name), + me->p_name, + twoletters(me), + me->p_login, + me->p_full_hostname + ); + sprintf(addrbuf, " %s->ALL", twoletters(me)); + pmessage2(buf, 0, MALL | MLEAVE, addrbuf, me->p_no); + me->p_stats.st_flags &= ~ST_CYBORG; /* clear this flag 8/27/91 TC */ + savestats(); + printStats(); + } + me->p_status = PFREE; + move_player(me->p_no, -1, -1, 1); + exit(0); +} + +#if defined(sparc) && !defined(SVR4) +int +atexitfunc(status, arg) + int status; + caddr_t arg; +#else +void +atexitfunc() +#endif +{ + me->p_ntspid = 0; + me->p_status = PFREE; +} + +#define PLURAL(n) (((n)==1)?"":"s") + +static char *weapon_types[WP_MAX] = { + "Plasma torpedos", + "Tractors", + "Missiles", + "Fighters", +}; + +void +sendSysDefs() +{ + char buf[200], buf2[200]; + int i; + + sendMotdLine("\t@@@"); + + if (!time_access()) + { + sendMotdLine("** WE ARE CLOSED, CHECK HOURS **"); + sendMotdLine(""); + } + + sendMotdLine("Available ship types:"); + buf[0] = 0; + for (i = 0; i < NUM_TYPES; i++) + { + struct ship *s = &shipvals[i]; + if (!shipsallowed[i]) + continue; + sprintf(buf2, " %c) %s/%c%c", s->s_letter, s->s_name, + s->s_desig1, s->s_desig2); + if (strlen(buf) + strlen(buf2) > 80) + { + sendMotdLine(buf); + strcpy(buf, buf2); + } + else + { + strcat(buf, buf2); + } + } + /* guaranteed to have stuff here */ + sendMotdLine(buf); + sendMotdLine(""); + sendMotdLine( + "SHIP REQUIRED RANK BUILD TIME LIMIT NUM PLYRS NUM PLNTS"); + + for (i = 0; i < NUM_TYPES; i++) + { + struct ship *s = &shipvals[i]; + if (!shipsallowed[i]) + continue; + buf2[0] = 0; + if (s->s_rank > 0 || s->s_timer > 0 || s->s_maxnum < 16 || + s->s_numdefn || s->s_numplan) + { + sprintf(buf2, "%-13s%-16s", s->s_name, + s->s_rank ? ranks[s->s_rank].name : "none"); + if (s->s_timer > 0) + sprintf(buf, "%d minutes", s->s_timer); + else + strcpy(buf, "none"); + sprintf(buf2 + strlen(buf2), "%-14s", buf); + + if (s->s_maxnum < 16) + sprintf(buf, "%d/team", s->s_maxnum); + else + strcpy(buf, "none"); + sprintf(buf2 + strlen(buf2), "%-12s %-3d %-3d", buf, + s->s_numdefn, s->s_numplan); + sendMotdLine(buf2); + } + } + sendMotdLine(""); + + + buf2[0] = 0; + for (i = 0; i < WP_MAX; i++) + { + if (weaponsallowed[i]) + { + if (buf2[0]) + strcat(buf2, ", "); + strcat(buf2, weapon_types[i]); + } + } + sprintf(buf, "Special weapons enabled: %s", buf2[0] ? buf2 : "none"); + sendMotdLine(buf); + + if (weaponsallowed[WP_PLASMA]) + { + sprintf(buf, "You need %.1f kill%s to get plasma torpedos", + configvals->plkills, PLURAL(configvals->plkills)); + sendMotdLine(buf); + } + if (weaponsallowed[WP_MISSILE]) + { + sprintf(buf, "You need %.1f kill%s to get missiles", + configvals->mskills, PLURAL(configvals->mskills)); + sendMotdLine(buf); + } + sendMotdLine(""); + + sprintf(buf, "Tournament mode requires %d player%s per team", + configvals->tournplayers, PLURAL(configvals->tournplayers)); + sendMotdLine(buf); + /* sendMotdLine(""); */ + + /* We don't blab about newturn */ +#if 0 + sendMotdLine(configvals->hiddenenemy ? + "Visibility is restricted during T-mode" : + "Visibility is unlimited all the time"); +#endif + sendMotdLine(configvals->binconfirm ? + "Only authorized binaries are allowed" : + "Non-authorized binaries are detected but not rejected"); + + if (configvals->planetlimittype) + { + sprintf(buf, "Independent planets may be taken if your team has fewer than %d planets", configvals->planetsinplay); + sendMotdLine(buf); + } + else + { + sprintf(buf, "Only %d planets can be in play at once", + configvals->planetsinplay); + sendMotdLine(buf); + } + + if (configvals->planupdspd == 0) + { + sendMotdLine("Planets do not orbit their stars"); + } + else + { + sprintf(buf, "Planets orbit their stars at a rate of %g", + configvals->planupdspd); + sendMotdLine(buf); + } + sendMotdLine(configvals->warpdecel ? + "New warp deceleration code is in effect" : + "Old-style instant warp deceleration is in effect"); + sprintf(buf, "The next galaxy will be generated using method #%d", + configvals->galaxygenerator); + sendMotdLine(buf); + sendMotdLine + (configvals->affect_shiptimers_outside_T ? + "Ship deaths outside tournament mode affect construction timers" : + "Construction timers are not affected by ship deaths outside tournament mode"); + + sprintf(buf, "Cloaking during warp prep is %sallowed", + configvals->cloakduringwarpprep ? "" : "not "); + sendMotdLine(buf); + + sprintf(buf, "Cloaking during warp is %sallowed", + configvals->cloakwhilewarping ? "" : "not "); + sendMotdLine(buf); + + sprintf(buf, "Variable warp speed is %sabled", + configvals->variable_warp ? "en" : "dis"); + sendMotdLine(buf); + + sprintf(buf, "Warp prep suspension is %sallowed", + configvals->warpprep_suspendable ? "" : "not "); + sendMotdLine(buf); + + switch (configvals->warpprepstyle) + { + case WPS_NOTRACT: + sendMotdLine("Tractors do not affect warp prep"); + break; + case WPS_TABORT: + sendMotdLine("Tractors make warp fail to engage"); + break; + case WPS_TPREVENT: + sendMotdLine("Tractors prevent entering warp"); + break; + case WPS_TABORTNOW: + sendMotdLine("Tractors abort warp prep countdown"); + break; + case WPS_TSUSPEND: + sendMotdLine("Tractors suspend warp prep countdown"); + break; + } + + sprintf(buf, "There is a %d%% chance that you'll orbit a planet CCW", + (int) ((1.0 - configvals->orbitdirprob) * 100)); + sendMotdLine(buf); + + sprintf(buf, "Army growth: %d. Pop choice: %d. Pop speed: %d%%.", + configvals->popscheme, configvals->popchoice, configvals->popspeed); + sendMotdLine(buf); + + if (configvals->warpzone) + { + sprintf(buf, "Warp zones are enabled with radius %d.", + configvals->warpzone); + } + else + { + sprintf(buf, "Warp zones are disabled."); + } + sendMotdLine(buf); +} + +void +sendMotd() +{ + FILE *motd; + char buf[100], buf2[30]; /* big enough... */ + char *paths; + + time_t curtime; + struct tm *tmstruct; + int hour, tacc; + + time(&curtime); + tmstruct = localtime(&curtime); + if (!(hour = tmstruct->tm_hour % 12)) + hour = 12; + sprintf(buf, "Netrek II (Paradise) server %s, connection established at %d:%02d%s.", + PARAVERS, + hour, + tmstruct->tm_min, + tmstruct->tm_hour >= 12 ? "pm" : "am"); + + /* + * if (!(tacc = time_access())) strcat(buf, " WE'RE CLOSED, CHECK HOURS"); + */ + sendMotdLine(buf); + sendMotdLine(" "); + + if (!blk_flag) + { + paths = build_path(WCMOTD); /* Wrong client message */ + if ((motd = fopen(paths, "r")) != NULL) + { + while (fgets(buf, sizeof(buf), motd) != NULL) + { + buf[strlen(buf) - 1] = '\0'; + sendMotdLine(buf); + } + fclose(motd); + } + else + { /* default message */ + sendMotdLine(" "); + sendMotdLine( + " ****************************************************************"); + sendMotdLine(" "); + + sendMotdLine( + " This is a Paradise server; you need a Paradise client to play!"); + sendMotdLine(" "); + sendMotdLine( + " Paradise clients can be had from"); + sendMotdLine( + " ftp.cis.ufl.edu pub/netrek.paradise/"); + sendMotdLine( + " ftp.reed.edu mirrors/netrek.paradise/"); + sendMotdLine(" "); + sendMotdLine( + " ****************************************************************"); + } + return; + } + + /* if (blk_flag) */ + { /* added 1/19/93 KAO */ + int i, first = 1; + + strcpy(buf, "BLK: REFIT "); + + for (i = 0; i < NUM_TYPES; i++) + { + struct ship *s = &shipvals[i]; + if (!shipsallowed[i]) + continue; + + if (!first) + strcat(buf, ", "); + else + first = 0; + + sprintf(buf2, "%c) %c%c", s->s_letter, s->s_desig1, s->s_desig2); + strcat(buf, buf2); + } + sendMotdLine(buf); + } + /* the following will read a motd */ + if (!time_access()) + { + paths = build_path(CLOSEDMOTD); + if ((motd = fopen(paths, "r")) == NULL) + { + paths = build_path(MOTD); + motd = fopen(paths, "r"); + } + } + else + { + paths = build_path(MOTD); + motd = fopen(paths, "r"); + } + if (motd != NULL) + { +#ifdef CLUECHECK1 + init_motdbuf(paths); +#endif + while (fgets(buf, sizeof(buf), motd) != NULL) + { + buf[strlen(buf) - 1] = '\0'; + sendMotdLine(buf); + } + (void) fclose(motd); + } + sendSysDefs(); + + /* wait till the end for the pictures */ + if (!blk_metaserver) + doMotdPics(); +} + +int +reaper(sig) + int sig; +{ +#ifndef SVR4 + while (wait3((union wait *) 0, WNOHANG, (struct rusage *) 0) > 0); +#else + while (waitpid(0, NULL, WNOHANG) > 0); +#endif /* SVR4 */ + return 0; +} + +void +printStats() +{ + FILE *logfile; +#if defined(SVR4) || defined(sparc) + time_t curtime; +#else + int curtime; +#endif /* SVR4 */ + char *paths; /* added 1/18/93 KAO */ + + paths = build_path(LOGFILENAME); + logfile = fopen(paths, "a"); + if (!logfile) + return; + curtime = time(NULL); + +#ifdef LOG_LONG_INFO /*-[ Long info printed to logfiles and startup.log ]-*/ + fprintf(logfile, "Leaving: %-16s (%s) %3dP %3dA %3dW/%3dL %3dmin %drtt %dsdv %dls %dplan <%s@%s> %s", + me->p_name, + twoletters(me), + me->p_stats.st_tplanets - startTplanets, + me->p_stats.st_tarmsbomb - startTarms, + me->p_stats.st_tkills - startTkills, + me->p_stats.st_tlosses - startTlosses, + (me->p_stats.st_tticks - startTticks) / 600, + me->p_avrt, me->p_stdv, me->p_pkls, + numPlanets(me->p_team), + +#else + + fprintf(logfile, "Leaving: %s <%s@%s> %s", + me->p_name, +#endif + me->p_login, + me->p_full_hostname, + ctime(&curtime)); + + /* #endif /*-[ LOG_LONG_INFO ]- */ + + if (goAway) + fprintf(logfile, "^^^ 2 players/1 slot. was %s (%s)\n", + start_name, start_login); + fclose(logfile); +} + + +/* + * .pics file format: + * + * name x y page name x y page etc + */ + +void +doMotdPics() +{ + FILE *ptr, *ftemp; + char buf[128], fname[128]; + unsigned char *bits; + char *result; + int x, y, page, w, h; + int bytesperline; /* pad the width to a byte */ + int linesperblock; /* how many lines in 1016 bytes? */ + int i; + char *paths; + + paths = build_path(PICS); + ptr = fopen(paths, "r"); + if (ptr == NULL) + return; + while (1) + { + result = fgets(fname, 125, ptr); + if (result == NULL) + /* must fclose ptr */ + break; + + if (fname[strlen(fname) - 1] == '\n') + fname[strlen(fname) - 1] = 0; + + paths = build_path(fname); + ftemp = fopen(paths, "r"); + bits = 0; + if (ftemp == 0) + { + fprintf(stderr, "ntserv: couldn't open file %s. skipping\n", paths); + } + else + { + ParseXbmFile(ftemp, &w, &h, &bits); /* parsexbm.c */ + + bytesperline = (w - 1) / 8 + 1; + linesperblock = 1016 /* packets.h */ / bytesperline; + } + + fgets(buf, 125, ptr); + + if (3 != sscanf(buf, "%d %d %d", &x, &y, &page)) + { + printf("Format error in .pics file\n"); + if (bits) + free(bits); + bits = NULL; + } + + if (bits) + { + if (me != 0 && (me->p_stats.st_flags & ST_NOBITMAPS)) + { + sendMotdNopic(x, y, page, w, h); + } + else + for (i = 0; i * linesperblock < h; i++) + { + int nlines; + if ((i + 1) * linesperblock > h) + nlines = h - i * linesperblock; + else + nlines = linesperblock; +#if 0 + printf("Sending MotdPics: %s %d %d %d %d %d\n", + fname, x, y + i * linesperblock, page, w, nlines); +#endif + sendMotdPic(x, y + i * linesperblock, + bits + bytesperline * linesperblock * i, + page, w, nlines); + } + free(bits); + } + } + fclose(ptr); +} + + +#undef D diff -r cafa94d86546 -r aa38447a4b21 src/mes Binary file src/mes has changed diff -r cafa94d86546 -r aa38447a4b21 src/message.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/message.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,2513 @@ +/*-------------------------------------------------------------------------- +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 +--------------------------------------------------------------------------*/ + +/* was control_mess.c, but changed to message.c for a smaller filename (BG) */ + +/* + * Ugh, this code is in the middle of a rewrite. + * + * It used to use a tokenizer with a global dictionary to split the input into + * words. The tokenizer accepted abbreviations as long as these were unique. + * However, adding a new word to the dictionary would often cause old + * abbreviations to be invalidated. + * + * I wrote a new parser that was called as each token needed to be extracted. + * This used a dictionary that was local to each submenu. This localizes + * changes to the menu structure so that effects of adding new commands are + * minimized. + * + * Some of the file is converted to use this, but not all. Eventually the + * entire module will use the context-sensitive tokenizer. + * + */ + + +#include "config.h" +#include +#include +#include +#include +#include + +#include "defs.h" +#include "data.h" +#include "struct.h" +#include "shmem.h" + +enum token_names_e +{ + HELPTOK = 128, + CONTROLTOK, + VERSIONTOK, + QUEUETOK, + LEAGUETOK, + PARAMTOK, + INFOTOK, + OBSERVETOK, + CLUECHECKTOK, + + NUKEGAMETOK, + FREESLOTTOK, + ROBOTTOK, + TOURNTOK, + NEWGALAXY, + SHIPTIMERTOK, + + REFITTOK, + PLAYERTOK, + EJECTTOK, + DIETOK, + ARMIESTOK, + PLASMATOK, + MISSILETOK, + PLANETTOK, + RANKTOK, + MOVETOK, + + PASSWDTOK, + RATINGSTOK, + + TIMETOK, + CAPTAINTOK, + RESTARTTOK, + STARTTOK, + PASSTOK, + TIMEOUTTOK, + TEAMNAMETOK, + AWAYTOK, + HOMETOK, + PAUSETOK, + CONTINUETOK, + MAXPLAYERTOK, + + TEAMTOK, + + INDTOK, /* these need to be adjacent and in order */ + FEDTOK, /* these need to be adjacent and in order */ + ROMTOK, /* these need to be adjacent and in order */ + KLITOK, /* these need to be adjacent and in order */ + ORITOK, /* these need to be adjacent and in order */ + + SHIPTOK, + + SCOUTTOK, /* these need to be adjacent and in order */ + DESTROYERTOK, /* these need to be adjacent and in order */ + CRUISERTOK, /* these need to be adjacent and in order */ + BATTLESHIPTOK, /* these need to be adjacent and in order */ + ASSAULTTOK, /* these need to be adjacent and in order */ + STARBASETOK, /* these need to be adjacent and in order */ + ATTTOK, /* these need to be adjacent and in order */ + JUMPSHIPTOK, /* these need to be adjacent and in order */ + FRIGATETOK, /* these need to be adjacent and in order */ + WARBASETOK, /* these need to be adjacent and in order */ + LIGHTCRUISERTOK, + CARRIERTOK, + UTILITYTOK, + PATROLTOK, + + PLUSTOK, + MINUSTOK, + ROYALTOK, + QUIETTOK, + KILLSTOK, + HOSETOK, + SUPERTOK, + ALLOWTOK, /* control allow [teams] */ + + ERRORTOK = 255 +}; + +#ifdef GOD_CONTROLS +static int god_silent = 0; +#endif + +/* static char *con_shipnos = "0123456789abcdefghijklmnopqrstuvwxyz"; */ + +extern int pmessage2(); +extern int pmessage(); +#ifndef linux +extern int atoi(); +#endif /* linux */ +extern int detourneyqueue(); +extern void compute_ratings(); + +static void respond(); + +#if 0 +static enum token_names_e tokstring[128]; /* list of tokens */ +static char *thestrings[128]; /* list of corresponding strings */ +static char *therest[128]; /* list of pointers to the original text + * starting with token i */ +static int sizetokstring; + +struct token +{ + char string[32]; + int token; +}; + + + +struct token tstrings[] = { + {"0", 0}, {"1", 1}, {"2", 2}, {"3", 3}, + {"4", 4}, {"5", 5}, {"6", 6}, {"7", 7}, + {"8", 8}, {"9", 9}, {"a", 10}, {"b", 11}, + {"c", 12}, {"d", 13}, {"e", 14}, {"f", 15}, + {"g", 16}, {"h", 17}, {"i", 18}, {"j", 19}, + {"k", 20}, {"l", 21}, {"m", 22}, {"n", 23}, + {"o", 24}, {"p", 25}, {"q", 26}, {"r", 27}, + {"s", 28}, {"t", 29}, {"u", 30}, {"v", 31}, + {"w", 32}, {"x", 33}, {"y", 34}, {"z", 35}, + {"help", HELPTOK}, + {"control", CONTROLTOK}, + {"con", CONTROLTOK}, /* popular abbrev */ + {"version", VERSIONTOK}, + {"tq", QUEUETOK}, /* popular abbrev */ + {"queue", QUEUETOK}, + {"league", LEAGUETOK}, + {"params", PARAMTOK}, + {"observe", OBSERVETOK}, + {"info", INFOTOK}, + {"cluecheck", CLUECHECKTOK}, + + {"shiptimers", SHIPTIMERTOK}, + + {"refit", REFITTOK}, + {"player", PLAYERTOK}, + {"pl", PLAYERTOK}, /* popular abbrev */ + {"planet", PLANETTOK}, + {"eject", EJECTTOK}, + {"die", DIETOK}, + {"rank", RANKTOK}, + {"royalty", ROYALTOK}, + {"move", MOVETOK}, + {"armies", ARMIESTOK}, + {"plasma", PLASMATOK}, + {"missile", MISSILETOK}, + {"team", TEAMTOK}, + {"ship", SHIPTOK}, + {"quiet", QUIETTOK}, + {"kills", KILLSTOK}, + {"hose", HOSETOK}, + {"super", SUPERTOK}, + {"allow", ALLOWTOK}, + {"+", PLUSTOK}, + {"-", MINUSTOK}, + + {"robot", ROBOTTOK}, + {"nukegame", NUKEGAMETOK}, + {"freeslot", FREESLOTTOK}, + {"tourn", TOURNTOK}, + {"galaxy", NEWGALAXY}, + + /* player commands */ + {"password", PASSWDTOK}, + {"ratings", RATINGSTOK}, + + /* league commands */ + {"time", TIMETOK}, + {"captain", CAPTAINTOK}, + {"restart", RESTARTTOK}, + {"start", STARTTOK}, + {"pass", PASSTOK}, + {"timeout", TIMEOUTTOK}, + {"teamname", TEAMNAMETOK}, + {"away", AWAYTOK}, + {"home", HOMETOK}, + {"pause", PAUSETOK}, + {"continue", CONTINUETOK}, + {"maxplayers", MAXPLAYERTOK}, + + {"independent", INDTOK}, + {"federation", FEDTOK}, {"romulan", ROMTOK}, + {"klingon", KLITOK}, {"orion", ORITOK}, + + {"sc", SCOUTTOK}, {"dd", DESTROYERTOK}, + {"ca", CRUISERTOK}, {"bb", BATTLESHIPTOK}, + {"as", ASSAULTTOK}, {"sb", STARBASETOK}, + {"at", ATTTOK}, {"js", JUMPSHIPTOK}, + {"fr", FRIGATETOK}, {"wb", WARBASETOK}, + {"cl", LIGHTCRUISERTOK}, {"cv", CARRIERTOK}, + {"ut", UTILITYTOK}, {"pt", PATROLTOK}, + + {"", ERRORTOK} /* I'm last. Keep it that way. */ +}; + +static void +dotokenize(input) + char *input; +{ + char *temp0, *temp1; + int done = 0; + static char internal[120]; + + sizetokstring = 0; + + /* Convert string to lowercase. */ + + temp0 = strcpy(internal, input); + while (*temp0 != '\0') + { + if (isupper(*temp0)) + *temp0 = tolower(*temp0); + temp0++; + } + + + temp0 = internal; + + while (done == 0) + { + struct token *tptr; + int wordlen; + int potentialtok, ambiguous; + + /* Eat leading spaces. */ + + while (*temp0 == ' ') + temp0++; + + /* Find the next word and chop the rest of the string away. */ + + temp1 = temp0; + therest[sizetokstring] = input + (temp1 - internal); + while (*temp1 != '\0' && *temp1 != ' ') + temp1++; + if (*temp1 != '\0') + *temp1++ = '\0'; + wordlen = strlen(temp0); + + /* Go find out what they've typed. */ + + tptr = tstrings; + potentialtok = ERRORTOK; + ambiguous = 0; + while (tptr->token != ERRORTOK) + { + if (0 == strncmp(temp0, tptr->string, wordlen)) + { + if (strlen(tptr->string) == wordlen) + { + ambiguous = 0; + potentialtok = tptr->token; + break; /* exact match */ + } + if (potentialtok != ERRORTOK) + { + ambiguous = 1; /* this isn't the only match */ + } + potentialtok = tptr->token; + } + tptr++; + } + + thestrings[sizetokstring] = temp0; + tokstring[sizetokstring++] = ambiguous ? ERRORTOK : potentialtok; + temp0 = temp1; + + /* If *temp0 == 0 then we're done. */ + + if (*temp0 == '\0') + done = 1; + } + thestrings[sizetokstring] = 0; +} +#endif + +/**********************************************************************/ + +/* New parsing method. */ + +struct control_cmd +{ + char *literal; /* the command they should type */ + enum token_names_e tok; /* what the parser should return */ + char *doc; /* documentation to print for a help command */ +}; + +/* + * Scans the string cmd for the first whitespace delimited string. Tries to + * match this string in a case-insensitive manner against the list in legals. + * Returns the appropriate token. Alters the char* pointed to by after to be + * the beginning of the next whitespace-delimited string. + * + * cmd: unmodified legals: unmodified after: MODIFIED + * + */ + +enum token_names_e +next_token(cmd, legals, after) + char *cmd; + struct control_cmd *legals; + char **after; +{ + char buf[80]; /* space for the token */ + char *s; + int i; + int ambiguous = 0; + enum token_names_e potentialtok = ERRORTOK; + + while (*cmd && isspace(*cmd)) + cmd++; + + if (!*cmd) + return ERRORTOK; + + for (s = buf; *cmd && !isspace(*cmd); s++, cmd++) + *s = *cmd; + *s = 0; + + while (*cmd && isspace(*cmd)) + cmd++; + + if (after) + *after = cmd; /* so they can find the next token */ + + for (i = 0; legals[i].literal; i++) + { + int wordlen = strlen(buf); + if (0 == strncasecmp(buf, legals[i].literal, wordlen)) + { + if (strlen(legals[i].literal) == wordlen) + { + ambiguous = 0; + potentialtok = legals[i].tok; + break; /* exact match */ + } + if (potentialtok != ERRORTOK) + { + ambiguous = 1; /* this isn't the only match */ + return ERRORTOK; + } + potentialtok = legals[i].tok; + } + } + + return potentialtok; +} + +int +match_token(cmd, token, after) + char *cmd; + char *token; + char **after; +{ + struct control_cmd legals[2]; + legals[0].literal = token; + legals[0].tok = HELPTOK; /* pick any token but ERRORTOK */ + legals[1].literal = 0; + return HELPTOK == next_token(cmd, legals, after); +} + +/* + * Get a player slot number. Returns -1 on failure, slot number on success. + * Slot number is guaranteed to be = '0' && *cmd <= '9') + rval = *cmd - '0'; + else if (*cmd >= 'a' && *cmd <= 'z') + rval = *cmd - 'a' + 10; + else if (*cmd >= 'A' && *cmd <= 'Z') + rval = *cmd - 'A' + 10; + else + return -1; + + if (rval >= MAXPLAYER) + return -1; /* there aren't that many players */ + + if (after) + { + /* scan to next token */ + cmd++; + while (*cmd && isspace(*cmd)) + cmd++; + *after = cmd; + } + + return rval; +} + +void +bad_slotnum(msg) + char *msg; +{ + char buf[256]; + sprintf(buf, "`%s' requires player slot number", msg); + respond(buf, 1); +} + + +/* + * Get a single token. Returns 0 on failure, 1 on success. Token is returned + * in dst. + */ + +int +get_one_token(cmd, dst, dstsize, after) + char *cmd; + char *dst; /* destination */ + int dstsize; + char **after; +{ + while (*cmd && isspace(*cmd)) + cmd++; + + if (!*cmd) + return 0; /* no token */ + + while (dstsize > 1 && *cmd && !isspace(*cmd)) + { + *(dst++) = *(cmd++); + dstsize--; + } + *dst = 0; + + if (after) + { + /* scan to next token */ + while (*cmd && isspace(*cmd)) + cmd++; + *after = cmd; + } + + return 1; +} + +/* + * Get an integer Integer is returned in dst. Returns 0 on failure without + * modifying dst. + */ + +int +get_int(cmd, dst, after) + char *cmd; + int *dst; + char **after; +{ + int rval, offset; + + if (1 != sscanf(cmd, " %i%n", &rval, &offset)) + return 0; + + cmd += offset; + if (*cmd && !isspace(*cmd)) + return 0; /* token wasn't all digits */ + + *dst = rval; + + if (after) + { + /* scan to next token */ + while (*cmd && isspace(*cmd)) + cmd++; + *after = cmd; + } + + return 1; +} + +/* + * Get a double Double is returned in dst. Returns 0 on failure without + * modifying dst. + */ + +int +get_double(cmd, dst, after) + char *cmd; + double *dst; + char **after; +{ + double rval; + int offset; + + if (1 != sscanf(cmd, " %lg%n", &rval, &offset)) + return 0; + + cmd += offset; + if (*cmd && !isspace(*cmd)) + return 0; /* token wasn't all digits */ + + *dst = rval; + + if (after) + { + /* scan to next token */ + while (*cmd && isspace(*cmd)) + cmd++; + *after = cmd; + } + + return 1; +} + +int +get_teamid(cmd, team, after) + char *cmd; + int *team; + char **after; +{ + int i, j; + + while (*cmd && isspace(*cmd)) + { + cmd++; + } + if (cmd[3] && !isspace(cmd[3])) + return 0; /* too long */ + + *team = NOBODY; + + for (i = -1; i < NUMTEAM; i++) + { + j = idx_to_mask(i); + if (0 == strncasecmp(cmd, teams[j].shortname, 3)) + { + *team = i; + cmd += 3; + break; + } + } + + if (after) + { + /* scan to next token */ + while (*cmd && isspace(*cmd)) + cmd++; + *after = cmd; + } + + return i < NUMTEAM; +} + +int +get_shipid(cmd, shipn, after) + char *cmd; + int *shipn; + char **after; +{ + int i; + + while (*cmd && isspace(*cmd)) + { + cmd++; + } + *shipn = -1; + + for (i = 0; i < NUM_TYPES; i++) + { + struct ship *ship = &shipvals[i]; + int len; + len = strlen(ship->s_name); + if (0 == strncasecmp(cmd, ship->s_name, len) && + (cmd[len] == 0 || isspace(cmd[len]))) + { + *shipn = i; + cmd += len; + break; + } + else if (tolower(cmd[0]) == tolower(ship->s_desig1) && + tolower(cmd[1]) == tolower(ship->s_desig2) && + (cmd[2] == 0 || isspace(cmd[2]))) + { + *shipn = i; + cmd += 2; + break; + } + } + + if (after) + { + /* scan to next token */ + while (*cmd && isspace(*cmd)) + cmd++; + *after = cmd; + } + + return i < NUM_TYPES; +} + +/* writes a comma-separated list of help strings into the message window */ + +void +respond_with_help_string(legals) + struct control_cmd *legals; +{ + int i; + char buf[65]; /* leave space for the message prefix */ + + strcpy(buf, "Available commands: "); + for (i = 0; legals[i].literal; i++) + { + if (!(legals[i].doc && legals[i].doc[0])) + continue; + if (strlen(buf) + 3 + strlen(legals[i].doc) > sizeof(buf)) + { + respond(buf, 0); + strcpy(buf, " "); + if (!buf[0]) + { /* one of the help strings was just too long */ + respond("ACK! programmer error: help string too long", 0); + return; + } + i--; /* retry */ + continue; + } + strcat(buf, legals[i].doc); + if (legals[i + 1].literal) + strcat(buf, ", "); + } + if (buf[0]) + respond(buf, 0); +} + +/**********************************************************************/ + +static void +respond(msg, type) + char *msg; + int type; +{ + if (type == 1) + warning(msg); + else + pmessage2(msg, me->p_no, MINDIV, MCONTROL, 255); +} + +#ifdef GOD_CONTROLS + +/* + * Here we handle the controls on players. If you add something, make sure + * you place it in the help. Thanks, have a nice day. + */ + +static int +parse_control_player(cmd) + char *cmd; +{ + char buf[120]; + int pnum; + struct player *victim; + int godliness = me->p_stats.st_royal - GODLIKE + 1; + char *arg; + static struct control_cmd available_cmds[] = { + {"help", HELPTOK, 0}, + {"die", DIETOK, "die"}, + {"eject", EJECTTOK, "eject"}, + {"armies", ARMIESTOK, "armies [%d=5]"}, + {"plasma", PLASMATOK, "plasma [%d]"}, + {"missiles", MISSILETOK, "missiles [%d=max]"}, + {"team", TEAMTOK, "team "}, + {"ship", SHIPTOK, "ship "}, + {"rank", RANKTOK, "rank (+|-|%d)"}, + {"royal", ROYALTOK, "royal (+|-|%d)"}, + {"kills", KILLSTOK, "kills (+|-|%d)"}, + {"hose", HOSETOK, "hose"}, + {"move", MOVETOK, "move %d %d"}, + {0} + }; + + pnum = get_slotnum(cmd, &cmd); + if (pnum < 0) + { + bad_slotnum("control player"); + return 0; + } + victim = &players[pnum]; + + if (victim->p_status == PFREE) + { + respond("Slot is not alive.", 1); + return 1; + } + + /* + * These would probably work better as pointers to functions instead of a + * giant switch, but what the hell, I'm lazy. Maybe I'll change it later. + */ + + switch (next_token(cmd, available_cmds, &arg)) + { + case DIETOK: + victim->p_ship.s_type = STARBASE; + victim->p_whydead = KPROVIDENCE; + victim->p_explode = 10; + victim->p_status = PEXPLODE; + victim->p_whodead = 0; + if (!god_silent) + { + sprintf(buf, "%s (%2s) was utterly obliterated by %s (%2s).", + victim->p_name, twoletters(victim), + me->p_name, twoletters(me)); + pmessage(buf, 0, MALL, MCONTROL); + } + return 1; + + case EJECTTOK: + victim->p_ship.s_type = STARBASE; + victim->p_whydead = KQUIT; + victim->p_explode = 10; + victim->p_status = PEXPLODE; + victim->p_whodead = 0; + if (!god_silent) + { + sprintf(buf, + "%s (%2s) has been ejected from the game by %s (%2s).", + victim->p_name, twoletters(victim), + me->p_name, twoletters(me)); + pmessage(buf, 0, MALL, MCONTROL); + } + return 1; + + case ARMIESTOK: + { + int armies = 5; + if (*arg && !get_int(arg, &armies, (char **) 0)) + { + respond("optional arg to `control player armies` must be integer", 0); + return 0; + } + victim->p_armies += armies; + if (!god_silent) + { + sprintf(buf, "%s (%2s) has been given %d armies by %s (%2s).", + victim->p_name, twoletters(victim), armies, + me->p_name, twoletters(me)); + pmessage(buf, 0, MALL, MCONTROL); + } + return 1; + } + + case PLASMATOK: + { + int yes = 1; + if (*arg && !get_int(arg, &yes, (char **) 0)) + { + respond("optional arg to `control player plasma` must be integer", 0); + return 0; + } + + if (yes) + victim->p_ship.s_nflags |= SFNPLASMAARMED; + else + victim->p_ship.s_nflags &= ~SFNPLASMAARMED; + + if (!god_silent) + { + sprintf(buf, "%s (%2s) has been %s plasma torps by %s (%2s).", + victim->p_name, twoletters(victim), + yes ? "given" : "denied", + me->p_name, twoletters(me)); + pmessage(buf, 0, MALL, MCONTROL); + } + return 1; + } + + case MISSILETOK: + { + int yes = shipvals[victim->p_ship.s_type].s_missilestored; + + if (*arg && !get_int(arg, &yes, (char **) 0)) + { + respond("optional arg to `control player missile` must be integer", 0); + return 0; + } + + if (yes) + { + victim->p_ship.s_nflags |= SFNHASMISSILE; + victim->p_ship.s_missilestored = yes; + } + else + { + victim->p_ship.s_nflags &= ~SFNHASMISSILE; + } + + if (!god_silent) + { + sprintf(buf, "%s (%2s) has been %s %d missiles by %s (%2s).", + victim->p_name, twoletters(victim), + yes ? "given" : "denied", + yes, me->p_name, twoletters(me)); + pmessage(buf, 0, MALL, MCONTROL); + } + return 1; + } + + case TEAMTOK: + { + int team; + + if (!get_teamid(arg, &team, (char **) 0)) + { + respond("available teams: FED ORI ROM KLI IND", 0); + return 0; + } + team = idx_to_mask(team); + + victim->p_hostile |= victim->p_team; + victim->p_team = team; + victim->p_hostile &= ~team; + victim->p_swar &= ~team; + sprintf(buf, "%s (%2s) has been changed to a %s by %s (%2s).", + victim->p_name, twoletters(victim), teams[team].nickname, + me->p_name, twoletters(me)); + if (!god_silent) + pmessage(buf, 0, MALL, MCONTROL); + return 1; + } + + case SHIPTOK: + { + int ship; + if (!get_shipid(arg, &ship, (char **) 0)) + { + respond("available ships: SC DD CA AS BB SB AT JS FR WB CL CV SUPER", 0); + return 0; + } +#if 0 + if (tokstring[4] == SUPERTOK) + { + victim->p_ship.s_maxshield = 750; + victim->p_shield = 750; + victim->p_ship.s_maxdamage = 750; + victim->p_ship.s_maxegntemp = 5000; + sprintf(buf, "%s (%2s) has been supercharged by %s (%2s).", + victim->p_name, twoletters(victim), + me->p_name, twoletters(me)); + if (!god_silent) + pmessage(buf, 0, MALL, MCONTROL); + return 1; + } +#endif + /* If others are docked, then kick them off */ + if (allows_docking(victim->p_ship)) + { + int i; + for (i = 0; i < victim->p_ship.s_numports; i++) + { + base_undock(victim, i); + } + } + get_ship_for_player(victim, ship); + switch_special_weapon(); + victim->p_flags &= ~PFENG; + sprintf(buf, "%s (%2s) has been changed to a %c%c by %s (%2s).", + victim->p_name, twoletters(victim), + victim->p_ship.s_desig1, victim->p_ship.s_desig2, + me->p_name, twoletters(me)); + if (!god_silent) + pmessage(buf, 0, MALL, MCONTROL); + return 1; + } + + case RANKTOK: + { + int rank = victim->p_stats.st_rank; + + if (match_token(arg, "+", (char **) 0)) + rank++; + else if (match_token(arg, "-", (char **) 0)) + rank--; + else if (!get_int(arg, &rank, (char **) 0)) + { + respond("Try: control player %d rank [%d]+-", 0); + return 0; + } + + if (rank < 0) + rank = 0; + if (rank >= NUMRANKS) + rank = NUMRANKS - 1; + + victim->p_stats.st_rank = rank; + sprintf(buf, "%s (%2s) has been given a rank of %s by %s (%2s).", + victim->p_name, twoletters(victim), + ranks[victim->p_stats.st_rank].name, + me->p_name, twoletters(me)); + if (!god_silent) + pmessage(buf, 0, MALL, MCONTROL); + return 1; + } + + case ROYALTOK: + { + int rank = victim->p_stats.st_royal; + + if (match_token(arg, "+", (char **) 0)) + rank++; + else if (match_token(arg, "-", (char **) 0)) + rank--; + else if (!get_int(arg, &rank, (char **) 0)) + { + respond("Try: control player %d royal [%d]+-", 0); + return 0; + } + + if (rank < 0) + rank = 0; + if (rank >= NUMROYALRANKS) + rank = NUMROYALRANKS - 1; + + if (rank >= GODLIKE && godliness < 2) + { + respond("You aren't powerful enough to grant godlike royalty.", + 1); + return 1; + } + victim->p_stats.st_royal = rank; + sprintf(buf, "%s (%2s) has been given a rank of %s by %s (%2s).", + victim->p_name, twoletters(victim), + royal[victim->p_stats.st_royal].name, + me->p_name, twoletters(me)); + if (!god_silent) + pmessage(buf, 0, MALL, MCONTROL); + return 1; + } + + case KILLSTOK: + { + double kills = victim->p_kills; + + if (match_token(arg, "+", (char **) 0)) + kills += 1; + else if (match_token(arg, "-", (char **) 0)) + { + kills -= 1; + if (kills < 0) + kills = 0; + } + else if (!get_double(arg, &kills, (char **) 0)) + { + respond("Try: control player %d kills [%f]+-", 0); + return 0; + } + + victim->p_kills = kills; + sprintf(buf, "%s (%2s) has been given %f kills by %s (%2s).", + victim->p_name, twoletters(victim), + kills, me->p_name, twoletters(me)); + if (!god_silent) + pmessage(buf, 0, MALL, MCONTROL); + return 1; + } + + case HOSETOK: + victim->p_shield = 0; + victim->p_damage = victim->p_ship.s_maxdamage / 2; + sprintf(buf, "%s (%2s) has been hosed by %s (%2s).", + victim->p_name, twoletters(victim), + me->p_name, twoletters(me)); + if (!god_silent) + pmessage(buf, 0, MALL, MCONTROL); + return 1; + + case MOVETOK: + { + int x, y; + char *s; + if (!(get_int(arg, &x, &s) && get_int(s, &y, (char **) 0))) + { + respond("Try: control player %d move %d %d", 0); + return 0; + } + + if (x <= 0 || y <= 0 || x >= 200000 || y >= 200000) + { + respond("You want to move him where?", 0); + return 0; + } + victim->p_x = x; + victim->p_y = y; + sprintf(buf, "%s (%2s) has been moved to %d %d by %s (%2s).", + victim->p_name, twoletters(victim), + x, y, + me->p_name, twoletters(me)); + if (!god_silent) + pmessage(buf, 0, MALL, MCONTROL); + return 1; + } + + case HELPTOK: /* fall through */ + default: +#if 1 + respond_with_help_string(available_cmds); +#else + respond("player controls: die, eject, armies [%d], plasma [%d],", 0); + respond("player controls: missile [%d], team [team], ship [ship],", 0); + respond("player controls: rank [%d]+-, royal [%d]+-, kills [%d]+-", 0); + respond("player controls: hose, move %d %d", 0); +#endif + return 0; + } +} + +static int +parse_control(str) + char *str; +{ + char buf[120]; + struct player *victim; + int i; + int godliness = me->p_stats.st_royal - GODLIKE + 1; + + static struct control_cmd available_cmds[] = { + {"help", HELPTOK, 0}, + {"freeslot", FREESLOTTOK, "freeslot %p"}, + {"player", PLAYERTOK, "player ..."}, + {"robot", ROBOTTOK, "robot [args]"}, + {"quiet", QUIETTOK, "quiet"}, + {"nukegame", NUKEGAMETOK, "nukegame"}, + {"restart", RESTARTTOK, "restart"}, + {"galaxy", NEWGALAXY, "galaxy"}, + {"shiptimer", SHIPTIMERTOK, "shiptimer (teamstr|shipstr)*"}, + {"allow", ALLOWTOK, "allow [teams]"}, + {0} + }; + char *nexttoken; + + if (godliness <= 0) + { +#if 0 + respond("Those commands are only available to server gods"); +#endif + return 0; /* "fail" silently. Don't advertise divine + * powers to peasants. */ + } + + + switch (next_token(str, available_cmds, &nexttoken)) + { + case FREESLOTTOK: + { + int slot = get_slotnum(nexttoken, (char **) 0); + if (slot < 0) + { + respond("\"control freeslot\" requires slot number.", 0); + return 1; + } + victim = &players[slot]; + if (victim->p_ntspid) + kill(victim->p_ntspid, SIGHUP); + + victim->p_status = PFREE; + victim->p_ntspid = 0; + + if (!god_silent) + { + sprintf(buf, "Player slot %s has been freed by %s (%2s).", + nexttoken, me->p_name, twoletters(me)); + pmessage(buf, 0, MALL, MCONTROL); + } + } + return 1; + + case ALLOWTOK: + { + int newlock = 0; + int team; + char *s; + if (0 == *nexttoken) + { + newlock = ALLTEAM; + } + else + { + for (s = nexttoken; get_teamid(s, &team, &s);) + { + newlock |= idx_to_mask(team); + } + if (*s) + { + respond("Usage: control allow [fed] [rom] [kli] [ori]", 0); + return 1; + } + } + + status2->nontteamlock = newlock; + strcpy(buf, "Allowed teams now set to:"); + if (status2->nontteamlock == ALLTEAM) + { + strcat(buf, " "); + } + else + { + if (status2->nontteamlock & FED) + strcat(buf, " fed"); + if (status2->nontteamlock & ROM) + strcat(buf, " rom"); + if (status2->nontteamlock & KLI) + strcat(buf, " kli"); + if (status2->nontteamlock & ORI) + strcat(buf, " ori"); + } + respond(buf, 0); + } + return 1; + case PLAYERTOK: + return parse_control_player(nexttoken); + + case ROBOTTOK: + { + int pid; + char *s; + + pid = fork(); + if (pid == 0) + { + char *argv[40]; + argv[0] = build_path(ROBOT); + + s = nexttoken; + for (i = 1; 1; i++) + { + int size = 80; + argv[i] = malloc(size); + if (!get_one_token(s, argv[i], size, &s)) + break; + realloc(argv[i], strlen(argv[i]) + 1); + } + free(argv[i]); + argv[i] = 0; + + execvp(argv[0], argv); + fprintf(stderr, "Ack! Unable to exec %s\n", argv[0]); + exit(1); + } + else if (pid < 0) + { + respond("Unable to fork robot", 0); + } + else + { + sprintf(buf, "Robot forked (pid %d) with arguments %s", + pid, nexttoken); + respond(buf, 1); + } + } + return 1; + + case QUIETTOK: + if (godliness < 2) + { + respond("No sneaking allowed", 0); + return 1; + } + sprintf(buf, "Switching to %s mode.", god_silent ? "loud" : "quiet"); + respond(buf, 0); + god_silent = !god_silent; + return 1; + case NUKEGAMETOK: + warning("Nuking game. Have a nice day."); + if (!god_silent) + { + sprintf(buf, "The game has been nuked by %s (%2s).", + me->p_name, twoletters(me)); + pmessage(buf, 0, MALL, MCONTROL); + } + kill(status->nukegame, 15); + return 1; + case RESTARTTOK: + warning("Attempting daemon restart."); + startdaemon( +#ifdef LEAGUE_SUPPORT + status2->league +#else + 0 +#endif + ,1); + return 1; + case NEWGALAXY: + explode_everyone(KPROVIDENCE, 0); + if (!god_silent) + { + sprintf(buf, "The galaxy has been reset by %s (%2s).", + me->p_name, twoletters(me)); + pmessage(buf, 0, MALL, MCONTROL); + } + status2->newgalaxy = 1; + warning("Creating new galaxy"); + return 1; + case SHIPTIMERTOK: + { + int teammask = 0; + int shipmask = 0; + int i, j; + char *s = nexttoken; + while (1) + { + if (get_shipid(s, &j, &s)) + shipmask |= 1 << j; + else if (get_teamid(s, &j, &s)) + teammask |= idx_to_mask(j); + else if (*s) + { + respond("Usage:", 0); + respond("control shiptimers (fed|rom|kli|ori)* (sc|dd|ca|bb|as|sb|at|js|fr|wb)*", 0); + respond(" resets the ship timers.", 0); + return 0; + } + else + break; + } + for (i = 0; i < NUMTEAM; i++) + { + int teammask = idx_to_mask(i); + if (teammask && !(teammask & (1 << i))) + continue; + + for (j = 0; j < NUM_TYPES; j++) + { + if (shipmask && !(shipmask & (1 << j))) + continue; + + if (teams[teammask].s_turns[j]) + { + sprintf(buf, "%s %s reset", teams[teammask].name, shipvals[j].s_name); + respond(buf, 0); + teams[teammask].s_turns[j] = 0; + } + } + } + } + return 1; + case HELPTOK: /* fall through */ + default: +#if 1 + respond_with_help_string(available_cmds); +#else + respond("Available controls: player, quiet, nukegame, freeslot,", 0); + respond(" galaxy, restart, shiptimer", 0); +#endif + return 0; + } +} +#endif + +/* + */ + +static int +parse_info(cmd) + char *cmd; +{ + char buf[120]; + char *nexttoken; + + static struct control_cmd available_cmds[] = { + {"help", HELPTOK, 0}, + {"shiptimer", SHIPTIMERTOK, "shiptimer (teamstr|shipstr)*"}, + {0} + }; + + switch (next_token(cmd, available_cmds, &nexttoken)) + { + case SHIPTIMERTOK: + { + int race = 0; + int i, j; + int anydead = 0; +#if 0 + if (me->p_stats.st_royal < 2) + race = me->p_team; +#endif + for (i = 0; i < NUMTEAM; i++) + { + int teammask = idx_to_mask(i); + if (race && !(race & (1 << i))) + continue; + for (j = 0; j < NUM_TYPES; j++) + { + if (teams[teammask].s_turns[j]) + { + sprintf(buf, "%s %s: %d minutes", teams[teammask].name, + shipvals[j].s_name, teams[teammask].s_turns[j]); + anydead = 1; + respond(buf, 0); + } + } + } + if (!anydead) + respond("All ships are available", 0); + } + return 1; + case HELPTOK: + default: + respond("Available subcommands: shiptimer", 0); + return 1; + } +} + +#define crypt(a, b) (a) + +static int +parse_player(cmd) + char *cmd; +{ + static int passver = 0; + char buf[80]; +#if 0 + static char newpass[16]; +#endif + char *nexttoken; + + static struct control_cmd available_cmds[] = { + {"help", HELPTOK, 0}, + {"password", PASSWDTOK, "password %s"}, + {"passwd", PASSWDTOK, 0}, + {"ratings", RATINGSTOK, "ratings"}, + {"rank", RANKTOK, "rank"}, + {0} + }; + + if (0 == *cmd) + { + if (passver) + respond("Password change cancelled.", 0); + + passver = 0; + return 1; + } + + switch (next_token(cmd, available_cmds, &nexttoken)) + { + case PASSWDTOK: + { + static char newpass[16]; + if (me->p_pos < 0) + { /* guest login */ + respond("You don't have a password!", 0); + } + else if (*nexttoken == 0) + { + respond("\"player password\" requires new password as argument.", 0); + respond(" example: \"player password lh4ern\"", 0); + } + else if (!passver) + { + strcpy(newpass, crypt(nexttoken, me->p_name)); + respond("Repeat \"player password\" command to verify new password.", 0); + respond(" or send \"player\" (no arguments) to cancel.", 0); + passver = 1; + } + else + { + char *paths; + int fd; + if (!strcmp(newpass, crypt(nexttoken, me->p_name))) + { + + /* perhaps it'd be better to put this part in */ + /* a different place */ + paths = build_path(PLAYERFILE); + fd = open(paths, O_WRONLY, 0644); + if (fd >= 0) + { + lseek(fd, 16 + me->p_pos * sizeof(struct statentry), 0); + write(fd, newpass, 16); + close(fd); + respond("Password changed.", 0); + } + else + { + respond("open() of playerfile failed, password not changed.", 0); + } + } + else + respond("Passwords did not match, password unchanged.", 0); + passver = 0; + } + } + return 1; + case RATINGSTOK: /* print your ratings */ + { + struct rating r; + compute_ratings(me, &r); + + sprintf(buf, "Bomb:%5.2f Plnts:%5.2f Rsrcs:%5.2f Dshs:%5.2f Offns:%5.2f", r.bombrat, r.planetrat, r.resrat, r.dooshrat, r.offrat); + respond(buf, 0); + + sprintf(buf, " JS:%5.2f SB:%5.2f WB:%5.2f Ratio:%5.2f", r.jsrat, r.sbrat, r.wbrat, r.ratio); + respond(buf, 0); + + sprintf(buf, "Overall Ratings: Battle:%5.2f Strat:%5.2f Spec. Ship:%5.2f", r.battle, r.strategy, r.special); + respond(buf, 0); + } + return 1; + + case RANKTOK: /* print the requirements for the next rank */ + { + int rank; + rank = me->p_stats.st_rank; + strcpy(buf, "Your current rank is "); + strcat(buf, ranks[rank].name); + respond(buf, 0); + if (rank == NUMRANKS - 1) + return 1; + + sprintf(buf, "To make the next rank (%s) you need:", + ranks[rank + 1].name); + respond(buf, 0); + + sprintf(buf, " Genocides: %d DI: %.2f Battle: %.2f", + ranks[rank + 1].genocides, ranks[rank + 1].di, + ranks[rank + 1].battle); + respond(buf, 0); + + sprintf(buf, " Strategy: %.2f Spec. Ships: %.2f", + ranks[rank + 1].strategy, ranks[rank + 1].specship); + respond(buf, 0); + } + return 1; + + case HELPTOK: + default: + respond_with_help_string(available_cmds); + return 1; + } +} + +/* + */ + +#ifdef LEAGUE_SUPPORT + +static void +umpire_speak(msg) + char *msg; +{ + pmessage(msg, -1, MALL, UMPIRE); +} + +static void +talk_about_team(team, type) + struct league_team *team; + char *type; +{ + char buf[120]; + struct player *captain; + + if (team->captain >= 0) + captain = &players[team->captain]; + else + captain = 0; + + sprintf(buf, "The %s team is named `%s'.", type, team->name); + respond(buf, 0); + + if (captain) + sprintf(buf, " %s (%s) is their captain.", captain->p_name, + twoletters(captain)); + else + strcpy(buf, " They have not chosen a captain yet."); + respond(buf, 0); + + if (team->index >= 0) + { + sprintf(buf, " They have chosen the %s", + teams[idx_to_mask(team->index)].name); + } + else + { + strcpy(buf, " They have not chosen an empire yet."); + } + respond(buf, 0); +} + +static int +team_really_ready(team) + struct league_team *team; +{ + if (team->index < 0) + { + respond("You haven't chosen an empire", 1); + return 0; + } + if (team->name[0] == 0) + { + respond("You haven't chosen a name", 1); + return 0; + } + return 1; +} + +void +trydefect(victim, dest, destname, from, fromname, actor) + struct player *victim; + enum HomeAway dest; + char *destname; + enum HomeAway from; + char *fromname; + struct player *actor; +{ + char buf[120]; + struct league_team *fromteam = + (from == AWAY) ? &status2->away : &status2->home; + + if (victim->p_status == PFREE) + { + respond("Uh, he's not in the game.", 1); + return; + } + + if (victim->p_homeaway == dest) + { + sprintf(buf, "%s already belong to the %s team", + actor == victim ? "You" : "They", destname); + respond(buf, 1); + return; + } + if (actor->p_homeaway != from) + { + sprintf(buf, "You don't belong to the %s team. You can't kick him off.", + fromname); + respond(buf, 1); + return; + } + if (fromteam->captain == actor->p_no) + { + if (victim == actor) + { + if (status2->league > 1 || status2->home.ready || status2->away.ready) + { + respond("You can't defect in the middle of the game. You're the captain!", 1); + return; + } + sprintf(buf, "%s (%s), the captain of the %s team, has defected!", + victim->p_name, twoletters(victim), fromname); + umpire_speak(buf); + } + else + { + sprintf(buf, "%s (%s) has kicked %s (%s) off his team.", + actor->p_name, twoletters(actor), + victim->p_name, twoletters(victim)); + umpire_speak(buf); + } + } + else + { + if (victim == actor) + { + if (status2->league > 1 || status2->home.ready || status2->away.ready) + { + respond("Only the captain can kick you off now.", 1); + return; + } + sprintf(buf, "%s (%s) has defected to the %s team!", + victim->p_name, twoletters(victim), + destname); + umpire_speak(buf); + } + else + { + respond("Only the captain can kick other people off the team.", 1); + return; + } + } + victim->p_homeaway = dest; + victim->p_status = PEXPLODE; + victim->p_whydead = KPROVIDENCE; + victim->p_explode = 1; +} + +static int +parse_league(subcommand) + char *subcommand; +{ + struct league_team *myteam, *otherteam; + char *teamtype; + char buf[120]; + int i; + int iscaptain; + char *nexttoken; + static char captain_only[] = "That command is reserved for team captains."; + static struct control_cmd available_cmds[] = { + {"help", HELPTOK, 0}, + {"captain", CAPTAINTOK, "captain [%d]"}, + {"time", TIMETOK, "time [%d %d]"}, + {"pass", PASSTOK, "pass"}, + {"start", STARTTOK, "start [%d]"}, + {"restart", RESTARTTOK, "restart [%d]"}, +#if 0 + {"timeout", TIMEOUTTOK, "timeout [%d]"}, +#endif + {"teamname", TEAMNAMETOK, "teamname %s"}, + {"information", INFOTOK, "information"}, +#if 0 + /* damn, these should be initialized from the current race list */ + {"federation", FEDTOK, "fed"}, + {"romulan", ROMTOK, "rom"}, + {"klingon", KLITOK, "kli"}, + {"orion", ORITOK, "ori"}, +#endif + + {"away", AWAYTOK, "away [%d]"}, + {"home", HOMETOK, "home [%d]"}, + {"newgalaxy", NEWGALAXY, "newgalaxy [%d]"}, + {"pause", PAUSETOK, "pause"}, + {"continue", CONTINUETOK, "continue"}, + {"maxplayer", MAXPLAYERTOK, "maxplayer [%d]"}, + {"freeslot", FREESLOTTOK, "freeslot %d"}, + {0} + }; + + switch (me->p_homeaway) + { + case HOME: + myteam = &status2->home; + otherteam = &status2->away; + teamtype = "home"; + break; + case AWAY: + myteam = &status2->away; + otherteam = &status2->home; + teamtype = "away"; + break; + default: + respond("WHOA! internal error. You aren't on a team!", 0); + respond("I'm afraid I'm going to have to kill you", 0); + me->p_status = PEXPLODE; + me->p_explode = 1; + return 0; + } + + iscaptain = (myteam->captain == me->p_no); + + /********************/ + + if (get_teamid(subcommand, &i, (char **) 0)) + { + if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + if (status2->league != 1) + { + respond("The game has started. You can't change your mind now.", 1); + return 1; + } + if ((myteam->ready || otherteam->ready) && myteam->index >= 0) + { + respond("One of the teams is ready. You can't change your mind now.", 1); + return 1; + } + if (otherteam->index >= 0) + { + if (i == otherteam->index) + { + respond("The other team has already chosen that empire", 1); + return 1; + } + } + else + { + if (me->p_homeaway == HOME) + { + if (!status2->awaypassed) + { + respond("Away team gets first choice of empire.", 1); + return 1; + } + } + else /* away */ if (myteam->index >= 0 && 0 == status2->awaypassed) + { + respond("Give the other team a chance to choose a side, will ya?", 1); + return 1; + } + else if (status2->awaypassed == 1) + { + respond("You passed the choice of empire. You have to wait for their choice.", 1); + return 1; + } + } + + if (i == myteam->index) + { + respond("That already IS your empire.", 1); + return 1; + } + if (i < 0) + { +#if 0 + sprintf(buf, "The %s team no longer wishes the %s for their empire.", + teamtype, teams[idx_to_mask(myteam->index)].name); +#else + respond("You can't change your mind without a reset. Ask for one", 1); + return 1; +#endif + } + else + sprintf(buf, "The %s team has chosen the %s for their empire.", + teamtype, teams[idx_to_mask(i)].name); + umpire_speak(buf); + + myteam->index = i; + + return 1; + } + else + switch (next_token(subcommand, available_cmds, &nexttoken)) + { + default: + case HELPTOK: /********************/ + if (iscaptain) + { + respond_with_help_string(available_cmds); + } + else + { + respond("Available commands: captain [ %d ], time, information, maxplayer.", 0); + } + return 1; + + case CAPTAINTOK: /********************/ + { + int j; + i = !get_int(nexttoken, &j, (char **) 0) || j; + } + if (i) + { + if (myteam->captain < 0 || + players[myteam->captain].p_status != PALIVE || + players[myteam->captain].p_team != me->p_team) + { + if (myteam->captain >= 0) + { + /* + * safety valve in case the person is ghostbusted or on another + * team + */ + sprintf(buf, "%s has been overthrown as captain of the %s team", + players[myteam->captain].p_name, teamtype); + umpire_speak(buf); + } + respond("OK. *POOF* you're a captain!", 1); + sprintf(buf, "%s (%s) is now fearless leader of the %s team!", + me->p_name, twoletters(me), teamtype); + umpire_speak(buf); + myteam->captain = me->p_no; + } + else if (iscaptain) + { + respond("Listen, silly. You already are captain. No point in rubbing it in", 1); + } + else + { + /* if myteam->captain were <0, we wouldn't get here */ + struct player *capn = &players[myteam->captain]; + sprintf(buf, "Sorry, %s (%s) is already captain of your team.", + capn->p_name, twoletters(capn)); + respond(buf, 1); + } + } + else + { + if (iscaptain) + { + respond("Wimp. We didn't want you for captain anyway.", 1); + sprintf(buf, "%s (%s) has chickened out.", + me->p_name, twoletters(me)); + umpire_speak(buf); + sprintf(buf, "Who now will lead the %s team?", teamtype); + umpire_speak(buf); + myteam->captain = -1; + } + else + { + respond("You can't quit being a captain. You weren't one in the first place.", 1); + } + } + return 1; + + case TIMETOK: /********************/ + if (0 == *nexttoken) + { + switch (status2->league) + { + case 2: + sprintf(buf, "%d seconds left in pre-tourney warm-up.", + status2->leagueticksleft / SECONDS(1)); + break; + case 3: + sprintf(buf, "%d minutes left in regulation play.", + status2->leagueticksleft / MINUTES(1)); + break; + case 4: + sprintf(buf, "%d minutes left in overtime.", + status2->leagueticksleft / MINUTES(1)); + break; + default: + sprintf(buf, "game is configured for %d minutes (%d overtime).", + configvals->regulation_minutes, configvals->overtime_minutes); + break; + } + respond(buf, 0); + return 1; + } + else if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + else if (status2->league != 1) + { + respond("You can only adjust the time parameters during the configuration phase", 1); + return 1; + } + else if (otherteam->ready) + { + respond("The other team is ready to start. You can't change the game params NOW.", 1); + return 1; + } + else if (!get_int(nexttoken, &myteam->desired.regulation, &nexttoken) + || !get_int(nexttoken, &myteam->desired.overtime, (char **) 0)) + { + respond("Usage: time [ %d %d ]", 1); + return 1; + } + + if (status2->home.desired.regulation == status2->away.desired.regulation + && status2->home.desired.overtime == status2->away.desired.overtime) + { + configvals->regulation_minutes = status2->home.desired.regulation; + configvals->overtime_minutes = status2->home.desired.overtime; + sprintf(buf, "The captains have agreed to a %d minute game (%d overtime).", configvals->regulation_minutes, configvals->overtime_minutes); + umpire_speak(buf); + } + else + { + sprintf(buf, "The %s team wishes a game of %d minutes (%d overtime)", + teamtype, myteam->desired.regulation, myteam->desired.overtime); + umpire_speak(buf); + } + + return 1; + + case PASSTOK: /********************/ + if (status2->league != 1) + { + respond("The time for that is long past.", 1); + return 1; + } + if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + if (me->p_homeaway == AWAY && status2->awaypassed) + { + respond("You already passed the choice of empire.", 1); + return 1; + } + else if (me->p_homeaway == HOME && status2->awaypassed == 0) + { + respond("You can't possibly pass the choice of empire. You don't HAVE it!", 1); + return 1; + } + else if (status2->awaypassed > 1) + { + respond("You both passed already, so get on with it. (indecisive wishy-washy cretins)", 1); + return 1; + } + status2->awaypassed++; + + sprintf(buf, "The %s team has passed the choice of empire", teamtype); + umpire_speak(buf); + + if (status2->awaypassed > 1) + { + umpire_speak("Computer choosing randomly for both teams"); + if (status2->home.index < 0) + { + status2->home.index = lrand48() % ((status2->away.index < 0) ? 4 : 3); + if (status2->away.index >= 0 && + status2->home.index >= status2->away.index) + status2->home.index++; + } + if (status2->away.index < 0) + { + status2->away.index = lrand48() % 3; + if (status2->away.index >= status2->home.index) + status2->away.index++; + } + } + return 1; + + case STARTTOK: /********************/ + if (status2->league != 1) + { + respond("The game has already started.", 1); + return 1; + } + if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + if (get_int(nexttoken, &myteam->ready, (char **) 0) && !myteam->ready) + { + sprintf(buf, "The %s team is not ready.", teamtype); + umpire_speak(buf); + return 0; + } + myteam->ready = 1; + if (!team_really_ready(myteam)) + { + respond("Your team is not really ready. You need a name and an empire.", 0); + myteam->ready = 0; + return 0; + } + + if (otherteam->ready && !team_really_ready(otherteam)) + { + otherteam->ready = 0; + sprintf(buf, "The %s team was ready but the other wasn't.", teamtype); + } + else + { + sprintf(buf, "The %s team is ready to start now.", teamtype); + } + umpire_speak(buf); + + + if (otherteam->ready) + { + /* shit! we're good to go! */ + + umpire_speak("Both sides are ready. Let the carnage begin!"); + umpire_speak("Everybody dies. T-mode starts in 1 minute."); + status2->league = 2; + status2->leagueticksleft = 60 * TICKSPERSEC; + + /* version */ + + explode_everyone(KTOURNSTART, 0); + } + return 1; + + case RESTARTTOK: /********************/ + if (status2->league != 1) + { + respond("The game has started. You can't change your mind now.", 1); + return 1; + } + + if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + + myteam->desired.restart = !get_int(nexttoken, &i, (char **) 0) || i; + + sprintf(buf, myteam->desired.restart ? + "%s (%s) would like to restart team selection." : + "%s (%s) is satisfied with the teams.", + me->p_name, twoletters(me)); + umpire_speak(buf); + + if (status2->home.desired.restart && status2->away.desired.restart) + { + umpire_speak("Both captains have agreed to restart team selection."); + + status2->awaypassed = 0; + status2->home.index = status2->away.index = -1; + + status2->home.ready = status2->away.ready = 0; + + status2->home.desired.restart = status2->away.desired.restart = 0; + } + + return 1; + + case TIMEOUTTOK: + respond("NYI", 0); + return 1; + + case TEAMNAMETOK: /********************/ + if (status2->league != 1) + { + respond("The game has started. You can't change your mind now.", 1); + return 1; + } + if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + if (0 == *nexttoken) + { + respond("What do you want to call your team?\n", 1); + return 1; + } + strncpy(myteam->name, nexttoken, sizeof(myteam->name)); + myteam->name[sizeof(myteam->name) - 1] = 0; + + sprintf(buf, "Henceforth let the %s team be known as `%s'!", + teamtype, myteam->name); + umpire_speak(buf); + + return 1; + + case INFOTOK: /********************/ + sprintf(buf, "The game will last for %d minutes (%d overtime)", + configvals->regulation_minutes, + configvals->overtime_minutes); + respond(buf, 0); + sprintf(buf, "Teams are limited to %d players on the field at once", + configvals->playersperteam); + respond(buf, 0); + sprintf(buf, "You are on the %s team.", teamtype); + respond(buf, 0); + talk_about_team(&status2->home, "home"); + talk_about_team(&status2->away, "away"); + + if (status2->awaypassed > 1) + umpire_speak("Both teams passed empire choice. Computer assigned."); + else if (status2->awaypassed) + umpire_speak("Away has passed empire choice to the Home team"); + else + umpire_speak("Away chooses empire first"); + + return 1; + + + case AWAYTOK: /********************/ + { + struct player *victim; + if (!*nexttoken) + victim = me; + else + { + int idx = get_slotnum(nexttoken, (char **) 0); + if (idx < 0) + { + respond("`league away' requires a valid slot number", 0); + return 1; + } + else + { + victim = &players[idx]; + } + } + trydefect(victim, AWAY, "away", HOME, "home", me); + } + return 1; + + case HOMETOK: /********************/ + { + struct player *victim; + if (!*nexttoken) + victim = me; + else + { + int idx = get_slotnum(nexttoken, (char **) 0); + if (idx < 0) + { + respond("`league away' requires a valid slot number", 0); + return 1; + } + else + { + victim = &players[idx]; + } + } + trydefect(victim, HOME, "home", AWAY, "away", me); + } + + return 1; + case NEWGALAXY: /********************/ + + if (status2->league != 1) + { + respond("The game has started. You can't change your mind now.", 1); + return 1; + } + + if (myteam->ready || otherteam->ready) + { + respond("You can't reset the galaxy now. We're almost ready!", 1); + return 1; + } + if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + + { + int j; + myteam->desired.galaxyreset = + !get_int(nexttoken, &j, (char **) 0) || j; + } + + if (myteam->desired.galaxyreset) + { + sprintf(buf, "%s (%s) is dissatisfied with the galaxy", + me->p_name, twoletters(me)); + } + else + { + sprintf(buf, "%s (%s) thinks the galaxy is just fine, thank you.", + me->p_name, twoletters(me)); + } + umpire_speak(buf); + + if (status2->home.desired.galaxyreset && + status2->away.desired.galaxyreset) + { + umpire_speak("Both captains have agreed that the galaxy sucks."); + status2->newgalaxy = 1; + warning("Creating new galaxy"); + + status2->home.desired.galaxyreset = status2->away.desired.galaxyreset = 0; + + status2->awaypassed = 0; + status2->home.index = status2->away.index = -1; + status2->home.ready = status2->away.ready = 0; + status2->home.desired.restart = status2->away.desired.restart = 0; + } + + return 1; + + case PAUSETOK: /********************/ + if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + + myteam->desirepause = 1; + + if (status2->home.desirepause && status2->away.desirepause) + { + /* well, it's unanimous! */ + status2->paused = SECONDS(10); + umpire_speak("The game has been paused"); + } + else + { + sprintf(buf, "The %s team wishes to PAUSE the game.", teamtype); + umpire_speak(buf); + } + + status2->pausemsgfuse = 0; + + return 1; + + case CONTINUETOK: /********************/ + if (!iscaptain) + { + respond(captain_only, 1); + return 0; + } + + myteam->desirepause = 0; + + sprintf(buf, "The %s team wishes to CONTINUE.", teamtype); + umpire_speak(buf); + + status2->pausemsgfuse = 0; + + return 1; + + case MAXPLAYERTOK: + { + int mp; + if (!get_int(nexttoken, &mp, (char **) 0)) + { + sprintf(buf, "The game is currently configured for a maximum of %d players on each", configvals->playersperteam); + respond(buf, 0); + respond("team.", 0); + if (configvals->playersperteam != myteam->desired.maxplayers) + { + sprintf(buf, "You, however, want it to be %d.", + myteam->desired.maxplayers); + respond(buf, 0); + } + } + else + { + if (!iscaptain) + { + respond(captain_only, 1); + return 1; + } + + if (mp < 1) + { + respond("That's a stupid value for players-per-team.", 1); + return 1; + } + + myteam->desired.maxplayers = mp; + if (status2->away.desired.maxplayers + == status2->home.desired.maxplayers) + { + configvals->playersperteam = mp; + sprintf(buf, "Captains have agreed to limit players per team to %d", mp); + umpire_speak(buf); + } + else + { + sprintf(buf, "The %s team would like to limit the number of ", + teamtype); + umpire_speak(buf); + sprintf(buf, "players per team to %d", mp); + umpire_speak(buf); + } + } + } + return 1; + case FREESLOTTOK: + { + int slotnum; + struct player *victim; + slotnum = get_slotnum(nexttoken, (char **) 0); + if (slotnum < 0) + { + respond("freeslot requires slot number", 1); + return 0; + } + + victim = &players[slotnum]; + if (victim->p_ntspid) + kill(victim->p_ntspid, SIGHUP); + + victim->p_status = PFREE; + victim->p_ntspid = 0; + + sprintf(buf, "Player slot %s has been freed by %s (%2s).", + nexttoken, me->p_name, twoletters(me)); + umpire_speak(buf); + } + return 1; + } +} +#endif +/* + */ + + + +/* + * Parse command messages. + */ + +int +parse_command_mess(str, who) + char *str; + unsigned char who; +{ + char buf[120]; + char *nexttoken; + int godlike = me->p_stats.st_royal - GODLIKE + 1; + + static struct control_cmd available_cmds[] = { + {"help", HELPTOK, 0}, + {"control", CONTROLTOK, "control ..."}, + {"league", LEAGUETOK, "league ..."}, + {"version", VERSIONTOK, "version"}, + {"player", PLAYERTOK, "player ..."}, + {"queue", QUEUETOK, "queue"}, {"tq", QUEUETOK, 0}, + {"information", INFOTOK, "information ..."}, + {"observe", OBSERVETOK, "observe"}, + {"parameters", PARAMTOK, "parameters"}, {"params", PARAMTOK, 0}, + {"cluecheck", CLUECHECKTOK, "cluecheck [%s]"}, + {0} + }; + + if (godlike < 0) + godlike = 0; + + + +#if 0 + /* so we won't damage the original string */ + strcpy(buf, str); + + dotokenize(buf); + + if (sizetokstring == 0) /* nothing? ok, then let them send it :) */ + return 0; +#endif + + switch (next_token(str, available_cmds, &nexttoken)) + { + case HELPTOK: + sprintf(buf, "Available commands: %s%s%s", + godlike ? "control ..., " : "", +#ifdef LEAGUE_SUPPORT + status2->league ? "league ..., " : +#endif + "", + "version, player ..., queue,"); + respond(buf, 0); + respond(" information ..., observe [%d], parameters, cluecheck [%s], help", 0); + return 1; + case CONTROLTOK: +#ifdef GOD_CONTROLS +#ifdef LEAGUE_SUPPORT + if (status2->league) + { + respond("God controls are disabled during league play.", 1); + } + else +#endif + return parse_control(nexttoken); +#else + respond("This ntserv is not compiled with god controls.", 1); + return 1; +#endif + + case VERSIONTOK: + sprintf(buf, "NetrekII (Paradise), %s", PARAVERS); + respond(buf, 0); + return 1; + + case PLAYERTOK: + return parse_player(nexttoken); + + case QUEUETOK: + if (me->p_status == PTQUEUE) + { + detourneyqueue(); + } + else if (status->tourn) + respond("Dude, what are you waiting for!? It's T-mode. GO FIGHT!", 1); + else if (!(me->p_flags & PFGREEN)) + respond("Can not enter the tourney queue while at alert", 1); +#ifndef AEDILE + else if (me->p_damage != 0 || me->p_shield < me->p_ship.s_maxshield) + respond("Can not enter the tourney queue while damaged", 1); +#endif + else if (me->p_armies > 0) + respond("Can not take armies into the tourney queue", 1); + else + { + /* + * well, stick them on the queue. They will be awoken when T mode + * arrives + */ + + evaporate(me); + + /* need code to blab about this */ + me->p_status = PTQUEUE; + sprintf(buf, "%s has entered the tournament queue to wait for T-mode", me->p_name); + pmessage(buf, -1, MALL, "GOD->ALL"); + } + return 1; + + case LEAGUETOK: +#ifdef LEAGUE_SUPPORT + if (status2->league) + { + return parse_league(nexttoken); + } + else + { + respond("League commands are disabled during non-league play.", 1); + return 1; + } +#else + respond("Server is not compiled with league support.", 1); + respond("Edit config.h, recompile, install, and nuke the game.", 1); + return 1; +#endif + + case INFOTOK: + return parse_info(nexttoken); + + case OBSERVETOK: + { + int i; + i = !get_int(nexttoken, &i, (char **) 0) || i; + + if (i) + { + if (me->p_observer && me->p_status == POBSERVE) + { + respond("You are already an observer.", 1); + } + else + { + if (!(me->p_flags & PFGREEN)) + respond("Can not become an observer while at alert", 1); + else if (me->p_damage != 0 || me->p_shield < me->p_ship.s_maxshield) + respond("Can not become an observer while damaged", 1); + else if (me->p_armies > 0) + respond("Can not become an observer while carrying armies", 1); + else + { + evaporate(me); + me->p_status = POBSERVE; + } + me->p_observer = 1; + } + } + else + { + if (me->p_observer && me->p_status == POBSERVE) + { + me->p_observer = 0; +#if 1 +#ifdef LEAGUE_SUPPORT + if (!(status2->league && status->tourn)) +#endif + evaporate(me); +#else + respond("You may now self-destruct and reenter the game as a player", 0); + respond("(assuming there's room for you).", 0); +#endif + } + } + } + return 1; + + case PARAMTOK: + warning("Transmitting new game parameters"); + updateGameparams(); + return 1; + case CLUECHECKTOK: +#if defined(CLUECHECK1) || defined(CLUECHECK2) + return accept_cluecheck(nexttoken); +#else + return 0; +#endif + default: + return 0; + } +} diff -r cafa94d86546 -r aa38447a4b21 src/misc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,562 @@ +/*-------------------------------------------------------------------------- +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 "misc.h" +#include "struct.h" +#include "data.h" +#include "daemonII.h" +#include "planets.h" +#include "shmem.h" + +/*------------------------------MODULE VARIABLES--------------------------*/ + +#define NMESSAGES 16 +/* The list of messages that are sent when t-mode begins. */ +char *warmessages[] = { + "A dark mood settles upon the galaxy as galactic superpowers seek", + "to colonize new territory. Border disputes errupt developing", + "into all out intergalactic WAR!!!", + + "Slick Willy is elected president, the bottom falls out of the", + "economy, and the pressure to expand rises.", + + "Clinton found with foreign emperor's wife!", + "All out war ensues.", + + "Taxes on the rich raised to 80%.", + "The rich flee to neigboring empire.", + "Democrats demand extradition.", + "Foreign emporer refuses.", + "Hillary 'Rob Them' Clinton declares war!", + "Bill hides out in London.", + + "INTERGALACTIC BEER SHORTAGE!", + "CHAOS LIKE IT HAS NEVER BEEN SEEN BEFORE ENSUES!", + + "The American Gladiators hit as the number 1 show on the vid.", + "After a gruesome episode, the masses storm out their homes,", + "jump in their ships, make a quick stop at their local 7-11", + "to grab a few beers, then head out into the galaxy to ", + "KICK SOME ASS. WAR!!!!!!!!!!!!!!!!!!", + + "Khan is resurrected in a bizzare experiment. Elected as head of", + "the Starfleet Council, he removes all pajama-wearing new-age", + "hippies from Starfleet. (And you thought the borg were bad news)", + + "Several members of the computing support staff of the Galactic", + "Council are severely injured in a freak skydiving accident.", + "The rest are killed. The network collapses without their", + "guidance. Galactic chaos breaks out!", + + /* oldies */ + "A dark mood settles upon the galaxy", + "Political pressure to expand is rising", + "Border disputes break out as political tensions increase!", + "Galactic superpowers seek to colonize new territory!", + "'Manifest Destiny' becomes motive in galactic superpower conflict!", + "Diplomat insults foriegn emperor's mother and fighting breaks out!", + "Dan Quayle declares self as galactic emperor and chaos breaks out!", + "Peace parties have been demobilized, and fighting ensues.", +}; + + +/* + * The starting index of the message series and the number of messages in + * series. + */ +int warm[NMESSAGES][2] = { + {0, 3}, + {3, 2}, + {5, 2}, + {7, 6}, + {13, 2}, + {15, 5}, + {20, 3}, + {23, 4}, + {27, 1}, + {28, 1}, + {29, 1}, + {30, 1}, + {31, 1}, + {32, 1}, + {33, 1}, + {34, 1}, +}; + + +/* The set of message series that are displayed when t-mode ends. */ +char *peacemessages[] = { + "The expansionist pressure subsides, and temporary agreements are", + "reached in local border disputes.", + "Peace returns to the galaxy...", + + "Wild mob storms the White House!", + "Clinton flees.", + "Order returns to the galaxy.", + + "Slick Willy apologizes about incident with foreign emperor's wife.", + "Claims he did not penetrate.", + "Peace ensues.", + + "The economy goes belly up. The Democrats are kicked", + "out of office, tarred and feathered, and sent to the", + "zoo on Rigel 4. Capitalism is implemented and order", + "returns to the empire.", + + "Officials sieze hidden beer stockpiles at the Mackenzie brother's", + "house! The beer shortage is over. Peace breaks out.", + + "The people decide they would rather sit home and watch", + "Al Bundy than fight. The war comes to an end.", + + "Khan takes a fatal blow to the kidneys when Kirk returns from", + "retirement and whacks him in the back with his walker.", + "It looks like the hippies are back in control.", + + "Sole survivors of the skydiving accident that took out the", + "rest of the computing support staff, Michael McLean and Brad", + "Spatz are released from intensive care and rebuild the", + "network. Peace is restored to the Galaxy.", + + /* oldies */ + "A new day dawns as the oppressive mood lifts", + "The expansionist pressure subsides", + "Temporary agreement is reached in local border disputes.", + "Galactic governments reduce colonization efforts.", + "'Manifest Destiny is no longer a fad.' says influential philosopher.", + "Diplomat apologizes to foreign emperor's mother and invasion is stopped!", + "Dan Quayle is locked up and order returns to the galaxy!", + "The peace party has reformed, and is rallying for peace", +}; + + +/* + * The starting index of each message series and the number of messages in + * the series. + */ +int peacem[NMESSAGES][2] = { + {0, 3}, + {3, 3}, + {6, 3}, + {9, 4}, + {13, 2}, + {15, 2}, + {17, 3}, + {20, 4}, + {24, 1}, + {25, 1}, + {26, 1}, + {27, 1}, + {28, 1}, + {29, 1}, + {30, 1}, + {31, 1}, +}; + + +static int series = 0; /* the message series that was printed */ +/* when t-mode started. */ + +/*------------------------------------------------------------------------*/ + + + + + + + + +/*------------------------------VISIBLE FUNCTIONS-------------------------*/ + +/*---------------------------------WARMESSAGE----------------------------*/ +/* + * This function is called when t-mode ensues. It chooses a message series + * and prints it out. It records the message series in the module's series + * variable so that the corresponding peace message series can be printed. + */ + + +void +warmessage() +{ + int i; /* to hold index */ + int n; /* number of messages in a series */ + + i = lrand48() % NMESSAGES; /* choose message series */ + series = i; /* record series number */ + n = warm[i][1]; /* get number of messages in series */ + i = warm[i][0]; /* get index of first message */ + while (n > 0) + { /* print all messages */ + pmessage(warmessages[i], 0, MALL, " WAR-> "); + n--; /* dec messages that need to be printed */ + i++; /* on to next message */ + } +} + + + + +/*-------------------------------PEACEMESSAGE-----------------------------*/ +/* + * This function prints a peace message series. It uses the module variable + * series to decide which message series to print. + */ + +void +peacemessage() +{ + int i; /* to hold index */ + int n; /* number of messages in a series */ + + n = peacem[series][1]; /* get # messages in series */ + i = peacem[series][0]; /* get starting index */ + while (n > 0) + { /* print all messages */ + pmessage(peacemessages[i], 0, MALL, " PEACE-> "); + n--; /* dec messages that need to be printed */ + i++; /* on to next message */ + } +} + + + + +/*-------------------------------REALNUMSHIPS-----------------------------*/ +/* + * This function counts the number of ships on a team. If the race is the + * same and the slot is not free, then the ship is counted. + */ + +int +realNumShips(owner) + int owner; +{ + int i, num; /* for looping and counting */ + struct player *p; /* to point to a player */ + + num = 0; /* zero the count of ships */ + for (i = 0, p = players; i < MAXPLAYER; i++, p++) + if ((p->p_status != PFREE) && (p->p_team == owner)) + num++; /* found a ship on this team, inc count */ + return (num); /* return number of ships */ +} + + + + +/*------------------------------TOURNAMENTMODE------------------------------*/ +/* + * This function counts the number of players on each team and sees if two or + * more teams have enough players for t-mode. It returns a 0 for no team + * mode. + */ + +int +tournamentMode() +{ +#ifdef LEAGUE_SUPPORT + if (status2->league) + { + return status2->league > 2; + } + else +#endif + { + static int wt = -1; /* warning time due to team unbalance */ + static int lct = -1; /* last check time (ie last pmessage) */ + char buf[80]; /* temp buffer for tmode halt warning */ + int i; /* looping vars */ + int t[16]; /* to count players with */ + int counts[4]; + /* Even though teams go from 0-8, leave */ + /* this at 16...or bad things might happen */ + struct player *p; /* to point to players */ + + for (i = 0; i < 16; i++) /* clear the team players count array */ + t[i] = 0; + for (i = 0, p = players; i < MAXPLAYER; i++, p++) + { + /* through all players */ + if (p->p_flags & PFROBOT) + continue; /* robots don't count */ + switch (p->p_status) + { + case PFREE: /* free slots obviously don't count */ + case POBSERVE: /* and neither do observers */ + break; + + case PEXPLODE: + case PDEAD: + case PTQUEUE: + if (p->p_observer) + break; /* observers in these modes don't count */ + /* we can fall through here */ + case POUTFIT: + case PALIVE: + t[p->p_team]++; + break; + } + } + +#if 0 + /* + * If there hasnt been tmode recently (5 mins) clear all kills, and place + * any carried armies on the most valuble planet not yet finished. + */ + if ((tourntimestamp - ticks) > 300) + { + int x; + for (x = 0; x < MAXPLAYER; x++) + { + if (players[x].p_status == PALIVE) + { + if (players[x].p_armies > 0) + PlaceLostArmies(players[x]); + players[x].p_kills = 0.00; + } + } + } +#endif + + i = 0; /* zero count of # teams with tournplayers */ + if (t[FED] >= configvals->tournplayers) + counts[i++] = t[FED]; + if (t[ROM] >= configvals->tournplayers) + counts[i++] = t[ROM]; + if (t[KLI] >= configvals->tournplayers) + counts[i++] = t[KLI]; + if (t[ORI] >= configvals->tournplayers) + counts[i++] = t[ORI]; + if (i > 1) + { + i = counts[0] - counts[1]; + if (i < 0) + i = -i; + if (i > 2) + { /* Too big a team imbalance */ + if (wt == -1) + { + wt = status->clock; /* make a timestamp */ + lct = status->clock; /* used every time it sends the message */ + } + if (((status->clock - wt) < 3) && (lct < status->clock)) + { + /* + * teams are unblananced, and we havn't said anything for 1 minute, + * warn everybody Yes these are noisy strings, but I want people + * to notice. + */ + pmessage("**************************!! Teams are unbalanced !!**************************", 0, MALL, ""); + sprintf(buf, "********************* TMODE WILL BE HALTED IN %li MINUTES **********************", (wt - status->clock) + 3); + pmessage(buf, 0, MALL, ""); + pmessage("************************ if this problem isn't fixed *************************", 0, MALL, ""); + lct = status->clock; + return (1); + } + else if ((status->clock - wt) >= 3) + { + if (lct < status->clock) + { + pmessage("******************!! TMODE HALTED DUE TO TEAM IMBALANCE !!********************", 0, MALL, ""); + pmessage("*********************** Balance teams to resume tmode ************************", 0, MALL, ""); + lct = status->clock; + } + return (0); /* stop tmode */ + } + } + else + { + wt = -1; + lct = -1; + } + return (1); /* return that we are in team mode */ + } + return (0); /* we are NOT in T-mode */ + } +} + + + + +/*------------------------------PMESSAGE----------------------------------*/ +/* + * This function sens a message to the message board. It places the message + * in the next position of the array of messages. The message will ahve a + * header attached to the front of it. + */ + +void +pmessage(str, recip, group, address) + char *str; /* the message */ + int recip; /* who is the recipient */ + int group; /* group sent to and other flags */ + char *address; /* the header attached to front */ +{ + struct message *cur; /* to pnt to where to put message */ + int mesgnum; /* to hold index into array of messgs */ + + if ((mesgnum = ++(mctl->mc_current)) >= MAXMESSAGE) + { + mctl->mc_current = 0; /* move to next index in array and */ + mesgnum = 0; /* warp around if necessart */ + } + cur = &messages[mesgnum]; /* get addr of message struct */ + cur->m_no = mesgnum; /* set the message number */ + cur->m_flags = group; /* set the group and flags */ + cur->m_recpt = recip; /* set the recipient */ + cur->m_from = 255; /* message is from God */ + (void) sprintf(cur->m_data, "%s %s", address, str); + cur->m_flags |= MVALID; /* mark message as valid */ +} + +/* + * send a message from god to a particular player number + */ + +void +god2player(str, pno) + char *str; + int pno; +{ + struct message *cur; /* to pnt to where to put message */ + + if (++(mctl->mc_current) >= MAXMESSAGE) + mctl->mc_current = 0; + cur = &messages[mctl->mc_current]; + + cur->m_no = mctl->mc_current; + cur->m_flags = MINDIV; + cur->m_recpt = pno; + cur->m_from = 255; + sprintf(cur->m_data, "%s->%s %s", SERVNAME, twoletters(&players[pno]), str); + cur->m_flags |= MVALID; +} + + + + +/*-------------------------------LOG_MESSAGE------------------------------*/ +/* + * This function writes a message into the logfile so the server god can look + * at it later. It is used to record messages to god. + */ + +void +log_message(msg) + char *msg; /* the string to record */ +{ + char *path; /* to hold path and name */ + FILE *logfile; /* to open logfile with */ + + path = build_path(GODLOGFILE); + logfile = fopen(path, "a"); /* let's try to open this baby */ + if (!logfile) /* Oops, could not open */ + return; /* OUt of Dodge */ + fputs(msg, logfile); /* write the string to log file */ + fclose(logfile); /* close the sucker up */ +} + + + + +/*-----------------------------PARSE_GODMESSAGES----------------------------*/ +/* + * This function checks all the new messages in the message buffer to see if + * the keyword 'GOD' is at the first of the message. If it is, then the + * message is written to the logfile so the server god can read it. + */ + +void +parse_godmessages() +{ + char buf[100]; /* bigger than message::m_data */ + static int lastparsed = 0; /* keeps track of last message */ + + while (mctl->mc_current != lastparsed) + { /* Is there a new message? */ + struct message *cur; /* to point to message struct */ + char *s; /* to point to string */ + + if (++lastparsed >= MAXMESSAGE) /* rollover after end of */ + lastparsed = 0; /* message buffer */ + cur = &messages[lastparsed];/* get new message's struct */ + + s = cur->m_data + 1; /* get new message */ + while ((*s != ' ') && (*s != 0)) /* go until first space */ + s++; + while ((*s == ' ') && (*s != 0)) /* go past spaces */ + s++; + + if (!*s) + continue; + if (cur->m_flags & MGOD) + { /* if it's to god */ + sprintf(buf, "%s says: %s\n", + (cur->m_from >= 0) ? players[cur->m_from].p_name : "who", s); + } + else + { /* or labeled to god */ + if (strncmp(s, "GOD:", 4) != 0) /* check for 'GOD' keyword */ + continue; /* not there, then next message */ + sprintf(buf, "GOD: %s\n", s + 4); + } + log_message(buf); /* go record message */ + } +} + +/*------------------------------------------------------------------------*/ +#if 0 +/*--------------------------[ PLACE LOST ARMIES ]--------------------------*/ +/* + * If for some reason or another the player looses armies they may be + * carrying (ghost busts, etc), this function is called, to place the armies + * safely on a planet. + */ + +void +PlaceLostArmies(victim) + struct player *victim; +{ + char buf[80]; + int i, startplanet; + + ((startplanet = find_start_planet(me->p_team, PLSHIPYARD)) != -1 + || (startplanet = find_start_planet(me->p_team, PLREPAIR)) != -1 + || (startplanet = find_start_planet(me->p_team, PLAGRI)) != -1 + || (startplanet = find_start_planet(me->p_team, PLFUEL)) != -1 + || (startplanet = find_start_planet(me->p_team, PLHOME)) != -1 + || (startplanet = find_start_planet(me->p_team, 0)) != -1); + planets[startplanet].pl_armies += victim->p_armies; + (void) sprintf(buf, "%s's %d armies placed on %s", + victim->p_name, victim->p_armies, planets[startplanet].pl_name); + pmessage(buf, 0, MALL | MGHOST, MSERVA); +} +#endif +/*------------------------------------------------------------------------*/ + +/*----------END OF FILE--------*/ diff -r cafa94d86546 -r aa38447a4b21 src/misc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc.h Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- +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 warmessage(); /* print war message */ +void peacemessag(); /* print peace message */ +int realNumShips(); /* number of ships on a team */ +int tournamentMode(); /* are we in tourn mode */ +void pmessage( /* char *str, int recip, int group, char addr */ ); +void parse_godmesssages(); /* detect and log messages to god */ +void PlaceLostArmies(); /* places armies from a lost/GB'd player */ +/*--------------------------------------------------------------------------*/ + + + + + + +/*--------END OF FILE------*/ diff -r cafa94d86546 -r aa38447a4b21 src/orbit.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/orbit.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,235 @@ +/*-------------------------------------------------------------------------- +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" + + +void newdock(); +extern void move_player(); + +static void +deactivate_friendly_tractors() +{ + int i; + struct player *j; + for (i = 0; i < MAXPLAYER; i++) + { + j = &players[i]; + if (i == me->p_no || + j->p_team != me->p_team || + j->p_tractor != me->p_no) + continue; + /* j is a teammate with a tractor on me */ + j->p_flags &= ~(PFTRACT | PFPRESS); + } +} + +/*------------------------------VISIBLE PROCEDURES-------------------------*/ + +/*-----------------------------------ORBIT---------------------------------*/ +/* + * This function is called when the player presses the orbit key. It check + * to make sure the player can orbit or dock. The function first checks + * through the list of players to see whether there is a dockable ship + * nearby. If that fails, then the planets are checked. The orbit key acts + * as a toggle for docking and undocking at ships. + */ + +void +orbit() +{ + register int i; /* looping var */ + register struct planet *l; /* to point to planet being orbited */ + unsigned char dir; /* to hold course direction */ + int dx, dy; /* used to get distances */ + + if (me->p_flags & PFORBIT) /* if not orbiting then we do not */ + return; /* need to do this section of code */ + if (me->p_speed > ORBSPEED) + { /* going to fast to orbit/dock? */ + warning("Helmsman: Captain, the maximum safe speed for docking or orbiting is warp 2!"); + return; + } /* turn off flags */ + me->p_flags &= ~(PFORBIT | PFTRACT | PFPRESS | + PFWARP | PFAFTER | PFWARPPREP | PFWPSUSPENDED); + me->p_warptime = 0; + if ((me->p_flags & PFDOCK) && (players[me->p_docked].p_speed > 4)) + { + warning("It's unsafe to disengage from your base when it's moving faster then warp 4."); /* cannot disengage from + * travelling */ + return; /* ships if they are going too fast */ + } + else + undock_player(me); /* make sure I'm not docked */ + + if (!(me->p_flags & PFPLLOCK) && /* if we aren't locked onto a planet */ + can_dock(me->p_ship)) + { /* and player can dock then */ + for (i = 0; i < MAXPLAYER; i++) + { /* go through all players */ + if (me->p_no == i) /* and look for ships that */ + continue; /* allow docking */ + if (!allows_docking(players[i].p_ship)) + continue; + if (!isAlive(&players[i]))/* disregard players not */ + continue; /* alive */ + if (!friendlyPlayer(&players[i])) /* cannot dock on enemy */ + continue; /* players */ + dx = ABS(players[i].p_x - me->p_x); /* get distance */ + dy = ABS(players[i].p_y - me->p_y); + if (dx > DOCKDIST || dy > DOCKDIST) /* if too far away thenwe */ + continue; /* cannot dock here */ + newdock(i); /* find a port and dock */ + + deactivate_friendly_tractors(); + + me->p_flags &= ~(PFPLOCK | PFPLLOCK); + return; + } + } /* not docking with a player try a planet */ + if (!(me->p_flags & PFPLOCK)) + { /* aren't locked onto a player */ + for (i = 0, l = &planets[i]; i < NUMPLANETS; i++, l++) + { + switch (PL_TYPE(*l)) + { + case PLSTAR: + case PLNEB: + case PLBHOLE: + case PLPULSAR: + continue; + } + + dx = ABS(l->pl_x - me->p_x); /* go through all planets and */ + dy = ABS(l->pl_y - me->p_y); /* check their distance */ + if (dx > ENTORBDIST || dy > ENTORBDIST) + continue; /* too far away? */ + if (dx * dx + dy * dy > ENTORBDIST * ENTORBDIST) + continue; + + if (!(me->p_team & planets[i].pl_owner) && /* can player orbit? */ + !(me->p_ship.s_nflags & SFNCANORBIT)) + { + warning("Central Command regulations prohibits you from orbiting foreign planets"); + return; + } + if (!(me->p_team & planets[i].pl_owner) && + !status->tourn) + { + warning("No one is allowed to orbit alien planets outside of T-mode"); + return; + } + dir = (unsigned char) (int) (atan2((double) (me->p_x - l->pl_x), + (double) (l->pl_y - me->p_y)) / 3.14159 * 128.); + scout_planet(me->p_no, l->pl_no); +#if 0 + l->pl_torbit |= me->p_team; /* place team in orbit */ +#endif + me->p_orbitdir = drand48() < configvals->orbitdirprob; + me->p_dir = dir + (me->p_orbitdir ? 64 : -64); /* get direction for + * player */ + me->p_flags |= PFORBIT; /* set his orbiting flag */ + + deactivate_friendly_tractors(); + + move_player(me->p_no, (int) (l->pl_x + ORBDIST * Cos[dir]), + (int) (l->pl_y + ORBDIST * Sin[dir]), 1); + + me->p_speed = me->p_desspeed = 0; + me->p_planet = l->pl_no; /* set the planet number */ + me->p_flags &= ~(PFPLOCK | PFPLLOCK); + return; + } + } + warning("Helmsman: Sensors read no valid targets in range to dock or orbit sir!"); +} + + + +/*--------------------------------NEWDOCK--------------------------------*/ + + +void +newdock(base_num) + int base_num; +{ + char buf[80]; /* to sprintf into */ + struct player *base = &players[base_num]; + int port_id, i; + int numports; + long distsq = 0; /* will be set by the first matching port */ + int angle; + + if (!(base->p_flags & PFDOCKOK)) + { /* docking allowed? */ + sprintf(buf, "Starbase %s refusing us docking permission captain.", + base->p_name); + warning(buf); /* if not say so then */ + return; /* get out of here */ + } + port_id = -1; + numports = base->p_ship.s_numports; + + for (i = 0; i < numports; i++) + { + long ds; + int x, y; + angle = (2 * i + 1) * 128 / numports; + + if (base->p_port[i] != VACANT) + continue; + + x = base->p_x + DOCKDIST * Cos[angle]; + y = base->p_y + DOCKDIST * Sin[angle]; + ds = (me->p_x - x) * (me->p_x - x) + (me->p_y - y) * (me->p_y - y); + if (port_id == -1 || ds < distsq) + { + port_id = i; + distsq = ds; + } + } + + if (port_id < 0) + { + sprintf(buf, "Base %s: Permission to dock denied, all ports currently occupied.", base->p_name); + warning(buf); /* print message to tell */ + return; + } /* player */ + dock_to(me, base_num, port_id); + + sprintf(buf, "Helmsman: Docking manuever completed Captain. All moorings secured at port %d.", port_id); + warning(buf); /* tell user he's docked */ +} + +#ifdef HAVE_RAND48 + +double drand48(); + +#endif + +/*------------END OF FILE--------*/ diff -r cafa94d86546 -r aa38447a4b21 src/packets.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/packets.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,359 @@ +/*-------------------------------------------------------------------------- +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 "defs.h" +#include "packets.h" +#include "gppackets.h" +#include "wtext.h" + +size_t client_packet_sizes[] = { + 0, + sizeof(struct mesg_cpacket), + sizeof(struct speed_cpacket), + sizeof(struct dir_cpacket), + sizeof(struct phaser_cpacket), + sizeof(struct plasma_cpacket), + sizeof(struct torp_cpacket), + sizeof(struct quit_cpacket), + sizeof(struct login_cpacket), + sizeof(struct outfit_cpacket), + /* 10 v */ + sizeof(struct war_cpacket), + sizeof(struct practr_cpacket), + sizeof(struct shield_cpacket), + sizeof(struct repair_cpacket), + sizeof(struct orbit_cpacket), + sizeof(struct planlock_cpacket), + sizeof(struct playlock_cpacket), + sizeof(struct bomb_cpacket), + sizeof(struct beam_cpacket), + sizeof(struct cloak_cpacket), + /* 20 v */ + sizeof(struct det_torps_cpacket), + sizeof(struct det_mytorp_cpacket), + sizeof(struct copilot_cpacket), + sizeof(struct refit_cpacket), + sizeof(struct tractor_cpacket), + sizeof(struct repress_cpacket), + sizeof(struct coup_cpacket), + sizeof(struct socket_cpacket), + sizeof(struct options_cpacket), + sizeof(struct bye_cpacket), + /* 30 v */ + sizeof(struct dockperm_cpacket), + sizeof(struct updates_cpacket), + sizeof(struct resetstats_cpacket), + sizeof(struct reserved_cpacket), + sizeof(struct scan_cpacket), + sizeof(struct udp_req_cpacket), + sizeof(struct sequence_cpacket), + sizeof(struct rsa_key_cpacket), + sizeof(struct obvious_packet), + 0, + /* 40 v */ + 0, + 0, + sizeof(struct ping_cpacket), +#ifdef SHORT_PACKETS + sizeof(struct shortreq_cpacket), + sizeof(struct threshold_cpacket), + 0, /* CP_S_MESSAGE */ + 0, /* CP_S_RESERVED */ + 0, /* CP_S_DUMMY */ +#else + 0, + 0, + 0, + 0, + 0, +#endif + 0, + 0, + /* 50 v */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 60 v */ +#ifdef FEATURE + sizeof(struct feature_cpacket)/* CP_FEATURE */ +#else + 0 +#endif +}; + +#define num_cpacket_sizes sizeof(client_packet_sizes)/sizeof(*client_packet_sizes) + +int +size_of_cpacket(pkt) + void *pkt; +{ + CARD8 type; + CARD8 subtype; + + type = ((CARD8 *) pkt)[0]; + subtype = ((CARD8 *) pkt)[1]; + + if (type < num_cpacket_sizes && client_packet_sizes[type] > 0) + return client_packet_sizes[type]; + + switch (type) + { +#ifdef CP_FIRE_WEAPON + case CP_FIRE_WEAPON: + { + struct fire_weapon_cpacket *fwp = pkt; + return (fwp->mech == TM_POSITION) ? 12 : 4; + } +#endif + +#ifdef SHORT_PACKETS + case CP_S_MESSAGE: + return ((unsigned char *) pkt)[3]; + case CP_S_RESERVED: + case CP_S_DUMMY: + /* hmm? good question */ + return 0; +#endif /* SHORT_PACKETS */ + + default: + return 0; + } +} + + +int server_packet_sizes[] = { + 0, /* record 0 */ + sizeof(struct mesg_spacket), /* SP_MESSAGE */ + sizeof(struct plyr_info_spacket), /* SP_PLAYER_INFO */ + sizeof(struct kills_spacket), /* SP_KILLS */ + sizeof(struct player_spacket),/* SP_PLAYER */ + sizeof(struct torp_info_spacket), /* SP_TORP_INFO */ + sizeof(struct torp_spacket), /* SP_TORP */ + sizeof(struct phaser_spacket),/* SP_PHASER */ + sizeof(struct plasma_info_spacket), /* SP_PLASMA_INFO */ + sizeof(struct plasma_spacket),/* SP_PLASMA */ + /* 10 v */ + sizeof(struct warning_spacket), /* SP_WARNING */ + sizeof(struct motd_spacket), /* SP_MOTD */ + sizeof(struct you_spacket), /* SP_YOU */ + sizeof(struct queue_spacket), /* SP_QUEUE */ + sizeof(struct status_spacket),/* SP_STATUS */ + sizeof(struct planet_spacket),/* SP_PLANET */ + sizeof(struct pickok_spacket),/* SP_PICKOK */ + sizeof(struct login_spacket), /* SP_LOGIN */ + sizeof(struct flags_spacket), /* SP_FLAGS */ + sizeof(struct mask_spacket), /* SP_MASK */ + /* 20 v */ + sizeof(struct pstatus_spacket), /* SP_PSTATUS */ + sizeof(struct badversion_spacket), /* SP_BADVERSION */ + sizeof(struct hostile_spacket), /* SP_HOSTILE */ + sizeof(struct stats_spacket), /* SP_STATS */ + sizeof(struct plyr_login_spacket), /* SP_PL_LOGIN */ + sizeof(struct reserved_spacket), /* SP_RESERVED */ + sizeof(struct planet_loc_spacket), /* SP_PLANET_LOC */ + sizeof(struct scan_spacket), /* SP_SCAN (ATM) */ + sizeof(struct udp_reply_spacket), /* SP_UDP_REPLY */ + sizeof(struct sequence_spacket), /* SP_SEQUENCE */ + /* 30 v */ + sizeof(struct sc_sequence_spacket), /* SP_SC_SEQUENCE */ + sizeof(struct rsa_key_spacket), /* SP_RSA_KEY */ + sizeof(struct motd_pic_spacket), /* SP_MOTD_PIC */ + sizeof(struct stats_spacket2),/* SP_STATS2 */ + sizeof(struct status_spacket2), /* SP_STATUS2 */ + sizeof(struct planet_spacket2), /* SP_PLANET2 */ + sizeof(struct obvious_packet),/* SP_NEW_MOTD */ + sizeof(struct thingy_spacket),/* SP_THINGY */ + sizeof(struct thingy_info_spacket), /* SP_THINGY_INFO */ + sizeof(struct ship_cap_spacket), /* SP_SHIP_CAP */ + /* 40 v */ +#ifdef SHORT_PACKETS + sizeof(struct shortreply_spacket), /* SP_S_REPLY */ + -1, /* SP_S_MESSAGE */ + -1, /* SP_S_WARNING */ + sizeof(struct youshort_spacket), /* SP_S_YOU */ + sizeof(struct youss_spacket), /* SP_S_YOU_SS */ + -1, /* SP_S_PLAYER */ +#else + -1, + -1, + -1, + -1, + -1, + -1, +#endif + sizeof(struct ping_spacket), /* SP_PING */ + -1, /* SP_S_TORP */ + -1, /* SP_S_TORP_INFO */ + 20, /* SP_S_8_TORP */ + /* 50 v */ + -1, /* SP_S_PLANET */ + -1, /* SP_GPARAM */ + -1, /* SP_PARADISE_EXT1 */ + sizeof(struct terrain_packet2), /* SP_TERRAIN2 */ + sizeof(struct terrain_info_packet2), /* SP_TERRAIN_INFO2 */ + -1, + -1, + -1, + -1, + -1, + /* 60 v */ +#ifdef FEATURE + sizeof(struct feature_spacket), /* SP_FEATURE */ +#else + -1, +#endif + -1 /* The fools! I'm pretty sure there is an */ + /* off-by-one in the test in the last fnc */ + /* but I'm not sure and this WILL fix it. */ +}; + +#define num_spacket_sizes (sizeof(server_packet_sizes) / sizeof(server_packet_sizes[0]) - 1) + +#ifdef SHORT_PACKETS +unsigned char numofbits[256] = +{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, + 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, + 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, + 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, + 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, + 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, + 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, + 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, + 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, + 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, + 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, + 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, + 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, + 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, + 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, +5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; + +static int vtsize[9] = +{4, 8, 8, 12, 12, 16, 20, 20, 24}; /* How big is the torppacket */ +int vtisize[9] = +{4, 7, 9, 11, 13, 16, 18, 20, 22}; /* 4 byte Header + torpdata */ + + +static int +padto4(sz) + int sz; +{ + return (sz % 4) ? (sz / 4 + 1) * 4 : sz; + +} +#endif + +int +size_of_spacket(pkt) + unsigned char *pkt; +{ + switch (pkt[0]) + { + case SP_GPARAM: + switch (pkt[1]) + { + case 0: + return sizeof(struct gp_sizes_spacket); + case 1: + return sizeof(struct gp_team_spacket); + case 2: + return sizeof(struct gp_teamlogo_spacket); + case 3: + return sizeof(struct gp_shipshape_spacket); + case 4: + return sizeof(struct gp_shipbitmap_spacket); + case 5: + return sizeof(struct gp_rank_spacket); + case 6: + return sizeof(struct gp_royal_spacket); + case 7: + return sizeof(struct gp_teamplanet_spacket); + default: + return 0; + } +#ifdef SHORT_PACKETS + case SP_S_MESSAGE: + return padto4(pkt[4]); /* IMPORTANT Changed */ + case SP_S_WARNING: + if (pkt[1] == STEXTE_STRING || + pkt[1] == SHORT_WARNING) + { + return padto4(pkt[3]); + } + else + return 4; /* Normal Packet */ + case SP_S_PLAYER: + if (pkt[1] & 128) + { /* Small +extended Header */ + return padto4(((pkt[1] & 0x3f) * 4) + 4); + } + else if (pkt[1] & 64) + { /* Small Header */ + return padto4(((pkt[1] & 0x3f) * 4) + 4); + } + else + { /* Big Header */ + return padto4((pkt[1] * 4 + 12)); + } + case SP_S_TORP: + return padto4(vtsize[numofbits[pkt[1]]]); + case SP_S_TORP_INFO: + return padto4((vtisize[numofbits[pkt[1]]] + numofbits[pkt[3]])); + case SP_S_PLANET: + return padto4((pkt[1] * VPLANET_SIZE) + 2); +#endif + case SP_PARADISE_EXT1: + switch (pkt[1]) + { + case SP_PE1_MISSING_BITMAP: + return sizeof(struct pe1_missing_bitmap_spacket); + case SP_PE1_NUM_MISSILES: + return sizeof(struct pe1_num_missiles_spacket); + default: + return 0; + } + default: +#ifdef FEATURE_DIAG + if (*pkt >= num_spacket_sizes) + { + fprintf(stderr, "Packet type %d out of range (%d)\n", (*pkt), num_spacket_sizes); + return (0); + } + if (server_packet_sizes[*pkt] < 0) + { + fprintf(stderr, "Packet type %d has no size\n", (*pkt)); + return (0); + } + return (server_packet_sizes[*pkt]); +#else + return (*pkt < num_spacket_sizes && server_packet_sizes[*pkt] >= 0) + ? server_packet_sizes[*pkt] : 0; +#endif + } +} diff -r cafa94d86546 -r aa38447a4b21 src/packets.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/packets.h Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,1201 @@ +/*-------------------------------------------------------------------------- +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 file for socket I/O xtrek. + * + * Kevin P. Smith 1/29/89 + */ + +#ifndef packets_h_ +#define packets_h_ + +#define STATUS_TOKEN "\t@@@" /* ATM */ + +/* + * the following typedefs allow portability to machines without the + * ubiquitous 32-bit architecture (KSR1, Cray, DEC Alpha) + */ + +typedef unsigned int CARD32; +typedef unsigned short CARD16; +typedef unsigned char CARD8; + +typedef int INT32; +typedef short INT16; +#if __STDC__ || defined(sgi) || defined(AIXV3) +typedef signed char INT8; +#else +/* stupid compilers */ +typedef char INT8; +#endif + +/* + * TCP and UDP use identical packet formats; the only difference is that, + * when in UDP mode, all packets sent from server to client have a sequence + * number appended to them. + * + * (note: ALL packets, whether sent on the TCP or UDP channel, will have the + * sequence number. Thus it's important that client & server agree on when + * to switch. This was done to keep critical and non-critical data in sync.) + */ + +/* + * the various pad members of the structures are used for explicit data + * alignment. They do not contain any data. All structures are aligned to 4 + * bytes. If your compiler forces 8 byte alignment, you will not be adhering + * to the netrek protocol. + */ + +/* packets sent from xtrek server to remote client */ +#define SP_MESSAGE 1 +#define SP_PLAYER_INFO 2 /* general player info not elsewhere */ +#define SP_KILLS 3 /* # kills a player has */ +#define SP_PLAYER 4 /* x,y for player */ +#define SP_TORP_INFO 5 /* torp status */ +#define SP_TORP 6 /* torp location */ +#define SP_PHASER 7 /* phaser status and direction */ +#define SP_PLASMA_INFO 8 /* player login information */ +#define SP_PLASMA 9 /* like SP_TORP */ +#define SP_WARNING 10 /* like SP_MESG */ +#define SP_MOTD 11 /* line from .motd screen */ +#define SP_YOU 12 /* info on you? */ +#define SP_QUEUE 13 /* estimated loc in queue? */ +#define SP_STATUS 14 /* galaxy status numbers */ +#define SP_PLANET 15 /* planet armies & facilities */ +#define SP_PICKOK 16 /* your team & ship was accepted */ +#define SP_LOGIN 17 /* login response */ +#define SP_FLAGS 18 /* give flags for a player */ +#define SP_MASK 19 /* tournament mode mask */ +#define SP_PSTATUS 20 /* give status for a player */ +#define SP_BADVERSION 21 /* invalid version number */ +#define SP_HOSTILE 22 /* hostility settings for a player */ +#define SP_STATS 23 /* a player's statistics */ +#define SP_PL_LOGIN 24 /* new player logs in */ +#define SP_RESERVED 25 /* for future use */ +#define SP_PLANET_LOC 26 /* planet name, x, y */ + +#define SP_SCAN 27 /* scan packet */ +#define SP_UDP_REPLY 28 /* notify client of UDP status */ +#define SP_SEQUENCE 29 /* sequence # packet */ +#define SP_SC_SEQUENCE 30 /* this trans is semi-critical info */ +#define SP_RSA_KEY 31 /* RSA data packet */ + +#define SP_MOTD_PIC 32 /* motd bitmap pictures */ +#define SP_STATS2 33 /* new stats packet */ +#define SP_STATUS2 34 /* new status packet */ +#define SP_PLANET2 35 /* new planet packet */ +#define SP_NEW_MOTD 36 /* New MOTD info notification uses */ +#define SP_THINGY 37 /* thingy location */ +#define SP_THINGY_INFO 38 /* thingy status */ +#define SP_SHIP_CAP 39 /* ship capabilities */ + +#ifdef SHORT_PACKETS +#define SP_S_REPLY 40 /* reply to send-short request */ +#define SP_S_MESSAGE 41 /* var. Message Packet */ +#define SP_S_WARNING 42 /* Warnings with 4 Bytes */ +#define SP_S_YOU 43 /* hostile,armies,whydead,etc .. */ +#define SP_S_YOU_SS 44 /* your ship status */ +#define SP_S_PLAYER 45 /* variable length player packet */ +#endif + +#define SP_PING 46 /* ping packet */ + +#ifdef SHORT_PACKETS +#define SP_S_TORP 47 /* variable length torp packet */ +#define SP_S_TORP_INFO 48 /* SP_S_TORP with TorpInfo */ +#define SP_S_8_TORP 49 /* optimized SP_S_TORP */ +#define SP_S_PLANET 50 /* see SP_PLANET */ + +/* variable length packets */ +#define VPLAYER_SIZE 4 +#define SHORTVERSION 10 /* other number blocks, like UDP Version */ +#endif + +#define SP_GPARAM 51 /* game params packet */ + +/* + * the following is a family of packets with the same type, but a + * discriminating subtype + */ +#define SP_PARADISE_EXT1 52 +#define SP_PE1_MISSING_BITMAP 0 +#define SP_PE1_NUM_MISSILES 1 +/* end of packet 52 subtypes */ +#define SP_TERRAIN2 53 /* GZipped terrain packet - 5/16/95 rpg */ +#define SP_TERRAIN_INFO2 54 /* header for terrain info */ +#ifdef FEATURE +#define SP_FEATURE 60 /* type 60 is FEATURE packets */ +#endif + + +/* packets sent from remote client to xtrek server */ +#define CP_MESSAGE 1 /* send a message */ +#define CP_SPEED 2 /* set speed */ +#define CP_DIRECTION 3 /* change direction */ +#define CP_PHASER 4 /* phaser in a direction */ +#define CP_PLASMA 5 /* plasma (in a direction) */ +#define CP_TORP 6 /* fire torp in a direction */ +#define CP_QUIT 7 /* self destruct */ +#define CP_LOGIN 8 /* log in (name, password) */ +#define CP_OUTFIT 9 /* outfit to new ship */ +#define CP_WAR 10 /* change war status */ +#define CP_PRACTR 11 /* create practice robot? */ +#define CP_SHIELD 12 /* raise/lower sheilds */ +#define CP_REPAIR 13 /* enter repair mode */ +#define CP_ORBIT 14 /* orbit planet/starbase */ +#define CP_PLANLOCK 15 /* lock on planet */ +#define CP_PLAYLOCK 16 /* lock on player */ +#define CP_BOMB 17 /* bomb a planet */ +#define CP_BEAM 18 /* beam armies up/down */ +#define CP_CLOAK 19 /* cloak on/off */ +#define CP_DET_TORPS 20 /* detonate enemy torps */ +#define CP_DET_MYTORP 21 /* detonate one of my torps */ +#define CP_COPILOT 22 /* toggle copilot mode */ +#define CP_REFIT 23 /* refit to different ship type */ +#define CP_TRACTOR 24 /* tractor on/off */ +#define CP_REPRESS 25 /* pressor on/off */ +#define CP_COUP 26 /* coup home planet */ +#define CP_SOCKET 27 /* new socket for reconnection */ +#define CP_OPTIONS 28 /* send my options to be saved */ +#define CP_BYE 29 /* I'm done! */ +#define CP_DOCKPERM 30 /* set docking permissions */ +#define CP_UPDATES 31 /* set number of usecs per update */ +#define CP_RESETSTATS 32 /* reset my stats packet */ +#define CP_RESERVED 33 /* for future use */ + +#define CP_SCAN 34 /* ATM: request for player scan */ + +#define CP_UDP_REQ 35 /* request UDP on/off */ +#define CP_SEQUENCE 36 /* sequence # packet */ +#define CP_RSA_KEY 37 /* request MOTD */ +#define CP_ASK_MOTD 38 /* request MOTD */ + +#define CP_PING_RESPONSE 42 /* client response */ + +#ifdef SHORT_PACKETS +#define CP_S_REQ 43 +#define CP_S_THRS 44 +#define CP_S_MESSAGE 45 /* vari. Message Packet */ +#define CP_S_RESERVED 46 +#define CP_S_DUMMY 47 +#endif + +#ifdef FEATURE +#define CP_FEATURE 60 /* Feature packets */ +#endif + +#define SOCKVERSION 4 +#define UDPVERSION 10 /* changing this blocks other */ +/* versions */ + +struct packet_handler +{ + void (*handler) (); +}; + + +/* + * These are server --> client packets + */ + +struct mesg_spacket +{ + INT8 type; /* SP_MESSAGE */ + CARD8 m_flags; + CARD8 m_recpt; + CARD8 m_from; + char mesg[80]; +}; + +struct plyr_info_spacket +{ + INT8 type; /* SP_PLAYER_INFO */ + INT8 pnum; + INT8 shiptype; + INT8 team; +}; + +struct kills_spacket +{ + INT8 type; /* SP_KILLS */ + INT8 pnum; + INT8 pad1; + INT8 pad2; + CARD32 kills; /* where 1234=12.34 kills and 0=0.00 kills */ +}; + +struct player_spacket +{ + INT8 type; /* SP_PLAYER */ + INT8 pnum; + CARD8 dir; + INT8 speed; + INT32 x, y; +}; + +struct torp_info_spacket +{ + INT8 type; /* SP_TORP_INFO */ + INT8 war; + INT8 status; /* TFREE, TDET, etc... */ + INT8 pad1; /* pad needed for cross cpu compatibility */ + INT16 tnum; + INT16 pad2; +}; + +struct torp_spacket +{ + INT8 type; /* SP_TORP */ + CARD8 dir; + INT16 tnum; + INT32 x, y; +}; + +/* + * Shapes of thingys. It would be best to add to the end of this list and + * try to coordinate your additions with other hackers. + */ +enum thingy_types +{ + SHP_BLANK, SHP_MISSILE, SHP_BOOM, SHP_TORP, SHP_PLASMA, SHP_MINE, + SHP_PBOOM, SHP_FIGHTER, SHP_WARP_BEACON +}; + +struct thingy_info_spacket +{ + INT8 type; /* SP_THINGY_INFO */ + INT8 war; + INT16 shape; /* a thingy_types */ + INT16 tnum; + INT16 owner; +}; + +struct thingy_spacket +{ + INT8 type; /* SP_THINGY */ + CARD8 dir; + INT16 tnum; + INT32 x, y; +}; + +struct phaser_spacket +{ + INT8 type; /* SP_PHASER */ + INT8 pnum; + INT8 status; /* PH_HIT, etc... */ + CARD8 dir; + INT32 x, y; + INT32 target; +}; + +struct plasma_info_spacket +{ + INT8 type; /* SP_PLASMA_INFO */ + INT8 war; + INT8 status; /* TFREE, TDET, etc... */ + INT8 pad1; /* pad needed for cross cpu compatibility */ + INT16 pnum; + INT16 pad2; +}; + +struct plasma_spacket +{ + INT8 type; /* SP_PLASMA */ + INT8 pad1; + INT16 pnum; + INT32 x, y; +}; + +struct warning_spacket +{ + INT8 type; /* SP_WARNING */ + INT8 pad1; + INT8 pad2; + INT8 pad3; + char mesg[80]; +}; + +struct motd_spacket +{ + INT8 type; /* SP_MOTD */ + INT8 pad1; + INT8 pad2; + INT8 pad3; + char line[80]; +}; + +struct you_spacket +{ + INT8 type; /* SP_YOU */ + INT8 pnum; /* Guy needs to know this... */ + INT8 hostile; + INT8 swar; + INT8 armies; + INT8 tractor; /* ATM - visible tractor (was pad1) */ + CARD8 pad2; + CARD8 pad3; + CARD32 flags; + INT32 damage; + INT32 shield; + INT32 fuel; + INT16 etemp; + INT16 wtemp; + INT16 whydead; + INT16 whodead; +}; + +struct queue_spacket +{ + INT8 type; /* SP_QUEUE */ + INT8 pad1; + INT16 pos; +}; + +struct status_spacket +{ + INT8 type; /* SP_STATUS */ + INT8 tourn; + INT8 pad1; + INT8 pad2; + CARD32 armsbomb; + CARD32 planets; + CARD32 kills; + CARD32 losses; + CARD32 time; + CARD32 timeprod; +}; + +struct planet_spacket +{ + INT8 type; /* SP_PLANET */ + INT8 pnum; + INT8 owner; + INT8 info; + INT16 flags; + INT16 pad2; + INT32 armies; +}; + +struct pickok_spacket +{ + INT8 type; /* SP_PICKOK */ + INT8 state; + INT8 pad2; + INT8 pad3; +}; + +struct login_spacket +{ + INT8 type; /* SP_LOGIN */ + INT8 accept; /* 1/0 */ + INT8 pad2; + INT8 pad3; + INT32 flags; + char keymap[96]; +}; + +struct flags_spacket +{ + INT8 type; /* SP_FLAGS */ + INT8 pnum; /* whose flags are they? */ + INT8 tractor; /* ATM - visible tractors */ + INT8 pad2; + CARD32 flags; +}; + +struct mask_spacket +{ + INT8 type; /* SP_MASK */ + INT8 mask; + INT8 pad1; + INT8 pad2; +}; + +struct pstatus_spacket +{ + INT8 type; /* SP_PSTATUS */ + INT8 pnum; + INT8 status; + INT8 pad1; +}; + +struct badversion_spacket +{ + INT8 type; /* SP_BADVERSION */ + INT8 why; + INT8 pad2; + INT8 pad3; +}; + +struct hostile_spacket +{ + INT8 type; /* SP_HOSTILE */ + INT8 pnum; + INT8 war; + INT8 hostile; +}; + +struct stats_spacket +{ + INT8 type; /* SP_STATS */ + INT8 pnum; + INT8 pad1; + INT8 pad2; + INT32 tkills; /* Tournament kills */ + INT32 tlosses; /* Tournament losses */ + INT32 kills; /* overall */ + INT32 losses; /* overall */ + INT32 tticks; /* ticks of tournament play time */ + INT32 tplanets; /* Tournament planets */ + INT32 tarmies; /* Tournament armies */ + INT32 sbkills; /* Starbase kills */ + INT32 sblosses; /* Starbase losses */ + INT32 armies; /* non-tourn armies */ + INT32 planets; /* non-tourn planets */ + INT32 maxkills; /* max kills as player * 100 */ + INT32 sbmaxkills; /* max kills as sb * 100 */ +}; + +struct plyr_login_spacket +{ + INT8 type; /* SP_PL_LOGIN */ + INT8 pnum; + INT8 rank; + INT8 pad1; + INT8 name[16]; + INT8 monitor[16]; + INT8 login[16]; +}; + +struct reserved_spacket +{ + INT8 type; /* SP_RESERVED */ + INT8 pad1; + INT8 pad2; + INT8 pad3; + INT8 data[16]; +}; + +struct planet_loc_spacket +{ + INT8 type; /* SP_PLANET_LOC */ + INT8 pnum; + INT8 pad2; + INT8 pad3; + INT32 x; + INT32 y; + INT8 name[16]; +}; + +struct scan_spacket +{ /* ATM */ + INT8 type; /* SP_SCAN */ + INT8 pnum; + INT8 success; + INT8 pad1; + INT32 p_fuel; + INT32 p_armies; + INT32 p_shield; + INT32 p_damage; + INT32 p_etemp; + INT32 p_wtemp; +}; + +struct udp_reply_spacket +{ /* UDP */ + INT8 type; /* SP_UDP_REPLY */ + INT8 reply; + INT8 pad1; + INT8 pad2; + INT32 port; +}; + +struct sequence_spacket +{ /* UDP */ + INT8 type; /* SP_SEQUENCE */ + INT8 pad1; + CARD16 sequence; +}; +struct sc_sequence_spacket +{ /* UDP */ + INT8 type; /* SP_CP_SEQUENCE */ + INT8 pad1; + CARD16 sequence; +}; + +/* + * Game configuration. KAO 1/23/93 + */ + +struct ship_cap_spacket +{ /* Server configuration of client */ + INT8 type; /* screw motd method */ + INT8 operation; /* 0 = add/change a ship, 1 = remove a ship */ + INT16 s_type; /* SP_SHIP_CAP */ + INT16 s_torpspeed; + INT16 s_phaserrange; + INT32 s_maxspeed; + INT32 s_maxfuel; + INT32 s_maxshield; + INT32 s_maxdamage; + INT32 s_maxwpntemp; + INT32 s_maxegntemp; + INT16 s_width; + INT16 s_height; + INT16 s_maxarmies; + INT8 s_letter; + INT8 pad2; + INT8 s_name[16]; + INT8 s_desig1; + INT8 s_desig2; + INT16 s_bitmap; +}; + +struct motd_pic_spacket +{ + INT8 type; /* SP_MOTD_PIC */ + INT8 pad1; + INT16 x, y, page; + INT16 width, height; + INT8 bits[1016]; +}; + + +/* This is used to send paradise style stats */ +struct stats_spacket2 +{ + INT8 type; /* SP_STATS2 */ + INT8 pnum; + INT8 pad1; + INT8 pad2; + + INT32 genocides; /* number of genocides participated in */ + INT32 maxkills; /* max kills ever * 100 */ + INT32 di; /* destruction inflicted for all time * 100 */ + INT32 kills; /* Kills in tournament play */ + INT32 losses; /* Losses in tournament play */ + INT32 armsbomb; /* Tournament armies bombed */ + INT32 resbomb; /* resources bombed off */ + INT32 dooshes; /* armies killed while being carried */ + INT32 planets; /* Tournament planets conquered */ + INT32 tticks; /* Tournament ticks */ + /* SB/WB/JS stats are entirely separate */ + INT32 sbkills; /* Kills as starbase */ + INT32 sblosses; /* Losses as starbase */ + INT32 sbticks; /* Time as starbase */ + INT32 sbmaxkills; /* Max kills as starbase * 100 */ + INT32 wbkills; /* Kills as warbase */ + INT32 wblosses; /* Losses as warbase */ + INT32 wbticks; /* Time as warbase */ + INT32 wbmaxkills; /* Max kills as warbase * 100 */ + INT32 jsplanets; /* planets assisted with in JS */ + INT32 jsticks; /* ticks played as a JS */ + INT32 rank; /* Ranking of the player */ + INT32 royal; /* royaly, specialty, rank */ +}; + +/* status info for paradise stats */ +struct status_spacket2 +{ + INT8 type; /* SP_STATUS2 */ + INT8 tourn; + INT8 pad1; + INT8 pad2; + CARD32 dooshes; /* total number of armies dooshed */ + CARD32 armsbomb; /* all t-mode armies bombed */ + CARD32 resbomb; /* resources bombed */ + CARD32 planets; /* all t-mode planets taken */ + CARD32 kills; /* all t-mode kills made */ + CARD32 losses; /* all t-mode losses */ + CARD32 sbkills; /* total kills in SB's */ + CARD32 sblosses; /* total losses in Sb's */ + CARD32 sbtime; /* total time in SB's */ + CARD32 wbkills; /* kills in warbases */ + CARD32 wblosses; /* losses in warbases */ + CARD32 wbtime; /* total time played in wb's */ + CARD32 jsplanets; /* total planets taken by jump ships */ + CARD32 jstime; /* total time in a jump ship */ + CARD32 time; /* t mode time in this game */ + CARD32 timeprod; /* t-mode ship ticks--sort of like */ +}; + + +/* planet info for a paradise planet */ +struct planet_spacket2 +{ + INT8 type; /* SP_PLANET2 */ + INT8 pnum; /* planet number */ + INT8 owner; /* owner of the planet */ + INT8 info; /* who has touched planet */ + INT32 flags; /* planet's flags */ + INT32 timestamp; /* timestamp for info on planet */ + INT32 armies; /* armies on the planet */ +}; + +/* terrain info for Paradise terrain */ +/* 5/16/95 rpg */ + +struct terrain_info_packet2 +{ + CARD8 type; /* SP_TERRAIN_INFO2 */ + CARD8 pad; + CARD16 pad2; + CARD16 xdim; /* x dimension of grid */ + CARD16 ydim; /* y dimension of grid */ +}; + +struct terrain_packet2 +{ + CARD8 type; /* SP_TERRAIN2 */ + CARD8 sequence; /* Sequence number - may need multiple + * packets */ + CARD8 total_pkts; /* since terrain is gzipped, we need length + * (may have) */ + CARD8 length; /* multiple packets */ + CARD8 terrain_type[NTERRAIN]; /* send up to 128 gzipped bytes at once */ + /* CARD16 terrain_alt1[128]; *//* Note - these values should be *changed* */ + /* CARD16 terrain_atl2[128]; *//* depending on if alt1/alt2 are used. */ +}; + +struct obvious_packet +{ + INT8 type; /* SP_NEW_MOTD */ + INT8 pad1; /* CP_ASK_MOTD */ +}; + +struct rsa_key_spacket +{ + INT8 type; /* SP_RSA_KEY */ + INT8 pad1; + INT8 pad2; + INT8 pad3; + CARD8 data[KEY_SIZE]; +}; + + +struct ping_spacket +{ + INT8 type; /* SP_PING */ + CARD8 number; /* id (ok to wrap) */ + CARD16 lag; /* delay of last ping in ms */ + + CARD8 tloss_sc; /* total loss server-client 0-100% */ + CARD8 tloss_cs; /* total loss client-server 0-100% */ + + CARD8 iloss_sc; /* inc. loss server-client 0-100% */ + CARD8 iloss_cs; /* inc. loss client-server 0-100% */ +}; + +struct paradiseext1_spacket +{ + INT8 type; + CARD8 subtype; + INT16 pad; +}; + +struct pe1_missing_bitmap_spacket +{ + INT8 type; + CARD8 subtype; + + INT16 page; + + INT16 x, y; + INT16 width, height; +}; + +struct pe1_num_missiles_spacket +{ + INT8 type; /* SP_PARADISE_EXT1 */ + CARD8 subtype; /* SP_PE1_NUM_MISSILES */ + + INT16 num; /* number of missiles */ +}; + +/* + * These are the client --> server packets + */ + +struct mesg_cpacket +{ + INT8 type; /* CP_MESSAGE */ + INT8 group; + INT8 indiv; + INT8 pad1; + INT8 mesg[80]; +}; + +struct speed_cpacket +{ + INT8 type; /* CP_SPEED */ + INT8 speed; + INT8 pad1; + INT8 pad2; +}; + +struct dir_cpacket +{ + INT8 type; /* CP_DIRECTION */ + CARD8 dir; + INT8 pad1; + INT8 pad2; +}; + +struct phaser_cpacket +{ + INT8 type; /* CP_PHASER */ + CARD8 dir; + INT8 pad1; + INT8 pad2; +}; + +struct plasma_cpacket +{ + INT8 type; /* CP_PLASMA */ + CARD8 dir; + INT8 pad1; + INT8 pad2; +}; + +struct torp_cpacket +{ + INT8 type; /* CP_TORP */ + CARD8 dir; /* direction to fire torp */ + INT8 pad1; + INT8 pad2; +}; + +struct quit_cpacket +{ + INT8 type; /* CP_QUIT */ + INT8 pad1; + INT8 pad2; + INT8 pad3; +}; + +struct login_cpacket +{ + INT8 type; /* CP_LOGIN */ + INT8 query; + INT8 pad2; + INT8 pad3; + INT8 name[16]; + INT8 password[16]; + INT8 login[16]; +}; + +struct outfit_cpacket +{ + INT8 type; /* CP_OUTFIT */ + INT8 team; + INT8 ship; + INT8 pad1; +}; + +struct war_cpacket +{ + INT8 type; /* CP_WAR */ + INT8 newmask; + INT8 pad1; + INT8 pad2; +}; + +struct practr_cpacket +{ + INT8 type; /* CP_PRACTR */ + INT8 pad1; + INT8 pad2; + INT8 pad3; +}; + +struct shield_cpacket +{ + INT8 type; /* CP_SHIELD */ + INT8 state; /* up/down */ + INT8 pad1; + INT8 pad2; +}; + +struct repair_cpacket +{ + INT8 type; /* CP_REPAIR */ + INT8 state; /* on/off */ + INT8 pad1; + INT8 pad2; +}; + +struct orbit_cpacket +{ + INT8 type; /* CP_ORBIT */ + INT8 state; /* on/off */ + INT8 pad1; + INT8 pad2; +}; + +struct planlock_cpacket +{ + INT8 type; /* CP_PLANLOCK */ + INT8 pnum; + INT8 pad1; + INT8 pad2; +}; + +struct playlock_cpacket +{ + INT8 type; /* CP_PLAYLOCK */ + INT8 pnum; + INT8 pad1; + INT8 pad2; +}; + +struct bomb_cpacket +{ + INT8 type; /* CP_BOMB */ + INT8 state; + INT8 pad1; + INT8 pad2; +}; + +struct beam_cpacket +{ + INT8 type; /* CP_BEAM */ + INT8 state; + INT8 pad1; + INT8 pad2; +}; + +struct cloak_cpacket +{ + INT8 type; /* CP_CLOAK */ + INT8 state; + INT8 pad1; + INT8 pad2; +}; + +struct det_torps_cpacket +{ + INT8 type; /* CP_DET_TORPS */ + INT8 pad1; + INT8 pad2; + INT8 pad3; +}; + +struct det_mytorp_cpacket +{ + INT8 type; /* CP_DET_MYTORP */ + INT8 pad1; + INT16 tnum; +}; + +struct copilot_cpacket +{ + INT8 type; /* CP_COPLIOT */ + INT8 state; + INT8 pad1; + INT8 pad2; +}; + +struct refit_cpacket +{ + INT8 type; /* CP_REFIT */ + INT8 ship; + INT8 pad1; + INT8 pad2; +}; + +struct tractor_cpacket +{ + INT8 type; /* CP_TRACTOR */ + INT8 state; + INT8 pnum; + INT8 pad2; +}; + +struct repress_cpacket +{ + INT8 type; /* CP_REPRESS */ + INT8 state; + INT8 pnum; + INT8 pad2; +}; + +struct coup_cpacket +{ + INT8 type; /* CP_COUP */ + INT8 pad1; + INT8 pad2; + INT8 pad3; +}; + +struct socket_cpacket +{ + INT8 type; /* CP_SOCKET */ + INT8 version; + INT8 udp_version; /* was pad2 */ + INT8 pad3; + CARD32 socket; +}; + +struct options_cpacket +{ + INT8 type; /* CP_OPTIONS */ + INT8 pad1; + INT8 pad2; + INT8 pad3; + CARD32 flags; + INT8 keymap[96]; +}; + +struct bye_cpacket +{ + INT8 type; /* CP_BYE */ + INT8 pad1; + INT8 pad2; + INT8 pad3; +}; + +struct dockperm_cpacket +{ + INT8 type; /* CP_DOCKPERM */ + INT8 state; + INT8 pad2; + INT8 pad3; +}; + +struct updates_cpacket +{ + INT8 type; /* CP_UPDATES */ + INT8 pad1; + INT8 pad2; + INT8 pad3; + CARD32 usecs; +}; + +struct resetstats_cpacket +{ + INT8 type; /* CP_RESETSTATS */ + INT8 verify; /* 'Y' - just to make sure he meant it */ + INT8 pad2; + INT8 pad3; +}; + +struct reserved_cpacket +{ + INT8 type; /* CP_RESERVED */ + INT8 pad1; + INT8 pad2; + INT8 pad3; + INT8 data[16]; + INT8 resp[16]; +}; + +struct scan_cpacket +{ /* ATM */ + INT8 type; /* CP_SCAN */ + INT8 pnum; + INT8 pad1; + INT8 pad2; +}; + +struct udp_req_cpacket +{ /* UDP */ + INT8 type; /* CP_UDP_REQ */ + INT8 request; + INT8 connmode; /* respond with port # or just send UDP + * packet? */ + INT8 pad2; + INT32 port; /* compensate for hosed recvfrom() */ +}; + +struct sequence_cpacket +{ /* UDP */ + INT8 type; /* CP_SEQUENCE */ + INT8 pad1; + CARD16 sequence; +}; + +struct rsa_key_cpacket +{ + INT8 type; /* CP_RSA_KEY */ + INT8 pad1; + INT8 pad2; + INT8 pad3; + CARD8 global[KEY_SIZE]; + CARD8 public[KEY_SIZE]; + CARD8 resp[KEY_SIZE]; +}; + +/* the CP_ASK_MOTD packet is the same as temp_spacket */ + +struct ping_cpacket +{ + INT8 type; /* CP_PING_RESPONSE */ + CARD8 number; /* id */ + INT8 pingme; /* if client wants server to ping */ + INT8 pad1; + + INT32 cp_sent; /* # packets sent to server */ + INT32 cp_recv; /* # packets recv from server */ +}; + +#ifdef FEATURE +struct feature_cpacket +{ + char type; + char feature_type; + char arg1, arg2; + int value; + char name[80]; +}; + +struct feature_spacket +{ + char type; + char feature_type; + char arg1, arg2; + int value; + char name[80]; +}; +#endif + +/* + * short stuff + */ + +#ifdef SHORT_PACKETS +struct shortreq_cpacket +{ /* CP_S_REQ */ + INT8 type; + INT8 req; + INT8 version; + INT8 pad2; +}; + +struct threshold_cpacket +{ /* CP_S_THRS */ + INT8 type; + INT8 pad1; + CARD16 thresh; +}; + +struct shortreply_spacket +{ /* SP_S_REPLY */ + INT8 type; + INT8 repl; + CARD16 winside; + INT32 gwidth; +}; + +struct youshort_spacket +{ /* SP_S_YOU */ + INT8 type; + + INT8 pnum; + INT8 hostile; + INT8 swar; + + INT8 armies; + INT8 whydead; + INT8 whodead; + + INT8 pad1; + + CARD32 flags; +}; + +struct youss_spacket +{ /* SP_S_YOU_SS */ + INT8 type; + INT8 pad1; + + CARD16 damage; + CARD16 shield; + CARD16 fuel; + CARD16 etemp; + CARD16 wtemp; +}; + +#define VPLANET_SIZE 6 + +struct planet_s_spacket +{ /* body of SP_S_PLANET */ + INT8 pnum; + INT8 owner; + INT8 info; + CARD8 armies; /* more than 255 Armies ? ... */ + INT16 flags; +}; +struct warning_s_spacket +{ /* SP_S_WARNING */ + INT8 type; + CARD8 whichmessage; + INT8 argument, argument2; /* for phaser etc ... */ +}; + +struct player_s_spacket +{ + INT8 type; /* SP_S_PLAYER Header */ + INT8 packets; /* How many player-packets are in this packet + * ( only the first 6 bits are relevant ) */ + CARD8 dir; + INT8 speed; + INT32 x, y; /* To get the absolute Position */ +}; + +/* + * The format of the body: struct player_s_body_spacket { Body of new + * Player Packet CARD8 pnum; 0-4 = pnum, 5 local or galactic, 6 = 9. + * x-bit, 7 9. y-bit CARD8 speeddir; 0-3 = speed , 4-7 direction of ship + * CARD8 x; low 8 bits from X-Pixelcoordinate CARD8 y; low 8 bits + * from Y-Pixelcoordinate }; + */ + +struct torp_s_spacket +{ + INT8 type; /* SP_S_TORP */ + CARD8 bitset; /* bit=1 that torp is in packet */ + CARD8 whichtorps; /* Torpnumber of first torp / 8 */ + CARD8 data[21]; /* For every torp 2*9 bit coordinates */ +}; + +struct mesg_s_spacket +{ + INT8 type; /* SP_S_MESSAGE */ + CARD8 m_flags; + CARD8 m_recpt; + CARD8 m_from; + CARD8 length; /* Length of whole packet */ + INT8 mesg; + INT8 pad2; + INT8 pad3; + INT8 pad[76]; +}; + +struct mesg_s_cpacket +{ + INT8 type; /* CP_S__MESSAGE */ + INT8 group; + INT8 indiv; + INT8 length; /* Size of whole packet */ + INT8 mesg[80]; +}; + +#endif + +#endif diff -r cafa94d86546 -r aa38447a4b21 src/parsexbm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parsexbm.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,159 @@ +/*-------------------------------------------------------------------------- +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 + +#define pm_error(str) {\ +fprintf(stderr, "Error in ParseXbmFile(): %s\n", str);\ +if(*dataP) { free(*dataP); *dataP = 0; }\ +return -1; } + +/* + * most of the following function came from xbmtopbm.c in the PBMPLUS library + */ + +#define MAX_LINE 500 + +int +ParseXbmFile(stream, widthP, heightP, dataP) + FILE *stream; + int *widthP; + int *heightP; + char **dataP; +{ + char line[MAX_LINE], name_and_type[MAX_LINE]; + char *ptr; + char *t; + int raster_length, v; + register int bytes, bytes_per_line; + register int c1, c2, value1, value2; + int hex_table[256]; + + *widthP = *heightP = -1; + *dataP = 0; + + for (;;) + { + if (fgets(line, MAX_LINE, stream) == NULL) + pm_error("EOF / read error"); + if (strlen(line) == MAX_LINE - 1) + pm_error("line too long"); + + if (sscanf(line, "#define %s %d", name_and_type, &v) == 2) + { + if ((t = strrchr(name_and_type, '_')) == NULL) + t = name_and_type; + else + ++t; + if (!strcmp("width", t)) + *widthP = v; + else if (!strcmp("height", t)) + *heightP = v; + continue; + } + + if (sscanf(line, "static char %s = {", name_and_type) == 1 || + sscanf(line, "static unsigned char %s = {", name_and_type) == 1) + break; + } + + if (*widthP == -1) + pm_error("invalid width"); + if (*heightP == -1) + pm_error("invalid height"); + + bytes_per_line = (*widthP + 7) / 8; + + raster_length = bytes_per_line * *heightP; + *dataP = (char *) malloc(raster_length); + if (*dataP == (char *) 0) + pm_error("out of memory"); + + /* Initialize hex_table. */ + for (c1 = 0; c1 < 256; ++c1) + hex_table[c1] = 256; + + hex_table['0'] = 0; + hex_table['1'] = 1; + hex_table['2'] = 2; + hex_table['3'] = 3; + hex_table['4'] = 4; + hex_table['5'] = 5; + hex_table['6'] = 6; + hex_table['7'] = 7; + hex_table['8'] = 8; + hex_table['9'] = 9; + hex_table['A'] = 10; + hex_table['B'] = 11; + hex_table['C'] = 12; + hex_table['D'] = 13; + hex_table['E'] = 14; + hex_table['F'] = 15; + hex_table['a'] = 10; + hex_table['b'] = 11; + hex_table['c'] = 12; + hex_table['d'] = 13; + hex_table['e'] = 14; + hex_table['f'] = 15; + + for (bytes = 0, ptr = *dataP; bytes < raster_length; ++bytes) + { + /* + * Skip until digit is found. + */ + for (;;) + { + c1 = getc(stream); + if (c1 == EOF) + pm_error("EOF / read error"); + value1 = hex_table[c1]; + if (value1 != 256) + break; + } + /* + * Loop on digits. + */ + for (;;) + { + c2 = getc(stream); + if (c2 == EOF) + pm_error("EOF / read error"); + value2 = hex_table[c2]; + if (value2 != 256) + { + value1 = (value1 << 4) | value2; + if (value1 >= 256) + pm_error("syntax error"); + } + else if (c2 == 'x' || c2 == 'X') + { + if (value1 == 0) + continue; + else + pm_error("syntax error"); + } + else + break; + } + *ptr++ = (char) (value1 ^ 0xFF); + } + return (raster_length); +} diff -r cafa94d86546 -r aa38447a4b21 src/path.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/path.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,77 @@ +/*-------------------------------------------------------------------------- +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 + +/* + * This is the default path, you don't have to change this as long as you set + * the NETREKDIR env + */ +char netrekpath[256] = "/local/lib/paradise"; + + +static char buf[512]; +static int initted = 0; + +char * +build_path(suffix) + char *suffix; +{ + int len; + if (!initted) + { + char *ptr; + initted = 1; + ptr = (char *) getenv("NETREKDIR"); + if (ptr == NULL) + { + fprintf(stderr, "Warning, no NETREKDIR envariable. Using default of %s\n", netrekpath); + } + else + { + strncpy(netrekpath, ptr, 255); + netrekpath[255] = '\0'; + } + len = strlen(netrekpath); + if (len > 230) + { + fprintf(stderr, "NETREKDIR enviroment variable too long.\n"); + fprintf(stderr, "Please change it.\n"); + exit(1); + } + if (netrekpath[len - 1] != '/') + { + netrekpath[len] = '/'; + netrekpath[len + 1] = '\0'; + } + } + if (*suffix == '/') + { /* absolute path... don't prepend anything */ + strcpy(buf, suffix); + } + else + { + strcpy(buf, netrekpath); + strcat(buf, suffix); + } + + return buf; +} diff -r cafa94d86546 -r aa38447a4b21 src/path.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/path.h Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,19 @@ +/*-------------------------------------------------------------------------- +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 *build_path(); diff -r cafa94d86546 -r aa38447a4b21 src/phaser.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/phaser.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,247 @@ +/*-------------------------------------------------------------------------- +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" + +/*-----------------------------VISIBLE FUNCTIONS---------------------------*/ + +/*----------------------------------PHASER---------------------------------*/ +/* + * This function shoots a phaser for a player. Various conditions are + * checked to see if the phaser should be allowed to fire. If the player can + * fire then, a player is found in the direction the phaser was fired. + */ + + +extern int angdist(); + +void +phaser(course) + unsigned char course; +{ + int i; /* looping var */ + struct player *j, *target = 0;/* to hold player found */ + struct plasmatorp *k, *target2 = 0; /* to hold plasma torp found */ + struct missile *d, *target3 = 0; + struct phaser *mine; /* to pnt to player's phaser */ + int whichtarget; /* to hold type of target */ + int target_x = 0, target_y = 0; /* target's x and y coords */ + unsigned char dir; /* to get direction of phasr */ + int range, trange; /* range of target */ + int maxangle; /* potential target range */ + int myphrange; /* angle to hit potentl targ */ + char buf[80]; /* to sprintf warnings into */ + + mine = &phasers[me->p_no]; /* get phaser struct */ + if (!(myship->s_nflags & SFNHASPHASERS)) + { /* do we have phasers? */ + warning("Weapons Officer: This ship is not armed with phasers, captain!"); + return; + } + if (mine->ph_status != PHFREE) + { /* is phaser currently being */ + warning("Phasers have not recharged"); /* fired */ + return; + } + if (me->p_fuel < myship->s_phaser.cost) + { /* do we have enough fuel */ + warning("Not enough fuel for phaser"); + return; + } + if (me->p_flags & PFREPAIR) + { /* cannot fire while in */ + warning("Can't fire while repairing"); /* repair mode */ + return; + } + if (me->p_flags & PFWEP) + { /* cannot fire while weapon */ + warning("Weapons overheated"); /* temped */ + return; + } + if ((me->p_cloakphase) && (me->p_ship.s_type != ATT)) + { + warning("Cannot fire while cloaked"); /* cannot fire while cloaked */ + return; + } + if (!check_fire_warp() + || !check_fire_warpprep() + || !check_fire_docked()) + return; + + me->p_fuel -= myship->s_phaser.cost; /* subtract off fuel cost */ + me->p_wtemp += myship->s_phaser.wtemp; /* add to w temp */ + mine->ph_dir = course; /* get direction of phaser */ + whichtarget = 0; /* no target fount yet */ + range = 1000000; /* Sufficiently big. */ + /* check the players */ + for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) + { /* loop all players */ + if (((j->p_status != PALIVE) +#ifdef PFBIRD + && !(j->p_flags & PFBIRD) +#endif + ) || (j == me)) /* only check alive players */ + continue; + if ((!((j->p_swar | j->p_hostile) & me->p_team)) && + (!((me->p_swar | me->p_hostile) & j->p_team)) && +#ifdef PFBIRD + !(j->p_flags & PFBIRD) +#endif + ) + continue; /* only check at war with */ + dir = (unsigned char) (int) (atan2((double) (j->p_x - me->p_x), + (double) (me->p_y - j->p_y)) / 3.14159 * 128.); + /* get range of target */ + trange = ihypot(j->p_x - me->p_x, j->p_y - me->p_y); + if (trange == 0) /* don't want zero in atan */ + trange = 1; + maxangle = atan((float) EXPDIST / trange) / 3.14159 * 128.0; + if (angdist(dir, course) <= maxangle) + { /* if angle within tolerance */ + if (range > trange) + { /* then check to see if */ + whichtarget = 1; /* this is the closest target */ + target = j; /* found yet */ + range = trange; /* record if it is */ + } + } + } /* check the plasmas */ + for (i = 0, k = &plasmatorps[i]; i < MAXPLASMA * MAXPLAYER; i++, k++) + { + if ((k->pt_status != PTMOVE) || (k->pt_owner == me->p_no)) + continue; /* only check live plasmas */ + if ((!(k->pt_war & me->p_team)) && /* and unfriendly ones */ + (!((me->p_swar | me->p_hostile) & k->pt_team))) + continue; + dir = (unsigned char) (int) (atan2((double) (k->pt_x - me->p_x), + (double) (me->p_y - k->pt_y)) / 3.14159 * 128.); /* find direction */ + trange = ihypot(k->pt_x - me->p_x, k->pt_y - me->p_y); + if (trange == 0) /* no zeroes in math funcs */ + trange = 1; + maxangle = atan((float) EXPDIST / 4 / trange) / 3.14159 * 128.0; + if (angdist(dir, course) <= (maxangle + 1)) + { /* if we can hit it */ + if (range > trange) + { /* then check to see if this */ + target_x = k->pt_x; /* is the closest plasma */ + target_y = k->pt_y; /* found yet */ + whichtarget = 2; /* and record it if it is */ + target2 = k; + range = trange; + } + } + } + /* check the fighters */ + for (i = 0, d = &missiles[i]; i < NPTHINGIES * MAXPLAYER; i++, d++) + { + if ((d->ms_owner == me->p_no) || (d->ms_type != FIGHTERTHINGY)) + continue; /* only check live fighters */ + if ((!(d->ms_war & me->p_team)) && /* and unfriendly ones */ + (!((me->p_swar | me->p_hostile) & d->ms_team))) + continue; + dir = (unsigned char) (atan2((double) (d->ms_x - me->p_x), + (double) (me->p_y - d->ms_y)) + / 3.14159 * 128.); /* find direction */ + trange = ihypot(d->ms_x - me->p_x, d->ms_y - me->p_y); + if (trange == 0) /* no zeroes in math funcs */ + trange = 1; + maxangle = atan((float) EXPDIST / 8 / trange) / 3.14159 * 128.0; + if (angdist(dir, course) <= (maxangle + 1)) + { /* if we can hit it */ + if (range > trange) + { /* then check to see if this */ + target_x = d->ms_x; /* is the closest fighter */ + target_y = d->ms_y; /* found yet */ + whichtarget = 3; /* and record it if it is */ + target3 = d; + range = trange; + } + } + } + + mine->ph_fuse = me->p_ship.s_phaser.fuse; /* set phaser fuse */ + myphrange = me->p_ship.s_phaser.speed; /* phaser range */ + if ((whichtarget == 0) || /* if no target found or all */ + (range > myphrange)) + { /* targets too long */ + mine->ph_status = PHMISS; /* then we missed */ + warning("Phaser missed!!!"); + } + else if (whichtarget == 2) + { /* if we hit a plasma then */ + warning("You destroyed the plasma torpedo!"); + mine->ph_x = target_x; /* the set point to shoot at */ + mine->ph_y = target_y; + mine->ph_status = PHHIT2; /* we hit a plasma */ + target2->pt_status = PTEXPLODE; /* Plasmas hurt everyone */ + target2->pt_whodet = me->p_no; + } + else if (whichtarget == 3) + { /* if we hit a fighter then */ + warning("You shot a fighter!"); + mine->ph_x = target_x; /* the set point to shoot at */ + mine->ph_y = target_y; + mine->ph_status = PHHIT2; /* we hit the fighter */ + target3->ms_status = TDET; /* det the fighter */ + target3->ms_whodet = me->p_no; + } + else + { /* else if we hit player */ + mine->ph_target = target->p_no; /* set the player number */ + mine->ph_damage = me->p_ship.s_phaser.damage * /* get damage */ + (1.0 - (range / (float) myphrange)); + if (mine->ph_damage < 0) /* if damage inflicted */ + mine->ph_damage = -mine->ph_damage; /* set the phaser damage */ + mine->ph_status = PHHIT; /* status is a hit */ + +#ifdef PFBIRD + if (target->p_flags & PFBIRD) + { + /* change to PHHIT2 so phaser won't follow bird */ + mine->ph_status = PHHIT2; + mine->ph_x = target->p_x; + mine->ph_y = target->p_y; + /* xx: slight misuse of fields here */ + target->p_damage = mine->ph_damage; + target->p_whodead = me->p_no; + + (void) sprintf(buf, "\"AAWWK!\""); + } +#endif + + (void) sprintf(buf, "Phaser burst hit %s for %d points", + target->p_name, mine->ph_damage); + warning(buf); + } +} + +/*------------------------------------------------------------------------*/ + + + + + +/*-------END OF FILE-------*/ diff -r cafa94d86546 -r aa38447a4b21 src/ping.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ping.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,374 @@ +/*-------------------------------------------------------------------------- +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 "defs.h" +#include "struct.h" +#include "data.h" +#include "packets.h" +#include "shmem.h" + +#define PING_DEBUG 0 /* debugging */ + +/* special fields in stats record for rountrip delay and packet loss */ +#define INL_STATS + + +static unsigned char ping_id; /* wraparound expected */ +static int ping_lag; /* ping roundtrip delay */ + +static int tloss_sc, /* total packet loss s-c */ + tloss_cs, /* total packet loss c-s */ + iloss_sc, /* inc. packet loss s-c */ + iloss_cs; /* inc. packet loss c-s */ + +/* + * This structure allows us to send several pings before any response is + * received without losing information -- as would be the case for roundtrip + * times equal to or larger then the ping interval times. HASHSIZE * ping + * interval must be greater then the largest expected roundtrip time. + */ + +#define HASHSIZE 32 +#define PITH(i) (((int)i) & (HASHSIZE-1)) + +static +struct +{ + long time; + long packets_sent_at_ping; +} ping_sent[HASHSIZE]; + + +void calc_loss(); +void update_lag_stats(); +void update_loss_stats(); +int mstime(); +int msetime(); + +/* + * response from client + */ + +void +pingResponse(packet) + struct ping_cpacket *packet; +{ + register i; + static int last_num; + + if (!ping || packet->pingme != 1) + return; /* oops, garbage */ + + ping_ghostbust = 0; /* don't ghostbust, client is alive */ + + /* throw out out-of-order packets */ + i = uchar_diff((int) packet->number, last_num); + if (i < 0) + { +#if PING_DEBUG >= 1 + fprintf(stderr, "out-of-order response ignored: %d (last: %d)\n", + packet->number, last_num); + fflush(stderr); +#endif + return; + } + last_num = packet->number; + i = PITH(last_num); + + /* calculate roundtrip */ + ping_lag = mstime() - ping_sent[i].time; + +#ifdef INL_STATS + /* fill in lag stats fields */ + update_lag_stats(); +#endif + + /* watch out for div by 0 */ + if (!packets_received || !ping_sent[i].packets_sent_at_ping) + return; + + /* calculate total packet loss */ + calc_loss(i, packet); + +#ifdef INL_STATS + update_loss_stats(); +#endif +} + +/* + * request from server + */ + +void +sendClientPing() +{ + struct ping_spacket packet; + + ping_ghostbust++; + ping_id++; /* ok to wrap */ + + packet.type = SP_PING; + packet.number = (unsigned char) ping_id; + packet.lag = htons((unsigned short) ping_lag); + packet.tloss_sc = tloss_sc; + packet.tloss_cs = tloss_cs; + packet.iloss_sc = iloss_sc; + packet.iloss_cs = iloss_cs; + + ping_sent[PITH(ping_id)].time = mstime(); + /* + * printf("ping sent at %d\n", msetime()); + */ + + sendClientPacket(&packet); + + ping_sent[PITH(ping_id)].packets_sent_at_ping = packets_sent; +} + +void +calc_loss(i, packet) + int i; + struct ping_cpacket *packet; +{ + /* tloss vars */ + register cp_recv, /* client packets recv */ + cp_sent; /* client packets sent */ + int s_to_c_dropped, /* server to client */ + c_to_s_dropped; /* client to server */ + static int old_s_to_c_dropped,/* previous update */ + old_c_to_s_dropped; /* "" */ + /* iloss vars */ + int p_sent, p_recv; + + static + int timer; + + static int inc_packets_sent, /* packets sent start-point */ + inc_packets_received, /* packets recvd start-pt */ + inc_s_to_c_dropped, /* dropped s-to-c start-pt */ + inc_c_to_s_dropped; /* dropped c-to-s start-pt */ + + if (!timer) + timer = configvals->ping_iloss_interval; + + cp_recv = ntohl(packet->cp_recv); + cp_sent = ntohl(packet->cp_sent); + + /* at ping time, total packets dropped from server to client */ + s_to_c_dropped = ping_sent[i].packets_sent_at_ping - cp_recv; + + if (s_to_c_dropped < old_s_to_c_dropped) + { + /* + * The network may duplicate or send out-of-order packets. Both are + * detected and thrown out by the client if sequence checking is on. If + * not there's not much we can do -- there's no way to distinguish a + * duplicated packet from a series of out of order packets. While the + * latter case cancels itself out eventually in terms of packet loss, the + * former hides real packet loss by adding extra packets. We'll have to + * kludge it by adding the extra packets the client thinks it got to + * packets_sent + */ + packets_sent += old_s_to_c_dropped - s_to_c_dropped; + /* and adjust s_to_c_dropped so we don't get a negative packet loss */ + s_to_c_dropped = old_s_to_c_dropped; + } + + /* total loss server-to-client since start of connection */ + tloss_sc = 100 - + (100 * (ping_sent[i].packets_sent_at_ping - s_to_c_dropped)) / + ping_sent[i].packets_sent_at_ping; + + /* + * at ping time, total packets dropped from client to server NOTE: not + * packets_received_at_ping since the client may have sent any amount of + * packets between the time we sent the ping and the time the client + * received it. + */ + c_to_s_dropped = cp_sent - packets_received; + +#if PING_DEBUG >= 2 + printf("cp_sent: %d, packets_received: %d\n", + cp_sent, packets_received); +#endif + + if (c_to_s_dropped < old_c_to_s_dropped) + { + /* + * The network may duplicate or send out-of-order packets. Since no + * sequence checking is done by the server, there's not much we can do -- + * there's no way to distinguish a duplicated packet from a series of out + * of order packets. While the latter case cancels itself out eventually + * in terms of packet loss, the former hides real packet loss by adding + * extra packets. We'll have to kludge it by subtracting the extra + * packets we think we got from the client from packets_received. + */ + packets_received -= old_c_to_s_dropped - c_to_s_dropped; + /* and adjust c_to_s_dropped so we don't get a negative packet loss */ + c_to_s_dropped = old_c_to_s_dropped; + } + + /* total loss client-to-server since start of connection */ + tloss_cs = 100 - + (100 * (packets_received - c_to_s_dropped)) / (packets_received ? packets_received : 1); + + old_s_to_c_dropped = s_to_c_dropped; + old_c_to_s_dropped = c_to_s_dropped; + + /* Incremental packet loss */ + + /* packets sent since last ping response */ + p_sent = ping_sent[i].packets_sent_at_ping - inc_packets_sent; + + /* packets received since last ping response */ + p_recv = packets_received - inc_packets_received; + + if (!p_sent || !p_recv) + { + /* just in case */ + return; + } + + /* percent loss server-to-client since PACKET_LOSS_INTERVAL */ + iloss_sc = 100 - + (100 * (p_sent - (s_to_c_dropped - inc_s_to_c_dropped))) / p_sent; + /* + * we're not going to do any of the adjustments we did in tloss + * calculations since this starts fresh every PACKET_LOSS_INTERVAL + */ + if (iloss_sc < 0) + iloss_sc = 0; + + /* total percent loss client-to-server since PACKET_LOSS_INTERVAL */ + iloss_cs = 100 - + (100 * (p_recv - (c_to_s_dropped - inc_c_to_s_dropped))) / p_recv; + /* + * we're not going to do any of the adjustments we did in tloss + * calculations since this starts fresh every PACKET_LOSS_INTERVAL + */ + if (iloss_cs < 0) + iloss_cs = 0; + + /* + * we update these variables every PACKET_LOSS_INTERVAL seconds to start a + * fresh increment + */ + if ((timer % configvals->ping_iloss_interval) == 0) + { + inc_s_to_c_dropped = s_to_c_dropped; + inc_c_to_s_dropped = c_to_s_dropped; + + inc_packets_sent = ping_sent[i].packets_sent_at_ping; + inc_packets_received = packets_received; + } + + timer++; +} + +#ifdef INL_STATS + +/* + * Lag stats struct player .p_avrt - average round trip time ms struct + * player .p_stdv - standard deviation in rt time struct player .p_pkls - + * input/output packet loss + */ + +static int sum, n, s2; +static int M, var; + +void +update_lag_stats() +{ + n++; + sum += ping_lag; + s2 += (ping_lag * ping_lag); + if (n == 1) + return; + + M = sum / n; + var = (s2 - M * sum) / (n - 1); + + /* average round trip time */ + me->p_avrt = M; + /* standard deviation */ + if (var > 0) + me->p_stdv = (int) isqrt(var); +} + +void +update_loss_stats() +{ + /* + * packet loss (as average of server-to-client, client-to-server loss), + * give tloss_sc extra weight (or should we?) + */ + me->p_pkls = (2 * tloss_sc + tloss_cs) / 3; +} +#endif /* INL_STATS */ + +/* utilities */ + +/* ms time from start */ +int +mstime() +{ + static struct timeval tv_base = {0, 0}; + struct timeval tv; + + if (!tv_base.tv_sec) + { + gettimeofday(&tv_base, NULL); + return 0; + } + gettimeofday(&tv, NULL); + return (tv.tv_sec - tv_base.tv_sec) * 1000 + + (tv.tv_usec - tv_base.tv_usec) / 1000; +} + +/* debugging */ +int +msetime() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec - 732737182) * 1000 + tv.tv_usec / 1000; +} + +int +uchar_diff(x, y) + int x, y; +{ + register res; + + res = x - y; + + if (res > 128) + return res - 256; + else if (res < -128) + return res + 256; + else + return res; +} diff -r cafa94d86546 -r aa38447a4b21 src/pl_gen0.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pl_gen0.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,336 @@ +/*-------------------------------------------------------------------------- +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 "defs.h" +#include "struct.h" +#include "shmem.h" +#include "planets.h" + +/* + * This file contains utility procedures useful when laying out the galaxy. + * + */ + +/* #define SLOWER */ + +int +place_stars(first, count, border, minpad, maxpad, + othercheck, ocount) + struct planet *first; + int count; + int border, minpad, maxpad; + struct planet *othercheck; + int ocount; +{ + int i; + double x, y; + + for (i = 0; i < count; i++) + { + int done, attempts; + int j; + + attempts = 0; + done = 0; +#ifndef SLOWER + x = drand48() * (configvals->gwidth - 2 * border) + border; + y = drand48() * (configvals->gwidth - 2 * border) + border; +#endif + do + { + + attempts++; + +#ifdef SLOWER + x = drand48() * (configvals->gwidth - 2 * border) + border; + y = drand48() * (configvals->gwidth - 2 * border) + border; +#else + x = border + fmod(x + 3574 - border, + (configvals->gwidth - 2.0 * border)); + y = border + fmod(y + 1034 - border, + (configvals->gwidth - 2.0 * border)); +#endif + done = 1; + /* check to make sure we aren't too close to other stars */ + for (j = 0; j < ocount; j++) + { + double dist = hypot(x - othercheck[j].pl_x, + y - othercheck[j].pl_y); + if (dist < minpad || dist > maxpad) + { + done = 0; + break; + } + } + /* + * check to make sure we're not too close to the current set of stars + */ + if (done) + for (j = 0; j < i; j++) + { + double dist = hypot(x - first[j].pl_x, + y - first[j].pl_y); + if (dist < minpad || dist > maxpad) + { + done = 0; + break; + } + } + } while (!done && attempts < 1000); + if (!done) + return 0; + + first[i].pl_owner = NOBODY; + first[i].pl_system = (&first[i] - planets) + 1; + first[i].pl_flags |= PLSTAR; + move_planet(&first[i] - planets, (int) x, (int) y, 0); + first[i].pl_hinfo = ALLTEAM;/* all teams know its a star */ + for (j = 0; j < MAXTEAM + 1; j++) + { /* go put in info for teams */ + first[i].pl_tinfo[j].owner = NOBODY; /* nobody owns it */ + first[i].pl_tinfo[j].armies = 0; + first[i].pl_tinfo[j].flags = first[i].pl_flags; + } + } + return 1; +} + +void +zero_plflags(first, count) + struct planet *first; + int count; +{ + int i; + for (i = 0; i < count; i++) + { + first[i].pl_flags = 0; + } +} + +void +randomize_atmospheres(first, count, p1, p2, p3, p4) + struct planet *first; + int count; + int p1, p2, p3, p4; +{ + int i; + int sum = p1 + p2 + p3 + p4; + for (i = 0; i < count; i++) + { + int val; + int atmosphere; + val = lrand48() % sum; + if ((val -= p1) < 0) + atmosphere = PLATYPE1; + else if ((val -= p2) < 0) + atmosphere = PLATYPE2; + else if ((val -= p3) < 0) + atmosphere = PLATYPE3; + else + atmosphere = PLPOISON; + first[i].pl_flags &= !PLATMASK; + first[i].pl_flags |= atmosphere; + } +} + +/* + * special note. + * + * It looks like this function originally wanted to make all Dilithium planets + * toxic, but the code was buggy and if an arable happened to be placed on + * the same planet later, you would get an STND DA. + * + * I am loath to fix this bug, because it would noticably alter the galactic + * mix. This must be brought before the PLC. + * + * -RF + * + */ +void +randomize_resources(first, count, nm, nd, na) + struct planet *first; + int count; + int nm, nd, na; +{ + for (; count > 0; count--, first++) + { + int val; + + val = lrand48() % count; + if (val < nm) + { + nm--; + first->pl_flags |= PLMETAL; + if (!configvals->resource_bombing) + first->pl_flags |= PLREPAIR; + } + + val = lrand48() % count; + if (val < nd) + { + nd--; + first->pl_flags |= PLDILYTH; + first->pl_flags &= ~(PLATMASK | PLARABLE); + first->pl_flags |= PLPOISON; + if (!configvals->resource_bombing) + first->pl_flags |= PLFUEL; + } + + val = lrand48() % count; + if (val < na) + { + na--; + first->pl_flags |= PLARABLE | PLATYPE1; + if (!configvals->resource_bombing) + first->pl_flags |= PLAGRI; + } + } +} + +static int +count_planets_in_system(sysnum) + int sysnum; +{ + int rval = 0; + int i; + + for (i = 0; i < NUMPLANETS; i++) + { + if (PL_TYPE(planets[i]) == PLPLANET && + planets[i].pl_system == sysnum) + rval++; + } + return rval; +} + +static int +pick_metal_planet_from_system(sysnum, nplanets) + int sysnum, nplanets; +{ + int i; + + for (i = 0; i < NUMPLANETS; i++) + { + if (PL_TYPE(planets[i]) == PLPLANET && + planets[i].pl_system == sysnum && + (planets[i].pl_flags & PLMETAL)) + { + if (lrand48() % nplanets == 0) + return i; + nplanets--; + } + } + return -1; +} + +static int +pick_planet_from_system(sysnum, nplanets) + int sysnum, nplanets; +{ + int i; + + if (nplanets < 0) + nplanets = count_planets_in_system(sysnum); + + for (i = 0; i < NUMPLANETS; i++) + { + if (PL_TYPE(planets[i]) == PLPLANET && + planets[i].pl_system == sysnum) + { + if (lrand48() % nplanets == 0) + return i; + nplanets--; + } + } + return -1; +} + + +void +justify_galaxy(numsystems) + int numsystems; +/* + * Balances the galaxy to be "fair". Currently ensures that: -> One metal + * planet exists within each system. + */ +{ + int i, j; + int *metalcount; + + metalcount = malloc(sizeof(*metalcount) * (numsystems + 1)); + + for (i = 0; i <= numsystems; i++) + metalcount[i] = 0; + + for (i = 0; i < NUMPLANETS; i++) + { + switch (PL_TYPE(planets[i])) + { + case PLPLANET: + { + int system = planets[i].pl_system; + if (system < 0 || system > numsystems) + break; + if (planets[i].pl_flags & PLMETAL) + metalcount[system]++; + } + break; + default: + ; + /* don't care about other stuff */ + } + } + + for (i = 1; i <= numsystems; i++) + { + if (metalcount[i] < 1) + { + int to, from; + int randbase; + + randbase = lrand48() % (numsystems + 1); + + for (j = 0; j <= numsystems; j++) + if (metalcount[(j + randbase) % (numsystems + 1)] > 1) + break; + if (j > numsystems) + { + fprintf(stderr, "error stealing metal planet. Too few!\n"); + return; + } + j = (j + randbase) % (numsystems + 1); + to = pick_planet_from_system(i, -1); + from = pick_metal_planet_from_system(j, metalcount[j]); + planets[to].pl_flags |= PLMETAL; + planets[from].pl_flags &= ~PLMETAL; + if (!configvals->resource_bombing) + { + planets[to].pl_flags |= PLREPAIR; + planets[from].pl_flags &= PLREPAIR; + } + metalcount[i]++; + metalcount[j]--; + } + } + free(metalcount); +} diff -r cafa94d86546 -r aa38447a4b21 src/pl_gen1.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pl_gen1.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,509 @@ +/*-------------------------------------------------------------------------- +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) /* width of a system */ + +#define SYSTEMS 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 2 /* number of metal deposits */ +#define NDILYTH 10 /* number of dilythium deposits */ +#define NARABLE 30 /* number of arable land planets */ +/* defines that deal with star placement */ + +#define GW ((float)GWIDTH) /* size of galaxy in floating point */ +#define STARBORD (SYSWIDTH/2) +#define STARMIN (GW/3.7)/* min dist between stars */ +#define STARMIN2 STARMIN*STARMIN /* min star dist squared */ + +/* defines that deal with systems and their planets */ +#define SYSMINP 4 /* min number of planets per system */ +#define SYSADD 2 /* number possible above min number */ +#define SYSBORD (5000.0 + (float)(GWIDTH/200)) /* min distance from + * border wall */ +#define SYSMIN (7000.0 + (float)(GWIDTH/100)) /* 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; + + for (i = 0; i < SYSTEMS; i++) + { /* star for each system */ + 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 + 134.0, GW); /* every loop */ + if ((x > GW - STARBORD) || (x < STARBORD) + || (y < STARBORD) || (y > GW - STARBORD)) + continue; /* too close to border? */ + 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); + if (dx * dx + dy * dy < STARMIN2) /* if too close 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 */ + } + } + } while (!done && attempts < 100); /* 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; /* 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 + 134.0, GW); /* every loop */ + if ((x > GW - SYSBORD) || (x < SYSBORD) + || (y < SYSBORD) || (y > GW - SYSBORD)) + continue; /* too close to border? */ + 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 < 100); /* 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. This is the algorithm used by the paradise + * 2.01 server in its first release. I hope. + */ + +void +gen_galaxy_1() +{ + int t; + while (1) + { + NUMPLANETS = 60; + GWIDTH = 200000; + 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 */ + if (!place_stars(planets, SYSTEMS, + (int) STARBORD, (int) STARMIN, (int) GW, + (struct planet *) 0, 0)) + continue; + + t = placesystems(); /* place planets in systems */ + if (!t) + continue; + + if (!placeindep(t)) /* place independent planets */ + continue; + + break; /* success */ + } + if (configvals->justify_galaxy) + justify_galaxy(SYSTEMS); + + placeraces(); /* place home planets for races */ +} diff -r cafa94d86546 -r aa38447a4b21 src/pl_gen2.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pl_gen2.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,559 @@ +/*-------------------------------------------------------------------------- +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/8) /* width of a system */ + +#define SYSTEMS 8 /* 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 3 /* number of metal deposits */ +#define NDILYTH 10 /* number of dilythium deposits */ +#define NARABLE 30 /* number of arable land planets */ +/* defines that deal with star placement */ + +#define GW ((float)GWIDTH) /* size of galaxy in floating point */ +#define STARBORD ((GWIDTH-SYSWIDTH*4)/2) /* cannot be this close to + * wall */ +#define STARMIN (6*SYSWIDTH/5) /* min dist between stars */ +#define STARMIN2 STARMIN*STARMIN /* min star dist squared */ + +/* defines that deal with systems and their planets */ +#define SYSMINP 4 /* min number of planets per system */ +#define SYSADD 2 /* number possible above min number */ +#define SYSBORD (SYSWIDTH/4) /* min distance from border wall */ +#define SYSMIN (SYSWIDTH/3) /* 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 < NUMPLANETS; i++) + planets[i].pl_flags = 0; + + 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; + + for (i = 0; i < SYSTEMS; i++) + { /* star for each system */ + 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 + 134.0, GW); /* every loop */ + if ((x > GW - STARBORD) || (x < STARBORD) + || (y < STARBORD) || (y > GW - STARBORD)) + continue; /* too close to border? */ + 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); + if (dx * dx + dy * dy < STARMIN2) /* if too close then */ + done = 0; /* we must get another coord */ + } + } while (!done && attempts < 1000); /* do until location found */ + + if (!done) + return 0; + + 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 */ + } + } + } while (!done && attempts < 100); /* 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; /* 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 + 134.0, GW); /* every loop */ + if ((x > GW - SYSBORD) || (x < SYSBORD) + || (y < SYSBORD) || (y > GW - SYSBORD)) + continue; /* too close to border? */ + done = 1; /* assume valid coord */ + for (j = 0; j < i; 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 * (2 * 2)) + { /* if planet to close */ + done = 0; /* we must get another coord */ + } + } + } while (!done && attempts < 100); /* 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 + 134.0, GW); /* every loop */ + + 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 wormhole */ + planets[i].pl_hinfo = ALLTEAM; /* all teams know its a wormhole */ + 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 colony planet with + * dilythium deposits and COLONYARMIES on it. + */ + +static int +placeraces() +{ + int i, j, k; /* looping vars */ + int p; /* to hold planet for race */ + int racestars[4 /* NRACES */ ]; /* hold the home stars of each race */ + int attempts = 0; + int n; + + for (i = 0; i < NUMPLANETS; i++) + { + /* zero ownership */ + planets[i].pl_owner = NOBODY; /* no team owns a star */ + if ((PL_TYPE(planets[i]) != PLSTAR) && (PL_TYPE(planets[i]) != PLWHOLE)) + planets[i].pl_hinfo = NOBODY; /* no race has planet info */ + } + + for (i = 0; i < 4 && attempts < 1000; i++) + { /* go through races */ + /* find home planet */ + attempts++; + p = lrand48() % NUMPLANETS; /* pick random planet */ + while ((planets[p].pl_system == 0) + || (PL_TYPE(planets[p]) == PLSTAR) + || (planets[p].pl_owner != NOBODY)) + p = (p + 1) % NUMPLANETS; /* go on to next planet */ + + racestars[i] = planets[p].pl_system - 1; + for (j = 0; j < i; j++) + { + struct planet *mystar = &planets[racestars[i]]; + struct planet *otherstar = &planets[racestars[j]]; + float dx, dy; + dx = otherstar->pl_x - mystar->pl_x; + dy = otherstar->pl_y - mystar->pl_y; + if (dx * dx + dy * dy < 3.0 * SYSWIDTH * SYSWIDTH) + { + break; + } + } + if (j < i) + { + i--; + continue; + } + 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 != racestars[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; + n = 0; + for (j = 0; j < NUMPLANETS; j++) + { + if ((planets[j].pl_system == racestars[i] + 1) + && !(PL_TYPE(planets[j]) == PLSTAR)) + { + + if (planets[j].pl_owner == NOBODY) + { + planets[j].pl_flags &= ~(PLATMASK | PLSURMASK); + planets[j].pl_flags |= (n << PLATSHIFT) | (1 << (n + PLSURSHIFT)); + n++; + } + planets[j].pl_owner = 1 << i; + planets[j].pl_hinfo = +#ifdef LEAGUE_SUPPORT + status2->league ? (1 << 4) - 1 : +#endif + (1 << i); + +#ifdef LEAGUE_SUPPORT + for (k = (status2->league ? 0 : i); + k < (status2->league ? 4 : i + 1); + k++) +#else + k = i; +#endif + { + struct teaminfo *info = &planets[j].pl_tinfo[1 << k]; + info->owner = 1 << i; + info->armies = planets[j].pl_armies; + info->flags = planets[j].pl_flags; + } + } + } + } + return i >= 4; +} + +/* + * generate a complete galaxy. + * + * This algorithm was invented by Robert Forsman. + * + * It tries to make a denser universe with fairer race resource distribution and + * races that are further apart.. + */ + +void +gen_galaxy_2() +{ + int t; + + while (1) + { + NUMPLANETS = 60; + GWIDTH = 200000; + + 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); + + if (!place_stars(planets, SYSTEMS, + (int) STARBORD, (int) STARMIN, (int) GW, + (struct planet *) 0, 0)) /* place system centers */ + continue; + + t = placesystems(); /* place planets in systems */ + if (!t) + continue; + + if (!placeindep(t)) /* place independent planets */ + continue; + + if (configvals->justify_galaxy) + justify_galaxy(SYSTEMS); + + if (!placeraces()) /* place home planets for races */ + continue; + break; /* success! */ + } + +} diff -r cafa94d86546 -r aa38447a4b21 src/pl_gen3.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pl_gen3.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,561 @@ +/*-------------------------------------------------------------------------- +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 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 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 < 2) + { /* choose optimal position for first two */ + min = TEAMMIN2; + max = TEAMMAX2; + bord = TEAMBORD; + } + else if (i < 4) + { + min = TEAMMIN2; + max = STARMAX2; + bord = STARBORD * 0.8; + } + 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 */ + } + } + } 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; /* 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; + status2->nontteamlock = (1 << r[0]) | (1 << r[1]); /* only allow these + * teams */ + + for (i = 0; i < 4; i++) + { /* go through races */ + t = r[i]; /* which team */ + 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 << 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_3() +{ + 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 cafa94d86546 -r aa38447a4b21 src/pl_gen4.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pl_gen4.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,260 @@ +/*-------------------------------------------------------------------------- +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 "defs.h" +#include "struct.h" +#include "data.h" +#include "shmem.h" +#include "planets.h" + +#if 0 +#define SYSWIDTH (GWIDTH/5.75) /* width of a system */ +#endif + +#define SYSTEMS 0 /* number of planetary systems */ + +/* atmosphere chances form a cascade win rand()%100 */ +#define PATMOS1 100 /* chance for normal atmosphere */ +#define PATMOS2 100 /* chance for thin atmosphere */ +#define PATMOS3 100 /* chance for slightly toxic stmos */ +#define PPOISON 100 /* chance for poison atmos */ + +/* defines that deal with planets resources and types */ +#define NMETAL 8 /* number of metal deposits */ +#define NDILYTH 12 /* number of dilythium deposits */ +#define NARABLE 8 /* number of arable land 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 */ + + +/*-------------------------------INITBRONCO------------------------------*/ +/* + * Initializes the planet array the way normaltrek did it -- not much + * variety, but some people dig playing chess from the same setup over and + * over again too. :) + */ +static void +initbronco() +{ + int i, j; + + static struct planet pdata[MAXPLANETS] = { + {0, (FED | PLHOME | PLCORE | PLFUEL | PLREPAIR | PLSHIPYARD | PLMETAL | PLARABLE | PLDILYTH), + FED, 20000, 80000, 0, 0, 0, "Earth", 5, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {1, FED | PLCORE, FED, 30000, 90000, 0, 0, 0, "Deneb", 5, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {2, FED | PLCORE, FED, 11000, 75000, 0, 0, 0, "Altair", 6, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {3, FED | PLCORE, FED, 8000, 93000, 0, 0, 0, "Vega", 4, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {4, FED, FED, 10000, 60000, 0, 0, 0, "Rigel", 5, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {5, FED, FED, 25000, 60000, 0, 0, 0, "Canopus", 7, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {6, FED, FED, 44000, 81000, 0, 0, 0, "Beta Crucis", 11, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {7, FED, FED, 39000, 55000, 0, 0, 0, "Organia", 7, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {8, FED, FED, 45000, 66000, 0, 0, 0, "Ceti Alpha V", 12, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {9, FED, FED, 32000, 74000, 0, 0, 0, "Alpha Centauri", 14, + (ROM | KLI | ORI), 0, 0, 0, 30, 0, FED}, + {10, (ROM | PLHOME | PLCORE | PLFUEL | PLREPAIR | PLSHIPYARD | PLMETAL | PLARABLE | PLDILYTH), + ROM, 20000, 20000, 0, 0, 0, "Romulus", 7, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {11, ROM | PLCORE, ROM, 28000, 8000, 0, 0, 0, "Tauri", 5, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {12, ROM | PLCORE, ROM, 28000, 23000, 0, 0, 0, "Draconis", 8, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {13, ROM | PLCORE, ROM, 4000, 12000, 0, 0, 0, "Aldeberan", 9, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {14, ROM, ROM, 45000, 7000, 0, 0, 0, "Eridani", 7, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {15, ROM, ROM, 42000, 44000, 0, 0, 0, "Regulus", 7, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {16, ROM, ROM, 13000, 45000, 0, 0, 0, "Capella", 7, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {17, ROM, ROM, 40000, 25000, 0, 0, 0, "Sirius", 6, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {18, ROM, ROM, 25000, 44000, 0, 0, 0, "Indi", 4, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {19, ROM, ROM, 8000, 29000, 0, 0, 0, "Hydrae", 6, + (FED | KLI | ORI), 0, 0, 0, 30, 0, ROM}, + {20, (KLI | PLHOME | PLCORE | PLFUEL | PLREPAIR | PLSHIPYARD | PLMETAL | PLARABLE | PLDILYTH), + KLI, 80000, 20000, 0, 0, 0, "Klingus", 7, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {21, KLI | PLCORE, KLI, 88000, 12000, 0, 0, 0, "Pollux", 6, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {22, KLI | PLCORE, KLI, 69000, 31000, 0, 0, 0, "Scorpii", 7, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {23, KLI | PLCORE, KLI, 73000, 5000, 0, 0, 0, "Castor", 6, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {24, KLI, KLI, 70000, 40000, 0, 0, 0, "Pleiades V", 10, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {25, KLI, KLI, 60000, 10000, 0, 0, 0, "Andromeda", 9, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {26, KLI, KLI, 54000, 40000, 0, 0, 0, "Lalande", 7, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {27, KLI, KLI, 90000, 37000, 0, 0, 0, "Lyrae", 5, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {28, KLI, KLI, 83000, 48000, 0, 0, 0, "Mira", 4, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {29, KLI, KLI, 54000, 21000, 0, 0, 0, "Cygni", 5, + (FED | ROM | ORI), 0, 0, 0, 30, 0, KLI}, + {30, (ORI | PLHOME | PLCORE | PLFUEL | PLREPAIR | PLSHIPYARD | PLMETAL | PLARABLE | PLDILYTH), + ORI, 80000, 80000, 0, 0, 0, "Orion", 5, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {31, ORI | PLCORE, ORI, 72000, 69000, 0, 0, 0, "Procyon", 7, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {32, ORI | PLCORE, ORI, 91000, 94000, 0, 0, 0, "Ursae Majoris", 13, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {33, ORI | PLCORE, ORI, 85000, 70000, 0, 0, 0, "Antares", 7, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {34, ORI, ORI, 92000, 59000, 0, 0, 0, "Cassiopia", 9, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {35, ORI, ORI, 65000, 55000, 0, 0, 0, "El Nath", 7, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {36, ORI, ORI, 52000, 60000, 0, 0, 0, "Spica", 5, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {37, ORI, ORI, 64000, 80000, 0, 0, 0, "Polaris", 7, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {38, ORI, ORI, 56000, 89000, 0, 0, 0, "Arcturus", 8, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI}, + {39, ORI, ORI, 70000, 93000, 0, 0, 0, "Herculis", 8, + (FED | ROM | KLI), 0, 0, 0, 30, 0, ORI} + }; + for (i = 0; i < NUMPLANETS; i++) + { + for (j = 0; j < MAXTEAM + 1; j++) + { + pdata[i].pl_tinfo[j].owner = pdata[i].pl_owner; + pdata[i].pl_tinfo[j].armies = pdata[i].pl_armies; + pdata[i].pl_tinfo[j].flags = pdata[i].pl_flags; + pdata[i].pl_tinfo[j].timestamp = 0; + } + pdata[i].pl_trevolt = 0; + pdata[i].pl_next = 0; + pdata[i].pl_prev = 0; + pdata[i].pl_gridnum = 0; + } + memcpy((char *) planets, (char *) pdata, MAXPLANETS * sizeof(struct planet)); +} +/*-------------------------------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. This version's been bronco-ified. :) + */ + +static void +genresources_bronco() +{ + int i, j; /* looping vars */ + int t; /* temp var */ + + 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) / 4) + SYSTEMS + + ((i / (NMETAL / 4)) * ((NUMPLANETS - SYSTEMS) / 4)); + if (!(planets[t].pl_flags & PLMETAL & PLSURMASK)) + { + planets[t].pl_flags |= PLMETAL; /* OR in the metal flag */ + planets[t].pl_flags |= PLREPAIR; + } + else + i--; + } + for (i = 0; i < NDILYTH; i++) + { /* place the crystals */ + t = lrand48() % ((NUMPLANETS - SYSTEMS) / 4) + SYSTEMS + + ((i / (NDILYTH / 4)) * ((NUMPLANETS - SYSTEMS) / 4)); + if (!(planets[t].pl_flags & PLDILYTH & PLSURMASK)) + { + planets[t].pl_flags |= PLDILYTH; /* OR in the dilyth flag */ + planets[t].pl_flags |= PLFUEL; + } + else + i--; + } + for (i = 0; i < NARABLE; i++) + { /* place the farms */ + t = lrand48() % ((NUMPLANETS - SYSTEMS) / 4) + SYSTEMS + + ((i / (NARABLE / 4)) * ((NUMPLANETS - SYSTEMS) / 4)); + if (!(planets[t].pl_flags & PLARABLE & PLSURMASK) && + !(planets[t].pl_flags & PLHOME)) + { + planets[t].pl_flags |= PLARABLE | PLATYPE1; /* OR in the arable flag */ + planets[t].pl_flags |= PLAGRI; + } + else + i--; + } + for (i = 0; i < NUMPLANETS; i++) + for (j = 0; j < MAXTEAM + 1; j++) + if (j == planets[i].pl_owner) + planets[i].pl_tinfo[j].flags = planets[i].pl_flags; +} + + + +/* + * Generate a complete galaxy. Uses ye old bronco planet setup. + */ + +void +gen_galaxy_4() +{ + GWIDTH = 100000; + NUMPLANETS = 40; + initbronco(); /* initialize planet structures */ + genresources_bronco(); /* place the resources */ + return; +} diff -r cafa94d86546 -r aa38447a4b21 src/pl_gen5.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pl_gen5.c Sat Dec 06 04:37:03 1997 +0000 @@ -0,0 +1,544 @@ +/*-------------------------------------------------------------------------- +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.75) /* 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 */ + } + } + } 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. Generates like generator 3, only in a smaller + * environment + */ + +void +gen_galaxy_5() +{ + int t; + + GWIDTH = 100000; + NUMPLANETS = 48; + + 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 */ + +}