mirror of
https://github.com/XProger/OpenLara.git
synced 2025-02-26 00:13:09 +01:00
104 lines
3.3 KiB
C
104 lines
3.3 KiB
C
|
#ifndef H_COLLISION
|
||
|
#define H_COLLISION
|
||
|
|
||
|
#include "core.h"
|
||
|
#include "utils.h"
|
||
|
#include "format.h"
|
||
|
|
||
|
struct Collision {
|
||
|
enum Side { NONE, LEFT, RIGHT, FRONT, TOP, BOTTOM } side;
|
||
|
|
||
|
struct Info {
|
||
|
int room, roomAbove, roomBelow, floor, ceiling;
|
||
|
} info[4];
|
||
|
|
||
|
Collision() : side(NONE) {}
|
||
|
|
||
|
Collision(TR::Level *level, int room, vec3 &pos, const vec3 &offset, const vec3 &velocity, float radius, float angle, int minHeight, int maxHeight, int maxAscent, int maxDescent) {
|
||
|
if (velocity.x > 0.0f || velocity.z > 0.0f)
|
||
|
angle = normalizeAngle(PI2 + vec2(velocity.z, velocity.x).angle());
|
||
|
pos += velocity;
|
||
|
|
||
|
int q = angleQuadrant(angle);
|
||
|
|
||
|
const vec2 v[] = {
|
||
|
{ -radius, radius },
|
||
|
{ radius, radius },
|
||
|
{ radius, -radius },
|
||
|
{ -radius, -radius },
|
||
|
};
|
||
|
|
||
|
const vec2 &l = v[q], &r = v[(q + 1) % 4];
|
||
|
|
||
|
vec2 f = (q %= 2) ? vec2(l.x, radius * cosf(angle)) : vec2(radius * sinf(angle), l.y),
|
||
|
p(pos.x, pos.z),
|
||
|
d(0.0F);
|
||
|
|
||
|
vec3 hpos = pos + offset;
|
||
|
|
||
|
int height = maxHeight - minHeight;
|
||
|
|
||
|
if (checkHeight(level, room, hpos, vec2(0.0f), height, 0xFFFFFF, 0xFFFFFF, side = NONE)) {
|
||
|
pos -= velocity;
|
||
|
side = FRONT;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (info[NONE].ceiling > hpos.y - maxHeight) {
|
||
|
pos.y = info[NONE].ceiling + maxHeight - offset.y;
|
||
|
side = TOP;
|
||
|
}
|
||
|
|
||
|
if (info[NONE].floor < hpos.y + minHeight) {
|
||
|
pos.y = info[NONE].floor - minHeight - offset.y;
|
||
|
side = BOTTOM;
|
||
|
}
|
||
|
|
||
|
if (checkHeight(level, room, hpos, f, height, maxAscent, maxDescent, FRONT)) {
|
||
|
d = vec2(-velocity.x, -velocity.z);
|
||
|
q ^= 1;
|
||
|
d[q] = getOffset(p[q] + f[q], p[q]);
|
||
|
} else if (checkHeight(level, room, hpos, l, height, maxAscent, maxDescent, LEFT)) {
|
||
|
d[q] = getOffset(p[q] + l[q], p[q] + f[q]);
|
||
|
} else if (checkHeight(level, room, hpos, r, height, maxAscent, maxDescent, RIGHT)) {
|
||
|
d[q] = getOffset(p[q] + r[q], p[q] + f[q]);
|
||
|
} else
|
||
|
return;
|
||
|
|
||
|
pos += vec3(d.x, 0.0f, d.y);
|
||
|
}
|
||
|
|
||
|
inline bool checkHeight(TR::Level *level, int room, const vec3 &pos, const vec2 &offset, int height, int maxAscent, int maxDescent, Side side) {
|
||
|
TR::Level::FloorInfo info;
|
||
|
int py = int(pos.y);
|
||
|
level->getFloorInfo(room, int(pos.x + offset.x), py, int(pos.z + offset.y), info);
|
||
|
|
||
|
Info &inf = this->info[side];
|
||
|
inf.room = info.roomNext != TR::NO_ROOM ? info.roomNext : room;
|
||
|
inf.roomAbove = info.roomAbove;
|
||
|
inf.roomBelow = info.roomBelow;
|
||
|
inf.floor = info.floor;
|
||
|
inf.ceiling = info.ceiling;
|
||
|
|
||
|
if ((info.ceiling == info.floor) || (info.floor - info.ceiling < height) || (py - info.floor > maxAscent) || (info.floor - py > maxDescent) || (info.ceiling > py)) {
|
||
|
this->side = side;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
inline float getOffset(float from, float to) {
|
||
|
int a = int(from) / 1024;
|
||
|
int b = int(to) / 1024;
|
||
|
|
||
|
from -= float(a * 1024.0f);
|
||
|
|
||
|
if (b == a)
|
||
|
return 0.0f;
|
||
|
else if (b > a)
|
||
|
return -from + 1025.0f;
|
||
|
return -from - 1.0f;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#endif
|