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 "mytypes.h"
29 #include "keys.h"
30 #include "names2.h"
31 #include "panel.h"
32 #include "game.h"
33 #include "tags.h"
34 #include "player.h"
35 #include "mclip.h"
36
37 #if 0
38 int MultiClipMove(PLAYERp pp, int z, int floor_dist)
39 {
40 int i;
41 int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
42 SPRITEp sp = pp->sop->sp_child;
43 USERp u = User[sp - sprite];
44 SECTOR_OBJECTp sop = pp->sop;
45 short ang;
46 short min_ndx;
47 int min_dist = 999999;
48 int dist;
49
50 int ret_start;
51 int ret[MAX_CLIPBOX];
52 int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
53
54 for (i = 0; i < sop->clipbox_num; i++)
55 {
56 ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
57 ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
58 oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);
59
60 // move the box
61 ret[i] = clipmove(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
62
63 // save the dist moved
64 dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);
65
66 if (dist < min_dist)
67 {
68 min_dist = dist;
69 min_ndx = i;
70 }
71 }
72
73 // put posx and y off from offset
74 pp->posx -= ox[min_ndx] - x[min_ndx];
75 pp->posy -= oy[min_ndx] - y[min_ndx];
76
77 return(ret[min_ndx]);
78 }
79 #endif
80
81 #if 0
82 int MultiClipMove(PLAYERp pp, int z, int floor_dist)
83 {
84 int i;
85 int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
86 SPRITEp sp = pp->sop->sp_child;
87 USERp u = User[sp - sprite];
88 SECTOR_OBJECTp sop = pp->sop;
89 short ang;
90 short min_ndx;
91 int min_dist = 999999;
92 int dist;
93
94 int ret_start;
95 int ret[MAX_CLIPBOX];
96 int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
97
98 for (i = 0; i < sop->clipbox_num; i++)
99 {
100 ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
101 ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
102 oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);
103
104 // move the box
105 //pushmove(&x[i], &y[i], &z, &pp->cursectnum, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
106 ret[i] = clipmove(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
107 //pushmove(&x[i], &y[i], &z, &pp->cursectnum, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
108
109 // save the dist moved
110 dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);
111
112 if (dist < min_dist)
113 {
114 min_dist = dist;
115 min_ndx = i;
116 }
117 }
118
119 // put posx and y off from offset
120 pp->posx -= ox[min_ndx] - x[min_ndx];
121 pp->posy -= oy[min_ndx] - y[min_ndx];
122
123 return(ret[min_ndx]);
124 }
125 #endif
126
127 #if 0
128 int MultiClipMove(PLAYERp pp, int z, int floor_dist)
129 {
130 int i;
131 int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
132 SPRITEp sp = pp->sop->sp_child;
133 USERp u = User[sp - sprite];
134 SECTOR_OBJECTp sop = pp->sop;
135 short ang;
136 short min_ndx;
137 int min_dist = 999999;
138 int dist;
139
140 int ret_start;
141 int ret[MAX_CLIPBOX];
142 int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
143
144 int xvect,yvect;
145 int xs,ys;
146
147 for (i = 0; i < sop->clipbox_num; i++)
148 {
149 // move the box to position instead of using offset- this prevents small rounding errors
150 // allowing you to move through wall
151 ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
152
153 xs = pp->posx;
154 ys = pp->posy;
155
156 xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
157 yvect = (sop->clipbox_vdist[i] * sintable[ang]);
158 ret_start = clipmove(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
159
160 // save off the start position
161 ox[i] = x[i] = xs;
162 oy[i] = y[i] = ys;
163
164 // move the box
165 ret[i] = clipmove(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
166
167 // save the dist moved
168 dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
169 //dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);
170
171 if (ret[i])
172 {
173 //DSPRINTF(ds,"i %d, ret %d, dist %d",i, ret[i], dist);
174 //printf("%s\n",ds);
175 MONO_PRINT(ds);
176 }
177
178 if (dist < min_dist)
179 {
180 min_dist = dist;
181 min_ndx = i;
182 }
183 }
184
185 // put posx and y off from offset
186 pp->posx -= ox[min_ndx] - x[min_ndx];
187 pp->posy -= oy[min_ndx] - y[min_ndx];
188
189 return(ret[min_ndx]);
190 }
191 #endif
192
193 #if 0
194 int MultiClipMove(PLAYERp pp, int z, int floor_dist)
195 {
196 int i;
197 int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
198 SPRITEp sp = pp->sop->sp_child;
199 USERp u = User[sp - sprite];
200 SECTOR_OBJECTp sop = pp->sop;
201 short ang;
202 short min_ndx;
203 int min_dist = 999999;
204 int dist;
205
206 int ret_start;
207 int ret[MAX_CLIPBOX];
208 int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
209
210 int xvect,yvect;
211 int xs,ys;
212
213 for (i = 0; i < sop->clipbox_num; i++)
214 {
215 // move the box to position instead of using offset- this prevents small rounding errors
216 // allowing you to move through wall
217 ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
218
219 xs = pp->posx;
220 ys = pp->posy;
221
222 xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
223 yvect = (sop->clipbox_vdist[i] * sintable[ang]);
224 ret_start = clipmove(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
225
226 if (ret_start)
227 {
228 // hit something moving into position
229 min_dist = 0;
230 min_ndx = i;
231 // ox is where it should be
232 ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
233 oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);
234
235 x[i] = xs;
236 y[i] = ys;
237
238 dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
239 //ox[i] = x[i] = oy[i] = y[i] = 0;
240 }
241 else
242 {
243 // save off the start position
244 ox[i] = x[i] = xs;
245 oy[i] = y[i] = ys;
246
247 // move the box
248 ret[i] = clipmove(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
249
250 // save the dist moved
251 dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
252 //dist = FindDistance2D(x[i] - ox[i], y[i] - oy[i]);
253
254 if (ret[i])
255 {
256 //DSPRINTF(ds,"i %d, ret %d, dist %d",i, ret[i], dist);
257 MONO_PRINT(ds);
258 }
259
260 if (dist < min_dist)
261 {
262 min_dist = dist;
263 min_ndx = i;
264 }
265 }
266 }
267
268 // put posx and y off from offset
269 pp->posx -= ox[min_ndx] - x[min_ndx];
270 pp->posy -= oy[min_ndx] - y[min_ndx];
271
272 return(ret[min_ndx]);
273 }
274 #endif
275
MultiClipMove(PLAYERp pp,int z,int floor_dist)276 int MultiClipMove(PLAYERp pp, int z, int floor_dist)
277 {
278 int i;
279 int ox[MAX_CLIPBOX],oy[MAX_CLIPBOX];
280 SPRITEp sp = pp->sop->sp_child;
281 USERp u = User[sp - sprite];
282 SECTOR_OBJECTp sop = pp->sop;
283 short ang;
284 short min_ndx = 0;
285 int min_dist = 999999;
286 int dist;
287
288 int ret_start;
289 int ret;
290 int min_ret=0;
291 int x[MAX_CLIPBOX],y[MAX_CLIPBOX];
292
293 int xvect,yvect;
294 int xs,ys;
295
296 for (i = 0; i < sop->clipbox_num; i++)
297 {
298 // move the box to position instead of using offset- this prevents small rounding errors
299 // allowing you to move through wall
300 ang = NORM_ANGLE(pp->pang + sop->clipbox_ang[i]);
301
302 xs = pp->posx;
303 ys = pp->posy;
304
305 xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
306 yvect = (sop->clipbox_vdist[i] * sintable[ang]);
307 clipmoveboxtracenum = 1;
308 ret_start = clipmove(&xs, &ys, &z, &pp->cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
309 clipmoveboxtracenum = 3;
310
311 if (ret_start)
312 {
313 // hit something moving into start position
314 min_dist = 0;
315 min_ndx = i;
316 // ox is where it should be
317 ox[i] = x[i] = pp->posx + (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)] >> 14);
318 oy[i] = y[i] = pp->posy + (sop->clipbox_vdist[i] * sintable[ang] >> 14);
319
320 // xs is where it hit
321 x[i] = xs;
322 y[i] = ys;
323
324 // see the dist moved
325 dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
326
327 // save it off
328 if (dist < min_dist)
329 {
330 min_dist = dist;
331 min_ndx = i;
332 min_ret = ret_start;
333 }
334 }
335 else
336 {
337 // save off the start position
338 ox[i] = x[i] = xs;
339 oy[i] = y[i] = ys;
340
341 // move the box
342 ret = clipmove(&x[i], &y[i], &z, &pp->cursectnum, pp->xvect, pp->yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
343
344 // save the dist moved
345 dist = ksqrt(SQ(x[i] - ox[i]) + SQ(y[i] - oy[i]));
346
347 if (ret)
348 {
349 }
350
351 if (dist < min_dist)
352 {
353 min_dist = dist;
354 min_ndx = i;
355 min_ret = ret;
356 }
357 }
358 }
359
360 // put posx and y off from offset
361 pp->posx += x[min_ndx] - ox[min_ndx];
362 pp->posy += y[min_ndx] - oy[min_ndx];
363
364 return(min_ret);
365 }
366
MultiClipTurn(PLAYERp pp,short new_ang,int z,int floor_dist)367 short MultiClipTurn(PLAYERp pp, short new_ang, int z, int floor_dist)
368 {
369 int i;
370 SECTOR_OBJECTp sop = pp->sop;
371 int ret;
372 int x,y;
373 short ang;
374 int xvect, yvect;
375 short cursectnum = pp->cursectnum;
376
377 for (i = 0; i < sop->clipbox_num; i++)
378 {
379 ang = NORM_ANGLE(new_ang + sop->clipbox_ang[i]);
380
381 x = pp->posx;
382 y = pp->posy;
383
384 xvect = (sop->clipbox_vdist[i] * sintable[NORM_ANGLE(ang + 512)]);
385 yvect = (sop->clipbox_vdist[i] * sintable[ang]);
386
387 // move the box
388 ret = clipmove(&x, &y, &z, &cursectnum, xvect, yvect, (int)sop->clipbox_dist[i], Z(4), floor_dist, CLIPMASK_PLAYER);
389
390 ASSERT(cursectnum >= 0);
391
392 if (ret)
393 {
394 // attempt to move a bit when turning against a wall
395 //ang = NORM_ANGLE(ang + 1024);
396 //pp->xvect += 20 * sintable[NORM_ANGLE(ang + 512)];
397 //pp->yvect += 20 * sintable[ang];
398 return(FALSE);
399 }
400 }
401
402 return(TRUE);
403 }
404
testquadinsect(int * point_num,int qx[],int qy[],short sectnum)405 int testquadinsect(int *point_num, int qx[], int qy[], short sectnum)
406 {
407 int i,next_i;
408
409 *point_num = -1;
410
411 for(i=0; i < 4; i++)
412 {
413 if (!inside(qx[i], qy[i], sectnum))
414 {
415 ////DSPRINTF(ds,"inside %ld failed",i);
416 //MONO_PRINT(ds);
417
418 *point_num = i;
419
420 return(FALSE);
421 }
422 }
423
424 for(i=0;i<4;i++)
425 {
426 next_i = MOD4(i+1);
427 if (!cansee(qx[i], qy[i],0x3fffffff, sectnum,
428 qx[next_i], qy[next_i],0x3fffffff, sectnum))
429 {
430 DSPRINTF(ds,"cansee %ld failed, x1 %d, y1 %d, x2 %d, y2 %d, sectnum %d",i, qx[i], qy[i], qx[next_i], qy[next_i], sectnum);
431 MONO_PRINT(ds);
432
433 return(FALSE);
434 }
435 }
436
437 return(TRUE);
438 }
439
440
441 //Ken gives the tank clippin' a try...
RectClipMove(PLAYERp pp,int * qx,int * qy)442 int RectClipMove(PLAYERp pp, int *qx, int *qy)
443 {
444 SECTORp *sectp;
445 SECTOR_OBJECTp sop = pp->sop;
446 WALLp wp;
447 int count=0;
448 int i, x[4], y[4];
449 short startwall,endwall;
450 int point_num;
451
452 for (i = 0; i < 4; i++)
453 {
454 x[i] = qx[i] + (pp->xvect>>14);
455 y[i] = qy[i] + (pp->yvect>>14);
456 }
457
458 //Given the 4 points: x[4], y[4]
459 if (testquadinsect(&point_num, x, y, pp->cursectnum))
460 {
461 pp->posx += (pp->xvect>>14);
462 pp->posy += (pp->yvect>>14);
463 return(TRUE);
464 }
465
466 if (point_num < 0)
467 return(FALSE);
468
469 if ((point_num == 0) || (point_num == 3)) //Left side bad - strafe right
470 {
471 for (i = 0; i < 4; i++)
472 {
473 x[i] = qx[i] - (pp->yvect>>15);
474 y[i] = qy[i] + (pp->xvect>>15);
475 }
476 if (testquadinsect(&point_num, x, y, pp->cursectnum))
477 {
478 pp->posx -= (pp->yvect>>15);
479 pp->posy += (pp->xvect>>15);
480 }
481
482 return(FALSE);
483 }
484
485 if ((point_num == 1) || (point_num == 2)) //Right side bad - strafe left
486 {
487 for (i = 0; i < 4; i++)
488 {
489 x[i] = qx[i] + (pp->yvect>>15);
490 y[i] = qy[i] - (pp->xvect>>15);
491 }
492 if (testquadinsect(&point_num, x, y, pp->cursectnum))
493 {
494 pp->posx += (pp->yvect>>15);
495 pp->posy -= (pp->xvect>>15);
496 }
497
498 return(FALSE);
499 }
500
501 return(FALSE);
502 }
503
testpointinquad(int x,int y,int * qx,int * qy)504 int testpointinquad(int x, int y, int *qx, int *qy)
505 {
506 int i, cnt, x1, y1, x2, y2;
507
508 cnt = 0;
509 for(i=0;i<4;i++)
510 {
511 y1 = qy[i]-y;
512 y2 = qy[(i+1)&3]-y;
513 if ((y1^y2) >= 0) continue;
514
515 x1 = qx[i]-x;
516 x2 = qx[(i+1)&3]-x;
517 if ((x1^x2) >= 0)
518 cnt ^= x1;
519 else
520 cnt ^= (x1*y2-x2*y1)^y2;
521 }
522 return(cnt>>31);
523 }
524
RectClipTurn(PLAYERp pp,short new_ang,int * qx,int * qy,int * ox,int * oy)525 short RectClipTurn(PLAYERp pp, short new_ang, int *qx, int *qy, int *ox, int *oy)
526 {
527 int i, x[4], y[4];
528 SECTOR_OBJECTp sop = pp->sop;
529 int ret;
530 short ang;
531 short rot_ang;
532 int point_num;
533
534 rot_ang = NORM_ANGLE(new_ang + sop->spin_ang - sop->ang_orig);
535 for (i = 0; i < 4; i++)
536 {
537 rotatepoint(pp->posx, pp->posy, ox[i], oy[i], rot_ang, &x[i], &y[i]);
538 // cannot use sop->xmid and ymid because the SO is off the map at this point
539 //rotatepoint(sop->xmid, sop->ymid, ox[i], oy[i], rot_ang, &x[i], &y[i]);
540 }
541
542 //Given the 4 points: x[4], y[4]
543 if (testquadinsect(&point_num, x, y, pp->cursectnum))
544 {
545 // move to new pos
546 for (i = 0; i < 4; i++)
547 {
548 qx[i] = x[i];
549 qy[i] = y[i];
550 }
551 return(TRUE);
552 }
553
554 if (point_num < 0)
555 return(FALSE);
556
557 return(FALSE);
558 }
559