mirror of
https://github.com/XProger/OpenLara.git
synced 2025-03-13 23:59:41 +01:00
#3 slide on slant blocks, climb on 2-3 clicks height blocks, asc/desc 1 click blocks while walk or run;
#13 add dummy boulder trigger to stop inactive animation & sound, fix short angle checks and non-zero velocity for switch and keyhole triggers;
This commit is contained in:
parent
3f3a590f73
commit
5a99d547ba
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
24
src/camera.h
24
src/camera.h
@ -7,6 +7,8 @@
|
||||
|
||||
#define MAX_CLIP_PLANES 10
|
||||
|
||||
#define CAMERA_OFFSET (1024.0f + 512.0f)
|
||||
|
||||
struct Frustum {
|
||||
|
||||
struct Poly {
|
||||
@ -64,15 +66,15 @@ struct Frustum {
|
||||
float t2 = v2.dot(plane.xyz) + plane.w;
|
||||
|
||||
// hack for big float numbers
|
||||
int s1 = sign((int)t1);
|
||||
int s2 = sign((int)t2);
|
||||
int s1 = (int)t1;
|
||||
int s2 = (int)t2;
|
||||
|
||||
if (s1 >= 0) {
|
||||
dst.vertices[dst.count++] = v1;
|
||||
ASSERT(dst.count < MAX_CLIP_PLANES);
|
||||
}
|
||||
|
||||
if (s1 * s2 < 0) {
|
||||
if ((s1 ^ s2) < 0) { // check for opposite signs
|
||||
float k1 = t2 / (t2 - t1);
|
||||
float k2 = t1 / (t2 - t1);
|
||||
dst.vertices[dst.count++] = v1 * (float)k1 - v2 * (float)k2;
|
||||
@ -224,24 +226,12 @@ struct Camera : Controller {
|
||||
Input::mouse.start.R = Input::mouse.pos;
|
||||
}
|
||||
|
||||
float height = 0.0f;
|
||||
switch (owner->stand) {
|
||||
case Controller::STAND_AIR :
|
||||
case Controller::STAND_GROUND :
|
||||
height = 768.0f;
|
||||
break;
|
||||
case Controller::STAND_UNDERWATER :
|
||||
case Controller::STAND_ONWATER :
|
||||
height = 256.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
angle = owner->angle + angleAdv;
|
||||
angle.z = 0.0f;
|
||||
//angle.x = min(max(angle.x, -80 * DEG2RAD), 80 * DEG2RAD);
|
||||
|
||||
vec3 dir;
|
||||
target = vec3(owner->pos.x, owner->pos.y - height, owner->pos.z);
|
||||
target = vec3(owner->pos.x, owner->pos.y, owner->pos.z) + owner->getViewOffset();
|
||||
|
||||
if (actCamera > -1) {
|
||||
TR::Camera &c = level->cameras[actCamera];
|
||||
@ -260,7 +250,7 @@ struct Camera : Controller {
|
||||
dir = getDir();
|
||||
|
||||
if (owner->state != Lara::STATE_BACK_JUMP || actTargetEntity > -1) {
|
||||
vec3 eye = target - dir * 1024.0f;
|
||||
vec3 eye = target - dir * CAMERA_OFFSET;
|
||||
destPos = trace(owner->getRoomIndex(), target, eye);
|
||||
lastDest = destPos;
|
||||
} else {
|
||||
|
@ -6,12 +6,14 @@
|
||||
#define GRAVITY 6.0f
|
||||
#define NO_OVERLAP 0x7FFFFFFF
|
||||
|
||||
#define SPRITE_FPS 10.0f
|
||||
|
||||
struct Controller {
|
||||
TR::Level *level;
|
||||
int entity;
|
||||
|
||||
enum Stand {
|
||||
STAND_AIR, STAND_GROUND, STAND_UNDERWATER, STAND_ONWATER
|
||||
STAND_AIR, STAND_GROUND, STAND_SLIDE, STAND_HANG, STAND_UNDERWATER, STAND_ONWATER
|
||||
} stand;
|
||||
int state;
|
||||
int mask;
|
||||
@ -54,7 +56,7 @@ struct Controller {
|
||||
pos = vec3((float)e.x, (float)e.y, (float)e.z);
|
||||
angle = vec3(0.0f, e.rotation, 0.0f);
|
||||
stand = STAND_GROUND;
|
||||
animIndex = e.modelIndex > 0 ? level->models[e.modelIndex - 1].animation : 0;
|
||||
animIndex = e.modelIndex > 0 ? getModel().animation : 0;
|
||||
state = level->anims[animIndex].state;
|
||||
}
|
||||
|
||||
@ -63,6 +65,8 @@ struct Controller {
|
||||
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;
|
||||
e.rotation = angle.y;
|
||||
}
|
||||
|
||||
@ -76,6 +80,10 @@ struct Controller {
|
||||
pos.z >= min.z && pos.z <= max.z;
|
||||
}
|
||||
|
||||
TR::Model& getModel() const {
|
||||
return level->models[getEntity().modelIndex - 1];
|
||||
}
|
||||
|
||||
TR::Entity& getEntity() const {
|
||||
return level->entities[entity];
|
||||
}
|
||||
@ -198,7 +206,7 @@ struct Controller {
|
||||
if (info.roomNext != 0xFF)
|
||||
entity.room = info.roomNext;
|
||||
|
||||
if (entity.y >= info.floor) {
|
||||
if (entity.y > info.floor) {
|
||||
if (info.roomBelow == 0xFF) {
|
||||
entity.y = info.floor;
|
||||
pos.y = entity.y;
|
||||
@ -275,6 +283,8 @@ struct Controller {
|
||||
virtual int getHeight() { return 0; }
|
||||
virtual int getStateAir() { return state; }
|
||||
virtual int getStateGround() { return state; }
|
||||
virtual int getStateSlide() { return state; }
|
||||
virtual int getStateHang() { return state; }
|
||||
virtual int getStateUnderwater() { return state; }
|
||||
virtual int getStateOnwater() { return state; }
|
||||
virtual int getStateDeath() { return state; }
|
||||
@ -290,6 +300,10 @@ struct Controller {
|
||||
state = getStateDeath();
|
||||
else if (stand == STAND_GROUND)
|
||||
state = getStateGround();
|
||||
else if (stand == STAND_SLIDE)
|
||||
state = getStateSlide();
|
||||
else if (stand == STAND_HANG)
|
||||
state = getStateHang();
|
||||
else if (stand == STAND_AIR)
|
||||
state = getStateAir();
|
||||
else if (stand == STAND_UNDERWATER)
|
||||
@ -317,10 +331,34 @@ struct Controller {
|
||||
|
||||
virtual void updateState() {}
|
||||
|
||||
virtual vec3 getAnimMove() {
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
int16 *ptr = &level->commands[anim->animCommand];
|
||||
|
||||
for (int i = 0; i < anim->acCount; i++) {
|
||||
int cmd = *ptr++;
|
||||
switch (cmd) {
|
||||
case TR::ANIM_CMD_MOVE : { // cmd position
|
||||
int16 sx = *ptr++;
|
||||
int16 sy = *ptr++;
|
||||
int16 sz = *ptr++;
|
||||
return vec3((float)sx, (float)sy, (float)sz);
|
||||
break;
|
||||
}
|
||||
case TR::ANIM_CMD_SPEED : // cmd jump speed
|
||||
case TR::ANIM_CMD_SOUND : // play sound
|
||||
case TR::ANIM_CMD_SPECIAL : // special commands
|
||||
ptr += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return vec3(0.0f);
|
||||
}
|
||||
|
||||
virtual void updateAnimation(bool commands) {
|
||||
int frameIndex = int((animTime += Core::deltaTime) * 30.0f);
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
bool endFrame = frameIndex > anim->frameEnd - anim->frameStart;
|
||||
bool endFrame = frameIndex > anim->frameEnd - anim->frameStart;
|
||||
|
||||
// apply animation commands
|
||||
if (commands) {
|
||||
@ -334,7 +372,7 @@ struct Controller {
|
||||
int16 sy = *ptr++;
|
||||
int16 sz = *ptr++;
|
||||
if (endFrame) {
|
||||
pos = pos + vec3(sx, sy, sz).rotateY(angle.y);
|
||||
pos = pos + vec3(sx, sy, sz).rotateY(-angle.y);
|
||||
updateEntity();
|
||||
LOG("move: %d %d %d\n", (int)sx, (int)sy, (int)sz);
|
||||
}
|
||||
@ -360,11 +398,9 @@ struct Controller {
|
||||
int frame = (*ptr++);
|
||||
int id = (*ptr++) & 0x3FFF;
|
||||
int idx = frame - anim->frameStart;
|
||||
|
||||
if (idx > animPrevFrame && idx <= frameIndex) {
|
||||
if (getEntity().id != TR::Entity::ENEMY_BAT) // temporary mute the bat
|
||||
playSound(id);
|
||||
}
|
||||
|
||||
if (idx > animPrevFrame && idx <= frameIndex)
|
||||
playSound(id);
|
||||
break;
|
||||
}
|
||||
case TR::ANIM_CMD_SPECIAL : // special commands
|
||||
@ -430,14 +466,14 @@ struct SpriteController : Controller {
|
||||
animTime += Core::deltaTime;
|
||||
|
||||
if (animated) {
|
||||
frame = int(animTime * 10.0f);
|
||||
frame = int(animTime * SPRITE_FPS);
|
||||
TR::SpriteSequence &seq = getSequence();
|
||||
if (instant && frame >= seq.sCount)
|
||||
remove = true;
|
||||
else
|
||||
frame %= seq.sCount;
|
||||
} else
|
||||
if (instant && animTime >= 0.1f)
|
||||
if (instant && animTime >= (1.0f / SPRITE_FPS))
|
||||
remove = true;
|
||||
|
||||
if (remove) {
|
||||
|
31
src/debug.h
31
src/debug.h
@ -138,6 +138,14 @@ namespace Debug {
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void line(const vec3 &a, const vec3 &b, const vec4 &color) {
|
||||
glBegin(GL_LINES);
|
||||
glColor4fv((GLfloat*)&color);
|
||||
glVertex3fv((GLfloat*)&a);
|
||||
glVertex3fv((GLfloat*)&b);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void text(const vec2 &pos, const vec4 &color, const char *str) {
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
@ -189,6 +197,8 @@ namespace Debug {
|
||||
|
||||
bool isPortal = false;
|
||||
|
||||
float fx = 0.0f, fz = 0.0f;
|
||||
|
||||
TR::FloorData *fd = &level.floors[floorIndex];
|
||||
TR::FloorData::Command cmd;
|
||||
do {
|
||||
@ -208,6 +218,9 @@ namespace Debug {
|
||||
auto &p = cmd.func == 0x02 ? vf : vc;
|
||||
|
||||
if (cmd.func == TR::FloorData::FLOOR) { // floor
|
||||
fx = (float)slant.x;
|
||||
fz = (float)slant.z;
|
||||
|
||||
if (sx > 0) {
|
||||
p[0].y += sx;
|
||||
p[3].y += sx;
|
||||
@ -283,6 +296,24 @@ namespace Debug {
|
||||
glVertex3f(x, c.y, z);
|
||||
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 c = 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*)&c);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void debugBox(const TR::Box &b) {
|
||||
|
21
src/format.h
21
src/format.h
@ -33,6 +33,7 @@ namespace TR {
|
||||
|
||||
enum {
|
||||
SND_NO = 2,
|
||||
SND_LANDING = 4,
|
||||
SND_BUBBLE = 37,
|
||||
SND_SECRET = 173,
|
||||
};
|
||||
@ -280,7 +281,7 @@ namespace TR {
|
||||
TRAP_FLOOR = 35,
|
||||
TRAP_BLADE = 36,
|
||||
TRAP_SPIKES = 37,
|
||||
TRAP_STONE = 38,
|
||||
TRAP_BOULDER = 38,
|
||||
TRAP_DART = 39,
|
||||
TRAP_DARTGUN = 40,
|
||||
|
||||
@ -633,6 +634,7 @@ namespace TR {
|
||||
|
||||
struct FloorInfo {
|
||||
int floor, ceiling;
|
||||
int slantX, slantZ;
|
||||
int roomNext, roomBelow, roomAbove;
|
||||
int floorIndex;
|
||||
int kill;
|
||||
@ -640,6 +642,19 @@ namespace TR {
|
||||
Trigger trigger;
|
||||
FloorData::TriggerInfo trigInfo;
|
||||
FloorData::TriggerCommand trigCmd[16];
|
||||
|
||||
vec3 getNormal() {
|
||||
return vec3((float)-slantX, -4.0f, (float)-slantZ).normal();
|
||||
}
|
||||
|
||||
vec3 getSlant(const vec3 &dir) {
|
||||
// project floor normal into plane(dir, up)
|
||||
vec3 r = vec3(dir.z, 0.0f, -dir.x); // up(0, 1, 0).cross(dir)
|
||||
vec3 n = getNormal();
|
||||
n = n - r * r.dot(n);
|
||||
// project dir into plane(dir, n)
|
||||
return n.cross(dir.cross(n)).normal();
|
||||
}
|
||||
};
|
||||
|
||||
bool secrets[MAX_SECRETS_COUNT];
|
||||
@ -891,6 +906,8 @@ namespace TR {
|
||||
|
||||
info.floor = 256 * (int)s.floor;
|
||||
info.ceiling = 256 * (int)s.ceiling;
|
||||
info.slantX = 0;
|
||||
info.slantZ = 0;
|
||||
info.roomNext = 255;
|
||||
info.roomBelow = s.roomBelow;
|
||||
info.roomAbove = s.roomAbove;
|
||||
@ -919,6 +936,8 @@ namespace TR {
|
||||
int sx = (int)slant.x;
|
||||
int sz = (int)slant.z;
|
||||
if (cmd.func == FloorData::FLOOR) {
|
||||
info.slantX = sx;
|
||||
info.slantZ = sz;
|
||||
info.floor -= sx * (sx > 0 ? (dx - 1024) : dx) >> 2;
|
||||
info.floor -= sz * (sz > 0 ? (dz - 1024) : dz) >> 2;
|
||||
} else {
|
||||
|
292
src/lara.h
292
src/lara.h
@ -17,6 +17,8 @@
|
||||
|
||||
#define MAX_TRIGGER_ACTIONS 64
|
||||
|
||||
#define DESCENT_SPEED 2048.0f
|
||||
|
||||
struct Lara : Controller {
|
||||
|
||||
ActionCommand actionList[MAX_TRIGGER_ACTIONS];
|
||||
@ -24,19 +26,39 @@ struct Lara : Controller {
|
||||
// http://www.tombraiderforums.com/showthread.php?t=148859
|
||||
enum {
|
||||
ANIM_STAND = 11,
|
||||
|
||||
ANIM_CLIMB_JUMP = 26,
|
||||
|
||||
ANIM_FALL = 34,
|
||||
ANIM_SMASH_JUMP = 32,
|
||||
|
||||
ANIM_CLIMB_3 = 42,
|
||||
|
||||
ANIM_CLIMB_2 = 50,
|
||||
|
||||
ANIM_SMASH_RUN_LEFT = 53,
|
||||
ANIM_SMASH_RUN_RIGHT = 54,
|
||||
ANIM_RUN_ASCEND_LEFT = 55,
|
||||
ANIM_RUN_ASCEND_RIGHT = 56,
|
||||
ANIM_WALK_ASCEND_LEFT = 57,
|
||||
ANIM_WALK_ASCEND_RIGHT = 58,
|
||||
ANIM_WALK_DESCEND_RIGHT = 59,
|
||||
ANIM_WALK_DESCEND_LEFT = 60,
|
||||
ANIM_BACK_DESCEND_LEFT = 61,
|
||||
ANIM_BACK_DESCEND_RIGHT = 62,
|
||||
|
||||
ANIM_SLIDE_FORTH = 70,
|
||||
ANIM_SLIDE_BACK = 105,
|
||||
|
||||
ANIM_WATER_FALL = 112,
|
||||
ANIM_TO_ONWATER = 114,
|
||||
ANIM_STAND_ROLL_BEGIN = 146,
|
||||
ANIM_STAND_ROLL_END = 147,
|
||||
ANIM_TO_UNDERWATER = 119,
|
||||
ANIM_HIT_FRONT = 125,
|
||||
ANIM_HIT_BACK = 126,
|
||||
ANIM_HIT_LEFT = 127,
|
||||
ANIM_HIT_RIGHT = 128,
|
||||
ANIM_STAND_ROLL_BEGIN = 146,
|
||||
ANIM_STAND_ROLL_END = 147,
|
||||
};
|
||||
|
||||
// http://www.tombraiderforums.com/showthread.php?t=211681
|
||||
@ -60,7 +82,7 @@ struct Lara : Controller {
|
||||
STATE_BACK,
|
||||
STATE_SWIM,
|
||||
STATE_GLIDE,
|
||||
STATE_NULL_19,
|
||||
STATE_HANG_JUMP,
|
||||
STATE_FAST_TURN,
|
||||
STATE_STEP_RIGHT,
|
||||
STATE_STEP_LEFT,
|
||||
@ -127,10 +149,6 @@ struct Lara : Controller {
|
||||
// updateEntity();
|
||||
}
|
||||
|
||||
bool isMovingState(int state) {
|
||||
return state == STATE_RUN || state == STATE_FAST_BACK || state == STATE_ROLL || state == STATE_WALK || state == STATE_STEP_LEFT || state == STATE_STEP_RIGHT;
|
||||
}
|
||||
|
||||
bool waterOut(int &outState) {
|
||||
// TODO: playSound 36
|
||||
vec3 dst = pos + getDir() * 32.0f;
|
||||
@ -181,14 +199,14 @@ struct Lara : Controller {
|
||||
actionState = (isActive && stand == STAND_GROUND) ? STATE_SWITCH_UP : STATE_SWITCH_DOWN;
|
||||
if ((mask & ACTION) == 0 || state == actionState)
|
||||
return;
|
||||
if (fabsf(level->entities[info.trigCmd[0].args].rotation - e.rotation) > PI * 0.25f)
|
||||
if (fabsf(shortAngle(level->entities[info.trigCmd[0].args].rotation, e.rotation)) > PI * 0.25f) // TODO clamp angles
|
||||
return;
|
||||
break;
|
||||
case TR::Level::Trigger::KEY :
|
||||
actionState = STATE_USE_KEY;
|
||||
if (isActive || (mask & ACTION) == 0 || state == actionState) // TODO: STATE_USE_PUZZLE
|
||||
return;
|
||||
if (fabsf(level->entities[info.trigCmd[0].args].rotation - e.rotation) > PI * 0.25f)
|
||||
if (fabsf(shortAngle(level->entities[info.trigCmd[0].args].rotation, e.rotation)) > PI * 0.25f) // TODO clamp angles
|
||||
return;
|
||||
break;
|
||||
case TR::Level::Trigger::PICKUP :
|
||||
@ -208,6 +226,7 @@ struct Lara : Controller {
|
||||
angle.y = p.rotation;
|
||||
angle.x = 0;
|
||||
pos = vec3(p.x, p.y, p.z) + vec3(sinf(angle.y), 0, cosf(angle.y)) * (stand == STAND_GROUND ? 384 : 128);
|
||||
velocity = vec3(0.0f);
|
||||
updateEntity();
|
||||
}
|
||||
|
||||
@ -245,6 +264,70 @@ struct Lara : Controller {
|
||||
activateNext();
|
||||
}
|
||||
|
||||
vec3 getViewOffset() {
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
TR::Model &model = getModel();
|
||||
|
||||
float k = animTime * 30.0f / anim->frameRate;
|
||||
int fIndex = (int)k;
|
||||
int fCount = (anim->frameEnd - anim->frameStart) / anim->frameRate + 1;
|
||||
|
||||
int fSize = sizeof(TR::AnimFrame) + model.mCount * sizeof(uint16) * 2;
|
||||
k = k - fIndex;
|
||||
|
||||
int fIndexA = fIndex % fCount, fIndexB = (fIndex + 1) % fCount;
|
||||
TR::AnimFrame *frameA = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexA * fSize) >> 1];
|
||||
|
||||
TR::Animation *nextAnim = NULL;
|
||||
|
||||
vec3 move(0.0f);
|
||||
if (fIndexB == 0) {
|
||||
move = getAnimMove();
|
||||
nextAnim = &level->anims[anim->nextAnimation];
|
||||
fIndexB = (anim->nextFrame - nextAnim->frameStart) / nextAnim->frameRate;
|
||||
} else
|
||||
nextAnim = anim;
|
||||
|
||||
TR::AnimFrame *frameB = (TR::AnimFrame*)&level->frameData[(nextAnim->frameOffset + fIndexB * fSize) >> 1];
|
||||
|
||||
float h = ((vec3)frameA->pos).lerp(move + frameB->pos, k).y;
|
||||
|
||||
switch (stand) {
|
||||
case Controller::STAND_AIR :
|
||||
case Controller::STAND_GROUND :
|
||||
case Controller::STAND_SLIDE :
|
||||
case Controller::STAND_HANG :
|
||||
h -= 256.0f;
|
||||
break;
|
||||
case Controller::STAND_UNDERWATER :
|
||||
case Controller::STAND_ONWATER :
|
||||
h -= 128.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return vec3(0.0f, h, 0.0f);
|
||||
|
||||
/*
|
||||
|
||||
|
||||
return offset;
|
||||
*/
|
||||
/*
|
||||
switch (stand) {
|
||||
case Controller::STAND_AIR :
|
||||
case Controller::STAND_GROUND :
|
||||
case Controller::STAND_SLIDE :
|
||||
case Controller::STAND_HANG :
|
||||
offset.y = 768.0f;
|
||||
break;
|
||||
case Controller::STAND_UNDERWATER :
|
||||
case Controller::STAND_ONWATER :
|
||||
offset.y = 256.0f;
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
|
||||
virtual Stand getStand() {
|
||||
if (stand == STAND_ONWATER && state != STATE_DIVE && state != STATE_STOP)
|
||||
return stand;
|
||||
@ -252,11 +335,20 @@ struct Lara : Controller {
|
||||
if (getRoom().flags & TR::ROOM_FLAG_WATER)
|
||||
return STAND_UNDERWATER; // TODO: ONWATER
|
||||
|
||||
int extra = isMovingState(state) ? 256 : 0;
|
||||
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||
|
||||
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 (stand == STAND_AIR)
|
||||
playSound(TR::SND_LANDING);
|
||||
return STAND_SLIDE;
|
||||
}
|
||||
}
|
||||
|
||||
int extra = stand != STAND_AIR ? 256 : 0;
|
||||
|
||||
if (info.roomBelow == 0xFF && e.y + extra >= info.floor)
|
||||
return STAND_GROUND;
|
||||
|
||||
@ -283,7 +375,8 @@ struct Lara : Controller {
|
||||
}
|
||||
|
||||
virtual int getStateGround() {
|
||||
angle.x = 0.0f;
|
||||
angle.x = 0.0f;
|
||||
|
||||
/*
|
||||
// hit test
|
||||
if (animIndex != ANIM_HIT_FRONT)
|
||||
@ -314,7 +407,11 @@ struct Lara : Controller {
|
||||
if (mask & JUMP) {
|
||||
if ((mask & FORTH) && state == STATE_FORWARD_JUMP)
|
||||
return STATE_RUN;
|
||||
return state == STATE_RUN ? STATE_FORWARD_JUMP : STATE_COMPRESS;
|
||||
if (state == STATE_RUN)
|
||||
return STATE_FORWARD_JUMP;
|
||||
if (animIndex == ANIM_SLIDE_BACK)
|
||||
return STATE_SLIDE_BACK;
|
||||
return STATE_COMPRESS;
|
||||
}
|
||||
|
||||
// walk button is pressed
|
||||
@ -324,14 +421,69 @@ struct Lara : Controller {
|
||||
if (mask & LEFT) return STATE_STEP_LEFT;
|
||||
if (mask & RIGHT) return STATE_STEP_RIGHT;
|
||||
return STATE_STOP;
|
||||
}
|
||||
|
||||
// only dpad buttons pressed
|
||||
if (mask & FORTH) return STATE_RUN;
|
||||
if (mask & BACK) return STATE_FAST_BACK;
|
||||
if (mask & LEFT) return turnTime < FAST_TURN_TIME ? STATE_TURN_LEFT : STATE_FAST_TURN;
|
||||
if (mask & RIGHT) return turnTime < FAST_TURN_TIME ? STATE_TURN_RIGHT : STATE_FAST_TURN;
|
||||
return STATE_STOP;
|
||||
}
|
||||
|
||||
if ( (mask & (FORTH | ACTION)) == (FORTH | ACTION) ) {
|
||||
vec3 p = pos + getDir() * 64.0f;
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getRoomIndex(), (int)p.x, (int)p.z, info);
|
||||
int h = (int)pos.y - info.floor;
|
||||
if (h >= 2 * 256 - 16 && h <= 2 * 256 + 16 && animIndex != ANIM_CLIMB_2)
|
||||
return setAnimation(ANIM_CLIMB_2);
|
||||
if (h >= 3 * 256 - 16 && h <= 3 * 256 + 16 && animIndex != ANIM_CLIMB_3)
|
||||
return setAnimation(ANIM_CLIMB_3);
|
||||
if (h >= 4 * 256 - 16 && h <= 7 * 256 + 16 && state != STATE_HANG_JUMP)
|
||||
return setAnimation(ANIM_CLIMB_JUMP);
|
||||
}
|
||||
|
||||
// only dpad buttons pressed
|
||||
if (mask & FORTH) return STATE_RUN;
|
||||
if (mask & BACK) return STATE_FAST_BACK;
|
||||
if (mask & LEFT) return turnTime < FAST_TURN_TIME ? STATE_TURN_LEFT : STATE_FAST_TURN;
|
||||
if (mask & RIGHT) return turnTime < FAST_TURN_TIME ? STATE_TURN_RIGHT : STATE_FAST_TURN;
|
||||
return STATE_STOP;
|
||||
}
|
||||
|
||||
virtual int getStateSlide() {
|
||||
|
||||
TR::Entity &e = getEntity();
|
||||
|
||||
if (state != STATE_SLIDE && state != STATE_SLIDE_BACK) {
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||
|
||||
int sx = abs(info.slantX), sz = abs(info.slantZ);
|
||||
// get direction
|
||||
float dir;
|
||||
if (sx > sz)
|
||||
dir = info.slantX > 0 ? 3.0f : 1.0f;
|
||||
else
|
||||
dir = info.slantZ > 0 ? 2.0f : 0.0f;
|
||||
dir *= PI * 0.5f;
|
||||
|
||||
int aIndex = ANIM_SLIDE_FORTH;
|
||||
if (fabsf(shortAngle(dir, angle.y)) > PI * 0.5f) {
|
||||
aIndex = ANIM_SLIDE_BACK;
|
||||
dir += PI;
|
||||
}
|
||||
|
||||
angle.y = dir;
|
||||
updateEntity();
|
||||
return setAnimation(aIndex);
|
||||
}
|
||||
|
||||
if (mask & JUMP) {
|
||||
stand = STAND_GROUND;
|
||||
pos.y -= 16;
|
||||
updateEntity();
|
||||
return state == STATE_SLIDE ? STATE_FORWARD_JUMP : STATE_BACK_JUMP;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
virtual int getStateHang() {
|
||||
return Controller::getStateHang();
|
||||
}
|
||||
|
||||
virtual int getStateUnderwater() {
|
||||
@ -417,11 +569,13 @@ struct Lara : Controller {
|
||||
if (Input::down[ikEnter]) {
|
||||
if (!lState) {
|
||||
lState = true;
|
||||
/*
|
||||
static int snd_id = 0;//160;
|
||||
playSound(snd_id);
|
||||
*/
|
||||
// setAnimation(snd_id);
|
||||
LOG("sound: %d\n", snd_id++);
|
||||
/*
|
||||
//LOG("sound: %d\n", snd_id++);
|
||||
|
||||
LOG("state: %d\n", anim->state);
|
||||
for (int i = 0; i < anim->scCount; i++) {
|
||||
auto &sc = level->states[anim->scOffset + i];
|
||||
@ -432,7 +586,7 @@ struct Lara : Controller {
|
||||
}
|
||||
LOG("\n");
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
@ -486,6 +640,7 @@ struct Lara : Controller {
|
||||
case STATE_SURF_BACK :
|
||||
case STATE_BACK_JUMP :
|
||||
case STATE_FAST_BACK :
|
||||
case STATE_SLIDE_BACK :
|
||||
angleExt += PI;
|
||||
break;
|
||||
case STATE_LEFT_JUMP :
|
||||
@ -514,7 +669,9 @@ struct Lara : Controller {
|
||||
case STAND_AIR :
|
||||
velocity.y += GRAVITY * dt;
|
||||
break;
|
||||
case STAND_GROUND :
|
||||
case STAND_GROUND :
|
||||
case STAND_SLIDE :
|
||||
case STAND_HANG :
|
||||
case STAND_ONWATER : {
|
||||
|
||||
float speed = 0.0f;
|
||||
@ -531,12 +688,18 @@ struct Lara : Controller {
|
||||
speed = -speed;
|
||||
}
|
||||
|
||||
velocity.x = sinf(angleExt) * speed;
|
||||
velocity.z = cosf(angleExt) * speed;
|
||||
if (stand == STAND_GROUND)
|
||||
velocity.y += GRAVITY * dt;
|
||||
else
|
||||
if (stand == STAND_ONWATER) {
|
||||
velocity.x = sinf(angleExt) * speed;
|
||||
velocity.z = cosf(angleExt) * speed;
|
||||
velocity.y = 0.0f;
|
||||
} else {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.z, info);
|
||||
|
||||
vec3 v(sinf(angleExt), 0.0f, cosf(angleExt));
|
||||
velocity = info.getSlant(v) * speed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STAND_UNDERWATER : {
|
||||
@ -563,7 +726,7 @@ struct Lara : Controller {
|
||||
|
||||
vec3 p = pos;
|
||||
pos = pos + offset;
|
||||
|
||||
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getEntity().room, (int)pos.x, (int)pos.z, info);
|
||||
|
||||
@ -573,6 +736,8 @@ struct Lara : Controller {
|
||||
int height = getHeight();
|
||||
bool canPassGap;
|
||||
|
||||
float h = info.floor - pos.y;
|
||||
|
||||
switch (stand) {
|
||||
case STAND_AIR :
|
||||
canPassGap = ((int)p.y - d) <= 512 && (info.roomAbove != 0xFF || (pos.y - height - info.ceiling > -256));
|
||||
@ -585,12 +750,19 @@ struct Lara : Controller {
|
||||
break;
|
||||
}
|
||||
default : // TODO: height
|
||||
if (state == STATE_WALK || state == STATE_BACK || state == STATE_STEP_LEFT || state == STATE_STEP_RIGHT)
|
||||
canPassGap = delta <= 256;
|
||||
if (state == STATE_WALK || state == STATE_BACK)
|
||||
canPassGap = h >= -256 && h <= 256;
|
||||
else
|
||||
canPassGap = delta >= -256 - 16;
|
||||
if (state == STATE_STEP_LEFT || state == STATE_STEP_RIGHT)
|
||||
canPassGap = h >= -128 && h <= 128;
|
||||
else
|
||||
canPassGap = h >= -256 - 16;
|
||||
}
|
||||
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
int frame = int(animTime * 30.0f);
|
||||
bool left = (anim->frameEnd - anim->frameStart) / 2 > frame;
|
||||
|
||||
if (d == NO_OVERLAP || !canPassGap) {
|
||||
pos = p; // TODO: use smart ejection
|
||||
|
||||
@ -602,22 +774,56 @@ struct Lara : Controller {
|
||||
velocity.x = -velocity.x * 0.5f;
|
||||
velocity.z = -velocity.z * 0.5f;
|
||||
velocity.y = 0.0f;
|
||||
} else
|
||||
} else {
|
||||
velocity.x = velocity.z = 0.0f;
|
||||
pos.y = p.y;
|
||||
updateEntity();
|
||||
}
|
||||
break;
|
||||
case STAND_GROUND :
|
||||
if (delta <= -256 * 4 && state == STATE_RUN)
|
||||
setAnimation(ANIM_SMASH_RUN_LEFT); // TODO: RIGHT
|
||||
else
|
||||
setAnimation(ANIM_STAND);
|
||||
if (state != STATE_UP_JUMP) { // early stage of up jump
|
||||
if (delta <= -256 * 4 && state == STATE_RUN)
|
||||
setAnimation(left ? ANIM_SMASH_RUN_LEFT : ANIM_SMASH_RUN_RIGHT);
|
||||
else
|
||||
setAnimation(ANIM_STAND);
|
||||
} else {
|
||||
pos.y = p.y;
|
||||
updateEntity();
|
||||
}
|
||||
velocity.x = velocity.z = 0.0f;
|
||||
break;
|
||||
case STAND_UNDERWATER :
|
||||
case STAND_ONWATER :
|
||||
break;
|
||||
default : ;// no smash animation
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
if (state == STATE_RUN || state == STATE_WALK || state == STATE_BACK || state == STATE_ROLL) {
|
||||
if (h <= -128 && h >= -256) { // ascend
|
||||
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 (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;
|
||||
setAnimation(ANIM_FALL);
|
||||
} else
|
||||
pos.y += DESCENT_SPEED * Core::deltaTime;
|
||||
}
|
||||
|
||||
|
||||
updateEntity();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
13
src/level.h
13
src/level.h
@ -86,9 +86,11 @@ struct Level {
|
||||
case TR::Entity::TRAP_FLOOR :
|
||||
case TR::Entity::TRAP_BLADE :
|
||||
case TR::Entity::TRAP_SPIKES :
|
||||
case TR::Entity::TRAP_STONE :
|
||||
entity.controller = new Trigger(&level, i, true);
|
||||
break;
|
||||
case TR::Entity::TRAP_BOULDER :
|
||||
entity.controller = new Boulder(&level, i);
|
||||
break;
|
||||
case TR::Entity::TRAP_DARTGUN :
|
||||
entity.controller = new Dartgun(&level, i);
|
||||
break;
|
||||
@ -386,12 +388,15 @@ struct Level {
|
||||
|
||||
TR::Animation *nextAnim = NULL;
|
||||
|
||||
vec3 move(0.0f);
|
||||
if (fIndexB == 0) {
|
||||
if (controller)
|
||||
move = controller->getAnimMove();
|
||||
nextAnim = &level.anims[anim->nextAnimation];
|
||||
fIndexB = (anim->nextFrame - nextAnim->frameStart) / nextAnim->frameRate;
|
||||
} else
|
||||
nextAnim = anim;
|
||||
|
||||
|
||||
TR::AnimFrame *frameB = (TR::AnimFrame*)&level.frameData[(nextAnim->frameOffset + fIndexB * fSize) >> 1];
|
||||
|
||||
vec3 bmin = frameA->box.min().lerp(frameB->box.min(), k);
|
||||
@ -403,7 +408,7 @@ struct Level {
|
||||
|
||||
mat4 m;
|
||||
m.identity();
|
||||
m.translate(((vec3)frameA->pos).lerp(frameB->pos, k));
|
||||
m.translate(((vec3)frameA->pos).lerp(move + frameB->pos, k));
|
||||
|
||||
int sIndex = 0;
|
||||
mat4 stack[20];
|
||||
@ -601,7 +606,7 @@ struct Level {
|
||||
// Debug::Level::lights(level);
|
||||
// Debug::Level::portals(level);
|
||||
// Debug::Level::meshes(level);
|
||||
Debug::Level::entities(level);
|
||||
// Debug::Level::entities(level);
|
||||
Debug::Level::info(level, lara->getEntity());
|
||||
Debug::end();
|
||||
#endif
|
||||
|
@ -88,7 +88,7 @@ varying vec4 vColor;
|
||||
// fog
|
||||
float fog = clamp(1.0 / exp(gl_FragCoord.z / gl_FragCoord.w * 0.000025), 0.0, 1.0);
|
||||
|
||||
gl_FragColor = mix(vec4(0.0), color, fog);
|
||||
gl_FragColor = mix(vec4(0.0, 0.0, 0.0, 1.0), color, fog);
|
||||
}
|
||||
#endif
|
||||
)===="
|
@ -380,8 +380,10 @@ namespace Sound {
|
||||
if (!stream) return;
|
||||
if (channelsCount < SND_CHANNELS_MAX)
|
||||
channels[channelsCount++] = new Sample(stream, volume, pitch, flags);
|
||||
else
|
||||
LOG("! no free channels\n");
|
||||
else {
|
||||
LOG("! no free channels\n");
|
||||
delete stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,8 +109,10 @@ struct Dartgun : Trigger {
|
||||
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);
|
||||
if (smokeIndex > -1)
|
||||
if (smokeIndex > -1) {
|
||||
level->entities[smokeIndex].intensity = 0x1FFF - level->rooms[entity.room].ambient;
|
||||
level->entities[smokeIndex].controller = new SpriteController(level, smokeIndex);
|
||||
}
|
||||
|
||||
playSound(151);
|
||||
|
||||
@ -119,4 +121,16 @@ struct Dartgun : Trigger {
|
||||
|
||||
};
|
||||
|
||||
struct Boulder : Trigger {
|
||||
|
||||
Boulder(TR::Level *level, int entity) : Trigger(level, entity, true) {}
|
||||
|
||||
virtual void update() {
|
||||
if (getEntity().flags & ENTITY_FLAG_ACTIVE) {
|
||||
updateAnimation(true);
|
||||
updateEntity();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
21
src/utils.h
21
src/utils.h
@ -25,6 +25,7 @@
|
||||
|
||||
|
||||
#define PI 3.14159265358979323846f
|
||||
#define PI2 (PI * 2.0f)
|
||||
#define DEG2RAD (PI / 180.0f)
|
||||
#define RAD2DEG (180.0f / PI)
|
||||
#define EPS FLT_EPSILON
|
||||
@ -74,6 +75,16 @@ inline const int sign(const T &x) {
|
||||
return x > 0 ? 1 : (x < 0 ? -1 : 0);
|
||||
}
|
||||
|
||||
float clampAngle(float a) {
|
||||
return a < -PI ? a + PI2 : (a >= PI ? a - PI2 : a);
|
||||
}
|
||||
|
||||
float shortAngle(float a, float b) {
|
||||
float n = clampAngle(b) - clampAngle(a);
|
||||
return clampAngle(n - int(n / PI2) * PI2);
|
||||
}
|
||||
|
||||
|
||||
struct vec2 {
|
||||
float x, y;
|
||||
vec2() {}
|
||||
@ -110,7 +121,7 @@ struct vec3 {
|
||||
vec3 cross(const vec3 &v) const { return vec3(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x); }
|
||||
float length2() const { return dot(*this); }
|
||||
float length() const { return sqrtf(length2()); }
|
||||
vec3 normal() const { float s = length(); return s == 0.0 ? (*this) : (*this)*(1.0f/s); }
|
||||
vec3 normal() const { float s = length(); return s == 0.0f ? (*this) : (*this)*(1.0f/s); }
|
||||
|
||||
vec3 lerp(const vec3 &v, const float t) const {
|
||||
if (t <= 0.0f) return *this;
|
||||
@ -227,10 +238,10 @@ struct quat {
|
||||
temp = q;
|
||||
|
||||
if (1.0f - cosom > EPS) {
|
||||
omega = acos(cosom);
|
||||
sinom = 1.0f / sin(omega);
|
||||
scale0 = sin((1.0f - t) * omega) * sinom;
|
||||
scale1 = sin(t * omega) * sinom;
|
||||
omega = acosf(cosom);
|
||||
sinom = 1.0f / sinf(omega);
|
||||
scale0 = sinf((1.0f - t) * omega) * sinom;
|
||||
scale1 = sinf(t * omega) * sinom;
|
||||
} else {
|
||||
scale0 = 1.0f - t;
|
||||
scale1 = t;
|
||||
|
Loading…
x
Reference in New Issue
Block a user