1 /*
2 * Copyright 2011-2012 Arx Libertatis Team (see the AUTHORS file)
3 *
4 * This file is part of Arx Libertatis.
5 *
6 * Arx Libertatis is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Arx Libertatis is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>.
18 */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
33 <http://www.gnu.org/licenses/>.
34
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Code: Cyril Meynier
44 //
45 // Copyright (c) 1999-2001 ARKANE Studios SA. All rights reserved
46
47 #include "physics/Collisions.h"
48
49 #include "core/GameTime.h"
50 #include "core/Core.h"
51 #include "game/Damage.h"
52 #include "game/EntityManager.h"
53 #include "game/NPC.h"
54 #include "game/Player.h"
55 #include "graphics/Math.h"
56 #include "physics/Anchors.h"
57 #include "scene/Interactive.h"
58
59 using std::min;
60 using std::max;
61 using std::vector;
62
63 //-----------------------------------------------------------------------------
64 extern float FrameDiff;
65 long ON_PLATFORM=0;
66 //-----------------------------------------------------------------------------
67 size_t MAX_IN_SPHERE_Pos = 0;
68 short EVERYTHING_IN_SPHERE[MAX_IN_SPHERE + 1];
69 size_t EXCEPTIONS_LIST_Pos = 0;
70 short EXCEPTIONS_LIST[MAX_IN_SPHERE + 1];
71
72 static long POLYIN = 0;
73 long COLLIDED_CLIMB_POLY=0;
74 long MOVING_CYLINDER=0;
75
76 Vec3f vector2D;
77 bool DIRECT_PATH=true;
78
79 //-----------------------------------------------------------------------------
80 // Added immediate return (return anything;)
IsPolyInCylinder(EERIEPOLY * ep,EERIE_CYLINDER * cyl,long flag)81 inline float IsPolyInCylinder(EERIEPOLY *ep, EERIE_CYLINDER * cyl,long flag)
82 {
83 long flags=flag;
84 POLYIN=0;
85 float minf = cyl->origin.y + cyl->height;
86 float maxf = cyl->origin.y;
87
88 if (minf>ep->max.y) return 999999.f;
89
90 if (maxf<ep->min.y) return 999999.f;
91
92 long to;
93
94 if (ep->type & POLY_QUAD) to=4;
95 else to=3;
96
97 float nearest = 99999999.f;
98
99 for (long num=0;num<to;num++)
100 {
101 float dd = fdist(Vec2f(ep->v[num].p.x, ep->v[num].p.z), Vec2f(cyl->origin.x, cyl->origin.z));
102
103 if (dd<nearest)
104 {
105 nearest=dd;
106 }
107 }
108
109 if (nearest > max(82.f,cyl->radius)) return 999999.f;
110
111 if ( (cyl->radius<30.f)
112 || (cyl->height>-80.f)
113 || (ep->area>5000.f) )
114 flags|=CFLAG_EXTRA_PRECISION;
115
116 if (!(flags & CFLAG_EXTRA_PRECISION))
117 {
118 if (ep->area<100.f) return 999999.f;
119 }
120
121 float anything=999999.f;
122
123 if (PointInCylinder(cyl, &ep->center))
124 {
125 POLYIN = 1;
126
127 if (ep->norm.y<0.5f)
128 anything=min(anything,ep->min.y);
129 else
130 anything=min(anything,ep->center.y);
131
132 if (!(flags & CFLAG_EXTRA_PRECISION)) return anything;
133 }
134
135
136 long r=to-1;
137
138 Vec3f center;
139 long n;
140
141 for (n=0;n<to;n++)
142 {
143 if (flags & CFLAG_EXTRA_PRECISION)
144 {
145 for (long o=0;o<5;o++)
146 {
147 float p=(float)o*( 1.0f / 5 );
148 center = ep->v[n].p * p + ep->center * (1.f-p);
149 if(PointInCylinder(cyl, ¢er)) {
150 anything=min(anything,center.y);
151 POLYIN=1;
152 if (!(flags & CFLAG_EXTRA_PRECISION)) return anything;
153 }
154 }
155 }
156
157 if ((ep->area>2000.f)
158 || (flags & CFLAG_EXTRA_PRECISION) )
159 {
160 center = (ep->v[n].p + ep->v[r].p) * 0.5f;
161 if(PointInCylinder(cyl, ¢er)) {
162 anything=min(anything,center.y);
163 POLYIN=1;
164 if (!(flags & CFLAG_EXTRA_PRECISION)) return anything;
165 }
166
167 if ((ep->area>4000.f) || (flags & CFLAG_EXTRA_PRECISION)) {
168 center = (ep->v[n].p + ep->center) * 0.5f;
169 if (PointInCylinder(cyl, ¢er))
170 {
171 anything=min(anything,center.y);
172 POLYIN=1;
173
174 if (!(flags & CFLAG_EXTRA_PRECISION)) return anything;
175 }
176 }
177
178 if ((ep->area>6000.f) || (flags & CFLAG_EXTRA_PRECISION)) {
179 center = (center + ep->v[n].p) * 0.5f;
180 if(PointInCylinder(cyl, ¢er))
181 {
182 anything=min(anything,center.y);
183 POLYIN=1;
184
185 if (!(flags & CFLAG_EXTRA_PRECISION)) return anything;
186 }
187 }
188 }
189
190 if(PointInCylinder(cyl, &ep->v[n].p)) {
191
192 anything=min(anything,ep->v[n].p.y);
193 POLYIN = 1;
194
195 if (!(flags & CFLAG_EXTRA_PRECISION)) return anything;
196 }
197
198 r++;
199
200 if (r>=to) r=0;
201
202 }
203
204
205 // To Add "more" precision
206
207 /*if (flags & CFLAG_EXTRA_PRECISION)
208 {
209
210 for (long j=0;j<360;j+=90)
211 {
212 float xx=-EEsin(radians((float)j))*cyl->radius;
213 float yy=EEcos(radians((float)j))*cyl->radius;
214 EERIE_3D pos;
215 pos.x=cyl->origin.x+xx;
216
217 pos.z=cyl->origin.z+yy;
218 //EERIEPOLY * epp;
219
220 if (PointIn2DPolyXZ(ep, pos.x, pos.z))
221 {
222 if (GetTruePolyY(ep,&pos,&xx))
223 {
224 anything=min(anything,xx);
225 return anything;
226 }
227 }
228 }
229 //}*/
230 if ((anything!=999999.f) && (ep->norm.y<0.1f) && (ep->norm.y>-0.1f))
231 anything=min(anything,ep->min.y);
232
233 return anything;
234 }
235
236 //-----------------------------------------------------------------------------
IsPolyInSphere(EERIEPOLY * ep,EERIE_SPHERE * sph)237 inline bool IsPolyInSphere(EERIEPOLY *ep, EERIE_SPHERE * sph)
238 {
239 if ((!ep) || (!sph)) return false;
240
241 if (ep->area<100.f) return false;
242
243 long to;
244
245 if (ep->type & POLY_QUAD) to=4;
246 else to=3;
247
248 long r=to-1;
249 Vec3f center;
250
251 for (long n=0;n<to;n++)
252 {
253
254 if(ep->area > 2000.f) {
255 center = (ep->v[n].p + ep->v[r].p) * 0.5f;
256 if(sph->contains(center)) {
257 return true;
258 }
259 if(ep->area > 4000.f) {
260 center = (ep->v[n].p + ep->center) * 0.5f;
261 if(sph->contains(center)) {
262 return true;
263 }
264 }
265 if(ep->area > 6000.f) {
266 center = (center + ep->v[n].p) * 0.5f;
267 if(sph->contains(center)) {
268 return true;
269 }
270 }
271 }
272
273 Vec3f v(ep->v[n].p.x, ep->v[n].p.y, ep->v[n].p.z);
274
275 if(sph->contains(v)) {
276 return true;
277 }
278
279 r++;
280
281 if (r>=to) r=0;
282 }
283
284 return false;
285 }
286
287 //-----------------------------------------------------------------------------
IsCollidingIO(Entity * io,Entity * ioo)288 bool IsCollidingIO(Entity * io,Entity * ioo)
289 {
290 if ( (ioo!=NULL)
291 && (io!=ioo)
292 && !(ioo->ioflags & IO_NO_COLLISIONS)
293 && (ioo->show==SHOW_FLAG_IN_SCENE)
294 && (ioo->obj)
295 )
296 {
297 if (ioo->ioflags & IO_NPC)
298 {
299 float old=ioo->physics.cyl.radius;
300 ioo->physics.cyl.radius+=25.f;
301
302 for (size_t j=0;j<io->obj->vertexlist3.size();j++)
303 {
304 if (PointInCylinder(&ioo->physics.cyl,&io->obj->vertexlist3[j].v))
305 {
306 ioo->physics.cyl.radius=old;
307 return true;
308 }
309 }
310
311 ioo->physics.cyl.radius=old;
312 }
313 }
314
315 return false;
316 }
317
318 // TODO include header?
319 extern void GetIOCyl(Entity * io,EERIE_CYLINDER * cyl);
PushIO_ON_Top(Entity * ioo,float ydec)320 void PushIO_ON_Top(Entity * ioo, float ydec) {
321
322 if(ydec != 0.f)
323 for(size_t i = 0; i < entities.size(); i++) {
324 Entity * io = entities[i];
325
326 if ( (io)
327 && (io!=ioo)
328 && !(io->ioflags & IO_NO_COLLISIONS)
329 && (io->show==SHOW_FLAG_IN_SCENE)
330 && (io->obj)
331 && (!(io->ioflags & (IO_FIX | IO_CAMERA | IO_MARKER)))
332 )
333 {
334 if(closerThan(Vec2f(io->pos.x, io->pos.z), Vec2f(ioo->pos.x, ioo->pos.z), 450.f)) {
335 EERIEPOLY ep;
336 ep.type=0;
337 float miny=9999999.f;
338 float maxy=-9999999.f;
339
340 for (size_t ii=0;ii<ioo->obj->vertexlist3.size();ii++)
341 {
342 miny=min(miny,ioo->obj->vertexlist3[ii].v.y);
343 maxy=max(maxy,ioo->obj->vertexlist3[ii].v.y);
344 }
345
346 float posy = (io == entities.player()) ? player.basePosition().y : io->pos.y;
347 float modd = (ydec > 0) ? -20.f : 0;
348
349 if ((posy<=maxy) && (posy>=miny+modd))
350 {
351 for (size_t ii=0;ii<ioo->obj->facelist.size();ii++)
352 {
353 float cx=0;
354 float cz=0;
355
356 for (long kk=0;kk<3;kk++)
357 {
358 cx+=ep.v[kk].p.x=ioo->obj->vertexlist3[ioo->obj->facelist[ii].vid[kk]].v.x;
359 ep.v[kk].p.y=ioo->obj->vertexlist3[ioo->obj->facelist[ii].vid[kk]].v.y;
360 cz+=ep.v[kk].p.z=ioo->obj->vertexlist3[ioo->obj->facelist[ii].vid[kk]].v.z;
361 }
362
363 cx*=( 1.0f / 3 );
364 cz*=( 1.0f / 3 );
365
366 float tval=1.1f;
367
368 for (int kk=0;kk<3;kk++)
369 {
370 ep.v[kk].p.x = (ep.v[kk].p.x - cx) * tval + cx;
371 ep.v[kk].p.z = (ep.v[kk].p.z - cz) * tval + cz;
372 }
373
374 if(PointIn2DPolyXZ(&ep, io->pos.x, io->pos.z)) {
375
376 if(io == entities.player()) {
377
378 if(ydec <= 0) {
379 player.pos.y += ydec;
380 moveto.y += ydec;
381 EERIE_CYLINDER cyl = player.baseCylinder();
382 cyl.origin.y += ydec;
383 float vv = CheckAnythingInCylinder(&cyl, entities.player(), 0);
384 if(vv < 0) {
385 player.pos.y += ydec + vv;
386 }
387 } else {
388 EERIE_CYLINDER cyl = player.baseCylinder();
389 cyl.origin.y += ydec;
390 if(CheckAnythingInCylinder(&cyl, entities.player(), 0) >= 0) {
391 player.pos.y += ydec;
392 moveto.y += ydec;
393 }
394 }
395
396 } else {
397
398 if(ydec <= 0) {
399 io->pos.y += ydec;
400 } else {
401 EERIE_CYLINDER cyl;
402 GetIOCyl(io, &cyl);
403 cyl.origin.y += ydec;
404 if(CheckAnythingInCylinder(&cyl, io ,0) >= 0) {
405 io->pos.y += ydec;
406 }
407 }
408
409 }
410 break;
411 }
412 }
413 }
414 }
415 }
416 }
417 }
418
IsAnyNPCInPlatform(Entity * pfrm)419 bool IsAnyNPCInPlatform(Entity * pfrm) {
420
421 for(size_t i = 0; i < entities.size(); i++) {
422 Entity * io = entities[i];
423
424 if ( (io)
425 && (io!=pfrm)
426 && (io->ioflags & IO_NPC)
427 && !(io->ioflags & IO_NO_COLLISIONS)
428 && (io->show==SHOW_FLAG_IN_SCENE)
429 )
430 {
431 EERIE_CYLINDER cyl;
432 GetIOCyl(io,&cyl);
433
434 if (CylinderPlatformCollide(&cyl,pfrm)!=0.f) return true;
435 }
436 }
437
438 return false;
439 }
440
CylinderPlatformCollide(EERIE_CYLINDER * cyl,Entity * io)441 float CylinderPlatformCollide(EERIE_CYLINDER * cyl, Entity * io) {
442
443 float miny = io->bbox3D.min.y;
444 float maxy = io->bbox3D.max.y;
445
446 if(maxy <= cyl->origin.y + cyl->height || miny >= cyl->origin.y) {
447 return 0.f;
448 }
449
450 if(In3DBBoxTolerance(&cyl->origin,&io->bbox3D,cyl->radius)) {
451 return 1.f;
452 }
453
454 return 0.f;
455 }
456
457 static long NPC_IN_CYLINDER = 0;
458
459 extern void GetIOCyl(Entity * io,EERIE_CYLINDER * cyl);
460
EE_RotateY(TexturedVertex * in,TexturedVertex * out,float c,float s)461 inline void EE_RotateY(TexturedVertex *in,TexturedVertex *out,float c, float s)
462 {
463 out->p.x = (in->p.x*c) + (in->p.z*s);
464 out->p.y = in->p.y;
465 out->p.z = (in->p.z*c) - (in->p.x*s);
466 }
467
CollidedFromBack(Entity * io,Entity * ioo)468 bool CollidedFromBack(Entity * io,Entity * ioo)
469 {
470 // io was collided from back ?
471 EERIEPOLY ep;
472 ep.type=0;
473
474 if ( (io )
475 && (ioo)
476 && (io->ioflags & IO_NPC)
477 && (ioo->ioflags & IO_NPC) )
478 {
479
480
481 ep.v[0].p.x=io->pos.x;
482 ep.v[0].p.z=io->pos.z;
483 float ft=radians(135.f+90.f);
484 ep.v[1].p.x = EEsin(ft) * 180.f;
485 ep.v[1].p.z = -EEcos(ft) * 180.f;
486 ft=radians(225.f+90.f);
487 ep.v[2].p.x = EEsin(ft) * 180.f;
488 ep.v[2].p.z = -EEcos(ft) * 180.f;
489 ft=radians(270.f-io->angle.b);
490 float ec=EEcos(ft);
491 float es=EEsin(ft);
492 EE_RotateY( &ep.v[1] , &ep.tv[1] , ec , es );
493 EE_RotateY( &ep.v[2] , &ep.tv[2] , ec , es );
494 ep.v[1].p.x=ep.tv[1].p.x+ep.v[0].p.x;
495 ep.v[1].p.z=ep.tv[1].p.z+ep.v[0].p.z;
496 ep.v[2].p.x=ep.tv[2].p.x+ep.v[0].p.x;
497 ep.v[2].p.z=ep.tv[2].p.z+ep.v[0].p.z;
498
499 // To keep if we need some visual debug
500 if (PointIn2DPolyXZ(&ep,ioo->pos.x,ioo->pos.z))
501 return true;
502 }
503
504 return false;
505 }
506
507 // Returns 0 if nothing in cyl
508 // Else returns Y Offset to put cylinder in a proper place
CheckAnythingInCylinder(EERIE_CYLINDER * cyl,Entity * ioo,long flags)509 float CheckAnythingInCylinder(EERIE_CYLINDER * cyl,Entity * ioo,long flags) {
510
511 NPC_IN_CYLINDER = 0;
512
513 long rad = (cyl->radius + 100) * ACTIVEBKG->Xmul;
514 long px,pz;
515 px = cyl->origin.x*ACTIVEBKG->Xmul;
516
517 if (px>ACTIVEBKG->Xsize-2-rad)
518 return 0.f;
519
520 if (px< 1+rad)
521 return 0.f;
522
523 pz = cyl->origin.z*ACTIVEBKG->Zmul;
524
525 if (pz>ACTIVEBKG->Zsize-2-rad)
526 return 0.f;
527
528 if (pz< 1+rad)
529 return 0.f;
530
531 float anything = 999999.f;
532
533 EERIEPOLY * ep;
534 FAST_BKG_DATA * feg;
535
536 for (long j=pz-rad;j<=pz+rad;j++)
537 for (long i=px-rad;i<=px+rad;i++)
538 {
539 float nearx,nearz;
540 float nearest=99999999.f;
541
542 for (long num=0;num<4;num++)
543 {
544
545 nearx = static_cast<float>(i * 100);
546 nearz = static_cast<float>(j * 100);
547
548 if ((num==1) || (num==2))
549 nearx += 100;
550
551 if ((num==2) || (num==3))
552 nearz += 100;
553
554 float dd = fdist(Vec2f(nearx, nearz), Vec2f(cyl->origin.x, cyl->origin.z));
555
556 if (dd<nearest)
557 {
558 nearest=dd;
559 }
560 }
561
562 if (nearest>max(82.f,cyl->radius)) continue;
563
564
565 feg=&ACTIVEBKG->fastdata[i][j];
566 for (long k=0;k<feg->nbpoly;k++)
567 {
568 ep=&feg->polydata[k];
569
570 if (ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL) ) continue;
571
572 if (ep->min.y<anything)
573 {
574
575 anything= min(anything,IsPolyInCylinder(ep,cyl,flags));
576
577 if (POLYIN)
578 {
579 if (ep->type & POLY_CLIMB)
580 COLLIDED_CLIMB_POLY=1;
581 }
582 }
583 }
584 }
585
586 float tempo;
587
588 ep=CheckInPolyPrecis(cyl->origin.x,cyl->origin.y+cyl->height,cyl->origin.z,&tempo);
589
590 if (ep)
591 {
592 anything=min(anything,tempo);
593 }
594
595 if (!(flags & CFLAG_NO_INTERCOL))
596 {
597 Entity * io;
598 long FULL_TEST=0;
599 long AMOUNT=TREATZONE_CUR;
600
601 if ( ioo
602 && (ioo->ioflags & IO_NPC)
603 && (ioo->_npcdata->pathfind.flags & PATHFIND_ALWAYS))
604 {
605 FULL_TEST=1;
606 AMOUNT=entities.size();
607 }
608
609 for (long i=0;i<AMOUNT;i++)
610 {
611 if(FULL_TEST) {
612 io=entities[i];
613 } else {
614 io=treatio[i].io;
615 }
616
617 if ( !io
618 || (io==ioo)
619 || (!io->obj)
620 || ( (io->show!=SHOW_FLAG_IN_SCENE)
621 || ((io->ioflags & IO_NO_COLLISIONS) && !(flags & CFLAG_COLLIDE_NOCOL))
622 )
623 || distSqr(io->pos, cyl->origin) > square(1000.f)) continue;
624
625 {
626 EERIE_CYLINDER * io_cyl=&io->physics.cyl;
627 GetIOCyl(io,io_cyl);
628 float dealt = 0;
629
630 if ( (io->gameFlags & GFLAG_PLATFORM)
631 || ((flags & CFLAG_COLLIDE_NOCOL) && (io->ioflags & IO_NPC) && (io->ioflags & IO_NO_COLLISIONS))
632 )
633 {
634 if(closerThan(Vec2f(io->pos.x, io->pos.z), Vec2f(cyl->origin.x, cyl->origin.z), 440.f + cyl->radius))
635 if (In3DBBoxTolerance(&cyl->origin,&io->bbox3D, cyl->radius+80))
636 {
637 if (io->ioflags & IO_FIELD)
638 {
639 if (In3DBBoxTolerance(&cyl->origin,&io->bbox3D, cyl->radius+10))
640 anything=-99999.f;
641 }
642 else
643 {
644 for (size_t ii=0;ii<io->obj->vertexlist3.size();ii++)
645 {
646 long res=PointInUnderCylinder(cyl,&io->obj->vertexlist3[ii].v);
647
648 if (res>0)
649 {
650 if (res==2) ON_PLATFORM=1;
651
652 anything = min(anything, io->obj->vertexlist3[ii].v.y - 10.f);
653 }
654 }
655
656 for (size_t ii=0;ii<io->obj->facelist.size();ii++)
657 {
658 Vec3f c = Vec3f::ZERO;
659 float height=io->obj->vertexlist3[io->obj->facelist[ii].vid[0]].v.y;
660
661 for (long kk=0;kk<3;kk++)
662 {
663 c.x+=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.x;
664 c.y+=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.y;
665 height=min(height,io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.y);
666 c.z+=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.z;
667 }
668
669 c.x*=( 1.0f / 3 );
670 c.z*=( 1.0f / 3 );
671 c.y = io->bbox3D.min.y;
672 long res=PointInUnderCylinder(cyl,&c);
673
674 if (res>0)
675 {
676 if (res==2) ON_PLATFORM=1;
677 anything = min(anything, height);
678 }
679 }
680 }
681 }
682 }
683 else if ( (io->ioflags & IO_NPC)
684 && (!(flags & CFLAG_NO_NPC_COLLIDE)) // MUST be checked here only (not before...)
685 && (!(ioo && (ioo->ioflags & IO_NO_COLLISIONS)))
686 && (io->_npcdata->life>0.f)
687 )
688 {
689
690 if(CylinderInCylinder(cyl, io_cyl)) {
691 NPC_IN_CYLINDER = 1;
692 anything = min(anything, io_cyl->origin.y + io_cyl->height);
693
694 if (!(flags & CFLAG_JUST_TEST) && ioo)
695 {
696 if (float(arxtime) > io->collide_door_time + 500)
697 {
698 EVENT_SENDER=ioo;
699 io->collide_door_time = (unsigned long)(arxtime);
700
701 if (CollidedFromBack(io,ioo))
702 SendIOScriptEvent(io,SM_COLLIDE_NPC,"back");
703 else
704 SendIOScriptEvent(io,SM_COLLIDE_NPC);
705
706 EVENT_SENDER=io;
707 io->collide_door_time = (unsigned long)(arxtime);
708
709 if (CollidedFromBack(ioo,io))
710 SendIOScriptEvent(ioo,SM_COLLIDE_NPC,"back");
711 else
712 SendIOScriptEvent(ioo,SM_COLLIDE_NPC);
713 }
714
715 if ((!dealt) && ((ioo->damager_damages>0) || (io->damager_damages>0)))
716 {
717
718 if (ioo->damager_damages>0)
719 ARX_DAMAGES_DealDamages(i,ioo->damager_damages,ioo->index(),ioo->damager_type,&io->pos);
720
721 if (io->damager_damages>0)
722 ARX_DAMAGES_DealDamages(ioo->index(),io->damager_damages,io->index(),io->damager_type,&ioo->pos);
723 }
724
725 if(io->targetinfo == i) {
726 if(io->_npcdata->pathfind.listnb > 0) {
727 io->_npcdata->pathfind.listpos = 0;
728 io->_npcdata->pathfind.listnb = -1;
729 free(io->_npcdata->pathfind.list), io->_npcdata->pathfind.list = NULL;
730 SendIOScriptEvent(io, SM_NULL, "", "pathfinder_end");
731 }
732 if(!io->_npcdata->reachedtarget) {
733 EVENT_SENDER = ioo;
734 SendIOScriptEvent(io, SM_REACHEDTARGET);
735 io->_npcdata->reachedtarget = 1;
736 }
737 }
738 }
739 }
740 }
741 else if (io->ioflags & IO_FIX)
742 {
743 EERIE_SPHERE sp;
744
745 float miny = io->bbox3D.min.y;
746 float maxy = io->bbox3D.max.y;
747
748 if (maxy<= cyl->origin.y+cyl->height) goto suivant;
749
750 if (miny>= cyl->origin.y) goto suivant;
751
752 if (In3DBBoxTolerance(&cyl->origin,&io->bbox3D,cyl->radius+30.f))
753 {
754 vector<EERIE_VERTEX> & vlist = io->obj->vertexlist3;
755 size_t nbv = io->obj->vertexlist.size();
756
757 if (io->obj->nbgroups>10)
758 {
759 for (long ii=0;ii<io->obj->nbgroups;ii++)
760 {
761 long idx = io->obj->grouplist[ii].origin;
762 sp.origin = vlist[idx].v;
763
764 if (ioo==entities.player())
765 {
766 sp.radius = 22.f;
767 }
768 else if (ioo->ioflags & IO_NPC)
769 sp.radius = 26.f;
770 else
771 sp.radius = 22.f;
772
773 if (SphereInCylinder(cyl,&sp))
774 {
775 if (!(flags & CFLAG_JUST_TEST) && ioo)
776 {
777 if (io->gameFlags&GFLAG_DOOR)
778 {
779
780 if (float(arxtime) > io->collide_door_time+500)
781 {
782 EVENT_SENDER=ioo;
783 io->collide_door_time = (unsigned long)(arxtime);
784 SendIOScriptEvent(io,SM_COLLIDE_DOOR);
785 EVENT_SENDER=io;
786 io->collide_door_time = (unsigned long)(arxtime);
787 SendIOScriptEvent(ioo,SM_COLLIDE_DOOR);
788 }
789 }
790
791 if (io->ioflags & IO_FIELD)
792 {
793 EVENT_SENDER=NULL;
794 io->collide_door_time = (unsigned long)(arxtime);
795 SendIOScriptEvent(ioo,SM_COLLIDE_FIELD);
796 }
797
798 if ((!dealt) && ((ioo->damager_damages>0) || (io->damager_damages>0)))
799 {
800 dealt=1;
801
802 if (ioo->damager_damages>0)
803 ARX_DAMAGES_DealDamages(i, ioo->damager_damages, ioo->index(), ioo->damager_type, &io->pos);
804
805 if (io->damager_damages>0)
806 ARX_DAMAGES_DealDamages(ioo->index(), io->damager_damages, io->index(), io->damager_type, &ioo->pos);
807 }
808 }
809
810 anything=min(anything,min(sp.origin.y-sp.radius , io->bbox3D.min.y));
811 }
812 }
813 }
814 else
815 {
816 long step;
817
818 if (ioo==entities.player())
819 sp.radius = 23.f;
820 else if (ioo && !(ioo->ioflags & IO_NPC))
821 sp.radius = 32.f;
822 else
823 sp.radius = 25.f;
824
825 if (nbv<300)
826 {
827 step=1;
828 }
829 else if (nbv<600) step=2;
830 else if (nbv<1200) step=4;
831 else step=6;
832
833 for (size_t ii=1;ii<nbv;ii+=step)
834 {
835 if (ii != (size_t)io->obj->origin)
836 {
837 sp.origin = vlist[ii].v;
838
839 if (SphereInCylinder(cyl,&sp))
840 {
841 if (!(flags & CFLAG_JUST_TEST) && ioo)
842 {
843 if (io->gameFlags&GFLAG_DOOR)
844 {
845 if (float(arxtime) > io->collide_door_time+500)
846 {
847 EVENT_SENDER=ioo;
848 io->collide_door_time = (unsigned long)(arxtime);
849 SendIOScriptEvent(io,SM_COLLIDE_DOOR);
850 EVENT_SENDER=io;
851 io->collide_door_time = (unsigned long)(arxtime);
852 SendIOScriptEvent(ioo,SM_COLLIDE_DOOR);
853 }
854 }
855
856 if (io->ioflags & IO_FIELD)
857 {
858 EVENT_SENDER=NULL;
859 io->collide_door_time = (unsigned long)(arxtime);
860 SendIOScriptEvent(ioo,SM_COLLIDE_FIELD);
861 }
862
863 if ((!dealt) && ioo && ((ioo->damager_damages > 0) || (io->damager_damages > 0)))
864 {
865 dealt=1;
866
867 if (ioo->damager_damages>0)
868 ARX_DAMAGES_DealDamages(i, ioo->damager_damages, ioo->index(), ioo->damager_type, &io->pos);
869
870 if (io->damager_damages>0)
871 ARX_DAMAGES_DealDamages(ioo->index(), io->damager_damages, io->index(), io->damager_type, &ioo->pos);
872 }
873 }
874 anything=min(anything,min(sp.origin.y-sp.radius,io->bbox3D.min.y));
875 }
876 }
877 }
878 }
879 }
880 }
881 }
882 suivant:
883 ;
884 }
885 }
886
887 if (anything == 999999.f) return 0.f;
888
889 anything=anything-cyl->origin.y;
890
891 return anything;
892 }
893
InExceptionList(long val)894 static bool InExceptionList(long val) {
895
896 for(size_t i = 0; i < EXCEPTIONS_LIST_Pos; i++) {
897 if(val == EXCEPTIONS_LIST[i]) {
898 return true;
899 }
900 }
901
902 return false;
903 }
904
905 //-----------------------------------------------------------------------------
CheckEverythingInSphere(EERIE_SPHERE * sphere,long source,long targ)906 bool CheckEverythingInSphere(EERIE_SPHERE * sphere,long source,long targ) //except source...
907 {
908 bool vreturn = false;
909 MAX_IN_SPHERE_Pos=0;
910
911 Entity * io;
912 long ret_idx=-1;
913
914 float sr30=sphere->radius+20.f;
915 float sr40=sphere->radius+30.f;
916 float sr180=sphere->radius+500.f;
917
918 for (long i=0;i<TREATZONE_CUR;i++)
919 {
920 if (targ>-1)
921 {
922 i=TREATZONE_CUR;
923 io=entities[targ];
924
925 if ( (!io)
926 || (InExceptionList(targ))
927 || (targ==source)
928 || (io->show!=SHOW_FLAG_IN_SCENE)
929 || !(io->gameFlags & GFLAG_ISINTREATZONE)
930 || !(io->obj)
931 )
932 return false;
933
934 ret_idx=targ;
935 }
936 else
937 {
938 if ( (treatio[i].show!=1) ||
939 (treatio[i].io==NULL) ||
940 (treatio[i].num==source) ||
941 (InExceptionList(treatio[i].num)) ) continue;
942
943 io=treatio[i].io;
944 ret_idx=treatio[i].num;
945 }
946
947 if (!(io->ioflags & IO_NPC) && (io->ioflags & IO_NO_COLLISIONS)) continue;
948
949 if (!io->obj) continue;
950
951
952 if (io->gameFlags & GFLAG_PLATFORM)
953 {
954 float miny,maxy;
955 miny=io->bbox3D.min.y;
956 maxy=io->bbox3D.max.y;
957
958 if ( (maxy<= sphere->origin.y+sphere->radius)
959 || (miny>= sphere->origin.y) )
960 if (In3DBBoxTolerance(&sphere->origin,&io->bbox3D,sphere->radius))
961 {
962 if(closerThan(Vec2f(io->pos.x, io->pos.z), Vec2f(sphere->origin.x, sphere->origin.z), 440.f + sphere->radius)) {
963
964 EERIEPOLY ep;
965 ep.type=0;
966
967 for (size_t ii=0;ii<io->obj->facelist.size();ii++)
968 {
969 float cx=0;
970 float cz=0;
971
972 for (long kk=0;kk<3;kk++)
973 {
974 cx+=ep.v[kk].p.x=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.x;
975 ep.v[kk].p.y=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.y;
976 cz+=ep.v[kk].p.z=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.z;
977 }
978
979 cx*=( 1.0f / 3 );
980 cz*=( 1.0f / 3 );
981
982 for (int kk=0;kk<3;kk++)
983 {
984 ep.v[kk].p.x=(ep.v[kk].p.x-cx)*3.5f+cx;
985 ep.v[kk].p.z=(ep.v[kk].p.z-cz)*3.5f+cz;
986 }
987
988 if (PointIn2DPolyXZ(&ep, sphere->origin.x, sphere->origin.z))
989 {
990 EVERYTHING_IN_SPHERE[MAX_IN_SPHERE_Pos]=(short)ret_idx;
991 MAX_IN_SPHERE_Pos++;
992
993 if (MAX_IN_SPHERE_Pos>=MAX_IN_SPHERE) MAX_IN_SPHERE_Pos--;
994
995 vreturn = true;
996 goto suivant;
997 }
998 }
999 }
1000 }
1001 }
1002
1003 if(distSqr(io->pos, sphere->origin) < square(sr180)) {
1004
1005 long amount=1;
1006 vector<EERIE_VERTEX> & vlist = io->obj->vertexlist3;
1007
1008 if (io->obj->nbgroups>4)
1009 {
1010 for (long ii=0;ii<io->obj->nbgroups;ii++)
1011 {
1012 if(distSqr(vlist[io->obj->grouplist[ii].origin].v, sphere->origin) < square(sr40)) {
1013 EVERYTHING_IN_SPHERE[MAX_IN_SPHERE_Pos]=(short)ret_idx;
1014 MAX_IN_SPHERE_Pos++;
1015
1016 if (MAX_IN_SPHERE_Pos>=MAX_IN_SPHERE) MAX_IN_SPHERE_Pos--;
1017
1018 vreturn = true;
1019 goto suivant;
1020 }
1021 }
1022
1023 amount=2;
1024 }
1025
1026 for (size_t ii=0;ii<io->obj->facelist.size();ii+=amount)
1027 {
1028 EERIE_FACE * ef=&io->obj->facelist[ii];
1029
1030 if (ef->facetype & POLY_HIDE) continue;
1031
1032 Vec3f fcenter = (vlist[ef->vid[0]].v + vlist[ef->vid[1]].v
1033 + vlist[ef->vid[2]].v) * (1.0f / 3);
1034 if (distSqr(fcenter, sphere->origin) < square(sr30) || distSqr(vlist[ef->vid[0]].v, sphere->origin) < square(sr30) || distSqr(vlist[ef->vid[1]].v, sphere->origin) < square(sr30) || distSqr(vlist[ef->vid[2]].v, sphere->origin) < square(sr30)) {
1035 EVERYTHING_IN_SPHERE[MAX_IN_SPHERE_Pos]=(short)ret_idx;
1036 MAX_IN_SPHERE_Pos++;
1037
1038 if (MAX_IN_SPHERE_Pos>=MAX_IN_SPHERE) MAX_IN_SPHERE_Pos--;
1039
1040 vreturn = true;
1041 goto suivant;
1042 }
1043 }
1044 }
1045
1046 suivant:
1047 ;
1048
1049 }
1050
1051 return vreturn;
1052 }
1053
1054 //-----------------------------------------------------------------------------
CheckBackgroundInSphere(EERIE_SPHERE * sphere)1055 EERIEPOLY * CheckBackgroundInSphere(EERIE_SPHERE * sphere) //except source...
1056 {
1057 long rad = sphere->radius*ACTIVEBKG->Xmul;
1058 rad+=2;
1059 long px,pz;
1060 px = sphere->origin.x * ACTIVEBKG->Xmul;
1061 pz = sphere->origin.z * ACTIVEBKG->Zmul;
1062
1063 EERIEPOLY * ep;
1064 FAST_BKG_DATA * feg;
1065 long spx=max(px-rad,0L);
1066 long epx=min(px+rad,ACTIVEBKG->Xsize-1L);
1067 long spz=max(pz-rad,0L);
1068 long epz=min(pz+rad,ACTIVEBKG->Zsize-1L);
1069
1070 for (long j=spz;j<=epz;j++)
1071 for (long i=spx;i<=epx;i++)
1072 {
1073 feg=&ACTIVEBKG->fastdata[i][j];
1074
1075 for (long k=0;k<feg->nbpoly;k++)
1076 {
1077 ep=&feg->polydata[k];
1078
1079 if (ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL)) continue;
1080
1081 if (IsPolyInSphere(ep,sphere))
1082 {
1083 return ep;
1084 }
1085 }
1086 }
1087
1088 return NULL;
1089 }
1090
1091 //-----------------------------------------------------------------------------
1092
CheckAnythingInSphere(EERIE_SPHERE * sphere,long source,CASFlags flags,long * num)1093 bool CheckAnythingInSphere(EERIE_SPHERE * sphere,long source,CASFlags flags,long * num) //except source...
1094 {
1095 if (num) *num=-1;
1096
1097 long rad = sphere->radius*ACTIVEBKG->Xmul;
1098 rad+=2;
1099 long px,pz;
1100 px = sphere->origin.x*ACTIVEBKG->Xmul;
1101 pz = sphere->origin.z*ACTIVEBKG->Zmul;
1102
1103 EERIEPOLY * ep;
1104 FAST_BKG_DATA * feg;
1105
1106 if (!(flags & CAS_NO_BACKGROUND_COL))
1107 {
1108 long spz=max(pz-rad,0L);
1109 long epz=min(pz+rad,ACTIVEBKG->Zsize-1L);
1110 long spx=max(px-rad,0L);
1111 long epx=min(px+rad,ACTIVEBKG->Xsize-1L);
1112
1113 for (long j=spz;j<=epz;j++)
1114 for (long i=spx;i<=epx;i++)
1115 {
1116 feg=&ACTIVEBKG->fastdata[i][j];
1117
1118 for (long k=0;k<feg->nbpoly;k++)
1119 {
1120 ep=&feg->polydata[k];
1121
1122 if (ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL)) continue;
1123
1124 if (IsPolyInSphere(ep,sphere))
1125 return true;
1126 }
1127 }
1128 }
1129
1130 if (flags & CAS_NO_NPC_COL) return false;
1131
1132 long validsource=0;
1133
1134 if (flags & CAS_NO_SAME_GROUP) validsource=ValidIONum(source);
1135
1136 Entity * io;
1137 float sr30=sphere->radius+20.f;
1138 float sr40=sphere->radius+30.f;
1139 float sr180=sphere->radius+500.f;
1140
1141 for (long i=0;i<TREATZONE_CUR;i++)
1142 {
1143
1144 if ( (treatio[i].show!=1) ||
1145 (treatio[i].io==NULL) ||
1146 (treatio[i].num==source)
1147 ) continue;
1148
1149 io=treatio[i].io;
1150
1151 if (!io->obj) continue;
1152
1153 if (!(io->ioflags & IO_NPC) && (io->ioflags & IO_NO_COLLISIONS)) continue;
1154
1155 if ((flags & CAS_NO_DEAD_COL) && (io->ioflags & IO_NPC) && (IsDeadNPC(io))) continue;
1156
1157 if ((io->ioflags & IO_FIX) && (flags & CAS_NO_FIX_COL)) continue;
1158
1159 if ((io->ioflags & IO_ITEM) && (flags & CAS_NO_ITEM_COL)) continue;
1160
1161 if ((treatio[i].num!=0) && (source!=0)
1162 && validsource && (HaveCommonGroup(io,entities[source])))
1163 continue;
1164
1165 if (io->gameFlags & GFLAG_PLATFORM)
1166 {
1167 float miny,maxy;
1168 miny=io->bbox3D.min.y;
1169 maxy=io->bbox3D.max.y;
1170
1171 if ( (maxy> sphere->origin.y-sphere->radius)
1172 || (miny< sphere->origin.y+sphere->radius) )
1173 if (In3DBBoxTolerance(&sphere->origin,&io->bbox3D,sphere->radius))
1174 {
1175 if(closerThan(Vec2f(io->pos.x, io->pos.z), Vec2f(sphere->origin.x, sphere->origin.z), 440.f + sphere->radius)) {
1176
1177 EERIEPOLY ep;
1178 ep.type=0;
1179
1180 for (size_t ii=0;ii<io->obj->facelist.size();ii++)
1181 {
1182 float cx=0;
1183 float cz=0;
1184
1185 for (long kk=0;kk<3;kk++)
1186 {
1187 cx+=ep.v[kk].p.x=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.x;
1188 ep.v[kk].p.y=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.y;
1189 cz+=ep.v[kk].p.z=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.z;
1190 }
1191
1192 cx*=( 1.0f / 3 );
1193 cz*=( 1.0f / 3 );
1194
1195 for (int kk=0;kk<3;kk++)
1196 {
1197 ep.v[kk].p.x=(ep.v[kk].p.x-cx)*3.5f+cx;
1198 ep.v[kk].p.z=(ep.v[kk].p.z-cz)*3.5f+cz;
1199 }
1200
1201 if (PointIn2DPolyXZ(&ep, sphere->origin.x, sphere->origin.z))
1202 {
1203 if (num) *num=treatio[i].num;
1204
1205 return true;
1206 }
1207 }
1208 }
1209 }
1210 }
1211
1212 if(distSqr(io->pos, sphere->origin) < square(sr180)) {
1213 long amount=1;
1214 vector<EERIE_VERTEX> & vlist=io->obj->vertexlist3;
1215
1216 if (io->obj->nbgroups>4)
1217 {
1218 for (long ii=0;ii<io->obj->nbgroups;ii++)
1219 {
1220 if (distSqr(vlist[io->obj->grouplist[ii].origin].v, sphere->origin) < square(sr40)) {
1221 if (num) *num=treatio[i].num;
1222
1223 return true;
1224 }
1225 }
1226
1227 amount=2;
1228 }
1229
1230 for (size_t ii=0;ii<io->obj->facelist.size();ii+=amount)
1231 {
1232
1233 if (io->obj->facelist[ii].facetype & POLY_HIDE) continue;
1234
1235 if(distSqr(vlist[io->obj->facelist[ii].vid[0]].v, sphere->origin) < square(sr30)
1236 || distSqr(vlist[io->obj->facelist[ii].vid[1]].v, sphere->origin) < square(sr30)) {
1237 if (num) *num=treatio[i].num;
1238 return true;
1239 }
1240 }
1241 }
1242
1243 }
1244
1245 return false;
1246 }
1247
1248
CheckIOInSphere(EERIE_SPHERE * sphere,long target,bool ignoreNoCollisionFlag)1249 bool CheckIOInSphere(EERIE_SPHERE * sphere, long target, bool ignoreNoCollisionFlag) {
1250
1251 if (!ValidIONum(target)) return false;
1252
1253 Entity * io=entities[target];
1254 float sr30 = sphere->radius + 22.f;
1255 float sr40 = sphere->radius + 27.f;
1256 float sr180=sphere->radius+500.f;
1257
1258 if ((ignoreNoCollisionFlag || !(io->ioflags & IO_NO_COLLISIONS))
1259 && (io->show==SHOW_FLAG_IN_SCENE)
1260 && (io->gameFlags & GFLAG_ISINTREATZONE)
1261 && (io->obj)
1262 )
1263 {
1264 if(distSqr(io->pos, sphere->origin) < square(sr180)) {
1265 vector<EERIE_VERTEX> & vlist = io->obj->vertexlist3;
1266
1267 if (io->obj->nbgroups>10)
1268 {
1269 long count=0;
1270 long ii=io->obj->nbgroups-1;
1271
1272 while (ii)
1273 {
1274 if(distSqr(vlist[io->obj->grouplist[ii].origin].v, sphere->origin) < square(sr40)) {
1275 count++;
1276 if (count>3) return true;
1277 }
1278
1279 ii--;
1280 }
1281 }
1282
1283 long count=0;
1284 long step;
1285
1286 if (io->obj->vertexlist.size()<150) step=1;
1287 else if (io->obj->vertexlist.size()<300) step=2;
1288 else if (io->obj->vertexlist.size()<600) step=4;
1289 else if (io->obj->vertexlist.size()<1200) step=6;
1290 else step=7;
1291
1292 for (size_t ii=0;ii<vlist.size();ii+=step)
1293 {
1294 if(closerThan(vlist[ii].v, sphere->origin, sr30)) {
1295 count++;
1296
1297 if (count>6) return true;
1298 }
1299
1300 if (io->obj->vertexlist.size()<120)
1301 {
1302 for (size_t kk=0;kk<vlist.size();kk+=1)
1303 {
1304 if (kk!=ii)
1305 {
1306 for (float nn=0.2f;nn<1.f;nn+=0.2f)
1307 {
1308 Vec3f posi = vlist[ii].v * nn + vlist[kk].v * (1.f - nn);
1309 if(distSqr(sphere->origin, posi) <= square(sr30 + 20)) {
1310 count++;
1311
1312 if (count>3)
1313 {
1314 if (io->ioflags & IO_FIX)
1315 return true;
1316
1317 if (count>6)
1318 return true;
1319 }
1320 }
1321 }
1322 }
1323 }
1324 }
1325 }
1326
1327 if ((count>3) && (io->ioflags & IO_FIX))
1328 return true;
1329
1330 }
1331 }
1332
1333 return false;
1334 }
1335
1336
1337 float MAX_ALLOWED_PER_SECOND=12.f;
1338 //-----------------------------------------------------------------------------
1339 // Checks if a position is valid, Modify it for height if necessary
1340 // Returns true or false
1341
AttemptValidCylinderPos(EERIE_CYLINDER * cyl,Entity * io,CollisionFlags flags)1342 bool AttemptValidCylinderPos(EERIE_CYLINDER * cyl, Entity * io, CollisionFlags flags) {
1343
1344 float anything = CheckAnythingInCylinder(cyl, io, flags);
1345
1346 if ((flags & CFLAG_LEVITATE) && (anything==0.f)) return true;
1347
1348 if (anything>=0.f) // Falling Cylinder but valid pos !
1349 {
1350 if (flags & CFLAG_RETURN_HEIGHT)
1351 cyl->origin.y+=anything;
1352
1353 return true;
1354 }
1355
1356 EERIE_CYLINDER tmp;
1357
1358 if (!(flags & CFLAG_ANCHOR_GENERATION))
1359 {
1360
1361 memcpy(&tmp,cyl,sizeof(EERIE_CYLINDER));
1362
1363 while (anything<0.f)
1364 {
1365 tmp.origin.y+=anything;
1366 anything=CheckAnythingInCylinder(&tmp,io,flags);
1367 }
1368
1369 anything=tmp.origin.y-cyl->origin.y;
1370 }
1371
1372 if (MOVING_CYLINDER)
1373 {
1374 if (flags & CFLAG_NPC)
1375 {
1376 float tolerate;
1377
1378 if((flags & CFLAG_PLAYER) && player.jumpphase != NotJumping) {
1379 tolerate=0;
1380 }
1381 else if ((io) && (io->ioflags & IO_NPC) && (io->_npcdata->pathfind.listnb > 0) && (io->_npcdata->pathfind.listpos < io->_npcdata->pathfind.listnb))
1382 {
1383 tolerate=-65-io->_npcdata->moveproblem;
1384 }
1385 else
1386 {
1387 if ((io) &&
1388 (io->_npcdata))
1389 {
1390 tolerate = -55 - io->_npcdata->moveproblem;
1391 }
1392 else
1393 {
1394 tolerate=0.f;
1395 }
1396 }
1397
1398 if(NPC_IN_CYLINDER) {
1399 tolerate = cyl->height * 0.5f;
1400 }
1401
1402 if(anything < tolerate) {
1403 return false;
1404 }
1405 }
1406
1407 if (io && (flags & CFLAG_PLAYER) && (anything<0.f) && (flags & CFLAG_JUST_TEST))
1408 {
1409 EERIE_CYLINDER tmpp;
1410 memcpy(&tmpp,cyl,sizeof(EERIE_CYLINDER));
1411 tmpp.radius*=0.7f;
1412 float tmp=CheckAnythingInCylinder(&tmpp,io,flags | CFLAG_JUST_TEST);
1413
1414 if ((tmp > 50.f))
1415 {
1416 tmpp.radius=cyl->radius*1.4f;
1417 tmpp.origin.y-=30.f;
1418 float tmp=CheckAnythingInCylinder(&tmpp,io,flags | CFLAG_JUST_TEST);
1419
1420 if (tmp<0)
1421 return false;
1422 }
1423 }
1424
1425 if (io && (!(flags & CFLAG_JUST_TEST)))
1426 {
1427 if ((flags & CFLAG_PLAYER) && (anything<0.f))
1428 {
1429
1430 if(player.jumpphase != NotJumping) {
1431 io->_npcdata->climb_count = MAX_ALLOWED_PER_SECOND;
1432 return false;
1433 }
1434
1435 float dist = max(vector2D.length(),1.f);
1436 float pente = EEfabs(anything) / dist * ( 1.0f / 2 );
1437 io->_npcdata->climb_count+=pente;
1438
1439 if (io->_npcdata->climb_count>MAX_ALLOWED_PER_SECOND)
1440 {
1441 io->_npcdata->climb_count=MAX_ALLOWED_PER_SECOND;
1442 }
1443
1444 if (anything < -55)
1445 {
1446 io->_npcdata->climb_count=MAX_ALLOWED_PER_SECOND;
1447 return false;
1448 }
1449
1450 EERIE_CYLINDER tmpp;
1451 memcpy(&tmpp,cyl,sizeof(EERIE_CYLINDER));
1452 tmpp.radius *= 0.65f;
1453 float tmp=CheckAnythingInCylinder(&tmpp,io,flags | CFLAG_JUST_TEST);
1454
1455 if (tmp > 50.f)
1456 {
1457 tmpp.radius=cyl->radius*1.45f;
1458 tmpp.origin.y-=30.f;
1459 float tmp=CheckAnythingInCylinder(&tmpp,io,flags | CFLAG_JUST_TEST);
1460
1461 if (tmp<0)
1462 return false;
1463 }
1464 }
1465 }
1466 }
1467 else if (anything<-45) return false;
1468
1469 if ((flags & CFLAG_SPECIAL) && (anything<-40))
1470 {
1471 if (flags & CFLAG_RETURN_HEIGHT)
1472 cyl->origin.y+=anything;
1473
1474 return false;
1475 }
1476
1477 memcpy(&tmp,cyl,sizeof(EERIE_CYLINDER));
1478 tmp.origin.y+=anything;
1479 anything = CheckAnythingInCylinder(&tmp, io, flags);
1480
1481 if (anything<0.f)
1482 {
1483 if (flags & CFLAG_RETURN_HEIGHT)
1484 {
1485 while (anything<0.f)
1486 {
1487 tmp.origin.y+=anything;
1488 anything=CheckAnythingInCylinder(&tmp,io,flags);
1489 }
1490
1491 cyl->origin.y = tmp.origin.y;
1492 }
1493
1494 return false;
1495 }
1496
1497 cyl->origin.y=tmp.origin.y;
1498 return true;
1499 }
1500
1501 //----------------------------------------------------------------------------------------------
1502 //flags & 1 levitate
1503 //flags & 2 no inter col
1504 //flags & 4 special
1505 //flags & 8 easier sliding.
1506 //flags & 16 climbing !!!
1507 //flags & 32 Just Test !!!
1508 //flags & 64 NPC mode
1509 //----------------------------------------------------------------------------------------------
ARX_COLLISION_Move_Cylinder(IO_PHYSICS * ip,Entity * io,float MOVE_CYLINDER_STEP,CollisionFlags flags)1510 bool ARX_COLLISION_Move_Cylinder(IO_PHYSICS * ip,Entity * io,float MOVE_CYLINDER_STEP, CollisionFlags flags)
1511 {
1512 // HERMESPerf script(HPERF_PHYSICS);
1513 // +5 on 15
1514 //
1515 // memcpy(&ip->cyl.origin,&ip->targetpos,sizeof(EERIE_3D));
1516 // return true;
1517
1518 ON_PLATFORM=0;
1519 MOVING_CYLINDER=1;
1520 COLLIDED_CLIMB_POLY=0;
1521 DIRECT_PATH=true;
1522 IO_PHYSICS test;
1523
1524 if (ip==NULL)
1525 {
1526 MOVING_CYLINDER=0;
1527 return false;
1528 }
1529
1530 float distance = dist(ip->startpos, ip->targetpos);
1531
1532 if (distance < 0.1f)
1533 {
1534 MOVING_CYLINDER=0;
1535
1536 if (distance==0.f)
1537 return true;
1538
1539 return false;
1540 }
1541
1542 Vec3f mvector = (ip->targetpos - ip->startpos) / distance;
1543 long count=100;
1544
1545 while ((distance>0.f) && (count--))
1546 {
1547 // First We compute current increment
1548 float curmovedist=min(distance,MOVE_CYLINDER_STEP);
1549 distance-=curmovedist;
1550
1551 // Store our cylinder desc into a test struct
1552 memcpy(&test,ip,sizeof(IO_PHYSICS));
1553
1554 // uses test struct to simulate movement.
1555 vector2D.x=mvector.x*curmovedist;
1556 vector2D.y=0.f;
1557 vector2D.z=mvector.z*curmovedist;
1558
1559 test.cyl.origin.x += vector2D.x;
1560 test.cyl.origin.y+=mvector.y*curmovedist;
1561 test.cyl.origin.z += vector2D.z;
1562
1563 if ((flags & CFLAG_CHECK_VALID_POS)
1564 && (CylinderAboveInvalidZone(&test.cyl)))
1565 return false;
1566
1567 if (AttemptValidCylinderPos(&test.cyl,io,flags))
1568 {
1569 // Found without complication
1570 memcpy(ip,&test,sizeof(IO_PHYSICS));
1571 }
1572 else
1573 {
1574 //return false;
1575 if ((mvector.x==0.f) && (mvector.z==0.f))
1576 return true;
1577
1578 if (flags & CFLAG_CLIMBING)
1579 {
1580 memcpy(&test.cyl, &ip->cyl, sizeof(EERIE_CYLINDER));
1581 test.cyl.origin.y+=mvector.y*curmovedist;
1582
1583 if (AttemptValidCylinderPos(&test.cyl,io,flags))
1584 {
1585 memcpy(ip,&test,sizeof(IO_PHYSICS));
1586 goto oki;
1587 }
1588 }
1589
1590 DIRECT_PATH=false;
1591 // Must Attempt To Slide along collisions
1592 Vec3f vecatt;
1593 Vec3f rpos;
1594 Vec3f lpos;
1595 long RFOUND=0;
1596 long LFOUND=0;
1597 long maxRANGLE=90;
1598 float ANGLESTEPP;
1599
1600 if (flags & CFLAG_EASY_SLIDING) // player sliding in fact...
1601 {
1602 ANGLESTEPP=10.f;
1603 maxRANGLE=70;
1604 }
1605 else ANGLESTEPP=30.f;
1606
1607 float rangle = ANGLESTEPP;
1608 float langle = 360.f - ANGLESTEPP;
1609
1610
1611 while (rangle<=maxRANGLE) //tries on the Right and Left sides
1612 {
1613 memcpy(&test.cyl, &ip->cyl, sizeof(EERIE_CYLINDER));
1614 float t=radians(MAKEANGLE(rangle));
1615 YRotatePoint(&mvector,&vecatt,EEcos(t),EEsin(t));
1616 test.cyl.origin += vecatt * curmovedist;
1617 float cc=io->_npcdata->climb_count;
1618
1619 if (AttemptValidCylinderPos(&test.cyl, io, flags))
1620 {
1621 rpos = test.cyl.origin;
1622 RFOUND=1;
1623 }
1624 else io->_npcdata->climb_count=cc;
1625
1626 rangle+=ANGLESTEPP;
1627
1628 memcpy(&test.cyl, &ip->cyl, sizeof(EERIE_CYLINDER));
1629 t=radians(MAKEANGLE(langle));
1630 YRotatePoint(&mvector,&vecatt,EEcos(t),EEsin(t));
1631 test.cyl.origin += vecatt * curmovedist;
1632 cc=io->_npcdata->climb_count;
1633
1634 if (AttemptValidCylinderPos(&test.cyl, io, flags))
1635 {
1636 lpos = test.cyl.origin;
1637 LFOUND=1;
1638 }
1639 else io->_npcdata->climb_count=cc;
1640
1641 langle-=ANGLESTEPP;
1642
1643 if ((RFOUND) || (LFOUND)) break;
1644 }
1645
1646 if ((LFOUND) && (RFOUND))
1647 {
1648 langle=360.f-langle;
1649
1650 if (langle<rangle)
1651 {
1652 ip->cyl.origin = lpos;
1653 distance -= curmovedist;
1654 }
1655 else
1656 {
1657 ip->cyl.origin = rpos;
1658 distance -= curmovedist;
1659 }
1660 }
1661 else if (LFOUND)
1662 {
1663 ip->cyl.origin = lpos;
1664 distance -= curmovedist;
1665 }
1666 else if (RFOUND)
1667 {
1668 ip->cyl.origin = rpos;
1669 distance -= curmovedist;
1670 }
1671 else //stopped
1672 {
1673 ip->velocity = Vec3f::ZERO;
1674 MOVING_CYLINDER=0;
1675 return false;
1676 }
1677 }
1678
1679 if (flags & CFLAG_NO_HEIGHT_MOD)
1680 {
1681 if (EEfabs(ip->startpos.y - ip->cyl.origin.y)>30.f)
1682 return false;
1683 }
1684
1685 oki:
1686 ;
1687 }
1688
1689 MOVING_CYLINDER=0;
1690 return true;
1691 }
1692
1693 //-----------------------------------------------------------------------------
IO_Visible(Vec3f * orgn,Vec3f * dest,EERIEPOLY * epp,Vec3f * hit)1694 bool IO_Visible(Vec3f * orgn, Vec3f * dest,EERIEPOLY * epp,Vec3f * hit)
1695 {
1696
1697
1698 float x,y,z; //current ray pos
1699 float dx,dy,dz; // ray incs
1700 float adx,ady,adz; // absolute ray incs
1701 float ix,iy,iz;
1702 long px,pz;
1703 EERIEPOLY * ep;
1704
1705 FAST_BKG_DATA * feg;
1706 float pas=35.f;
1707
1708
1709 Vec3f found_hit = Vec3f::ZERO;
1710 EERIEPOLY * found_ep=NULL;
1711 float iter,t;
1712
1713 x=orgn->x;
1714 y=orgn->y;
1715 z=orgn->z;
1716 float distance;
1717 float nearest = distance = fdist(*orgn, *dest);
1718
1719 if (distance<pas) pas=distance*( 1.0f / 2 );
1720
1721 dx=(dest->x-orgn->x);
1722 adx=EEfabs(dx);
1723 dy=(dest->y-orgn->y);
1724 ady=EEfabs(dy);
1725 dz=(dest->z-orgn->z);
1726 adz=EEfabs(dz);
1727
1728 if ( (adx>=ady) && (adx>=adz))
1729 {
1730 if (adx != dx)
1731 {
1732 ix = -pas;
1733 }
1734 else
1735 {
1736 ix = pas;
1737 }
1738
1739 iter=adx/pas;
1740 t=1.f/(iter);
1741 iy=dy*t;
1742 iz=dz*t;
1743 }
1744 else if ( (ady>=adx) && (ady>=adz))
1745 {
1746 if (ady != dy)
1747 {
1748 iy = -pas;
1749 }
1750 else
1751 {
1752 iy = pas;
1753 }
1754
1755 iter=ady/pas;
1756 t=1.f/(iter);
1757 ix=dx*t;
1758 iz=dz*t;
1759 }
1760 else
1761 {
1762 if (adz != dz)
1763 {
1764 iz = -pas;
1765 }
1766 else
1767 {
1768 iz = pas;
1769 }
1770
1771 iter=adz/pas;
1772 t=1.f/(iter);
1773 ix=dx*t;
1774 iy=dy*t;
1775 }
1776
1777 float dd;
1778 x-=ix;
1779 y-=iy;
1780 z-=iz;
1781
1782 while (iter>0.f)
1783 {
1784 iter-=1.f;
1785 x+=ix;
1786 y+=iy;
1787 z+=iz;
1788
1789 EERIE_SPHERE sphere;
1790 sphere.origin.x=x;
1791 sphere.origin.y=y;
1792 sphere.origin.z=z;
1793 sphere.radius=65.f;
1794
1795 for(size_t num = 0; num < entities.size(); num++) {
1796 Entity * io = entities[num];
1797
1798 if ((io) && (io->gameFlags & GFLAG_VIEW_BLOCKER))
1799 {
1800 if ( CheckIOInSphere(&sphere,num) )
1801 {
1802 dd = fdist(*orgn, sphere.origin);
1803
1804 if (dd<nearest)
1805 {
1806 hit->x=x;
1807 hit->y=y;
1808 hit->z=z;
1809 return false;
1810 }
1811 }
1812 }
1813 }
1814
1815 px=(long)(x* ACTIVEBKG->Xmul);
1816 pz=(long)(z* ACTIVEBKG->Zmul);
1817
1818 if (px>=ACTIVEBKG->Xsize) goto fini;
1819 else if (px< 0) goto fini;
1820
1821 if (pz>= ACTIVEBKG->Zsize) goto fini;
1822 else if (pz< 0) goto fini;
1823
1824 feg=&ACTIVEBKG->fastdata[px][pz];
1825
1826 for (long k=0;k<feg->nbpolyin;k++)
1827 {
1828 ep=feg->polyin[k];
1829
1830 if (!(ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL) ) )
1831 if ((ep->min.y-pas<y) && (ep->max.y+pas>y))
1832 if ((ep->min.x-pas<x) && (ep->max.x+pas>x))
1833 if ((ep->min.z-pas<z) && (ep->max.z+pas>z))
1834 {
1835 if (RayCollidingPoly(orgn,dest,ep,hit))
1836 {
1837 dd = fdist(*orgn, *hit);
1838 if(dd < nearest) {
1839 nearest = dd;
1840 found_ep = ep;
1841 found_hit = *hit;
1842 }
1843 }
1844 }
1845 }
1846
1847 }
1848
1849 fini:
1850 ;
1851
1852 if ( found_ep == NULL ) return true;
1853
1854 if ( found_ep == epp ) return true;
1855
1856 *hit = found_hit;
1857 return false;
1858 }
ANCHOR_BLOCK_Clear()1859 void ANCHOR_BLOCK_Clear()
1860 {
1861 EERIE_BACKGROUND * eb=ACTIVEBKG;
1862
1863 if (eb)
1864 {
1865 for (long k=0;k<eb->nbanchors;k++)
1866 {
1867 ANCHOR_DATA * ad=&eb->anchors[k];
1868 ad->flags&=~ANCHOR_FLAG_BLOCKED;
1869 }
1870 }
1871 }
1872
ANCHOR_BLOCK_By_IO(Entity * io,long status)1873 void ANCHOR_BLOCK_By_IO(Entity * io,long status)
1874 {
1875 EERIE_BACKGROUND * eb=ACTIVEBKG;
1876
1877 for (long k=0;k<eb->nbanchors;k++)
1878 {
1879 ANCHOR_DATA * ad=&eb->anchors[k];
1880
1881 if (distSqr(ad->pos, io->pos) > square(600.f)) continue;
1882
1883 if(closerThan(Vec2f(io->pos.x, io->pos.z), Vec2f(ad->pos.x, ad->pos.z), 440.f)) {
1884
1885 EERIEPOLY ep;
1886 ep.type=0;
1887
1888 for (size_t ii=0;ii<io->obj->facelist.size();ii++)
1889 {
1890 float cx=0;
1891 float cz=0;
1892
1893 for (long kk=0;kk<3;kk++)
1894 {
1895 cx+=ep.v[kk].p.x=io->obj->vertexlist[io->obj->facelist[ii].vid[kk]].v.x+io->pos.x;
1896 ep.v[kk].p.y=io->obj->vertexlist[io->obj->facelist[ii].vid[kk]].v.y+io->pos.y;
1897 cz+=ep.v[kk].p.z=io->obj->vertexlist[io->obj->facelist[ii].vid[kk]].v.z+io->pos.z;
1898 }
1899
1900 cx*=( 1.0f / 3 );
1901 cz*=( 1.0f / 3 );
1902
1903 for (int kk=0;kk<3;kk++)
1904 {
1905 ep.v[kk].p.x=(ep.v[kk].p.x-cx)*3.5f+cx;
1906 ep.v[kk].p.z=(ep.v[kk].p.z-cz)*3.5f+cz;
1907 }
1908
1909 if (PointIn2DPolyXZ(&ep, ad->pos.x, ad->pos.z))
1910 {
1911 if (status)
1912 ad->flags|=ANCHOR_FLAG_BLOCKED;
1913 else
1914 ad->flags&=~ANCHOR_FLAG_BLOCKED;
1915 }
1916 }
1917 }
1918 }
1919 }
1920