1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-16 01:54:38 +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 renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {}
virtual void renderCompose(int roomIndex) {} virtual void renderCompose(int roomIndex) {}
virtual void renderView(int roomIndex, bool water) {} 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) {} virtual void checkTrigger(Controller *controller, bool heavy) {}
@@ -520,7 +520,7 @@ struct Controller {
if (cmd == TR::ANIM_CMD_EFFECT) { if (cmd == TR::ANIM_CMD_EFFECT) {
switch (fx) { switch (fx) {
case TR::Effect::ROTATE_180 : angle.y = angle.y + PI; break; 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; case TR::Effect::FLIP_MAP : level->isFlipped = !level->isFlipped; break;
default : cmdEffect(fx); break; default : cmdEffect(fx); break;
} }
@@ -698,28 +698,35 @@ struct Controller {
if (entity.isActor()) // cutscene entities have no blob shadow if (entity.isActor()) // cutscene entities have no blob shadow
return; return;
Box box = animation.getBoundingBox(pos, 0); Box boxL = getBoundingBoxLocal();
vec3 center = box.center(); Box boxA = boxL * getMatrix();
vec3 center = boxA.center();
TR::Level::FloorInfo info; TR::Level::FloorInfo info;
level->getFloorInfo(entity.room, int(center.x), int(center.y), int(center.z), 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 = boxL.size() * (1.0f / 1024.0f);
const vec3 size = box.size();
mat4 m = Core::mViewProj; vec3 dir = getDir();
m.translate(fpos); vec3 up = info.getNormal();
m.rotateY(angle.y); vec3 right = dir.cross(up).normal();
m.translate(vec3(center.x - pos.x, 0.0f, center.z - pos.z)); dir = up.cross(right).normal();
m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f));
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; Basis b;
b.identity(); b.identity();
game->setShader(Core::pass, Shader::FLASH, false, false); 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); 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(uMaterial, vec4(vec3(0.5f * (1.0f - alpha)), alpha));
Core::active.shader->setParam(uAmbient, vec3(0.0f)); Core::active.shader->setParam(uAmbient, vec3(0.0f));

View File

@@ -662,7 +662,8 @@ namespace TR {
return isEnemy() || return isEnemy() ||
isDoor() || isDoor() ||
(type == DRAWBRIDGE && flags.active != ACTIVE) || (type == DRAWBRIDGE && flags.active != ACTIVE) ||
(type == SCION_HOLDER); (type == SCION_HOLDER) ||
((type == HAMMER_HANDLE || type == HAMMER_BLOCK) && flags.collision);
} }
bool isItem() const { bool isItem() const {
@@ -2266,6 +2267,13 @@ namespace TR {
} }
break; 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_0 :
case Entity::BRIDGE_1 : case Entity::BRIDGE_1 :
case Entity::BRIDGE_2 : { case Entity::BRIDGE_2 : {

View File

@@ -1366,14 +1366,20 @@ struct Lara : Character {
} }
case TR::HIT_BOULDER : { case TR::HIT_BOULDER : {
animation.setAnim(ANIM_DEATH_BOULDER); animation.setAnim(ANIM_DEATH_BOULDER);
if (enemy)
vec3 v(0.0f);
if (enemy && enemy->getEntity().type == TR::Entity::TRAP_BOULDER) {
angle = enemy->angle; angle = enemy->angle;
TR::Level::FloorInfo info; TR::Level::FloorInfo info;
level->getFloorInfo(getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), info); level->getFloorInfo(getRoomIndex(), int(pos.x), int(pos.y), int(pos.z), info);
vec3 d = getDir(); vec3 d = getDir();
vec3 v = info.getSlant(d); v = info.getSlant(d);
angle.x = -acos(d.dot(v)); float dp = d.dot(v);
v = enemy ? ((TrapBoulder*)enemy)->velocity * 2.0f : vec3(0.0f); if (fabsf(dp) < 0.999)
angle.x = -acosf(dp);
v = ((TrapBoulder*)enemy)->velocity * 2.0f;
}
for (int i = 0; i < 15; i++) for (int i = 0; i < 15; i++)
addBlood(256.0f, 512.0f, v); addBlood(256.0f, 512.0f, v);
break; break;
@@ -1822,7 +1828,7 @@ struct Lara : Character {
if (needFlip) { if (needFlip) {
level->isFlipped = !level->isFlipped; level->isFlipped = !level->isFlipped;
game->setEffect(effect, 0); game->setEffect(this, effect);
} }
} }
@@ -2573,7 +2579,7 @@ struct Lara : Character {
} }
// check enemies & doors // 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]; TR::Entity &e = level->entities[i];
if (!e.isCollider()) continue; if (!e.isCollider()) continue;
@@ -2581,11 +2587,12 @@ struct Lara : Character {
Controller *controller = (Controller*)e.controller; Controller *controller = (Controller*)e.controller;
if (e.isEnemy()) { 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 { } else {
// fast distance check for object // fast distance check for object
TR::Entity &entity = getEntity(); 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; vec3 dir = pos - vec3(0.0f, 128.0f, 0.0f) - controller->pos;
@@ -2594,7 +2601,7 @@ struct Lara : Character {
Box box = controller->getBoundingBoxLocal(); Box box = controller->getBoundingBoxLocal();
box.expand(vec3(LARA_RADIUS, 0.0f, LARA_RADIUS)); 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; continue;
if (e.isEnemy()) { // enemy collision 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->effect = effect;
this->effectTimer = 0.0f; this->effectTimer = 0.0f;
this->effectIdx = 0; this->effectIdx = 0;
switch (effect) { switch (effect) {
case TR::Effect::FLOOR_SHAKE : 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; return;
case TR::Effect::FLOOD : { case TR::Effect::FLOOD : {
Sound::Sample *sample = playSound(TR::SND_FLOOD, vec3(), 0); 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_CEILING_2 : return new TrapCeiling(this, index);
case TR::Entity::TRAP_SLAM : return new TrapSlam(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::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::DOOR_LATCH : return new DoorLatch(this, index);
case TR::Entity::SWITCH : case TR::Entity::SWITCH :
case TR::Entity::SWITCH_WATER : return new Switch(this, index); case TR::Entity::SWITCH_WATER : return new Switch(this, index);

View File

@@ -283,7 +283,9 @@ struct Block : Controller {
STATE_PULL, 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); updateFloor(true);
} }
@@ -339,13 +341,34 @@ struct Block : Controller {
} }
virtual void update() { virtual void update() {
if (state == STATE_STAND) return; TR::Entity &e = getEntity();
updateAnimation(true); TR::Level::FloorInfo info;
if (state == STATE_STAND) { 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(); updateEntity();
updateFloor(true); } else {
deactivate(); if (state == STATE_STAND) return;
game->checkTrigger(this, true); updateAnimation(true);
if (state == STATE_STAND) {
updateEntity();
updateFloor(true);
deactivate();
game->checkTrigger(this, true);
}
} }
updateLights(); 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 { struct TrapLava : Controller {
bool done; bool done;