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:
@@ -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();
|
||||
|
@@ -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));
|
||||
|
117
src/format.h
117
src/format.h
@@ -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) {
|
||||
|
@@ -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
3868
src/lara.h
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
92
src/utils.h
92
src/utils.h
@@ -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; };
|
||||
|
Reference in New Issue
Block a user