From ebd381c228d0cb1a4e3723c36b4e8224edb2bdb5 Mon Sep 17 00:00:00 2001 From: Misa Date: Sat, 27 Jun 2020 17:08:57 -0700 Subject: [PATCH] Fix the two-frame-delay when entering a room with an "init" script This patch is very kludge-y, but at least it fixes a semi-noticeable visual issue in custom levels that use internal scripts to spawn entities when loading a room. Basically, the problem here is that when the game checks for script boxes and sets newscript, newscript has already been processed for that frame, and when the game does load a script, script.run() has already been processed for that frame. That issue can be fixed, but it turns out that due to my over-30-FPS game loop changes, there's now ANOTHER visible frame of delay between room load and entity creation, because the render function gets called in between the script being loaded at the end of gamelogic() and the script actually getting run. So... I have to temporary move script.run() to the end of gamelogic() (in map.twoframedelayfix()), and make sure it doesn't get run next frame, because double-evaluations are bad. To do that, I have to introduce the kludge variable script.dontrunnextframe, which does exactly as it says. And with all that work, the two-frame (now three-frame) delay is fixed. --- desktop_version/src/Entity.cpp | 1 + desktop_version/src/Game.cpp | 1 + desktop_version/src/Logic.cpp | 11 +++++++++++ desktop_version/src/Map.cpp | 27 +++++++++++++++++++++++++++ desktop_version/src/Map.h | 2 ++ desktop_version/src/Script.cpp | 1 + desktop_version/src/Script.h | 2 +- desktop_version/src/main.cpp | 9 ++++++++- 8 files changed, 52 insertions(+), 2 deletions(-) diff --git a/desktop_version/src/Entity.cpp b/desktop_version/src/Entity.cpp index 9c47e408..b426d39e 100644 --- a/desktop_version/src/Entity.cpp +++ b/desktop_version/src/Entity.cpp @@ -4780,6 +4780,7 @@ void entityclass::entitycollisioncheck() } } + // WARNING: If updating this code, don't forget to update Map.cpp mapclass::twoframedelayfix() activetrigger = -1; if (checktrigger() > -1) { diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index ea55b8a2..af0832e2 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -1753,6 +1753,7 @@ void Game::updatestate() break; + // WARNING: If updating this code, make sure to update Map.cpp mapclass::twoframedelayfix() case 300: startscript = true; newscript="custom_"+customscript[0]; diff --git a/desktop_version/src/Logic.cpp b/desktop_version/src/Logic.cpp index 11c4fb6a..1d5bc411 100644 --- a/desktop_version/src/Logic.cpp +++ b/desktop_version/src/Logic.cpp @@ -1117,6 +1117,8 @@ void gamelogic() } } + bool screen_transition = false; + if (!map.warpy && !map.towermode) { //Normal! Just change room @@ -1125,11 +1127,13 @@ void gamelogic() { obj.entities[player].yp -= 240; map.gotoroom(game.roomx, game.roomy + 1); + screen_transition = true; } if (player > -1 && game.door_up > -2 && obj.entities[player].yp < -2) { obj.entities[player].yp += 240; map.gotoroom(game.roomx, game.roomy - 1); + screen_transition = true; } } @@ -1141,11 +1145,13 @@ void gamelogic() { obj.entities[player].xp += 320; map.gotoroom(game.roomx - 1, game.roomy); + screen_transition = true; } if (player > -1 && game.door_right > -2 && obj.entities[player].xp >= 308) { obj.entities[player].xp -= 320; map.gotoroom(game.roomx + 1, game.roomy); + screen_transition = true; } } @@ -1364,6 +1370,11 @@ void gamelogic() } } } + + if (screen_transition) + { + map.twoframedelayfix(); + } } //Update colour cycling for final level diff --git a/desktop_version/src/Map.cpp b/desktop_version/src/Map.cpp index c915a9f6..2d6e0289 100644 --- a/desktop_version/src/Map.cpp +++ b/desktop_version/src/Map.cpp @@ -1980,3 +1980,30 @@ void mapclass::loadlevel(int rx, int ry) } } } + +void mapclass::twoframedelayfix() +{ + // Fixes the two-frame delay in custom levels that use scripts to spawn an entity upon room load. + // Because when the room loads and newscript is set to run, newscript has already ran for that frame, + // and when the script gets loaded script.run() has already ran for that frame, too. + // A bit kludge-y, but it's the least we can do without changing the frame ordering. + + if (game.deathseq != -1 + // obj.checktrigger() sets obj.activetrigger + || obj.checktrigger() <= -1 + || obj.activetrigger < 300) + { + return; + } + + game.newscript = "custom_" + game.customscript[obj.activetrigger - 300]; + obj.removetrigger(obj.activetrigger); + game.state = 0; + game.statedelay = 0; + script.load(game.newscript); + if (script.running) + { + script.run(); + script.dontrunnextframe = true; + } +} diff --git a/desktop_version/src/Map.h b/desktop_version/src/Map.h index 870cd71b..2a46bd32 100644 --- a/desktop_version/src/Map.h +++ b/desktop_version/src/Map.h @@ -75,6 +75,8 @@ public: void loadlevel(int rx, int ry); + void twoframedelayfix(); + std::vector roomdeaths; std::vector roomdeathsfinal; diff --git a/desktop_version/src/Script.cpp b/desktop_version/src/Script.cpp index b93cb277..e8800e5a 100644 --- a/desktop_version/src/Script.cpp +++ b/desktop_version/src/Script.cpp @@ -16,6 +16,7 @@ scriptclass::scriptclass() position = 0; scriptdelay = 0; running = false; + dontrunnextframe = false; b = 0; g = 0; diff --git a/desktop_version/src/Script.h b/desktop_version/src/Script.h index c1aa6bb2..1cdbd066 100644 --- a/desktop_version/src/Script.h +++ b/desktop_version/src/Script.h @@ -56,7 +56,7 @@ public: int looppoint, loopcount; int scriptdelay; - bool running; + bool running, dontrunnextframe; std::string tempword; std::string currentletter; diff --git a/desktop_version/src/main.cpp b/desktop_version/src/main.cpp index ed9ec51a..ca923e49 100644 --- a/desktop_version/src/main.cpp +++ b/desktop_version/src/main.cpp @@ -542,7 +542,14 @@ void inline fixedloop() titlelogic(); break; case GAMEMODE: - if (script.running) + // WARNING: If updating this code, don't forget to update Map.cpp mapclass::twoframedelayfix() + + // Ugh, I hate this kludge variable but it's the only way to do it + if (script.dontrunnextframe) + { + script.dontrunnextframe = false; + } + else if (script.running) { script.run(); }