mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-23 01:59:43 +01:00
Evaluate flipping eligibility per-entity
This fixes a regression where the behavior of duplicate player entities is different, causing a gameplay section in Vespera Scientifica to be impossible, as described in #903. In the level, you are allowed to flip in mid-air. Vespera accomplishes this by having two duplicate player entities stuck in a platform. One of them is responsible for letting the player flip in one direction, and one of them is responsible for letting them flip in the other. In 2.3, this works because in order for a player entity to flip, `game.jumppressed` is checked, and the entity will flip if `game.jumppressed` is greater than 0, then `game.jumppressed` will be set to 0. In this way, whenever a player entity flips, it will set `game.jumppressed` to 0, so whenever the next player entity is evaluated, `game.jumppressed` is 0 and thus _that_ entity will not flip. This is because the for-loop surrounds both the `game.jumppressed` check and flipping the entity. In 2.4 after #609 and subsequent patches, however, this is not the case. Here, the for-loop only surrounds flipping the entity. Therefore, the `game.jumppressed` check is evaluated only once. So, it will end up flipping every player entity if the entities are eligible. In this case, one of them is eligible twice, resulting in the game flipping gravitycontrol four times, which is essentially the same as not flipping at all (except for all the sound effects). Hence, the fix here is to make it so the for-loop surrounds the `game.jumppressed` check. Now, this doesn't mean that the intent of #609 - that duplicate player entities have the same initial velocity applied to them when flipping - has to be removed. We can just put the for-loops back in. But I carefully implemented them in such a way that the overall function is not quadratic, i.e. O(n²). Instead, there's a pass done over the `obj.entities` vector beforehand to store all indexes of a player entity in a temporary vector, and then that vector is used to update all the player entities. In this manner, the function is still linear - O(n) - over the number of entities in the room. I tested this to make sure that no previous regressions popped up again, including #839, #855, and #887. And #484 is still resolved. Fixes #903.
This commit is contained in:
parent
ba7519106f
commit
88d49547d4
1 changed files with 30 additions and 22 deletions
|
@ -1,4 +1,5 @@
|
|||
#include <tinyxml2.h>
|
||||
#include <vector>
|
||||
|
||||
#include "Credits.h"
|
||||
#include "CustomLevels.h"
|
||||
|
@ -2508,8 +2509,6 @@ void gameinput(void)
|
|||
bool has_control = false;
|
||||
bool enter_pressed = game.press_map && !game.mapheld;
|
||||
bool enter_already_processed = false;
|
||||
bool any_onground = false;
|
||||
bool any_onroof = false;
|
||||
bool interact_pressed;
|
||||
if (game.separate_interact)
|
||||
{
|
||||
|
@ -2626,15 +2625,6 @@ void gameinput(void)
|
|||
obj.entities[ie].dir = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.entities[ie].onground > 0)
|
||||
{
|
||||
any_onground = true;
|
||||
}
|
||||
if (obj.entities[ie].onroof > 0)
|
||||
{
|
||||
any_onroof = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2695,33 +2685,51 @@ void gameinput(void)
|
|||
game.jumpheld = true;
|
||||
}
|
||||
|
||||
if (game.jumppressed > 0)
|
||||
std::vector<size_t> player_entities;
|
||||
for (size_t ie = 0; ie < obj.entities.size(); ie++)
|
||||
{
|
||||
if (obj.entities[ie].rule == 0)
|
||||
{
|
||||
player_entities.push_back(ie);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t ie = 0; ie < obj.entities.size(); ie++)
|
||||
{
|
||||
const bool process_flip = obj.entities[ie].rule == 0 &&
|
||||
game.jumppressed > 0;
|
||||
if (!process_flip)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
game.jumppressed--;
|
||||
if (any_onground && game.gravitycontrol == 0)
|
||||
if (obj.entities[ie].onground > 0 && game.gravitycontrol == 0)
|
||||
{
|
||||
game.gravitycontrol = 1;
|
||||
for (size_t ie = 0; ie < obj.entities.size(); ++ie)
|
||||
for (size_t j = 0; j < player_entities.size(); j++)
|
||||
{
|
||||
if (obj.entities[ie].rule == 0 && (obj.entities[ie].onground > 0 || obj.entities[ie].onroof > 0))
|
||||
const size_t e = player_entities[j];
|
||||
if (obj.entities[e].onground > 0 || obj.entities[e].onroof > 0)
|
||||
{
|
||||
obj.entities[ie].vy = -4;
|
||||
obj.entities[ie].ay = -3;
|
||||
obj.entities[e].vy = -4;
|
||||
obj.entities[e].ay = -3;
|
||||
}
|
||||
}
|
||||
music.playef(0);
|
||||
game.jumppressed = 0;
|
||||
game.totalflips++;
|
||||
}
|
||||
if (any_onroof && game.gravitycontrol == 1)
|
||||
if (obj.entities[ie].onroof > 0 && game.gravitycontrol == 1)
|
||||
{
|
||||
game.gravitycontrol = 0;
|
||||
for (size_t ie = 0; ie < obj.entities.size(); ++ie)
|
||||
for (size_t j = 0; j < player_entities.size(); j++)
|
||||
{
|
||||
if (obj.entities[ie].rule == 0 && (obj.entities[ie].onground > 0 || obj.entities[ie].onroof > 0))
|
||||
const size_t e = player_entities[j];
|
||||
if (obj.entities[e].onground > 0 || obj.entities[e].onroof > 0)
|
||||
{
|
||||
obj.entities[ie].vy = 4;
|
||||
obj.entities[ie].ay = 3;
|
||||
obj.entities[e].vy = 4;
|
||||
obj.entities[e].ay = 3;
|
||||
}
|
||||
}
|
||||
music.playef(1);
|
||||
|
|
Loading…
Reference in a new issue