1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-13 16:44:50 +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, WALK = 1 << 6,
ACTION = 1 << 7, ACTION = 1 << 7,
WEAPON = 1 << 8, WEAPON = 1 << 8,
LOOK = 1 << 9, LOOK = 1 << 9
DEATH = 1 << 10
}; };
Controller *viewTarget; Controller *viewTarget;
@@ -143,10 +142,11 @@ struct Character : Controller {
virtual int getStateWade() { return state; } virtual int getStateWade() { return state; }
virtual int getStateDeath() { return state; } virtual int getStateDeath() { return state; }
virtual int getStateDefault() { 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; } virtual bool useHeadAnimation() { return false; }
int getNextState() { int getNextState() {
/*
if (input & DEATH) { if (input & DEATH) {
int deathState = getStateDeath(); int deathState = getStateDeath();
if (state == deathState || animation.canSetState(deathState)) { if (state == deathState || animation.canSetState(deathState)) {
@@ -155,7 +155,7 @@ struct Character : Controller {
return deathState; return deathState;
} }
} }
*/
switch (stand) { switch (stand) {
case STAND_AIR : return getStateAir(); case STAND_AIR : return getStateAir();
case STAND_GROUND : return getStateGround(); case STAND_GROUND : return getStateGround();

View File

@@ -573,7 +573,7 @@ namespace Debug {
TR::StaticMesh *sm = &level.staticMeshes[m.meshIndex]; TR::StaticMesh *sm = &level.staticMeshes[m.meshIndex];
Box box; 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 sm->getBox(false, m.rotation, box); // visible box
Debug::Draw::box(offset + box.min, offset + box.max, vec4(1, 1, 0, 0.25)); Debug::Draw::box(offset + box.min, offset + box.max, vec4(1, 1, 0, 0.25));

View File

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

View File

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

3816
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; if (!level->meshOffsets[s->mesh]) continue;
TR::Mesh &mesh = level->meshes[level->meshOffsets[s->mesh]]; TR::Mesh &mesh = level->meshes[level->meshOffsets[s->mesh]];
int x = m.x - room.info.x; int x = m.pos.x - room.info.x;
int y = m.y; int y = m.pos.y;
int z = m.z - room.info.z; int z = m.pos.z - room.info.z;
int d = m.rotation.value / 0x4000; 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); 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 SQR(x) ((x)*(x))
#define randf() (float(rand())/float(RAND_MAX)) #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 char int8;
typedef signed short int16; typedef signed short int16;
typedef signed int int32; 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 { struct vec2 {
float x, y; float x, y;
vec2() {} vec2() {}
@@ -1225,17 +1251,6 @@ struct Box {
return min; 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) { Box& operator += (const Box &box) {
min.x = ::min(min.x, box.min.x); min.x = ::min(min.x, box.min.x);
min.y = ::min(min.y, box.min.y); min.y = ::min(min.y, box.min.y);
@@ -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 union Color32 { // RGBA8888
uint32 value; uint32 value;
struct { uint8 r, g, b, a; }; struct { uint8 r, g, b, a; };