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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 "mathutil.h"
34 #include "net.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 	(isShareware ? \
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 BOOL 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 BOOL BorderAdjust;
74 BOOL 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     extern BOOL DrawBeforeView;
81 
82     psp = pSpawnSprite(pp, NULL, pri, x, y);
83 
84     psp->ID = id;
85     psp->numpages = numpages;
86     if (GlobSpriteBoxUpdateEveryFrame)
87         {
88         psp->numpages = 1;
89         }
90     psp->picndx = -1;
91     psp->picnum = pic;
92     psp->x1 = x1;
93     psp->y1 = y1;
94     psp->x2 = x2;
95     psp->y2 = y2;
96     psp->shade = DebugBorderShade;
97 
98     //SET(psp->flags, PANF_STATUS_AREA | PANF_KILL_AFTER_SHOW | PANF_IGNORE_START_MOST  | PANF_DRAW_BEFORE_VIEW | PANF_NOT_ALL_PAGES);
99     SET(psp->flags, PANF_STATUS_AREA | PANF_KILL_AFTER_SHOW | PANF_IGNORE_START_MOST | PANF_DRAW_BEFORE_VIEW);
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 = ((windowx2-windowx1)/2);
112     wdy = ((windowy2-windowy1)/2);
113     x = windowx1 + wdx;
114     y = windowy1 + 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     int xstart;
143 
144     int i;
145     int adj=0;
146 
147     // dont setup the startumost/dmost arrays if border is 0
148     if (gs.BorderNum == BORDER_NONE || gs.BorderNum == BORDER_MINI_BAR)
149         return;
150 
151     //
152     // Set the whole thing to the size of the bar
153     //
154 
155     ystart = f_ydim - Y_TO_FIXED(BAR_HEIGHT);
156 
157     if (ydim == 480 && gs.BorderNum == 2)
158         adj = 1;
159 
160     //for (i = FIXED(0, 0); i < f_320; i += x_pix_size)
161     for (i = 0; i < xdim; i++)
162         // define picture
163         // boundaries
164         {
165         startdmost[i] = MSW(ystart) + adj;
166         }
167     }
168 
ClearStartMost(VOID)169 VOID ClearStartMost(VOID)
170     {
171     int i;
172 
173     for (i = 0; i < xdim; i++)
174         startdmost[i] = ydim;
175 
176     memset(startumost, 0, sizeof(startumost));
177     }
178 
179 VOID
SetFragBar(PLAYERp pp)180 SetFragBar(PLAYERp pp)
181     {
182     short i, num_frag_bars;
183     int y;
184     extern SHORT OrigCommPlayers;
185     PANEL_SPRITEp psp;
186 
187     if (CommPlayers <= 1)
188         return;
189 
190     if (gNet.MultiGameType == MULTI_GAME_COOPERATIVE)
191         return;
192 
193     // if player sprite has not been initialized we have no business
194     // sticking a frag bar up.  Prevents processing from MenuLevel etc.
195     if (!pp->SpriteP)
196         return;
197 
198     num_frag_bars = ((OrigCommPlayers-1)/4)+1;
199 
200     for (i = windowx1; i <= windowx2; i++)
201         {
202         y = (tilesizy[FRAG_BAR] * num_frag_bars) - (2 * (num_frag_bars-1));
203         y = y * (ydim/200.0);
204 
205         if (windowy1 < y)
206             startumost[i] = y;
207         }
208 
209      for (i = 0, y = 0; i < num_frag_bars; i++)
210         {
211         psp = pSpawnFullScreenSprite(pp, FRAG_BAR, PRI_MID, 0, y);
212         SET(psp->flags, PANF_NON_MASKED|PANF_SCALE_TOP);
213         y += tilesizy[FRAG_BAR] - 2;
214         }
215 
216     // write each persons kill info to everybody
217     TRAVERSE_CONNECT(i)
218         {
219         PlayerUpdateKills(Player + i, 0);
220         DisplayFragNames(Player + i);
221         }
222     }
223 
RectOverlap(short tx1,short ty1,short bx1,short by1,short tx2,short ty2,short bx2,short by2)224 BOOL RectOverlap(short tx1, short ty1, short bx1, short by1, short tx2, short ty2, short bx2, short by2)
225     {
226     if (bx1 >= tx2)
227         if (tx1 <= bx2)
228             if (ty1 <= by2)
229                 if (by1 >= ty2)
230                     return(TRUE);
231 
232     return(FALSE);
233     }
234 
DrawBorderShade(PLAYERp pp,short shade_num,short wx1,short wy1,short wx2,short wy2)235 VOID DrawBorderShade(PLAYERp pp, short shade_num, short wx1, short wy1, short wx2, short wy2)
236     {
237     short i,j,k,l;
238     PANEL_SPRITEp psp;
239     int dark_shade = 27 - (shade_num * 6);
240     int light_shade = 20 - (shade_num * 6);
241 
242     for (i = 0; i < xdim; i += tilesizx[BORDER_TILE])
243         {
244         for (j = 0; j < ydim; j += tilesizy[BORDER_TILE])
245             {
246             k = i + tilesizx[BORDER_TILE];
247             l = j + tilesizy[BORDER_TILE];
248 
249             if (RectOverlap(i, j, k, l, wx1 - 1, wy1 - 1, wx2 + 1, wy1))
250                 {
251                 // draw top box of the border
252                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_TOP, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy1 - 1, wx2 + 1, wy1);
253                 SET(psp->flags, PANF_NON_MASKED);
254                 psp->shade = dark_shade;
255                 psp->ID = ID_BORDER_SHADE;
256                 }
257 
258             if (RectOverlap(i, j, k, l, wx1 - 1, wy2, wx2 + 1, wy2 + 1))
259                 {
260                 // draw bottom box of the border
261                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_BOTTOM, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy2, wx2 + 1, wy2 + 1);
262                 SET(psp->flags, PANF_NON_MASKED);
263                 psp->shade = light_shade;
264                 psp->ID = ID_BORDER_SHADE;
265                 }
266             if (RectOverlap(i, j, k, l, wx1 - 1, wy1 - 1, wx1, wy2 + 1))
267                 {
268                 // draw left box of the border
269                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_LEFT, BORDER_TILE, PRI_BACK + 1, i, j, wx1 - 1, wy1 - 1, wx1, wy2 + 1);
270                 SET(psp->flags, PANF_NON_MASKED);
271                 psp->shade = dark_shade;
272                 psp->ID = ID_BORDER_SHADE;
273                 }
274             if (RectOverlap(i, j, k, l, wx2, wy1 - 1, wx2 + 1, wy2 + 1))
275                 {
276                 // draw right box of the border
277                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_RIGHT, BORDER_TILE, PRI_BACK + 1, i, j, wx2, wy1 - 1, wx2 + 1, wy2 + 1);
278                 SET(psp->flags, PANF_NON_MASKED);
279                 psp->shade = light_shade;
280                 psp->ID = ID_BORDER_SHADE;
281                 }
282             }
283         }
284     }
285 
286 VOID
BorderShade(PLAYERp pp,BOOL UNUSED (refresh))287 BorderShade(PLAYERp pp, BOOL UNUSED(refresh))
288     {
289     int i, j, k, l, wx1, wx2, wy1, wy2;
290     PANEL_SPRITEp psp;
291     BYTE lines;
292 
293     wx1 = windowx1 - 1;
294     wy1 = windowy1 - 1;
295     wx2 = windowx2 + 1;
296     wy2 = windowy2 + 1;
297 
298     for (lines = 0; lines < 4; lines++)
299         {
300 
301         // make sure that these values dont go out of bound - which they do
302         wx1 = max(wx1, 0);
303         wx2 = min(wx2, xdim - 1);
304         wy1 = max(wy1, 0);
305         wy2 = min(wy2, MSW(f_ydim - mulscale16(Y_TO_FIXED(BAR_HEIGHT), PanelScale)) - 1);
306 
307         DrawBorderShade(pp, lines, wx1, wy1, wx2, wy2);
308         // increase view size by one - dont do a set view though
309         wx1--;
310         wy1--;
311         wx2++;
312         wy2++;
313         }
314     }
315 
316 
317 BORDER_INFO BorderInfoValues[] =
318     {
319     // x,y,screensize
320     {0, 0, 0},
321     {0, 0, 0},
322     {0, BAR_HEIGHT, 0},
323 
324     {0, BAR_HEIGHT, (1 * 16)},
325     {0, BAR_HEIGHT, (2 * 16)},
326     {0, BAR_HEIGHT, (3 * 16)},
327     {0, BAR_HEIGHT, (4 * 16)},
328     {0, BAR_HEIGHT, (5 * 16)},
329     {0, BAR_HEIGHT, (6 * 16)},
330     {0, BAR_HEIGHT, (7 * 16)},
331     {0, BAR_HEIGHT, (8 * 16)},
332     {0, BAR_HEIGHT, (9 * 16)},
333     {0, BAR_HEIGHT, (10 * 16)},
334     {0, BAR_HEIGHT, (11 * 16)},
335     {0, BAR_HEIGHT, (12 * 16)}
336     };
337 
338 
DrawBorder(PLAYERp pp,short x,short y,short x2,short y2)339 VOID DrawBorder(PLAYERp pp, short x, short y, short x2, short y2)
340     {
341     short i,j,k,l;
342     short count = 0;
343     PANEL_SPRITEp psp;
344 
345     for (i = 0; i < xdim; i += tilesizx[BORDER_TILE])
346         {
347         for (j = 0; j < ydim; j += tilesizy[BORDER_TILE])
348             {
349             k = i + tilesizx[BORDER_TILE];
350             l = j + tilesizy[BORDER_TILE];
351 
352             if (RectOverlap(i, j, k, l, x, y, windowx1-1, y2))
353                 {
354                 // draw top box of the border
355                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_TOP, BORDER_TILE, PRI_BACK, i, j, x, y, windowx1-1, y2);
356                 SET(psp->flags, PANF_NON_MASKED);
357                 count++;
358                 }
359 
360             if (RectOverlap(i, j, k, l, windowx2+1, y, x2, y2))
361                 {
362                 // draw bottom box of the border
363                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_BOTTOM, BORDER_TILE, PRI_BACK, i, j, windowx2+1, y, x2, y2);
364                 SET(psp->flags, PANF_NON_MASKED);
365                 count++;
366                 }
367 
368             if (RectOverlap(i, j, k, l, windowx1, y, windowx2, windowy1-1))
369                 {
370                 // draw left box of the border
371                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_LEFT, BORDER_TILE, PRI_BACK, i, j, windowx1, y, windowx2, windowy1-1);
372                 SET(psp->flags, PANF_NON_MASKED);
373                 count++;
374                 }
375 
376             if (RectOverlap(i, j, k, l, windowx1, windowy2+1, windowx2, y2))
377                 {
378                 // draw right box of the border
379                 psp = pSpawnFullScreenSpriteBox(pp, ID_BORDER_RIGHT, BORDER_TILE, PRI_BACK, i, j, windowx1, windowy2+1, windowx2, y2);
380                 SET(psp->flags, PANF_NON_MASKED);
381                 count++;
382                 }
383             }
384         }
385     }
386 
DrawPanelBorderSides(PLAYERp pp,short x,short y,short x2,short y2,short panl,short panr)387 VOID DrawPanelBorderSides(PLAYERp pp, short x, short y, short x2, short y2, short panl, short panr)
388     {
389     short i,j,k,l;
390     short count = 0;
391     PANEL_SPRITEp psp;
392 
393     for (i = 0; i < xdim; i += tilesizx[BORDER_TILE])
394         {
395         for (j = 0; j < ydim; j += tilesizy[BORDER_TILE])
396             {
397             k = i + tilesizx[BORDER_TILE];
398             l = j + tilesizy[BORDER_TILE];
399 
400             if (RectOverlap(i, j, k, l, x, y, panl, y2))
401                 {
402                 psp = pSpawnFullScreenSpriteBox(pp, ID_PANEL_BORDER_LEFT, BORDER_TILE, PRI_BACK, i, j, x, y, panl, y2);
403                 SET(psp->flags, PANF_NON_MASKED);
404                 count++;
405                 }
406 
407             if (RectOverlap(i, j, k, l, panr, y, x2, y2))
408                 {
409                 psp = pSpawnFullScreenSpriteBox(pp, ID_PANEL_BORDER_RIGHT, BORDER_TILE, PRI_BACK, i, j, panr, y, x2, y2);
410                 SET(psp->flags, PANF_NON_MASKED);
411                 count++;
412                 }
413             }
414         }
415     }
416 
417 static
BorderSetView(PLAYERp UNUSED (pp),int * Xdim,int * Ydim,int * ScreenSize)418 VOID BorderSetView(PLAYERp UNUSED(pp), int *Xdim, int *Ydim, int *ScreenSize)
419     {
420     void setview(int scrx1, int scry1, int scrx2, int scry2);
421     int x, x2, y, y2;
422     int xd, yd, sc;
423     BORDER_INFO *b;
424 
425     BorderInfo = BorderInfoValues[gs.BorderNum];
426 
427     b = &BorderInfo;
428 
429     // figure out the viewing window x and y dimensions
430     xd = f_xdim - X_TO_FIXED(b->Xdim);
431     yd = f_ydim - mulscale16(Y_TO_FIXED(b->Ydim), PanelScale);
432     sc = f_xdim - X_TO_FIXED(b->ScreenSize);
433     *Xdim = MSW(xd);
434     *Ydim = MSW(yd);
435     *ScreenSize = MSW(sc);
436 
437     // figure out the viewing window x and y coordinates
438     x = MSW(DIV2(xd - sc));
439     x2 = MSW(DIV2(xd + sc));
440     y = MSW(DIV2(yd - scale(sc, yd, xd)));
441     y2 = MSW_ROUND(DIV2(yd + scale(sc, yd, xd)) + 32768);
442     if (y2 > ydim)
443         y2 = ydim;
444 
445     // global windowx1, windowx2, windowy1, windowy2 coords set here
446     setview(x, y, x2-1, y2-1);
447     SetCrosshair();
448     }
449 
450 //
451 // Redraw the border without changing the view
452 //
453 
454 static VOID
BorderRefresh(PLAYERp pp)455 BorderRefresh(PLAYERp pp)
456     {
457     int i, j;
458     int x, x2, y, y2;
459     BORDER_INFO *b;
460 
461     if (pp != Player + myconnectindex)
462         return;
463 
464     if (!BorderAdjust)
465         return;
466 
467     if (gs.BorderNum < BORDER_BAR)
468         return;
469 
470     // Redraw the BORDER_TILE only if getting smaller
471     BorderInfo = BorderInfoValues[gs.BorderNum];
472 
473     b = &BorderInfo;
474 
475     // A refresh does not change the view size so we dont need to do a
476     // setview
477     // We don't need the calculations for the border drawing boxes - its
478     // the whole screen
479     // minus the border if necessary
480 
481     // fill in the sides of the panel when the screen is wide
482     if (gs.BorderNum >= BORDER_BAR && (widescreen || PanelScale < FIXED(1,0)))
483         {
484         int barw = scale(f_320, f_ydim, 200 * pixelaspect);
485         int sidel, sider;
486 
487         x = 0;
488         x2 = xdim - 1;
489 
490         y = MSW_ROUND(f_ydim - mulscale16(Y_TO_FIXED(b->Ydim), PanelScale) + 32768);
491         y2 = ydim - 1;
492 
493         sidel = MSW_ROUND(DIV2(f_xdim - mulscale16(barw, PanelScale)));
494         sider = MSW(DIV2(f_xdim + mulscale16(barw, PanelScale)));
495 
496         DrawPanelBorderSides(pp, x, y, x2, y2, sidel, sider);
497         }
498 
499     // only need a border if border is > BORDER_BAR
500     if (gs.BorderNum > BORDER_BAR)
501         {
502         // make sure that these values dont go out of bound - which they do
503         x = 0;
504         x2 = xdim - 1;
505 
506         y = 0;
507         y2 = MSW_ROUND(f_ydim - mulscale16(Y_TO_FIXED(b->Ydim), PanelScale));
508 
509         DrawBorder(pp, x, y, x2, y2);
510 
511         // kill ALL outstanding (not yet drawn) border shade sprites before
512         // doing more shading
513         pKillScreenSpiteIDs(pp, ID_BORDER_SHADE);
514 
515         BorderShade(pp, TRUE);
516         }
517     }
518 
519 //
520 // Redraw the whole screen
521 //
522 
SetBorder(PLAYERp pp,int value)523 VOID SetBorder(PLAYERp pp, int value)
524     {
525     int diff;
526     int Xdim, Ydim, ScreenSize;
527     BOOL set_view = TRUE;
528     PANEL_SPRITEp psp;
529 
530     if (pp != Player + myconnectindex)
531         return;
532 
533     if (!BorderAdjust)
534         return;
535 
536     if (value >= 0) // just refresh
537         gs.BorderNum = value;
538 
539     if (gs.BorderNum < BORDER_NONE)
540         {
541         gs.BorderNum = BORDER_NONE;
542         //return;
543         }
544 
545     if (gs.BorderNum > (int)SIZ(BorderInfoValues) - 1)
546         {
547         gs.BorderNum = SIZ(BorderInfoValues) - 1;
548         return;
549         }
550 
551     BorderSetView(pp, &Xdim, &Ydim, &ScreenSize);
552 
553     if (gs.BorderNum >= BORDER_BAR)
554         {
555         BorderRefresh(pp);
556 
557         psp = pSpawnFullScreenSprite(pp, STATUS_BAR, PRI_BACK, 0, 200 - tilesizy[STATUS_BAR]);
558         SET(psp->flags, PANF_NON_MASKED|PANF_SCALE_BOTTOM);
559         PlayerUpdatePanelInfo(Player + screenpeek);
560         }
561 
562     SetFragBar(pp);
563     }
564 
565 VOID
SetRedrawScreen(PLAYERp pp)566 SetRedrawScreen(PLAYERp pp)
567     {
568     int i, j;
569     //int x, x2, y, y2;
570     BORDER_INFO *b;
571 
572     if (pp != Player + myconnectindex)
573         return;
574 
575     if (!BorderAdjust)
576         return;
577 
578     if (gs.BorderNum < BORDER_NONE)
579         gs.BorderNum = BORDER_NONE;
580 
581     // Redraw the BORDER_TILE only if getting smaller
582     BorderInfo = BorderInfoValues[gs.BorderNum];
583 
584     b = &BorderInfo;
585 
586     // test at redrawing the whole screen
587     RedrawScreen = TRUE;
588     }
589 
590