1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-14 00:54:05 +02:00

#22 add falling blocks, add thor hammer; #23 blob shadows surface projection

This commit is contained in:
XProger
2017-10-04 07:12:27 +03:00
parent 77d96ccb05
commit b16e7d2f67
5 changed files with 132 additions and 35 deletions

View File

@@ -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));

View File

@@ -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 : {

View File

@@ -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

View File

@@ -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);

View File

@@ -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;