mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-23 01:59:43 +01:00
Fix entity and block indices after destroying them
This patch restores some 2.2 behavior, fixing a regression caused by the refactor of properly using std::vectors. In 2.2, the game allocated 200 items in obj.entities, but used a system where each entity had an `active` attribute to signify if the entity actually existed or not. When dealing with entities, you would have to check this `active` flag, or else you'd be dealing with an entity that didn't actually exist. (By the way, what I'm saying applies to blocks and obj.blocks as well, except for some small differing details like the game allocating 500 block slots versus obj.entities's 200.) As a consequence, the game had to use a separate tracking variable, obj.nentity, because obj.entities.size() would just report 200, instead of the actual amount of entities. Needless to say, having to check for `active` and use `obj.nentity` is a bit error-prone, and it's messier than simply using the std::vector the way it was intended. Also, this resulted in a hard limit of 200 entities, which custom level makers ran into surprisingly quite often. 2.3 comes along, and removes the whole system. Now, std::vectors are properly being used, and obj.entities.size() reports the actual number of entities in the vector; you no longer have to check for `active` when dealing with entities of any sort. But there was one previous behavior of 2.2 that this system kind of forgets about - namely, the ability to have holes in between entities. You see, when an entity got disabled in 2.2 (which just meant turning its `active` off), the indices of all other entities stayed the same; the indice of the entity that got disabled stays there as a hole in the array. But when an entity gets removed in 2.3 (previous to this patch), the indices of every entity afterwards in the array get shifted down by one. std::vector isn't really meant to be able to contain holes. Do the indices of entities and blocks matter? Yes; they determine the order in which entities and blocks get evaluated (the highest indice gets evaluated first), and I had to fix some block evaluation order stuff in previous PRs. And in the case of entities, they matter hugely when using the recently-discovered Arbitrary Entity Manipulation glitch (where crewmate script commands are used on arbitrary entities by setting the `i` attribute of `scriptclass` and passing invalid crewmate identifiers to the commands). If you use Arbitrary Entity Manipulation after destroying some entities, there is a chance that your script won't work between 2.2 and 2.3. The indices also still determine the rendering order of entities (highest indice gets drawn first, which means lowest indice gets drawn in front of other entities). As an example: let's say we have the player at 0, a gravity line at 1, and a checkpoint at 2; then we destroy the gravity line and create a crewmate (let's do Violet). If we're able to have holes, then after removing the gravity line, none of the other indices shift. Then Violet will be created at indice 1, and will be drawn in front of the checkpoint. But if we can't have holes, then removing the gravity line results in the indice of the checkpoint shifting down to indice 1. Then Violet is created at indice 2, and gets drawn behind the checkpoint! This is a clear illustration of changing the behavior that existed in 2.2. However, I also don't want to go back to the `active` system of having to check an attribute before operating on an entity. So... what do we do to restore the holes? Well, we don't need to have an `active` attribute, or modify any existing code that operates on entities. Instead, we can just set the attributes of the entities so that they naturally get ignored by everything that comes into contact with it. For entities, we set their invis to true, and their size, type, and rule to -1 (the game never uses a size, type, or rule of -1 anywhere); for blocks, we set their type to -1, and their width and height to 0. obj.entities.size() will no longer necessarily equal the amount of entities in the room; rather, it will be the amount of entity SLOTS that have been allocated. But nothing that uses obj.entities.size() needs to actually know the amount of entities; it's mostly used for iterating over every entity in the vector. Excess entity slots get cleaned up upon every call of mapclass::gotoroom(), which will now deallocate entity slots starting from the end until it hits a player, at which point it will switch to disabling entity slots instead of removing them entirely. The entclass::clear() and blockclass::clear() functions have been restored because we need to call their initialization functions when reusing a block/entity slot; it's possible to create an entity with an invalid type number (it creates a glitchy Viridian), and without calling the initialization function again, it would simply not create anything. After this patch is applied, entity and block indices will be restored to how they behaved in 2.2.
This commit is contained in:
parent
99276d7cdd
commit
3927bb9713
11 changed files with 152 additions and 80 deletions
|
@ -1,6 +1,11 @@
|
||||||
#include "BlockV.h"
|
#include "BlockV.h"
|
||||||
|
|
||||||
blockclass::blockclass()
|
blockclass::blockclass()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void blockclass::clear()
|
||||||
{
|
{
|
||||||
type = 0;
|
type = 0;
|
||||||
trigger = 0;
|
trigger = 0;
|
||||||
|
@ -20,6 +25,11 @@ blockclass::blockclass()
|
||||||
|
|
||||||
x = 0.0f;
|
x = 0.0f;
|
||||||
y = 0.0f;
|
y = 0.0f;
|
||||||
|
|
||||||
|
/* std::strings get initialized automatically, but this is */
|
||||||
|
/* in case this function gets called again after construction */
|
||||||
|
script.clear();
|
||||||
|
prompt.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockclass::rectset(const int xi, const int yi, const int wi, const int hi)
|
void blockclass::rectset(const int xi, const int yi, const int wi, const int hi)
|
||||||
|
|
|
@ -8,6 +8,7 @@ class blockclass
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
blockclass();
|
blockclass();
|
||||||
|
void clear();
|
||||||
|
|
||||||
void rectset(const int xi, const int yi, const int wi, const int hi);
|
void rectset(const int xi, const int yi, const int wi, const int hi);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
|
|
||||||
entclass::entclass()
|
entclass::entclass()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void entclass::clear()
|
||||||
{
|
{
|
||||||
invis = false;
|
invis = false;
|
||||||
type = 0;
|
type = 0;
|
||||||
|
|
|
@ -9,6 +9,7 @@ class entclass
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
entclass();
|
entclass();
|
||||||
|
void clear();
|
||||||
|
|
||||||
bool outside();
|
bool outside();
|
||||||
|
|
||||||
|
|
|
@ -760,7 +760,35 @@ void entityclass::createblock( int t, int xp, int yp, int w, int h, int trig /*=
|
||||||
{
|
{
|
||||||
k = blocks.size();
|
k = blocks.size();
|
||||||
|
|
||||||
blockclass block;
|
blockclass newblock;
|
||||||
|
blockclass* blockptr;
|
||||||
|
|
||||||
|
/* Can we reuse the slot of a disabled block? */
|
||||||
|
bool reuse = false;
|
||||||
|
for (size_t i = 0; i < blocks.size(); ++i)
|
||||||
|
{
|
||||||
|
if (blocks[i].type == -1
|
||||||
|
&& blocks[i].wp == 0
|
||||||
|
&& blocks[i].hp == 0
|
||||||
|
&& blocks[i].rect.w == 0
|
||||||
|
&& blocks[i].rect.h == 0)
|
||||||
|
{
|
||||||
|
reuse = true;
|
||||||
|
blockptr = &blocks[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reuse)
|
||||||
|
{
|
||||||
|
blockptr = &newblock;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blockptr->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
blockclass& block = *blockptr;
|
||||||
switch(t)
|
switch(t)
|
||||||
{
|
{
|
||||||
case BLOCK: //Block
|
case BLOCK: //Block
|
||||||
|
@ -1038,23 +1066,31 @@ void entityclass::createblock( int t, int xp, int yp, int w, int h, int trig /*=
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks.push_back(block);
|
if (!reuse)
|
||||||
|
{
|
||||||
|
blocks.push_back(block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove entity, and return true if entity was successfully removed
|
/* Disable entity, and return true if entity was successfully disabled */
|
||||||
bool entityclass::removeentity(int t)
|
bool entityclass::disableentity(int t)
|
||||||
{
|
{
|
||||||
if (!INBOUNDS_VEC(t, entities))
|
if (!INBOUNDS_VEC(t, entities))
|
||||||
{
|
{
|
||||||
puts("removeentity() out-of-bounds!");
|
puts("disableentity() out-of-bounds!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (entities[t].rule == 0 && t == getplayer())
|
if (entities[t].rule == 0 && t == getplayer())
|
||||||
{
|
{
|
||||||
// Don't remove the player entity!
|
/* Don't disable the player entity! */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
entities.erase(entities.begin() + t);
|
|
||||||
|
entities[t].invis = true;
|
||||||
|
entities[t].size = -1;
|
||||||
|
entities[t].type = -1;
|
||||||
|
entities[t].rule = -1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,22 +1099,21 @@ void entityclass::removeallblocks()
|
||||||
blocks.clear();
|
blocks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityclass::removeblock( int t )
|
void entityclass::disableblock( int t )
|
||||||
{
|
{
|
||||||
if (!INBOUNDS_VEC(t, blocks))
|
if (!INBOUNDS_VEC(t, blocks))
|
||||||
{
|
{
|
||||||
puts("removeblock() out-of-bounds!");
|
puts("disableblock() out-of-bounds!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
blocks.erase(blocks.begin() + t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void entityclass::removeblockat( int x, int y )
|
blocks[t].type = -1;
|
||||||
{
|
|
||||||
for (size_t i = 0; i < blocks.size(); i++)
|
blocks[t].wp = 0;
|
||||||
{
|
blocks[t].hp = 0;
|
||||||
if(blocks[i].xp == int(x) && blocks[i].yp == int(y)) removeblock_iter(i);
|
|
||||||
}
|
blocks[t].rect.w = blocks[t].wp;
|
||||||
|
blocks[t].rect.h = blocks[t].hp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityclass::moveblockto(int x1, int y1, int x2, int y2, int w, int h)
|
void entityclass::moveblockto(int x1, int y1, int x2, int y2, int w, int h)
|
||||||
|
@ -1099,17 +1134,13 @@ void entityclass::moveblockto(int x1, int y1, int x2, int y2, int w, int h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityclass::nocollisionat(int x, int y)
|
void entityclass::disableblockat(int x, int y)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < blocks.size(); i++)
|
for (size_t i = 0; i < blocks.size(); i++)
|
||||||
{
|
{
|
||||||
if (blocks[i].xp == x && blocks[i].yp == y)
|
if (blocks[i].xp == x && blocks[i].yp == y)
|
||||||
{
|
{
|
||||||
blocks[i].wp = 0;
|
disableblock(i);
|
||||||
blocks[i].hp = 0;
|
|
||||||
|
|
||||||
blocks[i].rect.w = blocks[i].wp;
|
|
||||||
blocks[i].rect.h = blocks[i].hp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1120,7 +1151,7 @@ void entityclass::removetrigger( int t )
|
||||||
{
|
{
|
||||||
if(blocks[i].type == TRIGGER && blocks[i].trigger == t)
|
if(blocks[i].type == TRIGGER && blocks[i].trigger == t)
|
||||||
{
|
{
|
||||||
removeblock_iter(i);
|
disableblock(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1186,6 +1217,33 @@ void entityclass::createentity( float xp, float yp, int t, float vx /*= 0*/, flo
|
||||||
{
|
{
|
||||||
k = entities.size();
|
k = entities.size();
|
||||||
|
|
||||||
|
entclass newent;
|
||||||
|
entclass* entptr;
|
||||||
|
|
||||||
|
/* Can we reuse the slot of a disabled entity? */
|
||||||
|
bool reuse = false;
|
||||||
|
for (size_t i = 0; i < entities.size(); ++i)
|
||||||
|
{
|
||||||
|
if (entities[i].invis
|
||||||
|
&& entities[i].size == -1
|
||||||
|
&& entities[i].type == -1
|
||||||
|
&& entities[i].rule == -1)
|
||||||
|
{
|
||||||
|
reuse = true;
|
||||||
|
entptr = &entities[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reuse)
|
||||||
|
{
|
||||||
|
entptr = &newent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entptr->clear();
|
||||||
|
}
|
||||||
|
|
||||||
//Size 0 is a sprite
|
//Size 0 is a sprite
|
||||||
//Size 1 is a tile
|
//Size 1 is a tile
|
||||||
//Beyond that are special cases (to do)
|
//Beyond that are special cases (to do)
|
||||||
|
@ -1210,7 +1268,7 @@ void entityclass::createentity( float xp, float yp, int t, float vx /*= 0*/, flo
|
||||||
bool custom_gray = false;
|
bool custom_gray = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
entclass entity;
|
entclass& entity = *entptr;
|
||||||
entity.xp = xp;
|
entity.xp = xp;
|
||||||
entity.yp = yp;
|
entity.yp = yp;
|
||||||
entity.lerpoldxp = xp;
|
entity.lerpoldxp = xp;
|
||||||
|
@ -2128,7 +2186,10 @@ void entityclass::createentity( float xp, float yp, int t, float vx /*= 0*/, flo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entities.push_back(entity);
|
if (!reuse)
|
||||||
|
{
|
||||||
|
entities.push_back(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Returns true if entity is removed
|
//Returns true if entity is removed
|
||||||
|
@ -2324,13 +2385,13 @@ bool entityclass::updateentities( int i )
|
||||||
{
|
{
|
||||||
if (entities[i].xp >= 335)
|
if (entities[i].xp >= 335)
|
||||||
{
|
{
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
if (game.roomx == 117)
|
if (game.roomx == 117)
|
||||||
{
|
{
|
||||||
if (entities[i].xp >= (33*8)-32)
|
if (entities[i].xp >= (33*8)-32)
|
||||||
{
|
{
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
//collector for LIES
|
//collector for LIES
|
||||||
}
|
}
|
||||||
|
@ -2359,13 +2420,13 @@ bool entityclass::updateentities( int i )
|
||||||
{
|
{
|
||||||
if (entities[i].yp <= -60)
|
if (entities[i].yp <= -60)
|
||||||
{
|
{
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
if (game.roomx == 113 && game.roomy == 108)
|
if (game.roomx == 113 && game.roomy == 108)
|
||||||
{
|
{
|
||||||
if (entities[i].yp <= 60)
|
if (entities[i].yp <= 60)
|
||||||
{
|
{
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
//collector for factory
|
//collector for factory
|
||||||
}
|
}
|
||||||
|
@ -2520,7 +2581,7 @@ bool entityclass::updateentities( int i )
|
||||||
if (entities[i].life % 3 == 0) entities[i].tile++;
|
if (entities[i].life % 3 == 0) entities[i].tile++;
|
||||||
if (entities[i].life <= 0)
|
if (entities[i].life <= 0)
|
||||||
{
|
{
|
||||||
removeblockat(entities[i].xp, entities[i].yp);
|
disableblockat(entities[i].xp, entities[i].yp);
|
||||||
entities[i].state = 3;// = false;
|
entities[i].state = 3;// = false;
|
||||||
entities[i].invis = true;
|
entities[i].invis = true;
|
||||||
}
|
}
|
||||||
|
@ -2566,8 +2627,8 @@ bool entityclass::updateentities( int i )
|
||||||
entities[i].tile++;
|
entities[i].tile++;
|
||||||
if (entities[i].life <= 0)
|
if (entities[i].life <= 0)
|
||||||
{
|
{
|
||||||
removeblockat(entities[i].xp, entities[i].yp);
|
disableblockat(entities[i].xp, entities[i].yp);
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2576,7 +2637,7 @@ bool entityclass::updateentities( int i )
|
||||||
if (entities[i].state == 1)
|
if (entities[i].state == 1)
|
||||||
{
|
{
|
||||||
game.gravitycontrol = (game.gravitycontrol + 1) % 2;
|
game.gravitycontrol = (game.gravitycontrol + 1) % 2;
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2586,7 +2647,7 @@ bool entityclass::updateentities( int i )
|
||||||
entities[i].life--;
|
entities[i].life--;
|
||||||
if (entities[i].life < 0)
|
if (entities[i].life < 0)
|
||||||
{
|
{
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2600,7 +2661,7 @@ bool entityclass::updateentities( int i )
|
||||||
collect[(int) entities[i].para] = true;
|
collect[(int) entities[i].para] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 7: //Found a trinket
|
case 7: //Found a trinket
|
||||||
|
@ -2627,7 +2688,7 @@ bool entityclass::updateentities( int i )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8: //Savepoints
|
case 8: //Savepoints
|
||||||
|
@ -3143,7 +3204,7 @@ bool entityclass::updateentities( int i )
|
||||||
if (entities[i].xp >= 310)
|
if (entities[i].xp >= 310)
|
||||||
{
|
{
|
||||||
game.scmprogress++;
|
game.scmprogress++;
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3168,7 +3229,7 @@ bool entityclass::updateentities( int i )
|
||||||
entities[i].vx = 7;
|
entities[i].vx = 7;
|
||||||
if (entities[i].xp > 320)
|
if (entities[i].xp > 320)
|
||||||
{
|
{
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3178,7 +3239,7 @@ bool entityclass::updateentities( int i )
|
||||||
entities[i].vx = -7;
|
entities[i].vx = -7;
|
||||||
if (entities[i].xp <-20)
|
if (entities[i].xp <-20)
|
||||||
{
|
{
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3273,7 +3334,7 @@ bool entityclass::updateentities( int i )
|
||||||
music.playef(27);
|
music.playef(27);
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeentity(i);
|
return disableentity(i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 100: //The teleporter
|
case 100: //The teleporter
|
||||||
|
@ -4662,7 +4723,7 @@ void entityclass::collisioncheck(int i, int j, bool scm /*= false*/)
|
||||||
{
|
{
|
||||||
//Disable collision temporarily so we don't push the person out!
|
//Disable collision temporarily so we don't push the person out!
|
||||||
//Collision will be restored at end of platform update loop in gamelogic
|
//Collision will be restored at end of platform update loop in gamelogic
|
||||||
nocollisionat(entities[j].xp, entities[j].yp);
|
disableblockat(entities[j].xp, entities[j].yp);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: //Entity to entity
|
case 3: //Entity to entity
|
||||||
|
|
|
@ -10,23 +10,6 @@
|
||||||
#include "BlockV.h"
|
#include "BlockV.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
|
||||||
#define removeentity_iter(index) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
extern entityclass obj; \
|
|
||||||
if (obj.removeentity(index)) \
|
|
||||||
{ \
|
|
||||||
index--; \
|
|
||||||
} \
|
|
||||||
} while (false)
|
|
||||||
#define removeblock_iter(index) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
extern entityclass obj; \
|
|
||||||
obj.removeblock(index); \
|
|
||||||
index--; \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
BLOCK = 0,
|
BLOCK = 0,
|
||||||
|
@ -71,18 +54,16 @@ public:
|
||||||
|
|
||||||
void createblock(int t, int xp, int yp, int w, int h, int trig = 0, const std::string& script = "");
|
void createblock(int t, int xp, int yp, int w, int h, int trig = 0, const std::string& script = "");
|
||||||
|
|
||||||
bool removeentity(int t);
|
bool disableentity(int t);
|
||||||
|
|
||||||
void removeallblocks();
|
void removeallblocks();
|
||||||
|
|
||||||
void removeblock(int t);
|
void disableblock(int t);
|
||||||
|
|
||||||
void removeblockat(int x, int y);
|
void disableblockat(int x, int y);
|
||||||
|
|
||||||
void moveblockto(int x1, int y1, int x2, int y2, int w, int h);
|
void moveblockto(int x1, int y1, int x2, int y2, int w, int h);
|
||||||
|
|
||||||
void nocollisionat(int x, int y);
|
|
||||||
|
|
||||||
void removetrigger(int t);
|
void removetrigger(int t);
|
||||||
|
|
||||||
void copylinecross(int t);
|
void copylinecross(int t);
|
||||||
|
|
|
@ -2173,7 +2173,7 @@ void Game::updatestate()
|
||||||
i = obj.getcompanion();
|
i = obj.getcompanion();
|
||||||
if(INBOUNDS_VEC(i, obj.entities))
|
if(INBOUNDS_VEC(i, obj.entities))
|
||||||
{
|
{
|
||||||
obj.removeentity(i);
|
obj.disableentity(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
i = obj.getteleporter();
|
i = obj.getteleporter();
|
||||||
|
|
|
@ -1891,7 +1891,7 @@ void gameinput()
|
||||||
if((int(SDL_fabsf(obj.entities[ie].vx))<=1) && (int(obj.entities[ie].vy) == 0) )
|
if((int(SDL_fabsf(obj.entities[ie].vx))<=1) && (int(obj.entities[ie].vy) == 0) )
|
||||||
{
|
{
|
||||||
script.load(obj.blocks[game.activeactivity].script);
|
script.load(obj.blocks[game.activeactivity].script);
|
||||||
obj.removeblock(game.activeactivity);
|
obj.disableblock(game.activeactivity);
|
||||||
game.activeactivity = -1;
|
game.activeactivity = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,7 +347,7 @@ void gamelogic()
|
||||||
//(and if the tile wasn't there it would pass straight through again)
|
//(and if the tile wasn't there it would pass straight through again)
|
||||||
int prevx = obj.entities[i].xp;
|
int prevx = obj.entities[i].xp;
|
||||||
int prevy = obj.entities[i].yp;
|
int prevy = obj.entities[i].yp;
|
||||||
obj.nocollisionat(prevx, prevy);
|
obj.disableblockat(prevx, prevy);
|
||||||
|
|
||||||
obj.entities[i].xp = 152;
|
obj.entities[i].xp = 152;
|
||||||
obj.entities[i].newxp = 152;
|
obj.entities[i].newxp = 152;
|
||||||
|
@ -668,7 +668,7 @@ void gamelogic()
|
||||||
obj.entities[line].xp += 24;
|
obj.entities[line].xp += 24;
|
||||||
if (obj.entities[line].xp > 320)
|
if (obj.entities[line].xp > 320)
|
||||||
{
|
{
|
||||||
obj.removeentity(line);
|
obj.disableentity(line);
|
||||||
game.swngame = 8;
|
game.swngame = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -783,7 +783,7 @@ void gamelogic()
|
||||||
|
|
||||||
int prevx = obj.entities[i].xp;
|
int prevx = obj.entities[i].xp;
|
||||||
int prevy = obj.entities[i].yp;
|
int prevy = obj.entities[i].yp;
|
||||||
obj.nocollisionat(prevx, prevy);
|
obj.disableblockat(prevx, prevy);
|
||||||
|
|
||||||
bool entitygone = obj.updateentities(i); // Behavioral logic
|
bool entitygone = obj.updateentities(i); // Behavioral logic
|
||||||
if (entitygone) continue;
|
if (entitygone) continue;
|
||||||
|
@ -811,7 +811,7 @@ void gamelogic()
|
||||||
|
|
||||||
int prevx = obj.entities[ie].xp;
|
int prevx = obj.entities[ie].xp;
|
||||||
int prevy = obj.entities[ie].yp;
|
int prevy = obj.entities[ie].yp;
|
||||||
obj.nocollisionat(prevx, prevy);
|
obj.disableblockat(prevx, prevy);
|
||||||
|
|
||||||
bool entitygone = obj.updateentities(ie); // Behavioral logic
|
bool entitygone = obj.updateentities(ie); // Behavioral logic
|
||||||
if (entitygone) continue;
|
if (entitygone) continue;
|
||||||
|
|
|
@ -871,11 +871,25 @@ void mapclass::gotoroom(int rx, int ry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < obj.entities.size(); i++)
|
/* Disable all entities in the room, and deallocate any unnecessary entity slots. */
|
||||||
|
/* However don't disable player entities, but do preserve holes between them (if any). */
|
||||||
|
bool player_found = false;
|
||||||
|
for (int i = obj.entities.size() - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
if (obj.entities[i].rule != 0)
|
/* Iterate in reverse order to prevent unnecessary indice shifting */
|
||||||
|
if (obj.entities[i].rule == 0)
|
||||||
{
|
{
|
||||||
removeentity_iter(i);
|
player_found = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player_found)
|
||||||
|
{
|
||||||
|
obj.entities.erase(obj.entities.begin() + i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obj.disableentity(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,16 +167,16 @@ void scriptclass::run()
|
||||||
{
|
{
|
||||||
if(words[1]=="gravitylines"){
|
if(words[1]=="gravitylines"){
|
||||||
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
||||||
if(obj.entities[edi].type==9) removeentity_iter(edi);
|
if(obj.entities[edi].type==9) obj.disableentity(edi);
|
||||||
if(obj.entities[edi].type==10) removeentity_iter(edi);
|
if(obj.entities[edi].type==10) obj.disableentity(edi);
|
||||||
}
|
}
|
||||||
}else if(words[1]=="warptokens"){
|
}else if(words[1]=="warptokens"){
|
||||||
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
||||||
if(obj.entities[edi].type==11) removeentity_iter(edi);
|
if(obj.entities[edi].type==11) obj.disableentity(edi);
|
||||||
}
|
}
|
||||||
}else if(words[1]=="platforms"){
|
}else if(words[1]=="platforms"){
|
||||||
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
||||||
if(obj.entities[edi].rule==2 && obj.entities[edi].animate==100) removeentity_iter(edi);
|
if(obj.entities[edi].rule==2 && obj.entities[edi].animate==100) obj.disableentity(edi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3701,13 +3701,12 @@ void scriptclass::hardreset()
|
||||||
obj.entities[theplayer].tile = 0;
|
obj.entities[theplayer].tile = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove duplicate player entities
|
/* Disable duplicate player entities */
|
||||||
for (int i = 0; i < (int) obj.entities.size(); i++)
|
for (int i = 0; i < (int) obj.entities.size(); i++)
|
||||||
{
|
{
|
||||||
if (obj.entities[i].rule == 0 && i != theplayer)
|
if (obj.entities[i].rule == 0 && i != theplayer)
|
||||||
{
|
{
|
||||||
removeentity_iter(i);
|
obj.disableentity(i);
|
||||||
theplayer--; // just in case indice of player is not 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue