From f9e76d9dc078c5fa108b7e6a9b65be45e698ea47 Mon Sep 17 00:00:00 2001 From: Misa Date: Sat, 9 Jan 2021 14:50:06 -0800 Subject: [PATCH] Fix tile of disappearing platforms during final stretch During the final stretch, after Viridian turns off the Dimensional Stability Generator, the map goes all psychedelic and changes colors every 40 frames. Entities change their colors too, including conveyors, moving platforms, and disappearing platforms. But play around with the disappearing platforms for a bit and you'll notice they seem a bit glitchy. If you run on them at the right time, the tile they use while disappearing seems to abruptly change whenever the color of the room changes. If there's a color change while they're reappearing (when you die and respawn in the same room as them), they'll have the wrong tile and look like a conveyor. And even if you've never interacted with them at all, dying and respawning in the same room as them will change their tile to something wrong and also look like a conveyor. So, what's the problem? Well, first off, the tile of every untouched disappearing platform changing into a conveyor after you die and respawn in the same room is caused by a block of code in gamelogic() that gets run on each entity whenever you die. This block of code is the exact same block of code that gets ran on a disappearing platform if it's in the middle of disappearing. As a quick primer, every entity in the game has a state, which is just a number. You can view each entity's state in entityclass::updateentities(). State 0 of disappearing platforms is doing nothing, and they start with an onentity of 1, which means they turn to state 1 when they get touched. State 1 moves to state 2. State 2 does some decrementing, then moves to state 3 and sets the onentity to 4. State 3 also does nothing. After being touched, state 4 makes the platform reappear and move to state 5, but state 5 does the actual reappearing; state 5 then sets the state back to 0 and onentity back to 1. So, back to the copy-pasted block of code. The block of code was originally intended to fast-forward disappearing platforms if they were in the middle of disappearing, so the player respawn code would properly respawn the disappearing platform, instead of leaving it disappeared. What it does is keep updating the entity, while the state of the entity is 2, until it is no longer in state 2, then sets it to state 4. Crucially, the original block of code only ran if the disappearing platform was in state 2. But the other block of code, which was copy-pasted with slight modifications, runs on ALL disappearing platforms in final stretch, regardless of if they are in state 2 or not. Thus, all untouched platforms will be set to state 4, and state 4 will do the animation of the platform reappearing, which is invalid given that the platform never disappeared in the first place. So that's why dying and respawning in the same room as some disappearing platforms during final stretch will change their tiles to be conveyors. It seems to me that doing anything with death is wrong, here. The root cause is that map.changefinalcol() "resets" the tile of every disappearing platform, which is a function that gets called on every color change. The color change has nothing to do with dying, so why fiddle with the death code? Thus, I've deleted that entire block of code. What I've done to fix the issue is to make it so the tile of disappearing platforms aren't manually controlled. You see, unlike other entities in the game, the tile of disappearing platforms gets manually modified whenever it disappears or reappears. Other entities use the tile as a base and store their tile offset in the separate walkingframe attribute, which will be added to the tile attribute to produce the drawframe, which is the final thing that gets rendered - but for disappearing platforms, their tile gets directly incremented or decremented whenever they disappear or reappear, so when map.changefinalcol() gets ran to update the tile of every platform and conveyor, it basically discards the tile offset that was manually added in. Instead, what I've done is make it so disappearing platforms now use walkingframe, and thus their final drawframe will be their tile plus their walkingframe. Whenever map.changefinalcol() gets called, it is now free to modify the tile of disappearing platforms accordingly - after all, the tile offset is now stored in walkingframe, so no weird glitchiness can happen there. --- desktop_version/src/Entity.cpp | 11 +++++++---- desktop_version/src/Logic.cpp | 15 --------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/desktop_version/src/Entity.cpp b/desktop_version/src/Entity.cpp index 7b97d0f3..0b42bae1 100644 --- a/desktop_version/src/Entity.cpp +++ b/desktop_version/src/Entity.cpp @@ -2506,7 +2506,7 @@ bool entityclass::updateentities( int i ) else if (entities[i].state == 2) { entities[i].life--; - if (entities[i].life % 3 == 0) entities[i].tile++; + if (entities[i].life % 3 == 0) entities[i].walkingframe++; if (entities[i].life <= 0) { disableblockat(entities[i].xp, entities[i].yp); @@ -2524,19 +2524,19 @@ bool entityclass::updateentities( int i ) createblock(0, entities[i].xp, entities[i].yp, 32, 8); entities[i].state = 4; entities[i].invis = false; - entities[i].tile--; + entities[i].walkingframe--; entities[i].state++; entities[i].onentity = 1; } else if (entities[i].state == 5) { entities[i].life+=3; - if (entities[i].life % 3 == 0) entities[i].tile--; + if (entities[i].life % 3 == 0) entities[i].walkingframe--; if (entities[i].life >= 12) { entities[i].life = 12; entities[i].state = 0; - entities[i].tile++; + entities[i].walkingframe++; } } break; @@ -3593,6 +3593,9 @@ void entityclass::animateentities( int _i ) break; } break; + case 2: //Disappearing platforms + entities[_i].drawframe = entities[_i].tile + entities[_i].walkingframe; + break; case 11: entities[_i].drawframe = entities[_i].tile; if(entities[_i].animate==2) diff --git a/desktop_version/src/Logic.cpp b/desktop_version/src/Logic.cpp index 91b26542..a1ed2669 100644 --- a/desktop_version/src/Logic.cpp +++ b/desktop_version/src/Logic.cpp @@ -418,21 +418,6 @@ void gamelogic(void) } if (!entitygone) obj.entities[i].state = 4; } - else if (map.finalstretch && obj.entities[i].type == 2) - { - //for the final level. probably something 99% of players won't see. - bool entitygone = false; - while (obj.entities[i].state == 2) - { - entitygone = obj.updateentities(i); - if (entitygone) - { - i--; - break; - } - } - if (!entitygone) obj.entities[i].state = 4; - } else if (obj.entities[i].type == 23 && game.swnmode && game.deathseq<15) { //if playing SWN, get the enemies offscreen.