1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-12-23 18:19:43 +01:00

Prevent removing the player entity

Removing the player entity has all sorts of nasty effects, such as
softlocking the game because many inputs require there to be a player
present, such as opening the quit menu.

The most infamous glitch to remove the player entity is the Gravitron
Fling, where the game doesn't see a gravity line at a specific
y-position in the current room, and when it moves the bottom gravity
line it moves the player instead. When the gravity line gets outside the
room, it gets destroyed, so if the player gets dragged outside the room,
they get destroyed, too. (Don't misinterpret this as saying anytime the
player gets dragged outside the room, they get destroyed - it's only the
Gravitron logic that destroys them.)

Also, there are many places in the code that use entity-getting
functions that have a fallback value of 0. If it was possible to remove
the player, then it's possible for this fallback value of 0 to index
obj.entities out-of-bounds, which is not good.

To fix this, entityclass::removeentity() is now a bool that signifies if
the entity was successfully removed or not. If the entity given is the
player (meaning it first checks if it's rule 0, just so in 99% of cases
it'll short-circuit and won't do the next check, which is if
entityclass::getplayer() says the indice to be removed is the player),
then it'll refuse to remove the entity, and return false.

This is a change in behavior where callers might expect
entityclass::removeentity() to always succeed, so I changed the
removeentity_iter() macro to only decrement if removing the entity
succeeded. I also changed entityclass::updateentities() from
'removeentity(i); return true;' to 'return removeentity(i);'.
This commit is contained in:
Misa 2020-06-13 12:00:04 -07:00 committed by Ethan Lee
parent 51d852601d
commit 4f50883d58
2 changed files with 24 additions and 30 deletions

View file

@ -1035,14 +1035,21 @@ void entityclass::createblock( int t, int xp, int yp, int w, int h, int trig /*=
blocks.push_back(block); blocks.push_back(block);
} }
void entityclass::removeentity(int t) // Remove entity, and return true if entity was successfully removed
bool entityclass::removeentity(int t)
{ {
if (t < 0 || t > (int) entities.size()) if (t < 0 || t > (int) entities.size())
{ {
puts("removeentity() out-of-bounds!"); puts("removeentity() out-of-bounds!");
return; return true;
}
if (entities[t].rule == 0 && t == getplayer())
{
// Don't remove the player entity!
return false;
} }
entities.erase(entities.begin() + t); entities.erase(entities.begin() + t);
return true;
} }
void entityclass::removeallblocks() void entityclass::removeallblocks()
@ -2257,15 +2264,13 @@ bool entityclass::updateentities( int i )
{ {
if (entities[i].xp >= 335) if (entities[i].xp >= 335)
{ {
removeentity(i); return removeentity(i);
return true;
} }
if (game.roomx == 117) if (game.roomx == 117)
{ {
if (entities[i].xp >= (33*8)-32) if (entities[i].xp >= (33*8)-32)
{ {
removeentity(i); return removeentity(i);
return true;
} }
//collector for LIES //collector for LIES
} }
@ -2294,15 +2299,13 @@ bool entityclass::updateentities( int i )
{ {
if (entities[i].yp <= -60) if (entities[i].yp <= -60)
{ {
removeentity(i); return removeentity(i);
return true;
} }
if (game.roomy == 108) if (game.roomy == 108)
{ {
if (entities[i].yp <= 60) if (entities[i].yp <= 60)
{ {
removeentity(i); return removeentity(i);
return true;
} }
//collector for factory //collector for factory
} }
@ -2498,8 +2501,7 @@ bool entityclass::updateentities( int i )
if (entities[i].life <= 0) if (entities[i].life <= 0)
{ {
removeblockat(entities[i].xp, entities[i].yp); removeblockat(entities[i].xp, entities[i].yp);
removeentity(i); return removeentity(i);
return true;
} }
} }
break; break;
@ -2507,9 +2509,8 @@ bool entityclass::updateentities( int i )
//wait for collision //wait for collision
if (entities[i].state == 1) if (entities[i].state == 1)
{ {
removeentity(i);
game.gravitycontrol = (game.gravitycontrol + 1) % 2; game.gravitycontrol = (game.gravitycontrol + 1) % 2;
return true; return removeentity(i);
} }
break; break;
@ -2519,8 +2520,7 @@ bool entityclass::updateentities( int i )
entities[i].life--; entities[i].life--;
if (entities[i].life < 0) if (entities[i].life < 0)
{ {
removeentity(i); return removeentity(i);
return true;
} }
} }
break; break;
@ -2531,8 +2531,7 @@ bool entityclass::updateentities( int i )
music.playef(4); music.playef(4);
collect[entities[i].para] = true; collect[entities[i].para] = true;
removeentity(i); return removeentity(i);
return true;
} }
break; break;
case 7: //Found a trinket case 7: //Found a trinket
@ -2556,8 +2555,7 @@ bool entityclass::updateentities( int i )
} }
} }
removeentity(i); return removeentity(i);
return true;
} }
break; break;
case 8: //Savepoints case 8: //Savepoints
@ -3057,8 +3055,7 @@ bool entityclass::updateentities( int i )
if (entities[i].xp >= 310) if (entities[i].xp >= 310)
{ {
game.scmprogress++; game.scmprogress++;
removeentity(i); return removeentity(i);
return true;
} }
} }
break; break;
@ -3083,8 +3080,7 @@ bool entityclass::updateentities( int i )
entities[i].vx = 7; entities[i].vx = 7;
if (entities[i].xp > 320) if (entities[i].xp > 320)
{ {
removeentity(i); return removeentity(i);
return true;
} }
} }
break; break;
@ -3094,8 +3090,7 @@ bool entityclass::updateentities( int i )
entities[i].vx = -7; entities[i].vx = -7;
if (entities[i].xp <-20) if (entities[i].xp <-20)
{ {
removeentity(i); return removeentity(i);
return true;
} }
} }
break; break;
@ -3187,8 +3182,7 @@ bool entityclass::updateentities( int i )
customcollect[entities[i].para] = true; customcollect[entities[i].para] = true;
} }
removeentity(i); return removeentity(i);
return true;
} }
break; break;
case 100: //The teleporter case 100: //The teleporter

View file

@ -8,7 +8,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#define removeentity_iter(index) { obj.removeentity(index); index--; } #define removeentity_iter(index) { if (obj.removeentity(index)) index--; }
#define removeblock_iter(index) { obj.removeblock(index); index--; } #define removeblock_iter(index) { obj.removeblock(index); index--; }
enum enum
@ -55,7 +55,7 @@ public:
void createblock(int t, int xp, int yp, int w, int h, int trig = 0); void createblock(int t, int xp, int yp, int w, int h, int trig = 0);
void removeentity(int t); bool removeentity(int t);
void removeallblocks(); void removeallblocks();