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