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