mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-05 20:57:46 +02:00
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
85
src/camera.h
85
src/camera.h
@@ -160,25 +160,53 @@ struct Camera : Controller {
|
|||||||
vec3 target, destPos, lastDest, angleAdv;
|
vec3 target, destPos, lastDest, angleAdv;
|
||||||
int room;
|
int room;
|
||||||
|
|
||||||
Camera(TR::Level *level, Lara *owner) : Controller(level, owner->entity), owner(owner), frustum(new Frustum()) {
|
float timer;
|
||||||
|
int actTargetEntity, actCamera;
|
||||||
|
|
||||||
|
Camera(TR::Level *level, Lara *owner) : Controller(level, owner ? owner->entity : 0), owner(owner), frustum(new Frustum()), timer(0.0f), actTargetEntity(-1), actCamera(-1) {
|
||||||
fov = 75.0f;
|
fov = 75.0f;
|
||||||
znear = 128;
|
znear = 128;
|
||||||
zfar = 100.0f * 1024.0f;
|
zfar = 100.0f * 1024.0f;
|
||||||
angleAdv = vec3(0.0f);
|
angleAdv = vec3(0.0f);
|
||||||
|
|
||||||
room = owner->getEntity().room;
|
if (owner) {
|
||||||
pos = pos - owner->getDir() * 1024.0f;
|
room = owner->getEntity().room;
|
||||||
|
pos = pos - owner->getDir() * 1024.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~Camera() {
|
virtual ~Camera() {
|
||||||
delete frustum;
|
delete frustum;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int getRoomIndex() const {
|
virtual int getRoomIndex() const {
|
||||||
return room;
|
return actCamera > -1 ? level->cameras[actCamera].room : room;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool activate(ActionCommand *cmd) {
|
||||||
|
Controller::activate(cmd);
|
||||||
|
if (cmd->timer)
|
||||||
|
this->timer = cmd->timer;
|
||||||
|
if (cmd->action == TR::Action::CAMERA_TARGET)
|
||||||
|
actTargetEntity = cmd->value;
|
||||||
|
if (cmd->action == TR::Action::CAMERA_SWITCH) {
|
||||||
|
actCamera = cmd->value;
|
||||||
|
lastDest = pos;
|
||||||
|
}
|
||||||
|
activateNext();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update() {
|
virtual void update() {
|
||||||
|
if (timer > 0.0f) {
|
||||||
|
timer -= Core::deltaTime;
|
||||||
|
if (timer <= 0.0f) {
|
||||||
|
timer = 0.0f;
|
||||||
|
if (room != getRoomIndex())
|
||||||
|
pos = lastDest;
|
||||||
|
actTargetEntity = actCamera = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
#ifdef FREE_CAMERA
|
#ifdef FREE_CAMERA
|
||||||
vec3 dir = vec3(sinf(angle.y - PI) * cosf(-angle.x), -sinf(-angle.x), cosf(angle.y - PI) * cosf(-angle.x));
|
vec3 dir = vec3(sinf(angle.y - PI) * cosf(-angle.x), -sinf(-angle.x), cosf(angle.y - PI) * cosf(-angle.x));
|
||||||
vec3 v = vec3(0);
|
vec3 v = vec3(0);
|
||||||
@@ -212,27 +240,40 @@ struct Camera : Controller {
|
|||||||
angle.z = 0.0f;
|
angle.z = 0.0f;
|
||||||
//angle.x = min(max(angle.x, -80 * DEG2RAD), 80 * DEG2RAD);
|
//angle.x = min(max(angle.x, -80 * DEG2RAD), 80 * DEG2RAD);
|
||||||
|
|
||||||
|
vec3 dir;
|
||||||
target = vec3(owner->pos.x, owner->pos.y - height, owner->pos.z);
|
target = vec3(owner->pos.x, owner->pos.y - height, owner->pos.z);
|
||||||
|
|
||||||
vec3 dir;
|
if (actCamera > -1) {
|
||||||
float lerpFactor = 2.0f;
|
TR::Camera &c = level->cameras[actCamera];
|
||||||
if (owner->targetEntity > -1) {
|
destPos = vec3(c.x, c.y, c.z);
|
||||||
TR::Entity &e = level->entities[owner->targetEntity];
|
if (room != getRoomIndex())
|
||||||
dir = (vec3(e.x, e.y, e.z) - target).normal();
|
pos = destPos;
|
||||||
lerpFactor = 10.0f;
|
if (actTargetEntity > -1) {
|
||||||
} else
|
TR::Entity &e = level->entities[actTargetEntity];
|
||||||
dir = getDir();
|
target = vec3(e.x, e.y, e.z);
|
||||||
|
}
|
||||||
if (owner->state != Lara::STATE_BACK_JUMP) {
|
|
||||||
vec3 eye = target - dir * 1024.0f;
|
|
||||||
destPos = trace(owner->getRoomIndex(), target, eye);
|
|
||||||
lastDest = destPos;
|
|
||||||
} else {
|
} else {
|
||||||
vec3 eye = lastDest + dir.cross(vec3(0, 1, 0)).normal() * 2048.0f - vec3(0.0f, 512.0f, 0.0f);
|
if (actTargetEntity > -1) {
|
||||||
destPos = trace(owner->getRoomIndex(), target, eye);
|
TR::Entity &e = level->entities[actTargetEntity];
|
||||||
|
dir = (vec3(e.x, e.y, e.z) - target).normal();
|
||||||
|
} else
|
||||||
|
dir = getDir();
|
||||||
|
|
||||||
|
if (owner->state != Lara::STATE_BACK_JUMP || actTargetEntity > -1) {
|
||||||
|
vec3 eye = target - dir * 1024.0f;
|
||||||
|
destPos = trace(owner->getRoomIndex(), target, eye);
|
||||||
|
lastDest = destPos;
|
||||||
|
} else {
|
||||||
|
vec3 eye = lastDest + dir.cross(vec3(0, 1, 0)).normal() * 2048.0f - vec3(0.0f, 512.0f, 0.0f);
|
||||||
|
destPos = trace(owner->getRoomIndex(), target, eye);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = pos.lerp(destPos, min(1.0f, Core::deltaTime * lerpFactor));
|
float lerpFactor = (actTargetEntity == -1) ? 2.0f : 10.0f;
|
||||||
|
|
||||||
|
pos = pos.lerp(destPos, Core::deltaTime * lerpFactor);
|
||||||
|
|
||||||
|
if (actCamera > -1) return;
|
||||||
|
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
level->getFloorInfo(room, (int)pos.x, (int)pos.z, info);
|
level->getFloorInfo(room, (int)pos.x, (int)pos.z, info);
|
||||||
@@ -313,7 +354,7 @@ struct Camera : Controller {
|
|||||||
return x < z ? vec3(-1, 0, 0) : vec3(0, 0, -1);
|
return x < z ? vec3(-1, 0, 0) : vec3(0, 0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
virtual void setup() {
|
||||||
Core::mViewInv = mat4(pos, target, vec3(0, -1, 0));
|
Core::mViewInv = mat4(pos, target, vec3(0, -1, 0));
|
||||||
Core::mView = Core::mViewInv.inverse();
|
Core::mView = Core::mViewInv.inverse();
|
||||||
Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar);
|
Core::mProj = mat4(fov, (float)Core::width / (float)Core::height, znear, zfar);
|
||||||
|
@@ -6,8 +6,6 @@
|
|||||||
#define GRAVITY 6.0f
|
#define GRAVITY 6.0f
|
||||||
#define NO_OVERLAP 0x7FFFFFFF
|
#define NO_OVERLAP 0x7FFFFFFF
|
||||||
|
|
||||||
#define SND_SECRET 13
|
|
||||||
|
|
||||||
struct Controller {
|
struct Controller {
|
||||||
TR::Level *level;
|
TR::Level *level;
|
||||||
int entity;
|
int entity;
|
||||||
@@ -41,15 +39,17 @@ struct Controller {
|
|||||||
|
|
||||||
float turnTime;
|
float turnTime;
|
||||||
|
|
||||||
struct Action {
|
struct ActionCommand {
|
||||||
TR::Action action;
|
TR::Action action;
|
||||||
int value;
|
int value;
|
||||||
float timer;
|
float timer;
|
||||||
|
ActionCommand *next;
|
||||||
|
|
||||||
Action(TR::Action action, int value, float timer) : action(action), value(value), timer(timer) {}
|
ActionCommand() {}
|
||||||
} nextAction;
|
ActionCommand(TR::Action action, int value, float timer, ActionCommand *next = NULL) : action(action), value(value), timer(timer), next(next) {}
|
||||||
|
} *actionCommand;
|
||||||
|
|
||||||
Controller(TR::Level *level, int entity) : level(level), entity(entity), velocity(0.0f), animTime(0.0f), animPrevFrame(0), health(100), turnTime(0.0f), nextAction(TR::Action::NONE, 0, 0.0f) {
|
Controller(TR::Level *level, int entity) : level(level), entity(entity), velocity(0.0f), animTime(0.0f), animPrevFrame(0), health(100), turnTime(0.0f), actionCommand(NULL) {
|
||||||
TR::Entity &e = getEntity();
|
TR::Entity &e = getEntity();
|
||||||
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
||||||
angle = vec3(0.0f, e.rotation, 0.0f);
|
angle = vec3(0.0f, e.rotation, 0.0f);
|
||||||
@@ -94,6 +94,7 @@ struct Controller {
|
|||||||
animIndex = index;
|
animIndex = index;
|
||||||
TR::Animation &anim = level->anims[animIndex];
|
TR::Animation &anim = level->anims[animIndex];
|
||||||
animTime = frame == -1 ? 0.0f : ((frame - anim.frameStart) / 30.0f);
|
animTime = frame == -1 ? 0.0f : ((frame - anim.frameStart) / 30.0f);
|
||||||
|
ASSERT(anim.frameStart <= anim.frameEnd);
|
||||||
animPrevFrame = -1;
|
animPrevFrame = -1;
|
||||||
return state = anim.state;
|
return state = anim.state;
|
||||||
}
|
}
|
||||||
@@ -226,15 +227,50 @@ struct Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void activateNext() { // activate next entity (for triggers)
|
void activateNext() { // activate next entity (for triggers)
|
||||||
if (nextAction.action == TR::Action::NONE) return;
|
if (!actionCommand || !actionCommand->next) {
|
||||||
|
actionCommand = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ActionCommand *next = actionCommand->next;
|
||||||
|
|
||||||
Controller *controller = (Controller*)level->entities[nextAction.value].controller;
|
Controller *controller = NULL;
|
||||||
nextAction.action = TR::Action::NONE;
|
switch (next->action) {
|
||||||
if (controller)
|
case TR::Action::ACTIVATE :
|
||||||
controller->activate(nextAction.timer);
|
controller = (Controller*)level->entities[next->value].controller;
|
||||||
|
break;
|
||||||
|
case TR::Action::CAMERA_SWITCH :
|
||||||
|
case TR::Action::CAMERA_TARGET :
|
||||||
|
controller = (Controller*)level->cameraController;
|
||||||
|
break;
|
||||||
|
case TR::Action::SECRET :
|
||||||
|
if (!level->secrets[next->value]) {
|
||||||
|
level->secrets[next->value] = true;
|
||||||
|
playSound(TR::SND_SECRET);
|
||||||
|
}
|
||||||
|
actionCommand = next;
|
||||||
|
activateNext();
|
||||||
|
return;
|
||||||
|
case TR::Action::FLOW :
|
||||||
|
case TR::Action::FLIP_MAP :
|
||||||
|
case TR::Action::FLIP_ON :
|
||||||
|
case TR::Action::FLIP_OFF :
|
||||||
|
case TR::Action::END :
|
||||||
|
case TR::Action::SOUNDTRACK :
|
||||||
|
case TR::Action::HARDCODE :
|
||||||
|
case TR::Action::CLEAR :
|
||||||
|
case TR::Action::CAMERA_FLYBY :
|
||||||
|
case TR::Action::CUTSCENE :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller) {
|
||||||
|
if (controller->activate(next))
|
||||||
|
actionCommand = NULL;
|
||||||
|
} else
|
||||||
|
actionCommand = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool activate(float timer) { return false; }
|
virtual bool activate(ActionCommand *cmd) { actionCommand = cmd; return true; }
|
||||||
virtual void updateVelocity() {}
|
virtual void updateVelocity() {}
|
||||||
virtual void move() {}
|
virtual void move() {}
|
||||||
virtual Stand getStand() { return STAND_AIR; }
|
virtual Stand getStand() { return STAND_AIR; }
|
||||||
|
10
src/core.h
10
src/core.h
@@ -7,11 +7,11 @@
|
|||||||
#include <gl/GL.h>
|
#include <gl/GL.h>
|
||||||
#include <gl/glext.h>
|
#include <gl/glext.h>
|
||||||
#elif __EMSCRIPTEN__
|
#elif __EMSCRIPTEN__
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#include <html5.h>
|
#include <html5.h>
|
||||||
#include <GLES3/gl3.h>
|
#include <GLES3/gl3.h>
|
||||||
#include <GLES3/gl2ext.h>
|
#include <GLES3/gl2ext.h>
|
||||||
#define MOBILE
|
#define MOBILE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
149
src/format.h
149
src/format.h
@@ -6,6 +6,7 @@
|
|||||||
#define TR1_DEMO
|
#define TR1_DEMO
|
||||||
|
|
||||||
#define MAX_RESERVED_ENTITIES 64
|
#define MAX_RESERVED_ENTITIES 64
|
||||||
|
#define MAX_SECRETS_COUNT 16
|
||||||
|
|
||||||
namespace TR {
|
namespace TR {
|
||||||
|
|
||||||
@@ -15,12 +16,13 @@ namespace TR {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ANIM_CMD_MOVE = 1,
|
ANIM_CMD_NONE ,
|
||||||
ANIM_CMD_SPEED = 2,
|
ANIM_CMD_MOVE ,
|
||||||
ANIM_CMD_EMPTY = 3,
|
ANIM_CMD_SPEED ,
|
||||||
ANIM_CMD_KILL = 4,
|
ANIM_CMD_EMPTY ,
|
||||||
ANIM_CMD_SOUND = 5,
|
ANIM_CMD_KILL ,
|
||||||
ANIM_CMD_SPECIAL = 6,
|
ANIM_CMD_SOUND ,
|
||||||
|
ANIM_CMD_SPECIAL ,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -30,44 +32,28 @@ namespace TR {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
SND_NO = 2,
|
||||||
SND_BUBBLE = 37,
|
SND_BUBBLE = 37,
|
||||||
|
SND_SECRET = 173,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum Action : uint16 {
|
||||||
TRIGGER_ACTIVATE = 0,
|
ACTIVATE , // activate item
|
||||||
TRIGGER_PAD = 1,
|
CAMERA_SWITCH , // switch to camera
|
||||||
TRIGGER_SWITCH = 2,
|
FLOW , // underwater flow
|
||||||
TRIGGER_KEY = 3,
|
FLIP_MAP , // flip map
|
||||||
TRIGGER_PICKUP = 4,
|
FLIP_ON , // flip on
|
||||||
TRIGGER_HEAVY = 5,
|
FLIP_OFF , // flip off
|
||||||
TRIGGER_ANTIPAD = 6,
|
CAMERA_TARGET , // look at item
|
||||||
TRIGGER_COMBAT = 7,
|
END , // end level
|
||||||
TRIGGER_DUMMY = 8,
|
SOUNDTRACK , // play soundtrack
|
||||||
TRIGGER_ANTI = 9
|
HARDCODE , // special hadrdcode trigger
|
||||||
|
SECRET , // secret found
|
||||||
|
CLEAR , // clear bodies
|
||||||
|
CAMERA_FLYBY , // flyby camera sequence
|
||||||
|
CUTSCENE , // play cutscene
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Action {
|
|
||||||
NONE = -1, // no action
|
|
||||||
ACTIVATE = 0, // activate item
|
|
||||||
CAMERA_SWITCH = 1, // switch to camera
|
|
||||||
UNDERWATER = 2, // underwater flow
|
|
||||||
FLIP_MAP = 3, // flip map
|
|
||||||
FLIP_ON = 4, // flip on
|
|
||||||
FLIP_OFF = 5, // flip off
|
|
||||||
LOOK_AT = 6, // look at item
|
|
||||||
END = 7, // end level
|
|
||||||
SOUNDTRACK = 8, // play soundtrack
|
|
||||||
HARDCODE = 9, // special hadrdcode trigger
|
|
||||||
SECRET = 10, // secret found
|
|
||||||
CLEAR_BODIES = 11, // clear bodies
|
|
||||||
CAMERA_FLYBY = 12, // flyby camera sequence
|
|
||||||
CUTSCENE = 13, // play cutscene
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DATA_PORTAL 0x01
|
|
||||||
#define DATA_FLOOR 0x02
|
|
||||||
#define DATA_CEILING 0x03
|
|
||||||
|
|
||||||
#define ENTITY_FLAG_CLEAR 0x0080
|
#define ENTITY_FLAG_CLEAR 0x0080
|
||||||
#define ENTITY_FLAG_VISIBLE 0x0100
|
#define ENTITY_FLAG_VISIBLE 0x0100
|
||||||
#define ENTITY_FLAG_ACTIVE 0x3E00
|
#define ENTITY_FLAG_ACTIVE 0x3E00
|
||||||
@@ -198,16 +184,24 @@ namespace TR {
|
|||||||
struct TriggerInfo {
|
struct TriggerInfo {
|
||||||
uint16 timer:8, once:1, mask:5, :2;
|
uint16 timer:8, once:1, mask:5, :2;
|
||||||
} triggerInfo;
|
} triggerInfo;
|
||||||
struct TriggerCommand {
|
union TriggerCommand {
|
||||||
uint16 args:10, action:5, end:1;
|
struct {
|
||||||
|
uint16 args:10;
|
||||||
|
Action action:5;
|
||||||
|
uint16 end:1;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
uint16 delay:8, once:1;
|
||||||
|
};
|
||||||
} triggerCmd;
|
} triggerCmd;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PORTAL = 1,
|
NONE ,
|
||||||
FLOOR = 2,
|
PORTAL ,
|
||||||
CEILING = 3,
|
FLOOR ,
|
||||||
TRIGGER = 4,
|
CEILING ,
|
||||||
KILL = 5,
|
TRIGGER ,
|
||||||
|
KILL ,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -586,7 +580,7 @@ namespace TR {
|
|||||||
SpriteSequence *spriteSequences;
|
SpriteSequence *spriteSequences;
|
||||||
|
|
||||||
int32 camerasCount;
|
int32 camerasCount;
|
||||||
Camera *camera;
|
Camera *cameras;
|
||||||
|
|
||||||
int32 soundSourcesCount;
|
int32 soundSourcesCount;
|
||||||
SoundSource *soundSources;
|
SoundSource *soundSources;
|
||||||
@@ -623,6 +617,34 @@ namespace TR {
|
|||||||
int32 soundOffsetsCount;
|
int32 soundOffsetsCount;
|
||||||
uint32 *soundOffsets;
|
uint32 *soundOffsets;
|
||||||
|
|
||||||
|
// common
|
||||||
|
enum Trigger : uint32 {
|
||||||
|
ACTIVATE ,
|
||||||
|
PAD ,
|
||||||
|
SWITCH ,
|
||||||
|
KEY ,
|
||||||
|
PICKUP ,
|
||||||
|
HEAVY ,
|
||||||
|
ANTIPAD ,
|
||||||
|
COMBAT ,
|
||||||
|
DUMMY ,
|
||||||
|
ANTI ,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FloorInfo {
|
||||||
|
int floor, ceiling;
|
||||||
|
int roomNext, roomBelow, roomAbove;
|
||||||
|
int floorIndex;
|
||||||
|
int kill;
|
||||||
|
int trigCmdCount;
|
||||||
|
Trigger trigger;
|
||||||
|
FloorData::TriggerInfo trigInfo;
|
||||||
|
FloorData::TriggerCommand trigCmd[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool secrets[MAX_SECRETS_COUNT];
|
||||||
|
void *cameraController;
|
||||||
|
|
||||||
Level(Stream &stream) {
|
Level(Stream &stream) {
|
||||||
// read version
|
// read version
|
||||||
stream.read(version);
|
stream.read(version);
|
||||||
@@ -701,7 +723,7 @@ namespace TR {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// cameras
|
// cameras
|
||||||
stream.read(camera, stream.read(camerasCount));
|
stream.read(cameras, stream.read(camerasCount));
|
||||||
// sound sources
|
// sound sources
|
||||||
stream.read(soundSources, stream.read(soundSourcesCount));
|
stream.read(soundSources, stream.read(soundSourcesCount));
|
||||||
// AI
|
// AI
|
||||||
@@ -720,8 +742,10 @@ namespace TR {
|
|||||||
e.controller = NULL;
|
e.controller = NULL;
|
||||||
e.modelIndex = getModelIndex(e.id);
|
e.modelIndex = getModelIndex(e.id);
|
||||||
}
|
}
|
||||||
for (int i = entitiesBaseCount; i < entitiesCount; i++)
|
for (int i = entitiesBaseCount; i < entitiesCount; i++) {
|
||||||
entities[i].id = -1;
|
entities[i].id = -1;
|
||||||
|
entities[i].controller = NULL;
|
||||||
|
}
|
||||||
// palette
|
// palette
|
||||||
stream.seek(32 * 256); // skip lightmap palette
|
stream.seek(32 * 256); // skip lightmap palette
|
||||||
|
|
||||||
@@ -747,6 +771,8 @@ namespace TR {
|
|||||||
c.g <<= 2;
|
c.g <<= 2;
|
||||||
c.b <<= 2;
|
c.b <<= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(secrets, 0, MAX_SECRETS_COUNT * sizeof(secrets[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
~Level() {
|
~Level() {
|
||||||
@@ -778,7 +804,7 @@ namespace TR {
|
|||||||
delete[] objectTextures;
|
delete[] objectTextures;
|
||||||
delete[] spriteTextures;
|
delete[] spriteTextures;
|
||||||
delete[] spriteSequences;
|
delete[] spriteSequences;
|
||||||
delete[] camera;
|
delete[] cameras;
|
||||||
delete[] soundSources;
|
delete[] soundSources;
|
||||||
delete[] boxes;
|
delete[] boxes;
|
||||||
delete[] overlaps;
|
delete[] overlaps;
|
||||||
@@ -838,19 +864,9 @@ namespace TR {
|
|||||||
|
|
||||||
void entityRemove(int entityIndex) {
|
void entityRemove(int entityIndex) {
|
||||||
entities[entityIndex].id = -1;
|
entities[entityIndex].id = -1;
|
||||||
|
entities[entityIndex].controller = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FloorInfo {
|
|
||||||
int floor, ceiling;
|
|
||||||
int roomNext, roomBelow, roomAbove;
|
|
||||||
int floorIndex;
|
|
||||||
bool kill;
|
|
||||||
int trigger;
|
|
||||||
FloorData::TriggerInfo trigInfo;
|
|
||||||
FloorData::TriggerCommand trigCmd[16];
|
|
||||||
int trigCmdCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
Room::Sector& getSector(int roomIndex, int x, int z, int &dx, int &dz) const {
|
Room::Sector& getSector(int roomIndex, int x, int z, int &dx, int &dz) const {
|
||||||
ASSERT(roomIndex >= 0 && roomIndex < roomsCount);
|
ASSERT(roomIndex >= 0 && roomIndex < roomsCount);
|
||||||
Room &room = rooms[roomIndex];
|
Room &room = rooms[roomIndex];
|
||||||
@@ -879,8 +895,8 @@ namespace TR {
|
|||||||
info.roomBelow = s.roomBelow;
|
info.roomBelow = s.roomBelow;
|
||||||
info.roomAbove = s.roomAbove;
|
info.roomAbove = s.roomAbove;
|
||||||
info.floorIndex = s.floorIndex;
|
info.floorIndex = s.floorIndex;
|
||||||
info.kill = false;
|
info.kill = 0;
|
||||||
info.trigger = -1;
|
info.trigger = Trigger::ACTIVATE;
|
||||||
info.trigCmdCount = 0;
|
info.trigCmdCount = 0;
|
||||||
|
|
||||||
if (!s.floorIndex) return;
|
if (!s.floorIndex) return;
|
||||||
@@ -913,22 +929,19 @@ namespace TR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case FloorData::TRIGGER : {
|
case FloorData::TRIGGER : {
|
||||||
info.trigger = cmd.sub;
|
info.trigger = (Trigger)cmd.sub;
|
||||||
info.trigCmdCount = 0;
|
info.trigCmdCount = 0;
|
||||||
info.trigInfo = (*fd++).triggerInfo;
|
info.trigInfo = (*fd++).triggerInfo;
|
||||||
FloorData::TriggerCommand trigCmd;
|
FloorData::TriggerCommand trigCmd;
|
||||||
do {
|
do {
|
||||||
trigCmd = (*fd++).triggerCmd; // trigger action
|
trigCmd = (*fd++).triggerCmd; // trigger action
|
||||||
info.trigCmd[info.trigCmdCount++] = trigCmd;
|
info.trigCmd[info.trigCmdCount++] = trigCmd;
|
||||||
if (trigCmd.action == Action::CAMERA_SWITCH) {
|
|
||||||
|
|
||||||
}
|
|
||||||
} while (!trigCmd.end);
|
} while (!trigCmd.end);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FloorData::KILL :
|
case FloorData::KILL :
|
||||||
info.kill = true;
|
info.kill = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default : LOG("unknown func: %d\n", cmd.func);
|
default : LOG("unknown func: %d\n", cmd.func);
|
||||||
|
127
src/lara.h
127
src/lara.h
@@ -14,9 +14,14 @@
|
|||||||
#define TURN_WATER_SLOW PI * 2.0f / 3.0f
|
#define TURN_WATER_SLOW PI * 2.0f / 3.0f
|
||||||
#define GLIDE_SPEED 50.0f
|
#define GLIDE_SPEED 50.0f
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_TRIGGER_ACTIONS 64
|
||||||
|
|
||||||
struct Lara : Controller {
|
struct Lara : Controller {
|
||||||
|
|
||||||
// http://www.tombraiderforums.com/showthread.php?t=148859&highlight=Explanation+left
|
ActionCommand actionList[MAX_TRIGGER_ACTIONS];
|
||||||
|
|
||||||
|
// http://www.tombraiderforums.com/showthread.php?t=148859
|
||||||
enum {
|
enum {
|
||||||
ANIM_STAND = 11,
|
ANIM_STAND = 11,
|
||||||
ANIM_FALL = 34,
|
ANIM_FALL = 34,
|
||||||
@@ -76,8 +81,8 @@ struct Lara : Controller {
|
|||||||
STATE_PULL_BLOCK,
|
STATE_PULL_BLOCK,
|
||||||
STATE_PUSH_PULL_READY,
|
STATE_PUSH_PULL_READY,
|
||||||
STATE_PICK_UP,
|
STATE_PICK_UP,
|
||||||
STATE_SWITCH_ON,
|
STATE_SWITCH_DOWN,
|
||||||
STATE_SWITCH_OFF,
|
STATE_SWITCH_UP,
|
||||||
STATE_USE_KEY,
|
STATE_USE_KEY,
|
||||||
STATE_USE_PUZZLE,
|
STATE_USE_PUZZLE,
|
||||||
STATE_UNDERWATER_DEATH,
|
STATE_UNDERWATER_DEATH,
|
||||||
@@ -94,10 +99,7 @@ struct Lara : Controller {
|
|||||||
STATE_WATER_OUT,
|
STATE_WATER_OUT,
|
||||||
STATE_MAX };
|
STATE_MAX };
|
||||||
|
|
||||||
int targetEntity;
|
Lara(TR::Level *level, int entity) : Controller(level, entity) {
|
||||||
float targetTimer;
|
|
||||||
|
|
||||||
Lara(TR::Level *level, int entity) : Controller(level, entity), targetEntity(-1), targetTimer(0.0f) {
|
|
||||||
/*
|
/*
|
||||||
// level 2 (pool)
|
// level 2 (pool)
|
||||||
pos = vec3(70067, -256, 29104);
|
pos = vec3(70067, -256, 29104);
|
||||||
@@ -157,6 +159,8 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void performTrigger() {
|
void performTrigger() {
|
||||||
|
if (actionCommand) return;
|
||||||
|
|
||||||
TR::Entity &e = getEntity();
|
TR::Entity &e = getEntity();
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
level->getFloorInfo(e.room, e.x, e.z, info);
|
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||||
@@ -165,36 +169,30 @@ struct Lara : Controller {
|
|||||||
bool isActive = (level->entities[info.trigCmd[0].args].flags & ENTITY_FLAG_ACTIVE);
|
bool isActive = (level->entities[info.trigCmd[0].args].flags & ENTITY_FLAG_ACTIVE);
|
||||||
if (info.trigInfo.once == 1 && (level->entities[info.trigCmd[0].args].flags & ENTITY_FLAG_ACTIVE)) return; // once trigger is already activated
|
if (info.trigInfo.once == 1 && (level->entities[info.trigCmd[0].args].flags & ENTITY_FLAG_ACTIVE)) return; // once trigger is already activated
|
||||||
|
|
||||||
int actionState = 0;
|
int actionState = state;
|
||||||
switch (info.trigger) {
|
switch (info.trigger) {
|
||||||
case TR::TRIGGER_ACTIVATE :
|
case TR::Level::Trigger::ACTIVATE :
|
||||||
if (isActive) return;
|
if (isActive) return;
|
||||||
actionState = state;
|
|
||||||
break;
|
break;
|
||||||
case TR::TRIGGER_PAD :
|
case TR::Level::Trigger::PAD :
|
||||||
if (stand != STAND_GROUND || isActive) return;
|
if (stand != STAND_GROUND || isActive) return;
|
||||||
actionState = state;
|
|
||||||
break;
|
break;
|
||||||
case TR::TRIGGER_SWITCH :
|
case TR::Level::Trigger::SWITCH :
|
||||||
if (mask & ACTION) {
|
actionState = (isActive && stand == STAND_GROUND) ? STATE_SWITCH_UP : STATE_SWITCH_DOWN;
|
||||||
actionState = isActive ? STATE_SWITCH_OFF : STATE_SWITCH_ON;
|
if ((mask & ACTION) == 0 || state == actionState)
|
||||||
} else
|
return;
|
||||||
|
if (fabsf(level->entities[info.trigCmd[0].args].rotation - e.rotation) > PI * 0.25f)
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
case TR::TRIGGER_KEY :
|
case TR::Level::Trigger::KEY :
|
||||||
if (isActive) return;
|
actionState = STATE_USE_KEY;
|
||||||
if (mask & ACTION)
|
if (isActive || (mask & ACTION) == 0 || state == actionState) // TODO: STATE_USE_PUZZLE
|
||||||
// if (entity.id == ENTITY_PUZZLE_1)
|
return;
|
||||||
// actionState = STATE_USE_PUZZLE;
|
if (fabsf(level->entities[info.trigCmd[0].args].rotation - e.rotation) > PI * 0.25f)
|
||||||
// else
|
|
||||||
actionState = STATE_USE_KEY;
|
|
||||||
else
|
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
case TR::TRIGGER_PICKUP :
|
case TR::Level::Trigger::PICKUP :
|
||||||
if ((mask & ACTION) && stand == STAND_GROUND)
|
if (!isActive) // check if item is not picked up
|
||||||
actionState = STATE_PICK_UP;
|
|
||||||
else
|
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
@@ -205,40 +203,46 @@ struct Lara : Controller {
|
|||||||
// try to activate Lara state
|
// try to activate Lara state
|
||||||
if (!setState(actionState)) return;
|
if (!setState(actionState)) return;
|
||||||
|
|
||||||
// build trigger activation chain
|
if (info.trigger == TR::Level::Trigger::SWITCH || info.trigger == TR::Level::Trigger::KEY) {
|
||||||
for (int i = 0; i < info.trigCmdCount; i++) {
|
TR::Entity &p = level->entities[info.trigCmd[0].args];
|
||||||
TR::FloorData::TriggerCommand &cmd = info.trigCmd[i];
|
angle.y = p.rotation;
|
||||||
switch (cmd.action) {
|
angle.x = 0;
|
||||||
case TR::Action::ACTIVATE : {
|
pos = vec3(p.x, p.y, p.z) + vec3(sinf(angle.y), 0, cosf(angle.y)) * (stand == STAND_GROUND ? 384 : 128);
|
||||||
Controller *controller = (Controller*)level->entities[cmd.args].controller;
|
updateEntity();
|
||||||
if (!controller) {
|
|
||||||
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].id);
|
|
||||||
playSound(2);
|
|
||||||
return;
|
|
||||||
} else
|
|
||||||
controller->nextAction = (i < info.trigCmdCount - 1) ? Action(TR::Action::ACTIVATE, info.trigCmd[i + 1].args, 0.0f) : Action(TR::Action::NONE, 0, 0.0f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TR::Action::LOOK_AT :
|
|
||||||
level->entities[cmd.args].flags |= ENTITY_FLAG_ACTIVE;
|
|
||||||
targetEntity = cmd.args;
|
|
||||||
targetTimer = info.trigInfo.timer;
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
LOG("unsupported trigger action %d\n", cmd.action);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// activate first entity in chain
|
// build trigger activation chain
|
||||||
Controller *controller = (Controller*)level->entities[info.trigCmd[0].args].controller;
|
ActionCommand *actionItem = &actionList[1];
|
||||||
if (controller) {
|
|
||||||
if (info.trigger == TR::TRIGGER_KEY) {
|
Controller *controller = this;
|
||||||
nextAction = controller->nextAction;
|
for (int i = 0; i < info.trigCmdCount; i++) {
|
||||||
controller->nextAction.action = TR::Action::NONE;
|
if (!controller) {
|
||||||
} else
|
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].id);
|
||||||
controller->activate((float)info.trigInfo.timer);
|
playSound(TR::SND_NO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.trigger == TR::Level::Trigger::KEY && i == 0) continue; // skip keyhole
|
||||||
|
|
||||||
|
TR::FloorData::TriggerCommand &cmd = info.trigCmd[i];
|
||||||
|
switch (cmd.action) {
|
||||||
|
case TR::Action::CAMERA_SWITCH :
|
||||||
|
*actionItem = ActionCommand(cmd.action, cmd.args, (float)info.trigCmd[++i].delay); // camera switch uses next command for delay timer
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
*actionItem = ActionCommand(cmd.action, cmd.args, info.trigInfo.timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
actionItem->next = (i < info.trigCmdCount - 1) ? actionItem + 1 : NULL;
|
||||||
|
actionItem++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG("perform\n");
|
||||||
|
actionList[0].next = &actionList[1];
|
||||||
|
actionCommand = &actionList[0];
|
||||||
|
|
||||||
|
if (info.trigger != TR::Level::Trigger::KEY)
|
||||||
|
activateNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Stand getStand() {
|
virtual Stand getStand() {
|
||||||
@@ -398,11 +402,6 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateState() {
|
virtual void updateState() {
|
||||||
if (targetTimer > 0.0f && (targetTimer -= Core::deltaTime) <= 0.0f) {
|
|
||||||
targetEntity = -1;
|
|
||||||
targetTimer = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
performTrigger();
|
performTrigger();
|
||||||
|
|
||||||
TR::Animation *anim = &level->anims[animIndex];
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
16
src/level.h
16
src/level.h
@@ -103,6 +103,8 @@ struct Level {
|
|||||||
|
|
||||||
ASSERT(lara != NULL);
|
ASSERT(lara != NULL);
|
||||||
camera = new Camera(&level, lara);
|
camera = new Camera(&level, lara);
|
||||||
|
|
||||||
|
level.cameraController = camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Level() {
|
~Level() {
|
||||||
@@ -110,8 +112,7 @@ struct Level {
|
|||||||
Debug::free();
|
Debug::free();
|
||||||
#endif
|
#endif
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
if (level.entities[i].id > -1)
|
delete (Controller*)level.entities[i].controller;
|
||||||
delete (Controller*)level.entities[i].controller;
|
|
||||||
|
|
||||||
for (int i = 0; i < shMAX; i++)
|
for (int i = 0; i < shMAX; i++)
|
||||||
delete shaders[i];
|
delete shaders[i];
|
||||||
@@ -532,13 +533,6 @@ struct Level {
|
|||||||
camera->update();
|
camera->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getCameraRoomIndex() {
|
|
||||||
for (int i = 0; i < level.roomsCount; i++)
|
|
||||||
if (lara->insideRoom(Core::viewPos, i))
|
|
||||||
return i;
|
|
||||||
return lara->getEntity().room;
|
|
||||||
}
|
|
||||||
|
|
||||||
void render() {
|
void render() {
|
||||||
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||||
|
|
||||||
@@ -573,7 +567,7 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: collision detection for camera
|
// TODO: collision detection for camera
|
||||||
renderRoom(camera->room);
|
renderRoom(camera->getRoomIndex());
|
||||||
|
|
||||||
shaders[shStatic]->bind();
|
shaders[shStatic]->bind();
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
@@ -603,7 +597,7 @@ struct Level {
|
|||||||
*/
|
*/
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Debug::begin();
|
Debug::begin();
|
||||||
Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||||
// Debug::Level::lights(level);
|
// Debug::Level::lights(level);
|
||||||
// Debug::Level::portals(level);
|
// Debug::Level::portals(level);
|
||||||
// Debug::Level::meshes(level);
|
// Debug::Level::meshes(level);
|
||||||
|
@@ -17,9 +17,10 @@ struct Trigger : Controller {
|
|||||||
return (state != baseState) == (getEntity().flags & ENTITY_FLAG_ACTIVE) > 0;
|
return (state != baseState) == (getEntity().flags & ENTITY_FLAG_ACTIVE) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool activate(float timer) {
|
virtual bool activate(ActionCommand *cmd) {
|
||||||
if (this->timer != 0.0f || !inState()) return false;
|
if (this->timer != 0.0f || !inState() || actionCommand) return false;
|
||||||
this->timer = timer;
|
Controller::activate(cmd);
|
||||||
|
this->timer = cmd->timer;
|
||||||
|
|
||||||
getEntity().flags ^= ENTITY_FLAG_ACTIVE;
|
getEntity().flags ^= ENTITY_FLAG_ACTIVE;
|
||||||
|
|
||||||
@@ -93,8 +94,8 @@ struct Dartgun : Trigger {
|
|||||||
|
|
||||||
Dartgun(TR::Level *level, int entity) : Trigger(level, entity, true), origin(pos) {}
|
Dartgun(TR::Level *level, int entity) : Trigger(level, entity, true), origin(pos) {}
|
||||||
|
|
||||||
virtual bool activate(float timer) {
|
virtual bool activate(ActionCommand *cmd) {
|
||||||
if (!Trigger::activate(timer))
|
if (!Trigger::activate(cmd))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// add dart (bullet)
|
// add dart (bullet)
|
||||||
|
@@ -111,6 +111,8 @@ struct vec3 {
|
|||||||
vec3 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
|
vec3 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
|
||||||
|
|
||||||
vec3 lerp(const vec3 &v, const float t) const {
|
vec3 lerp(const vec3 &v, const float t) const {
|
||||||
|
if (t <= 0.0f) return *this;
|
||||||
|
if (t >= 1.0f) return v;
|
||||||
return *this + (v - *this) * t;
|
return *this + (v - *this) * t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
<span id="status">Starting...</span>
|
<span id="status">Starting...</span>
|
||||||
<input type="button" value="fullscreen" onclick="Module.requestFullScreen(false, true)"><br><br>
|
<input type="button" value="fullscreen" onclick="Module.requestFullScreen(false, true)"><br><br>
|
||||||
<canvas id="canvas" width="160" height="120" oncontextmenu="event.preventDefault()"></canvas><br>
|
<canvas id="canvas" width="160" height="120" oncontextmenu="event.preventDefault()"></canvas><br>
|
||||||
<span id="info"></span>
|
<span id="info"><a target="_blank" href="https://github.com/XProger/OpenLara">OpenLara on github</a></span>
|
||||||
|
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
var statusElement = document.getElementById('status');
|
var statusElement = document.getElementById('status');
|
||||||
|
Reference in New Issue
Block a user