mirror of
https://github.com/XProger/OpenLara.git
synced 2025-01-17 21:09:00 +01:00
#3 underwater acceleration and tilt; #4 new collision detection system for walls (slide and rotate along walls); #8 first person view mode (V key); auto-rotate camera to the back while moving
This commit is contained in:
parent
ab89e08549
commit
d9fce4457d
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
@ -145,7 +145,7 @@ struct Animation {
|
||||
TR::AnimRange &range = level->ranges[s.rangesOffset + j];
|
||||
if (anim->frameStart + frameIndex >= range.low && anim->frameStart + frameIndex <= range.high) {
|
||||
setAnim(range.nextAnimation - model->animation, range.nextFrame);
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
141
src/camera.h
141
src/camera.h
@ -13,28 +13,21 @@ struct Camera : Controller {
|
||||
Frustum *frustum;
|
||||
|
||||
float fov, znear, zfar;
|
||||
vec3 target, destPos, lastDest, angleAdv;
|
||||
vec3 target, destPos, lastDest, advAngle;
|
||||
float advTimer;
|
||||
mat4 mViewInv;
|
||||
int room;
|
||||
|
||||
float timer;
|
||||
int actTargetEntity, actCamera;
|
||||
bool cutscene;
|
||||
bool firstPerson;
|
||||
Basis prevBasis;
|
||||
|
||||
vec4 *reflectPlane;
|
||||
|
||||
Camera(IGame *game, Lara *owner) : Controller(game, owner ? owner->entity : 0), owner(owner), frustum(new Frustum()), timer(0.0f), actTargetEntity(-1), actCamera(-1), reflectPlane(NULL) {
|
||||
fov = 65.0f;
|
||||
znear = 16;
|
||||
zfar = 40.0f * 1024.0f;
|
||||
angleAdv = vec3(0.0f);
|
||||
|
||||
if (owner) {
|
||||
room = owner->getEntity().room;
|
||||
pos = pos - owner->getDir() * 1024.0f;
|
||||
target = owner->getViewPoint();
|
||||
}
|
||||
|
||||
changeView(false);
|
||||
cutscene = owner->getEntity().type != TR::Entity::LARA && level->cameraFrames;
|
||||
}
|
||||
|
||||
@ -46,6 +39,30 @@ struct Camera : Controller {
|
||||
return actCamera > -1 ? level->cameras[actCamera].room : room;
|
||||
}
|
||||
|
||||
virtual void checkRoom() {
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(room, (int)pos.x, (int)pos.y, (int)pos.z, info);
|
||||
|
||||
if (info.roomNext != TR::NO_ROOM)
|
||||
room = info.roomNext;
|
||||
|
||||
if (pos.y < info.roomCeiling) {
|
||||
if (info.roomAbove != TR::NO_ROOM)
|
||||
room = info.roomAbove;
|
||||
else
|
||||
if (info.roomCeiling != 0xffff8100)
|
||||
pos.y = (float)info.roomCeiling;
|
||||
}
|
||||
|
||||
if (pos.y > info.roomFloor) {
|
||||
if (info.roomBelow != TR::NO_ROOM)
|
||||
room = info.roomBelow;
|
||||
else
|
||||
if (info.roomFloor != 0xffff8100)
|
||||
pos.y = (float)info.roomFloor;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool activate(ActionCommand *cmd) {
|
||||
Controller::activate(cmd);
|
||||
this->timer = max(max(1.0f, this->timer), cmd->timer);
|
||||
@ -88,18 +105,43 @@ struct Camera : Controller {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
vec3 advAngleOld = advAngle;
|
||||
|
||||
if (Input::down[ikMouseL]) {
|
||||
vec2 delta = Input::mouse.pos - Input::mouse.start.L;
|
||||
angleAdv.x -= delta.y * 0.01f;
|
||||
angleAdv.y += delta.x * 0.01f;
|
||||
advAngle.x -= delta.y * 0.01f;
|
||||
advAngle.y += delta.x * 0.01f;
|
||||
Input::mouse.start.L = Input::mouse.pos;
|
||||
}
|
||||
|
||||
angleAdv.x -= Input::joy.R.y * 2.0f * Core::deltaTime;
|
||||
angleAdv.y += Input::joy.R.x * 2.0f * Core::deltaTime;
|
||||
|
||||
angle = owner->angle + angleAdv;
|
||||
angle.z = 0.0f;
|
||||
advAngle.x -= Input::joy.R.y * 2.0f * Core::deltaTime;
|
||||
advAngle.y += Input::joy.R.x * 2.0f * Core::deltaTime;
|
||||
|
||||
if (advAngleOld == advAngle) {
|
||||
if (advTimer > 0.0f) {
|
||||
advTimer -= Core::deltaTime;
|
||||
if (advTimer <= 0.0f)
|
||||
advTimer = 0.0f;
|
||||
}
|
||||
} else
|
||||
advTimer = -1.0f;
|
||||
|
||||
if (owner->velocity != 0.0f && advTimer < 0.0f && !Input::down[ikMouseL])
|
||||
advTimer = -advTimer;
|
||||
|
||||
if (advTimer == 0.0f && advAngle != 0.0f) {
|
||||
float t = 10.0f * Core::deltaTime;
|
||||
advAngle.x = lerp(clampAngle(advAngle.x), 0.0f, t);
|
||||
advAngle.y = lerp(clampAngle(advAngle.y), 0.0f, t);
|
||||
}
|
||||
|
||||
angle = owner->angle + advAngle;
|
||||
angle.z = 0.0f;
|
||||
|
||||
if (owner->stand == Lara::STAND_ONWATER)
|
||||
angle.x -= 22.0f * DEG2RAD;
|
||||
if (owner->state == Lara::STATE_HANG || owner->state == Lara::STATE_HANG_LEFT || owner->state == Lara::STATE_HANG_RIGHT)
|
||||
angle.x -= 60.0f * DEG2RAD;
|
||||
|
||||
#ifdef LEVEL_EDITOR
|
||||
angle = angleAdv;
|
||||
@ -124,7 +166,6 @@ struct Camera : Controller {
|
||||
|
||||
return;
|
||||
#endif
|
||||
|
||||
int lookAt = -1;
|
||||
if (actTargetEntity > -1) lookAt = actTargetEntity;
|
||||
if (owner->target > -1) lookAt = owner->target;
|
||||
@ -142,6 +183,25 @@ struct Camera : Controller {
|
||||
}
|
||||
}
|
||||
|
||||
if (firstPerson && actCamera == -1) {
|
||||
Basis head = owner->animation.getJoints(owner->getMatrix(), 14, true);
|
||||
Basis eye(quat(0.0f, 0.0f, 0.0f, 1.0f), vec3(0.0f, -40.0f, 10.0f));
|
||||
eye = head * eye;
|
||||
mViewInv.identity();
|
||||
|
||||
//prevBasis = prevBasis.lerp(eye, 15.0f * Core::deltaTime);
|
||||
|
||||
mViewInv.setRot(eye.rot);
|
||||
mViewInv.setPos(eye.pos);
|
||||
mViewInv.rotateY(advAngle.y);
|
||||
mViewInv.rotateX(advAngle.x + PI);
|
||||
|
||||
pos = mViewInv.getPos();
|
||||
checkRoom();
|
||||
Sound::listener.matrix = mViewInv;
|
||||
return;
|
||||
}
|
||||
|
||||
float lerpFactor = (lookAt == -1) ? 6.0f : 10.0f;
|
||||
vec3 dir;
|
||||
target = target.lerp(owner->getViewPoint(), lerpFactor * Core::deltaTime);
|
||||
@ -170,34 +230,13 @@ struct Camera : Controller {
|
||||
} 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, destRoom, true);
|
||||
}
|
||||
}
|
||||
room = destRoom;
|
||||
}
|
||||
pos = pos.lerp(destPos, Core::deltaTime * lerpFactor);
|
||||
|
||||
if (actCamera <= -1) {
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(room, (int)pos.x, (int)pos.y, (int)pos.z, info);
|
||||
|
||||
if (info.roomNext != 255)
|
||||
room = info.roomNext;
|
||||
|
||||
if (pos.y < info.roomCeiling) {
|
||||
if (info.roomAbove != 255)
|
||||
room = info.roomAbove;
|
||||
else
|
||||
if (info.roomCeiling != 0xffff8100)
|
||||
pos.y = (float)info.roomCeiling;
|
||||
}
|
||||
|
||||
if (pos.y > info.roomFloor) {
|
||||
if (info.roomBelow != 255)
|
||||
room = info.roomBelow;
|
||||
else
|
||||
if (info.roomFloor != 0xffff8100)
|
||||
pos.y = (float)info.roomFloor;
|
||||
}
|
||||
}
|
||||
if (actCamera <= -1)
|
||||
checkRoom();
|
||||
}
|
||||
|
||||
mViewInv = mat4(pos, target, vec3(0, -1, 0));
|
||||
@ -226,6 +265,20 @@ struct Camera : Controller {
|
||||
frustum->pos = Core::viewPos;
|
||||
frustum->calcPlanes(Core::mViewProj);
|
||||
}
|
||||
|
||||
void changeView(bool firstPerson) {
|
||||
this->firstPerson = firstPerson;
|
||||
|
||||
room = owner->getRoomIndex();
|
||||
pos = owner->pos - owner->getDir() * 1024.0f;
|
||||
target = owner->getViewPoint();
|
||||
advAngle = vec3(0.0f);
|
||||
advTimer = 0.0f;
|
||||
|
||||
fov = firstPerson ? 90.0f : 65.0f;
|
||||
znear = firstPerson ? 8.0f : 16.0f;
|
||||
zfar = 40.0f * 1024.0f;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -29,12 +29,24 @@ struct Character : Controller {
|
||||
|
||||
vec3 velocity;
|
||||
float angleExt;
|
||||
float speed;
|
||||
|
||||
Collision collision;
|
||||
|
||||
Character(IGame *game, int entity, int health) : Controller(game, entity), target(-1), health(health), tilt(0.0f), stand(STAND_GROUND), lastInput(0), velocity(0.0f) {
|
||||
animation.initOverrides();
|
||||
rotHead = rotChest = quat(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
void rotateY(float delta) {
|
||||
angle.y += delta;
|
||||
velocity = velocity.rotateY(-delta);
|
||||
}
|
||||
|
||||
void rotateX(float delta) {
|
||||
angle.x = clamp(angle.x + delta, -PI * 0.49f, PI * 0.49f);
|
||||
}
|
||||
|
||||
virtual void hit(int damage, Controller *enemy = NULL) {
|
||||
health -= damage;
|
||||
};
|
||||
@ -44,13 +56,13 @@ struct Character : Controller {
|
||||
TR::Entity &e = getEntity();
|
||||
level->getFloorInfo(e.room, e.x, e.y, e.z, info);
|
||||
|
||||
if (info.roomNext != 0xFF)
|
||||
if (info.roomNext != TR::NO_ROOM)
|
||||
e.room = info.roomNext;
|
||||
|
||||
if (info.roomBelow != 0xFF && e.y > info.roomFloor)
|
||||
if (info.roomBelow != TR::NO_ROOM && e.y > info.roomFloor)
|
||||
e.room = info.roomBelow;
|
||||
|
||||
if (info.roomAbove != 0xFF && e.y <= info.roomCeiling) {
|
||||
if (info.roomAbove != TR::NO_ROOM && e.y <= info.roomCeiling) {
|
||||
if (stand == STAND_UNDERWATER && !level->rooms[info.roomAbove].flags.water) {
|
||||
stand = STAND_ONWATER;
|
||||
velocity.y = 0;
|
||||
@ -106,18 +118,13 @@ struct Character : Controller {
|
||||
virtual void updateTilt(bool active, float tiltSpeed, float tiltMax) {
|
||||
// calculate turning tilt
|
||||
if (active && (input & (LEFT | RIGHT)) && (tilt == 0.0f || (tilt < 0.0f && (input & LEFT)) || (tilt > 0.0f && (input & RIGHT)))) {
|
||||
if (input & LEFT) tilt -= tiltSpeed * Core::deltaTime;
|
||||
if (input & RIGHT) tilt += tiltSpeed * Core::deltaTime;
|
||||
} else
|
||||
if (fabsf(tilt) > 0.01f) {
|
||||
if (tilt > 0.0f)
|
||||
tilt -= min(tilt, tiltSpeed * 4.0f * Core::deltaTime);
|
||||
else
|
||||
tilt -= max(tilt, -tiltSpeed * 4.0f * Core::deltaTime);
|
||||
} else
|
||||
tilt = 0.0f;
|
||||
tilt = clamp(tilt, -tiltMax, tiltMax);
|
||||
|
||||
if (input & LEFT) tilt -= tiltSpeed;
|
||||
if (input & RIGHT) tilt += tiltSpeed;
|
||||
tilt = clamp(tilt, -tiltMax, +tiltMax);
|
||||
} else {
|
||||
if (tilt > 0.0f) tilt = max(0.0f, tilt - tiltSpeed);
|
||||
if (tilt < 0.0f) tilt = min(0.0f, tilt + tiltSpeed);
|
||||
}
|
||||
angle.z = tilt;
|
||||
}
|
||||
|
||||
|
104
src/collision.h
Normal file
104
src/collision.h
Normal file
@ -0,0 +1,104 @@
|
||||
#ifndef H_COLLISION
|
||||
#define H_COLLISION
|
||||
|
||||
#include "core.h"
|
||||
#include "utils.h"
|
||||
#include "format.h"
|
||||
|
||||
struct Collision {
|
||||
enum Side { NONE, LEFT, RIGHT, FRONT, TOP, BOTTOM } side;
|
||||
|
||||
struct Info {
|
||||
int room, roomAbove, roomBelow, floor, ceiling;
|
||||
} info[4];
|
||||
|
||||
Collision() : side(NONE) {}
|
||||
|
||||
Collision(TR::Level *level, int room, vec3 &pos, const vec3 &offset, const vec3 &velocity, float radius, float angle, int minHeight, int maxHeight, int maxAscent, int maxDescent) {
|
||||
if (velocity.x > 0.0f || velocity.z > 0.0f)
|
||||
angle = normalizeAngle(PI2 + vec2(velocity.z, velocity.x).angle());
|
||||
pos += velocity;
|
||||
|
||||
int q = angleQuadrant(angle);
|
||||
|
||||
const vec2 v[] = {
|
||||
{ -radius, radius },
|
||||
{ radius, radius },
|
||||
{ radius, -radius },
|
||||
{ -radius, -radius },
|
||||
};
|
||||
|
||||
const vec2 &l = v[q], &r = v[(q + 1) % 4];
|
||||
|
||||
vec2 f = (q %= 2) ? vec2(l.x, radius * cosf(angle)) : vec2(radius * sinf(angle), l.y),
|
||||
p(pos.x, pos.z),
|
||||
d(0.0F);
|
||||
|
||||
vec3 hpos = pos + offset;
|
||||
|
||||
int height = maxHeight - minHeight;
|
||||
|
||||
if (checkHeight(level, room, hpos, vec2(0.0f), height, 0xFFFFFF, 0xFFFFFF, side = NONE)) {
|
||||
pos -= velocity;
|
||||
side = FRONT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (info[NONE].ceiling > hpos.y - maxHeight) {
|
||||
pos.y = info[NONE].ceiling + maxHeight - offset.y;
|
||||
side = TOP;
|
||||
}
|
||||
|
||||
if (info[NONE].floor < hpos.y + minHeight) {
|
||||
pos.y = info[NONE].floor - minHeight - offset.y;
|
||||
side = BOTTOM;
|
||||
}
|
||||
|
||||
if (checkHeight(level, room, hpos, f, height, maxAscent, maxDescent, FRONT)) {
|
||||
d = vec2(-velocity.x, -velocity.z);
|
||||
q ^= 1;
|
||||
d[q] = getOffset(p[q] + f[q], p[q]);
|
||||
} else if (checkHeight(level, room, hpos, l, height, maxAscent, maxDescent, LEFT)) {
|
||||
d[q] = getOffset(p[q] + l[q], p[q] + f[q]);
|
||||
} else if (checkHeight(level, room, hpos, r, height, maxAscent, maxDescent, RIGHT)) {
|
||||
d[q] = getOffset(p[q] + r[q], p[q] + f[q]);
|
||||
} else
|
||||
return;
|
||||
|
||||
pos += vec3(d.x, 0.0f, d.y);
|
||||
}
|
||||
|
||||
inline bool checkHeight(TR::Level *level, int room, const vec3 &pos, const vec2 &offset, int height, int maxAscent, int maxDescent, Side side) {
|
||||
TR::Level::FloorInfo info;
|
||||
int py = int(pos.y);
|
||||
level->getFloorInfo(room, int(pos.x + offset.x), py, int(pos.z + offset.y), info);
|
||||
|
||||
Info &inf = this->info[side];
|
||||
inf.room = info.roomNext != TR::NO_ROOM ? info.roomNext : room;
|
||||
inf.roomAbove = info.roomAbove;
|
||||
inf.roomBelow = info.roomBelow;
|
||||
inf.floor = info.floor;
|
||||
inf.ceiling = info.ceiling;
|
||||
|
||||
if ((info.ceiling == info.floor) || (info.floor - info.ceiling < height) || (py - info.floor > maxAscent) || (info.floor - py > maxDescent) || (info.ceiling > py)) {
|
||||
this->side = side;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline float getOffset(float from, float to) {
|
||||
int a = int(from) / 1024;
|
||||
int b = int(to) / 1024;
|
||||
|
||||
from -= float(a * 1024.0f);
|
||||
|
||||
if (b == a)
|
||||
return 0.0f;
|
||||
else if (b > a)
|
||||
return -from + 1025.0f;
|
||||
return -from - 1.0f;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -5,6 +5,7 @@
|
||||
#include "frustum.h"
|
||||
#include "mesh.h"
|
||||
#include "animation.h"
|
||||
#include "collision.h"
|
||||
|
||||
#define GRAVITY (6.0f * 30.0f)
|
||||
#define NO_OVERLAP 0x7FFFFFFF
|
||||
@ -119,13 +120,14 @@ struct Controller {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void updateEntity() {
|
||||
TR::Entity &e = getEntity();
|
||||
e.x = int(pos.x);
|
||||
e.y = int(pos.y);
|
||||
e.z = int(pos.z);
|
||||
while (angle.y < 0.0f) angle.y += 2 * PI;
|
||||
while (angle.y > 2 * PI) angle.y -= 2 * PI;
|
||||
angle.y = normalizeAngle(angle.y);
|
||||
e.rotation = angle.y;
|
||||
}
|
||||
|
||||
@ -220,26 +222,18 @@ struct Controller {
|
||||
}
|
||||
|
||||
void alignToWall(float offset = 0.0f) {
|
||||
float fx = pos.x / 1024.0f;
|
||||
float fz = pos.z / 1024.0f;
|
||||
fx -= (int)fx;
|
||||
fz -= (int)fz;
|
||||
int q = angleQuadrant(angle.y);
|
||||
int x = int(pos.x) & ~1023;
|
||||
int z = int(pos.z) & ~1023;
|
||||
|
||||
int k;
|
||||
if (fx > 1.0f - fz)
|
||||
k = fx < fz ? 0 : 1;
|
||||
else
|
||||
k = fx < fz ? 3 : 2;
|
||||
|
||||
angle.y = k * PI * 0.5f; // clamp angle to n*PI/2
|
||||
|
||||
if (offset != 0.0f) {
|
||||
vec3 dir = getDir() * (512.0f - offset);
|
||||
if (k % 2)
|
||||
pos.x = int(pos.x / 1024.0f) * 1024.0f + 512.0f + dir.x;
|
||||
else
|
||||
pos.z = int(pos.z / 1024.0f) * 1024.0f + 512.0f + dir.z;
|
||||
switch (q) {
|
||||
case 0 : pos.z = z + 1024 + offset; break;
|
||||
case 1 : pos.x = x + 1024 + offset; break;
|
||||
case 2 : pos.z = z - offset; break;
|
||||
case 3 : pos.x = x - offset; break;
|
||||
}
|
||||
|
||||
angle.y = q * (PI * 0.5f);
|
||||
updateEntity();
|
||||
}
|
||||
|
||||
@ -264,7 +258,7 @@ struct Controller {
|
||||
|
||||
if (lr != room || lx != sx || lz != sz) {
|
||||
level->getFloorInfo(room, sx, py, sz, info);
|
||||
if (info.roomNext != 0xFF) {
|
||||
if (info.roomNext != TR::NO_ROOM) {
|
||||
room = info.roomNext;
|
||||
level->getFloorInfo(room, sx, py, sz, info);
|
||||
}
|
||||
@ -274,9 +268,9 @@ struct Controller {
|
||||
}
|
||||
|
||||
if (isCamera) {
|
||||
if (py > info.floor && info.roomBelow != 0xFF)
|
||||
if (py > info.floor && info.roomBelow != TR::NO_ROOM)
|
||||
room = info.roomBelow;
|
||||
else if (py < info.ceiling && info.roomAbove != 0xFF)
|
||||
else if (py < info.ceiling && info.roomAbove != TR::NO_ROOM)
|
||||
room = info.roomAbove;
|
||||
else if (py > info.floor || py < info.ceiling) {
|
||||
int minX = px / 1024 * 1024;
|
||||
@ -289,14 +283,14 @@ struct Controller {
|
||||
}
|
||||
} else {
|
||||
if (py > info.floor) {
|
||||
if (info.roomBelow != 0xFF)
|
||||
if (info.roomBelow != TR::NO_ROOM)
|
||||
room = info.roomBelow;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (py < info.ceiling) {
|
||||
if (info.roomAbove != 0xFF)
|
||||
if (info.roomAbove != TR::NO_ROOM)
|
||||
room = info.roomAbove;
|
||||
else
|
||||
break;
|
||||
|
@ -179,7 +179,7 @@ struct Wolf : Enemy {
|
||||
return (state == STATE_STOP || state == STATE_SLEEP) ? STATE_SLEEP : STATE_STOP;
|
||||
|
||||
switch (state) {
|
||||
case STATE_SLEEP : return target > -1 ? STATE_STOP : state;
|
||||
case STATE_SLEEP : return (target > -1 && level->entities[target].room == getRoomIndex()) ? STATE_STOP : state;
|
||||
case STATE_STOP : return target > -1 ? STATE_HOWL : STATE_SLEEP;
|
||||
case STATE_HOWL : return state;
|
||||
case STATE_GROWL : return target > -1 ? (randf() > 0.5f ? STATE_STALKING : STATE_RUN) : STATE_STOP;
|
||||
|
10
src/format.h
10
src/format.h
@ -1551,8 +1551,8 @@ namespace TR {
|
||||
int sx = x - room.info.x;
|
||||
int sz = z - room.info.z;
|
||||
|
||||
sx = clamp(sx, 0, (room.xSectors - 1) * 1024);
|
||||
sz = clamp(sz, 0, (room.zSectors - 1) * 1024);
|
||||
sx = clamp(sx, 0, room.xSectors * 1024 - 1);
|
||||
sz = clamp(sz, 0, room.zSectors * 1024 - 1);
|
||||
|
||||
dx = sx % 1024;
|
||||
dz = sz % 1024;
|
||||
@ -1584,13 +1584,13 @@ namespace TR {
|
||||
return;
|
||||
|
||||
Room::Sector *sBelow = &s;
|
||||
while (sBelow->roomBelow != 0xFF) sBelow = &getSector(sBelow->roomBelow, x, z, dx, dz);
|
||||
while (sBelow->roomBelow != TR::NO_ROOM) sBelow = &getSector(sBelow->roomBelow, x, z, dx, dz);
|
||||
info.floor = 256 * sBelow->floor;
|
||||
parseFloorData(info, sBelow->floorIndex, dx, dz);
|
||||
|
||||
if (info.roomNext == 0xFF) {
|
||||
if (info.roomNext == TR::NO_ROOM) {
|
||||
Room::Sector *sAbove = &s;
|
||||
while (sAbove->roomAbove != 0xFF) sAbove = &getSector(sAbove->roomAbove, x, z, dx, dz);
|
||||
while (sAbove->roomAbove != TR::NO_ROOM) sAbove = &getSector(sAbove->roomAbove, x, z, dx, dz);
|
||||
if (sAbove != sBelow) {
|
||||
info.ceiling = 256 * sAbove->ceiling;
|
||||
parseFloorData(info, sAbove->floorIndex, dx, dz);
|
||||
|
12
src/game.h
12
src/game.h
@ -39,13 +39,21 @@ namespace Game {
|
||||
|
||||
void update() {
|
||||
float dt = Core::deltaTime;
|
||||
if (Input::down[ikV]) { // third <-> first person view
|
||||
level->camera->changeView(!level->camera->firstPerson);
|
||||
Input::down[ikV] = false;
|
||||
}
|
||||
|
||||
if (Input::down[ikR]) // slow motion (for animation debugging)
|
||||
Core::deltaTime /= 10.0f;
|
||||
if (Input::down[ikT])
|
||||
Core::deltaTime *= 10.0f;
|
||||
|
||||
if (Input::down[ikT]) // fast motion
|
||||
for (int i = 0; i < 9; i++)
|
||||
level->update();
|
||||
|
||||
level->update();
|
||||
|
||||
|
||||
Core::deltaTime = dt;
|
||||
}
|
||||
|
||||
|
290
src/lara.h
290
src/lara.h
@ -12,16 +12,25 @@
|
||||
#define TURN_FAST_BACK PI * 3.0f / 4.0f
|
||||
#define TURN_NORMAL PI / 2.0f
|
||||
#define TURN_SLOW PI / 3.0f
|
||||
#define TURN_WATER_FAST PI * 3.0f / 4.0f
|
||||
#define TURN_WATER_SLOW PI * 2.0f / 3.0f
|
||||
#define TURN_WATER_FAST (DEG2RAD * 150.0f)
|
||||
#define TURN_WATER_SLOW (DEG2RAD * 60.0f)
|
||||
#define TURN_WALL_Y (DEG2RAD * 150.0f)
|
||||
#define TURN_WALL_X (DEG2RAD * 60.0f)
|
||||
#define TURN_WALL_X_CLAMP (DEG2RAD * 35.0f)
|
||||
|
||||
#define TILT_MAX (PI / 18.0f)
|
||||
#define TILT_SPEED TILT_MAX
|
||||
#define LARA_TILT_SPEED (DEG2RAD * 37.5f)
|
||||
#define LARA_TILT_MAX (DEG2RAD * 10.0f)
|
||||
|
||||
#define GLIDE_SPEED 35.0f
|
||||
#define SWIM_SPEED 45.0f
|
||||
#define LARA_HANG_OFFSET 724
|
||||
#define LARA_HEIGHT 762
|
||||
#define LARA_HEIGHT_WATER 400
|
||||
#define LARA_RADIUS 100.0f
|
||||
#define LARA_RADIUS_WATER 300.0f
|
||||
|
||||
#define LARA_HANG_OFFSET 724.0f
|
||||
#define LARA_WATER_ACCEL 2.0f
|
||||
#define LARA_SURF_SPEED 15.0f
|
||||
#define LARA_SWIM_SPEED 50.0f
|
||||
#define LARA_SWIM_FRICTION 1.0f
|
||||
|
||||
#define LARA_WET_SPECULAR 0.5f
|
||||
#define LARA_WET_TIMER (LARA_WET_SPECULAR / 16.0f) // 4 sec
|
||||
@ -232,8 +241,8 @@ struct Lara : Character {
|
||||
for (int i = 0; i < jointsCount - 1; i++) {
|
||||
TR::Node &t = node[min(i, model->mCount - 2)];
|
||||
joints[i].posPrev = joints[i].pos = basis.pos;
|
||||
joints[i].length = t.z;
|
||||
basis.translate(vec3(0.0f, 0.0f, -t.z));
|
||||
joints[i].length = float(t.z);
|
||||
basis.translate(vec3(0.0f, 0.0f, -joints[i].length));
|
||||
}
|
||||
joints[jointsCount - 1].posPrev = joints[jointsCount - 1].pos = basis.pos;
|
||||
joints[jointsCount - 1].length = 1.0f;
|
||||
@ -397,7 +406,7 @@ struct Lara : Character {
|
||||
|
||||
if (level->extra.braid > -1)
|
||||
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
|
||||
/*
|
||||
/*
|
||||
pos = vec3(40448, 3584, 60928);
|
||||
angle = vec3(0.0f, PI * 0.5f, 0.0f);
|
||||
getEntity().room = 14;
|
||||
@ -434,12 +443,12 @@ struct Lara : Character {
|
||||
angle = vec3(0.0f, -PI * 0.25f, 0.0f);
|
||||
getEntity().room = 13;
|
||||
|
||||
// level 2 (room 43)
|
||||
// level 2 (reach)
|
||||
pos = vec3(31400, -2560, 25200);
|
||||
angle = vec3(0.0f, PI, 0.0f);
|
||||
getEntity().room = 43;
|
||||
|
||||
// level 2 (room 16)
|
||||
// level 2 (hang & climb)
|
||||
pos = vec3(60907, 0, 39642);
|
||||
angle = vec3(0.0f, PI * 3 / 2, 0.0f);
|
||||
getEntity().room = 16;
|
||||
@ -1074,6 +1083,13 @@ struct Lara : Character {
|
||||
wpnHide();
|
||||
}
|
||||
|
||||
virtual void cmdJump(const vec3 &vel) {
|
||||
vec3 v = vel;
|
||||
if (state == STATE_HANG_UP)
|
||||
v.y = (3.0f - sqrtf(-2.0f * GRAVITY / 30.0f * (collision.info[Collision::FRONT].floor - pos.y + 800.0f)));
|
||||
Character::cmdJump(v);
|
||||
}
|
||||
|
||||
void drawGun(int right) {
|
||||
int mask = right ? BODY_ARM_R3 : BODY_ARM_L3; // unholster
|
||||
if (layers[1].mask & mask)
|
||||
@ -1100,22 +1116,21 @@ struct Lara : Character {
|
||||
|
||||
bool waterOut() {
|
||||
// TODO: playSound 36
|
||||
vec3 dst = pos + getDir() * 32.0f;
|
||||
if (collision.side != Collision::FRONT || pos.y - collision.info[Collision::FRONT].floor > 256 + 128)
|
||||
return false;
|
||||
|
||||
TR::Level::FloorInfo infoCur, infoDst;
|
||||
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.y, (int)pos.z, infoCur),
|
||||
level->getFloorInfo(infoCur.roomAbove, (int)dst.x, (int)dst.y, (int)dst.z, infoDst);
|
||||
vec3 dst = pos + getDir() * (LARA_RADIUS + 32.0f);
|
||||
|
||||
int h = int(pos.y - infoDst.floor);
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(collision.info[Collision::NONE].roomAbove, int(dst.x), int(dst.y), int(dst.z), info);
|
||||
|
||||
if (h >= 0 && h <= 356 && (state == STATE_SURF_TREAD || animation.setState(STATE_SURF_TREAD)) && animation.setState(STATE_STOP)) { // possibility check
|
||||
alignToWall(-96.0f);
|
||||
pos.y = float(infoDst.floor);
|
||||
//pos = dst; // set new position
|
||||
|
||||
int h = int(pos.y - info.floor);
|
||||
|
||||
if (h >= 0 && h <= (256 + 128) && (state == STATE_SURF_TREAD || animation.setState(STATE_SURF_TREAD)) && animation.setState(STATE_STOP)) {
|
||||
alignToWall(LARA_RADIUS);
|
||||
getEntity().room = collision.info[Collision::NONE].roomAbove;
|
||||
pos.y = float(info.floor);
|
||||
specular = LARA_WET_SPECULAR;
|
||||
|
||||
getEntity().room = infoCur.roomAbove;
|
||||
updateEntity();
|
||||
return true;
|
||||
}
|
||||
@ -1353,12 +1368,35 @@ struct Lara : Character {
|
||||
velocity.x = velocity.z = 0.0f;
|
||||
|
||||
if ((state == STATE_REACH || state == STATE_UP_JUMP) && (input & ACTION) && emptyHands()) {
|
||||
|
||||
if (state == STATE_REACH && velocity.y < 0.0f)
|
||||
return state;
|
||||
|
||||
vec3 p = pos;
|
||||
Collision c = Collision(level, getRoomIndex(), p, getDir() * 32.0f, vec3(0.0f), LARA_RADIUS, angleExt, 0, 0, 0, 0);
|
||||
|
||||
if (c.side != Collision::FRONT)
|
||||
return state;
|
||||
|
||||
Box bounds = animation.getBoundingBox(pos, 0);
|
||||
|
||||
int floor = c.info[Collision::FRONT].floor;
|
||||
int hands = int(bounds.min.y);
|
||||
|
||||
if (abs(floor - hands) < 32) {
|
||||
alignToWall(-LARA_RADIUS);
|
||||
pos.y = float(floor + LARA_HANG_OFFSET);
|
||||
stand = STAND_HANG;
|
||||
updateEntity();
|
||||
|
||||
if (state == STATE_REACH) {
|
||||
return STATE_HANG; // TODO: ANIM_HANG_WALL / ANIM_HANG_NOWALL
|
||||
} else
|
||||
return animation.setAnim(ANIM_HANG, -15);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
vec3 p = pos + getDir() * 128.0f;
|
||||
TR::Level::FloorInfo info;
|
||||
// TODO: use brain
|
||||
@ -1372,7 +1410,7 @@ struct Lara : Character {
|
||||
} while (info.ceiling > bounds.min.y && info.roomAbove != 0xFF);
|
||||
|
||||
if (abs(info.floor - int(bounds.min.y)) < 16) { // reach fall
|
||||
alignToWall(96.0f);
|
||||
alignToWall(LARA_RADIUS);
|
||||
pos.y = info.floor + 724.0f;
|
||||
updateEntity();
|
||||
|
||||
@ -1382,6 +1420,7 @@ struct Lara : Character {
|
||||
} else
|
||||
return animation.setAnim(ANIM_HANG, -15);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (state == STATE_FORWARD_JUMP) {
|
||||
@ -1409,7 +1448,7 @@ struct Lara : Character {
|
||||
if ((dx <= (512 + 128) && dz <= (512 - 128)) ||
|
||||
(dx <= (512 - 128) && dz <= (512 + 128))) {
|
||||
|
||||
alignToWall();
|
||||
alignToWall(-LARA_RADIUS);
|
||||
|
||||
Block *block = (Block*)e.controller;
|
||||
block->angle.y = angle.y;
|
||||
@ -1427,26 +1466,22 @@ struct Lara : Character {
|
||||
if ((input & ACTION) && emptyHands() && doPickUp())
|
||||
return STATE_PICK_UP;
|
||||
|
||||
if ((input & (FORTH | ACTION)) == (FORTH | ACTION) && (animation.index == ANIM_STAND || animation.index == ANIM_STAND_NORMAL) && emptyHands()) { // TODO: get rid of animation.index
|
||||
vec3 p = pos + getDir() * 64.0f;
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.y, (int)p.z, info);
|
||||
int h = (int)pos.y - info.floor;
|
||||
if ((input & (FORTH | ACTION)) == (FORTH | ACTION) && (animation.index == ANIM_STAND || animation.index == ANIM_STAND_NORMAL) && emptyHands() && collision.side == Collision::FRONT) { // TODO: get rid of animation.index
|
||||
int floor = collision.info[Collision::FRONT].floor;
|
||||
int h = (int)pos.y - floor;
|
||||
|
||||
int aIndex = animation.index;
|
||||
if (info.floor == info.ceiling || h < 256 + 128) {
|
||||
; // do nothing
|
||||
} else if (h <= 2 * 256 + 128) {
|
||||
if (h <= 2 * 256 + 128) {
|
||||
aIndex = ANIM_CLIMB_2;
|
||||
pos.y = info.floor + 512.0f;
|
||||
pos.y = floor + 512.0f;
|
||||
} else if (h <= 3 * 256 + 128) {
|
||||
aIndex = ANIM_CLIMB_3;
|
||||
pos.y = info.floor + 768.0f;
|
||||
pos.y = floor + 768.0f;
|
||||
} else if (h <= 7 * 256 + 128)
|
||||
aIndex = ANIM_CLIMB_JUMP;
|
||||
|
||||
if (aIndex != animation.index) {
|
||||
alignToWall(96.0f);
|
||||
alignToWall(-LARA_RADIUS);
|
||||
return animation.setAnim(aIndex);
|
||||
}
|
||||
}
|
||||
@ -1490,7 +1525,7 @@ struct Lara : Character {
|
||||
int pushState = (input & FORTH) ? STATE_PUSH_BLOCK : STATE_PULL_BLOCK;
|
||||
Block *block = getBlock();
|
||||
if (animation.canSetState(pushState) && block->doMove((input & FORTH) != 0)) {
|
||||
alignToWall(128.0f);
|
||||
alignToWall(-LARA_RADIUS);
|
||||
return pushState;
|
||||
}
|
||||
}
|
||||
@ -1553,9 +1588,9 @@ struct Lara : Character {
|
||||
if (input & FORTH) {
|
||||
// possibility check
|
||||
TR::Level::FloorInfo info;
|
||||
vec3 p = pos + getDir() * 128.0f;
|
||||
vec3 p = pos + getDir() * (LARA_RADIUS + 2.0f);
|
||||
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.y, (int)p.z, info);
|
||||
if (info.floor - info.ceiling >= 768)
|
||||
if (info.floor - info.ceiling >= LARA_HEIGHT)
|
||||
return (input & WALK) ? STATE_HANDSTAND : STATE_HANG_UP;
|
||||
}
|
||||
return STATE_HANG;
|
||||
@ -1568,6 +1603,8 @@ struct Lara : Character {
|
||||
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) {
|
||||
game->waterDrop(pos, 256.0f, 0.2f);
|
||||
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
|
||||
pos.y += 100.0f;
|
||||
angle.x = -45.0f * DEG2RAD;
|
||||
return animation.setAnim(ANIM_WATER_FALL); // TODO: wronng animation
|
||||
}
|
||||
|
||||
@ -1577,10 +1614,13 @@ struct Lara : Character {
|
||||
Sprite::add(game, TR::Entity::WATER_SPLASH, getRoomIndex(), (int)pos.x, (int)pos.y, (int)pos.z);
|
||||
return STATE_DIVE;
|
||||
}
|
||||
|
||||
|
||||
if (input & JUMP) return STATE_SWIM;
|
||||
|
||||
if (state == STATE_GLIDE && speed < LARA_SWIM_SPEED * 2.0f / 3.0f)
|
||||
return STATE_TREAD;
|
||||
|
||||
return (state == STATE_SWIM || velocity.y > GLIDE_SPEED) ? STATE_GLIDE : STATE_TREAD;
|
||||
return STATE_GLIDE;
|
||||
}
|
||||
|
||||
virtual int getStateOnwater() {
|
||||
@ -1709,9 +1749,9 @@ struct Lara : Character {
|
||||
if (state == STATE_SWIM || state == STATE_GLIDE)
|
||||
w *= TURN_WATER_FAST;
|
||||
else if (state == STATE_TREAD || state == STATE_SURF_TREAD || state == STATE_SURF_SWIM || state == STATE_SURF_BACK)
|
||||
w *= TURN_WATER_SLOW;
|
||||
w *= TURN_WATER_FAST;
|
||||
else if (state == STATE_RUN)
|
||||
w *= sign(w) != sign(tilt) ? 0.0f : w * TURN_FAST * tilt / TILT_MAX;
|
||||
w *= sign(w) != sign(tilt) ? 0.0f : w * TURN_FAST * tilt / LARA_TILT_MAX;
|
||||
else if (state == STATE_FAST_TURN)
|
||||
w *= TURN_FAST;
|
||||
else if (state == STATE_FAST_BACK)
|
||||
@ -1723,17 +1763,12 @@ struct Lara : Character {
|
||||
else
|
||||
w = 0.0f;
|
||||
|
||||
if (w != 0.0f) {
|
||||
w *= Core::deltaTime;
|
||||
angle.y += w;
|
||||
velocity = velocity.rotateY(-w); // in-air velocity rotation control
|
||||
}
|
||||
if (w != 0.0f)
|
||||
rotateY(w * Core::deltaTime);
|
||||
|
||||
// pitch (underwater only)
|
||||
if (stand == STAND_UNDERWATER && (input & (FORTH | BACK)) ) {
|
||||
angle.x += ((input & FORTH) ? -TURN_WATER_SLOW : TURN_WATER_SLOW) * 0.5f * Core::deltaTime;
|
||||
angle.x = clamp(angle.x, -PI * 0.5f, PI * 0.5f);
|
||||
}
|
||||
if (stand == STAND_UNDERWATER && (input & (FORTH | BACK)))
|
||||
rotateX(((input & FORTH) ? -TURN_WATER_SLOW : TURN_WATER_SLOW) * Core::deltaTime);
|
||||
|
||||
// get animation direction
|
||||
angleExt = angle.y;
|
||||
@ -1743,6 +1778,7 @@ struct Lara : Character {
|
||||
case STATE_BACK_JUMP :
|
||||
case STATE_FAST_BACK :
|
||||
case STATE_SLIDE_BACK :
|
||||
case STATE_ROLL_1 :
|
||||
angleExt += PI;
|
||||
break;
|
||||
case STATE_LEFT_JUMP :
|
||||
@ -1768,18 +1804,15 @@ struct Lara : Character {
|
||||
case STAND_HANG :
|
||||
case STAND_ONWATER : {
|
||||
|
||||
float speed = 0.0f;
|
||||
switch (state) {
|
||||
case STATE_SURF_SWIM :
|
||||
case STATE_SURF_BACK :
|
||||
case STATE_SURF_LEFT :
|
||||
case STATE_SURF_RIGHT :
|
||||
speed = 15.0f;
|
||||
case STATE_SURF_RIGHT :
|
||||
speed = min(speed + 30.0f * LARA_WATER_ACCEL * Core::deltaTime, LARA_SURF_SPEED);
|
||||
break;
|
||||
default :
|
||||
speed = animation.getSpeed();
|
||||
if (animation.index == ANIM_STAND_ROLL_END)
|
||||
speed = -speed;
|
||||
}
|
||||
|
||||
if (stand == STAND_ONWATER) {
|
||||
@ -1790,9 +1823,9 @@ struct Lara : Character {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
if (stand == STAND_HANG) {
|
||||
vec3 p = pos + getDir() * 128.0f;
|
||||
vec3 p = pos + getDir() * (LARA_RADIUS + 2.0f);
|
||||
level->getFloorInfo(e.room, (int)p.x, (int)p.y, (int)p.z, info);
|
||||
if (info.roomAbove != 0xFF && info.floor >= e.y - LARA_HANG_OFFSET)
|
||||
if (info.roomAbove != TR::NO_ROOM && info.floor >= e.y - LARA_HANG_OFFSET)
|
||||
level->getFloorInfo(info.roomAbove, (int)p.x, (int)p.y, (int)p.z, info);
|
||||
} else
|
||||
level->getFloorInfo(e.room, e.x, e.y, e.z, info);
|
||||
@ -1803,16 +1836,13 @@ struct Lara : Character {
|
||||
break;
|
||||
}
|
||||
case STAND_UNDERWATER : {
|
||||
float speed = 0.0f;
|
||||
if (animation.index == ANIM_TO_UNDERWATER)
|
||||
speed = 15.0f;
|
||||
if (state == STATE_SWIM)
|
||||
speed = SWIM_SPEED;
|
||||
|
||||
if (speed != 0.0f)
|
||||
velocity = vec3(angle.x, angle.y) * speed;
|
||||
else
|
||||
velocity = velocity - velocity * min(1.0f, Core::deltaTime * 2.0f);
|
||||
speed = min(speed + 30.0f * LARA_WATER_ACCEL * Core::deltaTime, LARA_SWIM_SPEED);
|
||||
if (state == STATE_TREAD || state == STATE_GLIDE)
|
||||
speed = max(speed - 30.0f * LARA_SWIM_FRICTION * Core::deltaTime, 0.0f);
|
||||
velocity = vec3(angle.x, angle.y) * speed;
|
||||
// TODO: apply flow velocity
|
||||
break;
|
||||
}
|
||||
@ -1820,9 +1850,13 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
virtual void updatePosition() { // TODO: sphere / bbox collision
|
||||
updateTilt(state == STATE_RUN, TILT_SPEED, TILT_MAX);
|
||||
// tilt control
|
||||
vec2 vTilt(LARA_TILT_SPEED * Core::deltaTime, LARA_TILT_MAX);
|
||||
if (stand == STAND_UNDERWATER)
|
||||
vTilt *= 2.0f;
|
||||
updateTilt(state == STATE_RUN || stand == STAND_UNDERWATER, vTilt.x, vTilt.y);
|
||||
|
||||
if (velocity.length() >= 0.001f)
|
||||
if (velocity.length() >= 1.0f)
|
||||
move();
|
||||
|
||||
if (getEntity().type != TR::Entity::LARA) {
|
||||
@ -1844,11 +1878,11 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
void move() {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
//TR::Entity &e = getEntity();
|
||||
//TR::Level::FloorInfo info;
|
||||
|
||||
float f, c;
|
||||
bool canPassGap = true;
|
||||
//float f, c;
|
||||
//bool canPassGap = true;
|
||||
/*
|
||||
if (velocity != 0.0f) {
|
||||
vec3 dir = velocity.normal() * 128.0f;
|
||||
@ -1868,11 +1902,53 @@ struct Lara : Character {
|
||||
}
|
||||
}
|
||||
*/
|
||||
vec3 offset = velocity * Core::deltaTime * 30.0f;
|
||||
vec3 vel = velocity * Core::deltaTime * 30.0f;
|
||||
vec3 opos(pos), offset(0.0f);
|
||||
|
||||
vec3 p = pos;
|
||||
pos = pos + offset;
|
||||
float radius = stand == STAND_UNDERWATER ? LARA_RADIUS_WATER : LARA_RADIUS;
|
||||
int maxHeight = stand == STAND_UNDERWATER ? LARA_HEIGHT_WATER : LARA_HEIGHT;
|
||||
int minHeight = 0;
|
||||
int maxAscent = 256 + 128;
|
||||
int maxDescent = 0xFFFFFF;
|
||||
|
||||
if (state == STATE_WALK || state == STATE_BACK)
|
||||
maxDescent = maxAscent;
|
||||
if (state == STATE_STEP_LEFT || state == STATE_STEP_RIGHT)
|
||||
maxAscent = maxDescent = 64;
|
||||
if (stand == STAND_ONWATER)
|
||||
maxAscent = -1;
|
||||
if (stand == STAND_HANG) {
|
||||
maxHeight = 0;
|
||||
maxAscent = maxDescent = 64;
|
||||
offset = getDir() * (LARA_RADIUS + 32.0f);
|
||||
offset.y -= LARA_HANG_OFFSET;
|
||||
}
|
||||
if (stand == STAND_UNDERWATER) {
|
||||
offset.y += LARA_HEIGHT_WATER * 0.5f;
|
||||
}
|
||||
|
||||
int room = getRoomIndex();
|
||||
|
||||
collision = Collision(level, room, pos, offset, vel, radius, angleExt, minHeight, maxHeight, maxAscent, maxDescent);
|
||||
|
||||
if (stand != STAND_HANG && (collision.side == Collision::LEFT || collision.side == Collision::RIGHT)) {
|
||||
float rot = TURN_WALL_Y * Core::deltaTime;
|
||||
rotateY((collision.side == Collision::LEFT) ? rot : -rot);
|
||||
}
|
||||
|
||||
if (stand == STAND_HANG && collision.side != Collision::FRONT) {
|
||||
offset.x = offset.z = 0.0f;
|
||||
minHeight = LARA_HANG_OFFSET;
|
||||
maxDescent = 0xFFFFFF;
|
||||
maxAscent = -LARA_HANG_OFFSET;
|
||||
vec3 p = pos;
|
||||
collision = Collision(level, room, p, offset, vec3(0.0f), radius, angleExt, minHeight, maxHeight, maxAscent, maxDescent);
|
||||
if (collision.side == Collision::FRONT)
|
||||
pos = opos;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
if (canPassGap) {
|
||||
level->getFloorInfo(e.room, (int)pos.x, (int)pos.y, (int)pos.z, info);
|
||||
canPassGap = (info.floor - info.ceiling) >= (stand == STAND_GROUND ? 768 : 512);
|
||||
@ -1880,6 +1956,8 @@ struct Lara : Character {
|
||||
|
||||
f = info.floor - pos.y;
|
||||
c = pos.y - info.ceiling;
|
||||
*/
|
||||
|
||||
/*
|
||||
TR::Animation *anim = animation;
|
||||
Box eBox = Box(pos - vec3(128.0f, 0.0f, 128.0f), pos + vec3(128.0, getHeight(), 128.0f)); // getBoundingBox();
|
||||
@ -1915,6 +1993,7 @@ struct Lara : Character {
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if (canPassGap)
|
||||
switch (stand) {
|
||||
case STAND_AIR : {
|
||||
@ -1959,38 +2038,46 @@ struct Lara : Character {
|
||||
break;
|
||||
default : ;
|
||||
}
|
||||
*/
|
||||
|
||||
// get current leading foot in animation
|
||||
int rightStart = 0;
|
||||
if (state == STATE_RUN) rightStart = 6;
|
||||
if (state == STATE_WALK) rightStart = 13;
|
||||
if (state == STATE_BACK) rightStart = 28;
|
||||
bool isLeftFoot = animation.frameIndex < rightStart || animation.frameIndex > (rightStart + animation.framesCount / 2);
|
||||
|
||||
|
||||
if (!canPassGap) {
|
||||
pos = p; // TODO: use smart ejection
|
||||
if (stand == STAND_UNDERWATER) {
|
||||
if (collision.side == Collision::TOP)
|
||||
rotateX(-TURN_WALL_X * Core::deltaTime);
|
||||
if (collision.side == Collision::BOTTOM)
|
||||
rotateX( TURN_WALL_X * Core::deltaTime);
|
||||
}
|
||||
|
||||
if (stand == STAND_AIR && collision.side == Collision::TOP && velocity.y < 0.0f)
|
||||
velocity.y = 30.0f;
|
||||
|
||||
if (collision.side == Collision::FRONT) {
|
||||
int floor = collision.info[Collision::FRONT].floor;
|
||||
|
||||
// hit the wall
|
||||
switch (stand) {
|
||||
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) {
|
||||
animation.setAnim(ANIM_SMASH_JUMP);
|
||||
velocity.x = -velocity.x * 0.5f;
|
||||
velocity.z = -velocity.z * 0.5f;
|
||||
if (offset.y < 0.0f)
|
||||
offset.y = velocity.y = 0.0f;
|
||||
velocity.x = -velocity.x * 0.25f;
|
||||
velocity.z = -velocity.z * 0.25f;
|
||||
if (velocity.y < 0.0f)
|
||||
velocity.y = 30.0f;
|
||||
}
|
||||
|
||||
pos.y = p.y + offset.y;
|
||||
|
||||
break;
|
||||
case STAND_GROUND :
|
||||
case STAND_HANG :
|
||||
if (f <= -(256 * 3 - 128) && state == STATE_RUN)
|
||||
if (opos.y - floor > (256 * 3 - 128) && state == STATE_RUN)
|
||||
animation.setAnim(isLeftFoot ? ANIM_SMASH_RUN_LEFT : ANIM_SMASH_RUN_RIGHT);
|
||||
else if (stand == STAND_HANG)
|
||||
animation.setAnim(ANIM_HANG, -21);
|
||||
@ -1998,11 +2085,18 @@ struct Lara : Character {
|
||||
animation.setAnim((state == STATE_RUN || state == STATE_WALK) ? (isLeftFoot ? ANIM_STAND_LEFT : ANIM_STAND_RIGHT) : ANIM_STAND);
|
||||
velocity.x = velocity.z = 0.0f;
|
||||
break;
|
||||
case STAND_UNDERWATER :
|
||||
if (fabsf(angle.x) > TURN_WALL_X_CLAMP)
|
||||
rotateX(TURN_WALL_X * Core::deltaTime * sign(angle.x));
|
||||
else
|
||||
pos.y = opos.y;
|
||||
break;
|
||||
default : ;// no smash animation
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
if (stand == STAND_GROUND) {
|
||||
int h = int(info.floor - pos.y);
|
||||
int floor = collision.info[Collision::NONE].floor;
|
||||
int h = int(floor - opos.y);
|
||||
|
||||
if (h >= 256 && state == STATE_FAST_BACK) {
|
||||
stand = STAND_AIR;
|
||||
@ -2010,18 +2104,20 @@ struct Lara : Character {
|
||||
} else if (h >= 128 && (state == STATE_WALK || state == STATE_BACK)) { // descend
|
||||
if (state == STATE_WALK) animation.setAnim(isLeftFoot ? ANIM_WALK_DESCEND_LEFT : ANIM_WALK_DESCEND_RIGHT);
|
||||
if (state == STATE_BACK) animation.setAnim(isLeftFoot ? ANIM_BACK_DESCEND_LEFT : ANIM_BACK_DESCEND_RIGHT);
|
||||
pos.y = float(info.floor);
|
||||
pos.y = float(floor);
|
||||
} else if (h > -1.0f) {
|
||||
pos.y = min((float)info.floor, pos.y += DESCENT_SPEED * Core::deltaTime);
|
||||
pos.y = min(float(floor), pos.y += DESCENT_SPEED * Core::deltaTime);
|
||||
} else if (h > -128) {
|
||||
pos.y = float(info.floor);
|
||||
pos.y = float(floor);
|
||||
} else if (h >= -(256 + 128) && (state == STATE_RUN || state == STATE_WALK)) { // ascend
|
||||
if (state == STATE_RUN) animation.setAnim(isLeftFoot ? ANIM_RUN_ASCEND_LEFT : ANIM_RUN_ASCEND_RIGHT);
|
||||
if (state == STATE_WALK) animation.setAnim(isLeftFoot ? ANIM_WALK_ASCEND_LEFT : ANIM_WALK_ASCEND_RIGHT);
|
||||
pos.y = float(info.floor);
|
||||
pos.y = float(floor);
|
||||
} else
|
||||
pos.y = float(info.floor);
|
||||
pos.y = float(floor);
|
||||
}
|
||||
collision.side = Collision::NONE;
|
||||
}
|
||||
|
||||
updateEntity();
|
||||
checkRoom();
|
||||
|
45
src/level.h
45
src/level.h
@ -767,7 +767,8 @@ struct Level : IGame {
|
||||
delete cube;
|
||||
delete mesh;
|
||||
|
||||
delete camera;
|
||||
delete camera;
|
||||
Sound::stopAll();
|
||||
}
|
||||
|
||||
void initTextures() {
|
||||
@ -1148,7 +1149,7 @@ struct Level : IGame {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
camera->update();
|
||||
waterCache->update();
|
||||
@ -1375,6 +1376,40 @@ struct Level : IGame {
|
||||
// renderModel(level.models[modelIndex], level.entities[4]);
|
||||
*/
|
||||
Debug::begin();
|
||||
|
||||
lara->updateEntity(); // TODO clip angle while rotating
|
||||
|
||||
int q = int(normalizeAngle(lara->angleExt + PI * 0.25f) / (PI * 0.5f));
|
||||
float radius = 256.0f;
|
||||
|
||||
const vec2 v[] = {
|
||||
{ -radius, radius },
|
||||
{ radius, radius },
|
||||
{ radius, -radius },
|
||||
{ -radius, -radius },
|
||||
};
|
||||
|
||||
const vec2 &l = v[q],
|
||||
&r = v[(q + 1) % 4],
|
||||
&f = (q %= 2) ? vec2(l.x, radius * cosf(lara->angleExt)) : vec2(radius * sinf(lara->angleExt), l.y);
|
||||
|
||||
vec3 F = vec3(f.x, 0.0f, f.y);
|
||||
vec3 L = vec3(l.x, 0.0f, l.y);
|
||||
vec3 R = vec3(r.x, 0.0f, r.y);
|
||||
|
||||
vec3 p, n = lara->pos + vec3(0.0f, -512.0f, 0.0f);
|
||||
|
||||
Core::setDepthTest(false);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(0, 0, 1); p = n; glVertex3fv((GLfloat*)&p); p += F; glVertex3fv((GLfloat*)&p);
|
||||
glColor3f(1, 0, 0); p = n; glVertex3fv((GLfloat*)&p); p += L; glVertex3fv((GLfloat*)&p);
|
||||
glColor3f(0, 1, 0); p = n; glVertex3fv((GLfloat*)&p); p += R; glVertex3fv((GLfloat*)&p);
|
||||
glColor3f(1, 1, 0); p = lara->pos; glVertex3fv((GLfloat*)&p); p -= vec3(0.0f, LARA_HANG_OFFSET, 0.0f); glVertex3fv((GLfloat*)&p);
|
||||
glEnd();
|
||||
Core::setDepthTest(true);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
@ -1415,15 +1450,17 @@ struct Level : IGame {
|
||||
glPopMatrix();
|
||||
*/
|
||||
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
// Debug::Level::lights(level, lara->getRoomIndex());
|
||||
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
||||
Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
||||
// Core::setDepthTest(false);
|
||||
// Debug::Level::portals(level);
|
||||
// Core::setDepthTest(true);
|
||||
// Debug::Level::meshes(level);
|
||||
// Debug::Level::entities(level);
|
||||
Core::setBlending(bmNone);
|
||||
|
||||
/*
|
||||
static int dbg_ambient = 0;
|
||||
dbg_ambient = int(params.time * 2) % 4;
|
||||
|
@ -124,6 +124,8 @@
|
||||
controls:<br>
|
||||
keyboad: move - WASD / arrows, jump - Space, action - E/Ctrl, draw weapon - Q, change weapon - 1-4, walk - Shift, side steps - ZX/walk+direction, camera - MouseR)<br>
|
||||
gamepad: PSX controls on XBox controller<br>
|
||||
Change view: V<br>
|
||||
Time Control: R - slow motion, T - fast motion<br>
|
||||
FullScreen: Alt + Enter
|
||||
</span>
|
||||
|
||||
|
@ -189,6 +189,7 @@
|
||||
<ClInclude Include="..\..\animation.h" />
|
||||
<ClInclude Include="..\..\camera.h" />
|
||||
<ClInclude Include="..\..\character.h" />
|
||||
<ClInclude Include="..\..\collision.h" />
|
||||
<ClInclude Include="..\..\controller.h" />
|
||||
<ClInclude Include="..\..\core.h" />
|
||||
<ClInclude Include="..\..\debug.h" />
|
||||
|
@ -530,6 +530,12 @@ namespace Sound {
|
||||
delete stream;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void stopAll() {
|
||||
for (int i = 0; i < channelsCount; i++)
|
||||
delete channels[i];
|
||||
channelsCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
38
src/utils.h
38
src/utils.h
@ -85,6 +85,16 @@ float shortAngle(float a, float b) {
|
||||
return clampAngle(n - int(n / PI2) * PI2);
|
||||
}
|
||||
|
||||
float normalizeAngle(float angle) {
|
||||
while (angle < 0.0f) angle += PI2;
|
||||
while (angle > PI2) angle -= PI2;
|
||||
return angle;
|
||||
}
|
||||
|
||||
int angleQuadrant(float angle) {
|
||||
return int(normalizeAngle(angle + PI * 0.25f) / (PI * 0.5f));
|
||||
}
|
||||
|
||||
float decrease(float delta, float &value, float &speed) {
|
||||
if (speed > 0.0f && fabsf(delta) > 0.01f) {
|
||||
if (delta > 0) speed = min(delta, speed);
|
||||
@ -112,11 +122,13 @@ struct vec2 {
|
||||
vec2(float s) : x(s), y(s) {}
|
||||
vec2(float x, float y) : x(x), y(y) {}
|
||||
|
||||
float& operator [] (int index) const { ASSERT(index >= 0 && index <= 1); return ((float*)this)[index]; }
|
||||
inline float& operator [] (int index) const { ASSERT(index >= 0 && index <= 1); return ((float*)this)[index]; }
|
||||
|
||||
bool operator == (float s) const { return x == s && y == s; }
|
||||
bool operator != (float s) const { return !(*this == s); }
|
||||
vec2 operator - () const { return vec2(-x, -y); }
|
||||
inline bool operator == (const vec2 &v) const { return x == v.x && y == v.y; }
|
||||
inline bool operator != (const vec2 &v) const { return !(*this == v); }
|
||||
inline bool operator == (float s) const { return x == s && y == s; }
|
||||
inline bool operator != (float s) const { return !(*this == s); }
|
||||
inline vec2 operator - () const { return vec2(-x, -y); }
|
||||
|
||||
vec2& operator += (const vec2 &v) { x += v.x; y += v.y; return *this; }
|
||||
vec2& operator -= (const vec2 &v) { x -= v.x; y -= v.y; return *this; }
|
||||
@ -138,6 +150,7 @@ struct vec2 {
|
||||
float length2() const { return dot(*this); }
|
||||
float length() const { return sqrtf(length2()); }
|
||||
vec2 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
|
||||
float angle() const { return atan2(y, x); }
|
||||
};
|
||||
|
||||
struct vec3 {
|
||||
@ -148,11 +161,13 @@ struct vec3 {
|
||||
vec3(const vec2 &xy, float z = 0.0f) : x(xy.x), y(xy.y), z(z) {}
|
||||
vec3(float lng, float lat) : x(sinf(lat) * cosf(lng)), y(-sinf(lng)), z(cosf(lat) * cosf(lng)) {}
|
||||
|
||||
float& operator [] (int index) const { ASSERT(index >= 0 && index <= 2); return ((float*)this)[index]; }
|
||||
inline float& operator [] (int index) const { ASSERT(index >= 0 && index <= 2); return ((float*)this)[index]; }
|
||||
|
||||
bool operator == (float s) const { return x == s && y == s && z == s; }
|
||||
bool operator != (float s) const { return !(*this == s); }
|
||||
vec3 operator - () const { return vec3(-x, -y, -z); }
|
||||
inline bool operator == (const vec3 &v) const { return x == v.x && y == v.y && z == v.z; }
|
||||
inline bool operator != (const vec3 &v) const { return !(*this == v); }
|
||||
inline bool operator == (float s) const { return x == s && y == s && z == s; }
|
||||
inline bool operator != (float s) const { return !(*this == s); }
|
||||
inline vec3 operator - () const { return vec3(-x, -y, -z); }
|
||||
|
||||
vec3& operator += (const vec3 &v) { x += v.x; y += v.y; z += v.z; return *this; }
|
||||
vec3& operator -= (const vec3 &v) { x -= v.x; y -= v.y; z -= v.z; return *this; }
|
||||
@ -598,6 +613,13 @@ struct Basis {
|
||||
void rotate(const quat &q) {
|
||||
rot = rot * q;
|
||||
}
|
||||
|
||||
Basis lerp(const Basis &basis, float t) {
|
||||
Basis b;
|
||||
b.rot = rot.lerp(basis.rot, t);
|
||||
b.pos = pos.lerp(basis.pos, t);
|
||||
return b;
|
||||
}
|
||||
};
|
||||
|
||||
struct ubyte2 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user