1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2025-01-05 16:39:44 +01:00

Remove entityclonefix in favor of improving emitters

Emitters are odd. They rely on `setenemy` to set the right type of the
entities they emit. However, `setenemy` only gets called in specific
rooms, so if you use these enemy types outside of those rooms, they'd
just infinitely spawn themselves and, well, that's a memory leak.

The prior fix for this was simply not allowing emitter types outside
of those rooms. This, however, feels very hacky and is a little
disappointing as well.

This commit improves emitters by no longer relying on `setenemy`, and
instead setting the emitted enemy type ourselves. However, `setenemy`
still happens, and to make sure we don't set the enemy type *twice*,
we set the `para` attribute of the spawned enemies to `-1`, so that
`setenemy` will not do anything at all to the spawned enemy.

The reason I don't remove the code in `setenemy` outright is a couple
things:

- The main game code still relies on it for spawning the initial
enemies in the room

- Custom levels may rely on the prior behavior (sadly)
This commit is contained in:
AllyTally 2023-09-02 11:23:27 -03:00 committed by NyakoFox
parent baf76cb78e
commit 3aca47e890
2 changed files with 107 additions and 122 deletions

View file

@ -239,6 +239,11 @@ void entityclass::add_default_types(void)
void entityclass::set_enemy_type(entclass* entity, const char* type) void entityclass::set_enemy_type(entclass* entity, const char* type)
{ {
if (entity == NULL)
{
return;
}
if (enemy_types.count(type) > 0) if (enemy_types.count(type) > 0)
{ {
EnemyType* enemyType = &enemy_types[type]; EnemyType* enemyType = &enemy_types[type];
@ -1446,33 +1451,7 @@ static bool gridmatch( int p1, int p2, int p3, int p4, int p11, int p21, int p31
return false; return false;
} }
static void entityclonefix(entclass* entity) entclass* entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int p1, int p2, int p3, int p4)
{
const bool is_lies_emitter = entity->behave == 10;
const bool is_factory_emitter = entity->behave == 12;
const bool is_emitter = is_lies_emitter || is_factory_emitter;
if (!is_emitter)
{
return;
}
const bool in_lies_emitter_room =
game.roomx >= 113 && game.roomx <= 117 && game.roomy == 111;
const bool in_factory_emitter_room =
game.roomx == 113 && game.roomy >= 108 && game.roomy <= 110;
const bool valid = (is_lies_emitter && in_lies_emitter_room)
|| (is_factory_emitter && in_factory_emitter_room);
if (!valid)
{
/* Fix memory leak */
entity->behave = -1;
}
}
void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int p1, int p2, int p3, int p4)
{ {
k = entities.size(); k = entities.size();
@ -1590,7 +1569,6 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
else else
{ {
entity.setenemyroom(game.roomx, game.roomy); entity.setenemyroom(game.roomx, game.roomy);
entityclonefix(&entity);
} }
break; break;
case 2: //A moving platform case 2: //A moving platform
@ -1750,7 +1728,7 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
//Check if it's already been collected //Check if it's already been collected
entity.para = meta1; entity.para = meta1;
if (!INBOUNDS_ARR(meta1, collect) || collect[meta1]) return; if (!INBOUNDS_ARR(meta1, collect) || collect[meta1]) return NULL;
break; break;
case 9: //Something Shiny case 9: //Something Shiny
entity.rule = 3; entity.rule = 3;
@ -1765,7 +1743,7 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
//Check if it's already been collected //Check if it's already been collected
entity.para = meta1; entity.para = meta1;
if (!INBOUNDS_ARR(meta1, collect) || collect[meta1]) return; if (!INBOUNDS_ARR(meta1, collect) || collect[meta1]) return NULL;
break; break;
case 10: //Savepoint case 10: //Savepoint
entity.rule = 3; entity.rule = 3;
@ -1787,7 +1765,7 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
if (game.nodeathmode) if (game.nodeathmode)
{ {
return; return NULL;
} }
break; break;
case 11: //Horizontal Gravity Line case 11: //Horizontal Gravity Line
@ -1961,7 +1939,7 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
//Check if it's already been collected //Check if it's already been collected
entity.para = meta1; entity.para = meta1;
if (INBOUNDS_ARR(meta1, collect) && !collect[meta1]) return; if (INBOUNDS_ARR(meta1, collect) && !collect[meta1]) return NULL;
break; break;
case 23: //SWN Enemies case 23: //SWN Enemies
//Given a different behavior, these enemies are especially for SWN mode and disappear outside the screen. //Given a different behavior, these enemies are especially for SWN mode and disappear outside the screen.
@ -2299,9 +2277,10 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
//Check if it's already been collected //Check if it's already been collected
entity.para = meta1; entity.para = meta1;
if (!INBOUNDS_ARR(meta1, customcollect) || customcollect[meta1]) return; if (!INBOUNDS_ARR(meta1, customcollect) || customcollect[meta1]) return NULL;
break; break;
case 56: //Custom enemy case 56: //Custom enemy
{
entity.rule = 1; entity.rule = 1;
entity.type = EntityType_MOVING; entity.type = EntityType_MOVING;
entity.behave = meta1; entity.behave = meta1;
@ -2323,9 +2302,9 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
//Set colour based on room tile //Set colour based on room tile
//Set custom colours //Set custom colours
if(customplatformtile>0){ if (customplatformtile > 0) {
int entcol=(customplatformtile/12); int entcol = (customplatformtile / 12);
switch(entcol){ switch (entcol) {
//RED //RED
case 3: case 7: case 12: case 23: case 28: case 3: case 7: case 12: case 23: case 28:
case 34: case 42: case 48: case 58: case 34: case 42: case 48: case 58:
@ -2362,12 +2341,11 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
} }
} }
if(custom_gray){ if (custom_gray) {
entity.colour = 18; entity.colour = 18;
} }
entityclonefix(&entity);
break; break;
}
case 100: // Invalid enemy, but gets treated as a teleporter case 100: // Invalid enemy, but gets treated as a teleporter
entity.type = EntityType_TELEPORTER; entity.type = EntityType_TELEPORTER;
break; break;
@ -2382,12 +2360,6 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
entities.push_back(entity); entities.push_back(entity);
} }
/* Fix crewmate facing directions
* This is a bit kludge-y but it's better than copy-pasting
* and is okay to do because entity 12 does not change state on its own
*/
if (entity.type == EntityType_CREWMATE)
{
size_t indice; size_t indice;
if (reuse) if (reuse)
{ {
@ -2397,33 +2369,42 @@ void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int
{ {
indice = entities.size() - 1; indice = entities.size() - 1;
} }
/* Fix crewmate facing directions
* This is a bit kludge-y but it's better than copy-pasting
* and is okay to do because entity 12 does not change state on its own
*/
if (entity.type == EntityType_CREWMATE)
{
updateentities(indice); updateentities(indice);
} }
return &entities[indice];
} }
void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int p1, int p2) entclass* entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int p1, int p2)
{ {
createentity(xp, yp, t, meta1, meta2, p1, p2, 320, 240); return createentity(xp, yp, t, meta1, meta2, p1, p2, 320, 240);
} }
void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int p1) entclass* entityclass::createentity(int xp, int yp, int t, int meta1, int meta2, int p1)
{ {
createentity(xp, yp, t, meta1, meta2, p1, 0); return createentity(xp, yp, t, meta1, meta2, p1, 0);
} }
void entityclass::createentity(int xp, int yp, int t, int meta1, int meta2) entclass* entityclass::createentity(int xp, int yp, int t, int meta1, int meta2)
{ {
createentity(xp, yp, t, meta1, meta2, 0); return createentity(xp, yp, t, meta1, meta2, 0);
} }
void entityclass::createentity(int xp, int yp, int t, int meta1) entclass* entityclass::createentity(int xp, int yp, int t, int meta1)
{ {
createentity(xp, yp, t, meta1, 0); return createentity(xp, yp, t, meta1, 0);
} }
void entityclass::createentity(int xp, int yp, int t) entclass* entityclass::createentity(int xp, int yp, int t)
{ {
createentity(xp, yp, t, 0); return createentity(xp, yp, t, 0);
} }
//Returns true if entity is removed //Returns true if entity is removed
@ -2600,7 +2581,9 @@ bool entityclass::updateentities( int i )
//Emitter: shoot an enemy every so often //Emitter: shoot an enemy every so often
if (entities[i].state == 0) if (entities[i].state == 0)
{ {
createentity(entities[i].xp+28, entities[i].yp, 1, 10, 1); entclass* entity = createentity(entities[i].xp+28, entities[i].yp, 1, 10, -1);
set_enemy_type(entity, "lies");
entity->setenemyroom(game.roomx, game.roomy); // For the color
entities[i].state = 1; entities[i].state = 1;
entities[i].statedelay = 12; entities[i].statedelay = 12;
} }
@ -2635,7 +2618,9 @@ bool entityclass::updateentities( int i )
//Emitter: shoot an enemy every so often (up) //Emitter: shoot an enemy every so often (up)
if (entities[i].state == 0) if (entities[i].state == 0)
{ {
createentity(entities[i].xp, entities[i].yp, 1, 12, 1); entclass* entity = createentity(entities[i].xp, entities[i].yp, 1, 12, -1);
set_enemy_type(entity, "factory_clouds");
entity->setenemyroom(game.roomx, game.roomy); // For the color
entities[i].state = 1; entities[i].state = 1;
entities[i].statedelay = 16; entities[i].statedelay = 16;
} }

View file

@ -115,15 +115,15 @@ public:
void revertlinecross(std::vector<entclass>& linecrosskludge, int t, int s); void revertlinecross(std::vector<entclass>& linecrosskludge, int t, int s);
void createentity(int xp, int yp, int t, int meta1, int meta2, entclass* createentity(int xp, int yp, int t, int meta1, int meta2,
int p1, int p2, int p3, int p4); int p1, int p2, int p3, int p4);
void createentity(int xp, int yp, int t, int meta1, int meta2, entclass* createentity(int xp, int yp, int t, int meta1, int meta2,
int p1, int p2); int p1, int p2);
void createentity(int xp, int yp, int t, int meta1, int meta2, entclass* createentity(int xp, int yp, int t, int meta1, int meta2,
int p1); int p1);
void createentity(int xp, int yp, int t, int meta1, int meta2); entclass* createentity(int xp, int yp, int t, int meta1, int meta2);
void createentity(int xp, int yp, int t, int meta1); entclass* createentity(int xp, int yp, int t, int meta1);
void createentity(int xp, int yp, int t); entclass* createentity(int xp, int yp, int t);
bool updateentities(int i); bool updateentities(int i);