1 /*
2  * XPilot NG, a multiplayer space war game.
3  *
4  * Copyright (C) 1991-2001 by
5  *
6  *      Bj�rn Stabell        <bjoern@xpilot.org>
7  *      Ken Ronny Schouten   <ken@xpilot.org>
8  *      Bert Gijsbers        <bert@xpilot.org>
9  *      Dick Balaska         <dick@xpilot.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25 
26 #include "xpclient.h"
27 
28 client_data_t	clData = { 0, };
29 
30 char	*geometry;
31 xp_args_t xpArgs;
32 Connect_param_t connectParam;
33 
34 bool	newbie;
35 int	baseWarningType;	/* Which type of base warning you prefer */
36 int	maxCharsInNames;
37 int	hudRadarDotSize;	/* Size for hudradar dot drawing */
38 double	hudRadarScale;		/* Scale for hudradar drawing */
39 double	hudRadarLimit;		/* Hudradar dots are not drawn if closer to
40 				   your ship than this factor of visible
41 				   range */
42 int	hudSize;		/* Size for HUD drawing, depends on hudScale */
43 
44 bool	is_server = false;	/* used in common code */
45 
46 bool	scoresChanged = true;
47 unsigned RadarHeight = 0;
48 unsigned RadarWidth = 256;	/* radar width at the server */
49 bool     UpdateRadar = false;   /* radar update because of polystyle changes? */
50 
51 int     oldServer;
52 ipos_t	selfPos;
53 ipos_t	selfVel;
54 short	heading;
55 short	nextCheckPoint;
56 
57 u_byte	numItems[NUM_ITEMS];	/* Count of currently owned items */
58 u_byte	lastNumItems[NUM_ITEMS];/* Last item count shown */
59 int	numItemsTime[NUM_ITEMS];/* Number of frames to show this item count */
60 double	showItemsTime;		/* How long to show changed item count for */
61 double	scoreObjectTime;	/* How long to flash score objects */
62 
63 short	autopilotLight;
64 
65 int	showScoreDecimals;
66 
67 short	lock_id;		/* Id of player locked onto */
68 short	lock_dir;		/* Direction of lock */
69 short	lock_dist;		/* Distance to player locked onto */
70 
71 int	eyesId;                 /* Player we get frame updates for */
72 other_t	*eyes = NULL;	        /* Player we get frame updates for */
73 bool	snooping;               /* are we snooping on someone else? */
74 int	eyeTeam = TEAM_NOT_SET;
75 
76 other_t	*self = NULL;	        /* player info */
77 short	selfVisible;		/* Are we alive and playing? */
78 short	damaged;		/* Damaged by ECM */
79 short	destruct;		/* If self destructing */
80 short	shutdown_delay;
81 short	shutdown_count;
82 short	thrusttime;
83 short	thrusttimemax;
84 short	shieldtime;
85 short	shieldtimemax;
86 short	phasingtime;
87 short	phasingtimemax;
88 
89 int	roundDelay;		/* != 0 means we're in a delay */
90 int	roundDelayMax;		/* (not yet) used for graph of time
91 				   remaining in delay */
92 
93 int	backgroundPointDist;	/* spacing of navigation points */
94 int	backgroundPointSize;	/* size of navigation points */
95 int	sparkSize;		/* size of debris and spark */
96 int	shotSize;		/* size of shot */
97 int	teamShotSize;		/* size of team shot */
98 double	controlTime;		/* Display control for how long? */
99 u_byte	spark_rand;		/* Sparkling effect */
100 u_byte	old_spark_rand;		/* previous value of spark_rand */
101 
102 double	fuelSum;		/* Sum of fuel in all tanks */
103 double	fuelMax;		/* How much fuel can you take? */
104 short	fuelCurrent;		/* Number of currently used tank */
105 short	numTanks;		/* Number of tanks */
106 double	fuelTime;		/* Display fuel for how long? */
107 double	fuelCritical;		/* Fuel critical level */
108 double	fuelWarning;		/* Fuel warning level */
109 double	fuelNotify;		/* Fuel notify level */
110 
111 char	*shipShape = NULL;	/* Shape of player's ship */
112 double	power;			/* Force of thrust */
113 double	power_s;		/* Saved power fiks */
114 double	turnspeed;		/* How fast player acc-turns */
115 double	turnspeed_s;		/* Saved turnspeed */
116 double	turnresistance;		/* How much is lost in % */
117 double	turnresistance_s;	/* Saved (see above) */
118 double	displayedPower;		/* What the server is sending us */
119 double	displayedTurnspeed;	/* What the server is sending us */
120 double	displayedTurnresistance;/* What the server is sending us */
121 double	sparkProb;		/* Sparkling effect user configurable */
122 int     charsPerSecond;         /* Message output speed (configurable) */
123 
124 double	hud_move_fact;		/* scale the hud-movement (speed) */
125 double	ptr_move_fact;		/* scale the speed pointer length */
126 instruments_t	instruments;		/* Instruments on screen */
127 char	mods[MAX_CHARS];	/* Current modifiers in effect */
128 int	packet_size;		/* Current frame update packet size */
129 int	packet_loss;		/* lost packets per second */
130 int	packet_drop;		/* dropped packets per second */
131 int	packet_lag;		/* approximate lag in frames */
132 char	*packet_measure;	/* packet measurement in a second */
133 long	packet_loop;		/* start of measurement */
134 
135 bool	showUserName = false;	/* Show user name instead of nick name */
136 char	servername[MAX_CHARS];	/* Name of server connecting to */
137 unsigned	version;	/* Version of the server */
138 bool	toggle_shield;		/* Are shields toggled by a press? */
139 bool	shields = true;		/* When shields are considered up */
140 bool	auto_shield = true;	/* shield drops for fire */
141 char	modBankStr[NUM_MODBANKS][MAX_CHARS]; /* modifier banks */
142 
143 int	maxFPS;			/* Max FPS player wants from server */
144 int	oldMaxFPS = 0;
145 double	clientFPS = 1.0;	/* FPS client is drawing at */
146 int	recordFPS = 0;		/* What FPS to record at */
147 time_t	currentTime = 0;	/* Current value of time() */
148 bool	newSecond = false;	/* Did time() increment this frame? */
149 
150 int	maxMouseTurnsPS = 0;
151 int	mouseMovementInterval = 0;
152 int	cumulativeMouseMovement = 0;
153 
154 int	clientPortStart = 0;	/* First UDP port for clients */
155 int	clientPortEnd = 0;	/* Last one (these are for firewalls) */
156 
157 byte	lose_item;		/* index for dropping owned item */
158 int	lose_item_active;	/* one of the lose keys is pressed */
159 
160 static double       teamscores[MAX_TEAMS];
161 static cannontime_t *cannons = NULL;
162 static int          num_cannons = 0;
163 static target_t     *targets = NULL;
164 static int          num_targets = 0;
165 
166 fuelstation_t       *fuels = NULL;
167 int                 num_fuels = 0;
168 homebase_t          *bases = NULL;
169 int                 num_bases = 0;
170 checkpoint_t        *checks = NULL;
171 int                 num_checks = 0;
172 xp_polygon_t        *polygons = NULL;
173 int                 num_polygons = 0;
174 edge_style_t        *edge_styles = NULL;
175 int                 num_edge_styles = 0;
176 polygon_style_t     *polygon_styles = NULL;
177 int                 num_polygon_styles = 0;
178 
179 score_object_t      score_objects[MAX_SCORE_OBJECTS];
180 int                 score_object = 0;
181 other_t             *Others = NULL;
182 int                 num_others = 0, max_others = 0;
183 refuel_t            *refuel_ptr;
184 int                 num_refuel, max_refuel;
185 connector_t         *connector_ptr;
186 int                 num_connector, max_connector;
187 laser_t             *laser_ptr;
188 int                 num_laser, max_laser;
189 missile_t           *missile_ptr;
190 int                 num_missile, max_missile;
191 ball_t              *ball_ptr;
192 int                 num_ball, max_ball;
193 ship_t              *ship_ptr;
194 int                 num_ship, max_ship;
195 mine_t              *mine_ptr;
196 int                 num_mine, max_mine;
197 itemtype_t          *itemtype_ptr;
198 int                 num_itemtype, max_itemtype;
199 ecm_t               *ecm_ptr;
200 int                 num_ecm, max_ecm;
201 trans_t             *trans_ptr;
202 int                 num_trans, max_trans;
203 paused_t            *paused_ptr;
204 int                 num_paused, max_paused;
205 appearing_t         *appearing_ptr;
206 int                 num_appearing, max_appearing;
207 radar_t             *radar_ptr;
208 int                 num_radar, max_radar;
209 vcannon_t           *vcannon_ptr;
210 int                 num_vcannon, max_vcannon;
211 vfuel_t             *vfuel_ptr;
212 int                 num_vfuel, max_vfuel;
213 vbase_t             *vbase_ptr;
214 int                 num_vbase, max_vbase;
215 debris_t            *debris_ptr[DEBRIS_TYPES];
216 int                 num_debris[DEBRIS_TYPES],
217                     max_debris[DEBRIS_TYPES];
218 debris_t            *fastshot_ptr[DEBRIS_TYPES * 2];
219 int                 num_fastshot[DEBRIS_TYPES * 2],
220                     max_fastshot[DEBRIS_TYPES * 2];
221 vdecor_t            *vdecor_ptr;
222 int                 num_vdecor, max_vdecor;
223 wreckage_t          *wreckage_ptr;
224 int                 num_wreckage, max_wreckage;
225 asteroid_t          *asteroid_ptr;
226 int                 num_asteroids, max_asteroids;
227 wormhole_t          *wormhole_ptr;
228 int                 num_wormholes, max_wormholes;
229 
230 int                 num_playing_teams = 0;
231 long		    time_left = -1;
232 long		    start_loops, end_loops;
233 
Fuelstation_by_pos(int x,int y)234 static fuelstation_t *Fuelstation_by_pos(int x, int y)
235 {
236     int			i, lo, hi, pos;
237 
238     lo = 0;
239     hi = num_fuels - 1;
240     pos = x * Setup->y + y;
241     while (lo < hi) {
242 	i = (lo + hi) >> 1;
243 	if (pos > fuels[i].pos)
244 	    lo = i + 1;
245 	else
246 	    hi = i;
247     }
248     if (lo == hi && pos == fuels[lo].pos)
249 	return &fuels[lo];
250     warn("No fuelstation at (%d,%d)", x, y);
251     return NULL;
252 }
253 
Fuel_by_pos(int x,int y)254 double Fuel_by_pos(int x, int y)
255 {
256     fuelstation_t	*fuelp;
257 
258     if ((fuelp = Fuelstation_by_pos(x, y)) == NULL)
259 	return 0;
260     return fuelp->fuel;
261 }
262 
Target_by_index(int ind,int * xp,int * yp,int * dead_time,double * damage)263 int Target_by_index(int ind, int *xp, int *yp, int *dead_time, double *damage)
264 {
265     if (ind < 0 || ind >= num_targets)
266 	return -1;
267     *xp = targets[ind].pos / Setup->y;
268     *yp = targets[ind].pos % Setup->y;
269     *dead_time = targets[ind].dead_time;
270     *damage = targets[ind].damage;
271     return 0;
272 }
273 
Target_alive(int x,int y,double * damage)274 int Target_alive(int x, int y, double *damage)
275 {
276     int 		i, lo, hi, pos;
277 
278     lo = 0;
279     hi = num_targets - 1;
280     pos = x * Setup->y + y;
281     while (lo < hi) {
282 	i = (lo + hi) >> 1;
283 	if (pos > targets[i].pos)
284 	    lo = i + 1;
285 	else
286 	    hi = i;
287     }
288     if (lo == hi && pos == targets[lo].pos) {
289 	*damage = targets[lo].damage;
290 	return targets[lo].dead_time;
291     }
292     warn("No targets at (%d,%d)", x, y);
293     return -1;
294 }
295 
Handle_fuel(int ind,double fuel)296 int Handle_fuel(int ind, double fuel)
297 {
298     if (ind < 0 || ind >= num_fuels) {
299 	warn("Bad fuelstation index (%d)", ind);
300 	return -1;
301     }
302     fuels[ind].fuel = fuel;
303     return 0;
304 }
305 
Cannon_by_pos(int x,int y)306 static cannontime_t *Cannon_by_pos(int x, int y)
307 {
308     int			i, lo, hi, pos;
309 
310     lo = 0;
311     hi = num_cannons - 1;
312     pos = x * Setup->y + y;
313     while (lo < hi) {
314 	i = (lo + hi) >> 1;
315 	if (pos > cannons[i].pos)
316 	    lo = i + 1;
317 	else
318 	    hi = i;
319     }
320     if (lo == hi && pos == cannons[lo].pos)
321 	return &cannons[lo];
322     warn("No cannon at (%d,%d)", x, y);
323     return NULL;
324 }
325 
Cannon_dead_time_by_pos(int x,int y,int * dot)326 int Cannon_dead_time_by_pos(int x, int y, int *dot)
327 {
328     cannontime_t	*cannonp;
329 
330     if ((cannonp = Cannon_by_pos(x, y)) == NULL)
331 	return -1;
332     *dot = cannonp->dot;
333     return cannonp->dead_time;
334 }
335 
Handle_cannon(int ind,int dead_time)336 int Handle_cannon(int ind, int dead_time)
337 {
338     if (ind < 0 || ind >= num_cannons) {
339 	warn("Bad cannon index (%d)", ind);
340 	return 0;
341     }
342     cannons[ind].dead_time = dead_time;
343     return 0;
344 }
345 
Handle_target(int num,int dead_time,double damage)346 int Handle_target(int num, int dead_time, double damage)
347 {
348     if (num < 0 || num >= num_targets) {
349 	warn("Bad target index (%d)", num);
350 	return 0;
351     }
352     if (dead_time == 0
353 	&& (damage <= 0.0 || damage > TARGET_DAMAGE))
354 	warn("BUG target %d, dead %d, damage %f", num, dead_time, damage);
355 
356     if (targets[num].dead_time > 0 && dead_time == 0) {
357 	int pos = targets[num].pos;
358 	Radar_show_target(pos / Setup->y, pos % Setup->y);
359     }
360     else if (targets[num].dead_time == 0 && dead_time > 0) {
361 	int pos = targets[num].pos;
362 	Radar_hide_target(pos / Setup->y, pos % Setup->y);
363     }
364 
365     targets[num].dead_time = dead_time;
366     targets[num].damage = damage;
367 
368     return 0;
369 }
370 
Homebase_by_pos(int x,int y)371 static homebase_t *Homebase_by_pos(int x, int y)
372 {
373     int			i, lo, hi, pos;
374 
375     lo = 0;
376     hi = num_bases - 1;
377     pos = x * Setup->y + y;
378     while (lo < hi) {
379 	i = (lo + hi) >> 1;
380 	if (pos > bases[i].pos)
381 	    lo = i + 1;
382 	else
383 	    hi = i;
384     }
385     if (lo == hi && pos == bases[lo].pos)
386 	return &bases[lo];
387     warn("No homebase at (%d,%d)", x, y);
388     return NULL;
389 }
390 
Base_info_by_pos(int x,int y,int * idp,int * teamp)391 int Base_info_by_pos(int x, int y, int *idp, int *teamp)
392 {
393     homebase_t	*basep;
394 
395     if ((basep = Homebase_by_pos(x, y)) == NULL)
396 	return -1;
397     *idp = basep->id;
398     *teamp = basep->team;
399     return 0;
400 }
401 
Handle_base(int id,int ind)402 int Handle_base(int id, int ind)
403 {
404     int		i;
405 
406     if (ind < 0 || ind >= num_bases) {
407 	warn("Bad homebase index (%d)", ind);
408 	return -1;
409     }
410     for (i = 0; i < num_bases; i++) {
411 	if (bases[i].id == id)
412 	    bases[i].id = -1;
413     }
414     bases[ind].id = id;
415 
416     return 0;
417 }
418 
Check_pos_by_index(int ind,int * xp,int * yp)419 int Check_pos_by_index(int ind, int *xp, int *yp)
420 {
421     if (ind < 0 || ind >= num_checks) {
422 	warn("Bad checkpoint index (%d)", ind);
423 	*xp = 0;
424 	*yp = 0;
425 	return -1;
426     }
427     *xp = checks[ind].pos / Setup->y;
428     *yp = checks[ind].pos % Setup->y;
429     return 0;
430 }
431 
Check_index_by_pos(int x,int y)432 int Check_index_by_pos(int x, int y)
433 {
434     int			i, pos;
435 
436     pos = x * Setup->y + y;
437     for (i = 0; i < num_checks; i++) {
438 	if (pos == checks[i].pos)
439 	    return i;
440     }
441     warn("Can't find checkpoint (%d,%d)", x, y);
442     return 0;
443 }
444 
445 /*
446  * Convert a 'space' map block into a dot.
447  */
Map_make_dot(unsigned char * data)448 static void Map_make_dot(unsigned char *data)
449 {
450     if (*data == SETUP_SPACE)
451 	*data = SETUP_SPACE_DOT;
452     else if (*data == SETUP_DECOR_FILLED)
453 	*data = SETUP_DECOR_DOT_FILLED;
454     else if (*data == SETUP_DECOR_RU)
455 	*data = SETUP_DECOR_DOT_RU;
456     else if (*data == SETUP_DECOR_RD)
457 	*data = SETUP_DECOR_DOT_RD;
458     else if (*data == SETUP_DECOR_LU)
459 	*data = SETUP_DECOR_DOT_LU;
460     else if (*data == SETUP_DECOR_LD)
461 	*data = SETUP_DECOR_DOT_LD;
462 }
463 
464 /*
465  * Optimize the drawing of all blue space dots by converting
466  * certain map objects into a specialised form of their type.
467  */
Map_dots(void)468 void Map_dots(void)
469 {
470     int			i,
471 			x,
472 			y,
473 			start;
474     unsigned char	dot[256];
475 
476     /*
477      * Lookup table to recognize dots.
478      */
479     memset(dot, 0, sizeof dot);
480     dot[SETUP_SPACE_DOT] = 1;
481     dot[SETUP_DECOR_DOT_FILLED] = 1;
482     dot[SETUP_DECOR_DOT_RU] = 1;
483     dot[SETUP_DECOR_DOT_RD] = 1;
484     dot[SETUP_DECOR_DOT_LU] = 1;
485     dot[SETUP_DECOR_DOT_LD] = 1;
486 
487     /*
488      * Restore the map to unoptimized form.
489      */
490     for (i = Setup->x * Setup->y; i-- > 0; ) {
491 	if (dot[Setup->map_data[i]]) {
492 	    if (Setup->map_data[i] == SETUP_SPACE_DOT)
493 		Setup->map_data[i] = SETUP_SPACE;
494 	    else if (Setup->map_data[i] == SETUP_DECOR_DOT_FILLED)
495 		Setup->map_data[i] = SETUP_DECOR_FILLED;
496 	    else if (Setup->map_data[i] == SETUP_DECOR_DOT_RU)
497 		Setup->map_data[i] = SETUP_DECOR_RU;
498 	    else if (Setup->map_data[i] == SETUP_DECOR_DOT_RD)
499 		Setup->map_data[i] = SETUP_DECOR_RD;
500 	    else if (Setup->map_data[i] == SETUP_DECOR_DOT_LU)
501 		Setup->map_data[i] = SETUP_DECOR_LU;
502 	    else if (Setup->map_data[i] == SETUP_DECOR_DOT_LD)
503 		Setup->map_data[i] = SETUP_DECOR_LD;
504 	}
505     }
506 
507     /*
508      * Lookup table to test for map data which can be turned into a dot.
509      */
510     memset(dot, 0, sizeof dot);
511     dot[SETUP_SPACE] = 1;
512     if (!instruments.showDecor) {
513 	dot[SETUP_DECOR_FILLED] = 1;
514 	dot[SETUP_DECOR_RU] = 1;
515 	dot[SETUP_DECOR_RD] = 1;
516 	dot[SETUP_DECOR_LU] = 1;
517 	dot[SETUP_DECOR_LD] = 1;
518     }
519 
520     /*
521      * Optimize.
522      */
523     if (backgroundPointSize > 0) {
524 	if (BIT(Setup->mode, WRAP_PLAY)) {
525 	    for (x = 0; x < Setup->x; x++) {
526 		if (dot[Setup->map_data[x * Setup->y]])
527 		    Map_make_dot(&Setup->map_data[x * Setup->y]);
528 	    }
529 	    for (y = 0; y < Setup->y; y++) {
530 		if (dot[Setup->map_data[y]])
531 		    Map_make_dot(&Setup->map_data[y]);
532 	    }
533 	    start = backgroundPointDist;
534 	} else
535 	    start = 0;
536 
537 	if (backgroundPointDist > 0) {
538 	    for (x = start; x < Setup->x; x += backgroundPointDist) {
539 		for (y = start; y < Setup->y; y += backgroundPointDist) {
540 		    if (dot[Setup->map_data[x * Setup->y + y]])
541 			Map_make_dot(&Setup->map_data[x * Setup->y + y]);
542 		}
543 	    }
544 	}
545 	for (i = 0; i < num_cannons; i++) {
546 	    x = cannons[i].pos / Setup->y;
547 	    y = cannons[i].pos % Setup->y;
548 	    if ((x == 0 || y == 0) && BIT(Setup->mode, WRAP_PLAY))
549 		cannons[i].dot = 1;
550 	    else if (backgroundPointDist > 0
551 		&& x % backgroundPointDist == 0
552 		&& y % backgroundPointDist == 0)
553 		cannons[i].dot = 1;
554 	    else
555 		cannons[i].dot = 0;
556 	}
557     }
558 }
559 
560 /*
561  * Optimize the drawing of all blue map objects by converting
562  * their map type to a bitmask with bits for each blue segment.
563  */
Map_restore(int startx,int starty,int width,int height)564 void Map_restore(int startx, int starty, int width, int height)
565 {
566     int			i, j,
567 			x, y,
568 			map_index,
569 			type;
570 
571     /*
572      * Restore an optimized map to its original unoptimized state.
573      */
574     x = startx;
575     for (i = 0; i < width; i++, x++) {
576 	if (x < 0)
577 	    x += Setup->x;
578 	else if (x >= Setup->x)
579 	    x -= Setup->x;
580 
581 	y = starty;
582 	for (j = 0; j < height; j++, y++) {
583 	    if (y < 0)
584 		y += Setup->y;
585 	    else if (y >= Setup->y)
586 		y -= Setup->y;
587 
588 	    map_index = x * Setup->y + y;
589 
590 	    type = Setup->map_data[map_index];
591 	    if ((type & BLUE_BIT) == 0) {
592 		if (type == SETUP_FILLED_NO_DRAW)
593 		    Setup->map_data[map_index] = SETUP_FILLED;
594 	    }
595 	    else if ((type & BLUE_FUEL) == BLUE_FUEL)
596 		Setup->map_data[map_index] = SETUP_FUEL;
597 
598 	    else if (type & BLUE_OPEN) {
599 		if (type & BLUE_BELOW)
600 		    Setup->map_data[map_index] = SETUP_REC_RD;
601 		else
602 		    Setup->map_data[map_index] = SETUP_REC_LU;
603 	    }
604 	    else if (type & BLUE_CLOSED) {
605 		if (type & BLUE_BELOW)
606 		    Setup->map_data[map_index] = SETUP_REC_LD;
607 		else
608 		    Setup->map_data[map_index] = SETUP_REC_RU;
609 	    } else
610 		Setup->map_data[map_index] = SETUP_FILLED;
611 	}
612     }
613 }
614 
Map_blue(int startx,int starty,int width,int height)615 void Map_blue(int startx, int starty, int width, int height)
616 {
617     int			i, j,
618 			x, y,
619 			map_index,
620 			type,
621 			newtype;
622     unsigned char	blue[256];
623     bool		outline = false;
624 
625     if (instruments.outlineWorld ||
626 	instruments.filledWorld ||
627 	instruments.texturedWalls)
628 	outline = true;
629     /*
630      * Optimize the map for blue.
631      */
632     memset(blue, 0, sizeof blue);
633     blue[SETUP_FILLED] = BLUE_LEFT | BLUE_UP | BLUE_RIGHT | BLUE_DOWN;
634     blue[SETUP_FILLED_NO_DRAW] = blue[SETUP_FILLED];
635     blue[SETUP_FUEL] = blue[SETUP_FILLED];
636     blue[SETUP_REC_RU] = BLUE_RIGHT | BLUE_UP;
637     blue[SETUP_REC_RD] = BLUE_RIGHT | BLUE_DOWN;
638     blue[SETUP_REC_LU] = BLUE_LEFT | BLUE_UP;
639     blue[SETUP_REC_LD] = BLUE_LEFT | BLUE_DOWN;
640     blue[BLUE_BIT|BLUE_OPEN] =
641     blue[BLUE_BIT|BLUE_OPEN|BLUE_LEFT] =
642     blue[BLUE_BIT|BLUE_OPEN|BLUE_UP] =
643     blue[BLUE_BIT|BLUE_OPEN|BLUE_LEFT|BLUE_UP] =
644 	blue[SETUP_REC_LU];
645     blue[BLUE_BIT|BLUE_OPEN|BLUE_BELOW] =
646     blue[BLUE_BIT|BLUE_OPEN|BLUE_BELOW|BLUE_RIGHT] =
647     blue[BLUE_BIT|BLUE_OPEN|BLUE_BELOW|BLUE_DOWN] =
648     blue[BLUE_BIT|BLUE_OPEN|BLUE_BELOW|BLUE_RIGHT|BLUE_DOWN] =
649 	blue[SETUP_REC_RD];
650     blue[BLUE_BIT|BLUE_CLOSED] =
651     blue[BLUE_BIT|BLUE_CLOSED|BLUE_RIGHT] =
652     blue[BLUE_BIT|BLUE_CLOSED|BLUE_UP] =
653     blue[BLUE_BIT|BLUE_CLOSED|BLUE_RIGHT|BLUE_UP] =
654 	blue[SETUP_REC_RU];
655     blue[BLUE_BIT|BLUE_CLOSED|BLUE_BELOW] =
656     blue[BLUE_BIT|BLUE_CLOSED|BLUE_BELOW|BLUE_LEFT] =
657     blue[BLUE_BIT|BLUE_CLOSED|BLUE_BELOW|BLUE_DOWN] =
658     blue[BLUE_BIT|BLUE_CLOSED|BLUE_BELOW|BLUE_LEFT|BLUE_DOWN] =
659 	blue[SETUP_REC_LD];
660     for (i = BLUE_BIT; i < (int)(sizeof blue); i++) {
661 	if ((i & BLUE_FUEL) == BLUE_FUEL
662 	    || (i & (BLUE_OPEN|BLUE_CLOSED)) == 0)
663 	    blue[i] = blue[SETUP_FILLED];
664     }
665 
666     x = startx;
667     for (i = 0; i < width; i++, x++) {
668 	if (x < 0)
669 	    x += Setup->x;
670 	else if (x >= Setup->x)
671 	    x -= Setup->x;
672 
673 	y = starty;
674 	for (j = 0; j < height; j++, y++) {
675 	    if (y < 0)
676 		y += Setup->y;
677 	    else if (y >= Setup->y)
678 		y -= Setup->y;
679 
680 	    map_index = x * Setup->y + y;
681 
682 	    type = Setup->map_data[map_index];
683 	    newtype = 0;
684 	    switch (type) {
685 	    case SETUP_FILLED:
686 	    case SETUP_FILLED_NO_DRAW:
687 	    case SETUP_FUEL:
688 		newtype = BLUE_BIT;
689 		if (type == SETUP_FUEL) {
690 		    newtype |= BLUE_FUEL;
691 		}
692 		if ((x == 0)
693 		    ? (!BIT(Setup->mode, WRAP_PLAY) ||
694 			!(blue[Setup->map_data[(Setup->x - 1) * Setup->y + y]]
695 			    & BLUE_RIGHT))
696 		    : !(blue[Setup->map_data[(x - 1) * Setup->y + y]]
697 			& BLUE_RIGHT))
698 		    newtype |= BLUE_LEFT;
699 		if ((y == 0)
700 		    ? (!BIT(Setup->mode, WRAP_PLAY) ||
701 			!(blue[Setup->map_data[x * Setup->y + Setup->y - 1]]
702 			    & BLUE_UP))
703 		    : !(blue[Setup->map_data[x * Setup->y + (y - 1)]]
704 			& BLUE_UP))
705 		    newtype |= BLUE_DOWN;
706 		if (!outline
707 		    || ((x == Setup->x - 1)
708 			? (!BIT(Setup->mode, WRAP_PLAY)
709 			   || !(blue[Setup->map_data[y]]
710 				& BLUE_LEFT))
711 			: !(blue[Setup->map_data[(x + 1) * Setup->y + y]]
712 			    & BLUE_LEFT)))
713 		    newtype |= BLUE_RIGHT;
714 		if (!outline
715 		    || ((y == Setup->y - 1)
716 			? (!BIT(Setup->mode, WRAP_PLAY)
717 			   || !(blue[Setup->map_data[x * Setup->y]]
718 				& BLUE_DOWN))
719 			: !(blue[Setup->map_data[x * Setup->y + (y + 1)]]
720 			    & BLUE_DOWN)))
721 		    newtype |= BLUE_UP;
722 		break;
723 
724 	    case SETUP_REC_LU:
725 		newtype = BLUE_BIT | BLUE_OPEN;
726 		if (x == 0
727 		    ? (!BIT(Setup->mode, WRAP_PLAY) ||
728 			!(blue[Setup->map_data[(Setup->x - 1) * Setup->y + y]]
729 			    & BLUE_RIGHT))
730 		    : !(blue[Setup->map_data[(x - 1) * Setup->y + y]]
731 			& BLUE_RIGHT))
732 		    newtype |= BLUE_LEFT;
733 		if (!outline
734 		    || ((y == Setup->y - 1)
735 			? (!BIT(Setup->mode, WRAP_PLAY)
736 			   || !(blue[Setup->map_data[x * Setup->y]]
737 				& BLUE_DOWN))
738 			: !(blue[Setup->map_data[x * Setup->y + (y + 1)]]
739 			    & BLUE_DOWN)))
740 		    newtype |= BLUE_UP;
741 		break;
742 
743 	    case SETUP_REC_RU:
744 		newtype = BLUE_BIT | BLUE_CLOSED;
745 		if (!outline
746 		    || ((x == Setup->x - 1)
747 			? (!BIT(Setup->mode, WRAP_PLAY)
748 			   || !(blue[Setup->map_data[y]]
749 				& BLUE_LEFT))
750 			: !(blue[Setup->map_data[(x + 1) * Setup->y + y]]
751 			    & BLUE_LEFT)))
752 		    newtype |= BLUE_RIGHT;
753 		if (!outline
754 		    || ((y == Setup->y - 1)
755 			? (!BIT(Setup->mode, WRAP_PLAY)
756 			   || !(blue[Setup->map_data[x * Setup->y]]
757 				& BLUE_DOWN))
758 			: !(blue[Setup->map_data[x * Setup->y + (y + 1)]]
759 			    & BLUE_DOWN)))
760 		    newtype |= BLUE_UP;
761 		break;
762 
763 	    case SETUP_REC_LD:
764 		newtype = BLUE_BIT | BLUE_BELOW | BLUE_CLOSED;
765 		if ((x == 0)
766 		    ? (!BIT(Setup->mode, WRAP_PLAY) ||
767 			!(blue[Setup->map_data[(Setup->x - 1) * Setup->y + y]]
768 			    & BLUE_RIGHT))
769 		    : !(blue[Setup->map_data[(x - 1) * Setup->y + y]]
770 			& BLUE_RIGHT))
771 		    newtype |= BLUE_LEFT;
772 		if ((y == 0)
773 		    ? (!BIT(Setup->mode, WRAP_PLAY) ||
774 			!(blue[Setup->map_data[x * Setup->y + Setup->y - 1]]
775 			    & BLUE_UP))
776 		    : !(blue[Setup->map_data[x * Setup->y + (y - 1)]]
777 			& BLUE_UP))
778 		    newtype |= BLUE_DOWN;
779 		break;
780 
781 	    case SETUP_REC_RD:
782 		newtype = BLUE_BIT | BLUE_BELOW | BLUE_OPEN;
783 		if (!outline
784 		    || ((x == Setup->x - 1)
785 			? (!BIT(Setup->mode, WRAP_PLAY)
786 			   || !(blue[Setup->map_data[y]]
787 				& BLUE_LEFT))
788 			: !(blue[Setup->map_data[(x + 1) * Setup->y + y]]
789 			    & BLUE_LEFT)))
790 		    newtype |= BLUE_RIGHT;
791 		if ((y == 0)
792 		    ? (!BIT(Setup->mode, WRAP_PLAY) ||
793 			!(blue[Setup->map_data[x * Setup->y + Setup->y - 1]]
794 			    & BLUE_UP))
795 		    : !(blue[Setup->map_data[x * Setup->y + (y - 1)]]
796 			& BLUE_UP))
797 		    newtype |= BLUE_DOWN;
798 		break;
799 
800 	    default:
801 		continue;
802 	    }
803 	    if (newtype != 0) {
804 		if (newtype == BLUE_BIT)
805 		    newtype = SETUP_FILLED_NO_DRAW;
806 		Setup->map_data[map_index] = newtype;
807 	    }
808 	}
809     }
810 }
811 
812 /* Get signed short and advance ptr */
get_short(char ** ptr)813 static int get_short(char **ptr)
814 {
815     *ptr += 2;
816     return ((signed char) *(*ptr - 2) << 8) + (unsigned char) (*(*ptr - 1));
817 }
818 
819 /* Unsigned version */
get_ushort(char ** ptr)820 static unsigned int get_ushort(char **ptr)
821 {
822     *ptr += 2;
823     return ((unsigned char) *(*ptr - 2) << 8) + (unsigned char) *(*ptr - 1);
824 }
825 
get_32bit(char ** ptr)826 static int get_32bit(char **ptr)
827 {
828     int res;
829 
830     res = get_ushort(ptr) << 16;
831     return res + get_ushort(ptr);
832 }
833 
parse_styles(char ** callptr)834 static void parse_styles(char **callptr)
835 {
836     int i, num_bmaps;
837     char *ptr;
838 
839     ptr = *callptr;
840     num_polygon_styles = *ptr++ & 0xff;
841     num_edge_styles = *ptr++ & 0xff;
842     num_bmaps = *ptr++ & 0xff;
843 
844     polygon_styles = XMALLOC(polygon_style_t, MAX(1, num_polygon_styles));
845     if (polygon_styles == NULL) {
846 	error("no memory for polygon styles");
847 	exit(1);
848     }
849 
850     edge_styles = XMALLOC(edge_style_t, MAX(1, num_edge_styles));
851     if (edge_styles == NULL) {
852 	error("no memory for edge styles");
853 	exit(1);
854     }
855 
856     for (i = 0; i < num_polygon_styles; i++) {
857 	polygon_styles[i].rgb = get_32bit(&ptr);
858 	polygon_styles[i].texture = *ptr++ & 0xff;
859 	polygon_styles[i].def_edge_style = *ptr++ & 0xff;
860 	polygon_styles[i].flags = *ptr++ & 0xff;
861     }
862 
863     if (num_polygon_styles == 0) {
864 	/* default polygon style */
865 	polygon_styles[0].flags = 0;
866 	polygon_styles[0].def_edge_style = 0;
867 	num_polygon_styles = 1;
868     }
869 
870     for (i = 0; i < num_edge_styles; i++) {
871 	edge_styles[i].width = *ptr++; /* -1 means hidden */
872 	edge_styles[i].rgb = get_32bit(&ptr);
873 	/* kps - what the **** is this ? */
874 	/* baron - it's line style from XSetLineAttributes */
875 	/* 0 = LineSolid, 1 = LineOnOffDash, 2 = LineDoubleDash */
876 	edge_styles[i].style =
877 	    (*ptr == 1) ? 1 :
878 	    (*ptr == 2) ? 2 : 0;
879 	ptr++;
880     }
881 
882     for (i = 0; i < num_bmaps; i++) {
883 	char fname[30];
884 	int flags;
885 
886 	strlcpy(fname, ptr, 30);
887 	ptr += strlen(fname) + 1;
888 	flags = *ptr++ & 0xff;
889 	Bitmap_add(fname, 1, flags);
890     }
891     *callptr = ptr;
892 }
893 
init_polymap(void)894 static int init_polymap(void)
895 {
896     int i, j, startx, starty, ecount, edgechange, current_estyle;
897     int dx, dy, cx, cy, pc;
898     int *styles;
899     xp_polygon_t *poly;
900     ipos_t *points, min, max;
901     char *ptr, *edgeptr;
902 
903     oldServer = 0;
904     ptr = (char *)Setup->map_data;
905 
906     parse_styles(&ptr);
907 
908     num_polygons = get_ushort(&ptr);
909     polygons = XMALLOC(xp_polygon_t, num_polygons);
910     if (polygons == NULL) {
911 	error("no memory for polygons");
912 	exit(1);
913     }
914 
915     for (i = 0; i < num_polygons; i++) {
916 	poly = &polygons[i];
917 	poly->style = *ptr++ & 0xff;
918 	current_estyle = polygon_styles[poly->style].def_edge_style;
919 	dx = 0;
920 	dy = 0;
921 	ecount = get_ushort(&ptr);
922 	edgeptr = ptr;
923 	if (ecount)
924 	    edgechange = get_ushort(&edgeptr);
925 	else
926 	    edgechange = INT_MAX;
927 	ptr += ecount * 2;
928 	pc = get_ushort(&ptr);
929 	if ((points = XMALLOC(ipos_t, pc)) == NULL) {
930 	    error("no memory for points");
931 	    exit(1);
932 	}
933 	if (ecount) {
934 	    if ((styles = XMALLOC(int, pc)) == NULL) {
935 		error("no memory for special edges");
936 		exit(1);
937 	    }
938 	} else
939 	    styles = NULL;
940 	startx = get_ushort(&ptr);
941 	starty = get_ushort(&ptr);
942 	points[0].x = cx = min.x = max.x = startx;
943 	points[0].y = cy = min.y = max.y = starty;
944 
945 	if (!edgechange) {
946 	    current_estyle = get_ushort(&edgeptr);
947 	    ecount--;
948 	    if (ecount)
949 		edgechange = get_ushort(&edgeptr);
950 	}
951 	if (styles)
952 	    styles[0] = current_estyle;
953 
954 	for (j = 1; j < pc; j++) {
955 	    dx = get_short(&ptr);
956 	    dy = get_short(&ptr);
957 	    cx += dx;
958 	    cy += dy;
959 	    if (min.x > cx)
960 		min.x = cx;
961 	    if (min.y > cy)
962 		min.y = cy;
963 	    if (max.x < cx)
964 		max.x = cx;
965 	    if (max.y < cy)
966 		max.y = cy;
967 	    points[j].x = dx;
968 	    points[j].y = dy;
969 
970 	    if (edgechange == j) {
971 		current_estyle = get_ushort(&edgeptr);
972 		ecount--;
973 		if (ecount)
974 		    edgechange = get_ushort(&edgeptr);
975 	    }
976 	    if (styles)
977 		styles[j] = current_estyle;
978 	}
979 	poly->points = points;
980 	poly->edge_styles = styles;
981 	poly->num_points = pc;
982 	poly->bounds.x = min.x;
983 	poly->bounds.y = min.y;
984 	poly->bounds.w = max.x - min.x;
985 	poly->bounds.h = max.y - min.y;
986     }
987     num_bases = *ptr++ & 0xff;
988     bases = XMALLOC(homebase_t, num_bases);
989     if (bases == NULL) {
990 	error("No memory for Map bases (%d)", num_bases);
991 	exit(1);
992     }
993     for (i = 0; i < num_bases; i++) {
994 	/* base.pos is not used */
995 	bases[i].id = -1;
996 	bases[i].team = *ptr++ & 0xff;
997 	cx = get_ushort(&ptr);
998 	cy = get_ushort(&ptr);
999 	bases[i].bounds.x = cx - BLOCK_SZ / 2;
1000 	bases[i].bounds.y = cy - BLOCK_SZ / 2;
1001 	bases[i].bounds.w = BLOCK_SZ;
1002 	bases[i].bounds.h = BLOCK_SZ;
1003 	if (*ptr < 16)
1004 	    bases[i].type = SETUP_BASE_RIGHT;
1005 	else if (*ptr < 48)
1006 	    bases[i].type = SETUP_BASE_UP;
1007 	else if (*ptr < 80)
1008 	    bases[i].type = SETUP_BASE_LEFT;
1009 	else if (*ptr < 112)
1010 	    bases[i].type = SETUP_BASE_DOWN;
1011 	else
1012 	    bases[i].type = SETUP_BASE_RIGHT;
1013 	bases[i].appeartime = 0;
1014 	ptr++;
1015     }
1016     num_fuels = get_ushort(&ptr);
1017     if (num_fuels != 0) {
1018 	fuels = XMALLOC(fuelstation_t, num_fuels);
1019 	if (fuels == NULL) {
1020 	    error("No memory for Map fuels (%d)", num_fuels);
1021 	    exit(1);
1022 	}
1023     }
1024     for (i = 0; i < num_fuels; i++) {
1025 	cx = get_ushort(&ptr);
1026 	cy = get_ushort(&ptr);
1027 	fuels[i].fuel = MAX_STATION_FUEL;
1028 	fuels[i].bounds.x = cx - BLOCK_SZ / 2;
1029 	fuels[i].bounds.y = cy - BLOCK_SZ / 2;
1030 	fuels[i].bounds.w = BLOCK_SZ;
1031 	fuels[i].bounds.h = BLOCK_SZ;
1032     }
1033     num_checks = *ptr++ & 0xff;
1034     if (num_checks != 0) {
1035 
1036 	checks = XMALLOC(checkpoint_t, num_checks);
1037 	if (checks == NULL) {
1038 	    error("No memory for checkpoints (%d)", num_checks);
1039 	    exit(1);
1040 	}
1041     }
1042     for (i = 0; i < num_checks; i++) {
1043 	cx = get_ushort(&ptr);
1044 	cy = get_ushort(&ptr);
1045 	checks[i].bounds.x = cx - BLOCK_SZ / 2;
1046 	checks[i].bounds.y = cy - BLOCK_SZ / 2;
1047 	checks[i].bounds.w = BLOCK_SZ;
1048 	checks[i].bounds.h = BLOCK_SZ;
1049     }
1050 
1051     /*
1052      * kps - hack.
1053      * Player can disable downloading of textures by having texturedWalls off.
1054      */
1055     if (instruments.texturedWalls && Setup->data_url[0])
1056 	Mapdata_setup(Setup->data_url);
1057     Colors_init_style_colors();
1058 
1059     return 0;
1060 }
1061 
init_blockmap(void)1062 static int init_blockmap(void)
1063 {
1064     int			i,
1065 			max,
1066 			type;
1067     u_byte		types[256];
1068 
1069     num_fuels = 0;
1070     num_bases = 0;
1071     num_cannons = 0;
1072     num_targets = 0;
1073     num_checks = 0;
1074     fuels = NULL;
1075     bases = NULL;
1076     cannons = NULL;
1077     targets = NULL;
1078     checks = NULL;
1079     memset(types, 0, sizeof types);
1080     types[SETUP_FUEL] = 1;
1081     types[SETUP_CANNON_UP] = 2;
1082     types[SETUP_CANNON_RIGHT] = 2;
1083     types[SETUP_CANNON_DOWN] = 2;
1084     types[SETUP_CANNON_LEFT] = 2;
1085     for (i = SETUP_TARGET; i < SETUP_TARGET + 10; i++)
1086 	types[i] = 3;
1087     for (i = SETUP_BASE_LOWEST; i <= SETUP_BASE_HIGHEST; i++)
1088 	types[i] = 4;
1089     for (i = 0; i < OLD_MAX_CHECKS; i++)
1090 	types[SETUP_CHECK + i] = 5;
1091     max = Setup->x * Setup->y;
1092     for (i = 0; i < max; i++) {
1093 	switch (types[Setup->map_data[i]]) {
1094 	case 1: num_fuels++; break;
1095 	case 2: num_cannons++; break;
1096 	case 3: num_targets++; break;
1097 	case 4: num_bases++; break;
1098 	case 5: num_checks++; break;
1099 	default: break;
1100 	}
1101     }
1102     if (num_bases != 0) {
1103 	bases = XMALLOC(homebase_t, num_bases);
1104 	if (bases == NULL) {
1105 	    error("No memory for Map bases (%d)", num_bases);
1106 	    return -1;
1107 	}
1108 	num_bases = 0;
1109     }
1110     if (num_fuels != 0) {
1111 	fuels = XMALLOC(fuelstation_t, num_fuels);
1112 	if (fuels == NULL) {
1113 	    error("No memory for Map fuels (%d)", num_fuels);
1114 	    return -1;
1115 	}
1116 	num_fuels = 0;
1117     }
1118     if (num_targets != 0) {
1119 	targets = XMALLOC(target_t, num_targets);
1120 	if (targets == NULL) {
1121 	    error("No memory for Map targets (%d)", num_targets);
1122 	    return -1;
1123 	}
1124 	num_targets = 0;
1125     }
1126     if (num_cannons != 0) {
1127 	cannons = XMALLOC(cannontime_t, num_cannons);
1128 	if (cannons == NULL) {
1129 	    error("No memory for Map cannons (%d)", num_cannons);
1130 	    return -1;
1131 	}
1132 	num_cannons = 0;
1133     }
1134     if (num_checks != 0) {
1135 	checks = XMALLOC(checkpoint_t, num_checks);
1136 	if (checks == NULL) {
1137 	    error("No memory for Map checks (%d)", num_checks);
1138 	    return -1;
1139 	}
1140 	num_checks = 0;
1141     }
1142 
1143     for (i = 0; i < max; i++) {
1144 	type = Setup->map_data[i];
1145 	switch (types[type]) {
1146 	case 1:
1147 	    fuels[num_fuels].pos = i;
1148 	    fuels[num_fuels].fuel = MAX_STATION_FUEL;
1149 	    num_fuels++;
1150 	    break;
1151 	case 2:
1152 	    cannons[num_cannons].pos = i;
1153 	    cannons[num_cannons].dead_time = 0;
1154 	    cannons[num_cannons].dot = 0;
1155 	    num_cannons++;
1156 	    break;
1157 	case 3:
1158 	    targets[num_targets].pos = i;
1159 	    targets[num_targets].dead_time = 0;
1160 	    targets[num_targets].damage = TARGET_DAMAGE;
1161 	    num_targets++;
1162 	    break;
1163 	case 4:
1164 	    bases[num_bases].pos = i;
1165 	    bases[num_bases].id = -1;
1166 	    bases[num_bases].team = type % 10;
1167 	    bases[num_bases].type = type - (type % 10);
1168 	    bases[num_bases].appeartime = 0;
1169 	    num_bases++;
1170 	    Setup->map_data[i] = type - (type % 10);
1171 	    break;
1172 	case 5:
1173 	    checks[type - SETUP_CHECK].pos = i;
1174 	    num_checks++;
1175 	    Setup->map_data[i] = SETUP_CHECK;
1176 	    break;
1177 	default:
1178 	    break;
1179 	}
1180     }
1181     return 0;
1182 }
1183 
Map_init(void)1184 static int Map_init(void)
1185 {
1186     return oldServer ? init_blockmap() : init_polymap();
1187 }
1188 
Map_cleanup(void)1189 static int Map_cleanup(void)
1190 {
1191     if (num_bases > 0) {
1192 	XFREE(bases);
1193 	num_bases = 0;
1194     }
1195     if (num_fuels > 0) {
1196 	XFREE(fuels);
1197 	num_fuels = 0;
1198     }
1199     if (num_targets > 0) {
1200 	XFREE(targets);
1201 	num_targets = 0;
1202     }
1203     if (num_cannons > 0) {
1204 	XFREE(cannons);
1205 	num_cannons = 0;
1206     }
1207     return 0;
1208 }
1209 
1210 
Homebase_by_id(int id)1211 homebase_t *Homebase_by_id(int id)
1212 {
1213     int i;
1214 
1215     if (id != -1) {
1216 	for (i = 0; i < num_bases; i++) {
1217 	    if (bases[i].id == id)
1218 		return &bases[i];
1219 	}
1220     }
1221     return NULL;
1222 }
1223 
Other_by_id(int id)1224 other_t *Other_by_id(int id)
1225 {
1226     int i;
1227 
1228     if (id != -1) {
1229 	for (i = 0; i < num_others; i++) {
1230 	    if (Others[i].id == id)
1231 		return &Others[i];
1232 	}
1233     }
1234     return NULL;
1235 }
1236 
Other_by_name(const char * name,bool show_error_msg)1237 other_t *Other_by_name(const char *name, bool show_error_msg)
1238 {
1239     int i;
1240     other_t *found_other = NULL, *other;
1241     size_t len;
1242 
1243     if (name == NULL || (len = strlen(name)) == 0)
1244 	goto match_none;
1245 
1246     /* Look for an exact match on player nickname. */
1247     for (i = 0; i < num_others; i++) {
1248 	other = &Others[i];
1249 	if (!strcasecmp(other->nick_name, name))
1250 	    return other;
1251     }
1252 
1253     /* Look if 'name' matches beginning of only one nick. */
1254     for (i = 0; i < num_others; i++) {
1255 	other = &Others[i];
1256 
1257 	if (!strncasecmp(other->nick_name, name, len)) {
1258 	    if (found_other)
1259 		goto match_several;
1260 	    found_other = other;
1261 	    continue;
1262 	}
1263     }
1264     if (found_other)
1265 	return found_other;
1266 
1267     /*
1268      * Check what players' name 'name' is a substring of (case insensitively).
1269      */
1270     for (i = 0; i < num_others; i++) {
1271 	int j;
1272 	other = &Others[i];
1273 
1274 	for (j = 0; j < 1 + (int)strlen(other->nick_name) - (int)len; j++) {
1275 	    if (!strncasecmp(other->nick_name + j, name, len)) {
1276 		if (found_other)
1277 		    goto match_several;
1278 		found_other = other;
1279 		break;
1280 	    }
1281 	}
1282     }
1283     if (found_other)
1284 	return found_other;
1285 
1286  match_none:
1287     {
1288 	if (show_error_msg)
1289 	    Add_message("Name does not match any player. [*Client reply*]");
1290 	return NULL;
1291     }
1292  match_several:
1293     {
1294 	if (show_error_msg)
1295 	    Add_message("Name matches several players. [*Client reply*]");
1296 	return NULL;
1297     }
1298 }
1299 
Ship_by_id(int id)1300 shipshape_t *Ship_by_id(int id)
1301 {
1302     other_t		*other;
1303 
1304     if ((other = Other_by_id(id)) == NULL)
1305 	return Parse_shape_str(NULL);
1306     return other->ship;
1307 }
1308 
Handle_leave(int id)1309 int Handle_leave(int id)
1310 {
1311     other_t		*other;
1312     char		msg[MSG_LEN];
1313 
1314     if ((other = Other_by_id(id)) != NULL) {
1315 	if (other == self) {
1316 	    warn("Self left?!");
1317 	    self = NULL;
1318 	}
1319 	Free_ship_shape(other->ship);
1320 	other->ship = NULL;
1321 	/*
1322 	 * Silent about tanks and robots.
1323 	 */
1324 	if (other->mychar != 'T' && other->mychar != 'R') {
1325 	    sprintf(msg, "%s left this world.", other->nick_name);
1326 	    Add_message(msg);
1327 	}
1328 	num_others--;
1329 	while (other < &Others[num_others]) {
1330 	    *other = other[1];
1331 	    other++;
1332 	}
1333 	scoresChanged = true;
1334     }
1335     return 0;
1336 }
1337 
Handle_player(int id,int player_team,int mychar,char * nick_name,char * user_name,char * host_name,char * shape,int myself)1338 int Handle_player(int id, int player_team, int mychar,
1339 		  char *nick_name, char *user_name, char *host_name,
1340 		  char *shape, int myself)
1341 {
1342     other_t		*other;
1343 
1344     if (BIT(Setup->mode, TEAM_PLAY)
1345 	&& (player_team < 0 || player_team >= MAX_TEAMS)) {
1346 	warn("Illegal team %d for received player, setting to 0", player_team);
1347 	player_team = 0;
1348     }
1349     if ((other = Other_by_id(id)) == NULL) {
1350 	if (num_others >= max_others) {
1351 	    max_others += 5;
1352 	    if (num_others == 0)
1353 		Others = XMALLOC(other_t, max_others);
1354 	    else
1355 		Others = XREALLOC(other_t, Others, max_others);
1356 	    if (Others == NULL)
1357 		fatal("Not enough memory for player info");
1358 	    if (self != NULL)
1359 		/* We've made 'self' the first member of Others[]. */
1360 		self = &Others[0];
1361 	}
1362 	other = &Others[num_others++];
1363     }
1364     if (self == NULL
1365 	&& (myself
1366 	    || (version < 0x4F10
1367 		&& strcmp(connectParam.nick_name, nick_name) == 0))) {
1368 	if (other != &Others[0]) {
1369 	    /* Make 'self' the first member of Others[]. */
1370 	    *other = Others[0];
1371 	    other = &Others[0];
1372 	}
1373 	self = other;
1374     }
1375     memset(other, 0, sizeof(other_t));
1376     other->id = id;
1377     other->team = player_team;
1378     other->mychar = mychar;
1379     strlcpy(other->nick_name, nick_name, sizeof(other->nick_name));
1380     strlcpy(other->user_name, user_name, sizeof(other->user_name));
1381     strlcpy(other->host_name, host_name, sizeof(other->host_name));
1382     strlcpy(other->id_string, nick_name, sizeof(other->id_string));
1383     other->max_chars_in_names = -1;
1384     scoresChanged = true;
1385     other->ship = Convert_shape_str(shape);
1386     Calculate_shield_radius(other->ship);
1387 
1388     return 0;
1389 }
1390 
Handle_team(int id,int pl_team)1391 int Handle_team(int id, int pl_team)
1392 {
1393     other_t *other;
1394 
1395     other = Other_by_id(id);
1396     if (other == NULL) {
1397 	warn("Received packet to change team for nonexistent id %d", id);
1398 	return 0;
1399     }
1400     if (BIT(Setup->mode, TEAM_PLAY) && (pl_team < 0 || pl_team >= MAX_TEAMS)) {
1401 	warn("Illegal team %d received for player id %d", pl_team, id);
1402 	return 0;
1403     }
1404     other->team = pl_team;
1405     scoresChanged = true;
1406 
1407     return 0;
1408 }
1409 
Handle_score(int id,double score,int life,int mychar,int alliance)1410 int Handle_score(int id, double score, int life, int mychar, int alliance)
1411 {
1412     other_t		*other;
1413 
1414     if ((other = Other_by_id(id)) == NULL) {
1415 	warn("Can't update score for non-existing player %d,%.2f,%d",
1416 	      id, score, life);
1417 	return 0;
1418     }
1419     else if (other->score != score
1420 	|| other->life != life
1421 	|| other->mychar != mychar
1422 	|| other->alliance != alliance) {
1423 	other->score = score;
1424 	other->life = life;
1425 	other->mychar = mychar;
1426 	other->alliance = alliance;
1427 	scoresChanged = true;
1428     }
1429 
1430     return 0;
1431 }
1432 
Handle_team_score(int team,double score)1433 int Handle_team_score(int team, double score)
1434 {
1435     if (teamscores[team] != score) {
1436 	teamscores[team] = score;
1437 	scoresChanged = true;
1438     }
1439 
1440     return 0;
1441 }
1442 
Handle_timing(int id,int check,int round,long tloops)1443 int Handle_timing(int id, int check, int round, long tloops)
1444 {
1445     other_t		*other;
1446 
1447     if ((other = Other_by_id(id)) == NULL) {
1448 	warn("Can't update timing for non-existing player %d,%d,%d",
1449 	      id, check, round);
1450 	return 0;
1451     }
1452     else if (other->check != check
1453 	|| other->round != round) {
1454 	other->check = check;
1455 	other->round = round;
1456 	other->timing = round * num_checks + check;
1457 	other->timing_loops = tloops;
1458 	scoresChanged = true;
1459     }
1460 
1461     return 0;
1462 }
1463 
Handle_score_object(double score,int x,int y,char * msg)1464 int Handle_score_object(double score, int x, int y, char *msg)
1465 {
1466     score_object_t*	sobj = &score_objects[score_object];
1467 
1468     sobj->score = score;
1469     sobj->x = x;
1470     sobj->y = y;
1471     sobj->life_time = scoreObjectTime;
1472 
1473     /* Initialize sobj->hud_msg (is shown on the HUD) */
1474     if (msg[0] != '\0') {
1475 	if (Using_score_decimals())
1476 	    sprintf(sobj->hud_msg, "%s %.*f", msg, showScoreDecimals, score);
1477 	else {
1478 	    int sc = (int)(score >= 0.0 ? score + 0.5 : score - 0.5);
1479 	    sprintf(sobj->hud_msg, "%s %d", msg, sc);
1480 	}
1481 	sobj->hud_msg_len = strlen(sobj->hud_msg);
1482 	sobj->hud_msg_width = -1;
1483     } else
1484 	sobj->hud_msg_len = 0;
1485 
1486     /* Initialize sobj->msg data (is shown on game area) */
1487     if (Using_score_decimals())
1488 	sprintf(sobj->msg, "%.*f", showScoreDecimals, score);
1489     else {
1490 	int sc = (int)(score >= 0.0 ? score + 0.5 : score - 0.5);
1491 	sprintf(sobj->msg, "%d", sc);
1492     }
1493     sobj->msg_len = strlen(sobj->msg);
1494     sobj->msg_width = -1;
1495 
1496     /* Update global index variable */
1497     score_object = (score_object + 1) % MAX_SCORE_OBJECTS;
1498 
1499     return 0;
1500 }
1501 
Handle_start(long server_loops)1502 int Handle_start(long server_loops)
1503 {
1504     int			i;
1505 
1506     start_loops = server_loops;
1507 
1508     num_refuel = 0;
1509     num_connector = 0;
1510     num_missile = 0;
1511     num_ball = 0;
1512     num_ship = 0;
1513     num_mine = 0;
1514     num_itemtype = 0;
1515     num_ecm = 0;
1516     num_trans = 0;
1517     num_paused = 0;
1518     num_radar = 0;
1519     num_vcannon = 0;
1520     num_vfuel = 0;
1521     num_vbase = 0;
1522     num_vdecor = 0;
1523     for (i = 0; i < DEBRIS_TYPES; i++)
1524 	num_debris[i] = 0;
1525 
1526     damaged = 0;
1527     destruct = 0;
1528     shutdown_delay = 0;
1529     shutdown_count = -1;
1530     eyesId = (self != NULL) ? self->id : 0;
1531     eyes = Other_by_id(eyesId);
1532     thrusttime = -1;
1533     shieldtime = -1;
1534     phasingtime = -1;
1535     return 0;
1536 }
1537 
update_timing(void)1538 static void update_timing(void)
1539 {
1540     static int frame_counter = 0;
1541     static struct timeval old_tv = {0, 0};
1542     struct timeval now;
1543 
1544     frame_counter++;
1545     gettimeofday(&now, NULL);
1546     if (now.tv_sec != old_tv.tv_sec) {
1547 	double usecs, fps;
1548 
1549 	currentTime = time(NULL);
1550 	usecs = 1e6 + (now.tv_usec - old_tv.tv_usec);
1551 	fps = (1e6 * frame_counter) / usecs;
1552 	old_tv = now;
1553 	newSecond = true;
1554 	clientFPS = MAX(1.0, fps);
1555 	frame_counter = 0;
1556     } else
1557 	newSecond = false;
1558 }
1559 
Handle_end(long server_loops)1560 int Handle_end(long server_loops)
1561 {
1562     end_loops = server_loops;
1563     snooping = (self && eyesId != self->id) ? true : false;
1564     update_timing();
1565     Paint_frame();
1566 #ifdef SOUND
1567     audioUpdate();
1568 #endif
1569     return 0;
1570 }
1571 
Handle_self_items(u_byte * newNumItems)1572 int Handle_self_items(u_byte *newNumItems)
1573 {
1574     memcpy(numItems, newNumItems, NUM_ITEMS * sizeof(u_byte));
1575     return 0;
1576 }
1577 
update_status(int status)1578 static void update_status(int status)
1579 {
1580     static int old_status = 0;
1581 
1582     if (BIT(old_status, OLD_GAME_OVER) && !BIT(status, OLD_GAME_OVER)
1583 	&& !BIT(status, OLD_PAUSE))
1584 	Raise_window();
1585 
1586     /* Player appeared? */
1587     if (BIT(old_status, OLD_PLAYING|OLD_PAUSE|OLD_GAME_OVER) != OLD_PLAYING) {
1588 	if (BIT(status, OLD_PLAYING|OLD_PAUSE|OLD_GAME_OVER) == OLD_PLAYING)
1589 	    Reset_shields();
1590     }
1591 
1592     old_status = status;
1593 }
1594 
Handle_self(int x,int y,int vx,int vy,int newHeading,double newPower,double newTurnspeed,double newTurnresistance,int newLockId,int newLockDist,int newLockBearing,int newNextCheckPoint,int newAutopilotLight,u_byte * newNumItems,int newCurrentTank,double newFuelSum,double newFuelMax,int newPacketSize,int status)1595 int Handle_self(int x, int y, int vx, int vy, int newHeading,
1596 		double newPower, double newTurnspeed, double newTurnresistance,
1597 		int newLockId, int newLockDist, int newLockBearing,
1598 		int newNextCheckPoint, int newAutopilotLight,
1599 		u_byte *newNumItems, int newCurrentTank,
1600 		double newFuelSum, double newFuelMax, int newPacketSize,
1601 		int status)
1602 {
1603     selfPos.x = x;
1604     selfPos.y = y;
1605     selfVel.x = vx;
1606     selfVel.y = vy;
1607     heading = newHeading;
1608     displayedPower = newPower;
1609     displayedTurnspeed = newTurnspeed;
1610     displayedTurnresistance = newTurnresistance;
1611     lock_id = newLockId;
1612     lock_dist = newLockDist;
1613     lock_dir = newLockBearing;
1614     nextCheckPoint = newNextCheckPoint;
1615     autopilotLight = newAutopilotLight;
1616     memcpy(numItems, newNumItems, NUM_ITEMS * sizeof(u_byte));
1617     fuelCurrent = newCurrentTank;
1618     if (newFuelSum > fuelSum && selfVisible)
1619 	fuelTime = FUEL_NOTIFY_TIME;
1620     fuelSum = newFuelSum;
1621     fuelMax = newFuelMax;
1622     selfVisible = 0;
1623     if (newPacketSize + 16 < packet_size)
1624 	packet_size -= 16;
1625     else
1626 	packet_size = newPacketSize;
1627     update_status(status);
1628     return 0;
1629 }
1630 
1631 
Handle_eyes(int id)1632 int Handle_eyes(int id)
1633 {
1634     eyesId = id;
1635     eyes = Other_by_id(eyesId);
1636     return 0;
1637 }
1638 
Handle_damaged(int dam)1639 int Handle_damaged(int dam)
1640 {
1641     damaged = dam;
1642     return 0;
1643 }
1644 
Handle_modifiers(char * m)1645 int Handle_modifiers(char *m)
1646 {
1647     strlcpy(mods, m, MAX_CHARS);
1648     return 0;
1649 }
1650 
Handle_destruct(int count)1651 int Handle_destruct(int count)
1652 {
1653     destruct = count;
1654     return 0;
1655 }
1656 
1657 
Handle_shutdown(int count,int delay)1658 int Handle_shutdown(int count, int delay)
1659 {
1660     shutdown_count = count;
1661     shutdown_delay = delay;
1662     return 0;
1663 }
1664 
Handle_thrusttime(int count,int max)1665 int Handle_thrusttime(int count, int max)
1666 {
1667     thrusttime = count;
1668     thrusttimemax = max;
1669     return 0;
1670 }
1671 
Handle_shieldtime(int count,int max)1672 int Handle_shieldtime(int count, int max)
1673 {
1674     shieldtime = count;
1675     shieldtimemax = max;
1676     return 0;
1677 }
1678 
Handle_phasingtime(int count,int max)1679 int Handle_phasingtime(int count, int max)
1680 {
1681     phasingtime = count;
1682     phasingtimemax = max;
1683     return 0;
1684 }
1685 
Handle_rounddelay(int count,int max)1686 int Handle_rounddelay(int count, int max)
1687 {
1688     roundDelay = count;
1689     roundDelayMax = max;
1690     return 0;
1691 }
1692 
Handle_refuel(int x_0,int y_0,int x_1,int y_1)1693 int Handle_refuel(int x_0, int y_0, int x_1, int y_1)
1694 {
1695     refuel_t	t;
1696 
1697     t.x0 = x_0;
1698     t.x1 = x_1;
1699     t.y0 = y_0;
1700     t.y1 = y_1;
1701     STORE(refuel_t, refuel_ptr, num_refuel, max_refuel, t);
1702     return 0;
1703 }
1704 
Handle_connector(int x_0,int y_0,int x_1,int y_1,int tractor)1705 int Handle_connector(int x_0, int y_0, int x_1, int y_1, int tractor)
1706 {
1707     connector_t	t;
1708 
1709     t.x0 = x_0;
1710     t.x1 = x_1;
1711     t.y0 = y_0;
1712     t.y1 = y_1;
1713     t.tractor = tractor;
1714     STORE(connector_t, connector_ptr, num_connector, max_connector, t);
1715     return 0;
1716 }
1717 
Handle_laser(int color,int x,int y,int len,int dir)1718 int Handle_laser(int color, int x, int y, int len, int dir)
1719 {
1720     laser_t	t;
1721 
1722     t.color = color;
1723     t.x = x;
1724     t.y = y;
1725     t.len = len;
1726     t.dir = dir;
1727     STORE(laser_t, laser_ptr, num_laser, max_laser, t);
1728     return 0;
1729 }
1730 
Handle_missile(int x,int y,int len,int dir)1731 int Handle_missile(int x, int y, int len, int dir)
1732 {
1733     missile_t	t;
1734 
1735     t.x = x;
1736     t.y = y;
1737     t.dir = dir;
1738     t.len = len;
1739     STORE(missile_t, missile_ptr, num_missile, max_missile, t);
1740     return 0;
1741 }
1742 
Handle_ball(int x,int y,int id,int style)1743 int Handle_ball(int x, int y, int id, int style)
1744 {
1745     ball_t	t;
1746 
1747     t.x = x;
1748     t.y = y;
1749     t.id = id;
1750     t.style = style;
1751     STORE(ball_t, ball_ptr, num_ball, max_ball, t);
1752     return 0;
1753 }
1754 
predict_self_dir(int received_dir)1755 static int predict_self_dir(int received_dir)
1756 {
1757     double pointer_delta = 0, dir_delta, new_dir;
1758     int ind = pointer_move_next - 1;
1759     int count = 0, int_new_dir;
1760 
1761     if (ind < 0)
1762 	ind = MAX_POINTER_MOVES - 1;
1763 
1764     while (pointer_moves[ind].id > last_keyboard_ack && count < 50) {
1765         pointer_delta += pointer_moves[ind].movement
1766 	    * pointer_moves[ind].turnspeed;
1767 	ind--;
1768 	if (ind < 0)
1769 	    ind = MAX_POINTER_MOVES - 1;
1770 	count++;
1771     }
1772 
1773     dir_delta = pointer_delta / (RES/2);
1774     new_dir = (received_dir - dir_delta);
1775     while (new_dir < 0)
1776 	new_dir += RES;
1777     while (new_dir >= RES)
1778 	new_dir -= RES;
1779     int_new_dir = (int)(new_dir + 0.5);
1780     while (int_new_dir >= RES)
1781 	/* might be == RES */
1782 	int_new_dir -= RES;
1783 
1784     return int_new_dir;
1785 }
1786 
Handle_ship(int x,int y,int id,int dir,int shield,int cloak,int eshield,int phased,int deflector)1787 int Handle_ship(int x, int y, int id, int dir, int shield, int cloak,
1788 		int eshield, int phased, int deflector)
1789 {
1790     ship_t	t;
1791 
1792     t.x = x;
1793     t.y = y;
1794     t.id = id;
1795     if (dirPrediction && self && self->id == id)
1796         t.dir = predict_self_dir(dir);
1797     else
1798         t.dir = dir;
1799     t.shield = shield;
1800     t.cloak = cloak;
1801     t.eshield = eshield;
1802     t.phased = phased;
1803     t.deflector = deflector;
1804     STORE(ship_t, ship_ptr, num_ship, max_ship, t);
1805 
1806     /* if we see a ship in the center of the display, we may be watching
1807      * it, especially if it's us!  consider any ship there to be our eyes
1808      * until we see a ship that really is us.
1809      * BG: XXX there was a bug here.  self was dereferenced at "self->id"
1810      * while self could be NULL here.
1811      */
1812     if (!selfVisible
1813 	&& ((x == selfPos.x && y == selfPos.y) || (self && id == self->id))) {
1814 
1815         eyesId = id;
1816 	eyes = Other_by_id(eyesId);
1817 	if (eyes != NULL)
1818 	    eyeTeam = eyes->team;
1819 	selfVisible = (self && (id == self->id));
1820 	return Handle_radar(x, y, 3);
1821     }
1822 
1823     return 0;
1824 }
1825 
Handle_mine(int x,int y,int teammine,int id)1826 int Handle_mine(int x, int y, int teammine, int id)
1827 {
1828     mine_t	t;
1829 
1830     t.x = x;
1831     t.y = y;
1832     t.teammine = teammine;
1833     t.id = id;
1834     STORE(mine_t, mine_ptr, num_mine, max_mine, t);
1835     return 0;
1836 }
1837 
Handle_item(int x,int y,int type)1838 int Handle_item(int x, int y, int type)
1839 {
1840     itemtype_t	t;
1841 
1842     t.x = x;
1843     t.y = y;
1844     t.type = type;
1845     STORE(itemtype_t, itemtype_ptr, num_itemtype, max_itemtype, t);
1846     return 0;
1847 }
1848 
1849 #define STORE_DEBRIS(typ_e, _p, _n) \
1850     if (_n > max_) {						\
1851 	if (max_ == 0) {						\
1852 	    ptr_ = (debris_t *)malloc(n * sizeof(*ptr_));		\
1853 	} else {						\
1854 	    ptr_ = (debris_t *)realloc(ptr_, _n * sizeof(*ptr_));	\
1855 	}							\
1856 	if (ptr_ == NULL) {					\
1857 	    error("No memory for debris");			\
1858 	    num_ = max_ = 0;					\
1859 	    return -1;						\
1860 	}							\
1861 	max_ = _n;						\
1862     }								\
1863     else if (_n <= 0) {						\
1864 	printf("debris %d < 0\n", _n);				\
1865 	return 0;						\
1866     }								\
1867     num_ = _n;							\
1868     memcpy(ptr_, _p, _n * sizeof(*ptr_));				\
1869     return 0;
1870 
1871 
Handle_fastshot(int type,u_byte * p,int n)1872 int Handle_fastshot(int type, u_byte *p, int n)
1873 {
1874 #define num_		(num_fastshot[type])
1875 #define max_		(max_fastshot[type])
1876 #define ptr_		(fastshot_ptr[type])
1877     STORE_DEBRIS(type, p, n);
1878 #undef num_
1879 #undef max_
1880 #undef ptr_
1881 }
1882 
Handle_debris(int type,u_byte * p,int n)1883 int Handle_debris(int type, u_byte *p, int n)
1884 {
1885 #define num_		(num_debris[type])
1886 #define max_		(max_debris[type])
1887 #define ptr_		(debris_ptr[type])
1888     STORE_DEBRIS(type, p, n);
1889 #undef num_
1890 #undef max_
1891 #undef ptr_
1892 }
1893 
Handle_wreckage(int x,int y,int wrecktype,int size,int rotation)1894 int Handle_wreckage(int x, int y, int wrecktype, int size, int rotation)
1895 {
1896     wreckage_t	t;
1897 
1898     t.x = x;
1899     t.y = y;
1900     t.wrecktype = wrecktype;
1901     t.size = size;
1902     t.rotation = rotation;
1903     STORE(wreckage_t, wreckage_ptr, num_wreckage, max_wreckage, t);
1904     return 0;
1905 }
1906 
Handle_asteroid(int x,int y,int type,int size,int rotation)1907 int Handle_asteroid(int x, int y, int type, int size, int rotation)
1908 {
1909     asteroid_t	t;
1910 
1911     t.x = x;
1912     t.y = y;
1913     t.type = type;
1914     t.size = size;
1915     t.rotation = rotation;
1916     STORE(asteroid_t, asteroid_ptr, num_asteroids, max_asteroids, t);
1917     return 0;
1918 }
1919 
Handle_wormhole(int x,int y)1920 int Handle_wormhole(int x, int y)
1921 {
1922     wormhole_t	t;
1923 
1924     t.x = x - BLOCK_SZ / 2;
1925     t.y = y - BLOCK_SZ / 2;
1926     STORE(wormhole_t, wormhole_ptr, num_wormholes, max_wormholes, t);
1927     return 0;
1928 }
1929 
Handle_polystyle(int polyind,int newstyle)1930 int Handle_polystyle(int polyind, int newstyle)
1931 {
1932     xp_polygon_t *poly;
1933 
1934     poly = &polygons[polyind];
1935     poly->style = newstyle;
1936     /*warn("polygon %d style set to %d", polyind, newstyle);*/
1937     UpdateRadar=true;
1938     return 0;
1939 }
1940 
Handle_ecm(int x,int y,int size)1941 int Handle_ecm(int x, int y, int size)
1942 {
1943     ecm_t	t;
1944 
1945     t.x = x;
1946     t.y = y;
1947     t.size = size;
1948     STORE(ecm_t, ecm_ptr, num_ecm, max_ecm, t);
1949     return 0;
1950 }
1951 
Handle_trans(int x_1,int y_1,int x_2,int y_2)1952 int Handle_trans(int x_1, int y_1, int x_2, int y_2)
1953 {
1954     trans_t	t;
1955 
1956     t.x1 = x_1;
1957     t.y1 = y_1;
1958     t.x2 = x_2;
1959     t.y2 = y_2;
1960     STORE(trans_t, trans_ptr, num_trans, max_trans, t);
1961     return 0;
1962 }
1963 
Handle_paused(int x,int y,int count)1964 int Handle_paused(int x, int y, int count)
1965 {
1966     paused_t	t;
1967 
1968     t.x = x;
1969     t.y = y;
1970     t.count = count;
1971     STORE(paused_t, paused_ptr, num_paused, max_paused, t);
1972     return 0;
1973 }
1974 
Handle_appearing(int x,int y,int id,int count)1975 int Handle_appearing(int x, int y, int id, int count)
1976 {
1977     appearing_t	t;
1978 
1979     t.x = x;
1980     t.y = y;
1981     t.id = id;
1982     t.count = count;
1983     STORE(appearing_t, appearing_ptr, num_appearing, max_appearing, t);
1984     return 0;
1985 }
1986 
Handle_fastradar(int x,int y,int size)1987 int Handle_fastradar(int x, int y, int size)
1988 {
1989     radar_t t;
1990 
1991     t.x = x;
1992     t.y = y;
1993     t.type = RadarEnemy;
1994 
1995     if ((size & 0x80) != 0) {
1996 	t.type = RadarFriend;
1997 	size &= ~0x80;
1998     }
1999 
2000     t.size = size;
2001     STORE(radar_t, radar_ptr, num_radar, max_radar, t);
2002     return 0;
2003 }
2004 
2005 
Handle_radar(int x,int y,int size)2006 int Handle_radar(int x, int y, int size)
2007 {
2008     return Handle_fastradar
2009 	((int)((double)(x * RadarWidth) / Setup->width + 0.5),
2010 	 (int)((double)(y * RadarHeight) / Setup->height + 0.5),
2011 	 size);
2012 }
2013 
Handle_message(char * msg)2014 int Handle_message(char *msg)
2015 {
2016     int i;
2017     char ignoree[MAX_CHARS];
2018     other_t *other;
2019 
2020     if (msg[strlen(msg) - 1] == ']') {
2021 	for (i = strlen(msg) - 1; i > 0; i--) {
2022 	    if (msg[i - 1] == ' ' && msg[i] == '[')
2023 		break;
2024 	}
2025 
2026 	if (i == 0) {		/* Odd, but let it pass */
2027 	    Add_message(msg);
2028 	    return 0;
2029 	}
2030 
2031 	strcpy(ignoree, &msg[i + 1]);
2032 
2033 	for (i = 0; i < (int) strlen(ignoree); i++) {
2034 	    if (ignoree[i] == ']')
2035 		break;
2036 	}
2037 	ignoree[i] = '\0';
2038 
2039 	other = Other_by_name(ignoree, false);
2040 
2041 	if (other == NULL) {	/* Not in list, probably servermessage */
2042 	    Add_message(msg);
2043 	    return 0;
2044 	}
2045 
2046 	if (other->ignorelevel <= 0) {
2047 	    Add_message(msg);
2048 	    return 0;
2049 	}
2050 
2051 	if (other->ignorelevel >= 2)
2052 	    return 0;
2053 
2054 	/* ignorelevel must be 1 */
2055 
2056 	crippleTalk(msg);
2057 	Add_message(msg);
2058     } else
2059 	Add_message(msg);
2060     return 0;
2061 }
2062 
Handle_time_left(long sec)2063 int Handle_time_left(long sec)
2064 {
2065     if (sec >= 0 && sec < 10 && (time_left > sec || sec == 0))
2066 	Play_beep();
2067     time_left = (sec >= 0) ? sec : 0;
2068     return 0;
2069 }
2070 
Handle_vcannon(int x,int y,int type)2071 int Handle_vcannon(int x, int y, int type)
2072 {
2073     vcannon_t	t;
2074 
2075     t.x = x;
2076     t.y = y;
2077     t.type = type;
2078     STORE(vcannon_t, vcannon_ptr, num_vcannon, max_vcannon, t);
2079     return 0;
2080 }
2081 
Handle_vfuel(int x,int y,double fuel)2082 int Handle_vfuel(int x, int y, double fuel)
2083 {
2084     vfuel_t	t;
2085 
2086     t.x = x;
2087     t.y = y;
2088     t.fuel = fuel;
2089     STORE(vfuel_t, vfuel_ptr, num_vfuel, max_vfuel, t);
2090     return 0;
2091 }
2092 
Handle_vbase(int x,int y,int xi,int yi,int type)2093 int Handle_vbase(int x, int y, int xi, int yi, int type)
2094 {
2095     vbase_t	t;
2096 
2097     t.x = x;
2098     t.y = y;
2099     t.xi = xi;
2100     t.yi = yi;
2101     t.type = type;
2102     STORE(vbase_t, vbase_ptr, num_vbase, max_vbase, t);
2103     return 0;
2104 }
2105 
Handle_vdecor(int x,int y,int xi,int yi,int type)2106 int Handle_vdecor(int x, int y, int xi, int yi, int type)
2107 {
2108     vdecor_t	t;
2109 
2110     t.x = x;
2111     t.y = y;
2112     t.xi = xi;
2113     t.yi = yi;
2114     t.type = type;
2115     STORE(vdecor_t, vdecor_ptr, num_vdecor, max_vdecor, t);
2116     return 0;
2117 }
2118 
Using_score_decimals(void)2119 bool Using_score_decimals(void)
2120 {
2121     if (showScoreDecimals > 0 && version >= 0x4500
2122 	&& (version < 0x4F09 || version >= 0x4F11))
2123 	return true;
2124     return false;
2125 }
2126 
Client_init(char * server,unsigned server_version)2127 int Client_init(char *server, unsigned server_version)
2128 {
2129     version = server_version;
2130     if (server_version < 0x4F09)
2131 	oldServer = 1;
2132     else
2133 	oldServer = 0;
2134 
2135     Make_table();
2136 
2137     if (Paint_init() == -1)
2138 	return -1;
2139 
2140     strlcpy(servername, server, sizeof(servername));
2141 
2142     return 0;
2143 }
2144 
Client_setup(void)2145 int Client_setup(void)
2146 {
2147     if (Map_init() == -1) return -1;
2148 
2149     if (oldServer) {
2150 	Map_dots();
2151 	Map_restore(0, 0, Setup->x, Setup->y);
2152 	Map_blue(0, 0, Setup->x, Setup->y);
2153 	/* kps -remove this, you shouldn't change options this way */
2154 	/* No one wants this on old-style maps anyway, so turn it off.
2155 	 * I do, so turn it on.
2156 	 * This allows people to turn it on in their .xpilotrc for new maps
2157 	 * without affecting old ones. It's still possible to turn in on
2158 	 * from the config menu during play for old maps.
2159 	 * -- But doesn't seem to work anyway if turned on? Well who cares */
2160 	instruments.texturedWalls = false;
2161     }
2162 
2163     RadarHeight = (RadarWidth * Setup->height) / Setup->width;
2164 
2165     if (Init_playing_windows() == -1)
2166 	return -1;
2167 
2168     if (Alloc_msgs() == -1)
2169 	return -1;
2170 
2171     if (Alloc_history() == -1)
2172 	return -1;
2173 
2174     return 0;
2175 }
2176 
Client_fps_request(void)2177 int Client_fps_request(void)
2178 {
2179     LIMIT(maxFPS, 1, MAX_SUPPORTED_FPS);
2180     oldMaxFPS = maxFPS;
2181     return Send_fps_request(maxFPS);
2182 }
2183 
Check_client_fps(void)2184 int Check_client_fps(void)
2185 {
2186     if (oldMaxFPS != maxFPS)
2187 	return Client_fps_request();
2188     return 0;
2189 }
2190 
Client_power(void)2191 int Client_power(void)
2192 {
2193     int i;
2194 
2195     if (Send_power(power) == -1
2196 	|| Send_power_s(power_s) == -1
2197 	|| Send_turnspeed(turnspeed) == -1
2198 	|| Send_turnspeed_s(turnspeed_s) == -1
2199 	|| Send_turnresistance(turnresistance) == -1
2200 	|| Send_turnresistance_s(turnresistance_s) == -1)
2201 	return -1;
2202 
2203     if (Check_view_dimensions() == -1)
2204 	return -1;
2205 
2206     for (i = 0; i < NUM_MODBANKS; i++) {
2207 	if (Send_modifier_bank(i) == -1)
2208 	    return -1;
2209     }
2210 
2211     return 0;
2212 }
2213 
Client_start(void)2214 int Client_start(void)
2215 {
2216     Key_init();
2217 
2218     return 0;
2219 }
2220 
Client_cleanup(void)2221 void Client_cleanup(void)
2222 {
2223     int i;
2224 
2225     Pointer_control_set_state(false);
2226     Platform_specific_cleanup();
2227     Free_selectionAndHistory();
2228     Free_msgs();
2229     if (max_others > 0) {
2230 	for (i = 0; i < num_others; i++) {
2231 	    other_t* other = &Others[i];
2232 	    Free_ship_shape(other->ship);
2233 	}
2234 	free(Others);
2235 	num_others = 0;
2236 	max_others = 0;
2237     }
2238     if (max_refuel > 0 && refuel_ptr) {
2239 	max_refuel = 0;
2240 	XFREE(refuel_ptr);
2241     }
2242     if (max_connector > 0 && connector_ptr) {
2243 	max_connector = 0;
2244 	XFREE(connector_ptr);
2245     }
2246     if (max_laser > 0 && laser_ptr) {
2247 	max_laser = 0;
2248 	XFREE(laser_ptr);
2249     }
2250     if (max_missile > 0 && missile_ptr) {
2251 	max_missile = 0;
2252 	XFREE(missile_ptr);
2253     }
2254     if (max_ball > 0 && ball_ptr) {
2255 	max_ball = 0;
2256 	XFREE(ball_ptr);
2257     }
2258     if (max_ship > 0 && ship_ptr) {
2259 	max_ship = 0;
2260 	XFREE(ship_ptr);
2261     }
2262     if (max_mine > 0 && mine_ptr) {
2263 	max_mine = 0;
2264 	XFREE(mine_ptr);
2265     }
2266     if (max_ecm > 0 && ecm_ptr) {
2267 	max_ecm = 0;
2268 	XFREE(ecm_ptr);
2269     }
2270     if (max_trans > 0 && trans_ptr) {
2271 	max_trans = 0;
2272 	XFREE(trans_ptr);
2273     }
2274     if (max_paused > 0 && paused_ptr) {
2275 	max_paused = 0;
2276 	XFREE(paused_ptr);
2277     }
2278     if (max_appearing > 0 && appearing_ptr) {
2279 	max_appearing = 0;
2280 	XFREE(appearing_ptr);
2281     }
2282     if (max_radar > 0 && radar_ptr) {
2283 	max_radar = 0;
2284 	XFREE(radar_ptr);
2285     }
2286     if (max_vcannon > 0 && vcannon_ptr) {
2287 	max_vcannon = 0;
2288 	XFREE(vcannon_ptr);
2289     }
2290     if (max_vfuel > 0 && vfuel_ptr) {
2291 	max_vfuel = 0;
2292 	XFREE(vfuel_ptr);
2293     }
2294     if (max_vbase > 0 && vbase_ptr) {
2295 	max_vbase = 0;
2296 	XFREE(vbase_ptr);
2297     }
2298     if (max_vdecor > 0 && vdecor_ptr) {
2299 	max_vdecor = 0;
2300 	XFREE(vdecor_ptr);
2301     }
2302     if (max_itemtype > 0 && itemtype_ptr) {
2303 	max_itemtype = 0;
2304 	XFREE(itemtype_ptr);
2305     }
2306     if (max_wreckage > 0 && wreckage_ptr) {
2307 	max_wreckage = 0;
2308 	XFREE(wreckage_ptr);
2309     }
2310     if (max_asteroids > 0 && asteroid_ptr) {
2311 	max_asteroids = 0;
2312 	XFREE(asteroid_ptr);
2313     }
2314     if (max_wormholes > 0 && wormhole_ptr) {
2315 	max_wormholes = 0;
2316 	XFREE(wormhole_ptr);
2317     }
2318     Map_cleanup();
2319     Paint_cleanup();
2320 }
2321 
Client_pointer_move(int movement)2322 int Client_pointer_move(int movement)
2323 {
2324     if (maxMouseTurnsPS == 0)
2325 	return Send_pointer_move(movement);
2326 
2327     /*
2328      * maxMouseTurnsPS is not 0: player wants to limit amount
2329      * of pointer move packets sent to server.
2330      */
2331     cumulativeMouseMovement += movement;
2332 
2333     return 0;
2334 }
2335 
2336 /*
2337  * Check if there is any pointer move we need to send to server.
2338  * Returns how many microseconds to wait in select().
2339  */
Client_check_pointer_move_interval(void)2340 int Client_check_pointer_move_interval(void)
2341 {
2342     struct timeval now;
2343     static int last_send_interval_num = -1;
2344     int interval_num; /* 0 ... maxMouseTurnsPS - 1 */
2345     int next_interval_start;
2346 
2347     assert(maxMouseTurnsPS > 0);
2348 
2349     /*
2350      * Let's see if we've sent any pointer move this interval,
2351      * if not and there is something to send, do that now.
2352      */
2353     gettimeofday(&now, NULL);
2354     interval_num = ((int)now.tv_usec) / mouseMovementInterval;
2355     if (interval_num != last_send_interval_num
2356 	&& cumulativeMouseMovement != 0) {
2357 	Send_pointer_move(cumulativeMouseMovement);
2358 	cumulativeMouseMovement = 0;
2359 	last_send_interval_num = interval_num;
2360     }
2361 
2362     if (cumulativeMouseMovement != 0) {
2363 	/* calculate how long to wait to next interval */
2364 	next_interval_start = (interval_num + 1) * mouseMovementInterval;
2365 	return next_interval_start - (int)now.tv_usec;
2366     }
2367 
2368     return 1000000;
2369 }
2370 
2371 /*
2372  * Exit the entire client.
2373  */
Client_exit(int status)2374 void Client_exit(int status)
2375 {
2376     Net_cleanup();
2377     Client_cleanup();
2378     exit(status);
2379 }
2380