/* =========================================================================== ARX FATALIS GPL Source Code Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company. This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code'). Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see . In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ ////////////////////////////////////////////////////////////////////////////////////// // @@ @@@ @@@ @@ @@@@@ // // @@@ @@@@@@ @@@ @@ @@@@ @@@ @@@ // // @@@ @@@@@@@ @@@ @@@@ @@@@ @@ @@@@ // // @@@ @@ @@@@ @@@ @@@@@ @@@@@@ @@@ @@@ // // @@@@@ @@ @@@@ @@@ @@@@@ @@@@@@@ @@@ @ @@@ // // @@@@@ @@ @@@@ @@@@@@@@ @@@@ @@@ @@@@@ @@ @@@@@@@ // // @@ @@@ @@ @@@@ @@@@@@@ @@@ @@@ @@@@@@ @@ @@@@ // // @@@ @@@ @@@ @@@@ @@@@@ @@@@@@@@@ @@@@@@@ @@@ @@@@ // // @@@ @@@@ @@@@@@@ @@@@@@ @@@ @@@@ @@@ @@@ @@@ @@@@ // // @@@@@@@@ @@@@@ @@@@@@@@@@ @@@ @@@ @@@ @@@ @@@ @@@@@ // // @@@ @@@@ @@@@ @@@ @@@@@@@ @@@ @@@ @@@@ @@@ @@@@ @@@@@ // //@@@ @@@@ @@@@@ @@@ @@@@@@ @@ @@@ @@@@ @@@@@@@ @@@@@ @@@@@ // //@@@ @@@@@ @@@@@ @@@@ @@@ @@ @@ @@@@ @@@@@@@ @@@@@@@@@ // //@@@ @@@@ @@@@@@@ @@@@ @@ @@ @@@@ @@@@@ @@@@@ // //@@@ @@@@ @@@@@@@ @@@@ @@ @@ @@@@ @@@@@ @@ // //@@@ @@@ @@@ @@@@@ @@ @@@ // // @@@ @@@ @@ @@ STUDIOS // ////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////// // ARX_Collisions ////////////////////////////////////////////////////////////////////////////////////// // // Description: // ARX Collisions Management // // Updates: (date) (person) (update) // // Code: Cyril Meynier // // Copyright (c) 1999-2001 ARKANE Studios SA. All rights reserved ////////////////////////////////////////////////////////////////////////////////////// #include #include "ARX_Collisions.h" #include "HERMESMain.h" #include "EERIEMath.h" #include "ARX_Damages.h" #include "ARX_Interactive.h" #include "ARX_NPC.h" #include "ARX_Time.h" #define _CRTDBG_MAP_ALLOC #include //----------------------------------------------------------------------------- #define MAX_IN_SPHERE 20 //----------------------------------------------------------------------------- extern float FrameDiff; long ON_PLATFORM=0; //----------------------------------------------------------------------------- long MAX_IN_SPHERE_Pos=0; short EVERYTHING_IN_SPHERE[MAX_IN_SPHERE+1]; long EXCEPTIONS_LIST_Pos=0; short EXCEPTIONS_LIST[MAX_IN_SPHERE+1]; long POLYIN=0; long COLLIDED_CLIMB_POLY=0; INTERACTIVE_OBJ * PUSHABLE_NPC=NULL; long MOVING_CYLINDER=0; EERIE_3D vector2D; BOOL DIRECT_PATH=TRUE; long APPLY_PUSH=0; //----------------------------------------------------------------------------- // Added immediate return (return anything;) __inline float IsPolyInCylinder(EERIEPOLY *ep, EERIE_CYLINDER * cyl,long flag) { long flags=flag; POLYIN=0; float min = cyl->origin.y + cyl->height; float max = cyl->origin.y; if (min>ep->max.y) return 999999.f; if (maxmin.y) return 999999.f; long to; if (ep->type & POLY_QUAD) to=4; else to=3; float nearest = 99999999.f; for (long num=0;numv[num].sx,ep->v[num].sz,cyl->origin.x,cyl->origin.z); if (dd__max(82.f,cyl->radius)) return 999999.f; if ( (cyl->radius<30.f) || (cyl->height>-80.f) || (ep->area>5000.f) ) flags|=CFLAG_EXTRA_PRECISION; if (!(flags & CFLAG_EXTRA_PRECISION)) { if (ep->area<100.f) return 999999.f; } float anything=999999.f; if (PointInCylinder(cyl, &ep->center)) { POLYIN = 1; if (ep->norm.y<0.5f) anything=__min(anything,ep->min.y); else anything=__min(anything,ep->center.y); if (!(flags & CFLAG_EXTRA_PRECISION)) return anything; } long r=to-1; EERIE_3D center; long n; for (n=0;nv[n].sx*p+ep->center.x*(1.f-p)); center.y=(ep->v[n].sy*p+ep->center.y*(1.f-p)); center.z=(ep->v[n].sz*p+ep->center.z*(1.f-p)); if (PointInCylinder(cyl, ¢er)) { anything=__min(anything,center.y); POLYIN=1; if (!(flags & CFLAG_EXTRA_PRECISION)) return anything; } } } if ((ep->area>2000.f) || (flags & CFLAG_EXTRA_PRECISION) ) { center.x=(ep->v[n].sx+ep->v[r].sx)*DIV2; center.y=(ep->v[n].sy+ep->v[r].sy)*DIV2; center.z=(ep->v[n].sz+ep->v[r].sz)*DIV2; if (PointInCylinder(cyl, ¢er)) { anything=__min(anything,center.y); POLYIN=1; if (!(flags & CFLAG_EXTRA_PRECISION)) return anything; } if ((ep->area>4000.f) || (flags & CFLAG_EXTRA_PRECISION)) { center.x=(ep->v[n].sx+ep->center.x)*DIV2; center.y=(ep->v[n].sy+ep->center.y)*DIV2; center.z=(ep->v[n].sz+ep->center.z)*DIV2; if (PointInCylinder(cyl, ¢er)) { anything=__min(anything,center.y); POLYIN=1; if (!(flags & CFLAG_EXTRA_PRECISION)) return anything; } } if ((ep->area>6000.f) || (flags & CFLAG_EXTRA_PRECISION)) { center.x=(center.x+ep->v[n].sx)*DIV2; center.y=(center.y+ep->v[n].sy)*DIV2; center.z=(center.z+ep->v[n].sz)*DIV2; if (PointInCylinder(cyl, ¢er)) { anything=__min(anything,center.y); POLYIN=1; if (!(flags & CFLAG_EXTRA_PRECISION)) return anything; } } } if (PointInCylinder(cyl, (EERIE_3D *)&ep->v[n])) { anything=__min(anything,ep->v[n].sy); POLYIN=1; if (!(flags & CFLAG_EXTRA_PRECISION)) return anything; } r++; if (r>=to) r=0; } // To Add "more" precision /*if (flags & CFLAG_EXTRA_PRECISION) { for (long j=0;j<360;j+=90) { float xx=-EEsin(DEG2RAD((float)j))*cyl->radius; float yy=EEcos(DEG2RAD((float)j))*cyl->radius; EERIE_3D pos; pos.x=cyl->origin.x+xx; pos.z=cyl->origin.z+yy; //EERIEPOLY * epp; if (PointIn2DPolyXZ(ep, pos.x, pos.z)) { if (GetTruePolyY(ep,&pos,&xx)) { anything=__min(anything,xx); return anything; } } } //}*/ if ((anything!=999999.f) && (ep->norm.y<0.1f) && (ep->norm.y>-0.1f)) anything=__min(anything,ep->min.y); return anything; } //----------------------------------------------------------------------------- __inline BOOL IsPolyInSphere(EERIEPOLY *ep, EERIE_SPHERE * sph) { if ((!ep) || (!sph)) return FALSE; if (ep->area<100.f) return FALSE; long to; if (ep->type & POLY_QUAD) to=4; else to=3; long r=to-1; EERIE_3D center; for (long n=0;narea>2000.f) { center.x=(ep->v[n].sx+ep->v[r].sx)*DIV2; center.y=(ep->v[n].sy+ep->v[r].sy)*DIV2; center.z=(ep->v[n].sz+ep->v[r].sz)*DIV2; if (EEDistance3D(&sph->origin, ¢er) < sph->radius) { return TRUE; } if (ep->area>4000.f) { center.x=(ep->v[n].sx+ep->center.x)*DIV2; center.y=(ep->v[n].sy+ep->center.y)*DIV2; center.z=(ep->v[n].sz+ep->center.z)*DIV2; if (EEDistance3D(&sph->origin, ¢er) < sph->radius) { return TRUE; } } if (ep->area>6000.f) { center.x=(center.x+ep->v[n].sx)*DIV2; center.y=(center.y+ep->v[n].sy)*DIV2; center.z=(center.z+ep->v[n].sz)*DIV2; if (EEDistance3D(&sph->origin, ¢er) < sph->radius) { return TRUE; } } } if (EEDistance3D(&sph->origin, (EERIE_3D *)&ep->v[n]) < sph->radius) { return TRUE; } r++; if (r>=to) r=0; } return FALSE; } //----------------------------------------------------------------------------- BOOL IsCollidingIO(INTERACTIVE_OBJ * io,INTERACTIVE_OBJ * ioo) { if ( (ioo!=NULL) && (io!=ioo) && !(ioo->ioflags & IO_NO_COLLISIONS) && (ioo->show==SHOW_FLAG_IN_SCENE) && (ioo->obj) ) { if (ioo->ioflags & IO_NPC) { float old=ioo->physics.cyl.radius; ioo->physics.cyl.radius+=25.f; for (long j=0;jobj->nbvertex;j++) { if (PointInCylinder(&ioo->physics.cyl,&io->obj->vertexlist3[j].v)) { ioo->physics.cyl.radius=old; return TRUE; } } ioo->physics.cyl.radius=old; } } return FALSE; } extern void GetIOCyl(INTERACTIVE_OBJ * io,EERIE_CYLINDER * cyl); void PushIO_ON_Top(INTERACTIVE_OBJ * ioo,float ydec) { if (ydec!=0.f) for (long i=0;iioflags & IO_NO_COLLISIONS) && (io->show==SHOW_FLAG_IN_SCENE) && (io->obj) && (!(io->ioflags & (IO_FIX | IO_CAMERA | IO_MARKER))) ) { if (Distance2D(io->pos.x,io->pos.z,ioo->pos.x,ioo->pos.z)<450.f) { EERIEPOLY ep; ep.type=0; float miny=9999999.f; float maxy=-9999999.f; for (long ii=0;iiobj->nbvertex;ii++) { miny=__min(miny,ioo->obj->vertexlist3[ii].v.y); maxy=__max(maxy,ioo->obj->vertexlist3[ii].v.y); } float posy; if (io==inter.iobj[0]) posy=player.pos.y-PLAYER_BASE_HEIGHT; else posy=io->pos.y; float modd=0; if (ydec>0) modd=-20.f; if ((posy<=maxy) && (posy>=miny+modd)) { for (long ii=0;iiobj->nbfaces;ii++) { float cx=0; float cz=0; for (long kk=0;kk<3;kk++) { cx+=ep.v[kk].sx=ioo->obj->vertexlist3[ioo->obj->facelist[ii].vid[kk]].v.x; ep.v[kk].sy=ioo->obj->vertexlist3[ioo->obj->facelist[ii].vid[kk]].v.y; cz+=ep.v[kk].sz=ioo->obj->vertexlist3[ioo->obj->facelist[ii].vid[kk]].v.z; } cx*=DIV3; cz*=DIV3; float tval=1.1f; for (int kk=0;kk<3;kk++) { ep.v[kk].sx = (ep.v[kk].sx - cx) * tval + cx; ep.v[kk].sz = (ep.v[kk].sz - cz) * tval + cz; } if (PointIn2DPolyXZ(&ep, io->pos.x, io->pos.z)) { EERIE_CYLINDER cyl; if (io==inter.iobj[0]) { if (ydec<=0) { player.pos.y+=ydec; moveto.y+=ydec; cyl.origin.x=player.pos.x; cyl.origin.y=player.pos.y+170.f+ydec; cyl.origin.z=player.pos.z; cyl.height=PLAYER_BASE_HEIGHT; cyl.radius=PLAYER_BASE_RADIUS; float vv; if ((vv=CheckAnythingInCylinder(&cyl,inter.iobj[0],0))<0) { player.pos.y+=ydec+vv; } } else { cyl.origin.x=player.pos.x; cyl.origin.y=player.pos.y+170.f+ydec; cyl.origin.z=player.pos.z; cyl.height=PLAYER_BASE_HEIGHT; cyl.radius=PLAYER_BASE_RADIUS; if (CheckAnythingInCylinder(&cyl,inter.iobj[0],0)>=0) { player.pos.y+=ydec; moveto.y+=ydec; } } } else { if (ydec<=0) { io->pos.y+=ydec; } else { GetIOCyl(io,&cyl); cyl.origin.y=io->pos.y+ydec; if (CheckAnythingInCylinder(&cyl,io,0)>=0) io->pos.y+=ydec; } } break; } } } } } } } //----------------------------------------------------------------------------- bool IsAnyNPCInPlatform(INTERACTIVE_OBJ * pfrm) { for (long i=0;iioflags & IO_NPC) && !(io->ioflags & IO_NO_COLLISIONS) && (io->show==SHOW_FLAG_IN_SCENE) ) { EERIE_CYLINDER cyl; GetIOCyl(io,&cyl); if (CylinderPlatformCollide(&cyl,pfrm)!=0.f) return TRUE; } } return FALSE; } float CylinderPlatformCollide(EERIE_CYLINDER * cyl,INTERACTIVE_OBJ * io) { float miny,maxy; miny=io->bbox3D.min.y; maxy=io->bbox3D.max.y; if (maxy <= cyl->origin.y + cyl->height) return 0; if (miny >= cyl->origin.y) return 0; if (In3DBBoxTolerance(&cyl->origin,&io->bbox3D,cyl->radius)) { return 1.f; } return 0.f; } long NPC_IN_CYLINDER=0; // backup du dernier polingue EERIEPOLY * pEPBackup = NULL; int iXBackup = -1; int iYBackup = -1; extern int TSU_TEST_COLLISIONS; extern void GetIOCyl(INTERACTIVE_OBJ * io,EERIE_CYLINDER * cyl); __inline void EE_RotateY(D3DTLVERTEX *in,D3DTLVERTEX *out,float c, float s) { out->sx = (in->sx*c) + (in->sz*s); out->sy = in->sy; out->sz = (in->sz*c) - (in->sx*s); } bool CollidedFromBack(INTERACTIVE_OBJ * io,INTERACTIVE_OBJ * ioo) { // io was collided from back ? EERIEPOLY ep; ep.type=0; if ( (io ) && (ioo) && (io->ioflags & IO_NPC) && (ioo->ioflags & IO_NPC) ) { ep.v[0].sx=io->pos.x; ep.v[0].sz=io->pos.z; float ft=DEG2RAD(135.f+90.f); ep.v[1].sx = EEsin(ft) * 180.f; ep.v[1].sz = -EEcos(ft) * 180.f; ft=DEG2RAD(225.f+90.f); ep.v[2].sx = EEsin(ft) * 180.f; ep.v[2].sz = -EEcos(ft) * 180.f; ft=DEG2RAD(270.f-io->angle.b); float ec=EEcos(ft); float es=EEsin(ft); EE_RotateY( &ep.v[1] , &ep.tv[1] , ec , es ); EE_RotateY( &ep.v[2] , &ep.tv[2] , ec , es ); ep.v[1].sx=ep.tv[1].sx+ep.v[0].sx; ep.v[1].sz=ep.tv[1].sz+ep.v[0].sz; ep.v[2].sx=ep.tv[2].sx+ep.v[0].sx; ep.v[2].sz=ep.tv[2].sz+ep.v[0].sz; // To keep if we need some visual debug if (PointIn2DPolyXZ(&ep,ioo->pos.x,ioo->pos.z)) return true; } return false; } //----------------------------------------------------------------------------- // Returns 0 if nothing in cyl // Else returns Y Offset to put cylinder in a proper place float CheckAnythingInCylinder(EERIE_CYLINDER * cyl,INTERACTIVE_OBJ * ioo,long flags) { NPC_IN_CYLINDER=0; long rad; F2L((cyl->radius + 100)*ACTIVEBKG->Xmul, &rad); long px,pz; F2L(cyl->origin.x*ACTIVEBKG->Xmul,&px); if (px>ACTIVEBKG->Xsize-2-rad) return 0.f; if (px< 1+rad) return 0.f; F2L(cyl->origin.z*ACTIVEBKG->Zmul,&pz); if (pz>ACTIVEBKG->Zsize-2-rad) return 0.f; if (pz< 1+rad) return 0.f; float anything = 999999.f; EERIEPOLY * ep; FAST_BKG_DATA * feg; int itest = 0; if (TSU_TEST_COLLISIONS) if ( (iXBackup >= px-rad) && (iXBackup <= px-rad) && (iYBackup >= pz-rad) && (iYBackup <= pz-rad) ) { float minanything = __min(anything,IsPolyInCylinder(pEPBackup,cyl,flags)); if (anything != minanything) { anything = minanything; itest = 1; } if (POLYIN && (pEPBackup->type & POLY_CLIMB)) { COLLIDED_CLIMB_POLY=1; } } /* TO KEEP... EERIE_BKG_INFO * eg=&ACTIVEBKG->Backg[px+pz*ACTIVEBKG->Xsize]; if ( (cyl->origin.y+cyl->height < eg->tile_miny) && (cyl->origin.y > eg->tile_miny) //|| (cyl->origin.y > eg->tile_maxy) ) { return 999999.f; } */ for (long j=pz-rad;j<=pz+rad;j++) for (long i=px-rad;i<=px+rad;i++) { float nearx,nearz; float nearest=99999999.f; for (long num=0;num<4;num++) { nearx = ARX_CLEAN_WARN_CAST_FLOAT(i * 100); nearz = ARX_CLEAN_WARN_CAST_FLOAT(j * 100); if ((num==1) || (num==2)) nearx += 100; if ((num==2) || (num==3)) nearz += 100; float dd=Distance2D(nearx,nearz,cyl->origin.x,cyl->origin.z); if (dd__max(82.f,cyl->radius)) continue; feg=&ACTIVEBKG->fastdata[i][j]; // tsu bool bOk = true; if (TSU_TEST_COLLISIONS) { EERIE_BKG_INFO *eg=&ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize]; if (!(eg->tile_miny < anything)) bOk = false; } if (bOk) for (long k=0;knbpoly;k++) { ep=&feg->polydata[k]; if (ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL) ) continue; if (ep->min.ytype & POLY_CLIMB) COLLIDED_CLIMB_POLY=1; } } } } float tempo; ep=CheckInPolyPrecis(cyl->origin.x,cyl->origin.y+cyl->height,cyl->origin.z,&tempo); if (ep) { anything=__min(anything,tempo); } long dealt = 0; if (!(flags & CFLAG_NO_INTERCOL)) { INTERACTIVE_OBJ * io; long FULL_TEST=0; long AMOUNT=TREATZONE_CUR; if ( ioo && (ioo->ioflags & IO_NPC) && (ioo->_npcdata->pathfind.flags & PATHFIND_ALWAYS)) { FULL_TEST=1; AMOUNT=inter.nbmax; } for (long i=0;iobj) || ( (io->show!=SHOW_FLAG_IN_SCENE) || ((io->ioflags & IO_NO_COLLISIONS) && !(flags & CFLAG_COLLIDE_NOCOL)) ) || (EEDistance3D(&io->pos,&cyl->origin)>1000.f)) continue; { EERIE_CYLINDER * io_cyl=&io->physics.cyl; GetIOCyl(io,io_cyl); dealt=0; if ( (io->GameFlags & GFLAG_PLATFORM) || ((flags & CFLAG_COLLIDE_NOCOL) && (io->ioflags & IO_NPC) && (io->ioflags & IO_NO_COLLISIONS)) ) { float miny,maxy; miny=io->bbox3D.min.y; maxy=io->bbox3D.max.y; if (Distance2D(io->pos.x,io->pos.z,cyl->origin.x,cyl->origin.z)<440.f+cyl->radius) if (In3DBBoxTolerance(&cyl->origin,&io->bbox3D, cyl->radius+80)) { if (io->ioflags & IO_FIELD) { if (In3DBBoxTolerance(&cyl->origin,&io->bbox3D, cyl->radius+10)) anything=-99999.f; } else { for (long ii=0;iiobj->nbvertex;ii++) { long res=PointInUnderCylinder(cyl,&io->obj->vertexlist3[ii].v); if (res>0) { if (res==2) ON_PLATFORM=1; anything = __min(anything, io->obj->vertexlist3[ii].v.y - 10.f); } } for (int ii=0;iiobj->nbfaces;ii++) { EERIE_3D c; Vector_Init(&c); float height=io->obj->vertexlist3[io->obj->facelist[ii].vid[0]].v.y; for (long kk=0;kk<3;kk++) { c.x+=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.x; c.y+=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.y; height=__min(height,io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.y); c.z+=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.z; } c.x*=DIV3; c.z*=DIV3; c.y = io->bbox3D.min.y; long res=PointInUnderCylinder(cyl,&c); if (res>0) { if (res==2) ON_PLATFORM=1; anything = __min(anything, height); } } } } } else if ( (io->ioflags & IO_NPC) && (!(flags & CFLAG_NO_NPC_COLLIDE)) // MUST be checked here only (not before...) && (!(ioo && (ioo->ioflags & IO_NO_COLLISIONS))) && (io->_npcdata->life>0.f) ) { if (CylinderInCylinder(cyl,io_cyl)) { NPC_IN_CYLINDER=1; anything = __min(anything, io_cyl->origin.y + io_cyl->height); if (!(flags & CFLAG_JUST_TEST) && ioo) { if (ARXTime > io->collide_door_time + 500) { EVENT_SENDER=ioo; io->collide_door_time = ARXTimeUL(); if (CollidedFromBack(io,ioo)) SendIOScriptEvent(io,SM_COLLIDE_NPC,"BACK",NULL); else SendIOScriptEvent(io,SM_COLLIDE_NPC,"",NULL); EVENT_SENDER=io; io->collide_door_time = ARXTimeUL(); if (CollidedFromBack(ioo,io)) SendIOScriptEvent(ioo,SM_COLLIDE_NPC,"BACK",NULL); else SendIOScriptEvent(ioo,SM_COLLIDE_NPC,"",NULL); } if ((!dealt) && ((ioo->damager_damages>0) || (io->damager_damages>0))) { dealt=1; if (ioo->damager_damages>0) ARX_DAMAGES_DealDamages(i,ioo->damager_damages,GetInterNum(ioo),ioo->damager_type,&io->pos); if (io->damager_damages>0) ARX_DAMAGES_DealDamages(GetInterNum(ioo),io->damager_damages,GetInterNum(io),io->damager_type,&ioo->pos); } PUSHABLE_NPC=io; if (io->targetinfo==i) { if (io->_npcdata->pathfind.listnb>0) { io->_npcdata->pathfind.listpos=0; io->_npcdata->pathfind.listnb=-1; if (io->_npcdata->pathfind.list) free(io->_npcdata->pathfind.list); io->_npcdata->pathfind.list=NULL; SendIOScriptEvent(io,0,"","PATHFINDER_END"); } if (!io->_npcdata->reachedtarget) { EVENT_SENDER=ioo; SendIOScriptEvent(io,SM_REACHEDTARGET,""); io->_npcdata->reachedtarget=1; } } } } } else if (io->ioflags & IO_FIX) { long nbv; long idx; EERIE_VERTEX * vlist; EERIE_SPHERE sp; float miny,maxy; miny=io->bbox3D.min.y; maxy=io->bbox3D.max.y; if (maxy<= cyl->origin.y+cyl->height) goto suivant; if (miny>= cyl->origin.y) goto suivant; if (In3DBBoxTolerance(&cyl->origin,&io->bbox3D,cyl->radius+30.f)) { vlist=io->obj->vertexlist3; nbv=io->obj->nbvertex; if (io->obj->nbgroups>10) { for (long ii=0;iiobj->nbgroups;ii++) { idx=io->obj->grouplist[ii].origin; sp.origin.x=vlist[idx].v.x; sp.origin.y=vlist[idx].v.y; sp.origin.z=vlist[idx].v.z; if (ioo==inter.iobj[0]) { sp.radius = 22.f; } else if (ioo->ioflags & IO_NPC) sp.radius = 26.f; else sp.radius = 22.f; if (SphereInCylinder(cyl,&sp)) { if (!(flags & CFLAG_JUST_TEST) && ioo) { if (io->GameFlags&GFLAG_DOOR) { if (ARXTime>io->collide_door_time+500) { EVENT_SENDER=ioo; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(io,SM_COLLIDE_DOOR,"",NULL); EVENT_SENDER=io; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(ioo,SM_COLLIDE_DOOR,"",NULL); } } if (io->ioflags & IO_FIELD) { EVENT_SENDER=NULL; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(ioo,SM_COLLIDE_FIELD,"",NULL); } if ((!dealt) && ((ioo->damager_damages>0) || (io->damager_damages>0))) { dealt=1; if (ioo->damager_damages>0) ARX_DAMAGES_DealDamages(i,ioo->damager_damages,GetInterNum(ioo),ioo->damager_type,&io->pos); if (io->damager_damages>0) ARX_DAMAGES_DealDamages(GetInterNum(ioo),io->damager_damages,GetInterNum(io),io->damager_type,&ioo->pos); } } anything=__min(anything,__min(sp.origin.y-sp.radius , io->bbox3D.min.y)); } } } else { long step; if (ioo==inter.iobj[0]) sp.radius = 23.f; else if (ioo && !(ioo->ioflags & IO_NPC)) sp.radius = 32.f; else sp.radius = 25.f; if (nbv<300) { step=1; } else if (nbv<600) step=2; else if (nbv<1200) step=4; else step=6; for (long ii=1;iiobj->origin) { sp.origin.x=vlist[ii].v.x; sp.origin.y=vlist[ii].v.y; sp.origin.z=vlist[ii].v.z; if (SphereInCylinder(cyl,&sp)) { if (!(flags & CFLAG_JUST_TEST) && ioo) { if (io->GameFlags&GFLAG_DOOR) { if (ARXTime>io->collide_door_time+500) { EVENT_SENDER=ioo; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(io,SM_COLLIDE_DOOR,"",NULL); EVENT_SENDER=io; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(ioo,SM_COLLIDE_DOOR,"",NULL); } } if (io->ioflags & IO_FIELD) { EVENT_SENDER=NULL; io->collide_door_time = ARXTimeUL(); SendIOScriptEvent(ioo,SM_COLLIDE_FIELD,"",NULL); } if ((!dealt) && ioo && ((ioo->damager_damages > 0) || (io->damager_damages > 0))) { dealt=1; if (ioo->damager_damages>0) ARX_DAMAGES_DealDamages(i,ioo->damager_damages,GetInterNum(ioo),ioo->damager_type,&io->pos); if (io->damager_damages>0) ARX_DAMAGES_DealDamages(GetInterNum(ioo),io->damager_damages,GetInterNum(io),io->damager_type,&ioo->pos); } } anything=__min(anything,__min(sp.origin.y-sp.radius,io->bbox3D.min.y)); } } } } } } } suivant: ; } } if (anything == 999999.f) return 0.f; anything=anything-cyl->origin.y; return anything; } //----------------------------------------------------------------------------- __forceinline BOOL InExceptionList(long val) { for (long i=0;iradius+20.f; float sr40=sphere->radius+30.f; float sr180=sphere->radius+500.f; for (long i=0;i-1) { i=TREATZONE_CUR; io=inter.iobj[targ]; if ( (!io) || (InExceptionList(targ)) || (targ==source) || (io->show!=SHOW_FLAG_IN_SCENE) || !(io->GameFlags & GFLAG_ISINTREATZONE) || !(io->obj) ) return FALSE; ret_idx=targ; } else { if ( (treatio[i].show!=1) || (treatio[i].io==NULL) || (treatio[i].num==source) || (InExceptionList(treatio[i].num)) ) continue; io=treatio[i].io; ret_idx=treatio[i].num; } if (!(io->ioflags & IO_NPC) && (io->ioflags & IO_NO_COLLISIONS)) continue; if (!io->obj) continue; if (io->GameFlags & GFLAG_PLATFORM) { float miny,maxy; miny=io->bbox3D.min.y; maxy=io->bbox3D.max.y; if ( (maxy<= sphere->origin.y+sphere->radius) || (miny>= sphere->origin.y) ) if (In3DBBoxTolerance(&sphere->origin,&io->bbox3D,sphere->radius)) { if (Distance2D(io->pos.x,io->pos.z,sphere->origin.x,sphere->origin.z)<440.f+sphere->radius) { EERIEPOLY ep; ep.type=0; for (long ii=0;iiobj->nbfaces;ii++) { float cx=0; float cz=0; for (long kk=0;kk<3;kk++) { cx+=ep.v[kk].sx=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.x; ep.v[kk].sy=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.y; cz+=ep.v[kk].sz=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.z; } cx*=DIV3; cz*=DIV3; for (int kk=0;kk<3;kk++) { ep.v[kk].sx=(ep.v[kk].sx-cx)*3.5f+cx; ep.v[kk].sz=(ep.v[kk].sz-cz)*3.5f+cz; } if (PointIn2DPolyXZ(&ep, sphere->origin.x, sphere->origin.z)) { EVERYTHING_IN_SPHERE[MAX_IN_SPHERE_Pos]=(short)ret_idx; MAX_IN_SPHERE_Pos++; if (MAX_IN_SPHERE_Pos>=MAX_IN_SPHERE) MAX_IN_SPHERE_Pos--; vreturn=TRUE; goto suivant; } } } } } if (EEDistance3D(&io->pos,&sphere->origin)< sr180) { long amount=1; vlist=io->obj->vertexlist3; if (io->obj->nbgroups>4) { for (long ii=0;iiobj->nbgroups;ii++) { if (EEDistance3D(&vlist[io->obj->grouplist[ii].origin].v,&sphere->origin)< sr40) { EVERYTHING_IN_SPHERE[MAX_IN_SPHERE_Pos]=(short)ret_idx; MAX_IN_SPHERE_Pos++; if (MAX_IN_SPHERE_Pos>=MAX_IN_SPHERE) MAX_IN_SPHERE_Pos--; vreturn=TRUE; goto suivant; } } amount=2; } for (long ii=0;iiobj->nbfaces;ii+=amount) { EERIE_FACE * ef=&io->obj->facelist[ii]; if (ef->facetype & POLY_HIDE) continue; EERIE_3D fcenter; fcenter.x=(vlist[ef->vid[0]].v.x+vlist[ef->vid[1]].v.x+vlist[ef->vid[2]].v.x)*DIV3; fcenter.y=(vlist[ef->vid[0]].v.y+vlist[ef->vid[1]].v.y+vlist[ef->vid[2]].v.y)*DIV3; fcenter.z=(vlist[ef->vid[0]].v.z+vlist[ef->vid[1]].v.z+vlist[ef->vid[2]].v.z)*DIV3; if ( ( EEDistance3D(&fcenter,&sphere->origin)< sr30) || ( EEDistance3D(&vlist[ef->vid[0]].v,&sphere->origin)< sr30) || (EEDistance3D(&vlist[ef->vid[1]].v,&sphere->origin)< sr30) || (EEDistance3D(&vlist[ef->vid[2]].v,&sphere->origin)< sr30)) { EVERYTHING_IN_SPHERE[MAX_IN_SPHERE_Pos]=(short)ret_idx; MAX_IN_SPHERE_Pos++; if (MAX_IN_SPHERE_Pos>=MAX_IN_SPHERE) MAX_IN_SPHERE_Pos--; vreturn=TRUE; goto suivant; } } } suivant: ; } return vreturn; } //----------------------------------------------------------------------------- EERIEPOLY * CheckBackgroundInSphere(EERIE_SPHERE * sphere) //except source... { long rad; F2L(sphere->radius*ACTIVEBKG->Xmul,&rad); rad+=2; long px,pz; F2L(sphere->origin.x*ACTIVEBKG->Xmul,&px); F2L(sphere->origin.z*ACTIVEBKG->Zmul,&pz); EERIEPOLY * ep; FAST_BKG_DATA * feg; long spx=__max(px-rad,0); long epx=__min(px+rad,ACTIVEBKG->Xsize-1); long spz=__max(pz-rad,0); long epz=__min(pz+rad,ACTIVEBKG->Zsize-1); for (long j=spz;j<=epz;j++) for (long i=spx;i<=epx;i++) { feg=&ACTIVEBKG->fastdata[i][j]; for (long k=0;knbpoly;k++) { ep=&feg->polydata[k]; if (ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL)) continue; if (IsPolyInSphere(ep,sphere)) { return ep; } } } return NULL; } //----------------------------------------------------------------------------- BOOL CheckAnythingInSphere(EERIE_SPHERE * sphere,long source,long flags,long * num) //except source... { if (num) *num=-1; long rad; F2L(sphere->radius*ACTIVEBKG->Xmul,&rad); rad+=2; long px,pz; F2L(sphere->origin.x*ACTIVEBKG->Xmul,&px); F2L(sphere->origin.z*ACTIVEBKG->Zmul,&pz); EERIEPOLY * ep; FAST_BKG_DATA * feg; if (!(flags & CAS_NO_BACKGROUND_COL)) { long spz=__max(pz-rad,0); long epz=__min(pz+rad,ACTIVEBKG->Zsize-1); long spx=__max(px-rad,0); long epx=__min(px+rad,ACTIVEBKG->Xsize-1); for (long j=spz;j<=epz;j++) for (long i=spx;i<=epx;i++) { feg=&ACTIVEBKG->fastdata[i][j]; for (long k=0;knbpoly;k++) { ep=&feg->polydata[k]; if (ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL)) continue; if (IsPolyInSphere(ep,sphere)) return TRUE; } } } if (flags & CAS_NO_NPC_COL) return FALSE; long validsource=0; if (flags & CAS_NO_SAME_GROUP) validsource=ValidIONum(source); EERIE_VERTEX * vlist; INTERACTIVE_OBJ * io; float sr30=sphere->radius+20.f; float sr40=sphere->radius+30.f; float sr180=sphere->radius+500.f; for (long i=0;iobj) continue; if (!(io->ioflags & IO_NPC) && (io->ioflags & IO_NO_COLLISIONS)) continue; if ((flags & CAS_NO_DEAD_COL) && (io->ioflags & IO_NPC) && (IsDeadNPC(io))) continue; if ((io->ioflags & IO_FIX) && (flags & CAS_NO_FIX_COL)) continue; if ((io->ioflags & IO_ITEM) && (flags & CAS_NO_ITEM_COL)) continue; if ((treatio[i].num!=0) && (source!=0) && validsource && (HaveCommonGroup(io,inter.iobj[source]))) continue; if (io->GameFlags & GFLAG_PLATFORM) { float miny,maxy; miny=io->bbox3D.min.y; maxy=io->bbox3D.max.y; if ( (maxy> sphere->origin.y-sphere->radius) || (miny< sphere->origin.y+sphere->radius) ) if (In3DBBoxTolerance(&sphere->origin,&io->bbox3D,sphere->radius)) { if (Distance2D(io->pos.x,io->pos.z,sphere->origin.x,sphere->origin.z)<440.f+sphere->radius) { EERIEPOLY ep; ep.type=0; for (long ii=0;iiobj->nbfaces;ii++) { float cx=0; float cz=0; for (long kk=0;kk<3;kk++) { cx+=ep.v[kk].sx=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.x; ep.v[kk].sy=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.y; cz+=ep.v[kk].sz=io->obj->vertexlist3[io->obj->facelist[ii].vid[kk]].v.z; } cx*=DIV3; cz*=DIV3; for (int kk=0;kk<3;kk++) { ep.v[kk].sx=(ep.v[kk].sx-cx)*3.5f+cx; ep.v[kk].sz=(ep.v[kk].sz-cz)*3.5f+cz; } if (PointIn2DPolyXZ(&ep, sphere->origin.x, sphere->origin.z)) { if (num) *num=treatio[i].num; return TRUE; } } } } } if (EEDistance3D(&io->pos,&sphere->origin)< sr180 ) { long amount=1; vlist=io->obj->vertexlist3; if (io->obj->nbgroups>4) { for (long ii=0;iiobj->nbgroups;ii++) { if (EEDistance3D(&vlist[io->obj->grouplist[ii].origin].v,&sphere->origin)< sr40) { if (num) *num=treatio[i].num; return TRUE; } } amount=2; } for (long ii=0;iiobj->nbfaces;ii+=amount) { if (io->obj->facelist[ii].facetype & POLY_HIDE) continue; if (( EEDistance3D(&vlist[io->obj->facelist[ii].vid[0]].v,&sphere->origin)< sr30) || (EEDistance3D(&vlist[io->obj->facelist[ii].vid[1]].v,&sphere->origin)< sr30)) { if (num) *num=treatio[i].num; return TRUE; } } } } return FALSE; } //----------------------------------------------------------------------------- BOOL CheckIOInSphere(EERIE_SPHERE * sphere,long target,long flags) { if (!ValidIONum(target)) return FALSE; EERIE_VERTEX * vlist; INTERACTIVE_OBJ * io=inter.iobj[target]; float sr30 = sphere->radius + 22.f; float sr40 = sphere->radius + 27.f; float sr180=sphere->radius+500.f; if ( ((flags & IIS_NO_NOCOL) || (!(flags & IIS_NO_NOCOL) && !(io->ioflags & IO_NO_COLLISIONS))) && (io->show==SHOW_FLAG_IN_SCENE) && (io->GameFlags & GFLAG_ISINTREATZONE) && (io->obj) ) { if (EEDistance3D(&io->pos,&sphere->origin)< sr180) { vlist=io->obj->vertexlist3; if (io->obj->nbgroups>10) { long count=0; long ii=io->obj->nbgroups-1; while (ii) { if (EEDistance3D(&vlist[io->obj->grouplist[ii].origin].v,&sphere->origin)< sr40) { count++; if (count>3) return TRUE; } ii--; } } long count=0; long step; if (io->obj->nbvertex<150) step=1; else if (io->obj->nbvertex<300) step=2; else if (io->obj->nbvertex<600) step=4; else if (io->obj->nbvertex<1200) step=6; else step=7; for (long ii=0;iiobj->nbvertex;ii+=step) { if (EEDistance3D(&vlist[ii].v,&sphere->origin)< sr30) { count++; if (count>6) return TRUE; } if (io->obj->nbvertex<120) { for (long kk=0;kkobj->nbvertex;kk+=1) { if (kk!=ii) { for (float nn=0.2f;nn<1.f;nn+=0.2f) { EERIE_3D posi; posi.x=(vlist[ii].v.x*nn+vlist[kk].v.x*(1.f-nn)); posi.y=(vlist[ii].v.y*nn+vlist[kk].v.y*(1.f-nn)); posi.z=(vlist[ii].v.z*nn+vlist[kk].v.z*(1.f-nn)); float dist=EEDistance3D(&sphere->origin,&posi); if (dist<=sr30+20) { count++; if (count>3) { if (io->ioflags & IO_FIX) return TRUE; if (count>6) return TRUE; } } } } } } } if ((count>3) && (io->ioflags & IO_FIX)) return TRUE; } } return FALSE; } float MAX_ALLOWED_PER_SECOND=12.f; //----------------------------------------------------------------------------- // Checks if a position is valid, Modify it for height if necessary // Returns TRUE or FALSE BOOL AttemptValidCylinderPos(EERIE_CYLINDER * cyl,INTERACTIVE_OBJ * io,long flags) { PUSHABLE_NPC=NULL; float anything = CheckAnythingInCylinder(cyl, io, flags); if ((flags & CFLAG_LEVITATE) && (anything==0.f)) return TRUE; if (anything>=0.f) // Falling Cylinder but valid pos ! { if (flags & CFLAG_RETURN_HEIGHT) cyl->origin.y+=anything; return TRUE; } EERIE_CYLINDER tmp; if (!(flags & CFLAG_ANCHOR_GENERATION)) { memcpy(&tmp,cyl,sizeof(EERIE_CYLINDER)); while (anything<0.f) { tmp.origin.y+=anything; anything=CheckAnythingInCylinder(&tmp,io,flags); } anything=tmp.origin.y-cyl->origin.y; } if (MOVING_CYLINDER) { if (flags & CFLAG_NPC) { float tolerate; if ((flags & CFLAG_PLAYER) && (player.jumpphase) ) { tolerate=0; } else if ((io) && (io->ioflags & IO_NPC) && (io->_npcdata->pathfind.listnb > 0) && (io->_npcdata->pathfind.listpos < io->_npcdata->pathfind.listnb)) { tolerate=-65-io->_npcdata->moveproblem; } else { if ((io) && (io->_npcdata)) { tolerate = -55 - io->_npcdata->moveproblem; } else { tolerate=0.f; } } if (NPC_IN_CYLINDER) { tolerate=cyl->height*DIV2; } if (anything 50.f)) { tmpp.radius=cyl->radius*1.4f; tmpp.origin.y-=30.f; float tmp=CheckAnythingInCylinder(&tmpp,io,flags | CFLAG_JUST_TEST); if (tmp<0) return FALSE; } } if (io && (!(flags & CFLAG_JUST_TEST))) { if ((flags & CFLAG_PLAYER) && (anything<0.f)) { if (player.jumpphase) { io->_npcdata->climb_count=MAX_ALLOWED_PER_SECOND; return FALSE; } float dist; dist=__max(TRUEVector_Magnitude(&vector2D),1.f); float pente; pente = EEfabs(anything) / dist * DIV2; io->_npcdata->climb_count+=pente; if (io->_npcdata->climb_count>MAX_ALLOWED_PER_SECOND) { io->_npcdata->climb_count=MAX_ALLOWED_PER_SECOND; } if (anything < -55) { io->_npcdata->climb_count=MAX_ALLOWED_PER_SECOND; return FALSE; } EERIE_CYLINDER tmpp; memcpy(&tmpp,cyl,sizeof(EERIE_CYLINDER)); tmpp.radius *= 0.65f; float tmp=CheckAnythingInCylinder(&tmpp,io,flags | CFLAG_JUST_TEST); if (tmp > 50.f) { tmpp.radius=cyl->radius*1.45f; tmpp.origin.y-=30.f; float tmp=CheckAnythingInCylinder(&tmpp,io,flags | CFLAG_JUST_TEST); if (tmp<0) return FALSE; } } } } else if (anything<-45) return FALSE; if ((flags & CFLAG_SPECIAL) && (anything<-40)) { if (flags & CFLAG_RETURN_HEIGHT) cyl->origin.y+=anything; return FALSE; } memcpy(&tmp,cyl,sizeof(EERIE_CYLINDER)); tmp.origin.y+=anything; anything = CheckAnythingInCylinder(&tmp, io, flags); if (anything<0.f) { if (flags & CFLAG_RETURN_HEIGHT) { while (anything<0.f) { tmp.origin.y+=anything; anything=CheckAnythingInCylinder(&tmp,io,flags); } cyl->origin.y = tmp.origin.y; } return FALSE; } cyl->origin.y=tmp.origin.y; return TRUE; } //---------------------------------------------------------------------------------------------- //flags & 1 levitate //flags & 2 no inter col //flags & 4 special //flags & 8 easier sliding. //flags & 16 climbing !!! //flags & 32 Just Test !!! //flags & 64 NPC mode //---------------------------------------------------------------------------------------------- BOOL ARX_COLLISION_Move_Cylinder(IO_PHYSICS * ip,INTERACTIVE_OBJ * io,float MOVE_CYLINDER_STEP,long flags) { // HERMESPerf script(HPERF_PHYSICS); // +5 on 15 // // memcpy(&ip->cyl.origin,&ip->targetpos,sizeof(EERIE_3D)); // return TRUE; ON_PLATFORM=0; MOVING_CYLINDER=1; COLLIDED_CLIMB_POLY=0; DIRECT_PATH=TRUE; IO_PHYSICS test; if (ip==NULL) { MOVING_CYLINDER=0; return FALSE; } float distance=TRUEEEDistance3D(&ip->startpos,&ip->targetpos); if (distance < 0.1f) { MOVING_CYLINDER=0; if (distance==0.f) return TRUE; return FALSE; } float onedist=1.f/distance; EERIE_3D mvector; mvector.x=(ip->targetpos.x-ip->startpos.x)*onedist; mvector.y=(ip->targetpos.y-ip->startpos.y)*onedist; mvector.z=(ip->targetpos.z-ip->startpos.z)*onedist; long count=100; while ((distance>0.f) && (count--)) { // First We compute current increment float curmovedist=__min(distance,MOVE_CYLINDER_STEP); distance-=curmovedist; // Store our cylinder desc into a test struct memcpy(&test,ip,sizeof(IO_PHYSICS)); // uses test struct to simulate movement. vector2D.x=mvector.x*curmovedist; vector2D.y=0.f; vector2D.z=mvector.z*curmovedist; test.cyl.origin.x += vector2D.x; test.cyl.origin.y+=mvector.y*curmovedist; test.cyl.origin.z += vector2D.z; PUSHABLE_NPC=NULL; if ((flags & CFLAG_CHECK_VALID_POS) && (CylinderAboveInvalidZone(&test.cyl))) return FALSE; if (AttemptValidCylinderPos(&test.cyl,io,flags)) { // Found without complication memcpy(ip,&test,sizeof(IO_PHYSICS)); } else { //return FALSE; if ((mvector.x==0.f) && (mvector.z==0.f)) return TRUE; //goto oki; if (flags & CFLAG_CLIMBING) { memcpy(&test.cyl, &ip->cyl, sizeof(EERIE_CYLINDER)); test.cyl.origin.y+=mvector.y*curmovedist; if (AttemptValidCylinderPos(&test.cyl,io,flags)) { memcpy(ip,&test,sizeof(IO_PHYSICS)); goto oki; } } DIRECT_PATH=FALSE; // Must Attempt To Slide along collisions register EERIE_3D vecatt; EERIE_3D rpos; EERIE_3D lpos; long RFOUND=0; long LFOUND=0; long maxRANGLE=90; long maxLANGLE=270; float ANGLESTEPP; if (flags & CFLAG_EASY_SLIDING) // player sliding in fact... { ANGLESTEPP=10.f; maxRANGLE=70; maxLANGLE=290; } else ANGLESTEPP=30.f; register float rangle=ANGLESTEPP; register float langle=360.f-ANGLESTEPP; while (rangle<=maxRANGLE) //tries on the Right and Left sides { memcpy(&test.cyl, &ip->cyl, sizeof(EERIE_CYLINDER)); float t=DEG2RAD(MAKEANGLE(rangle)); _YRotatePoint(&mvector,&vecatt,EEcos(t),EEsin(t)); test.cyl.origin.x+=vecatt.x*curmovedist; test.cyl.origin.y+=vecatt.y*curmovedist; test.cyl.origin.z+=vecatt.z*curmovedist; float cc=io->_npcdata->climb_count; if (AttemptValidCylinderPos(&test.cyl, io, flags)) { Vector_Copy(&rpos,&test.cyl.origin); RFOUND=1; } else io->_npcdata->climb_count=cc; rangle+=ANGLESTEPP; memcpy(&test.cyl, &ip->cyl, sizeof(EERIE_CYLINDER)); t=DEG2RAD(MAKEANGLE(langle)); _YRotatePoint(&mvector,&vecatt,EEcos(t),EEsin(t)); test.cyl.origin.x+=vecatt.x*curmovedist; test.cyl.origin.y+=vecatt.y*curmovedist; test.cyl.origin.z+=vecatt.z*curmovedist; cc=io->_npcdata->climb_count; if (AttemptValidCylinderPos(&test.cyl, io, flags)) { Vector_Copy(&lpos,&test.cyl.origin); LFOUND=1; } else io->_npcdata->climb_count=cc; langle-=ANGLESTEPP; if ((RFOUND) || (LFOUND)) break; } if ((LFOUND) && (RFOUND)) { langle=360.f-langle; if (langlecyl.origin,&lpos); distance -= curmovedist; } else { Vector_Copy(&ip->cyl.origin,&rpos); distance -= curmovedist; } } else if (LFOUND) { Vector_Copy(&ip->cyl.origin,&lpos); distance -= curmovedist; } else if (RFOUND) { Vector_Copy(&ip->cyl.origin,&rpos); distance -= curmovedist; } else //stopped { ip->velocity.x=ip->velocity.y=ip->velocity.z=0.f; MOVING_CYLINDER=0; return FALSE; } } if (flags & CFLAG_NO_HEIGHT_MOD) { if (EEfabs(ip->startpos.y - ip->cyl.origin.y)>30.f) return FALSE; } oki: ; } MOVING_CYLINDER=0; return TRUE; } //----------------------------------------------------------------------------- BOOL IO_Visible(EERIE_3D * orgn, EERIE_3D * dest,EERIEPOLY * epp,EERIE_3D * hit) { float x,y,z; //current ray pos float dx,dy,dz; // ray incs float adx,ady,adz; // absolute ray incs float ix,iy,iz; long px,pz; EERIEPOLY * ep; FAST_BKG_DATA * feg; float pas=35.f; float found_dd=999999999999.f; EERIE_3D found_hit; EERIEPOLY * found_ep=NULL; float iter,t; found_hit.x = found_hit.y = found_hit.z = 0; x=orgn->x; y=orgn->y; z=orgn->z; float distance; float nearest=distance=EEDistance3D( orgn,dest ); if (distancex-orgn->x); adx=EEfabs(dx); dy=(dest->y-orgn->y); ady=EEfabs(dy); dz=(dest->z-orgn->z); adz=EEfabs(dz); if ( (adx>=ady) && (adx>=adz)) { if (adx != dx) { ix = -pas; } else { ix = pas; } iter=adx/pas; t=1.f/(iter); iy=dy*t; iz=dz*t; } else if ( (ady>=adx) && (ady>=adz)) { if (ady != dy) { iy = -pas; } else { iy = pas; } iter=ady/pas; t=1.f/(iter); ix=dx*t; iz=dz*t; } else { if (adz != dz) { iz = -pas; } else { iz = pas; } iter=adz/pas; t=1.f/(iter); ix=dx*t; iy=dy*t; } float dd; x-=ix; y-=iy; z-=iz; while (iter>0.f) { iter-=1.f; x+=ix; y+=iy; z+=iz; EERIE_SPHERE sphere; sphere.origin.x=x; sphere.origin.y=y; sphere.origin.z=z; sphere.radius=65.f; for (long num=0;numGameFlags & GFLAG_VIEW_BLOCKER)) { if ( CheckIOInSphere(&sphere,num) ) { dd=EEDistance3D(orgn,&sphere.origin); if (ddx=x; hit->y=y; hit->z=z; return FALSE; } } } } px=(long)(x* ACTIVEBKG->Xmul); pz=(long)(z* ACTIVEBKG->Zmul); if (px>=ACTIVEBKG->Xsize) goto fini; else if (px< 0) goto fini; if (pz>= ACTIVEBKG->Zsize) goto fini; else if (pz< 0) goto fini; feg=&ACTIVEBKG->fastdata[px][pz]; for (long k=0;knbpolyin;k++) { ep=feg->polyin[k]; if (!(ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL) ) ) if ((ep->min.y-pasmax.y+pas>y)) if ((ep->min.x-pasmax.x+pas>x)) if ((ep->min.z-pasmax.z+pas>z)) { if (RayCollidingPoly(orgn,dest,ep,hit)) { dd=EEDistance3D(orgn,hit); if (ddx; found_hit.y=hit->y; found_hit.z=hit->z; } } } } } fini: ; if ( found_ep == NULL ) return TRUE; if ( found_ep == epp ) return TRUE; hit->x = found_hit.x; hit->y = found_hit.y; hit->z = found_hit.z; return FALSE; } void ANCHOR_BLOCK_Clear() { EERIE_BACKGROUND * eb=ACTIVEBKG; if (eb) { for (long k=0;knbanchors;k++) { _ANCHOR_DATA * ad=&eb->anchors[k]; ad->flags&=~ANCHOR_FLAG_BLOCKED; } } } void ANCHOR_BLOCK_By_IO(INTERACTIVE_OBJ * io,long status) { EERIE_BACKGROUND * eb=ACTIVEBKG; for (long k=0;knbanchors;k++) { _ANCHOR_DATA * ad=&eb->anchors[k]; if (EEDistance3D(&ad->pos,&io->pos)>600.f) continue; if (Distance2D(io->pos.x,io->pos.z,ad->pos.x,ad->pos.z)<440.f) { EERIEPOLY ep; ep.type=0; for (long ii=0;iiobj->nbfaces;ii++) { float cx=0; float cz=0; for (long kk=0;kk<3;kk++) { cx+=ep.v[kk].sx=io->obj->vertexlist[io->obj->facelist[ii].vid[kk]].v.x+io->pos.x; ep.v[kk].sy=io->obj->vertexlist[io->obj->facelist[ii].vid[kk]].v.y+io->pos.y; cz+=ep.v[kk].sz=io->obj->vertexlist[io->obj->facelist[ii].vid[kk]].v.z+io->pos.z; } cx*=DIV3; cz*=DIV3; for (int kk=0;kk<3;kk++) { ep.v[kk].sx=(ep.v[kk].sx-cx)*3.5f+cx; ep.v[kk].sz=(ep.v[kk].sz-cz)*3.5f+cz; } if (PointIn2DPolyXZ(&ep, ad->pos.x, ad->pos.z)) { if (status) ad->flags|=ANCHOR_FLAG_BLOCKED; else ad->flags&=~ANCHOR_FLAG_BLOCKED; } } } } }