mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-07 21:56:37 +02:00
#3 climb & hang states fixes, water splash, item pickup, slow motion mode for debug (R key)
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
26
src/camera.h
26
src/camera.h
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#define MAX_CLIP_PLANES 10
|
#define MAX_CLIP_PLANES 10
|
||||||
|
|
||||||
#define CAMERA_OFFSET (1024.0f + 512.0f)
|
#define CAMERA_OFFSET (1024.0f + 256.0f)
|
||||||
|
|
||||||
struct Frustum {
|
struct Frustum {
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ struct Camera : Controller {
|
|||||||
activateNext();
|
activateNext();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void update() {
|
virtual void update() {
|
||||||
if (timer > 0.0f) {
|
if (timer > 0.0f) {
|
||||||
timer -= Core::deltaTime;
|
timer -= Core::deltaTime;
|
||||||
@@ -210,13 +210,13 @@ struct Camera : Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#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 d = 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);
|
||||||
|
|
||||||
if (Input::down[ikW]) v = v + dir;
|
if (Input::down[ikUp]) v = v + d;
|
||||||
if (Input::down[ikS]) v = v - dir;
|
if (Input::down[ikDown]) v = v - d;
|
||||||
if (Input::down[ikD]) v = v + dir.cross(vec3(0, 1, 0));
|
if (Input::down[ikRight]) v = v + d.cross(vec3(0, 1, 0));
|
||||||
if (Input::down[ikA]) v = v - dir.cross(vec3(0, 1, 0));
|
if (Input::down[ikLeft]) v = v - d.cross(vec3(0, 1, 0));
|
||||||
pos = pos + v.normal() * (Core::deltaTime * 2048.0f);
|
pos = pos + v.normal() * (Core::deltaTime * 2048.0f);
|
||||||
#endif
|
#endif
|
||||||
if (Input::down[ikMouseR]) {
|
if (Input::down[ikMouseR]) {
|
||||||
@@ -274,7 +274,7 @@ struct Camera : Controller {
|
|||||||
if (info.roomNext != 255)
|
if (info.roomNext != 255)
|
||||||
room = info.roomNext;
|
room = info.roomNext;
|
||||||
|
|
||||||
if (destPos.y < info.ceiling) {
|
if (pos.y < info.ceiling) {
|
||||||
if (info.roomAbove != 255)
|
if (info.roomAbove != 255)
|
||||||
room = info.roomAbove;
|
room = info.roomAbove;
|
||||||
else
|
else
|
||||||
@@ -300,17 +300,21 @@ struct Camera : Controller {
|
|||||||
float dist = dir.length();
|
float dist = dir.length();
|
||||||
dir = dir * (1.0f / dist);
|
dir = dir * (1.0f / dist);
|
||||||
|
|
||||||
int lx = -1, lz = -1;
|
int lr = -1, lx = -1, lz = -1;
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
while (dist > 1.0f) {
|
while (dist > 1.0f) {
|
||||||
int sx = px / 1024 * 1024 + 512,
|
int sx = px / 1024 * 1024 + 512,
|
||||||
sz = pz / 1024 * 1024 + 512;
|
sz = pz / 1024 * 1024 + 512;
|
||||||
|
|
||||||
if (lx != sx || lz != sz) {
|
if (lr != room || lx != sx || lz != sz) {
|
||||||
level->getFloorInfo(room, sx, sz, info);
|
level->getFloorInfo(room, sx, sz, info);
|
||||||
|
if (info.roomNext != 0xFF) {
|
||||||
|
room = info.roomNext;
|
||||||
|
level->getFloorInfo(room, sx, sz, info);
|
||||||
|
}
|
||||||
|
lr = room;
|
||||||
lx = sx;
|
lx = sx;
|
||||||
lz = sz;
|
lz = sz;
|
||||||
if (info.roomNext != 0xFF) room = info.roomNext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (py > info.floor && info.roomBelow != 0xFF)
|
if (py > info.floor && info.roomBelow != 0xFF)
|
||||||
|
@@ -98,10 +98,10 @@ struct Controller {
|
|||||||
return getEntity().room;
|
return getEntity().room;
|
||||||
}
|
}
|
||||||
|
|
||||||
int setAnimation(int index, int frame = -1) {
|
int setAnimation(int index, int frame = 0) {
|
||||||
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 <= 0 ? -frame : (frame - anim.frameStart)) / 30.0f;
|
||||||
ASSERT(anim.frameStart <= anim.frameEnd);
|
ASSERT(anim.frameStart <= anim.frameEnd);
|
||||||
animPrevFrame = int(animTime * 30.0f) - 1;
|
animPrevFrame = int(animTime * 30.0f) - 1;
|
||||||
return state = anim.state;
|
return state = anim.state;
|
||||||
@@ -134,26 +134,25 @@ struct Controller {
|
|||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getOverlap(int fromX, int fromY, int fromZ, int toX, int toZ, int &delta) const {
|
int getOverlap(int fromX, int fromY, int fromZ, int toX, int toZ) const {
|
||||||
int dx, dz;
|
int dx, dz;
|
||||||
TR::Room::Sector &s = level->getSector(getEntity().room, fromX, fromZ, dx, dz);
|
TR::Room::Sector &s = level->getSector(getEntity().room, fromX, fromZ, dx, dz);
|
||||||
|
|
||||||
if (s.boxIndex == 0xFFFF) return NO_OVERLAP;
|
if (s.boxIndex == 0xFFFF)
|
||||||
|
return NO_OVERLAP;
|
||||||
|
|
||||||
TR::Box &b = level->boxes[s.boxIndex];
|
TR::Box &b = level->boxes[s.boxIndex];
|
||||||
if (b.contains(toX, toZ)) {
|
if (b.contains(toX, toZ))
|
||||||
delta = 0;
|
return 0;
|
||||||
return b.floor;
|
|
||||||
}
|
|
||||||
|
|
||||||
int floor = NO_OVERLAP;
|
int floor = NO_OVERLAP;
|
||||||
delta = floor;
|
int delta = NO_OVERLAP;
|
||||||
|
|
||||||
TR::Overlap *o = &level->overlaps[b.overlap & 0x7FFF];
|
TR::Overlap *o = &level->overlaps[b.overlap & 0x7FFF];
|
||||||
do {
|
do {
|
||||||
TR::Box &ob = level->boxes[o->boxIndex];
|
TR::Box &ob = level->boxes[o->boxIndex];
|
||||||
if (ob.contains(toX, toZ)) { // get min delta
|
if (ob.contains(toX, toZ)) { // get min delta
|
||||||
int d = abs(ob.floor - fromY);
|
int d = abs(b.floor - ob.floor);
|
||||||
if (d < delta) {
|
if (d < delta) {
|
||||||
floor = ob.floor;
|
floor = ob.floor;
|
||||||
delta = d;
|
delta = d;
|
||||||
@@ -161,8 +160,10 @@ struct Controller {
|
|||||||
}
|
}
|
||||||
} while (!(o++)->end);
|
} while (!(o++)->end);
|
||||||
|
|
||||||
delta = floor - b.floor;
|
if (floor == NO_OVERLAP)
|
||||||
return floor;
|
return NO_OVERLAP;
|
||||||
|
|
||||||
|
return b.floor - floor;
|
||||||
}
|
}
|
||||||
|
|
||||||
void playSound(int id) const {
|
void playSound(int id) const {
|
||||||
@@ -208,20 +209,23 @@ struct Controller {
|
|||||||
|
|
||||||
if (entity.y > info.floor) {
|
if (entity.y > info.floor) {
|
||||||
if (info.roomBelow == 0xFF) {
|
if (info.roomBelow == 0xFF) {
|
||||||
entity.y = info.floor;
|
if (entity.y > info.floor) {
|
||||||
pos.y = entity.y;
|
entity.y = info.floor;
|
||||||
velocity.y = 0.0f;
|
pos.y = entity.y;
|
||||||
|
velocity.y = 0.0f;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
entity.room = info.roomBelow;
|
entity.room = info.roomBelow;
|
||||||
}
|
}
|
||||||
|
|
||||||
int height = getHeight();
|
int height = getHeight();
|
||||||
if (entity.y - getHeight() < info.ceiling) {
|
if (entity.y - height < info.ceiling) {
|
||||||
if (info.roomAbove == 0xFF) {
|
if (info.roomAbove == 0xFF) {
|
||||||
pos.y = entity.y = info.ceiling + height;
|
pos.y = entity.y = info.ceiling + height;
|
||||||
velocity.y = fabsf(velocity.y);
|
if (velocity.y < 0.0f)
|
||||||
|
velocity.y = GRAVITY;
|
||||||
} else {
|
} else {
|
||||||
if (stand == STAND_UNDERWATER && !(level->rooms[info.roomAbove].flags & TR::ROOM_FLAG_WATER)) {
|
if (stand == STAND_UNDERWATER && !level->rooms[info.roomAbove].flags.water) {
|
||||||
stand = STAND_ONWATER;
|
stand = STAND_ONWATER;
|
||||||
velocity.y = 0;
|
velocity.y = 0;
|
||||||
pos.y = info.ceiling;
|
pos.y = info.ceiling;
|
||||||
@@ -277,19 +281,21 @@ struct Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual bool activate(ActionCommand *cmd) { actionCommand = cmd; return true; }
|
virtual bool activate(ActionCommand *cmd) { actionCommand = cmd; return true; }
|
||||||
|
virtual void doCustomCommand (int curFrame, int prevFrame) {}
|
||||||
virtual void updateVelocity() {}
|
virtual void updateVelocity() {}
|
||||||
virtual void move() {}
|
virtual void checkRoom() {}
|
||||||
virtual Stand getStand() { return STAND_AIR; }
|
virtual void move() {}
|
||||||
virtual int getHeight() { return 0; }
|
virtual Stand getStand() { return STAND_AIR; }
|
||||||
virtual int getStateAir() { return state; }
|
virtual int getHeight() { return 0; }
|
||||||
virtual int getStateGround() { return state; }
|
virtual int getStateAir() { return state; }
|
||||||
virtual int getStateSlide() { return state; }
|
virtual int getStateGround() { return state; }
|
||||||
virtual int getStateHang() { return state; }
|
virtual int getStateSlide() { return state; }
|
||||||
virtual int getStateUnderwater() { return state; }
|
virtual int getStateHang() { return state; }
|
||||||
virtual int getStateOnwater() { return state; }
|
virtual int getStateUnderwater() { return state; }
|
||||||
virtual int getStateDeath() { return state; }
|
virtual int getStateOnwater() { return state; }
|
||||||
virtual int getStateDefault() { return state; }
|
virtual int getStateDeath() { return state; }
|
||||||
virtual int getInputMask() { return 0; }
|
virtual int getStateDefault() { return state; }
|
||||||
|
virtual int getInputMask() { return 0; }
|
||||||
|
|
||||||
virtual int getState(Stand stand) {
|
virtual int getState(Stand stand) {
|
||||||
TR::Animation *anim = &level->anims[animIndex];
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
@@ -324,8 +330,8 @@ struct Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateEnd() {
|
virtual void updateEnd() {
|
||||||
|
TR::Entity &e = getEntity();
|
||||||
move();
|
move();
|
||||||
collide();
|
|
||||||
updateEntity();
|
updateEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,6 +380,7 @@ struct Controller {
|
|||||||
if (endFrame) {
|
if (endFrame) {
|
||||||
pos = pos + vec3(sx, sy, sz).rotateY(-angle.y);
|
pos = pos + vec3(sx, sy, sz).rotateY(-angle.y);
|
||||||
updateEntity();
|
updateEntity();
|
||||||
|
checkRoom();
|
||||||
LOG("move: %d %d %d\n", (int)sx, (int)sy, (int)sz);
|
LOG("move: %d %d %d\n", (int)sx, (int)sy, (int)sz);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -403,8 +410,9 @@ struct Controller {
|
|||||||
if (idx > animPrevFrame && idx <= frameIndex) {
|
if (idx > animPrevFrame && idx <= frameIndex) {
|
||||||
if (cmd == TR::ANIM_CMD_EFFECT) {
|
if (cmd == TR::ANIM_CMD_EFFECT) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case TR::EFFECT_ROTATE_180 : angle.y = angle.y + PI; break;
|
case TR::EFFECT_ROTATE_180 : angle.y = angle.y + PI; break;
|
||||||
case TR::EFFECT_LARA_BUBBLES : playSound(TR::SND_BUBBLE); break;
|
case TR::EFFECT_LARA_BUBBLES : if (rand() % 10 > 6) playSound(TR::SND_BUBBLE); break;
|
||||||
|
case TR::EFFECT_LARA_HANDSFREE : break;
|
||||||
default : LOG("unknown special cmd %d (anim %d)\n", id, animIndex);
|
default : LOG("unknown special cmd %d (anim %d)\n", id, animIndex);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -416,6 +424,8 @@ struct Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doCustomCommand(frameIndex, animPrevFrame);
|
||||||
|
|
||||||
if (endFrame) { // if animation is end - switch to next
|
if (endFrame) { // if animation is end - switch to next
|
||||||
setAnimation(anim->nextAnimation, anim->nextFrame);
|
setAnimation(anim->nextAnimation, anim->nextFrame);
|
||||||
activateNext();
|
activateNext();
|
||||||
@@ -479,4 +489,12 @@ struct SpriteController : Controller {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void addSprite(TR::Level *level, TR::Entity::Type type, int room, int x, int y, int z, int frame = -1) {
|
||||||
|
int index = level->entityAdd(type, room, x, y, z, 0, -1);
|
||||||
|
if (index > -1) {
|
||||||
|
level->entities[index].intensity = 0x1FFF - level->rooms[room].ambient;
|
||||||
|
level->entities[index].controller = new SpriteController(level, index, true, frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
138
src/debug.h
138
src/debug.h
@@ -184,58 +184,35 @@ namespace Debug {
|
|||||||
|
|
||||||
namespace Level {
|
namespace Level {
|
||||||
|
|
||||||
void debugFloor(const TR::Level &level, const vec3 &f, const vec3 &c, int floorIndex, int boxIndex, bool current) {
|
void debugFloor(const TR::Level &level, int roomIndex, int x, int z) {
|
||||||
if (floorIndex == 0) return;
|
TR::Level::FloorInfo info;
|
||||||
|
level.getFloorInfo(roomIndex, x, z, info);
|
||||||
|
|
||||||
|
vec3 f = vec3(x, info.floor, z);
|
||||||
|
vec3 c = vec3(x, info.ceiling, z);
|
||||||
vec3 vf[4] = { f, f + vec3(1024, 0, 0), f + vec3(1024, 0, 1024), f + vec3(0, 0, 1024) };
|
vec3 vf[4] = { f, f + vec3(1024, 0, 0), f + vec3(1024, 0, 1024), f + vec3(0, 0, 1024) };
|
||||||
vec3 vc[4] = { c, c + vec3(1024, 0, 0), c + vec3(1024, 0, 1024), c + vec3(0, 0, 1024) };
|
vec3 vc[4] = { c, c + vec3(1024, 0, 0), c + vec3(1024, 0, 1024), c + vec3(0, 0, 1024) };
|
||||||
|
|
||||||
if (current)
|
|
||||||
glColor3f(1, 1, 1);
|
|
||||||
else
|
|
||||||
glColor3f(0, 1, 0);
|
|
||||||
|
|
||||||
bool isPortal = false;
|
|
||||||
|
|
||||||
float fx = 0.0f, fz = 0.0f;
|
|
||||||
|
|
||||||
TR::FloorData *fd = &level.floors[floorIndex];
|
|
||||||
TR::FloorData::Command cmd;
|
|
||||||
do {
|
|
||||||
cmd = (*fd++).cmd;
|
|
||||||
|
|
||||||
switch (cmd.func) {
|
|
||||||
case TR::FloorData::PORTAL :
|
|
||||||
isPortal = true;
|
|
||||||
fd++;
|
|
||||||
break; // portal
|
|
||||||
case TR::FloorData::FLOOR : // floor & ceiling
|
|
||||||
case TR::FloorData::CEILING : {
|
|
||||||
TR::FloorData::Slant slant = (*fd++).slant;
|
|
||||||
int sx = 256 * (int)slant.x;
|
|
||||||
int sz = 256 * (int)slant.z;
|
|
||||||
|
|
||||||
auto &p = cmd.func == 0x02 ? vf : vc;
|
|
||||||
|
|
||||||
if (cmd.func == TR::FloorData::FLOOR) { // floor
|
int sx = 256 * info.slantX;
|
||||||
fx = (float)slant.x;
|
int sz = 256 * info.slantZ;
|
||||||
fz = (float)slant.z;
|
|
||||||
|
|
||||||
if (sx > 0) {
|
if (sx > 0) {
|
||||||
p[0].y += sx;
|
vf[0].y += sx;
|
||||||
p[3].y += sx;
|
vf[3].y += sx;
|
||||||
} else {
|
} else {
|
||||||
p[1].y -= sx;
|
vf[1].y -= sx;
|
||||||
p[2].y -= sx;
|
vf[2].y -= sx;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sz > 0) {
|
if (sz > 0) {
|
||||||
p[0].y += sz;
|
vf[0].y += sz;
|
||||||
p[1].y += sz;
|
vf[1].y += sz;
|
||||||
} else {
|
} else {
|
||||||
p[3].y -= sz;
|
vf[3].y -= sz;
|
||||||
p[2].y -= sz;
|
vf[2].y -= sz;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
} else { // ceiling
|
} else { // ceiling
|
||||||
if (sx < 0) {
|
if (sx < 0) {
|
||||||
p[0].y += sx;
|
p[0].y += sx;
|
||||||
@@ -253,22 +230,7 @@ namespace Debug {
|
|||||||
p[2].y += sz;
|
p[2].y += sz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
*/
|
||||||
}
|
|
||||||
case TR::FloorData::TRIGGER : {
|
|
||||||
TR::FloorData::TriggerInfo info = (*fd++).triggerInfo;
|
|
||||||
TR::FloorData::TriggerCommand trigCmd;
|
|
||||||
glColor3f(1, 0, 1);
|
|
||||||
do {
|
|
||||||
trigCmd = (*fd++).triggerCmd; // trigger action
|
|
||||||
} while (!trigCmd.end);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default :
|
|
||||||
if (!cmd.end)
|
|
||||||
LOG("unknown func %d : %d\n", cmd.func, cmd.sub);
|
|
||||||
}
|
|
||||||
} while (!cmd.end);
|
|
||||||
|
|
||||||
glBegin(GL_LINE_STRIP);
|
glBegin(GL_LINE_STRIP);
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
@@ -281,7 +243,7 @@ namespace Debug {
|
|||||||
glVertex3fv((GLfloat*)&vc[i % 4]);
|
glVertex3fv((GLfloat*)&vc[i % 4]);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
if (isPortal) {
|
if (info.roomNext != 0xFF) {
|
||||||
glColor4f(0.0f, 0.0f, 1.0f, 0.5f);
|
glColor4f(0.0f, 0.0f, 1.0f, 0.5f);
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
for (int i = 3; i >= 0; i--)
|
for (int i = 3; i >= 0; i--)
|
||||||
@@ -289,31 +251,26 @@ namespace Debug {
|
|||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info.roomAbove != 0xFF) {
|
||||||
|
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
for (int i = 3; i >= 0; i--) {
|
||||||
|
vec3 v = vf[i];
|
||||||
|
v.y -= 32.0f;
|
||||||
|
glVertex3fv((GLfloat*)&v);
|
||||||
|
}
|
||||||
|
glEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
if (boxIndex == 0xFFFF) {
|
if (boxIndex == 0xFFFF) {
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
float x = f.x + 512.0f, z = f.z + 512.0f;
|
float x = f.x + 512.0f, z = f.z + 512.0f;
|
||||||
glVertex3f(x, f.y, z);
|
glVertex3f(x, f.y, z);
|
||||||
glVertex3f(x, c.y, z);
|
glVertex3f(x, c.y, z);
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}*/
|
||||||
|
|
||||||
vec3 a = (vf[0] + vf[1] + vf[2] + vf[3]) * 0.25f;
|
|
||||||
vec3 n = vec3(-fx, -4.0f, -fz).normal();
|
|
||||||
vec3 b = a + n * 1.0f;
|
|
||||||
|
|
||||||
vec3 v = ((Controller*)level.entities[0].controller)->getDir();
|
|
||||||
vec3 p = v - n * n.dot(v);
|
|
||||||
vec3 d = b + p.normal() * 256.0f;
|
|
||||||
|
|
||||||
glBegin(GL_LINES);
|
|
||||||
glColor3f(1, 1, 1);
|
|
||||||
glVertex3fv((GLfloat*)&a);
|
|
||||||
glVertex3fv((GLfloat*)&b);
|
|
||||||
|
|
||||||
glColor3f(1, 1, 0);
|
|
||||||
glVertex3fv((GLfloat*)&b);
|
|
||||||
glVertex3fv((GLfloat*)&d);
|
|
||||||
glEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugBox(const TR::Box &b) {
|
void debugBox(const TR::Box &b) {
|
||||||
@@ -340,6 +297,7 @@ namespace Debug {
|
|||||||
|
|
||||||
vec3 p = (pos - vec3(room.info.x, 0, room.info.z)) / vec3(1024, 1, 1024);
|
vec3 p = (pos - vec3(room.info.x, 0, room.info.z)) / vec3(1024, 1, 1024);
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
for (int z = 0; z < room.zSectors; z++)
|
for (int z = 0; z < room.zSectors; z++)
|
||||||
for (int x = 0; x < room.xSectors; x++) {
|
for (int x = 0; x < room.xSectors; x++) {
|
||||||
TR::Room::Sector &s = room.sectors[x * room.zSectors + z];
|
TR::Room::Sector &s = room.sectors[x * room.zSectors + z];
|
||||||
@@ -354,18 +312,17 @@ namespace Debug {
|
|||||||
vec3 c(x * 1024 + room.info.x, s.ceiling * 256 + 1, z * 1024 + room.info.z);
|
vec3 c(x * 1024 + room.info.x, s.ceiling * 256 + 1, z * 1024 + room.info.z);
|
||||||
|
|
||||||
bool current = (int)p.x == x && (int)p.z == z;
|
bool current = (int)p.x == x && (int)p.z == z;
|
||||||
debugFloor(level, f, c, s.floorIndex, s.boxIndex, current);
|
debugFloor(level, roomIndex, room.info.x + x * 1024, room.info.z + z * 1024);
|
||||||
/*
|
|
||||||
if (current && s.boxIndex != 0xFFFF && level.boxes[s.boxIndex].overlap != 0xFFFF) {
|
if (current && s.boxIndex != 0xFFFF && level.boxes[s.boxIndex].overlap != 0xFFFF) {
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glColor4f(0.0f, 1.0f, 0.0f, 0.25f);
|
glColor4f(0.0f, 1.0f, 0.0f, 0.25f);
|
||||||
debugBox(level.boxes[s.boxIndex]);
|
debugBox(level.boxes[s.boxIndex]);
|
||||||
glColor4f(1.0f, 1.0f, 0.0f, 0.25f);
|
glColor4f(1.0f, 1.0f, 0.0f, 0.25f);
|
||||||
debugOverlaps(level, s.boxIndex);
|
debugOverlaps(level, s.boxIndex);
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rooms(const TR::Level &level, const vec3 &pos, int roomIndex) {
|
void rooms(const TR::Level &level, const vec3 &pos, int roomIndex) {
|
||||||
@@ -395,6 +352,7 @@ namespace Debug {
|
|||||||
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
for (int i = 0; i < level.roomsCount; i++) {
|
||||||
|
// if (level.entities[91].room != i) continue;
|
||||||
TR::Room &r = level.rooms[i];
|
TR::Room &r = level.rooms[i];
|
||||||
for (int j = 0; j < r.portalsCount; j++) {
|
for (int j = 0; j < r.portalsCount; j++) {
|
||||||
TR::Room::Portal &p = r.portals[j];
|
TR::Room::Portal &p = r.portals[j];
|
||||||
@@ -415,7 +373,7 @@ namespace Debug {
|
|||||||
TR::Entity &e = level.entities[i];
|
TR::Entity &e = level.entities[i];
|
||||||
|
|
||||||
char buf[255];
|
char buf[255];
|
||||||
sprintf(buf, "%d", (int)e.id);
|
sprintf(buf, "%d", (int)e.type);
|
||||||
Debug::Draw::text(vec3(e.x, e.y, e.z), vec4(0.8, 0.0, 0.0, 1), buf);
|
Debug::Draw::text(vec3(e.x, e.y, e.z), vec4(0.8, 0.0, 0.0, 1), buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -491,7 +449,7 @@ namespace Debug {
|
|||||||
|
|
||||||
if (!node) continue; // ???
|
if (!node) continue; // ???
|
||||||
|
|
||||||
if (e.id == m.id) {
|
if (e.type == m.type) {
|
||||||
ASSERT(m.animation < 0xFFFF);
|
ASSERT(m.animation < 0xFFFF);
|
||||||
|
|
||||||
int fSize = sizeof(TR::AnimFrame) + m.mCount * sizeof(uint16) * 2;
|
int fSize = sizeof(TR::AnimFrame) + m.mCount * sizeof(uint16) * 2;
|
||||||
@@ -554,11 +512,11 @@ namespace Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void info(const TR::Level &level, const TR::Entity &entity) {
|
void info(const TR::Level &level, const TR::Entity &entity, int state, int anim, int frame) {
|
||||||
char buf[255];
|
char buf[255];
|
||||||
sprintf(buf, "DIP = %d, TRI = %d, SND = %d", Core::stats.dips, Core::stats.tris, Sound::channelsCount);
|
sprintf(buf, "DIP = %d, TRI = %d, SND = %d", Core::stats.dips, Core::stats.tris, Sound::channelsCount);
|
||||||
Debug::Draw::text(vec2(16, 16), vec4(1.0f), buf);
|
Debug::Draw::text(vec2(16, 16), vec4(1.0f), buf);
|
||||||
sprintf(buf, "pos = (%d, %d, %d), room = %d", entity.x, entity.y, entity.z, entity.room);
|
sprintf(buf, "pos = (%d, %d, %d), room = %d, state = %d, anim = %d, frame = %d", entity.x, entity.y, entity.z, entity.room, state, anim, frame);
|
||||||
Debug::Draw::text(vec2(16, 32), vec4(1.0f), buf);
|
Debug::Draw::text(vec2(16, 32), vec4(1.0f), buf);
|
||||||
|
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
|
132
src/format.h
132
src/format.h
@@ -10,11 +10,6 @@
|
|||||||
|
|
||||||
namespace TR {
|
namespace TR {
|
||||||
|
|
||||||
enum : int32 {
|
|
||||||
ROOM_FLAG_WATER = 0x0001,
|
|
||||||
ROOM_FLAG_VISIBLE = 0x8000
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ANIM_CMD_NONE ,
|
ANIM_CMD_NONE ,
|
||||||
ANIM_CMD_MOVE ,
|
ANIM_CMD_MOVE ,
|
||||||
@@ -100,10 +95,6 @@ namespace TR {
|
|||||||
CUTSCENE , // play cutscene
|
CUTSCENE , // play cutscene
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ENTITY_FLAG_CLEAR 0x0080
|
|
||||||
#define ENTITY_FLAG_VISIBLE 0x0100
|
|
||||||
#define ENTITY_FLAG_ACTIVE 0x3E00
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
struct fixed {
|
struct fixed {
|
||||||
@@ -186,7 +177,9 @@ namespace TR {
|
|||||||
uint16 lightsCount;
|
uint16 lightsCount;
|
||||||
uint16 meshesCount;
|
uint16 meshesCount;
|
||||||
int16 alternateRoom;
|
int16 alternateRoom;
|
||||||
int16 flags;
|
struct {
|
||||||
|
uint16 water:1, unused:14, rendered:1;
|
||||||
|
} flags;
|
||||||
|
|
||||||
struct Portal {
|
struct Portal {
|
||||||
uint16 roomIndex;
|
uint16 roomIndex;
|
||||||
@@ -215,7 +208,9 @@ namespace TR {
|
|||||||
angle rotation;
|
angle rotation;
|
||||||
uint16 intensity;
|
uint16 intensity;
|
||||||
uint16 meshID;
|
uint16 meshID;
|
||||||
uint16 flags; // ! not exists in file !
|
struct { // ! not exists in file !
|
||||||
|
uint16 unused:15, rendered:1;
|
||||||
|
} flags;
|
||||||
} *meshes;
|
} *meshes;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -287,20 +282,8 @@ namespace TR {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Entity {
|
struct Entity {
|
||||||
int16 id; // Object Identifier (matched in Models[], or SpriteSequences[], as appropriate)
|
enum Type : int16 {
|
||||||
int16 room; // which room contains this item
|
NONE = -1,
|
||||||
int32 x, y, z; // world coords
|
|
||||||
angle rotation; // ((0xc000 >> 14) * 90) degrees
|
|
||||||
int16 intensity; // (constant lighting; -1 means use mesh lighting)
|
|
||||||
uint16 flags; // 0x0100 indicates "initially invisible", 0x3e00 is Activation Mask
|
|
||||||
// 0x3e00 indicates "open" or "activated"; these can be XORed with
|
|
||||||
// related FloorData::FDlist fields (e.g. for switches)
|
|
||||||
// not exists in file
|
|
||||||
uint16 align;
|
|
||||||
int16 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays
|
|
||||||
void *controller; // Controller implementation or NULL
|
|
||||||
|
|
||||||
enum {
|
|
||||||
LARA = 0,
|
LARA = 0,
|
||||||
|
|
||||||
ENEMY_TWIN = 6,
|
ENEMY_TWIN = 6,
|
||||||
@@ -353,11 +336,24 @@ namespace TR {
|
|||||||
AMMO_SHOTGUN = 89, // sprite
|
AMMO_SHOTGUN = 89, // sprite
|
||||||
AMMO_MAGNUMS = 90, // sprite
|
AMMO_MAGNUMS = 90, // sprite
|
||||||
AMMO_UZIS = 91, // sprite
|
AMMO_UZIS = 91, // sprite
|
||||||
|
|
||||||
MEDIKIT_SMALL = 93, // sprite
|
MEDIKIT_SMALL = 93, // sprite
|
||||||
MEDIKIT_BIG = 94, // sprite
|
MEDIKIT_BIG = 94, // sprite
|
||||||
|
|
||||||
|
PUZZLE_1 = 110, // sprite
|
||||||
|
PUZZLE_2 = 111, // sprite
|
||||||
|
PUZZLE_3 = 112, // sprite
|
||||||
|
PUZZLE_4 = 113, // sprite
|
||||||
|
|
||||||
HOLE_PUZZLE = 118,
|
HOLE_PUZZLE = 118,
|
||||||
|
|
||||||
|
PICKUP = 126, // sprite
|
||||||
|
|
||||||
|
KEY_1 = 129, // sprite
|
||||||
|
KEY_2 = 130, // sprite
|
||||||
|
KEY_3 = 131, // sprite
|
||||||
|
KEY_4 = 132, // sprite
|
||||||
|
|
||||||
HOLE_KEY = 137,
|
HOLE_KEY = 137,
|
||||||
|
|
||||||
ARTIFACT = 143, // sprite
|
ARTIFACT = 143, // sprite
|
||||||
@@ -375,7 +371,19 @@ namespace TR {
|
|||||||
VIEW_TARGET = 169,
|
VIEW_TARGET = 169,
|
||||||
|
|
||||||
GLYPH = 190, // sprite
|
GLYPH = 190, // sprite
|
||||||
};
|
} type;
|
||||||
|
int16 room;
|
||||||
|
int32 x, y, z;
|
||||||
|
angle rotation;
|
||||||
|
int16 intensity;
|
||||||
|
union {
|
||||||
|
struct { uint16 unused:7, clear:1, invisible:1, active:5, unused2:1, rendered:1; };
|
||||||
|
uint16 value;
|
||||||
|
} flags;
|
||||||
|
// not exists in file
|
||||||
|
uint16 align;
|
||||||
|
int16 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays
|
||||||
|
void *controller; // Controller implementation or NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Animation {
|
struct Animation {
|
||||||
@@ -447,25 +455,27 @@ namespace TR {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
uint32 id; // Item Identifier (matched in Entities[])
|
Entity::Type type;
|
||||||
uint16 mCount; // number of meshes in this object
|
uint16 unused;
|
||||||
uint16 mStart; // stating mesh (offset into MeshPointers[])
|
uint16 mCount;
|
||||||
uint32 node; // offset into MeshTree[]
|
uint16 mStart;
|
||||||
uint32 frame; // byte offset into Frames[] (divide by 2 for Frames[i])
|
uint32 node;
|
||||||
uint16 animation; // offset into Animations[]
|
uint32 frame;
|
||||||
uint16 align; // ! not exists in file !
|
uint16 animation;
|
||||||
|
uint16 align;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StaticMesh {
|
struct StaticMesh {
|
||||||
uint32 id; // Static Mesh Identifier
|
uint32 id;
|
||||||
uint16 mesh; // Mesh (offset into MeshPointers[])
|
uint16 mesh;
|
||||||
MinMax box[2]; // visible (minX, maxX, minY, maxY, minZ, maxZ) & collision
|
MinMax vbox;
|
||||||
|
MinMax cbox;
|
||||||
uint16 flags;
|
uint16 flags;
|
||||||
|
|
||||||
void getBox(bool collision, angle rotation, vec3 &min, vec3 &max) {
|
void getBox(bool collision, angle rotation, vec3 &min, vec3 &max) {
|
||||||
int k = rotation.value / 0x4000;
|
int k = rotation.value / 0x4000;
|
||||||
|
|
||||||
MinMax &m = box[collision];
|
MinMax &m = collision ? cbox : vbox;
|
||||||
|
|
||||||
ASSERT(m.minX <= m.maxX && m.minY <= m.maxY && m.minZ <= m.maxZ);
|
ASSERT(m.minX <= m.maxX && m.minY <= m.maxY && m.minZ <= m.maxZ);
|
||||||
|
|
||||||
@@ -516,9 +526,10 @@ namespace TR {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SpriteSequence {
|
struct SpriteSequence {
|
||||||
int32 id; // Sprite identifier
|
Entity::Type type;
|
||||||
int16 sCount; // Negative of ``how many sprites are in this sequence''
|
uint16 unused;
|
||||||
int16 sStart; // Where (in sprite texture list) this sequence starts
|
int16 sCount;
|
||||||
|
int16 sStart;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Camera {
|
struct Camera {
|
||||||
@@ -800,10 +811,10 @@ namespace TR {
|
|||||||
stream.raw(&e, sizeof(e) - sizeof(e.align) - sizeof(e.controller) - sizeof(e.modelIndex));
|
stream.raw(&e, sizeof(e) - sizeof(e.align) - sizeof(e.controller) - sizeof(e.modelIndex));
|
||||||
e.align = 0;
|
e.align = 0;
|
||||||
e.controller = NULL;
|
e.controller = NULL;
|
||||||
e.modelIndex = getModelIndex(e.id);
|
e.modelIndex = getModelIndex(e.type);
|
||||||
}
|
}
|
||||||
for (int i = entitiesBaseCount; i < entitiesCount; i++) {
|
for (int i = entitiesBaseCount; i < entitiesCount; i++) {
|
||||||
entities[i].id = -1;
|
entities[i].type = Entity::NONE;
|
||||||
entities[i].controller = NULL;
|
entities[i].controller = NULL;
|
||||||
}
|
}
|
||||||
// palette
|
// palette
|
||||||
@@ -889,33 +900,33 @@ namespace TR {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16 getModelIndex(int16 id) const {
|
int16 getModelIndex(Entity::Type type) const {
|
||||||
for (int i = 0; i < modelsCount; i++)
|
for (int i = 0; i < modelsCount; i++)
|
||||||
if (id == models[i].id)
|
if (type == models[i].type)
|
||||||
return i + 1;
|
return i + 1;
|
||||||
|
|
||||||
for (int i = 0; i < spriteSequencesCount; i++)
|
for (int i = 0; i < spriteSequencesCount; i++)
|
||||||
if (id == spriteSequences[i].id)
|
if (type == spriteSequences[i].type)
|
||||||
return -(i + 1);
|
return -(i + 1);
|
||||||
|
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int entityAdd(int16 id, int16 room, int32 x, int32 y, int32 z, angle rotation, int16 intensity) {
|
int entityAdd(TR::Entity::Type type, int16 room, int32 x, int32 y, int32 z, angle rotation, int16 intensity) {
|
||||||
int entityIndex = -1;
|
int entityIndex = -1;
|
||||||
for (int i = entitiesBaseCount; i < entitiesCount; i++)
|
for (int i = entitiesBaseCount; i < entitiesCount; i++)
|
||||||
if (entities[i].id == -1) {
|
if (entities[i].type == Entity::NONE) {
|
||||||
Entity &e = entities[i];
|
Entity &e = entities[i];
|
||||||
e.id = id;
|
e.type = type;
|
||||||
e.room = room;
|
e.room = room;
|
||||||
e.x = x;
|
e.x = x;
|
||||||
e.y = y;
|
e.y = y;
|
||||||
e.z = z;
|
e.z = z;
|
||||||
e.rotation = rotation;
|
e.rotation = rotation;
|
||||||
e.intensity = intensity;
|
e.intensity = intensity;
|
||||||
e.flags = 0;
|
e.flags.value = 0;
|
||||||
e.modelIndex = getModelIndex(e.id);
|
e.modelIndex = getModelIndex(e.type);
|
||||||
e.controller = NULL;
|
e.controller = NULL;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@@ -923,7 +934,7 @@ namespace TR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void entityRemove(int entityIndex) {
|
void entityRemove(int entityIndex) {
|
||||||
entities[entityIndex].id = -1;
|
entities[entityIndex].type = Entity::NONE;
|
||||||
entities[entityIndex].controller = NULL;
|
entities[entityIndex].controller = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -945,7 +956,7 @@ namespace TR {
|
|||||||
return room.sectors[sx * room.zSectors + sz];
|
return room.sectors[sx * room.zSectors + sz];
|
||||||
}
|
}
|
||||||
|
|
||||||
void getFloorInfo(int roomIndex, int x, int z, FloorInfo &info) const {
|
void getFloorInfo(int roomIndex, int x, int z, FloorInfo &info, bool actual = false, int prevRoom = 0xFF) const {
|
||||||
int dx, dz;
|
int dx, dz;
|
||||||
Room::Sector &s = getSector(roomIndex, x, z, dx, dz);
|
Room::Sector &s = getSector(roomIndex, x, z, dx, dz);
|
||||||
|
|
||||||
@@ -961,6 +972,20 @@ namespace TR {
|
|||||||
info.trigger = Trigger::ACTIVATE;
|
info.trigger = Trigger::ACTIVATE;
|
||||||
info.trigCmdCount = 0;
|
info.trigCmdCount = 0;
|
||||||
|
|
||||||
|
if (actual) {
|
||||||
|
if (info.roomBelow != 0xFF && info.roomBelow != prevRoom) {
|
||||||
|
FloorInfo tmp;
|
||||||
|
getFloorInfo(info.roomBelow, x, z, tmp, true, roomIndex);
|
||||||
|
info.floor = tmp.floor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.roomAbove != 0xFF && info.roomAbove != prevRoom) {
|
||||||
|
FloorInfo tmp;
|
||||||
|
getFloorInfo(info.roomAbove, x, z, tmp, true, roomIndex);
|
||||||
|
info.ceiling = tmp.ceiling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!s.floorIndex) return;
|
if (!s.floorIndex) return;
|
||||||
|
|
||||||
FloorData *fd = &floors[s.floorIndex];
|
FloorData *fd = &floors[s.floorIndex];
|
||||||
@@ -1012,6 +1037,9 @@ namespace TR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} while (!cmd.end);
|
} while (!cmd.end);
|
||||||
|
|
||||||
|
if (actual && info.roomNext != 0xFF)
|
||||||
|
getFloorInfo(info.roomNext, x, z, info, actual, prevRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // struct Level
|
}; // struct Level
|
||||||
|
408
src/lara.h
408
src/lara.h
@@ -14,6 +14,10 @@
|
|||||||
#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 LARA_HANG_OFFSET 735
|
||||||
|
|
||||||
|
#define PICKUP_FRAME_GROUND 40
|
||||||
|
#define PICKUP_FRAME_UNDERWATER 16
|
||||||
|
|
||||||
#define MAX_TRIGGER_ACTIONS 64
|
#define MAX_TRIGGER_ACTIONS 64
|
||||||
|
|
||||||
@@ -22,6 +26,7 @@
|
|||||||
struct Lara : Controller {
|
struct Lara : Controller {
|
||||||
|
|
||||||
ActionCommand actionList[MAX_TRIGGER_ACTIONS];
|
ActionCommand actionList[MAX_TRIGGER_ACTIONS];
|
||||||
|
int lastPickUp;
|
||||||
|
|
||||||
// http://www.tombraiderforums.com/showthread.php?t=148859
|
// http://www.tombraiderforums.com/showthread.php?t=148859
|
||||||
enum {
|
enum {
|
||||||
@@ -29,7 +34,8 @@ struct Lara : Controller {
|
|||||||
|
|
||||||
ANIM_CLIMB_JUMP = 26,
|
ANIM_CLIMB_JUMP = 26,
|
||||||
|
|
||||||
ANIM_HANG_UP = 29,
|
ANIM_HANG_FALL = 28,
|
||||||
|
ANIM_HANG_WALL = 29,
|
||||||
|
|
||||||
ANIM_FALL = 34,
|
ANIM_FALL = 34,
|
||||||
ANIM_SMASH_JUMP = 32,
|
ANIM_SMASH_JUMP = 32,
|
||||||
@@ -51,7 +57,7 @@ struct Lara : Controller {
|
|||||||
|
|
||||||
ANIM_SLIDE_FORTH = 70,
|
ANIM_SLIDE_FORTH = 70,
|
||||||
|
|
||||||
ANIM_HANG_FORTH = 96,
|
ANIM_HANG = 96,
|
||||||
|
|
||||||
ANIM_STAND_NORMAL = 103,
|
ANIM_STAND_NORMAL = 103,
|
||||||
|
|
||||||
@@ -66,6 +72,8 @@ struct Lara : Controller {
|
|||||||
ANIM_HIT_RIGHT = 128,
|
ANIM_HIT_RIGHT = 128,
|
||||||
ANIM_STAND_ROLL_BEGIN = 146,
|
ANIM_STAND_ROLL_BEGIN = 146,
|
||||||
ANIM_STAND_ROLL_END = 147,
|
ANIM_STAND_ROLL_END = 147,
|
||||||
|
|
||||||
|
ANIM_HANG_NOWALL = 150,
|
||||||
};
|
};
|
||||||
|
|
||||||
// http://www.tombraiderforums.com/showthread.php?t=211681
|
// http://www.tombraiderforums.com/showthread.php?t=211681
|
||||||
@@ -93,7 +101,7 @@ struct Lara : Controller {
|
|||||||
STATE_FAST_TURN,
|
STATE_FAST_TURN,
|
||||||
STATE_STEP_RIGHT,
|
STATE_STEP_RIGHT,
|
||||||
STATE_STEP_LEFT,
|
STATE_STEP_LEFT,
|
||||||
STATE_ROLL,
|
STATE_ROLL_1,
|
||||||
STATE_SLIDE,
|
STATE_SLIDE,
|
||||||
STATE_BACK_JUMP,
|
STATE_BACK_JUMP,
|
||||||
STATE_RIGHT_JUMP,
|
STATE_RIGHT_JUMP,
|
||||||
@@ -115,7 +123,7 @@ struct Lara : Controller {
|
|||||||
STATE_USE_KEY,
|
STATE_USE_KEY,
|
||||||
STATE_USE_PUZZLE,
|
STATE_USE_PUZZLE,
|
||||||
STATE_UNDERWATER_DEATH,
|
STATE_UNDERWATER_DEATH,
|
||||||
STATE_ROLL_45,
|
STATE_ROLL_2,
|
||||||
STATE_SPECIAL,
|
STATE_SPECIAL,
|
||||||
STATE_SURF_BACK,
|
STATE_SURF_BACK,
|
||||||
STATE_SURF_LEFT,
|
STATE_SURF_LEFT,
|
||||||
@@ -129,18 +137,38 @@ struct Lara : Controller {
|
|||||||
STATE_MAX };
|
STATE_MAX };
|
||||||
|
|
||||||
Lara(TR::Level *level, int entity) : Controller(level, entity) {
|
Lara(TR::Level *level, int entity) : Controller(level, entity) {
|
||||||
|
#ifdef _DEBUG
|
||||||
/*
|
/*
|
||||||
|
// gym
|
||||||
|
pos = vec3(43182, 2473, 51556);
|
||||||
|
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||||
|
getEntity().room = 12;
|
||||||
|
*/
|
||||||
|
|
||||||
// level 2 (pool)
|
// level 2 (pool)
|
||||||
pos = vec3(70067, -256, 29104);
|
pos = vec3(70067, -256, 29104);
|
||||||
angle = vec3(0.0f, -0.68f, 0.0f);
|
angle = vec3(0.0f, -0.68f, 0.0f);
|
||||||
getEntity().room = 15;
|
getEntity().room = 15;
|
||||||
*/
|
|
||||||
/*
|
/*
|
||||||
// level 2 (wolf)
|
// level 2 (wolf)
|
||||||
pos = vec3(75671, -1024, 22862);
|
pos = vec3(75671, -1024, 22862);
|
||||||
angle = vec3(0.0f, -PI * 0.25f, 0.0f);
|
angle = vec3(0.0f, -PI * 0.25f, 0.0f);
|
||||||
getEntity().room = 13;
|
getEntity().room = 13;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// level 2 (room 1)
|
||||||
|
pos = vec3(31400, -2560, 25200);
|
||||||
|
angle = vec3(0.0f, PI, 0.0f);
|
||||||
|
getEntity().room = 43;
|
||||||
|
|
||||||
|
// level 2 (medikit)
|
||||||
|
pos = vec3(30800, -7936, 22131);
|
||||||
|
angle = vec3(0.0f, 0.0f, 0.0f);
|
||||||
|
getEntity().room = 58;
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// level 3a
|
// level 3a
|
||||||
pos = vec3(41015, 3584, 34494);
|
pos = vec3(41015, 3584, 34494);
|
||||||
@@ -153,7 +181,8 @@ struct Lara : Controller {
|
|||||||
angle = vec3(0.0f, PI, 0.0f);
|
angle = vec3(0.0f, PI, 0.0f);
|
||||||
getEntity().room = 14;
|
getEntity().room = 14;
|
||||||
*/
|
*/
|
||||||
// updateEntity();
|
updateEntity();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool waterOut(int &outState) {
|
bool waterOut(int &outState) {
|
||||||
@@ -164,7 +193,9 @@ struct Lara : Controller {
|
|||||||
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.z, infoCur),
|
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.z, infoCur),
|
||||||
level->getFloorInfo(infoCur.roomAbove, (int)dst.x, (int)dst.z, infoDst);
|
level->getFloorInfo(infoCur.roomAbove, (int)dst.x, (int)dst.z, infoDst);
|
||||||
|
|
||||||
if (infoDst.roomBelow == 0xFF && pos.y - infoDst.floor <= 256) { // possibility check
|
int h = int(pos.y - infoDst.floor);
|
||||||
|
|
||||||
|
if (h > 0 && h <= 256) { // possibility check
|
||||||
if (!setState(STATE_STOP)) { // can't set water out state
|
if (!setState(STATE_STOP)) { // can't set water out state
|
||||||
outState = STATE_STOP;
|
outState = STATE_STOP;
|
||||||
return true;
|
return true;
|
||||||
@@ -183,7 +214,55 @@ struct Lara : Controller {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void performTrigger() {
|
bool doPickUp() {
|
||||||
|
int room = getRoomIndex();
|
||||||
|
TR::Entity &e = getEntity();
|
||||||
|
|
||||||
|
for (int i = 0; i < level->entitiesCount; i++) {
|
||||||
|
TR::Entity &item = level->entities[i];
|
||||||
|
if (item.room == room && !item.flags.invisible) {
|
||||||
|
if (abs(item.x - e.x) > 256 || abs(item.z - e.z) > 256)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (item.type) {
|
||||||
|
case TR::Entity::WEAPON_PISTOLS :
|
||||||
|
case TR::Entity::WEAPON_SHOTGUN :
|
||||||
|
case TR::Entity::WEAPON_MAGNUMS :
|
||||||
|
case TR::Entity::WEAPON_UZIS :
|
||||||
|
case TR::Entity::AMMO_SHOTGUN :
|
||||||
|
case TR::Entity::AMMO_MAGNUMS :
|
||||||
|
case TR::Entity::AMMO_UZIS :
|
||||||
|
case TR::Entity::MEDIKIT_SMALL :
|
||||||
|
case TR::Entity::MEDIKIT_BIG :
|
||||||
|
case TR::Entity::PUZZLE_1 :
|
||||||
|
case TR::Entity::PUZZLE_2 :
|
||||||
|
case TR::Entity::PUZZLE_3 :
|
||||||
|
case TR::Entity::PUZZLE_4 :
|
||||||
|
case TR::Entity::PICKUP :
|
||||||
|
case TR::Entity::KEY_1 :
|
||||||
|
case TR::Entity::KEY_2 :
|
||||||
|
case TR::Entity::KEY_3 :
|
||||||
|
case TR::Entity::KEY_4 :
|
||||||
|
case TR::Entity::ARTIFACT :
|
||||||
|
lastPickUp = i;
|
||||||
|
angle.x = 0.0f;
|
||||||
|
pos.x = item.x;
|
||||||
|
pos.y = item.y;
|
||||||
|
pos.z = item.z;
|
||||||
|
if (stand == STAND_UNDERWATER) { // TODO: lerp to pos/angle
|
||||||
|
pos = pos - getDir() * 256.0f;
|
||||||
|
pos.y -= 256;
|
||||||
|
}
|
||||||
|
updateEntity();
|
||||||
|
return true;
|
||||||
|
default : ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doTrigger() {
|
||||||
if (actionCommand) return;
|
if (actionCommand) return;
|
||||||
|
|
||||||
TR::Entity &e = getEntity();
|
TR::Entity &e = getEntity();
|
||||||
@@ -191,8 +270,8 @@ struct Lara : Controller {
|
|||||||
level->getFloorInfo(e.room, e.x, e.z, info);
|
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||||
|
|
||||||
if (!info.trigCmdCount) return; // has no trigger
|
if (!info.trigCmdCount) return; // has no trigger
|
||||||
bool isActive = (level->entities[info.trigCmd[0].args].flags & ENTITY_FLAG_ACTIVE);
|
bool isActive = (level->entities[info.trigCmd[0].args].flags.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 && isActive) return; // once trigger is already activated
|
||||||
|
|
||||||
int actionState = state;
|
int actionState = state;
|
||||||
switch (info.trigger) {
|
switch (info.trigger) {
|
||||||
@@ -243,7 +322,7 @@ struct Lara : Controller {
|
|||||||
Controller *controller = this;
|
Controller *controller = this;
|
||||||
for (int i = 0; i < info.trigCmdCount; i++) {
|
for (int i = 0; i < info.trigCmdCount; i++) {
|
||||||
if (!controller) {
|
if (!controller) {
|
||||||
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].id);
|
LOG("! next activation entity %d has no controller\n", level->entities[info.trigCmd[i].args].type);
|
||||||
playSound(TR::SND_NO);
|
playSound(TR::SND_NO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -263,7 +342,6 @@ struct Lara : Controller {
|
|||||||
actionItem++;
|
actionItem++;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("perform\n");
|
|
||||||
actionList[0].next = &actionList[1];
|
actionList[0].next = &actionList[1];
|
||||||
actionCommand = &actionList[0];
|
actionCommand = &actionList[0];
|
||||||
|
|
||||||
@@ -316,31 +394,52 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual Stand getStand() {
|
virtual Stand getStand() {
|
||||||
if (stand == STAND_HANG && (mask & ACTION))
|
if (state == STATE_HANG || state == STATE_HANG_LEFT || state == STATE_HANG_RIGHT) {
|
||||||
return stand;
|
if (mask & ACTION)
|
||||||
|
return STAND_HANG;
|
||||||
|
setAnimation(ANIM_HANG_FALL);
|
||||||
|
velocity = vec3(0.0f);
|
||||||
|
pos.y += 128.0f;
|
||||||
|
updateEntity();
|
||||||
|
return STAND_AIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == STATE_HANDSTAND || state == STATE_HANG_UP)
|
||||||
|
return STAND_HANG;
|
||||||
|
|
||||||
if (stand == STAND_ONWATER && state != STATE_DIVE && state != STATE_STOP)
|
if (stand == STAND_ONWATER && state != STATE_DIVE && state != STATE_STOP)
|
||||||
return stand;
|
return stand;
|
||||||
|
|
||||||
if (getRoom().flags & TR::ROOM_FLAG_WATER)
|
if (getRoom().flags.water)
|
||||||
return STAND_UNDERWATER; // TODO: ONWATER
|
return STAND_UNDERWATER; // TODO: ONWATER
|
||||||
|
|
||||||
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, true);
|
||||||
|
|
||||||
if (stand == STAND_SLIDE || (stand == STAND_AIR && velocity.y > 0) || stand == STAND_GROUND) {
|
if (stand == STAND_SLIDE || (stand == STAND_AIR && velocity.y > 0) || stand == STAND_GROUND) {
|
||||||
if (e.y + 8 >= info.floor && (abs(info.slantX) > 2 || abs(info.slantZ) > 2)) {
|
if (e.y + 8 >= info.floor && (abs(info.slantX) > 2 || abs(info.slantZ) > 2)) {
|
||||||
if (stand == STAND_AIR)
|
if (stand == STAND_AIR)
|
||||||
playSound(TR::SND_LANDING);
|
playSound(TR::SND_LANDING);
|
||||||
|
pos.y = info.floor;
|
||||||
|
updateEntity();
|
||||||
|
|
||||||
|
if (stand == STAND_GROUND || stand == STAND_AIR)
|
||||||
|
slideStart();
|
||||||
|
|
||||||
return STAND_SLIDE;
|
return STAND_SLIDE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int extra = stand != STAND_AIR ? 256 : 0;
|
int extra = stand != STAND_AIR ? 256 : 0;
|
||||||
|
|
||||||
if (stand != STAND_HANG && info.roomBelow == 0xFF && e.y + extra >= info.floor)
|
if (e.y + extra >= info.floor) {
|
||||||
|
if (stand != STAND_GROUND) {
|
||||||
|
pos.y = info.floor;
|
||||||
|
updateEntity();
|
||||||
|
}
|
||||||
return STAND_GROUND;
|
return STAND_GROUND;
|
||||||
|
}
|
||||||
|
|
||||||
return STAND_AIR;
|
return STAND_AIR;
|
||||||
}
|
}
|
||||||
@@ -354,18 +453,37 @@ struct Lara : Controller {
|
|||||||
virtual int getStateAir() {
|
virtual int getStateAir() {
|
||||||
angle.x = 0.0f;
|
angle.x = 0.0f;
|
||||||
|
|
||||||
|
if (state == STATE_REACH && getDir().dot(vec3(velocity.x, 0.0f, velocity.z)) < 0)
|
||||||
|
velocity.x = velocity.z = 0.0f;
|
||||||
|
|
||||||
if ((state == STATE_REACH || state == STATE_UP_JUMP) && (mask & ACTION)) {
|
if ((state == STATE_REACH || state == STATE_UP_JUMP) && (mask & ACTION)) {
|
||||||
|
|
||||||
|
if (state == STATE_REACH && velocity.y < 0.0f)
|
||||||
|
return state;
|
||||||
|
|
||||||
vec3 p = pos + getDir() * 128.0f;
|
vec3 p = pos + getDir() * 128.0f;
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.z, info);
|
|
||||||
|
info.roomAbove = getRoomIndex();
|
||||||
|
level->getFloorInfo(info.roomAbove, (int)pos.x, (int)pos.z, info);
|
||||||
|
if (info.roomAbove == 0xFF)
|
||||||
|
info.roomAbove = getRoomIndex();
|
||||||
|
|
||||||
if (abs(int(info.floor - (p.y - 768.0f + 64.0f))) < 32) {
|
do {
|
||||||
|
level->getFloorInfo(info.roomAbove, (int)p.x, (int)p.z, info, true);
|
||||||
|
} while (info.ceiling > p.y - LARA_HANG_OFFSET && info.roomAbove != 0xFF);
|
||||||
|
|
||||||
|
if (abs(int(info.floor - (p.y - LARA_HANG_OFFSET))) < 16) {
|
||||||
turnToWall();
|
turnToWall();
|
||||||
pos = pos - getDir() * 128.0f; // TODO: collision wall offset
|
pos = pos - getDir() * 96.0f; // TODO: collision wall offset
|
||||||
pos.y = info.floor + 768.0f - 64.0f;
|
pos.y = info.floor + LARA_HANG_OFFSET;
|
||||||
stand = STAND_HANG;
|
|
||||||
updateEntity();
|
updateEntity();
|
||||||
return setAnimation(state == STATE_HANG ? ANIM_HANG_UP : ANIM_HANG_FORTH);
|
|
||||||
|
stand = STAND_HANG;
|
||||||
|
if (state == STATE_REACH) {
|
||||||
|
return STATE_HANG; // TODO: ANIM_HANG_WALL / ANIM_HANG_NOWALL
|
||||||
|
} else
|
||||||
|
return setAnimation(ANIM_HANG, -15);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,14 +491,17 @@ struct Lara : Controller {
|
|||||||
if (mask & ACTION) return STATE_REACH;
|
if (mask & ACTION) return STATE_REACH;
|
||||||
if ((mask & (FORTH | WALK)) == (FORTH | WALK)) return STATE_SWAN_DIVE;
|
if ((mask & (FORTH | WALK)) == (FORTH | WALK)) return STATE_SWAN_DIVE;
|
||||||
} else
|
} else
|
||||||
if (state != STATE_SWAN_DIVE && state != STATE_REACH && state != STATE_FALL && state != STATE_UP_JUMP && state != STATE_BACK_JUMP && state != STATE_LEFT_JUMP && state != STATE_RIGHT_JUMP && state != STATE_ROLL)
|
if (state != STATE_SWAN_DIVE && state != STATE_REACH && state != STATE_FALL && state != STATE_UP_JUMP && state != STATE_BACK_JUMP && state != STATE_LEFT_JUMP && state != STATE_RIGHT_JUMP && state != STATE_ROLL_1 && state != STATE_ROLL_2)
|
||||||
return setAnimation(ANIM_FALL);
|
return setAnimation(ANIM_FALL);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int getStateGround() {
|
virtual int getStateGround() {
|
||||||
angle.x = 0.0f;
|
angle.x = 0.0f;
|
||||||
|
|
||||||
|
if (mask == ACTION && doPickUp())
|
||||||
|
return STATE_PICK_UP;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// hit test
|
// hit test
|
||||||
@@ -431,18 +552,20 @@ struct Lara : Controller {
|
|||||||
if ( (mask & (FORTH | ACTION)) == (FORTH | ACTION) && (animIndex == ANIM_STAND || animIndex == ANIM_STAND_NORMAL) ) {
|
if ( (mask & (FORTH | ACTION)) == (FORTH | ACTION) && (animIndex == ANIM_STAND || animIndex == ANIM_STAND_NORMAL) ) {
|
||||||
vec3 p = pos + getDir() * 64.0f;
|
vec3 p = pos + getDir() * 64.0f;
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.z, info);
|
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.z, info, true);
|
||||||
int h = (int)pos.y - info.floor;
|
int h = (int)pos.y - info.floor;
|
||||||
|
|
||||||
int aIndex = animIndex;
|
int aIndex = animIndex;
|
||||||
if (h < 2 * 256 - 16)
|
if (h < 256 + 128) {
|
||||||
; // do nothing
|
; // do nothing
|
||||||
else if (h <= 2 * 256 + 16)
|
} else if (h <= 2 * 256 + 128) {
|
||||||
aIndex = ANIM_CLIMB_2;
|
aIndex = ANIM_CLIMB_2;
|
||||||
else if (h <= 3 * 256 + 16)
|
pos.y = info.floor + 512;
|
||||||
|
} else if (h <= 3 * 256 + 128) {
|
||||||
aIndex = ANIM_CLIMB_3;
|
aIndex = ANIM_CLIMB_3;
|
||||||
else if (h <= 7 * 256 + 16)
|
pos.y = info.floor + 768;
|
||||||
aIndex = ANIM_CLIMB_JUMP;
|
} else if (h <= 7 * 256 + 128)
|
||||||
|
aIndex = ANIM_CLIMB_JUMP;
|
||||||
|
|
||||||
if (aIndex != animIndex) {
|
if (aIndex != animIndex) {
|
||||||
turnToWall();
|
turnToWall();
|
||||||
@@ -459,8 +582,7 @@ struct Lara : Controller {
|
|||||||
return STATE_STOP;
|
return STATE_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int getStateSlide() {
|
void slideStart() {
|
||||||
|
|
||||||
TR::Entity &e = getEntity();
|
TR::Entity &e = getEntity();
|
||||||
|
|
||||||
if (state != STATE_SLIDE && state != STATE_SLIDE_BACK) {
|
if (state != STATE_SLIDE && state != STATE_SLIDE_BACK) {
|
||||||
@@ -484,29 +606,40 @@ struct Lara : Controller {
|
|||||||
|
|
||||||
angle.y = dir;
|
angle.y = dir;
|
||||||
updateEntity();
|
updateEntity();
|
||||||
return setAnimation(aIndex);
|
setAnimation(aIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mask & JUMP) {
|
virtual int getStateSlide() {
|
||||||
stand = STAND_GROUND;
|
if (mask & JUMP)
|
||||||
pos.y -= 16;
|
|
||||||
updateEntity();
|
|
||||||
return state == STATE_SLIDE ? STATE_FORWARD_JUMP : STATE_BACK_JUMP;
|
return state == STATE_SLIDE ? STATE_FORWARD_JUMP : STATE_BACK_JUMP;
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int getStateHang() {
|
virtual int getStateHang() {
|
||||||
if (mask & LEFT) return STATE_HANG_LEFT;
|
if (mask & LEFT) return STATE_HANG_LEFT;
|
||||||
if (mask & RIGHT) return STATE_HANG_RIGHT;
|
if (mask & RIGHT) return STATE_HANG_RIGHT;
|
||||||
if (mask & FORTH) return (mask & WALK) ? STATE_HANDSTAND : STATE_HANG_UP;
|
if (mask & FORTH) {
|
||||||
|
// possibility check
|
||||||
|
TR::Level::FloorInfo info;
|
||||||
|
vec3 p = pos + getDir() * 128.0f;
|
||||||
|
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.z, info, true);
|
||||||
|
if (info.floor - info.ceiling >= 768) {
|
||||||
|
LOG("%d %d %d\n", info.floor, info.ceiling, info.floor - info.ceiling);
|
||||||
|
return (mask & WALK) ? STATE_HANDSTAND : STATE_HANG_UP;
|
||||||
|
}
|
||||||
|
}
|
||||||
return STATE_HANG;
|
return STATE_HANG;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int getStateUnderwater() {
|
virtual int getStateUnderwater() {
|
||||||
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH)
|
if (mask == ACTION && doPickUp())
|
||||||
|
return STATE_PICK_UP;
|
||||||
|
|
||||||
|
if (state == STATE_FORWARD_JUMP || state == STATE_UP_JUMP || state == STATE_BACK_JUMP || state == STATE_LEFT_JUMP || state == STATE_RIGHT_JUMP || state == STATE_FALL || state == STATE_REACH) {
|
||||||
|
addSprite(level, TR::Entity::Type::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
|
||||||
return setAnimation(ANIM_WATER_FALL);
|
return setAnimation(ANIM_WATER_FALL);
|
||||||
|
}
|
||||||
|
|
||||||
if (state == STATE_SWAN_DIVE) {
|
if (state == STATE_SWAN_DIVE) {
|
||||||
angle.x = -PI * 0.5f;
|
angle.x = -PI * 0.5f;
|
||||||
@@ -550,7 +683,7 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual int getStateDefault() {
|
virtual int getStateDefault() {
|
||||||
if (state == STATE_DIVE) return state;
|
if (state == STATE_DIVE || (state == STATE_RUN && (mask & JUMP)) ) return state;
|
||||||
switch (stand) {
|
switch (stand) {
|
||||||
case STAND_GROUND : return STATE_STOP;
|
case STAND_GROUND : return STATE_STOP;
|
||||||
case STAND_HANG : return STATE_HANG;
|
case STAND_HANG : return STATE_HANG;
|
||||||
@@ -580,7 +713,7 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void updateState() {
|
virtual void updateState() {
|
||||||
performTrigger();
|
doTrigger();
|
||||||
|
|
||||||
TR::Animation *anim = &level->anims[animIndex];
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
|
||||||
@@ -595,11 +728,11 @@ struct Lara : Controller {
|
|||||||
if (Input::down[ikEnter]) {
|
if (Input::down[ikEnter]) {
|
||||||
if (!lState) {
|
if (!lState) {
|
||||||
lState = true;
|
lState = true;
|
||||||
/*
|
|
||||||
static int snd_id = 0;//160;
|
static int snd_id = 0;//160;
|
||||||
playSound(snd_id);
|
/*playSound(snd_id);
|
||||||
*/
|
*/
|
||||||
// setAnimation(snd_id);
|
//setAnimation(snd_id);
|
||||||
//LOG("sound: %d\n", snd_id++);
|
//LOG("sound: %d\n", snd_id++);
|
||||||
|
|
||||||
LOG("state: %d\n", anim->state);
|
LOG("state: %d\n", anim->state);
|
||||||
@@ -684,6 +817,17 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual void doCustomCommand(int curFrame, int prevFrame) {
|
||||||
|
if (state == STATE_PICK_UP) {
|
||||||
|
if (!level->entities[lastPickUp].flags.invisible) {
|
||||||
|
int pickupFrame = stand == STAND_GROUND ? PICKUP_FRAME_GROUND : PICKUP_FRAME_UNDERWATER;
|
||||||
|
if (curFrame >= pickupFrame)
|
||||||
|
level->entities[lastPickUp].flags.invisible = true; // TODO: add to inventory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual void updateVelocity() {
|
virtual void updateVelocity() {
|
||||||
// calculate moving speed
|
// calculate moving speed
|
||||||
float dt = Core::deltaTime * 30.0f;
|
float dt = Core::deltaTime * 30.0f;
|
||||||
@@ -723,7 +867,13 @@ struct Lara : Controller {
|
|||||||
} else {
|
} else {
|
||||||
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);
|
if (stand == STAND_HANG) {
|
||||||
|
vec3 p = pos + getDir() * 128.0f;
|
||||||
|
level->getFloorInfo(e.room, (int)p.x, (int)p.z, info);
|
||||||
|
if (info.roomAbove != 0xFF && info.floor >= e.y - LARA_HANG_OFFSET)
|
||||||
|
level->getFloorInfo(info.roomAbove, (int)p.x, (int)p.z, info);
|
||||||
|
} else
|
||||||
|
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||||
|
|
||||||
vec3 v(sinf(angleExt), 0.0f, cosf(angleExt));
|
vec3 v(sinf(angleExt), 0.0f, cosf(angleExt));
|
||||||
velocity = info.getSlant(v) * speed;
|
velocity = info.getSlant(v) * speed;
|
||||||
@@ -747,8 +897,31 @@ struct Lara : Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void move() { // TORO: as part of Controller
|
virtual void checkRoom() {
|
||||||
if (velocity.length() < EPS) return;
|
TR::Level::FloorInfo info;
|
||||||
|
TR::Entity &e = getEntity();
|
||||||
|
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||||
|
|
||||||
|
if (info.roomNext != 0xFF)
|
||||||
|
e.room = info.roomNext;
|
||||||
|
|
||||||
|
if (info.roomBelow != 0xFF && e.y > info.floor)
|
||||||
|
e.room = info.roomBelow;
|
||||||
|
|
||||||
|
if (info.roomAbove != 0xFF && e.y <= info.ceiling) {
|
||||||
|
if (stand == STAND_UNDERWATER && !level->rooms[info.roomAbove].flags.water) {
|
||||||
|
stand = STAND_ONWATER;
|
||||||
|
velocity.y = 0;
|
||||||
|
pos.y = info.ceiling;
|
||||||
|
updateEntity();
|
||||||
|
} else
|
||||||
|
if (stand != STAND_ONWATER)
|
||||||
|
e.room = info.roomAbove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void move() { // TODO: sphere / bbox collision
|
||||||
|
if (velocity.length() < 0.001f) return;
|
||||||
|
|
||||||
vec3 offset = velocity * Core::deltaTime * 30.0f;
|
vec3 offset = velocity * Core::deltaTime * 30.0f;
|
||||||
|
|
||||||
@@ -756,96 +929,107 @@ struct Lara : Controller {
|
|||||||
pos = pos + offset;
|
pos = pos + offset;
|
||||||
|
|
||||||
TR::Level::FloorInfo info;
|
TR::Level::FloorInfo info;
|
||||||
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.z, info);
|
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.z, info, true);
|
||||||
|
|
||||||
int delta;
|
// get frame to get height
|
||||||
int d = getOverlap((int)p.x, (int)p.y, (int)p.z, (int)pos.x, (int)pos.z, delta);
|
TR::Animation *anim = &level->anims[animIndex];
|
||||||
|
|
||||||
int height = getHeight();
|
bool canPassGap = (info.floor - info.ceiling) >= (stand == STAND_GROUND ? 768 : 512);
|
||||||
bool canPassGap;
|
float f = info.floor - pos.y;
|
||||||
|
float c = pos.y - info.ceiling;
|
||||||
|
|
||||||
float h = info.floor - pos.y;
|
if (canPassGap)
|
||||||
|
switch (stand) {
|
||||||
switch (stand) {
|
case STAND_GROUND : {
|
||||||
case STAND_AIR :
|
if (state == STATE_WALK || state == STATE_BACK)
|
||||||
canPassGap = ((int)p.y - d) <= 512 && (info.roomAbove != 0xFF || (pos.y - height - info.ceiling > -256));
|
canPassGap = fabsf(f) <= (256.0f + 128.0f);
|
||||||
break;
|
|
||||||
case STAND_UNDERWATER :
|
|
||||||
canPassGap = ((int)p.y - d) < 128;
|
|
||||||
break;
|
|
||||||
case STAND_ONWATER : {
|
|
||||||
canPassGap = info.roomAbove != 0xFF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default : // TODO: height
|
|
||||||
if (state == STATE_WALK || state == STATE_BACK)
|
|
||||||
canPassGap = h >= -256 && h <= 256;
|
|
||||||
else
|
|
||||||
if (state == STATE_STEP_LEFT || state == STATE_STEP_RIGHT)
|
|
||||||
canPassGap = h >= -128 && h <= 128;
|
|
||||||
else
|
else
|
||||||
canPassGap = h >= -256 - 16;
|
if (state == STATE_STEP_LEFT || state == STATE_STEP_RIGHT)
|
||||||
}
|
canPassGap = fabsf(f) <= (128.0f + 64.0f);
|
||||||
|
else
|
||||||
|
canPassGap = f >= -(256 + 128);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STAND_UNDERWATER :
|
||||||
|
canPassGap = f > 0.0f && c > 0.0f;
|
||||||
|
break;
|
||||||
|
case STAND_AIR : {
|
||||||
|
int fSize = sizeof(TR::AnimFrame) + getModel().mCount * sizeof(uint16) * 2;
|
||||||
|
TR::AnimFrame *frame = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + (int(animTime * 30.0f / anim->frameRate) * fSize) / 2)];
|
||||||
|
|
||||||
TR::Animation *anim = &level->anims[animIndex];
|
f = info.floor - (p.y + frame->box.maxY);
|
||||||
int frame = int(animTime * 30.0f);
|
c = (p.y + frame->box.minY) - info.ceiling;
|
||||||
bool left = (anim->frameEnd - anim->frameStart) / 2 > frame;
|
canPassGap = f >= -256 && c >= (state == STATE_UP_JUMP ? 0.0f : -256);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STAND_ONWATER : {
|
||||||
|
canPassGap = (info.floor - p.y) >= 1.0f && c >= 1.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default : ;
|
||||||
|
}
|
||||||
|
|
||||||
if (d == NO_OVERLAP || !canPassGap) {
|
bool isLeftFoot = (anim->frameEnd - anim->frameStart) / 2 > int(animTime * 30.0f);
|
||||||
|
|
||||||
|
if (!canPassGap) {
|
||||||
pos = p; // TODO: use smart ejection
|
pos = p; // TODO: use smart ejection
|
||||||
|
|
||||||
// hit the wall
|
// hit the wall
|
||||||
switch (stand) {
|
switch (stand) {
|
||||||
case STAND_AIR :
|
case STAND_AIR :
|
||||||
if (state != STATE_UP_JUMP && state != STATE_REACH) {
|
if (state == STATE_UP_JUMP || state == STATE_REACH) {
|
||||||
|
velocity.x = velocity.z = 0.0f;
|
||||||
|
if (c <= 0 && offset.y < 0.0f) offset.y = velocity.y = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (velocity.x != 0.0f || velocity.z != 0.0f) {
|
||||||
setAnimation(ANIM_SMASH_JUMP);
|
setAnimation(ANIM_SMASH_JUMP);
|
||||||
velocity.x = -velocity.x * 0.5f;
|
velocity.x = -velocity.x * 0.5f;
|
||||||
velocity.z = -velocity.z * 0.5f;
|
velocity.z = -velocity.z * 0.5f;
|
||||||
velocity.y = 0.0f;
|
if (offset.y < 0.0f)
|
||||||
} else {
|
offset.y = velocity.y = 0.0f;
|
||||||
velocity.x = velocity.z = 0.0f;
|
|
||||||
pos.y = p.y + offset.y;
|
|
||||||
updateEntity();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pos.y = p.y + offset.y;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case STAND_GROUND :
|
case STAND_GROUND :
|
||||||
if (delta <= -256 * 4 && state == STATE_RUN)
|
case STAND_HANG :
|
||||||
setAnimation(left ? ANIM_SMASH_RUN_LEFT : ANIM_SMASH_RUN_RIGHT);
|
if (f <= -(256 * 3 - 128) && state == STATE_RUN)
|
||||||
else
|
setAnimation(isLeftFoot ? ANIM_SMASH_RUN_LEFT : ANIM_SMASH_RUN_RIGHT);
|
||||||
|
else if (stand == STAND_HANG)
|
||||||
|
setAnimation(ANIM_HANG, -21);
|
||||||
|
else if (state != STATE_ROLL_1 && state != STATE_ROLL_2)
|
||||||
setAnimation(ANIM_STAND);
|
setAnimation(ANIM_STAND);
|
||||||
velocity.x = velocity.z = 0.0f;
|
velocity.x = velocity.z = 0.0f;
|
||||||
break;
|
break;
|
||||||
default : ;// no smash animation
|
default : ;// no smash animation
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
if (state == STATE_RUN || state == STATE_WALK || state == STATE_BACK || state == STATE_ROLL) {
|
if (stand == STAND_GROUND) {
|
||||||
if (h <= -128 && h >= -256) { // ascend
|
int h = int(info.floor - pos.y);
|
||||||
if (state == STATE_RUN) setAnimation(left ? ANIM_RUN_ASCEND_LEFT : ANIM_RUN_ASCEND_RIGHT);
|
|
||||||
if (state == STATE_WALK) setAnimation(left ? ANIM_WALK_ASCEND_LEFT : ANIM_WALK_ASCEND_RIGHT);
|
|
||||||
pos.y = info.floor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h >= 128 && h <= 256 && (state == STATE_WALK || state == STATE_BACK)) { // descend
|
if (h >= 256 && state == STATE_FAST_BACK) {
|
||||||
if (state == STATE_WALK) setAnimation(left ? ANIM_WALK_DESCEND_LEFT : ANIM_WALK_DESCEND_RIGHT);
|
|
||||||
if (state == STATE_BACK) setAnimation(left ? ANIM_BACK_DESCEND_LEFT : ANIM_BACK_DESCEND_RIGHT);
|
|
||||||
pos.y = info.floor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h > 0 && (state == STATE_RUN || state == STATE_ROLL)) {
|
|
||||||
pos.y += DESCENT_SPEED * Core::deltaTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == STATE_FAST_BACK) {
|
|
||||||
if (h >= 255) {
|
|
||||||
stand = STAND_AIR;
|
stand = STAND_AIR;
|
||||||
setAnimation(ANIM_FALL);
|
setAnimation(ANIM_FALL);
|
||||||
|
} else if (h >= 128 && (state == STATE_WALK || state == STATE_BACK)) { // descend
|
||||||
|
if (state == STATE_WALK) setAnimation(isLeftFoot ? ANIM_WALK_DESCEND_LEFT : ANIM_WALK_DESCEND_RIGHT);
|
||||||
|
if (state == STATE_BACK) setAnimation(isLeftFoot ? ANIM_BACK_DESCEND_LEFT : ANIM_BACK_DESCEND_RIGHT);
|
||||||
|
pos.y = info.floor;
|
||||||
|
} else if (h > -1.0f) {
|
||||||
|
pos.y = min((float)info.floor, pos.y += DESCENT_SPEED * Core::deltaTime);
|
||||||
|
} else if (h > -128) {
|
||||||
|
pos.y = info.floor;
|
||||||
|
} else if (h >= -(256 + 128) && (state == STATE_RUN || state == STATE_WALK)) { // ascend
|
||||||
|
if (state == STATE_RUN) setAnimation(isLeftFoot ? ANIM_RUN_ASCEND_LEFT : ANIM_RUN_ASCEND_RIGHT);
|
||||||
|
if (state == STATE_WALK) setAnimation(isLeftFoot ? ANIM_WALK_ASCEND_LEFT : ANIM_WALK_ASCEND_RIGHT);
|
||||||
|
pos.y = info.floor;
|
||||||
} else
|
} else
|
||||||
pos.y += DESCENT_SPEED * Core::deltaTime;
|
pos.y = info.floor;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEntity();
|
updateEntity();
|
||||||
}
|
checkRoom();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
39
src/level.h
39
src/level.h
@@ -42,7 +42,7 @@ struct Level {
|
|||||||
|
|
||||||
for (int i = 0; i < level.entitiesCount; i++) {
|
for (int i = 0; i < level.entitiesCount; i++) {
|
||||||
TR::Entity &entity = level.entities[i];
|
TR::Entity &entity = level.entities[i];
|
||||||
switch (entity.id) {
|
switch (entity.type) {
|
||||||
case TR::Entity::LARA :
|
case TR::Entity::LARA :
|
||||||
case TR::Entity::LARA_CUT :
|
case TR::Entity::LARA_CUT :
|
||||||
entity.controller = (lara = new Lara(&level, i));
|
entity.controller = (lara = new Lara(&level, i));
|
||||||
@@ -100,6 +100,7 @@ struct Level {
|
|||||||
case TR::Entity::HOLE_KEY :
|
case TR::Entity::HOLE_KEY :
|
||||||
entity.controller = new Trigger(&level, i, false);
|
entity.controller = new Trigger(&level, i, false);
|
||||||
break;
|
break;
|
||||||
|
default : ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +209,7 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Shader *setRoomShader(const TR::Room &room, float intensity) {
|
Shader *setRoomShader(const TR::Room &room, float intensity) {
|
||||||
if (room.flags & TR::ROOM_FLAG_WATER) {
|
if (room.flags.water) {
|
||||||
Core::color = vec4(0.6f * intensity, 0.9f * intensity, 0.9f * intensity, 1.0f);
|
Core::color = vec4(0.6f * intensity, 0.9f * intensity, 0.9f * intensity, 1.0f);
|
||||||
return shaders[shCaustics];
|
return shaders[shCaustics];
|
||||||
} else {
|
} else {
|
||||||
@@ -231,7 +232,7 @@ struct Level {
|
|||||||
// room static meshes
|
// room static meshes
|
||||||
for (int i = 0; i < room.meshesCount; i++) {
|
for (int i = 0; i < room.meshesCount; i++) {
|
||||||
TR::Room::Mesh &rMesh = room.meshes[i];
|
TR::Room::Mesh &rMesh = room.meshes[i];
|
||||||
if ((rMesh.flags & TR::ROOM_FLAG_VISIBLE)) continue; // skip if already rendered
|
if (rMesh.flags.rendered) continue; // skip if already rendered
|
||||||
|
|
||||||
TR::StaticMesh *sMesh = level.getMeshByID(rMesh.meshID);
|
TR::StaticMesh *sMesh = level.getMeshByID(rMesh.meshID);
|
||||||
ASSERT(sMesh != NULL);
|
ASSERT(sMesh != NULL);
|
||||||
@@ -241,7 +242,7 @@ struct Level {
|
|||||||
sMesh->getBox(false, rMesh.rotation, min, max);
|
sMesh->getBox(false, rMesh.rotation, min, max);
|
||||||
if (!camera->frustum->isVisible(offset + min, offset + max))
|
if (!camera->frustum->isVisible(offset + min, offset + max))
|
||||||
continue;
|
continue;
|
||||||
rMesh.flags |= TR::ROOM_FLAG_VISIBLE;
|
rMesh.flags.rendered = true;
|
||||||
|
|
||||||
// set light parameters
|
// set light parameters
|
||||||
getLight(offset, roomIndex);
|
getLight(offset, roomIndex);
|
||||||
@@ -255,8 +256,8 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// room geometry & sprites
|
// room geometry & sprites
|
||||||
if (!(room.flags & TR::ROOM_FLAG_VISIBLE)) { // skip if already rendered
|
if (!room.flags.rendered) { // skip if already rendered
|
||||||
room.flags |= TR::ROOM_FLAG_VISIBLE;
|
room.flags.rendered = true;
|
||||||
|
|
||||||
Core::lightColor = vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
Core::lightColor = vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
Core::ambient = vec3(1.0f);
|
Core::ambient = vec3(1.0f);
|
||||||
@@ -494,10 +495,10 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void renderEntity(const TR::Entity &entity) {
|
void renderEntity(const TR::Entity &entity) {
|
||||||
if (entity.id < 0) return;
|
if (entity.type == TR::Entity::NONE) return;
|
||||||
|
|
||||||
TR::Room &room = level.rooms[entity.room];
|
TR::Room &room = level.rooms[entity.room];
|
||||||
if (!(room.flags & TR::ROOM_FLAG_VISIBLE)) // check for room visibility
|
if (!room.flags.rendered || entity.flags.invisible) // check for room visibility
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mat4 m = Core::mModel;
|
mat4 m = Core::mModel;
|
||||||
@@ -529,7 +530,7 @@ struct Level {
|
|||||||
time += Core::deltaTime;
|
time += Core::deltaTime;
|
||||||
|
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
if (level.entities[i].id > -1) {
|
if (level.entities[i].type != TR::Entity::NONE) {
|
||||||
Controller *controller = (Controller*)level.entities[i].controller;
|
Controller *controller = (Controller*)level.entities[i].controller;
|
||||||
if (controller)
|
if (controller)
|
||||||
controller->update();
|
controller->update();
|
||||||
@@ -565,10 +566,10 @@ struct Level {
|
|||||||
// clear visible flags for rooms & static meshes
|
// clear visible flags for rooms & static meshes
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
for (int i = 0; i < level.roomsCount; i++) {
|
||||||
TR::Room &room = level.rooms[i];
|
TR::Room &room = level.rooms[i];
|
||||||
room.flags &= ~TR::ROOM_FLAG_VISIBLE; // clear visible flag for room geometry & sprites
|
room.flags.rendered = false; // clear visible flag for room geometry & sprites
|
||||||
|
|
||||||
for (int j = 0; j < room.meshesCount; j++)
|
for (int j = 0; j < room.meshesCount; j++)
|
||||||
room.meshes[j].flags &= ~TR::ROOM_FLAG_VISIBLE; // clear visible flag for room static meshes
|
room.meshes[j].flags.rendered = false; // clear visible flag for room static meshes
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: collision detection for camera
|
// TODO: collision detection for camera
|
||||||
@@ -582,18 +583,30 @@ struct Level {
|
|||||||
static int modelIndex = 0;
|
static int modelIndex = 0;
|
||||||
static bool lastStateK = false;
|
static bool lastStateK = false;
|
||||||
|
|
||||||
|
static int lastEntity = -1;
|
||||||
|
|
||||||
if (Input::down[ikM]) {
|
if (Input::down[ikM]) {
|
||||||
if (!lastStateK) {
|
if (!lastStateK) {
|
||||||
lastStateK = true;
|
lastStateK = true;
|
||||||
// modelIndex = (modelIndex + 1) % level.modelsCount;
|
// modelIndex = (modelIndex + 1) % level.modelsCount;
|
||||||
modelIndex = (modelIndex + 1) % level.spriteSequencesCount;
|
modelIndex = (modelIndex + 1) % level.spriteSequencesCount;
|
||||||
LOG("model: %d %d\n", modelIndex, level.spriteSequences[modelIndex].id);
|
LOG("model: %d %d\n", modelIndex, level.spriteSequences[modelIndex].id);
|
||||||
|
if (lastEntity > -1) {
|
||||||
|
delete level.entities[lastEntity].controller;
|
||||||
|
level.entityRemove(lastEntity);
|
||||||
|
}
|
||||||
|
lastEntity = level.entityAdd(level.models[modelIndex].id, lara->getRoomIndex(), lara->pos.x + 1024, lara->pos.y - 1024, lara->pos.z, lara->getEntity().rotation, -1);
|
||||||
|
level.entities[lastEntity].controller = new Controller(&level, lastEntity);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
lastStateK = false;
|
lastStateK = false;
|
||||||
|
|
||||||
Core::mModel.translate(lara->pos + vec3(512, -512, 0));
|
Core::mModel.translate(lara->pos + vec3(512, -512, 0));
|
||||||
//renderModel(level.models[modelIndex], level.entities[4]);
|
if (lastEntity > -1)
|
||||||
|
renderEntity(level.entities[lastEntity]);
|
||||||
|
// renderModel(level.models[modelIndex], level.entities[4]);
|
||||||
|
*/
|
||||||
|
/*
|
||||||
TR::Entity seq;
|
TR::Entity seq;
|
||||||
seq.modelIndex = -(modelIndex + 1);
|
seq.modelIndex = -(modelIndex + 1);
|
||||||
seq.controller = NULL;
|
seq.controller = NULL;
|
||||||
@@ -607,7 +620,7 @@ struct Level {
|
|||||||
// Debug::Level::portals(level);
|
// Debug::Level::portals(level);
|
||||||
// Debug::Level::meshes(level);
|
// Debug::Level::meshes(level);
|
||||||
// Debug::Level::entities(level);
|
// Debug::Level::entities(level);
|
||||||
Debug::Level::info(level, lara->getEntity());
|
Debug::Level::info(level, lara->getEntity(), (int)lara->state, lara->animIndex, int(lara->animTime * 30.0f));
|
||||||
Debug::end();
|
Debug::end();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@@ -309,12 +309,14 @@ int main() {
|
|||||||
if (time <= lastTime)
|
if (time <= lastTime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
float slow = Input::down[ikR] ? 8.0f : 1.0f;
|
||||||
|
|
||||||
float delta = (time - lastTime) * 0.001f;
|
float delta = (time - lastTime) * 0.001f;
|
||||||
EnterCriticalSection(&sndCS);
|
EnterCriticalSection(&sndCS);
|
||||||
while (delta > EPS) {
|
while (delta > EPS) {
|
||||||
Core::deltaTime = min(delta, 1.0f / 30.0f);
|
Core::deltaTime = min(delta, 1.0f / 30.0f) / slow;
|
||||||
Game::update();
|
Game::update();
|
||||||
delta -= Core::deltaTime;
|
delta -= Core::deltaTime * slow;
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&sndCS);
|
LeaveCriticalSection(&sndCS);
|
||||||
lastTime = time;
|
lastTime = time;
|
||||||
|
@@ -14,7 +14,7 @@ struct Trigger : Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool inState() {
|
bool inState() {
|
||||||
return (state != baseState) == (getEntity().flags & ENTITY_FLAG_ACTIVE) > 0;
|
return (state != baseState) == (getEntity().flags.active != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool activate(ActionCommand *cmd) {
|
virtual bool activate(ActionCommand *cmd) {
|
||||||
@@ -22,7 +22,7 @@ struct Trigger : Controller {
|
|||||||
Controller::activate(cmd);
|
Controller::activate(cmd);
|
||||||
this->timer = cmd->timer;
|
this->timer = cmd->timer;
|
||||||
|
|
||||||
getEntity().flags ^= ENTITY_FLAG_ACTIVE;
|
getEntity().flags.active ^= 0x1F;
|
||||||
|
|
||||||
if (immediate)
|
if (immediate)
|
||||||
activateNext();
|
activateNext();
|
||||||
@@ -37,7 +37,7 @@ struct Trigger : Controller {
|
|||||||
timer -= Core::deltaTime;
|
timer -= Core::deltaTime;
|
||||||
if (timer <= 0.0f) {
|
if (timer <= 0.0f) {
|
||||||
timer = 0.0f;
|
timer = 0.0f;
|
||||||
entity.flags &= ~ENTITY_FLAG_ACTIVE;
|
entity.flags.active ^= 0x1F;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,12 +45,12 @@ struct Trigger : Controller {
|
|||||||
timer += Core::deltaTime;
|
timer += Core::deltaTime;
|
||||||
if (timer >= 0.0f) {
|
if (timer >= 0.0f) {
|
||||||
timer = 0.0f;
|
timer = 0.0f;
|
||||||
entity.flags |= ENTITY_FLAG_ACTIVE;
|
entity.flags.active ^= 0x1F;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inState())
|
if (!inState())
|
||||||
setState(state != baseState ? baseState : (entity.id == TR::Entity::TRAP_BLADE ? 2 : (baseState ^ 1)));
|
setState(state != baseState ? baseState : (entity.type == TR::Entity::TRAP_BLADE ? 2 : (baseState ^ 1)));
|
||||||
|
|
||||||
updateAnimation(true);
|
updateAnimation(true);
|
||||||
updateEntity();
|
updateEntity();
|
||||||
@@ -77,9 +77,7 @@ struct Dart : Controller {
|
|||||||
TR::Entity &e = getEntity();
|
TR::Entity &e = getEntity();
|
||||||
|
|
||||||
vec3 p = pos - dir * 64.0f; // wall offset = 64
|
vec3 p = pos - dir * 64.0f; // wall offset = 64
|
||||||
int sparkIndex = level->entityAdd(TR::Entity::SPARK, e.room, (int)p.x, (int)p.y, (int)p.z, e.rotation, -1);
|
addSprite(level, TR::Entity::SPARK, e.room, (int)p.x, (int)p.y, (int)p.z, SpriteController::FRAME_RANDOM);
|
||||||
if (sparkIndex > -1)
|
|
||||||
level->entities[sparkIndex].controller = new SpriteController(level, sparkIndex, true, SpriteController::FRAME_RANDOM);
|
|
||||||
|
|
||||||
level->entityRemove(entity);
|
level->entityRemove(entity);
|
||||||
delete this;
|
delete this;
|
||||||
@@ -108,12 +106,8 @@ struct Dartgun : Trigger {
|
|||||||
if (dartIndex > -1)
|
if (dartIndex > -1)
|
||||||
level->entities[dartIndex].controller = new Dart(level, dartIndex);
|
level->entities[dartIndex].controller = new Dart(level, dartIndex);
|
||||||
|
|
||||||
int smokeIndex = level->entityAdd(TR::Entity::SMOKE, entity.room, (int)pos.x, (int)pos.y, (int)pos.z, entity.rotation, -1);
|
addSprite(level, TR::Entity::SMOKE, entity.room, (int)pos.x, (int)pos.y, (int)pos.z);
|
||||||
if (smokeIndex > -1) {
|
|
||||||
level->entities[smokeIndex].intensity = 0x1FFF - level->rooms[entity.room].ambient;
|
|
||||||
level->entities[smokeIndex].controller = new SpriteController(level, smokeIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
playSound(151);
|
playSound(151);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -126,7 +120,7 @@ struct Boulder : Trigger {
|
|||||||
Boulder(TR::Level *level, int entity) : Trigger(level, entity, true) {}
|
Boulder(TR::Level *level, int entity) : Trigger(level, entity, true) {}
|
||||||
|
|
||||||
virtual void update() {
|
virtual void update() {
|
||||||
if (getEntity().flags & ENTITY_FLAG_ACTIVE) {
|
if (getEntity().flags.active) {
|
||||||
updateAnimation(true);
|
updateAnimation(true);
|
||||||
updateEntity();
|
updateEntity();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user