#include "game.h" #include "pap.h" #include "walkable.h" #include "memory.h" #include "mav.h" extern void highlight_rface(SLONG rface); // // code to do with walkable faces // // // this whole module has been changed to treat walkable faces as 10% (more in terms of area) bigger for collision. // SLONG clock(const SLONG dx,const SLONG dz,const SLONG dx1,const SLONG dz1) { if((dx*dz1-dz*dx1)<=0) return(0); else return(1); } SLONG point_in_quad(SLONG px,SLONG pz,SLONG x,SLONG y,SLONG z,SWORD face) { SLONG c0; SWORD vx[4],vz[4]; SLONG mx=0,mz=0; ASSERT(face>=0); for(c0=0;c0<4;c0++) { vx[c0]=x+prim_points[prim_faces4[face].Points[c0]].X; vz[c0]=z+prim_points[prim_faces4[face].Points[c0]].Z; mx+=vx[c0]; mz+=vz[c0]; } // mx=0; mx>>=2; // mz/=mx; mz>>=2; for(c0=0;c0<4;c0++) { vx[c0]=( ( (vx[c0]-mx)*268)>>8 )+mx; vz[c0]=( ( (vz[c0]-mz)*268)>>8 )+mz; } if(clock(vx[1]-vx[0],vz[1]-vz[0],px-vx[0],pz-vz[0]))//x2-x1,z2-z1,px-x1,pz-z1)) { if(clock(vx[3]-vx[1],vz[3]-vz[1],px-vx[1],pz-vz[1])) { if(clock(vx[2]-vx[3],vz[2]-vz[3],px-vx[3],pz-vz[3])) { if(clock(vx[0]-vx[2],vz[0]-vz[2],px-vx[2],pz-vz[2])) { return(1); } } } } return(0); } // // returns true if on face // *height always trys to have the height SLONG gh_vx[4],gh_vy[4],gh_vz[4];//out of stack space (on PSX) so words SLONG get_height_on_face_quad64_at(SLONG rx, SLONG rz, SWORD face,SLONG *height) { // SLONG ux,uy,uz,vx,vy,vz,wx,wy,wz; struct PrimFace4 *this_face4; SLONG ax,ay,az,bx,by,bz; SLONG top, bot; SLONG alpha, beta; SLONG x,y,z; SLONG mx=0,my=0,mz=0; UWORD c0; SLONG on_face=1; ASSERT(face>=0); this_face4=&prim_faces4[face]; for(c0=0;c0<4;c0++) { gh_vx[c0] = prim_points[this_face4->Points[c0]].X; gh_vy[c0] = prim_points[this_face4->Points[c0]].Y; gh_vz[c0] = prim_points[this_face4->Points[c0]].Z; mx+=gh_vx[c0]; // my+=gh_vy[c0]; mz+=gh_vz[c0]; } if(gh_vy[0]==gh_vy[1] && gh_vy[1]==gh_vy[2] && gh_vy[2]==gh_vy[3]) { *height=gh_vy[0]; return(1); } mx>>=2; // my>>=2; mz>>=2; for(c0=0;c0<4;c0++) { gh_vx[c0]=( ( (gh_vx[c0]-mx)*268)>>8 )+mx; // gh_vy[c0]=( ( (gh_vy[c0]-my)*268)>>8 )+my; gh_vz[c0]=( ( (gh_vz[c0]-mz)*268)>>8 )+mz; } /* ux= obj_x+prim_points[this_face4->Points[0]].X; uy= obj_y+prim_points[this_face4->Points[0]].Y; uz= obj_z+prim_points[this_face4->Points[0]].Z; vx= obj_x+prim_points[this_face4->Points[1]].X; vy= obj_y+prim_points[this_face4->Points[1]].Y; vz= obj_z+prim_points[this_face4->Points[1]].Z; wx= obj_x+prim_points[this_face4->Points[2]].X; wy= obj_y+prim_points[this_face4->Points[2]].Y; wz= obj_z+prim_points[this_face4->Points[2]].Z; if(uy==vy && vy==wy) return(uy); */ ax = (gh_vx[1] - gh_vx[0]) << 8; ay = (gh_vy[1] - gh_vy[0]) << 8; az = (gh_vz[1] - gh_vz[0]) << 8; bx = (gh_vx[2] - gh_vx[0]) << 8; by = (gh_vy[2] - gh_vy[0]) << 8; bz = (gh_vz[2] - gh_vz[0]) << 8; x = (rx<<8) - (gh_vx[0] << 8); z = (rz<<8) - (gh_vz[0] << 8); //printf("face =%d a=(%d,%d,%d) b =(%d,%d,%d) xz=(%d,%d)\n",face,ax,ay,az,bx,by,bz,x,z); // Work out alpha and beta such that x = alpha*ax + beta*bx and y = alhpa*ay + beta*by // First alpha... top = MUL64(x, bz) - MUL64(z, bx); bot = MUL64(bz, ax) - MUL64(bx, az); if (bot == 0) {bot = 0x8000;} alpha = DIV64(top, bot); // Now beta... top = MUL64(z, ax) - MUL64(x, az); if(bot<3) { *height=gh_vy[0]; return(1); } beta = DIV64(top, bot); if(alpha<0) { alpha=0; on_face=0; } if(beta<0) { beta=0; on_face=0; } if(alpha>0x10000) { alpha=0x10000; on_face=0; } if(beta>0x10000) { beta=0x10000; on_face=0; } /* if (alpha < 0 || alpha > 0x10000 || beta < 0 || beta > 0x10000) { LogText(" get height on QUAD NOT %d alpha %x beta %x \n",face,alpha,beta); return 1000000; } */ // else if (alpha+beta>0x10000) { // 0 1 3 2 // // 2 1 0 // 3 // // other triangular half of quad // ax = (gh_vx[2] - gh_vx[3]) << 8; ay = (gh_vy[2] - gh_vy[3]) << 8; az = (gh_vz[2] - gh_vz[3]) << 8; bx = (gh_vx[1] - gh_vx[3]) << 8; by = (gh_vy[1] - gh_vy[3]) << 8; bz = (gh_vz[1] - gh_vz[3]) << 8; x = (rx<<8) - (gh_vx[3] << 8); z = (rz<<8) - (gh_vz[3] << 8); //printf("face =%d a=(%d,%d,%d) b =(%d,%d,%d) xz=(%d,%d)\n",face,ax,ay,az,bx,by,bz,x,z); // Work out alpha and beta such that x = alpha*ax + beta*bx and y = alhpa*ay + beta*by // First alpha... top = MUL64(x, bz) - MUL64(z, bx); bot = MUL64(bz, ax) - MUL64(bx, az); if (bot == 0) {bot = 0x8000;} alpha = DIV64(top, bot); // Now beta... top = MUL64(z, ax) - MUL64(x, az); if(bot<3) { *height=gh_vy[3]; return(on_face); } beta = DIV64(top, bot); /* if (alpha < 0 || alpha > 0x10000 || beta < 0 || beta > 0x10000) { } else */ if(alpha<0) { alpha=0; on_face=0; } if(beta<0) { beta=0; on_face=0; } if(alpha>0x10000) { alpha=0x10000; on_face=0; } if(beta>0x10000) { beta=0x10000; on_face=0; } if (alpha+beta>0x10000) { // This is benign - happens very very occasionally - don't worry about it. ASSERT(0); *height=gh_vy[1]; return(0); } else { y = gh_vy[3] << 8; y += MUL64(alpha, ay); y += MUL64(beta, by); *height= y >> 8; return(on_face); } } else { // LogText(" get height on face=%d alpha %x beta %x uy %d vy %d wy %d\n",y>>8,face,alpha,beta),uy,vy,wy; y = gh_vy[0] << 8; y += MUL64(alpha, ay); y += MUL64(beta, by); *height= y >> 8; return(on_face); } } // // returns 0 or 1 (on face false/true) new_y is alt on face // /* SLONG calc_height_on_face(SLONG x,SLONG z,SLONG face,SLONG *new_y) { if (face > 0) { return(get_height_on_face_quad64_at(x,z,face,new_y)); } ASSERT(0); // return(1000000); // return(-100); } */ SLONG is_thing_on_this_quad(SLONG x,SLONG z,SLONG face) { if(face<0) { struct RoofFace4 *rf; // highlight_rface(-face); if(IS_ROOF_HIDDEN_FACE(face)) { if((x>>8)==ROOF_HIDDEN_X(face) && (z>>8)==ROOF_HIDDEN_Z(face)) return(1); else return(0); } rf=&roof_faces4[-face]; x>>=8; z>>=8; if(x==(rf->RX&127) && z==(rf->RZ&127)) return(1); else return(0); } else { if(point_in_quad(x,z,0,0,0,face)) { return(1); } else { return(0); } } } SLONG calc_height_on_rface(SLONG x, SLONG z,SWORD face,SLONG *ret_y) { SLONG h0; SLONG h1; SLONG h2; SLONG h3; SLONG xfrac; SLONG zfrac; SLONG answer; struct RoofFace4 *rf; ASSERT(face>0); if(IS_ROOF_HIDDEN_FACE(-face)) { if(ROOF_HIDDEN_X(-face)!=(x>>8) || ROOF_HIDDEN_Z(-face)!=(z>>8)) return(0); if(PAP_hi[x>>8][z>>8].Flags&PAP_FLAG_ROOF_EXISTS) { *ret_y = MAVHEIGHT(x>>8,z>>8)<<6; return(ROOF_HIDDEN_GET_FACE(x>>8,z>>8)); } else return(0); } // highlight_rface(face); rf=&roof_faces4[face]; if(x>>8!=(rf->RX&127) ||z>>8!=(rf->RZ&127)) return(0); h0 = rf->Y; if(!(rf->RZ&128)) { *ret_y=h0; return(face); } h1 = h0+(rf->DY[2]<DY[0]<DY[1]<RX&1<<7) { xfrac = x & 0xff; zfrac = z & 0xff; if (xfrac + (256-zfrac) < 0x100) { answer = h1; answer += (h3 - h1) * xfrac >> 8; answer += (h0 - h1) * (256-zfrac) >> 8; } else { answer = h2; answer += (h0 - h2) * (0x100 - xfrac) >> 8; answer += (h3 - h2) * (zfrac) >> 8; } } else { xfrac = x & 0xff; zfrac = z & 0xff; if (xfrac + zfrac < 0x100) { answer = h0; answer += (h2 - h0) * xfrac >> 8; answer += (h1 - h0) * zfrac >> 8; } else { answer = h3; answer += (h1 - h3) * (0x100 - xfrac) >> 8; answer += (h2 - h3) * (0x100 - zfrac) >> 8; } } } *ret_y=answer; return(face); } // // Finds a face to be stood on (checks height is not out of range) // SLONG find_face_for_this_pos( SLONG x, SLONG y, SLONG z, SLONG *ret_y, SLONG ignore_building, UBYTE ignore_height_flag) { UBYTE mx; UBYTE mz; SWORD dy; SLONG facey; SWORD index; SWORD groundy; SWORD best_face = NULL; SWORD best_dy = 0x7fff; SWORD best_facey = 0; SWORD mx1 = x - 0x200 >> PAP_SHIFT_LO; SWORD mz1 = z - 0x200 >> PAP_SHIFT_LO; SWORD mx2 = x + 0x200 >> PAP_SHIFT_LO; SWORD mz2 = z + 0x200 >> PAP_SHIFT_LO; SATURATE(mx1, 0, PAP_SIZE_LO - 1); SATURATE(mz1, 0, PAP_SIZE_LO - 1); SATURATE(mx2, 0, PAP_SIZE_LO - 1); SATURATE(mz2, 0, PAP_SIZE_LO - 1); if(PAP_hi[x>>8][z>>8].Flags&PAP_FLAG_ROOF_EXISTS) { best_face=ROOF_HIDDEN_GET_FACE(x>>8,z>>8); if(ignore_height_flag==FIND_ANYFACE) { *ret_y = MAVHEIGHT(x>>8,z>>8)<<6; return(best_face); } best_facey=MAVHEIGHT(x>>8,z>>8)<<6; best_dy = best_facey - y; if(best_dy<30 && ignore_height_flag==FIND_FACE_NEAR_BELOW) { *ret_y = best_facey; return best_face; } if (best_dy < 0xa0) { best_face = best_face; best_dy = abs(best_dy); } } for (mx = mx1; mx <= mx2; mx++) for (mz = mz1; mz <= mz2; mz++) { index = PAP_2LO(mx,mz).Walkable; while(index) { // ASSERT(index >= 0); // ASSERT(WITHIN(index, 1, next_prim_face4 - 1)); if (is_thing_on_this_quad(x,z, index)) { // // We've found a face to stand on. But at what height? // we are on this face so use clipped alpha and beta in calc height on face // if(index<0) { calc_height_on_rface(x,z, -index,&facey); } else { calc_height_on_face(x,z, index,&facey); } dy = facey - y; if(ignore_height_flag==FIND_ANYFACE) { *ret_y = facey; return index; } if(dy<30 && ignore_height_flag==FIND_FACE_NEAR_BELOW) { *ret_y = facey; return index; } if (dy <= 0xa0) { // // This is a candidate face. // if (abs(dy) < best_dy) { best_dy = abs(dy); best_face = index; best_facey = facey; } } else { // // Too much difference in y. Ignore this face. // } } if(index<0) { index = roof_faces4[-index].Next; } else { index = prim_faces4[index].WALKABLE; } } } if (best_face == NULL) { // // Could not find a face to stand on. How about the ground? // if(PAP_2HI(x>>PAP_SHIFT_HI,z>>PAP_SHIFT_HI).Flags & PAP_FLAG_HIDDEN) { return(0); } groundy = PAP_calc_height_at(x,z); //+5 *ret_y = groundy; dy = y - groundy; if (abs(dy) < 0x50) { return GRAB_FLOOR; // step onto floor } } else { *ret_y = best_facey; return best_face; } return NULL; } SLONG find_height_for_this_pos( SLONG x,SLONG z, SLONG *ret_face) { UBYTE mx; UBYTE mz; SLONG dy; SLONG facey; SWORD index; SLONG groundy; SWORD mx1 = x - 0x200 >> PAP_SHIFT_LO; SWORD mz1 = z - 0x200 >> PAP_SHIFT_LO; SWORD mx2 = x + 0x200 >> PAP_SHIFT_LO; SWORD mz2 = z + 0x200 >> PAP_SHIFT_LO; SATURATE(mx1, 0, PAP_SIZE_LO - 1); SATURATE(mz1, 0, PAP_SIZE_LO - 1); SATURATE(mx2, 0, PAP_SIZE_LO - 1); SATURATE(mz2, 0, PAP_SIZE_LO - 1); if(PAP_hi[x>>8][z>>8].Flags&PAP_FLAG_ROOF_EXISTS) { *ret_face=ROOF_HIDDEN_GET_FACE(x>>8,z>>8); return(MAVHEIGHT(x>>8,z>>8)<<6); } for (mx = mx1; mx <= mx2; mx++) for (mz = mz1; mz <= mz2; mz++) { index = PAP_2LO(mx,mz).Walkable; while(index) { // ASSERT(index >= 0); // ASSERT(WITHIN(index, 1, next_prim_face4 - 1)); if (is_thing_on_this_quad(x,z, index)) { // // We've found a face to stand on. But at what height? // // // use result no matter what as we are on the face // if(index<0) { calc_height_on_rface(x,z, -index,&facey); } else { calc_height_on_face(x,z, index,&facey); } { *ret_face = index; return facey; } } if(index<0) { index = roof_faces4[-index].Next; } else { index = prim_faces4[index].WALKABLE; } } } // // How about the ground? // if(PAP_2HI(x>>PAP_SHIFT_HI,z>>PAP_SHIFT_HI).Flags & PAP_FLAG_HIDDEN) return(0); groundy = PAP_calc_height_at(x,z); //+5 *ret_face = 0; return groundy; // step onto floor } SLONG RFACE_on_slope(SLONG face,SLONG x,SLONG z,SLONG *angle) { SLONG h0; SLONG h1; SLONG h2; SLONG h3; SLONG xfrac; SLONG zfrac; struct RoofFace4 *rf; ASSERT(face>0); if(IS_ROOF_HIDDEN_FACE(-face)) return(0); rf=&roof_faces4[face]; if(!(rf->RZ&128)) { *angle=0; return(0); } if(x>>8!=(rf->RX&127) ||z>>8!=(rf->RZ&127)) return(0); h0 = rf->Y; h1 = h0+(rf->DY[2]<DY[0]<DY[1]<RX&(1<<7)) { if (xfrac + (256-zfrac) < 0x100) { SLONG vx,vy,vz; SLONG wx,wy,wz; SLONG rx,ry,rz; SLONG len; vx=256; vy=h3-h1; vz=0; wx=0; wy=h0-h1; wz=256; rx=(vy*wz); //-vz*wy; ry=65536; //vz*wx-vx*wz; dont care about this rz=(vx*wy); //-vy*wx; if(rx==0 && rz==0) return(0); *angle = (Arctan(rx,rz))&2047; rx=abs(rx); rz=abs(rz); len=QDIST3(rx,ry,rz); ry=(ry<<8)/(len); return(abs(256-(len>>8))); } else { SLONG vx,vy,vz; SLONG wx,wy,wz; SLONG rx,ry,rz; SLONG len; vx=-256; vy=h0-h2; vz=0; wx=0; wy=h3-h2; wz=256; rx=(vy*wz); //-vz*wy; ry=65536; //vz*wx-vx*wz; dont care about this rz=(vx*wy); //-vy*wx; if(rx==0 && rz==0) return(0); *angle = (Arctan(-rx,rz))&2047 ; rx=abs(rx); rz=abs(rz); len=QDIST3(rx,ry,rz); ry=(ry<<8)/(len); return(abs(256-(len>>8))); } } else { if (xfrac + zfrac < 0x100) { SLONG vx,vy,vz; SLONG wx,wy,wz; SLONG rx,ry,rz; SLONG len; vx=256; vy=h2-h0; vz=0; wx=0; wy=h1-h0; wz=-256; rx=(vy*wz); //-vz*wy; ry=65536; //vz*wx-vx*wz; dont care about this rz=(vx*wy); //-vy*wx; if(rx==0 && rz==0) return(0); *angle = (Arctan(-rx,-rz))&2047; rx=abs(rx); rz=abs(rz); len=QDIST3(rx,ry,rz); ry=(ry<<8)/(len); return(abs(256-(len>>8))); } else { SLONG vx,vy,vz; SLONG wx,wy,wz; SLONG rx,ry,rz; SLONG len; vx=-256; vy=h1-h3; vz=0; wx=0; wy=h2-h3; wz=-256; rx=(vy*wz); //-vz*wy; ry=65536; //vz*wx-vx*wz; dont care about this rz=(vx*wy); //-vy*wx; if(rx==0 && rz==0) return(0); *angle = (Arctan(rx,-rz))&2047 ; rx=abs(rx); rz=abs(rz); len=QDIST3(rx,ry,rz); ry=(ry<<8)/(len); return(abs(256-(len>>8))); } } } } #ifndef PSX void WALKABLE_remove_rface(UBYTE map_x, UBYTE map_z) { SWORD next; SWORD *prev; PAP_Lo *pl; RoofFace4 *rf; pl = &PAP_2LO(map_x >> 2, map_z >> 2); if(PAP_hi[map_x][map_z].Flags&PAP_FLAG_ROOF_EXISTS) { PAP_hi[map_x][map_z].Flags&=~PAP_FLAG_ROOF_EXISTS; return; } prev = &pl->Walkable; next = pl->Walkable; while(next) { if (next < 0) { rf = &roof_faces4[-next]; if ((rf->RX&127) == map_x && (rf->RZ&127) == map_z) { // // We have found the face to get rid of. Take it out of the linked list // for this square. // *prev = rf->Next; // // Instead of deleting this face proper, we mark it as no-draw for now. // rf->DrawFlags |= RFACE_FLAG_NODRAW; return; } prev = &rf->Next; next = rf->Next; } else { // // This is a normal walkable face. // prev = &prim_faces4[next].WALKABLE; next = prim_faces4[next].WALKABLE; } } // // Make this mapsquare be HIDDEN. // PAP_2HI(map_x,map_z).Flags |= PAP_FLAG_HIDDEN; } #endif