1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-15 09:34:18 +02:00

#23 fix items opacity; fix water mask for desktop NVIDIA cards; #22 fix lava trap; cutscene wait timer (for sound sync WIP); #15 extern osGetTime

This commit is contained in:
XProger
2017-12-07 12:11:25 +03:00
parent 1b4a6dadb0
commit 353e09cb64
13 changed files with 281 additions and 194 deletions

View File

@@ -413,7 +413,7 @@ struct Controller {
} while (!cmd.end);
}
virtual void getSaveData(TR::SaveGame::Entity &data) {
virtual bool getSaveData(TR::SaveGame::Entity &data) {
const TR::Entity &e = getEntity();
const TR::Model *m = getModel();
if (entity < level->entitiesBaseCount) {
@@ -439,6 +439,8 @@ struct Controller {
data.animFrame = m ? animation.frameIndex : 0;
data.extraSize = 0;
return true;
}
virtual void setSaveData(const TR::SaveGame::Entity &data) {
@@ -945,6 +947,7 @@ struct Controller {
virtual void update() {
updateAnimation(true);
updateExplosion();
updateLights(true);
}
void updateLights(bool lerp = true) {
@@ -1043,9 +1046,7 @@ struct Controller {
}
void renderShadow(MeshBuilder *mesh) {
const TR::Entity &entity = getEntity();
if (Core::pass != Core::passCompose || !entity.castShadow() || entity.isActor())
if (Core::pass != Core::passCompose || level->isCutsceneLevel())
return;
Box boxL = getBoundingBoxLocal();

View File

@@ -162,7 +162,8 @@ struct KeySet {
namespace Core {
float deltaTime;
int width, height;
int lastTime;
int width, height;
struct {
int maxVectors;
@@ -237,6 +238,17 @@ namespace Core {
bool reverb;
} audio;
} settings;
bool resetState;
int getTime() {
return osGetTime();
}
void resetTime() {
lastTime = getTime();
resetState = true;
}
}
#include "input.h"
@@ -444,8 +456,6 @@ struct Vertex {
enum CullFace { cfNone, cfBack, cfFront };
enum BlendMode { bmNone, bmAlpha, bmAdd, bmMult, bmPremult };
extern int getTime();
namespace Core {
float eye;
vec4 viewport, viewportDef;
@@ -506,16 +516,16 @@ namespace Core {
}
void stop() {
if (fpsTime < getTime()) {
if (fpsTime < Core::getTime()) {
LOG("FPS: %d DIP: %d TRI: %d\n", fps, dips, tris);
#ifdef PROFILE
LOG("frame time: %d mcs\n", tFrame / 1000);
#endif
fps = frame;
frame = 0;
fpsTime = getTime() + 1000;
fpsTime = Core::getTime() + 1000;
} else
frame++;
frame++;
}
} stats;
}
@@ -723,6 +733,7 @@ namespace Core {
#ifdef __RPI__
settings.detail.setShadows(Core::Settings::LOW);
#endif
resetTime();
}
void deinit() {
@@ -762,6 +773,16 @@ namespace Core {
return cache.count++;
}
bool update() {
resetState = false;
int time = getTime();
if (time - lastTime <= 0)
return false;
deltaTime = (time - lastTime) * 0.001f;
lastTime = time;
return true;
}
void validateRenderState() {
int32 mask = renderState ^ active.renderState;
if (!mask) return;

View File

@@ -77,17 +77,20 @@ struct Enemy : Character {
delete path;
}
virtual void getSaveData(TR::SaveGame::Entity &data) {
virtual bool getSaveData(TR::SaveGame::Entity &data) {
Character::getSaveData(data);
data.extraSize = sizeof(data.extra.enemy);
data.extra.enemy.health = uint16(health);
data.extra.enemy.mood = uint16(mood);
data.extra.enemy.health = health;
data.extra.enemy.mood = mood;
data.extra.enemy.targetBox = targetBox;
return true;
}
virtual void setSaveData(const TR::SaveGame::Entity &data) {
Character::setSaveData(data);
health = float(data.extra.enemy.health);
mood = Mood(data.extra.enemy.mood);
health = data.extra.enemy.health;
mood = Mood(data.extra.enemy.mood);
targetBox = data.extra.enemy.targetBox;
}
virtual bool activate() {
@@ -1321,9 +1324,7 @@ struct Doppelganger : Enemy {
struct ScionTarget : Enemy {
float timer;
ScionTarget(IGame *game, int entity) : Enemy(game, entity, 5, 0, 0, 0), timer(0.0f) {}
ScionTarget(IGame *game, int entity) : Enemy(game, entity, 5, 0, 0, 0) {}
virtual void update() {
Controller::update();

View File

@@ -1648,10 +1648,10 @@ namespace TR {
return type;
if (version & VER_TR2)
type = TR::Entity::Type(type + TR2_TYPES_START);
type = Type(type + TR2_TYPES_START);
if (version & VER_TR3)
type = TR::Entity::Type(type + TR3_TYPES_START);
type = Type(type + TR3_TYPES_START);
#define REMAP_2(TYPE) case _##TYPE : return TYPE
#define REMAP_3(TYPE) case __##TYPE : return TYPE
@@ -2327,6 +2327,25 @@ namespace TR {
struct SaveGame {
struct Item {
uint16 type;
uint16 count;
};
struct Progress {
uint32 size;
uint32 time;
uint32 distance;
uint8 levelID;
uint8 mediUsed;
uint8 secrets;
uint8 pickups;
uint16 ammoUsed;
uint8 kills;
uint8 itemsCount;
// Item items[itemsCount]
};
struct Entity {
// base
int32 x, y, z;
@@ -2338,64 +2357,56 @@ namespace TR {
uint16 animIndex;
uint16 animFrame;
// common
uint8 room;
uint8 extraSize;
uint16 room;
uint16 extraSize;
union Extra {
struct {
float velX, velY, velZ;
uint16 angleX;
uint16 health;
uint16 oxygen;
uint16 stamina;
uint8 itemHands;
uint8 itemBack;
uint8 itemHolster;
float angleX;
float health;
float oxygen;
float stamina;
float poison;
float freeze;
uint16 itemHands;
uint16 itemBack;
uint16 itemHolster;
union {
struct { uint8 wet:1, burn:1; };
uint8 value;
struct { uint16 wet:1, burn:1; };
uint16 value;
} flags;
} lara;
struct {
uint16 health;
float health;
uint16 mood;
uint16 targetBox;
} enemy;
struct {
int32 jointIndex;
float sleep;
} flame;
} extra;
};
struct Item {
uint16 type;
uint16 count;
};
struct CurrentState {
// EntityState entities[entitiesCount];
ByteFlags flipmaps[MAX_FLIPMAP_COUNT];
ByteFlags tracks[MAX_TRACKS_COUNT];
uint32 fogColor;
uint16 secrets;
uint16 fogColor;
union {
struct { uint16 track:8, flipped:1; };
uint16 value;
} flags;
ByteFlags flipmaps[MAX_FLIPMAP_COUNT];
ByteFlags tracks[MAX_TRACKS_COUNT];
uint16 entitiesCount;
Progress progress;
//Entity entities[entitiesCount];
};
uint32 size;
uint16 levelID;
// full game stats
uint16 mediUsed;
uint16 pickups;
uint16 secrets;
uint32 kills;
uint32 ammoUsed;
uint32 distance;
uint32 time;
uint16 itemsCount; // 0 -> skip inventory items array
uint16 entitiesCount; // 0 -> skip current state
// Item items[itemsCount]
int32 size;
uint16 version;
uint16 progressCount;
// Progress progress[levelsCount];
// CurrentState currentState;
};

View File

@@ -75,16 +75,21 @@ namespace Game {
Core::deltaTime = dt;
}
void update(float delta) {
bool update() {
PROFILE_MARKER("UPDATE");
if (!Core::update())
return false;
float delta = Core::deltaTime;
if (nextLevel) {
startLevel(nextLevel);
nextLevel = NULL;
}
if (level->isEnded)
return;
return true;
Input::update();
@@ -94,7 +99,7 @@ namespace Game {
Input::down[ikV] = false;
}
}
/*
if (Input::down[ikS]) {
if (level->lara->canSaveGame())
level->saveGame(0);
@@ -105,16 +110,10 @@ namespace Game {
level->loadGame(0);
Input::down[ikL] = false;
}
*/
if (!level->level.isCutsceneLevel())
delta = min(0.2f, delta);
if (level->cutsceneFirstFrame) {
level->cutsceneFirstFrame = false;
delta = 1.0f / 30.0f;
}
Core::deltaTime = delta;
UI::update();
@@ -122,7 +121,11 @@ namespace Game {
Core::deltaTime = min(delta, 1.0f / 30.0f);
Game::updateTick();
delta -= Core::deltaTime;
if (Core::resetState) // resetTime was called
break;
}
return true;
}
void render() {

View File

@@ -529,30 +529,33 @@ struct Lara : Character {
return health > 0.0f && (state == STATE_STOP || state == STATE_TREAD || state == STATE_SURF_TREAD);
}
virtual void getSaveData(TR::SaveGame::Entity &data) {
virtual bool getSaveData(TR::SaveGame::Entity &data) {
Character::getSaveData(data);
data.extraSize = sizeof(data.extra.lara);
data.extra.lara.velX = velocity.x;
data.extra.lara.velY = velocity.y;
data.extra.lara.velZ = velocity.z;
data.extra.lara.angleX = TR::angle(normalizeAngle(angle.x)).value;
data.extra.lara.health = uint16(health);
data.extra.lara.oxygen = uint16(oxygen);
// data.extra.lara.curWeapon = int8(wpnCurrent);
// data.extra.lara.emptyHands = emptyHands();
/*
uint16 itemHands;
uint16 itemBack;
uint16 itemHolster;
*/
data.extra.lara.velX = velocity.x;
data.extra.lara.velY = velocity.y;
data.extra.lara.velZ = velocity.z;
data.extra.lara.angleX = angle.x;
data.extra.lara.health = health;
data.extra.lara.oxygen = oxygen;
data.extra.lara.stamina = 0.0f;
data.extra.lara.poison = 0.0f;
data.extra.lara.freeze = 0.0f;
data.extra.lara.itemHands = TR::Entity::LARA;
data.extra.lara.itemBack = TR::Entity::SHOTGUN;
data.extra.lara.itemHolster = TR::Entity::PISTOLS;
data.extra.lara.flags.value = 0;
data.extra.lara.flags.burn = 0; // TODO
data.extra.lara.flags.wet = 0; // TODO
return true;
}
virtual void setSaveData(const TR::SaveGame::Entity &data) {
Character::setSaveData(data);
velocity = vec3(data.extra.lara.velX, data.extra.lara.velY, data.extra.lara.velZ);
angle.x = TR::angle(data.extra.lara.angleX);
health = float(data.extra.lara.health);
oxygen = float(data.extra.lara.oxygen);
health = data.extra.lara.health;
oxygen = data.extra.lara.oxygen;
layers[1].mask = layers[2].mask = layers[3].mask = 0;
wpnState = Weapon::IS_HIDDEN;
@@ -1998,8 +2001,8 @@ struct Lara : Character {
effect = TR::Effect(cmd.args);
break;
case TR::Action::SECRET :
if (!(level->state.secrets & (1 << cmd.args))) {
level->state.secrets |= 1 << cmd.args;
if (!(level->state.progress.secrets & (1 << cmd.args))) {
level->state.progress.secrets |= 1 << cmd.args;
if (!game->playSound(TR::SND_SECRET, pos))
game->playTrack(TR::TRACK_TR1_SECRET);
}

View File

@@ -46,11 +46,11 @@ struct Level : IGame {
bool lastTitle;
bool isEnded;
bool cutsceneFirstFrame;
TR::Effect effect;
float effectTimer;
int effectIdx;
float cutsceneWaitTimer;
Texture *cube360;
@@ -105,40 +105,50 @@ struct Level : IGame {
*save = level.save;
ptr += sizeof(*save);
// inventory items
save->itemsCount = 0;
for (int i = 0; i < inventory.itemsCount; i++) {
TR::SaveGame::Item *item = (TR::SaveGame::Item*)ptr;
Inventory::Item *invItem = inventory.items[i];
// save levels progress
save->progressCount = 0;
bool saveCurrentState = true;
if (saveCurrentState) {
TR::SaveGame::CurrentState *currentState = (TR::SaveGame::CurrentState*)ptr;
ptr += sizeof(TR::SaveGame::CurrentState);
*currentState = level.state;
// inventory items
currentState->progress.itemsCount = 0;
for (int i = 0; i < inventory.itemsCount; i++) {
TR::SaveGame::Item *item = (TR::SaveGame::Item*)ptr;
Inventory::Item *invItem = inventory.items[i];
if (!TR::Entity::isPickup(TR::Entity::convFromInv(invItem->type))) continue;
if (!TR::Entity::isPickup(TR::Entity::convFromInv(invItem->type))) continue;
item->type = invItem->type;
item->count = invItem->count;
item->type = invItem->type;
item->count = invItem->count;
ptr += sizeof(*item);
save->itemsCount++;
ptr += sizeof(*item);
currentState->progress.itemsCount++;
}
// level entities
currentState->entitiesCount = 0;
for (int i = 0; i < level.entitiesCount; i++) {
Controller *controller = (Controller*)level.entities[i].controller;
TR::SaveGame::Entity *entity = (TR::SaveGame::Entity*)ptr;
if (!controller || !controller->getSaveData(*entity)) continue;
ptr += (sizeof(TR::SaveGame::Entity) - sizeof(TR::SaveGame::Entity::Extra)) + entity->extraSize;
currentState->entitiesCount++;
}
}
// level entities
save->entitiesCount = 0;
for (int i = 0; i < level.entitiesCount; i++) {
Controller *controller = (Controller*)level.entities[i].controller;
if (!controller || (controller->getEntity().isSprite() && !controller->getEntity().isPickup())) continue;
TR::SaveGame::Entity *entity = (TR::SaveGame::Entity*)ptr;
controller->getSaveData(*entity);
ptr += (sizeof(TR::SaveGame::Entity) - sizeof(TR::SaveGame::Entity::Extra)) + entity->extraSize;
save->entitiesCount++;
}
save->size = ptr - data;
save->version = level.version & TR::VER_VERSION;
// current level state
if (save->entitiesCount) {
TR::SaveGame::CurrentState *state = (TR::SaveGame::CurrentState*)ptr;
*state = level.state;
ptr += sizeof(*state);
}
//Stream::write("savegame.dat", data, int(ptr - data));
Stream::write("savegame.dat", data, int(ptr - data));
delete[] data;
LOG("Ok\n");
@@ -160,15 +170,19 @@ struct Level : IGame {
level.save = *save;
ptr += sizeof(*save);
for (int i = 0; i < save->itemsCount; i++) {
TR::SaveGame::Item *item = (TR::SaveGame::Item*)ptr;
inventory.add(TR::Entity::Type(item->type), item->count, false);
ptr += sizeof(*item);
}
if (save->size > (ptr - data)) { // has current state
TR::SaveGame::CurrentState *currentState = (TR::SaveGame::CurrentState*)ptr;
ptr += sizeof(TR::SaveGame::CurrentState);
if (save->entitiesCount) {
level.state = *currentState;
for (int i = 0; i < save->entitiesCount; i++) {
for (int i = 0; i < currentState->progress.itemsCount; i++) {
TR::SaveGame::Item *item = (TR::SaveGame::Item*)ptr;
inventory.add(TR::Entity::Type(item->type), item->count, false);
ptr += sizeof(*item);
}
for (int i = 0; i < currentState->entitiesCount; i++) {
TR::SaveGame::Entity *entity = (TR::SaveGame::Entity*)ptr;
Controller *controller;
@@ -186,17 +200,13 @@ struct Level : IGame {
ptr += (sizeof(TR::SaveGame::Entity) - sizeof(TR::SaveGame::Entity::Extra)) + entity->extraSize;
}
TR::SaveGame::CurrentState *state = (TR::SaveGame::CurrentState*)ptr;
level.state = *state;
ptr += sizeof(*state);
delete[] data;
uint8 track = level.state.flags.track;
level.state.flags.track = 0;
playTrack(track, true);
}
delete[] data;
// camera->room = lara->getRoomIndex();
// camera->pos = camera->destPos = lara->pos;
LOG("Ok\n");
@@ -516,11 +526,15 @@ struct Level : IGame {
Level *level = (Level*)userData;
level->sndSoundtrack = Sound::play(stream, vec3(0.0f), 0.01f, 1.0f, Sound::MUSIC);
if (level->sndSoundtrack)
if (level->sndSoundtrack) {
if (level->level.isCutsceneLevel()) {
// level->sndSoundtrack->setVolume(0.0f, 0.0f);
// level->sndCurrent = level->sndSoundtrack;
Core::resetTime();
}
level->sndSoundtrack->setVolume(1.0f, 0.2f);
if (level->level.isCutsceneLevel())
level->cutsceneFirstFrame = true;
}
LOG("play soundtrack - %d\n", Core::getTime());
}
virtual void playTrack(uint8 track, bool restart = false) {
@@ -575,7 +589,7 @@ struct Level : IGame {
}
//==============================
Level(Stream &stream) : level(stream), inventory(this), lara(NULL), isEnded(false), cutsceneFirstFrame(false) {
Level(Stream &stream) : level(stream), inventory(this), lara(NULL), isEnded(false), cutsceneWaitTimer(0.0f) {
params->time = 0.0f;
#ifdef _DEBUG
@@ -632,12 +646,14 @@ struct Level : IGame {
inventory.toggle(Inventory::PAGE_OPTION);
}
effect = TR::Effect::NONE;
cube360 = NULL;
sndSoundtrack = NULL;
playTrack(0);
sndCurrent = sndSoundtrack;
effect = TR::Effect::NONE;
cube360 = NULL;
Core::resetTime();
}
virtual ~Level() {
@@ -1252,10 +1268,24 @@ struct Level : IGame {
}
void update() {
if (level.isCutsceneLevel() && (lara->health > 0.0f && !sndSoundtrack && TR::LEVEL_INFO[level.id].ambientTrack != TR::NO_TRACK)) {
if (camera->timer > 0.0f)
loadNextLevel();
return;
if (level.isCutsceneLevel()) {
if (!sndSoundtrack && TR::LEVEL_INFO[level.id].ambientTrack != TR::NO_TRACK) {
if (camera->timer > 0.0f) // for the case that audio stops before animation ends
loadNextLevel();
return;
}
if (cutsceneWaitTimer > 0.0f) {
cutsceneWaitTimer -= Core::deltaTime;
if (cutsceneWaitTimer > 0.0f)
return;
if (sndSoundtrack)
sndSoundtrack->setVolume(1.0f, 0.0f);
cutsceneWaitTimer = 0.0f;
Core::resetTime();
LOG("reset timer - %d\n", Core::getTime());
return;
}
}
if (Input::state[cInventory] && !level.isTitle()) {
@@ -1357,10 +1387,8 @@ struct Level : IGame {
mesh->transparent = transp;
for (int i = 0; i < level.entitiesCount; i++) {
TR::Entity &e = level.entities[i];
if (!e.controller) continue;
int modelIndex = e.modelIndex;
if (modelIndex != 0)
renderEntity(e);
if (!e.controller || e.modelIndex == 0) continue;
renderEntity(e);
}
}

View File

@@ -388,7 +388,7 @@ struct MeshBuilder {
addSprite(indices, vertices, iCount, vCount, vStartSprite, 0, 0, 0, sprite, TR::Color32(255, 255, 255, 255), TR::Color32(255, 255, 255, 255));
}
range.iCount = iCount - range.iStart;
sequences[i].transp = 2;
sequences[i].transp = 1; // alpha blending by default
}
ASSERT(vCount - vStartSprite <= 0xFFFF);

View File

@@ -3,15 +3,24 @@
#include "game.h"
int lastTime, lastJoy = -1;
int lastJoy = -1;
EGLDisplay display;
EGLSurface surface;
EGLContext context;
int getTime() {
int osGetTime() {
return (int)emscripten_get_now();
}
bool osSave(const char *name, const void *data, int size) {
// TODO cookie? idb?
FILE *f = fopen(name, "wb");
if (!f) return false;
fwrite(data, size, 1, f);
fclose(f);
return true;
}
extern "C" {
void EMSCRIPTEN_KEEPALIVE snd_fill(Sound::Frame *frames, int count) {
Sound::fill(frames, count);
@@ -95,14 +104,10 @@ void joyUpdate() {
void main_loop() {
joyUpdate();
int time = getTime();
if (time - lastTime <= 0)
return;
Game::update((time - lastTime) * 0.001f);
lastTime = time;
Game::render();
eglSwapBuffers(display, surface);
if (Game::update()) {
Game::render();
eglSwapBuffers(display, surface);
}
}
bool initGL() {
@@ -291,8 +296,6 @@ int main() {
emscripten_run_script("snd_init()");
resize();
lastTime = getTime();
emscripten_set_main_loop(main_loop, 0, true);
Game::deinit();

View File

@@ -16,7 +16,7 @@
#include "game.h"
int getTime() {
int osGetTime() {
#ifdef DEBUG
LARGE_INTEGER Freq, Count;
QueryPerformanceFrequency(&Freq);
@@ -28,6 +28,14 @@ int getTime() {
#endif
}
bool osSave(const char *name, const void *data, int size) {
FILE *f = fopen(name, "wb");
if (!f) return false;
fwrite(data, size, 1, f);
fclose(f);
return true;
}
// common input functions
InputKey keyToInputKey(int code) {
static const int codes[] = {
@@ -295,11 +303,16 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
HGLRC initGL(HDC hDC) {
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.cColorBits = 32;
pfd.cRedBits = 8;
pfd.cGreenBits = 8;
pfd.cBlueBits = 8;
pfd.cAlphaBits = 8;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
int format = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, format, &pfd);
@@ -356,7 +369,6 @@ int main(int argc, char** argv) {
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&WndProc);
ShowWindow(hWnd, SW_SHOWDEFAULT);
DWORD lastTime = getTime();
MSG msg;
do {
@@ -365,16 +377,10 @@ int main(int argc, char** argv) {
DispatchMessage(&msg);
} else {
joyUpdate();
DWORD time = getTime();
if (time <= lastTime)
continue;
Game::update((time - lastTime) * 0.001f);
lastTime = time;
Game::render();
SwapBuffers(hDC);
if (Game::update()) {
Game::render();
SwapBuffers(hDC);
}
#ifdef _DEBUG
Sleep(20);
#endif

View File

@@ -15,8 +15,6 @@ struct Sprite : Controller {
float time;
vec3 velocity;
BlendMode blendMode;
Sprite(IGame *game, int entity, bool instant = true, int frame = FRAME_ANIMATED) : Controller(game, entity), instant(instant), flag(frame), time(0), velocity(0) {
if (frame >= 0) { // specific frame
this->frame = frame;

View File

@@ -126,7 +126,7 @@ struct Flame : Sprite {
return flame;
}
int jointIndex;
int32 jointIndex;
float sleep;
Flame(IGame *game, int entity) : Sprite(game, entity, false, Sprite::FRAME_ANIMATED), jointIndex(0), sleep(0.0f) {
@@ -134,6 +134,20 @@ struct Flame : Sprite {
activate();
}
virtual bool getSaveData(TR::SaveGame::Entity &data) {
Controller::getSaveData(data);
data.extraSize = sizeof(data.extra.flame);
data.extra.flame.jointIndex = jointIndex;
data.extra.flame.sleep = sleep;
return true;
}
virtual void setSaveData(const TR::SaveGame::Entity &data) {
Controller::setSaveData(data);
jointIndex = data.extra.flame.jointIndex;
sleep = data.extra.flame.sleep;
}
virtual void update() {
Sprite::update();
game->playSound(TR::SND_FLAME, pos, Sound::PAN);
@@ -201,10 +215,14 @@ struct LavaParticle : Sprite {
LavaParticle(IGame *game, int entity) : Sprite(game, entity, false, Sprite::FRAME_RANDOM), bounces(0) {
float speed = randf() * LAVA_H_SPEED;
velocity = vec3(cosf(angle.y) * speed, randf() * LAVA_V_SPEED, sinf(angle.y) * speed);
blendMode = bmAdd;
game->getMesh()->sequences[-(getEntity().modelIndex + 1)].transp = 2; // fix blending mode to additive
activate();
}
virtual bool getSaveData(TR::SaveGame::Entity &data) {
return false;
}
virtual void update() {
applyGravity(velocity.y);
Sprite::update();
@@ -1138,27 +1156,21 @@ struct MidasHand : Controller {
};
struct TrapLava : Controller {
bool done;
TrapLava(IGame *game, int entity) : Controller(game, entity), done(false) {}
TrapLava(IGame *game, int entity) : Controller(game, entity) {}
virtual void update() {
Character *lara = (Character*)level->laraController;
if (lara->health > 0.0f && collide(lara))
lara->hit(1001.0f, this, TR::HIT_LAVA);
if (done) {
deactivate();
return;
}
vec3 dir = getDir();
pos += dir * (25.0f * 30.0f * Core::deltaTime);
roomIndex = getRoomIndex();
TR::Room::Sector *s = level->getSector(roomIndex, int(pos.x + dir.x * 2048.0f), int(pos.y), int(pos.z + dir.z * 2048.0f));
if (!s || s->floor * 256 != int(pos.y))
done = true;
return;
pos += dir * (25.0f * 30.0f * Core::deltaTime);
}
};
@@ -1411,6 +1423,10 @@ struct Bubble : Sprite {
game->waterDrop(pos, 64.0f, 0.01f);
}
virtual bool getSaveData(TR::SaveGame::Entity &data) {
return false;
}
virtual void update() {
pos.y -= speed * Core::deltaTime;
angle.x += 30.0f * 13.0f * DEG2RAD * Core::deltaTime;
@@ -1426,6 +1442,7 @@ struct Explosion : Sprite {
Explosion(IGame *game, int entity) : Sprite(game, entity, true, Sprite::FRAME_ANIMATED) {
game->playSound(TR::SND_EXPLOSION, pos, 0);
game->getMesh()->sequences[-(getEntity().modelIndex + 1)].transp = 2; // fix blending mode to additive
}
};

View File

@@ -35,6 +35,9 @@
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"OpenLara",__VA_ARGS__)
#endif
extern int osGetTime();
extern bool osSave(const char *name, const void *data, int size);
#define DECL_ENUM(v) v,
#define DECL_STR(v) #v,
@@ -1062,15 +1065,7 @@ struct Stream {
}
static void write(const char *name, const void *data, int size) {
#ifdef __EMSCRIPTEN__
extern void osSave(const char *name, const void *data, int size);
osSave(name, data, size);
#else
FILE *f = fopen(name, "wb");
if (!f) return;
fwrite(data, size, 1, f);
fclose(f);
#endif
}
void setPos(int pos) {