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:
parent
51d852601d
commit
4f50883d58
2 changed files with 24 additions and 30 deletions
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue