1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4 
5 This file is part of Shadow Warrior version 1.2
6 
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 #include "build.h"
27 
28 #include "keys.h"
29 #include "names2.h"
30 #include "panel.h"
31 #include "lists.h"
32 #include "game.h"
33 #include "common_game.h"
34 #include "network.h"
35 #include "text.h"
36 
37 #define BAR_HEIGHT 48
38 #define XDIM 320
39 #define YDIM 200
40 
41 short DebugBorderShade = 0;
42 
43 short RegBorderTest[] =
44 {
45     51, 53, 127, 128, 140, 145, 152, 197, 198, 201, 205, 206, 213, 218, 242, 243,
46     245, 246, 247, 257, 2560, 2561, 2562, 2570, 2571, 2572, 2573, 2576, 2578,
47     2579, 2580, 2581, 2582, 2583, 2584, 2585, 2593, 2594
48 };
49 short SWBorderTest[] =
50 {
51     51, 53, 127, 128, 140, 145, 201, 205, 206, 213, 218,
52     245, 2560, 2573, 2576, 2580, 2581, 2582, 2583, 2584, 2593
53 };
54 
55 #undef BORDER_TILE
56 #define BORDER_TILE \
57     (SW_SHAREWARE ? \
58      SWBorderTest[gs.BorderTile % SIZ(SWBorderTest)] : \
59      RegBorderTest[gs.BorderTile % SIZ(RegBorderTest)] \
60     )
61 
62 #define f_320 FIXED(320,0)
63 #define f_200 FIXED(200,0)
64 
65 #define X_TO_FIXED(val) (x_aspect_mul*(val))
66 #define Y_TO_FIXED(val) (y_aspect_mul*(val))
67 
68 SWBOOL RedrawScreen = FALSE;
69 
70 int f_xdim, f_ydim, x_pix_size, y_pix_size, x_aspect_mul, y_aspect_mul;
71 int CrosshairX, CrosshairY;
72 
73 extern SWBOOL BorderAdjust;
74 SWBOOL GlobSpriteBoxUpdateEveryFrame = FALSE;
75 
76 PANEL_SPRITEp
pSpawnFullScreenSpriteBox(PLAYERp pp,short id,short pic,short pri,int x,int y,short x1,short y1,short x2,short y2)77 pSpawnFullScreenSpriteBox(PLAYERp pp, short id, short pic, short pri, int x, int y, short x1, short y1, short x2, short y2)
78 {
79     PANEL_SPRITEp psp;
80 
81     psp = pSpawnSprite(pp, NULL, pri, x, y);
82 
83     psp->ID = id;
84     psp->numpages = numpages;
85     if (GlobSpriteBoxUpdateEveryFrame)
86     {
87         psp->numpages = 1;
88     }
89     psp->picndx = -1;
90     psp->picnum = pic;
91     psp->x1 = x1;
92     psp->y1 = y1;
93     psp->x2 = x2;
94     psp->y2 = y2;
95     psp->shade = DebugBorderShade;
96 
97     //SET(psp->flags, PANF_STATUS_AREA | PANF_KILL_AFTER_SHOW | PANF_IGNORE_START_MOST  | PANF_DRAW_BEFORE_VIEW | PANF_NOT_ALL_PAGES);
98     SET(psp->flags, PANF_STATUS_AREA | PANF_KILL_AFTER_SHOW | PANF_IGNORE_START_MOST | PANF_DRAW_BEFORE_VIEW);
99     //extern SWBOOL DrawBeforeView;
100     //DrawBeforeView = TRUE;
101 
102     //SET(psp->flags, PANF_SCREEN_CLIP | PANF_KILL_AFTER_SHOW | PANF_IGNORE_START_MOST);
103 
104     return psp;
105 }
106 
SetCrosshair(void)107 void SetCrosshair(void)
108 {
109     int wdx,wdy,x,y;
110 
111     wdx = ((windowxy2.x-windowxy1.x)/2);
112     wdy = ((windowxy2.y-windowxy1.y)/2);
113     x = windowxy1.x + wdx;
114     y = windowxy1.y + wdy;
115 
116     CrosshairX = x / (xdim/320.0);
117     CrosshairY = y / (ydim/200.0);
118 
119     // rotatesprite takes FIXED point number
120     CrosshairX <<= 16;
121     CrosshairY <<= 16;
122 }
123 
124 
125 void
SetupAspectRatio(void)126 SetupAspectRatio(void)
127 {
128     f_xdim = FIXED(xdim, 0);
129     f_ydim = FIXED(ydim, 0);
130 
131     x_pix_size = (f_320 / xdim);
132     y_pix_size = (f_200 / ydim);
133 
134     x_aspect_mul = (f_xdim / 320);
135     y_aspect_mul = (f_ydim / 200);
136 }
137 
138 void
SetConsoleDmost(void)139 SetConsoleDmost(void)
140 {
141     int ystart;
142 
143     int i;
144     int adj=0;
145 
146     // dont setup the startumost/dmost arrays if border is 0
147     if (gs.BorderNum == BORDER_NONE || gs.BorderNum == BORDER_MINI_BAR)
148         return;
149 
150     //
151     // Set the whole thing to the size of the bar
152     //
153 
154     ystart = f_ydim - Y_TO_FIXED(BAR_HEIGHT);
155 
156     if (ydim == 480 && gs.BorderNum == 2)
157         adj = 1;
158 
159     //for (i = FIXED(0, 0); i < f_320; i += x_pix_size)
160     for (i = 0; i < xdim; i++)
161     // define picture
162     // boundaries
163     {
164         startdmost[i] = MSW(ystart) + adj;
165     }
166 }
167 
ClearStartMost(void)168 void ClearStartMost(void)
169 {
170     int i;
171 
172     for (i = 0; i < xdim; i++)
173         startdmost[i] = ydim;
174 
175     memset(startumost, 0, xdim * sizeof(int16_t));
176 }
177 
178 void
SetFragBar(PLAYERp pp)179 SetFragBar(PLAYERp pp)
180 {
181     short i, num_frag_bars;
182     int y;
183     extern int16_t OrigCommPlayers;
184 
185     if (numplayers <= 1)
186         return;
187 
188     if (gNet.MultiGameType == MULTI_GAME_COOPERATIVE)
189         return;
190 
191     // if player sprite has not been initialized we have no business
192     // sticking a frag bar up.  Prevents processing from MenuLevel etc.
193     if (!pp->SpriteP)
194         return;
195 
196     //num_frag_bars = ((numplayers-1)/4)+1;
197     num_frag_bars = ((OrigCommPlayers-1)/4)+1;
198 
199     for (i = windowxy1.x; i <= windowxy2.x; i++)
200     {
201         y = (tilesiz[FRAG_BAR].y * num_frag_bars) - (2 * (num_frag_bars-1));
202         y = y * (ydim/200.0);
203 
204         if (windowxy1.y < y)
205             startumost[i] = y;
206     }
207 
208     for (i = 0, y = 0; i < num_frag_bars; i++)
209     {
210         pSpawnFullScreenSprite(pp, FRAG_BAR, PRI_MID, 0, y);
211         y += tilesiz[FRAG_BAR].y - 2;
212     }
213 
214     // write each persons kill info to everybody
215     // for (i = 0; i < numplayers; i++)
216     TRAVERSE_CONNECT(i)
217     {
218         PlayerUpdateKills(Player + i, 0);
219         DisplayFragNames(Player + i);
220     }
221 }
222 
RectOverlap(short tx1,short ty1,short bx1,short by1,short tx2,short ty2,short bx2,short by2)223 SWBOOL RectOverlap(short tx1, short ty1, short bx1, short by1, short tx2, short ty2, short bx2, short by2)
224 {
225     if (bx1 >= tx2)
226         if (tx1 <= bx2)
227             if (ty1 <= by2)
228                 if (by1 >= ty2)
229                     return TRUE;
230 
231     return FALSE;
232 }
233 
DrawBorderShade(PLAYERp pp,short shade_num,short wx1,short wy1,short wx2,short wy2)234 void DrawBorderShade(PLAYERp pp, short shade_num, short wx1, short wy1, short wx2, short wy2)
235 {
236     short i,j,k,l;
237     PANEL_SPRITEp psp;
238     int dark_shade = 27 - (shade_num * 6);
239     int light_shade = 20 - (shade_num * 6);
240 
241     for (i = 0; i < xdim; i += tilesiz[BORDER_TILE].x)
242     {
243         for (j = 0; j < ydim; j += tilesiz[BORDER_TILE].y)
244         {
245             k = i + tilesiz[BORDER_TILE].x;
246             l = j + tilesiz[BORDER_TILE].y;
247 
248             if (RectOverlap(i, j, k, l, wx1 - 1, wy1 - 1, wx2 + 1, wy1))
249             {
250                 // draw top box of the border
251                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_TOP, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy1 - 1, wx2 + 1, wy1);
252                 psp->shade = dark_shade;
253                 psp->ID = ID_BORDER_SHADE;
254             }
255 
256             if (RectOverlap(i, j, k, l, wx1 - 1, wy2, wx2 + 1, wy2 + 1))
257             {
258                 // draw bottom box of the border
259                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_BOTTOM, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy2, wx2 + 1, wy2 + 1);
260                 psp->shade = light_shade;
261                 psp->ID = ID_BORDER_SHADE;
262             }
263             if (RectOverlap(i, j, k, l, wx1 - 1, wy1 - 1, wx1, wy2 + 1))
264             {
265                 // draw left box of the border
266                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_LEFT, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy1 - 1, wx1, wy2 + 1);
267                 psp->shade = dark_shade;
268                 psp->ID = ID_BORDER_SHADE;
269             }
270             if (RectOverlap(i, j, k, l, wx2, wy1 - 1, wx2 + 1, wy2 + 1))
271             {
272                 // draw right box of the border
273                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_RIGHT, BORDER_TILE, PRI_BACK + 1, i, j, wx2, wy1 - 1, wx2 + 1, wy2 + 1);
274                 psp->shade = light_shade;
275                 psp->ID = ID_BORDER_SHADE;
276             }
277         }
278     }
279 }
280 
281 void
BorderShade(PLAYERp pp,SWBOOL refresh)282 BorderShade(PLAYERp pp, SWBOOL refresh)
283 {
284     int wx1, wx2, wy1, wy2;
285     uint8_t lines;
286 
287     wx1 = windowxy1.x - 1;
288     wy1 = windowxy1.y - 1;
289     wx2 = windowxy2.x + 1;
290     wy2 = windowxy2.y + 1;
291 
292     for (lines = 0; lines < 4; lines++)
293     {
294 
295         // make sure that these values dont go out of bound - which they do
296         wx1 = max(wx1, 0);
297         wx2 = min(wx2, xdim - 1);
298         wy1 = max(wy1, 0);
299 
300         if (refresh)
301         {
302             // silly thing seems off by 1
303             wy2 = min(wy2, ydim - (Y_TO_FIXED(BAR_HEIGHT) >> 16) - 2);
304         }
305         else
306         {
307             if (gs.BorderNum >= BORDER_BAR+1 && gs.BorderNum <= BORDER_BAR+2)
308                 wy2 = min(wy2, ydim - 1);
309             else
310                 wy2 = min(wy2, ydim - (Y_TO_FIXED(BAR_HEIGHT) >> 16) - 1);
311         }
312 
313         DrawBorderShade(pp, lines, wx1, wy1, wx2, wy2);
314         // increase view size by one - dont do a set view though
315         wx1--;
316         wy1--;
317         wx2++;
318         wy2++;
319     }
320 }
321 
322 
323 BORDER_INFO BorderInfoValues[] =
324 {
325     // x,y,screensize
326     {0, 0, 0},
327     {0, 0, 0},
328     {0, BAR_HEIGHT, 0},
329 
330     {0, BAR_HEIGHT, (1 * 16)},
331     {0, BAR_HEIGHT, (2 * 16)},
332     {0, BAR_HEIGHT, (3 * 16)},
333     {0, BAR_HEIGHT, (4 * 16)},
334     {0, BAR_HEIGHT, (5 * 16)},
335     {0, BAR_HEIGHT, (6 * 16)},
336     {0, BAR_HEIGHT, (7 * 16)},
337     {0, BAR_HEIGHT, (8 * 16)},
338     {0, BAR_HEIGHT, (9 * 16)},
339     {0, BAR_HEIGHT, (10 * 16)},
340     {0, BAR_HEIGHT, (11 * 16)},
341     {0, BAR_HEIGHT, (12 * 16)}
342 };
343 
344 
DrawBorder(PLAYERp pp,short x,short y,short x2,short y2)345 void DrawBorder(PLAYERp pp, short x, short y, short x2, short y2)
346 {
347     short i,j,k,l;
348     short count = 0;
349 
350     for (i = 0; i < xdim; i += tilesiz[BORDER_TILE].x)
351     {
352         for (j = 0; j < ydim; j += tilesiz[BORDER_TILE].y)
353         {
354             k = i + tilesiz[BORDER_TILE].x;
355             l = j + tilesiz[BORDER_TILE].y;
356 
357             if (RectOverlap(i, j, k, l, x, y, windowxy1.x-1, y2))
358             {
359                 // draw top box of the border
360                 pSpawnFullScreenSpriteBox(pp, ID_BORDER_TOP, BORDER_TILE, PRI_BACK, i, j, x, y, windowxy1.x-1, y2);
361                 count++;
362             }
363 
364             if (RectOverlap(i, j, k, l, windowxy2.x+1, y, x2, y2))
365             {
366                 // draw bottom box of the border
367                 pSpawnFullScreenSpriteBox(pp, ID_BORDER_BOTTOM, BORDER_TILE, PRI_BACK, i, j, windowxy2.x+1, y, x2, y2);
368                 count++;
369             }
370 
371             if (RectOverlap(i, j, k, l, windowxy1.x, y, windowxy2.x, windowxy1.y-1))
372             {
373                 // draw left box of the border
374                 pSpawnFullScreenSpriteBox(pp, ID_BORDER_LEFT, BORDER_TILE, PRI_BACK, i, j, windowxy1.x, y, windowxy2.x, windowxy1.y-1);
375                 count++;
376             }
377 
378             if (RectOverlap(i, j, k, l, windowxy1.x, windowxy2.y+1, windowxy2.x, y2))
379             {
380                 // draw right box of the border
381                 pSpawnFullScreenSpriteBox(pp, ID_BORDER_RIGHT, BORDER_TILE, PRI_BACK, i, j, windowxy1.x, windowxy2.y+1, windowxy2.x, y2);
382                 count++;
383             }
384         }
385     }
386 }
387 
DrawPanelBorderSides(PLAYERp pp,short x,short y,short x2,short y2,short panl,short panr)388 void DrawPanelBorderSides(PLAYERp pp, short x, short y, short x2, short y2, short panl, short panr)
389 {
390     short i,j,k,l;
391     short count = 0;
392 
393     for (i = 0; i < xdim; i += tilesiz[BORDER_TILE].x)
394     {
395         for (j = 0; j < ydim; j += tilesiz[BORDER_TILE].y)
396         {
397             k = i + tilesiz[BORDER_TILE].x;
398             l = j + tilesiz[BORDER_TILE].y;
399 
400             if (RectOverlap(i, j, k, l, x, y, panl, y2))
401             {
402                 pSpawnFullScreenSpriteBox(pp, ID_PANEL_BORDER_LEFT, BORDER_TILE, PRI_BACK, i, j, x, y, panl, y2);
403                 count++;
404             }
405 
406             if (RectOverlap(i, j, k, l, panr, y, x2, y2))
407             {
408                 pSpawnFullScreenSpriteBox(pp, ID_PANEL_BORDER_RIGHT, BORDER_TILE, PRI_BACK, i, j, panr, y, x2, y2);
409                 count++;
410             }
411         }
412     }
413 }
414 
415 static
BorderSetView(PLAYERp UNUSED (pp),int * Xdim,int * Ydim,int * ScreenSize)416 void BorderSetView(PLAYERp UNUSED(pp), int *Xdim, int *Ydim, int *ScreenSize)
417 {
418     int x, x2, y, y2;
419     BORDER_INFO *b;
420 
421     BorderInfo = BorderInfoValues[gs.BorderNum];
422 
423     b = &BorderInfo;
424 
425     // figure out the viewing window x and y dimensions
426     *Xdim = MSW(f_xdim - X_TO_FIXED(b->Xdim));
427     *Ydim = MSW(f_ydim - Y_TO_FIXED(b->Ydim));
428     *ScreenSize = MSW(f_xdim - X_TO_FIXED(b->ScreenSize));
429 
430     // figure out the viewing window x and y coordinates
431     x = DIV2(*Xdim) - DIV2(*ScreenSize);
432     x2 = x + *ScreenSize - 1;
433     y = DIV2(*Ydim) - DIV2((*ScreenSize **Ydim) / *Xdim);
434     y2 = y + ((*ScreenSize **Ydim) / *Xdim) - 1;
435 
436     // avoid a one-pixel tall HOM
437     if (gs.BorderNum == BORDER_BAR)
438         ++y2;
439 
440     // global windowxy1, windowxy2 coords set here
441     videoSetViewableArea(x, y, x2, y2);
442     SetCrosshair();
443 }
444 
445 //
446 // Redraw the border without changing the view
447 //
448 
449 static void
BorderRefresh(PLAYERp pp)450 BorderRefresh(PLAYERp pp)
451 {
452     int x, x2, y, y2;
453     BORDER_INFO *b;
454 
455     if (pp != Player + myconnectindex)
456         return;
457 
458     if (!BorderAdjust)
459         return;
460 
461     if (gs.BorderNum < BORDER_BAR)
462         return;
463 
464     // Redraw the BORDER_TILE only if getting smaller
465     BorderInfo = BorderInfoValues[gs.BorderNum];
466 
467     b = &BorderInfo;
468 
469     // A refresh does not change the view size so we dont need to do a
470     // setview
471     // We don't need the calculations for the border drawing boxes - its
472     // the whole screen
473     // minus the border if necessary
474 
475     // fill in the sides of the panel when the screen is wide
476     if (gs.BorderNum >= BORDER_BAR && r_usenewaspect)
477     {
478         const int sidew = (xdim - scale(4, ydim, 3)) / 2;
479 
480         x = 0;
481         x2 = xdim - 1;
482 
483         y = ydim - (Y_TO_FIXED(b->Ydim) >> 16);
484         y2 = ydim - 1;
485 
486         DrawPanelBorderSides(pp, x, y, x2, y2, sidew, xdim-sidew);
487     }
488 
489     // only need a border if border is > BORDER_BAR
490     if (gs.BorderNum > BORDER_BAR)
491     {
492         // make sure that these values dont go out of bound - which they do
493         x = 0;
494         x2 = xdim - 1;
495 
496         y = 0;
497         y2 = ydim - (Y_TO_FIXED(b->Ydim) >> 16) - 1;
498 
499         DrawBorder(pp, x, y, x2, y2);
500 
501         // kill ALL outstanding (not yet drawn) border shade sprites before
502         // doing more shading
503         pKillScreenSpiteIDs(pp, ID_BORDER_SHADE);
504 
505         BorderShade(pp, TRUE);
506     }
507 }
508 
509 //
510 // Redraw the whole screen
511 //
512 
SetBorder(PLAYERp pp,int value)513 void SetBorder(PLAYERp pp, int value)
514 {
515     int Xdim, Ydim, ScreenSize;
516 
517     if (pp != Player + myconnectindex)
518         return;
519 
520     if (!BorderAdjust)
521         return;
522 
523     if (value >= 0) // just refresh
524         gs.BorderNum = value;
525 
526     if (gs.BorderNum < BORDER_NONE)
527     {
528         gs.BorderNum = BORDER_NONE;
529         //return;
530     }
531 
532     if (gs.BorderNum > (int)SIZ(BorderInfoValues) - 1)
533     {
534         gs.BorderNum = SIZ(BorderInfoValues) - 1;
535         return;
536     }
537 
538     BorderSetView(pp, &Xdim, &Ydim, &ScreenSize);
539 
540     if (gs.BorderNum >= BORDER_BAR)
541     {
542         BorderRefresh(pp);
543 
544         if (gs.BorderNum == BORDER_BAR)
545             SetConsoleDmost();
546 
547         pSpawnFullScreenSprite(pp, STATUS_BAR, PRI_FRONT, 0, 200 - tilesiz[STATUS_BAR].y);
548         PlayerUpdatePanelInfo(Player + screenpeek);
549     }
550 
551     SetFragBar(pp);
552 }
553 
554 void
SetRedrawScreen(PLAYERp pp)555 SetRedrawScreen(PLAYERp pp)
556 {
557     //int x, x2, y, y2;
558 
559     if (pp != Player + myconnectindex)
560         return;
561 
562     if (!BorderAdjust)
563         return;
564 
565     if (gs.BorderNum < BORDER_NONE)
566         gs.BorderNum = BORDER_NONE;
567 
568     // Redraw the BORDER_TILE only if getting smaller
569     BorderInfo = BorderInfoValues[gs.BorderNum];
570 
571     // test at redrawing the whole screen
572     RedrawScreen = TRUE;
573 }
574 
575