mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-01 02:40:43 +02:00
#7 pistols aiming
This commit is contained in:
@@ -22,7 +22,7 @@ struct Camera : Controller {
|
||||
vec3 viewOffset;
|
||||
|
||||
Camera(TR::Level *level, Lara *owner) : Controller(level, owner ? owner->entity : 0), owner(owner), frustum(new Frustum()), timer(0.0f), actTargetEntity(-1), actCamera(-1) {
|
||||
fov = 75.0f;
|
||||
fov = 80.0f;
|
||||
znear = 128;
|
||||
zfar = 100.0f * 1024.0f;
|
||||
angleAdv = vec3(0.0f);
|
||||
@@ -57,6 +57,8 @@ struct Camera : Controller {
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
actTargetEntity = owner->target;
|
||||
|
||||
if (timer > 0.0f) {
|
||||
timer -= Core::deltaTime;
|
||||
if (timer <= 0.0f) {
|
||||
|
141
src/controller.h
141
src/controller.h
@@ -96,6 +96,89 @@ struct Controller {
|
||||
}
|
||||
}
|
||||
|
||||
int getFrameIndex(int animIndex, float t) {
|
||||
TR::Animation &anim = level->anims[animIndex];
|
||||
return int(t * 30.0f / anim.frameRate) % ((anim.frameEnd - anim.frameStart) / anim.frameRate + 1);
|
||||
}
|
||||
|
||||
void getFrames(TR::AnimFrame **frameA, TR::AnimFrame **frameB, float &t, int animIndex, float animTime, bool nextAnim = false, vec3 *move = NULL) {
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
|
||||
t = animTime * 30.0f / anim->frameRate;
|
||||
int fIndex = (int)t;
|
||||
int fCount = (anim->frameEnd - anim->frameStart) / anim->frameRate + 1;
|
||||
|
||||
int fSize = sizeof(TR::AnimFrame) + getModel().mCount * sizeof(uint16) * 2;
|
||||
t -= fIndex;
|
||||
|
||||
int fIndexA = fIndex % fCount, fIndexB = (fIndex + 1) % fCount;
|
||||
*frameA = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexA * fSize) >> 1];
|
||||
|
||||
if (!fIndexB) {
|
||||
if (move)
|
||||
*move = getAnimMove();
|
||||
if (nextAnim) {
|
||||
int nextFrame = anim->nextFrame;
|
||||
anim = &level->anims[anim->nextAnimation];
|
||||
fIndexB = (nextFrame - anim->frameStart) / anim->frameRate;
|
||||
}
|
||||
}
|
||||
*frameB = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexB * fSize) >> 1];
|
||||
}
|
||||
|
||||
mat4 getJoint(int index, bool postRot = false) {
|
||||
mat4 matrix;
|
||||
matrix.identity();
|
||||
|
||||
matrix.translate(pos);
|
||||
if (angle.y != 0.0f) matrix.rotateY(angle.y);
|
||||
if (angle.x != 0.0f) matrix.rotateX(angle.x);
|
||||
if (angle.z != 0.0f) matrix.rotateZ(angle.z);
|
||||
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
TR::Model &model = getModel();
|
||||
|
||||
float t;
|
||||
vec3 move(0.0f);
|
||||
TR::AnimFrame *frameA, *frameB;
|
||||
getFrames(&frameA, &frameB, t, animIndex, animTime, true, &move);
|
||||
|
||||
TR::Node *node = (int)model.node < level->nodesDataSize ? (TR::Node*)&level->nodesData[model.node] : NULL;
|
||||
|
||||
matrix.translate(((vec3)frameA->pos).lerp(move + frameB->pos, t));
|
||||
|
||||
int sIndex = 0;
|
||||
mat4 stack[20];
|
||||
|
||||
for (int i = 0; i < model.mCount; i++) {
|
||||
|
||||
if (i > 0 && node) {
|
||||
TR::Node &t = node[i - 1];
|
||||
|
||||
if (t.flags & 0x01) matrix = stack[--sIndex];
|
||||
if (t.flags & 0x02) stack[sIndex++] = matrix;
|
||||
|
||||
ASSERT(sIndex >= 0 && sIndex < 20);
|
||||
|
||||
matrix.translate(vec3(t.x, t.y, t.z));
|
||||
}
|
||||
|
||||
if (i == index && !postRot)
|
||||
return matrix;
|
||||
|
||||
quat q;
|
||||
if (animOverrideMask & (1 << i))
|
||||
q = animOverrides[i];
|
||||
else
|
||||
q = lerpAngle(frameA->getAngle(i), frameB->getAngle(i), t);
|
||||
matrix = matrix * mat4(q, vec3(0.0f));
|
||||
|
||||
if (i == index && postRot)
|
||||
return matrix;
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void updateEntity() {
|
||||
TR::Entity &e = getEntity();
|
||||
e.x = int(pos.x);
|
||||
@@ -265,20 +348,11 @@ struct Controller {
|
||||
}
|
||||
|
||||
virtual Box getBoundingBox() {
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
TR::Model &model = getModel();
|
||||
float t;
|
||||
TR::AnimFrame *frameA, *frameB;
|
||||
getFrames(&frameA, &frameB, t, animIndex, animTime, true);
|
||||
|
||||
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 *fA = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexA * fSize) >> 1];
|
||||
TR::AnimFrame *fB = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexB * fSize) >> 1];
|
||||
Box box(fA->box.min().lerp(fB->box.min(), k), fA->box.max().lerp(fB->box.max(), k));
|
||||
Box box(frameA->box.min().lerp(frameB->box.min(), t), frameA->box.max().lerp(frameB->box.max(), t));
|
||||
box.rotate90(getEntity().rotation.value / 0x4000);
|
||||
box.min += pos;
|
||||
box.max += pos;
|
||||
@@ -625,44 +699,19 @@ struct Controller {
|
||||
TR::Entity &entity = getEntity();
|
||||
TR::Model &model = getModel();
|
||||
|
||||
TR::Animation *anim;
|
||||
float fTime;
|
||||
vec3 angle;
|
||||
|
||||
Controller *controller = (Controller*)entity.controller;
|
||||
|
||||
anim = &level->anims[controller->animIndex];
|
||||
angle = controller->angle;
|
||||
fTime = controller->animTime;
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
|
||||
if (angle.y != 0.0f) Core::mModel.rotateY(angle.y);
|
||||
if (angle.x != 0.0f) Core::mModel.rotateX(angle.x);
|
||||
if (angle.z != 0.0f) Core::mModel.rotateZ(angle.z);
|
||||
|
||||
float k = fTime * 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;
|
||||
|
||||
float t;
|
||||
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];
|
||||
TR::AnimFrame *frameA, *frameB;
|
||||
getFrames(&frameA, &frameB, t, animIndex, animTime, true, &move);
|
||||
|
||||
vec3 bmin = frameA->box.min().lerp(frameB->box.min(), k);
|
||||
vec3 bmax = frameA->box.max().lerp(frameB->box.max(), k);
|
||||
vec3 bmin = frameA->box.min().lerp(frameB->box.min(), t);
|
||||
vec3 bmax = frameA->box.max().lerp(frameB->box.max(), t);
|
||||
if (frustum && !frustum->isVisible(Core::mModel, bmin, bmax))
|
||||
return;
|
||||
|
||||
@@ -670,7 +719,7 @@ struct Controller {
|
||||
|
||||
mat4 m;
|
||||
m.identity();
|
||||
m.translate(((vec3)frameA->pos).lerp(move + frameB->pos, k));
|
||||
m.translate(((vec3)frameA->pos).lerp(move + frameB->pos, t));
|
||||
|
||||
int sIndex = 0;
|
||||
mat4 stack[20];
|
||||
@@ -692,7 +741,7 @@ struct Controller {
|
||||
if (animOverrideMask & (1 << i))
|
||||
q = animOverrides[i];
|
||||
else
|
||||
q = lerpAngle(frameA->getAngle(i), frameB->getAngle(i), k);
|
||||
q = lerpAngle(frameA->getAngle(i), frameB->getAngle(i), t);
|
||||
m = m * mat4(q, vec3(0.0f));
|
||||
|
||||
mat4 tmp = Core::mModel;
|
||||
|
@@ -415,6 +415,10 @@ namespace TR {
|
||||
uint16 align;
|
||||
int16 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays
|
||||
void *controller; // Controller implementation or NULL
|
||||
|
||||
bool isEnemy() {
|
||||
return type >= ENEMY_TWIN && type <= ENEMY_LARSON;
|
||||
}
|
||||
};
|
||||
|
||||
struct Animation {
|
||||
|
632
src/lara.h
632
src/lara.h
@@ -25,6 +25,8 @@
|
||||
#define MAX_TRIGGER_ACTIONS 64
|
||||
|
||||
#define DESCENT_SPEED 2048.0f
|
||||
#define MUZZLE_FLASH_TIME 0.1f
|
||||
#define TARGET_MAX_DIST (8.0f * 1024.0f)
|
||||
|
||||
struct Lara : Controller {
|
||||
|
||||
@@ -141,19 +143,19 @@ struct Lara : Controller {
|
||||
|
||||
enum : int {
|
||||
BODY_HIP = 0x0001,
|
||||
BODY_LEG_R1 = 0x0002,
|
||||
BODY_LEG_R2 = 0x0004,
|
||||
BODY_LEG_R3 = 0x0008,
|
||||
BODY_LEG_L1 = 0x0010,
|
||||
BODY_LEG_L2 = 0x0020,
|
||||
BODY_LEG_L3 = 0x0040,
|
||||
BODY_LEG_L1 = 0x0002,
|
||||
BODY_LEG_L2 = 0x0004,
|
||||
BODY_LEG_L3 = 0x0008,
|
||||
BODY_LEG_R1 = 0x0010,
|
||||
BODY_LEG_R2 = 0x0020,
|
||||
BODY_LEG_R3 = 0x0040,
|
||||
BODY_CHEST = 0x0080,
|
||||
BODY_ARM_L1 = 0x0100,
|
||||
BODY_ARM_L2 = 0x0200,
|
||||
BODY_ARM_L3 = 0x0400,
|
||||
BODY_ARM_R1 = 0x0800,
|
||||
BODY_ARM_R2 = 0x1000,
|
||||
BODY_ARM_R3 = 0x2000,
|
||||
BODY_ARM_R1 = 0x0100,
|
||||
BODY_ARM_R2 = 0x0200,
|
||||
BODY_ARM_R3 = 0x0400,
|
||||
BODY_ARM_L1 = 0x0800,
|
||||
BODY_ARM_L2 = 0x1000,
|
||||
BODY_ARM_L3 = 0x2000,
|
||||
BODY_HEAD = 0x4000,
|
||||
BODY_ARM_L = BODY_ARM_L1 | BODY_ARM_L2 | BODY_ARM_L3,
|
||||
BODY_ARM_R = BODY_ARM_R1 | BODY_ARM_R2 | BODY_ARM_R3,
|
||||
@@ -172,24 +174,43 @@ struct Lara : Controller {
|
||||
} weapons[Weapon::MAX];
|
||||
|
||||
Weapon::Type wpnCurrent;
|
||||
Weapon::State wpnState;
|
||||
Weapon::Anim wpnAnim;
|
||||
float wpnAnimTime;
|
||||
float wpnAnimDir;
|
||||
int wpnLastFrame;
|
||||
Weapon::Type wpnNext;
|
||||
float wpnShotTime[2];
|
||||
Weapon::State wpnState;
|
||||
vec3 chestOffset;
|
||||
|
||||
Lara(TR::Level *level, int entity) : Controller(level, entity), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY) {
|
||||
struct Arm {
|
||||
int target;
|
||||
int lastFrame;
|
||||
float shotTimer;
|
||||
float weight;
|
||||
float animDir;
|
||||
float animTime;
|
||||
float animMaxTime;
|
||||
int animIndex;
|
||||
quat rot;
|
||||
Weapon::Anim anim;
|
||||
} arms[2];
|
||||
|
||||
int target;
|
||||
quat rotHead, rotChest;
|
||||
|
||||
|
||||
Lara(TR::Level *level, int entity) : Controller(level, entity), wpnCurrent(Weapon::EMPTY), wpnNext(Weapon::EMPTY), chestOffset(pos), target(-1) {
|
||||
initMeshOverrides();
|
||||
wpnShotTime[0] = wpnShotTime[1] = 0.0f;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
arms[i].shotTimer = MUZZLE_FLASH_TIME + 1.0f;
|
||||
arms[i].animTime = 0.0f;
|
||||
arms[i].rot = quat(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
rotHead = rotChest = quat(0, 0, 0, 1);
|
||||
memset(weapons, -1, sizeof(weapons));
|
||||
weapons[Weapon::PISTOLS].ammo = 0;
|
||||
weapons[Weapon::SHOTGUN].ammo = 9000;
|
||||
weapons[Weapon::MAGNUMS].ammo = 9000;
|
||||
weapons[Weapon::UZIS ].ammo = 9000;
|
||||
|
||||
setWeapon(Weapon::PISTOLS, Weapon::IS_HIDDEN);
|
||||
wpnSet(Weapon::PISTOLS);
|
||||
#ifdef _DEBUG
|
||||
/*
|
||||
// gym
|
||||
@@ -211,7 +232,7 @@ struct Lara : Controller {
|
||||
pos = vec3(75671, -1024, 22862);
|
||||
angle = vec3(0.0f, -PI * 0.25f, 0.0f);
|
||||
getEntity().room = 13;
|
||||
|
||||
|
||||
// level 2 (room 1)
|
||||
pos = vec3(31400, -2560, 25200);
|
||||
angle = vec3(0.0f, PI, 0.0f);
|
||||
@@ -241,21 +262,38 @@ struct Lara : Controller {
|
||||
#endif
|
||||
}
|
||||
|
||||
void setWeapon(Weapon::Type wType, Weapon::State wState, Weapon::Anim wAnim = Weapon::Anim::NONE, float wAnimDir = 0.0f) {
|
||||
wpnAnimDir = wAnimDir;
|
||||
void wpnSet(Weapon::Type wType) {
|
||||
wpnCurrent = wType;
|
||||
wpnState = Weapon::IS_FIRING;
|
||||
wpnSetAnim(arms[0], Weapon::IS_HIDDEN, Weapon::Anim::NONE, 0.0f, 0.0f);
|
||||
wpnSetAnim(arms[1], Weapon::IS_HIDDEN, Weapon::Anim::NONE, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (wAnim != wpnAnim) {
|
||||
wpnAnim = wAnim;
|
||||
TR::Animation *anim = &level->anims[getWeaponAnimIndex(wpnAnim)];
|
||||
wpnAnimTime = wpnAnimDir >= 0.0f ? 0.0f : ((anim->frameEnd - anim->frameStart) / 30.0f);
|
||||
wpnLastFrame = 0xFFFF;
|
||||
}
|
||||
void wpnSetAnim(Arm &arm, Weapon::State wState, Weapon::Anim wAnim, float wAnimTime, float wAnimDir, bool playing = true) {
|
||||
if (arm.anim != wAnim)
|
||||
arm.lastFrame = 0xFFFF;
|
||||
|
||||
if (wpnCurrent == wType && wpnState == wState)
|
||||
return;
|
||||
arm.anim = wAnim;
|
||||
arm.animIndex = wpnGetAnimIndex(wAnim);
|
||||
TR::Animation &anim = level->anims[arm.animIndex];
|
||||
|
||||
arm.animDir = playing ? wAnimDir : 0.0f;
|
||||
arm.animMaxTime = (anim.frameEnd - anim.frameStart) / 30.0f;
|
||||
|
||||
if (wAnimDir > 0.0f)
|
||||
arm.animTime = wAnimTime;
|
||||
else
|
||||
if (wAnimDir < 0.0f)
|
||||
arm.animTime = arm.animMaxTime + wAnimTime;
|
||||
|
||||
wpnSetState(wState);
|
||||
}
|
||||
|
||||
void wpnSetState(Weapon::State wState) {
|
||||
if (wpnState == wState) return;
|
||||
|
||||
int mask = 0;
|
||||
switch (wType) {
|
||||
switch (wpnCurrent) {
|
||||
case Weapon::EMPTY : break;
|
||||
case Weapon::PISTOLS :
|
||||
case Weapon::MAGNUMS :
|
||||
@@ -280,30 +318,56 @@ struct Lara : Controller {
|
||||
if (wpnState == Weapon::IS_ARMED && wState == Weapon::IS_HIDDEN) playSound(TR::SND_HOLSTER, pos, Sound::Flags::PAN);
|
||||
|
||||
int resetMask = BODY_HEAD | BODY_UPPER | BODY_LOWER;
|
||||
if (wType == Weapon::SHOTGUN)
|
||||
if (wpnCurrent == Weapon::SHOTGUN)
|
||||
resetMask &= ~(BODY_LEG_L1 | BODY_LEG_R1);
|
||||
|
||||
// restore original meshes first
|
||||
meshSwap(level->models[Weapon::EMPTY], resetMask);
|
||||
// replace some parts
|
||||
meshSwap(level->models[wType], mask);
|
||||
meshSwap(level->models[wpnCurrent], mask);
|
||||
// have a shotgun in inventory place it on the back if another weapon is in use
|
||||
if (wType != Weapon::SHOTGUN && weapons[Weapon::SHOTGUN].ammo != -1)
|
||||
if (wpnCurrent != Weapon::SHOTGUN && weapons[Weapon::SHOTGUN].ammo != -1)
|
||||
meshSwap(level->models[Weapon::SHOTGUN], BODY_CHEST);
|
||||
// mesh swap to angry Lara's head while firing (from uzis model)
|
||||
if (wState == Weapon::IS_FIRING)
|
||||
meshSwap(level->models[Weapon::UZIS], BODY_HEAD);
|
||||
|
||||
wpnCurrent = wType;
|
||||
wpnState = wState;
|
||||
}
|
||||
|
||||
/*
|
||||
void setWeaponAnim(Weapon::Anim wAnim, float wAnimDir, Arm *arm) {
|
||||
arm->animDir = wAnimDir;
|
||||
|
||||
if (wAnim != arm->anim) {
|
||||
arm->anim = wAnim;
|
||||
TR::Animation *anim = &level->anims[getWeaponAnimIndex(arm->anim)];
|
||||
arm->animTime = arm->animDir >= 0.0f ? 0.0f : ((anim->frameEnd - anim->frameStart) / 30.0f);
|
||||
arm->lastFrame = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
void setWeapon(Weapon::Type wType, Weapon::State wState, Weapon::Anim wAnim = Weapon::Anim::NONE, float wAnimDir = 0.0f, Arm *arm = NULL) {
|
||||
|
||||
if (wpnCurrent != Weapon::SHOTGUN && wAnim != Weapon::Anim::HOLD && wAnim != Weapon::Anim::AIM && wAnim != Weapon::Anim::FIRE) {
|
||||
setWeaponAnim(wAnim, wAnimDir, &arms[0]);
|
||||
setWeaponAnim(wAnim, wAnimDir, &arms[1]);
|
||||
} else
|
||||
setWeaponAnim(wAnim, wAnimDir, !arm ? &arms[1] : arm);
|
||||
|
||||
if (wpnCurrent == wType && wpnState == wState)
|
||||
return;
|
||||
wpnCurrent = wType;
|
||||
wpnSetState(wState);
|
||||
}
|
||||
*/
|
||||
bool emptyHands() {
|
||||
return wpnState == Weapon::IS_HIDDEN;
|
||||
return arms[0].anim == Weapon::Anim::NONE;
|
||||
}
|
||||
|
||||
bool canDrawWeapon() {
|
||||
return wpnCurrent != Weapon::EMPTY
|
||||
&& emptyHands()
|
||||
&& state != STATE_DEATH
|
||||
&& state != STATE_HANG
|
||||
&& state != STATE_REACH
|
||||
@@ -336,33 +400,39 @@ struct Lara : Controller {
|
||||
&& state != STATE_WATER_OUT;
|
||||
}
|
||||
|
||||
void drawWeapon() {
|
||||
bool wpnReady() {
|
||||
return arms[0].anim != Weapon::Anim::PREPARE && arms[0].anim != Weapon::Anim::UNHOLSTER && arms[0].anim != Weapon::Anim::HOLSTER;
|
||||
}
|
||||
|
||||
void wpnDraw() {
|
||||
if (!canDrawWeapon()) return;
|
||||
|
||||
if (wpnAnim != Weapon::Anim::PREPARE && wpnAnim != Weapon::Anim::UNHOLSTER && wpnAnim != Weapon::Anim::HOLSTER && emptyHands()) {
|
||||
bool isRifle = wpnCurrent == Weapon::SHOTGUN;
|
||||
setWeapon(wpnCurrent, wpnState, isRifle ? Weapon::Anim::UNHOLSTER : Weapon::Anim::PREPARE, 1.0f);
|
||||
if (wpnReady() && emptyHands()) {
|
||||
if (wpnCurrent != Weapon::SHOTGUN) {
|
||||
wpnSetAnim(arms[0], wpnState, Weapon::Anim::PREPARE, 0.0f, 1.0f);
|
||||
wpnSetAnim(arms[1], wpnState, Weapon::Anim::PREPARE, 0.0f, 1.0f);
|
||||
} else
|
||||
wpnSetAnim(arms[0], wpnState, Weapon::Anim::UNHOLSTER, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void hideWeapon() {
|
||||
if (wpnAnim != Weapon::Anim::PREPARE && wpnAnim != Weapon::Anim::UNHOLSTER && wpnAnim != Weapon::Anim::HOLSTER && !emptyHands()) {
|
||||
bool isRifle = wpnCurrent == Weapon::SHOTGUN;
|
||||
|
||||
if (isRifle)
|
||||
setWeapon(wpnCurrent, wpnState, Weapon::Anim::HOLSTER, 1.0f);
|
||||
else
|
||||
setWeapon(wpnCurrent, wpnState, Weapon::Anim::UNHOLSTER, -1.0f);
|
||||
void wpnHide() {
|
||||
if (wpnReady() && !emptyHands()) {
|
||||
if (wpnCurrent != Weapon::SHOTGUN) {
|
||||
wpnSetAnim(arms[0], wpnState, Weapon::Anim::UNHOLSTER, 0.0f, -1.0f);
|
||||
wpnSetAnim(arms[1], wpnState, Weapon::Anim::UNHOLSTER, 0.0f, -1.0f);
|
||||
} else
|
||||
wpnSetAnim(arms[0], wpnState, Weapon::Anim::UNHOLSTER, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void changeWeapon(Weapon::Type wType) {
|
||||
void wpnChange(Weapon::Type wType) {
|
||||
if (wpnCurrent == wType) return;
|
||||
wpnNext = wType;
|
||||
hideWeapon();
|
||||
wpnHide();
|
||||
}
|
||||
|
||||
int getWeaponAnimIndex(Weapon::Anim wAnim) {
|
||||
int wpnGetAnimIndex(Weapon::Anim wAnim) {
|
||||
int baseAnim = level->models[wpnCurrent == Weapon::SHOTGUN ? Weapon::SHOTGUN : Weapon::PISTOLS].animation;
|
||||
|
||||
if (wpnCurrent == Weapon::SHOTGUN) {
|
||||
@@ -388,7 +458,7 @@ struct Lara : Controller {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getWeaponSound() {
|
||||
int wpnGetSound() {
|
||||
switch (wpnCurrent) {
|
||||
case Weapon::PISTOLS : return TR::SND_PISTOLS_SHOT;
|
||||
case Weapon::SHOTGUN : return TR::SND_SHOTGUN_SHOT;
|
||||
@@ -398,23 +468,62 @@ struct Lara : Controller {
|
||||
}
|
||||
}
|
||||
|
||||
void doShot() {
|
||||
playSound(getWeaponSound(), pos, Sound::Flags::PAN);
|
||||
void wpnFire() {
|
||||
bool armShot[2] = { false, false };
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int frameIndex = getFrameIndex(arms[i].animIndex, arms[i].animTime);
|
||||
if (arms[i].anim == Weapon::Anim::FIRE) {
|
||||
if (frameIndex < arms[i].lastFrame) {
|
||||
if (target == -1 || ((mask & ACTION) && arms[i].target > -1)) {
|
||||
armShot[i] = true;
|
||||
} else
|
||||
wpnSetAnim(arms[i], Weapon::IS_ARMED, Weapon::Anim::AIM, 0.0f, -1.0f, target == -1);
|
||||
}
|
||||
// shotgun reload sound
|
||||
if (wpnCurrent == Weapon::SHOTGUN) {
|
||||
if (frameIndex >= 10 && arms[i].lastFrame < 10)
|
||||
playSound(TR::SND_SHOTGUN_RELOAD, pos, Sound::Flags::PAN);
|
||||
}
|
||||
}
|
||||
arms[i].lastFrame = frameIndex;
|
||||
|
||||
if (wpnCurrent == Weapon::SHOTGUN) break;
|
||||
}
|
||||
|
||||
if (armShot[0] || armShot[1])
|
||||
doShot(armShot[0], armShot[1]);
|
||||
}
|
||||
|
||||
void doShot(bool rightHand, bool leftHand) {
|
||||
int count = wpnCurrent == Weapon::SHOTGUN ? 6 : 2;
|
||||
|
||||
float nearDist = 32.0f * 1024.0f;
|
||||
vec3 nearPos;
|
||||
bool hasShot = false;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
vec3 p = pos - vec3(0.0f, LARA_HANG_OFFSET, 0.0f);
|
||||
vec3 d = getDir();
|
||||
vec3 r = d.cross(vec3(0, -1, 0)); // right dir
|
||||
|
||||
if (wpnCurrent != Weapon::SHOTGUN)
|
||||
p += r.normal() * ((i * 2 - 1) * 48);
|
||||
Arm *arm;
|
||||
if (wpnCurrent == Weapon::SHOTGUN) {
|
||||
if (!rightHand) continue;
|
||||
arm = &arms[0];
|
||||
} else {
|
||||
if (!(i ? leftHand : rightHand)) continue;
|
||||
arm = &arms[i];
|
||||
}
|
||||
|
||||
vec3 t = p + d * (24.0f * 1024.0f) + ((vec3(randf(), randf(), randf()) * 2.0f) - 1.0f) * 1024.0f;
|
||||
arm->shotTimer = 0.0f;
|
||||
hasShot = true;
|
||||
|
||||
int joint = wpnCurrent == Weapon::SHOTGUN ? 8 : (i ? 11 : 8);
|
||||
|
||||
quat tmp = animOverrides[joint];
|
||||
animOverrides[joint] = arm->rot * quat(vec3(1, 0, 0), PI * 0.5f) ;
|
||||
mat4 m = getJoint(joint, true);
|
||||
animOverrides[joint] = tmp;
|
||||
|
||||
vec3 p = m.getPos();
|
||||
vec3 d = (m * vec4(0, 1, 0, 0)).xyz;
|
||||
vec3 t = p + d * (24.0f * 1024.0f) + ((vec3(randf(), randf(), randf()) * 2.0f) - vec3(1.0f)) * 1024.0f;
|
||||
|
||||
int room;
|
||||
vec3 hit = trace(getRoomIndex(), p, t, room, false);
|
||||
@@ -428,155 +537,264 @@ struct Lara : Controller {
|
||||
}
|
||||
}
|
||||
|
||||
playSound(TR::SND_RICOCHET, nearPos, Sound::Flags::PAN);
|
||||
|
||||
wpnShotTime[0] = wpnShotTime[1] = 0.0f;
|
||||
if (hasShot) {
|
||||
playSound(wpnGetSound(), pos, Sound::Flags::PAN);
|
||||
playSound(TR::SND_RICOCHET, nearPos, Sound::Flags::PAN);
|
||||
}
|
||||
}
|
||||
|
||||
void updateWeapon() {
|
||||
wpnShotTime[0] += Core::deltaTime;
|
||||
wpnShotTime[1] += Core::deltaTime;
|
||||
updateTargets();
|
||||
updateOverrides();
|
||||
|
||||
TR::Animation *anim = &level->anims[getWeaponAnimIndex(wpnAnim)];
|
||||
if (Input::down[ik1]) wpnChange(Weapon::PISTOLS);
|
||||
if (Input::down[ik2]) wpnChange(Weapon::SHOTGUN);
|
||||
if (Input::down[ik3]) wpnChange(Weapon::MAGNUMS);
|
||||
if (Input::down[ik4]) wpnChange(Weapon::UZIS);
|
||||
|
||||
if (Input::down[ik1]) changeWeapon(Weapon::PISTOLS);
|
||||
if (Input::down[ik2]) changeWeapon(Weapon::SHOTGUN);
|
||||
if (Input::down[ik3]) changeWeapon(Weapon::MAGNUMS);
|
||||
if (Input::down[ik4]) changeWeapon(Weapon::UZIS);
|
||||
|
||||
if (wpnNext != Weapon::EMPTY && wpnState == Weapon::IS_HIDDEN) {
|
||||
setWeapon(wpnNext, Weapon::IS_HIDDEN);
|
||||
drawWeapon();
|
||||
if (wpnNext != Weapon::EMPTY && emptyHands()) {
|
||||
wpnSet(wpnNext);
|
||||
wpnDraw();
|
||||
wpnNext = Weapon::EMPTY;
|
||||
}
|
||||
|
||||
// apply weapon state changes
|
||||
if (wpnCurrent == Weapon::EMPTY) {
|
||||
animOverrideMask &= ~(BODY_ARM_L | BODY_ARM_R);
|
||||
return;
|
||||
}
|
||||
|
||||
Weapon::Anim nextAnim = wpnAnim;
|
||||
|
||||
bool isRifle = wpnCurrent == Weapon::SHOTGUN;
|
||||
|
||||
if (mask & WEAPON) {
|
||||
if (emptyHands())
|
||||
drawWeapon();
|
||||
wpnDraw();
|
||||
else
|
||||
hideWeapon();
|
||||
wpnHide();
|
||||
}
|
||||
|
||||
if (!emptyHands()) {
|
||||
if (mask & ACTION) {
|
||||
if (wpnAnim == Weapon::Anim::HOLD)
|
||||
setWeapon(wpnCurrent, wpnState, Weapon::Anim::AIM, 1.0f);
|
||||
} else
|
||||
if (wpnAnim == Weapon::Anim::AIM)
|
||||
wpnAnimDir = -1.0f;
|
||||
bool isRifle = wpnCurrent == Weapon::SHOTGUN;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (arms[i].target > -1 || ((mask & ACTION) && target == -1)) {
|
||||
if (arms[i].anim == Weapon::Anim::HOLD)
|
||||
wpnSetAnim(arms[i], wpnState, Weapon::Anim::AIM, 0.0f, 1.0f);
|
||||
} else
|
||||
if (arms[i].anim == Weapon::Anim::AIM)
|
||||
arms[i].animDir = -1.0f;
|
||||
|
||||
if (isRifle) break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++){
|
||||
arms[i].animTime += Core::deltaTime * arms[i].animDir;
|
||||
arms[i].shotTimer += Core::deltaTime;
|
||||
}
|
||||
|
||||
if (isRifle)
|
||||
animateShotgun();
|
||||
else
|
||||
animatePistols();
|
||||
|
||||
wpnFire(); // make a shot
|
||||
}
|
||||
}
|
||||
|
||||
anim = &level->anims[getWeaponAnimIndex(wpnAnim)];
|
||||
float maxTime = (anim->frameEnd - anim->frameStart) / 30.0f;
|
||||
void animatePistols() {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Arm &arm = arms[i];
|
||||
|
||||
if (wpnAnim == Weapon::Anim::NONE) {
|
||||
animOverrideMask &= ~(BODY_ARM_L | BODY_ARM_R);
|
||||
return;
|
||||
}
|
||||
animOverrideMask |= BODY_ARM_L | BODY_ARM_R;
|
||||
|
||||
Weapon::Anim prevAnim = wpnAnim; // cache before changes
|
||||
|
||||
wpnAnimTime += Core::deltaTime * wpnAnimDir;
|
||||
|
||||
if (isRifle) {
|
||||
if (wpnAnimDir > 0.0f)
|
||||
switch (wpnAnim) {
|
||||
case Weapon::Anim::UNHOLSTER :
|
||||
if (wpnAnimTime >= maxTime)
|
||||
setWeapon(wpnCurrent, Weapon::IS_ARMED, Weapon::Anim::HOLD, 0.0f);
|
||||
else if (wpnAnimTime >= maxTime * 0.3f)
|
||||
setWeapon(wpnCurrent, Weapon::IS_ARMED, wpnAnim, 1.0f);
|
||||
if (arm.animDir >= 0.0f && arm.animTime >= arm.animMaxTime)
|
||||
switch (arm.anim) {
|
||||
case Weapon::Anim::PREPARE : wpnSetAnim(arm, Weapon::IS_ARMED, Weapon::Anim::UNHOLSTER, arm.animTime - arm.animMaxTime, 1.0f); break;
|
||||
case Weapon::Anim::UNHOLSTER : wpnSetAnim(arm, Weapon::IS_ARMED, Weapon::Anim::HOLD, 0.0f, 1.0f, false); break;
|
||||
case Weapon::Anim::AIM :
|
||||
if (mask & ACTION)
|
||||
wpnSetAnim(arm, Weapon::IS_FIRING, Weapon::Anim::FIRE, arm.animTime - arm.animMaxTime, wpnCurrent == Weapon::UZIS ? 2.0f : 1.0f);
|
||||
else
|
||||
wpnSetAnim(arm, Weapon::IS_ARMED, Weapon::Anim::AIM, 0.0f, -1.0f, false);
|
||||
break;
|
||||
case Weapon::Anim::HOLSTER :
|
||||
if (wpnAnimTime >= maxTime)
|
||||
setWeapon(wpnCurrent, Weapon::IS_HIDDEN, Weapon::Anim::NONE, wpnAnimDir);
|
||||
else if (wpnAnimTime >= maxTime * 0.7f)
|
||||
setWeapon(wpnCurrent, Weapon::IS_HIDDEN, wpnAnim, 1.0f);
|
||||
break;
|
||||
case Weapon::Anim::AIM :
|
||||
if (wpnAnimTime >= maxTime)
|
||||
setWeapon(wpnCurrent, Weapon::IS_FIRING, Weapon::Anim::FIRE, wpnAnimDir);
|
||||
break;
|
||||
default : ;
|
||||
};
|
||||
|
||||
if (wpnAnimDir < 0.0f && wpnAnimTime <= 0.0f)
|
||||
if (wpnAnim == Weapon::Anim::AIM) {
|
||||
setWeapon(wpnCurrent, wpnState, Weapon::Anim::HOLD, 0.0f);
|
||||
};
|
||||
} else {
|
||||
if (wpnAnimDir > 0.0f && wpnAnimTime >= maxTime)
|
||||
switch (wpnAnim) {
|
||||
case Weapon::Anim::PREPARE : setWeapon(wpnCurrent, Weapon::IS_ARMED, Weapon::Anim::UNHOLSTER, wpnAnimDir); break;
|
||||
case Weapon::Anim::UNHOLSTER : setWeapon(wpnCurrent, wpnState, Weapon::Anim::HOLD, 0.0f); break;
|
||||
case Weapon::Anim::AIM : setWeapon(wpnCurrent, Weapon::IS_FIRING, Weapon::Anim::FIRE, wpnCurrent == Weapon::UZIS ? 2.0f : 1.0f); break;
|
||||
default : ;
|
||||
};
|
||||
|
||||
if (wpnAnimDir < 0.0f && wpnAnimTime <= 0.0f)
|
||||
switch (wpnAnim) {
|
||||
case Weapon::Anim::PREPARE : setWeapon(wpnCurrent, wpnState, Weapon::Anim::NONE, wpnAnimDir); break;
|
||||
case Weapon::Anim::UNHOLSTER : setWeapon(wpnCurrent, Weapon::IS_HIDDEN, Weapon::Anim::PREPARE, wpnAnimDir); break;
|
||||
case Weapon::Anim::AIM : setWeapon(wpnCurrent, wpnState, Weapon::Anim::HOLD, 0.0f); break;
|
||||
if (arm.animDir < 0.0f && arm.animTime <= 0.0f)
|
||||
switch (arm.anim) {
|
||||
case Weapon::Anim::PREPARE : wpnSetAnim(arm, Weapon::IS_HIDDEN, Weapon::Anim::NONE, 0.0f, 1.0f, false); break;
|
||||
case Weapon::Anim::UNHOLSTER : wpnSetAnim(arm, Weapon::IS_HIDDEN, Weapon::Anim::PREPARE, arm.animTime, -1.0f); break;
|
||||
case Weapon::Anim::AIM : wpnSetAnim(arm, Weapon::IS_ARMED, Weapon::Anim::HOLD, 0.0f, 1.0f, false); break;
|
||||
default : ;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (prevAnim != wpnAnim) // check by cache
|
||||
anim = &level->anims[getWeaponAnimIndex(wpnAnim)];
|
||||
void animateShotgun() {
|
||||
/*
|
||||
float &wpnAnimDir = arms[0].animDir;
|
||||
float &wpnAnimTime = arms[0].animTime;
|
||||
Weapon::Anim &wpnAnim = arms[0].anim;
|
||||
TR::Animation *anim = &level->anims[getWeaponAnimIndex(arms[0].anim)];
|
||||
float maxTime = (anim->frameEnd - anim->frameStart) / 30.0f;
|
||||
|
||||
// make a shot
|
||||
int frameIndex = int(wpnAnimTime * 30.0f / anim->frameRate) % ((anim->frameEnd - anim->frameStart) / anim->frameRate + 1);
|
||||
if (wpnAnim == Weapon::Anim::FIRE) {
|
||||
if (frameIndex < wpnLastFrame) {
|
||||
if (mask & ACTION) {
|
||||
doShot();
|
||||
} else
|
||||
setWeapon(wpnCurrent, Weapon::IS_ARMED, Weapon::Anim::AIM, -1.0f);
|
||||
}
|
||||
// shotgun reload sound
|
||||
if (isRifle && frameIndex >= 10 && wpnLastFrame < 10)
|
||||
playSound(TR::SND_SHOTGUN_RELOAD, pos, Sound::Flags::PAN);
|
||||
if (wpnAnimDir > 0.0f)
|
||||
switch (wpnAnim) {
|
||||
case Weapon::Anim::UNHOLSTER :
|
||||
if (wpnAnimTime >= maxTime)
|
||||
setWeapon(wpnCurrent, Weapon::IS_ARMED, Weapon::Anim::HOLD, 0.0f);
|
||||
else if (wpnAnimTime >= maxTime * 0.3f)
|
||||
setWeapon(wpnCurrent, Weapon::IS_ARMED, wpnAnim, 1.0f);
|
||||
break;
|
||||
case Weapon::Anim::HOLSTER :
|
||||
if (wpnAnimTime >= maxTime)
|
||||
setWeapon(wpnCurrent, Weapon::IS_HIDDEN, Weapon::Anim::NONE, wpnAnimDir);
|
||||
else if (wpnAnimTime >= maxTime * 0.7f)
|
||||
setWeapon(wpnCurrent, Weapon::IS_HIDDEN, wpnAnim, 1.0f);
|
||||
break;
|
||||
case Weapon::Anim::AIM :
|
||||
if (wpnAnimTime >= maxTime)
|
||||
setWeapon(wpnCurrent, Weapon::IS_FIRING, Weapon::Anim::FIRE, wpnAnimDir);
|
||||
break;
|
||||
default : ;
|
||||
};
|
||||
|
||||
if (wpnAnimDir < 0.0f && wpnAnimTime <= 0.0f)
|
||||
if (wpnAnim == Weapon::Anim::AIM) {
|
||||
setWeapon(wpnCurrent, wpnState, Weapon::Anim::HOLD, 0.0f);
|
||||
};
|
||||
*/
|
||||
}
|
||||
|
||||
void updateOverrides() {
|
||||
// update animation overrides
|
||||
TR::AnimFrame *frameA, *frameB;
|
||||
float t;
|
||||
|
||||
// head & chest
|
||||
animOverrideMask |= BODY_CHEST | BODY_HEAD;
|
||||
|
||||
getFrames(&frameA, &frameB, t, animIndex, animTime, true);
|
||||
animOverrides[ 7] = lerpFrames(frameA, frameB, t, 7);
|
||||
animOverrides[14] = lerpFrames(frameA, frameB, t, 14);
|
||||
|
||||
// right arm
|
||||
if (arms[0].anim != Weapon::Anim::NONE) {
|
||||
getFrames(&frameA, &frameB, t, arms[0].animIndex, arms[0].animTime);
|
||||
animOverrides[ 8] = lerpFrames(frameA, frameB, t, 8);
|
||||
animOverrides[ 9] = lerpFrames(frameA, frameB, t, 9);
|
||||
animOverrides[10] = lerpFrames(frameA, frameB, t, 10);
|
||||
animOverrideMask |= BODY_ARM_R;
|
||||
} else
|
||||
animOverrideMask &= ~BODY_ARM_R;
|
||||
|
||||
// left arm
|
||||
if (arms[1].anim != Weapon::Anim::NONE) {
|
||||
getFrames(&frameA, &frameB, t, arms[1].animIndex, arms[1].animTime);
|
||||
animOverrides[11] = lerpFrames(frameA, frameB, t, 11);
|
||||
animOverrides[12] = lerpFrames(frameA, frameB, t, 12);
|
||||
animOverrides[13] = lerpFrames(frameA, frameB, t, 13);
|
||||
animOverrideMask |= BODY_ARM_L;
|
||||
} else
|
||||
animOverrideMask &= ~BODY_ARM_L;
|
||||
|
||||
lookAt(target);
|
||||
|
||||
if (wpnCurrent != Weapon::SHOTGUN)
|
||||
aimPistols();
|
||||
}
|
||||
|
||||
void lookAt(int target) {
|
||||
float speed = 8.0f * Core::deltaTime;
|
||||
quat rot;
|
||||
|
||||
// chest
|
||||
if ((stand == STAND_GROUND || stand == STAND_SLIDE) && aim(target, 7, vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.9f, PI * 0.9f), rot))
|
||||
rotChest = rotChest.slerp(quat(0, 0, 0, 1).slerp(rot, 0.5f), speed);
|
||||
else
|
||||
rotChest = rotChest.slerp(quat(0, 0, 0, 1), speed);
|
||||
animOverrides[7] = rotChest * animOverrides[7];
|
||||
|
||||
// head
|
||||
if (aim(target, 14, vec4(-PI * 0.25f, PI * 0.25f, -PI * 0.5f, PI * 0.5f), rot))
|
||||
rotHead = rotHead.slerp(rot, speed);
|
||||
else
|
||||
rotHead = rotHead.slerp(quat(0, 0, 0, 1), speed);
|
||||
animOverrides[14] = rotHead * animOverrides[14];
|
||||
}
|
||||
|
||||
void aimPistols() {
|
||||
float speed = 8.0f * Core::deltaTime;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
int joint = i ? 11 : 8;
|
||||
vec4 range = i ? vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.5f, PI * 0.2f) : vec4(-PI * 0.4f, PI * 0.4f, -PI * 0.2f, PI * 0.5f);
|
||||
|
||||
Arm *arm = &arms[i];
|
||||
quat rot;
|
||||
if (!aim(target, joint, range, rot)) {
|
||||
arm->target = -1;
|
||||
rot = quat(0, 0, 0, 1);
|
||||
} else
|
||||
arm->target = target;
|
||||
|
||||
float t;
|
||||
if (arm->anim == Weapon::Anim::FIRE)
|
||||
t = 1.0f;
|
||||
else if (arm->anim == Weapon::Anim::AIM)
|
||||
t = arm->animTime / arm->animMaxTime;
|
||||
else
|
||||
t = 0.0f;
|
||||
|
||||
arm->rot = arm->rot.slerp(rot, speed);
|
||||
animOverrides[joint] = animOverrides[joint].slerp(arm->rot * animOverrides[joint], t);
|
||||
}
|
||||
wpnLastFrame = frameIndex;
|
||||
}
|
||||
|
||||
bool aim(int target, int joint, const vec4 &angleRange, quat &rot) {
|
||||
if (target == -1) return false;
|
||||
|
||||
if (wpnAnim == Weapon::Anim::NONE) {
|
||||
animOverrideMask &= ~(BODY_ARM_L | BODY_ARM_R);
|
||||
TR::Entity &e = level->entities[target];
|
||||
vec3 t(e.x, e.y, e.z);
|
||||
|
||||
mat4 m = getJoint(joint);
|
||||
vec3 delta = (m.inverse() * t).normal();
|
||||
|
||||
float angleY = clampAngle(atan2(delta.x, delta.z));
|
||||
float angleX = clampAngle(asinf(delta.y));
|
||||
|
||||
if (angleX < angleRange.x || angleX > angleRange.y ||
|
||||
angleY < angleRange.z || angleY > angleRange.w)
|
||||
return false;
|
||||
|
||||
quat ax(vec3(1, 0, 0), -angleX);
|
||||
quat ay(vec3(0, 1, 0), angleY);
|
||||
|
||||
rot = ay * ax;
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateTargets() {
|
||||
if (emptyHands() || !wpnReady()) {
|
||||
target = arms[0].target = arms[1].target = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// update animation overrides
|
||||
float k = wpnAnimTime * 30.0f / anim->frameRate;
|
||||
int fIndex = (int)k;
|
||||
int fCount = (anim->frameEnd - anim->frameStart) / anim->frameRate + 1;
|
||||
if (!(mask & ACTION) || target == -1) {
|
||||
target = getTarget();
|
||||
arms[0].target = target;
|
||||
arms[1].target = target;
|
||||
}
|
||||
}
|
||||
|
||||
int fSize = sizeof(TR::AnimFrame) + getModel().mCount * sizeof(uint16) * 2;
|
||||
k = k - fIndex;
|
||||
int getTarget() {
|
||||
int dist = TARGET_MAX_DIST * 3.0f;
|
||||
|
||||
int index = -1;
|
||||
TR::Entity &entity = getEntity();
|
||||
for (int i = 0; i < level->entitiesCount; i++) {
|
||||
TR::Entity &e = level->entities[i];
|
||||
if (!e.isEnemy()) continue;
|
||||
|
||||
int fIndexA = fIndex % fCount, fIndexB = (fIndex + 1) % fCount;
|
||||
TR::AnimFrame *frameA = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexA * fSize) >> 1];
|
||||
TR::AnimFrame *frameB = (TR::AnimFrame*)&level->frameData[(anim->frameOffset + fIndexB * fSize) >> 1];
|
||||
int d = abs(e.x - entity.x) + abs(e.y - entity.y) + abs(e.z - entity.z);
|
||||
if (d < dist) {
|
||||
index = i;
|
||||
dist = d;
|
||||
}
|
||||
}
|
||||
|
||||
// left arm
|
||||
animOverrides[ 8] = lerpFrames(frameA, frameB, k, 8);
|
||||
animOverrides[ 9] = lerpFrames(frameA, frameB, k, 9);
|
||||
animOverrides[10] = lerpFrames(frameA, frameB, k, 10);
|
||||
// right arm
|
||||
animOverrides[11] = lerpFrames(frameA, frameB, k, 11);
|
||||
animOverrides[12] = lerpFrames(frameA, frameB, k, 12);
|
||||
animOverrides[13] = lerpFrames(frameA, frameB, k, 13);
|
||||
return index;
|
||||
}
|
||||
|
||||
bool waterOut(int &outState) {
|
||||
@@ -748,49 +966,13 @@ struct Lara : Controller {
|
||||
}
|
||||
|
||||
vec3 getViewOffset() {
|
||||
TR::Animation *anim = &level->anims[animIndex];
|
||||
TR::Model &model = getModel();
|
||||
vec3 offset = vec3(0.0f);
|
||||
if (stand != STAND_UNDERWATER)
|
||||
offset.y -= 256.0f;
|
||||
if (wpnState != Weapon::IS_HIDDEN)
|
||||
offset.y -= 256.0f;
|
||||
|
||||
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;
|
||||
if (wpnState != Weapon::IS_HIDDEN)
|
||||
h -= 256.0f;
|
||||
break;
|
||||
case Controller::STAND_UNDERWATER :
|
||||
case Controller::STAND_ONWATER :
|
||||
h -= 128.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
return vec3(0.0f, h, 0.0f);
|
||||
return chestOffset - pos + offset;
|
||||
}
|
||||
|
||||
virtual Stand getStand() {
|
||||
@@ -811,7 +993,7 @@ struct Lara : Controller {
|
||||
return stand;
|
||||
|
||||
if (getRoom().flags.water) {
|
||||
hideWeapon();
|
||||
wpnHide();
|
||||
return STAND_UNDERWATER;
|
||||
}
|
||||
|
||||
@@ -1173,8 +1355,8 @@ struct Lara : Controller {
|
||||
if (!lState) {
|
||||
lState = true;
|
||||
|
||||
static int snd_id = 0;
|
||||
//playSound(snd_id, pos, 0);
|
||||
static int snd_id = 81;
|
||||
playSound(snd_id, pos, 0);
|
||||
|
||||
LOG("sound: %d\n", snd_id++);
|
||||
/*
|
||||
@@ -1536,7 +1718,7 @@ struct Lara : Controller {
|
||||
}
|
||||
|
||||
void renderMuzzleFlash(MeshBuilder *mesh, const mat4 &matrix, const vec3 &offset, float time) {
|
||||
if (time > 0.1f) return;
|
||||
if (time > MUZZLE_FLASH_TIME) return;
|
||||
float alpha = min(1.0f, (0.1f - time) * 20.0f);
|
||||
float lum = 3.0f;
|
||||
|
||||
@@ -1552,9 +1734,11 @@ struct Lara : Controller {
|
||||
|
||||
virtual void render(Frustum *frustum, MeshBuilder *mesh) {
|
||||
Controller::render(frustum, mesh);
|
||||
chestOffset = joints[7].getPos();
|
||||
|
||||
if (wpnCurrent != Weapon::SHOTGUN) {
|
||||
renderMuzzleFlash(mesh, joints[10], vec3(-10, -50, 150), wpnShotTime[0]);
|
||||
renderMuzzleFlash(mesh, joints[13], vec3( 10, -50, 150), wpnShotTime[1]);
|
||||
renderMuzzleFlash(mesh, joints[10], vec3(-10, -50, 150), arms[0].shotTimer);
|
||||
renderMuzzleFlash(mesh, joints[13], vec3( 10, -50, 150), arms[1].shotTimer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
32
src/utils.h
32
src/utils.h
@@ -141,6 +141,10 @@ struct vec3 {
|
||||
float s = sinf(angle), c = cosf(angle);
|
||||
return vec3(x*c - z*s, y, x*s + z*c);
|
||||
}
|
||||
|
||||
float angle(const vec3 &v) {
|
||||
return dot(v) / (length() * v.length());
|
||||
}
|
||||
};
|
||||
|
||||
struct vec4 {
|
||||
@@ -158,7 +162,10 @@ struct vec4 {
|
||||
};
|
||||
|
||||
struct quat {
|
||||
float x, y, z, w;
|
||||
union {
|
||||
struct { float x, y, z, w; };
|
||||
struct { vec3 xyz; };
|
||||
};
|
||||
|
||||
quat() {}
|
||||
quat(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
||||
@@ -492,20 +499,17 @@ struct mat4 {
|
||||
}
|
||||
};
|
||||
|
||||
quat rotYXZ(const vec3 &a) {
|
||||
mat4 m;
|
||||
m.identity();
|
||||
m.rotateY(a.y);
|
||||
m.rotateX(a.x);
|
||||
m.rotateZ(a.z);
|
||||
return m.getRot();
|
||||
}
|
||||
|
||||
quat lerpAngle(const vec3 &a, const vec3 &b, float t) { // TODO: optimization
|
||||
mat4 ma, mb;
|
||||
ma.identity();
|
||||
mb.identity();
|
||||
|
||||
ma.rotateY(a.y);
|
||||
ma.rotateX(a.x);
|
||||
ma.rotateZ(a.z);
|
||||
|
||||
mb.rotateY(b.y);
|
||||
mb.rotateX(b.x);
|
||||
mb.rotateZ(b.z);
|
||||
|
||||
return ma.getRot().slerp(mb.getRot(), t).normal();
|
||||
return rotYXZ(a).slerp(rotYXZ(b), t).normal();
|
||||
}
|
||||
|
||||
vec3 boxNormal(int x, int z) {
|
||||
|
Reference in New Issue
Block a user