1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-07 13:46:45 +02:00

TR1 Lara state changes and collision re-implementation (close to original)

This commit is contained in:
Timur Gagiev
2020-08-21 01:10:39 +03:00
parent c498f2fd9c
commit 683a991d57
7 changed files with 3340 additions and 757 deletions

View File

@@ -31,8 +31,7 @@ struct Character : Controller {
WALK = 1 << 6,
ACTION = 1 << 7,
WEAPON = 1 << 8,
LOOK = 1 << 9,
DEATH = 1 << 10
LOOK = 1 << 9
};
Controller *viewTarget;
@@ -143,10 +142,11 @@ struct Character : Controller {
virtual int getStateWade() { return state; }
virtual int getStateDeath() { return state; }
virtual int getStateDefault() { return state; }
virtual int getInput() { return health <= 0 ? DEATH : 0; }
virtual int getInput() { return 0; }
virtual bool useHeadAnimation() { return false; }
int getNextState() {
/*
if (input & DEATH) {
int deathState = getStateDeath();
if (state == deathState || animation.canSetState(deathState)) {
@@ -155,7 +155,7 @@ struct Character : Controller {
return deathState;
}
}
*/
switch (stand) {
case STAND_AIR : return getStateAir();
case STAND_GROUND : return getStateGround();

View File

@@ -573,7 +573,7 @@ namespace Debug {
TR::StaticMesh *sm = &level.staticMeshes[m.meshIndex];
Box box;
vec3 offset = vec3(float(m.x), float(m.y), float(m.z));
vec3 offset = vec3(float(m.pos.x), float(m.pos.y), float(m.pos.z));
sm->getBox(false, m.rotation, box); // visible box
Debug::Draw::box(offset + box.min, offset + box.max, vec4(1, 1, 0, 0.25));

View File

@@ -1274,7 +1274,7 @@
E( MESHSWAP1 ) \
E( MESHSWAP2 ) \
E( MESHSWAP3 ) \
E( DEATH_SLIDE ) \
E( ZIPLINE ) \
E( BODY_PART ) \
E( CAMERA_TARGET ) \
E( WATERFALL1 ) \
@@ -1382,6 +1382,7 @@ namespace TR {
enum {
NO_FLOOR = -127,
NO_VALUE = NO_FLOOR * 256,
NO_ROOM = 0xFF,
NO_BOX = 0xFFFF,
NO_WATER = 0x7FFFFFFF,
@@ -1617,7 +1618,7 @@ namespace TR {
}
union fixed {
uint32 value;
int32 value;
struct {
uint16 L;
int16 H;
@@ -1887,7 +1888,7 @@ namespace TR {
} *lights;
struct Mesh {
int32 x, y, z;
vec3i pos;
angle rotation;
uint16 meshID;
Color32 color;
@@ -1987,6 +1988,12 @@ namespace TR {
}
};
enum SlantType {
SLANT_NONE,
SLANT_LOW,
SLANT_HIGH
};
union FloorData {
uint16 value;
union Command {
@@ -2015,6 +2022,9 @@ namespace TR {
};
} triggerCmd;
FloorData() {}
FloorData(uint16 value) : value(value) {}
enum {
NONE
, PORTAL
@@ -2661,6 +2671,18 @@ namespace TR {
vec3 min() const { return vec3((float)minX, (float)minY, (float)minZ); }
vec3 max() const { return vec3((float)maxX, (float)maxY, (float)maxZ); }
MinMax lerp(const MinMax &b, int32 mod, int32 rate) const {
#define LERP(v) r.##v = v + ((b.##v - v) * mod) / rate;
MinMax r;
LERP(minX); LERP(maxX);
LERP(minY); LERP(maxY);
LERP(minZ); LERP(maxZ);
return r;
#undef LERP
}
};
struct AnimFrame {
@@ -2744,8 +2766,13 @@ namespace TR {
MinMax cbox;
uint16 flags;
BoxV2 getBox(bool collision) {
MinMax &b = collision ? cbox : vbox;
return BoxV2(vec3i(b.minX, b.minY, b.minZ), vec3i(b.maxX, b.maxY, b.maxZ));
}
void getBox(bool collision, angle rotation, ::Box &box) {
int k = rotation.value / 0x4000;
int k = rotation.value / ANGLE_90;
MinMax &m = collision ? cbox : vbox;
@@ -3997,9 +4024,9 @@ namespace TR {
room->meshes = room->meshesCount ? new Room::Mesh[room->meshesCount] : NULL;
for (int i = 0; i < room->meshesCount; i++) {
Room::Mesh &m = room->meshes[i];
m.x = stream.readBE32();
m.y = stream.readBE32();
m.z = stream.readBE32();
m.pos.x = stream.readBE32();
m.pos.y = stream.readBE32();
m.pos.z = stream.readBE32();
m.rotation.value = stream.readBE16();
uint16 intensity = stream.readBE16();
stream.readBE16();
@@ -5462,9 +5489,9 @@ namespace TR {
r.meshes = r.meshesCount ? new Room::Mesh[r.meshesCount] : NULL;
for (int i = 0; i < r.meshesCount; i++) {
Room::Mesh &m = r.meshes[i];
stream.read(m.x);
stream.read(m.y);
stream.read(m.z);
stream.read(m.pos.x);
stream.read(m.pos.y);
stream.read(m.pos.z);
stream.read(m.rotation.value);
if (version & (VER_TR3 | VER_TR4)) {
Color16 color;
@@ -6646,15 +6673,11 @@ namespace TR {
return room.sectors[sectorIndex = (x * room.zSectors + z)];
}
Room::Sector* getSector(int16 &roomIndex, const vec3 &pos) {
Room::Sector* getSector(int16 &roomIndex, int32 x, int32 y, int32 z) {
ASSERT(roomIndex >= 0 && roomIndex <= roomsCount);
Room::Sector *sector = NULL;
int x = int(pos.x);
int y = int(pos.y);
int z = int(pos.z);
// check horizontal
int16 prevRoom = roomIndex;
@@ -6687,23 +6710,38 @@ namespace TR {
return sector;
}
float getFloor(const Room::Sector *sector, const vec3 &pos, int16 *roomIndex = NULL) {
int x = int(pos.x);
int z = int(pos.z);
Room::Sector* getSector(int16 &roomIndex, const vec3 &pos) {
return getSector(roomIndex, int32(pos.x), int32(pos.y), int32(pos.z));
}
int16 getFloor(const Room::Sector *sector, int32 x, int32 y, int32 z, SlantType *slantType = NULL, int16 *slant = NULL, int16 **trigger = NULL, int16 *roomIndex = NULL) {
int dx = x & 1023;
int dz = z & 1023;
if (slant) {
*slant = 0;
}
if (slantType) {
*slantType = SLANT_NONE;
}
if (trigger) {
*trigger = NULL;
}
while (sector->roomBelow != NO_ROOM) {
Room &room = rooms[sector->roomBelow];
if (roomIndex)
if (roomIndex) {
*roomIndex = sector->roomBelow;
}
sector = room.getSector((x - room.info.x) / 1024, (z - room.info.z) / 1024);
}
int floor = sector->floor * 256;
if (!sector->floorIndex)
return float(floor);
return floor;
FloorData *fd = &floors[sector->floorIndex];
FloorData::Command cmd;
@@ -6724,6 +6762,14 @@ namespace TR {
if (cmd.func == TR::FloorData::FLOOR) {
sx = fd->slantX;
sz = fd->slantZ;
if (slant) {
*slant = fd->value;
}
if (slantType) {
*slantType = (abs(sx) <= 2 && abs(sz) <= 2) ? SLANT_LOW : SLANT_HIGH;
}
} else {
if (cmd.func == TR::FloorData::FLOOR_NW_SE_SOLID ||
cmd.func == TR::FloorData::FLOOR_NW_SE_PORTAL_SE ||
@@ -6757,6 +6803,9 @@ namespace TR {
}
case FloorData::TRIGGER : {
if (trigger && *trigger == NULL) {
*trigger = (int16*)(fd - 1);
}
fd++;
FloorData::TriggerCommand trigCmd;
do {
@@ -6772,12 +6821,10 @@ namespace TR {
}
} while (!cmd.end);
return float(floor);
return floor;
}
float getCeiling(const Room::Sector *sector, const vec3 &pos) {
int x = int(pos.x);
int z = int(pos.z);
int16 getCeiling(const Room::Sector *sector, int32 x, int32 y, int32 z) {
int dx = x & 1023;
int dz = z & 1023;
@@ -6790,7 +6837,7 @@ namespace TR {
int ceiling = sector->ceiling * 256;
if (!sector->floorIndex)
return float(ceiling);
return ceiling;
FloorData *fd = &floors[sector->floorIndex];
FloorData::Command cmd;
@@ -6859,13 +6906,18 @@ namespace TR {
}
} while (!cmd.end);
return float(ceiling);
return ceiling;
}
Room::Sector* getWaterLevelSector(int16 &roomIndex, const vec3 &pos) {
int x = int(pos.x);
int z = int(pos.z);
float getFloor(const Room::Sector *sector, const vec3 &pos, int16 *roomIndex = NULL) {
return (float)getFloor(sector, int32(pos.x), int32(pos.y), int32(pos.z), NULL, NULL, NULL, roomIndex);
}
float getCeiling(const Room::Sector *sector, const vec3 &pos, int16 *roomIndex = NULL) {
return (float)getCeiling(sector, int32(pos.x), int32(pos.y), int32(pos.z));
}
Room::Sector* getWaterLevelSector(int16 &roomIndex, int32 x, int32 z) {
Room *room = &rooms[roomIndex];
Room::Sector *sector = room->getSector((x - room->info.x) / 1024, (z - room->info.z) / 1024);
@@ -6877,6 +6929,7 @@ namespace TR {
roomIndex = sector->roomAbove;
sector = room->getSector((x - room->info.x) / 1024, (z - room->info.z) / 1024);
}
return sector;
} else { // go down to the water
while (sector->roomBelow != NO_ROOM) {
room = &rooms[roomIndex = sector->roomBelow];
@@ -6884,8 +6937,12 @@ namespace TR {
if (room->flags.water)
return sector;
}
return NULL;
}
return NULL;
}
Room::Sector* getWaterLevelSector(int16 &roomIndex, const vec3 &pos) {
return getWaterLevelSector(roomIndex, int32(pos.x), int32(pos.z));
}
void getWaterInfo(int16 roomIndex, const vec3 &pos, float &level, float &depth) {

View File

@@ -262,6 +262,10 @@ namespace Game {
return false;
}
if (frameDelta > 30) { // maximum one sec frame drop
frameDelta = 30;
}
if (nextLevel) {
startLevel(nextLevel);
nextLevel = NULL;

3868
src/lara.h

File diff suppressed because it is too large Load Diff

View File

@@ -358,9 +358,9 @@ struct MeshBuilder {
if (!level->meshOffsets[s->mesh]) continue;
TR::Mesh &mesh = level->meshes[level->meshOffsets[s->mesh]];
int x = m.x - room.info.x;
int y = m.y;
int z = m.z - room.info.z;
int x = m.pos.x - room.info.x;
int y = m.pos.y;
int z = m.pos.z - room.info.z;
int d = m.rotation.value / 0x4000;
buildMesh(geom, blendMask, mesh, level, indices, vertices, iCount, vCount, vStartRoom, 0, x, y, z, d, m.color, true, false);
}

View File

@@ -88,6 +88,14 @@
#define SQR(x) ((x)*(x))
#define randf() (float(rand())/float(RAND_MAX))
// fixed point angles
#define DEG2SHORT (0x10000 / 360)
#define ANGLE_0 0
#define ANGLE_1 DEG2SHORT
#define ANGLE_45 0x2000 // != 45 * DEG2SHORT !!!
#define ANGLE_90 0x4000
#define ANGLE_180 0x8000
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
@@ -348,6 +356,24 @@ namespace Noise { // based on https://github.com/Auburns/FastNoise
}
}
struct vec3i {
int32 x, y, z;
inline vec3i() {}
inline vec3i(int s) : x(s), y(s), z(s) {}
inline vec3i(int32 x, int32 y, int32 z) : x(x), y(y), z(z) {}
inline vec3i operator + (const vec3i &v) const { return vec3i(x + v.x, y + v.y, z + v.z); }
inline vec3i operator - (const vec3i &v) const { return vec3i(x - v.x, y - v.y, z - v.z); }
inline vec3i operator * (int32 s) const { return vec3i(x * s, y * s, z * s); }
inline vec3i operator / (int32 s) const { return vec3i(x / s, y / s, z / s); }
};
struct vec3s {
int16 x, y, z;
};
struct vec2 {
float x, y;
vec2() {}
@@ -1225,17 +1251,6 @@ struct Box {
return min;
}
Box intersection2D(const Box &b) const {
Box r(vec3(0.0f), vec3(0.0f));
if (max.x < b.min.x || min.x > b.max.x) return r;
if (max.y < b.min.y || min.y > b.max.y) return r;
r.max.x = ::min(max.x, b.max.x);
r.max.y = ::min(max.y, b.max.y);
r.min.x = ::max(min.x, b.min.x);
r.min.y = ::max(min.y, b.min.y);
return r;
}
Box& operator += (const Box &box) {
min.x = ::min(min.x, box.min.x);
min.y = ::min(min.y, box.min.y);
@@ -1269,7 +1284,7 @@ struct Box {
Box operator * (const mat4 &m) const {
Box res(vec3(+INF), vec3(-INF));
for (int i = 0; i < 8; i++) {
vec4 v = m * vec4((*this)[i], 1.0f);
vec4 v = m * vec4((*this)[i], 1.0f);
res += v.xyz() /= v.w;
}
return res;
@@ -1384,6 +1399,59 @@ struct Box {
}
};
struct BoxV2 {
vec3i min, max;
BoxV2() {}
BoxV2(const vec3i &min, const vec3i &max) : min(min), max(max) {}
bool intersect(const BoxV2 &box) const {
return !((max.x <= box.min.x || min.x >= box.max.x) || (max.y <= box.min.y || min.y >= box.max.y) || (max.z <= box.min.z || min.z >= box.max.z));
}
vec3i center() const {
return (min + max) / 2;
}
vec3i size() const {
return max - min;
}
vec3i closestPoint(const vec3i &p) const {
return vec3i(clamp(p.x, min.x, max.x),
clamp(p.y, min.y, max.y),
clamp(p.z, min.z, max.z));
}
vec3i pushOut2D(const BoxV2 &b) const {
int32 ax = b.max.x - min.x;
int32 bx = max.x - b.min.x;
int32 az = b.max.z - min.z;
int32 bz = max.z - b.min.z;
return vec3i(
(ax < bx) ? -ax : bx,
0,
(az < bz) ? -az : bz
);
}
void translate(const vec3i &v) {
min = min + v;
max = max + v;
}
void rotate90(int n) {
switch (n) {
case 0 : break;
case 1 : *this = BoxV2(vec3i( min.z, min.y, -max.x), vec3i( max.z, max.y, -min.x)); break;
case 2 : *this = BoxV2(vec3i(-max.x, min.y, -max.z), vec3i(-min.x, max.y, -min.z)); break;
case 3 : *this = BoxV2(vec3i(-max.z, min.y, min.x), vec3i(-min.z, max.y, max.x)); break;
default : ASSERT(false);
}
}
};
union Color32 { // RGBA8888
uint32 value;
struct { uint8 r, g, b, a; };