1 #ifndef H_COLLISION 2 #define H_COLLISION 3 4 #include "core.h" 5 #include "utils.h" 6 #include "format.h" 7 #include "controller.h" 8 9 struct Collision { 10 enum Side { NONE, LEFT, RIGHT, FRONT, BACK, TOP, BOTTOM } side; 11 12 struct Info { 13 int room, roomAbove, roomBelow; 14 int climb; 15 float floor, ceiling; 16 } info[4]; 17 CollisionCollision18 Collision() : side(NONE) {} 19 CollisionCollision20 Collision(Controller *controller, int roomIndex, vec3 &pos, const vec3 &offset, const vec3 &velocity, float radius, float angle, int minHeight, int maxHeight, int maxAscent, int maxDescent) { 21 if (velocity.x > 0.0f || velocity.z > 0.0f) 22 angle = normalizeAngle(PI2 + vec2(velocity.z, velocity.x).angle()); 23 pos += velocity; 24 25 int q = angleQuadrant(angle, 0.25f); 26 27 const vec2 v[] = { 28 vec2( -radius, radius ), 29 vec2( radius, radius ), 30 vec2( radius, -radius ), 31 vec2( -radius, -radius ), 32 }; 33 34 const vec2 &l = v[q], &r = v[(q + 1) % 4]; 35 36 vec2 f = (q %= 2) ? vec2(l.x, radius * cosf(angle)) : vec2(radius * sinf(angle), l.y), 37 p(pos.x, pos.z), 38 d(0.0F); 39 40 vec3 hpos = pos + offset; 41 42 int height = maxHeight - minHeight; 43 44 getFloor(controller->level, roomIndex, vec3(pos.x, hpos.y, pos.z)); 45 46 if (checkHeight(controller, roomIndex, hpos, vec2(0.0f), height, 0xFFFFFF, 0xFFFFFF, side = NONE)) { 47 pos.x -= velocity.x; 48 pos.z -= velocity.z; 49 side = FRONT; 50 return; 51 } 52 53 float hCell = info[NONE].ceiling - (hpos.y - maxHeight); 54 if (hCell > 0) { 55 if (hCell > 128) { 56 pos.x -= velocity.x; 57 pos.z -= velocity.z; 58 side = FRONT; 59 } else { 60 pos.y = info[NONE].ceiling + maxHeight - offset.y; 61 side = TOP; 62 } 63 } 64 65 float hFloor = info[NONE].floor - (hpos.y + minHeight); 66 if (hFloor < 0 && hFloor > -256) { 67 pos.y = info[NONE].floor - minHeight - offset.y; 68 side = BOTTOM; 69 } 70 71 if (checkHeight(controller, roomIndex, hpos, f, height, maxAscent, maxDescent, FRONT)) { 72 d = vec2(-velocity.x, -velocity.z); 73 q ^= 1; 74 d[q] = getOffset(p[q] + f[q], p[q]); 75 } else if (checkHeight(controller, roomIndex, hpos, l, height, maxAscent, maxDescent, LEFT)) { 76 d[q] = getOffset(p[q] + l[q], p[q] + f[q]); 77 } else if (checkHeight(controller, roomIndex, hpos, r, height, maxAscent, maxDescent, RIGHT)) { 78 d[q] = getOffset(p[q] + r[q], p[q] + f[q]); 79 } else 80 return; 81 82 pos += vec3(d.x, 0.0f, d.y); 83 } 84 checkHeightCollision85 inline bool checkHeight(Controller *controller, int roomIndex, const vec3 &pos, const vec2 &offset, int height, int maxAscent, int maxDescent, Side side) { 86 TR::Level::FloorInfo info; 87 controller->getFloorInfo(roomIndex, pos + vec3(offset.x, 0.0f, offset.y), info); 88 89 Info &inf = this->info[side]; 90 inf.room = info.roomNext != TR::NO_ROOM ? info.roomNext : roomIndex; 91 inf.roomAbove = info.roomAbove; 92 inf.roomBelow = info.roomBelow; 93 inf.floor = info.floor; 94 inf.ceiling = info.ceiling; 95 inf.climb = info.climb; 96 97 if ((info.ceiling == info.floor) || (info.floor - info.ceiling < height) || (pos.y - info.floor > maxAscent) || (info.floor - pos.y > maxDescent) || (info.ceiling > pos.y) || 98 (maxAscent == maxDescent && (maxAscent <= 256 + 128) && (abs(info.slantX) > 2 || abs(info.slantZ) > 2))) { 99 this->side = side; 100 return true; 101 } 102 return false; 103 } 104 getOffsetCollision105 inline float getOffset(float from, float to) { 106 int a = int(from) / 1024; 107 int b = int(to) / 1024; 108 109 from -= float(a * 1024.0f); 110 111 if (b == a) 112 return 0.0f; 113 else if (b > a) 114 return -from + 1025.0f; 115 return -from - 1.0f; 116 } 117 getFloorCollision118 static int getFloor(TR::Level *level, int &roomIndex, const vec3 &pos) { 119 int dx, dz, x = int(pos.x), z = int(pos.z); 120 121 TR::Room::Sector *s = &level->getSector(roomIndex, x, z, dx, dz); 122 while (s->ceiling * 256 > pos.y && s->roomAbove != TR::NO_ROOM) { 123 roomIndex = s->roomAbove; 124 s = &level->getSector(roomIndex, x, z, dx, dz); 125 } 126 127 return s->floor * 256; 128 } 129 }; 130 131 #endif