mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-17 18:36:43 +02:00
This commit is contained in:
@@ -60,7 +60,7 @@ struct Camera : ICamera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual int getRoomIndex() const {
|
virtual int getRoomIndex() const {
|
||||||
return room;
|
return (level->isFlipped && level->rooms[room].alternateRoom > -1) ? level->rooms[room].alternateRoom : room;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void checkRoom() {
|
virtual void checkRoom() {
|
||||||
|
@@ -764,7 +764,7 @@ namespace TR {
|
|||||||
opaque = true;
|
opaque = true;
|
||||||
if (type == SWITCH || type == SWITCH_WATER)
|
if (type == SWITCH || type == SWITCH_WATER)
|
||||||
opaque = true;
|
opaque = true;
|
||||||
if (type == PUZZLE_HOLE_1) // LEVEL3A cogs
|
if (type == PUZZLE_HOLE_1 || type == LIGHTNING) // LEVEL3A cogs
|
||||||
opaque = false;
|
opaque = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
37
src/lara.h
37
src/lara.h
@@ -228,6 +228,7 @@ struct Lara : Character {
|
|||||||
TR::Entity::Type usedKey;
|
TR::Entity::Type usedKey;
|
||||||
TR::Entity *pickupEntity;
|
TR::Entity *pickupEntity;
|
||||||
KeyHole *keyHole;
|
KeyHole *keyHole;
|
||||||
|
Lightning *lightning;
|
||||||
|
|
||||||
int roomPrev; // water out from room
|
int roomPrev; // water out from room
|
||||||
vec2 rotFactor;
|
vec2 rotFactor;
|
||||||
@@ -410,6 +411,9 @@ struct Lara : Character {
|
|||||||
damageTime = LARA_DAMAGE_TIME;
|
damageTime = LARA_DAMAGE_TIME;
|
||||||
hitTime = 0.0f;
|
hitTime = 0.0f;
|
||||||
|
|
||||||
|
keyHole = NULL;
|
||||||
|
lightning = NULL;
|
||||||
|
|
||||||
getEntity().flags.active = 1;
|
getEntity().flags.active = 1;
|
||||||
initMeshOverrides();
|
initMeshOverrides();
|
||||||
|
|
||||||
@@ -1341,10 +1345,11 @@ struct Lara : Character {
|
|||||||
Character::hit(damage, enemy, hitType);
|
Character::hit(damage, enemy, hitType);
|
||||||
|
|
||||||
switch (hitType) {
|
switch (hitType) {
|
||||||
case TR::HIT_BLADE : addBloodBlade(); break;
|
case TR::HIT_BLADE : addBloodBlade(); break;
|
||||||
case TR::HIT_SPIKES : addBloodSpikes(); break;
|
case TR::HIT_SPIKES : addBloodSpikes(); break;
|
||||||
case TR::HIT_SLAM : addBloodSlam(enemy); break;
|
case TR::HIT_SLAM : addBloodSlam(enemy); break;
|
||||||
default : ;
|
case TR::HIT_LIGHTNING : lightning = (Lightning*)enemy; break;
|
||||||
|
default : ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (health > 0.0f)
|
if (health > 0.0f)
|
||||||
@@ -2321,8 +2326,17 @@ struct Lara : Character {
|
|||||||
if (Input::state[cWeapon]) input |= WEAPON;
|
if (Input::state[cWeapon]) input |= WEAPON;
|
||||||
|
|
||||||
// scion debug (TODO: remove)
|
// scion debug (TODO: remove)
|
||||||
if (Input::down[ikP] && level->id == TR::LEVEL_3B)
|
if (Input::down[ikP]) {
|
||||||
reset(5, vec3(73394, 3840, 60758), 0); // level 3b (scion)
|
switch (level->id) {
|
||||||
|
case TR::LEVEL_3B :
|
||||||
|
reset(5, vec3(73394, 3840, 60758), 0); // level 3b (scion)
|
||||||
|
break;
|
||||||
|
case TR::LEVEL_4 :
|
||||||
|
reset(18, vec3(34914, 11008, 41315), 90 * DEG2RAD); // main hall
|
||||||
|
break;
|
||||||
|
default : game->playSound(TR::SND_NO, pos, Sound::PAN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// analog control
|
// analog control
|
||||||
rotFactor = vec2(1.0f);
|
rotFactor = vec2(1.0f);
|
||||||
@@ -2470,7 +2484,7 @@ struct Lara : Character {
|
|||||||
switch (stand) {
|
switch (stand) {
|
||||||
case STAND_AIR :
|
case STAND_AIR :
|
||||||
velocity.y += (velocity.y >= 128.0f ? 30.0f : GRAVITY) * Core::deltaTime;
|
velocity.y += (velocity.y >= 128.0f ? 30.0f : GRAVITY) * Core::deltaTime;
|
||||||
if (velocity.y >= 154.0f)
|
if (velocity.y >= 154.0f && state == STATE_FALL)
|
||||||
game->playSound(TR::SND_SCREAM, pos, Sound::PAN);
|
game->playSound(TR::SND_SCREAM, pos, Sound::PAN);
|
||||||
/*
|
/*
|
||||||
if (state == STATE_FALL || state == STATE_FAST_DIVE) {
|
if (state == STATE_FALL || state == STATE_FAST_DIVE) {
|
||||||
@@ -2636,7 +2650,14 @@ struct Lara : Character {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
hitDir = -1;
|
if (lightning && lightning->flash && !lightning->armed) {
|
||||||
|
if (hitDir == -1)
|
||||||
|
hitTime = 0.0f;
|
||||||
|
hitDir = int(randf() * 4);
|
||||||
|
} else {
|
||||||
|
hitDir = -1;
|
||||||
|
lightning = NULL;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
28
src/level.h
28
src/level.h
@@ -504,6 +504,8 @@ struct Level : IGame {
|
|||||||
|
|
||||||
static void fillCallback(int id, int width, int height, int tileX, int tileY, void *userData, void *data) {
|
static void fillCallback(int id, int width, int height, int tileX, int tileY, void *userData, void *data) {
|
||||||
static const uint32 barColor[UI::BAR_MAX][25] = {
|
static const uint32 barColor[UI::BAR_MAX][25] = {
|
||||||
|
// flash bar
|
||||||
|
{ 0x00000000, 0xFFA20058, 0xFFFFFFFF, 0xFFA20058, 0x00000000 },
|
||||||
// health bar
|
// health bar
|
||||||
{ 0xFF2C5D71, 0xFF5E81AE, 0xFF2C5D71, 0xFF1B4557, 0xFF16304F },
|
{ 0xFF2C5D71, 0xFF5E81AE, 0xFF2C5D71, 0xFF1B4557, 0xFF16304F },
|
||||||
// oxygen bar
|
// oxygen bar
|
||||||
@@ -548,6 +550,7 @@ struct Level : IGame {
|
|||||||
uvCount = 4;
|
uvCount = 4;
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
case UI::BAR_FLASH :
|
||||||
case UI::BAR_HEALTH :
|
case UI::BAR_HEALTH :
|
||||||
case UI::BAR_OXYGEN :
|
case UI::BAR_OXYGEN :
|
||||||
case UI::BAR_OPTION :
|
case UI::BAR_OPTION :
|
||||||
@@ -661,14 +664,10 @@ struct Level : IGame {
|
|||||||
|
|
||||||
tiles->add(uv, texIdx++);
|
tiles->add(uv, texIdx++);
|
||||||
}
|
}
|
||||||
// add health bar
|
// add common textures
|
||||||
tiles->add(short4(2048, 2048, 2048, 2048 + 4), texIdx++);
|
const short2 bar[UI::BAR_MAX] = { {0, 4}, {0, 4}, {0, 4}, {4, 4}, {0, 0} };
|
||||||
// add oxygen bar
|
for (int i = 0; i < UI::BAR_MAX; i++)
|
||||||
tiles->add(short4(4096, 4096, 4096, 4096 + 4), texIdx++);
|
tiles->add(short4(i * 32, 4096, i * 32 + bar[i].x, 4096 + bar[i].y), texIdx++);
|
||||||
// add option bar
|
|
||||||
tiles->add(short4(8192, 8192, 8192 + 4, 8192 + 4), texIdx++);
|
|
||||||
// add white color
|
|
||||||
tiles->add(short4(2048, 2048, 2048, 2048), texIdx++);
|
|
||||||
|
|
||||||
// get result texture
|
// get result texture
|
||||||
atlas = tiles->pack();
|
atlas = tiles->pack();
|
||||||
@@ -993,10 +992,19 @@ struct Level : IGame {
|
|||||||
setupBinding();
|
setupBinding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: opqque/transparent pass for rooms and entities
|
||||||
|
void renderEntities(bool opaque) {
|
||||||
|
for (int i = 0; i < level.entitiesCount; i++) {
|
||||||
|
int modelIndex = level.entities[i].modelIndex;
|
||||||
|
if ((modelIndex < 0 && !opaque) || (modelIndex > 0 && mesh->models[modelIndex - 1].opaque == opaque))
|
||||||
|
renderEntity(level.entities[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void renderEntities() {
|
void renderEntities() {
|
||||||
PROFILE_MARKER("ENTITIES");
|
PROFILE_MARKER("ENTITIES");
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
renderEntities(true);
|
||||||
renderEntity(level.entities[i]);
|
renderEntities(false);
|
||||||
|
|
||||||
for (int i = 0; i < level.entitiesCount; i++) {
|
for (int i = 0; i < level.entitiesCount; i++) {
|
||||||
TR::Entity &entity = level.entities[i];
|
TR::Entity &entity = level.entities[i];
|
||||||
|
@@ -5,8 +5,8 @@
|
|||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
|
||||||
TR::ObjectTexture barTile[4 /* UI::BAR_MAX */];
|
TR::ObjectTexture barTile[5 /* UI::BAR_MAX */];
|
||||||
TR::ObjectTexture &whiteTile = barTile[3];
|
TR::ObjectTexture &whiteTile = barTile[4]; // BAR_WHITE
|
||||||
|
|
||||||
struct MeshRange {
|
struct MeshRange {
|
||||||
int iStart;
|
int iStart;
|
||||||
|
109
src/trigger.h
109
src/trigger.h
@@ -353,7 +353,7 @@ struct Block : Controller {
|
|||||||
pos.y += Core::deltaTime * velocity * 30.0f;
|
pos.y += Core::deltaTime * velocity * 30.0f;
|
||||||
if (pos.y >= info.floor) {
|
if (pos.y >= info.floor) {
|
||||||
velocity = 0.0f;
|
velocity = 0.0f;
|
||||||
pos.y = info.floor;
|
pos.y = float(info.floor);
|
||||||
game->setEffect(this, TR::Effect::FLOOR_SHAKE);
|
game->setEffect(this, TR::Effect::FLOOR_SHAKE);
|
||||||
game->playSound(TR::SND_BOULDER, pos, Sound::PAN);
|
game->playSound(TR::SND_BOULDER, pos, Sound::PAN);
|
||||||
deactivate(true);
|
deactivate(true);
|
||||||
@@ -839,7 +839,7 @@ struct ThorHammer : Controller {
|
|||||||
#define LIGHTNING_DAMAGE 400
|
#define LIGHTNING_DAMAGE 400
|
||||||
|
|
||||||
struct Lightning : Controller {
|
struct Lightning : Controller {
|
||||||
Basis target;
|
vec3 target;
|
||||||
float timer;
|
float timer;
|
||||||
bool flash;
|
bool flash;
|
||||||
bool armed;
|
bool armed;
|
||||||
@@ -850,6 +850,8 @@ struct Lightning : Controller {
|
|||||||
if (isActive()) {
|
if (isActive()) {
|
||||||
timer -= Core::deltaTime;
|
timer -= Core::deltaTime;
|
||||||
|
|
||||||
|
Character *lara = (Character*)level->laraController;
|
||||||
|
|
||||||
if (timer <= 0.0f) {
|
if (timer <= 0.0f) {
|
||||||
if (flash) {
|
if (flash) {
|
||||||
level->isFlipped = false;
|
level->isFlipped = false;
|
||||||
@@ -861,17 +863,15 @@ struct Lightning : Controller {
|
|||||||
flash = true;
|
flash = true;
|
||||||
timer = 20.0f / 30.0f;
|
timer = 20.0f / 30.0f;
|
||||||
|
|
||||||
Character *lara = (Character*)level->laraController;
|
|
||||||
|
|
||||||
bool hasTargets = getModel()->mCount > 1; // LEVEL4 has, LEVEL10C not
|
bool hasTargets = getModel()->mCount > 1; // LEVEL4 has, LEVEL10C not
|
||||||
|
|
||||||
if ((lara->pos - pos).length() < (hasTargets ? 2560.0f : 1024.0f)) {
|
if ((lara->pos - pos).length() < (hasTargets ? 2560.0f : 1024.0f)) {
|
||||||
lara->hit(LIGHTNING_DAMAGE, this, TR::HIT_LIGHTNING);
|
lara->hit(LIGHTNING_DAMAGE, this, TR::HIT_LIGHTNING);
|
||||||
armed = false;
|
armed = false;
|
||||||
} else if (!hasTargets) {
|
} else if (!hasTargets) {
|
||||||
//
|
target = pos + vec3(0.0f, 1024.0f, 0.0f);
|
||||||
} else
|
} else
|
||||||
animation.getJoints(getMatrix(), int(randf() * 5), false, &target);
|
target = animation.getJoints(getMatrix(), 1 + int(randf() * 5)).pos;
|
||||||
}
|
}
|
||||||
game->playSound(TR::SND_LIGHTNING, pos, Sound::PAN);
|
game->playSound(TR::SND_LIGHTNING, pos, Sound::PAN);
|
||||||
}
|
}
|
||||||
@@ -883,10 +883,105 @@ struct Lightning : Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void divide(vec3 *points, int L, int R, float spread) {
|
||||||
|
int M = (L + R) / 2;
|
||||||
|
if (M == L || M == R) return;
|
||||||
|
points[M] = (points[L] + points[R]) * 0.5f + (vec3(randf(), randf(), randf()) - 0.5f) * spread;
|
||||||
|
spread *= 0.5f;
|
||||||
|
divide(points, L, M, spread);
|
||||||
|
divide(points, M, R, spread);
|
||||||
|
}
|
||||||
|
|
||||||
|
short4 toCoord(const vec3 &v, int16 joint) {
|
||||||
|
return short4(int16(v.x), int16(v.y), int16(v.z), joint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setVertex(Vertex &v, const vec3 &coord, int16 joint, int idx) {
|
||||||
|
v.coord = toCoord(coord, joint);
|
||||||
|
v.normal = { 0, -1, 0, 0 };
|
||||||
|
v.texCoord = { barTile[0].texCoord[idx].x, barTile[0].texCoord[idx].y, 32767, 32767 };
|
||||||
|
v.param = { 0, 0, 0, 0 };
|
||||||
|
v.color = { 255, 255, 255, 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderPolyline(const vec3 &start, const vec3 &end, float width, float spread, int depth) {
|
||||||
|
vec3 points[9];
|
||||||
|
points[0] = start;
|
||||||
|
points[8] = end;
|
||||||
|
divide(points, 0, 8, spread);
|
||||||
|
|
||||||
|
Index indices[(COUNT(points) - 1) * 6];
|
||||||
|
Vertex vertices[COUNT(points) * 2];
|
||||||
|
|
||||||
|
int iCount = 0;
|
||||||
|
int vCount = 0;
|
||||||
|
int count = COUNT(points);
|
||||||
|
// build indices
|
||||||
|
for (int i = 0; i < count - 1; i++) {
|
||||||
|
indices[iCount++] = vCount;
|
||||||
|
indices[iCount++] = vCount + 1;
|
||||||
|
indices[iCount++] = vCount + 2;
|
||||||
|
indices[iCount++] = vCount + 1;
|
||||||
|
indices[iCount++] = vCount + 3;
|
||||||
|
indices[iCount++] = vCount + 2;
|
||||||
|
vCount += 2;
|
||||||
|
}
|
||||||
|
vCount += 2;
|
||||||
|
ASSERT(iCount == (count - 1) * 6);
|
||||||
|
ASSERT(vCount == count * 2);
|
||||||
|
|
||||||
|
// build vertices
|
||||||
|
vec3 dir = Core::mViewInv.dir.xyz;
|
||||||
|
|
||||||
|
vCount = 0;
|
||||||
|
vec3 n;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
if (i < count - 1)
|
||||||
|
n = dir.cross(points[i + 1] - points[i]).normal() * width;
|
||||||
|
setVertex(vertices[vCount++], points[i] - n, 0, 0);
|
||||||
|
setVertex(vertices[vCount++], points[i] + n, 0, 3);
|
||||||
|
}
|
||||||
|
ASSERT(vCount == count * 2);
|
||||||
|
|
||||||
|
game->getMesh()->renderBuffer(indices, iCount, vertices, vCount);
|
||||||
|
|
||||||
|
if (depth > 0) {
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
vec3 a = points[int(randf() * (count - 1))];
|
||||||
|
vec3 b = a;
|
||||||
|
b.x += (randf() - 0.5f) * spread;
|
||||||
|
b.y = points[count - 1].y;
|
||||||
|
b.z += (randf() - 0.5f) * spread;
|
||||||
|
|
||||||
|
renderPolyline(a, b, width * 0.75f, spread * 0.5f, depth - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
|
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
|
||||||
Controller::render(frustum, mesh, type, caustics);
|
Controller::render(frustum, mesh, type, caustics);
|
||||||
if (!flash) return;
|
if (!flash) return;
|
||||||
// TODO
|
|
||||||
|
if (!armed)
|
||||||
|
target = game->getLara()->pos;
|
||||||
|
|
||||||
|
Basis b = animation.getJoints(getMatrix(), 0);
|
||||||
|
b.rot = quat(0, 0, 0, 1);
|
||||||
|
|
||||||
|
game->setShader(Core::pass, Shader::FLASH, false, false);
|
||||||
|
Core::active.shader->setParam(uMaterial, vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||||
|
Core::active.shader->setParam(uBasis, b);
|
||||||
|
|
||||||
|
Core::setCulling(cfNone);
|
||||||
|
Core::setBlending(bmAdd);
|
||||||
|
Core::setDepthWrite(false);
|
||||||
|
|
||||||
|
renderPolyline(vec3(0.0f), target - b.pos, 64.0f, 512.0f, 1);
|
||||||
|
|
||||||
|
Core::setDepthWrite(true);
|
||||||
|
Core::setBlending(bmNone);
|
||||||
|
Core::setCulling(cfFront);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
1
src/ui.h
1
src/ui.h
@@ -204,6 +204,7 @@ namespace UI {
|
|||||||
#define MAX_CHARS DYN_MESH_QUADS
|
#define MAX_CHARS DYN_MESH_QUADS
|
||||||
|
|
||||||
enum BarType {
|
enum BarType {
|
||||||
|
BAR_FLASH,
|
||||||
BAR_HEALTH,
|
BAR_HEALTH,
|
||||||
BAR_OXYGEN,
|
BAR_OXYGEN,
|
||||||
BAR_OPTION,
|
BAR_OPTION,
|
||||||
|
@@ -204,8 +204,8 @@ struct vec2 {
|
|||||||
|
|
||||||
struct vec3 {
|
struct vec3 {
|
||||||
union {
|
union {
|
||||||
struct { vec2 xy; };
|
|
||||||
struct { float x, y, z; };
|
struct { float x, y, z; };
|
||||||
|
struct { vec2 xy; };
|
||||||
};
|
};
|
||||||
|
|
||||||
vec3() {}
|
vec3() {}
|
||||||
@@ -271,9 +271,9 @@ struct vec3 {
|
|||||||
|
|
||||||
struct vec4 {
|
struct vec4 {
|
||||||
union {
|
union {
|
||||||
|
struct { float x, y, z, w; };
|
||||||
struct { vec2 xy, zw; };
|
struct { vec2 xy, zw; };
|
||||||
struct { vec3 xyz; };
|
struct { vec3 xyz; };
|
||||||
struct { float x, y, z, w; };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
vec4() {}
|
vec4() {}
|
||||||
|
Reference in New Issue
Block a user