diff --git a/README.md b/README.md
index bc59cb8..82fda24 100644
--- a/README.md
+++ b/README.md
@@ -6,3 +6,7 @@ Classic Tomb Raider open-source engine
inspired by OpenTomb project http://opentomb.github.io/
[](https://opensource.org/licenses/BSD-2-Clause)
+
+## Links
+* [Discord channel](https://discord.gg/EF8JaQB)
+* [Tomb Raider Forums thread](http://www.tombraiderforums.com/showthread.php?t=216618)
diff --git a/src/camera.h b/src/camera.h
index d9be322..393eb62 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -142,11 +142,13 @@ struct Camera : Controller {
if (owner->velocity != 0.0f && advTimer < 0.0f && !Input::down[ikMouseL])
advTimer = -advTimer;
+ #ifndef LEVEL_EDITOR
if (advTimer == 0.0f && advAngle != 0.0f) {
float t = 10.0f * Core::deltaTime;
advAngle.x = lerp(clampAngle(advAngle.x), 0.0f, t);
advAngle.y = lerp(clampAngle(advAngle.y), 0.0f, t);
}
+ #endif
angle = owner->angle + advAngle;
angle.z = 0.0f;
diff --git a/src/character.h b/src/character.h
index 2fb10ed..593c317 100644
--- a/src/character.h
+++ b/src/character.h
@@ -31,11 +31,26 @@ struct Character : Controller {
float angleExt;
float speed;
+ int zone;
+ int box;
+
+ bool flying;
+
Collision collision;
Character(IGame *game, int entity, int health) : Controller(game, entity), target(-1), health(health), tilt(0.0f), stand(STAND_GROUND), lastInput(0), velocity(0.0f), angleExt(0.0f) {
animation.initOverrides();
rotHead = rotChest = quat(0, 0, 0, 1);
+
+ flying = getEntity().type == TR::Entity::ENEMY_BAT;
+ updateZone();
+ }
+
+ void updateZone() {
+ TR::Level *level = game->getLevel();
+ int dx, dz;
+ box = level->getSector(getRoomIndex(), int(pos.x), int(pos.z), dx, dz).boxIndex;
+ zone = flying ? level->zones[0].fly[box] : level->zones[0].ground1[box];
}
void rotateY(float delta) {
@@ -141,8 +156,10 @@ struct Character : Controller {
Controller::update();
updateVelocity();
updatePosition();
- if (p != pos)
+ if (p != pos) {
updateLights();
+ updateZone();
+ }
}
virtual void cmdJump(const vec3 &vel) {
diff --git a/src/controller.h b/src/controller.h
index 60a4e73..f0a8914 100644
--- a/src/controller.h
+++ b/src/controller.h
@@ -192,7 +192,7 @@ struct Controller {
int floor = NO_OVERLAP;
int delta = NO_OVERLAP;
- TR::Overlap *o = &level->overlaps[b.overlap & 0x7FFF];
+ TR::Overlap *o = &level->overlaps[b.overlap.index];
do {
TR::Box &ob = level->boxes[o->boxIndex];
if (ob.contains(toX, toZ)) { // get min delta
diff --git a/src/debug.h b/src/debug.h
index 69ed5d6..6e64a10 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -185,7 +185,14 @@ namespace Debug {
namespace Level {
- void debugFloor(const TR::Level &level, int roomIndex, int x, int y, int z) {
+ void debugFloor(const TR::Level &level, int roomIndex, int x, int y, int z, int zone = -1) {
+ if (zone != -1) {
+ int dx, dz;
+ TR::Room::Sector &s = level.getSector(roomIndex, x, z, dx, dz);
+ if (zone != level.zones[0].ground1[s.boxIndex])
+ return;
+ }
+
TR::Level::FloorInfo info;
vec3 rf[4], rc[4], f[4], c[4];
@@ -270,23 +277,47 @@ namespace Debug {
glEnd();
}
+ void blocks(const TR::Level &level) {
+ Core::setDepthTest(false);
+ char buf[64];
+
+ for (int j = 0; j < level.roomsCount; j++) {
+ TR::Room &r = level.rooms[j];
+
+ for (int z = 0; z < r.zSectors; z++)
+ for (int x = 0; x < r.xSectors; x++) {
+ TR::Room::Sector &s = r.sectors[x * r.zSectors + z];
+ if (s.boxIndex != 0xFFFF) {
+ bool blockable = level.boxes[s.boxIndex].overlap.value & 0x8000;
+ bool block = level.boxes[s.boxIndex].overlap.value & 0x4000;
+ int floor = level.boxes[s.boxIndex].floor;
+
+ if (blockable || block) {
+ sprintf(buf, "blocked: %s", block ? "true" : "false");
+ Debug::Draw::text(vec3(r.info.x + x * 1024 + 512, floor, r.info.z + z * 1024 + 512), vec4(1, 1, 0, 1), buf);
+ }
+ }
+ }
+ }
+
+ Core::setDepthTest(true);
+ }
+
void debugOverlaps(const TR::Level &level, int boxIndex) {
glColor4f(1.0f, 1.0f, 0.0f, 0.25f);
- TR::Overlap *o = &level.overlaps[level.boxes[boxIndex].overlap & 0x7FFF];
+ TR::Overlap *o = &level.overlaps[level.boxes[boxIndex].overlap.index];
do {
TR::Box &b = level.boxes[o->boxIndex];
debugBox(b);
} while (!(o++)->end);
}
- void sectors(const TR::Level &level, int roomIndex, int y) {
+ void sectors(const TR::Level &level, int roomIndex, int y, int zone = -1) {
TR::Room &room = level.rooms[roomIndex];
- // glDisable(GL_DEPTH_TEST);
for (int z = 0; z < room.zSectors; z++)
for (int x = 0; x < room.xSectors; x++)
- debugFloor(level, roomIndex, room.info.x + x * 1024, y, room.info.z + z * 1024);
- // glEnable(GL_DEPTH_TEST);
+ debugFloor(level, roomIndex, room.info.x + x * 1024, y, room.info.z + z * 1024, zone);
}
void rooms(const TR::Level &level, const vec3 &pos, int roomIndex) {
@@ -350,6 +381,24 @@ namespace Debug {
}
}
+ void zones(const TR::Level &level, Lara *lara) {
+ Core::setDepthTest(false);
+ for (int i = 0; i < level.roomsCount; i++)
+ sectors(level, i, int(lara->pos.y), lara->zone);
+ Core::setDepthTest(true);
+
+ char buf[64];
+ for (int i = 0; i < level.entitiesCount; i++) {
+ TR::Entity &e = level.entities[i];
+
+ if (e.type < TR::Entity::LARA || e.type > TR::Entity::ENEMY_GIANT_MUTANT)
+ continue;
+
+ sprintf(buf, "zone: %d", ((Character*)e.controller)->zone );
+ Debug::Draw::text(vec3(e.x, e.y - 128, e.z), vec4(0, 1.0, 0.8, 1), buf);
+ }
+ }
+
void lights(const TR::Level &level, int room, Controller *lara) {
// int roomIndex = level.entities[lara->entity].room;
// int lightIndex = getLightIndex(lara->pos, roomIndex);
@@ -394,14 +443,16 @@ namespace Debug {
sm->getBox(true, m.rotation, box);
Debug::Draw::box(offset + box.min - vec3(10.0f), offset + box.max + vec3(10.0f), vec4(1, 0, 0, 0.50));
}
- /*
- TR::Mesh *mesh = (TR::Mesh*)&level.meshData[level.meshOffsets[sm->mesh] / 2];
- { //if (mesh->collider.info || mesh->collider.flags) {
+
+ if (!level.meshOffsets[sm->mesh]) continue;
+ const TR::Mesh &mesh = level.meshes[level.meshOffsets[sm->mesh]];
+
+ {
char buf[255];
- sprintf(buf, "radius %d info %d flags %d", (int)mesh->collider.radius, (int)mesh->collider.info, (int)mesh->collider.flags);
- Debug::Draw::text(offset + (min + max) * 0.5f, vec4(0.5, 0.5, 0.5, 1), buf);
+ sprintf(buf, "flags %d", (int)mesh.flags.value);
+ Debug::Draw::text(offset + (box.min + box.max) * 0.5f, vec4(0.5, 0.5, 1.0, 1), buf);
}
- */
+
}
}
// dynamic objects
@@ -466,13 +517,13 @@ namespace Debug {
TR::Mesh *mesh = (TR::Mesh*)&level.meshes[offset];
//if (!mesh->flags) continue;
Debug::Draw::sphere(matrix * joint * mesh->center, mesh->radius, vec4(0, 1, 1, 0.5f));
- /*
+
{ //if (e.id != 0) {
char buf[255];
- sprintf(buf, "(%d) radius %d flags %d", (int)e.type, (int)mesh->radius, (int)mesh->flags);
+ sprintf(buf, "(%d) radius %d flags %d", (int)e.type, (int)mesh->radius, (int)mesh->flags.value);
Debug::Draw::text(matrix * joint * mesh->center, vec4(0.5, 1, 0.5, 1), buf);
}
- */
+
}
Debug::Draw::box(matrix, frame->box.min(), frame->box.max(), vec4(1.0));
@@ -587,7 +638,7 @@ namespace Debug {
case_name(TR::Entity, ENEMY_RAT_WATER );
case_name(TR::Entity, ENEMY_REX );
case_name(TR::Entity, ENEMY_RAPTOR );
- case_name(TR::Entity, ENEMY_MUTANT );
+ case_name(TR::Entity, ENEMY_MUTANT_1 );
case_name(TR::Entity, ENEMY_CENTAUR );
case_name(TR::Entity, ENEMY_MUMMY );
case_name(TR::Entity, ENEMY_LARSON );
diff --git a/src/format.h b/src/format.h
index 9a7a8e4..e39e762 100644
--- a/src/format.h
+++ b/src/format.h
@@ -348,7 +348,12 @@ namespace TR {
TR::Vertex center;
uint16 radius;
- uint16 flags;
+ union {
+ struct {
+ uint16 transparent:1, reserved:15;
+ };
+ uint16 value;
+ } flags;
int16 vCount;
int16 rCount;
int16 tCount;
@@ -374,7 +379,7 @@ namespace TR {
LARA_SHOTGUN = 2,
LARA_MAGNUMS = 3,
LARA_UZIS = 4,
-
+ LARA_SPEC = 5,
ENEMY_TWIN = 6,
ENEMY_WOLF = 7,
ENEMY_BEAR = 8,
@@ -389,12 +394,19 @@ namespace TR {
ENEMY_RAT_WATER = 17,
ENEMY_REX = 18,
ENEMY_RAPTOR = 19,
- ENEMY_MUTANT = 20,
-
+ ENEMY_MUTANT_1 = 20,
+ ENEMY_MUTANT_2 = 21,
+ ENEMY_MUTANT_3 = 22,
ENEMY_CENTAUR = 23,
ENEMY_MUMMY = 24,
ENEMY_LARSON = 27,
-
+ ENEMY_PIERRE = 28,
+ ENEMY_SKATEBOARD = 29,
+ ENEMY_SKATEBOY = 30,
+ ENEMY_COWBOY = 31,
+ ENEMY_MR_T = 32,
+ ENEMY_NATLA = 33,
+ ENEMY_GIANT_MUTANT = 34,
TRAP_FLOOR = 35,
TRAP_BLADE = 36,
TRAP_SPIKES = 37,
@@ -512,6 +524,13 @@ namespace TR {
bool isBlock() {
return type >= TR::Entity::BLOCK_1 && type <= TR::Entity::BLOCK_2;
}
+
+ static void fixOpaque(Type type, bool &opaque) {
+ if (type >= LARA && type <= ENEMY_GIANT_MUTANT && type != ENEMY_MUMMY && type != ENEMY_CENTAUR && type != ENEMY_MUTANT_1 && type != ENEMY_NATLA && type != DOOR_BIG_1 && type != DOOR_BIG_2)
+ opaque = true;
+ if (type == SWITCH || type == SWITCH_WATER)
+ opaque = true;
+ }
};
struct Animation {
@@ -668,7 +687,12 @@ namespace TR {
uint32 minZ, maxZ; // Horizontal dimensions in global units
uint32 minX, maxX;
int16 floor; // Height value in global units
- uint16 overlap; // Index into Overlaps[].
+ union {
+ struct {
+ uint16 index:14, block:1, blockable:1; // Index into Overlaps[].
+ };
+ uint16 value;
+ } overlap;
bool contains(uint32 x, uint32 z) {
return x >= minX && x <= maxX && z >= minZ && z <= maxZ;
@@ -676,11 +700,9 @@ namespace TR {
};
struct Zone {
- struct {
- uint16 groundZone1;
- uint16 groundZone2;
- uint16 flyZone;
- } normal, alternate;
+ uint16 *ground1;
+ uint16 *ground2;
+ uint16 *fly;
};
struct SoundInfo {
@@ -761,7 +783,7 @@ namespace TR {
Box *boxes;
int32 overlapsCount;
Overlap *overlaps;
- Zone *zones;
+ Zone zones[2]; // default and alternative
int32 animTexturesDataSize;
uint16 *animTexturesData;
@@ -989,8 +1011,13 @@ namespace TR {
stream.read(soundSources, stream.read(soundSourcesCount));
// AI
stream.read(boxes, stream.read(boxesCount));
+
stream.read(overlaps, stream.read(overlapsCount));
- stream.read(zones, boxesCount);
+ for (int i = 0; i < 2; i++) {
+ stream.read(zones[i].ground1, boxesCount);
+ stream.read(zones[i].ground2, boxesCount);
+ stream.read(zones[i].fly, boxesCount);
+ }
// animated textures
stream.read(animTexturesData, stream.read(animTexturesDataSize));
// entities (enemies, items, lara etc.)
@@ -1112,7 +1139,11 @@ namespace TR {
delete[] soundSources;
delete[] boxes;
delete[] overlaps;
- delete[] zones;
+ for (int i = 0; i < 2; i++) {
+ delete[] zones[i].ground1;
+ delete[] zones[i].ground2;
+ delete[] zones[i].fly;
+ }
delete[] animTexturesData;
delete[] entities;
delete[] palette;
diff --git a/src/lara.h b/src/lara.h
index cd75d33..788d28a 100644
--- a/src/lara.h
+++ b/src/lara.h
@@ -435,7 +435,35 @@ struct Lara : Character {
delete braid;
}
+ int getRoomByPos(const vec3 &pos) {
+ int x = int(pos.x),
+ y = int(pos.y),
+ z = int(pos.z);
+
+ for (int i = 0; i < level->roomsCount; i++) {
+ TR::Room &r = level->rooms[i];
+ int mx = r.info.x + r.xSectors * 1024;
+ int mz = r.info.z + r.zSectors * 1024;
+ if (x >= r.info.x && x < mx && z >= r.info.z && z < mz && y >= r.info.yTop && y < r.info.yBottom)
+ return i;
+ }
+ return TR::NO_ROOM;
+ }
+
void reset(int room, const vec3 &pos, float angle, bool onwater = false) {
+ if (room == TR::NO_ROOM) {
+ stand = STAND_AIR;
+ room = getRoomByPos(pos);
+ }
+
+ if (room == TR::NO_ROOM)
+ return;
+
+ if (level->rooms[room].flags.water)
+ stand = STAND_UNDERWATER;
+
+ velocity = vec3(0.0f);
+
getEntity().room = room;
this->pos = pos;
this->angle = vec3(0.0f, angle, 0.0f);
diff --git a/src/level.h b/src/level.h
index fb91e03..983ad93 100644
--- a/src/level.h
+++ b/src/level.h
@@ -138,7 +138,9 @@ struct Level : IGame {
case TR::Entity::ENEMY_RAT_WATER :
case TR::Entity::ENEMY_REX :
case TR::Entity::ENEMY_RAPTOR :
- case TR::Entity::ENEMY_MUTANT :
+ case TR::Entity::ENEMY_MUTANT_1 :
+ case TR::Entity::ENEMY_MUTANT_2 :
+ case TR::Entity::ENEMY_MUTANT_3 :
case TR::Entity::ENEMY_CENTAUR :
case TR::Entity::ENEMY_MUMMY :
case TR::Entity::ENEMY_LARSON :
@@ -490,7 +492,7 @@ struct Level : IGame {
// if (entity.type == TR::Entity::LARA && ((Lara*)entity.controller)->state == Lara::STATE_WATER_OUT)
// roomIndex = ((Lara*)entity.controller)->roomPrev;
- setRoomParams(roomIndex, type, 1.0f, intensityf(lum), controller->specular, 1.0f, isModel ? mesh->models[entity.modelIndex].opaque : true);
+ setRoomParams(roomIndex, type, 1.0f, intensityf(lum), controller->specular, 1.0f, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
if (isModel) { // model
vec3 pos = controller->getPos();
@@ -517,6 +519,12 @@ struct Level : IGame {
}
void update() {
+ #ifdef LEVEL_EDITOR
+ if (Input::down[ikCtrl]) {
+ Input::down[ikCtrl] = false;
+ lara->reset(TR::NO_ROOM, camera->pos, camera->angle.y, false);
+ }
+ #endif
params->time += Core::deltaTime;
for (int i = 0; i < level.entitiesCount; i++) {
@@ -810,20 +818,23 @@ struct Level : IGame {
glEnd();
Core::setDepthTest(true);
- Debug::Draw::sphere(lara->mainLightPos, lara->mainLightColor.w, vec4(1, 1, 0, 1));
+ // Debug::Draw::sphere(lara->mainLightPos, lara->mainLightColor.w, vec4(1, 1, 0, 1));
Box bbox = lara->getBoundingBox();
Debug::Draw::box(bbox.min, bbox.max, vec4(1, 0, 1, 1));
Core::setBlending(bmAlpha);
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
- Debug::Level::lights(level, lara->getRoomIndex(), lara);
+ // Debug::Level::lights(level, lara->getRoomIndex(), lara);
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Core::setDepthTest(false);
// Debug::Level::portals(level);
// Core::setDepthTest(true);
// Debug::Level::meshes(level);
// Debug::Level::entities(level);
+ Debug::Level::zones(level, lara);
+ Debug::Level::blocks(level);
+
Core::setBlending(bmNone);
/*
diff --git a/src/platform/web/index.html b/src/platform/web/index.html
index a477a7c..5ff642f 100644
--- a/src/platform/web/index.html
+++ b/src/platform/web/index.html
@@ -120,10 +120,10 @@
(.PHD, .PSX)
- OpenLara on github
+ OpenLara on github & facebook
controls:
keyboad: move - WASD / arrows, jump - Space, action - E/Ctrl, draw weapon - Q, change weapon - 1-4, walk - Shift, side steps - ZX/walk+direction, camera - MouseR)
- gamepad: PSX controls on XBox controller
+ gamepad: PSX controls for Xbox controller
Change view: V
Time Control: R - slow motion, T - fast motion
FullScreen: Alt + Enter
diff --git a/src/platform/win/OpenLara.vcxproj.filters b/src/platform/win/OpenLara.vcxproj.filters
new file mode 100644
index 0000000..2c1879e
--- /dev/null
+++ b/src/platform/win/OpenLara.vcxproj.filters
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+ shaders
+
+
+
+
+ {3fcb6c00-268a-4570-b6ca-3bf1cf1e10d7}
+
+
+
\ No newline at end of file
diff --git a/src/platform/win/OpenLara.vcxproj.user b/src/platform/win/OpenLara.vcxproj.user
new file mode 100644
index 0000000..a4941d7
--- /dev/null
+++ b/src/platform/win/OpenLara.vcxproj.user
@@ -0,0 +1,19 @@
+
+
+
+ ../../../bin
+ WindowsLocalDebugger
+
+
+ ../../../bin
+ WindowsLocalDebugger
+
+
+ ../../../bin
+ WindowsLocalDebugger
+
+
+ ../../../bin
+ WindowsLocalDebugger
+
+
\ No newline at end of file