From 4f50883d58d3c17e5427169ab8f35a4c22666e70 Mon Sep 17 00:00:00 2001 From: Misa Date: Sat, 13 Jun 2020 12:00:04 -0700 Subject: [PATCH] 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);'. --- desktop_version/src/Entity.cpp | 50 +++++++++++++++------------------- desktop_version/src/Entity.h | 4 +-- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/desktop_version/src/Entity.cpp b/desktop_version/src/Entity.cpp index 037b659c..4c16f1fc 100644 --- a/desktop_version/src/Entity.cpp +++ b/desktop_version/src/Entity.cpp @@ -1035,14 +1035,21 @@ void entityclass::createblock( int t, int xp, int yp, int w, int h, int trig /*= 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()) { 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); + return true; } void entityclass::removeallblocks() @@ -2257,15 +2264,13 @@ bool entityclass::updateentities( int i ) { if (entities[i].xp >= 335) { - removeentity(i); - return true; + return removeentity(i); } if (game.roomx == 117) { if (entities[i].xp >= (33*8)-32) { - removeentity(i); - return true; + return removeentity(i); } //collector for LIES } @@ -2294,15 +2299,13 @@ bool entityclass::updateentities( int i ) { if (entities[i].yp <= -60) { - removeentity(i); - return true; + return removeentity(i); } if (game.roomy == 108) { if (entities[i].yp <= 60) { - removeentity(i); - return true; + return removeentity(i); } //collector for factory } @@ -2498,8 +2501,7 @@ bool entityclass::updateentities( int i ) if (entities[i].life <= 0) { removeblockat(entities[i].xp, entities[i].yp); - removeentity(i); - return true; + return removeentity(i); } } break; @@ -2507,9 +2509,8 @@ bool entityclass::updateentities( int i ) //wait for collision if (entities[i].state == 1) { - removeentity(i); game.gravitycontrol = (game.gravitycontrol + 1) % 2; - return true; + return removeentity(i); } break; @@ -2519,8 +2520,7 @@ bool entityclass::updateentities( int i ) entities[i].life--; if (entities[i].life < 0) { - removeentity(i); - return true; + return removeentity(i); } } break; @@ -2531,8 +2531,7 @@ bool entityclass::updateentities( int i ) music.playef(4); collect[entities[i].para] = true; - removeentity(i); - return true; + return removeentity(i); } break; case 7: //Found a trinket @@ -2556,8 +2555,7 @@ bool entityclass::updateentities( int i ) } } - removeentity(i); - return true; + return removeentity(i); } break; case 8: //Savepoints @@ -3057,8 +3055,7 @@ bool entityclass::updateentities( int i ) if (entities[i].xp >= 310) { game.scmprogress++; - removeentity(i); - return true; + return removeentity(i); } } break; @@ -3083,8 +3080,7 @@ bool entityclass::updateentities( int i ) entities[i].vx = 7; if (entities[i].xp > 320) { - removeentity(i); - return true; + return removeentity(i); } } break; @@ -3094,8 +3090,7 @@ bool entityclass::updateentities( int i ) entities[i].vx = -7; if (entities[i].xp <-20) { - removeentity(i); - return true; + return removeentity(i); } } break; @@ -3187,8 +3182,7 @@ bool entityclass::updateentities( int i ) customcollect[entities[i].para] = true; } - removeentity(i); - return true; + return removeentity(i); } break; case 100: //The teleporter diff --git a/desktop_version/src/Entity.h b/desktop_version/src/Entity.h index edc194b2..b15dcfbf 100644 --- a/desktop_version/src/Entity.h +++ b/desktop_version/src/Entity.h @@ -8,7 +8,7 @@ #include #include -#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--; } enum @@ -55,7 +55,7 @@ public: 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();