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