/* * GenSPkt.c * * Kevin O'Connor 10/3/97 * * Provides the means to generate server packets. * * Code to establish connection, maintain connection, and to send * packets remains in socket.c. */ #include #include #include #include #include #include "defs.h" #include "struct.h" #include "data.h" #include "packets.h" #include "proto.h" #include "genspkt.h" #include "ip.h" #include "util.h" #define FALSE 0 #define TRUE 1 /* file scope prototypes */ static void updateFlagsAll(int offset); static void updateVPlayer(struct player_spacket *p); static void sendVPlayers(void); void sendVPlanets(void); void sendVKills(void); int check_sendself_critical(struct player* pl, u_int flags, char armies, char swar, short whydead, short whodead, char pnum); int sizes[TOTAL_SPACKETS] = { 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 */ 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 */ 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 */ sizeof(struct sc_sequence_spacket), /* SP_SC_SEQUENCE */ #ifdef RSA sizeof(struct rsa_key_spacket), /* SP_RSA_KEY */ #else 0, /* 31 */ #endif sizeof(struct generic_32_spacket), /* SP_GENERIC_32 */ sizeof(struct flags_all_spacket), /* SP_FLAGS_ALL */ 0, /* 34 */ 0, /* 35 */ 0, /* 36 */ 0, /* 37 */ 0, /* 38 */ sizeof(struct ship_cap_spacket), /* SP_SHIP_CAP */ sizeof(struct shortreply_spacket), /* SP_S_REPLY */ -1, /* SP_S_MESSAGE */ sizeof(struct warning_s_spacket), /* SP_S_WARNING */ sizeof(struct you_short_spacket), /* SP_S_YOU */ sizeof(struct youss_spacket), /* SP_S_YOU_SS */ -1, /* variable */ /* SP_S_PLAYER */ #ifdef PING sizeof(struct ping_spacket), /* SP_PING */ #else 0, /* SP_PING */ #endif -1, /* variable */ /* SP_S_TORP */ -1, /* variable */ /* SP_S_TORP_INFO */ 20, /* SP_S_8_TORP */ -1, /* variable */ /* SP_S_PLANET */ 0, /* 51 */ 0, /* 52 */ 0, /* 53 */ 0, /* 54 */ 0, /* 55 */ 0, /* 56 */ -1, /* variable S_P2 */ /* SP_S_PHASER */ -1, /* variable */ /* SP_S_KILLS */ sizeof (struct stats_s_spacket), /* SP_S_STATS */ #ifdef FEATURE_PACKETS sizeof(struct feature_spacket), /* SP_FEATURE */ #else 0, /* 60 */ #endif 0, /* 61 */ }; /* a collection of previously sent packets by packet type and slot, used to determine whether to send another one if critical values change */ struct plyr_info_spacket clientPlayersInfo[MAXPLAYER]; struct plyr_login_spacket clientLogin[MAXPLAYER]; struct hostile_spacket clientHostile[MAXPLAYER]; struct stats_spacket clientStats[MAXPLAYER]; struct player_spacket clientPlayers[MAXPLAYER]; struct kills_spacket clientKills[MAXPLAYER]; struct flags_spacket clientFlags[MAXPLAYER]; struct pstatus_spacket clientPStatus[MAXPLAYER]; int msgCurrent; struct torp_info_spacket clientTorpsInfo[MAXPLAYER*MAXTORP]; struct torp_spacket clientTorps[MAXPLAYER*MAXTORP]; struct phaser_spacket clientPhasers[MAXPLAYER]; struct phaser_s_spacket client_s_Phasers[MAXPLAYER]; struct you_spacket clientSelf; struct status_spacket clientStatus; struct planet_spacket clientPlanets[MAXPLANETS]; struct planet_loc_spacket clientPlanetLocs[MAXPLANETS]; struct plasma_info_spacket clientPlasmasInfo[MAXPLAYER*MAXPLASMA]; struct plasma_spacket clientPlasmas[MAXPLAYER*MAXPLASMA]; int mustUpdate[MAXPLAYER]; struct youss_spacket clientSelfShip; struct you_short_spacket clientSelfShort; struct generic_32_spacket clientGeneric32; /* HW */ u_char clientVPlanets[MAXPLANETS*sizeof(struct planet_s_spacket)+2 +6]; int clientVPlanetCount; static int vtsize[9] ={ 4,8,8,12,12,16,20,20,24 }; /* How big is the * SP_S_TORP packet */ static int vtdata[9] ={0,3,5,7,9,12,14,16,18 }; /* How big is Torpdata */ static int mustsend; /* Flag to remind me that i must send SP_S_TORP */ static u_char clientVTorps[40]; static u_char clientVTorpsInfo[16]; static u_char clientVPlayers[MAXPLAYER*VPLAYER_SIZE + 16]; /* S_P2 */ u_char clientVKills[MAXPLAYER*2+2 +4]; int clientVKillsCount; struct stats_s_spacket singleStats; static unsigned char n_flags[MAXPLAYER]; static int highest_active_player; #if MAXPLAYER > 32 static u_char clientVXPlayers[33*4]; #endif static int clientVPlayerCount; static int clientVXPlayerCount; static int big; extern int ignored[]; /* Variables referenced from Socket.c */ extern int sizes[]; extern int use_newyou; extern int f_many_self; 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; /***** Low level checks for packets *****/ #define UPDT_ALL 0 #define UPDT_MOST 1 #define UPDT_MANY 2 #define UPDT_LITTLE 3 #define UPDT_LEAST 4 int sndLogin( struct plyr_login_spacket* login, struct player* pl) { if ( strcmp(pl->p_name, login->name)!=0 || pl->p_stats.st_rank != login->rank || strcmp(pl->p_monitor, login->monitor)!=0 || strcmp(pl->p_login, login->login)!=0) { STRNCPY(login->name,pl->p_name,NAME_LEN); STRNCPY(login->monitor,pl->p_monitor,NAME_LEN); STRNCPY(login->login,pl->p_login,NAME_LEN); login->name[NAME_LEN-1]=0; login->monitor[NAME_LEN-1]=0; login->login[NAME_LEN-1]=0; login->type=SP_PL_LOGIN; login->pnum=pl->p_no; login->rank=pl->p_stats.st_rank; sendClientPacket(login); /* on every change to player list, check saved ignore status */ if (me != pl && pl->p_status == PFREE) ip_ignore_login(me, pl); return TRUE; } return FALSE; } inline static int sndHostile( struct hostile_spacket *hostile, struct player *pl, int howmuch) { if (howmuch == UPDT_ALL) { if ( (pl->p_swar != hostile->war) || (pl->p_hostile != hostile->hostile)) { hostile->type=SP_HOSTILE; hostile->war=pl->p_swar; hostile->hostile=pl->p_hostile; hostile->pnum=pl->p_no; sendClientPacket(hostile); return (TRUE); } } else { if ( (pl->p_swar & me->p_team)!=hostile->war || (pl->p_hostile & me->p_team)!=hostile->hostile) { hostile->type=SP_HOSTILE; hostile->war=(pl->p_swar & me->p_team); hostile->hostile=(pl->p_hostile & me->p_team); hostile->pnum=pl->p_no; sendClientPacket(hostile); return (TRUE); } } return (FALSE); } int sndPlayerInfo( struct plyr_info_spacket *cpli, struct player *pl) { if (pl->p_ship.s_type != cpli->shiptype || pl->p_team != cpli->team) { cpli->type=SP_PLAYER_INFO; cpli->pnum=pl->p_no; cpli->shiptype=pl->p_ship.s_type; cpli->team=pl->p_team; sendClientPacket(cpli); return (TRUE); } return (FALSE); } inline static int updtKills( struct kills_spacket *kills, struct player *pl) { if ( kills->kills != htonl((int) (pl->p_kills*100))) { kills->type=SP_KILLS; kills->pnum=pl->p_no; kills->kills=htonl((int) (pl->p_kills*100)); return (TRUE); } return (FALSE); } inline static void addVKills( struct player *pl) { /* S_P2 */ static unsigned char *vkills; unsigned short shiftkills; if (!clientVKillsCount) vkills = &clientVKills[2]; clientVKillsCount++; shiftkills = pl->p_kills * 100; shiftkills |= (pl->p_no << 10); *vkills++ = (unsigned char) shiftkills & 0xff; *vkills++ = (shiftkills >> 8) & 0xff; } int sndKills( struct kills_spacket *kills, struct player *pl) { if (updtKills(kills, pl)) { /* S_P2 */ if (send_short > 1 && (pl->p_kills*100 < 1001) && pl->p_no < 64) addVKills(pl); else sendClientPacket(kills); return (TRUE); } return (FALSE); } void sendVKills(void) { if ( clientVKillsCount) { clientVKills[0] = SP_S_KILLS; clientVKills[1] = (unsigned char) clientVKillsCount; clientVKillsCount = 2+ (clientVKillsCount *2); if((clientVKillsCount % 4) != 0) clientVKillsCount += (4 - (clientVKillsCount % 4)); sizes[SP_S_KILLS] = clientVKillsCount; sendClientPacket((struct kills_spacket *) clientVKills); } } /* This function is for sending the flags of OTHER players, the player's own flags are handled elsewhere. The cambot will set f_many_self, and use this function to record the flags of all players. */ int sndFlags( struct flags_spacket *flags, struct player *pl, int howmuch) { /*#define FLAGMASK (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFBEAMUP|PFBEAMDOWN|PFPRACTR|PFDOCK|PFTRACT|PFPRESS|PFDOCKOK) aieee, too much. 7/27/91 TC */ /*#define FLAGMASK (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT| PFPRACTR|PFDOCK|PFTRACT|PFPRESS|PFDOCKOK) still more than needed */ /* Flags we get to know about players not seen */ #if defined(BASEPRACTICE) || defined(NEWBIESERVER) || defined(PRETSERVER) #define INVISOMASK (PFCLOAK|PFROBOT|PFPRACTR|PFDOCKOK|PFOBSERV|PFBPROBOT) #else #define INVISOMASK (PFCLOAK|PFROBOT|PFPRACTR|PFDOCKOK|PFOBSERV) #endif /* Flags we get to know about players who are seen */ #define FLAGMASK (PFSHIELD | INVISOMASK) int mask, masked; int tractor = ((F_show_all_tractors || f_many_self) && pl->p_flags&PFTRACT)? (pl->p_tractor|0x40):0; if (!f_many_self && pl->p_status == POBSERV) { mask = PFOBSERV; /* All we need to know about observers. */ tractor = 0; } else if (howmuch == UPDT_ALL) { mask = FLAGMASK; if (F_show_all_tractors || f_many_self) mask |= PFTRACT|PFPRESS; } else { mask = INVISOMASK; } masked = htonl(pl->p_flags & mask); if (flags->flags == masked && flags->tractor == tractor) /* Nothing has changed, don't send a packet */ return FALSE; flags->type = SP_FLAGS; flags->pnum = pl->p_no; flags->flags = masked; flags->tractor = tractor; sendClientPacket(flags); return (TRUE); } /* Only called if clients send SP_FLAGS_ALL, sends all players' cloak, shield, and PALIVE status. The data is stored in the n_flags[i] array, similiar to how it is set in updateShips() for those using S_P2. The packet format is designed to be compatable with how clients would handle a short packets flags header, see new_flags() in any COW-derived client. */ void updateFlagsAll(int offset) { struct player *pl; struct flags_all_spacket flags_all; int i, j, new = 0; flags_all.type = SP_FLAGS_ALL; flags_all.offset = offset; for (i=flags_all.offset * 16, j=0; i < (flags_all.offset + 1) * 16 && i < MAXPLAYER; i++, j += 2) { pl = &players[i]; switch (pl->p_status) { case POBSERV: case PALIVE: if (pl->p_flags & PFCLOAK) n_flags[i] = FLAGS_ALL_CLOAK_ON; else if (pl->p_flags & PFSHIELD) n_flags[i] = FLAGS_ALL_CLOAK_OFF_SHIELDS_UP; else n_flags[i] = FLAGS_ALL_CLOAK_OFF_SHIELDS_DOWN; break; case PEXPLODE: case PDEAD: n_flags[i] = FLAGS_ALL_DEAD; break; default: /* Treat as dead */ n_flags[i] = FLAGS_ALL_DEAD; break; } new = new | ((unsigned int)n_flags[i] << j); } flags_all.flags = (long) htonl(new); sendClientPacket(&flags_all); } static int observed_status(struct player *pl) { if (pl->p_status != POBSERV) return pl->p_status; return (pl == me) ? PALIVE : POUTFIT; } int sndPStatus (struct pstatus_spacket *pstatus, struct player *pl) { int ostatus = observed_status(pl); if (pstatus->status != ostatus) { pstatus->type = SP_PSTATUS; pstatus->pnum = pl->p_no; pstatus->status = ostatus; sendClientPacket(pstatus); if (dead_warp) dead_warp = 1; return TRUE; } return FALSE; } int updtPlayer( struct player_spacket *cpl, struct player *pl, int howmuch) /* UPDT_ALL : If needed send accurate position; accurate speed. (normal) * UPDT_MOST : If needed send accurate position; speed = 15 (cloaking) * UPDT_MANY : If needed send inacurate position; speed = 15 (cloaked) * UPDT_LITTLE: If needed send outdated packet (cloaked; no update) * UPDT_LEAST : If needed send bogus position (-10000); (player hidden) */ { if ( howmuch == UPDT_LEAST ) { if (ntohl(cpl->x) == -10000 && ntohl(cpl->y) == -10000) return (FALSE); /* Make player disappear */ cpl->type = SP_PLAYER; cpl->x = cpl->y = htonl(-10000); cpl->pnum = pl->p_no; /* FEATURE: dead_warp */ if ( (pl->p_status == PDEAD || pl->p_status == PEXPLODE) && dead_warp) { cpl->dir = dead_warp++; cpl->speed = 0xe; /* 14 = dead */ } else { cpl->dir = 0; cpl->speed = 0; } return (TRUE); } if ( pl->p_x != ntohl(cpl->x) || pl->p_y != ntohl(cpl->y) || pl->p_dir != cpl->dir || pl->p_speed != cpl->speed) { /* FEATURE: dead_warp */ if ( (pl->p_status == PDEAD || pl->p_status == PEXPLODE) && dead_warp) { cpl->type=SP_PLAYER; cpl->pnum=pl->p_no; cpl->dir = dead_warp++; cpl->speed = 0xe; /* 14 = dead */ cpl->x = cpl->y = htonl(-10000); return (TRUE); } if (howmuch == UPDT_LITTLE) { /* NEW: Send old position again */ return(TRUE); } cpl->type=SP_PLAYER; cpl->pnum=pl->p_no; if (howmuch == UPDT_MANY) { cpl->speed = 0xf; /* NEW: Joe Rumsey, 15 == cloaked */ #ifdef AS_CLOAK if (pl->p_ship.s_type == ASSAULT) { cpl->x=htonl(pl->p_x+(random() % 3000)-1500); cpl->y=htonl(pl->p_y+(random() % 3000)-1500); } else #endif { cpl->x=htonl(pl->p_x+(random() % 2000)-1000); cpl->y=htonl(pl->p_y+(random() % 2000)-1000); } } else { cpl->dir = pl->p_dir; cpl->x = htonl(pl->p_x); cpl->y = htonl(pl->p_y); if (howmuch == UPDT_ALL) cpl->speed = pl->p_speed; else /* Feature: CLOAK_MAXWARP */ cpl->speed = 0xf; /* NEW: Joe Rumsey, 15 == cloaked */ } return (TRUE); } return(FALSE); } inline static int sndPlayer( struct player_spacket *cpl, struct player *pl, int howmuch) { if (updtPlayer(cpl, pl, howmuch)) { if (send_short && !F_full_direction_resolution) updateVPlayer(cpl); else sendClientPacket(cpl); return (TRUE); } return (FALSE); } int sndSelfShip(struct youss_spacket *self, struct player *pl) { if(ntohs(self->damage) != pl->p_damage || ntohs(self->shield) != pl->p_shield || ntohs(self->fuel) != pl->p_fuel || ntohs(self->etemp) != pl->p_etemp || ntohs(self->wtemp) != pl->p_wtemp) { self->type = SP_S_YOU_SS; if (f_many_self) { /* f_many_self is turned on by cambot when it uses this code to record the game to a file. The normal server doesn't use it. Since the player number is stuck in pad1, it can't be used to send player flags */ self->pad1 = pl->p_no; } else { /* See if we can stuff some flags in the pad byte */ u_int f=0; if (F_19flags) { f = pl->p_flags; self->pad1 = ((f&PFGREEN )?2:(f&PFYELLOW )?1:0) + ((f&PFBEAMUP)?2:(f&PFBEAMDOWN)?1:0)*3 + ((f&PFPLOCK )?2:(f&PFPLLOCK )?1:0)*9 + ((f&PFPRESS )?1:(f&PFTRACT )?2:0)*27 + ((f&PFORBIT )?2:(f&PFDOCK )?1:0)*81; f = (PFGREEN|PFYELLOW|PFRED|PFBEAMUP|PFBEAMDOWN|PFPLOCK| PFPLLOCK|PFPRESS|PFTRACT|PFORBIT|PFDOCK); } else if (F_self_8flags) { self->pad1 = pl->p_flags & 0xff; f = 0xff; } /* since flags are sent now, note the update */ if(f) clientSelfShort.flags = (clientSelfShort.flags & htonl(~f)) | htonl(pl->p_flags & f); } self->damage=htons(pl->p_damage); self->shield=htons(pl->p_shield); self->fuel=htons(pl->p_fuel); self->etemp=htons(pl->p_etemp); self->wtemp=htons(pl->p_wtemp); sendClientPacket((CVOID) self); return (TRUE); } return (FALSE); } int sndTorp(struct torp_info_spacket *tpi, struct torp_spacket *tp, struct torp *t, int i, int howmuch) { /* * If it was free before, and is still, do nothing. */ if ((t->t_status == TFREE) && (tpi->status == TFREE)) return (FALSE); if (howmuch == UPDT_ALL) { if ((t->t_war != tpi->war) || (t->t_status != tpi->status)) { tpi->type = SP_TORP_INFO; tpi->war = t->t_war; tpi->status = t->t_status; tpi->tnum = htons(i); sendClientPacket(tpi); /* return (TRUE);*/ } if ((tp->x != htonl(t->t_x)) || (tp->y != htonl(t->t_y))) { tp->type = SP_TORP; tp->x = htonl(t->t_x); tp->y = htonl(t->t_y); tp->dir = t->t_dir; tp->tnum = htons(i); sendClientPacket(tp); return (TRUE); } } else if (howmuch == UPDT_MOST) { tp->type = SP_TORP; tp->x = htonl(t->t_x); tp->y = htonl(t->t_y); tp->dir = t->t_dir; /* The robot needs this */ tp->tnum = htons(i); sendClientPacket(tp); if ( (t->t_status != tpi->status) || ((t->t_war & me->p_team) != tpi->war)) { tpi->type = SP_TORP_INFO; tpi->war = t->t_war & me->p_team; tpi->tnum = htons(i); tpi->status = t->t_status; sendClientPacket(tpi); } return (TRUE); } else { if ((t->t_status == TFREE) && (tpi->status == TEXPLODE)) { tpi->status = TFREE; return (FALSE); } if (tpi->status != TFREE) { tpi->type = SP_TORP_INFO; tpi->status = TFREE; tpi->tnum = htons(i); sendClientPacket(tpi); return (TRUE); } } return (FALSE); } int sndPlasma(struct plasma_info_spacket *tpi, struct plasma_spacket *tp, struct torp *t, int i, int howmuch) { /* * If it was free before, and is still, do nothing. */ if ((t->t_status == TFREE) && (tpi->status == TFREE)) return (FALSE); if (howmuch == UPDT_ALL) { if ((t->t_war != tpi->war) || (t->t_status != tpi->status)) { tpi->type = SP_PLASMA_INFO; tpi->war = t->t_war; tpi->status = t->t_status; tpi->pnum = htons(i); sendClientPacket(tpi); /* return (TRUE);*/ } if ((tp->x != htonl(t->t_x)) || (tp->y != htonl(t->t_y))) { tp->type = SP_PLASMA; tp->x = htonl(t->t_x); tp->y = htonl(t->t_y); tp->pnum = htons(i); sendClientPacket(tp); return (TRUE); } } else if (howmuch == UPDT_MOST) { tp->type = SP_PLASMA; tp->x = htonl(t->t_x); tp->y = htonl(t->t_y); tp->pnum = htons(i); sendClientPacket(tp); if ( (t->t_status != tpi->status) || ((t->t_war & me->p_team) != tpi->war)) { tpi->type = SP_PLASMA_INFO; tpi->war = t->t_war & me->p_team; /* In PP plasma mode, plasmas change teams, but client doesn't know. If player is at war with plasma's new team, set the plasma's war flag, so client knows it is hostile. */ if (pingpong_plasma && (t->t_team & me->p_war)) tpi->war |= me->p_team; tpi->pnum = htons(i); tpi->status = t->t_status; sendClientPacket(tpi); } return (TRUE); } else { if ((t->t_status == TFREE) && (tpi->status == TEXPLODE)) { tpi->status = TFREE; return (FALSE); } if (tpi->status != TFREE) { tpi->type = SP_PLASMA_INFO; tpi->status = TFREE; tpi->pnum = htons(i); sendClientPacket(tpi); return (TRUE); } } return (FALSE); } inline static int updtPhaser(struct phaser_spacket *ph, struct phaser *phase, int i, int howmuch) { if (howmuch == UPDT_ALL) { if ( ph->status!=phase->ph_status || ph->dir!=phase->ph_dir || ph->target!=htonl(phase->ph_target)) { ph->pnum=i; ph->type=SP_PHASER; ph->status=phase->ph_status; ph->dir=phase->ph_dir; ph->x=htonl(phase->ph_x); ph->y=htonl(phase->ph_y); ph->target=htonl(phase->ph_target); return (TRUE); } } else { if (ph->status!=PHFREE) { ph->pnum=i; ph->type=SP_PHASER; ph->status=PHFREE; return (TRUE); } } return (FALSE); } inline static int addVPhaser(struct phaser_spacket *ph, struct phaser_s_spacket *phs, struct phaser *phase, int i, int howmuch) { unsigned char damage; /* get rid of annoying compiler message */ if (howmuch) ; switch(ph->status) { case PHFREE: phs->pnum = i; phs->type = SP_S_PHASER; phs->status = PHFREE; sizes[SP_S_PHASER] = 4; sendClientPacket (phs); break; case PHHIT: if(phase->ph_damage > 255) damage = 255; /* Could be used as flag */ else damage = phase->ph_damage; phs->pnum = (i & 0x3f)| (damage & 0x30) << 2 ; phs->type = SP_S_PHASER; phs->status = (unsigned char)ph->status |(damage & 0x0f) << 4; phs->target = (phase->ph_target & 0x3f)|(damage & 192); sizes[SP_S_PHASER] = 4; sendClientPacket (phs); break; case PHMISS: phs->pnum = i; phs->type = SP_S_PHASER; phs->status = ph->status; phs->target = ph->dir; /* Do not get confused */ sizes[SP_S_PHASER] = 4; sendClientPacket (phs); break; case PHHIT2: phs->pnum = i; phs->type = SP_S_PHASER; phs->status = ph->status; phs->x = htons ((phase->ph_x+SCALE/2) / SCALE); phs->y = htons ((phase->ph_y+SCALE/2) / SCALE); phs->target = phase->ph_target; sizes[SP_S_PHASER]= 8; sendClientPacket (phs); break; default: phs->pnum = i; phs->type = SP_S_PHASER; phs->status = ph->status; phs->dir = ph->dir; phs->x = htons ((phase->ph_x+SCALE/2) / SCALE); phs->y = htons ((phase->ph_y+SCALE/2) / SCALE); phs->target = phase->ph_target; sizes[SP_S_PHASER]= sizeof(struct phaser_s_spacket); sendClientPacket (phs); break; } return (TRUE); } int sndPhaser(struct phaser_spacket *ph, struct phaser_s_spacket *phs, struct phaser *phase, int i, int howmuch) { if (updtPhaser(ph, phase, i, howmuch)) { if ( send_short > 1 && (!(ph->status & 0xf0)) #if MAXPLAYER >= 65 && i < 64 #endif #ifdef STURGEON /* Sturgeon phasers can vary from default length, need to send the end coordinate, so avoid short packet */ && ((sturgeon && ph->status == PHMISS) ? 0 : 1) #endif ) addVPhaser(ph, phs, phase, i, howmuch); else sendClientPacket(ph); return (TRUE); } return (FALSE); } /* Determines if the planet's info has changed since it was last sent to the client. If so, it updates the planet packet with current data and returns true. */ inline static int updtPlanet(struct planet_spacket *pl, struct planet *plan, int howmuch) { if (howmuch == UPDT_ALL) { if ( pl->info != plan->pl_info || pl->armies != htonl(plan->pl_armies) || pl->owner != plan->pl_owner || pl->flags != htons((short) (plan->pl_flags & PLFLAGMASK))) { pl->type=SP_PLANET; pl->pnum=plan->pl_no; pl->info=plan->pl_info; pl->flags=htons((short) (plan->pl_flags & PLFLAGMASK)); pl->armies=htonl(plan->pl_armies); pl->owner=plan->pl_owner; return (TRUE); } } else { /* UPDT_LITTLE */ if (pl->info & me->p_team) { pl->type=SP_PLANET; pl->pnum=plan->pl_no; pl->info=0; pl->flags=0; pl->armies=0; pl->owner=0; return (TRUE); } } return (FALSE); } /* Given a normal planet packet in pl, pack the data onto the end of the VPlanet buffer and increment the count. The vplanet packet is a more efficient way to send multiple planet updates with typical values. */ inline static int addVPlanet(struct planet_spacket *pl) { static struct planet_s_spacket *npl; if (!clientVPlanetCount) npl = (struct planet_s_spacket *) &clientVPlanets[2]; npl->pnum=pl->pnum; npl->info=pl->info; npl->flags=pl->flags; npl->armies=(u_char) ntohl(pl->armies); npl->owner=pl->owner; npl++; clientVPlanetCount++; return (TRUE); } /* howmuch is how much info to send, UPDT_LITTLE means just the information sent for unscouted planets, UPDT_ALL means send everything. The return value isn't actually used. */ int sndPlanet(struct planet_spacket *pl, struct planet *plan, int howmuch) { if (updtPlanet(pl, plan, howmuch)) { /* Vplanet is more efficient, but only works when there are less than 256 armies */ if ( send_short && plan->pl_armies < 256 ) addVPlanet(pl); else sendClientPacket(pl); return (TRUE); } return (FALSE); } void sendVPlanets(void) { if (clientVPlanetCount != 0) { clientVPlanets[0] = SP_S_PLANET; /* The type */ clientVPlanets[1] = clientVPlanetCount; clientVPlanetCount = 2 +(clientVPlanetCount * 6); /* make sure on machine word boundary (assuming 4 bytes per word) */ if((clientVPlanetCount % 4) != 0) clientVPlanetCount += (4 - (clientVPlanetCount % 4)); sizes[SP_S_PLANET] = clientVPlanetCount; sendClientPacket((struct planet_spacket *) clientVPlanets); } } int sndPlanetLoc(struct planet_loc_spacket *pll, struct planet *plan) { if ((pll->x != htonl(plan->pl_x)) || (pll->y != htonl(plan->pl_y))) { pll->x=htonl(plan->pl_x); pll->y=htonl(plan->pl_y); pll->pnum=plan->pl_no; strcpy(pll->name, plan->pl_name); pll->type=SP_PLANET_LOC; sendClientPacket(pll); return (TRUE); } return (FALSE); /* TODO: planet name changes by server admin are not propogated to client until planet is moved */ } int updtMessageSMessage(struct message *cur) { switch(cur->args[0]) { case DMKILL: if ( cur->args[3] < 32000 && cur->args[4] < 32 && cur->args[1] < 64 && cur->args[2] < 64 ) { u_short tmp; tmp= cur->args[3] | ((cur->args[4] & 16) << 11); swarning(KILLARGS,(u_char)(tmp & 0xff), (u_char)((tmp >> 8) & 0xff)); if (why_dead) { swarning(KILLARGS2,(u_char)cur->args[5],0); } tmp= (u_char)(cur->args[2] | ((cur->args[4] & 12)<< 4)); swarning(DMKILL,(u_char)(cur->args[1] | ((cur->args[4] & 3)<< 6)), tmp); return(TRUE); } break; case KILLARGS: /* Only to help the compiler */ break; case KILLARGS2: /* Only to help the compiler */ break; case DMKILLP: if (why_dead) { swarning(KILLARGS2,(u_char)cur->args[5],(u_char)cur->args[4]); } swarning(DMKILLP, (u_char)cur->args[1], (u_char)cur->args[2]); return(TRUE); case DMBOMB: swarning(ARGUMENTS, (u_char)cur->args[2],0); /* Damage */ swarning(DMBOMB, (u_char)cur->args[1], (u_char)cur->args[3]); /* To get the vital info in one packet */ return(TRUE); case DMDEST: swarning(DMDEST, (u_char)cur->args[1], (u_char)cur->args[2]); return(TRUE); case DMTAKE: swarning(DMTAKE, (u_char)cur->args[1], (u_char)cur->args[2]); return(TRUE); case DGHOSTKILL: if(cur->args[2] < 64000){ swarning(KILLARGS,(u_char)(cur->args[2] & 0xff), (u_char)((cur->args[2] >> 8) & 0xff)); if (why_dead) { swarning(KILLARGS2,(u_char)cur->args[5],0); } swarning(DGHOSTKILL, (u_char)cur->args[1], 0); return(TRUE); } break; case SVALID: /* We can send it over SP_S_MESSAGE HW */ break; case SINVALID: /* Can't be send over SP_S_MESSAGE */ break; default: /* I must test if the message from GOD has a real header (== "GOD->") */ /* This tests gets all messages from tools */ if (strstr(cur->m_data,"GOD->") != NULL) cur->args[0] = SVALID; /* It has a real header */ break; } return(FALSE); } void updtMessage(struct mesg_spacket *msg, struct message *cur) { if ( send_short && (cur->m_from < MAXPLAYER || cur->args[0] == SVALID) && (!(cur->m_flags & MLEAVE)) ) { /* This is the SAFE version.(All playermessages must have an header.) * It's nicer without MLEAVE */ struct mesg_s_spacket *shortmsg = (struct mesg_s_spacket *) msg; int size; shortmsg->type = SP_S_MESSAGE; shortmsg->m_flags=cur->m_flags; shortmsg->m_recpt=cur->m_recpt; shortmsg->m_from=cur->m_from; cur->m_data[MSG_LEN-1]='\0'; /* Is this all right ? */ strcpy(&shortmsg->mesg,&cur->m_data[9]); /* 9 because of GOD messages */ /* Now the size */ size = strlen(&shortmsg->mesg); size += 6; /* 1 for '\0', 5 packetheader */ if((size % 4) != 0) size += (4 - (size % 4)); shortmsg->length = size; sizes[SP_S_MESSAGE] = size; } else { msg->type=SP_MESSAGE; STRNCPY(msg->mesg, cur->m_data, MSG_LEN); msg->mesg[MSG_LEN-1]='\0'; msg->m_flags=cur->m_flags; msg->m_recpt=cur->m_recpt; msg->m_from=cur->m_from; #ifdef RCD /* kludge for clients that can't handle RCD's */ /* if I understood heiko's short_packet code I would put this in the above ... but I dont - jmn */ if ((cur->m_recpt == me->p_team) && !F_rc_distress && (cur->m_flags == (MTEAM | MDISTR | MVALID))) { struct distress dist; char buf[MSG_LEN]; buf[0] = '\0'; msg->m_flags ^= MDISTR; /* get rid of MDISTR flag so client isn't confused */ HandleGenDistr(cur->m_data,cur->m_from,cur->m_recpt,&dist); makedistress(&dist,buf,distmacro[dist.distype].macro); /* note that we do NOT send the F0->FED part so strncat is fine */ strcpy(msg->mesg, buf); } #endif } if (cur->m_from==DOOSHMSG) msg->m_from=255; /* god */ sendClientPacket((CVOID) msg); } /* End of low level packet update routines */ void updateStatus(int force) /* if force is false, packet only sent when status->tourn changes */ /* if force is true, send every 10 seconds as long as timeprod has changed */ { if ((clientStatus.tourn != status->tourn) || (force && !(repCount%efticks(50)) && ntohl(clientStatus.timeprod) != timeprod_int())) { #ifdef LTD_STATS /* Hey, Tmode changed. Do I have an enemy? */ setEnemy(me->p_team, me); #endif /* LTD_STATS */ clientStatus.type=SP_STATUS; clientStatus.tourn=status->tourn; clientStatus.armsbomb=htonl(status->armsbomb/10); clientStatus.planets=htonl(status->planets/10); clientStatus.kills=htonl(status->kills/10); clientStatus.losses=htonl(status->losses/10); clientStatus.time=htonl(status->time/10); clientStatus.timeprod=htonl(timeprod_int()); sendClientPacket((CVOID) &clientStatus); } } /*! @brief translate p_whydead to older protocol meanings. @details if the WHY_DEAD_2 feature F_why_dead_2 is set, then the daemon values of p_whydead can be sent as is to the client, otherwise the values that are unique to WHY_DEAD_2 feature are translated to the older values. */ static int legacy_whydead(int p_whydead) { if (F_why_dead_2) return p_whydead; if (p_whydead == KTORP2) return KTORP; if (p_whydead == KSHIP2) return KSHIP; if (p_whydead == KPLASMA2) return KPLASMA; return p_whydead; } /* Determine if sendself packet should be flagged as critical */ int check_sendself_critical(struct player* pl, u_int flags, char armies, char swar, short whydead, short whodead, char pnum) { int type; /* Determine packet type, as per updateSelf check */ if(send_short && pl->p_fuel < 61000) type = SP_S_YOU; else type = SP_YOU; if (commMode == COMM_UDP) { if ( flags != pl->p_flags || armies != pl->p_armies || swar != pl->p_swar) { type = type | 0x40; /* mark as semi-critical */ } if ( whydead != legacy_whydead(pl->p_whydead) || whodead != pl->p_whodead || pnum != pl->p_no) { type = type | 0x80; /* mark as critical */ } } return type; } int sndSSelf(struct you_short_spacket *youp, struct player* pl, int howmuch) { if ( howmuch == UPDT_ALL || youp->pnum != pl->p_no || youp->hostile != pl->p_hostile || youp->swar != pl->p_swar || youp->armies != pl->p_armies || youp->whydead != legacy_whydead(pl->p_whydead) || youp->whodead != pl->p_whodead || ntohl(youp->flags) != pl->p_flags ) { /* we want to send it, but how? */ youp->type = check_sendself_critical(pl, ntohl(youp->flags), youp->armies, youp->swar, youp->whydead, youp->whodead, youp->pnum); youp->pnum = pl->p_no; youp->hostile = pl->p_hostile; youp->swar = pl->p_swar; youp->armies = pl->p_armies; youp->whydead = legacy_whydead(pl->p_whydead); youp->whodead = pl->p_whodead; youp->flags = htonl(pl->p_flags); sendClientPacket((CVOID) youp); return (TRUE); } return (FALSE); } inline static int sndSelf(struct you_spacket* youp, struct player* pl, int howmuch) { int tractor = (pl->p_flags&PFTRACT)?(char)(pl->p_tractor|0x40):0; if ( howmuch == UPDT_ALL || ntohl(youp->fuel) != pl->p_fuel || ntohl(youp->shield) != pl->p_shield || ntohl(youp->damage) != pl->p_damage || ntohs(youp->etemp) != pl->p_etemp || ntohs(youp->wtemp) != pl->p_wtemp || ntohl(youp->flags) != pl->p_flags || youp->armies != pl->p_armies || youp->swar != pl->p_swar || ntohs(youp->whydead) != legacy_whydead(pl->p_whydead) || ntohs(youp->whodead) != pl->p_whodead || youp->tractor != tractor || youp->pnum != pl->p_no) { /* we want to send it, but how? */ youp->type = check_sendself_critical(pl, ntohl(youp->flags), youp->armies, youp->swar, ntohs(youp->whydead), ntohs(youp->whodead), youp->pnum); youp->pnum=pl->p_no; youp->flags=htonl(pl->p_flags); youp->swar=pl->p_swar; youp->hostile=pl->p_hostile; youp->armies=pl->p_armies; youp->shield=htonl(pl->p_shield); youp->fuel=htonl(pl->p_fuel); youp->etemp=htons(pl->p_etemp); youp->wtemp=htons(pl->p_wtemp); youp->whydead=htons(legacy_whydead(pl->p_whydead)); youp->whodead=htons(pl->p_whodead); youp->damage=htonl(pl->p_damage); youp->tractor=tractor; sendClientPacket((CVOID) youp); return (TRUE); } return (FALSE); } void updateSelf(int force) /* If force is true, a packet will be guarenteed to be sent. */ { static int again = 0; /* Flag, SP_S_YOU is always (almost) send two times. * * Because SP_S_YOU is now send via UDP HW 27.06.93 */ if(send_short && me->p_fuel < 61000 ) { /* A little margin ... */ sndSelfShip(&clientSelfShip, me); { /* Send Self using short packets */ if (!sndSSelf(&clientSelfShort, me, UPDT_MOST)) if (again || force) { sndSSelf(&clientSelfShort, me, UPDT_ALL); if (!force) /* again - sortof boolean HW,sent SP_S_YOU again */ again ^= 1; } } } else /* Send Self using normal packets */ sndSelf(&clientSelf, me, force ? UPDT_ALL : UPDT_MOST); sendGeneric32Packet(); } void updateShips(void) { int i; struct player *pl; struct plyr_info_spacket *cpli; struct player_spacket *cpl; struct kills_spacket *kills; struct flags_spacket *flags; struct pstatus_spacket *pstatus; struct plyr_login_spacket *login; struct hostile_spacket *hostile; struct stats_spacket *stats; int update; clientVKillsCount = 0; highest_active_player = 0; /* S_P2 end */ clientVPlayerCount = 12; clientVXPlayerCount = 4; clientVPlayers[1] = 0; /* How many packets are in the Big... */ #if MAXPLAYER > 32 clientVXPlayers[1] = 0; #endif big=0; /* Please excuse the ugliness of this loop declaration */ for (i=0, pl=players, cpli=clientPlayersInfo, cpl=clientPlayers, kills=clientKills, flags=clientFlags, pstatus=clientPStatus, login=clientLogin, hostile=clientHostile, stats=clientStats; ip_flags & PFROBOT) && (me->p_team == NOBODY) ) ) sndHostile(hostile, pl, UPDT_ALL); else if (is_invisible_due_idle(pl)) sndHostile(hostile, pl, UPDT_LEAST); else sndHostile(hostile, pl, UPDT_MOST); sndPlayerInfo(cpli, pl); sndKills(kills, pl); /* S_P2 new flag sampling */ if (send_short > 1) { u_int oldflags; /* Skip observers' flags, unless I am the observer. */ if (pl->p_status != POBSERV || pl == me) { switch(pl->p_status){ case POBSERV: case PALIVE: /* huh, we must work */ highest_active_player = i; if(pl->p_flags & PFCLOAK){ n_flags[i] = 1; } else if(pl->p_flags & PFSHIELD){ n_flags[i] = 2; } else n_flags[i] = 3; break; case PEXPLODE: case PDEAD: highest_active_player = i; n_flags[i] = 0; break; default: n_flags[i] = 0; /* Is it ok to send the old value ? */ break; } /* Mark shield and cloak as updated, so they won't be resent again with a flags packet. */ if (F_full_direction_resolution && !F_flags_all) ; else { oldflags = ntohl(flags->flags); oldflags &= ~(PFSHIELD|PFCLOAK); oldflags |= pl->p_flags&(PFSHIELD|PFCLOAK); flags->flags = htonl(oldflags); } } } if (sndPStatus(pstatus, pl)) { update=1; if (pl->p_status == PFREE) { /* I think this will turn off ignores for players that leave. 7/24/91 TC */ ignored[i] = 0; } } /* Used to send flags here, see below 8/7/91 TC */ /* hidden enemies? -- note OBSERVer is always inviso to everyone else */ if ( (hiddenenemy && pl->p_team != me->p_team && !(pl->p_flags & PFSEEN) && status->tourn) || (pl->p_status == POBSERV && pl != me) || (is_invisible_due_idle(pl) && pl != me) ) { /* Player is invisible, send limited flags information, * and bogus player position. */ if (me!=pl) sndFlags(flags, pl, UPDT_MOST); sndPlayer(cpl, pl, UPDT_LEAST); continue; } if (me!=pl) sndFlags(flags, pl, UPDT_ALL); /* We update the player if any of the following are true: * 0) galactic_smooth is set in sysdef * 1) haven't updated him for 9 intervals. * 2) he is on the screen * 3) he was on the screen recently. */ if (!update && !galactic_smooth && repCount % efticks(9) != 0 && (ntohl(cpl->x) < me->p_x - SCALE*WINSIDE/2 || ntohl(cpl->x) > me->p_x + SCALE*WINSIDE/2 || ntohl(cpl->y) > me->p_y + SCALE*WINSIDE/2 || ntohl(cpl->y) < me->p_y - SCALE*WINSIDE/2) && (pl->p_y > me->p_y + SCALE*WINSIDE/2 || pl->p_x > me->p_x + SCALE*WINSIDE/2 || pl->p_x < me->p_x - SCALE*WINSIDE/2 || pl->p_y < me->p_y - SCALE*WINSIDE/2)) continue; /* If the guy is cloaked, give information only occasionally, * and make it slightly inaccurate. * Also, we don't give a direction. The client has no reason * to know. */ if ( (pl->p_flags & PFCLOAK) && (pl->p_cloakphase == (CLOAK_PHASES - 1)) && (me != pl) && !mustUpdate[i]) { if (repCount % efticks(9) != 0) { /* Player is cloaked on users screen, * but is not ready for another update. * Resend old packet. */ sndPlayer(cpl, pl, UPDT_LITTLE); continue; } /* Player is cloaked on users screen, * update his position with innacurate location */ sndPlayer(cpl, pl, UPDT_MANY); continue; } if (pl != me && (pl->p_flags & PFCLOAK)) /* Player is cloaking on user screen */ sndPlayer(cpl, pl, UPDT_MOST); else /* Send normal postion for player */ sndPlayer(cpl, pl, UPDT_ALL); } if(send_short && (clientVPlayerCount > 12 || clientVXPlayerCount > 4 || big != 0 || send_short > 1 /* S_P2 fl;agsampling */)) sendVPlayers(); /* S_P2 */ if(send_short > 1) sendVKills(); if (F_flags_all) { if (send_short) { if (F_full_direction_resolution) { updateFlagsAll(0); if (highest_active_player > 15) updateFlagsAll(1); } } else { updateFlagsAll(0); if (highest_active_player > 15) updateFlagsAll(1); } } } void updateTorps(void) { struct torp *t; int i; struct torp_info_spacket *tpi; struct torp_spacket *tp; for (i=0, t=firstTorp, tpi=clientTorpsInfo, tp=clientTorps; t<=lastTorp; i++, t++, tpi++, tp++) { /* * If it's my torp, send info on it regardless of position; * helps clients to display number of torps in flight, and allows * observers to show all torps */ if (myTorp(t) || (F_full_weapon_resolution && me->p_status == POBSERV) ) { sndTorp(tpi, tp, t, i, UPDT_ALL); continue; } /* * Not my torp. * If not in view, only send limited information * Full weapon resolution torps are skipped, they are instead * sent via SupdateTorps */ if (F_full_weapon_resolution) continue; if ((t->t_y > me->p_y + SCALE*WINSIDE/2) || (t->t_y < me->p_y - SCALE*WINSIDE/2) || (t->t_x > me->p_x + SCALE*WINSIDE/2) || (t->t_x < me->p_x - SCALE*WINSIDE/2) || (t->t_status == TFREE)) { sndTorp(tpi, tp, t, i, UPDT_LITTLE); continue; } /* * Not my torp, and in view. * Send torp info (we assume it moved) */ sndTorp(tpi, tp, t, i, UPDT_MOST); } } void updatePlasmas(void) { struct torp *t; int i; struct plasma_info_spacket *tpi; struct plasma_spacket *tp; for (i=0, t=firstPlasma, tpi=clientPlasmasInfo, tp=clientPlasmas; t<=lastPlasma; i++, t++, tpi++, tp++) { if (myTorp(t) || (F_full_weapon_resolution && me->p_status == POBSERV) ) { sndPlasma(tpi, tp, t, i, UPDT_ALL); continue; } /* * Not my torp. * If not in view, only send limited information */ if ((t->t_y > me->p_y + SCALE*WINSIDE/2) || (t->t_y < me->p_y - SCALE*WINSIDE/2) || (t->t_x > me->p_x + SCALE*WINSIDE/2) || (t->t_x < me->p_x - SCALE*WINSIDE/2) || (t->t_status == TFREE)) { sndPlasma(tpi, tp, t, i, UPDT_LITTLE); continue; } /* * Not my torp, and in view. * Send torp info (we assume it moved) */ sndPlasma(tpi, tp, t, i, UPDT_MOST); } } void updatePhasers(void) { int i; struct phaser_spacket *ph; struct phaser *phase; struct player *pl; struct phaser_s_spacket *phs; /* Clear old mustUpdate values */ for (i=0; ip_y > me->p_y + SCALE*WINSIDE/2 || pl->p_x > me->p_x + SCALE*WINSIDE/2 || pl->p_x < me->p_x - SCALE*WINSIDE/2 || pl->p_y < me->p_y - SCALE*WINSIDE/2) && ((F_full_weapon_resolution && me->p_status == POBSERV) ? 0: 1) ) { sndPhaser(ph, phs, phase, i, UPDT_LITTLE); } else { if (phase->ph_status==PHHIT) { mustUpdate[phase->ph_target]=1; } sndPhaser(ph, phs, phase, i, UPDT_ALL); } } } void updatePlanets(void) { int i; struct planet_spacket *pl; struct planet *plan; struct planet_loc_spacket *pll; clientVPlanetCount = 0; for (i=0, pl=clientPlanets, plan=planets, pll=clientPlanetLocs; ip_x > 0) && (me->p_y > 0) && (me->p_team == NOBODY) ) { sndPlanet(pl, plan, UPDT_ALL); } else if ( plan->pl_info & me->p_team ) { /* scouted */ sndPlanet(pl, plan, UPDT_ALL); } else { /* Not scouted */ sndPlanet(pl, plan, UPDT_LITTLE); } /* Assume that the planet only needs to be updated once... */ /* Odd, changes in pl_y not supported. 5/31/92 TC */ sndPlanetLoc(pll, plan); } /* Now we can send our Planet Packet */ sendVPlanets(); } /* give session stats if you send yourself a '?' 2/27/92 TC */ /* return true if you should eat message */ static int parseQuery(struct message *msg) { /* 0-8 for address, 9 is space */ char *cchar = &msg->m_data[10]; if (*cchar == '?' && *(cchar+1) == '\0') return bounceSessionStats(msg->m_from); #ifdef PING if (*cchar == '!' && *(cchar+1) == '\0') return bouncePingStats(msg->m_from); #endif #ifdef RSA if (*cchar == '#' && *(cchar+1) == '\0') return bounceRSAClientType(msg->m_from); #endif if (*cchar == '^' && *(cchar+1) == '\0') return bounceSBStats(msg->m_from); if (*cchar == '@' && *(cchar+1) == '\0') return bounceWhois(msg->m_from); if (strcmp(cchar, "udpstats") == 0) return bounceUDPStats(msg->m_from); return FALSE; } void updateMessages(void) { struct message *cur; struct mesg_spacket msg; int reset_flags = 0; int send_msg; struct player *p_from; int is_whitelisted = 0; int warning_shown = 0; for (; msgCurrent!=(mctl->mc_current+1) % MAXMESSAGE; msgCurrent=(msgCurrent+1) % MAXMESSAGE) { if (msgCurrent>=MAXMESSAGE) msgCurrent=0; cur = &messages[msgCurrent]; if ((macroignore && cur->m_flags & MMACRO) || (dooshignore && cur->m_from == DOOSHMSG)) { continue; } if (cur->m_flags & MVALID && (cur->m_flags & MALL || (cur->m_flags & MTEAM && cur->m_recpt & me->p_team) || (cur->m_flags & MINDIV && cur->m_recpt == me->p_no) )) { /* hack for displaying MINDIV && MCONQ messages to stdout on the clients. Clients only show MALL && MCONQ. but we don't want to send to all. So at this point, MINDIV has already directed it to the right guy. Now, cancel MINDIV and set MALL, for the client's benefit. ATH, 11/5/95 */ if ((cur->m_flags & MINDIV) && (cur->m_flags & MCONQ)) { cur->m_flags &= ~MINDIV; cur->m_flags |= MALL; reset_flags = 1; } if(send_short && (cur->m_from == 255)) { /* Test if possible to send with SP_S_WARNING */ if (updtMessageSMessage(cur)) { continue; } } send_msg = FALSE; if ((cur->m_from < 0) || (cur->m_from > MAXPLAYER)) { is_whitelisted = 0; } else { p_from = p_no(cur->m_from); is_whitelisted = ip_whitelisted(p_from->p_ip); } if ((cur->m_from < 0) || (cur->m_from > MAXPLAYER)) send_msg = TRUE; else if (cur->m_flags & MALL) { if (ignored[cur->m_from] & MALL) { if (is_whitelisted && whitelist_all) send_msg = TRUE; } else { send_msg = TRUE; } } else if (cur->m_flags & MTEAM) { if (ignored[cur->m_from] & MTEAM) { if (is_whitelisted && whitelist_team) send_msg = TRUE; } else { send_msg = TRUE; } } else if (cur->m_flags & MINDIV) { int query = 0; /* session stats now parsed here. parseQuery == true */ /* means eat message 4/17/92 TC */ query = parseQuery(cur); if (!query) { if (ignored[cur->m_from] & MINDIV) { if (is_whitelisted && whitelist_indiv) { send_msg = TRUE; if (!warning_shown) { god(cur->m_from, "Player is ignoring you but your whitelist entry overrides it."); warning_shown = 1; } } else { god(cur->m_from, "That player is currently ignoring you."); } } else { send_msg = TRUE; } } } #ifdef CONTINUUM_MUTE_COMMANDS /* observer muting commands, available to players */ if (send_msg) { char *cchar = &cur->m_data[10]; if (!strcasecmp(cchar, "mute on")) { if (me->p_status == POBSERV) { if (!mute) { god(cur->m_from, "Mute enabled."); mute = TRUE; } send_msg = FALSE; } } else if (!strcasecmp(cchar, "mute off")) { if (me->p_status == POBSERV) { if (mute) { god(cur->m_from, "Mute disabled."); mute = FALSE; } send_msg = FALSE; } } } #endif if (send_msg) updtMessage(&msg, cur); } /* Put eject message back as MINDIV, so everyone doesn't get it later */ if (reset_flags) { cur->m_flags &= ~MALL; cur->m_flags |= MINDIV; reset_flags = 0; } } } static void updateVPlayer(struct player_spacket *p) { int i = clientVPlayerCount; #if MAXPLAYER > 32 int j = clientVXPlayerCount; #endif U_LONG x = ntohl(p->x), y = ntohl(p->y); int dir,dx,dy; int view = SCALE * WINSIDE / 2; if (p->pnum == me->p_no){ if ( send_short > 1) { /* S_P2 */ struct player_s2_spacket *pl = (struct player_s2_spacket *) &clientVPlayers[0]; pl->x = (short) htons((x+SCALE/2)/SCALE) /* p->x*/ ; pl->y = (short) htons((y+SCALE/2)/SCALE) /*p->y*/; pl->speed = p->speed; pl->dir = p->dir; big = 1; /* Flag to remind me that we must send big header */ } else { struct player_s_spacket *pl = (struct player_s_spacket *) &clientVPlayers[0]; pl->x = (long) htonl(x)/* p->x*/ ; pl->y = (long) htonl(y) /*p->y*/; pl->speed = p->speed; pl->dir = p->dir; big = 1; /* Flag to remind me that we must send big header */ } } else #if (MAXPLAYER > 32) if ( p->pnum < 32) #endif { clientVPlayers[1] += 1; /* Another packet... */ /* Where is the ship? On local or galactic map. */ dx = (int) x - me->p_x; dy = (int) y - me->p_y; if (dx > view || dx < -view || dy > view || dy < -view) { /* Galactic */ dx = (int) x * WINSIDE / GWIDTH; /* Orig. */ dy = (int) y * WINSIDE / GWIDTH; if ( dx < 0 || dy < 0 || dx >= WINSIDE || dy >= WINSIDE) { dx = 501; /* clipped */ dy = 501; } dir = rosette (p->dir); clientVPlayers[i++] = (u_char) ((p->pnum)|((dx & 256) >> 2)|((dy & 256)>>1) | 32); clientVPlayers[i++] = ( u_char)(( p->speed & 0x0f)|(dir << 4)); clientVPlayers[i++] = (u_char) (dx & 0xff); clientVPlayers[i++] = (u_char) ( dy & 0xff); clientVPlayerCount = i; } else { /* Local */ /* dx = dx / SCALE + WINSIDE / 2; dy = dy / SCALE + WINSIDE / 2; */ /* NEW -- fix precision loss -tsh */ dx = (int) x/SCALE - me->p_x/SCALE + WINSIDE/2; dy = (int) y/SCALE - me->p_y/SCALE + WINSIDE/2; dir = rosette (p->dir); clientVPlayers[i++] = (u_char) ((p->pnum)|((dx & 256) >> 2)|((dy & 256)>>1) ); clientVPlayers[i++] = ( u_char)(( p->speed & 0x0f)|(dir << 4)); clientVPlayers[i++] = (u_char) (dx & 0xff); clientVPlayers[i++] = (u_char) ( dy & 0xff); clientVPlayerCount = i; } } #if (MAXPLAYER > 32) else #if (MAXPLAYER > 64) if ( p->pnum < 64) #endif { clientVXPlayers[1] += 1; /* Where is the ship? On local or galactic map. */ dx = x - me->p_x; dy = y - me->p_y; if (dx > view || dx < -view || dy > view || dy < -view) { /* Galactic */ dx = x * WINSIDE / GWIDTH; /* Orig. */ dy = y * WINSIDE / GWIDTH; if ( dx < 0 || dy < 0 || dx >= WINSIDE || dy >= WINSIDE) { dx = 501; /* clipped */ dy = 501; } dir = rosette (p->dir); clientVXPlayers[j++] = (u_char) ((p->pnum - 32)|((dx & 256) >> 2)|((dy & 256)>>1) | 32); clientVXPlayers[j++] = (u_char)(( p->speed & 0x0f)|(dir << 4)); clientVXPlayers[j++] = (u_char) (dx & 0xff); clientVXPlayers[j++] = (u_char) ( dy & 0xff); clientVXPlayerCount = j; } else { /* Local */ dx = dx / SCALE + WINSIDE / 2; dy = dy / SCALE + WINSIDE / 2; dir = rosette (p->dir); clientVXPlayers[j++] = (u_char) ((p->pnum-32)|((dx & 256) >> 2)|((dy & 256)>>1) ); clientVXPlayers[j++] = (u_char)(( p->speed & 0x0f)|(dir << 4)); clientVXPlayers[j++] = (u_char) (dx & 0xff); clientVXPlayers[j++] = (u_char) ( dy & 0xff); clientVXPlayerCount = j; } } #if (MAXPLAYER > 64) else sendClientPacket((struct player_spacket *) p); #endif #endif /* MAXPLAYER > 32 */ } static void sendVPlayers(void) { unsigned int size,i,j,new; /* initialize type & length fields */ clientVPlayers[0] = (u_char) SP_S_PLAYER; #if MAXPLAYER > 32 clientVXPlayers[0] = (u_char) SP_S_PLAYER; #endif if ( big != 0) { /* Big Packet */ if ( send_short > 1) { /* S_P2 */ struct player_s2_spacket *pa = (struct player_s2_spacket *) &clientVPlayers[0]; pa->flags = 0; new = 0; for(i=0,j=0; i < 16 && i < MAXPLAYER;i++ , j += 2) { new = new | ((unsigned int)n_flags[i] << j); } /* for */ pa->flags = (long) htonl(new); size = 12+(clientVPlayers[1]*4); sizes[SP_S_PLAYER] = size; sendClientPacket((struct player_spacket *) clientVPlayers); if(highest_active_player > 15 && highest_active_player < 32) { struct top_flags *ptr = (struct top_flags *) &clientVPlayers[4]; new = 0; for(i=16,j=0; i < 32 && i < MAXPLAYER; i++, j +=2) { new = new | ((unsigned int)n_flags[i] << j); } /* for */ ptr->tflags = htonl(new); ptr->type = (u_char) SP_S_PLAYER; ptr->packets = (unsigned char) 64; ptr->numflags = 1; ptr->index = 1; size = 8; sizes[SP_S_PLAYER] = size; sendClientPacket((struct player_spacket *) &clientVPlayers[4]); } } /* if */ else { size = 12+( clientVPlayers[1]*4); sizes[SP_S_PLAYER] = size; sendClientPacket((struct player_spacket *) clientVPlayers); } } else if ( clientVPlayerCount > 12){ /* Small packet */ if (send_short > 1) { /* S_P2 */ if(highest_active_player > 15 && highest_active_player < 32) { struct top_flags *ptr = (struct top_flags *) &clientVPlayers[0]; new = 0; size = 12 + ( clientVPlayers[1]*4); for(i=16,j=0; i < 32 && i < MAXPLAYER; i++, j +=2) { new = new | ((unsigned int)n_flags[i] << j); } /* for */ ptr->tflags = htonl(new); new=0; for(i=0,j=0; i < 16 && i < MAXPLAYER;i++ , j += 2) { new = new | ((unsigned int)n_flags[i] << j); } /* for */ ptr->tflags2 = htonl(new); ptr->type = (u_char) SP_S_PLAYER; ptr->packets = (unsigned char) clientVPlayers[1] | 64; ptr->numflags = 2; ptr->index = 1; sizes[SP_S_PLAYER] = size; sendClientPacket((struct player_spacket *) &clientVPlayers[0]); } else { /* No players > 15 */ struct top_flags *ptr = (struct top_flags *) &clientVPlayers[4]; new = 0; size = 8 + ( clientVPlayers[1]*4); for(i=0,j=0; i < 16 && i < MAXPLAYER; i++, j +=2) { new = new | ((unsigned int)n_flags[i] << j); } /* for */ ptr->tflags = htonl(new); ptr->type = (u_char) SP_S_PLAYER; ptr->packets = (unsigned char) clientVPlayers[1] | 64; ptr->numflags = 1; ptr->index = 0; sizes[SP_S_PLAYER] = size; sendClientPacket((struct player_spacket *) &clientVPlayers[4]); } /* active player if */ } /* S_P2 */ else { size = 4 + ( clientVPlayers[1]*4); sizes[SP_S_PLAYER] = size; clientVPlayers[8] = (u_char) SP_S_PLAYER; clientVPlayers[9] = clientVPlayers[1] | 64; clientVPlayers[10]=0; clientVPlayers[11]=0; sendClientPacket((struct player_spacket *) &clientVPlayers[8]); } } #if MAXPLAYER > 32 if ( clientVXPlayerCount > 4) { /* Small + extended Packet */ sizes[SP_S_PLAYER] = (clientVXPlayers[1]*4)+4; clientVXPlayers[1] |= 128; /* To mark it as a short header + Extended */ sendClientPacket((struct player_spacket *) clientVXPlayers); } #endif } /* New Torp Routine */ void SupdateTorps(void) { struct torp *torp; int i,j; struct torp_info_spacket *tpi; struct torp_spacket *tp; u_char *tinfo; /* TorpInfo data */ u_char *torp_xy; /* The torp coord. */ u_char infobitset, torpbitset; int numtorps ; /* How many torps ? */ int shift; /* Shift for 9 bit xy coordinate */ int dx,dy; int view = SCALE * WINSIDE / 2; mustsend = 0; for ( j=0, torp=torps, tpi=clientTorpsInfo, tp=clientTorps; #if ((MAXPLAYER*MAXTORP) % 8 == 0) j< (MAXPLAYER * MAXTORP)/8; #else /* This normally wont test true.. But this will make the code more flexible, * in case someone starts messing with the defaults.. */ j< (MAXPLAYER*MAXTORP + 7)/8; #endif j++) { shift = 0; numtorps = 0; infobitset = 0; torpbitset = 0; torp_xy = &clientVTorps[4]; *torp_xy = 0; /* Clear first data byte */ tinfo = & clientVTorpsInfo[0]; for (i=0; i<8; i++, torp++, tpi++, tp++) { #if ((MAXPLAYER*MAXTORP) % 8 != 0) /* This normally wont test true.. But this will make the code more flexible, * in case someone starts messing with the defaults.. */ if (j*8+i >= (MAXPLAYER * MAXTORP)) break; #endif if (torp->t_owner==me->p_no) { /* With full weapon resolution, self torps sent via updateTorps */ if (F_full_weapon_resolution) continue; if (torp->t_war!=tpi->war || torp->t_status!=tpi->status) { if (torp->t_war == tpi->war){ /* Don't send TMOVE/TFREE . It's encoded in the SP_S_TORP bitset. */ switch(torp->t_status){ case TFREE: if (tpi->status == TEXPLODE){ /* Send real TFREE if torp exploded */ /* set bit for torp */ infobitset = infobitset | ( 01 << i); *tinfo++ = ((u_char)tpi->war & 0x0f) | ((u_char) torp->t_status << 4); } else mustsend = 1; tpi->status=torp->t_status; /* Don't forget... */ tp->x=htonl(torp->t_x); tp->y=htonl(torp->t_y); tp->dir=torp->t_dir; continue; /* We continue , because server sends obsolete data otherwise */ case TMOVE: tpi->status=torp->t_status; break; default: tpi->status=torp->t_status; /* set bit for torp */ infobitset = infobitset | ( 01 << i); *tinfo++ = ((u_char)tpi->war & 0x0f) |((u_char) tpi->status << 4); break; } } else { tpi->war=torp->t_war; /* set bit for torp */ tpi->status=torp->t_status; infobitset = infobitset | ( 01 << i); *tinfo++ = ((u_char)tpi->war & 0x0f) |((u_char) tpi->status << 4); } } if ( tp->x!=htonl(torp->t_x) || tp->y!=htonl(torp->t_y) || ( (torp->t_gspeed == 0) && (torp->t_status != TFREE))) { /* Hadley */ tp->type=SP_TORP; tp->x=htonl(torp->t_x); tp->y=htonl(torp->t_y); tp->dir=torp->t_dir; /* Now the fun begins .. */ /* set bit for torp */ torpbitset = torpbitset | ( 01 << i); numtorps++; /* Now the Coordi. */ dx = torp->t_x - me->p_x; dy = torp->t_y - me->p_y; if (dx > view || dx < -view || dy > view || dy < -view) { /* any torps off screen appear at 501 = clipped */ dx = dy = 501; dx <<= shift; *torp_xy++ |= ( dx & 255); *torp_xy = (((u_int) dx >> 8) & 255); shift++; dy <<= shift; *torp_xy++ |= (dy & 255); *torp_xy = (((u_int) dy >> 8) & 255); shift++; if ( shift == 8){ shift = 0; torp_xy++; *torp_xy = 0; } continue; } /* dx = dx / SCALE + WINSIDE / 2; dy = dy / SCALE + WINSIDE / 2; */ /* NEW: fix precision loss -tsh */ dx = torp->t_x/SCALE - me->p_x/SCALE + WINSIDE/2; dy = torp->t_y/SCALE - me->p_y/SCALE + WINSIDE/2; dx <<= shift; *torp_xy++ |= (dx & 0xff ); *torp_xy = (((u_int) dx >> 8) & 255); shift++; dy <<= shift; *torp_xy++ |= (dy & 255); *torp_xy = (((u_int) dy >> 8) & 255); shift++; if ( shift == 8){ shift = 0; torp_xy++; *torp_xy = 0; } } } else { /* Someone else's torp... */ if (torp->t_y > me->p_y + SCALE*WINSIDE/2 || torp->t_x > me->p_x + SCALE*WINSIDE/2 || torp->t_x < me->p_x - SCALE*WINSIDE/2 || torp->t_y < me->p_y - SCALE*WINSIDE/2 || torp->t_status==TFREE) { if (torp->t_status==TFREE && tpi->status==TEXPLODE) { tpi->status=TFREE; continue; } if (tpi->status!=TFREE) { tpi->status=TFREE; mustsend = 1; } } else { /* in view */ if (torp->t_status!=tpi->status || (torp->t_war & me->p_team)!=tpi->war) { if ( (torp->t_war & me->p_team) == tpi->war){ /* Don't send TMOVE/TFREE . It's encoded in the SP_S_TORP bitset. */ switch(torp->t_status){ case TFREE: /* We continue , because server sends obsolete data otherwise */ tpi->status=torp->t_status; mustsend = 1; /* Don't forget... */ tp->x=htonl(torp->t_x); tp->y=htonl(torp->t_y); tp->dir=torp->t_dir; continue; case TMOVE: tpi->status=torp->t_status; break; default: tpi->status=torp->t_status; infobitset = infobitset | ( 01 << i); /* set bit for torp */ *tinfo++ = ((u_char)tpi->war & 0x0f)|((u_char) tpi->status << 4); break; } } else { /* Let the client fade away the explosion on its own */ tpi->war=torp->t_war & me->p_team; tpi->status=torp->t_status; infobitset = infobitset | ( 01 << i); /* set bit for torp */ *tinfo++ = ((u_char)tpi->war & 0x0f)|((u_char) tpi->status << 4); } } if (tp->x!=htonl(torp->t_x) || tp->y!=htonl(torp->t_y) || (torp->t_gspeed == 0 && torp->t_status != TFREE)) {/*Hadley*/ tp->x=htonl(torp->t_x); tp->y=htonl(torp->t_y); tp->dir=torp->t_dir; /* Now the fun begins .. */ torpbitset = torpbitset | ( 01 << i); /* set bit for torp */ numtorps++; /* Now the Coordi. */ /* dx = torp->t_x - me->p_x; dx = dx / SCALE + WINSIDE / 2; dy = torp->t_y - me->p_y; dy = dy / SCALE + WINSIDE / 2; */ /* NEW: fix precision loss -tsh */ dx = torp->t_x/SCALE - me->p_x/SCALE + WINSIDE/2; dy = torp->t_y/SCALE - me->p_y/SCALE + WINSIDE/2; dx <<= shift; *torp_xy++ |= (dx & 255); *torp_xy = (((u_int) dx >> 8) & 255); shift++; dy <<= shift; *torp_xy++ |= (dy & 255); *torp_xy = (((u_int) dy >> 8) & 255); shift++; if ( shift == 8){ shift = 0; torp_xy++; *torp_xy = 0; } } /* second if */ } } } /* 2. for */ /* Is there something to send ? */ if ( infobitset != 0) { int size = tinfo -clientVTorpsInfo; u_char *dest = &clientVTorps[4+ vtdata[numtorps]]; u_char *source = &clientVTorpsInfo[0]; /* I must copy the Torpinfo behind the Torpdata */ while ( --size >= 0) { /* size doubly used */ *dest++ = *source++; } size = 4 + vtdata[numtorps]+ (tinfo -clientVTorpsInfo); if((size % 4) != 0) size += (4 - (size % 4)); sizes[SP_S_TORP_INFO] = size; clientVTorps[0] = SP_S_TORP_INFO; /* The type */ clientVTorps[1] = (u_char) torpbitset; clientVTorps[2] = (u_char) j; /* which torps */ clientVTorps[3] = (u_char) infobitset; sendClientPacket((struct torp_spacket *) &clientVTorps[0]); mustsend = 0; } else if ( torpbitset != 0){ /* NO TorpInfo */ mustsend = 0; if ( numtorps == 8) { /* we do not need bitset */ clientVTorps[2] = SP_S_8_TORP; /* The type */ clientVTorps[3] = (u_char) j; /* which torps */ sendClientPacket((struct torp_spacket *) &clientVTorps[2]); } else { sizes[SP_S_TORP] = vtsize[numtorps]; clientVTorps[1] = SP_S_TORP; /* The type */ clientVTorps[2] = (u_char) torpbitset; clientVTorps[3] = (u_char) j; /* which torps */ sendClientPacket((struct torp_spacket *) &clientVTorps[1]); } } else if (mustsend != 0){ /* TFREE's */ mustsend = 0; sizes[SP_S_TORP] = 4; clientVTorps[1] = SP_S_TORP; /* The type */ clientVTorps[2] = (u_char)torpbitset; clientVTorps[3] = (u_char) j; /* which torps */ sendClientPacket((struct torp_spacket *) &clientVTorps[1]); } } /* auesseres for */ } /* Function */ void updatePlayerStats(void) { int i; struct stats_spacket *stats; struct stats_s_spacket *s_stats = &singleStats; struct player *pl; static int lastpno = -1; /* Variables for stats */ int kills, losses, armsbomb, planets; int tkills, tlosses, tarmsbomb, tplanets; int sbkills, sblosses, sbticks, tticks; double maxkills, sbmaxkills; int my_tkills, my_tlosses, my_tarmsbomb, my_tplanets, my_tticks; /* Wait at least 1 second before sending another stats packet */ if(repCount % efticks(5) != 0) return; /* Look for the next non-empty non-observer slot */ for(i=1;i<=MAXPLAYER;i++) { pl = &players[(lastpno+i)%MAXPLAYER]; if(pl->p_status!=PFREE && pl->p_status!=POBSERV) break; } /* No one playing...? */ if(i>MAXPLAYER) return; lastpno = pl->p_no; stats = &clientStats[pl->p_no]; /* Put the stats into local variables, one version for LTD and one version for non-LTD */ #ifdef LTD_STATS tkills = ltd_kills(pl, LTD_TOTAL); tlosses = ltd_deaths(pl, LTD_TOTAL); tarmsbomb = ltd_armies_bombed(pl, LTD_TOTAL); tplanets = ltd_planets_taken(pl, LTD_TOTAL); kills = 0; losses = 0; armsbomb = 0; planets = 0; sbkills = ltd_kills(pl, LTD_SB); sblosses = ltd_deaths(pl, LTD_SB); sbticks = ltd_ticks(pl, LTD_SB); tticks = ltd_ticks(pl, LTD_TOTAL); maxkills = ltd_kills_max(pl, LTD_TOTAL); sbmaxkills = ltd_kills_max(pl, LTD_SB); my_tkills = ltd_kills(me, LTD_TOTAL); my_tlosses = ltd_deaths(me, LTD_TOTAL); my_tarmsbomb = ltd_armies_bombed(me, LTD_TOTAL); my_tplanets = ltd_planets_taken(me, LTD_TOTAL); my_tticks = ltd_ticks(me, LTD_TOTAL); #else /* not LTD_STATS */ tkills = pl->p_stats.st_tkills; tlosses = pl->p_stats.st_tlosses; tarmsbomb = pl->p_stats.st_tarmsbomb; tplanets = pl->p_stats.st_tplanets; kills = pl->p_stats.st_kills; losses = pl->p_stats.st_losses; armsbomb = pl->p_stats.st_armsbomb; planets = pl->p_stats.st_planets; sbkills = pl->p_stats.st_sbkills; sblosses = pl->p_stats.st_sblosses; sbticks = pl->p_stats.st_sbticks; tticks = pl->p_stats.st_tticks; maxkills = pl->p_stats.st_maxkills; sbmaxkills = pl->p_stats.st_sbmaxkills; my_tkills = me->p_stats.st_tkills; my_tlosses = me->p_stats.st_tlosses; my_tarmsbomb = me->p_stats.st_tarmsbomb; my_tplanets = me->p_stats.st_tplanets; my_tticks = me->p_stats.st_tticks; #endif /* LTD_STATS */ /* Taken from inl source, socket.c. Hack for INL robot (when stats are reset). Stick it in here for lack of a better place. Needed because these are ntserv process variables, so robot can't touch them. */ if (startTkills > my_tkills || startTlosses > my_tlosses || startTarms > my_tarmsbomb || startTplanets > my_tplanets || startTticks > my_tticks) { startTkills = my_tkills; startTlosses = my_tlosses; startTarms = my_tarmsbomb; startTplanets = my_tplanets; startTticks = my_tticks; } /* * Send stat packets once per five updates. But, only send one. We * will cycle through them all eventually. */ if (stats->tkills!=htonl(tkills) || stats->tlosses!=htonl(tlosses) || stats->kills!=htonl(kills) || stats->losses!=htonl(losses) || stats->sbkills!=htonl(sbkills) || stats->sblosses!=htonl(sblosses) || stats->tplanets!=htonl(tplanets) || stats->tarmies!=htonl(tarmsbomb) || stats->planets!=htonl(planets) || stats->armies!=htonl(armsbomb) || stats->tticks!=htonl(tticks) ) { stats->type = SP_STATS; stats->pnum = pl->p_no; stats->tkills = htonl(tkills); stats->tlosses = htonl(tlosses); stats->kills = htonl(kills); stats->losses = htonl(losses); stats->tticks = htonl(tticks); stats->tplanets = htonl(tplanets); stats->tarmies = htonl(tarmsbomb); stats->sbkills = htonl(sbkills); stats->sblosses = htonl(sblosses); stats->armies = htonl(armsbomb); stats->planets = htonl(planets); if ((pl->p_ship.s_type == STARBASE) && (SBhours)) { stats->maxkills=htonl((int) (sbticks)); } else { stats->maxkills=htonl((int) (maxkills * 100)); } stats->sbmaxkills = htonl((int) (sbmaxkills * 100)); /* Should we send the short packets version instead? */ if (send_short > 1 && tkills < 0xffff && tlosses < 0xffff && kills < 0xffff && losses < 0xffff && sbkills < 0xffff && sblosses < 0xffff && armsbomb < 0xffff && planets < 0xffff && tplanets < 0xffff ) { s_stats->type=SP_S_STATS; s_stats->pnum=pl->p_no; s_stats->tkills = htons(tkills); s_stats->tlosses = htons(tlosses); s_stats->kills = htons(kills); s_stats->losses = htons(losses); s_stats->armies = htons(armsbomb); s_stats->planets = htons(planets); s_stats->tplanets = htons(tplanets); s_stats->sbkills = htons(sbkills); s_stats->sblosses = htons(sblosses); s_stats->tticks = htonl(tticks); s_stats->tarmies = htonl(tarmsbomb); s_stats->maxkills = stats->maxkills; s_stats->sbmaxkills = stats->sbmaxkills; sendClientPacket(s_stats); } else sendClientPacket((CVOID) stats); } } /* Called by initClientData - This routine initialized the local packet information to an unobtainable state. (Which then forces updates to occur) */ void initSPackets(void) { int i; for (i=0; imc_current+1) % MAXMESSAGE; clientSelf.pnum= -1; clientSelfShip.damage = -1; clientSelfShort.pnum = -1; clientGeneric32.type = 0; if (sizeof(struct generic_32_spacket_a) != GENERIC_32_LENGTH) { fprintf(stderr, "SP_GENERIC_32 size a wrong at %d bytes\n", sizeof(struct generic_32_spacket_a)); } if (sizeof(struct generic_32_spacket_b) != GENERIC_32_LENGTH) { fprintf(stderr, "SP_GENERIC_32 size b wrong at %d bytes\n", sizeof(struct generic_32_spacket_b)); } } /* Routine called by forceUpdate to clear local packet info, and force an update */ void clearSPackets(int update_all, int update_sall) { int i; /* WE must do this or change the torp implementation ( It is now changed )*/ /* But it should be no problem because normally NO packet is send */ if ( send_short) { for (i=0; ip_team; clientPlanets[i].armies= htonl(-1); /* clientPlanetLocs[i].x= htonl(-1); (critical) */ } /* msgCurrent=(mctl->mc_current+1) % MAXMESSAGE;*/ clientSelf.pnum= -1; clientSelfShort.pnum = -1; clientSelfShip.damage = -1; } #ifdef FEATURE_PACKETS void sendFeature(struct feature_spacket *packet) { packet->type = SP_FEATURE; packet->value = htonl(packet->value); sendClientPacket((CVOID) packet); } static void send_server_feature(char *name, int value) { struct feature_spacket fp; memset(&fp, 0, sizeof(struct feature_spacket)); fp.type = SP_FEATURE; fp.feature_type = 'S'; fp.value = htonl(value); strcpy(fp.name, name); sendClientPacket(&fp); } void sendFeatureFps() { send_server_feature("FPS", fps); } void sendFeatureUps() { send_server_feature("UPS", me == NULL ? defups : me->p_ups); } void sendLameRefit() { if (lame_refit != 1) send_server_feature("LAME_REFIT", lame_refit); } void sendLameBaseRefit() { if (lame_base_refit != 1) send_server_feature("LAME_BASE_REFIT", lame_base_refit); } #endif /* FEATURE_PACKETS */ /* * If we're in UDP mode, add a sequence number to the transmission buffer. * Returns the #of bytes inserted. * * This will add a sequence # to transmissions on either channel. However, * the current implementation doesn't put sequences on TCP transmissions * because mixed TCP packets and UDP packets rarely arrive in the order * in which they were sent. */ int addSequence(char *outbuf, LONG *seq_no) { struct sequence_spacket *ssp; #ifdef nodef /* assume true */ if (commMode != COMM_UDP || udpMode == MODE_TCP) return (0); #endif #ifdef PING /* this needs to be counted */ packets_sent ++; #endif ssp = (struct sequence_spacket *) outbuf; ssp->type = SP_SEQUENCE; ssp->sequence = htons((u_short) *seq_no); (*seq_no)++; return (sizeof(struct sequence_spacket)); } /* Add some of the player flags into the sequence packet. This isn't done when the sequence packet is made, because that is at the beginning of the update. The flags sent should be from the end of the update, nominally 100ms later. */ void addSequenceFlags(void *buf) { struct sequence_spacket *ssp = (struct sequence_spacket *) buf; u_int f=0; /* Doesn't look like a sequence packet */ if(ssp->type != SP_SEQUENCE) return; /* In cambot mode, we are dumping packets about all players, not just one. So sending the flags for "me" makes no sense. */ if(f_many_self) return; if (F_19flags) { /* Send the most useful flags that aren't packed into the SelfShip packet. */ ssp->flag8 = (me->p_flags&PFSHIELD ? 0x01 : 0) | (me->p_flags&PFREPAIR ? 0x02 : 0) | (me->p_flags&PFBOMB ? 0x04 : 0) | (me->p_flags&PFCLOAK ? 0x08 : 0) | (me->p_flags&PFWEP ? 0x10 : 0) | (me->p_flags&PFENG ? 0x20 : 0) | (me->p_flags&PFREFITTING ? 0x40 : 0) | (me->p_flags&PFDOCKOK ? 0x80 : 0); f = (PFSHIELD|PFREPAIR|PFBOMB|PFCLOAK| PFWEP|PFENG|PFREFITTING|PFDOCKOK); } else { /* S_P2 mode, send flags 8-15. Flags 0-7 are in the SelfShip packet. */ ssp->flag8 = (((unsigned int)me->p_flags >> 8) & 0xff); /* S_P2 */ if(send_short > 1 ) { /* In S_P2 mode, consider the flags sent to the client */ f = 0xff00; } else { /* Non-SP2, probably the client doesn't understand these flags but maybe it does. Sent them, but consider them not sent. */ f = 0; } } /* Consider the flags sent in this packet as sent, and do not resend with a SelfShort or Self packet */ clientSelfShort.flags = (clientSelfShort.flags & htonl(~f)) | htonl(me->p_flags & f); } void sendQueuePacket(short pos) { struct queue_spacket qPacket; qPacket.type=SP_QUEUE; qPacket.pos=htons(pos); sendClientPacket((CVOID) &qPacket); flushSockBuf(); } void sendPickokPacket(int state) { struct pickok_spacket pickPack; pickPack.type=SP_PICKOK; pickPack.state=state; sendClientPacket((CVOID) &pickPack); } void sendClientLogin(struct stats *stats) { struct login_spacket logPacket; logPacket.type=SP_LOGIN; if (stats==NULL) { logPacket.accept=0; } else { logPacket.accept=1; logPacket.flags=htonl(stats->st_flags); MCOPY(stats->st_keymap, logPacket.keymap, 96); } sendClientPacket((CVOID) &logPacket); } void sendMotdLine(char *line) { struct motd_spacket motdPacket; int len; /* Well it seems that we can really only send 79 characters for the motd. Seems kinda hosed... Added wraparound capability (mostly for the compiler options) DRG Jun 93 */ if ((len = strlen(line)) < (MSG_LEN - 1)) { /* no need to wrap around */ memset(&motdPacket, 0, sizeof(struct motd_spacket)); motdPacket.type = SP_MOTD; STRNCPY(motdPacket.line, line, MSG_LEN); motdPacket.line[MSG_LEN-1]='\0'; sendClientPacket((CVOID) &motdPacket); } else { char dmy[MSG_LEN]; char *ptr1,*ptr2; int i,j; dmy[MSG_LEN-1] ='\0'; for (i=0;i<(int)(((float)(len)/(float)(MSG_LEN-1.0))+0.99);i++) { ptr1 = dmy; ptr2 = &(line[i*(MSG_LEN-1)]); for (j=0;jtype = SP_GENERIC_32; ga->version = 'a'; /*! we did not use network byte order for these two fields */ ga->repair_time = pl->p_repair_time; ga->pl_orbit = pl->p_flags & PFORBIT ? pl->p_planet : -1; return ga; } static struct generic_32_spacket_b * sendGeneric32PacketB(struct player *pl, struct generic_32_spacket_b *gb) { int v, t; gb->type = SP_GENERIC_32; gb->version = 'b'; gb->repair_time = htons(pl->p_repair_time); gb->pl_orbit = pl->p_flags & PFORBIT ? pl->p_planet : -1; v = (status->gameup & ~GU_UNSAFE) | (is_idle(pl) ? 0 : GU_UNSAFE); gb->gameup = htons(v & 0xffff); gb->tournament_teams = ((context->quorum[1] << 4) & 0xf0) | (context->quorum[0] & 0xf); v = (context->frame - context->frame_tourn_start) / fps; s2du(v, &gb->tournament_age, &gb->tournament_age_units); v = context->inl_remaining / fps; s2du(v, &gb->tournament_remain, &gb->tournament_remain_units); v = teams[pl->p_team].te_turns; if (v < 0) v = 0; if (v > 255) v = 255; gb->starbase_remain = v; for (t=0;((t<=MAXTEAM)&&(teams[t].te_surrender==0));t++); if (t > MAXTEAM) { gb->team_remain = 0; /* no one is considering surrender now */ } else { v = teams[t].te_surrender * 60 + ((context->frame - teams[t].te_surrender_frame) / fps); gb->team_remain = (v > 255) ? 255 : v; } return gb; } void sendGeneric32Packet(void) { struct generic_32_spacket g, *gp; int len = GENERIC_32_LENGTH; if (!F_sp_generic_32) return; memset(&g, 0, len); gp = NULL; if (A_sp_generic_32 == GENERIC_32_VERSION_A || A_sp_generic_32 == 0) gp = (struct generic_32_spacket *) sendGeneric32PacketA(my(), (struct generic_32_spacket_a *)&g); if (A_sp_generic_32 == GENERIC_32_VERSION_B) gp = (struct generic_32_spacket *) sendGeneric32PacketB(my(), (struct generic_32_spacket_b *)&g); if (gp == NULL) return; if (memcmp(&clientGeneric32, gp, len) != 0) { memcpy(&clientGeneric32, gp, len); sendClientPacket(gp); } } /* Hey Emacs! -*- Mode: C; c-file-style: "bsd"; indent-tabs-mode: nil -*- */