From 353e09cb64a687ed7e2733c7626066a063a26805 Mon Sep 17 00:00:00 2001 From: XProger Date: Thu, 7 Dec 2017 12:11:25 +0300 Subject: [PATCH] #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 --- src/controller.h | 9 +-- src/core.h | 33 +++++++-- src/enemy.h | 17 ++--- src/format.h | 91 +++++++++++++----------- src/game.h | 21 +++--- src/lara.h | 39 ++++++----- src/level.h | 142 +++++++++++++++++++++++--------------- src/mesh.h | 2 +- src/platform/web/main.cpp | 27 ++++---- src/platform/win/main.cpp | 40 ++++++----- src/sprite.h | 2 - src/trigger.h | 41 +++++++---- src/utils.h | 11 +-- 13 files changed, 281 insertions(+), 194 deletions(-) diff --git a/src/controller.h b/src/controller.h index f1498bf..859b58d 100644 --- a/src/controller.h +++ b/src/controller.h @@ -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(); diff --git a/src/core.h b/src/core.h index 245a2f0..0a4237f 100644 --- a/src/core.h +++ b/src/core.h @@ -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; diff --git a/src/enemy.h b/src/enemy.h index b0ef638..ac7192c 100644 --- a/src/enemy.h +++ b/src/enemy.h @@ -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(); diff --git a/src/format.h b/src/format.h index 133e8b2..1a59521 100644 --- a/src/format.h +++ b/src/format.h @@ -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; }; diff --git a/src/game.h b/src/game.h index 44e04fd..81444cf 100644 --- a/src/game.h +++ b/src/game.h @@ -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() { diff --git a/src/lara.h b/src/lara.h index bd9066b..74f2305 100644 --- a/src/lara.h +++ b/src/lara.h @@ -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); } diff --git a/src/level.h b/src/level.h index 3caf705..6aafe9b 100644 --- a/src/level.h +++ b/src/level.h @@ -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); } } diff --git a/src/mesh.h b/src/mesh.h index cf56c8a..bcd99cd 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -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); diff --git a/src/platform/web/main.cpp b/src/platform/web/main.cpp index cf0af2f..1d9bcf0 100644 --- a/src/platform/web/main.cpp +++ b/src/platform/web/main.cpp @@ -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(); diff --git a/src/platform/win/main.cpp b/src/platform/win/main.cpp index 7eb5865..a351d0d 100644 --- a/src/platform/win/main.cpp +++ b/src/platform/win/main.cpp @@ -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 diff --git a/src/sprite.h b/src/sprite.h index 23787f1..5d38b55 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -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; diff --git a/src/trigger.h b/src/trigger.h index 526bf80..14f0bf7 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -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 } }; diff --git a/src/utils.h b/src/utils.h index 6ed3b5a..c9342da 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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) {