diff --git a/src/debug.h b/src/debug.h index 1a5d5f0..d3d8ecf 100644 --- a/src/debug.h +++ b/src/debug.h @@ -458,10 +458,8 @@ namespace Debug { TR::Room &r = level.rooms[i]; for (int j = 0; j < r.meshesCount; j++) { - TR::Room::Mesh &m = r.meshes[j]; - - TR::StaticMesh *sm = level.getMeshByID(m.meshID); - ASSERT(sm != NULL); + TR::Room::Mesh &m = r.meshes[j]; + TR::StaticMesh *sm = &level.staticMeshes[m.meshIndex]; Box box; vec3 offset = vec3(m.x, m.y, m.z); diff --git a/src/enemy.h b/src/enemy.h index 5f995a4..ac48a42 100644 --- a/src/enemy.h +++ b/src/enemy.h @@ -148,10 +148,7 @@ struct Enemy : Character { TR::Level::FloorInfo info; level->getFloorInfo(getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z, info); - - int dx, dz; - TR::Room::Sector &s = level->getSector(info.roomNext != TR::NO_ROOM ? info.roomNext : getRoomIndex(), int(pos.x), int(pos.z), dx, dz); - if (s.boxIndex != 0xFFFF && zone == getZones()[s.boxIndex]) { + if (info.boxIndex != 0xFFFF && zone == getZones()[info.boxIndex] && !level->boxes[info.boxIndex].overlap.block) { switch (stand) { case STAND_GROUND : { float fallSpeed = 2048.0f * Core::deltaTime; @@ -410,6 +407,9 @@ struct Enemy : Character { TR::Box &b = game->getLevel()->boxes[box]; TR::Entity::Type type = e.type; + if (b.overlap.block) + return false; + if (type == TR::Entity::ENEMY_REX || type == TR::Entity::ENEMY_MUTANT_1 || type == TR::Entity::ENEMY_CENTAUR) { if (b.overlap.blockable) return false; diff --git a/src/format.h b/src/format.h index b10efcc..e8536c1 100644 --- a/src/format.h +++ b/src/format.h @@ -292,7 +292,7 @@ namespace TR { angle rotation; int16 intensity; uint16 meshID; - uint16 align; // PSX + uint16 meshIndex; // index into static meshes array } *meshes; }; @@ -983,8 +983,17 @@ namespace TR { // meshes stream.read(r.meshesCount); r.meshes = r.meshesCount ? new Room::Mesh[r.meshesCount] : NULL; - for (int i = 0; i < r.meshesCount; i++) - stream.raw(&r.meshes[i], sizeof(r.meshes[i]) - (version == VER_TR1_PC ? sizeof(r.meshes[i].align) : 0)); + 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.rotation); + stream.read(m.intensity); + stream.read(m.meshID); + if (version == VER_TR1_PSX) + stream.read(m.meshIndex); // just an align for PSX version + } // misc flags stream.read(r.alternateRoom); stream.read(r.flags); @@ -1068,6 +1077,7 @@ namespace TR { stream.read(cameraFrames, stream.read(cameraFramesCount)); } + initRoomMeshes(); initTiles(tiles4, tiles8, palette, cluts); //delete[] tiles4; tiles4 = NULL; @@ -1447,6 +1457,14 @@ namespace TR { spriteSequences[i].sCount = -spriteSequences[i].sCount; } + void initRoomMeshes() { + for (int i = 0; i < roomsCount; i++) { + Room &room = rooms[i]; + for (int j = 0; j < room.meshesCount; j++) + room.meshes[j].meshIndex = getMeshByID(room.meshes[j].meshID); + } + } + void initTiles(Tile4 *tiles4, Tile8 *tiles8, Color24 *palette, CLUT *cluts) { tiles = new Tile32[tilesCount]; @@ -1542,11 +1560,12 @@ namespace TR { return new Stream(data, size); } - StaticMesh* getMeshByID(int id) const { // TODO: map this + int getMeshByID(int id) const { for (int i = 0; i < staticMeshesCount; i++) if (staticMeshes[i].id == id) - return &staticMeshes[i]; - return NULL; + return i; + ASSERT(false); + return 0; } int16 getModelIndex(Entity::Type type) const { diff --git a/src/lara.h b/src/lara.h index aad5d25..1b9fc6e 100644 --- a/src/lara.h +++ b/src/lara.h @@ -621,6 +621,19 @@ struct Lara : Character { && state != STATE_WATER_OUT; } + bool canHitAnim() { + return state == STATE_WALK + || state == STATE_RUN + || state == STATE_STOP + || state == STATE_FAST_BACK + || state == STATE_TURN_RIGHT + || state == STATE_TURN_LEFT + || state == STATE_BACK + || state == STATE_FAST_TURN + || state == STATE_STEP_RIGHT + || state == STATE_STEP_LEFT; + } + bool wpnReady() { return arms[0].anim != Weapon::Anim::PREPARE && arms[0].anim != Weapon::Anim::UNHOLSTER && arms[0].anim != Weapon::Anim::HOLSTER; } @@ -1526,7 +1539,7 @@ struct Lara : Character { if (state == STATE_PUSH_PULL_READY && (input & (FORTH | BACK))) { int pushState = (input & FORTH) ? STATE_PUSH_BLOCK : STATE_PULL_BLOCK; Block *block = getBlock(); - if (animation.canSetState(pushState) && block->doMove((input & FORTH) != 0)) { + if (block && animation.canSetState(pushState) && block->doMove((input & FORTH) != 0)) { alignToWall(-LARA_RADIUS); return pushState; } @@ -1921,7 +1934,23 @@ struct Lara : Character { } void checkCollisions() { - if (state == STATE_DEATH || stand != STAND_GROUND) { + // check static objects (TODO: check linked rooms?) + TR::Room &room = getRoom(); + Box box(pos - vec3(LARA_RADIUS, LARA_HEIGHT, LARA_RADIUS), pos + vec3(LARA_RADIUS, 0.0f, LARA_RADIUS)); + + for (int i = 0; i < room.meshesCount; i++) { + TR::Room::Mesh &m = room.meshes[i]; + TR::StaticMesh &sm = level->staticMeshes[m.meshIndex]; + if (sm.flags != 2) continue; + Box meshBox; + sm.getBox(true, m.rotation, meshBox); + meshBox.translate(vec3(float(m.x), float(m.y), float(m.z))); + if (!box.intersect(meshBox)) continue; + + collisionOffset += meshBox.pushOut2D(box); + } + + if (!canHitAnim()) { hitDir = -1; return; } @@ -1941,7 +1970,7 @@ struct Lara : Character { continue; // get shift - p = enemyBox.closestPoint2D(p); + p += enemyBox.pushOut2D(p); p = (p.rotateY(enemy->angle.y) + enemy->pos) - pos; collisionOffset += vec3(p.x, 0.0f, p.z); diff --git a/src/mesh.h b/src/mesh.h index 2210163..1c36570 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -201,7 +201,7 @@ struct MeshBuilder { for (int j = 0; j < r.meshesCount; j++) { TR::Room::Mesh &m = r.meshes[j]; - TR::StaticMesh *s = level.getMeshByID(m.meshID); + TR::StaticMesh *s = &level.staticMeshes[m.meshIndex]; if (!level.meshOffsets[s->mesh]) continue; TR::Mesh &mesh = level.meshes[level.meshOffsets[s->mesh]]; @@ -310,7 +310,7 @@ struct MeshBuilder { // static meshes for (int j = 0; j < room.meshesCount; j++) { TR::Room::Mesh &m = room.meshes[j]; - TR::StaticMesh *s = level.getMeshByID(m.meshID); + TR::StaticMesh *s = &level.staticMeshes[m.meshIndex]; if (!level.meshOffsets[s->mesh]) continue; TR::Mesh &mesh = level.meshes[level.meshOffsets[s->mesh]]; diff --git a/src/utils.h b/src/utils.h index bbb986d..71c2995 100644 --- a/src/utils.h +++ b/src/utils.h @@ -808,17 +808,41 @@ struct Box { } } + void translate(const vec3 &offset) { + min += offset; + max += offset; + } + bool contains(const vec3 &v) const { return v.x >= min.x && v.x <= max.x && v.y >= min.y && v.y <= max.x && v.z >= min.z && v.z <= max.z; } - vec3 closestPoint2D(const vec3 &v) const { + vec3 pushOut2D(const vec3 &v) const { float ax = v.x - min.x; float bx = max.x - v.x; float az = v.z - min.z; float bz = max.z - v.z; - vec3 p = v; + vec3 p = vec3(0.0f); + if (ax <= bx && ax <= az && ax <= bz) + p.x = -ax; + else if (bx <= ax && bx <= az && bx <= bz) + p.x = bx; + else if (az <= ax && az <= bx && az <= bz) + p.z = -az; + else + p.z = bz; + + return p; + } + + vec3 pushOut2D(const Box &b) const { + float ax = b.max.x - min.x; + float bx = max.x - b.min.x; + float az = b.max.z - min.z; + float bz = max.z - b.min.z; + + vec3 p = vec3(0.0f); if (ax <= bx && ax <= az && ax <= bz) p.x -= ax; else if (bx <= ax && bx <= az && bx <= bz)