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