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 * Copyright (C) 2003-2004 Kristian S�derblom <kps@users.sourceforge.net>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28 #include "xpclient_x11.h"
29
30 static bool texturedShips = false; /* Turned this off because the images drawn
31 * don't match the actual shipshape used
32 * for wall collisions by the server. */
33 static int ballColor; /* Color index for ball drawing */
34 static int connColor; /* Color index for connector drawing */
35 static int teamShotColor; /* Color index for harmless shot drawing */
36 static int zeroLivesColor; /* Color to associate with 0 lives */
37 static int oneLifeColor; /* Color to associate with 1 life */
38 static int twoLivesColor; /* Color to associate with 2 lives */
39 static int manyLivesColor; /* Color to associate with >2 lives */
40 static int selfLWColor; /* Color index for selfLifeWarning */
41 static int enemyLWColor; /* Color index for enemyLifeWarning */
42 static int teamLWColor; /* Color index for teamLifeWarning */
43 static int shipNameColor; /* Color index for ship name drawing */
44 static int mineNameColor; /* Color index for mine name drawing */
45 static int teamShipColor; /* Color index to associate with team 0 */
46 static int team0Color; /* Color index to associate with team 0 */
47 static int team1Color; /* Color index to associate with team 1 */
48 static int team2Color; /* Color index to associate with team 2 */
49 static int team3Color; /* Color index to associate with team 3 */
50 static int team4Color; /* Color index to associate with team 4 */
51 static int team5Color; /* Color index to associate with team 5 */
52 static int team6Color; /* Color index to associate with team 6 */
53 static int team7Color; /* Color index to associate with team 7 */
54 static int team8Color; /* Color index to associate with team 8 */
55 static int team9Color; /* Color index to associate with team 9 */
56
57
58 static int asteroidRawShapes[NUM_ASTEROID_SHAPES][NUM_ASTEROID_POINTS][2] = {
59 { ASTEROID_SHAPE_0 },
60 { ASTEROID_SHAPE_1 },
61 };
62
63
64 position_t *asteroidShapes[NUM_ASTEROID_SHAPES][NUM_ASTEROID_POINTS];
65
66
Init_asteroids(void)67 int Init_asteroids(void)
68 {
69 int shp, i;
70 size_t point_size;
71 size_t total_size;
72 char *dynmem;
73
74 /*
75 * Allocate memory for all the asteroid points.
76 */
77 point_size = sizeof(position_t) * RES;
78 total_size = point_size * NUM_ASTEROID_POINTS * NUM_ASTEROID_SHAPES;
79 if ((dynmem = (char *) malloc(total_size)) == NULL) {
80 error("Not enough memory for asteroid shapes");
81 return -1;
82 }
83
84 /*
85 * For each asteroid-shape rotate all points.
86 */
87 for ( shp = 0; shp < NUM_ASTEROID_SHAPES; shp++ ) {
88 for ( i = 0; i < NUM_ASTEROID_POINTS; i++ ) {
89 asteroidShapes[shp][i] = (position_t *) dynmem;
90 dynmem += point_size;
91 asteroidShapes[shp][i][0].x = asteroidRawShapes[shp][i][0];
92 asteroidShapes[shp][i][0].y = asteroidRawShapes[shp][i][1];
93 Rotate_position( &asteroidShapes[shp][i][0] );
94 }
95 }
96
97 return 0;
98 }
99
100
Gui_paint_item_symbol(int type,Drawable d,GC mygc,int x,int y,int c)101 void Gui_paint_item_symbol(int type, Drawable d, GC mygc, int x, int y, int c)
102 {
103 if (!texturedObjects) {
104 gcv.stipple = itemBitmaps[type];
105 gcv.fill_style = FillStippled;
106 gcv.ts_x_origin = x;
107 gcv.ts_y_origin = y;
108 XChangeGC(dpy, mygc,
109 GCStipple|GCFillStyle|GCTileStipXOrigin|GCTileStipYOrigin,
110 &gcv);
111 rd.paintItemSymbol(type, d, mygc, x, y, c);
112 XFillRectangle(dpy, d, mygc, x, y, ITEM_SIZE, ITEM_SIZE);
113 gcv.fill_style = FillSolid;
114 XChangeGC(dpy, mygc, GCFillStyle, &gcv);
115 } else
116 Bitmap_paint(d, BM_ALL_ITEMS, x, y, type);
117 }
118
Gui_paint_item(int type,Drawable d,GC mygc,int x,int y)119 void Gui_paint_item(int type, Drawable d, GC mygc, int x, int y)
120 {
121 const int SIZE = ITEM_TRIANGLE_SIZE;
122 XPoint points[5];
123
124 #ifndef NO_ITEM_TRIANGLES
125 points[0].x = x - SIZE;
126 points[0].y = y - SIZE;
127 points[1].x = x;
128 points[1].y = y + SIZE;
129 points[2].x = x + SIZE;
130 points[2].y = y - SIZE;
131 points[3] = points[0];
132 SET_FG(colors[BLUE].pixel);
133 rd.drawLines(dpy, d, mygc, points, 4, CoordModeOrigin);
134 #endif
135
136 SET_FG(colors[RED].pixel);
137 #if 0
138 str[0] = itemtype_ptr[i].type + '0';
139 str[1] = '\0';
140 rd.drawString(dpy, d, mygc,
141 x - XTextWidth(gameFont, str, 1)/2,
142 y + SIZE - 1,
143 str, 1);
144 #endif
145 Gui_paint_item_symbol(type, d, mygc,
146 x - ITEM_SIZE/2,
147 y - SIZE + 2, ITEM_PLAYFIELD);
148 }
149
Gui_paint_item_object(int type,int x,int y)150 void Gui_paint_item_object(int type, int x, int y)
151 {
152 Gui_paint_item(type, drawPixmap, gameGC, WINSCALE(X(x)), WINSCALE(Y(y)));
153 }
154
Gui_paint_ball(int x,int y,int style)155 void Gui_paint_ball(int x, int y, int style)
156 {
157 unsigned long rgb = 0;
158
159 x = X(x);
160 y = Y(y);
161
162 /*
163 * kps - currently style 0xff means no style.
164 * This code assumes num_polygon_styles < 256.
165 */
166 if (style >= 0 && style < num_polygon_styles)
167 rgb = polygon_styles[style].rgb;
168
169 if (!texturedObjects) {
170 /* hack */
171 if (rgb == 0)
172 Arc_add(ballColor, x - BALL_RADIUS, y - BALL_RADIUS,
173 2 * BALL_RADIUS, 2 * BALL_RADIUS, 0, 64 * 360);
174 else
175 Arc_add_rgb(rgb, ballColor, x - BALL_RADIUS, y - BALL_RADIUS,
176 2 * BALL_RADIUS, 2 * BALL_RADIUS, 0, 64 * 360);
177 } else {
178 if (style == 0xff) {
179 Bitmap_paint(drawPixmap, BM_BALL, WINSCALE(x - BALL_RADIUS),
180 WINSCALE(y - BALL_RADIUS), 0);
181 } else {
182 Bitmap_paint_blended(drawPixmap, BM_BALL_GRAY,
183 WINSCALE(x - BALL_RADIUS),
184 WINSCALE(y - BALL_RADIUS), rgb);
185 }
186 }
187 }
188
189
Gui_paint_ball_connector(int x_1,int y_1,int x_2,int y_2)190 void Gui_paint_ball_connector(int x_1, int y_1, int x_2, int y_2)
191 {
192 x_2 = X(x_2);
193 y_2 = Y(y_2);
194 x_1 = X(x_1);
195 y_1 = Y(y_1);
196 Segment_add(connColor, x_1, y_1, x_2, y_2);
197 }
198
Gui_paint_mine_name(int x,int y,char * name)199 static void Gui_paint_mine_name(int x, int y, char *name)
200 {
201 int name_len, name_width;
202
203 if (!name || !mineNameColor)
204 return;
205
206 SET_FG(colors[mineNameColor].pixel);
207
208 name_len = strlen(name);
209 name_width = XTextWidth(gameFont, name, name_len);
210
211 rd.drawString(dpy, drawPixmap, gameGC,
212 WINSCALE(x) - name_width / 2,
213 WINSCALE(y + 4) + gameFont->ascent + 1,
214 name, name_len);
215 }
216
Gui_paint_mine(int x,int y,int teammine,char * name)217 void Gui_paint_mine(int x, int y, int teammine, char *name)
218 {
219 if (!texturedObjects) {
220 static double lastScaleFactor;
221 static XPoint mine_points[21];
222 static XPoint world_mine_points[21] = {
223 { 0, 0 },
224 { 1, 0 },
225 { 0, -1 },
226 { 4, 0 },
227 { 0, -1 },
228 { 6, 0 },
229 { 0, 1 },
230 { 4, 0 },
231 { 0, 1 },
232 { 1, 0 },
233 { 0, 2 },
234 { -1, 0 },
235 { 0, 1 },
236 { -4, 0 },
237 { 0, 1 },
238 { -6, 0 },
239 { 0, -1 },
240 { -4, 0 },
241 { 0, -1 },
242 { -1, 0 },
243 { 0, -2 }
244 };
245
246 if (lastScaleFactor != clData.scaleFactor) {
247 int i;
248 lastScaleFactor = clData.scaleFactor;
249 for (i = 1; i < 21; ++i) {
250 mine_points[i].x = WINSCALE(world_mine_points[i].x);
251 mine_points[i].y = WINSCALE(world_mine_points[i].y);
252 }
253 }
254
255 x = X(x);
256 y = Y(y);
257 mine_points[0].x = WINSCALE(x - 8);
258 mine_points[0].y = WINSCALE(y - 1);
259 if (teammine == 0) {
260 SET_FG(colors[BLUE].pixel);
261 rd.fillRectangle(dpy, drawPixmap, gameGC,
262 WINSCALE(x - 7), WINSCALE(y - 2),
263 UWINSCALE(15), UWINSCALE(5));
264 }
265
266 SET_FG(colors[WHITE].pixel);
267 rd.drawLines(dpy, drawPixmap, gameGC,
268 mine_points, 21, CoordModePrevious);
269
270 if (name)
271 Gui_paint_mine_name(x, y, name);
272 }
273 else {
274 x = X(x);
275 y = Y(y);
276 if (teammine == 0) {
277 SET_FG(colors[BLUE].pixel);
278 Bitmap_paint(drawPixmap, BM_MINE_OTHER, WINSCALE(x - 10),
279 WINSCALE(y - 7), 0);
280 }
281 else {
282 SET_FG(colors[WHITE].pixel);
283 Bitmap_paint(drawPixmap, BM_MINE_TEAM, WINSCALE(x - 10),
284 WINSCALE(y - 7), 0);
285 }
286
287 if (name)
288 Gui_paint_mine_name(x, y, name);
289 }
290 }
291
292
Gui_paint_spark(int color,int x,int y)293 void Gui_paint_spark(int color, int x, int y)
294 {
295 color = spark_color[color];
296
297 Rectangle_add(color,
298 x - sparkSize/2,
299 y - sparkSize/2,
300 sparkSize, sparkSize);
301
302 }
303
304
Gui_paint_wreck(int x,int y,bool deadly,int wtype,int rot,int size)305 void Gui_paint_wreck(int x, int y, bool deadly, int wtype, int rot, int size)
306 {
307 int color, cnt, tx, ty;
308 static XPoint points[NUM_WRECKAGE_POINTS+2];
309
310 for (cnt = 0; cnt < NUM_WRECKAGE_POINTS; cnt++) {
311 tx = (int)(wreckageShapes[wtype][cnt][rot].x * size) >> 8;
312 ty = (int)(wreckageShapes[wtype][cnt][rot].y * size) >> 8;
313
314 points[cnt].x = WINSCALE(X(x + tx));
315 points[cnt].y = WINSCALE(Y(y + ty));
316
317 }
318 points[cnt++] = points[0];
319
320 color = (deadly) ? WHITE: RED;
321 SET_FG(colors[color].pixel);
322 rd.drawLines(dpy, drawPixmap, gameGC, points, cnt, 0);
323 }
324
Gui_paint_asteroids_begin(void)325 void Gui_paint_asteroids_begin(void)
326 {
327 }
328
Gui_paint_asteroids_end(void)329 void Gui_paint_asteroids_end(void)
330 {
331 }
332
Gui_paint_asteroid(int x,int y,int type,int rot,int size)333 void Gui_paint_asteroid(int x, int y, int type, int rot, int size)
334 {
335 int cnt, tx, ty;
336 static XPoint points[NUM_ASTEROID_POINTS+2];
337
338 type = type % NUM_ASTEROID_SHAPES;
339 for (cnt = 0; cnt < NUM_ASTEROID_POINTS; cnt++) {
340 tx = (int)(asteroidShapes[type][cnt][rot].x * size * 1.4);
341 ty = (int)(asteroidShapes[type][cnt][rot].y * size * 1.4);
342
343 points[cnt].x = WINSCALE(X(x + tx));
344 points[cnt].y = WINSCALE(Y(y + ty));
345 }
346 points[cnt++] = points[0];
347
348 SET_FG(colors[WHITE].pixel);
349 rd.drawLines(dpy, drawPixmap, gameGC, points, cnt, 0);
350 }
351
352
Gui_paint_nastyshot(int color,int x,int y,int size)353 static void Gui_paint_nastyshot(int color, int x, int y, int size)
354 {
355 int z = size;
356
357 if (rfrac() < 0.5) {
358 Segment_add(color,
359 x - z, y - z,
360 x + z, y + z);
361 Segment_add(color,
362 x + z, y - z,
363 x - z, y + z);
364 } else {
365 Segment_add(color,
366 x - z, y,
367 x + z, y);
368 Segment_add(color,
369 x, y - z,
370 x, y + z);
371 }
372 }
373
374
Gui_paint_fastshot(int color,int x,int y)375 void Gui_paint_fastshot(int color, int x, int y)
376 {
377 /* this is for those pesky invisible shots */
378 if (color == 0)
379 return;
380
381 if (!texturedObjects) {
382 int z = shotSize/2;
383
384 if (instruments.showNastyShots)
385 Gui_paint_nastyshot(color, x, y, z);
386 else {
387 /* Show round shots - jiman392 */
388 if (shotSize > 2) {
389 SET_FG(colors[color].pixel);
390 rd.fillArc(dpy, drawPixmap, gameGC,
391 WINSCALE(x - z), WINSCALE(y - z),
392 UWINSCALE(shotSize), UWINSCALE(shotSize),
393 0, 64*360);
394 } else
395 Rectangle_add(color,
396 x - z,
397 y - z,
398 shotSize, shotSize);
399 }
400 }
401 else {
402 int s_size = MIN(shotSize, 16);
403 int z = s_size / 2;
404
405 Bitmap_paint(drawPixmap, BM_BULLET, WINSCALE(x) - z,
406 WINSCALE(y) - z, s_size - 1);
407 }
408 }
409
Gui_paint_teamshot(int x,int y)410 void Gui_paint_teamshot(int x, int y)
411 {
412 int color = teamShotColor;
413
414 if (color == 0)
415 return;
416
417 if (!texturedObjects) {
418 int z = teamShotSize/2;
419
420 if (instruments.showNastyShots)
421 Gui_paint_nastyshot(color, x, y, z);
422 else {
423 /* Show round shots - jiman392 */
424 if (teamShotSize > 2) {
425 SET_FG(colors[color].pixel);
426 rd.fillArc(dpy, drawPixmap, gameGC,
427 WINSCALE(x - z), WINSCALE(y - z),
428 UWINSCALE(teamShotSize), UWINSCALE(teamShotSize),
429 0, 64*360);
430 } else
431 Rectangle_add(color,
432 x - z,
433 y - z,
434 teamShotSize, teamShotSize);
435 }
436 }
437 else {
438 int s_size = MIN(teamShotSize, 16);
439 int z = s_size / 2;
440 Bitmap_paint(drawPixmap, BM_BULLET_OWN, WINSCALE(x) - z,
441 WINSCALE(y) - z, s_size - 1);
442 }
443 }
444
445
Gui_paint_missiles_begin(void)446 void Gui_paint_missiles_begin(void)
447 {
448 SET_FG(colors[WHITE].pixel);
449 XSetLineAttributes(dpy, gameGC, 4,
450 LineSolid, CapButt, JoinMiter);
451 }
452
453
Gui_paint_missiles_end(void)454 void Gui_paint_missiles_end(void)
455 {
456 XSetLineAttributes(dpy, gameGC, 0,
457 LineSolid, CapButt, JoinMiter);
458 }
459
460
Gui_paint_missile(int x,int y,int len,int dir)461 void Gui_paint_missile(int x, int y, int len, int dir)
462 {
463 int x_1, x_2, y_1, y_2;
464
465 x_1 = X(x);
466 y_1 = Y(y);
467 x_2 = (int)(x_1 - tcos(dir) * len);
468 y_2 = (int)(y_1 + tsin(dir) * len);
469 rd.drawLine(dpy, drawPixmap, gameGC,
470 WINSCALE(x_1), WINSCALE(y_1), WINSCALE(x_2), WINSCALE(y_2));
471 }
472
473
Gui_paint_lasers_begin(void)474 void Gui_paint_lasers_begin(void)
475 {
476 XSetLineAttributes(dpy, gameGC, 3,
477 LineSolid, CapButt, JoinMiter);
478 }
479
480
Gui_paint_lasers_end(void)481 void Gui_paint_lasers_end(void)
482 {
483 XSetLineAttributes(dpy, gameGC, 0,
484 LineSolid, CapButt, JoinMiter);
485 }
486
487
Gui_paint_laser(int color,int x_1,int y_1,int len,int dir)488 void Gui_paint_laser(int color, int x_1, int y_1, int len, int dir)
489 {
490 int x_2, y_2;
491
492 x_2 = (int)(x_1 + len * tcos(dir));
493 y_2 = (int)(y_1 + len * tsin(dir));
494 if ((unsigned)(color) >= NUM_COLORS)
495 color = WHITE;
496 SET_FG(colors[color].pixel);
497 rd.drawLine(dpy, drawPixmap, gameGC,
498 WINSCALE(X(x_1)), WINSCALE(Y(y_1)),
499 WINSCALE(X(x_2)), WINSCALE(Y(y_2)));
500 }
501
502
Gui_paint_paused(int x,int y,int count)503 void Gui_paint_paused(int x, int y, int count)
504 {
505 if (!texturedObjects) {
506 int x_0, y_0;
507 static int pauseCharWidth = -1;
508 const unsigned half_pause_size = 3*BLOCK_SZ/7;
509
510 if (pauseCharWidth < 0)
511 pauseCharWidth = XTextWidth(gameFont, "P", 1);
512
513 SET_FG(colors[BLUE].pixel);
514 x_0 = X(x - half_pause_size);
515 y_0 = Y(y + half_pause_size);
516 rd.fillRectangle(dpy, drawPixmap, gameGC,
517 WINSCALE(x_0), WINSCALE(y_0),
518 UWINSCALE(2*half_pause_size+1),
519 UWINSCALE(2*half_pause_size+1));
520 if (count <= 0 || loopsSlow % 10 >= 5) {
521 SET_FG(colors[WHITE].pixel);
522 rd.drawRectangle(dpy, drawPixmap, gameGC,
523 WINSCALE(x_0 - 1),
524 WINSCALE(y_0 - 1),
525 UWINSCALE(2*(half_pause_size+1)),
526 UWINSCALE(2*(half_pause_size+1)));
527 rd.drawString(dpy, drawPixmap, gameGC,
528 WINSCALE(X(x)) - pauseCharWidth/2,
529 WINSCALE(Y(y-1)) + gameFont->ascent/2,
530 "P", 1);
531 }
532 } else
533 Bitmap_paint(drawPixmap, BM_PAUSED, WINSCALE(X(x - BLOCK_SZ / 2)),
534 WINSCALE(Y(y + BLOCK_SZ / 2)),
535 (count <= 0 || loopsSlow % 10 >= 5) ? 1 : 0);
536 }
537
538
539 /* Create better graphics for this. */
Gui_paint_appearing(int x,int y,int id,int count)540 void Gui_paint_appearing(int x, int y, int id, int count)
541 {
542 const unsigned hsize = 3 * BLOCK_SZ / 7;
543 other_t *other = Other_by_id(id);
544 int color = other ? Life_color(other) : 0;
545
546 if (!color)
547 color = WHITE;
548
549 /* Make a note we are doing the base warning */
550 if (version >= 0x4F12) {
551 homebase_t *base = Homebase_by_id(id);
552 if (base != NULL)
553 base->appeartime = (long)(loops + (count * clientFPS) / 120);
554 }
555
556 SET_FG(colors[color].pixel);
557 rd.fillRectangle(dpy, drawPixmap, gameGC,
558 SCALEX(x - (int)hsize),
559 SCALEY(y - (int)hsize + (int)(count / 180. * hsize + 1)),
560 UWINSCALE(2 * hsize + 1),
561 UWINSCALE((unsigned)(count / 180. * hsize + 1)));
562 }
563
564
Gui_paint_ecm(int x,int y,int size)565 void Gui_paint_ecm(int x, int y, int size)
566 {
567 Arc_add(WHITE,
568 X(x - size / 2),
569 Y(y + size / 2),
570 size, size, 0, 64 * 360);
571 }
572
573
Gui_paint_refuel(int x_0,int y_0,int x_1,int y_1)574 void Gui_paint_refuel(int x_0, int y_0, int x_1, int y_1)
575 {
576 if (!texturedObjects) {
577 rd.drawLine(dpy, drawPixmap, gameGC,
578 WINSCALE(X(x_0)), WINSCALE(Y(y_0)),
579 WINSCALE(X(x_1)), WINSCALE(Y(y_1)));
580 }
581 else {
582 int size = WINSCALE(8);
583 double dx, dy;
584 int i;
585 int fuel[16] = { 1, 2, 3, 3, 2, 1, 0, 1, 2, 3, 2, 1, 2, 3, 3, 2 };
586
587 x_0 = WINSCALE(X(x_0));
588 y_0 = WINSCALE(Y(y_0));
589 x_1 = WINSCALE(X(x_1));
590 y_1 = WINSCALE(Y(y_1));
591 dx = (double)(x_1 - x_0) / 16;
592 dy = (double)(y_1 - y_0) / 16;
593 for (i = 0; i < 16; i++) {
594 Bitmap_paint(drawPixmap, BM_REFUEL,
595 (int)(x_0 + (dx * i) - size / 2),
596 (int)(y_0 + (dy * i) - size / 2),
597 fuel[(loops + 16 - i) % 16]);
598 }
599 }
600 }
601
602
Gui_paint_connector(int x_0,int y_0,int x_1,int y_1,int tractor)603 void Gui_paint_connector(int x_0, int y_0, int x_1, int y_1, int tractor)
604 {
605 if (tractor)
606 rd.setDashes(dpy, gameGC, 0, cdashes, NUM_CDASHES);
607 else
608 rd.setDashes(dpy, gameGC, 0, dashes, NUM_DASHES);
609
610 rd.drawLine(dpy, drawPixmap, gameGC,
611 WINSCALE(X(x_0)), WINSCALE(Y(y_0)),
612 WINSCALE(X(x_1)), WINSCALE(Y(y_1)));
613 if (tractor)
614 rd.setDashes(dpy, gameGC, 0, dashes, NUM_DASHES);
615 }
616
617
Gui_paint_transporter(int x_0,int y_0,int x_1,int y_1)618 void Gui_paint_transporter(int x_0, int y_0, int x_1, int y_1)
619 {
620 rd.drawLine(dpy, drawPixmap, gameGC,
621 WINSCALE(X(x_0)), WINSCALE(Y(y_0)),
622 WINSCALE(X(x_1)), WINSCALE(Y(y_1)));
623 }
624
625
Gui_paint_all_connectors_begin(void)626 void Gui_paint_all_connectors_begin(void)
627 {
628 unsigned long mask;
629
630 SET_FG(colors[connColor].pixel);
631 if (gcv.line_style != LineOnOffDash) {
632 gcv.line_style = LineOnOffDash;
633 mask = GCLineStyle;
634 #ifndef NO_ROTATING_DASHES
635 mask |= GCDashOffset;
636 #endif
637 XChangeGC(dpy, gameGC, mask, &gcv);
638 }
639
640 }
641
642
Gui_paint_ships_begin(void)643 void Gui_paint_ships_begin(void)
644 {
645 gcv.dash_offset = WINSCALE(DASHES_LENGTH - (loops % DASHES_LENGTH));
646 }
647
648
Gui_paint_ships_end(void)649 void Gui_paint_ships_end(void)
650 {
651 unsigned long mask;
652 if (gcv.line_style != LineSolid) {
653 gcv.line_style = LineSolid;
654 mask = GCLineStyle;
655 XChangeGC(dpy, gameGC, mask, &gcv);
656 }
657 gcv.dash_offset = 0;
658 }
659
660
Gui_paint_rounddelay(int x,int y)661 static void Gui_paint_rounddelay(int x, int y)
662 {
663 char s[12];
664 int t, text_width;
665
666 sprintf(s, "%d", roundDelay / FPS);
667 t = strlen(s);
668 SET_FG(colors[WHITE].pixel);
669 text_width = XTextWidth(gameFont, s, t);
670 rd.drawString(dpy, drawPixmap, gameGC,
671 WINSCALE(X(x)) - text_width / 2,
672 WINSCALE(Y(y)) + gameFont->ascent/2,
673 s, t);
674 }
675
676
677 /* Here starts the paint functions for ships (MM) */
Gui_paint_ship_name(int x,int y,other_t * other)678 static void Gui_paint_ship_name(int x, int y, other_t *other)
679 {
680 Check_name_string(other);
681 if (shipNameColor) {
682 int color = Life_color(other);
683 if (!color)
684 color = shipNameColor;
685
686 SET_FG(colors[color].pixel);
687 rd.drawString(dpy, drawPixmap, gameGC,
688 WINSCALE(X(x)) - other->name_width / 2,
689 WINSCALE(Y(y) + 16) + gameFont->ascent,
690 other->id_string, other->name_len);
691 } else
692 SET_FG(colors[BLUE].pixel);
693
694 if (instruments.showLivesByShip
695 && BIT(Setup->mode, LIMITED_LIVES)) {
696 char keff[4] = "";
697
698 sprintf(keff, "%03d", other->life);
699 rd.drawString(dpy, drawPixmap, gameGC,
700 WINSCALE(X(x) + SHIP_SZ),
701 WINSCALE(Y(y) - SHIP_SZ) + gameFont->ascent,
702 &keff[2], 1);
703 }
704 }
705
706
Gui_is_my_tank(other_t * other)707 static int Gui_is_my_tank(other_t *other)
708 {
709 char tank_name[MAX_NAME_LEN];
710
711 if (self == NULL
712 || other == NULL
713 || other->mychar != 'T'
714 || (BIT(Setup->mode, TEAM_PLAY)
715 && self->team != other->team)) {
716 return 0;
717 }
718
719 if (strlcpy(tank_name, self->nick_name, MAX_NAME_LEN) < MAX_NAME_LEN)
720 strlcat(tank_name, "'s tank", MAX_NAME_LEN);
721
722 if (strcmp(tank_name, other->nick_name))
723 return 0;
724
725 return 1;
726 }
727
Gui_calculate_ship_color(int id,other_t * other)728 static int Gui_calculate_ship_color(int id, other_t *other)
729 {
730 int ship_color = WHITE;
731
732 if (BIT(Setup->mode, TEAM_PLAY)
733 && eyesId != id
734 && other != NULL
735 && eyeTeam == other->team) {
736 /* Paint teammates and allies ships with last life in teamLWColor */
737 if (BIT(Setup->mode, LIMITED_LIVES)
738 && (other->life == 0))
739 ship_color = teamLWColor;
740 else
741 ship_color = teamShipColor;
742 }
743
744 if (eyes != NULL
745 && eyesId != id
746 && other != NULL
747 && eyes->alliance != ' '
748 && eyes->alliance == other->alliance) {
749 /* Paint teammates and allies ships with last life in teamLWColor */
750 if (BIT(Setup->mode, LIMITED_LIVES)
751 && (other->life == 0))
752 ship_color = teamLWColor;
753 else
754 ship_color = teamShipColor;
755 }
756
757 if (Gui_is_my_tank(other))
758 ship_color = BLUE;
759
760 if (roundDelay > 0 && ship_color == WHITE)
761 ship_color = RED;
762
763 /* Check for team color */
764 if (other && BIT(Setup->mode, TEAM_PLAY)) {
765 int team_color = Team_color(other->team);
766 if (team_color)
767 return team_color;
768 }
769
770 /* Vato color hack start, edited by mara & kps */
771 if (BIT(Setup->mode, LIMITED_LIVES)) {
772 /* Paint your ship in selfLWColor when on last life */
773 if (eyes != NULL
774 && eyes->id == id
775 && eyes->life == 0) {
776 ship_color = selfLWColor;
777 }
778
779 /* Paint enemy ships with last life in enemyLWColor */
780 if (eyes != NULL
781 && eyes->id != id
782 && other != NULL
783 && eyeTeam != other->team
784 && other->life == 0) {
785 ship_color = enemyLWColor;
786 }
787 }
788 /* Vato color hack end */
789
790 return ship_color;
791 }
792
793
Gui_paint_marking_lights(int id,int x,int y,shipshape_t * ship,int dir)794 static void Gui_paint_marking_lights(int id, int x, int y,
795 shipshape_t *ship, int dir)
796 {
797 int lcnt;
798
799 if (((loopsSlow + id) & 0xF) == 0) {
800 for (lcnt = 0; lcnt < ship->num_l_light; lcnt++) {
801 position_t l_light = Ship_get_l_light_position(ship, lcnt, dir);
802 Rectangle_add(RED,
803 X(x + l_light.x) - 2,
804 Y(y + l_light.y) - 2,
805 6, 6);
806 Segment_add(RED,
807 X(x + l_light.x)-8,
808 Y(y + l_light.y),
809 X(x + l_light.x)+8,
810 Y(y + l_light.y));
811 Segment_add(RED,
812 X(x + l_light.x),
813 Y(y + l_light.y)-8,
814 X(x + l_light.x),
815 Y(y + l_light.y)+8);
816 }
817 } else if (((loopsSlow + id) & 0xF) == 2) {
818 for (lcnt = 0; lcnt < ship->num_r_light; lcnt++) {
819 int rightLightColor = maxColors > 4 ? 4 : BLUE;
820 position_t r_light = Ship_get_r_light_position(ship, lcnt, dir);
821 Rectangle_add(rightLightColor,
822 X(x + r_light.x)-2,
823 Y(y + r_light.y)-2,
824 6, 6);
825 Segment_add(rightLightColor,
826 X(x + r_light.x)-8,
827 Y(y + r_light.y),
828 X(x + r_light.x)+8,
829 Y(y + r_light.y));
830 Segment_add(rightLightColor,
831 X(x + r_light.x),
832 Y(y + r_light.y)-8,
833 X(x + r_light.x),
834 Y(y + r_light.y)+8);
835 }
836 }
837 }
838
839
Gui_paint_shields_deflectors(int x,int y,int radius,int shield,int deflector,int eshield,int ship_color)840 static void Gui_paint_shields_deflectors(int x, int y, int radius, int shield,
841 int deflector, int eshield,
842 int ship_color)
843 {
844 int e_radius = radius + 4;
845 int half_radius = radius >> 1;
846 int half_e_radius = e_radius >> 1;
847 int scolor = -1;
848 int ecolor = -1;
849
850 if (shield)
851 scolor = ship_color;
852 if (deflector)
853 ecolor = loopsSlow & 0x02 ? RED : BLUE;
854 if (eshield && shield) {
855 if (ecolor != -1) {
856 scolor = ecolor;
857 ecolor = ship_color;
858 } else
859 scolor = ecolor = ship_color;
860 }
861
862 if (ecolor != -1) { /* outer shield */
863 SET_FG(colors[ecolor].pixel);
864 rd.drawArc(dpy, drawPixmap, gameGC,
865 WINSCALE(X(x - half_e_radius)),
866 WINSCALE(Y(y + half_e_radius)),
867 (unsigned)WINSCALE(e_radius),
868 (unsigned)WINSCALE(e_radius),
869 0, 64 * 360);
870 }
871 if (scolor != -1) {
872 SET_FG(colors[scolor].pixel);
873 rd.drawArc(dpy, drawPixmap, gameGC,
874 WINSCALE(X(x - half_radius)),
875 WINSCALE(Y(y + half_radius)),
876 (unsigned)WINSCALE(radius),
877 (unsigned)WINSCALE(radius),
878 0, 64 * 360);
879 }
880 }
881
882 static void Set_drawstyle_dashed(int ship_color);
883
Gui_paint_ship_cloaked(int ship_color,XPoint * points,int point_count)884 static void Gui_paint_ship_cloaked(int ship_color, XPoint *points,
885 int point_count)
886 {
887 Set_drawstyle_dashed(ship_color);
888 rd.drawLines(dpy, drawPixmap, gameGC, points, point_count, 0);
889 }
890
Gui_paint_ship_phased(int ship_color,XPoint * points,int point_count)891 static void Gui_paint_ship_phased(int ship_color, XPoint *points,
892 int point_count)
893 {
894 Gui_paint_ship_cloaked(ship_color, points, point_count);
895 }
896
generic_paint_ship(int x,int y,int ang,int ship)897 static void generic_paint_ship(int x, int y, int ang, int ship)
898 {
899 Bitmap_paint(drawPixmap, ship,
900 WINSCALE(X(x) - 16), WINSCALE(Y(y) - 16), ang);
901 }
902
903
Gui_paint_ship_uncloaked(int id,XPoint * points,int ship_color,int point_count)904 static void Gui_paint_ship_uncloaked(int id, XPoint *points,
905 int ship_color, int point_count)
906 {
907 if (gcv.line_style != LineSolid) {
908 gcv.line_style = LineSolid;
909 XChangeGC(dpy, gameGC, GCLineStyle, &gcv);
910 }
911 SET_FG(colors[ship_color].pixel);
912 rd.drawLines(dpy, drawPixmap, gameGC, points, point_count, 0);
913
914 if (lock_id == id && id != -1 && lock_dist != 0)
915 rd.fillPolygon(dpy, drawPixmap, gameGC,
916 points, point_count,
917 Complex, CoordModeOrigin);
918 }
919
920
Set_drawstyle_dashed(int ship_color)921 static void Set_drawstyle_dashed(int ship_color)
922 {
923 unsigned long mask;
924 if (gcv.line_style != LineOnOffDash) {
925 gcv.line_style = LineOnOffDash;
926 mask = GCLineStyle;
927 #ifndef NO_ROTATING_DASHES
928 mask |= GCDashOffset;
929 #endif
930 XChangeGC(dpy, gameGC, mask, &gcv);
931 }
932 SET_FG(colors[ship_color].pixel);
933 }
934
set_shipshape(int world_x,int world_y,int dir,shipshape_t * ship,XPoint * points)935 static int set_shipshape(int world_x, int world_y,
936 int dir, shipshape_t *ship, XPoint *points)
937 {
938 int cnt;
939 position_t ship_point_pos;
940 XPoint *xpts = points;
941 double x, y;
942
943 for (cnt = 0; cnt < ship->num_points; cnt++) {
944 ship_point_pos = Ship_get_point_position(ship, cnt, dir);
945 x = (world_x - world.x + ship_point_pos.x) / clData.scaleFactor;
946 y = (world.y + ext_view_height - world_y - ship_point_pos.y)
947 / clData.scaleFactor;
948 xpts->x = (short)rint(x);
949 xpts->y = (short)rint(y);
950 xpts++;
951 }
952 points[cnt++] = points[0];
953
954 return cnt;
955 }
956
957
Gui_paint_ship(int x,int y,int dir,int id,int cloak,int phased,int shield,int deflector,int eshield)958 void Gui_paint_ship(int x, int y, int dir, int id, int cloak, int phased,
959 int shield, int deflector, int eshield)
960 {
961 int cnt, ship_color;
962 other_t *other;
963 shipshape_t *ship;
964 XPoint points[64];
965 int ship_shape;
966
967 ship = Ship_by_id(id);
968 other = Other_by_id(id);
969 ship_color = WHITE;
970
971 /* mara attempts similar behaviour to the kth ss hack */
972 if ((!instruments.showShipShapes)
973 && (self != NULL)
974 && (self->id != id))
975 cnt = set_shipshape(x, y, dir, Default_ship(), points);
976 else if ((!instruments.showMyShipShape)
977 && (self != NULL)
978 && (self->id == id))
979 cnt = set_shipshape(x, y, dir, Default_ship(), points);
980 else
981 cnt = set_shipshape(x, y, dir, ship, points);
982
983 /*
984 * Determine if the name of the player should be drawn below
985 * his/her ship.
986 */
987 if (self != NULL
988 && self->id != id
989 && other != NULL)
990 Gui_paint_ship_name(x, y, other);
991
992 if (roundDelay > 0 && roundDelay % FPS < FPS/2) {
993 Gui_paint_rounddelay(x, y);
994 return;
995 }
996
997 if (!(ship_color = Gui_calculate_ship_color(id, other))) return;
998
999 if (cloak == 0 && phased == 0) {
1000 if (!texturedObjects || !texturedShips) {
1001 Gui_paint_ship_uncloaked(id, points, ship_color, cnt);
1002 /* shipshapeshack by Mara */
1003 if (instruments.showShipShapesHack) {
1004 Segment_add(ship_color,
1005 (X(x + SHIP_SZ * tcos(dir))),
1006 (Y(y + SHIP_SZ * tsin(dir))),
1007 (X(x + (SHIP_SZ + 12) * tcos(dir))),
1008 (Y(y + (SHIP_SZ + 12) * tsin(dir))));
1009 Arc_add(ship_color,
1010 X(x - SHIP_SZ), Y(y + SHIP_SZ),
1011 2 * SHIP_SZ, 2 * SHIP_SZ,
1012 0, 64 * 360);
1013 }
1014 } else {
1015 if (ship_color == BLUE)
1016 ship_shape = BM_SHIP_FRIEND;
1017 else if (self != NULL && self->id != id)
1018 ship_shape = BM_SHIP_ENEMY;
1019 else
1020 ship_shape = BM_SHIP_SELF;
1021
1022 generic_paint_ship(x, y, dir, ship_shape);
1023 }
1024
1025 }
1026
1027 if (phased)
1028 Gui_paint_ship_phased(ship_color, points, cnt);
1029 else if (cloak)
1030 Gui_paint_ship_cloaked(ship_color, points, cnt);
1031
1032 if (markingLights)
1033 Gui_paint_marking_lights(id, x, y, ship, dir);
1034
1035 if (shield || deflector) {
1036 Set_drawstyle_dashed(ship_color);
1037 Gui_paint_shields_deflectors(x, y, ship->shield_radius,
1038 shield, deflector,
1039 eshield, ship_color);
1040 }
1041 }
1042
1043
Team_color(int team)1044 int Team_color(int team)
1045 {
1046 /* This code assumes we have max 10 teams. */
1047 assert(MAX_TEAMS == 10);
1048 switch (team) {
1049 case 0: return team0Color;
1050 case 1: return team1Color;
1051 case 2: return team2Color;
1052 case 3: return team3Color;
1053 case 4: return team4Color;
1054 case 5: return team5Color;
1055 case 6: return team6Color;
1056 case 7: return team7Color;
1057 case 8: return team8Color;
1058 case 9: return team9Color;
1059 default: break;
1060 }
1061 return 0;
1062 }
1063
Life_color(other_t * other)1064 int Life_color(other_t *other)
1065 {
1066 int color = 0; /* default is 'no special color' */
1067
1068 if (other
1069 && (other->mychar == ' ' || other->mychar == 'R')
1070 && BIT(Setup->mode, LIMITED_LIVES))
1071 color = Life_color_by_life(other->life);
1072 return color;
1073 }
1074
Life_color_by_life(int life)1075 int Life_color_by_life(int life)
1076 {
1077 int color;
1078
1079 if (life > 2)
1080 color = manyLivesColor;
1081 else if (life == 2)
1082 color = twoLivesColor;
1083 else if (life == 1)
1084 color = oneLifeColor;
1085 else /* we catch all */
1086 color = zeroLivesColor;
1087 return color;
1088 }
1089
1090
1091
1092 static xp_option_t guiobject_options[] = {
1093 COLOR_INDEX_OPTION(
1094 "teamShotColor",
1095 2,
1096 &teamShotColor,
1097 "Which color number to use for drawing harmless shots.\n"),
1098
1099 COLOR_INDEX_OPTION(
1100 "ballColor",
1101 1,
1102 &ballColor,
1103 "Which color number to use for drawing balls.\n"),
1104
1105 COLOR_INDEX_OPTION(
1106 "connColor",
1107 2,
1108 &connColor,
1109 "Which color number to use for drawing connectors.\n"),
1110
1111 COLOR_INDEX_OPTION(
1112 "zeroLivesColor",
1113 5,
1114 &zeroLivesColor,
1115 "Which color to associate with ships with zero lives left.\n"
1116 "This can be used to paint for example ship and base names.\n"),
1117
1118 COLOR_INDEX_OPTION(
1119 "oneLifeColor",
1120 11,
1121 &oneLifeColor,
1122 "Which color to associate with ships with one life left.\n"
1123 "This can be used to paint for example ship and base names.\n"),
1124
1125 COLOR_INDEX_OPTION(
1126 "twoLivesColor",
1127 4,
1128 &twoLivesColor,
1129 "Which color to associate with ships with two lives left.\n"
1130 "This can be used to paint for example ship and base names.\n"),
1131
1132 COLOR_INDEX_OPTION(
1133 "manyLivesColor",
1134 0,
1135 &manyLivesColor,
1136 "Which color to associate with ships with more than two lives left.\n"
1137 "This can be used to paint for example ship and base names.\n"),
1138
1139 COLOR_INDEX_OPTION(
1140 "selfLWColor",
1141 3,
1142 &selfLWColor,
1143 "Which color to use to paint your ship in when on last life.\n"
1144 "Original color for this is red.\n"),
1145
1146 COLOR_INDEX_OPTION(
1147 "enemyLWColor",
1148 3,
1149 &enemyLWColor,
1150 "Which color to use to paint enemy ships in when on last life.\n"
1151 "Original color for this is red.\n"),
1152
1153 COLOR_INDEX_OPTION(
1154 "teamLWColor",
1155 2,
1156 &teamLWColor,
1157 "Which color to use to paint teammate ships in when on last life.\n"
1158 "Original color for this is green.\n"),
1159
1160 COLOR_INDEX_OPTION(
1161 "shipNameColor",
1162 2,
1163 &shipNameColor,
1164 "Which color number to use for drawing names of ships\n"
1165 "(unless drawn in one of the life colors).\n"),
1166
1167 COLOR_INDEX_OPTION(
1168 "mineNameColor",
1169 2,
1170 &mineNameColor,
1171 "Which color number to use for drawing names of mines.\n"),
1172
1173 COLOR_INDEX_OPTION(
1174 "teamShipColor",
1175 2,
1176 &teamShipColor,
1177 "Which color number to use for drawing your teammates.\n"),
1178
1179 COLOR_INDEX_OPTION(
1180 "team0Color",
1181 0,
1182 &team0Color,
1183 "Which color number to use for drawing team 0 objects.\n"),
1184
1185 COLOR_INDEX_OPTION(
1186 "team1Color",
1187 0,
1188 &team1Color,
1189 "Which color number to use for drawing team 1 objects.\n"),
1190
1191 COLOR_INDEX_OPTION(
1192 "team2Color",
1193 0,
1194 &team2Color,
1195 "Which color number to use for drawing team 2 objects.\n"),
1196
1197 COLOR_INDEX_OPTION(
1198 "team3Color",
1199 0,
1200 &team3Color,
1201 "Which color number to use for drawing team 3 objects.\n"),
1202
1203 COLOR_INDEX_OPTION(
1204 "team4Color",
1205 0,
1206 &team4Color,
1207 "Which color number to use for drawing team 4 objects.\n"),
1208
1209 COLOR_INDEX_OPTION(
1210 "team5Color",
1211 0,
1212 &team5Color,
1213 "Which color number to use for drawing team 5 objects.\n"),
1214
1215 COLOR_INDEX_OPTION(
1216 "team6Color",
1217 0,
1218 &team6Color,
1219 "Which color number to use for drawing team 6 objects.\n"),
1220
1221 COLOR_INDEX_OPTION(
1222 "team7Color",
1223 0,
1224 &team7Color,
1225 "Which color number to use for drawing team 7 objects.\n"),
1226
1227 COLOR_INDEX_OPTION(
1228 "team8Color",
1229 0,
1230 &team8Color,
1231 "Which color number to use for drawing team 8 objects.\n"),
1232
1233 COLOR_INDEX_OPTION(
1234 "team9Color",
1235 0,
1236 &team9Color,
1237 "Which color number to use for drawing team 9 objects.\n"),
1238 };
1239
Store_guiobject_options(void)1240 void Store_guiobject_options(void)
1241 {
1242 STORE_OPTIONS(guiobject_options);
1243 }
1244