//------------------------------------------------------------------------- /* Copyright (C) 1997, 2005 - 3D Realms Entertainment This file is part of Shadow Warrior version 1.2 Shadow Warrior 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Original Source: 1997 - Frank Maddin and Jim Norwood Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms */ //------------------------------------------------------------------------- #include "ns.h" #include "build.h" #include "keys.h" #include "names2.h" #include "panel.h" #include "lists.h" #include "game.h" #include "common_game.h" #include "network.h" #include "text.h" #include "menus.h" BEGIN_SW_NS #define BAR_HEIGHT 48 #define XDIM 320 #define YDIM 200 short DebugBorderShade = 0; short RegBorderTest[] = { 51, 53, 127, 128, 140, 145, 152, 197, 198, 201, 205, 206, 213, 218, 242, 243, 245, 246, 247, 257, 2560, 2561, 2562, 2570, 2571, 2572, 2573, 2576, 2578, 2579, 2580, 2581, 2582, 2583, 2584, 2585, 2593, 2594 }; short SWBorderTest[] = { 51, 53, 127, 128, 140, 145, 201, 205, 206, 213, 218, 245, 2560, 2573, 2576, 2580, 2581, 2582, 2583, 2584, 2593 }; #undef BORDER_TILE #define BORDER_TILE \ (isShareware ? \ SWBorderTest[gs.BorderTile % SIZ(SWBorderTest)] : \ RegBorderTest[gs.BorderTile % SIZ(RegBorderTest)] \ ) #define f_320 FIXED(320,0) #define f_200 FIXED(200,0) #define X_TO_FIXED(val) (x_aspect_mul*(val)) #define Y_TO_FIXED(val) (y_aspect_mul*(val)) SWBOOL RedrawScreen = FALSE; int f_xdim, f_ydim, x_pix_size, y_pix_size, x_aspect_mul, y_aspect_mul; int CrosshairX, CrosshairY; extern SWBOOL BorderAdjust; SWBOOL GlobSpriteBoxUpdateEveryFrame = FALSE; PANEL_SPRITEp pSpawnFullScreenSpriteBox(PLAYERp pp, short id, short pic, short pri, int x, int y, short x1, short y1, short x2, short y2) { PANEL_SPRITEp psp; psp = pSpawnSprite(pp, NULL, pri, x, y); psp->ID = id; psp->numpages = numpages; if (GlobSpriteBoxUpdateEveryFrame) { psp->numpages = 1; } psp->picndx = -1; psp->picnum = pic; psp->x1 = x1; psp->y1 = y1; psp->x2 = x2; psp->y2 = y2; psp->shade = DebugBorderShade; //SET(psp->flags, PANF_STATUS_AREA | PANF_KILL_AFTER_SHOW | PANF_IGNORE_START_MOST | PANF_DRAW_BEFORE_VIEW | PANF_NOT_ALL_PAGES); SET(psp->flags, PANF_STATUS_AREA | PANF_KILL_AFTER_SHOW | PANF_IGNORE_START_MOST | PANF_DRAW_BEFORE_VIEW); //extern SWBOOL DrawBeforeView; //DrawBeforeView = TRUE; //SET(psp->flags, PANF_SCREEN_CLIP | PANF_KILL_AFTER_SHOW | PANF_IGNORE_START_MOST); return psp; } void SetCrosshair(void) { int wdx,wdy,x,y; wdx = ((windowxy2.x-windowxy1.x)/2); wdy = ((windowxy2.y-windowxy1.y)/2); x = windowxy1.x + wdx; y = windowxy1.y + wdy; CrosshairX = x / (xdim/320.0); CrosshairY = y / (ydim/200.0); // rotatesprite takes FIXED point number CrosshairX <<= 16; CrosshairY <<= 16; } void SetupAspectRatio(void) { f_xdim = FIXED(xdim, 0); f_ydim = FIXED(ydim, 0); x_pix_size = (f_320 / xdim); y_pix_size = (f_200 / ydim); x_aspect_mul = (f_xdim / 320); y_aspect_mul = (f_ydim / 200); } void SetConsoleDmost(void) { int ystart; int i; int adj=0; // dont setup the startumost/dmost arrays if border is 0 if (gs.BorderNum == BORDER_NONE || gs.BorderNum == BORDER_MINI_BAR) return; // // Set the whole thing to the size of the bar // ystart = f_ydim - Y_TO_FIXED(BAR_HEIGHT); if (ydim == 480 && gs.BorderNum == 2) adj = 1; //for (i = FIXED(0, 0); i < f_320; i += x_pix_size) for (i = 0; i < xdim; i++) // define picture // boundaries { startdmost[i] = MSW(ystart) + adj; } } void ClearStartMost(void) { int i; for (i = 0; i < xdim; i++) startdmost[i] = ydim; memset(startumost.Data(), 0, xdim * sizeof(int16_t)); } void SetFragBar(PLAYERp pp) { short i, num_frag_bars; int y; extern int16_t OrigCommPlayers; if (numplayers <= 1) return; if (gNet.MultiGameType == MULTI_GAME_COOPERATIVE) return; // if player sprite has not been initialized we have no business // sticking a frag bar up. Prevents processing from MenuLevel etc. if (!pp->SpriteP) return; //num_frag_bars = ((numplayers-1)/4)+1; num_frag_bars = ((OrigCommPlayers-1)/4)+1; for (i = windowxy1.x; i <= windowxy2.x; i++) { y = (tilesiz[FRAG_BAR].y * num_frag_bars) - (2 * (num_frag_bars-1)); y = y * (ydim/200.0); if (windowxy1.y < y) startumost[i] = y; } for (i = 0, y = 0; i < num_frag_bars; i++) { pSpawnFullScreenSprite(pp, FRAG_BAR, PRI_MID, 0, y); y += tilesiz[FRAG_BAR].y - 2; } // write each persons kill info to everybody // for (i = 0; i < numplayers; i++) TRAVERSE_CONNECT(i) { PlayerUpdateKills(Player + i, 0); DisplayFragNames(Player + i); } } SWBOOL RectOverlap(short tx1, short ty1, short bx1, short by1, short tx2, short ty2, short bx2, short by2) { if (bx1 >= tx2) if (tx1 <= bx2) if (ty1 <= by2) if (by1 >= ty2) return TRUE; return FALSE; } void DrawBorderShade(PLAYERp pp, short shade_num, short wx1, short wy1, short wx2, short wy2) { short i,j,k,l; PANEL_SPRITEp psp; int dark_shade = 27 - (shade_num * 6); int light_shade = 20 - (shade_num * 6); for (i = 0; i < xdim; i += tilesiz[BORDER_TILE].x) { for (j = 0; j < ydim; j += tilesiz[BORDER_TILE].y) { k = i + tilesiz[BORDER_TILE].x; l = j + tilesiz[BORDER_TILE].y; if (RectOverlap(i, j, k, l, wx1 - 1, wy1 - 1, wx2 + 1, wy1)) { // draw top box of the border psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_TOP, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy1 - 1, wx2 + 1, wy1); psp->shade = dark_shade; psp->ID = ID_BORDER_SHADE; } if (RectOverlap(i, j, k, l, wx1 - 1, wy2, wx2 + 1, wy2 + 1)) { // draw bottom box of the border psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_BOTTOM, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy2, wx2 + 1, wy2 + 1); psp->shade = light_shade; psp->ID = ID_BORDER_SHADE; } if (RectOverlap(i, j, k, l, wx1 - 1, wy1 - 1, wx1, wy2 + 1)) { // draw left box of the border psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_LEFT, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy1 - 1, wx1, wy2 + 1); psp->shade = dark_shade; psp->ID = ID_BORDER_SHADE; } if (RectOverlap(i, j, k, l, wx2, wy1 - 1, wx2 + 1, wy2 + 1)) { // draw right box of the border psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_RIGHT, BORDER_TILE, PRI_BACK + 1, i, j, wx2, wy1 - 1, wx2 + 1, wy2 + 1); psp->shade = light_shade; psp->ID = ID_BORDER_SHADE; } } } } void BorderShade(PLAYERp pp, SWBOOL refresh) { int wx1, wx2, wy1, wy2; uint8_t lines; wx1 = windowxy1.x - 1; wy1 = windowxy1.y - 1; wx2 = windowxy2.x + 1; wy2 = windowxy2.y + 1; for (lines = 0; lines < 4; lines++) { // make sure that these values dont go out of bound - which they do wx1 = max(wx1, 0); wx2 = min(wx2, xdim - 1); wy1 = max(wy1, 0); if (refresh) { // silly thing seems off by 1 wy2 = min(wy2, ydim - (Y_TO_FIXED(BAR_HEIGHT) >> 16) - 2); } else { if (gs.BorderNum >= BORDER_BAR+1 && gs.BorderNum <= BORDER_BAR+2) wy2 = min(wy2, ydim - 1); else wy2 = min(wy2, ydim - (Y_TO_FIXED(BAR_HEIGHT) >> 16) - 1); } DrawBorderShade(pp, lines, wx1, wy1, wx2, wy2); // increase view size by one - dont do a set view though wx1--; wy1--; wx2++; wy2++; } } BORDER_INFO BorderInfoValues[] = { // x,y,screensize {0, 0, 0}, {0, 0, 0}, {0, BAR_HEIGHT, 0}, {0, BAR_HEIGHT, (1 * 16)}, {0, BAR_HEIGHT, (2 * 16)}, {0, BAR_HEIGHT, (3 * 16)}, {0, BAR_HEIGHT, (4 * 16)}, {0, BAR_HEIGHT, (5 * 16)}, {0, BAR_HEIGHT, (6 * 16)}, {0, BAR_HEIGHT, (7 * 16)}, {0, BAR_HEIGHT, (8 * 16)}, {0, BAR_HEIGHT, (9 * 16)}, {0, BAR_HEIGHT, (10 * 16)}, {0, BAR_HEIGHT, (11 * 16)}, {0, BAR_HEIGHT, (12 * 16)} }; void DrawBorder(PLAYERp pp, short x, short y, short x2, short y2) { short i,j,k,l; short count = 0; for (i = 0; i < xdim; i += tilesiz[BORDER_TILE].x) { for (j = 0; j < ydim; j += tilesiz[BORDER_TILE].y) { k = i + tilesiz[BORDER_TILE].x; l = j + tilesiz[BORDER_TILE].y; if (RectOverlap(i, j, k, l, x, y, windowxy1.x-1, y2)) { // draw top box of the border pSpawnFullScreenSpriteBox(pp, ID_BORDER_TOP, BORDER_TILE, PRI_BACK, i, j, x, y, windowxy1.x-1, y2); count++; } if (RectOverlap(i, j, k, l, windowxy2.x+1, y, x2, y2)) { // draw bottom box of the border pSpawnFullScreenSpriteBox(pp, ID_BORDER_BOTTOM, BORDER_TILE, PRI_BACK, i, j, windowxy2.x+1, y, x2, y2); count++; } if (RectOverlap(i, j, k, l, windowxy1.x, y, windowxy2.x, windowxy1.y-1)) { // draw left box of the border pSpawnFullScreenSpriteBox(pp, ID_BORDER_LEFT, BORDER_TILE, PRI_BACK, i, j, windowxy1.x, y, windowxy2.x, windowxy1.y-1); count++; } if (RectOverlap(i, j, k, l, windowxy1.x, windowxy2.y+1, windowxy2.x, y2)) { // draw right box of the border pSpawnFullScreenSpriteBox(pp, ID_BORDER_RIGHT, BORDER_TILE, PRI_BACK, i, j, windowxy1.x, windowxy2.y+1, windowxy2.x, y2); count++; } } } } void DrawPanelBorderSides(PLAYERp pp, short x, short y, short x2, short y2, short panl, short panr) { short i,j,k,l; short count = 0; for (i = 0; i < xdim; i += tilesiz[BORDER_TILE].x) { for (j = 0; j < ydim; j += tilesiz[BORDER_TILE].y) { k = i + tilesiz[BORDER_TILE].x; l = j + tilesiz[BORDER_TILE].y; if (RectOverlap(i, j, k, l, x, y, panl, y2)) { pSpawnFullScreenSpriteBox(pp, ID_PANEL_BORDER_LEFT, BORDER_TILE, PRI_BACK, i, j, x, y, panl, y2); count++; } if (RectOverlap(i, j, k, l, panr, y, x2, y2)) { pSpawnFullScreenSpriteBox(pp, ID_PANEL_BORDER_RIGHT, BORDER_TILE, PRI_BACK, i, j, panr, y, x2, y2); count++; } } } } static void BorderSetView(PLAYERp, int *Xdim, int *Ydim, int *ScreenSize) { int x, x2, y, y2; BORDER_INFO *b; BorderInfo = BorderInfoValues[gs.BorderNum]; b = &BorderInfo; // figure out the viewing window x and y dimensions *Xdim = MSW(f_xdim - X_TO_FIXED(b->Xdim)); *Ydim = MSW(f_ydim - Y_TO_FIXED(b->Ydim)); *ScreenSize = MSW(f_xdim - X_TO_FIXED(b->ScreenSize)); // figure out the viewing window x and y coordinates x = DIV2(*Xdim) - DIV2(*ScreenSize); x2 = x + *ScreenSize - 1; y = DIV2(*Ydim) - DIV2((*ScreenSize **Ydim) / *Xdim); y2 = y + ((*ScreenSize **Ydim) / *Xdim) - 1; // avoid a one-pixel tall HOM if (gs.BorderNum == BORDER_BAR) ++y2; // global windowxy1, windowxy2 coords set here videoSetViewableArea(x, y, x2, y2); SetCrosshair(); } // // Redraw the border without changing the view // static void BorderRefresh(PLAYERp pp) { int x, x2, y, y2; BORDER_INFO *b; if (pp != Player + myconnectindex) return; if (!BorderAdjust) return; if (gs.BorderNum < BORDER_BAR) return; // Redraw the BORDER_TILE only if getting smaller BorderInfo = BorderInfoValues[gs.BorderNum]; b = &BorderInfo; // A refresh does not change the view size so we dont need to do a // setview // We don't need the calculations for the border drawing boxes - its // the whole screen // minus the border if necessary // fill in the sides of the panel when the screen is wide if (gs.BorderNum >= BORDER_BAR && r_usenewaspect) { const int sidew = (xdim - scale(4, ydim, 3)) / 2; x = 0; x2 = xdim - 1; y = ydim - (Y_TO_FIXED(b->Ydim) >> 16); y2 = ydim - 1; DrawPanelBorderSides(pp, x, y, x2, y2, sidew, xdim-sidew); } // only need a border if border is > BORDER_BAR if (gs.BorderNum > BORDER_BAR) { // make sure that these values dont go out of bound - which they do x = 0; x2 = xdim - 1; y = 0; y2 = ydim - (Y_TO_FIXED(b->Ydim) >> 16) - 1; DrawBorder(pp, x, y, x2, y2); // kill ALL outstanding (not yet drawn) border shade sprites before // doing more shading pKillScreenSpiteIDs(pp, ID_BORDER_SHADE); BorderShade(pp, TRUE); } } // // Redraw the whole screen // void SetBorder(PLAYERp pp, int value) { int Xdim, Ydim, ScreenSize; if (pp != Player + myconnectindex) return; if (!BorderAdjust) return; if (value >= 0) // just refresh gs.BorderNum = value; if (gs.BorderNum < BORDER_NONE) { gs.BorderNum = BORDER_NONE; //return; } if (gs.BorderNum > (int)SIZ(BorderInfoValues) - 1) { gs.BorderNum = SIZ(BorderInfoValues) - 1; return; } if (xdim == 0) return; // game not set up yet. BorderSetView(pp, &Xdim, &Ydim, &ScreenSize); if (gs.BorderNum >= BORDER_BAR) { BorderRefresh(pp); if (gs.BorderNum == BORDER_BAR) SetConsoleDmost(); pSpawnFullScreenSprite(pp, STATUS_BAR, PRI_FRONT, 0, 200 - tilesiz[STATUS_BAR].y); PlayerUpdatePanelInfo(Player + screenpeek); } SetFragBar(pp); } void SetRedrawScreen(PLAYERp pp) { if (pp != Player + myconnectindex) return; if (!BorderAdjust) return; if (gs.BorderNum < BORDER_NONE) gs.BorderNum = BORDER_NONE; // Redraw the BORDER_TILE only if getting smaller BorderInfo = BorderInfoValues[gs.BorderNum]; // test at redrawing the whole screen RedrawScreen = TRUE; } END_SW_NS