/* * XPilot NG, a multiplayer space war game. * * Copyright (C) 1991-2001 by * * Bjørn Stabell * Ken Ronny Schouten * Bert Gijsbers * Dick Balaska * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "xpclient_x11.h" static int baseNameColor; /* Color index for base name drawing */ static int backgroundPointColor; /* background point drawing */ static int fuelColor; /* fuel station drawing */ static int visibilityBorderColor; /* visibility border drawing */ void Gui_paint_walls(int x, int y, int type) { if (!texturedObjects) { if (type & BLUE_LEFT) Segment_add(wallColor, X(x), Y(y), X(x), Y(y+BLOCK_SZ)); if (type & BLUE_DOWN) Segment_add(wallColor, X(x), Y(y), X(x+BLOCK_SZ), Y(y)); if (type & BLUE_RIGHT) Segment_add(wallColor, X(x+BLOCK_SZ), Y(y), X(x+BLOCK_SZ), Y(y+BLOCK_SZ)); if (type & BLUE_UP) Segment_add(wallColor, X(x), Y(y+BLOCK_SZ), X(x+BLOCK_SZ), Y(y+BLOCK_SZ)); if ((type & BLUE_FUEL) == BLUE_FUEL) ; else if (type & BLUE_OPEN) Segment_add(wallColor, X(x), Y(y), X(x+BLOCK_SZ), Y(y+BLOCK_SZ)); else if (type & BLUE_CLOSED) Segment_add(wallColor, X(x), Y(y+BLOCK_SZ), X(x+BLOCK_SZ), Y(y)); } else { if (type & BLUE_LEFT) Bitmap_paint(drawPixmap, BM_WALL_LEFT, WINSCALE(X(x - 1)), WINSCALE(Y(y + BLOCK_SZ)), 0); if (type & BLUE_DOWN) Bitmap_paint(drawPixmap, BM_WALL_BOTTOM, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ - 1)), 0); if (type & BLUE_RIGHT) Bitmap_paint(drawPixmap, BM_WALL_RIGHT, WINSCALE(X(x + 1)), WINSCALE(Y(y + BLOCK_SZ)), 0); if (type & BLUE_UP) Bitmap_paint(drawPixmap, BM_WALL_TOP, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ + 1)), 0); if ((type & BLUE_FUEL) == BLUE_FUEL) ; else if (type & BLUE_OPEN) Bitmap_paint(drawPixmap, BM_WALL_UR, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); else if (type & BLUE_CLOSED) Bitmap_paint(drawPixmap, BM_WALL_UL, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); } } void Gui_paint_filled_slice(int bl, int tl, int tr, int br, int y) { XPoint points[5]; SET_FG(colors[wallColor].pixel); points[0].x = WINSCALE(X(bl)); points[0].y = WINSCALE(Y(y)); points[1].x = WINSCALE(X(tl)); points[1].y = WINSCALE(Y(y + BLOCK_SZ)); points[2].x = WINSCALE(X(tr)); points[2].y = WINSCALE(Y(y + BLOCK_SZ)); points[3].x = WINSCALE(X(br)); points[3].y = WINSCALE(Y(y)); points[4] = points[0]; rd.fillPolygon(dpy, drawPixmap, gameGC, points, 5, Convex, CoordModeOrigin); } void Gui_paint_cannon(int x, int y, int type) { if (!texturedObjects) { XPoint points[5]; SET_FG(colors[WHITE].pixel); switch (type) { case SETUP_CANNON_UP: points[0].x = WINSCALE(X(x)); points[0].y = WINSCALE(Y(y)); points[1].x = WINSCALE(X(x+BLOCK_SZ)); points[1].y = WINSCALE(Y(y)); points[2].x = WINSCALE(X(x+BLOCK_SZ/2)); points[2].y = WINSCALE(Y(y+BLOCK_SZ/3)); break; case SETUP_CANNON_DOWN: points[0].x = WINSCALE(X(x)); points[0].y = WINSCALE(Y(y+BLOCK_SZ)); points[1].x = WINSCALE(X(x+BLOCK_SZ)); points[1].y = WINSCALE(Y(y+BLOCK_SZ)); points[2].x = WINSCALE(X(x+BLOCK_SZ/2)); points[2].y = WINSCALE(Y(y+2*BLOCK_SZ/3)); break; case SETUP_CANNON_RIGHT: points[0].x = WINSCALE(X(x)); points[0].y = WINSCALE(Y(y)); points[1].x = WINSCALE(X(x)); points[1].y = WINSCALE(Y(y+BLOCK_SZ)); points[2].x = WINSCALE(X(x+BLOCK_SZ/3)); points[2].y = WINSCALE(Y(y+BLOCK_SZ/2)); break; case SETUP_CANNON_LEFT: points[0].x = WINSCALE(X(x+BLOCK_SZ)); points[0].y = WINSCALE(Y(y)); points[1].x = WINSCALE(X(x+BLOCK_SZ)); points[1].y = WINSCALE(Y(y+BLOCK_SZ)); points[2].x = WINSCALE(X(x+2*BLOCK_SZ/3)); points[2].y = WINSCALE(Y(y+BLOCK_SZ/2)); break; default: warn("Unknown cannon type %d", type); return; } points[3] = points[0]; rd.drawLines(dpy, drawPixmap, gameGC, points, 4, 0); } else { switch (type) { case SETUP_CANNON_UP: Bitmap_paint(drawPixmap, BM_CANNON_DOWN, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); break; case SETUP_CANNON_DOWN: Bitmap_paint(drawPixmap, BM_CANNON_UP, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ - 1)), 0); break; case SETUP_CANNON_LEFT: Bitmap_paint(drawPixmap, BM_CANNON_RIGHT, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); break; case SETUP_CANNON_RIGHT: Bitmap_paint(drawPixmap, BM_CANNON_LEFT, WINSCALE(X(x - 1)), WINSCALE(Y(y + BLOCK_SZ)), 0); break; default: warn("Unknown cannon type %d", type); return; } } } void Gui_paint_fuel(int x, int y, double fuel) { /* fuel box drawing can be disabled */ if (fuelColor == BLACK) return; if (!texturedObjects) { #define FUEL_BORDER 2 int size; static char s[2] = "F"; static int text_width = 0; static int text_is_bigger; static double lastScaleFactor; if (!text_width || lastScaleFactor != clData.scaleFactor) { lastScaleFactor = clData.scaleFactor; text_width = XTextWidth(gameFont, s, 1); text_is_bigger = (text_width + 4 > WINSCALE(BLOCK_SZ) + 1) || (gameFont->ascent + gameFont->descent) > WINSCALE(BLOCK_SZ) + 2; } SET_FG(colors[fuelColor].pixel); size = (int)((BLOCK_SZ - 2*FUEL_BORDER) * fuel / MAX_STATION_FUEL); rd.fillRectangle(dpy, drawPixmap, gameGC, SCALEX(x + FUEL_BORDER), SCALEY(y + FUEL_BORDER + size), (unsigned)WINSCALE(BLOCK_SZ - 2*FUEL_BORDER + 1), (unsigned)WINSCALE(size + 1)); /* Draw F in fuel cells */ XSetFunction(dpy, gameGC, GXxor); SET_FG(colors[BLACK].pixel ^ colors[fuelColor].pixel); x = SCALEX(x + BLOCK_SZ/2) - text_width/2, y = SCALEY(y + BLOCK_SZ/2) + gameFont->ascent/2, rd.drawString(dpy, drawPixmap, gameGC, x, y, s, 1); XSetFunction(dpy, gameGC, GXcopy); } else { #define BITMAP_FUEL_BORDER 3 int fuel_images = ABS(pixmaps[BM_FUEL].count); int size, image; irec_t area; bbox_t *box; xp_bitmap_t *bit; /* x + x * y will give a pseudo random number, * so different fuelcells will not be displayed with the same * image-frame. * The ABS is needed to ensure image is not negative even with * large scale factors. */ image = ABS((loopsSlow + x + x * y) % (fuel_images * 2)); /* the animation is played from image 0-15 then back again * from image 15-0 */ if (image >= fuel_images) image = (2 * fuel_images - 1) - image; size = (BLOCK_SZ - 2 * BITMAP_FUEL_BORDER) * fuel / MAX_STATION_FUEL; Bitmap_paint(drawPixmap, BM_FUELCELL, SCALEX(x), SCALEY(y + BLOCK_SZ), 0); bit = Bitmap_get(drawPixmap, BM_FUEL, image); if (bit != NULL) { box = &bit->bbox; area.x = 0; area.y = 0; area.w = WINSCALE(BLOCK_SZ - 2 * BITMAP_FUEL_BORDER); area.h = WINSCALE(size); Bitmap_paint_area(drawPixmap, bit, SCALEX(x + BITMAP_FUEL_BORDER), SCALEY(y + size + BITMAP_FUEL_BORDER), &area); } } } void Gui_paint_base(int x, int y, int id, int team, int type) { int color = 0; const int BORDER = 4; /* in pixels */ int size = 0, size2 = 0; other_t *other; char s[3]; char info[6]; homebase_t *base = NULL; bool do_basewarning = false; other = Other_by_id(id); base = Homebase_by_id(id); if (baseNameColor) { if (!(color = Life_color(other))) color = baseNameColor; } else color = WHITE; if (base != NULL) { /* * Hacks to support Mara's base warning on new servers and * the red "meter" basewarning on old servers. */ if (loops < base->appeartime) do_basewarning = true; if (version < 0x4F12 && do_basewarning) { if (baseWarningType & 1) { /* We assume the ship will appear after 3 seconds. */ int count = 360 * (base->appeartime - loops) / (3 * clientFPS); LIMIT(count, 0, 360); /* red box basewarning */ if (count > 0 && (baseWarningType & 1)) Gui_paint_appearing(x + BLOCK_SZ / 2, y + BLOCK_SZ / 2, id, count); } } } /* Mara's flashy basewarning */ if (do_basewarning && (baseWarningType & 2)) { if (loopsSlow & 1) { if (color != WHITE) color = WHITE; else color = BLUE; } } SET_FG(colors[color].pixel); if (!texturedObjects) { switch (type) { case SETUP_BASE_UP: Segment_add(color, X(x), Y(y-1), X(x+BLOCK_SZ), Y(y-1)); break; case SETUP_BASE_DOWN: Segment_add(color, X(x), Y(y+BLOCK_SZ+1), X(x+BLOCK_SZ), Y(y+BLOCK_SZ+1)); break; case SETUP_BASE_LEFT: Segment_add(color, X(x+BLOCK_SZ+1), Y(y+BLOCK_SZ), X(x+BLOCK_SZ+1), Y(y)); break; case SETUP_BASE_RIGHT: Segment_add(color, X(x-1), Y(y+BLOCK_SZ), X(x-1), Y(y)); break; default: warn("Bad base dir."); return; } } else { switch (type) { case SETUP_BASE_UP: Bitmap_paint(drawPixmap, BM_BASE_DOWN, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); break; case SETUP_BASE_DOWN: Bitmap_paint(drawPixmap, BM_BASE_UP, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ - 1)), 0); break; case SETUP_BASE_LEFT: Bitmap_paint(drawPixmap, BM_BASE_RIGHT, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); break; case SETUP_BASE_RIGHT: Bitmap_paint(drawPixmap, BM_BASE_LEFT, WINSCALE(X(x - 1)), WINSCALE(Y(y + BLOCK_SZ)), 0); break; default: warn("Bad base dir."); return; } } /* only draw base teams if base naming is on, Mara 01/12/14 */ if (!baseNameColor) return; /* operate in pixels from here out */ x = SCALEX(x); y = SCALEY(y); Check_name_string(other); if (BIT(Setup->mode, TEAM_PLAY)) { s[0] = '0' + team; if (other) { s[1] = ' '; s[2] = '\0'; } else s[1] = '\0'; size = XTextWidth(gameFont, s, other ? 2 : 1); } switch (type) { case SETUP_BASE_UP: y += BORDER + gameFont->ascent; x += WINSCALE(BLOCK_SZ / 2); x -= size / 2 + (other ? other->name_width / 2 : 0); break; case SETUP_BASE_DOWN: y -= WINSCALE(BLOCK_SZ) + BORDER + gameFont->descent; x += WINSCALE(BLOCK_SZ / 2); x -= size / 2 + (other ? other->name_width / 2 : 0); break; case SETUP_BASE_LEFT: x += WINSCALE(BLOCK_SZ) + BORDER; y += -WINSCALE(BLOCK_SZ / 2) + gameFont->ascent / 2; break; case SETUP_BASE_RIGHT: x -= BORDER + (other ? other->name_width : 0) + size; y += -WINSCALE(BLOCK_SZ / 2) + gameFont->ascent / 2; break; default: warn("BUG: bad base setup type in Gui_paint_base()"); break; } /* * Determine whether to paint remaining lives or D (dead), P (paused) or * W (waiting for next round) at base. */ if (other) { if (other->mychar == ' ' || other->mychar == 'R') { if (BIT(Setup->mode, LIMITED_LIVES)) sprintf(info, " %d", other->life); else sprintf(info, " "); } else sprintf(info, " %c", other->mychar); size2 = XTextWidth(gameFont, info, (int)strlen(info)); } /* Team number */ if (size) { rd.drawString(dpy, drawPixmap, gameGC, x, y, s, other ? 2 : 1); x += size; } if (other) { rd.drawString(dpy, drawPixmap, gameGC, x, y, other->nick_name, other->name_len); x += other->name_width; } /* Extra base info */ if (size2) rd.drawString(dpy, drawPixmap, gameGC, x, y, info, (int)strlen(info)); } void Gui_paint_decor(int x, int y, int xi, int yi, int type, bool last, bool more_y) { XPoint points[5]; int mask; int fill_top_left = -1, fill_top_right = -1, fill_bottom_left = -1, fill_bottom_right = -1; static unsigned char decor[256]; static int decorReady = 0; SET_FG(colors[decorColor].pixel); if (!decorReady) { memset(decor, 0, sizeof decor); decor[SETUP_DECOR_FILLED] = DECOR_UP | DECOR_LEFT | DECOR_DOWN | DECOR_RIGHT; decor[SETUP_DECOR_RU] = DECOR_UP | DECOR_RIGHT | DECOR_CLOSED; decor[SETUP_DECOR_RD] = DECOR_DOWN | DECOR_RIGHT | DECOR_OPEN | DECOR_BELOW; decor[SETUP_DECOR_LU] = DECOR_UP | DECOR_LEFT | DECOR_OPEN; decor[SETUP_DECOR_LD] = DECOR_LEFT | DECOR_DOWN | DECOR_CLOSED | DECOR_BELOW; } mask = decor[type]; if (!(instruments.filledDecor||instruments.texturedDecor)) { if (mask & DECOR_LEFT) { if ((xi == 0) ? (!BIT(Setup->mode, WRAP_PLAY) || !(decor[Setup->map_data[(Setup->x - 1) * Setup->y + yi]] & DECOR_RIGHT)) : !(decor[Setup->map_data[(xi - 1) * Setup->y + yi]] & DECOR_RIGHT)) { Segment_add(decorColor, X(x), Y(y), X(x), Y(y+BLOCK_SZ)); } } if (mask & DECOR_DOWN) { if ((yi == 0) ? (!BIT(Setup->mode, WRAP_PLAY) || !(decor[Setup->map_data[xi * Setup->y + Setup->y - 1]] & DECOR_UP)) : !(decor[Setup->map_data[xi * Setup->y + (yi - 1)]] & DECOR_UP)) { Segment_add(decorColor, X(x), Y(y), X(x+BLOCK_SZ), Y(y)); } } if (mask & DECOR_RIGHT) { if (!instruments.outlineDecor || ((xi == Setup->x - 1) ? (!BIT(Setup->mode, WRAP_PLAY) || !(decor[Setup->map_data[yi]] & DECOR_LEFT)) : !(decor[Setup->map_data[(xi + 1) * Setup->y + yi]] & DECOR_LEFT))) { Segment_add(decorColor, X(x+BLOCK_SZ), Y(y), X(x+BLOCK_SZ), Y(y+BLOCK_SZ)); } } if (mask & DECOR_UP) { if (!instruments.outlineDecor || ((yi == Setup->y - 1) ? (!BIT(Setup->mode, WRAP_PLAY) || !(decor[Setup->map_data[xi * Setup->y]] & DECOR_DOWN)) : !(decor[Setup->map_data[xi * Setup->y + (yi + 1)]] & DECOR_DOWN))) { Segment_add(decorColor, X(x), Y(y+BLOCK_SZ), X(x+BLOCK_SZ), Y(y+BLOCK_SZ)); } } if (mask & DECOR_OPEN) { Segment_add(decorColor, X(x), Y(y), X(x+BLOCK_SZ), Y(y+BLOCK_SZ)); } else if (mask & DECOR_CLOSED) { Segment_add(decorColor, X(x), Y(y+BLOCK_SZ), X(x+BLOCK_SZ), Y(y)); } } else { if (mask & DECOR_OPEN) { if (mask & DECOR_BELOW) { fill_top_left = x + BLOCK_SZ; fill_bottom_left = x; fill_top_right = fill_bottom_right = -1; } else { fill_top_right = x + BLOCK_SZ; fill_bottom_right = x; } } else if (mask & DECOR_CLOSED) { if (!(mask & DECOR_BELOW)) { fill_top_left = x; fill_bottom_left = x + BLOCK_SZ; fill_top_right = fill_bottom_right = -1; } else { fill_top_right = x; fill_bottom_right = x + BLOCK_SZ; } } if (mask & DECOR_RIGHT) fill_top_right = fill_bottom_right = x + BLOCK_SZ; if (fill_top_left == -1) fill_top_left = fill_bottom_left = x; if (fill_top_right == -1 && (last || more_y)) { fill_top_right = x + BLOCK_SZ; fill_bottom_right = x + BLOCK_SZ; } if (fill_top_right != -1) { points[0].x = WINSCALE(X(fill_bottom_left)); points[0].y = WINSCALE(Y(y)); points[1].x = WINSCALE(X(fill_top_left)); points[1].y = WINSCALE(Y(y + BLOCK_SZ)); points[2].x = WINSCALE(X(fill_top_right)); points[2].y = WINSCALE(Y(y + BLOCK_SZ)); points[3].x = WINSCALE(X(fill_bottom_right)); points[3].y = WINSCALE(Y(y)); points[4] = points[0]; rd.fillPolygon(dpy, drawPixmap, gameGC, points, 5, Convex, CoordModeOrigin); fill_top_left = fill_top_right = fill_bottom_left = fill_bottom_right = -1; } } } void Gui_paint_setup_check(int x, int y, bool isNext) { XPoint points[5]; if (!texturedObjects) { SET_FG(colors[BLUE].pixel); points[0].x = WINSCALE(X(x+(BLOCK_SZ/2))); points[0].y = WINSCALE(Y(y)); points[1].x = WINSCALE(X(x)); points[1].y = WINSCALE(Y(y+BLOCK_SZ/2)); points[2].x = WINSCALE(X(x+BLOCK_SZ/2)); points[2].y = WINSCALE(Y(y+BLOCK_SZ)); points[3].x = WINSCALE(X(x+BLOCK_SZ)); points[3].y = WINSCALE(Y(y+(BLOCK_SZ/2))); points[4] = points[0]; if (isNext) rd.fillPolygon(dpy, drawPixmap, gameGC, points, 5, Convex, CoordModeOrigin); else rd.drawLines(dpy, drawPixmap, gameGC, points, 5, 0); } else { if (isNext) Bitmap_paint(drawPixmap, BM_CHECKPOINT, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 1); else Bitmap_paint(drawPixmap, BM_CHECKPOINT, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); } } void Gui_paint_border(int x, int y, int xi, int yi) { Segment_add(wallColor, X(x), Y(y), X(xi), Y(yi)); } static void Gui_paint_rectangle(int x, int y, int xi, int yi, int color) { Segment_add(color, X(x), Y(y), X(x), Y(yi)); Segment_add(color, X(xi), Y(y), X(xi), Y(yi)); Segment_add(color, X(x), Y(y), X(xi), Y(y)); Segment_add(color, X(x), Y(yi), X(xi), Y(yi)); } void Gui_paint_visible_border(int x, int y, int xi, int yi) { if (visibilityBorderColor) Gui_paint_rectangle(x, y, xi, yi, visibilityBorderColor); } void Gui_paint_hudradar_limit(int x, int y, int xi, int yi) { Gui_paint_rectangle(x, y, xi, yi, BLUE); } void Gui_paint_setup_acwise_grav(int x, int y) { Arc_add(RED, X(x+5), Y(y+BLOCK_SZ-5), BLOCK_SZ-10, BLOCK_SZ-10, 64*150, 64*300); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ-5), X(x+BLOCK_SZ/2+4), Y(y+BLOCK_SZ-1)); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ-5), X(x+BLOCK_SZ/2+4), Y(y+BLOCK_SZ-9)); } void Gui_paint_setup_cwise_grav(int x, int y) { Arc_add(RED, X(x+5), Y(y+BLOCK_SZ-5), BLOCK_SZ-10, BLOCK_SZ-10, 64*90, 64*300); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ-5), X(x+BLOCK_SZ/2-4), Y(y+BLOCK_SZ-1)); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ-5), X(x+BLOCK_SZ/2-4), Y(y+BLOCK_SZ-9)); } void Gui_paint_setup_pos_grav(int x, int y) { static const int INSIDE_BL = BLOCK_SZ - 2; if (!texturedObjects) { Arc_add(RED, X(x+1), Y(y+BLOCK_SZ-1), INSIDE_BL, INSIDE_BL, 0, 64*360); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y+5), X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ-5)); Segment_add(RED, X(x+5), Y(y+BLOCK_SZ/2), X(x+BLOCK_SZ-5), Y(y+BLOCK_SZ/2)); } else Bitmap_paint(drawPixmap, BM_PLUSGRAVITY, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); } void Gui_paint_setup_neg_grav(int x, int y) { static const int INSIDE_BL = BLOCK_SZ - 2; if (!texturedObjects) { Arc_add(RED, X(x+1), Y(y+BLOCK_SZ-1), INSIDE_BL, INSIDE_BL, 0, 64*360); Segment_add(RED, X(x+5), Y(y+BLOCK_SZ/2), X(x+BLOCK_SZ-5), Y(y+BLOCK_SZ/2)); } else Bitmap_paint(drawPixmap, BM_MINUSGRAVITY, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); } void Gui_paint_setup_up_grav(int x, int y) { Segment_add(RED, X(x+BLOCK_SZ/2), Y(y), X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ)); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ), X(x+BLOCK_SZ/2-10), Y(y+BLOCK_SZ-10)); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ), X(x+BLOCK_SZ/2+10), Y(y+BLOCK_SZ-10)); } void Gui_paint_setup_down_grav(int x, int y) { Segment_add(RED, X(x+BLOCK_SZ/2), Y(y), X(x+BLOCK_SZ/2), Y(y+BLOCK_SZ)); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y), X(x+BLOCK_SZ/2-10), Y(y+10)); Segment_add(RED, X(x+BLOCK_SZ/2), Y(y), X(x+BLOCK_SZ/2+10), Y(y+10)); } void Gui_paint_setup_right_grav(int x, int y) { Segment_add(RED, X(x), Y(y+BLOCK_SZ/2), X(x+BLOCK_SZ), Y(y+BLOCK_SZ/2)); Segment_add(RED, X(x+BLOCK_SZ), Y(y+BLOCK_SZ/2), X(x+BLOCK_SZ-10), Y(y+BLOCK_SZ/2+10)); Segment_add(RED, X(x+BLOCK_SZ), Y(y+BLOCK_SZ/2), X(x+BLOCK_SZ-10), Y(y+BLOCK_SZ/2-10)); } void Gui_paint_setup_left_grav(int x, int y) { Segment_add(RED, X(x), Y(y+BLOCK_SZ/2), X(x+BLOCK_SZ), Y(y+BLOCK_SZ/2)); Segment_add(RED, X(x), Y(y+BLOCK_SZ/2), X(x+10), Y(y+BLOCK_SZ/2+10)); Segment_add(RED, X(x), Y(y+BLOCK_SZ/2), X(x+10), Y(y+BLOCK_SZ/2-10)); } void Gui_paint_setup_worm(int x, int y) { int wormDrawCount = loopsSlow & 7; if (!texturedObjects) { static const int INSIDE_BL = BLOCK_SZ - 2; static int wormOffset[8][3] = { { 10, 10, 10 }, { 5, 10, 10 }, { 0, 10, 10 }, { 0, 5, 10 }, { 0, 0, 10 }, { 5, 0, 10 }, { 10, 0, 10 }, { 10, 5, 10 } }; #define _O wormOffset[wormDrawCount] SET_FG(colors[RED].pixel); Arc_add(RED, X(x) + 0, Y(y + BLOCK_SZ) + 0, INSIDE_BL - 0, INSIDE_BL - 0, 0, 64 * 360); Arc_add(RED, X(x) + _O[0], Y(y + BLOCK_SZ) + _O[1], INSIDE_BL - _O[2], INSIDE_BL - _O[2], 0, 64 * 360); Arc_add(RED, X(x) + _O[0] * 2, Y(y + BLOCK_SZ) + _O[1] * 2, INSIDE_BL - _O[2] * 2, INSIDE_BL - _O[2] * 2, 0, 64 * 360); } else Bitmap_paint(drawPixmap, BM_WORMHOLE, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), wormDrawCount); } void Gui_paint_setup_item_concentrator(int x, int y) { static struct concentrator_triangle { int radius; int displ; int dir_off; int rot_speed; int rot_dir; } tris[] = { #if 0 { 14, 3, 0, 1, 0 }, { 11, 5, 3, 2, 0 }, { 7, 8, 5, 3, 0 }, #else { 7, 3, 0, 3, 0 }, { 11, 5, 3, 3, 0 }, { 14, 8, 5, 3, 0 }, #endif }; static unsigned rot_dir; static long concentratorloop; unsigned rdir, tdir; int i, cx, cy; XPoint pts[4]; if (!texturedObjects) { SET_FG(colors[RED].pixel); if (concentratorloop != loops) { concentratorloop = loops; rot_dir += 5; for (i = 0; i < NELEM(tris); i++) tris[i].rot_dir += tris[i].rot_speed; } for (i = 0; i < NELEM(tris); i++) { /* I'll bet you didn't know that floating point math is faster than integer math on a pentium (and for some reason the UNIX way rounds off too much) */ rdir = MOD2(rot_dir + tris[i].dir_off, RES); cx = (int)(X(x + BLOCK_SZ / 2) + tris[i].displ * tcos(rdir)); cy = (int)(Y(y + BLOCK_SZ / 2) + tris[i].displ * tsin(rdir)); tdir = MOD2(tris[i].rot_dir, RES); pts[0].x = WINSCALE(cx + (int)(tris[i].radius * tcos(tdir))); pts[0].y = WINSCALE(cy + (int)(tris[i].radius * tsin(tdir))); pts[1].x = WINSCALE(cx + (int)(tris[i].radius * tcos(MOD2(tdir + RES/3, RES)))); pts[1].y = WINSCALE(cy + (int)(tris[i].radius * tsin(MOD2(tdir + RES/3, RES)))); pts[2].x = WINSCALE(cx + (int)(tris[i].radius * tcos(MOD2(tdir + 2*RES/3, RES)))); pts[2].y = WINSCALE(cy + (int)(tris[i].radius * tsin(MOD2(tdir + 2*RES/3, RES)))); /* Trace("DC: %d cx=%d/%d %d/%d %d/%d %d/%d %d/%d\n", i, cx, cy, pts[0].x, pts[0].y, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y); */ pts[3] = pts[0]; rd.drawLines(dpy, drawPixmap, gameGC, pts, NELEM(pts), CoordModeOrigin); } } else Bitmap_paint(drawPixmap, BM_CONCENTRATOR, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), (loopsSlow + (x + x * y)) % 32); } void Gui_paint_setup_asteroid_concentrator(int x, int y) { static struct concentrator_square { int size; int displ; int dir_off; int rot_speed; int rot_dir; } sqrs[] = { #if 0 { 16, 3, 0, 1, 0 }, { 12, 5, 3, 2, 0 }, { 8, 8, 5, 3, 0 }, #else { 8, 3, 0, 3, 0 }, { 12, 5, 3, 3, 0 }, { 16, 8, 5, 3, 0 }, #endif }; static unsigned rot_dir; static long concentratorloop; unsigned rdir, tdir; int i, cx, cy; XPoint pts[5]; if (!texturedObjects) { SET_FG(colors[RED].pixel); if (concentratorloop != loops) { concentratorloop = loops; rot_dir += 5; for (i = 0; i < NELEM(sqrs); i++) sqrs[i].rot_dir += sqrs[i].rot_speed; } for (i = 0; i < NELEM(sqrs); i++) { /* I'll bet you didn't know that floating point math is faster than integer math on a pentium (and for some reason the UNIX way rounds off too much) */ rdir = MOD2(rot_dir + sqrs[i].dir_off, RES); cx = (int)(X(x + BLOCK_SZ / 2) + sqrs[i].displ * tcos(rdir)); cy = (int)(Y(y + BLOCK_SZ / 2) + sqrs[i].displ * tsin(rdir)); tdir = MOD2(sqrs[i].rot_dir, RES); pts[0].x = WINSCALE(cx + (int)(sqrs[i].size * tcos(tdir))); pts[0].y = WINSCALE(cy + (int)(sqrs[i].size * tsin(tdir))); pts[1].x = WINSCALE(cx + (int)(sqrs[i].size * tcos(MOD2(tdir + RES/4, RES)))); pts[1].y = WINSCALE(cy + (int)(sqrs[i].size * tsin(MOD2(tdir + RES/4, RES)))); pts[2].x = WINSCALE(cx + (int)(sqrs[i].size * tcos(MOD2(tdir + 2*RES/4, RES)))); pts[2].y = WINSCALE(cy + (int)(sqrs[i].size * tsin(MOD2(tdir + 2*RES/4, RES)))); pts[3].x = WINSCALE(cx + (int)(sqrs[i].size * tcos(MOD2(tdir + 3*RES/4, RES)))); pts[3].y = WINSCALE(cy + (int)(sqrs[i].size * tsin(MOD2(tdir + 3*RES/4, RES)))); /* Trace("DC: %d cx=%d/%d %d/%d %d/%d %d/%d %d/%d\n", i, cx, cy, pts[0].x, pts[0].y, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y); */ pts[4] = pts[0]; rd.drawLines(dpy, drawPixmap, gameGC, pts, NELEM(pts), CoordModeOrigin); } } else Bitmap_paint(drawPixmap, BM_ASTEROIDCONC, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), (loopsSlow + (x + x * y)) % 32); } void Gui_paint_decor_dot(int x, int y, int size) { if (!backgroundPointColor) return; Rectangle_add(backgroundPointColor, X(x + BLOCK_SZ / 2) - (backgroundPointSize >> 1), Y(y + BLOCK_SZ / 2) - (backgroundPointSize >> 1), size, size); } void Gui_paint_setup_target(int x, int y, int team, double damage, bool own) { int size, a1, a2, b1, b2, color; char s[2]; color = own ? BLUE : RED; if (BIT(Setup->mode, TEAM_PLAY)) { int team_color = Team_color(team); if (team_color) color = team_color; } SET_FG(colors[color].pixel); a1 = X(x); b1 = Y(y+BLOCK_SZ); a2 = a1 + BLOCK_SZ; b2 = b1 + BLOCK_SZ; Segment_add(color, a1, b1, a1, b2); Segment_add(color, a2, b1, a2, b2); Segment_add(color, a1, b1, a2, b1); Segment_add(color, a1, b2, a2, b2); rd.drawRectangle(dpy, drawPixmap, gameGC, WINSCALE(X(x+(BLOCK_SZ+2)/4)), WINSCALE(Y(y+3*BLOCK_SZ/4)), UWINSCALE(BLOCK_SZ/2), UWINSCALE(BLOCK_SZ/2)); if (BIT(Setup->mode, TEAM_PLAY)) { s[0] = '0' + team; s[1] = '\0'; size = XTextWidth(gameFont, s, 1); rd.drawString(dpy, drawPixmap, gameGC, WINSCALE(X(x + BLOCK_SZ/2)) - size/2, WINSCALE(Y(y + BLOCK_SZ/2)) + gameFont->ascent/2, s, 1); } if (damage != TARGET_DAMAGE) { size = (damage * BLOCK_SZ) / (TARGET_DAMAGE * 2); a1 = x + size; a2 = y + size; b1 = x + (BLOCK_SZ - size); b2 = y + (BLOCK_SZ - size); Segment_add(RED, X(a1), Y(a2), X(b1), Y(b2)); Segment_add(RED, X(a1), Y(b2), X(b1), Y(a2)); } } void Gui_paint_setup_treasure(int x, int y, int team, bool own) { int color = own ? BLUE : RED; if (BIT(Setup->mode, TEAM_PLAY)) { int team_color = Team_color(team); if (team_color) color = team_color; } if (!texturedObjects) { char s[2]; int size; SET_FG(colors[color].pixel); Segment_add(color, X(x),Y(y), X(x),Y(y + BLOCK_SZ/2)); Segment_add(color, X(x + BLOCK_SZ),Y(y), X(x + BLOCK_SZ), Y(y + BLOCK_SZ/2)); Segment_add(color, X(x),Y(y), X(x + BLOCK_SZ),Y(y)); Arc_add(color, X(x), Y(y + BLOCK_SZ), BLOCK_SZ, BLOCK_SZ, 0, 64*180); if (BIT(Setup->mode, TEAM_PLAY)) { s[1] = '\0'; s[0] = '0' + team; size = XTextWidth(gameFont, s, 1); rd.drawString(dpy, drawPixmap, gameGC, WINSCALE(X(x + BLOCK_SZ/2)) - size/2, WINSCALE(Y(y + 2*BALL_RADIUS)), s, 1); } } else { char s[2]; int size, type; type = own ? BM_HOLDER_FRIEND : BM_HOLDER_ENEMY; Bitmap_paint(drawPixmap, type, WINSCALE(X(x)), WINSCALE(Y(y + BLOCK_SZ)), 0); if (BIT(Setup->mode, TEAM_PLAY)) { SET_FG(colors[color].pixel); s[1] = '\0'; s[0] = '0' + team; size = XTextWidth(gameFont, s, 1); rd.drawString(dpy, drawPixmap, gameGC, WINSCALE(X(x + BLOCK_SZ/2)) - size/2, WINSCALE(Y(y + BALL_RADIUS + 5)), s, 1); } } } void Gui_paint_polygon(int i, int xoff, int yoff) { static XPoint points[10000]; int j, x, y, sindex, width, did_fill; ipos_t ship; xp_polygon_t polygon; polygon_style_t style; bool textured, filled; polygon = polygons[i]; style = polygon_styles[polygon.style]; if (BIT(style.flags, STYLE_INVISIBLE)) return; textured = instruments.texturedWalls && fullColor; filled = instruments.filledWorld; x = xoff * Setup->width; y = yoff * Setup->height; ship.x = WINSCALE(world.x); ship.y = WINSCALE(world.y + ext_view_height); for (j = 0; j < polygon.num_points; j++) { x += polygon.points[j].x; y += polygon.points[j].y; points[j].x = WINSCALE(x) - ship.x; points[j].y = ship.y - WINSCALE(y); } points[j].x = points[0].x; points[j].y = points[0].y; did_fill = 0; if ((filled || textured) && (BIT(style.flags, STYLE_TEXTURED | STYLE_FILLED))) { if (textured && BIT(style.flags, STYLE_TEXTURED)) { xp_bitmap_t *bmp = Bitmap_get(drawPixmap, NUM_BITMAPS + style.texture, 0); if (bmp == NULL) goto notexture; /* Print an error here? */ XSetTile(dpy, gameGC, bmp->bitmap); /* XSetTSOrigin(dpy, gc, -WINSCALE(realWorld.x), WINSCALE(realWorld.y)); */ XSetTSOrigin(dpy, gameGC, WINSCALE(polygon.bounds.x + xoff * Setup->width) - ship.x, ship.y - WINSCALE(polygon.bounds.y + polygon.bounds.h + yoff * Setup->height)); XSetFillStyle(dpy, gameGC, FillTiled); } else { notexture: XSetFillStyle(dpy, gameGC, FillSolid); SET_FG(fullColor ? style.color : colors[wallColor].pixel); } did_fill = 1; rd.fillPolygon(dpy, drawPixmap, gameGC, points, polygon.num_points, Nonconvex, CoordModeOrigin); } XSetFillStyle(dpy, gameGC, FillSolid); sindex = style.def_edge_style; if (polygon.edge_styles == NULL) { /* No special edges */ width = edge_styles[sindex].width; if (width != -1 || !did_fill) { /* did_fill to avoid invisibility */ if (width == -1) width = 0; width = WINSCALE(width); if (width == 1) width = 0; XSetLineAttributes(dpy, gameGC, (unsigned)width, edge_styles[sindex].style, CapButt, JoinMiter); if (fullColor) SET_FG(edge_styles[sindex].color); else SET_FG(colors[wallColor].pixel); rd.drawLines(dpy, drawPixmap, gameGC, points, polygon.num_points + 1, CoordModeOrigin); } } else { /* This polygon has special edges */ int begin; for (j = 0; j < polygon.num_points;) { begin = j; sindex = polygon.edge_styles[j++]; while ((polygon.edge_styles[j] == sindex) && (j < polygon.num_points - 1)) j++; /* Style 0 means internal edges which are never shown */ width = edge_styles[sindex].width; if (sindex != 0 && (edge_styles[sindex].width != -1 || !did_fill)){ if (width == -1) width = 0; width = WINSCALE(width); if (width == 1) width = 0; XSetLineAttributes(dpy, gameGC, (unsigned)width, edge_styles[sindex].style, CapButt, JoinMiter); if (fullColor) SET_FG(edge_styles[sindex].color); else SET_FG(colors[wallColor].pixel); rd.drawLines (dpy, drawPixmap, gameGC, points + begin, j + 1 - begin, CoordModeOrigin); } } } XSetLineAttributes(dpy, gameGC, 0, LineSolid, CapButt, JoinMiter); } xp_option_t guimap_options[] = { COLOR_INDEX_OPTION( "baseNameColor", 2, &baseNameColor, "Which color number to use for drawing names of bases\n" "(unless drawn in one of the life colors).\n"), COLOR_INDEX_OPTION( "backgroundPointColor", 2, &backgroundPointColor, "Which color number to use for drawing background points.\n"), COLOR_INDEX_OPTION( "fuelColor", 3, &fuelColor, "Which color number to use for drawing fuel stations.\n"), COLOR_INDEX_OPTION( "visibilityBorderColor", 2, &visibilityBorderColor, "Which color number to use for drawing the visibility border.\n"), }; void Store_guimap_options(void) { STORE_OPTIONS(guimap_options); }