mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-14 00:54:05 +02:00
This commit is contained in:
@@ -49,7 +49,7 @@ struct IGame {
|
||||
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {}
|
||||
virtual void renderCompose(int roomIndex) {}
|
||||
virtual void renderView(int roomIndex, bool water) {}
|
||||
virtual void setEffect(TR::Effect effect, float param) {}
|
||||
virtual void setEffect(Controller *controller, TR::Effect effect) {}
|
||||
|
||||
virtual void checkTrigger(Controller *controller, bool heavy) {}
|
||||
|
||||
@@ -520,7 +520,7 @@ struct Controller {
|
||||
if (cmd == TR::ANIM_CMD_EFFECT) {
|
||||
switch (fx) {
|
||||
case TR::Effect::ROTATE_180 : angle.y = angle.y + PI; break;
|
||||
case TR::Effect::FLOOR_SHAKE : game->setEffect(TR::Effect(fx), 0.5f * max(0.0f, 1.0f - (pos - ((ICamera*)level->cameraController)->pos).length2() / (15 * 1024 * 15 * 1024) )); break;
|
||||
case TR::Effect::FLOOR_SHAKE : game->setEffect(this, TR::Effect(fx)); break;
|
||||
case TR::Effect::FLIP_MAP : level->isFlipped = !level->isFlipped; break;
|
||||
default : cmdEffect(fx); break;
|
||||
}
|
||||
@@ -698,28 +698,35 @@ struct Controller {
|
||||
if (entity.isActor()) // cutscene entities have no blob shadow
|
||||
return;
|
||||
|
||||
Box box = animation.getBoundingBox(pos, 0);
|
||||
vec3 center = box.center();
|
||||
Box boxL = getBoundingBoxLocal();
|
||||
Box boxA = boxL * getMatrix();
|
||||
|
||||
vec3 center = boxA.center();
|
||||
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(entity.room, int(center.x), int(center.y), int(center.z), info);
|
||||
|
||||
const vec3 fpos = vec3(pos.x, info.floor - 16.0f, pos.z);
|
||||
const vec3 size = box.size();
|
||||
const vec3 size = boxL.size() * (1.0f / 1024.0f);
|
||||
|
||||
mat4 m = Core::mViewProj;
|
||||
m.translate(fpos);
|
||||
m.rotateY(angle.y);
|
||||
m.translate(vec3(center.x - pos.x, 0.0f, center.z - pos.z));
|
||||
m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f));
|
||||
vec3 dir = getDir();
|
||||
vec3 up = info.getNormal();
|
||||
vec3 right = dir.cross(up).normal();
|
||||
dir = up.cross(right).normal();
|
||||
|
||||
mat4 m;
|
||||
m.identity();
|
||||
m.dir = vec4(dir * size.z, 0.0f);
|
||||
m.up = vec4(up, 0.0f);
|
||||
m.right = vec4(right * size.x, 0.0f);
|
||||
m.offset = vec4(center.x, info.floor - 8.0f, center.z, 1.0f);
|
||||
|
||||
Basis b;
|
||||
b.identity();
|
||||
|
||||
game->setShader(Core::pass, Shader::FLASH, false, false);
|
||||
Core::active.shader->setParam(uViewProj, m);
|
||||
Core::active.shader->setParam(uViewProj, Core::mViewProj * m);
|
||||
Core::active.shader->setParam(uBasis, b);
|
||||
float alpha = lerp(0.7f, 0.90f, clamp((fpos.y - box.max.y) / 1024.0f, 0.0f, 1.0f) );
|
||||
float alpha = lerp(0.7f, 0.90f, clamp((info.floor - boxA.max.y) / 1024.0f, 0.0f, 1.0f) );
|
||||
Core::active.shader->setParam(uMaterial, vec4(vec3(0.5f * (1.0f - alpha)), alpha));
|
||||
Core::active.shader->setParam(uAmbient, vec3(0.0f));
|
||||
|
||||
|
10
src/format.h
10
src/format.h
@@ -662,7 +662,8 @@ namespace TR {
|
||||
return isEnemy() ||
|
||||
isDoor() ||
|
||||
(type == DRAWBRIDGE && flags.active != ACTIVE) ||
|
||||
(type == SCION_HOLDER);
|
||||
(type == SCION_HOLDER) ||
|
||||
((type == HAMMER_HANDLE || type == HAMMER_BLOCK) && flags.collision);
|
||||
}
|
||||
|
||||
bool isItem() const {
|
||||
@@ -2266,6 +2267,13 @@ namespace TR {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Entity::HAMMER_HANDLE : {
|
||||
int dirX, dirZ;
|
||||
e.getAxis(dirX, dirZ);
|
||||
if (abs(e.x + dirX * 1024 * 3 - x) < 512 && abs(e.z + dirZ * 1024 * 3 - z) < 512)
|
||||
info.floor -= 1024 * 3;
|
||||
break;
|
||||
}
|
||||
case Entity::BRIDGE_0 :
|
||||
case Entity::BRIDGE_1 :
|
||||
case Entity::BRIDGE_2 : {
|
||||
|
31
src/lara.h
31
src/lara.h
@@ -1366,14 +1366,20 @@ struct Lara : Character {
|
||||
}
|
||||
case TR::HIT_BOULDER : {
|
||||
animation.setAnim(ANIM_DEATH_BOULDER);
|
||||
if (enemy)
|
||||
|
||||
vec3 v(0.0f);
|
||||
if (enemy && enemy->getEntity().type == TR::Entity::TRAP_BOULDER) {
|
||||
angle = enemy->angle;
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), info);
|
||||
vec3 d = getDir();
|
||||
vec3 v = info.getSlant(d);
|
||||
angle.x = -acos(d.dot(v));
|
||||
v = enemy ? ((TrapBoulder*)enemy)->velocity * 2.0f : vec3(0.0f);
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), info);
|
||||
vec3 d = getDir();
|
||||
v = info.getSlant(d);
|
||||
float dp = d.dot(v);
|
||||
if (fabsf(dp) < 0.999)
|
||||
angle.x = -acosf(dp);
|
||||
v = ((TrapBoulder*)enemy)->velocity * 2.0f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 15; i++)
|
||||
addBlood(256.0f, 512.0f, v);
|
||||
break;
|
||||
@@ -1822,7 +1828,7 @@ struct Lara : Character {
|
||||
|
||||
if (needFlip) {
|
||||
level->isFlipped = !level->isFlipped;
|
||||
game->setEffect(effect, 0);
|
||||
game->setEffect(this, effect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2573,7 +2579,7 @@ struct Lara : Character {
|
||||
}
|
||||
|
||||
// check enemies & doors
|
||||
for (int i = 0; i < level->entitiesBaseCount; i++) {
|
||||
for (int i = 0; i < level->entitiesCount; i++) {
|
||||
TR::Entity &e = level->entities[i];
|
||||
|
||||
if (!e.isCollider()) continue;
|
||||
@@ -2581,11 +2587,12 @@ struct Lara : Character {
|
||||
Controller *controller = (Controller*)e.controller;
|
||||
|
||||
if (e.isEnemy()) {
|
||||
if (e.type != TR::Entity::ENEMY_REX && (!e.flags.active || ((Character*)controller)->health <= 0)) continue;
|
||||
if (e.type != TR::Entity::ENEMY_REX && (e.flags.active != TR::ACTIVE || ((Character*)controller)->health <= 0)) continue;
|
||||
} else {
|
||||
// fast distance check for object
|
||||
TR::Entity &entity = getEntity();
|
||||
if (abs(entity.x - e.x) > 1024 || abs(entity.z - e.z) > 1024 || abs(entity.y - e.y) > 2048) continue;
|
||||
if (e.type != TR::Entity::HAMMER_HANDLE && e.type != TR::Entity::HAMMER_BLOCK)
|
||||
if (abs(entity.x - e.x) > 1024 || abs(entity.z - e.z) > 1024 || abs(entity.y - e.y) > 2048) continue;
|
||||
}
|
||||
|
||||
vec3 dir = pos - vec3(0.0f, 128.0f, 0.0f) - controller->pos;
|
||||
@@ -2594,7 +2601,7 @@ struct Lara : Character {
|
||||
Box box = controller->getBoundingBoxLocal();
|
||||
box.expand(vec3(LARA_RADIUS, 0.0f, LARA_RADIUS));
|
||||
|
||||
if (!box.contains(p))
|
||||
if (!box.contains(p)) // TODO: Box vs Box or check Lara's head point? (check thor hammer handle)
|
||||
continue;
|
||||
|
||||
if (e.isEnemy()) { // enemy collision
|
||||
|
@@ -187,14 +187,14 @@ struct Level : IGame {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setEffect(TR::Effect effect, float param) {
|
||||
virtual void setEffect(Controller *controller, TR::Effect effect) {
|
||||
this->effect = effect;
|
||||
this->effectTimer = 0.0f;
|
||||
this->effectIdx = 0;
|
||||
|
||||
switch (effect) {
|
||||
case TR::Effect::FLOOR_SHAKE :
|
||||
camera->shake = param;
|
||||
camera->shake = 0.5f * max(0.0f, 1.0f - (controller->pos - camera->pos).length2() / (15 * 1024 * 15 * 1024));
|
||||
return;
|
||||
case TR::Effect::FLOOD : {
|
||||
Sound::Sample *sample = playSound(TR::SND_FLOOD, vec3(), 0);
|
||||
@@ -476,6 +476,7 @@ struct Level : IGame {
|
||||
case TR::Entity::TRAP_CEILING_2 : return new TrapCeiling(this, index);
|
||||
case TR::Entity::TRAP_SLAM : return new TrapSlam(this, index);
|
||||
case TR::Entity::TRAP_SWORD : return new TrapSword(this, index);
|
||||
case TR::Entity::HAMMER_HANDLE : return new ThorHammer(this, index);
|
||||
case TR::Entity::DOOR_LATCH : return new DoorLatch(this, index);
|
||||
case TR::Entity::SWITCH :
|
||||
case TR::Entity::SWITCH_WATER : return new Switch(this, index);
|
||||
|
@@ -283,7 +283,9 @@ struct Block : Controller {
|
||||
STATE_PULL,
|
||||
};
|
||||
|
||||
Block(IGame *game, int entity) : Controller(game, entity) {
|
||||
float velocity;
|
||||
|
||||
Block(IGame *game, int entity) : Controller(game, entity), velocity(0.0f) {
|
||||
updateFloor(true);
|
||||
}
|
||||
|
||||
@@ -339,13 +341,34 @@ struct Block : Controller {
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
if (state == STATE_STAND) return;
|
||||
updateAnimation(true);
|
||||
if (state == STATE_STAND) {
|
||||
TR::Entity &e = getEntity();
|
||||
TR::Level::FloorInfo info;
|
||||
level->getFloorInfo(e.room, e.x, e.y, e.z, info);
|
||||
|
||||
if (pos.y < info.floor) {
|
||||
if (info.roomBelow != TR::NO_ROOM)
|
||||
e.room = info.roomBelow;
|
||||
|
||||
velocity += Core::deltaTime * GRAVITY;
|
||||
pos.y += Core::deltaTime * velocity * 30.0f;
|
||||
if (pos.y >= info.floor) {
|
||||
velocity = 0.0f;
|
||||
pos.y = info.floor;
|
||||
game->setEffect(this, TR::Effect::FLOOR_SHAKE);
|
||||
game->playSound(TR::SND_BOULDER, pos, Sound::PAN);
|
||||
deactivate(true);
|
||||
updateFloor(true);
|
||||
}
|
||||
updateEntity();
|
||||
updateFloor(true);
|
||||
deactivate();
|
||||
game->checkTrigger(this, true);
|
||||
} else {
|
||||
if (state == STATE_STAND) return;
|
||||
updateAnimation(true);
|
||||
if (state == STATE_STAND) {
|
||||
updateEntity();
|
||||
updateFloor(true);
|
||||
deactivate();
|
||||
game->checkTrigger(this, true);
|
||||
}
|
||||
}
|
||||
updateLights();
|
||||
}
|
||||
@@ -762,6 +785,57 @@ struct TrapSword : Controller {
|
||||
};
|
||||
|
||||
|
||||
struct ThorHammer : Controller {
|
||||
enum {
|
||||
STATE_IDLE,
|
||||
STATE_START,
|
||||
STATE_FALL,
|
||||
STATE_DOWN,
|
||||
};
|
||||
|
||||
Controller *block;
|
||||
|
||||
ThorHammer(IGame *game, int entity) : Controller(game, entity) {
|
||||
TR::Entity &e = getEntity();
|
||||
int index = level->entityAdd(TR::Entity::HAMMER_BLOCK, getRoomIndex(), e.x, e.y, e.z, e.rotation, -1);
|
||||
if (index > -1) {
|
||||
block = new Controller(game, index);
|
||||
level->entities[index].controller = block;
|
||||
}
|
||||
e.flags.collision = block->getEntity().flags.collision = false;
|
||||
}
|
||||
|
||||
virtual void update() {
|
||||
Character *lara = (Character*)game->getLara();
|
||||
|
||||
switch (state) {
|
||||
case STATE_IDLE : if (isActive()) animation.setState(STATE_START); break;
|
||||
case STATE_START : animation.setState(isActive() ? STATE_FALL : STATE_IDLE); break;
|
||||
case STATE_FALL : {
|
||||
if (animation.frameIndex > 30 && lara->health > 0.0f) {
|
||||
vec3 d = pos + getDir() * (3.0f * 1024.0f) - lara->pos;
|
||||
if (fabsf(d.x) < 520.0f && fabsf(d.z) < 520.0f)
|
||||
lara->hit(1001, this, TR::HIT_BOULDER);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_DOWN : {
|
||||
game->checkTrigger(this, 1);
|
||||
if (lara->health > 0.0f)
|
||||
getEntity().flags.collision = block->getEntity().flags.collision = true;
|
||||
deactivate(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateAnimation(true);
|
||||
block->animation.frameA = animation.frameA;
|
||||
block->animation.frameB = animation.frameB;
|
||||
block->animation.delta = animation.delta;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct TrapLava : Controller {
|
||||
bool done;
|
||||
|
||||
|
Reference in New Issue
Block a user